Hello community, here is the log from the commit of package ceph-iscsi for openSUSE:Factory checked in at 2019-03-12 09:54:27 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ceph-iscsi (Old) and /work/SRC/openSUSE:Factory/.ceph-iscsi.new.28833 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ceph-iscsi" Tue Mar 12 09:54:27 2019 rev:5 rq:683769 version:3.0+1552304123.g67b0d30 Changes: -------- --- /work/SRC/openSUSE:Factory/ceph-iscsi/ceph-iscsi.changes 2019-02-28 21:44:59.653484338 +0100 +++ /work/SRC/openSUSE:Factory/.ceph-iscsi.new.28833/ceph-iscsi.changes 2019-03-12 09:54:30.479524984 +0100 @@ -1,0 +2,6 @@ +Mon Mar 11 11:35:48 UTC 2019 - ncut...@suse.com + +- Update to 3.0+1552304123.g67b0d30: + + add support for 'rbd' backstore (Ricardo Marques) + +------------------------------------------------------------------- Old: ---- ceph-iscsi-3.0+1551361389.g157b5fd.tar.gz New: ---- ceph-iscsi-3.0+1552304123.g67b0d30.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ceph-iscsi.spec ++++++ --- /var/tmp/diff_new_pack.8jAQz8/_old 2019-03-12 09:54:31.803524721 +0100 +++ /var/tmp/diff_new_pack.8jAQz8/_new 2019-03-12 09:54:31.835524715 +0100 @@ -20,7 +20,7 @@ Name: ceph-iscsi -Version: 3.0+1551361389.g157b5fd +Version: 3.0+1552304123.g67b0d30 Release: 1%{?dist} Group: System/Filesystems Summary: Python modules for Ceph iSCSI gateway configuration management ++++++ ceph-iscsi-3.0+1551361389.g157b5fd.tar.gz -> ceph-iscsi-3.0+1552304123.g67b0d30.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1551361389.g157b5fd/ceph-iscsi.spec new/ceph-iscsi-3.0+1552304123.g67b0d30/ceph-iscsi.spec --- old/ceph-iscsi-3.0+1551361389.g157b5fd/ceph-iscsi.spec 2019-02-28 14:43:09.980709800 +0100 +++ new/ceph-iscsi-3.0+1552304123.g67b0d30/ceph-iscsi.spec 2019-03-11 12:35:23.551649077 +0100 @@ -20,7 +20,7 @@ Name: ceph-iscsi -Version: 3.0+1551361389.g157b5fd +Version: 3.0+1552304123.g67b0d30 Release: 1%{?dist} Group: System/Filesystems Summary: Python modules for Ceph iSCSI gateway configuration management diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1551361389.g157b5fd/ceph_iscsi_config/backstore.py new/ceph-iscsi-3.0+1552304123.g67b0d30/ceph_iscsi_config/backstore.py --- old/ceph-iscsi-3.0+1551361389.g157b5fd/ceph_iscsi_config/backstore.py 2019-02-28 14:43:09.700708236 +0100 +++ new/ceph-iscsi-3.0+1552304123.g67b0d30/ceph_iscsi_config/backstore.py 2019-03-11 12:35:23.211647200 +0100 @@ -1,2 +1,16 @@ +from rtslib_fb import UserBackedStorageObject, RBDStorageObject + +from ceph_iscsi_config.utils import CephiSCSIError + USER_RBD = 'user:rbd' RBD = 'rbd' + + +def lookup_storage_object(name, backstore): + if backstore == USER_RBD: + return UserBackedStorageObject(name=name) + elif backstore == RBD: + return RBDStorageObject(name=name) + else: + raise CephiSCSIError("Could not lookup storage object - " + "Unsupported backstore {}".format(backstore)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1551361389.g157b5fd/ceph_iscsi_config/client.py new/ceph-iscsi-3.0+1552304123.g67b0d30/ceph_iscsi_config/client.py --- old/ceph-iscsi-3.0+1551361389.g157b5fd/ceph_iscsi_config/client.py 2019-02-28 14:43:09.700708236 +0100 +++ new/ceph-iscsi-3.0+1552304123.g67b0d30/ceph_iscsi_config/client.py 2019-03-11 12:35:23.215647222 +0100 @@ -276,7 +276,7 @@ tpg.set_attribute('authentication', '0') - def configure_auth(self, chap_credentials, chap_mutual_credentials): + def configure_auth(self, chap_credentials, chap_mutual_credentials, target_config): """ Attempt to configure authentication for the client :return: @@ -362,6 +362,15 @@ else: self.change_count += 1 + self._update_acl(target_config) + + def _update_acl(self, target_config): + if self.tpg.node_acls: + self.tpg.set_attribute('generate_node_acls', 0) + if not target_config['acl_enabled']: + target_config['acl_enabled'] = True + self.change_count += 1 + def _add_lun(self, image, lun): """ Add a given image to the client ACL @@ -576,7 +585,7 @@ self.logger.warning("(main) client '{}' configured without" " security".format(self.iqn)) - self.configure_auth(self.chap, self.chap_mutual) + self.configure_auth(self.chap, self.chap_mutual, target_config) if self.error: return diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1551361389.g157b5fd/ceph_iscsi_config/common.py new/ceph-iscsi-3.0+1552304123.g67b0d30/ceph_iscsi_config/common.py --- old/ceph-iscsi-3.0+1551361389.g157b5fd/ceph_iscsi_config/common.py 2019-02-28 14:43:09.700708236 +0100 +++ new/ceph-iscsi-3.0+1552304123.g67b0d30/ceph_iscsi_config/common.py 2019-03-11 12:35:23.215647222 +0100 @@ -30,10 +30,7 @@ self.error = False self.error_msg = '' self.cluster = rados.Rados(conffile=settings.config.cephconf, - name=settings.config.cluster_client_name, - conf=dict(keyring="{}/{}".format( - settings.config.ceph_config_dir, - settings.config.gateway_keyring))) + name=settings.config.cluster_client_name) try: self.cluster.connect() except rados.Error as err: @@ -54,7 +51,7 @@ "targets": {}, "discovery_auth": {'chap': '', 'chap_mutual': ''}, - "version": 6, + "version": 7, "epoch": 0, "created": '', "updated": '' @@ -221,10 +218,16 @@ self.update_item("version", None, 5) if self.config['version'] == 5: + for target_iqn, target in self.config['targets'].items(): + target['acl_enabled'] = True + self.update_item("targets", target_iqn, target) + self.update_item("version", None, 6) + + if self.config['version'] == 6: for disk_id, disk in self.config['disks'].items(): disk['backstore_object_name'] = disk_id self.update_item("disks", disk_id, disk) - self.update_item("version", None, 6) + self.update_item("version", None, 7) self.commit("retain") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1551361389.g157b5fd/ceph_iscsi_config/gateway.py new/ceph-iscsi-3.0+1552304123.g67b0d30/ceph_iscsi_config/gateway.py --- old/ceph-iscsi-3.0+1551361389.g157b5fd/ceph_iscsi_config/gateway.py 2019-02-28 14:43:09.700708236 +0100 +++ new/ceph-iscsi-3.0+1552304123.g67b0d30/ceph_iscsi_config/gateway.py 2019-03-11 12:35:23.215647222 +0100 @@ -2,7 +2,6 @@ from rtslib_fb.target import Target, TPG, NetworkPortal, LUN from rtslib_fb.fabric import ISCSIFabricModule -from rtslib_fb import root from rtslib_fb.utils import RTSLibError, normalize_wwn from rtslib_fb.alua import ALUATargetPortGroup @@ -16,6 +15,7 @@ from ceph_iscsi_config.alua import alua_create_group, alua_format_group_name from ceph_iscsi_config.client import GWClient from ceph_iscsi_config.gateway_object import GWObject +from ceph_iscsi_config.backstore import lookup_storage_object __author__ = 'pcuz...@redhat.com' @@ -229,6 +229,14 @@ self.error = True self.error_msg = "Unable to delete target - {}".format(err) + def update_acl(self, config): + target_config = config.config["targets"][self.iqn] + for tpg in self.tpg_list: + if target_config['acl_enabled']: + tpg.set_attribute('generate_node_acls', 0) + else: + tpg.set_attribute('generate_node_acls', 1) + def create_tpg(self, ip): try: @@ -316,10 +324,11 @@ """ try: + self.target = Target(ISCSIFabricModule(), self.iqn, "lookup") - lio_root = root.RTSRoot() - self.target = [tgt for tgt in lio_root.targets - if tgt.wwn == self.iqn][0] + # clear list so we can rebuild with the current values below + if self.tpg_list: + del self.tpg_list[:] # there could/should be multiple tpg's for the target for tpg in self.target.tpgs: @@ -402,65 +411,61 @@ tpg.tag, alua_tpg.name)) - def map_luns(self, config): - """ - LIO will have objects already defined by the lun module, - so this method, brings those objects into the gateways TPG - """ + def _map_lun(self, config, stg_object): + for tpg in self.tpg_list: + self.logger.debug("processing tpg{}".format(tpg.tag)) - lio_root = root.RTSRoot() - target_config = config.config["targets"][self.iqn] - backstore_object_names = [disk['backstore_object_name'] for disk_id, disk in config.config['disks'].items() - if disk_id in target_config['disks']] - target_stg_object = [stg_object for stg_object in lio_root.storage_objects - if stg_object.name in backstore_object_names] - - # process each storage object added to the gateway, and map to the tpg - for stg_object in target_stg_object: - - for tpg in self.tpg_list: - self.logger.debug("processing tpg{}".format(tpg.tag)) - - if not self.lun_mapped(tpg, stg_object): - self.logger.debug("{} needed mapping to " - "tpg{}".format(stg_object.name, - tpg.tag)) + lun_id = int(stg_object.path.split('/')[-2].split('_')[1]) - lun_id = int(stg_object.path.split('/')[-2].split('_')[1]) + try: + mapped_lun = LUN(tpg, lun=lun_id, storage_object=stg_object) + self.changes_made = True + except RTSLibError as err: + if "already exists in configFS" not in err: + self.logger.error("LUN mapping failed: {}".format(err)) + self.error = True + self.error_msg = err + return - try: - mapped_lun = LUN(tpg, lun=lun_id, storage_object=stg_object) - self.changes_made = True - except RTSLibError as err: - self.logger.error("LUN mapping failed: {}".format(err)) - self.error = True - self.error_msg = err - return + # Already created. Ignore and loop to the next tpg. + continue - try: - self.bind_alua_group_to_lun(config, mapped_lun) - except CephiSCSIInval as err: - self.logger.error("Could not bind LUN to ALUA group: " - "{}".format(err)) - self.error = True - self.error_msg = err - return + try: + self.bind_alua_group_to_lun(config, mapped_lun) + except CephiSCSIInval as err: + self.logger.error("Could not bind LUN to ALUA group: " + "{}".format(err)) + self.error = True + self.error_msg = err + return - def lun_mapped(self, tpg, storage_object): + def map_lun(self, config, stg_object): + self.load_config() + self._map_lun(config, stg_object) + + def map_luns(self, config): """ - Check to see if a given storage object (i.e. block device) is already - mapped to the gateway's TPG - :param storage_object: storage object to look for - :return: boolean - is the storage object mapped or not + LIO will have objects already defined by the lun module, + so this method, brings those objects into the gateways TPG """ - mapped_state = False - for l in tpg.luns: - if l.storage_object.name == storage_object.name: - mapped_state = True - break + target_config = config.config["targets"][self.iqn] + + for disk in target_config['disks']: + backstore = config.config["disks"][disk]["backstore"] + backstore_object_name = config.config["disks"][disk]["backstore_object_name"] + + try: + stg_object = lookup_storage_object(backstore_object_name, backstore) + except (RTSLibError, CephiSCSIError) as err: + self.logger.error("Could not map {} to LUN: {}".format(disk, err)) + self.error = True + self.error_msg = err + return - return mapped_state + self._map_lun(config, stg_object) + if self.error: + return def delete(self): self.target.delete() @@ -552,6 +557,8 @@ self.map_luns(config) + self.update_acl(config) + else: self.error = True self.error_msg = ("Attempted to map to a gateway '{}' that " @@ -572,6 +579,7 @@ seed_target = { 'disks': [], 'clients': {}, + 'acl_enabled': True, 'portals': {}, 'groups': {}, 'controls': {} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1551361389.g157b5fd/ceph_iscsi_config/lun.py new/ceph-iscsi-3.0+1552304123.g67b0d30/ceph_iscsi_config/lun.py --- old/ceph-iscsi-3.0+1551361389.g157b5fd/ceph_iscsi_config/lun.py 2019-02-28 14:43:09.700708236 +0100 +++ new/ceph-iscsi-3.0+1552304123.g67b0d30/ceph_iscsi_config/lun.py 2019-03-11 12:35:23.215647222 +0100 @@ -22,6 +22,7 @@ from ceph_iscsi_config.gateway import GWTarget from ceph_iscsi_config.client import GWClient, CHAP from ceph_iscsi_config.group import Group +from ceph_iscsi_config.backstore import lookup_storage_object __author__ = 'pcuz...@redhat.com' @@ -450,20 +451,26 @@ self.config.commit() - def map_lun(self, target_iqn, owner, disk): - target_config = self.config.config['targets'][target_iqn] + def map_lun(self, gateway, owner, disk): + target_config = self.config.config['targets'][gateway.iqn] disk_metadata = self.config.config['disks'][disk] disk_metadata['owner'] = owner self.config.update_item("disks", disk, disk_metadata) target_config['disks'].append(disk) - self.config.update_item("targets", target_iqn, target_config) + self.config.update_item("targets", gateway.iqn, target_config) gateway_dict = self.config.config['gateways'][owner] gateway_dict['active_luns'] += 1 self.config.update_item('gateways', owner, gateway_dict) - self.allocate() + so = self.allocate() + if self.error: + raise CephiSCSIError(self.error_msg) + + gateway.map_lun(self.config, so) + if gateway.error: + raise CephiSCSIError(gateway.error_msg) def manage(self, desired_state): @@ -576,6 +583,14 @@ raise CephiSCSIError(client_err) def allocate(self, keep_dev_in_lio=True): + """ + Create image and add to LIO and config. + + :param keep_dev_in_lio: (bool) false if the LIO so should be removed + after allocating the wwn. + :return: LIO storage object if successful and keep_dev_in_lio=True + else None. + """ self.logger.debug("LUN.allocate starting, listing rbd devices") disk_list = RBDDev.rbd_list(pool=self.pool) self.logger.debug("rados pool '{}' contains the following - " @@ -605,7 +620,7 @@ else: self.error = True self.error_msg = rbd_image.error_msg - return + return None else: # the image isn't there, and this isn't the 'owning' host @@ -619,7 +634,7 @@ self.error = True self.error_msg = ("(LUN.allocate) timed out waiting " "for rbd to show up") - return + return None else: # requested image is already defined to ceph @@ -637,7 +652,7 @@ "with LIO\nOnly image features {} are" " supported".format(self.image, features)) self.logger.error(self.error_msg) - return + return None self.logger.debug("Check the rbd image size matches the request") @@ -651,7 +666,7 @@ self.logger.critical(rbd_image.error_msg) self.error = True self.error_msg = rbd_image.error_msg - return + return None if rbd_image.changed: self.logger.info("rbd image {} resized " @@ -681,17 +696,17 @@ if wwn == '': # disk hasn't been defined to LIO yet, it' not been defined # to the config yet and this is the allocating host - lun = self.add_dev_to_lio() + so = self.add_dev_to_lio() if self.error: - return + return None # lun is now in LIO, time for some housekeeping :P - wwn = lun._get_wwn() + wwn = so._get_wwn() if not keep_dev_in_lio: self.remove_dev_from_lio() if self.error: - return + return None disk_attr = {"wwn": wwn, "image": self.image, @@ -716,9 +731,9 @@ else: # config object already had wwn for this rbd image - self.add_dev_to_lio(wwn) + so = self.add_dev_to_lio(wwn) if self.error: - return + return None self.update_controls() self.logger.debug("(LUN.allocate) registered '{}' to LIO " @@ -750,13 +765,13 @@ self.error_msg = ("(LUN.allocate) waited too long for the " "wwn information on image {} to " "arrive".format(self.image)) - return + return None # At this point we have a wwn from the config for this rbd # image, so just add to LIO - self.add_dev_to_lio(wwn) + so = self.add_dev_to_lio(wwn) if self.error: - return + return None self.logger.info("(LUN.allocate) added {} to LIO using wwn " "'{}' defined by {}".format(self.image, @@ -771,7 +786,7 @@ self.error = True self.error_msg = "Unable to sync the rbd device size with LIO" self.logger.critical(self.error_msg) - return + return None self.logger.debug("config meta data for this disk is " "{}".format(self.config.config['disks'][self.config_key])) @@ -785,6 +800,10 @@ self.config.commit() self.error = self.config.error self.error_msg = self.config.error_msg + if self.error: + return None + + return so def lio_size_ok(self, rbd_object, stg_object): """ @@ -827,18 +846,11 @@ return size_ok def lio_stg_object(self): - found_it = False - rtsroot = root.RTSRoot() - for stg_object in rtsroot.storage_objects: - - # First match on name, but then check the pool incase the same - # name exists in multiple pools - if stg_object.name == self.backstore_object_name: - - found_it = True - break - - return stg_object if found_it else None + try: + return lookup_storage_object(self.backstore_object_name, self.backstore) + except RTSLibError as err: + self.logger.debug("lio stg lookup failed {}".format(err)) + return None def add_dev_to_lio(self, in_wwn=None): """ @@ -1009,19 +1021,21 @@ else: break # continue to the next tpg - for stg_object in lio_root.storage_objects: - if stg_object.name == self.backstore_object_name: - try: - stg_object.delete() - if self.backstore == RBD: - self._rbd_device_unmap() - except Exception as e: - self.error = True - self.error_msg = ("Delete from LIO/backstores failed - " - "{}".format(e)) - return + so = self.lio_stg_object() + if not so: + self.error = True + self.error_msg = ("Removal failed. Could not find LIO object.") + return - break + try: + so.delete() + if self.backstore == RBD: + self._rbd_device_unmap() + except Exception as err: + self.error = True + self.error_msg = ("Delete from LIO/backstores failed - " + "{}".format(err)) + return @staticmethod def valid_disk(ceph_iscsi_config, logger, **kwargs): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1551361389.g157b5fd/ceph_iscsi_config/settings.py new/ceph-iscsi-3.0+1552304123.g67b0d30/ceph_iscsi_config/settings.py --- old/ceph-iscsi-3.0+1551361389.g157b5fd/ceph_iscsi_config/settings.py 2019-02-28 14:43:09.700708236 +0100 +++ new/ceph-iscsi-3.0+1552304123.g67b0d30/ceph_iscsi_config/settings.py 2019-03-11 12:35:23.215647222 +0100 @@ -94,9 +94,8 @@ return v defaults = {"cluster_name": "ceph", - "cluster_client_name": "client.admin", - "gateway_keyring": "ceph.client.admin.keyring", "pool": "rbd", + "cluster_client_name": "client.admin", "time_out": 30, "api_host": "::", "api_port": 5000, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1551361389.g157b5fd/gwcli/ceph.py new/ceph-iscsi-3.0+1552304123.g67b0d30/gwcli/ceph.py --- old/ceph-iscsi-3.0+1551361389.g157b5fd/gwcli/ceph.py 2019-02-28 14:43:09.700708236 +0100 +++ new/ceph-iscsi-3.0+1552304123.g67b0d30/gwcli/ceph.py 2019-03-11 12:35:23.215647222 +0100 @@ -1,8 +1,6 @@ from .node import UIGroup, UINode import json import rados -import glob -import os from gwcli.utils import console_message, os_cmd import ceph_iscsi_config.settings as settings @@ -32,75 +30,15 @@ default_ceph_conf = '{}/ceph.conf'.format(ceph_config_dir) def __init__(self, parent): - UIGroup.__init__(self, 'clusters', parent) - self.cluster_map = self.get_clusters() - self.local_ceph = None - - for cluster_name in self.cluster_map.keys(): - - keyring = self.cluster_map[cluster_name]['keyring'] - cluster_client_name = None - if cluster_name == settings.config.cluster_name: - - if settings.config.gateway_keyring: - keyring = settings.config.gateway_keyring - self.cluster_map[cluster_name]['keyring'] = keyring - - if settings.config.cluster_client_name: - cluster_client_name = settings.config.cluster_client_name - self.cluster_map[cluster_name]['client_name'] = cluster_client_name - - # define the cluster object - self.logger.debug("Adding ceph cluster '{}' to the UI".format(cluster_name)) - cluster = CephCluster(self, - cluster_name, - self.cluster_map[cluster_name]['conf_file'], - cluster_client_name, - keyring) - - self.cluster_map[cluster_name]['object'] = cluster - if self.cluster_map[cluster_name]['local']: - self.local_ceph = cluster - - def get_clusters(self): - """ - Look at the /etc/ceph dir to generate a dict of clusters that are - defined/known to the gateway - :return: (dict) ceph_name -> conf_file, keyring - """ - - clusters = {} # dict ceph_name -> conf_file, keyring - - conf_files = glob.glob(os.path.join(CephGroup.ceph_config_dir, - '*.conf')) - - valid_conf_files = [conf for conf in conf_files - if CephGroup.valid_conf(conf)] - for conf in valid_conf_files: - name = os.path.basename(conf).split('.')[0] - keyring = glob.glob(os.path.join(CephGroup.ceph_config_dir, - '{}*.keyring'.format(name))) - if not keyring: - self.logger.debug("Skipping {} - no keyring found".format(conf)) - continue - - keyring = keyring[0] # select the first one - - client_name = None - if keyring.startswith("ceph.client."): - begin_idx = keyring.find(".") - end_idx = keyring.find(".keyring") - client_name = keyring[begin_idx+1:end_idx] - - local = True if name == settings.config.cluster_name else False - - clusters[name] = {'conf_file': conf, - 'keyring': keyring, - 'client_name': client_name, - 'name': name, - 'local': local} + UIGroup.__init__(self, 'cluster', parent) - return clusters + self.logger.debug("Adding ceph cluster '{}' to the UI" + .format(settings.config.cluster_name)) + self.cluster = CephCluster(self, + settings.config.cluster_name, + "{}/{}.conf".format(settings.config.ceph_config_dir, + settings.config.cluster_name), + settings.config.cluster_client_name) @staticmethod def valid_conf(config_file): @@ -136,11 +74,10 @@ class CephCluster(UIGroup): - def __init__(self, parent, cluster_name, conf_file, client_name, keyring): + def __init__(self, parent, cluster_name, conf_file, client_name): self.conf = conf_file self.client_name = client_name - self.keyring = keyring self.cluster_name = cluster_name UIGroup.__init__(self, cluster_name, parent) @@ -194,8 +131,6 @@ output += "Raw capacity: {}\n".format(human_size(raw)) output += "\nConfig : {}\n".format(self.conf) output += "Client Name: {}\n".format(self.client_name) - output += "Keyring: {}\n".format(os.path.join(CephGroup.ceph_config_dir, - self.keyring)) console_message(output, color=color[self.health_status]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1551361389.g157b5fd/gwcli/client.py new/ceph-iscsi-3.0+1552304123.g67b0d30/gwcli/client.py --- old/ceph-iscsi-3.0+1551361389.g157b5fd/gwcli/client.py 2019-02-28 14:43:09.700708236 +0100 +++ new/ceph-iscsi-3.0+1552304123.g67b0d30/gwcli/client.py 2019-03-11 12:35:23.215647222 +0100 @@ -1,6 +1,6 @@ from gwcli.node import UIGroup, UINode -from gwcli.utils import response_message, APIRequest +from gwcli.utils import response_message, APIRequest, get_config from ceph_iscsi_config.client import CHAP import ceph_iscsi_config.settings as settings @@ -43,6 +43,8 @@ self.shell.log.debug("Bookmarked %s as %s." % (self.path, 'hosts')) + self.config = get_config() + def load(self, client_info): for client_iqn, client_settings in client_info.items(): Client(self, client_iqn, client_settings) @@ -85,6 +87,7 @@ if api.response.status_code == 200: Client(self, client_iqn, cli_seed) + self.config = get_config() self.logger.debug("- Client '{}' added".format(client_iqn)) self.logger.info('ok') @@ -185,29 +188,50 @@ del self.client_map[child.client_iqn] self.remove_child(child) - def ui_command_auth(self, chap=None): + def ui_command_auth(self, action=None): """ - Clear CHAP settings for all clients on the target. + Disable/enable ACL authentication or clear CHAP settings for all clients on the target. + + - disable_acl ... Disable initiator name based ACL authentication. - Specifying 'nochap' will remove chap authentication for all clients - across all gateways. Initiator name based authentication will then be - used. + - enable_acl .... Enable initiator name based ACL authentication. + + - nochap ........ Remove chap authentication for all clients across all gateways. + Initiator name based authentication will then be used. e.g. - auth nochap + auth disable_acl """ - if not chap: - self.logger.error("Missing auth argument. Use 'auth nochap'") + if not action: + self.logger.error("Missing auth argument. Use 'auth nochap|disable_acl|enable_acl'") return - if chap != 'nochap': - self.logger.error("Invalid auth argument. Use 'auth nochap'") + if action not in ['nochap', 'enable_acl', 'disable_acl']: + self.logger.error("Invalid auth argument. Use 'auth nochap|disable_acl|enable_acl'") return - for client in self.children: - client.set_auth(chap, None) + if action == 'nochap': + for client in self.children: + client.set_auth(action, None) + else: + target_iqn = self.parent.name + api_vars = {'action': action} + targetauth_api = ('{}://localhost:{}/api/' + 'targetauth/{}'.format(self.http_mode, + settings.config.api_port, + target_iqn)) + api = APIRequest(targetauth_api, data=api_vars) + api.put() + if api.response.status_code == 200: + self.config = get_config() + self.logger.info('ok') + else: + self.logger.error("Failed to {}: " + "{}".format(action, response_message(api.response, + self.logger))) + return def summary(self): chap_enabled = False @@ -215,9 +239,8 @@ chap_mutual_enabled = False chap_mutual_disabled = False status = False - # initiator name based ACL is the default with the current kernel - # settings. - auth_stat_str = "None" + target_iqn = self.parent.name + auth_stat_str = "ACL" if self.config['targets'][target_iqn]['acl_enabled'] else "None" for client in self.children: if client.auth['chap'] == 'None': diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1551361389.g157b5fd/gwcli/storage.py new/ceph-iscsi-3.0+1552304123.g67b0d30/gwcli/storage.py --- old/ceph-iscsi-3.0+1551361389.g157b5fd/gwcli/storage.py 2019-02-28 14:43:09.700708236 +0100 +++ new/ceph-iscsi-3.0+1552304123.g67b0d30/gwcli/storage.py 2019-03-11 12:35:23.215647222 +0100 @@ -266,10 +266,7 @@ # first check that the intended pool is compatible with rbd images root = self.get_ui_root() - clusters = root.ceph.cluster_map - local_cluster = [clusters[cluster_name] for cluster_name in clusters - if clusters[cluster_name]['local']][0]['object'] - pools = local_cluster.pools + pools = root.ceph.cluster.pools pool_object = pools.pool_lookup.get(pool, None) if pool_object: if pool_object.type == 'replicated': @@ -349,7 +346,7 @@ raise GatewayAPIError("Unable to retrieve disk details " "for '{}' from the API".format(disk_key)) - ceph_pools = self.parent.ceph.local_ceph.pools + ceph_pools = self.parent.ceph.cluster.pools ceph_pools.refresh() else: @@ -517,7 +514,7 @@ self.logger))) return - ceph_pools = self.parent.ceph.local_ceph.pools + ceph_pools = self.parent.ceph.cluster.pools ceph_pools.refresh() self.logger.info('ok') @@ -534,7 +531,7 @@ ui_root = self.get_ui_root() state = True discovered_pools = [rados_pool.name for rados_pool in - ui_root.ceph.local_ceph.pools.children] + ui_root.ceph.cluster.pools.children] existing_rbds = self.disk_info.keys() storage_key = "{}.{}".format(pool, image) @@ -591,7 +588,7 @@ self.backstore_object_name = image_config['backstore_object_name'] self.controls = {} self.control_values = {} - self.ceph_cluster = self.parent.parent.ceph.local_ceph.name + self.ceph_cluster = self.parent.parent.ceph.cluster.name disk_map = self.parent.disk_info if image_id not in disk_map: @@ -875,7 +872,7 @@ """ root = self.parent.parent ceph_group = root.ceph - cluster = ceph_group.local_ceph + cluster = ceph_group.cluster pool = cluster.pools.pool_lookup.get(self.pool) if pool: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1551361389.g157b5fd/iscsi-gateway.cfg_sample new/ceph-iscsi-3.0+1552304123.g67b0d30/iscsi-gateway.cfg_sample --- old/ceph-iscsi-3.0+1551361389.g157b5fd/iscsi-gateway.cfg_sample 2019-02-28 14:43:09.700708236 +0100 +++ new/ceph-iscsi-3.0+1552304123.g67b0d30/iscsi-gateway.cfg_sample 2019-03-11 12:35:23.215647222 +0100 @@ -3,12 +3,11 @@ # cluster from the gateway node is required. cluster_name = <ceph cluster name> -# Place a copy of the ceph cluster's admin keyring in the gateway's /etc/ceph -# drectory and reference the filename here -gateway_keyring = <client.admin.keyring> - -cluster_client_name = client.<rados_id> # E.g. client.admin +# Pool name where internal `gateway.conf` object is stored +# pool = rbd +# CephX client name +# cluster_client_name = client.<rados_id> # E.g.: client.admin # API settings. # The api supports a number of options that allow you to tailor it to your diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1551361389.g157b5fd/rbd-target-api.py new/ceph-iscsi-3.0+1552304123.g67b0d30/rbd-target-api.py --- old/ceph-iscsi-3.0+1551361389.g157b5fd/rbd-target-api.py 2019-02-28 14:43:09.700708236 +0100 +++ new/ceph-iscsi-3.0+1552304123.g67b0d30/rbd-target-api.py 2019-03-11 12:35:23.215647222 +0100 @@ -826,19 +826,13 @@ "{}".format(lun.error_msg)) return jsonify(message="Error establishing LUN instance"), 500 - lun.map_lun(target_iqn, owner, disk) - if lun.error: - status_code = 400 if lun.error_msg else 500 - logger.error("LUN add failed : {}".format(lun.error_msg)) + try: + lun.map_lun(gateway, owner, disk) + except CephiSCSIError as err: + status_code = 400 if str(err) else 500 + logger.error("LUN add failed : {}".format(err)) return jsonify(message="Failed to add the LUN - " - "{}".format(lun.error_msg)), status_code - - logger.info("Syncing TPG to LUN mapping") - gateway.manage('map') - if gateway.error: - return jsonify(message="Failed to sync LUNs on gateway, " - "Err {}.".format(gateway.error_msg)), 500 - + "{}".format(err)), status_code else: # DELETE gateway request @@ -1497,6 +1491,79 @@ return jsonify(message='OK'), 200 + +@app.route('/api/targetauth/<target_iqn>', methods=['PUT']) +@requires_restricted_auth +def targetauth(target_iqn=None): + """ + Coordinate the gen-acls across each gateway node + :param target_iqn: (str) IQN of the target + :param action: (str) action to be performed + **RESTRICTED** + Examples: + curl --insecure --user admin:admin -d auth='disable_acl' + -X PUT https://192.168.122.69:5000/api/targetauth/iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw + """ + + action = request.form.get('action') + if action not in ['disable_acl', 'enable_acl']: + return jsonify(message='Invalid auth {}'.format(action)), 400 + + target_config = config.config['targets'][target_iqn] + + if action == 'disable_acl' and target_config['clients'].keys(): + return jsonify(message='Cannot disable ACL authentication ' + 'because target has clients'), 400 + + try: + gateways = get_remote_gateways(target_config['portals'], logger) + except CephiSCSIError as err: + return jsonify(message="{}".format(err)), 400 + local_gw = this_host() + gateways.insert(0, local_gw) + + # Apply to all gateways + api_vars = { + "committing_host": local_gw, + "action": action + } + resp_text, resp_code = call_api(gateways, '_targetauth', + target_iqn, + http_method='put', + api_vars=api_vars) + + return jsonify(message="target auth {} - {}".format(action, resp_text)), resp_code + + +@app.route('/api/_targetauth/<target_iqn>', methods=['PUT']) +@requires_restricted_auth +def _targetauth(target_iqn=None): + """ + Apply gen-acls on the local gateway + Internal Use ONLY + **RESTRICTED** + """ + + local_gw = this_host() + committing_host = request.form['committing_host'] + action = request.form['action'] + + target = GWTarget(logger, target_iqn, []) + + target_config = config.config['targets'][target_iqn] + if action in ['disable_acl', 'enable_acl']: + target_config['acl_enabled'] = (action == 'enable_acl') + config.update_item('targets', target_iqn, target_config) + + if target.exists(): + target.load_config() + target.update_acl(config) + + if committing_host == local_gw: + config.commit("retain") + + return jsonify(message='OK'), 200 + @app.route('/api/clients/<target_iqn>', methods=['GET']) @requires_restricted_auth diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1551361389.g157b5fd/test/test_common.py new/ceph-iscsi-3.0+1552304123.g67b0d30/test/test_common.py --- old/ceph-iscsi-3.0+1551361389.g157b5fd/test/test_common.py 2019-02-28 14:43:09.704708260 +0100 +++ new/ceph-iscsi-3.0+1552304123.g67b0d30/test/test_common.py 2019-03-11 12:35:23.215647222 +0100 @@ -190,6 +190,7 @@ } } }, + "acl_enabled": True, "controls": { "immediate_data": False, "nopin_response_timeout": 17 @@ -242,5 +243,5 @@ } }, "updated": "2018/12/07 09:18:13", - "version": 5 + "version": 7 }