From 6c6e8c192a42dea89f9889c225e00c033436acbf Mon Sep 17 00:00:00 2001 From: Luis Eduardo Bonatti Date: Tue, 9 Apr 2024 16:54:43 -0300 Subject: [PATCH] Replace load sysinv data This commit creates the sw_version field on i_host table, changes the pxe file creation to use this field and also creates a migrate script that will be executed on 22.12 to 24.09 scenario. There are other places where the version is read/write from loads table, these should be addressed by another commit. Test Plan: The tests below for deploy host was done from 24.03 to 24.09 iso. PASS: AIO-DX install/bootstrap/unlock PASS: AIO-SX install/bootstrap/unlock PASS: System host-show returning respective value at cli PASS: Deploy host of controller-1 Story: 2010676 Task: 49865 Change-Id: I7be0c4e48a10d4296d1cda50c49d6d1992e89139 Signed-off-by: Luis Eduardo Bonatti --- .../08-populate-ihost-sw-version-field.py | 94 +++++++++++++++++++ .../cgts-client/cgtsclient/v1/iHost_shell.py | 2 +- .../sysinv/sysinv/api/controllers/v1/host.py | 8 +- .../sysinv/sysinv/sysinv/conductor/manager.py | 8 +- .../versions/137_add_host_sw_version.py | 19 ++++ .../sysinv/sysinv/db/sqlalchemy/models.py | 2 + sysinv/sysinv/sysinv/sysinv/objects/host.py | 3 + .../sysinv/sysinv/tests/api/test_host.py | 1 + .../sysinv/tests/conductor/test_manager.py | 8 ++ sysinv/sysinv/sysinv/sysinv/tests/db/utils.py | 3 +- 10 files changed, 141 insertions(+), 7 deletions(-) create mode 100644 controllerconfig/controllerconfig/upgrade-scripts/08-populate-ihost-sw-version-field.py create mode 100644 sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/migrate_repo/versions/137_add_host_sw_version.py diff --git a/controllerconfig/controllerconfig/upgrade-scripts/08-populate-ihost-sw-version-field.py b/controllerconfig/controllerconfig/upgrade-scripts/08-populate-ihost-sw-version-field.py new file mode 100644 index 0000000000..c2412929de --- /dev/null +++ b/controllerconfig/controllerconfig/upgrade-scripts/08-populate-ihost-sw-version-field.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +# Copyright (c) 2024 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +# The purpose of this script is to populate the sw_version +# field on i_host table. + +import sys +import psycopg2 +from controllerconfig.common import log + +LOG = log.get_logger(__name__) +CONTROLLER_1_HOSTNAME = "controller-1" +DEFAULT_POSTGRES_PORT = 5432 + + +def main(): + action = None + from_release = None + to_release = None + postgres_port = DEFAULT_POSTGRES_PORT + arg = 1 + while arg < len(sys.argv): + if arg == 1: + from_release = sys.argv[arg] + elif arg == 2: + to_release = sys.argv[arg] + elif arg == 3: + action = sys.argv[arg] + elif arg == 4: + postgres_port = sys.argv[arg] + pass + else: + print("Invalid option %s." % sys.argv[arg]) + return 1 + arg += 1 + log.configure() + LOG.info( + "%s invoked from_release = %s to_release = %s action = %s" + % (sys.argv[0], from_release, to_release, action) + ) + res = 0 + if action == 'migrate' and from_release == '22.12': + try: + conn = psycopg2.connect("dbname=sysinv user=postgres port=%s" + % postgres_port) + populate_ihost_sw_version(conn, to_release, from_release) + conn.close() + except Exception as e: + LOG.exception("Error: {}".format(e)) + res = 1 + return res + + +def populate_ihost_sw_version(conn, to_release, from_release): + """ + Populate with the to_release/from_release sw_version field of i_host table + """ + hostname_query = "SELECT hostname from i_host" + res = db_query(conn, hostname_query) + for hostname in res: + # if len == 1 is SX. + if len(res) == 1 or hostname[0] == CONTROLLER_1_HOSTNAME: + update_query = ("UPDATE i_host set sw_version = %s WHERE " + "hostname = '%s'" % (to_release, hostname[0])) + db_update(conn, update_query) + LOG.info("Updated sw_version to %s on %s" % + (to_release, hostname[0])) + else: + update_query = ("UPDATE i_host set sw_version = %s WHERE " + "hostname = '%s'" % (from_release, hostname[0])) + db_update(conn, update_query) + LOG.info("Updated sw_version to %s on %s" % + (from_release, hostname[0])) + + +def db_update(conn, query): + with conn.cursor() as cur: + cur.execute(query) + conn.commit() + + +def db_query(conn, query): + result = [] + with conn.cursor() as cur: + cur.execute(query) + for rec in cur: + result.append(rec) + return result + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/sysinv/cgts-client/cgts-client/cgtsclient/v1/iHost_shell.py b/sysinv/cgts-client/cgts-client/cgtsclient/v1/iHost_shell.py index 1bfdf2e0c2..f65317a8b3 100755 --- a/sysinv/cgts-client/cgts-client/cgtsclient/v1/iHost_shell.py +++ b/sysinv/cgts-client/cgts-client/cgtsclient/v1/iHost_shell.py @@ -39,7 +39,7 @@ def _print_ihost_show(ihost, columns=None, output_format=None): 'reboot_needed', 'max_cpu_mhz_configured', 'min_cpu_mhz_allowed', 'max_cpu_mhz_allowed', 'cstates_available', 'apparmor', 'iscsi_initiator_name', - 'nvme_host_id', 'nvme_host_nqn'] + 'nvme_host_id', 'nvme_host_nqn', 'sw_version'] optional_fields = ['vsc_controllers', 'ttys_dcd'] if ihost.subfunctions != ihost.personality: fields.append('subfunctions') diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py index 83efc1073e..b0e0603529 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py @@ -107,7 +107,8 @@ HOST_XML_ATTRIBUTES = ['hostname', 'personality', 'subfunctions', 'mgmt_mac', 'mgmt_ip', 'bm_ip', 'bm_type', 'bm_username', 'bm_password', 'boot_device', 'rootfs_device', 'hw_settle', 'install_output', 'console', - 'vsc_controllers', 'power_on', 'location', 'apparmor'] + 'vsc_controllers', 'power_on', 'location', 'apparmor', + 'sw_version'] def _get_controller_address(hostname): @@ -584,6 +585,9 @@ class Host(base.APIBase): reboot_needed = types.boolean " Represent whether a reboot is needed after device image update" + sw_version = wtypes.text + "The host software version." + def __init__(self, **kwargs): self.fields = list(objects.host.fields.keys()) for k in self.fields: @@ -612,7 +616,7 @@ class Host(base.APIBase): 'reboot_needed', 'inv_state', 'clock_synchronization', 'max_cpu_mhz_configured', 'min_cpu_mhz_allowed', 'max_cpu_mhz_allowed', 'cstates_available', - 'apparmor', 'nvme_host_id', 'nvme_host_nqn'] + 'apparmor', 'nvme_host_id', 'nvme_host_nqn', 'sw_version'] fields = minimum_fields if not expand else None uhost = Host.from_rpc_object(rpc_ihost, fields) diff --git a/sysinv/sysinv/sysinv/sysinv/conductor/manager.py b/sysinv/sysinv/sysinv/sysinv/conductor/manager.py index 2f5622637f..bccef1ee79 100644 --- a/sysinv/sysinv/sysinv/sysinv/conductor/manager.py +++ b/sysinv/sysinv/sysinv/sysinv/conductor/manager.py @@ -1242,6 +1242,9 @@ class ConductorManager(service.PeriodicService): values.update({'forisystemid': system.id}) values.update({constants.HOST_ACTION_STATE: constants.HAS_REINSTALLING}) + # set sw_version value + values.update({'sw_version': tsc.SW_VERSION}) + # get tboot value from the active controller active_controller = None hosts = self.dbapi.ihost_get_by_personality(constants.CONTROLLER) @@ -1930,9 +1933,8 @@ class ConductorManager(service.PeriodicService): sw_version = load.software_version else: # No load provided, look it up... - host_upgrade = self.dbapi.host_upgrade_get_by_host(host.id) - target_load = self.dbapi.load_get(host_upgrade.target_load) - sw_version = target_load.software_version + host = self.dbapi.ihost_get_by_hostname(host.hostname) + sw_version = host.sw_version if (host.personality == constants.CONTROLLER and constants.WORKER in tsc.subfunctions): diff --git a/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/migrate_repo/versions/137_add_host_sw_version.py b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/migrate_repo/versions/137_add_host_sw_version.py new file mode 100644 index 0000000000..acb596827d --- /dev/null +++ b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/migrate_repo/versions/137_add_host_sw_version.py @@ -0,0 +1,19 @@ +# +# Copyright (c) 2024 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +from sqlalchemy import Column, MetaData, Table +from sqlalchemy import String + + +def upgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + host_table = Table('i_host', meta, autoload=True) + host_table.create_column(Column('sw_version', String(128))) + + +def downgrade(migrate_engine): + raise NotImplementedError('SysInv database downgrade is unsupported.') diff --git a/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/models.py b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/models.py index ef42779a98..6153087989 100644 --- a/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/models.py +++ b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/models.py @@ -197,6 +197,8 @@ class ihost(Base): mgmt_mac = Column(String(255), unique=True) mgmt_ip = Column(String(255)) + sw_version = Column(String(128)) + # board management IP address, MAC, type and username bm_ip = Column(String(255)) bm_mac = Column(String(255)) diff --git a/sysinv/sysinv/sysinv/sysinv/objects/host.py b/sysinv/sysinv/sysinv/sysinv/objects/host.py index 471481a357..d888212bbd 100644 --- a/sysinv/sysinv/sysinv/sysinv/objects/host.py +++ b/sysinv/sysinv/sysinv/sysinv/objects/host.py @@ -66,6 +66,9 @@ class Host(base.SysinvObject): 'mgmt_mac': utils.str_or_none, 'mgmt_ip': utils.str_or_none, + # Software version + 'sw_version': utils.str_or_none, + # Board management members 'bm_ip': utils.str_or_none, 'bm_mac': utils.str_or_none, diff --git a/sysinv/sysinv/sysinv/sysinv/tests/api/test_host.py b/sysinv/sysinv/sysinv/sysinv/tests/api/test_host.py index 3d6c0a37d2..7b3586e000 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/api/test_host.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/api/test_host.py @@ -1956,6 +1956,7 @@ class TestListHosts(TestHost): self.assertEqual(ndict['boot_device'], result['boot_device']) self.assertEqual(ndict['rootfs_device'], result['rootfs_device']) self.assertEqual(ndict['hw_settle'], result['hw_settle']) + self.assertEqual(ndict['sw_version'], result['sw_version']) self.assertEqual(ndict['install_output'], result['install_output']) self.assertEqual(ndict['console'], result['console']) self.assertEqual(ndict['tboot'], result['tboot']) diff --git a/sysinv/sysinv/sysinv/sysinv/tests/conductor/test_manager.py b/sysinv/sysinv/sysinv/sysinv/tests/conductor/test_manager.py index 693146a92c..8d2fb74999 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/conductor/test_manager.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/conductor/test_manager.py @@ -635,6 +635,7 @@ class ManagerTestCase(base.DbTestCase): 'boot_device': 'sda', 'rootfs_device': 'sda', 'hw_settle': '0', + 'sw_version': '0.0', 'install_output': 'text', 'console': 'ttyS0,115200', 'tboot': '' @@ -728,6 +729,7 @@ class ManagerTestCase(base.DbTestCase): ihost['boot_device'] = 'sda' ihost['rootfs_device'] = 'sda' ihost['hw_settle'] = '0' + ihost['sw_version'] = '0.0' ihost['install_output'] = 'text' ihost['console'] = 'ttyS0,115200' @@ -745,6 +747,7 @@ class ManagerTestCase(base.DbTestCase): self.assertEqual(res['boot_device'], 'sda') self.assertEqual(res['rootfs_device'], 'sda') self.assertEqual(res['hw_settle'], '0') + self.assertEqual(res['sw_version'], '0.0') self.assertEqual(res['install_output'], 'text') self.assertEqual(res['console'], 'ttyS0,115200') @@ -789,6 +792,7 @@ class ManagerTestCase(base.DbTestCase): ihost['boot_device'] = 'sda' ihost['rootfs_device'] = 'sda' ihost['hw_settle'] = '0' + ihost['sw_version'] = '0.0' ihost['install_output'] = 'text' ihost['console'] = 'ttyS0,115200' @@ -826,6 +830,7 @@ class ManagerTestCase(base.DbTestCase): ihost['boot_device'] = 'sda' ihost['rootfs_device'] = 'sda' ihost['hw_settle'] = '0' + ihost['sw_version'] = '0.0' ihost['install_output'] = 'text' ihost['console'] = 'ttyS0,115200' @@ -2560,6 +2565,7 @@ class ManagerTestCase(base.DbTestCase): ihost['boot_device'] = 'sda' ihost['rootfs_device'] = 'sda' ihost['hw_settle'] = '0' + ihost['sw_version'] = '0.0' ihost['install_output'] = 'text' ihost['console'] = 'ttyS0,115200' @@ -5932,6 +5938,7 @@ class ManagerTestCaseInternal(base.BaseHostTestCase): ihost['boot_device'] = 'sda' ihost['rootfs_device'] = 'sda' ihost['hw_settle'] = '0' + ihost['sw_version'] = '0.0' ihost['install_output'] = 'text' ihost['console'] = 'ttyS0,115200' @@ -5992,6 +5999,7 @@ class ManagerTestCaseInternal(base.BaseHostTestCase): ihost['boot_device'] = 'sda' ihost['rootfs_device'] = 'sda' ihost['hw_settle'] = '0' + ihost['sw_version'] = '0.0' ihost['install_output'] = 'text' ihost['console'] = 'ttyS0,115200' diff --git a/sysinv/sysinv/sysinv/sysinv/tests/db/utils.py b/sysinv/sysinv/sysinv/sysinv/tests/db/utils.py index 3eb02050f9..e3f49f0beb 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/db/utils.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/db/utils.py @@ -177,7 +177,8 @@ def get_test_ihost(**kw): 'max_cpu_mhz_allowed': kw.get('max_cpu_mhz_allowed', ''), 'cstates_available': kw.get('cstates_available', ''), 'nvme_host_id': kw.get('nvme_host_id', None), - 'nvme_host_nqn': kw.get('nvme_host_nqn', None) + 'nvme_host_nqn': kw.get('nvme_host_nqn', None), + 'sw_version': kw.get('sw_version', SW_VERSION) } return inv