Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package ceph-iscsi for openSUSE:Factory checked in at 2021-12-06 23:59:04 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ceph-iscsi (Old) and /work/SRC/openSUSE:Factory/.ceph-iscsi.new.31177 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ceph-iscsi" Mon Dec 6 23:59:04 2021 rev:22 rq:935281 version:3.5+1638408991.g5341b5d Changes: -------- --- /work/SRC/openSUSE:Factory/ceph-iscsi/ceph-iscsi.changes 2020-09-21 17:09:53.063270577 +0200 +++ /work/SRC/openSUSE:Factory/.ceph-iscsi.new.31177/ceph-iscsi.changes 2021-12-06 23:59:05.552625867 +0100 @@ -2 +2 @@ -Thu Sep 17 13:32:02 UTC 2020 - Ricardo Marques <[email protected]> +Thu Dec 2 18:49:22 UTC 2021 - Stefen Allen <[email protected]> @@ -4 +4,10 @@ -- Update to 3.4+1600349408.g516d37d +- Update to 3.5+1638408991.g5341b5d + + rbd unmap image when deleting target (bsc#1190772) + + gwcli: add error handling path for config api request (#231) + + rbd-target-api: misc fixing for disk API (#229) + + iscsi: raise if the 'gateway.conf' config file doesn't exist (#228) + + iscsi: write cert/key to temp files in mode 'w' to handle strings (#227) + + Fix the default value for gateway_conf (#226) + + Add a strip to ListSetting.Normalize (#220, bsc#1177100) + + Make settings mon config key store aware (#217) + + Rename blacklist to blocklist (#216) @@ -7,2 +16,2 @@ - + Fix list access violiation when load config (#200) - + Fix delete disk error when disk owner is not specified (#206) + + Fix list access violiation when load config (#200, bsc#1183028) + + fix delete disk error when disk owner is not specified (#206) @@ -10 +19 @@ - + Added dependency on ceph-common package (#201) + + spec: added dependency on ceph-common package (#201) @@ -13 +22 @@ -Tue Sep 15 12:14:23 UTC 2020 - Nathan Cutler <[email protected]> +Wed Feb 24 11:15:15 UTC 2021 - Ricardo Marques <[email protected]> @@ -15,2 +24,15 @@ -- Update to 3.4+1600172042.g4d04457 - + Rename blacklist to blocklist (#216) +- Update to 3.4+1614165221.g78e33bb + + Gateway fails to start when using SSL (bsc#1182611) + +------------------------------------------------------------------- +Fri Oct 16 12:18:01 UTC 2020 - Ricardo Marques <[email protected]> + +- Update to 3.4+1602850653.g9af452e + + Support spaces on 'trusted_ip_list' (#220, bsc#1177100) + +------------------------------------------------------------------- +Wed Oct 14 09:49:59 UTC 2020 - Ricardo Marques <[email protected]> + +- Update to 3.4+1602668899.ga7b4d38 + + Update RBD supported features for SLE15-SP2 kernel (bsc#1177202) + + Make settings mon config key store aware (#217) @@ -57 +79 @@ -Tue Oct 8 11:05:09 UTC 2019 - Nathan Cutler <[email protected]> +Tue Oct 8 11:42:55 UTC 2019 - Nathan Cutler <[email protected]> @@ -59 +81 @@ -- Update to 3.3+1570532654.g93940a4: +- Update to 3.3+1570534953.g93940a4: @@ -66 +88 @@ -Fri Sep 27 09:17:57 UTC 2019 - Ricardo Marques <[email protected]> +Fri Sep 27 09:28:51 UTC 2019 - Ricardo Marques <[email protected]> @@ -68 +90 @@ -- Update to 3.3+1569575733.g93940a4: +- Update to 3.3+1569576525.g93940a4: @@ -71,0 +94,6 @@ + +------------------------------------------------------------------- +Thu Sep 26 11:33:58 UTC 2019 - Nathan Cutler <[email protected]> + +- Update to 3.2+1569497618.ga2b17e1: + + incremental pre-Milestone1 build Old: ---- ceph-iscsi-3.4+1600349408.g516d37d.tar.gz New: ---- ceph-iscsi-3.5+1638408991.g5341b5d.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ceph-iscsi.spec ++++++ --- /var/tmp/diff_new_pack.TKoCLY/_old 2021-12-06 23:59:08.252616318 +0100 +++ /var/tmp/diff_new_pack.TKoCLY/_new 2021-12-06 23:59:08.256616304 +0100 @@ -19,7 +19,7 @@ %endif Name: ceph-iscsi -Version: 3.4+1600349408.g516d37d +Version: 3.5+1638408991.g5341b5d Release: 1%{?dist} Group: System/Filesystems Summary: Python modules for Ceph iSCSI gateway configuration management ++++++ ceph-iscsi-3.4+1600349408.g516d37d.tar.gz -> ceph-iscsi-3.5+1638408991.g5341b5d.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.4+1600349408.g516d37d/ceph-iscsi.spec new/ceph-iscsi-3.5+1638408991.g5341b5d/ceph-iscsi.spec --- old/ceph-iscsi-3.4+1600349408.g516d37d/ceph-iscsi.spec 2020-09-17 15:30:08.959841391 +0200 +++ new/ceph-iscsi-3.5+1638408991.g5341b5d/ceph-iscsi.spec 2021-12-02 02:36:31.155269945 +0100 @@ -19,7 +19,7 @@ %endif Name: ceph-iscsi -Version: 3.4+1600349408.g516d37d +Version: 3.5+1638408991.g5341b5d 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.4+1600349408.g516d37d/ceph_iscsi_config/backstore.py new/ceph-iscsi-3.5+1638408991.g5341b5d/ceph_iscsi_config/backstore.py --- old/ceph-iscsi-3.4+1600349408.g516d37d/ceph_iscsi_config/backstore.py 2020-09-17 15:30:07.815831872 +0200 +++ new/ceph-iscsi-3.5+1638408991.g5341b5d/ceph_iscsi_config/backstore.py 2021-12-02 02:36:30.967270160 +0100 @@ -6,6 +6,10 @@ USER_RBD = 'user:rbd' RBD = 'rbd' +def is_rbd_backstore(config, disk): + backstore = config.config["disks"][disk]["backstore"] + return backstore == RBD + def lookup_storage_object_by_disk(config, disk): backstore = config.config["disks"][disk]["backstore"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.4+1600349408.g516d37d/ceph_iscsi_config/gateway_setting.py new/ceph-iscsi-3.5+1638408991.g5341b5d/ceph_iscsi_config/gateway_setting.py --- old/ceph-iscsi-3.4+1600349408.g516d37d/ceph_iscsi_config/gateway_setting.py 2020-09-17 15:30:07.815831872 +0200 +++ new/ceph-iscsi-3.5+1638408991.g5341b5d/ceph_iscsi_config/gateway_setting.py 2021-12-02 02:36:30.967270160 +0100 @@ -71,7 +71,7 @@ return str(norm_val) def normalize(self, raw_val): - return raw_val.split(',') if raw_val else [] + return [r.strip() for r in raw_val.split(',')] if raw_val else [] class StrSetting(Setting): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.4+1600349408.g516d37d/ceph_iscsi_config/lun.py new/ceph-iscsi-3.5+1638408991.g5341b5d/ceph_iscsi_config/lun.py --- old/ceph-iscsi-3.4+1600349408.g516d37d/ceph_iscsi_config/lun.py 2020-09-17 15:30:07.815831872 +0200 +++ new/ceph-iscsi-3.5+1638408991.g5341b5d/ceph_iscsi_config/lun.py 2021-12-02 02:36:30.967270160 +0100 @@ -34,9 +34,6 @@ RBD: [ # TODO Uncomment after PR https://github.com/ceph/ceph/pull/28009 # 'RBD_FEATURE_MIGRATING', - 'RBD_FEATURE_OBJECT_MAP', - 'RBD_FEATURE_FAST_DIFF', - 'RBD_FEATURE_DEEP_FLATTEN', 'RBD_FEATURE_JOURNALING' ] } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.4+1600349408.g516d37d/ceph_iscsi_config/settings.py new/ceph-iscsi-3.5+1638408991.g5341b5d/ceph_iscsi_config/settings.py --- old/ceph-iscsi-3.4+1600349408.g516d37d/ceph_iscsi_config/settings.py 2020-09-17 15:30:07.815831872 +0200 +++ new/ceph-iscsi-3.5+1638408991.g5341b5d/ceph_iscsi_config/settings.py 2021-12-02 02:36:30.967270160 +0100 @@ -8,11 +8,15 @@ import hashlib import json +import rados import re -from ceph_iscsi_config.gateway_setting import (TGT_SETTINGS, TGT_KERNEL_SETTINGS, SYS_SETTINGS, +from ceph_iscsi_config.gateway_setting import (TGT_SETTINGS, + TGT_KERNEL_SETTINGS, + SYS_SETTINGS, TCMU_SETTINGS, - TCMU_DEV_STATUS_SETTINGS, KERNEL_SETTINGS) + TCMU_DEV_STATUS_SETTINGS, + KERNEL_SETTINGS) # this module when imported preserves the global values @@ -23,6 +27,9 @@ config = Settings() +MON_CONFIG_PREFIX = 'config://' + + class Settings(object): _float_regex = re.compile(r"^[0-9]*\.{1}[0-9]$") _int_regex = re.compile(r"^[0-9]+$") @@ -87,10 +94,13 @@ self._override_attrs_from_conf(config.items("target"), all_settings) - self.cephconf = '{}/{}.conf'.format(self.ceph_config_dir, self.cluster_name) if self.api_secure: self.api_ssl_verify = False if self.api_secure else None + @property + def cephconf(self): + return '{}/{}.conf'.format(self.ceph_config_dir, self.cluster_name) + def __repr__(self): s = '' for k in self.__dict__: @@ -107,14 +117,24 @@ for k, setting in def_settings.items(): self.__setattr__(k, setting.def_val) - def _override_attrs_from_conf(self, config, def_settings): - """ - receive a settings dict and apply those key/value to the - current instance, settings that look like numbers are converted - :param settings: dict of settings - :return: None - """ - for k, v in config: + def pull_from_mon_config(self, v): + if not self.cluster_client_name or not self.cephconf: + return '' + + with rados.Rados(conffile=self.cephconf, + name=self.cluster_client_name) as cluster: + if v.startswith(MON_CONFIG_PREFIX): + v = v[len(MON_CONFIG_PREFIX):] + + cmd = {"prefix": "config-key get", + "key": "{}".format(v)} + ret, v_data, outs = cluster.mon_command(json.dumps(cmd), b'') + if ret: + return '' + return v_data.decode('utf-8') + + def _override_attrs(self, override_attrs, def_settings): + for k, v in override_attrs.items(): if hasattr(self, k): setting = def_settings[k] try: @@ -124,6 +144,29 @@ # so the deamons can still start pass + def _override_attrs_from_conf(self, config, def_settings): + """ + receive a settings dict and apply those key/value to the + current instance, settings that look like numbers are converted + :param settings: dict of settings + :return: None + """ + mon_config_items = { + k: v for k, v in config + if isinstance(v, str) and v.startswith(MON_CONFIG_PREFIX)} + config_items = {k: v for k, v in config if k not in mon_config_items} + + # first process non mon config items because we need the + # cluster_client_name and ceph_conf in order to talk to the mon config + # store + self._override_attrs(config_items, def_settings) + + if mon_config_items: + # Now let's attempt to pull these from the config store + for k, v in mon_config_items.items(): + mon_config_items[k] = self.pull_from_mon_config(v) + self._override_attrs(mon_config_items, def_settings) + def _hash_settings(self, def_settings, sync_settings): for setting in def_settings: if setting not in Settings.exclude_from_hash: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.4+1600349408.g516d37d/ceph_iscsi_config/target.py new/ceph-iscsi-3.5+1638408991.g5341b5d/ceph_iscsi_config/target.py --- old/ceph-iscsi-3.4+1600349408.g516d37d/ceph_iscsi_config/target.py 2020-09-17 15:30:07.815831872 +0200 +++ new/ceph-iscsi-3.5+1638408991.g5341b5d/ceph_iscsi_config/target.py 2021-12-02 02:36:30.967270160 +0100 @@ -1,5 +1,6 @@ import glob import os +import subprocess from rtslib_fb.target import Target, TPG, NetworkPortal, LUN from rtslib_fb.fabric import ISCSIFabricModule @@ -17,10 +18,20 @@ from ceph_iscsi_config.alua import alua_create_group, alua_format_group_name from ceph_iscsi_config.client import GWClient, CHAP from ceph_iscsi_config.gateway_object import GWObject -from ceph_iscsi_config.backstore import lookup_storage_object_by_disk +from ceph_iscsi_config.backstore import lookup_storage_object_by_disk, is_rbd_backstore __author__ = '[email protected]' +def rbd_device_unmap(image_spec): + if not os.path.exists("/dev/rbd/{}".format(image_spec)): + return + + proc = subprocess.Popen(["rbd", "-n", settings.config.cluster_client_name, "device", + "unmap", image_spec]) + retcode = proc.wait() + if retcode != 0: + raise CephiSCSIError("Error unmapping device {}".format(image_spec)) + class GWTarget(GWObject): """ @@ -575,6 +586,8 @@ try: so.delete() + if is_rbd_backstore(config, disk): + rbd_device_unmap(disk) except RTSLibError as err: self.logger.error("lio disk deletion failed {}".format(err)) if saved_err is None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.4+1600349408.g516d37d/gwcli/gateway.py new/ceph-iscsi-3.5+1638408991.g5341b5d/gwcli/gateway.py --- old/ceph-iscsi-3.4+1600349408.g516d37d/gwcli/gateway.py 2020-09-17 15:30:07.815831872 +0200 +++ new/ceph-iscsi-3.5+1638408991.g5341b5d/gwcli/gateway.py 2021-12-02 02:36:30.967270160 +0100 @@ -33,7 +33,6 @@ UIRoot.__init__(self, shell) self.error = False - self.error_msg = '' self.interactive = True # default interactive mode self.scan_threads = scan_threads @@ -59,10 +58,9 @@ self.target = ISCSITargets(self) def refresh(self): - self.config = self._get_config() + self.config = self._get_config() if not self.error: - if 'disks' in self.config: self.disks.refresh(self.config['disks']) else: @@ -74,14 +72,10 @@ self.target.gateway_group = {} self.target.refresh(self.config['targets'], self.config['discovery_auth']) - self.ceph.refresh() - else: # Unable to get the config, tell the user and exit the cli - self.logger.critical("Unable to access the configuration " - "object : {}".format(self.error_msg)) - raise GatewayError + self.logger.critical("Unable to access the configuration object") def _get_config(self, endpoint=None): @@ -96,12 +90,14 @@ return api.response.json() except Exception: self.error = True - self.error_msg = "Malformed REST API response" + self.logger.error("Malformed REST API response") return {} else: + # 403 maybe due to the ip address is not in the iscsi + # gateway trusted ip list self.error = True - self.error_msg = "REST API failure, code : " \ - "{}".format(api.response.status_code) + self.logger.error("REST API failure, code : " + "{}".format(api.response.status_code)) return {} def export_copy(self, config): @@ -130,6 +126,9 @@ return current_config = self._get_config() + if not current_config: + self.logger.error("Unable to refresh local config.") + return if mode == 'copy': self.export_copy(current_config) @@ -200,11 +199,9 @@ if not target_exists: Target(target_iqn, self) else: - self.logger.error("Failed to create the target on the local node") - - raise GatewayAPIError("iSCSI target creation failed - " - "{}".format(response_message(api.response, - self.logger))) + self.logger.error("Failed to create the target on the local node " + "{}".format(response_message(api.response, + self.logger))) def ui_command_delete(self, target_iqn): """ @@ -297,7 +294,7 @@ msg = response_message(api.response, self.logger) self.logger.error("Delete of {} failed : {}".format(gw_name, msg)) - raise GatewayAPIError + return else: self.logger.debug("- deleted {}".format(gw_name)) @@ -363,7 +360,6 @@ self.logger.info('ok') else: self.logger.error("Error: {}".format(response_message(api.response, self.logger))) - return def _set_auth(self, username, password, mutual_username, mutual_password): if mutual_username != '' and mutual_password != '': @@ -417,6 +413,7 @@ config = self.parent.parent._get_config() if not config: self.logger.error("Unable to refresh local config") + raise GatewayError self.auth = config['targets'][target_iqn]['auth'] # decode the chap password if necessary @@ -516,14 +513,13 @@ self.logger.error("Failed to reconfigure : " "{}".format(response_message(api.response, self.logger))) - return config = self.parent.parent._get_config() if not config: - self.logger.error("Unable to refresh local config") - self.controls = config['targets'][self.target_iqn]['controls'] - - self.logger.info('ok') + self.logger.error("Unable to refresh local config.") + else: + self.controls = config['targets'][self.target_iqn]['controls'] + self.logger.info('ok') def ui_command_auth(self, username=None, password=None, mutual_username=None, mutual_password=None): @@ -591,7 +587,6 @@ self.logger.error("Failed to update target auth: " "{}".format(response_message(api.response, self.logger))) - return class GatewayGroup(UIGroup): @@ -705,7 +700,7 @@ config = self.parent.parent.parent._get_config() if not config: self.logger.error("Unable to refresh local config over API - sync " - "aborted, restart rbd-target-api on {} to " + "aborted, restart rbd-target-api on {0} to " "sync".format(gateway_name)) return @@ -757,6 +752,7 @@ config = self.parent.parent.parent._get_config() if not config: self.logger.error("Could not refresh display. Restart gwcli.") + return elif not config['targets'][target_iqn]['portals']: # no more gws so everything but the target is dropped. disks_object = self.parent.get_child("disks") @@ -820,7 +816,8 @@ if not config: self.logger.error("Unable to refresh local config" " over API - sync aborted, restart rbd-target-api" - " on {} to sync".format(gateway_name)) + " on {0} to sync".format(gateway_name)) + return target_iqn = self.parent.name target_config = config['targets'][target_iqn] @@ -849,6 +846,7 @@ "".format(msg, gateway_name, settings.config.api_port)) return + gateway_hostname = api.response.json()['data'] self.logger.info("Adding gateway, {}".format(sync_text)) @@ -877,6 +875,11 @@ # we get back is current (the other gateways will lag until they see # epoch xattr change on the config object) config = self.parent.parent.parent._get_config(endpoint=new_gw_endpoint) + if not config: + self.logger.error("Unable to refresh local config" + " over API - sync aborted, restart rbd-target-api" + " on {0} to sync".format(gateway_name)) + return target_config = config['targets'][target_iqn] portal_config = target_config['portals'][gateway_hostname] Gateway(self, gateway_hostname, portal_config) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.4+1600349408.g516d37d/iscsi-gateway.cfg_sample new/ceph-iscsi-3.5+1638408991.g5341b5d/iscsi-gateway.cfg_sample --- old/ceph-iscsi-3.4+1600349408.g516d37d/iscsi-gateway.cfg_sample 2020-09-17 15:30:07.815831872 +0200 +++ new/ceph-iscsi-3.5+1638408991.g5341b5d/iscsi-gateway.cfg_sample 2021-12-02 02:36:30.967270160 +0100 @@ -8,7 +8,7 @@ # CephX client name # cluster_client_name = client.<rados_id> # E.g.: client.admin -# gateway_conf = iscsi-gateway.conf +# gateway_conf = gateway.conf # 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.4+1600349408.g516d37d/rbd-target-api.py new/ceph-iscsi-3.5+1638408991.g5341b5d/rbd-target-api.py --- old/ceph-iscsi-3.4+1600349408.g516d37d/rbd-target-api.py 2020-09-17 15:30:07.819831905 +0200 +++ new/ceph-iscsi-3.5+1638408991.g5341b5d/rbd-target-api.py 2021-12-02 02:36:30.967270160 +0100 @@ -122,7 +122,7 @@ Display all the available API endpoints **UNRESTRICTED** Examples: - curl --insecure --user admin:admin -X GET http://192.168.122.69:5000/api + curl --user admin:admin -X GET http://192.168.122.69:5000/api """ links = [] @@ -170,7 +170,7 @@ Valid query types are: ip_addresses, checkconf and checkversions **RESTRICTED** Examples: - curl --insecure --user admin:admin -X GET http://192.168.122.69:5000/api/sysinfo/ip_addresses + curl --user admin:admin -X GET http://192.168.122.69:5000/api/sysinfo/ip_addresses """ if query_type == 'ip_addresses': @@ -229,7 +229,7 @@ List targets defined in the configuration. **RESTRICTED** Examples: - curl --insecure --user admin:admin -X GET https://192.168.122.69:5000/api/targets + curl --user admin:admin -X GET http://192.168.122.69:5000/api/targets """ return jsonify({'targets': list(config.config['targets'].keys())}), 200 @@ -247,9 +247,9 @@ :param controls: (JSON dict) valid control overrides **RESTRICTED** Examples: - curl --insecure --user admin:admin + curl --user admin:admin -X PUT http://192.168.122.69:5000/api/target/iqn.2003-01.com.redhat.iscsi-gw0 - curl --insecure --user admin:admin -d mode=reconfigure -d controls='{cmdsn_depth=128}' + curl --user admin:admin -d mode=reconfigure -d controls='{cmdsn_depth=128}' -X PUT http://192.168.122.69:5000/api/target/iqn.2003-01.com.redhat.iscsi-gw0 """ @@ -499,7 +499,7 @@ :param decrypt_passwords: (bool) if true, passwords will be decrypted **RESTRICTED** Examples: - curl --insecure --user admin:admin -X GET http://192.168.122.69:5000/api/config + curl --user admin:admin -X GET http://192.168.122.69:5000/api/config """ if request.method == 'GET': @@ -548,8 +548,8 @@ Return the gateway subsection of the config object to the caller **RESTRICTED** Examples: - curl --insecure --user admin:admin -X GET - http://192.168.122.69:5000/api/gateways/iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw + curl --user admin:admin -X GET + http://192.168.122.69:5000/api/gateways/iqn.2003-01.com.redhat.iscsi-gw """ try: @@ -581,8 +581,10 @@ :param force: (bool) if True will force removal of gateway. **RESTRICTED** Examples: - curl --insecure --user admin:admin -d ip_address=192.168.122.69 - -X PUT http://192.168.122.69:5000/api/gateway/iscsi-gw0 + curl --user admin:admin -d ip_address=192.168.122.69 + -X PUT http://192.168.122.69:5000/api/gateway/iqn.2003-01.com.redhat.iscsi-gw/gateway1 + curl --user admin:admin + -X DELETE http://192.168.122.69:5000/api/gateway/iqn.2003-01.com.redhat.iscsi-gw/gateway1 """ # the definition of a gateway into an existing configuration can apply the @@ -750,8 +752,10 @@ :param disk: (str) rbd image name on the format pool/image **RESTRICTED** Examples: - curl --insecure --user admin:admin -d disk=rbd.new2_1 - -X PUT https://192.168.122.69:5000/api/targetlun/iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw + curl --user admin:admin -d disk=rbd/new2_1 + -X PUT http://192.168.122.69:5000/api/targetlun/iqn.2003-01.com.redhat.iscsi-gw + curl --user admin:admin -d disk=rbd/new2_1 + -X DELETE http://192.168.122.69:5000/api/targetlun/iqn.2003-01.com.redhat.iscsi-gw """ try: @@ -952,7 +956,7 @@ :param config: (str) 'yes' to list the config info of all disks, default is 'no' **RESTRICTED** Examples: - curl --insecure --user admin:admin -d config=yes -X GET https://192.168.122.69:5000/api/disks + curl --user admin:admin -d config=yes -X GET http://192.168.122.69:5000/api/disks """ conf = request.form.get('config', 'no') @@ -985,18 +989,18 @@ :param count: (str) the number of images will be created :param owner: (str) the owner of the rbd image :param controls: (JSON dict) valid control overrides - :param preserve_image: (bool) do NOT delete RBD image - :param create_image: (bool) create RBD image if not exists + :param preserve_image: (bool, 'true/false') do NOT delete RBD image + :param create_image: (bool, 'true/false') create RBD image if not exists, true as default :param backstore: (str) lio backstore :param wwn: (str) unit serial number **RESTRICTED** Examples: - curl --insecure --user admin:admin -d mode=create -d size=1g -d pool=rbd -d count=5 - -X PUT https://192.168.122.69:5000/api/disk/rbd.new2_ - curl --insecure --user admin:admin -d mode=create -d size=10g -d pool=rbd - -X PUT https://192.168.122.69:5000/api/disk/rbd.new3_ - curl --insecure --user admin:admin -X GET https://192.168.122.69:5000/api/disk/rbd.new2_1 - curl --insecure --user admin:admin -X DELETE https://192.168.122.69:5000/api/disk/rbd.new2_1 + curl --user admin:admin -d mode=create -d size=1g -d pool=rbd -d count=5 + -X PUT http://192.168.122.69:5000/api/disk/rbd/new0_ + curl --user admin:admin -d mode=create -d size=10g -d pool=rbd -d create_image=false + -X PUT http://192.168.122.69:5000/api/disk/rbd/new1 + curl --user admin:admin -X GET http://192.168.122.69:5000/api/disk/rbd/new2 + curl --user admin:admin -X DELETE http://192.168.122.69:5000/api/disk/rbd/new3 """ local_gw = this_host() @@ -1065,17 +1069,26 @@ if disk_usable != 'ok': return jsonify(message=disk_usable), 400 - create_image = request.form.get('create_image') == 'true' - if mode == 'create' and (not create_image or not size): + create_image = request.form.get('create_image', 'true') + if create_image not in ['true', 'false']: + logger.error("Invalid 'create_image' value {}".format(create_image)) + return jsonify(message="Invalid 'create_image' value {}".format(create_image)), 400 + + if mode == 'create' and (create_image == 'false' or not size): try: + # no size implies not intention to create an image, try to + # check whether it exists rbd_image = RBDDev(image, 0, backstore, pool) size = rbd_image.current_size except rbd.ImageNotFound: - if not create_image: - return jsonify(message="Image {} does not exist".format(image_id)), 400 - else: + # the create_image=true will be implied if size is specified + # by default + if create_image == 'true': + # the size must be specified when creating an image return jsonify(message="Size parameter is required when creating a new " "image"), 400 + elif create_image == 'false': + return jsonify(message="Image {} does not exist".format(image_id)), 400 if mode == 'reconfigure': resp_text, resp_code = lun_reconfigure(image_id, controls, backstore) @@ -1125,7 +1138,7 @@ api_vars = { 'purge_host': local_gw, - 'preserve_image': request.form['preserve_image'], + 'preserve_image': request.form.get('preserve_image'), 'backstore': backstore } @@ -1268,7 +1281,7 @@ # if valid_request(request.remote_addr): purge_host = request.form['purge_host'] - preserve_image = request.form['preserve_image'] == 'true' + preserve_image = request.form.get('preserve_image') == 'true' logger.debug("delete request for disk image '{}'".format(image_id)) pool, image = image_id.split('/', 1) disk_config = config.config['disks'][image_id] @@ -1390,10 +1403,10 @@ :param mode: (str) 'create' or 'rollback' the rbd snapshot **RESTRICTED** Examples: - curl --insecure --user admin:admin -d mode=create - -X PUT https://192.168.122.69:5000/api/disksnap/rbd.image/new1 - curl --insecure --user admin:admin - -X DELETE https://192.168.122.69:5000/api/disksnap/rbd.image/new1 + curl --user admin:admin -d mode=create + -X PUT http://192.168.122.69:5000/api/disksnap/rbd.image/new1 + curl --user admin:admin + -X DELETE http://192.168.122.69:5000/api/disksnap/rbd.image/new1 """ if not valid_snapshot_name(name): @@ -1544,9 +1557,9 @@ [0-9a-zA-Z] and '@' '-' '_' '/' **RESTRICTED** Example: - curl --insecure --user admin:admin -d username=myiscsiusername -d password=myiscsipassword + curl --user admin:admin -d username=myiscsiusername -d password=myiscsipassword -d mutual_username=myiscsiusername -d mutual_password=myiscsipassword - -X PUT https://192.168.122.69:5000/api/discoveryauth + -X PUT http://192.168.122.69:5000/api/discoveryauth """ username = request.form.get('username', '') @@ -1619,8 +1632,8 @@ [0-9a-zA-Z] and '@' '-' '_' '/' **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 + curl --user admin:admin -d auth='disable_acl' + -X PUT http://192.168.122.69:5000/api/targetauth/iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw """ action = request.form.get('action') @@ -1750,7 +1763,7 @@ Returns the total number of active sessions for <target_iqn> **RESTRICTED** Examples: - curl --insecure --user admin:admin -X GET + curl --user admin:admin -X GET http://192.168.122.69:5000/api/targetinfo/iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw """ if target_iqn not in config.config['targets']: @@ -1780,7 +1793,7 @@ Returns the number of active sessions for <target_iqn> on local gateway **RESTRICTED** Examples: - curl --insecure --user admin:admin -X GET + curl --user admin:admin -X GET http://192.168.122.69:5000/api/_targetinfo/iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw """ if target_iqn not in config.config['targets']: @@ -1798,7 +1811,7 @@ Returns the number of active sessions on local gateway **RESTRICTED** Examples: - curl --insecure --user admin:admin -X GET + curl --user admin:admin -X GET http://192.168.122.69:5000/api/gatewayinfo """ local_gw = this_host() @@ -1822,8 +1835,8 @@ restricted_auth wrapper **RESTRICTED** Examples: - curl --insecure --user admin:admin -X GET - https://192.168.122.69:5000/api/clients/iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw + curl --user admin:admin -X GET + http://192.168.122.69:5000/api/clients/iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw """ try: @@ -1894,9 +1907,9 @@ [0-9a-zA-Z] and '@' '-' '_' '/' **RESTRICTED** Example: - curl --insecure --user admin:admin -d username=myiscsiusername -d password=myiscsipassword + curl --user admin:admin -d username=myiscsiusername -d password=myiscsipassword -d mutual_username=myiscsiusername -d mutual_password=myiscsipassword - -X PUT https://192.168.122.69:5000/api/clientauth/iqn.2017-08.org.ceph:iscsi-gw0 + -X PUT http://192.168.122.69:5000/api/clientauth/iqn.2017-08.org.ceph:iscsi-gw0 """ try: @@ -1994,8 +2007,12 @@ :param disk: (str) rbd image name of the format pool/image **RESTRICTED** Examples: - curl --insecure --user admin:admin -d disk=rbd.new2_1 - -X PUT https://192.168.122.69:5000/api/clientlun/iqn.2017-08.org.ceph:iscsi-gw0 + TARGET_IQN = iqn.2017-08.org.ceph:iscsi-gw + CLIENT_IQN = iqn.1994-05.com.redhat:myhost4 + curl --user admin:admin -d disk=rbd/new2_1 + -X PUT http://192.168.122.69:5000/api/clientlun/$TARGET_IQN/$CLIENT_IQN + curl --user admin:admin -d disk=rbd/new2_1 + -X DELETE http://192.168.122.69:5000/api/clientlun/$TARGET_IQN/$CLIENT_IQN """ try: @@ -2115,10 +2132,12 @@ :param client_iqn: (str) IQN of the client to create or delete **RESTRICTED** Examples: - curl --insecure --user admin:admin - -X PUT https://192.168.122.69:5000/api/client/iqn.1994-05.com.redhat:myhost4 - curl --insecure --user admin:admin - -X DELETE https://192.168.122.69:5000/api/client/iqn.1994-05.com.redhat:myhost4 + TARGET_IQN = iqn.2017-08.org.ceph:iscsi-gw + CLIENT_IQN = iqn.1994-05.com.redhat:myhost4 + curl --user admin:admin + -X PUT http://192.168.122.69:5000/api/client/$TARGET_IQN/$CLIENT_IQN + curl --user admin:admin + -X DELETE http://192.168.122.69:5000/api/client/$TARGET_IQN/$CLIENT_IQN """ method = {"PUT": 'create', @@ -2261,7 +2280,7 @@ Returns client alias, ip_address and state for each connected portal **RESTRICTED** Examples: - curl --insecure --user admin:admin -X GET + curl --user admin:admin -X GET http://192.168.122.69:5000/api/clientinfo/ iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw/iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw-client """ @@ -2304,7 +2323,7 @@ Returns client alias, ip_address and state for local gateway **RESTRICTED** Examples: - curl --insecure --user admin:admin -X GET + curl --user admin:admin -X GET http://192.168.122.69:5000/api/_clientinfo/ iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw/iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw-client """ @@ -2325,7 +2344,7 @@ Return the hostgroup names defined to the configuration **RESTRICTED** Examples: - curl --insecure --user admin:admin -X GET + curl --user admin:admin -X GET http://192.168.122.69:5000/api/hostgroups/iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw """ @@ -2352,12 +2371,12 @@ :param: action (str) 'add'/'remove' group's client members/disks, default is 'add' :return: Examples: - curl --insecure --user admin:admin -X GET http://192.168.122.69:5000/api/hostgroup/group_name - curl --insecure --user admin:admin -d members=iqn.1994-05.com.redhat:myhost4 + curl --user admin:admin -X GET http://192.168.122.69:5000/api/hostgroup/group_name + curl --user admin:admin -d members=iqn.1994-05.com.redhat:myhost4 -d disks=rbd.disk1 -X PUT http://192.168.122.69:5000/api/hostgroup/group_name - curl --insecure --user admin:admin -d action=remove -d disks=rbd.disk1 + curl --user admin:admin -d action=remove -d disks=rbd.disk1 -X PUT http://192.168.122.69:5000/api/hostgroup/group_name - curl --insecure --user admin:admin + curl --user admin:admin -X DELETE http://192.168.122.69:5000/api/hostgroup/group_name """ http_mode = 'https' if settings.config.api_secure else 'http' @@ -2490,7 +2509,7 @@ List settings. **RESTRICTED** Examples: - curl --insecure --user admin:admin -X GET https://192.168.122.69:5000/api/settings + curl --user admin:admin -X GET http://192.168.122.69:5000/api/settings """ target_default_controls, target_controls_limits = fill_settings_dict(GWTarget.SETTINGS) @@ -2807,11 +2826,7 @@ try: obj_epoch = int(ioctx.get_xattr('gateway.conf', 'epoch')) except rados.ObjectNotFound: - # daemon is running prior to any config being created or it has - # skip the error, and - logger.warning("config object missing, recreating") - config.refresh() - + raise else: # if it's changed, refresh the local config to ensure a query # to this node will return current state @@ -2825,18 +2840,16 @@ def get_ssl_files_from_mon(): client_name = settings.config.cluster_client_name temp_files = [] - with rados.Rados(conffile=settings.config.cephconf, - name=client_name) as cluster: - cmd = {"prefix": "config-key get", - "key": "iscsi/{}/iscsi-gateway.crt".format(client_name)} - ret, crt_data, outs = cluster.mon_command(json.dumps(cmd), b'') - if ret: - return temp_files - - cmd["key"] = "iscsi/{}/iscsi-gateway.key".format(client_name) - ret, key_data, outs = cluster.mon_command(json.dumps(cmd), b'') - if ret: - return temp_files + crt_data = settings.config.pull_from_mon_config( + "iscsi/{}/iscsi-gateway.crt".format(client_name)) + if not crt_data: + return temp_files + + key_data = settings.config.pull_from_mon_config( + "iscsi/{}/iscsi-gateway.key".format(client_name)) + if not key_data: + return temp_files + for data in crt_data, key_data: # NOTE: Annoyingly SSLContext.load_cert_chain can only take # paths to files and not file like objects.. yet. So we need to @@ -2844,7 +2857,7 @@ # https://bugs.python.org/issue16487 is resolved, we should be able # to simply use file-like objects and makes this much nicer. - tmp_f = tempfile.NamedTemporaryFile() + tmp_f = tempfile.NamedTemporaryFile(mode='w') tmp_f.write(data) tmp_f.flush() temp_files.append(tmp_f) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.4+1600349408.g516d37d/setup.py new/ceph-iscsi-3.5+1638408991.g5341b5d/setup.py --- old/ceph-iscsi-3.4+1600349408.g516d37d/setup.py 2020-09-17 15:30:07.819831905 +0200 +++ new/ceph-iscsi-3.5+1638408991.g5341b5d/setup.py 2021-12-02 02:36:30.967270160 +0100 @@ -28,7 +28,7 @@ setup( name="ceph_iscsi", - version="3.4", + version="3.5", description="Common classes/functions and CLI tools used to configure iSCSI " "gateways backed by Ceph RBD", long_description=long_description, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ceph-iscsi-3.4+1600349408.g516d37d/test/test_settings.py new/ceph-iscsi-3.5+1638408991.g5341b5d/test/test_settings.py --- old/ceph-iscsi-3.4+1600349408.g516d37d/test/test_settings.py 2020-09-17 15:30:07.819831905 +0200 +++ new/ceph-iscsi-3.5+1638408991.g5341b5d/test/test_settings.py 2021-12-02 02:36:30.967270160 +0100 @@ -5,13 +5,16 @@ from ceph_iscsi_config.settings import Settings from ceph_iscsi_config.target import GWTarget +from ceph_iscsi_config.gateway_setting import SYS_SETTINGS class SettingsTest(unittest.TestCase): @staticmethod - def _normalize(controls): - return Settings.normalize_controls(controls, GWTarget.SETTINGS) + def _normalize(controls, settings=None): + if not settings: + settings = GWTarget.SETTINGS + return Settings.normalize_controls(controls, settings) def test_normalize_controls_int(self): self.assertEqual( @@ -69,3 +72,16 @@ with self.assertRaises(ValueError) as cm: SettingsTest._normalize({'immediate_data': 123}) self.assertEqual('expected yes or no for immediate_data', str(cm.exception)) + + def test_normalise_list(self): + self.assertDictEqual( + SettingsTest._normalize( + {'trusted_ip_list': '10.1.1.1,10.1.1.2,10.1.1.3'}, + SYS_SETTINGS), + {'trusted_ip_list': ['10.1.1.1', '10.1.1.2', '10.1.1.3']}) + + self.assertDictEqual( + SettingsTest._normalize( + {'trusted_ip_list': '10.1.1.1, 10.1.1.2 , 10.1.1.3'}, + SYS_SETTINGS), + {'trusted_ip_list': ['10.1.1.1', '10.1.1.2', '10.1.1.3']})
