Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge upgrade and preupgrade script, add sync script #6

Merged
merged 2 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/check-scripts-updates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ jobs:

changed_files=$(git diff --name-only "$BASE_COMMIT" "$HEAD_COMMIT")

# Check if any files in scripts/ were updated (excluding wrap_scripts_in_yaml.py)
scripts_updated=$(echo "$changed_files" | grep -v 'wrap_scripts_in_yaml.py' | grep 'scripts/' || true)
Monnte marked this conversation as resolved.
Show resolved Hide resolved
# Check if any files in scripts/ were updated
scripts_updated=$(echo "$changed_files" | grep 'scripts/' || true)
echo "Scripts updated: $scripts_updated"

# Check if any files in playbooks/ were updated
Expand Down
7 changes: 4 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ repos:
"-sn", # Don't display the score
"--rcfile=.pylintrc", # Link to your config file
]
- id: wrap-scripts-in-yaml
name: wrap-scripts-in-yaml
entry: python scripts/wrap_scripts_in_yaml.py
- id: sync-scripts-to-yaml
name: sync-scripts-to-yaml
entry: python misc/sync_scripts_to_yaml.py
args: ["--target", "repo"]
language: python
files: scripts/.*\.py$

Expand Down
93 changes: 93 additions & 0 deletions misc/sync_scripts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import os
import argparse
import ruamel.yaml

# Scripts located in this project
SCRIPT_PATH = "scripts/leapp_script.py"

REPO_PRE_UPGRADE_YAML_PATH = os.path.join(".", "playbooks/leapp_preupgrade_script.yaml")
REPO_UPGRADE_YAML_PATH = os.path.join(".", "playbooks/leapp_upgrade_script.yaml")

WORKER_PRE_UPGRADE_YAML_PATH = os.path.join(
"..", "rhc-worker-script/development/nginx/data/leapp_preupgrade.yml"
)
WORKER_UPGRADE_YAML_PATH = os.path.join(
"..", "rhc-worker-script/development/nginx/data/leapp_upgrade.yml"
)

DEFAULT_YAML_ENVELOPE = """
- name: LEAPP
vars:
insights_signature: |
ascii_armored gpg signature
insights_signature_exclude: /vars/insights_signature,/vars/content_vars
interpreter: /usr/bin/python
content: |
placeholder
content_vars:
# variables that will be handed to the script as environment vars
# will be prefixed with RHC_WORKER_*
LEAPP_SCRIPT_TYPE: type
"""


def _get_updated_yaml_content(yaml_path, script_path):
if not os.path.exists(yaml_path):
yaml = ruamel.yaml.YAML()
config = yaml.load(DEFAULT_YAML_ENVELOPE)
mapping = 2
offset = 0
else:
config, mapping, offset = ruamel.yaml.util.load_yaml_guess_indent(
open(yaml_path)
)
print(mapping, offset)

with open(script_path) as script:
content = script.read()

script_type = "PREUPGRADE" if "preupgrade" in yaml_path else "UPGRADE"
config[0]["name"] = "Leapp %s for rhc-worker-script" % script_type.title()
config[0]["vars"]["content"] = content
config[0]["vars"]["content_vars"]["LEAPP_SCRIPT_TYPE"] = script_type
return config, mapping, offset


def _write_content(config, path, mapping=None, offset=None):
yaml = ruamel.yaml.YAML()
if mapping and offset:
yaml.indent(mapping=mapping, sequence=mapping, offset=offset)
with open(path, "w") as handler:
yaml.dump(config, handler)


def main():
parser = argparse.ArgumentParser()
parser.add_argument(
"--target",
choices=["repo", "worker"],
help="Target to sync scripts to",
default="worker",
)
args = parser.parse_args()

if args.target == "repo":
print("Syncing scripts to repo")
pre_upgrade_path = REPO_PRE_UPGRADE_YAML_PATH
upgrade_path = REPO_UPGRADE_YAML_PATH

elif args.target == "worker":
print("Syncing scripts to worker")
pre_upgrade_path = WORKER_PRE_UPGRADE_YAML_PATH
upgrade_path = WORKER_UPGRADE_YAML_PATH

config, mapping, offset = _get_updated_yaml_content(pre_upgrade_path, SCRIPT_PATH)
print("Writing new content to %s" % pre_upgrade_path)
_write_content(config, pre_upgrade_path, mapping, offset)
config, mapping, offset = _get_updated_yaml_content(upgrade_path, SCRIPT_PATH)
print("Writing new content to %s" % upgrade_path)
_write_content(config, upgrade_path, mapping, offset)


