#!/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]" + " ") 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())