Browse Source
Script to build test patches for debian using ostree. This initial version is building a reboot required patch by changing one package (logmgmt) and rebuilding it. The steps are as follows: - create a clone of ostree_repo - update logmgmt package - rebuild package - build-image to generate new ostree commit - create patch Story: 2009969 Task: 45635 Signed-off-by: Luis Sampaio <luis.sampaio@windriver.com> Change-Id: I5eb2d768c8a390c98d34a00d43822ba87a284f70changes/75/846075/4
1 changed files with 235 additions and 0 deletions
@ -0,0 +1,235 @@
|
||||
#!/bin/python3 |
||||
# |
||||
# Copyright (c) 2022 Wind River Systems, Inc. |
||||
# |
||||
# SPDX-License-Identifier: Apache-2.0 |
||||
# |
||||
""" |
||||
Debian Build Test Patches: |
||||
|
||||
Reboot required - all nodes |
||||
Update package - logmgmt |
||||
rebuild the pkg |
||||
build-image to generate a new commit in the build ostree_repo |
||||
build a patch |
||||
|
||||
Patches with dependency (reboot required) |
||||
TODO: |
||||
Patch A |
||||
update package - logmgmt |
||||
build-image to generate a new commit in the build ostree_repo |
||||
build patch A |
||||
Patch B (requires A) |
||||
|
||||
Requires: |
||||
debchange (devscripts) - Tool for maintenance of the debian/changelog file in a source package |
||||
https://manpages.debian.org/jessie/devscripts/debchange.1.en.html |
||||
|
||||
Steps to run: |
||||
# Setup debian build env |
||||
# For more information about how to setup the environment: |
||||
https://wiki.openstack.org/wiki/StarlingX/DebianBuildEnvironment |
||||
|
||||
export PROJECT="stx-debian-build" |
||||
export STX_BUILD_HOME="/localdisk/designer/${USER}/${PROJECT}" |
||||
# Initialize the build containers |
||||
stx control start |
||||
./build_test_patches.py --help |
||||
|
||||
""" |
||||
import argparse |
||||
import logging |
||||
import os |
||||
import shutil |
||||
import subprocess |
||||
import sys |
||||
|
||||
from requests import patch |
||||
|
||||
sys.path.insert(0, "../cgcs-patch") |
||||
from cgcs_make_patch.make_patch import PatchBuilder # noqa: E402 pylint: disable=wrong-import-position |
||||
from cgcs_make_patch.make_patch import PatchRecipeData # noqa: E402 pylint: disable=wrong-import-position |
||||
|
||||
logging.basicConfig( |
||||
level=logging.DEBUG, |
||||
format='%(asctime)s.%(msecs)03d %(levelname)s %(module)s - %(funcName)s: %(message)s', |
||||
datefmt='%Y-%m-%d %H:%M:%S', |
||||
) |
||||
log = logging.getLogger('build_test_patches') |
||||
|
||||
|
||||
def run_cmd(cmd): |
||||
''' |
||||
Run a cmd and return |
||||
param command: string representing the command to be executed |
||||
''' |
||||
log.debug("Running: %s", cmd) |
||||
return subprocess.run( |
||||
cmd, |
||||
shell=True, |
||||
executable='/bin/bash', |
||||
check=True) |
||||
|
||||
|
||||
class TestPatchInitException(Exception): |
||||
"""TestPatch initialization error""" |
||||
|
||||
|
||||
class TestPatchCreationException(Exception): |
||||
"""Patch creation error""" |
||||
|
||||
|
||||
class TestPatchBuilder(): |
||||
""" |
||||
Build test patches |
||||
""" |
||||
def __init__(self, sw_version): |
||||
try: |
||||
self.project = os.environ.get("PROJECT") |
||||
self.build_home = os.environ.get("STX_BUILD_HOME") |
||||
self.repo = os.path.join(self.build_home, "repo") |
||||
self.repo_root = os.path.join(self.repo, "cgcs-root") |
||||
self.patch_repo_base = os.path.join(self.repo_root, "stx/update") |
||||
self.sw_version = sw_version |
||||
except TestPatchInitException: |
||||
log.exception("TestPatchBuilder initialization failure") |
||||
sys.exit(1) |
||||
|
||||
def __upversion_pkg(self, pkg_dir): |
||||
""" |
||||
Updates changelog version in pkg_dir/debian/deb_folder |
||||
""" |
||||
log.info("Upversioning package %s", pkg_dir) |
||||
# cd pkg_dir/debian/deb_folder; dch -q "PATCH TEST" --changelog changelog |
||||
pwd = os.getcwd() |
||||
os.chdir(pkg_dir) |
||||
# Increase the change log version |
||||
cmd = "dch -q 'PATCH TEST' --changelog debian/deb_folder/changelog" |
||||
ret = run_cmd(cmd) |
||||
if ret.returncode != 0: |
||||
raise Exception("Error while changing the package version") |
||||
os.chdir(pwd) |
||||
|
||||
def __delete_dir(self, dir_path): |
||||
""" |
||||
Deletes a directory - called when cleaning up the cloned ostree |
||||
param dir_path: Path to the directory |
||||
""" |
||||
if os.path.isdir(dir_path): |
||||
log.info("removing %s", dir_path) |
||||
shutil.rmtree(dir_path) |
||||
|
||||
def build_pkg(self, pkg_name): |
||||
""" |
||||
Build package |
||||
""" |
||||
os.chdir(os.path.join(self.repo, "stx-tools")) |
||||
cmd = f''' |
||||
source import-stx |
||||
stx shell -c "build-pkgs -c -p {pkg_name}" |
||||
''' |
||||
ret = run_cmd(cmd) |
||||
log.info("Build pkgs return code %s", ret.returncode) |
||||
if ret.returncode != 0: |
||||
raise Exception("Failed to build packages") |
||||
|
||||
def build_image(self): |
||||
""" |
||||
Build image - generates new ostree commit |
||||
""" |
||||
cmd = ''' |
||||
source import-stx |
||||
stx shell -c "build-image" |
||||
''' |
||||
ret = run_cmd(cmd) |
||||
log.info("Build image return code %s", ret.returncode) |
||||
if ret.returncode != 0: |
||||
raise Exception("Failed to build image") |
||||
|
||||
def update_pkg(self, pname): |
||||
""" |
||||
Make a change on the logmgmt package and upversions it |
||||
param pname: patch name that is added to the script and can be used as patch validation |
||||
""" |
||||
pkg_name = "logmgmt" |
||||
log.info("Updating package %s", pkg_name) |
||||
pkg_dir = os.path.join(self.repo_root, "stx/utilities/utilities", pkg_name) |
||||
pkg_script = os.path.join(pkg_dir, "scripts/init.d/logmgmt") |
||||
# Insert a message into /etc/init.d/$(basename $SCRIPT) |
||||
cmd = "sed -i 's|start).*|start) logger -t \\$(basename \\$0) \"" + pname + " patch is applied\"|' " + pkg_script |
||||
run_cmd(cmd) |
||||
self.__upversion_pkg(pkg_dir) |
||||
# build the pkg to apply the change |
||||
self.build_pkg(pkg_name) |
||||
|
||||
def rr_allnodes_patch(self, pname, requires=False, formal=False): |
||||
""" |
||||
Creates a reboot required patch |
||||
param pname: Patch ID and file name |
||||
param requires: If set it will build the 2nd patch |
||||
""" |
||||
ostree_clone_name = "ostree_repo_patch" |
||||
patch_builder = PatchBuilder() |
||||
# Generating ostree_repo clone |
||||
patch_builder.prepare_env(ostree_clone_name) |
||||
# Update pkg |
||||
self.update_pkg(pname) |
||||
log.info("Generating RR patch for all nodes") |
||||
# build image to trigger a new ostree commit |
||||
self.build_image() |
||||
patch_data = PatchRecipeData() |
||||
patch_data.patch_id = pname |
||||
patch_data.sw_version = self.sw_version |
||||
patch_data.metadata = { |
||||
"SUMMARY": "RR ALL NODES", |
||||
"DESCRIPTION": "Test patch", |
||||
"INSTALL_INSTRUCTIONS": "Sample instructions", |
||||
"WARNINGS": "Sample Warning", |
||||
"STATUS": "DEV", |
||||
"UNREMOVABLE": "N", |
||||
"REBOOT_REQUIRED": "Y" |
||||
} |
||||
|
||||
# Create a patch |
||||
log.info("Creating patch %s", pname) |
||||
patch_builder.create_patch(patch_data, ostree_clone_name, formal) |
||||
log.info("Patch build done") |
||||
|
||||
clone_repo_path = os.path.join(patch_builder.deploy_dir, ostree_clone_name) |
||||
self.__delete_dir(clone_repo_path) |
||||
|
||||
if requires: |
||||
# Build the 2nd patch which will follow similar steps but will set the requires flag |
||||
patch_builder.prepare_env(ostree_clone_name) |
||||
# Update pkg |
||||
self.update_pkg(pname + "_REQUIRES") |
||||
log.info("Generating RR Requires patch for all nodes") |
||||
# build image to trigger a new ostree commit |
||||
self.build_image() |
||||
# Update patch ID and set requires |
||||
patch_data.patch_id = pname + "_REQUIRES" |
||||
patch_data.requires.append(pname) |
||||
# Create a patch |
||||
log.info("Creating patch requires patch") |
||||
patch_builder.create_patch(patch_data, ostree_clone_name, formal) |
||||
log.info("Patch build done") |
||||
self.__delete_dir(clone_repo_path) |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
parser = argparse.ArgumentParser(description="Debian build_test_patches") |
||||
|
||||
parser.add_argument("-sw", "--software-version", type=str, help="Patch Software version, will prefix the patch name", default=None, required=True) |
||||
parser.add_argument("-r", "--requires", action="store_true", help="Build the 2nd patch which requires the rr_patch") |
||||
parser.add_argument("-f", "--formal", action="store_true", help="Signs the patch with formal key") |
||||
args = parser.parse_args() |
||||
log.debug("Args: %s", args) |
||||
|
||||
try: |
||||
log.info("Building test patches") |
||||
patch_name = args.software_version + "_RR_ALL_NODES" |
||||
test_patch_builder = TestPatchBuilder(args.software_version) |
||||
test_patch_builder.rr_allnodes_patch(patch_name, args.requires, args.formal) |
||||
|
||||
except TestPatchCreationException: |
||||
log.exception("Error while creating test patches") |
Loading…
Reference in new issue