Force cleanup of checkout directory on deploy start

This commit checks if checkout directory exists on deploy start,
and if it does, then run the cleanup script to remove the directory
forcefully and proceeds with the upgrade, instead of just returning
an error.

The configparser method to get the sw_version is replaced with a
simpler approach.

Two robustness improvements are also added to the cleanup script:
1. Since it needs to determine the to-release major release version
to execute the cleanup tasks (like stopping the to-release database),
but it will fail if the checkout directory is empty or partially
checked out; so in this case, a fallback mechanism will try to get
the major release version from the temporary script path;
2. Check if the major release version to be cleaned up is not the
same as the one running in the system, in case any leftovers of the
previous upgrade are left in the system, so that the deploy cleanup
script doesn't end breaking the current running system.

Test Plan
PASS: deploy start (regression)
PASS: deploy start with checked out to-release ostree-repo,
      verify the cleanup script is executed and deploy start
      proceeds
PASS: deploy start with empty/partially checked out to-release
      ostree-repo, verify the cleanup script is executed and
      deploy start proceeds
PASS: deploy start with checked out ostree-repo from the same
      major release version as the running release, verify the
      cleanup script doesn't execute

Closes-bug: 2126797

Change-Id: I18294c4009da157140aa10091f9a9b3087c9107b
Signed-off-by: Heitor Matsui <heitorvieira.matsui@windriver.com>
This commit is contained in:
Heitor Matsui
2025-10-02 18:14:46 -03:00
parent c449a746a1
commit 868f14ba06
2 changed files with 33 additions and 12 deletions
+4 -4
View File
@@ -57,10 +57,10 @@ class DeployStart:
def _check_directories(self):
for directory in [self.SYSROOT_DIR]:
if os.path.isdir(directory):
error_msg = (f"{directory} already exists. Please ensure to "
f"clean up the environment before proceeding")
LOG.error(error_msg)
raise OSError(error_msg)
warning_msg = (f"{directory} already exists. Cleanup will "
"be executed before proceeding")
LOG.warning(warning_msg)
self._remove_temporary_data()
def _checkout_ostree_repo(self):
# TODO(bqian) make commit_id mandatory once the commit-id is built to metadata.xml for major releases
+29 -8
View File
@@ -15,9 +15,9 @@
# automatic cleanup process fails.
#
import configparser
import logging
import os
import re
import shutil
import subprocess
import sys
@@ -28,18 +28,32 @@ LOG = logging.getLogger('main_logger')
class RemoveTemporaryData:
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) # this script location
def __init__(self, checkout_dir):
self._checkout_dir = checkout_dir
try:
default_section = configparser.DEFAULTSECT
cp = configparser.ConfigParser()
with open(os.path.join(self._checkout_dir, "usr/etc/build.info"), "r") as fp:
cp.read_string(f"[{default_section}]\n" + fp.read())
self._sw_version = cp.get(default_section, "SW_VERSION").strip('"')
except Exception as e:
LOG.error(f"Error getting SW_VERSION: {str(e)}")
checkout_usr_etc = os.path.join(self._checkout_dir, "usr/etc")
self._sw_version = self.get_sw_version(checkout_usr_etc)
except subprocess.CalledProcessError as e:
LOG.warning("Attempting to get SW_VERSION it from the script path...")
match = re.match(r".*rel-(\d+.\d+)/", self.SCRIPT_DIR)
if match is None:
LOG.error(f"Failed to get SW_VERSION, won't proceed with the cleanup")
raise
self._sw_version = match.group(1)
@staticmethod
def get_sw_version(etc_dir="/etc"):
try:
p = subprocess.run(f"source {etc_dir}/build.info; echo $SW_VERSION",
shell=True, check=True, capture_output=True, text=True)
running_sw_version = p.stdout.strip()
except subprocess.CalledProcessError as e:
LOG.error(f"Error getting SW_VERSION from {etc_dir}: {e.stderr.strip()}")
raise
return running_sw_version
def stop_database(self):
db_dir = os.path.join(self._checkout_dir, "var/lib/postgresql", self._sw_version)
@@ -98,6 +112,13 @@ class RemoveTemporaryData:
LOG.info(f"{temp_dir} removed successfully")
def run(self):
running_sw_version = self.get_sw_version()
if running_sw_version == self._sw_version:
LOG.error(f"Cannot proceed with cleanup, running software version "
f"{running_sw_version} is the same as the requested cleanup "
f"version, please remove {self._checkout_dir} manually")
return 1
LOG.info("Starting temporary data cleanup...")
try:
self.stop_database()