if __name__ == "__main__":
main()
133 changes: 86 additions & 47 deletions playbooks/leapp_preupgrade_script.yaml
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
- name: Leapp pre-upgrade for rhc-worker-script
- name: Leapp Preupgrade for rhc-worker-script
vars:
insights_signature: !!binary |
needs signature
insights_signature_exclude: "/vars/insights_signature"
insights_signature: |
ascii_armored gpg signature
insights_signature_exclude: /vars/insights_signature,/vars/content_vars
interpreter: /usr/bin/python
content: |
import json
import os
import subprocess


# SCRIPT_TYPE is either 'PREUPGRADE' or 'UPGRADE'
# Value is set in signed yaml envelope in content_vars (RHC_WORKER_LEAPP_SCRIPT_TYPE)
SCRIPT_TYPE = os.environ.get("RHC_WORKER_LEAPP_SCRIPT_TYPE", "None")
IS_UPGRADE = SCRIPT_TYPE == "UPGRADE"
IS_PREUPGRADE = SCRIPT_TYPE == "PREUPGRADE"
JSON_REPORT_PATH = "/var/log/leapp/leapp-report.json"
TXT_REPORT_PATH = "/var/log/leapp/leapp-report.txt"
REBOOT_GUIDANCE_MESSAGE = "A reboot is required to continue. Please reboot your system."

# Based on https://github.com/oamg/leapp/blob/master/report-schema-v110.json#L211
STATUS_CODE = {
Expand Down Expand Up @@ -103,6 +108,7 @@


def is_non_eligible_releases(release):
"""Check if the release is eligible for upgrade or preupgrade."""
print("Exit if not RHEL 7 or RHEL 8 ...")
major_version, _ = release.split(".") if release is not None else (None, None)
return release is None or major_version not in ["7", "8"]
Expand Down Expand Up @@ -220,15 +226,18 @@


def setup_leapp(version):
print("Installing leapp ...")
leapp_install_command, rhel_rhui_packages = _get_leapp_command_and_packages(version)
output, returncode = run_subprocess(leapp_install_command)
if returncode:
raise ProcessError(
message="Installation of leapp failed",
report="Installation of leapp failed with code '%s' and output: %s."
% (returncode, output.rstrip("\n")),
)
if _check_if_package_installed('leapp-upgrade'):
print("'leapp-upgrade' already installed, skipping ...")
else:
print("Installing leapp ...")
output, returncode = run_subprocess(leapp_install_command)
if returncode:
raise ProcessError(
message="Installation of leapp failed",
report="Installation of leapp failed with code '%s' and output: %s."
% (returncode, output.rstrip("\n")),
)

print("Check installed rhui packages ...")
for pkg in rhel_rhui_packages:
Expand All @@ -252,7 +261,11 @@
)

if rhui_installed and not rhsm_repo_check_fail:
print("RHUI packages detected, adding --no-rhsm flag to preupgrade command")
print(
"RHUI packages detected, adding --no-rhsm flag to {} command".format(
SCRIPT_TYPE.title()
)
)
command.append("--no-rhsm")
return True
return False
Expand All @@ -274,7 +287,7 @@


def remove_previous_reports():
print("Removing previous preupgrade reports at /var/log/leapp/leapp-report.* ...")
print("Removing previous leapp reports at /var/log/leapp/leapp-report.* ...")

if os.path.exists(JSON_REPORT_PATH):
os.remove(JSON_REPORT_PATH)
Expand All @@ -283,17 +296,11 @@
os.remove(TXT_REPORT_PATH)


def execute_preupgrade(command):
print("Executing preupgrade ...")
_, _ = run_subprocess(command)
def execute_operation(command):
print("Executing {} ...".format(SCRIPT_TYPE.title()))
output, _ = run_subprocess(command)

# NOTE: we do not care about returncode because non-null always means actor error (or leapp error)
# if returncode:
# print(
# "The process leapp exited with code '%s' and output: %s\n"
# % (returncode, output)
# )
# raise ProcessError(message="Leapp exited with code '%s'." % returncode)
return output


def _find_highest_report_level(entries):
Expand All @@ -312,8 +319,8 @@
return STATUS_CODE_NAME_MAP[valid_action_levels[0]]


def parse_results(output):
print("Processing preupgrade results ...")
def parse_results(output, reboot_required=False):
print("Processing {} results ...".format(SCRIPT_TYPE.title()))

