Files
deb-python-rtslib-fb/doc/getting_started.md
Andy Grover 4b7562d49f Add a tutorial for rtslib use
Add a walkthrough that demonstrates how to get started using rtslib.

Signed-off-by: Andy Grover <agrover@redhat.com>
2014-01-03 11:10:33 -08:00

6.0 KiB

Getting started using the rtslib API

The rtslib API wraps the LIO kernel target's configfs-based userspace configuration with an object-based, Python interface. Its operating model is that instantiating a Python object will result in that object creating the corresponding kernel object if it doesn't already exist, or will refer to the existing object if it does.

Also, note that the Python objects wrap LIO's configfs objects, but do no buffering or caching of values or properties. Setting a value on an object via rtslib results in the LIO kernel configuration being modified immediately as well -- there is no additional save or flush required.

Let's try it.

> sudo python

Configuring LIO must be done by root, so run the python REPL as root.

>>> from rtslib import FileIOStorageObject
>>> f = FileIOStorageObject("test1", "/tmp/test.img", 100000000)

FileIO storage objects enable a file to serve as a disk image. In this example, a few things are happening. First, since a backing file path is given and does not yet exist, rtslib creates the backing file at /tmp/test.img with a size of 100000000 bytes. Next, rtslib configures LIO to use the file to back a fileio storage object called "test1".

The storage object has a number of properties.

>>> f.status
'deactivated'

This shows that while the backstore has been registered, it hasn't yet been exported via a fabric. Now, let's create a fabric.

>>> from rtslib import FabricModule, Target, TPG
>>> iscsi = FabricModule("iscsi")

Fabric objects are singleton objects. The preferred way to obtain a reference to one is via the FabricModule factory method, as shown. Then, we can create a Target, an instance of that fabric.

>>> target = Target(iscsi)

For other fabrics that are linked to actual hardware resources, we would have also needed to supply a valid "wwn" parameter that matched available hardware IDs. But for iscsi, we can omit this and rtslib will autogenerate one.

>>> target.wwn
'iqn.2003-01.org.linux-iscsi.localhost.x8664:sn.c11be18bebc3'

Next, we must create a TPG. iSCSI allows a single named target to have multiple independent configurations within it, divided into Target Port Groups, or TPGs. Usually one is enough, so we just need to create one, and then all further configuration will be on the TPG.

>>> tpg = TPG(target, 1)

Our TPG needs to listen on a TCP port for incoming connections from initiators, so let's set that up.

>>> from rtslib import NetworkPortal, NodeACL, LUN, MappedLUN
>>> portal = NetworkPortal(tpg, "0.0.0.0", 3260)

Now LIO is listening on all IP addresses, on port 3260, the iSCSI default. But, we aren't exporting any luns yet!

>>> lun = LUN(tpg, 0, f)

We've just assigned the FileIO storage object to the TPG. as we can see:

>>> f.status
'activated'

...the storage object is now active and linked to the TPG.

The final thing to configure is Node ACLs. There are some authentication modes where just assigning a LUN to a TPG will export it to all initiators (see targetcli manpage for more info), but usually one creates individual permissions and LUN mappings for each initiator.

LIO configures initiator access via initiator IQN, instead of some other targets that are based on initiator IP address. (For open-iscsi, the autogenerated initiator IQN is in "/etc/iscsi/initiatorname.iscsi".)

>>> nodeacl = NodeACL(tpg, "iqn.2004-03.com.example.foo:0987")

When we are using nodeacl-based authentication, i.e. when generate_node_acls is 0, we then need to map the tpg lun to the nodeacl. This is handy in that each initiator can have its own view of the available LUNs.

>>> mlun = MappedLUN(nodeacl, 5, lun)

Finding associated objects

All rtslib objects have properties to obtain other related objects. For example, if you have a TPG object called "tpg", then tpg.parent_target will be the Target that contains the tpg.

>>> tpg
<TPG 1>

>>> tpg.parent_target
<Target iqn.2003-01.org.linux-iscsi.localhost.x8664:sn.c11be18bebc3>

The FabricModule object is then accessible from the target:

>>> tpg.parent_target.fabric_module.name
'iscsi'

Going down the hierarchy, an object can have multiple child objects of a given type, so a list is returned:

>>> iscsi.targets
<generator object _list_targets at 0x2836f00>

Actually it's a Python generator, list's less memory-intensive cousin. If we really want a list, call:

>>> list(iscsi.targets)
[<Target iqn.2003-01.org.linux-iscsi.localhost.x8664:sn.c11be18bebc3>]

Finding objects using RTSRoot()

The RTSRoot object enables finding all rtslib objects of a type that are configured on the system.

>>> root = rtslib.RTSRoot()
>>> list(root.storage_objects)
[<FileIOStorageObject fileio/test1>]

RTSRoot contains generators for all levels of objects. For example, if we want to obtain all NodeACL objects, instead of needing nested for loops to iterate through all fabrics, then all targets, then all tpgs, then all node acls, the root.node_acls generator iterates through NodeACLs wherever they are:

>>> list(root.node_acls)
[<NodeACL iqn.2004-03.com.example.foo:0987>,
 <NodeACL iqn.2004-03.com.example.foo:1234>]

Other handy things to try

All objects have a dump() method, which outputs a dict of the object's current state.

>>> mlun.dump()
{'index': 5, 'tpg_lun': 0, 'write_protect': False}

Finally, rtslib is just a wrapper around LIO's configfs interface, which is usually mounted at /sys/kernel/config/target. Poking around there may also help to understand what's going on.

Other sample code

While targetcli uses rtslib, it has a parallel configshell-based tree structure that may make it less helpful as a reference. Focus on 'rtsnode' objects -- these are references to rtslib objects, as described here.

Also, the 'targetd' project (https://github.com/agrover/targetd) uses rtslib for its kernel target support, see 'targetd/block.py' for more examples of rtslib usage.