diff --git a/Cinder/Mitaka/huawei_conf.py b/Cinder/Mitaka/huawei_conf.py index 38a6c17..394c88c 100644 --- a/Cinder/Mitaka/huawei_conf.py +++ b/Cinder/Mitaka/huawei_conf.py @@ -95,6 +95,8 @@ def update_config_value(self): self._replication_pair_sync_speed, self._get_local_minimum_fc_initiator, self._hyper_enforce_multipath, + self._get_local_in_band_or_not, + self._get_local_storage_sn, self._rollback_speed) tree = ET.parse(self.conf.cinder_huawei_conf_file, @@ -103,14 +105,8 @@ def update_config_value(self): for f in set_attr_funcs: f(xml_root) - def _ssl_cert_path(self, xml_root): - text = xml_root.findtext('Storage/SSLCertPath') - if text: - setattr(self.conf, 'ssl_cert_path', text) - else: - setattr(self.conf, 'ssl_cert_path', None) - - def _ssl_cert_verify(self, xml_root): + @staticmethod + def _get_ssl_verify(xml_root): value = False text = xml_root.findtext('Storage/SSLCertVerify') if text: @@ -120,7 +116,22 @@ def _ssl_cert_verify(self, xml_root): msg = _("SSLCertVerify configured error.") LOG.error(msg) raise exception.InvalidInput(reason=msg) + return value + + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.conf, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.conf, 'ssl_cert_path', None) + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) setattr(self.conf, 'ssl_cert_verify', value) def _san_address(self, xml_root): @@ -468,6 +479,10 @@ def get_hypermetro_devices(self): dev_config['metro_sync_completed'] = ( dev['metro_sync_completed'] if 'metro_sync_completed' in dev else "True") + dev_config['in_band_or_not'] = ( + dev['in_band_or_not'].lower() == 'true' + if 'in_band_or_not' in dev else False) + dev_config['storage_sn'] = dev.get('storage_sn') devs_config.append(dev_config) return devs_config @@ -494,6 +509,10 @@ def get_replication_devices(self): dev['iscsi_default_target_ip'].split(';') if 'iscsi_default_target_ip' in dev else []) + dev_config['in_band_or_not'] = ( + dev['in_band_or_not'].lower() == 'true' + if 'in_band_or_not' in dev else False) + dev_config['storage_sn'] = dev.get('storage_sn') devs_config.append(dev_config) return devs_config @@ -509,6 +528,8 @@ def get_local_device(self): 'iscsi_info': self.conf.iscsi_info, 'fc_info': self.conf.fc_info, 'iscsi_default_target_ip': self.conf.iscsi_default_target_ip, + 'in_band_or_not': self.conf.in_band_or_not, + 'storage_sn': self.conf.storage_sn, } return dev_config @@ -611,6 +632,25 @@ def _get_local_minimum_fc_initiator(self, xml_root): raise exception.InvalidInput(reason=msg) setattr(self.conf, 'min_fc_ini_online', minimum_fc_initiator) + def _get_local_in_band_or_not(self, xml_root): + in_band_or_not = False + text = xml_root.findtext('Storage/InBandOrNot') + if text: + if text.lower() in ('true', 'false'): + in_band_or_not = text.lower() == 'true' + else: + msg = _("InBandOrNot configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + + setattr(self.conf, 'in_band_or_not', in_band_or_not) + + def _get_local_storage_sn(self, xml_root): + text = xml_root.findtext('Storage/Storagesn') + storage_sn = text.strip() if text else None + + setattr(self.conf, 'storage_sn', storage_sn) + def _rollback_speed(self, xml_root): text = xml_root.findtext('LUN/SnapshotRollbackSpeed') if text and text.strip() not in constants.SNAPSHOT_ROLLBACK_SPEED_TYPES: diff --git a/Cinder/Mitaka/rest_client.py b/Cinder/Mitaka/rest_client.py index 590d702..93a44ab 100644 --- a/Cinder/Mitaka/rest_client.py +++ b/Cinder/Mitaka/rest_client.py @@ -70,8 +70,18 @@ def __init__(self, configuration, san_address, san_user, san_password, self.url = None self.ssl_cert_verify = self.configuration.ssl_cert_verify self.ssl_cert_path = self.configuration.ssl_cert_path + self.in_band_or_not = kwargs.get('in_band_or_not', + self.configuration.in_band_or_not) + self.storage_sn = kwargs.get('storage_sn', + self.configuration.storage_sn) self.is_dorado_v6 = False + if self.in_band_or_not and not self.storage_sn: + msg = _("'Storagesn' is must be set if 'InBandOrNot' is True," + " Please Check Your config") + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) + if not self.ssl_cert_verify and hasattr(requests, 'packages'): LOG.warning("Suppressing requests library SSL Warnings") requests.packages.urllib3.disable_warnings( @@ -82,13 +92,14 @@ def __init__(self, configuration, san_address, san_user, san_password, def init_http_head(self): self.url = None self.session = requests.Session() - self.session.headers.update({ + session_headers = { "Connection": "keep-alive", - "Content-Type": "application/json"}) - self.session.verify = False + "Content-Type": "application/json"} + if self.in_band_or_not: + session_headers["IBA-Target-Array"] = self.storage_sn + self.session.headers.update(session_headers) - if self.ssl_cert_verify: - self.session.verify = self.ssl_cert_path + self.session.verify = self.ssl_cert_path if self.ssl_cert_verify else False def do_call(self, url=None, data=None, method=None, calltimeout=constants.SOCKET_TIMEOUT, filter_flag=False): diff --git a/Cinder/Newton/huawei_conf.py b/Cinder/Newton/huawei_conf.py index 38a6c17..394c88c 100644 --- a/Cinder/Newton/huawei_conf.py +++ b/Cinder/Newton/huawei_conf.py @@ -95,6 +95,8 @@ def update_config_value(self): self._replication_pair_sync_speed, self._get_local_minimum_fc_initiator, self._hyper_enforce_multipath, + self._get_local_in_band_or_not, + self._get_local_storage_sn, self._rollback_speed) tree = ET.parse(self.conf.cinder_huawei_conf_file, @@ -103,14 +105,8 @@ def update_config_value(self): for f in set_attr_funcs: f(xml_root) - def _ssl_cert_path(self, xml_root): - text = xml_root.findtext('Storage/SSLCertPath') - if text: - setattr(self.conf, 'ssl_cert_path', text) - else: - setattr(self.conf, 'ssl_cert_path', None) - - def _ssl_cert_verify(self, xml_root): + @staticmethod + def _get_ssl_verify(xml_root): value = False text = xml_root.findtext('Storage/SSLCertVerify') if text: @@ -120,7 +116,22 @@ def _ssl_cert_verify(self, xml_root): msg = _("SSLCertVerify configured error.") LOG.error(msg) raise exception.InvalidInput(reason=msg) + return value + + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.conf, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.conf, 'ssl_cert_path', None) + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) setattr(self.conf, 'ssl_cert_verify', value) def _san_address(self, xml_root): @@ -468,6 +479,10 @@ def get_hypermetro_devices(self): dev_config['metro_sync_completed'] = ( dev['metro_sync_completed'] if 'metro_sync_completed' in dev else "True") + dev_config['in_band_or_not'] = ( + dev['in_band_or_not'].lower() == 'true' + if 'in_band_or_not' in dev else False) + dev_config['storage_sn'] = dev.get('storage_sn') devs_config.append(dev_config) return devs_config @@ -494,6 +509,10 @@ def get_replication_devices(self): dev['iscsi_default_target_ip'].split(';') if 'iscsi_default_target_ip' in dev else []) + dev_config['in_band_or_not'] = ( + dev['in_band_or_not'].lower() == 'true' + if 'in_band_or_not' in dev else False) + dev_config['storage_sn'] = dev.get('storage_sn') devs_config.append(dev_config) return devs_config @@ -509,6 +528,8 @@ def get_local_device(self): 'iscsi_info': self.conf.iscsi_info, 'fc_info': self.conf.fc_info, 'iscsi_default_target_ip': self.conf.iscsi_default_target_ip, + 'in_band_or_not': self.conf.in_band_or_not, + 'storage_sn': self.conf.storage_sn, } return dev_config @@ -611,6 +632,25 @@ def _get_local_minimum_fc_initiator(self, xml_root): raise exception.InvalidInput(reason=msg) setattr(self.conf, 'min_fc_ini_online', minimum_fc_initiator) + def _get_local_in_band_or_not(self, xml_root): + in_band_or_not = False + text = xml_root.findtext('Storage/InBandOrNot') + if text: + if text.lower() in ('true', 'false'): + in_band_or_not = text.lower() == 'true' + else: + msg = _("InBandOrNot configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + + setattr(self.conf, 'in_band_or_not', in_band_or_not) + + def _get_local_storage_sn(self, xml_root): + text = xml_root.findtext('Storage/Storagesn') + storage_sn = text.strip() if text else None + + setattr(self.conf, 'storage_sn', storage_sn) + def _rollback_speed(self, xml_root): text = xml_root.findtext('LUN/SnapshotRollbackSpeed') if text and text.strip() not in constants.SNAPSHOT_ROLLBACK_SPEED_TYPES: diff --git a/Cinder/Newton/rest_client.py b/Cinder/Newton/rest_client.py index 590d702..93a44ab 100644 --- a/Cinder/Newton/rest_client.py +++ b/Cinder/Newton/rest_client.py @@ -70,8 +70,18 @@ def __init__(self, configuration, san_address, san_user, san_password, self.url = None self.ssl_cert_verify = self.configuration.ssl_cert_verify self.ssl_cert_path = self.configuration.ssl_cert_path + self.in_band_or_not = kwargs.get('in_band_or_not', + self.configuration.in_band_or_not) + self.storage_sn = kwargs.get('storage_sn', + self.configuration.storage_sn) self.is_dorado_v6 = False + if self.in_band_or_not and not self.storage_sn: + msg = _("'Storagesn' is must be set if 'InBandOrNot' is True," + " Please Check Your config") + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) + if not self.ssl_cert_verify and hasattr(requests, 'packages'): LOG.warning("Suppressing requests library SSL Warnings") requests.packages.urllib3.disable_warnings( @@ -82,13 +92,14 @@ def __init__(self, configuration, san_address, san_user, san_password, def init_http_head(self): self.url = None self.session = requests.Session() - self.session.headers.update({ + session_headers = { "Connection": "keep-alive", - "Content-Type": "application/json"}) - self.session.verify = False + "Content-Type": "application/json"} + if self.in_band_or_not: + session_headers["IBA-Target-Array"] = self.storage_sn + self.session.headers.update(session_headers) - if self.ssl_cert_verify: - self.session.verify = self.ssl_cert_path + self.session.verify = self.ssl_cert_path if self.ssl_cert_verify else False def do_call(self, url=None, data=None, method=None, calltimeout=constants.SOCKET_TIMEOUT, filter_flag=False): diff --git a/Cinder/Ocata/huawei_conf.py b/Cinder/Ocata/huawei_conf.py index 38a6c17..394c88c 100644 --- a/Cinder/Ocata/huawei_conf.py +++ b/Cinder/Ocata/huawei_conf.py @@ -95,6 +95,8 @@ def update_config_value(self): self._replication_pair_sync_speed, self._get_local_minimum_fc_initiator, self._hyper_enforce_multipath, + self._get_local_in_band_or_not, + self._get_local_storage_sn, self._rollback_speed) tree = ET.parse(self.conf.cinder_huawei_conf_file, @@ -103,14 +105,8 @@ def update_config_value(self): for f in set_attr_funcs: f(xml_root) - def _ssl_cert_path(self, xml_root): - text = xml_root.findtext('Storage/SSLCertPath') - if text: - setattr(self.conf, 'ssl_cert_path', text) - else: - setattr(self.conf, 'ssl_cert_path', None) - - def _ssl_cert_verify(self, xml_root): + @staticmethod + def _get_ssl_verify(xml_root): value = False text = xml_root.findtext('Storage/SSLCertVerify') if text: @@ -120,7 +116,22 @@ def _ssl_cert_verify(self, xml_root): msg = _("SSLCertVerify configured error.") LOG.error(msg) raise exception.InvalidInput(reason=msg) + return value + + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.conf, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.conf, 'ssl_cert_path', None) + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) setattr(self.conf, 'ssl_cert_verify', value) def _san_address(self, xml_root): @@ -468,6 +479,10 @@ def get_hypermetro_devices(self): dev_config['metro_sync_completed'] = ( dev['metro_sync_completed'] if 'metro_sync_completed' in dev else "True") + dev_config['in_band_or_not'] = ( + dev['in_band_or_not'].lower() == 'true' + if 'in_band_or_not' in dev else False) + dev_config['storage_sn'] = dev.get('storage_sn') devs_config.append(dev_config) return devs_config @@ -494,6 +509,10 @@ def get_replication_devices(self): dev['iscsi_default_target_ip'].split(';') if 'iscsi_default_target_ip' in dev else []) + dev_config['in_band_or_not'] = ( + dev['in_band_or_not'].lower() == 'true' + if 'in_band_or_not' in dev else False) + dev_config['storage_sn'] = dev.get('storage_sn') devs_config.append(dev_config) return devs_config @@ -509,6 +528,8 @@ def get_local_device(self): 'iscsi_info': self.conf.iscsi_info, 'fc_info': self.conf.fc_info, 'iscsi_default_target_ip': self.conf.iscsi_default_target_ip, + 'in_band_or_not': self.conf.in_band_or_not, + 'storage_sn': self.conf.storage_sn, } return dev_config @@ -611,6 +632,25 @@ def _get_local_minimum_fc_initiator(self, xml_root): raise exception.InvalidInput(reason=msg) setattr(self.conf, 'min_fc_ini_online', minimum_fc_initiator) + def _get_local_in_band_or_not(self, xml_root): + in_band_or_not = False + text = xml_root.findtext('Storage/InBandOrNot') + if text: + if text.lower() in ('true', 'false'): + in_band_or_not = text.lower() == 'true' + else: + msg = _("InBandOrNot configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + + setattr(self.conf, 'in_band_or_not', in_band_or_not) + + def _get_local_storage_sn(self, xml_root): + text = xml_root.findtext('Storage/Storagesn') + storage_sn = text.strip() if text else None + + setattr(self.conf, 'storage_sn', storage_sn) + def _rollback_speed(self, xml_root): text = xml_root.findtext('LUN/SnapshotRollbackSpeed') if text and text.strip() not in constants.SNAPSHOT_ROLLBACK_SPEED_TYPES: diff --git a/Cinder/Ocata/rest_client.py b/Cinder/Ocata/rest_client.py index 590d702..93a44ab 100644 --- a/Cinder/Ocata/rest_client.py +++ b/Cinder/Ocata/rest_client.py @@ -70,8 +70,18 @@ def __init__(self, configuration, san_address, san_user, san_password, self.url = None self.ssl_cert_verify = self.configuration.ssl_cert_verify self.ssl_cert_path = self.configuration.ssl_cert_path + self.in_band_or_not = kwargs.get('in_band_or_not', + self.configuration.in_band_or_not) + self.storage_sn = kwargs.get('storage_sn', + self.configuration.storage_sn) self.is_dorado_v6 = False + if self.in_band_or_not and not self.storage_sn: + msg = _("'Storagesn' is must be set if 'InBandOrNot' is True," + " Please Check Your config") + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) + if not self.ssl_cert_verify and hasattr(requests, 'packages'): LOG.warning("Suppressing requests library SSL Warnings") requests.packages.urllib3.disable_warnings( @@ -82,13 +92,14 @@ def __init__(self, configuration, san_address, san_user, san_password, def init_http_head(self): self.url = None self.session = requests.Session() - self.session.headers.update({ + session_headers = { "Connection": "keep-alive", - "Content-Type": "application/json"}) - self.session.verify = False + "Content-Type": "application/json"} + if self.in_band_or_not: + session_headers["IBA-Target-Array"] = self.storage_sn + self.session.headers.update(session_headers) - if self.ssl_cert_verify: - self.session.verify = self.ssl_cert_path + self.session.verify = self.ssl_cert_path if self.ssl_cert_verify else False def do_call(self, url=None, data=None, method=None, calltimeout=constants.SOCKET_TIMEOUT, filter_flag=False): diff --git a/Cinder/Pike/huawei_conf.py b/Cinder/Pike/huawei_conf.py index 38a6c17..394c88c 100644 --- a/Cinder/Pike/huawei_conf.py +++ b/Cinder/Pike/huawei_conf.py @@ -95,6 +95,8 @@ def update_config_value(self): self._replication_pair_sync_speed, self._get_local_minimum_fc_initiator, self._hyper_enforce_multipath, + self._get_local_in_band_or_not, + self._get_local_storage_sn, self._rollback_speed) tree = ET.parse(self.conf.cinder_huawei_conf_file, @@ -103,14 +105,8 @@ def update_config_value(self): for f in set_attr_funcs: f(xml_root) - def _ssl_cert_path(self, xml_root): - text = xml_root.findtext('Storage/SSLCertPath') - if text: - setattr(self.conf, 'ssl_cert_path', text) - else: - setattr(self.conf, 'ssl_cert_path', None) - - def _ssl_cert_verify(self, xml_root): + @staticmethod + def _get_ssl_verify(xml_root): value = False text = xml_root.findtext('Storage/SSLCertVerify') if text: @@ -120,7 +116,22 @@ def _ssl_cert_verify(self, xml_root): msg = _("SSLCertVerify configured error.") LOG.error(msg) raise exception.InvalidInput(reason=msg) + return value + + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.conf, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.conf, 'ssl_cert_path', None) + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) setattr(self.conf, 'ssl_cert_verify', value) def _san_address(self, xml_root): @@ -468,6 +479,10 @@ def get_hypermetro_devices(self): dev_config['metro_sync_completed'] = ( dev['metro_sync_completed'] if 'metro_sync_completed' in dev else "True") + dev_config['in_band_or_not'] = ( + dev['in_band_or_not'].lower() == 'true' + if 'in_band_or_not' in dev else False) + dev_config['storage_sn'] = dev.get('storage_sn') devs_config.append(dev_config) return devs_config @@ -494,6 +509,10 @@ def get_replication_devices(self): dev['iscsi_default_target_ip'].split(';') if 'iscsi_default_target_ip' in dev else []) + dev_config['in_band_or_not'] = ( + dev['in_band_or_not'].lower() == 'true' + if 'in_band_or_not' in dev else False) + dev_config['storage_sn'] = dev.get('storage_sn') devs_config.append(dev_config) return devs_config @@ -509,6 +528,8 @@ def get_local_device(self): 'iscsi_info': self.conf.iscsi_info, 'fc_info': self.conf.fc_info, 'iscsi_default_target_ip': self.conf.iscsi_default_target_ip, + 'in_band_or_not': self.conf.in_band_or_not, + 'storage_sn': self.conf.storage_sn, } return dev_config @@ -611,6 +632,25 @@ def _get_local_minimum_fc_initiator(self, xml_root): raise exception.InvalidInput(reason=msg) setattr(self.conf, 'min_fc_ini_online', minimum_fc_initiator) + def _get_local_in_band_or_not(self, xml_root): + in_band_or_not = False + text = xml_root.findtext('Storage/InBandOrNot') + if text: + if text.lower() in ('true', 'false'): + in_band_or_not = text.lower() == 'true' + else: + msg = _("InBandOrNot configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + + setattr(self.conf, 'in_band_or_not', in_band_or_not) + + def _get_local_storage_sn(self, xml_root): + text = xml_root.findtext('Storage/Storagesn') + storage_sn = text.strip() if text else None + + setattr(self.conf, 'storage_sn', storage_sn) + def _rollback_speed(self, xml_root): text = xml_root.findtext('LUN/SnapshotRollbackSpeed') if text and text.strip() not in constants.SNAPSHOT_ROLLBACK_SPEED_TYPES: diff --git a/Cinder/Pike/rest_client.py b/Cinder/Pike/rest_client.py index 590d702..93a44ab 100644 --- a/Cinder/Pike/rest_client.py +++ b/Cinder/Pike/rest_client.py @@ -70,8 +70,18 @@ def __init__(self, configuration, san_address, san_user, san_password, self.url = None self.ssl_cert_verify = self.configuration.ssl_cert_verify self.ssl_cert_path = self.configuration.ssl_cert_path + self.in_band_or_not = kwargs.get('in_band_or_not', + self.configuration.in_band_or_not) + self.storage_sn = kwargs.get('storage_sn', + self.configuration.storage_sn) self.is_dorado_v6 = False + if self.in_band_or_not and not self.storage_sn: + msg = _("'Storagesn' is must be set if 'InBandOrNot' is True," + " Please Check Your config") + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) + if not self.ssl_cert_verify and hasattr(requests, 'packages'): LOG.warning("Suppressing requests library SSL Warnings") requests.packages.urllib3.disable_warnings( @@ -82,13 +92,14 @@ def __init__(self, configuration, san_address, san_user, san_password, def init_http_head(self): self.url = None self.session = requests.Session() - self.session.headers.update({ + session_headers = { "Connection": "keep-alive", - "Content-Type": "application/json"}) - self.session.verify = False + "Content-Type": "application/json"} + if self.in_band_or_not: + session_headers["IBA-Target-Array"] = self.storage_sn + self.session.headers.update(session_headers) - if self.ssl_cert_verify: - self.session.verify = self.ssl_cert_path + self.session.verify = self.ssl_cert_path if self.ssl_cert_verify else False def do_call(self, url=None, data=None, method=None, calltimeout=constants.SOCKET_TIMEOUT, filter_flag=False): diff --git a/Cinder/Queens/huawei_conf.py b/Cinder/Queens/huawei_conf.py index 38a6c17..394c88c 100644 --- a/Cinder/Queens/huawei_conf.py +++ b/Cinder/Queens/huawei_conf.py @@ -95,6 +95,8 @@ def update_config_value(self): self._replication_pair_sync_speed, self._get_local_minimum_fc_initiator, self._hyper_enforce_multipath, + self._get_local_in_band_or_not, + self._get_local_storage_sn, self._rollback_speed) tree = ET.parse(self.conf.cinder_huawei_conf_file, @@ -103,14 +105,8 @@ def update_config_value(self): for f in set_attr_funcs: f(xml_root) - def _ssl_cert_path(self, xml_root): - text = xml_root.findtext('Storage/SSLCertPath') - if text: - setattr(self.conf, 'ssl_cert_path', text) - else: - setattr(self.conf, 'ssl_cert_path', None) - - def _ssl_cert_verify(self, xml_root): + @staticmethod + def _get_ssl_verify(xml_root): value = False text = xml_root.findtext('Storage/SSLCertVerify') if text: @@ -120,7 +116,22 @@ def _ssl_cert_verify(self, xml_root): msg = _("SSLCertVerify configured error.") LOG.error(msg) raise exception.InvalidInput(reason=msg) + return value + + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.conf, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.conf, 'ssl_cert_path', None) + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) setattr(self.conf, 'ssl_cert_verify', value) def _san_address(self, xml_root): @@ -468,6 +479,10 @@ def get_hypermetro_devices(self): dev_config['metro_sync_completed'] = ( dev['metro_sync_completed'] if 'metro_sync_completed' in dev else "True") + dev_config['in_band_or_not'] = ( + dev['in_band_or_not'].lower() == 'true' + if 'in_band_or_not' in dev else False) + dev_config['storage_sn'] = dev.get('storage_sn') devs_config.append(dev_config) return devs_config @@ -494,6 +509,10 @@ def get_replication_devices(self): dev['iscsi_default_target_ip'].split(';') if 'iscsi_default_target_ip' in dev else []) + dev_config['in_band_or_not'] = ( + dev['in_band_or_not'].lower() == 'true' + if 'in_band_or_not' in dev else False) + dev_config['storage_sn'] = dev.get('storage_sn') devs_config.append(dev_config) return devs_config @@ -509,6 +528,8 @@ def get_local_device(self): 'iscsi_info': self.conf.iscsi_info, 'fc_info': self.conf.fc_info, 'iscsi_default_target_ip': self.conf.iscsi_default_target_ip, + 'in_band_or_not': self.conf.in_band_or_not, + 'storage_sn': self.conf.storage_sn, } return dev_config @@ -611,6 +632,25 @@ def _get_local_minimum_fc_initiator(self, xml_root): raise exception.InvalidInput(reason=msg) setattr(self.conf, 'min_fc_ini_online', minimum_fc_initiator) + def _get_local_in_band_or_not(self, xml_root): + in_band_or_not = False + text = xml_root.findtext('Storage/InBandOrNot') + if text: + if text.lower() in ('true', 'false'): + in_band_or_not = text.lower() == 'true' + else: + msg = _("InBandOrNot configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + + setattr(self.conf, 'in_band_or_not', in_band_or_not) + + def _get_local_storage_sn(self, xml_root): + text = xml_root.findtext('Storage/Storagesn') + storage_sn = text.strip() if text else None + + setattr(self.conf, 'storage_sn', storage_sn) + def _rollback_speed(self, xml_root): text = xml_root.findtext('LUN/SnapshotRollbackSpeed') if text and text.strip() not in constants.SNAPSHOT_ROLLBACK_SPEED_TYPES: diff --git a/Cinder/Queens/rest_client.py b/Cinder/Queens/rest_client.py index 590d702..93a44ab 100644 --- a/Cinder/Queens/rest_client.py +++ b/Cinder/Queens/rest_client.py @@ -70,8 +70,18 @@ def __init__(self, configuration, san_address, san_user, san_password, self.url = None self.ssl_cert_verify = self.configuration.ssl_cert_verify self.ssl_cert_path = self.configuration.ssl_cert_path + self.in_band_or_not = kwargs.get('in_band_or_not', + self.configuration.in_band_or_not) + self.storage_sn = kwargs.get('storage_sn', + self.configuration.storage_sn) self.is_dorado_v6 = False + if self.in_band_or_not and not self.storage_sn: + msg = _("'Storagesn' is must be set if 'InBandOrNot' is True," + " Please Check Your config") + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) + if not self.ssl_cert_verify and hasattr(requests, 'packages'): LOG.warning("Suppressing requests library SSL Warnings") requests.packages.urllib3.disable_warnings( @@ -82,13 +92,14 @@ def __init__(self, configuration, san_address, san_user, san_password, def init_http_head(self): self.url = None self.session = requests.Session() - self.session.headers.update({ + session_headers = { "Connection": "keep-alive", - "Content-Type": "application/json"}) - self.session.verify = False + "Content-Type": "application/json"} + if self.in_band_or_not: + session_headers["IBA-Target-Array"] = self.storage_sn + self.session.headers.update(session_headers) - if self.ssl_cert_verify: - self.session.verify = self.ssl_cert_path + self.session.verify = self.ssl_cert_path if self.ssl_cert_verify else False def do_call(self, url=None, data=None, method=None, calltimeout=constants.SOCKET_TIMEOUT, filter_flag=False): diff --git a/Cinder/Rocky/huawei_base_driver.py b/Cinder/Rocky/huawei_base_driver.py index 3f12532..0e7ecaf 100644 --- a/Cinder/Rocky/huawei_base_driver.py +++ b/Cinder/Rocky/huawei_base_driver.py @@ -78,15 +78,17 @@ def __init__(self, *args, **kwargs): def do_setup(self, context): self.conf.update_config_value() - self.local_cli = rest_client.RestClient( - self.configuration.san_address, - self.configuration.san_user, - self.configuration.san_password, - self.configuration.vstore_name, - self.configuration.ssl_cert_verify, - self.configuration.ssl_cert_path, - self.configuration.in_band_or_not, - self.configuration.storage_sn) + config_dict = { + 'san_address': self.configuration.san_address, + 'san_user': self.configuration.san_user, + 'san_password': self.configuration.san_password, + 'vstore_name': self.configuration.vstore_name, + 'ssl_cert_verify': self.configuration.ssl_cert_verify, + 'ssl_cert_path': self.configuration.ssl_cert_path, + 'in_band_or_not': self.configuration.in_band_or_not, + 'storage_sn': self.configuration.storage_sn + } + self.local_cli = rest_client.RestClient(config_dict) self.local_cli.login() self.configuration.is_dorado_v6 = huawei_utils.is_support_clone_pair( self.local_cli) @@ -96,24 +98,12 @@ def do_setup(self, context): if self.configuration.hypermetro: self.hypermetro_rmt_cli = rest_client.RestClient( - self.configuration.hypermetro['san_address'], - self.configuration.hypermetro['san_user'], - self.configuration.hypermetro['san_password'], - self.configuration.hypermetro['vstore_name'], - self.configuration.hypermetro['in_band_or_not'], - self.configuration.hypermetro['storage_sn'], - ) + self.configuration.hypermetro) self.hypermetro_rmt_cli.login() if self.configuration.replication: self.replication_rmt_cli = rest_client.RestClient( - self.configuration.replication['san_address'], - self.configuration.replication['san_user'], - self.configuration.replication['san_password'], - self.configuration.replication['vstore_name'], - self.configuration.replication['in_band_or_not'], - self.configuration.replication['storage_sn'], - ) + self.configuration.replication) self.replication_rmt_cli.login() def check_for_setup_error(self): diff --git a/Cinder/Rocky/huawei_conf.py b/Cinder/Rocky/huawei_conf.py index aa04ed7..d4ed034 100644 --- a/Cinder/Rocky/huawei_conf.py +++ b/Cinder/Rocky/huawei_conf.py @@ -145,21 +145,36 @@ def _san_vstore(self, xml_root): vstore = base64.b64decode(six.b(text[4:])).decode() setattr(self.conf, 'vstore_name', vstore) - def _ssl_cert_path(self, xml_root): - text = xml_root.findtext('Storage/SSLCertPath') - setattr(self.conf, 'ssl_cert_path', text) + @staticmethod + def _parser_ssl_value(ssl_value): + if ssl_value.lower() in ('true', 'false'): + return ssl_value.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) - def _ssl_cert_verify(self, xml_root): + def _get_ssl_verify(self, xml_root): value = False text = xml_root.findtext('Storage/SSLCertVerify') if text: - if text.lower() in ('true', 'false'): - value = text.lower() == 'true' - else: - msg = _("SSLCertVerify configured error.") - LOG.error(msg) - raise exception.InvalidInput(reason=msg) + value = self._parser_ssl_value(text) + return value + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.conf, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.conf, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) setattr(self.conf, 'ssl_cert_verify', value) def _set_extra_constants_by_product(self, product): @@ -382,16 +397,29 @@ def _parse_remote_initiator_info(self, dev, ini_type): self._check_hostname_regex_config(ini_info) return ini_info + def _check_ssl_valid(self, dev): + ssl_cert_verify = dev.get('ssl_cert_verify', 'false') + ssl_verify = self._parser_ssl_value(ssl_cert_verify) + ssl_cert_path = dev.get('ssl_cert_path') + if not ssl_cert_path and ssl_verify: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return ssl_verify + def _hypermetro_devices(self, xml_root): dev = self.conf.safe_get('hypermetro_device') config = {} if dev: + ssl_verify = self._check_ssl_valid(dev) config = { 'san_address': dev['san_address'].split(';'), 'san_user': dev['san_user'], 'san_password': dev['san_password'], 'vstore_name': dev.get('vstore_name'), + 'ssl_cert_verify': ssl_verify, + 'ssl_cert_path': dev.get('ssl_cert_path'), 'metro_domain': dev['metro_domain'], 'storage_pools': dev['storage_pool'].split(';')[:1], 'iscsi_info': self._parse_remote_initiator_info( @@ -414,12 +442,15 @@ def _replication_devices(self, xml_root): if replication_devs: dev = replication_devs[0] + ssl_verify = self._check_ssl_valid(dev) config = { 'backend_id': dev['backend_id'], 'san_address': dev['san_address'].split(';'), 'san_user': dev['san_user'], 'san_password': dev['san_password'], 'vstore_name': dev.get('vstore_name'), + 'ssl_cert_verify': ssl_verify, + 'ssl_cert_path': dev.get('ssl_cert_path'), 'storage_pools': dev['storage_pool'].split(';')[:1], 'iscsi_info': self._parse_remote_initiator_info( dev, 'iscsi_info'), diff --git a/Cinder/Rocky/rest_client.py b/Cinder/Rocky/rest_client.py index 3555e6c..9d5c923 100644 --- a/Cinder/Rocky/rest_client.py +++ b/Cinder/Rocky/rest_client.py @@ -1459,16 +1459,15 @@ def wrapped(self, url, **kwargs): class RestClient(object): - def __init__(self, address, user, password, vstore=None, ssl_verify=None, - cert_path=None, in_band_or_not=None, storage_sn=None): - self.san_address = address - self.san_user = user - self.san_password = password - self.vstore_name = vstore - self.ssl_verify = ssl_verify - self.cert_path = cert_path - self.in_band_or_not = in_band_or_not - self.storage_sn = storage_sn + def __init__(self, config_dict): + self.san_address = config_dict.get('san_address') + self.san_user = config_dict.get('san_user') + self.san_password = config_dict.get('san_password') + self.vstore_name = config_dict.get('vstore_name') + self.ssl_verify = config_dict.get('ssl_cert_verify') + self.cert_path = config_dict.get('ssl_cert_path') + self.in_band_or_not = config_dict.get('in_band_or_not') + self.storage_sn = config_dict.get('storage_sn') self._login_url = None self._login_device_id = None @@ -1476,12 +1475,11 @@ def __init__(self, address, user, password, vstore=None, ssl_verify=None, self._session = None self._init_object_methods() - if self.in_band_or_not: - if not self.storage_sn: - msg = _("please check 'InBandOrNot' and 'Storagesn' " - "they are invaid.") - LOG.error(msg) - raise exception.VolumeBackendAPIException(data=msg) + if self.in_band_or_not and not self.storage_sn: + msg = _("please check 'InBandOrNot' and 'Storagesn' " + "they are invaid.") + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) if not self.ssl_verify and hasattr(requests, 'packages'): LOG.warning("Suppressing requests library SSL Warnings") @@ -1560,9 +1558,7 @@ def _init_http_head(self): def _loop_login(self): self._init_http_head() - self._session.verify = False - if self.ssl_verify: - self._session.verify = self.cert_path + self._session.verify = self.cert_path if self.ssl_verify else False for url in self.san_address: try: diff --git a/Cinder/Stein/huawei_base_driver.py b/Cinder/Stein/huawei_base_driver.py index 3f12532..0e7ecaf 100644 --- a/Cinder/Stein/huawei_base_driver.py +++ b/Cinder/Stein/huawei_base_driver.py @@ -78,15 +78,17 @@ def __init__(self, *args, **kwargs): def do_setup(self, context): self.conf.update_config_value() - self.local_cli = rest_client.RestClient( - self.configuration.san_address, - self.configuration.san_user, - self.configuration.san_password, - self.configuration.vstore_name, - self.configuration.ssl_cert_verify, - self.configuration.ssl_cert_path, - self.configuration.in_band_or_not, - self.configuration.storage_sn) + config_dict = { + 'san_address': self.configuration.san_address, + 'san_user': self.configuration.san_user, + 'san_password': self.configuration.san_password, + 'vstore_name': self.configuration.vstore_name, + 'ssl_cert_verify': self.configuration.ssl_cert_verify, + 'ssl_cert_path': self.configuration.ssl_cert_path, + 'in_band_or_not': self.configuration.in_band_or_not, + 'storage_sn': self.configuration.storage_sn + } + self.local_cli = rest_client.RestClient(config_dict) self.local_cli.login() self.configuration.is_dorado_v6 = huawei_utils.is_support_clone_pair( self.local_cli) @@ -96,24 +98,12 @@ def do_setup(self, context): if self.configuration.hypermetro: self.hypermetro_rmt_cli = rest_client.RestClient( - self.configuration.hypermetro['san_address'], - self.configuration.hypermetro['san_user'], - self.configuration.hypermetro['san_password'], - self.configuration.hypermetro['vstore_name'], - self.configuration.hypermetro['in_band_or_not'], - self.configuration.hypermetro['storage_sn'], - ) + self.configuration.hypermetro) self.hypermetro_rmt_cli.login() if self.configuration.replication: self.replication_rmt_cli = rest_client.RestClient( - self.configuration.replication['san_address'], - self.configuration.replication['san_user'], - self.configuration.replication['san_password'], - self.configuration.replication['vstore_name'], - self.configuration.replication['in_band_or_not'], - self.configuration.replication['storage_sn'], - ) + self.configuration.replication) self.replication_rmt_cli.login() def check_for_setup_error(self): diff --git a/Cinder/Stein/huawei_conf.py b/Cinder/Stein/huawei_conf.py index aa04ed7..d4ed034 100644 --- a/Cinder/Stein/huawei_conf.py +++ b/Cinder/Stein/huawei_conf.py @@ -145,21 +145,36 @@ def _san_vstore(self, xml_root): vstore = base64.b64decode(six.b(text[4:])).decode() setattr(self.conf, 'vstore_name', vstore) - def _ssl_cert_path(self, xml_root): - text = xml_root.findtext('Storage/SSLCertPath') - setattr(self.conf, 'ssl_cert_path', text) + @staticmethod + def _parser_ssl_value(ssl_value): + if ssl_value.lower() in ('true', 'false'): + return ssl_value.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) - def _ssl_cert_verify(self, xml_root): + def _get_ssl_verify(self, xml_root): value = False text = xml_root.findtext('Storage/SSLCertVerify') if text: - if text.lower() in ('true', 'false'): - value = text.lower() == 'true' - else: - msg = _("SSLCertVerify configured error.") - LOG.error(msg) - raise exception.InvalidInput(reason=msg) + value = self._parser_ssl_value(text) + return value + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.conf, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.conf, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) setattr(self.conf, 'ssl_cert_verify', value) def _set_extra_constants_by_product(self, product): @@ -382,16 +397,29 @@ def _parse_remote_initiator_info(self, dev, ini_type): self._check_hostname_regex_config(ini_info) return ini_info + def _check_ssl_valid(self, dev): + ssl_cert_verify = dev.get('ssl_cert_verify', 'false') + ssl_verify = self._parser_ssl_value(ssl_cert_verify) + ssl_cert_path = dev.get('ssl_cert_path') + if not ssl_cert_path and ssl_verify: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return ssl_verify + def _hypermetro_devices(self, xml_root): dev = self.conf.safe_get('hypermetro_device') config = {} if dev: + ssl_verify = self._check_ssl_valid(dev) config = { 'san_address': dev['san_address'].split(';'), 'san_user': dev['san_user'], 'san_password': dev['san_password'], 'vstore_name': dev.get('vstore_name'), + 'ssl_cert_verify': ssl_verify, + 'ssl_cert_path': dev.get('ssl_cert_path'), 'metro_domain': dev['metro_domain'], 'storage_pools': dev['storage_pool'].split(';')[:1], 'iscsi_info': self._parse_remote_initiator_info( @@ -414,12 +442,15 @@ def _replication_devices(self, xml_root): if replication_devs: dev = replication_devs[0] + ssl_verify = self._check_ssl_valid(dev) config = { 'backend_id': dev['backend_id'], 'san_address': dev['san_address'].split(';'), 'san_user': dev['san_user'], 'san_password': dev['san_password'], 'vstore_name': dev.get('vstore_name'), + 'ssl_cert_verify': ssl_verify, + 'ssl_cert_path': dev.get('ssl_cert_path'), 'storage_pools': dev['storage_pool'].split(';')[:1], 'iscsi_info': self._parse_remote_initiator_info( dev, 'iscsi_info'), diff --git a/Cinder/Stein/rest_client.py b/Cinder/Stein/rest_client.py index 3555e6c..9d5c923 100644 --- a/Cinder/Stein/rest_client.py +++ b/Cinder/Stein/rest_client.py @@ -1459,16 +1459,15 @@ def wrapped(self, url, **kwargs): class RestClient(object): - def __init__(self, address, user, password, vstore=None, ssl_verify=None, - cert_path=None, in_band_or_not=None, storage_sn=None): - self.san_address = address - self.san_user = user - self.san_password = password - self.vstore_name = vstore - self.ssl_verify = ssl_verify - self.cert_path = cert_path - self.in_band_or_not = in_band_or_not - self.storage_sn = storage_sn + def __init__(self, config_dict): + self.san_address = config_dict.get('san_address') + self.san_user = config_dict.get('san_user') + self.san_password = config_dict.get('san_password') + self.vstore_name = config_dict.get('vstore_name') + self.ssl_verify = config_dict.get('ssl_cert_verify') + self.cert_path = config_dict.get('ssl_cert_path') + self.in_band_or_not = config_dict.get('in_band_or_not') + self.storage_sn = config_dict.get('storage_sn') self._login_url = None self._login_device_id = None @@ -1476,12 +1475,11 @@ def __init__(self, address, user, password, vstore=None, ssl_verify=None, self._session = None self._init_object_methods() - if self.in_band_or_not: - if not self.storage_sn: - msg = _("please check 'InBandOrNot' and 'Storagesn' " - "they are invaid.") - LOG.error(msg) - raise exception.VolumeBackendAPIException(data=msg) + if self.in_band_or_not and not self.storage_sn: + msg = _("please check 'InBandOrNot' and 'Storagesn' " + "they are invaid.") + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) if not self.ssl_verify and hasattr(requests, 'packages'): LOG.warning("Suppressing requests library SSL Warnings") @@ -1560,9 +1558,7 @@ def _init_http_head(self): def _loop_login(self): self._init_http_head() - self._session.verify = False - if self.ssl_verify: - self._session.verify = self.cert_path + self._session.verify = self.cert_path if self.ssl_verify else False for url in self.san_address: try: diff --git a/Cinder/Train/huawei_base_driver.py b/Cinder/Train/huawei_base_driver.py index 3f12532..0e7ecaf 100644 --- a/Cinder/Train/huawei_base_driver.py +++ b/Cinder/Train/huawei_base_driver.py @@ -78,15 +78,17 @@ def __init__(self, *args, **kwargs): def do_setup(self, context): self.conf.update_config_value() - self.local_cli = rest_client.RestClient( - self.configuration.san_address, - self.configuration.san_user, - self.configuration.san_password, - self.configuration.vstore_name, - self.configuration.ssl_cert_verify, - self.configuration.ssl_cert_path, - self.configuration.in_band_or_not, - self.configuration.storage_sn) + config_dict = { + 'san_address': self.configuration.san_address, + 'san_user': self.configuration.san_user, + 'san_password': self.configuration.san_password, + 'vstore_name': self.configuration.vstore_name, + 'ssl_cert_verify': self.configuration.ssl_cert_verify, + 'ssl_cert_path': self.configuration.ssl_cert_path, + 'in_band_or_not': self.configuration.in_band_or_not, + 'storage_sn': self.configuration.storage_sn + } + self.local_cli = rest_client.RestClient(config_dict) self.local_cli.login() self.configuration.is_dorado_v6 = huawei_utils.is_support_clone_pair( self.local_cli) @@ -96,24 +98,12 @@ def do_setup(self, context): if self.configuration.hypermetro: self.hypermetro_rmt_cli = rest_client.RestClient( - self.configuration.hypermetro['san_address'], - self.configuration.hypermetro['san_user'], - self.configuration.hypermetro['san_password'], - self.configuration.hypermetro['vstore_name'], - self.configuration.hypermetro['in_band_or_not'], - self.configuration.hypermetro['storage_sn'], - ) + self.configuration.hypermetro) self.hypermetro_rmt_cli.login() if self.configuration.replication: self.replication_rmt_cli = rest_client.RestClient( - self.configuration.replication['san_address'], - self.configuration.replication['san_user'], - self.configuration.replication['san_password'], - self.configuration.replication['vstore_name'], - self.configuration.replication['in_band_or_not'], - self.configuration.replication['storage_sn'], - ) + self.configuration.replication) self.replication_rmt_cli.login() def check_for_setup_error(self): diff --git a/Cinder/Train/huawei_conf.py b/Cinder/Train/huawei_conf.py index aa04ed7..d4ed034 100644 --- a/Cinder/Train/huawei_conf.py +++ b/Cinder/Train/huawei_conf.py @@ -145,21 +145,36 @@ def _san_vstore(self, xml_root): vstore = base64.b64decode(six.b(text[4:])).decode() setattr(self.conf, 'vstore_name', vstore) - def _ssl_cert_path(self, xml_root): - text = xml_root.findtext('Storage/SSLCertPath') - setattr(self.conf, 'ssl_cert_path', text) + @staticmethod + def _parser_ssl_value(ssl_value): + if ssl_value.lower() in ('true', 'false'): + return ssl_value.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) - def _ssl_cert_verify(self, xml_root): + def _get_ssl_verify(self, xml_root): value = False text = xml_root.findtext('Storage/SSLCertVerify') if text: - if text.lower() in ('true', 'false'): - value = text.lower() == 'true' - else: - msg = _("SSLCertVerify configured error.") - LOG.error(msg) - raise exception.InvalidInput(reason=msg) + value = self._parser_ssl_value(text) + return value + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.conf, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.conf, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) setattr(self.conf, 'ssl_cert_verify', value) def _set_extra_constants_by_product(self, product): @@ -382,16 +397,29 @@ def _parse_remote_initiator_info(self, dev, ini_type): self._check_hostname_regex_config(ini_info) return ini_info + def _check_ssl_valid(self, dev): + ssl_cert_verify = dev.get('ssl_cert_verify', 'false') + ssl_verify = self._parser_ssl_value(ssl_cert_verify) + ssl_cert_path = dev.get('ssl_cert_path') + if not ssl_cert_path and ssl_verify: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return ssl_verify + def _hypermetro_devices(self, xml_root): dev = self.conf.safe_get('hypermetro_device') config = {} if dev: + ssl_verify = self._check_ssl_valid(dev) config = { 'san_address': dev['san_address'].split(';'), 'san_user': dev['san_user'], 'san_password': dev['san_password'], 'vstore_name': dev.get('vstore_name'), + 'ssl_cert_verify': ssl_verify, + 'ssl_cert_path': dev.get('ssl_cert_path'), 'metro_domain': dev['metro_domain'], 'storage_pools': dev['storage_pool'].split(';')[:1], 'iscsi_info': self._parse_remote_initiator_info( @@ -414,12 +442,15 @@ def _replication_devices(self, xml_root): if replication_devs: dev = replication_devs[0] + ssl_verify = self._check_ssl_valid(dev) config = { 'backend_id': dev['backend_id'], 'san_address': dev['san_address'].split(';'), 'san_user': dev['san_user'], 'san_password': dev['san_password'], 'vstore_name': dev.get('vstore_name'), + 'ssl_cert_verify': ssl_verify, + 'ssl_cert_path': dev.get('ssl_cert_path'), 'storage_pools': dev['storage_pool'].split(';')[:1], 'iscsi_info': self._parse_remote_initiator_info( dev, 'iscsi_info'), diff --git a/Cinder/Train/rest_client.py b/Cinder/Train/rest_client.py index 3555e6c..9d5c923 100644 --- a/Cinder/Train/rest_client.py +++ b/Cinder/Train/rest_client.py @@ -1459,16 +1459,15 @@ def wrapped(self, url, **kwargs): class RestClient(object): - def __init__(self, address, user, password, vstore=None, ssl_verify=None, - cert_path=None, in_band_or_not=None, storage_sn=None): - self.san_address = address - self.san_user = user - self.san_password = password - self.vstore_name = vstore - self.ssl_verify = ssl_verify - self.cert_path = cert_path - self.in_band_or_not = in_band_or_not - self.storage_sn = storage_sn + def __init__(self, config_dict): + self.san_address = config_dict.get('san_address') + self.san_user = config_dict.get('san_user') + self.san_password = config_dict.get('san_password') + self.vstore_name = config_dict.get('vstore_name') + self.ssl_verify = config_dict.get('ssl_cert_verify') + self.cert_path = config_dict.get('ssl_cert_path') + self.in_band_or_not = config_dict.get('in_band_or_not') + self.storage_sn = config_dict.get('storage_sn') self._login_url = None self._login_device_id = None @@ -1476,12 +1475,11 @@ def __init__(self, address, user, password, vstore=None, ssl_verify=None, self._session = None self._init_object_methods() - if self.in_band_or_not: - if not self.storage_sn: - msg = _("please check 'InBandOrNot' and 'Storagesn' " - "they are invaid.") - LOG.error(msg) - raise exception.VolumeBackendAPIException(data=msg) + if self.in_band_or_not and not self.storage_sn: + msg = _("please check 'InBandOrNot' and 'Storagesn' " + "they are invaid.") + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) if not self.ssl_verify and hasattr(requests, 'packages'): LOG.warning("Suppressing requests library SSL Warnings") @@ -1560,9 +1558,7 @@ def _init_http_head(self): def _loop_login(self): self._init_http_head() - self._session.verify = False - if self.ssl_verify: - self._session.verify = self.cert_path + self._session.verify = self.cert_path if self.ssl_verify else False for url in self.san_address: try: diff --git a/Cinder/Ussuri/huawei_base_driver.py b/Cinder/Ussuri/huawei_base_driver.py index 3f12532..0e7ecaf 100644 --- a/Cinder/Ussuri/huawei_base_driver.py +++ b/Cinder/Ussuri/huawei_base_driver.py @@ -78,15 +78,17 @@ def __init__(self, *args, **kwargs): def do_setup(self, context): self.conf.update_config_value() - self.local_cli = rest_client.RestClient( - self.configuration.san_address, - self.configuration.san_user, - self.configuration.san_password, - self.configuration.vstore_name, - self.configuration.ssl_cert_verify, - self.configuration.ssl_cert_path, - self.configuration.in_band_or_not, - self.configuration.storage_sn) + config_dict = { + 'san_address': self.configuration.san_address, + 'san_user': self.configuration.san_user, + 'san_password': self.configuration.san_password, + 'vstore_name': self.configuration.vstore_name, + 'ssl_cert_verify': self.configuration.ssl_cert_verify, + 'ssl_cert_path': self.configuration.ssl_cert_path, + 'in_band_or_not': self.configuration.in_band_or_not, + 'storage_sn': self.configuration.storage_sn + } + self.local_cli = rest_client.RestClient(config_dict) self.local_cli.login() self.configuration.is_dorado_v6 = huawei_utils.is_support_clone_pair( self.local_cli) @@ -96,24 +98,12 @@ def do_setup(self, context): if self.configuration.hypermetro: self.hypermetro_rmt_cli = rest_client.RestClient( - self.configuration.hypermetro['san_address'], - self.configuration.hypermetro['san_user'], - self.configuration.hypermetro['san_password'], - self.configuration.hypermetro['vstore_name'], - self.configuration.hypermetro['in_band_or_not'], - self.configuration.hypermetro['storage_sn'], - ) + self.configuration.hypermetro) self.hypermetro_rmt_cli.login() if self.configuration.replication: self.replication_rmt_cli = rest_client.RestClient( - self.configuration.replication['san_address'], - self.configuration.replication['san_user'], - self.configuration.replication['san_password'], - self.configuration.replication['vstore_name'], - self.configuration.replication['in_band_or_not'], - self.configuration.replication['storage_sn'], - ) + self.configuration.replication) self.replication_rmt_cli.login() def check_for_setup_error(self): diff --git a/Cinder/Ussuri/huawei_conf.py b/Cinder/Ussuri/huawei_conf.py index aa04ed7..d4ed034 100644 --- a/Cinder/Ussuri/huawei_conf.py +++ b/Cinder/Ussuri/huawei_conf.py @@ -145,21 +145,36 @@ def _san_vstore(self, xml_root): vstore = base64.b64decode(six.b(text[4:])).decode() setattr(self.conf, 'vstore_name', vstore) - def _ssl_cert_path(self, xml_root): - text = xml_root.findtext('Storage/SSLCertPath') - setattr(self.conf, 'ssl_cert_path', text) + @staticmethod + def _parser_ssl_value(ssl_value): + if ssl_value.lower() in ('true', 'false'): + return ssl_value.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) - def _ssl_cert_verify(self, xml_root): + def _get_ssl_verify(self, xml_root): value = False text = xml_root.findtext('Storage/SSLCertVerify') if text: - if text.lower() in ('true', 'false'): - value = text.lower() == 'true' - else: - msg = _("SSLCertVerify configured error.") - LOG.error(msg) - raise exception.InvalidInput(reason=msg) + value = self._parser_ssl_value(text) + return value + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.conf, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.conf, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) setattr(self.conf, 'ssl_cert_verify', value) def _set_extra_constants_by_product(self, product): @@ -382,16 +397,29 @@ def _parse_remote_initiator_info(self, dev, ini_type): self._check_hostname_regex_config(ini_info) return ini_info + def _check_ssl_valid(self, dev): + ssl_cert_verify = dev.get('ssl_cert_verify', 'false') + ssl_verify = self._parser_ssl_value(ssl_cert_verify) + ssl_cert_path = dev.get('ssl_cert_path') + if not ssl_cert_path and ssl_verify: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return ssl_verify + def _hypermetro_devices(self, xml_root): dev = self.conf.safe_get('hypermetro_device') config = {} if dev: + ssl_verify = self._check_ssl_valid(dev) config = { 'san_address': dev['san_address'].split(';'), 'san_user': dev['san_user'], 'san_password': dev['san_password'], 'vstore_name': dev.get('vstore_name'), + 'ssl_cert_verify': ssl_verify, + 'ssl_cert_path': dev.get('ssl_cert_path'), 'metro_domain': dev['metro_domain'], 'storage_pools': dev['storage_pool'].split(';')[:1], 'iscsi_info': self._parse_remote_initiator_info( @@ -414,12 +442,15 @@ def _replication_devices(self, xml_root): if replication_devs: dev = replication_devs[0] + ssl_verify = self._check_ssl_valid(dev) config = { 'backend_id': dev['backend_id'], 'san_address': dev['san_address'].split(';'), 'san_user': dev['san_user'], 'san_password': dev['san_password'], 'vstore_name': dev.get('vstore_name'), + 'ssl_cert_verify': ssl_verify, + 'ssl_cert_path': dev.get('ssl_cert_path'), 'storage_pools': dev['storage_pool'].split(';')[:1], 'iscsi_info': self._parse_remote_initiator_info( dev, 'iscsi_info'), diff --git a/Cinder/Ussuri/rest_client.py b/Cinder/Ussuri/rest_client.py index 3555e6c..9d5c923 100644 --- a/Cinder/Ussuri/rest_client.py +++ b/Cinder/Ussuri/rest_client.py @@ -1459,16 +1459,15 @@ def wrapped(self, url, **kwargs): class RestClient(object): - def __init__(self, address, user, password, vstore=None, ssl_verify=None, - cert_path=None, in_band_or_not=None, storage_sn=None): - self.san_address = address - self.san_user = user - self.san_password = password - self.vstore_name = vstore - self.ssl_verify = ssl_verify - self.cert_path = cert_path - self.in_band_or_not = in_band_or_not - self.storage_sn = storage_sn + def __init__(self, config_dict): + self.san_address = config_dict.get('san_address') + self.san_user = config_dict.get('san_user') + self.san_password = config_dict.get('san_password') + self.vstore_name = config_dict.get('vstore_name') + self.ssl_verify = config_dict.get('ssl_cert_verify') + self.cert_path = config_dict.get('ssl_cert_path') + self.in_band_or_not = config_dict.get('in_band_or_not') + self.storage_sn = config_dict.get('storage_sn') self._login_url = None self._login_device_id = None @@ -1476,12 +1475,11 @@ def __init__(self, address, user, password, vstore=None, ssl_verify=None, self._session = None self._init_object_methods() - if self.in_band_or_not: - if not self.storage_sn: - msg = _("please check 'InBandOrNot' and 'Storagesn' " - "they are invaid.") - LOG.error(msg) - raise exception.VolumeBackendAPIException(data=msg) + if self.in_band_or_not and not self.storage_sn: + msg = _("please check 'InBandOrNot' and 'Storagesn' " + "they are invaid.") + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) if not self.ssl_verify and hasattr(requests, 'packages'): LOG.warning("Suppressing requests library SSL Warnings") @@ -1560,9 +1558,7 @@ def _init_http_head(self): def _loop_login(self): self._init_http_head() - self._session.verify = False - if self.ssl_verify: - self._session.verify = self.cert_path + self._session.verify = self.cert_path if self.ssl_verify else False for url in self.san_address: try: diff --git a/Cinder/Victoria/huawei_base_driver.py b/Cinder/Victoria/huawei_base_driver.py index 3f12532..0e7ecaf 100644 --- a/Cinder/Victoria/huawei_base_driver.py +++ b/Cinder/Victoria/huawei_base_driver.py @@ -78,15 +78,17 @@ def __init__(self, *args, **kwargs): def do_setup(self, context): self.conf.update_config_value() - self.local_cli = rest_client.RestClient( - self.configuration.san_address, - self.configuration.san_user, - self.configuration.san_password, - self.configuration.vstore_name, - self.configuration.ssl_cert_verify, - self.configuration.ssl_cert_path, - self.configuration.in_band_or_not, - self.configuration.storage_sn) + config_dict = { + 'san_address': self.configuration.san_address, + 'san_user': self.configuration.san_user, + 'san_password': self.configuration.san_password, + 'vstore_name': self.configuration.vstore_name, + 'ssl_cert_verify': self.configuration.ssl_cert_verify, + 'ssl_cert_path': self.configuration.ssl_cert_path, + 'in_band_or_not': self.configuration.in_band_or_not, + 'storage_sn': self.configuration.storage_sn + } + self.local_cli = rest_client.RestClient(config_dict) self.local_cli.login() self.configuration.is_dorado_v6 = huawei_utils.is_support_clone_pair( self.local_cli) @@ -96,24 +98,12 @@ def do_setup(self, context): if self.configuration.hypermetro: self.hypermetro_rmt_cli = rest_client.RestClient( - self.configuration.hypermetro['san_address'], - self.configuration.hypermetro['san_user'], - self.configuration.hypermetro['san_password'], - self.configuration.hypermetro['vstore_name'], - self.configuration.hypermetro['in_band_or_not'], - self.configuration.hypermetro['storage_sn'], - ) + self.configuration.hypermetro) self.hypermetro_rmt_cli.login() if self.configuration.replication: self.replication_rmt_cli = rest_client.RestClient( - self.configuration.replication['san_address'], - self.configuration.replication['san_user'], - self.configuration.replication['san_password'], - self.configuration.replication['vstore_name'], - self.configuration.replication['in_band_or_not'], - self.configuration.replication['storage_sn'], - ) + self.configuration.replication) self.replication_rmt_cli.login() def check_for_setup_error(self): diff --git a/Cinder/Victoria/huawei_conf.py b/Cinder/Victoria/huawei_conf.py index aa04ed7..d4ed034 100644 --- a/Cinder/Victoria/huawei_conf.py +++ b/Cinder/Victoria/huawei_conf.py @@ -145,21 +145,36 @@ def _san_vstore(self, xml_root): vstore = base64.b64decode(six.b(text[4:])).decode() setattr(self.conf, 'vstore_name', vstore) - def _ssl_cert_path(self, xml_root): - text = xml_root.findtext('Storage/SSLCertPath') - setattr(self.conf, 'ssl_cert_path', text) + @staticmethod + def _parser_ssl_value(ssl_value): + if ssl_value.lower() in ('true', 'false'): + return ssl_value.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) - def _ssl_cert_verify(self, xml_root): + def _get_ssl_verify(self, xml_root): value = False text = xml_root.findtext('Storage/SSLCertVerify') if text: - if text.lower() in ('true', 'false'): - value = text.lower() == 'true' - else: - msg = _("SSLCertVerify configured error.") - LOG.error(msg) - raise exception.InvalidInput(reason=msg) + value = self._parser_ssl_value(text) + return value + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.conf, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.conf, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) setattr(self.conf, 'ssl_cert_verify', value) def _set_extra_constants_by_product(self, product): @@ -382,16 +397,29 @@ def _parse_remote_initiator_info(self, dev, ini_type): self._check_hostname_regex_config(ini_info) return ini_info + def _check_ssl_valid(self, dev): + ssl_cert_verify = dev.get('ssl_cert_verify', 'false') + ssl_verify = self._parser_ssl_value(ssl_cert_verify) + ssl_cert_path = dev.get('ssl_cert_path') + if not ssl_cert_path and ssl_verify: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return ssl_verify + def _hypermetro_devices(self, xml_root): dev = self.conf.safe_get('hypermetro_device') config = {} if dev: + ssl_verify = self._check_ssl_valid(dev) config = { 'san_address': dev['san_address'].split(';'), 'san_user': dev['san_user'], 'san_password': dev['san_password'], 'vstore_name': dev.get('vstore_name'), + 'ssl_cert_verify': ssl_verify, + 'ssl_cert_path': dev.get('ssl_cert_path'), 'metro_domain': dev['metro_domain'], 'storage_pools': dev['storage_pool'].split(';')[:1], 'iscsi_info': self._parse_remote_initiator_info( @@ -414,12 +442,15 @@ def _replication_devices(self, xml_root): if replication_devs: dev = replication_devs[0] + ssl_verify = self._check_ssl_valid(dev) config = { 'backend_id': dev['backend_id'], 'san_address': dev['san_address'].split(';'), 'san_user': dev['san_user'], 'san_password': dev['san_password'], 'vstore_name': dev.get('vstore_name'), + 'ssl_cert_verify': ssl_verify, + 'ssl_cert_path': dev.get('ssl_cert_path'), 'storage_pools': dev['storage_pool'].split(';')[:1], 'iscsi_info': self._parse_remote_initiator_info( dev, 'iscsi_info'), diff --git a/Cinder/Victoria/rest_client.py b/Cinder/Victoria/rest_client.py index 3555e6c..9d5c923 100644 --- a/Cinder/Victoria/rest_client.py +++ b/Cinder/Victoria/rest_client.py @@ -1459,16 +1459,15 @@ def wrapped(self, url, **kwargs): class RestClient(object): - def __init__(self, address, user, password, vstore=None, ssl_verify=None, - cert_path=None, in_band_or_not=None, storage_sn=None): - self.san_address = address - self.san_user = user - self.san_password = password - self.vstore_name = vstore - self.ssl_verify = ssl_verify - self.cert_path = cert_path - self.in_band_or_not = in_band_or_not - self.storage_sn = storage_sn + def __init__(self, config_dict): + self.san_address = config_dict.get('san_address') + self.san_user = config_dict.get('san_user') + self.san_password = config_dict.get('san_password') + self.vstore_name = config_dict.get('vstore_name') + self.ssl_verify = config_dict.get('ssl_cert_verify') + self.cert_path = config_dict.get('ssl_cert_path') + self.in_band_or_not = config_dict.get('in_band_or_not') + self.storage_sn = config_dict.get('storage_sn') self._login_url = None self._login_device_id = None @@ -1476,12 +1475,11 @@ def __init__(self, address, user, password, vstore=None, ssl_verify=None, self._session = None self._init_object_methods() - if self.in_band_or_not: - if not self.storage_sn: - msg = _("please check 'InBandOrNot' and 'Storagesn' " - "they are invaid.") - LOG.error(msg) - raise exception.VolumeBackendAPIException(data=msg) + if self.in_band_or_not and not self.storage_sn: + msg = _("please check 'InBandOrNot' and 'Storagesn' " + "they are invaid.") + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) if not self.ssl_verify and hasattr(requests, 'packages'): LOG.warning("Suppressing requests library SSL Warnings") @@ -1560,9 +1558,7 @@ def _init_http_head(self): def _loop_login(self): self._init_http_head() - self._session.verify = False - if self.ssl_verify: - self._session.verify = self.cert_path + self._session.verify = self.cert_path if self.ssl_verify else False for url in self.san_address: try: diff --git a/Cinder/Wallaby/huawei_base_driver.py b/Cinder/Wallaby/huawei_base_driver.py index 3f12532..0e7ecaf 100644 --- a/Cinder/Wallaby/huawei_base_driver.py +++ b/Cinder/Wallaby/huawei_base_driver.py @@ -78,15 +78,17 @@ def __init__(self, *args, **kwargs): def do_setup(self, context): self.conf.update_config_value() - self.local_cli = rest_client.RestClient( - self.configuration.san_address, - self.configuration.san_user, - self.configuration.san_password, - self.configuration.vstore_name, - self.configuration.ssl_cert_verify, - self.configuration.ssl_cert_path, - self.configuration.in_band_or_not, - self.configuration.storage_sn) + config_dict = { + 'san_address': self.configuration.san_address, + 'san_user': self.configuration.san_user, + 'san_password': self.configuration.san_password, + 'vstore_name': self.configuration.vstore_name, + 'ssl_cert_verify': self.configuration.ssl_cert_verify, + 'ssl_cert_path': self.configuration.ssl_cert_path, + 'in_band_or_not': self.configuration.in_band_or_not, + 'storage_sn': self.configuration.storage_sn + } + self.local_cli = rest_client.RestClient(config_dict) self.local_cli.login() self.configuration.is_dorado_v6 = huawei_utils.is_support_clone_pair( self.local_cli) @@ -96,24 +98,12 @@ def do_setup(self, context): if self.configuration.hypermetro: self.hypermetro_rmt_cli = rest_client.RestClient( - self.configuration.hypermetro['san_address'], - self.configuration.hypermetro['san_user'], - self.configuration.hypermetro['san_password'], - self.configuration.hypermetro['vstore_name'], - self.configuration.hypermetro['in_band_or_not'], - self.configuration.hypermetro['storage_sn'], - ) + self.configuration.hypermetro) self.hypermetro_rmt_cli.login() if self.configuration.replication: self.replication_rmt_cli = rest_client.RestClient( - self.configuration.replication['san_address'], - self.configuration.replication['san_user'], - self.configuration.replication['san_password'], - self.configuration.replication['vstore_name'], - self.configuration.replication['in_band_or_not'], - self.configuration.replication['storage_sn'], - ) + self.configuration.replication) self.replication_rmt_cli.login() def check_for_setup_error(self): diff --git a/Cinder/Wallaby/huawei_conf.py b/Cinder/Wallaby/huawei_conf.py index aa04ed7..d4ed034 100644 --- a/Cinder/Wallaby/huawei_conf.py +++ b/Cinder/Wallaby/huawei_conf.py @@ -145,21 +145,36 @@ def _san_vstore(self, xml_root): vstore = base64.b64decode(six.b(text[4:])).decode() setattr(self.conf, 'vstore_name', vstore) - def _ssl_cert_path(self, xml_root): - text = xml_root.findtext('Storage/SSLCertPath') - setattr(self.conf, 'ssl_cert_path', text) + @staticmethod + def _parser_ssl_value(ssl_value): + if ssl_value.lower() in ('true', 'false'): + return ssl_value.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) - def _ssl_cert_verify(self, xml_root): + def _get_ssl_verify(self, xml_root): value = False text = xml_root.findtext('Storage/SSLCertVerify') if text: - if text.lower() in ('true', 'false'): - value = text.lower() == 'true' - else: - msg = _("SSLCertVerify configured error.") - LOG.error(msg) - raise exception.InvalidInput(reason=msg) + value = self._parser_ssl_value(text) + return value + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.conf, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.conf, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) setattr(self.conf, 'ssl_cert_verify', value) def _set_extra_constants_by_product(self, product): @@ -382,16 +397,29 @@ def _parse_remote_initiator_info(self, dev, ini_type): self._check_hostname_regex_config(ini_info) return ini_info + def _check_ssl_valid(self, dev): + ssl_cert_verify = dev.get('ssl_cert_verify', 'false') + ssl_verify = self._parser_ssl_value(ssl_cert_verify) + ssl_cert_path = dev.get('ssl_cert_path') + if not ssl_cert_path and ssl_verify: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return ssl_verify + def _hypermetro_devices(self, xml_root): dev = self.conf.safe_get('hypermetro_device') config = {} if dev: + ssl_verify = self._check_ssl_valid(dev) config = { 'san_address': dev['san_address'].split(';'), 'san_user': dev['san_user'], 'san_password': dev['san_password'], 'vstore_name': dev.get('vstore_name'), + 'ssl_cert_verify': ssl_verify, + 'ssl_cert_path': dev.get('ssl_cert_path'), 'metro_domain': dev['metro_domain'], 'storage_pools': dev['storage_pool'].split(';')[:1], 'iscsi_info': self._parse_remote_initiator_info( @@ -414,12 +442,15 @@ def _replication_devices(self, xml_root): if replication_devs: dev = replication_devs[0] + ssl_verify = self._check_ssl_valid(dev) config = { 'backend_id': dev['backend_id'], 'san_address': dev['san_address'].split(';'), 'san_user': dev['san_user'], 'san_password': dev['san_password'], 'vstore_name': dev.get('vstore_name'), + 'ssl_cert_verify': ssl_verify, + 'ssl_cert_path': dev.get('ssl_cert_path'), 'storage_pools': dev['storage_pool'].split(';')[:1], 'iscsi_info': self._parse_remote_initiator_info( dev, 'iscsi_info'), diff --git a/Cinder/Wallaby/rest_client.py b/Cinder/Wallaby/rest_client.py index 3555e6c..9d5c923 100644 --- a/Cinder/Wallaby/rest_client.py +++ b/Cinder/Wallaby/rest_client.py @@ -1459,16 +1459,15 @@ def wrapped(self, url, **kwargs): class RestClient(object): - def __init__(self, address, user, password, vstore=None, ssl_verify=None, - cert_path=None, in_band_or_not=None, storage_sn=None): - self.san_address = address - self.san_user = user - self.san_password = password - self.vstore_name = vstore - self.ssl_verify = ssl_verify - self.cert_path = cert_path - self.in_band_or_not = in_band_or_not - self.storage_sn = storage_sn + def __init__(self, config_dict): + self.san_address = config_dict.get('san_address') + self.san_user = config_dict.get('san_user') + self.san_password = config_dict.get('san_password') + self.vstore_name = config_dict.get('vstore_name') + self.ssl_verify = config_dict.get('ssl_cert_verify') + self.cert_path = config_dict.get('ssl_cert_path') + self.in_band_or_not = config_dict.get('in_band_or_not') + self.storage_sn = config_dict.get('storage_sn') self._login_url = None self._login_device_id = None @@ -1476,12 +1475,11 @@ def __init__(self, address, user, password, vstore=None, ssl_verify=None, self._session = None self._init_object_methods() - if self.in_band_or_not: - if not self.storage_sn: - msg = _("please check 'InBandOrNot' and 'Storagesn' " - "they are invaid.") - LOG.error(msg) - raise exception.VolumeBackendAPIException(data=msg) + if self.in_band_or_not and not self.storage_sn: + msg = _("please check 'InBandOrNot' and 'Storagesn' " + "they are invaid.") + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) if not self.ssl_verify and hasattr(requests, 'packages'): LOG.warning("Suppressing requests library SSL Warnings") @@ -1560,9 +1558,7 @@ def _init_http_head(self): def _loop_login(self): self._init_http_head() - self._session.verify = False - if self.ssl_verify: - self._session.verify = self.cert_path + self._session.verify = self.cert_path if self.ssl_verify else False for url in self.san_address: try: diff --git a/Cinder/Xena/huawei_base_driver.py b/Cinder/Xena/huawei_base_driver.py index 3f12532..0e7ecaf 100644 --- a/Cinder/Xena/huawei_base_driver.py +++ b/Cinder/Xena/huawei_base_driver.py @@ -78,15 +78,17 @@ def __init__(self, *args, **kwargs): def do_setup(self, context): self.conf.update_config_value() - self.local_cli = rest_client.RestClient( - self.configuration.san_address, - self.configuration.san_user, - self.configuration.san_password, - self.configuration.vstore_name, - self.configuration.ssl_cert_verify, - self.configuration.ssl_cert_path, - self.configuration.in_band_or_not, - self.configuration.storage_sn) + config_dict = { + 'san_address': self.configuration.san_address, + 'san_user': self.configuration.san_user, + 'san_password': self.configuration.san_password, + 'vstore_name': self.configuration.vstore_name, + 'ssl_cert_verify': self.configuration.ssl_cert_verify, + 'ssl_cert_path': self.configuration.ssl_cert_path, + 'in_band_or_not': self.configuration.in_band_or_not, + 'storage_sn': self.configuration.storage_sn + } + self.local_cli = rest_client.RestClient(config_dict) self.local_cli.login() self.configuration.is_dorado_v6 = huawei_utils.is_support_clone_pair( self.local_cli) @@ -96,24 +98,12 @@ def do_setup(self, context): if self.configuration.hypermetro: self.hypermetro_rmt_cli = rest_client.RestClient( - self.configuration.hypermetro['san_address'], - self.configuration.hypermetro['san_user'], - self.configuration.hypermetro['san_password'], - self.configuration.hypermetro['vstore_name'], - self.configuration.hypermetro['in_band_or_not'], - self.configuration.hypermetro['storage_sn'], - ) + self.configuration.hypermetro) self.hypermetro_rmt_cli.login() if self.configuration.replication: self.replication_rmt_cli = rest_client.RestClient( - self.configuration.replication['san_address'], - self.configuration.replication['san_user'], - self.configuration.replication['san_password'], - self.configuration.replication['vstore_name'], - self.configuration.replication['in_band_or_not'], - self.configuration.replication['storage_sn'], - ) + self.configuration.replication) self.replication_rmt_cli.login() def check_for_setup_error(self): diff --git a/Cinder/Xena/huawei_conf.py b/Cinder/Xena/huawei_conf.py index aa04ed7..d4ed034 100644 --- a/Cinder/Xena/huawei_conf.py +++ b/Cinder/Xena/huawei_conf.py @@ -145,21 +145,36 @@ def _san_vstore(self, xml_root): vstore = base64.b64decode(six.b(text[4:])).decode() setattr(self.conf, 'vstore_name', vstore) - def _ssl_cert_path(self, xml_root): - text = xml_root.findtext('Storage/SSLCertPath') - setattr(self.conf, 'ssl_cert_path', text) + @staticmethod + def _parser_ssl_value(ssl_value): + if ssl_value.lower() in ('true', 'false'): + return ssl_value.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) - def _ssl_cert_verify(self, xml_root): + def _get_ssl_verify(self, xml_root): value = False text = xml_root.findtext('Storage/SSLCertVerify') if text: - if text.lower() in ('true', 'false'): - value = text.lower() == 'true' - else: - msg = _("SSLCertVerify configured error.") - LOG.error(msg) - raise exception.InvalidInput(reason=msg) + value = self._parser_ssl_value(text) + return value + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.conf, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.conf, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) setattr(self.conf, 'ssl_cert_verify', value) def _set_extra_constants_by_product(self, product): @@ -382,16 +397,29 @@ def _parse_remote_initiator_info(self, dev, ini_type): self._check_hostname_regex_config(ini_info) return ini_info + def _check_ssl_valid(self, dev): + ssl_cert_verify = dev.get('ssl_cert_verify', 'false') + ssl_verify = self._parser_ssl_value(ssl_cert_verify) + ssl_cert_path = dev.get('ssl_cert_path') + if not ssl_cert_path and ssl_verify: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return ssl_verify + def _hypermetro_devices(self, xml_root): dev = self.conf.safe_get('hypermetro_device') config = {} if dev: + ssl_verify = self._check_ssl_valid(dev) config = { 'san_address': dev['san_address'].split(';'), 'san_user': dev['san_user'], 'san_password': dev['san_password'], 'vstore_name': dev.get('vstore_name'), + 'ssl_cert_verify': ssl_verify, + 'ssl_cert_path': dev.get('ssl_cert_path'), 'metro_domain': dev['metro_domain'], 'storage_pools': dev['storage_pool'].split(';')[:1], 'iscsi_info': self._parse_remote_initiator_info( @@ -414,12 +442,15 @@ def _replication_devices(self, xml_root): if replication_devs: dev = replication_devs[0] + ssl_verify = self._check_ssl_valid(dev) config = { 'backend_id': dev['backend_id'], 'san_address': dev['san_address'].split(';'), 'san_user': dev['san_user'], 'san_password': dev['san_password'], 'vstore_name': dev.get('vstore_name'), + 'ssl_cert_verify': ssl_verify, + 'ssl_cert_path': dev.get('ssl_cert_path'), 'storage_pools': dev['storage_pool'].split(';')[:1], 'iscsi_info': self._parse_remote_initiator_info( dev, 'iscsi_info'), diff --git a/Cinder/Xena/rest_client.py b/Cinder/Xena/rest_client.py index 3555e6c..9d5c923 100644 --- a/Cinder/Xena/rest_client.py +++ b/Cinder/Xena/rest_client.py @@ -1459,16 +1459,15 @@ def wrapped(self, url, **kwargs): class RestClient(object): - def __init__(self, address, user, password, vstore=None, ssl_verify=None, - cert_path=None, in_band_or_not=None, storage_sn=None): - self.san_address = address - self.san_user = user - self.san_password = password - self.vstore_name = vstore - self.ssl_verify = ssl_verify - self.cert_path = cert_path - self.in_band_or_not = in_band_or_not - self.storage_sn = storage_sn + def __init__(self, config_dict): + self.san_address = config_dict.get('san_address') + self.san_user = config_dict.get('san_user') + self.san_password = config_dict.get('san_password') + self.vstore_name = config_dict.get('vstore_name') + self.ssl_verify = config_dict.get('ssl_cert_verify') + self.cert_path = config_dict.get('ssl_cert_path') + self.in_band_or_not = config_dict.get('in_band_or_not') + self.storage_sn = config_dict.get('storage_sn') self._login_url = None self._login_device_id = None @@ -1476,12 +1475,11 @@ def __init__(self, address, user, password, vstore=None, ssl_verify=None, self._session = None self._init_object_methods() - if self.in_band_or_not: - if not self.storage_sn: - msg = _("please check 'InBandOrNot' and 'Storagesn' " - "they are invaid.") - LOG.error(msg) - raise exception.VolumeBackendAPIException(data=msg) + if self.in_band_or_not and not self.storage_sn: + msg = _("please check 'InBandOrNot' and 'Storagesn' " + "they are invaid.") + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) if not self.ssl_verify and hasattr(requests, 'packages'): LOG.warning("Suppressing requests library SSL Warnings") @@ -1560,9 +1558,7 @@ def _init_http_head(self): def _loop_login(self): self._init_http_head() - self._session.verify = False - if self.ssl_verify: - self._session.verify = self.cert_path + self._session.verify = self.cert_path if self.ssl_verify else False for url in self.san_address: try: diff --git a/Cinder/Yoga/huawei_base_driver.py b/Cinder/Yoga/huawei_base_driver.py index 3f12532..0e7ecaf 100644 --- a/Cinder/Yoga/huawei_base_driver.py +++ b/Cinder/Yoga/huawei_base_driver.py @@ -78,15 +78,17 @@ def __init__(self, *args, **kwargs): def do_setup(self, context): self.conf.update_config_value() - self.local_cli = rest_client.RestClient( - self.configuration.san_address, - self.configuration.san_user, - self.configuration.san_password, - self.configuration.vstore_name, - self.configuration.ssl_cert_verify, - self.configuration.ssl_cert_path, - self.configuration.in_band_or_not, - self.configuration.storage_sn) + config_dict = { + 'san_address': self.configuration.san_address, + 'san_user': self.configuration.san_user, + 'san_password': self.configuration.san_password, + 'vstore_name': self.configuration.vstore_name, + 'ssl_cert_verify': self.configuration.ssl_cert_verify, + 'ssl_cert_path': self.configuration.ssl_cert_path, + 'in_band_or_not': self.configuration.in_band_or_not, + 'storage_sn': self.configuration.storage_sn + } + self.local_cli = rest_client.RestClient(config_dict) self.local_cli.login() self.configuration.is_dorado_v6 = huawei_utils.is_support_clone_pair( self.local_cli) @@ -96,24 +98,12 @@ def do_setup(self, context): if self.configuration.hypermetro: self.hypermetro_rmt_cli = rest_client.RestClient( - self.configuration.hypermetro['san_address'], - self.configuration.hypermetro['san_user'], - self.configuration.hypermetro['san_password'], - self.configuration.hypermetro['vstore_name'], - self.configuration.hypermetro['in_band_or_not'], - self.configuration.hypermetro['storage_sn'], - ) + self.configuration.hypermetro) self.hypermetro_rmt_cli.login() if self.configuration.replication: self.replication_rmt_cli = rest_client.RestClient( - self.configuration.replication['san_address'], - self.configuration.replication['san_user'], - self.configuration.replication['san_password'], - self.configuration.replication['vstore_name'], - self.configuration.replication['in_band_or_not'], - self.configuration.replication['storage_sn'], - ) + self.configuration.replication) self.replication_rmt_cli.login() def check_for_setup_error(self): diff --git a/Cinder/Yoga/huawei_conf.py b/Cinder/Yoga/huawei_conf.py index aa04ed7..d4ed034 100644 --- a/Cinder/Yoga/huawei_conf.py +++ b/Cinder/Yoga/huawei_conf.py @@ -145,21 +145,36 @@ def _san_vstore(self, xml_root): vstore = base64.b64decode(six.b(text[4:])).decode() setattr(self.conf, 'vstore_name', vstore) - def _ssl_cert_path(self, xml_root): - text = xml_root.findtext('Storage/SSLCertPath') - setattr(self.conf, 'ssl_cert_path', text) + @staticmethod + def _parser_ssl_value(ssl_value): + if ssl_value.lower() in ('true', 'false'): + return ssl_value.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) - def _ssl_cert_verify(self, xml_root): + def _get_ssl_verify(self, xml_root): value = False text = xml_root.findtext('Storage/SSLCertVerify') if text: - if text.lower() in ('true', 'false'): - value = text.lower() == 'true' - else: - msg = _("SSLCertVerify configured error.") - LOG.error(msg) - raise exception.InvalidInput(reason=msg) + value = self._parser_ssl_value(text) + return value + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.conf, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.conf, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) setattr(self.conf, 'ssl_cert_verify', value) def _set_extra_constants_by_product(self, product): @@ -382,16 +397,29 @@ def _parse_remote_initiator_info(self, dev, ini_type): self._check_hostname_regex_config(ini_info) return ini_info + def _check_ssl_valid(self, dev): + ssl_cert_verify = dev.get('ssl_cert_verify', 'false') + ssl_verify = self._parser_ssl_value(ssl_cert_verify) + ssl_cert_path = dev.get('ssl_cert_path') + if not ssl_cert_path and ssl_verify: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return ssl_verify + def _hypermetro_devices(self, xml_root): dev = self.conf.safe_get('hypermetro_device') config = {} if dev: + ssl_verify = self._check_ssl_valid(dev) config = { 'san_address': dev['san_address'].split(';'), 'san_user': dev['san_user'], 'san_password': dev['san_password'], 'vstore_name': dev.get('vstore_name'), + 'ssl_cert_verify': ssl_verify, + 'ssl_cert_path': dev.get('ssl_cert_path'), 'metro_domain': dev['metro_domain'], 'storage_pools': dev['storage_pool'].split(';')[:1], 'iscsi_info': self._parse_remote_initiator_info( @@ -414,12 +442,15 @@ def _replication_devices(self, xml_root): if replication_devs: dev = replication_devs[0] + ssl_verify = self._check_ssl_valid(dev) config = { 'backend_id': dev['backend_id'], 'san_address': dev['san_address'].split(';'), 'san_user': dev['san_user'], 'san_password': dev['san_password'], 'vstore_name': dev.get('vstore_name'), + 'ssl_cert_verify': ssl_verify, + 'ssl_cert_path': dev.get('ssl_cert_path'), 'storage_pools': dev['storage_pool'].split(';')[:1], 'iscsi_info': self._parse_remote_initiator_info( dev, 'iscsi_info'), diff --git a/Cinder/Yoga/rest_client.py b/Cinder/Yoga/rest_client.py index 3555e6c..9d5c923 100644 --- a/Cinder/Yoga/rest_client.py +++ b/Cinder/Yoga/rest_client.py @@ -1459,16 +1459,15 @@ def wrapped(self, url, **kwargs): class RestClient(object): - def __init__(self, address, user, password, vstore=None, ssl_verify=None, - cert_path=None, in_band_or_not=None, storage_sn=None): - self.san_address = address - self.san_user = user - self.san_password = password - self.vstore_name = vstore - self.ssl_verify = ssl_verify - self.cert_path = cert_path - self.in_band_or_not = in_band_or_not - self.storage_sn = storage_sn + def __init__(self, config_dict): + self.san_address = config_dict.get('san_address') + self.san_user = config_dict.get('san_user') + self.san_password = config_dict.get('san_password') + self.vstore_name = config_dict.get('vstore_name') + self.ssl_verify = config_dict.get('ssl_cert_verify') + self.cert_path = config_dict.get('ssl_cert_path') + self.in_band_or_not = config_dict.get('in_band_or_not') + self.storage_sn = config_dict.get('storage_sn') self._login_url = None self._login_device_id = None @@ -1476,12 +1475,11 @@ def __init__(self, address, user, password, vstore=None, ssl_verify=None, self._session = None self._init_object_methods() - if self.in_band_or_not: - if not self.storage_sn: - msg = _("please check 'InBandOrNot' and 'Storagesn' " - "they are invaid.") - LOG.error(msg) - raise exception.VolumeBackendAPIException(data=msg) + if self.in_band_or_not and not self.storage_sn: + msg = _("please check 'InBandOrNot' and 'Storagesn' " + "they are invaid.") + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) if not self.ssl_verify and hasattr(requests, 'packages'): LOG.warning("Suppressing requests library SSL Warnings") @@ -1560,9 +1558,7 @@ def _init_http_head(self): def _loop_login(self): self._init_http_head() - self._session.verify = False - if self.ssl_verify: - self._session.verify = self.cert_path + self._session.verify = self.cert_path if self.ssl_verify else False for url in self.san_address: try: diff --git a/Cinder/Zed/huawei_base_driver.py b/Cinder/Zed/huawei_base_driver.py index 3f12532..0e7ecaf 100644 --- a/Cinder/Zed/huawei_base_driver.py +++ b/Cinder/Zed/huawei_base_driver.py @@ -78,15 +78,17 @@ def __init__(self, *args, **kwargs): def do_setup(self, context): self.conf.update_config_value() - self.local_cli = rest_client.RestClient( - self.configuration.san_address, - self.configuration.san_user, - self.configuration.san_password, - self.configuration.vstore_name, - self.configuration.ssl_cert_verify, - self.configuration.ssl_cert_path, - self.configuration.in_band_or_not, - self.configuration.storage_sn) + config_dict = { + 'san_address': self.configuration.san_address, + 'san_user': self.configuration.san_user, + 'san_password': self.configuration.san_password, + 'vstore_name': self.configuration.vstore_name, + 'ssl_cert_verify': self.configuration.ssl_cert_verify, + 'ssl_cert_path': self.configuration.ssl_cert_path, + 'in_band_or_not': self.configuration.in_band_or_not, + 'storage_sn': self.configuration.storage_sn + } + self.local_cli = rest_client.RestClient(config_dict) self.local_cli.login() self.configuration.is_dorado_v6 = huawei_utils.is_support_clone_pair( self.local_cli) @@ -96,24 +98,12 @@ def do_setup(self, context): if self.configuration.hypermetro: self.hypermetro_rmt_cli = rest_client.RestClient( - self.configuration.hypermetro['san_address'], - self.configuration.hypermetro['san_user'], - self.configuration.hypermetro['san_password'], - self.configuration.hypermetro['vstore_name'], - self.configuration.hypermetro['in_band_or_not'], - self.configuration.hypermetro['storage_sn'], - ) + self.configuration.hypermetro) self.hypermetro_rmt_cli.login() if self.configuration.replication: self.replication_rmt_cli = rest_client.RestClient( - self.configuration.replication['san_address'], - self.configuration.replication['san_user'], - self.configuration.replication['san_password'], - self.configuration.replication['vstore_name'], - self.configuration.replication['in_band_or_not'], - self.configuration.replication['storage_sn'], - ) + self.configuration.replication) self.replication_rmt_cli.login() def check_for_setup_error(self): diff --git a/Cinder/Zed/huawei_conf.py b/Cinder/Zed/huawei_conf.py index aa04ed7..d4ed034 100644 --- a/Cinder/Zed/huawei_conf.py +++ b/Cinder/Zed/huawei_conf.py @@ -145,21 +145,36 @@ def _san_vstore(self, xml_root): vstore = base64.b64decode(six.b(text[4:])).decode() setattr(self.conf, 'vstore_name', vstore) - def _ssl_cert_path(self, xml_root): - text = xml_root.findtext('Storage/SSLCertPath') - setattr(self.conf, 'ssl_cert_path', text) + @staticmethod + def _parser_ssl_value(ssl_value): + if ssl_value.lower() in ('true', 'false'): + return ssl_value.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) - def _ssl_cert_verify(self, xml_root): + def _get_ssl_verify(self, xml_root): value = False text = xml_root.findtext('Storage/SSLCertVerify') if text: - if text.lower() in ('true', 'false'): - value = text.lower() == 'true' - else: - msg = _("SSLCertVerify configured error.") - LOG.error(msg) - raise exception.InvalidInput(reason=msg) + value = self._parser_ssl_value(text) + return value + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.conf, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.conf, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) setattr(self.conf, 'ssl_cert_verify', value) def _set_extra_constants_by_product(self, product): @@ -382,16 +397,29 @@ def _parse_remote_initiator_info(self, dev, ini_type): self._check_hostname_regex_config(ini_info) return ini_info + def _check_ssl_valid(self, dev): + ssl_cert_verify = dev.get('ssl_cert_verify', 'false') + ssl_verify = self._parser_ssl_value(ssl_cert_verify) + ssl_cert_path = dev.get('ssl_cert_path') + if not ssl_cert_path and ssl_verify: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return ssl_verify + def _hypermetro_devices(self, xml_root): dev = self.conf.safe_get('hypermetro_device') config = {} if dev: + ssl_verify = self._check_ssl_valid(dev) config = { 'san_address': dev['san_address'].split(';'), 'san_user': dev['san_user'], 'san_password': dev['san_password'], 'vstore_name': dev.get('vstore_name'), + 'ssl_cert_verify': ssl_verify, + 'ssl_cert_path': dev.get('ssl_cert_path'), 'metro_domain': dev['metro_domain'], 'storage_pools': dev['storage_pool'].split(';')[:1], 'iscsi_info': self._parse_remote_initiator_info( @@ -414,12 +442,15 @@ def _replication_devices(self, xml_root): if replication_devs: dev = replication_devs[0] + ssl_verify = self._check_ssl_valid(dev) config = { 'backend_id': dev['backend_id'], 'san_address': dev['san_address'].split(';'), 'san_user': dev['san_user'], 'san_password': dev['san_password'], 'vstore_name': dev.get('vstore_name'), + 'ssl_cert_verify': ssl_verify, + 'ssl_cert_path': dev.get('ssl_cert_path'), 'storage_pools': dev['storage_pool'].split(';')[:1], 'iscsi_info': self._parse_remote_initiator_info( dev, 'iscsi_info'), diff --git a/Cinder/Zed/rest_client.py b/Cinder/Zed/rest_client.py index 3555e6c..9d5c923 100644 --- a/Cinder/Zed/rest_client.py +++ b/Cinder/Zed/rest_client.py @@ -1459,16 +1459,15 @@ def wrapped(self, url, **kwargs): class RestClient(object): - def __init__(self, address, user, password, vstore=None, ssl_verify=None, - cert_path=None, in_band_or_not=None, storage_sn=None): - self.san_address = address - self.san_user = user - self.san_password = password - self.vstore_name = vstore - self.ssl_verify = ssl_verify - self.cert_path = cert_path - self.in_band_or_not = in_band_or_not - self.storage_sn = storage_sn + def __init__(self, config_dict): + self.san_address = config_dict.get('san_address') + self.san_user = config_dict.get('san_user') + self.san_password = config_dict.get('san_password') + self.vstore_name = config_dict.get('vstore_name') + self.ssl_verify = config_dict.get('ssl_cert_verify') + self.cert_path = config_dict.get('ssl_cert_path') + self.in_band_or_not = config_dict.get('in_band_or_not') + self.storage_sn = config_dict.get('storage_sn') self._login_url = None self._login_device_id = None @@ -1476,12 +1475,11 @@ def __init__(self, address, user, password, vstore=None, ssl_verify=None, self._session = None self._init_object_methods() - if self.in_band_or_not: - if not self.storage_sn: - msg = _("please check 'InBandOrNot' and 'Storagesn' " - "they are invaid.") - LOG.error(msg) - raise exception.VolumeBackendAPIException(data=msg) + if self.in_band_or_not and not self.storage_sn: + msg = _("please check 'InBandOrNot' and 'Storagesn' " + "they are invaid.") + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) if not self.ssl_verify and hasattr(requests, 'packages'): LOG.warning("Suppressing requests library SSL Warnings") @@ -1560,9 +1558,7 @@ def _init_http_head(self): def _loop_login(self): self._init_http_head() - self._session.verify = False - if self.ssl_verify: - self._session.verify = self.cert_path + self._session.verify = self.cert_path if self.ssl_verify else False for url in self.san_address: try: diff --git a/ConfigDoc/en/OpenStack Cinder Driver Configuration Guide.pdf b/ConfigDoc/en/OpenStack Cinder Driver Configuration Guide.pdf index df987b3..8e4b2db 100644 Binary files a/ConfigDoc/en/OpenStack Cinder Driver Configuration Guide.pdf and b/ConfigDoc/en/OpenStack Cinder Driver Configuration Guide.pdf differ diff --git a/ConfigDoc/en/OpenStack Manila Driver Configuration Guide.pdf b/ConfigDoc/en/OpenStack Manila Driver Configuration Guide.pdf index 909cbda..d8672ed 100644 Binary files a/ConfigDoc/en/OpenStack Manila Driver Configuration Guide.pdf and b/ConfigDoc/en/OpenStack Manila Driver Configuration Guide.pdf differ diff --git "a/ConfigDoc/zh/OpenStack Cinder Driver\351\205\215\347\275\256\346\214\207\345\215\227.pdf" "b/ConfigDoc/zh/OpenStack Cinder Driver\351\205\215\347\275\256\346\214\207\345\215\227.pdf" index 0c9844d..86f1e92 100644 Binary files "a/ConfigDoc/zh/OpenStack Cinder Driver\351\205\215\347\275\256\346\214\207\345\215\227.pdf" and "b/ConfigDoc/zh/OpenStack Cinder Driver\351\205\215\347\275\256\346\214\207\345\215\227.pdf" differ diff --git "a/ConfigDoc/zh/OpenStack Manila Driver\351\205\215\347\275\256\346\214\207\345\215\227.pdf" "b/ConfigDoc/zh/OpenStack Manila Driver\351\205\215\347\275\256\346\214\207\345\215\227.pdf" index 8401a8d..7dfb2e5 100644 Binary files "a/ConfigDoc/zh/OpenStack Manila Driver\351\205\215\347\275\256\346\214\207\345\215\227.pdf" and "b/ConfigDoc/zh/OpenStack Manila Driver\351\205\215\347\275\256\346\214\207\345\215\227.pdf" differ diff --git a/Manila/Mitaka/__init__.py b/Manila/Mitaka/__init__.py index c7da93a..c4097a6 100644 --- a/Manila/Mitaka/__init__.py +++ b/Manila/Mitaka/__init__.py @@ -1 +1 @@ -"""Version: 2.6.1""" +"""Version: 2.6.2""" diff --git a/Manila/Mitaka/helper.py b/Manila/Mitaka/helper.py index f055044..93150db 100644 --- a/Manila/Mitaka/helper.py +++ b/Manila/Mitaka/helper.py @@ -50,10 +50,13 @@ def _assert_result(result, format_str, *args): class RestHelper(object): """Helper class for Huawei OceanStor V3 storage system.""" - def __init__(self, nas_address, nas_username, nas_password): + def __init__(self, nas_address, nas_username, nas_password, + ssl_cert_verify, ssl_cert_path): self.nas_address = nas_address self.nas_username = nas_username self.nas_password = nas_password + self.ssl_cert_verify = ssl_cert_verify + self.ssl_cert_path = ssl_cert_path self.url = None self.session = None self.semaphore = threading.Semaphore(30) @@ -71,7 +74,7 @@ def init_http_head(self): self.session.headers.update({ "Connection": "keep-alive", "Content-Type": "application/json"}) - self.session.verify = False + self.session.verify = self.ssl_cert_path if self.ssl_cert_verify else False def do_call(self, postfix_url, method, data=None, timeout=constants.SOCKET_TIMEOUT, **kwargs): @@ -603,7 +606,7 @@ def get_partition_id_by_name(self, name): result = self.call(url, "GET") _assert_result(result, 'Get partition by name %s error.', name) for data in result.get('data', []): - return data + return data.get('ID') def get_partition_info_by_id(self, partitionid): url = '/cachepartition/' + partitionid diff --git a/Manila/Mitaka/huawei_config.py b/Manila/Mitaka/huawei_config.py index 45400af..49c60da 100644 --- a/Manila/Mitaka/huawei_config.py +++ b/Manila/Mitaka/huawei_config.py @@ -15,6 +15,7 @@ import base64 import os +import re from oslo_log import log as logging from oslo_utils import strutils @@ -62,6 +63,10 @@ def update_configs(self): self._snapshot_reserve, self._logical_ip, self._dns, + self._unix_permission, + self._show_snapshot_dir, + self._ssl_cert_path, + self._ssl_cert_verify, ) for f in attr_funcs: @@ -248,23 +253,47 @@ def _cifs_client(self, xml_root): def _snapshot_reserve(self, xml_root): snapshot_reserve = xml_root.findtext('Filesystem/SnapshotReserve') if snapshot_reserve: - try: - snapshot_reserve = int(snapshot_reserve.strip()) - except Exception as err: - err_msg = _('Config snapshot reserve error. The reason is: ' - '%s') % err - LOG.error(err_msg) - raise exception.InvalidInput(reason=err_msg) + snapshot_reserve = snapshot_reserve.strip() + if (snapshot_reserve.isdigit() and + 0 <= int(snapshot_reserve) <= 50): + setattr(self.config, 'snapshot_reserve', int(snapshot_reserve)) - if 0 <= snapshot_reserve <= 50: - setattr(self.config, 'snapshot_reserve', snapshot_reserve) else: err_msg = _("The snapshot reservation percentage can only be " - "between 0 and 50%") + "between 0 and 50") LOG.error(err_msg) raise exception.InvalidInput(reason=err_msg) else: - setattr(self.config, 'snapshot_reserve', 20) + setattr(self.config, 'snapshot_reserve', None) + + @staticmethod + def _get_ssl_verify(xml_root): + value = False + text = xml_root.findtext('Storage/SSLCertVerify') + if text: + if text.lower() in ('true', 'false'): + value = text.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return value + + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.config, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.config, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) + setattr(self.config, 'ssl_cert_verify', value) def get_metro_info(self): metro_infos = self.config.safe_get('metro_info') @@ -283,3 +312,39 @@ def get_metro_info(self): metro_configs.append(metro_config) return metro_configs + + @staticmethod + def _check_unix_permission_valid(unix_permission): + pattern = r'^[0-7]{3}$' + if re.search(pattern, unix_permission): + return True + return False + + def _unix_permission(self, xml_root): + unix_permission = xml_root.findtext('Filesystem/UnixPermission') + if unix_permission: + unix_permission = unix_permission.strip() + + if self._check_unix_permission_valid(unix_permission): + setattr(self.config, 'unix_permission', unix_permission) + else: + err_msg = _("The UnixPermission value consists of three" + " digits and every digit can only between 0 and 7") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'unix_permission', None) + + def _show_snapshot_dir(self, xml_root): + show_snapshot_dir = xml_root.findtext('Filesystem/ShowSnapshotDir') + if show_snapshot_dir: + show_snapshot_dir = show_snapshot_dir.strip() + if show_snapshot_dir.lower() in ('true', 'false'): + setattr(self.config, 'show_snapshot_dir', show_snapshot_dir) + else: + err_msg = _("The ShowSnapshotDir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'show_snapshot_dir', None) diff --git a/Manila/Mitaka/huawei_nas.py b/Manila/Mitaka/huawei_nas.py index 35f82d9..ce4adaa 100644 --- a/Manila/Mitaka/huawei_nas.py +++ b/Manila/Mitaka/huawei_nas.py @@ -75,7 +75,7 @@ class HuaweiNasDriver(driver.ShareDriver): - VERSION = "2.6.1" + VERSION = "2.6.2" def __init__(self, *args, **kwargs): super(HuaweiNasDriver, self).__init__((True, False), *args, **kwargs) @@ -84,7 +84,8 @@ def __init__(self, *args, **kwargs): self.helper = helper.RestHelper( self.configuration.nas_address, self.configuration.nas_user, - self.configuration.nas_password) + self.configuration.nas_password, self.configuration.ssl_cert_verify, + self.configuration.ssl_cert_path) self.metro_domain = None self.remote_backend = None self.vstore_pair_id = None @@ -241,11 +242,17 @@ def _add_hypermetro(self, context, opts, params, {"fs_id": local_fs_id, "err": err}) raise + @staticmethod + def _add_optional_parameter(params, opt_params, config_param, storage_param): + if opt_params is not None: + params[storage_param] = opt_params + elif config_param is not None: + params[storage_param] = config_param + def _get_share_base_params(self, share_name, opts): params = { "NAME": huawei_utils.share_name(share_name), - "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG), - "SNAPSHOTRESERVEPER": self.configuration.snapshot_reserve + "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG) } if opts.get('sectorsize'): @@ -259,6 +266,16 @@ def _get_share_base_params(self, share_name, opts): if controller: params['OWNINGCONTROLLER'] = controller + self._add_optional_parameter( + params, opts.get('unix_permission'), + self.configuration.unix_permission, 'unixPermissions') + self._add_optional_parameter( + params, opts.get('snapshot_reserve_percentage'), + self.configuration.snapshot_reserve, 'SNAPSHOTRESERVEPER') + self._add_optional_parameter( + params, opts.get('show_snapshot_dir'), + self.configuration.show_snapshot_dir, 'ISSHOWSNAPDIR') + remote_vstore_id = None if opts.get('hypermetro') and self.vstore_pair_id: vstore_info = self.helper.get_hypermetro_vstore_by_pair_id( diff --git a/Manila/Mitaka/huawei_utils.py b/Manila/Mitaka/huawei_utils.py index 734ff03..3b941b9 100644 --- a/Manila/Mitaka/huawei_utils.py +++ b/Manila/Mitaka/huawei_utils.py @@ -75,23 +75,42 @@ def _get_opt_key(spec_key): return key_split[1] -def _get_bool_param(k, v): - words = v.split() +def _get_bool_param(key, value): + words = value.split() if len(words) == 2 and words[0] == '': return strutils.bool_from_string(words[1], strict=True) - msg = _("%(k)s spec must be specified as %(k)s=' True' " - "or ' False'.") % {'k': k} + msg = _("%(key)s spec must be specified as %(key)s=' True' " + "or ' False'.") % {'key': key} LOG.error(msg) raise exception.InvalidInput(reason=msg) -def _get_string_param(k, v): - if not v: - msg = _("%s spec must be specified as a string.") % k +def _get_string_param(key, value): + if not value: + msg = _("%s spec must be specified as a string.") % key LOG.error(msg) raise exception.InvalidInput(reason=msg) - return v + return value + + +def _get_snapshot_dir_param(key, value): + value = _get_string_param(key, value) + if value.lower() not in ('true', 'false'): + err_msg = _("The show_snapshot_dir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + return value + + +def _get_integer_param(key, value): + if value and value.isdigit(): + return int(value) + + msg = _("%s spec must be specified as an integer.") % key + LOG.error(msg) + raise exception.InvalidInput(reason=msg) def _get_opts_from_specs(specs, is_dorado): @@ -108,6 +127,9 @@ def _get_opts_from_specs(specs, is_dorado): 'huawei_smartpartition:partitionname': (_get_string_param, None), 'huawei_sectorsize:sectorsize': (_get_string_param, None), 'huawei_controller:controllername': (_get_string_param, None), + 'huawei_unixpermission:unix_permission': (_get_string_param, None), + 'huawei_snapshotreserveper:snapshot_reserve_percentage': (_get_integer_param, None), + 'huawei_showsnapshotdir:show_snapshot_dir': (_get_snapshot_dir_param, None), 'qos:iotype': (_get_string_param, None), 'qos:maxiops': (_get_string_param, None), 'qos:miniops': (_get_string_param, None), diff --git a/Manila/Newton/__init__.py b/Manila/Newton/__init__.py index c7da93a..c4097a6 100644 --- a/Manila/Newton/__init__.py +++ b/Manila/Newton/__init__.py @@ -1 +1 @@ -"""Version: 2.6.1""" +"""Version: 2.6.2""" diff --git a/Manila/Newton/helper.py b/Manila/Newton/helper.py index f055044..93150db 100644 --- a/Manila/Newton/helper.py +++ b/Manila/Newton/helper.py @@ -50,10 +50,13 @@ def _assert_result(result, format_str, *args): class RestHelper(object): """Helper class for Huawei OceanStor V3 storage system.""" - def __init__(self, nas_address, nas_username, nas_password): + def __init__(self, nas_address, nas_username, nas_password, + ssl_cert_verify, ssl_cert_path): self.nas_address = nas_address self.nas_username = nas_username self.nas_password = nas_password + self.ssl_cert_verify = ssl_cert_verify + self.ssl_cert_path = ssl_cert_path self.url = None self.session = None self.semaphore = threading.Semaphore(30) @@ -71,7 +74,7 @@ def init_http_head(self): self.session.headers.update({ "Connection": "keep-alive", "Content-Type": "application/json"}) - self.session.verify = False + self.session.verify = self.ssl_cert_path if self.ssl_cert_verify else False def do_call(self, postfix_url, method, data=None, timeout=constants.SOCKET_TIMEOUT, **kwargs): @@ -603,7 +606,7 @@ def get_partition_id_by_name(self, name): result = self.call(url, "GET") _assert_result(result, 'Get partition by name %s error.', name) for data in result.get('data', []): - return data + return data.get('ID') def get_partition_info_by_id(self, partitionid): url = '/cachepartition/' + partitionid diff --git a/Manila/Newton/huawei_config.py b/Manila/Newton/huawei_config.py index 45400af..49c60da 100644 --- a/Manila/Newton/huawei_config.py +++ b/Manila/Newton/huawei_config.py @@ -15,6 +15,7 @@ import base64 import os +import re from oslo_log import log as logging from oslo_utils import strutils @@ -62,6 +63,10 @@ def update_configs(self): self._snapshot_reserve, self._logical_ip, self._dns, + self._unix_permission, + self._show_snapshot_dir, + self._ssl_cert_path, + self._ssl_cert_verify, ) for f in attr_funcs: @@ -248,23 +253,47 @@ def _cifs_client(self, xml_root): def _snapshot_reserve(self, xml_root): snapshot_reserve = xml_root.findtext('Filesystem/SnapshotReserve') if snapshot_reserve: - try: - snapshot_reserve = int(snapshot_reserve.strip()) - except Exception as err: - err_msg = _('Config snapshot reserve error. The reason is: ' - '%s') % err - LOG.error(err_msg) - raise exception.InvalidInput(reason=err_msg) + snapshot_reserve = snapshot_reserve.strip() + if (snapshot_reserve.isdigit() and + 0 <= int(snapshot_reserve) <= 50): + setattr(self.config, 'snapshot_reserve', int(snapshot_reserve)) - if 0 <= snapshot_reserve <= 50: - setattr(self.config, 'snapshot_reserve', snapshot_reserve) else: err_msg = _("The snapshot reservation percentage can only be " - "between 0 and 50%") + "between 0 and 50") LOG.error(err_msg) raise exception.InvalidInput(reason=err_msg) else: - setattr(self.config, 'snapshot_reserve', 20) + setattr(self.config, 'snapshot_reserve', None) + + @staticmethod + def _get_ssl_verify(xml_root): + value = False + text = xml_root.findtext('Storage/SSLCertVerify') + if text: + if text.lower() in ('true', 'false'): + value = text.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return value + + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.config, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.config, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) + setattr(self.config, 'ssl_cert_verify', value) def get_metro_info(self): metro_infos = self.config.safe_get('metro_info') @@ -283,3 +312,39 @@ def get_metro_info(self): metro_configs.append(metro_config) return metro_configs + + @staticmethod + def _check_unix_permission_valid(unix_permission): + pattern = r'^[0-7]{3}$' + if re.search(pattern, unix_permission): + return True + return False + + def _unix_permission(self, xml_root): + unix_permission = xml_root.findtext('Filesystem/UnixPermission') + if unix_permission: + unix_permission = unix_permission.strip() + + if self._check_unix_permission_valid(unix_permission): + setattr(self.config, 'unix_permission', unix_permission) + else: + err_msg = _("The UnixPermission value consists of three" + " digits and every digit can only between 0 and 7") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'unix_permission', None) + + def _show_snapshot_dir(self, xml_root): + show_snapshot_dir = xml_root.findtext('Filesystem/ShowSnapshotDir') + if show_snapshot_dir: + show_snapshot_dir = show_snapshot_dir.strip() + if show_snapshot_dir.lower() in ('true', 'false'): + setattr(self.config, 'show_snapshot_dir', show_snapshot_dir) + else: + err_msg = _("The ShowSnapshotDir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'show_snapshot_dir', None) diff --git a/Manila/Newton/huawei_nas.py b/Manila/Newton/huawei_nas.py index 35f82d9..ce4adaa 100644 --- a/Manila/Newton/huawei_nas.py +++ b/Manila/Newton/huawei_nas.py @@ -75,7 +75,7 @@ class HuaweiNasDriver(driver.ShareDriver): - VERSION = "2.6.1" + VERSION = "2.6.2" def __init__(self, *args, **kwargs): super(HuaweiNasDriver, self).__init__((True, False), *args, **kwargs) @@ -84,7 +84,8 @@ def __init__(self, *args, **kwargs): self.helper = helper.RestHelper( self.configuration.nas_address, self.configuration.nas_user, - self.configuration.nas_password) + self.configuration.nas_password, self.configuration.ssl_cert_verify, + self.configuration.ssl_cert_path) self.metro_domain = None self.remote_backend = None self.vstore_pair_id = None @@ -241,11 +242,17 @@ def _add_hypermetro(self, context, opts, params, {"fs_id": local_fs_id, "err": err}) raise + @staticmethod + def _add_optional_parameter(params, opt_params, config_param, storage_param): + if opt_params is not None: + params[storage_param] = opt_params + elif config_param is not None: + params[storage_param] = config_param + def _get_share_base_params(self, share_name, opts): params = { "NAME": huawei_utils.share_name(share_name), - "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG), - "SNAPSHOTRESERVEPER": self.configuration.snapshot_reserve + "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG) } if opts.get('sectorsize'): @@ -259,6 +266,16 @@ def _get_share_base_params(self, share_name, opts): if controller: params['OWNINGCONTROLLER'] = controller + self._add_optional_parameter( + params, opts.get('unix_permission'), + self.configuration.unix_permission, 'unixPermissions') + self._add_optional_parameter( + params, opts.get('snapshot_reserve_percentage'), + self.configuration.snapshot_reserve, 'SNAPSHOTRESERVEPER') + self._add_optional_parameter( + params, opts.get('show_snapshot_dir'), + self.configuration.show_snapshot_dir, 'ISSHOWSNAPDIR') + remote_vstore_id = None if opts.get('hypermetro') and self.vstore_pair_id: vstore_info = self.helper.get_hypermetro_vstore_by_pair_id( diff --git a/Manila/Newton/huawei_utils.py b/Manila/Newton/huawei_utils.py index 734ff03..3b941b9 100644 --- a/Manila/Newton/huawei_utils.py +++ b/Manila/Newton/huawei_utils.py @@ -75,23 +75,42 @@ def _get_opt_key(spec_key): return key_split[1] -def _get_bool_param(k, v): - words = v.split() +def _get_bool_param(key, value): + words = value.split() if len(words) == 2 and words[0] == '': return strutils.bool_from_string(words[1], strict=True) - msg = _("%(k)s spec must be specified as %(k)s=' True' " - "or ' False'.") % {'k': k} + msg = _("%(key)s spec must be specified as %(key)s=' True' " + "or ' False'.") % {'key': key} LOG.error(msg) raise exception.InvalidInput(reason=msg) -def _get_string_param(k, v): - if not v: - msg = _("%s spec must be specified as a string.") % k +def _get_string_param(key, value): + if not value: + msg = _("%s spec must be specified as a string.") % key LOG.error(msg) raise exception.InvalidInput(reason=msg) - return v + return value + + +def _get_snapshot_dir_param(key, value): + value = _get_string_param(key, value) + if value.lower() not in ('true', 'false'): + err_msg = _("The show_snapshot_dir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + return value + + +def _get_integer_param(key, value): + if value and value.isdigit(): + return int(value) + + msg = _("%s spec must be specified as an integer.") % key + LOG.error(msg) + raise exception.InvalidInput(reason=msg) def _get_opts_from_specs(specs, is_dorado): @@ -108,6 +127,9 @@ def _get_opts_from_specs(specs, is_dorado): 'huawei_smartpartition:partitionname': (_get_string_param, None), 'huawei_sectorsize:sectorsize': (_get_string_param, None), 'huawei_controller:controllername': (_get_string_param, None), + 'huawei_unixpermission:unix_permission': (_get_string_param, None), + 'huawei_snapshotreserveper:snapshot_reserve_percentage': (_get_integer_param, None), + 'huawei_showsnapshotdir:show_snapshot_dir': (_get_snapshot_dir_param, None), 'qos:iotype': (_get_string_param, None), 'qos:maxiops': (_get_string_param, None), 'qos:miniops': (_get_string_param, None), diff --git a/Manila/Ocata/__init__.py b/Manila/Ocata/__init__.py index c7da93a..c4097a6 100644 --- a/Manila/Ocata/__init__.py +++ b/Manila/Ocata/__init__.py @@ -1 +1 @@ -"""Version: 2.6.1""" +"""Version: 2.6.2""" diff --git a/Manila/Ocata/helper.py b/Manila/Ocata/helper.py index f055044..93150db 100644 --- a/Manila/Ocata/helper.py +++ b/Manila/Ocata/helper.py @@ -50,10 +50,13 @@ def _assert_result(result, format_str, *args): class RestHelper(object): """Helper class for Huawei OceanStor V3 storage system.""" - def __init__(self, nas_address, nas_username, nas_password): + def __init__(self, nas_address, nas_username, nas_password, + ssl_cert_verify, ssl_cert_path): self.nas_address = nas_address self.nas_username = nas_username self.nas_password = nas_password + self.ssl_cert_verify = ssl_cert_verify + self.ssl_cert_path = ssl_cert_path self.url = None self.session = None self.semaphore = threading.Semaphore(30) @@ -71,7 +74,7 @@ def init_http_head(self): self.session.headers.update({ "Connection": "keep-alive", "Content-Type": "application/json"}) - self.session.verify = False + self.session.verify = self.ssl_cert_path if self.ssl_cert_verify else False def do_call(self, postfix_url, method, data=None, timeout=constants.SOCKET_TIMEOUT, **kwargs): @@ -603,7 +606,7 @@ def get_partition_id_by_name(self, name): result = self.call(url, "GET") _assert_result(result, 'Get partition by name %s error.', name) for data in result.get('data', []): - return data + return data.get('ID') def get_partition_info_by_id(self, partitionid): url = '/cachepartition/' + partitionid diff --git a/Manila/Ocata/huawei_config.py b/Manila/Ocata/huawei_config.py index 45400af..49c60da 100644 --- a/Manila/Ocata/huawei_config.py +++ b/Manila/Ocata/huawei_config.py @@ -15,6 +15,7 @@ import base64 import os +import re from oslo_log import log as logging from oslo_utils import strutils @@ -62,6 +63,10 @@ def update_configs(self): self._snapshot_reserve, self._logical_ip, self._dns, + self._unix_permission, + self._show_snapshot_dir, + self._ssl_cert_path, + self._ssl_cert_verify, ) for f in attr_funcs: @@ -248,23 +253,47 @@ def _cifs_client(self, xml_root): def _snapshot_reserve(self, xml_root): snapshot_reserve = xml_root.findtext('Filesystem/SnapshotReserve') if snapshot_reserve: - try: - snapshot_reserve = int(snapshot_reserve.strip()) - except Exception as err: - err_msg = _('Config snapshot reserve error. The reason is: ' - '%s') % err - LOG.error(err_msg) - raise exception.InvalidInput(reason=err_msg) + snapshot_reserve = snapshot_reserve.strip() + if (snapshot_reserve.isdigit() and + 0 <= int(snapshot_reserve) <= 50): + setattr(self.config, 'snapshot_reserve', int(snapshot_reserve)) - if 0 <= snapshot_reserve <= 50: - setattr(self.config, 'snapshot_reserve', snapshot_reserve) else: err_msg = _("The snapshot reservation percentage can only be " - "between 0 and 50%") + "between 0 and 50") LOG.error(err_msg) raise exception.InvalidInput(reason=err_msg) else: - setattr(self.config, 'snapshot_reserve', 20) + setattr(self.config, 'snapshot_reserve', None) + + @staticmethod + def _get_ssl_verify(xml_root): + value = False + text = xml_root.findtext('Storage/SSLCertVerify') + if text: + if text.lower() in ('true', 'false'): + value = text.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return value + + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.config, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.config, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) + setattr(self.config, 'ssl_cert_verify', value) def get_metro_info(self): metro_infos = self.config.safe_get('metro_info') @@ -283,3 +312,39 @@ def get_metro_info(self): metro_configs.append(metro_config) return metro_configs + + @staticmethod + def _check_unix_permission_valid(unix_permission): + pattern = r'^[0-7]{3}$' + if re.search(pattern, unix_permission): + return True + return False + + def _unix_permission(self, xml_root): + unix_permission = xml_root.findtext('Filesystem/UnixPermission') + if unix_permission: + unix_permission = unix_permission.strip() + + if self._check_unix_permission_valid(unix_permission): + setattr(self.config, 'unix_permission', unix_permission) + else: + err_msg = _("The UnixPermission value consists of three" + " digits and every digit can only between 0 and 7") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'unix_permission', None) + + def _show_snapshot_dir(self, xml_root): + show_snapshot_dir = xml_root.findtext('Filesystem/ShowSnapshotDir') + if show_snapshot_dir: + show_snapshot_dir = show_snapshot_dir.strip() + if show_snapshot_dir.lower() in ('true', 'false'): + setattr(self.config, 'show_snapshot_dir', show_snapshot_dir) + else: + err_msg = _("The ShowSnapshotDir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'show_snapshot_dir', None) diff --git a/Manila/Ocata/huawei_nas.py b/Manila/Ocata/huawei_nas.py index 35f82d9..ce4adaa 100644 --- a/Manila/Ocata/huawei_nas.py +++ b/Manila/Ocata/huawei_nas.py @@ -75,7 +75,7 @@ class HuaweiNasDriver(driver.ShareDriver): - VERSION = "2.6.1" + VERSION = "2.6.2" def __init__(self, *args, **kwargs): super(HuaweiNasDriver, self).__init__((True, False), *args, **kwargs) @@ -84,7 +84,8 @@ def __init__(self, *args, **kwargs): self.helper = helper.RestHelper( self.configuration.nas_address, self.configuration.nas_user, - self.configuration.nas_password) + self.configuration.nas_password, self.configuration.ssl_cert_verify, + self.configuration.ssl_cert_path) self.metro_domain = None self.remote_backend = None self.vstore_pair_id = None @@ -241,11 +242,17 @@ def _add_hypermetro(self, context, opts, params, {"fs_id": local_fs_id, "err": err}) raise + @staticmethod + def _add_optional_parameter(params, opt_params, config_param, storage_param): + if opt_params is not None: + params[storage_param] = opt_params + elif config_param is not None: + params[storage_param] = config_param + def _get_share_base_params(self, share_name, opts): params = { "NAME": huawei_utils.share_name(share_name), - "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG), - "SNAPSHOTRESERVEPER": self.configuration.snapshot_reserve + "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG) } if opts.get('sectorsize'): @@ -259,6 +266,16 @@ def _get_share_base_params(self, share_name, opts): if controller: params['OWNINGCONTROLLER'] = controller + self._add_optional_parameter( + params, opts.get('unix_permission'), + self.configuration.unix_permission, 'unixPermissions') + self._add_optional_parameter( + params, opts.get('snapshot_reserve_percentage'), + self.configuration.snapshot_reserve, 'SNAPSHOTRESERVEPER') + self._add_optional_parameter( + params, opts.get('show_snapshot_dir'), + self.configuration.show_snapshot_dir, 'ISSHOWSNAPDIR') + remote_vstore_id = None if opts.get('hypermetro') and self.vstore_pair_id: vstore_info = self.helper.get_hypermetro_vstore_by_pair_id( diff --git a/Manila/Ocata/huawei_utils.py b/Manila/Ocata/huawei_utils.py index 734ff03..3b941b9 100644 --- a/Manila/Ocata/huawei_utils.py +++ b/Manila/Ocata/huawei_utils.py @@ -75,23 +75,42 @@ def _get_opt_key(spec_key): return key_split[1] -def _get_bool_param(k, v): - words = v.split() +def _get_bool_param(key, value): + words = value.split() if len(words) == 2 and words[0] == '': return strutils.bool_from_string(words[1], strict=True) - msg = _("%(k)s spec must be specified as %(k)s=' True' " - "or ' False'.") % {'k': k} + msg = _("%(key)s spec must be specified as %(key)s=' True' " + "or ' False'.") % {'key': key} LOG.error(msg) raise exception.InvalidInput(reason=msg) -def _get_string_param(k, v): - if not v: - msg = _("%s spec must be specified as a string.") % k +def _get_string_param(key, value): + if not value: + msg = _("%s spec must be specified as a string.") % key LOG.error(msg) raise exception.InvalidInput(reason=msg) - return v + return value + + +def _get_snapshot_dir_param(key, value): + value = _get_string_param(key, value) + if value.lower() not in ('true', 'false'): + err_msg = _("The show_snapshot_dir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + return value + + +def _get_integer_param(key, value): + if value and value.isdigit(): + return int(value) + + msg = _("%s spec must be specified as an integer.") % key + LOG.error(msg) + raise exception.InvalidInput(reason=msg) def _get_opts_from_specs(specs, is_dorado): @@ -108,6 +127,9 @@ def _get_opts_from_specs(specs, is_dorado): 'huawei_smartpartition:partitionname': (_get_string_param, None), 'huawei_sectorsize:sectorsize': (_get_string_param, None), 'huawei_controller:controllername': (_get_string_param, None), + 'huawei_unixpermission:unix_permission': (_get_string_param, None), + 'huawei_snapshotreserveper:snapshot_reserve_percentage': (_get_integer_param, None), + 'huawei_showsnapshotdir:show_snapshot_dir': (_get_snapshot_dir_param, None), 'qos:iotype': (_get_string_param, None), 'qos:maxiops': (_get_string_param, None), 'qos:miniops': (_get_string_param, None), diff --git a/Manila/Pike/__init__.py b/Manila/Pike/__init__.py index c7da93a..c4097a6 100644 --- a/Manila/Pike/__init__.py +++ b/Manila/Pike/__init__.py @@ -1 +1 @@ -"""Version: 2.6.1""" +"""Version: 2.6.2""" diff --git a/Manila/Pike/helper.py b/Manila/Pike/helper.py index f055044..93150db 100644 --- a/Manila/Pike/helper.py +++ b/Manila/Pike/helper.py @@ -50,10 +50,13 @@ def _assert_result(result, format_str, *args): class RestHelper(object): """Helper class for Huawei OceanStor V3 storage system.""" - def __init__(self, nas_address, nas_username, nas_password): + def __init__(self, nas_address, nas_username, nas_password, + ssl_cert_verify, ssl_cert_path): self.nas_address = nas_address self.nas_username = nas_username self.nas_password = nas_password + self.ssl_cert_verify = ssl_cert_verify + self.ssl_cert_path = ssl_cert_path self.url = None self.session = None self.semaphore = threading.Semaphore(30) @@ -71,7 +74,7 @@ def init_http_head(self): self.session.headers.update({ "Connection": "keep-alive", "Content-Type": "application/json"}) - self.session.verify = False + self.session.verify = self.ssl_cert_path if self.ssl_cert_verify else False def do_call(self, postfix_url, method, data=None, timeout=constants.SOCKET_TIMEOUT, **kwargs): @@ -603,7 +606,7 @@ def get_partition_id_by_name(self, name): result = self.call(url, "GET") _assert_result(result, 'Get partition by name %s error.', name) for data in result.get('data', []): - return data + return data.get('ID') def get_partition_info_by_id(self, partitionid): url = '/cachepartition/' + partitionid diff --git a/Manila/Pike/huawei_config.py b/Manila/Pike/huawei_config.py index 45400af..49c60da 100644 --- a/Manila/Pike/huawei_config.py +++ b/Manila/Pike/huawei_config.py @@ -15,6 +15,7 @@ import base64 import os +import re from oslo_log import log as logging from oslo_utils import strutils @@ -62,6 +63,10 @@ def update_configs(self): self._snapshot_reserve, self._logical_ip, self._dns, + self._unix_permission, + self._show_snapshot_dir, + self._ssl_cert_path, + self._ssl_cert_verify, ) for f in attr_funcs: @@ -248,23 +253,47 @@ def _cifs_client(self, xml_root): def _snapshot_reserve(self, xml_root): snapshot_reserve = xml_root.findtext('Filesystem/SnapshotReserve') if snapshot_reserve: - try: - snapshot_reserve = int(snapshot_reserve.strip()) - except Exception as err: - err_msg = _('Config snapshot reserve error. The reason is: ' - '%s') % err - LOG.error(err_msg) - raise exception.InvalidInput(reason=err_msg) + snapshot_reserve = snapshot_reserve.strip() + if (snapshot_reserve.isdigit() and + 0 <= int(snapshot_reserve) <= 50): + setattr(self.config, 'snapshot_reserve', int(snapshot_reserve)) - if 0 <= snapshot_reserve <= 50: - setattr(self.config, 'snapshot_reserve', snapshot_reserve) else: err_msg = _("The snapshot reservation percentage can only be " - "between 0 and 50%") + "between 0 and 50") LOG.error(err_msg) raise exception.InvalidInput(reason=err_msg) else: - setattr(self.config, 'snapshot_reserve', 20) + setattr(self.config, 'snapshot_reserve', None) + + @staticmethod + def _get_ssl_verify(xml_root): + value = False + text = xml_root.findtext('Storage/SSLCertVerify') + if text: + if text.lower() in ('true', 'false'): + value = text.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return value + + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.config, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.config, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) + setattr(self.config, 'ssl_cert_verify', value) def get_metro_info(self): metro_infos = self.config.safe_get('metro_info') @@ -283,3 +312,39 @@ def get_metro_info(self): metro_configs.append(metro_config) return metro_configs + + @staticmethod + def _check_unix_permission_valid(unix_permission): + pattern = r'^[0-7]{3}$' + if re.search(pattern, unix_permission): + return True + return False + + def _unix_permission(self, xml_root): + unix_permission = xml_root.findtext('Filesystem/UnixPermission') + if unix_permission: + unix_permission = unix_permission.strip() + + if self._check_unix_permission_valid(unix_permission): + setattr(self.config, 'unix_permission', unix_permission) + else: + err_msg = _("The UnixPermission value consists of three" + " digits and every digit can only between 0 and 7") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'unix_permission', None) + + def _show_snapshot_dir(self, xml_root): + show_snapshot_dir = xml_root.findtext('Filesystem/ShowSnapshotDir') + if show_snapshot_dir: + show_snapshot_dir = show_snapshot_dir.strip() + if show_snapshot_dir.lower() in ('true', 'false'): + setattr(self.config, 'show_snapshot_dir', show_snapshot_dir) + else: + err_msg = _("The ShowSnapshotDir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'show_snapshot_dir', None) diff --git a/Manila/Pike/huawei_nas.py b/Manila/Pike/huawei_nas.py index 35f82d9..ce4adaa 100644 --- a/Manila/Pike/huawei_nas.py +++ b/Manila/Pike/huawei_nas.py @@ -75,7 +75,7 @@ class HuaweiNasDriver(driver.ShareDriver): - VERSION = "2.6.1" + VERSION = "2.6.2" def __init__(self, *args, **kwargs): super(HuaweiNasDriver, self).__init__((True, False), *args, **kwargs) @@ -84,7 +84,8 @@ def __init__(self, *args, **kwargs): self.helper = helper.RestHelper( self.configuration.nas_address, self.configuration.nas_user, - self.configuration.nas_password) + self.configuration.nas_password, self.configuration.ssl_cert_verify, + self.configuration.ssl_cert_path) self.metro_domain = None self.remote_backend = None self.vstore_pair_id = None @@ -241,11 +242,17 @@ def _add_hypermetro(self, context, opts, params, {"fs_id": local_fs_id, "err": err}) raise + @staticmethod + def _add_optional_parameter(params, opt_params, config_param, storage_param): + if opt_params is not None: + params[storage_param] = opt_params + elif config_param is not None: + params[storage_param] = config_param + def _get_share_base_params(self, share_name, opts): params = { "NAME": huawei_utils.share_name(share_name), - "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG), - "SNAPSHOTRESERVEPER": self.configuration.snapshot_reserve + "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG) } if opts.get('sectorsize'): @@ -259,6 +266,16 @@ def _get_share_base_params(self, share_name, opts): if controller: params['OWNINGCONTROLLER'] = controller + self._add_optional_parameter( + params, opts.get('unix_permission'), + self.configuration.unix_permission, 'unixPermissions') + self._add_optional_parameter( + params, opts.get('snapshot_reserve_percentage'), + self.configuration.snapshot_reserve, 'SNAPSHOTRESERVEPER') + self._add_optional_parameter( + params, opts.get('show_snapshot_dir'), + self.configuration.show_snapshot_dir, 'ISSHOWSNAPDIR') + remote_vstore_id = None if opts.get('hypermetro') and self.vstore_pair_id: vstore_info = self.helper.get_hypermetro_vstore_by_pair_id( diff --git a/Manila/Pike/huawei_utils.py b/Manila/Pike/huawei_utils.py index 734ff03..3b941b9 100644 --- a/Manila/Pike/huawei_utils.py +++ b/Manila/Pike/huawei_utils.py @@ -75,23 +75,42 @@ def _get_opt_key(spec_key): return key_split[1] -def _get_bool_param(k, v): - words = v.split() +def _get_bool_param(key, value): + words = value.split() if len(words) == 2 and words[0] == '': return strutils.bool_from_string(words[1], strict=True) - msg = _("%(k)s spec must be specified as %(k)s=' True' " - "or ' False'.") % {'k': k} + msg = _("%(key)s spec must be specified as %(key)s=' True' " + "or ' False'.") % {'key': key} LOG.error(msg) raise exception.InvalidInput(reason=msg) -def _get_string_param(k, v): - if not v: - msg = _("%s spec must be specified as a string.") % k +def _get_string_param(key, value): + if not value: + msg = _("%s spec must be specified as a string.") % key LOG.error(msg) raise exception.InvalidInput(reason=msg) - return v + return value + + +def _get_snapshot_dir_param(key, value): + value = _get_string_param(key, value) + if value.lower() not in ('true', 'false'): + err_msg = _("The show_snapshot_dir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + return value + + +def _get_integer_param(key, value): + if value and value.isdigit(): + return int(value) + + msg = _("%s spec must be specified as an integer.") % key + LOG.error(msg) + raise exception.InvalidInput(reason=msg) def _get_opts_from_specs(specs, is_dorado): @@ -108,6 +127,9 @@ def _get_opts_from_specs(specs, is_dorado): 'huawei_smartpartition:partitionname': (_get_string_param, None), 'huawei_sectorsize:sectorsize': (_get_string_param, None), 'huawei_controller:controllername': (_get_string_param, None), + 'huawei_unixpermission:unix_permission': (_get_string_param, None), + 'huawei_snapshotreserveper:snapshot_reserve_percentage': (_get_integer_param, None), + 'huawei_showsnapshotdir:show_snapshot_dir': (_get_snapshot_dir_param, None), 'qos:iotype': (_get_string_param, None), 'qos:maxiops': (_get_string_param, None), 'qos:miniops': (_get_string_param, None), diff --git a/Manila/Queens/__init__.py b/Manila/Queens/__init__.py index c7da93a..c4097a6 100644 --- a/Manila/Queens/__init__.py +++ b/Manila/Queens/__init__.py @@ -1 +1 @@ -"""Version: 2.6.1""" +"""Version: 2.6.2""" diff --git a/Manila/Queens/helper.py b/Manila/Queens/helper.py index f055044..93150db 100644 --- a/Manila/Queens/helper.py +++ b/Manila/Queens/helper.py @@ -50,10 +50,13 @@ def _assert_result(result, format_str, *args): class RestHelper(object): """Helper class for Huawei OceanStor V3 storage system.""" - def __init__(self, nas_address, nas_username, nas_password): + def __init__(self, nas_address, nas_username, nas_password, + ssl_cert_verify, ssl_cert_path): self.nas_address = nas_address self.nas_username = nas_username self.nas_password = nas_password + self.ssl_cert_verify = ssl_cert_verify + self.ssl_cert_path = ssl_cert_path self.url = None self.session = None self.semaphore = threading.Semaphore(30) @@ -71,7 +74,7 @@ def init_http_head(self): self.session.headers.update({ "Connection": "keep-alive", "Content-Type": "application/json"}) - self.session.verify = False + self.session.verify = self.ssl_cert_path if self.ssl_cert_verify else False def do_call(self, postfix_url, method, data=None, timeout=constants.SOCKET_TIMEOUT, **kwargs): @@ -603,7 +606,7 @@ def get_partition_id_by_name(self, name): result = self.call(url, "GET") _assert_result(result, 'Get partition by name %s error.', name) for data in result.get('data', []): - return data + return data.get('ID') def get_partition_info_by_id(self, partitionid): url = '/cachepartition/' + partitionid diff --git a/Manila/Queens/huawei_config.py b/Manila/Queens/huawei_config.py index 45400af..49c60da 100644 --- a/Manila/Queens/huawei_config.py +++ b/Manila/Queens/huawei_config.py @@ -15,6 +15,7 @@ import base64 import os +import re from oslo_log import log as logging from oslo_utils import strutils @@ -62,6 +63,10 @@ def update_configs(self): self._snapshot_reserve, self._logical_ip, self._dns, + self._unix_permission, + self._show_snapshot_dir, + self._ssl_cert_path, + self._ssl_cert_verify, ) for f in attr_funcs: @@ -248,23 +253,47 @@ def _cifs_client(self, xml_root): def _snapshot_reserve(self, xml_root): snapshot_reserve = xml_root.findtext('Filesystem/SnapshotReserve') if snapshot_reserve: - try: - snapshot_reserve = int(snapshot_reserve.strip()) - except Exception as err: - err_msg = _('Config snapshot reserve error. The reason is: ' - '%s') % err - LOG.error(err_msg) - raise exception.InvalidInput(reason=err_msg) + snapshot_reserve = snapshot_reserve.strip() + if (snapshot_reserve.isdigit() and + 0 <= int(snapshot_reserve) <= 50): + setattr(self.config, 'snapshot_reserve', int(snapshot_reserve)) - if 0 <= snapshot_reserve <= 50: - setattr(self.config, 'snapshot_reserve', snapshot_reserve) else: err_msg = _("The snapshot reservation percentage can only be " - "between 0 and 50%") + "between 0 and 50") LOG.error(err_msg) raise exception.InvalidInput(reason=err_msg) else: - setattr(self.config, 'snapshot_reserve', 20) + setattr(self.config, 'snapshot_reserve', None) + + @staticmethod + def _get_ssl_verify(xml_root): + value = False + text = xml_root.findtext('Storage/SSLCertVerify') + if text: + if text.lower() in ('true', 'false'): + value = text.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return value + + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.config, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.config, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) + setattr(self.config, 'ssl_cert_verify', value) def get_metro_info(self): metro_infos = self.config.safe_get('metro_info') @@ -283,3 +312,39 @@ def get_metro_info(self): metro_configs.append(metro_config) return metro_configs + + @staticmethod + def _check_unix_permission_valid(unix_permission): + pattern = r'^[0-7]{3}$' + if re.search(pattern, unix_permission): + return True + return False + + def _unix_permission(self, xml_root): + unix_permission = xml_root.findtext('Filesystem/UnixPermission') + if unix_permission: + unix_permission = unix_permission.strip() + + if self._check_unix_permission_valid(unix_permission): + setattr(self.config, 'unix_permission', unix_permission) + else: + err_msg = _("The UnixPermission value consists of three" + " digits and every digit can only between 0 and 7") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'unix_permission', None) + + def _show_snapshot_dir(self, xml_root): + show_snapshot_dir = xml_root.findtext('Filesystem/ShowSnapshotDir') + if show_snapshot_dir: + show_snapshot_dir = show_snapshot_dir.strip() + if show_snapshot_dir.lower() in ('true', 'false'): + setattr(self.config, 'show_snapshot_dir', show_snapshot_dir) + else: + err_msg = _("The ShowSnapshotDir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'show_snapshot_dir', None) diff --git a/Manila/Queens/huawei_nas.py b/Manila/Queens/huawei_nas.py index 35f82d9..ce4adaa 100644 --- a/Manila/Queens/huawei_nas.py +++ b/Manila/Queens/huawei_nas.py @@ -75,7 +75,7 @@ class HuaweiNasDriver(driver.ShareDriver): - VERSION = "2.6.1" + VERSION = "2.6.2" def __init__(self, *args, **kwargs): super(HuaweiNasDriver, self).__init__((True, False), *args, **kwargs) @@ -84,7 +84,8 @@ def __init__(self, *args, **kwargs): self.helper = helper.RestHelper( self.configuration.nas_address, self.configuration.nas_user, - self.configuration.nas_password) + self.configuration.nas_password, self.configuration.ssl_cert_verify, + self.configuration.ssl_cert_path) self.metro_domain = None self.remote_backend = None self.vstore_pair_id = None @@ -241,11 +242,17 @@ def _add_hypermetro(self, context, opts, params, {"fs_id": local_fs_id, "err": err}) raise + @staticmethod + def _add_optional_parameter(params, opt_params, config_param, storage_param): + if opt_params is not None: + params[storage_param] = opt_params + elif config_param is not None: + params[storage_param] = config_param + def _get_share_base_params(self, share_name, opts): params = { "NAME": huawei_utils.share_name(share_name), - "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG), - "SNAPSHOTRESERVEPER": self.configuration.snapshot_reserve + "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG) } if opts.get('sectorsize'): @@ -259,6 +266,16 @@ def _get_share_base_params(self, share_name, opts): if controller: params['OWNINGCONTROLLER'] = controller + self._add_optional_parameter( + params, opts.get('unix_permission'), + self.configuration.unix_permission, 'unixPermissions') + self._add_optional_parameter( + params, opts.get('snapshot_reserve_percentage'), + self.configuration.snapshot_reserve, 'SNAPSHOTRESERVEPER') + self._add_optional_parameter( + params, opts.get('show_snapshot_dir'), + self.configuration.show_snapshot_dir, 'ISSHOWSNAPDIR') + remote_vstore_id = None if opts.get('hypermetro') and self.vstore_pair_id: vstore_info = self.helper.get_hypermetro_vstore_by_pair_id( diff --git a/Manila/Queens/huawei_utils.py b/Manila/Queens/huawei_utils.py index 734ff03..3b941b9 100644 --- a/Manila/Queens/huawei_utils.py +++ b/Manila/Queens/huawei_utils.py @@ -75,23 +75,42 @@ def _get_opt_key(spec_key): return key_split[1] -def _get_bool_param(k, v): - words = v.split() +def _get_bool_param(key, value): + words = value.split() if len(words) == 2 and words[0] == '': return strutils.bool_from_string(words[1], strict=True) - msg = _("%(k)s spec must be specified as %(k)s=' True' " - "or ' False'.") % {'k': k} + msg = _("%(key)s spec must be specified as %(key)s=' True' " + "or ' False'.") % {'key': key} LOG.error(msg) raise exception.InvalidInput(reason=msg) -def _get_string_param(k, v): - if not v: - msg = _("%s spec must be specified as a string.") % k +def _get_string_param(key, value): + if not value: + msg = _("%s spec must be specified as a string.") % key LOG.error(msg) raise exception.InvalidInput(reason=msg) - return v + return value + + +def _get_snapshot_dir_param(key, value): + value = _get_string_param(key, value) + if value.lower() not in ('true', 'false'): + err_msg = _("The show_snapshot_dir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + return value + + +def _get_integer_param(key, value): + if value and value.isdigit(): + return int(value) + + msg = _("%s spec must be specified as an integer.") % key + LOG.error(msg) + raise exception.InvalidInput(reason=msg) def _get_opts_from_specs(specs, is_dorado): @@ -108,6 +127,9 @@ def _get_opts_from_specs(specs, is_dorado): 'huawei_smartpartition:partitionname': (_get_string_param, None), 'huawei_sectorsize:sectorsize': (_get_string_param, None), 'huawei_controller:controllername': (_get_string_param, None), + 'huawei_unixpermission:unix_permission': (_get_string_param, None), + 'huawei_snapshotreserveper:snapshot_reserve_percentage': (_get_integer_param, None), + 'huawei_showsnapshotdir:show_snapshot_dir': (_get_snapshot_dir_param, None), 'qos:iotype': (_get_string_param, None), 'qos:maxiops': (_get_string_param, None), 'qos:miniops': (_get_string_param, None), diff --git a/Manila/Rocky/__init__.py b/Manila/Rocky/__init__.py index c7da93a..c4097a6 100644 --- a/Manila/Rocky/__init__.py +++ b/Manila/Rocky/__init__.py @@ -1 +1 @@ -"""Version: 2.6.1""" +"""Version: 2.6.2""" diff --git a/Manila/Rocky/helper.py b/Manila/Rocky/helper.py index f055044..93150db 100644 --- a/Manila/Rocky/helper.py +++ b/Manila/Rocky/helper.py @@ -50,10 +50,13 @@ def _assert_result(result, format_str, *args): class RestHelper(object): """Helper class for Huawei OceanStor V3 storage system.""" - def __init__(self, nas_address, nas_username, nas_password): + def __init__(self, nas_address, nas_username, nas_password, + ssl_cert_verify, ssl_cert_path): self.nas_address = nas_address self.nas_username = nas_username self.nas_password = nas_password + self.ssl_cert_verify = ssl_cert_verify + self.ssl_cert_path = ssl_cert_path self.url = None self.session = None self.semaphore = threading.Semaphore(30) @@ -71,7 +74,7 @@ def init_http_head(self): self.session.headers.update({ "Connection": "keep-alive", "Content-Type": "application/json"}) - self.session.verify = False + self.session.verify = self.ssl_cert_path if self.ssl_cert_verify else False def do_call(self, postfix_url, method, data=None, timeout=constants.SOCKET_TIMEOUT, **kwargs): @@ -603,7 +606,7 @@ def get_partition_id_by_name(self, name): result = self.call(url, "GET") _assert_result(result, 'Get partition by name %s error.', name) for data in result.get('data', []): - return data + return data.get('ID') def get_partition_info_by_id(self, partitionid): url = '/cachepartition/' + partitionid diff --git a/Manila/Rocky/huawei_config.py b/Manila/Rocky/huawei_config.py index 45400af..49c60da 100644 --- a/Manila/Rocky/huawei_config.py +++ b/Manila/Rocky/huawei_config.py @@ -15,6 +15,7 @@ import base64 import os +import re from oslo_log import log as logging from oslo_utils import strutils @@ -62,6 +63,10 @@ def update_configs(self): self._snapshot_reserve, self._logical_ip, self._dns, + self._unix_permission, + self._show_snapshot_dir, + self._ssl_cert_path, + self._ssl_cert_verify, ) for f in attr_funcs: @@ -248,23 +253,47 @@ def _cifs_client(self, xml_root): def _snapshot_reserve(self, xml_root): snapshot_reserve = xml_root.findtext('Filesystem/SnapshotReserve') if snapshot_reserve: - try: - snapshot_reserve = int(snapshot_reserve.strip()) - except Exception as err: - err_msg = _('Config snapshot reserve error. The reason is: ' - '%s') % err - LOG.error(err_msg) - raise exception.InvalidInput(reason=err_msg) + snapshot_reserve = snapshot_reserve.strip() + if (snapshot_reserve.isdigit() and + 0 <= int(snapshot_reserve) <= 50): + setattr(self.config, 'snapshot_reserve', int(snapshot_reserve)) - if 0 <= snapshot_reserve <= 50: - setattr(self.config, 'snapshot_reserve', snapshot_reserve) else: err_msg = _("The snapshot reservation percentage can only be " - "between 0 and 50%") + "between 0 and 50") LOG.error(err_msg) raise exception.InvalidInput(reason=err_msg) else: - setattr(self.config, 'snapshot_reserve', 20) + setattr(self.config, 'snapshot_reserve', None) + + @staticmethod + def _get_ssl_verify(xml_root): + value = False + text = xml_root.findtext('Storage/SSLCertVerify') + if text: + if text.lower() in ('true', 'false'): + value = text.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return value + + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.config, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.config, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) + setattr(self.config, 'ssl_cert_verify', value) def get_metro_info(self): metro_infos = self.config.safe_get('metro_info') @@ -283,3 +312,39 @@ def get_metro_info(self): metro_configs.append(metro_config) return metro_configs + + @staticmethod + def _check_unix_permission_valid(unix_permission): + pattern = r'^[0-7]{3}$' + if re.search(pattern, unix_permission): + return True + return False + + def _unix_permission(self, xml_root): + unix_permission = xml_root.findtext('Filesystem/UnixPermission') + if unix_permission: + unix_permission = unix_permission.strip() + + if self._check_unix_permission_valid(unix_permission): + setattr(self.config, 'unix_permission', unix_permission) + else: + err_msg = _("The UnixPermission value consists of three" + " digits and every digit can only between 0 and 7") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'unix_permission', None) + + def _show_snapshot_dir(self, xml_root): + show_snapshot_dir = xml_root.findtext('Filesystem/ShowSnapshotDir') + if show_snapshot_dir: + show_snapshot_dir = show_snapshot_dir.strip() + if show_snapshot_dir.lower() in ('true', 'false'): + setattr(self.config, 'show_snapshot_dir', show_snapshot_dir) + else: + err_msg = _("The ShowSnapshotDir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'show_snapshot_dir', None) diff --git a/Manila/Rocky/huawei_nas.py b/Manila/Rocky/huawei_nas.py index 35f82d9..ce4adaa 100644 --- a/Manila/Rocky/huawei_nas.py +++ b/Manila/Rocky/huawei_nas.py @@ -75,7 +75,7 @@ class HuaweiNasDriver(driver.ShareDriver): - VERSION = "2.6.1" + VERSION = "2.6.2" def __init__(self, *args, **kwargs): super(HuaweiNasDriver, self).__init__((True, False), *args, **kwargs) @@ -84,7 +84,8 @@ def __init__(self, *args, **kwargs): self.helper = helper.RestHelper( self.configuration.nas_address, self.configuration.nas_user, - self.configuration.nas_password) + self.configuration.nas_password, self.configuration.ssl_cert_verify, + self.configuration.ssl_cert_path) self.metro_domain = None self.remote_backend = None self.vstore_pair_id = None @@ -241,11 +242,17 @@ def _add_hypermetro(self, context, opts, params, {"fs_id": local_fs_id, "err": err}) raise + @staticmethod + def _add_optional_parameter(params, opt_params, config_param, storage_param): + if opt_params is not None: + params[storage_param] = opt_params + elif config_param is not None: + params[storage_param] = config_param + def _get_share_base_params(self, share_name, opts): params = { "NAME": huawei_utils.share_name(share_name), - "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG), - "SNAPSHOTRESERVEPER": self.configuration.snapshot_reserve + "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG) } if opts.get('sectorsize'): @@ -259,6 +266,16 @@ def _get_share_base_params(self, share_name, opts): if controller: params['OWNINGCONTROLLER'] = controller + self._add_optional_parameter( + params, opts.get('unix_permission'), + self.configuration.unix_permission, 'unixPermissions') + self._add_optional_parameter( + params, opts.get('snapshot_reserve_percentage'), + self.configuration.snapshot_reserve, 'SNAPSHOTRESERVEPER') + self._add_optional_parameter( + params, opts.get('show_snapshot_dir'), + self.configuration.show_snapshot_dir, 'ISSHOWSNAPDIR') + remote_vstore_id = None if opts.get('hypermetro') and self.vstore_pair_id: vstore_info = self.helper.get_hypermetro_vstore_by_pair_id( diff --git a/Manila/Rocky/huawei_utils.py b/Manila/Rocky/huawei_utils.py index 734ff03..3b941b9 100644 --- a/Manila/Rocky/huawei_utils.py +++ b/Manila/Rocky/huawei_utils.py @@ -75,23 +75,42 @@ def _get_opt_key(spec_key): return key_split[1] -def _get_bool_param(k, v): - words = v.split() +def _get_bool_param(key, value): + words = value.split() if len(words) == 2 and words[0] == '': return strutils.bool_from_string(words[1], strict=True) - msg = _("%(k)s spec must be specified as %(k)s=' True' " - "or ' False'.") % {'k': k} + msg = _("%(key)s spec must be specified as %(key)s=' True' " + "or ' False'.") % {'key': key} LOG.error(msg) raise exception.InvalidInput(reason=msg) -def _get_string_param(k, v): - if not v: - msg = _("%s spec must be specified as a string.") % k +def _get_string_param(key, value): + if not value: + msg = _("%s spec must be specified as a string.") % key LOG.error(msg) raise exception.InvalidInput(reason=msg) - return v + return value + + +def _get_snapshot_dir_param(key, value): + value = _get_string_param(key, value) + if value.lower() not in ('true', 'false'): + err_msg = _("The show_snapshot_dir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + return value + + +def _get_integer_param(key, value): + if value and value.isdigit(): + return int(value) + + msg = _("%s spec must be specified as an integer.") % key + LOG.error(msg) + raise exception.InvalidInput(reason=msg) def _get_opts_from_specs(specs, is_dorado): @@ -108,6 +127,9 @@ def _get_opts_from_specs(specs, is_dorado): 'huawei_smartpartition:partitionname': (_get_string_param, None), 'huawei_sectorsize:sectorsize': (_get_string_param, None), 'huawei_controller:controllername': (_get_string_param, None), + 'huawei_unixpermission:unix_permission': (_get_string_param, None), + 'huawei_snapshotreserveper:snapshot_reserve_percentage': (_get_integer_param, None), + 'huawei_showsnapshotdir:show_snapshot_dir': (_get_snapshot_dir_param, None), 'qos:iotype': (_get_string_param, None), 'qos:maxiops': (_get_string_param, None), 'qos:miniops': (_get_string_param, None), diff --git a/Manila/Stein/__init__.py b/Manila/Stein/__init__.py index c7da93a..c4097a6 100644 --- a/Manila/Stein/__init__.py +++ b/Manila/Stein/__init__.py @@ -1 +1 @@ -"""Version: 2.6.1""" +"""Version: 2.6.2""" diff --git a/Manila/Stein/helper.py b/Manila/Stein/helper.py index f055044..93150db 100644 --- a/Manila/Stein/helper.py +++ b/Manila/Stein/helper.py @@ -50,10 +50,13 @@ def _assert_result(result, format_str, *args): class RestHelper(object): """Helper class for Huawei OceanStor V3 storage system.""" - def __init__(self, nas_address, nas_username, nas_password): + def __init__(self, nas_address, nas_username, nas_password, + ssl_cert_verify, ssl_cert_path): self.nas_address = nas_address self.nas_username = nas_username self.nas_password = nas_password + self.ssl_cert_verify = ssl_cert_verify + self.ssl_cert_path = ssl_cert_path self.url = None self.session = None self.semaphore = threading.Semaphore(30) @@ -71,7 +74,7 @@ def init_http_head(self): self.session.headers.update({ "Connection": "keep-alive", "Content-Type": "application/json"}) - self.session.verify = False + self.session.verify = self.ssl_cert_path if self.ssl_cert_verify else False def do_call(self, postfix_url, method, data=None, timeout=constants.SOCKET_TIMEOUT, **kwargs): @@ -603,7 +606,7 @@ def get_partition_id_by_name(self, name): result = self.call(url, "GET") _assert_result(result, 'Get partition by name %s error.', name) for data in result.get('data', []): - return data + return data.get('ID') def get_partition_info_by_id(self, partitionid): url = '/cachepartition/' + partitionid diff --git a/Manila/Stein/huawei_config.py b/Manila/Stein/huawei_config.py index 45400af..49c60da 100644 --- a/Manila/Stein/huawei_config.py +++ b/Manila/Stein/huawei_config.py @@ -15,6 +15,7 @@ import base64 import os +import re from oslo_log import log as logging from oslo_utils import strutils @@ -62,6 +63,10 @@ def update_configs(self): self._snapshot_reserve, self._logical_ip, self._dns, + self._unix_permission, + self._show_snapshot_dir, + self._ssl_cert_path, + self._ssl_cert_verify, ) for f in attr_funcs: @@ -248,23 +253,47 @@ def _cifs_client(self, xml_root): def _snapshot_reserve(self, xml_root): snapshot_reserve = xml_root.findtext('Filesystem/SnapshotReserve') if snapshot_reserve: - try: - snapshot_reserve = int(snapshot_reserve.strip()) - except Exception as err: - err_msg = _('Config snapshot reserve error. The reason is: ' - '%s') % err - LOG.error(err_msg) - raise exception.InvalidInput(reason=err_msg) + snapshot_reserve = snapshot_reserve.strip() + if (snapshot_reserve.isdigit() and + 0 <= int(snapshot_reserve) <= 50): + setattr(self.config, 'snapshot_reserve', int(snapshot_reserve)) - if 0 <= snapshot_reserve <= 50: - setattr(self.config, 'snapshot_reserve', snapshot_reserve) else: err_msg = _("The snapshot reservation percentage can only be " - "between 0 and 50%") + "between 0 and 50") LOG.error(err_msg) raise exception.InvalidInput(reason=err_msg) else: - setattr(self.config, 'snapshot_reserve', 20) + setattr(self.config, 'snapshot_reserve', None) + + @staticmethod + def _get_ssl_verify(xml_root): + value = False + text = xml_root.findtext('Storage/SSLCertVerify') + if text: + if text.lower() in ('true', 'false'): + value = text.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return value + + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.config, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.config, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) + setattr(self.config, 'ssl_cert_verify', value) def get_metro_info(self): metro_infos = self.config.safe_get('metro_info') @@ -283,3 +312,39 @@ def get_metro_info(self): metro_configs.append(metro_config) return metro_configs + + @staticmethod + def _check_unix_permission_valid(unix_permission): + pattern = r'^[0-7]{3}$' + if re.search(pattern, unix_permission): + return True + return False + + def _unix_permission(self, xml_root): + unix_permission = xml_root.findtext('Filesystem/UnixPermission') + if unix_permission: + unix_permission = unix_permission.strip() + + if self._check_unix_permission_valid(unix_permission): + setattr(self.config, 'unix_permission', unix_permission) + else: + err_msg = _("The UnixPermission value consists of three" + " digits and every digit can only between 0 and 7") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'unix_permission', None) + + def _show_snapshot_dir(self, xml_root): + show_snapshot_dir = xml_root.findtext('Filesystem/ShowSnapshotDir') + if show_snapshot_dir: + show_snapshot_dir = show_snapshot_dir.strip() + if show_snapshot_dir.lower() in ('true', 'false'): + setattr(self.config, 'show_snapshot_dir', show_snapshot_dir) + else: + err_msg = _("The ShowSnapshotDir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'show_snapshot_dir', None) diff --git a/Manila/Stein/huawei_nas.py b/Manila/Stein/huawei_nas.py index 35f82d9..ce4adaa 100644 --- a/Manila/Stein/huawei_nas.py +++ b/Manila/Stein/huawei_nas.py @@ -75,7 +75,7 @@ class HuaweiNasDriver(driver.ShareDriver): - VERSION = "2.6.1" + VERSION = "2.6.2" def __init__(self, *args, **kwargs): super(HuaweiNasDriver, self).__init__((True, False), *args, **kwargs) @@ -84,7 +84,8 @@ def __init__(self, *args, **kwargs): self.helper = helper.RestHelper( self.configuration.nas_address, self.configuration.nas_user, - self.configuration.nas_password) + self.configuration.nas_password, self.configuration.ssl_cert_verify, + self.configuration.ssl_cert_path) self.metro_domain = None self.remote_backend = None self.vstore_pair_id = None @@ -241,11 +242,17 @@ def _add_hypermetro(self, context, opts, params, {"fs_id": local_fs_id, "err": err}) raise + @staticmethod + def _add_optional_parameter(params, opt_params, config_param, storage_param): + if opt_params is not None: + params[storage_param] = opt_params + elif config_param is not None: + params[storage_param] = config_param + def _get_share_base_params(self, share_name, opts): params = { "NAME": huawei_utils.share_name(share_name), - "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG), - "SNAPSHOTRESERVEPER": self.configuration.snapshot_reserve + "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG) } if opts.get('sectorsize'): @@ -259,6 +266,16 @@ def _get_share_base_params(self, share_name, opts): if controller: params['OWNINGCONTROLLER'] = controller + self._add_optional_parameter( + params, opts.get('unix_permission'), + self.configuration.unix_permission, 'unixPermissions') + self._add_optional_parameter( + params, opts.get('snapshot_reserve_percentage'), + self.configuration.snapshot_reserve, 'SNAPSHOTRESERVEPER') + self._add_optional_parameter( + params, opts.get('show_snapshot_dir'), + self.configuration.show_snapshot_dir, 'ISSHOWSNAPDIR') + remote_vstore_id = None if opts.get('hypermetro') and self.vstore_pair_id: vstore_info = self.helper.get_hypermetro_vstore_by_pair_id( diff --git a/Manila/Stein/huawei_utils.py b/Manila/Stein/huawei_utils.py index 734ff03..3b941b9 100644 --- a/Manila/Stein/huawei_utils.py +++ b/Manila/Stein/huawei_utils.py @@ -75,23 +75,42 @@ def _get_opt_key(spec_key): return key_split[1] -def _get_bool_param(k, v): - words = v.split() +def _get_bool_param(key, value): + words = value.split() if len(words) == 2 and words[0] == '': return strutils.bool_from_string(words[1], strict=True) - msg = _("%(k)s spec must be specified as %(k)s=' True' " - "or ' False'.") % {'k': k} + msg = _("%(key)s spec must be specified as %(key)s=' True' " + "or ' False'.") % {'key': key} LOG.error(msg) raise exception.InvalidInput(reason=msg) -def _get_string_param(k, v): - if not v: - msg = _("%s spec must be specified as a string.") % k +def _get_string_param(key, value): + if not value: + msg = _("%s spec must be specified as a string.") % key LOG.error(msg) raise exception.InvalidInput(reason=msg) - return v + return value + + +def _get_snapshot_dir_param(key, value): + value = _get_string_param(key, value) + if value.lower() not in ('true', 'false'): + err_msg = _("The show_snapshot_dir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + return value + + +def _get_integer_param(key, value): + if value and value.isdigit(): + return int(value) + + msg = _("%s spec must be specified as an integer.") % key + LOG.error(msg) + raise exception.InvalidInput(reason=msg) def _get_opts_from_specs(specs, is_dorado): @@ -108,6 +127,9 @@ def _get_opts_from_specs(specs, is_dorado): 'huawei_smartpartition:partitionname': (_get_string_param, None), 'huawei_sectorsize:sectorsize': (_get_string_param, None), 'huawei_controller:controllername': (_get_string_param, None), + 'huawei_unixpermission:unix_permission': (_get_string_param, None), + 'huawei_snapshotreserveper:snapshot_reserve_percentage': (_get_integer_param, None), + 'huawei_showsnapshotdir:show_snapshot_dir': (_get_snapshot_dir_param, None), 'qos:iotype': (_get_string_param, None), 'qos:maxiops': (_get_string_param, None), 'qos:miniops': (_get_string_param, None), diff --git a/Manila/Train/__init__.py b/Manila/Train/__init__.py index c7da93a..c4097a6 100644 --- a/Manila/Train/__init__.py +++ b/Manila/Train/__init__.py @@ -1 +1 @@ -"""Version: 2.6.1""" +"""Version: 2.6.2""" diff --git a/Manila/Train/helper.py b/Manila/Train/helper.py index f055044..93150db 100644 --- a/Manila/Train/helper.py +++ b/Manila/Train/helper.py @@ -50,10 +50,13 @@ def _assert_result(result, format_str, *args): class RestHelper(object): """Helper class for Huawei OceanStor V3 storage system.""" - def __init__(self, nas_address, nas_username, nas_password): + def __init__(self, nas_address, nas_username, nas_password, + ssl_cert_verify, ssl_cert_path): self.nas_address = nas_address self.nas_username = nas_username self.nas_password = nas_password + self.ssl_cert_verify = ssl_cert_verify + self.ssl_cert_path = ssl_cert_path self.url = None self.session = None self.semaphore = threading.Semaphore(30) @@ -71,7 +74,7 @@ def init_http_head(self): self.session.headers.update({ "Connection": "keep-alive", "Content-Type": "application/json"}) - self.session.verify = False + self.session.verify = self.ssl_cert_path if self.ssl_cert_verify else False def do_call(self, postfix_url, method, data=None, timeout=constants.SOCKET_TIMEOUT, **kwargs): @@ -603,7 +606,7 @@ def get_partition_id_by_name(self, name): result = self.call(url, "GET") _assert_result(result, 'Get partition by name %s error.', name) for data in result.get('data', []): - return data + return data.get('ID') def get_partition_info_by_id(self, partitionid): url = '/cachepartition/' + partitionid diff --git a/Manila/Train/huawei_config.py b/Manila/Train/huawei_config.py index 45400af..49c60da 100644 --- a/Manila/Train/huawei_config.py +++ b/Manila/Train/huawei_config.py @@ -15,6 +15,7 @@ import base64 import os +import re from oslo_log import log as logging from oslo_utils import strutils @@ -62,6 +63,10 @@ def update_configs(self): self._snapshot_reserve, self._logical_ip, self._dns, + self._unix_permission, + self._show_snapshot_dir, + self._ssl_cert_path, + self._ssl_cert_verify, ) for f in attr_funcs: @@ -248,23 +253,47 @@ def _cifs_client(self, xml_root): def _snapshot_reserve(self, xml_root): snapshot_reserve = xml_root.findtext('Filesystem/SnapshotReserve') if snapshot_reserve: - try: - snapshot_reserve = int(snapshot_reserve.strip()) - except Exception as err: - err_msg = _('Config snapshot reserve error. The reason is: ' - '%s') % err - LOG.error(err_msg) - raise exception.InvalidInput(reason=err_msg) + snapshot_reserve = snapshot_reserve.strip() + if (snapshot_reserve.isdigit() and + 0 <= int(snapshot_reserve) <= 50): + setattr(self.config, 'snapshot_reserve', int(snapshot_reserve)) - if 0 <= snapshot_reserve <= 50: - setattr(self.config, 'snapshot_reserve', snapshot_reserve) else: err_msg = _("The snapshot reservation percentage can only be " - "between 0 and 50%") + "between 0 and 50") LOG.error(err_msg) raise exception.InvalidInput(reason=err_msg) else: - setattr(self.config, 'snapshot_reserve', 20) + setattr(self.config, 'snapshot_reserve', None) + + @staticmethod + def _get_ssl_verify(xml_root): + value = False + text = xml_root.findtext('Storage/SSLCertVerify') + if text: + if text.lower() in ('true', 'false'): + value = text.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return value + + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.config, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.config, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) + setattr(self.config, 'ssl_cert_verify', value) def get_metro_info(self): metro_infos = self.config.safe_get('metro_info') @@ -283,3 +312,39 @@ def get_metro_info(self): metro_configs.append(metro_config) return metro_configs + + @staticmethod + def _check_unix_permission_valid(unix_permission): + pattern = r'^[0-7]{3}$' + if re.search(pattern, unix_permission): + return True + return False + + def _unix_permission(self, xml_root): + unix_permission = xml_root.findtext('Filesystem/UnixPermission') + if unix_permission: + unix_permission = unix_permission.strip() + + if self._check_unix_permission_valid(unix_permission): + setattr(self.config, 'unix_permission', unix_permission) + else: + err_msg = _("The UnixPermission value consists of three" + " digits and every digit can only between 0 and 7") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'unix_permission', None) + + def _show_snapshot_dir(self, xml_root): + show_snapshot_dir = xml_root.findtext('Filesystem/ShowSnapshotDir') + if show_snapshot_dir: + show_snapshot_dir = show_snapshot_dir.strip() + if show_snapshot_dir.lower() in ('true', 'false'): + setattr(self.config, 'show_snapshot_dir', show_snapshot_dir) + else: + err_msg = _("The ShowSnapshotDir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'show_snapshot_dir', None) diff --git a/Manila/Train/huawei_nas.py b/Manila/Train/huawei_nas.py index 35f82d9..ce4adaa 100644 --- a/Manila/Train/huawei_nas.py +++ b/Manila/Train/huawei_nas.py @@ -75,7 +75,7 @@ class HuaweiNasDriver(driver.ShareDriver): - VERSION = "2.6.1" + VERSION = "2.6.2" def __init__(self, *args, **kwargs): super(HuaweiNasDriver, self).__init__((True, False), *args, **kwargs) @@ -84,7 +84,8 @@ def __init__(self, *args, **kwargs): self.helper = helper.RestHelper( self.configuration.nas_address, self.configuration.nas_user, - self.configuration.nas_password) + self.configuration.nas_password, self.configuration.ssl_cert_verify, + self.configuration.ssl_cert_path) self.metro_domain = None self.remote_backend = None self.vstore_pair_id = None @@ -241,11 +242,17 @@ def _add_hypermetro(self, context, opts, params, {"fs_id": local_fs_id, "err": err}) raise + @staticmethod + def _add_optional_parameter(params, opt_params, config_param, storage_param): + if opt_params is not None: + params[storage_param] = opt_params + elif config_param is not None: + params[storage_param] = config_param + def _get_share_base_params(self, share_name, opts): params = { "NAME": huawei_utils.share_name(share_name), - "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG), - "SNAPSHOTRESERVEPER": self.configuration.snapshot_reserve + "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG) } if opts.get('sectorsize'): @@ -259,6 +266,16 @@ def _get_share_base_params(self, share_name, opts): if controller: params['OWNINGCONTROLLER'] = controller + self._add_optional_parameter( + params, opts.get('unix_permission'), + self.configuration.unix_permission, 'unixPermissions') + self._add_optional_parameter( + params, opts.get('snapshot_reserve_percentage'), + self.configuration.snapshot_reserve, 'SNAPSHOTRESERVEPER') + self._add_optional_parameter( + params, opts.get('show_snapshot_dir'), + self.configuration.show_snapshot_dir, 'ISSHOWSNAPDIR') + remote_vstore_id = None if opts.get('hypermetro') and self.vstore_pair_id: vstore_info = self.helper.get_hypermetro_vstore_by_pair_id( diff --git a/Manila/Train/huawei_utils.py b/Manila/Train/huawei_utils.py index 734ff03..3b941b9 100644 --- a/Manila/Train/huawei_utils.py +++ b/Manila/Train/huawei_utils.py @@ -75,23 +75,42 @@ def _get_opt_key(spec_key): return key_split[1] -def _get_bool_param(k, v): - words = v.split() +def _get_bool_param(key, value): + words = value.split() if len(words) == 2 and words[0] == '': return strutils.bool_from_string(words[1], strict=True) - msg = _("%(k)s spec must be specified as %(k)s=' True' " - "or ' False'.") % {'k': k} + msg = _("%(key)s spec must be specified as %(key)s=' True' " + "or ' False'.") % {'key': key} LOG.error(msg) raise exception.InvalidInput(reason=msg) -def _get_string_param(k, v): - if not v: - msg = _("%s spec must be specified as a string.") % k +def _get_string_param(key, value): + if not value: + msg = _("%s spec must be specified as a string.") % key LOG.error(msg) raise exception.InvalidInput(reason=msg) - return v + return value + + +def _get_snapshot_dir_param(key, value): + value = _get_string_param(key, value) + if value.lower() not in ('true', 'false'): + err_msg = _("The show_snapshot_dir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + return value + + +def _get_integer_param(key, value): + if value and value.isdigit(): + return int(value) + + msg = _("%s spec must be specified as an integer.") % key + LOG.error(msg) + raise exception.InvalidInput(reason=msg) def _get_opts_from_specs(specs, is_dorado): @@ -108,6 +127,9 @@ def _get_opts_from_specs(specs, is_dorado): 'huawei_smartpartition:partitionname': (_get_string_param, None), 'huawei_sectorsize:sectorsize': (_get_string_param, None), 'huawei_controller:controllername': (_get_string_param, None), + 'huawei_unixpermission:unix_permission': (_get_string_param, None), + 'huawei_snapshotreserveper:snapshot_reserve_percentage': (_get_integer_param, None), + 'huawei_showsnapshotdir:show_snapshot_dir': (_get_snapshot_dir_param, None), 'qos:iotype': (_get_string_param, None), 'qos:maxiops': (_get_string_param, None), 'qos:miniops': (_get_string_param, None), diff --git a/Manila/Ussuri/__init__.py b/Manila/Ussuri/__init__.py index c7da93a..c4097a6 100644 --- a/Manila/Ussuri/__init__.py +++ b/Manila/Ussuri/__init__.py @@ -1 +1 @@ -"""Version: 2.6.1""" +"""Version: 2.6.2""" diff --git a/Manila/Ussuri/helper.py b/Manila/Ussuri/helper.py index f055044..93150db 100644 --- a/Manila/Ussuri/helper.py +++ b/Manila/Ussuri/helper.py @@ -50,10 +50,13 @@ def _assert_result(result, format_str, *args): class RestHelper(object): """Helper class for Huawei OceanStor V3 storage system.""" - def __init__(self, nas_address, nas_username, nas_password): + def __init__(self, nas_address, nas_username, nas_password, + ssl_cert_verify, ssl_cert_path): self.nas_address = nas_address self.nas_username = nas_username self.nas_password = nas_password + self.ssl_cert_verify = ssl_cert_verify + self.ssl_cert_path = ssl_cert_path self.url = None self.session = None self.semaphore = threading.Semaphore(30) @@ -71,7 +74,7 @@ def init_http_head(self): self.session.headers.update({ "Connection": "keep-alive", "Content-Type": "application/json"}) - self.session.verify = False + self.session.verify = self.ssl_cert_path if self.ssl_cert_verify else False def do_call(self, postfix_url, method, data=None, timeout=constants.SOCKET_TIMEOUT, **kwargs): @@ -603,7 +606,7 @@ def get_partition_id_by_name(self, name): result = self.call(url, "GET") _assert_result(result, 'Get partition by name %s error.', name) for data in result.get('data', []): - return data + return data.get('ID') def get_partition_info_by_id(self, partitionid): url = '/cachepartition/' + partitionid diff --git a/Manila/Ussuri/huawei_config.py b/Manila/Ussuri/huawei_config.py index 45400af..49c60da 100644 --- a/Manila/Ussuri/huawei_config.py +++ b/Manila/Ussuri/huawei_config.py @@ -15,6 +15,7 @@ import base64 import os +import re from oslo_log import log as logging from oslo_utils import strutils @@ -62,6 +63,10 @@ def update_configs(self): self._snapshot_reserve, self._logical_ip, self._dns, + self._unix_permission, + self._show_snapshot_dir, + self._ssl_cert_path, + self._ssl_cert_verify, ) for f in attr_funcs: @@ -248,23 +253,47 @@ def _cifs_client(self, xml_root): def _snapshot_reserve(self, xml_root): snapshot_reserve = xml_root.findtext('Filesystem/SnapshotReserve') if snapshot_reserve: - try: - snapshot_reserve = int(snapshot_reserve.strip()) - except Exception as err: - err_msg = _('Config snapshot reserve error. The reason is: ' - '%s') % err - LOG.error(err_msg) - raise exception.InvalidInput(reason=err_msg) + snapshot_reserve = snapshot_reserve.strip() + if (snapshot_reserve.isdigit() and + 0 <= int(snapshot_reserve) <= 50): + setattr(self.config, 'snapshot_reserve', int(snapshot_reserve)) - if 0 <= snapshot_reserve <= 50: - setattr(self.config, 'snapshot_reserve', snapshot_reserve) else: err_msg = _("The snapshot reservation percentage can only be " - "between 0 and 50%") + "between 0 and 50") LOG.error(err_msg) raise exception.InvalidInput(reason=err_msg) else: - setattr(self.config, 'snapshot_reserve', 20) + setattr(self.config, 'snapshot_reserve', None) + + @staticmethod + def _get_ssl_verify(xml_root): + value = False + text = xml_root.findtext('Storage/SSLCertVerify') + if text: + if text.lower() in ('true', 'false'): + value = text.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return value + + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.config, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.config, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) + setattr(self.config, 'ssl_cert_verify', value) def get_metro_info(self): metro_infos = self.config.safe_get('metro_info') @@ -283,3 +312,39 @@ def get_metro_info(self): metro_configs.append(metro_config) return metro_configs + + @staticmethod + def _check_unix_permission_valid(unix_permission): + pattern = r'^[0-7]{3}$' + if re.search(pattern, unix_permission): + return True + return False + + def _unix_permission(self, xml_root): + unix_permission = xml_root.findtext('Filesystem/UnixPermission') + if unix_permission: + unix_permission = unix_permission.strip() + + if self._check_unix_permission_valid(unix_permission): + setattr(self.config, 'unix_permission', unix_permission) + else: + err_msg = _("The UnixPermission value consists of three" + " digits and every digit can only between 0 and 7") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'unix_permission', None) + + def _show_snapshot_dir(self, xml_root): + show_snapshot_dir = xml_root.findtext('Filesystem/ShowSnapshotDir') + if show_snapshot_dir: + show_snapshot_dir = show_snapshot_dir.strip() + if show_snapshot_dir.lower() in ('true', 'false'): + setattr(self.config, 'show_snapshot_dir', show_snapshot_dir) + else: + err_msg = _("The ShowSnapshotDir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'show_snapshot_dir', None) diff --git a/Manila/Ussuri/huawei_nas.py b/Manila/Ussuri/huawei_nas.py index 42a1244..753b3c9 100644 --- a/Manila/Ussuri/huawei_nas.py +++ b/Manila/Ussuri/huawei_nas.py @@ -75,7 +75,7 @@ class HuaweiNasDriver(driver.ShareDriver): - VERSION = "2.6.1" + VERSION = "2.6.2" def __init__(self, *args, **kwargs): super(HuaweiNasDriver, self).__init__((True, False), *args, **kwargs) @@ -84,7 +84,8 @@ def __init__(self, *args, **kwargs): self.helper = helper.RestHelper( self.configuration.nas_address, self.configuration.nas_user, - self.configuration.nas_password) + self.configuration.nas_password, self.configuration.ssl_cert_verify, + self.configuration.ssl_cert_path) self.metro_domain = None self.remote_backend = None self.vstore_pair_id = None @@ -241,11 +242,17 @@ def _add_hypermetro(self, context, opts, params, {"fs_id": local_fs_id, "err": err}) raise + @staticmethod + def _add_optional_parameter(params, opt_params, config_param, storage_param): + if opt_params is not None: + params[storage_param] = opt_params + elif config_param is not None: + params[storage_param] = config_param + def _get_share_base_params(self, share_name, opts): params = { "NAME": huawei_utils.share_name(share_name), - "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG), - "SNAPSHOTRESERVEPER": self.configuration.snapshot_reserve + "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG) } if opts.get('sectorsize'): @@ -259,6 +266,16 @@ def _get_share_base_params(self, share_name, opts): if controller: params['OWNINGCONTROLLER'] = controller + self._add_optional_parameter( + params, opts.get('unix_permission'), + self.configuration.unix_permission, 'unixPermissions') + self._add_optional_parameter( + params, opts.get('snapshot_reserve_percentage'), + self.configuration.snapshot_reserve, 'SNAPSHOTRESERVEPER') + self._add_optional_parameter( + params, opts.get('show_snapshot_dir'), + self.configuration.show_snapshot_dir, 'ISSHOWSNAPDIR') + remote_vstore_id = None if opts.get('hypermetro') and self.vstore_pair_id: vstore_info = self.helper.get_hypermetro_vstore_by_pair_id( @@ -942,7 +959,7 @@ def _get_share_proto(self, snapshot): return share_proto def create_share_from_snapshot(self, context, share, - snapshot, share_server=None, + snapshot, share_server=None, parent_share=None): share_fs_info = self._get_fs_info_by_name(snapshot['share_name']) if self._is_dorado_v6_hypermetro_filesystem_not_active(share_fs_info): diff --git a/Manila/Ussuri/huawei_utils.py b/Manila/Ussuri/huawei_utils.py index 734ff03..3b941b9 100644 --- a/Manila/Ussuri/huawei_utils.py +++ b/Manila/Ussuri/huawei_utils.py @@ -75,23 +75,42 @@ def _get_opt_key(spec_key): return key_split[1] -def _get_bool_param(k, v): - words = v.split() +def _get_bool_param(key, value): + words = value.split() if len(words) == 2 and words[0] == '': return strutils.bool_from_string(words[1], strict=True) - msg = _("%(k)s spec must be specified as %(k)s=' True' " - "or ' False'.") % {'k': k} + msg = _("%(key)s spec must be specified as %(key)s=' True' " + "or ' False'.") % {'key': key} LOG.error(msg) raise exception.InvalidInput(reason=msg) -def _get_string_param(k, v): - if not v: - msg = _("%s spec must be specified as a string.") % k +def _get_string_param(key, value): + if not value: + msg = _("%s spec must be specified as a string.") % key LOG.error(msg) raise exception.InvalidInput(reason=msg) - return v + return value + + +def _get_snapshot_dir_param(key, value): + value = _get_string_param(key, value) + if value.lower() not in ('true', 'false'): + err_msg = _("The show_snapshot_dir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + return value + + +def _get_integer_param(key, value): + if value and value.isdigit(): + return int(value) + + msg = _("%s spec must be specified as an integer.") % key + LOG.error(msg) + raise exception.InvalidInput(reason=msg) def _get_opts_from_specs(specs, is_dorado): @@ -108,6 +127,9 @@ def _get_opts_from_specs(specs, is_dorado): 'huawei_smartpartition:partitionname': (_get_string_param, None), 'huawei_sectorsize:sectorsize': (_get_string_param, None), 'huawei_controller:controllername': (_get_string_param, None), + 'huawei_unixpermission:unix_permission': (_get_string_param, None), + 'huawei_snapshotreserveper:snapshot_reserve_percentage': (_get_integer_param, None), + 'huawei_showsnapshotdir:show_snapshot_dir': (_get_snapshot_dir_param, None), 'qos:iotype': (_get_string_param, None), 'qos:maxiops': (_get_string_param, None), 'qos:miniops': (_get_string_param, None), diff --git a/Manila/Victoria/__init__.py b/Manila/Victoria/__init__.py index c7da93a..c4097a6 100644 --- a/Manila/Victoria/__init__.py +++ b/Manila/Victoria/__init__.py @@ -1 +1 @@ -"""Version: 2.6.1""" +"""Version: 2.6.2""" diff --git a/Manila/Victoria/helper.py b/Manila/Victoria/helper.py index f055044..93150db 100644 --- a/Manila/Victoria/helper.py +++ b/Manila/Victoria/helper.py @@ -50,10 +50,13 @@ def _assert_result(result, format_str, *args): class RestHelper(object): """Helper class for Huawei OceanStor V3 storage system.""" - def __init__(self, nas_address, nas_username, nas_password): + def __init__(self, nas_address, nas_username, nas_password, + ssl_cert_verify, ssl_cert_path): self.nas_address = nas_address self.nas_username = nas_username self.nas_password = nas_password + self.ssl_cert_verify = ssl_cert_verify + self.ssl_cert_path = ssl_cert_path self.url = None self.session = None self.semaphore = threading.Semaphore(30) @@ -71,7 +74,7 @@ def init_http_head(self): self.session.headers.update({ "Connection": "keep-alive", "Content-Type": "application/json"}) - self.session.verify = False + self.session.verify = self.ssl_cert_path if self.ssl_cert_verify else False def do_call(self, postfix_url, method, data=None, timeout=constants.SOCKET_TIMEOUT, **kwargs): @@ -603,7 +606,7 @@ def get_partition_id_by_name(self, name): result = self.call(url, "GET") _assert_result(result, 'Get partition by name %s error.', name) for data in result.get('data', []): - return data + return data.get('ID') def get_partition_info_by_id(self, partitionid): url = '/cachepartition/' + partitionid diff --git a/Manila/Victoria/huawei_config.py b/Manila/Victoria/huawei_config.py index 45400af..49c60da 100644 --- a/Manila/Victoria/huawei_config.py +++ b/Manila/Victoria/huawei_config.py @@ -15,6 +15,7 @@ import base64 import os +import re from oslo_log import log as logging from oslo_utils import strutils @@ -62,6 +63,10 @@ def update_configs(self): self._snapshot_reserve, self._logical_ip, self._dns, + self._unix_permission, + self._show_snapshot_dir, + self._ssl_cert_path, + self._ssl_cert_verify, ) for f in attr_funcs: @@ -248,23 +253,47 @@ def _cifs_client(self, xml_root): def _snapshot_reserve(self, xml_root): snapshot_reserve = xml_root.findtext('Filesystem/SnapshotReserve') if snapshot_reserve: - try: - snapshot_reserve = int(snapshot_reserve.strip()) - except Exception as err: - err_msg = _('Config snapshot reserve error. The reason is: ' - '%s') % err - LOG.error(err_msg) - raise exception.InvalidInput(reason=err_msg) + snapshot_reserve = snapshot_reserve.strip() + if (snapshot_reserve.isdigit() and + 0 <= int(snapshot_reserve) <= 50): + setattr(self.config, 'snapshot_reserve', int(snapshot_reserve)) - if 0 <= snapshot_reserve <= 50: - setattr(self.config, 'snapshot_reserve', snapshot_reserve) else: err_msg = _("The snapshot reservation percentage can only be " - "between 0 and 50%") + "between 0 and 50") LOG.error(err_msg) raise exception.InvalidInput(reason=err_msg) else: - setattr(self.config, 'snapshot_reserve', 20) + setattr(self.config, 'snapshot_reserve', None) + + @staticmethod + def _get_ssl_verify(xml_root): + value = False + text = xml_root.findtext('Storage/SSLCertVerify') + if text: + if text.lower() in ('true', 'false'): + value = text.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return value + + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.config, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.config, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) + setattr(self.config, 'ssl_cert_verify', value) def get_metro_info(self): metro_infos = self.config.safe_get('metro_info') @@ -283,3 +312,39 @@ def get_metro_info(self): metro_configs.append(metro_config) return metro_configs + + @staticmethod + def _check_unix_permission_valid(unix_permission): + pattern = r'^[0-7]{3}$' + if re.search(pattern, unix_permission): + return True + return False + + def _unix_permission(self, xml_root): + unix_permission = xml_root.findtext('Filesystem/UnixPermission') + if unix_permission: + unix_permission = unix_permission.strip() + + if self._check_unix_permission_valid(unix_permission): + setattr(self.config, 'unix_permission', unix_permission) + else: + err_msg = _("The UnixPermission value consists of three" + " digits and every digit can only between 0 and 7") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'unix_permission', None) + + def _show_snapshot_dir(self, xml_root): + show_snapshot_dir = xml_root.findtext('Filesystem/ShowSnapshotDir') + if show_snapshot_dir: + show_snapshot_dir = show_snapshot_dir.strip() + if show_snapshot_dir.lower() in ('true', 'false'): + setattr(self.config, 'show_snapshot_dir', show_snapshot_dir) + else: + err_msg = _("The ShowSnapshotDir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'show_snapshot_dir', None) diff --git a/Manila/Victoria/huawei_nas.py b/Manila/Victoria/huawei_nas.py index 42a1244..753b3c9 100644 --- a/Manila/Victoria/huawei_nas.py +++ b/Manila/Victoria/huawei_nas.py @@ -75,7 +75,7 @@ class HuaweiNasDriver(driver.ShareDriver): - VERSION = "2.6.1" + VERSION = "2.6.2" def __init__(self, *args, **kwargs): super(HuaweiNasDriver, self).__init__((True, False), *args, **kwargs) @@ -84,7 +84,8 @@ def __init__(self, *args, **kwargs): self.helper = helper.RestHelper( self.configuration.nas_address, self.configuration.nas_user, - self.configuration.nas_password) + self.configuration.nas_password, self.configuration.ssl_cert_verify, + self.configuration.ssl_cert_path) self.metro_domain = None self.remote_backend = None self.vstore_pair_id = None @@ -241,11 +242,17 @@ def _add_hypermetro(self, context, opts, params, {"fs_id": local_fs_id, "err": err}) raise + @staticmethod + def _add_optional_parameter(params, opt_params, config_param, storage_param): + if opt_params is not None: + params[storage_param] = opt_params + elif config_param is not None: + params[storage_param] = config_param + def _get_share_base_params(self, share_name, opts): params = { "NAME": huawei_utils.share_name(share_name), - "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG), - "SNAPSHOTRESERVEPER": self.configuration.snapshot_reserve + "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG) } if opts.get('sectorsize'): @@ -259,6 +266,16 @@ def _get_share_base_params(self, share_name, opts): if controller: params['OWNINGCONTROLLER'] = controller + self._add_optional_parameter( + params, opts.get('unix_permission'), + self.configuration.unix_permission, 'unixPermissions') + self._add_optional_parameter( + params, opts.get('snapshot_reserve_percentage'), + self.configuration.snapshot_reserve, 'SNAPSHOTRESERVEPER') + self._add_optional_parameter( + params, opts.get('show_snapshot_dir'), + self.configuration.show_snapshot_dir, 'ISSHOWSNAPDIR') + remote_vstore_id = None if opts.get('hypermetro') and self.vstore_pair_id: vstore_info = self.helper.get_hypermetro_vstore_by_pair_id( @@ -942,7 +959,7 @@ def _get_share_proto(self, snapshot): return share_proto def create_share_from_snapshot(self, context, share, - snapshot, share_server=None, + snapshot, share_server=None, parent_share=None): share_fs_info = self._get_fs_info_by_name(snapshot['share_name']) if self._is_dorado_v6_hypermetro_filesystem_not_active(share_fs_info): diff --git a/Manila/Victoria/huawei_utils.py b/Manila/Victoria/huawei_utils.py index 734ff03..3b941b9 100644 --- a/Manila/Victoria/huawei_utils.py +++ b/Manila/Victoria/huawei_utils.py @@ -75,23 +75,42 @@ def _get_opt_key(spec_key): return key_split[1] -def _get_bool_param(k, v): - words = v.split() +def _get_bool_param(key, value): + words = value.split() if len(words) == 2 and words[0] == '': return strutils.bool_from_string(words[1], strict=True) - msg = _("%(k)s spec must be specified as %(k)s=' True' " - "or ' False'.") % {'k': k} + msg = _("%(key)s spec must be specified as %(key)s=' True' " + "or ' False'.") % {'key': key} LOG.error(msg) raise exception.InvalidInput(reason=msg) -def _get_string_param(k, v): - if not v: - msg = _("%s spec must be specified as a string.") % k +def _get_string_param(key, value): + if not value: + msg = _("%s spec must be specified as a string.") % key LOG.error(msg) raise exception.InvalidInput(reason=msg) - return v + return value + + +def _get_snapshot_dir_param(key, value): + value = _get_string_param(key, value) + if value.lower() not in ('true', 'false'): + err_msg = _("The show_snapshot_dir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + return value + + +def _get_integer_param(key, value): + if value and value.isdigit(): + return int(value) + + msg = _("%s spec must be specified as an integer.") % key + LOG.error(msg) + raise exception.InvalidInput(reason=msg) def _get_opts_from_specs(specs, is_dorado): @@ -108,6 +127,9 @@ def _get_opts_from_specs(specs, is_dorado): 'huawei_smartpartition:partitionname': (_get_string_param, None), 'huawei_sectorsize:sectorsize': (_get_string_param, None), 'huawei_controller:controllername': (_get_string_param, None), + 'huawei_unixpermission:unix_permission': (_get_string_param, None), + 'huawei_snapshotreserveper:snapshot_reserve_percentage': (_get_integer_param, None), + 'huawei_showsnapshotdir:show_snapshot_dir': (_get_snapshot_dir_param, None), 'qos:iotype': (_get_string_param, None), 'qos:maxiops': (_get_string_param, None), 'qos:miniops': (_get_string_param, None), diff --git a/Manila/Wallaby/__init__.py b/Manila/Wallaby/__init__.py index c7da93a..c4097a6 100644 --- a/Manila/Wallaby/__init__.py +++ b/Manila/Wallaby/__init__.py @@ -1 +1 @@ -"""Version: 2.6.1""" +"""Version: 2.6.2""" diff --git a/Manila/Wallaby/helper.py b/Manila/Wallaby/helper.py index f055044..93150db 100644 --- a/Manila/Wallaby/helper.py +++ b/Manila/Wallaby/helper.py @@ -50,10 +50,13 @@ def _assert_result(result, format_str, *args): class RestHelper(object): """Helper class for Huawei OceanStor V3 storage system.""" - def __init__(self, nas_address, nas_username, nas_password): + def __init__(self, nas_address, nas_username, nas_password, + ssl_cert_verify, ssl_cert_path): self.nas_address = nas_address self.nas_username = nas_username self.nas_password = nas_password + self.ssl_cert_verify = ssl_cert_verify + self.ssl_cert_path = ssl_cert_path self.url = None self.session = None self.semaphore = threading.Semaphore(30) @@ -71,7 +74,7 @@ def init_http_head(self): self.session.headers.update({ "Connection": "keep-alive", "Content-Type": "application/json"}) - self.session.verify = False + self.session.verify = self.ssl_cert_path if self.ssl_cert_verify else False def do_call(self, postfix_url, method, data=None, timeout=constants.SOCKET_TIMEOUT, **kwargs): @@ -603,7 +606,7 @@ def get_partition_id_by_name(self, name): result = self.call(url, "GET") _assert_result(result, 'Get partition by name %s error.', name) for data in result.get('data', []): - return data + return data.get('ID') def get_partition_info_by_id(self, partitionid): url = '/cachepartition/' + partitionid diff --git a/Manila/Wallaby/huawei_config.py b/Manila/Wallaby/huawei_config.py index 45400af..49c60da 100644 --- a/Manila/Wallaby/huawei_config.py +++ b/Manila/Wallaby/huawei_config.py @@ -15,6 +15,7 @@ import base64 import os +import re from oslo_log import log as logging from oslo_utils import strutils @@ -62,6 +63,10 @@ def update_configs(self): self._snapshot_reserve, self._logical_ip, self._dns, + self._unix_permission, + self._show_snapshot_dir, + self._ssl_cert_path, + self._ssl_cert_verify, ) for f in attr_funcs: @@ -248,23 +253,47 @@ def _cifs_client(self, xml_root): def _snapshot_reserve(self, xml_root): snapshot_reserve = xml_root.findtext('Filesystem/SnapshotReserve') if snapshot_reserve: - try: - snapshot_reserve = int(snapshot_reserve.strip()) - except Exception as err: - err_msg = _('Config snapshot reserve error. The reason is: ' - '%s') % err - LOG.error(err_msg) - raise exception.InvalidInput(reason=err_msg) + snapshot_reserve = snapshot_reserve.strip() + if (snapshot_reserve.isdigit() and + 0 <= int(snapshot_reserve) <= 50): + setattr(self.config, 'snapshot_reserve', int(snapshot_reserve)) - if 0 <= snapshot_reserve <= 50: - setattr(self.config, 'snapshot_reserve', snapshot_reserve) else: err_msg = _("The snapshot reservation percentage can only be " - "between 0 and 50%") + "between 0 and 50") LOG.error(err_msg) raise exception.InvalidInput(reason=err_msg) else: - setattr(self.config, 'snapshot_reserve', 20) + setattr(self.config, 'snapshot_reserve', None) + + @staticmethod + def _get_ssl_verify(xml_root): + value = False + text = xml_root.findtext('Storage/SSLCertVerify') + if text: + if text.lower() in ('true', 'false'): + value = text.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return value + + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.config, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.config, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) + setattr(self.config, 'ssl_cert_verify', value) def get_metro_info(self): metro_infos = self.config.safe_get('metro_info') @@ -283,3 +312,39 @@ def get_metro_info(self): metro_configs.append(metro_config) return metro_configs + + @staticmethod + def _check_unix_permission_valid(unix_permission): + pattern = r'^[0-7]{3}$' + if re.search(pattern, unix_permission): + return True + return False + + def _unix_permission(self, xml_root): + unix_permission = xml_root.findtext('Filesystem/UnixPermission') + if unix_permission: + unix_permission = unix_permission.strip() + + if self._check_unix_permission_valid(unix_permission): + setattr(self.config, 'unix_permission', unix_permission) + else: + err_msg = _("The UnixPermission value consists of three" + " digits and every digit can only between 0 and 7") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'unix_permission', None) + + def _show_snapshot_dir(self, xml_root): + show_snapshot_dir = xml_root.findtext('Filesystem/ShowSnapshotDir') + if show_snapshot_dir: + show_snapshot_dir = show_snapshot_dir.strip() + if show_snapshot_dir.lower() in ('true', 'false'): + setattr(self.config, 'show_snapshot_dir', show_snapshot_dir) + else: + err_msg = _("The ShowSnapshotDir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'show_snapshot_dir', None) diff --git a/Manila/Wallaby/huawei_nas.py b/Manila/Wallaby/huawei_nas.py index 42a1244..753b3c9 100644 --- a/Manila/Wallaby/huawei_nas.py +++ b/Manila/Wallaby/huawei_nas.py @@ -75,7 +75,7 @@ class HuaweiNasDriver(driver.ShareDriver): - VERSION = "2.6.1" + VERSION = "2.6.2" def __init__(self, *args, **kwargs): super(HuaweiNasDriver, self).__init__((True, False), *args, **kwargs) @@ -84,7 +84,8 @@ def __init__(self, *args, **kwargs): self.helper = helper.RestHelper( self.configuration.nas_address, self.configuration.nas_user, - self.configuration.nas_password) + self.configuration.nas_password, self.configuration.ssl_cert_verify, + self.configuration.ssl_cert_path) self.metro_domain = None self.remote_backend = None self.vstore_pair_id = None @@ -241,11 +242,17 @@ def _add_hypermetro(self, context, opts, params, {"fs_id": local_fs_id, "err": err}) raise + @staticmethod + def _add_optional_parameter(params, opt_params, config_param, storage_param): + if opt_params is not None: + params[storage_param] = opt_params + elif config_param is not None: + params[storage_param] = config_param + def _get_share_base_params(self, share_name, opts): params = { "NAME": huawei_utils.share_name(share_name), - "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG), - "SNAPSHOTRESERVEPER": self.configuration.snapshot_reserve + "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG) } if opts.get('sectorsize'): @@ -259,6 +266,16 @@ def _get_share_base_params(self, share_name, opts): if controller: params['OWNINGCONTROLLER'] = controller + self._add_optional_parameter( + params, opts.get('unix_permission'), + self.configuration.unix_permission, 'unixPermissions') + self._add_optional_parameter( + params, opts.get('snapshot_reserve_percentage'), + self.configuration.snapshot_reserve, 'SNAPSHOTRESERVEPER') + self._add_optional_parameter( + params, opts.get('show_snapshot_dir'), + self.configuration.show_snapshot_dir, 'ISSHOWSNAPDIR') + remote_vstore_id = None if opts.get('hypermetro') and self.vstore_pair_id: vstore_info = self.helper.get_hypermetro_vstore_by_pair_id( @@ -942,7 +959,7 @@ def _get_share_proto(self, snapshot): return share_proto def create_share_from_snapshot(self, context, share, - snapshot, share_server=None, + snapshot, share_server=None, parent_share=None): share_fs_info = self._get_fs_info_by_name(snapshot['share_name']) if self._is_dorado_v6_hypermetro_filesystem_not_active(share_fs_info): diff --git a/Manila/Wallaby/huawei_utils.py b/Manila/Wallaby/huawei_utils.py index 734ff03..3b941b9 100644 --- a/Manila/Wallaby/huawei_utils.py +++ b/Manila/Wallaby/huawei_utils.py @@ -75,23 +75,42 @@ def _get_opt_key(spec_key): return key_split[1] -def _get_bool_param(k, v): - words = v.split() +def _get_bool_param(key, value): + words = value.split() if len(words) == 2 and words[0] == '': return strutils.bool_from_string(words[1], strict=True) - msg = _("%(k)s spec must be specified as %(k)s=' True' " - "or ' False'.") % {'k': k} + msg = _("%(key)s spec must be specified as %(key)s=' True' " + "or ' False'.") % {'key': key} LOG.error(msg) raise exception.InvalidInput(reason=msg) -def _get_string_param(k, v): - if not v: - msg = _("%s spec must be specified as a string.") % k +def _get_string_param(key, value): + if not value: + msg = _("%s spec must be specified as a string.") % key LOG.error(msg) raise exception.InvalidInput(reason=msg) - return v + return value + + +def _get_snapshot_dir_param(key, value): + value = _get_string_param(key, value) + if value.lower() not in ('true', 'false'): + err_msg = _("The show_snapshot_dir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + return value + + +def _get_integer_param(key, value): + if value and value.isdigit(): + return int(value) + + msg = _("%s spec must be specified as an integer.") % key + LOG.error(msg) + raise exception.InvalidInput(reason=msg) def _get_opts_from_specs(specs, is_dorado): @@ -108,6 +127,9 @@ def _get_opts_from_specs(specs, is_dorado): 'huawei_smartpartition:partitionname': (_get_string_param, None), 'huawei_sectorsize:sectorsize': (_get_string_param, None), 'huawei_controller:controllername': (_get_string_param, None), + 'huawei_unixpermission:unix_permission': (_get_string_param, None), + 'huawei_snapshotreserveper:snapshot_reserve_percentage': (_get_integer_param, None), + 'huawei_showsnapshotdir:show_snapshot_dir': (_get_snapshot_dir_param, None), 'qos:iotype': (_get_string_param, None), 'qos:maxiops': (_get_string_param, None), 'qos:miniops': (_get_string_param, None), diff --git a/Manila/Xena/__init__.py b/Manila/Xena/__init__.py index c7da93a..c4097a6 100644 --- a/Manila/Xena/__init__.py +++ b/Manila/Xena/__init__.py @@ -1 +1 @@ -"""Version: 2.6.1""" +"""Version: 2.6.2""" diff --git a/Manila/Xena/helper.py b/Manila/Xena/helper.py index f055044..93150db 100644 --- a/Manila/Xena/helper.py +++ b/Manila/Xena/helper.py @@ -50,10 +50,13 @@ def _assert_result(result, format_str, *args): class RestHelper(object): """Helper class for Huawei OceanStor V3 storage system.""" - def __init__(self, nas_address, nas_username, nas_password): + def __init__(self, nas_address, nas_username, nas_password, + ssl_cert_verify, ssl_cert_path): self.nas_address = nas_address self.nas_username = nas_username self.nas_password = nas_password + self.ssl_cert_verify = ssl_cert_verify + self.ssl_cert_path = ssl_cert_path self.url = None self.session = None self.semaphore = threading.Semaphore(30) @@ -71,7 +74,7 @@ def init_http_head(self): self.session.headers.update({ "Connection": "keep-alive", "Content-Type": "application/json"}) - self.session.verify = False + self.session.verify = self.ssl_cert_path if self.ssl_cert_verify else False def do_call(self, postfix_url, method, data=None, timeout=constants.SOCKET_TIMEOUT, **kwargs): @@ -603,7 +606,7 @@ def get_partition_id_by_name(self, name): result = self.call(url, "GET") _assert_result(result, 'Get partition by name %s error.', name) for data in result.get('data', []): - return data + return data.get('ID') def get_partition_info_by_id(self, partitionid): url = '/cachepartition/' + partitionid diff --git a/Manila/Xena/huawei_config.py b/Manila/Xena/huawei_config.py index 45400af..49c60da 100644 --- a/Manila/Xena/huawei_config.py +++ b/Manila/Xena/huawei_config.py @@ -15,6 +15,7 @@ import base64 import os +import re from oslo_log import log as logging from oslo_utils import strutils @@ -62,6 +63,10 @@ def update_configs(self): self._snapshot_reserve, self._logical_ip, self._dns, + self._unix_permission, + self._show_snapshot_dir, + self._ssl_cert_path, + self._ssl_cert_verify, ) for f in attr_funcs: @@ -248,23 +253,47 @@ def _cifs_client(self, xml_root): def _snapshot_reserve(self, xml_root): snapshot_reserve = xml_root.findtext('Filesystem/SnapshotReserve') if snapshot_reserve: - try: - snapshot_reserve = int(snapshot_reserve.strip()) - except Exception as err: - err_msg = _('Config snapshot reserve error. The reason is: ' - '%s') % err - LOG.error(err_msg) - raise exception.InvalidInput(reason=err_msg) + snapshot_reserve = snapshot_reserve.strip() + if (snapshot_reserve.isdigit() and + 0 <= int(snapshot_reserve) <= 50): + setattr(self.config, 'snapshot_reserve', int(snapshot_reserve)) - if 0 <= snapshot_reserve <= 50: - setattr(self.config, 'snapshot_reserve', snapshot_reserve) else: err_msg = _("The snapshot reservation percentage can only be " - "between 0 and 50%") + "between 0 and 50") LOG.error(err_msg) raise exception.InvalidInput(reason=err_msg) else: - setattr(self.config, 'snapshot_reserve', 20) + setattr(self.config, 'snapshot_reserve', None) + + @staticmethod + def _get_ssl_verify(xml_root): + value = False + text = xml_root.findtext('Storage/SSLCertVerify') + if text: + if text.lower() in ('true', 'false'): + value = text.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return value + + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.config, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.config, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) + setattr(self.config, 'ssl_cert_verify', value) def get_metro_info(self): metro_infos = self.config.safe_get('metro_info') @@ -283,3 +312,39 @@ def get_metro_info(self): metro_configs.append(metro_config) return metro_configs + + @staticmethod + def _check_unix_permission_valid(unix_permission): + pattern = r'^[0-7]{3}$' + if re.search(pattern, unix_permission): + return True + return False + + def _unix_permission(self, xml_root): + unix_permission = xml_root.findtext('Filesystem/UnixPermission') + if unix_permission: + unix_permission = unix_permission.strip() + + if self._check_unix_permission_valid(unix_permission): + setattr(self.config, 'unix_permission', unix_permission) + else: + err_msg = _("The UnixPermission value consists of three" + " digits and every digit can only between 0 and 7") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'unix_permission', None) + + def _show_snapshot_dir(self, xml_root): + show_snapshot_dir = xml_root.findtext('Filesystem/ShowSnapshotDir') + if show_snapshot_dir: + show_snapshot_dir = show_snapshot_dir.strip() + if show_snapshot_dir.lower() in ('true', 'false'): + setattr(self.config, 'show_snapshot_dir', show_snapshot_dir) + else: + err_msg = _("The ShowSnapshotDir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'show_snapshot_dir', None) diff --git a/Manila/Xena/huawei_nas.py b/Manila/Xena/huawei_nas.py index 42a1244..753b3c9 100644 --- a/Manila/Xena/huawei_nas.py +++ b/Manila/Xena/huawei_nas.py @@ -75,7 +75,7 @@ class HuaweiNasDriver(driver.ShareDriver): - VERSION = "2.6.1" + VERSION = "2.6.2" def __init__(self, *args, **kwargs): super(HuaweiNasDriver, self).__init__((True, False), *args, **kwargs) @@ -84,7 +84,8 @@ def __init__(self, *args, **kwargs): self.helper = helper.RestHelper( self.configuration.nas_address, self.configuration.nas_user, - self.configuration.nas_password) + self.configuration.nas_password, self.configuration.ssl_cert_verify, + self.configuration.ssl_cert_path) self.metro_domain = None self.remote_backend = None self.vstore_pair_id = None @@ -241,11 +242,17 @@ def _add_hypermetro(self, context, opts, params, {"fs_id": local_fs_id, "err": err}) raise + @staticmethod + def _add_optional_parameter(params, opt_params, config_param, storage_param): + if opt_params is not None: + params[storage_param] = opt_params + elif config_param is not None: + params[storage_param] = config_param + def _get_share_base_params(self, share_name, opts): params = { "NAME": huawei_utils.share_name(share_name), - "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG), - "SNAPSHOTRESERVEPER": self.configuration.snapshot_reserve + "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG) } if opts.get('sectorsize'): @@ -259,6 +266,16 @@ def _get_share_base_params(self, share_name, opts): if controller: params['OWNINGCONTROLLER'] = controller + self._add_optional_parameter( + params, opts.get('unix_permission'), + self.configuration.unix_permission, 'unixPermissions') + self._add_optional_parameter( + params, opts.get('snapshot_reserve_percentage'), + self.configuration.snapshot_reserve, 'SNAPSHOTRESERVEPER') + self._add_optional_parameter( + params, opts.get('show_snapshot_dir'), + self.configuration.show_snapshot_dir, 'ISSHOWSNAPDIR') + remote_vstore_id = None if opts.get('hypermetro') and self.vstore_pair_id: vstore_info = self.helper.get_hypermetro_vstore_by_pair_id( @@ -942,7 +959,7 @@ def _get_share_proto(self, snapshot): return share_proto def create_share_from_snapshot(self, context, share, - snapshot, share_server=None, + snapshot, share_server=None, parent_share=None): share_fs_info = self._get_fs_info_by_name(snapshot['share_name']) if self._is_dorado_v6_hypermetro_filesystem_not_active(share_fs_info): diff --git a/Manila/Xena/huawei_utils.py b/Manila/Xena/huawei_utils.py index 97ea907..5b4709d 100644 --- a/Manila/Xena/huawei_utils.py +++ b/Manila/Xena/huawei_utils.py @@ -75,23 +75,42 @@ def _get_opt_key(spec_key): return key_split[1] -def _get_bool_param(k, v): - words = v.split() +def _get_bool_param(key, value): + words = value.split() if len(words) == 2 and words[0] == '': return strutils.bool_from_string(words[1], strict=True) - msg = _("%(k)s spec must be specified as %(k)s=' True' " - "or ' False'.") % {'k': k} + msg = _("%(key)s spec must be specified as %(key)s=' True' " + "or ' False'.") % {'key': key} LOG.error(msg) raise exception.InvalidInput(reason=msg) -def _get_string_param(k, v): - if not v: - msg = _("%s spec must be specified as a string.") % k +def _get_string_param(key, value): + if not value: + msg = _("%s spec must be specified as a string.") % key LOG.error(msg) raise exception.InvalidInput(reason=msg) - return v + return value + + +def _get_snapshot_dir_param(key, value): + value = _get_string_param(key, value) + if value.lower() not in ('true', 'false'): + err_msg = _("The show_snapshot_dir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + return value + + +def _get_integer_param(key, value): + if value and value.isdigit(): + return int(value) + + msg = _("%s spec must be specified as an integer.") % key + LOG.error(msg) + raise exception.InvalidInput(reason=msg) def _get_opts_from_specs(specs, is_dorado): @@ -108,6 +127,9 @@ def _get_opts_from_specs(specs, is_dorado): 'huawei_smartpartition:partitionname': (_get_string_param, None), 'huawei_sectorsize:sectorsize': (_get_string_param, None), 'huawei_controller:controllername': (_get_string_param, None), + 'huawei_unixpermission:unix_permission': (_get_string_param, None), + 'huawei_snapshotreserveper:snapshot_reserve_percentage': (_get_integer_param, None), + 'huawei_showsnapshotdir:show_snapshot_dir': (_get_snapshot_dir_param, None), 'qos:iotype': (_get_string_param, None), 'qos:maxiops': (_get_string_param, None), 'qos:miniops': (_get_string_param, None), diff --git a/Manila/Yoga/__init__.py b/Manila/Yoga/__init__.py index c7da93a..c4097a6 100644 --- a/Manila/Yoga/__init__.py +++ b/Manila/Yoga/__init__.py @@ -1 +1 @@ -"""Version: 2.6.1""" +"""Version: 2.6.2""" diff --git a/Manila/Yoga/helper.py b/Manila/Yoga/helper.py index f055044..93150db 100644 --- a/Manila/Yoga/helper.py +++ b/Manila/Yoga/helper.py @@ -50,10 +50,13 @@ def _assert_result(result, format_str, *args): class RestHelper(object): """Helper class for Huawei OceanStor V3 storage system.""" - def __init__(self, nas_address, nas_username, nas_password): + def __init__(self, nas_address, nas_username, nas_password, + ssl_cert_verify, ssl_cert_path): self.nas_address = nas_address self.nas_username = nas_username self.nas_password = nas_password + self.ssl_cert_verify = ssl_cert_verify + self.ssl_cert_path = ssl_cert_path self.url = None self.session = None self.semaphore = threading.Semaphore(30) @@ -71,7 +74,7 @@ def init_http_head(self): self.session.headers.update({ "Connection": "keep-alive", "Content-Type": "application/json"}) - self.session.verify = False + self.session.verify = self.ssl_cert_path if self.ssl_cert_verify else False def do_call(self, postfix_url, method, data=None, timeout=constants.SOCKET_TIMEOUT, **kwargs): @@ -603,7 +606,7 @@ def get_partition_id_by_name(self, name): result = self.call(url, "GET") _assert_result(result, 'Get partition by name %s error.', name) for data in result.get('data', []): - return data + return data.get('ID') def get_partition_info_by_id(self, partitionid): url = '/cachepartition/' + partitionid diff --git a/Manila/Yoga/huawei_config.py b/Manila/Yoga/huawei_config.py index 45400af..49c60da 100644 --- a/Manila/Yoga/huawei_config.py +++ b/Manila/Yoga/huawei_config.py @@ -15,6 +15,7 @@ import base64 import os +import re from oslo_log import log as logging from oslo_utils import strutils @@ -62,6 +63,10 @@ def update_configs(self): self._snapshot_reserve, self._logical_ip, self._dns, + self._unix_permission, + self._show_snapshot_dir, + self._ssl_cert_path, + self._ssl_cert_verify, ) for f in attr_funcs: @@ -248,23 +253,47 @@ def _cifs_client(self, xml_root): def _snapshot_reserve(self, xml_root): snapshot_reserve = xml_root.findtext('Filesystem/SnapshotReserve') if snapshot_reserve: - try: - snapshot_reserve = int(snapshot_reserve.strip()) - except Exception as err: - err_msg = _('Config snapshot reserve error. The reason is: ' - '%s') % err - LOG.error(err_msg) - raise exception.InvalidInput(reason=err_msg) + snapshot_reserve = snapshot_reserve.strip() + if (snapshot_reserve.isdigit() and + 0 <= int(snapshot_reserve) <= 50): + setattr(self.config, 'snapshot_reserve', int(snapshot_reserve)) - if 0 <= snapshot_reserve <= 50: - setattr(self.config, 'snapshot_reserve', snapshot_reserve) else: err_msg = _("The snapshot reservation percentage can only be " - "between 0 and 50%") + "between 0 and 50") LOG.error(err_msg) raise exception.InvalidInput(reason=err_msg) else: - setattr(self.config, 'snapshot_reserve', 20) + setattr(self.config, 'snapshot_reserve', None) + + @staticmethod + def _get_ssl_verify(xml_root): + value = False + text = xml_root.findtext('Storage/SSLCertVerify') + if text: + if text.lower() in ('true', 'false'): + value = text.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return value + + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.config, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.config, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) + setattr(self.config, 'ssl_cert_verify', value) def get_metro_info(self): metro_infos = self.config.safe_get('metro_info') @@ -283,3 +312,39 @@ def get_metro_info(self): metro_configs.append(metro_config) return metro_configs + + @staticmethod + def _check_unix_permission_valid(unix_permission): + pattern = r'^[0-7]{3}$' + if re.search(pattern, unix_permission): + return True + return False + + def _unix_permission(self, xml_root): + unix_permission = xml_root.findtext('Filesystem/UnixPermission') + if unix_permission: + unix_permission = unix_permission.strip() + + if self._check_unix_permission_valid(unix_permission): + setattr(self.config, 'unix_permission', unix_permission) + else: + err_msg = _("The UnixPermission value consists of three" + " digits and every digit can only between 0 and 7") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'unix_permission', None) + + def _show_snapshot_dir(self, xml_root): + show_snapshot_dir = xml_root.findtext('Filesystem/ShowSnapshotDir') + if show_snapshot_dir: + show_snapshot_dir = show_snapshot_dir.strip() + if show_snapshot_dir.lower() in ('true', 'false'): + setattr(self.config, 'show_snapshot_dir', show_snapshot_dir) + else: + err_msg = _("The ShowSnapshotDir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'show_snapshot_dir', None) diff --git a/Manila/Yoga/huawei_nas.py b/Manila/Yoga/huawei_nas.py index 42a1244..753b3c9 100644 --- a/Manila/Yoga/huawei_nas.py +++ b/Manila/Yoga/huawei_nas.py @@ -75,7 +75,7 @@ class HuaweiNasDriver(driver.ShareDriver): - VERSION = "2.6.1" + VERSION = "2.6.2" def __init__(self, *args, **kwargs): super(HuaweiNasDriver, self).__init__((True, False), *args, **kwargs) @@ -84,7 +84,8 @@ def __init__(self, *args, **kwargs): self.helper = helper.RestHelper( self.configuration.nas_address, self.configuration.nas_user, - self.configuration.nas_password) + self.configuration.nas_password, self.configuration.ssl_cert_verify, + self.configuration.ssl_cert_path) self.metro_domain = None self.remote_backend = None self.vstore_pair_id = None @@ -241,11 +242,17 @@ def _add_hypermetro(self, context, opts, params, {"fs_id": local_fs_id, "err": err}) raise + @staticmethod + def _add_optional_parameter(params, opt_params, config_param, storage_param): + if opt_params is not None: + params[storage_param] = opt_params + elif config_param is not None: + params[storage_param] = config_param + def _get_share_base_params(self, share_name, opts): params = { "NAME": huawei_utils.share_name(share_name), - "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG), - "SNAPSHOTRESERVEPER": self.configuration.snapshot_reserve + "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG) } if opts.get('sectorsize'): @@ -259,6 +266,16 @@ def _get_share_base_params(self, share_name, opts): if controller: params['OWNINGCONTROLLER'] = controller + self._add_optional_parameter( + params, opts.get('unix_permission'), + self.configuration.unix_permission, 'unixPermissions') + self._add_optional_parameter( + params, opts.get('snapshot_reserve_percentage'), + self.configuration.snapshot_reserve, 'SNAPSHOTRESERVEPER') + self._add_optional_parameter( + params, opts.get('show_snapshot_dir'), + self.configuration.show_snapshot_dir, 'ISSHOWSNAPDIR') + remote_vstore_id = None if opts.get('hypermetro') and self.vstore_pair_id: vstore_info = self.helper.get_hypermetro_vstore_by_pair_id( @@ -942,7 +959,7 @@ def _get_share_proto(self, snapshot): return share_proto def create_share_from_snapshot(self, context, share, - snapshot, share_server=None, + snapshot, share_server=None, parent_share=None): share_fs_info = self._get_fs_info_by_name(snapshot['share_name']) if self._is_dorado_v6_hypermetro_filesystem_not_active(share_fs_info): diff --git a/Manila/Yoga/huawei_utils.py b/Manila/Yoga/huawei_utils.py index 97ea907..5b4709d 100644 --- a/Manila/Yoga/huawei_utils.py +++ b/Manila/Yoga/huawei_utils.py @@ -75,23 +75,42 @@ def _get_opt_key(spec_key): return key_split[1] -def _get_bool_param(k, v): - words = v.split() +def _get_bool_param(key, value): + words = value.split() if len(words) == 2 and words[0] == '': return strutils.bool_from_string(words[1], strict=True) - msg = _("%(k)s spec must be specified as %(k)s=' True' " - "or ' False'.") % {'k': k} + msg = _("%(key)s spec must be specified as %(key)s=' True' " + "or ' False'.") % {'key': key} LOG.error(msg) raise exception.InvalidInput(reason=msg) -def _get_string_param(k, v): - if not v: - msg = _("%s spec must be specified as a string.") % k +def _get_string_param(key, value): + if not value: + msg = _("%s spec must be specified as a string.") % key LOG.error(msg) raise exception.InvalidInput(reason=msg) - return v + return value + + +def _get_snapshot_dir_param(key, value): + value = _get_string_param(key, value) + if value.lower() not in ('true', 'false'): + err_msg = _("The show_snapshot_dir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + return value + + +def _get_integer_param(key, value): + if value and value.isdigit(): + return int(value) + + msg = _("%s spec must be specified as an integer.") % key + LOG.error(msg) + raise exception.InvalidInput(reason=msg) def _get_opts_from_specs(specs, is_dorado): @@ -108,6 +127,9 @@ def _get_opts_from_specs(specs, is_dorado): 'huawei_smartpartition:partitionname': (_get_string_param, None), 'huawei_sectorsize:sectorsize': (_get_string_param, None), 'huawei_controller:controllername': (_get_string_param, None), + 'huawei_unixpermission:unix_permission': (_get_string_param, None), + 'huawei_snapshotreserveper:snapshot_reserve_percentage': (_get_integer_param, None), + 'huawei_showsnapshotdir:show_snapshot_dir': (_get_snapshot_dir_param, None), 'qos:iotype': (_get_string_param, None), 'qos:maxiops': (_get_string_param, None), 'qos:miniops': (_get_string_param, None), diff --git a/Manila/Zed/__init__.py b/Manila/Zed/__init__.py index c7da93a..c4097a6 100644 --- a/Manila/Zed/__init__.py +++ b/Manila/Zed/__init__.py @@ -1 +1 @@ -"""Version: 2.6.1""" +"""Version: 2.6.2""" diff --git a/Manila/Zed/helper.py b/Manila/Zed/helper.py index f055044..93150db 100644 --- a/Manila/Zed/helper.py +++ b/Manila/Zed/helper.py @@ -50,10 +50,13 @@ def _assert_result(result, format_str, *args): class RestHelper(object): """Helper class for Huawei OceanStor V3 storage system.""" - def __init__(self, nas_address, nas_username, nas_password): + def __init__(self, nas_address, nas_username, nas_password, + ssl_cert_verify, ssl_cert_path): self.nas_address = nas_address self.nas_username = nas_username self.nas_password = nas_password + self.ssl_cert_verify = ssl_cert_verify + self.ssl_cert_path = ssl_cert_path self.url = None self.session = None self.semaphore = threading.Semaphore(30) @@ -71,7 +74,7 @@ def init_http_head(self): self.session.headers.update({ "Connection": "keep-alive", "Content-Type": "application/json"}) - self.session.verify = False + self.session.verify = self.ssl_cert_path if self.ssl_cert_verify else False def do_call(self, postfix_url, method, data=None, timeout=constants.SOCKET_TIMEOUT, **kwargs): @@ -603,7 +606,7 @@ def get_partition_id_by_name(self, name): result = self.call(url, "GET") _assert_result(result, 'Get partition by name %s error.', name) for data in result.get('data', []): - return data + return data.get('ID') def get_partition_info_by_id(self, partitionid): url = '/cachepartition/' + partitionid diff --git a/Manila/Zed/huawei_config.py b/Manila/Zed/huawei_config.py index 45400af..49c60da 100644 --- a/Manila/Zed/huawei_config.py +++ b/Manila/Zed/huawei_config.py @@ -15,6 +15,7 @@ import base64 import os +import re from oslo_log import log as logging from oslo_utils import strutils @@ -62,6 +63,10 @@ def update_configs(self): self._snapshot_reserve, self._logical_ip, self._dns, + self._unix_permission, + self._show_snapshot_dir, + self._ssl_cert_path, + self._ssl_cert_verify, ) for f in attr_funcs: @@ -248,23 +253,47 @@ def _cifs_client(self, xml_root): def _snapshot_reserve(self, xml_root): snapshot_reserve = xml_root.findtext('Filesystem/SnapshotReserve') if snapshot_reserve: - try: - snapshot_reserve = int(snapshot_reserve.strip()) - except Exception as err: - err_msg = _('Config snapshot reserve error. The reason is: ' - '%s') % err - LOG.error(err_msg) - raise exception.InvalidInput(reason=err_msg) + snapshot_reserve = snapshot_reserve.strip() + if (snapshot_reserve.isdigit() and + 0 <= int(snapshot_reserve) <= 50): + setattr(self.config, 'snapshot_reserve', int(snapshot_reserve)) - if 0 <= snapshot_reserve <= 50: - setattr(self.config, 'snapshot_reserve', snapshot_reserve) else: err_msg = _("The snapshot reservation percentage can only be " - "between 0 and 50%") + "between 0 and 50") LOG.error(err_msg) raise exception.InvalidInput(reason=err_msg) else: - setattr(self.config, 'snapshot_reserve', 20) + setattr(self.config, 'snapshot_reserve', None) + + @staticmethod + def _get_ssl_verify(xml_root): + value = False + text = xml_root.findtext('Storage/SSLCertVerify') + if text: + if text.lower() in ('true', 'false'): + value = text.lower() == 'true' + else: + msg = _("SSLCertVerify configured error.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + return value + + def _ssl_cert_path(self, xml_root): + text = xml_root.findtext('Storage/SSLCertPath') + ssl_value = self._get_ssl_verify(xml_root) + if text and ssl_value: + setattr(self.config, 'ssl_cert_path', text) + elif not text and ssl_value: + msg = _("Cert path is necessary if SSLCertVerify is True.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + else: + setattr(self.config, 'ssl_cert_path', None) + + def _ssl_cert_verify(self, xml_root): + value = self._get_ssl_verify(xml_root) + setattr(self.config, 'ssl_cert_verify', value) def get_metro_info(self): metro_infos = self.config.safe_get('metro_info') @@ -283,3 +312,39 @@ def get_metro_info(self): metro_configs.append(metro_config) return metro_configs + + @staticmethod + def _check_unix_permission_valid(unix_permission): + pattern = r'^[0-7]{3}$' + if re.search(pattern, unix_permission): + return True + return False + + def _unix_permission(self, xml_root): + unix_permission = xml_root.findtext('Filesystem/UnixPermission') + if unix_permission: + unix_permission = unix_permission.strip() + + if self._check_unix_permission_valid(unix_permission): + setattr(self.config, 'unix_permission', unix_permission) + else: + err_msg = _("The UnixPermission value consists of three" + " digits and every digit can only between 0 and 7") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'unix_permission', None) + + def _show_snapshot_dir(self, xml_root): + show_snapshot_dir = xml_root.findtext('Filesystem/ShowSnapshotDir') + if show_snapshot_dir: + show_snapshot_dir = show_snapshot_dir.strip() + if show_snapshot_dir.lower() in ('true', 'false'): + setattr(self.config, 'show_snapshot_dir', show_snapshot_dir) + else: + err_msg = _("The ShowSnapshotDir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + else: + setattr(self.config, 'show_snapshot_dir', None) diff --git a/Manila/Zed/huawei_nas.py b/Manila/Zed/huawei_nas.py index 42a1244..753b3c9 100644 --- a/Manila/Zed/huawei_nas.py +++ b/Manila/Zed/huawei_nas.py @@ -75,7 +75,7 @@ class HuaweiNasDriver(driver.ShareDriver): - VERSION = "2.6.1" + VERSION = "2.6.2" def __init__(self, *args, **kwargs): super(HuaweiNasDriver, self).__init__((True, False), *args, **kwargs) @@ -84,7 +84,8 @@ def __init__(self, *args, **kwargs): self.helper = helper.RestHelper( self.configuration.nas_address, self.configuration.nas_user, - self.configuration.nas_password) + self.configuration.nas_password, self.configuration.ssl_cert_verify, + self.configuration.ssl_cert_path) self.metro_domain = None self.remote_backend = None self.vstore_pair_id = None @@ -241,11 +242,17 @@ def _add_hypermetro(self, context, opts, params, {"fs_id": local_fs_id, "err": err}) raise + @staticmethod + def _add_optional_parameter(params, opt_params, config_param, storage_param): + if opt_params is not None: + params[storage_param] = opt_params + elif config_param is not None: + params[storage_param] = config_param + def _get_share_base_params(self, share_name, opts): params = { "NAME": huawei_utils.share_name(share_name), - "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG), - "SNAPSHOTRESERVEPER": self.configuration.snapshot_reserve + "ALLOCTYPE": opts.get('LUNType', constants.ALLOC_TYPE_THIN_FLAG) } if opts.get('sectorsize'): @@ -259,6 +266,16 @@ def _get_share_base_params(self, share_name, opts): if controller: params['OWNINGCONTROLLER'] = controller + self._add_optional_parameter( + params, opts.get('unix_permission'), + self.configuration.unix_permission, 'unixPermissions') + self._add_optional_parameter( + params, opts.get('snapshot_reserve_percentage'), + self.configuration.snapshot_reserve, 'SNAPSHOTRESERVEPER') + self._add_optional_parameter( + params, opts.get('show_snapshot_dir'), + self.configuration.show_snapshot_dir, 'ISSHOWSNAPDIR') + remote_vstore_id = None if opts.get('hypermetro') and self.vstore_pair_id: vstore_info = self.helper.get_hypermetro_vstore_by_pair_id( @@ -942,7 +959,7 @@ def _get_share_proto(self, snapshot): return share_proto def create_share_from_snapshot(self, context, share, - snapshot, share_server=None, + snapshot, share_server=None, parent_share=None): share_fs_info = self._get_fs_info_by_name(snapshot['share_name']) if self._is_dorado_v6_hypermetro_filesystem_not_active(share_fs_info): diff --git a/Manila/Zed/huawei_utils.py b/Manila/Zed/huawei_utils.py index 97ea907..5b4709d 100644 --- a/Manila/Zed/huawei_utils.py +++ b/Manila/Zed/huawei_utils.py @@ -75,23 +75,42 @@ def _get_opt_key(spec_key): return key_split[1] -def _get_bool_param(k, v): - words = v.split() +def _get_bool_param(key, value): + words = value.split() if len(words) == 2 and words[0] == '': return strutils.bool_from_string(words[1], strict=True) - msg = _("%(k)s spec must be specified as %(k)s=' True' " - "or ' False'.") % {'k': k} + msg = _("%(key)s spec must be specified as %(key)s=' True' " + "or ' False'.") % {'key': key} LOG.error(msg) raise exception.InvalidInput(reason=msg) -def _get_string_param(k, v): - if not v: - msg = _("%s spec must be specified as a string.") % k +def _get_string_param(key, value): + if not value: + msg = _("%s spec must be specified as a string.") % key LOG.error(msg) raise exception.InvalidInput(reason=msg) - return v + return value + + +def _get_snapshot_dir_param(key, value): + value = _get_string_param(key, value) + if value.lower() not in ('true', 'false'): + err_msg = _("The show_snapshot_dir value consists " + "can only be 'true' or 'false'") + LOG.error(err_msg) + raise exception.InvalidInput(reason=err_msg) + return value + + +def _get_integer_param(key, value): + if value and value.isdigit(): + return int(value) + + msg = _("%s spec must be specified as an integer.") % key + LOG.error(msg) + raise exception.InvalidInput(reason=msg) def _get_opts_from_specs(specs, is_dorado): @@ -108,6 +127,9 @@ def _get_opts_from_specs(specs, is_dorado): 'huawei_smartpartition:partitionname': (_get_string_param, None), 'huawei_sectorsize:sectorsize': (_get_string_param, None), 'huawei_controller:controllername': (_get_string_param, None), + 'huawei_unixpermission:unix_permission': (_get_string_param, None), + 'huawei_snapshotreserveper:snapshot_reserve_percentage': (_get_integer_param, None), + 'huawei_showsnapshotdir:show_snapshot_dir': (_get_snapshot_dir_param, None), 'qos:iotype': (_get_string_param, None), 'qos:maxiops': (_get_string_param, None), 'qos:miniops': (_get_string_param, None),