From f2b98a49500e962ef0580dc1040caafcac4eb2e0 Mon Sep 17 00:00:00 2001 From: Bin Qian Date: Tue, 30 Jul 2024 16:53:32 +0000 Subject: [PATCH] Add new USM initialize service The new service is enabled on a host that completed major release deployment prior to host-unlock. The service runs at the early stage of node reboot after host-unlock. It sets up the systemd preset for new deployed major release software, removes the initial_config_complete flag file, then disable itself. This service replicates the operations in the kickstart during a node installation. Other operations may be added in the future. Test Plan PASS: AIO-DX - run throught e2e USM major release deploy, verify the new systemd services added to the to-release are enabled Story: 2010676 Task: 50749 Change-Id: I77e819e9767071da6cd43f581c76661ba2fc06c1 Signed-off-by: Bin Qian Co-Signed-off-by: Heitor Matsui --- software/debian/deb_folder/rules | 2 + software/service-files/usm-initialize-init.sh | 99 +++++++++++++++++++ software/service-files/usm-initialize.service | 12 +++ software/software/agent_hooks.py | 71 ++++++++++++- 4 files changed, 181 insertions(+), 3 deletions(-) create mode 100755 software/service-files/usm-initialize-init.sh create mode 100644 software/service-files/usm-initialize.service diff --git a/software/debian/deb_folder/rules b/software/debian/deb_folder/rules index 8756ae78..31ab49fd 100755 --- a/software/debian/deb_folder/rules +++ b/software/debian/deb_folder/rules @@ -38,6 +38,8 @@ override_dh_install: ${ROOT}/etc/init.d/software install -m 500 service-files/software-controller-init.sh \ ${ROOT}/etc/init.d/software-controller + install -m 500 service-files/usm-initialize-init.sh \ + ${ROOT}/etc/init.d/usm-initialize install -m 600 service-files/software.conf \ ${ROOT}/etc/software/software.conf install -m 644 service-files/policy.json \ diff --git a/software/service-files/usm-initialize-init.sh b/software/service-files/usm-initialize-init.sh new file mode 100755 index 00000000..527c3293 --- /dev/null +++ b/software/service-files/usm-initialize-init.sh @@ -0,0 +1,99 @@ +#! /bin/sh +# +# Copyright (c) 2024 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +### BEGIN INIT INFO +# Description: usm-initialize +# +# Short-Description: USM initialize service. +# Provides: usm-initialize +# Required-Start: +# Required-Stop: +# Default-Start: 3 5 +# Default-Stop: 3 5 +### END INIT INFO + +logfile="/var/log/software.log" +INITIAL_CONFIG_COMPLETE="/etc/platform/.initial_config_complete" +SERVICE_NAME="usm-initialize.service" + +log() { + echo "`date "+%FT%T.%3N"`: $0: $*" >> $logfile +} + +set_presets() { + . /etc/platform/platform.conf + if [ "${system_type}" == "All-in-one" ] ; then + log "AIO System" + if [[ "${subfunction}" =~ "lowlatency" ]] ; then + log "System is lowlatency" + ln -sf /usr/share/systemd-presets/lowlatency.preset /etc/systemd/system-preset/10-aio.preset + else + ln -sf /usr/share/systemd-presets/aio.preset /etc/systemd/system-preset/10-aio.preset + fi + else + log "Standard System" + log "Setting ${nodetype} preset" + if [[ "${nodetype}" == "worker" ]] ; then + if [[ "${subfunction}" =~ "lowlatency" ]] ; then + log "System is lowlatency" + ln -sf /usr/share/systemd-presets/worker-lowlatency.preset /etc/systemd/system-preset/10-worker.preset + else + ln -sf /usr/share/systemd-presets/worker.preset /etc/systemd/system-preset/10-worker.preset + fi + elif [ "${nodetype}" == "storage" ] ; then + ln -sf /usr/share/systemd-presets/storage.preset /etc/systemd/system-preset/10-storage.preset + else + ln -sf /usr/share/systemd-presets/controller.preset /etc/systemd/system-preset/10-controller.preset + fi + fi + + systemctl daemon-reload + systemctl preset-all --preset-mode=full +} + +reset_initial_config_complete() { + if [[ -f ${INITIAL_CONFIG_COMPLETE} ]]; then + log "Removing ${INITIAL_CONFIG_COMPLETE}" + rm ${INITIAL_CONFIG_COMPLETE} || log "Failed to remove ${INITIAL_CONFIG_COMPLETE}" + fi +} + +disable_service() { + systemctl disable $SERVICE_NAME + rc=$? + if [ $rc -ne 0 ]; then + log "Failed to disable $SERVICE_NAME" + else + log "Disabled $SERVICE_NAME" + fi +} + +start() { + set_presets + reset_initial_config_complete + disable_service +} + +case "$1" in + start) + start + exit 0 + ;; + stop) + ;; + status) + ;; + restart) + ;; + reload) + ;; + force-reload) + ;; + *) +esac + +exit 0 diff --git a/software/service-files/usm-initialize.service b/software/service-files/usm-initialize.service new file mode 100644 index 00000000..b33dfc1e --- /dev/null +++ b/software/service-files/usm-initialize.service @@ -0,0 +1,12 @@ +[Unit] +Description=Unified Software Management Initialize Service +Before=network-online.target + +[Service] +Type=oneshot +User=root +ExecStart=/etc/init.d/usm-initialize start + +[Install] +WantedBy=multi-user.target + diff --git a/software/software/agent_hooks.py b/software/software/agent_hooks.py index 7115c6a3..17f012b4 100644 --- a/software/software/agent_hooks.py +++ b/software/software/agent_hooks.py @@ -4,7 +4,6 @@ Copyright (c) 2024 Wind River Systems, Inc. SPDX-License-Identifier: Apache-2.0 """ - import filecmp import glob import os @@ -25,6 +24,66 @@ class BaseHook(object): pass +class UsmInitHook(BaseHook): + def run(self): + cmd = "systemctl enable usm-initialize.service" + try: + subprocess.check_call(cmd, shell=True) + except subprocess.CalledProcessError as e: + LOG.exception("Error enabling usm-initialize.service: %s" % str(e)) + raise + LOG.info("Enabled usm-initialize.service on next reboot") + + +class EnableNewServicesHook(BaseHook): + SYSTEM_PRESET_DIR = "/etc/systemd/system-preset" + DEPLOYED_OSTREE_DIR = "/ostree/1" + SYSTEMD_LIB_DIR = "/lib/systemd/system" + SYSTEMD_ETC_DIR = "%s/etc/systemd/system/multi-user.target.wants" % DEPLOYED_OSTREE_DIR + + def find_new_services(self): + # get preset name + system_preset = None + presets = os.listdir(self.SYSTEM_PRESET_DIR) + for preset in presets: + if preset.startswith("10-"): + system_preset = os.readlink("%s/%s" % (self.SYSTEM_PRESET_DIR, preset)) + if not system_preset: + raise FileNotFoundError("System preset not found.") + + # read from-release preset + with open(system_preset, "r") as fp: + from_preset = fp.readlines() + from_services = [line.strip().split(" ")[1] for line in from_preset + if line.startswith("enable")] + # read to-release preset + with open("%s/%s" % (self.DEPLOYED_OSTREE_DIR, system_preset), "r") as fp: + to_preset = fp.readlines() + to_services = [line.strip().split(" ")[1] for line in to_preset + if line.startswith("enable")] + + # compare to find new services + # output will come as "+ " for new service in to-release + new_services = list(set(to_services) - set(from_services)) + LOG.info("New services found: %s" % ", ".join(new_services)) + return new_services + + def enable_new_services(self, services): + for service in services: + src = "%s/%s" % (self.SYSTEMD_LIB_DIR, service) + dst = "%s/%s" % (self.SYSTEMD_ETC_DIR, service) + try: + os.symlink(src, dst) + LOG.info("Enabled %s" % service) + except subprocess.CalledProcessError as e: + LOG.exception("Error enabling %s: %s" % (service, str(e))) + raise + + def run(self): + new_services = self.find_new_services() + self.enable_new_services(new_services) + + class CopyPxeFilesHook(BaseHook): """ Copy pxeboot files from the target feed post deploy host during @@ -134,14 +193,20 @@ MAJOR_RELEASE_ROLLBACK = "major_release_rollback" # agent hooks mapping per action AGENT_HOOKS = { MAJOR_RELEASE_UPGRADE: { - PRE: [CreateUSMUpgradeInProgressFlag], + PRE: [ + CreateUSMUpgradeInProgressFlag, + UsmInitHook, + ], POST: [ CopyPxeFilesHook, ReconfigureKernelHook, + EnableNewServicesHook, ], }, MAJOR_RELEASE_ROLLBACK: { - PRE: [], + PRE: [ + UsmInitHook, + ], POST: [ ReconfigureKernelHook, ],