report_json = "Not found"
message = "Can't open json report at " + JSON_REPORT_PATH
Expand All @@ -325,16 +332,28 @@
with open(JSON_REPORT_PATH, mode="r") as handler:
report_json = json.load(handler)

# NOTE: with newer schema we will need to parse groups instead of flags
report_entries = report_json.get("entries", [])

error_count = len(
[entry for entry in report_entries if "error" in entry.get("groups")]
)
inhibitor_count = len(
[entry for entry in report_entries if "inhibitor" in entry.get("flags")]
[entry for entry in report_entries if "inhibitor" in entry.get("groups")]
)
message = "Your system has %s inhibitors out of %s potential problems." % (
inhibitor_count,
len(report_entries),
message = (
"Your system has %s error%s and %s inhibitor%s out of %s potential problem%s."
% (
error_count,
"" if error_count == 1 else "s",
inhibitor_count,
"" if inhibitor_count == 1 else "s",
len(report_entries),
"" if len(report_entries) == 1 else "s",
)
)
alert = inhibitor_count > 0
if reboot_required:
message += " System is ready to be upgraded. Rebooting system in 1 minute."
alert = inhibitor_count > 0 or error_count > 0
status = (
_find_highest_report_level(report_entries)
if len(report_entries) > 0
Expand All @@ -355,24 +374,36 @@
output.report = report_txt


def update_insights_inventory():
def update_insights_inventory(output):
"""Call insights-client to update insights inventory."""
print("Updating system status in Red Hat Insights.")
output, returncode = run_subprocess(cmd=["/usr/bin/insights-client"])
_, returncode = run_subprocess(cmd=["/usr/bin/insights-client"])

if returncode:
raise ProcessError(
message="Failed to update Insights Inventory by registering the system again. See output the following output: %s"
% output,
report="insights-client execution exited with code '%s'." % returncode,
)
print("System registration failed with exit code %s." % returncode)
output.message += " Failed to update Insights Inventory."
output.alert = True
return

print("System registered with insights-client successfully.")


def reboot_system():
print("Rebooting system in 1 minute.")
run_subprocess(["/usr/sbin/shutdown", "-r", "1"], wait=False)


def main():
try:
# Exit if not RHEL 7 or 8
# Exit if invalid value for SCRIPT_TYPE
if SCRIPT_TYPE not in ["PREUPGRADE", "UPGRADE"]:
raise ProcessError(
message="Allowed values for RHC_WORKER_LEAPP_SCRIPT_TYPE are 'PREUPGRADE' and 'UPGRADE'.",
report="Exiting because RHC_WORKER_LEAPP_SCRIPT_TYPE='%s'"
% SCRIPT_TYPE,
)

# Exit if not eligible release
dist, version = get_rhel_version()
if dist != "rhel" or is_non_eligible_releases(version):
raise ProcessError(
Expand All @@ -382,19 +413,24 @@
)

output = OutputCollector()
preupgrade_command = ["/usr/bin/leapp", "preupgrade", "--report-schema=1.1.0"]
preupgrade_command = ["/usr/bin/leapp", "preupgrade", "--report-schema=1.2.0"]
upgrade_command = ["/usr/bin/leapp", "upgrade", "--report-schema=1.2.0"]
operation_command = preupgrade_command if IS_PREUPGRADE else upgrade_command
rhui_pkgs = setup_leapp(version)

# Check for RHUI PKGs
use_no_rhsm = should_use_no_rhsm_check(len(rhui_pkgs) > 1, preupgrade_command)
use_no_rhsm = should_use_no_rhsm_check(len(rhui_pkgs) > 1, operation_command)
if use_no_rhsm:
install_leapp_pkg_corresponding_to_installed_rhui(rhui_pkgs)

remove_previous_reports()
execute_preupgrade(preupgrade_command)
parse_results(output)
update_insights_inventory()
print("Pre-upgrade successfully executed.")
leapp_output = execute_operation(operation_command)
reboot_required = REBOOT_GUIDANCE_MESSAGE in leapp_output
parse_results(output, reboot_required)
update_insights_inventory(output)
print("Operation {} finished successfully.".format(SCRIPT_TYPE.title()))
if reboot_required:
reboot_system()
except ProcessError as exception:
print(exception.report)
output = OutputCollector(
Expand Down Expand Up @@ -422,3 +458,6 @@
if __name__ == "__main__":
main()
content_vars:
# variables that will be handed to the script as environment vars
# will be prefixed with RHC_WORKER_*
LEAPP_SCRIPT_TYPE: PREUPGRADE
Loading