--- /dev/null
+#!/usr/bin/env python
+# vim: et tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 - 2013 Red Hat, Inc.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import gettext
+import re
+import sys
+
+import rtslib
+
+gettext.install('cinder-rtstool', unicode=1)
+
+
+class RtstoolError(Exception):
+ pass
+
+
+class RtstoolImportError(RtstoolError):
+ pass
+
+
+def create(backing_device, name, userid, password, initiator_iqns=None):
+ try:
+ rtsroot = rtslib.root.RTSRoot()
+ except rtslib.utils.RTSLibError:
+ print _('Ensure that configfs is mounted at /sys/kernel/config.')
+ raise
+
+ # Look to see if BlockStorageObject already exists
+ for x in rtsroot.storage_objects:
+ if x.dump()['name'] == name:
+ # Already exists, use this one
+ return
+
+ so_new = rtslib.BlockStorageObject(name=name,
+ dev=backing_device)
+
+ target_new = rtslib.Target(rtslib.FabricModule('iscsi'), name, 'create')
+
+ tpg_new = rtslib.TPG(target_new, mode='create')
+ tpg_new.set_attribute('authentication', '1')
+
+ lun_new = rtslib.LUN(tpg_new, storage_object=so_new)
+
+ initiator_name = None
+ name_file = '/etc/iscsi/initiatorname.iscsi'
+
+ try:
+ with open(name_file, 'r') as f:
+ for line in f:
+ m = re.match('InitiatorName=(.+)', line)
+ if m != None:
+ initiator_name = m.group(1)
+ break
+ except IOError:
+ raise RtstoolError(_('Could not open %s') % name_file)
+
+ if initiator_name == None:
+ raise RtstoolError(_('Could not read InitiatorName from %s') %
+ name_file)
+
+ acl_new = rtslib.NodeACL(tpg_new, initiator_name, mode='create')
+
+ acl_new.chap_userid = userid
+ acl_new.chap_password = password
+
+ rtslib.MappedLUN(acl_new, lun_new.lun, lun_new.lun)
+
+ if initiator_iqns:
+ initiator_iqns = initiator_iqns.strip(' ')
+ for i in initiator_iqns.split(','):
+ acl_new = rtslib.NodeACL(tpg_new, i, mode='create')
+ acl_new.chap_userid = userid
+ acl_new.chap_password = password
+
+ rtslib.MappedLUN(acl_new, lun_new.lun, lun_new.lun)
+
+ tpg_new.enable = 1
+
+ try:
+ rtslib.NetworkPortal(tpg_new, '0.0.0.0', 3260, mode='any')
+ except rtslib.utils.RTSLibError:
+ print _('Error creating NetworkPortal: ensure port 3260 '
+ 'is not in use by another service.')
+ raise
+
+ try:
+ rtslib.NetworkPortal(tpg_new, '::0', 3260, mode='any')
+ except rtslib.utils.RTSLibError:
+ # TODO(emh): Binding to IPv6 fails sometimes -- let pass for now.
+ pass
+
+
+def add_initiator(target_iqn, initiator_iqn, userid, password):
+ try:
+ rtsroot = rtslib.root.RTSRoot()
+ except rtslib.utils.RTSLibError:
+ print _('Ensure that configfs is mounted at /sys/kernel/config.')
+ raise
+
+ # Look for the target
+ target = None
+ for t in rtsroot.targets:
+ if t.dump()['wwn'] == target_iqn:
+ target = t
+ break
+ if target == None:
+ raise RtstoolError(_('Could not find target %s') % target_iqn)
+
+ tpg = target.tpgs.next() # get the first one
+ for acl in tpg.dump()['node_acls']:
+ # See if this ACL configuration already exists
+ if acl['node_wwn'] == initiator_iqn:
+ # No further action required
+ return
+
+ acl_new = rtslib.NodeACL(tpg, initiator_iqn, mode='create')
+ acl_new.chap_userid = userid
+ acl_new.chap_password = password
+
+ rtslib.MappedLUN(acl_new, 0, tpg_lun=0)
+
+
+def get_targets():
+ rtsroot = rtslib.root.RTSRoot()
+ for x in rtsroot.targets:
+ print(x.dump()['wwn'])
+
+
+def delete(iqn):
+ rtsroot = rtslib.root.RTSRoot()
+ for x in rtsroot.targets:
+ if x.dump()['wwn'] == iqn:
+ x.delete()
+ break
+
+ for x in rtsroot.storage_objects:
+ if x.dump()['name'] == iqn:
+ x.delete()
+ break
+
+
+def verify_rtslib():
+ for member in ['BlockStorageObject', 'FabricModule', 'LUN',
+ 'MappedLUN', 'NetworkPortal', 'NodeACL', 'root',
+ 'Target', 'TPG']:
+ if not hasattr(rtslib, member):
+ raise RtstoolImportError(_("rtslib is missing member %s: "
+ "You may need a newer python-rtslib.") %
+ member)
+
+
+def usage():
+ print "Usage:"
+ print sys.argv[0], \
+ "create [device] [name] [userid] [password]", \
+ "<initiator_iqn,iqn2,iqn3,...>"
+ print sys.argv[0], \
+ "add-initiator [target_iqn] [userid] [password] [initiator_iqn]"
+ print sys.argv[0], "get-targets"
+ print sys.argv[0], "delete [iqn]"
+ print sys.argv[0], "verify"
+ sys.exit(1)
+
+
+def main(argv=None):
+ if argv is None:
+ argv = sys.argv
+
+ if len(argv) < 2:
+ usage()
+
+ if argv[1] == 'create':
+ if len(argv) < 6:
+ usage()
+
+ if len(argv) > 7:
+ usage()
+
+ backing_device = argv[2]
+ name = argv[3]
+ userid = argv[4]
+ password = argv[5]
+ initiator_iqns = None
+
+ if len(argv) > 6:
+ initiator_iqns = argv[6]
+
+ create(backing_device, name, userid, password, initiator_iqns)
+
+ elif argv[1] == 'add-initiator':
+ if len(argv) < 6:
+ usage()
+
+ target_iqn = argv[2]
+ userid = argv[3]
+ password = argv[4]
+ initiator_iqn = argv[5]
+
+ add_initiator(target_iqn, initiator_iqn, userid, password)
+
+ elif argv[1] == 'get-targets':
+ get_targets()
+
+ elif argv[1] == 'delete':
+ if len(argv) < 3:
+ usage()
+
+ iqn = argv[2]
+ delete(iqn)
+
+ elif argv[1] == 'verify':
+ # This is used to verify that this script can be called by cinder,
+ # and that rtslib is new enough to work.
+ verify_rtslib()
+ return 0
+
+ else:
+ usage()
+
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main())