From fde58110015639f9ac9ab63ef04515a0cd3dac3f Mon Sep 17 00:00:00 2001 From: Bin Qian Date: Thu, 28 Nov 2019 09:02:16 -0500 Subject: [PATCH] Add per-host board management protocol setting in sysinv Use bm_type field to store board management protocol setting, available bm protocols: redfish ipmi dynamic none (bm is not provisioned) The old service parameter bmc_access_method is removed. Partial-Bug: 1852328 Change-Id: I5097e53f6fc1bfbe23d2a1b765b5bc0e25423c22 Signed-off-by: Bin Qian --- sysinv/sysinv/centos/build_srpm.data | 2 +- .../sysinv/sysinv/api/controllers/v1/host.py | 86 ++++++++----------- .../sysinv/sysinv/sysinv/common/constants.py | 19 +++- .../sysinv/sysinv/common/service_parameter.py | 26 ------ .../sysinv/sysinv/sysinv/conductor/manager.py | 5 -- .../sysinv/sysinv/tests/api/test_host.py | 40 +++++++++ sysinv/sysinv/sysinv/sysinv/tests/db/utils.py | 2 +- 7 files changed, 94 insertions(+), 86 deletions(-) diff --git a/sysinv/sysinv/centos/build_srpm.data b/sysinv/sysinv/centos/build_srpm.data index 7636a3baf9..c5b92b6896 100644 --- a/sysinv/sysinv/centos/build_srpm.data +++ b/sysinv/sysinv/centos/build_srpm.data @@ -1,2 +1,2 @@ SRC_DIR="sysinv" -TIS_PATCH_VER=339 +TIS_PATCH_VER=340 diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py index 2ed0fdb24f..19fae91d62 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py @@ -1396,14 +1396,24 @@ class HostController(rest.RestController): delta.add(key) ihost_orig[key] = defaults[key] - bm_list = ['bm_type', 'bm_ip', - 'bm_username', 'bm_password'] + bm_list = ['bm_ip', 'bm_username', 'bm_password'] for bmi in bm_list: if bmi in ihost_dict: delta.add(bmi) changed_paths.append({'path': '/' + str(bmi), 'value': ihost_dict[bmi], 'op': 'replace'}) + if ihost_dict.get('bm_ip') and ihost_dict.get('bm_username'): + implict_bm_type = constants.HOST_BM_TYPE_DEFAULT + else: + implict_bm_type = constants.HOST_BM_TYPE_DEPROVISIONED + + if ihost_dict.get('bm_type') is None: + ihost_dict['bm_type'] = implict_bm_type + delta.add('bm_type') + changed_paths.append({'path': '/bm_type', + 'value': ihost_dict['bm_type'], + 'op': 'replace'}) self._bm_semantic_check_and_update(ihost_orig, ihost_dict, delta, changed_paths, @@ -3808,15 +3818,24 @@ class HostController(rest.RestController): password_exists = password_exists and patch_bm_password is not None - bm_type_orig = ohost.get('bm_type') or "" - bm_type_patch = phost.get('bm_type') or "" - if bm_type_patch.lower() == 'none': - bm_type_patch = '' - if (not bm_type_patch) and (bm_type_orig != bm_type_patch): - LOG.info("bm_type None from %s to %s." % - (ohost['bm_type'], phost['bm_type'])) + bm_type_patch = phost.get('bm_type') + # Semantic Check: Validate BM type against supported list + if bm_type_patch not in constants.HOST_BM_VALID_TYPE_LIST: + raise wsme.exc.ClientSideError( + _("%s: Rejected: '%s' is not a supported board management " + "type. Must be one of %s" % + (phost['hostname'], + phost['bm_type'], + constants.HOST_BM_VALID_TYPE_LIST))) - bm_type_changed_to_none = True + bm_type_orig = ohost.get('bm_type') + if bm_type_orig != bm_type_patch: + if bm_type_patch == constants.HOST_BM_TYPE_DEPROVISIONED: + LOG.info("BM is to be deprovisioned") + bm_type_changed_to_none = True + else: + LOG.info("BM type %s is changed to %s" % + (bm_type_orig, bm_type_patch)) if 'bm_ip' in delta: obm_ip = ohost['bm_ip'] or "" @@ -3831,50 +3850,19 @@ class HostController(rest.RestController): "controller IP Address is not user-modifiable." % (constants.REGION_PRIMARY, phost['hostname']))) - if (phost['bm_ip'] or phost['bm_type'] or phost['bm_username']): - if (not phost['bm_type'] or - (phost['bm_type'] and phost['bm_type'].lower() == - constants.BM_TYPE_NONE)) and not bm_type_changed_to_none: - raise wsme.exc.ClientSideError( - _("%s: Rejected: Board Management controller Type " - "is not provisioned. Provisionable values: 'bmc'." - % phost['hostname'])) + if phost['bm_ip'] or phost['bm_type'] or phost['bm_username']: + if bm_type_patch == constants.HOST_BM_TYPE_DEPROVISIONED: + if not bm_type_changed_to_none: + raise wsme.exc.ClientSideError( + _("%s: Rejected: Board Management controller Type " + "is not provisioned. Provisionable values: '%s'." % + (phost['hostname'], + constants.HOST_BM_VALID_PROVISIONED_TYPE_LIST))) elif not phost['bm_username']: raise wsme.exc.ClientSideError( _("%s: Rejected: Board Management controller username " "is not configured." % phost['hostname'])) - # Semantic Check: Validate BM type against supported list - # ilo, quanta is kept for backwards compatability only - valid_bm_type_list = [None, 'None', constants.BM_TYPE_NONE, - constants.BM_TYPE_GENERIC, - 'ilo', 'ilo3', 'ilo4', 'quanta'] - - if not phost['bm_type']: - phost['bm_type'] = None - - if not (phost['bm_type'] in valid_bm_type_list): - raise wsme.exc.ClientSideError( - _("%s: Rejected: '%s' is not a supported board management " - "type. Must be one of %s" % - (phost['hostname'], - phost['bm_type'], - valid_bm_type_list))) - - bm_type_str = phost['bm_type'] - if (phost['bm_type'] and - bm_type_str.lower() != constants.BM_TYPE_NONE): - LOG.info("Updating bm_type from %s to %s" % - (phost['bm_type'], constants.BM_TYPE_GENERIC)) - phost['bm_type'] = constants.BM_TYPE_GENERIC - if hostupdate: - hostupdate.ihost_val_update( - {'bm_type': constants.BM_TYPE_GENERIC}) - else: - phost['bm_type'] = None - if hostupdate: - hostupdate.ihost_val_update({'bm_type': None}) - if (phost['bm_type'] and phost['bm_ip'] and (ohost['bm_ip'] != phost['bm_ip'])): if not cutils.is_valid_ip(phost['bm_ip']): diff --git a/sysinv/sysinv/sysinv/sysinv/common/constants.py b/sysinv/sysinv/sysinv/sysinv/common/constants.py index d1da2bbd0a..f2bf94666e 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/constants.py +++ b/sysinv/sysinv/sysinv/sysinv/common/constants.py @@ -154,8 +154,6 @@ FORCE_LOCKING = "Force Locking" OPERATIONAL_ENABLED = 'enabled' OPERATIONAL_DISABLED = 'disabled' -BM_TYPE_GENERIC = 'bmc' -BM_TYPE_NONE = 'none' PROVISIONED = 'provisioned' PROVISIONING = 'provisioning' UNPROVISIONED = 'unprovisioned' @@ -956,7 +954,6 @@ SERVICE_PARAM_PLAT_MTCE_HBS_FAILURE_THRESHOLD = 'heartbeat_failure_threshold' SERVICE_PARAM_PLAT_MTCE_HBS_DEGRADE_THRESHOLD = 'heartbeat_degrade_threshold' SERVICE_PARAM_PLAT_MTCE_MNFA_THRESHOLD = 'mnfa_threshold' SERVICE_PARAM_PLAT_MTCE_MNFA_TIMEOUT = 'mnfa_timeout' -SERVICE_PARAM_PLAT_MTCE_BMC_ACCESS_METHOD = 'bmc_access_method' SERVICE_PARAM_PLAT_MTCE_WORKER_BOOT_TIMEOUT_DEFAULT = 720 SERVICE_PARAM_PLAT_MTCE_CONTROLLER_BOOT_TIMEOUT_DEFAULT = 1200 @@ -966,7 +963,6 @@ SERVICE_PARAM_PLAT_MTCE_HBS_FAILURE_THRESHOLD_DEFAULT = 10 SERVICE_PARAM_PLAT_MTCE_HBS_DEGRADE_THRESHOLD_DEFAULT = 6 SERVICE_PARAM_PLAT_MTCE_MNFA_THRESHOLD_DEFAULT = 2 SERVICE_PARAM_PLAT_MTCE_MNFA_TIMEOUT_DEFAULT = 0 -SERVICE_PARAM_PLAT_MTCE_BMC_ACCESS_METHOD_DEFAULT = 'learn' # default time to live seconds PM_TTL_DEFAULT = 86400 @@ -1540,3 +1536,18 @@ MELLANOX_DRIVERS = [DRIVER_MLX_CX3, # Traffic control TRAFFIC_CONTROL_SCRIPT = '/usr/local/bin/tc_setup.sh' + +# Host Board Management Constants +HOST_BM_TYPE_DEPROVISIONED = "none" +HOST_BM_TYPE_IPMI = "ipmi" +HOST_BM_TYPE_REDFISH = "redfish" +HOST_BM_TYPE_DYNAMIC = "dynamic" +HOST_BM_TYPE_DEFAULT = HOST_BM_TYPE_DYNAMIC + +HOST_BM_VALID_TYPE_LIST = [HOST_BM_TYPE_DEPROVISIONED, + HOST_BM_TYPE_DYNAMIC, + HOST_BM_TYPE_IPMI, + HOST_BM_TYPE_REDFISH] +HOST_BM_VALID_PROVISIONED_TYPE_LIST = [HOST_BM_TYPE_DYNAMIC, + HOST_BM_TYPE_IPMI, + HOST_BM_TYPE_REDFISH] diff --git a/sysinv/sysinv/sysinv/sysinv/common/service_parameter.py b/sysinv/sysinv/sysinv/sysinv/common/service_parameter.py index 78241931be..e72b9bb661 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/service_parameter.py +++ b/sysinv/sysinv/sysinv/sysinv/common/service_parameter.py @@ -228,25 +228,6 @@ def _validate_mnfa_timeout(name, value): SERVICE_PARAM_PLAT_MTCE_MNFA_TIMEOUT_MAX) -def _validate_bmc_access_method(name, value): - error = False - try: - if str(value) != SERVICE_PARAM_PLAT_MTCE_BMC_ACCESS_METHOD_LEARN and \ - str(value) != SERVICE_PARAM_PLAT_MTCE_BMC_ACCESS_METHOD_IPMI and \ - str(value) != SERVICE_PARAM_PLAT_MTCE_BMC_ACCESS_METHOD_REDFISH: - error = True - - except ValueError: - error = True - - if error is True: - raise wsme.exc.ClientSideError(_( - "Method must be one of '%s', '%s' or '%s'" % - (SERVICE_PARAM_PLAT_MTCE_BMC_ACCESS_METHOD_LEARN, - SERVICE_PARAM_PLAT_MTCE_BMC_ACCESS_METHOD_IPMI, - SERVICE_PARAM_PLAT_MTCE_BMC_ACCESS_METHOD_REDFISH))) - - def _validate_ipv4(name, value): """Check if router_id value is valid""" if not netaddr.valid_ipv4(value): @@ -369,7 +350,6 @@ PLATFORM_MTCE_PARAMETER_MANDATORY = [ constants.SERVICE_PARAM_PLAT_MTCE_HBS_DEGRADE_THRESHOLD, constants.SERVICE_PARAM_PLAT_MTCE_MNFA_THRESHOLD, constants.SERVICE_PARAM_PLAT_MTCE_MNFA_TIMEOUT, - constants.SERVICE_PARAM_PLAT_MTCE_BMC_ACCESS_METHOD, ] PLATFORM_SYSINV_PARAMETER_PROTECTED = ['firewall_rules_id'] @@ -392,9 +372,6 @@ SERVICE_PARAM_PLAT_MTCE_MNFA_THRESHOLD_MIN = 2 SERVICE_PARAM_PLAT_MTCE_MNFA_THRESHOLD_MAX = 100 SERVICE_PARAM_PLAT_MTCE_MNFA_TIMEOUT_MIN = 100 SERVICE_PARAM_PLAT_MTCE_MNFA_TIMEOUT_MAX = 86400 -SERVICE_PARAM_PLAT_MTCE_BMC_ACCESS_METHOD_LEARN = 'learn' -SERVICE_PARAM_PLAT_MTCE_BMC_ACCESS_METHOD_REDFISH = 'redfish' -SERVICE_PARAM_PLAT_MTCE_BMC_ACCESS_METHOD_IPMI = 'ipmi' PLATFORM_MTCE_PARAMETER_VALIDATOR = { @@ -414,8 +391,6 @@ PLATFORM_MTCE_PARAMETER_VALIDATOR = { _validate_mnfa_threshold, constants.SERVICE_PARAM_PLAT_MTCE_MNFA_TIMEOUT: _validate_mnfa_timeout, - constants.SERVICE_PARAM_PLAT_MTCE_BMC_ACCESS_METHOD: - _validate_bmc_access_method, } PLATFORM_MTCE_PARAMETER_RESOURCE = { @@ -427,7 +402,6 @@ PLATFORM_MTCE_PARAMETER_RESOURCE = { constants.SERVICE_PARAM_PLAT_MTCE_HBS_DEGRADE_THRESHOLD: 'platform::mtce::params::heartbeat_degrade_threshold', constants.SERVICE_PARAM_PLAT_MTCE_MNFA_THRESHOLD: 'platform::mtce::params::mnfa_threshold', constants.SERVICE_PARAM_PLAT_MTCE_MNFA_TIMEOUT: 'platform::mtce::params::mnfa_timeout', - constants.SERVICE_PARAM_PLAT_MTCE_BMC_ACCESS_METHOD: 'platform::mtce::params::bmc_access_method', } RADOSGW_CONFIG_PARAMETER_MANDATORY = [ diff --git a/sysinv/sysinv/sysinv/sysinv/conductor/manager.py b/sysinv/sysinv/sysinv/sysinv/conductor/manager.py index d8ca82ce60..24b6348241 100644 --- a/sysinv/sysinv/sysinv/sysinv/conductor/manager.py +++ b/sysinv/sysinv/sysinv/sysinv/conductor/manager.py @@ -487,11 +487,6 @@ class ConductorManager(service.PeriodicService): 'name': constants.SERVICE_PARAM_PLAT_MTCE_MNFA_TIMEOUT, 'value': constants.SERVICE_PARAM_PLAT_MTCE_MNFA_TIMEOUT_DEFAULT, }, - {'service': constants.SERVICE_TYPE_PLATFORM, - 'section': constants.SERVICE_PARAM_SECTION_PLATFORM_MAINTENANCE, - 'name': constants.SERVICE_PARAM_PLAT_MTCE_BMC_ACCESS_METHOD, - 'value': constants.SERVICE_PARAM_PLAT_MTCE_BMC_ACCESS_METHOD_DEFAULT, - }, {'service': constants.SERVICE_TYPE_RADOSGW, 'section': constants.SERVICE_PARAM_SECTION_RADOSGW_CONFIG, 'name': constants.SERVICE_PARAM_NAME_RADOSGW_SERVICE_ENABLED, diff --git a/sysinv/sysinv/sysinv/sysinv/tests/api/test_host.py b/sysinv/sysinv/sysinv/sysinv/tests/api/test_host.py index 5acbfe515e..d6f4386a83 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/api/test_host.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/api/test_host.py @@ -39,6 +39,7 @@ class FakeConductorAPI(object): self.store_default_config = mock.MagicMock() self.kube_upgrade_control_plane = mock.MagicMock() self.kube_upgrade_kubelet = mock.MagicMock() + self.create_barbican_secret = mock.MagicMock() def create_ihost(self, context, values): # Create the host in the DB as the code under test expects this @@ -1305,6 +1306,45 @@ class TestPatch(TestHost): self.assertEqual(constants.AVAILABILITY_ONLINE, ihost.availability) self.assertEqual(constants.PROVISIONED, ihost.invprovision) + def test_update_host_bm_valid(self): + # Create controller-0, provisioned + c0_host = self._create_controller_0( + invprovision=constants.PROVISIONED, + administrative=constants.ADMIN_UNLOCKED, + operational=constants.OPERATIONAL_DISABLED, + availability=constants.AVAILABILITY_OFFLINE) + self._create_test_host_platform_interface(c0_host) + + bm_ip = '128.224.141.222' + bm_username = 'root' + + for bm_type in constants.HOST_BM_VALID_PROVISIONED_TYPE_LIST: + bm_password = 'password' + bm_type + response = self._patch_host(c0_host['hostname'], + [{'path': '/bm_type', + 'value': bm_type, + 'op': 'replace'}, + {'path': '/bm_ip', + 'value': bm_ip, + 'op': 'replace'}, + {'path': '/bm_username', + 'value': bm_username, + 'op': 'replace'}, + {'path': '/bm_password', + 'value': bm_password, + 'op': 'replace'}], + '') + self.assertEqual(response.content_type, 'application/json') + self.assertEqual(response.status_code, http_client.OK) + + ihost = self._get_test_host_by_hostname(c0_host['hostname']) + self.assertEqual(bm_type, ihost.bm_type) + self.assertEqual(bm_ip, ihost.bm_ip) + self.assertEqual(bm_username, ihost.bm_username) + + self.fake_conductor_api.create_barbican_secret.assert_called_with( + mock.ANY, ihost.uuid, bm_password) + def test_unlock_action_controller(self): # Create controller-0 c0_host = self._create_controller_0( diff --git a/sysinv/sysinv/sysinv/sysinv/tests/db/utils.py b/sysinv/sysinv/sysinv/sysinv/tests/db/utils.py index a181f33a57..53efa67caa 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/db/utils.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/db/utils.py @@ -134,7 +134,7 @@ def get_test_ihost(**kw): 'serialid': kw.get('serialid', 'sysinv123456'), 'bm_ip': kw.get('bm_ip', "128.224.150.193"), 'bm_mac': kw.get('bm_mac', "a4:5d:36:fc:a5:6c"), - 'bm_type': kw.get('bm_type', constants.BM_TYPE_GENERIC), + 'bm_type': kw.get('bm_type', constants.HOST_BM_TYPE_DEPROVISIONED), 'bm_username': kw.get('bm_username', "ihostbmusername"), 'action': kw.get('action', "none"), 'task': kw.get('task', None),