Hello community, here is the log from the commit of package ceph-iscsi for openSUSE:Factory checked in at 2019-06-06 18:19:07 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ceph-iscsi (Old) and /work/SRC/openSUSE:Factory/.ceph-iscsi.new.4811 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ceph-iscsi" Thu Jun 6 18:19:07 2019 rev:13 rq:708099 version:3.0+1559815396.g7aa8f7f Changes: -------- --- /work/SRC/openSUSE:Factory/ceph-iscsi/ceph-iscsi.changes 2019-05-22 11:17:46.154461201 +0200 +++ /work/SRC/openSUSE:Factory/.ceph-iscsi.new.4811/ceph-iscsi.changes 2019-06-06 18:19:24.168649475 +0200 @@ -1,0 +2,11 @@ +Thu Jun 6 10:04:00 UTC 2019 - Nathan Cutler <ncut...@suse.com> + +- Update to 3.0+1559815396.g7aa8f7f: + + Set 'SUSE' SCSI vendor (bsc#1136769) + + Adds support for multiple IPs per gateway (bsc#1136757) + + Do not allow lrbd to be installed simultaneously with ceph-iscsi + + Temporary workaround to support ',' in configshell params (must be removed/reverted in the future, after configshell >= 1.1.f25 is available) + + Fix problem deleting target with clients/disks + + Removes the disk 'delete' command + +------------------------------------------------------------------- Old: ---- ceph-iscsi-3.0+1558465738.g6a0a021.tar.gz New: ---- ceph-iscsi-3.0+1559815396.g7aa8f7f.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ceph-iscsi.spec ++++++ --- /var/tmp/diff_new_pack.qSi1Cv/_old 2019-06-06 18:19:24.844649276 +0200 +++ /var/tmp/diff_new_pack.qSi1Cv/_new 2019-06-06 18:19:24.844649276 +0200 @@ -20,7 +20,7 @@ Name: ceph-iscsi -Version: 3.0+1558465738.g6a0a021 +Version: 3.0+1559815396.g7aa8f7f Release: 1%{?dist} Group: System/Filesystems Summary: Python modules for Ceph iSCSI gateway configuration management @@ -51,7 +51,7 @@ Requires: rpm-python >= 4.11 Requires: python-cryptography Requires: python-flask >= 0.10.1 -Requires: python-configshell +Requires: python-configshell >= 1.1.fb23 %else BuildRequires: python3-devel BuildRequires: python3-setuptools @@ -65,13 +65,17 @@ BuildRequires: python-rpm-macros BuildRequires: fdupes Requires: python3-Flask >= 0.10.1 -Requires: python3-configshell-fb +Requires: python3-configshell-fb >= 1.1.23 %else Requires: python3-flask >= 0.10.1 -Requires: python3-configshell +Requires: python3-configshell >= 1.1.fb23 %endif %endif +%if 0%{?suse_version} +Conflicts: lrbd +%endif + BuildRequires: systemd-rpm-macros %{?systemd_requires} ++++++ ceph-iscsi-3.0+1558465738.g6a0a021.tar.gz -> ceph-iscsi-3.0+1559815396.g7aa8f7f.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1558465738.g6a0a021/ceph-iscsi.spec new/ceph-iscsi-3.0+1559815396.g7aa8f7f/ceph-iscsi.spec --- old/ceph-iscsi-3.0+1558465738.g6a0a021/ceph-iscsi.spec 2019-05-21 21:08:58.372570734 +0200 +++ new/ceph-iscsi-3.0+1559815396.g7aa8f7f/ceph-iscsi.spec 2019-06-06 12:03:16.636671848 +0200 @@ -20,7 +20,7 @@ Name: ceph-iscsi -Version: 3.0+1558465738.g6a0a021 +Version: 3.0+1559815396.g7aa8f7f Release: 1%{?dist} Group: System/Filesystems Summary: Python modules for Ceph iSCSI gateway configuration management @@ -51,7 +51,7 @@ Requires: rpm-python >= 4.11 Requires: python-cryptography Requires: python-flask >= 0.10.1 -Requires: python-configshell +Requires: python-configshell >= 1.1.fb23 %else BuildRequires: python3-devel BuildRequires: python3-setuptools @@ -65,13 +65,17 @@ BuildRequires: python-rpm-macros BuildRequires: fdupes Requires: python3-Flask >= 0.10.1 -Requires: python3-configshell-fb +Requires: python3-configshell-fb >= 1.1.23 %else Requires: python3-flask >= 0.10.1 -Requires: python3-configshell +Requires: python3-configshell >= 1.1.fb23 %endif %endif +%if 0%{?suse_version} +Conflicts: lrbd +%endif + BuildRequires: systemd-rpm-macros %{?systemd_requires} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1558465738.g6a0a021/ceph_iscsi_config/gateway.py new/ceph-iscsi-3.0+1559815396.g7aa8f7f/ceph_iscsi_config/gateway.py --- old/ceph-iscsi-3.0+1558465738.g6a0a021/ceph_iscsi_config/gateway.py 2019-05-21 21:08:58.136569104 +0200 +++ new/ceph-iscsi-3.0+1559815396.g7aa8f7f/ceph_iscsi_config/gateway.py 2019-06-06 12:03:16.060678398 +0200 @@ -160,7 +160,7 @@ # 0, this is a boot time request self.logger.info("Setting up {}".format(target_iqn)) - target = GWTarget(self.logger, target_iqn, gw_ip_list, + target = GWTarget(self.logger, self.config, target_iqn, gw_ip_list, enable_portal=self.portals_active(target_iqn)) if target.error: raise CephiSCSIError("Error initializing iSCSI target: " @@ -241,7 +241,7 @@ def delete_target(self, target_iqn): - target = GWTarget(self.logger, target_iqn, {}) + target = GWTarget(self.logger, self.config, target_iqn, {}) if target.error: raise CephiSCSIError("Could not initialize target: {}". format(target.error_msg)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1558465738.g6a0a021/ceph_iscsi_config/lun.py new/ceph-iscsi-3.0+1559815396.g7aa8f7f/ceph_iscsi_config/lun.py --- old/ceph-iscsi-3.0+1558465738.g6a0a021/ceph_iscsi_config/lun.py 2019-05-21 21:08:58.136569104 +0200 +++ new/ceph-iscsi-3.0+1559815396.g7aa8f7f/ceph_iscsi_config/lun.py 2019-06-06 12:03:16.060678398 +0200 @@ -555,7 +555,7 @@ # Add the mapping for the lun to ensure the block device is # present on all TPG's - gateway = GWTarget(self.logger, target_iqn, ip_list) + gateway = GWTarget(self.logger, self.config, target_iqn, ip_list) gateway.map_lun(self.config, so) if gateway.error: raise CephiSCSIError("LUN mapping failed - {}".format(gateway.error_msg)) @@ -981,6 +981,11 @@ new_lun = RBDStorageObject(name=self.backstore_object_name, dev=dev, wwn=in_wwn) + path = glob.glob('/sys/kernel/config/target/core/rbd_*/{}/wwn/vendor_id'.format( + self.backstore_object_name)) + if path: + with open(path[0], "w") as file_vendor: + file_vendor.write("SUSE\n") except (RTSLibError, IOError) as err: self.error = True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1558465738.g6a0a021/ceph_iscsi_config/target.py new/ceph-iscsi-3.0+1559815396.g7aa8f7f/ceph_iscsi_config/target.py --- old/ceph-iscsi-3.0+1558465738.g6a0a021/ceph_iscsi_config/target.py 2019-05-21 21:08:58.136569104 +0200 +++ new/ceph-iscsi-3.0+1559815396.g7aa8f7f/ceph_iscsi_config/target.py 2019-06-06 12:03:16.064678352 +0200 @@ -48,7 +48,7 @@ # gwcli to get/set all tpgs/clients under the target instead of per obj. SETTINGS = TPG_SETTINGS + TPG_KERNEL_SETTINGS + GWClient.SETTINGS - def __init__(self, logger, iqn, gateway_ip_list, enable_portal=True): + def __init__(self, logger, config, iqn, gateway_ip_list, enable_portal=True): """ Instantiate the class :param iqn: iscsi iqn name for the gateway @@ -62,6 +62,7 @@ self.enable_portal = enable_portal # boolean to trigger portal IP creation self.logger = logger # logger object + self.config = config try: iqn, iqn_type = normalize_wwn(['iqn'], iqn) @@ -106,6 +107,7 @@ self.target = None self.tpg = None self.tpg_list = [] + self.tpg_tag_by_gateway_name = {} try: super(GWTarget, self).__init__('targets', iqn, logger, @@ -266,10 +268,27 @@ tpg.set_attribute('generate_node_acls', 1) tpg.set_attribute('demo_mode_write_protect', 0) + def _get_gateway_name(self, ip): + if ip in self.active_portal_ips: + return this_host() + target_config = self.config.config['targets'][self.iqn] + for portal_name, portal_config in target_config['portals'].items(): + if ip in portal_config['portal_ip_addresses']: + return portal_name + return None + def create_tpg(self, ip): try: - tpg = TPG(self.target) + tpg = None + gateway_name = self._get_gateway_name(ip) + tpg_tag = self.tpg_tag_by_gateway_name.get(gateway_name) + if tpg_tag: + for tpg_item in self.tpg_list: + if tpg_item.tag == tpg_tag: + tpg = tpg_item + if not tpg: + tpg = TPG(self.target) # Use initiator name based ACL by default. tpg.set_attribute('authentication', '0') @@ -293,6 +312,7 @@ "portal ip {} as disabled".format(ip)) self.tpg_list.append(tpg) + self.tpg_tag_by_gateway_name[gateway_name] = tpg.tag except RTSLibError as err: self.error_msg = err @@ -359,10 +379,16 @@ # clear list so we can rebuild with the current values below if self.tpg_list: del self.tpg_list[:] + if self.tpg_tag_by_gateway_name: + self.tpg_tag_by_gateway_name = {} # there could/should be multiple tpg's for the target for tpg in self.target.tpgs: self.tpg_list.append(tpg) + ip_address = list(tpg.network_portals)[0].ip_address + gateway_name = self._get_gateway_name(ip_address) + if gateway_name: + self.tpg_tag_by_gateway_name[gateway_name] = tpg.tag # self.portal = self.tpg.network_portals.next() @@ -410,7 +436,7 @@ # they do not have a common gw the owning gw may not exist here. # The LUN will just have all ANO paths then. if gw_config: - if gw_config["portal_ip_addresses"][0] == tpg_ip_address: + if tpg_ip_address in gw_config["portal_ip_addresses"]: is_owner = True try: @@ -681,6 +707,8 @@ if self.exists(): self.load_config() self.clear_config(config) + if self.error: + return target_config = config.config["targets"][self.iqn] if len(target_config['portals']) == 0: config.del_item('targets', self.iqn) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1558465738.g6a0a021/gwcli/gateway.py new/ceph-iscsi-3.0+1559815396.g7aa8f7f/gwcli/gateway.py --- old/ceph-iscsi-3.0+1558465738.g6a0a021/gwcli/gateway.py 2019-05-21 21:08:58.140569131 +0200 +++ new/ceph-iscsi-3.0+1559815396.g7aa8f7f/gwcli/gateway.py 2019-06-06 12:03:16.068678307 +0200 @@ -657,15 +657,15 @@ hosts_object = self.parent.get_child("hosts") hosts_object.reset() - def ui_command_create(self, gateway_name, ip_address, nosync=False, + def ui_command_create(self, gateway_name, ip_addresses, nosync=False, skipchecks='false'): """ Define a gateway to the gateway group for this iscsi target. The first host added should be the gateway running the command gateway_name ... should resolve to the hostname of the gateway - ip_address ..... is the IPv4/IPv6 address of the interface the iscsi - portal should use + ip_addresses ... are the IPv4/IPv6 addresses of the interfaces the + iSCSI portals should use nosync ......... by default new gateways are sync'd with the existing configuration by cli. By specifying nosync the sync step is bypassed - so the new gateway @@ -678,10 +678,10 @@ to result in an unstable configuration. """ - ip_address = normalize_ip_address(ip_address) + ip_addresses = [normalize_ip_address(ip_address) for ip_address in ip_addresses.split(',')] self.logger.debug("CMD: ../gateways/ create {} {} " "nosync={} skipchecks={}".format(gateway_name, - ip_address, + ip_addresses, nosync, skipchecks)) @@ -730,7 +730,7 @@ gw_rqst = gw_api + '/gateway/{}/{}'.format(target_iqn, gateway_name) gw_vars = {"nosync": nosync, "skipchecks": skipchecks, - "ip_address": ip_address} + "ip_address": ','.join(ip_addresses)} api = APIRequest(gw_rqst, data=gw_vars) api.put() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1558465738.g6a0a021/gwcli/storage.py new/ceph-iscsi-3.0+1559815396.g7aa8f7f/gwcli/storage.py --- old/ceph-iscsi-3.0+1558465738.g6a0a021/gwcli/storage.py 2019-05-21 21:08:58.140569131 +0200 +++ new/ceph-iscsi-3.0+1559815396.g7aa8f7f/gwcli/storage.py 2019-06-06 12:03:16.068678307 +0200 @@ -467,25 +467,6 @@ """ self.delete_disk(image_id, True) - def ui_command_delete(self, image_id): - """ - Delete a given rbd image from the configuration and ceph. This is a - destructive action that could lead to data loss, so please ensure - the rbd image name is correct! - - > delete <disk_name> - e.g. - > delete rbd.disk_1 - - "disk_name" refers to the name of the disk as shown in the UI, for - example rbd.disk_1. - - Also note that the delete process is a synchronous task, so the larger - the rbd image is, the longer the delete will take to run. - - """ - self.delete_disk(image_id, False) - def delete_disk(self, image_id, preserve_image): all_disks = [] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1558465738.g6a0a021/gwcli/utils.py new/ceph-iscsi-3.0+1559815396.g7aa8f7f/gwcli/utils.py --- old/ceph-iscsi-3.0+1558465738.g6a0a021/gwcli/utils.py 2019-05-21 21:08:58.140569131 +0200 +++ new/ceph-iscsi-3.0+1559815396.g7aa8f7f/gwcli/utils.py 2019-06-06 12:03:16.068678307 +0200 @@ -60,11 +60,11 @@ return {} -def valid_gateway(target_iqn, gw_name, gw_ip, config): +def valid_gateway(target_iqn, gw_name, gw_ips, config): """ validate the request for a new gateway :param gw_name: (str) host (shortname) of the gateway - :param gw_ip: (str) ip address on the gw that will be used for iSCSI + :param gw_ips: (str) ip addresses on the gw that will be used for iSCSI :param config: (dict) current config :return: (str) "ok" or error description """ @@ -76,17 +76,19 @@ if gw_name in target_config['portals']: return "Gateway name {} already defined".format(gw_name) - if gw_ip in target_config.get('ip_list', []): - return "IP address already defined to the configuration" + for gw_ip in gw_ips: + if gw_ip in target_config.get('ip_list', []): + return "IP address already defined to the configuration" # validate the gateway name is resolvable if not resolve_ip_addresses(gw_name): return ("Gateway '{}' is not resolvable to an IP address".format(gw_name)) # validate the ip_address is valid ip - if not resolve_ip_addresses(gw_ip): - return ("IP address provided is not usable (name doesn't" - " resolve, or not a valid IPv4/IPv6 address)") + for gw_ip in gw_ips: + if not resolve_ip_addresses(gw_ip): + return ("IP address provided is not usable (name doesn't" + " resolve, or not a valid IPv4/IPv6 address)") # At this point the request seems reasonable, so lets check a bit deeper @@ -108,11 +110,12 @@ except Exception: return "Malformed REST API response" - if gw_ip not in target_ips: - return ("IP address of {} is not available on {}. Valid " - "IPs are :{}".format(gw_ip, - gw_name, - ','.join(target_ips))) + for gw_ip in gw_ips: + if gw_ip not in target_ips: + return ("IP address of {} is not available on {}. Valid " + "IPs are :{}".format(gw_ip, + gw_name, + ','.join(target_ips))) # check that config file on the new gateway matches the local machine api = APIRequest(gw_api + '/sysinfo/checkconf') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1558465738.g6a0a021/gwcli.py new/ceph-iscsi-3.0+1559815396.g7aa8f7f/gwcli.py --- old/ceph-iscsi-3.0+1558465738.g6a0a021/gwcli.py 2019-05-21 21:08:58.140569131 +0200 +++ new/ceph-iscsi-3.0+1559815396.g7aa8f7f/gwcli.py 2019-06-06 12:03:16.064678352 +0200 @@ -11,7 +11,10 @@ import argparse import signal +from pyparsing import (alphanums, OneOrMore, Optional, Regex, Suppress, Word) + from configshell_fb import ConfigShell, ExecutionError +from configshell_fb.shell import locatedExpr from gwcli.gateway import ISCSIRoot import ceph_iscsi_config.settings as settings @@ -39,6 +42,25 @@ } + def __init__(self, preferences_dir=None): + super(GatewayCLI, self).__init__(preferences_dir) + # Grammar of the command line + command = locatedExpr(Word(alphanums + '_'))('command') + var = Word(alphanums + ',=_\+/.<>()~@:-%[]') + value = var + keyword = Word(alphanums + '_\-') + kparam = locatedExpr(keyword + Suppress('=') + Optional(value, default=''))('kparams*') + pparam = locatedExpr(var)('pparams*') + parameter = kparam | pparam + parameters = OneOrMore(parameter) + bookmark = Regex('@([A-Za-z0-9:_.]|-)+') + pathstd = Regex('([A-Za-z0-9:_.\[\]]|-)*' + '/' + '([A-Za-z0-9:_.\[\]/]|-)*') \ + | '..' | '.' + path = locatedExpr(bookmark | pathstd | '*')('path') + parser = Optional(path) + Optional(command) + Optional(parameters) + self._parser = parser + + def exception_handler(exception_type, exception, traceback, debug_hook=sys.excepthook): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.0+1558465738.g6a0a021/rbd-target-api.py new/ceph-iscsi-3.0+1559815396.g7aa8f7f/rbd-target-api.py --- old/ceph-iscsi-3.0+1558465738.g6a0a021/rbd-target-api.py 2019-05-21 21:08:58.140569131 +0200 +++ new/ceph-iscsi-3.0+1559815396.g7aa8f7f/rbd-target-api.py 2019-06-06 12:03:16.068678307 +0200 @@ -280,6 +280,7 @@ gateway_ip_list = [] target = GWTarget(logger, + config, str(target_iqn), gateway_ip_list) @@ -368,7 +369,7 @@ def local_target_reconfigure(target_iqn, tpg_controls, client_controls): config.refresh() - target = GWTarget(logger, str(target_iqn), []) + target = GWTarget(logger, config, str(target_iqn), []) if target.error: logger.error("Unable to create an instance of the GWTarget class") return target.error_msg @@ -473,7 +474,7 @@ else: # DELETE target request - target = GWTarget(logger, target_iqn, '') + target = GWTarget(logger, config, target_iqn, '') if target.error: return jsonify(message="Failed to access target"), 500 @@ -563,7 +564,7 @@ required for PUT only. :param target_iqn: (str) target iqn :param gateway_name: (str) gateway name - :param ip_address: (str) IPv4/IPv6 address iSCSI should use + :param ip_address: (str) IPv4/IPv6 addresses iSCSI should use :param nosync: (bool) whether to sync the LIO objects to the new gateway default: FALSE :param skipchecks: (bool) whether to skip OS/software versions checks @@ -592,7 +593,11 @@ target_config = config.config['targets'][target_iqn] if request.method == 'PUT': - ip_address = request.form.get('ip_address') + if gateway_name in target_config['portals']: + err_str = "Gateway already exists in configuration" + logger.error(err_str) + return jsonify(message=err_str), 400 + ip_address = request.form.get('ip_address').split(',') nosync = request.form.get('nosync', 'false') skipchecks = request.form.get('skipchecks', 'false') @@ -620,7 +625,7 @@ nosync = 'true' gateway_ip_list = target_config.get('ip_list', []) - gateway_ip_list.append(ip_address) + gateway_ip_list += ip_address op = 'creation' api_vars = {"gateway_ip_list": ",".join(gateway_ip_list), @@ -842,6 +847,7 @@ target_config = config.config['targets'][target_iqn] ip_list = target_config.get('ip_list', []) gateway = GWTarget(logger, + config, target_iqn, ip_list) @@ -1605,7 +1611,7 @@ committing_host = request.form['committing_host'] action = request.form['action'] - target = GWTarget(logger, target_iqn, []) + target = GWTarget(logger, config, target_iqn, []) acl_enabled = (action == 'enable_acl')