Files
distcloud/distributedcloud/dcmanager/orchestrator/states/patch/updating_patches.py
Hugo Brito 3c2cb2638a Disable patch-strategy for current release and onwards
This commit introduces changes to disable the patch-strategy for the
current release and onwards. The patch-strategy is still active for n-1
subclouds to allow the application of a specific patch to enable the new
USM feature through the usage of the --patch argument.

To reflect the current behavior of the patch orchestration, the
FinishingPatchStrategyState and PatchJobData were removed, as they
are no longer required to apply the USM patch.

Test Plan:

PASS - Execute patch-strategy create/apply for n-1 subclouds
- dcmanager patch-strategy create --upload-only --patch test.patch
- dcmanager patch-strategy apply
- dcmanager patch-strategy delete
- dcmanager patch-strategy create --patch test.patch
- dcmanager patch-strategy apply

Failure Path:

PASS - Unable to execute `patch-strategy create` for current release
- dcmanager patch-strategy create --patch test.patch
  - ERROR (app) Unable to process the contained instructions Unable to
    create strategy of type 'patch': Bad strategy request: Subcloud
    subcloud1-stx-latest has the same software version than the system
    controller. The --patch option only works with n-1 subclouds
PASS - Unable to execute `patch-strategy create` without a patch file
- dcmanager patch-strategy create
  - ERROR (app) The server could not comply with the request since it
    is either malformed or otherwise incorrect. Patch paramater is
    required for strategy type: patch.

Story: 2010676
Task: 50609

Change-Id: Id7b57fd6b22c92d561c1faeedb017002a58a66b6
Signed-off-by: Hugo Brito <hugo.brito@windriver.com>
2024-07-19 16:13:32 -03:00

131 lines
4.7 KiB
Python

#
# Copyright (c) 2023-2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import os
import time
from dcmanager.common import consts
from dcmanager.common.exceptions import StrategyStoppedException
from dcmanager.common import utils
from dcmanager.orchestrator.states.base import BaseState
# Max time: 1 minute = 6 queries x 10 seconds between
DEFAULT_MAX_QUERIES = 6
DEFAULT_SLEEP_DURATION = 10
class UpdatingPatchesState(BaseState):
"""Patch orchestration state for updating patches"""
def __init__(self, region_name):
super(UpdatingPatchesState, self).__init__(
next_state=consts.STRATEGY_STATE_CREATING_VIM_PATCH_STRATEGY,
region_name=region_name,
)
self.max_queries = DEFAULT_MAX_QUERIES
self.sleep_duration = DEFAULT_SLEEP_DURATION
self.region_one_patches = None
self.region_one_applied_patch_ids = None
def upload_patch(self, patch_file, strategy_step):
"""Upload a patch file to the subcloud"""
if not os.path.isfile(patch_file):
message = f"Patch file {patch_file} is missing"
self.error_log(strategy_step, message)
raise Exception(message)
self.info_log(
strategy_step,
f"Patch {patch_file} will be uploaded to subcloud",
)
self.get_patching_client(self.region_name).upload([patch_file])
if self.stopped():
self.info_log(strategy_step, "Exiting because task is stopped")
raise StrategyStoppedException()
def perform_state_action(self, strategy_step):
"""Update patches in this subcloud"""
self.info_log(strategy_step, "Updating patches")
extra_args = utils.get_sw_update_strategy_extra_args(self.context)
upload_only = extra_args.get(consts.EXTRA_ARGS_UPLOAD_ONLY)
patch_file = extra_args.get(consts.EXTRA_ARGS_PATCH)
# Retrieve all subcloud patches
try:
subcloud_patches = self.get_patching_client(self.region_name).query()
except Exception:
message = "Cannot retrieve subcloud patches. Please see logs for details."
self.exception_log(strategy_step, message)
raise Exception(message)
subcloud_patch_ids = subcloud_patches.keys()
patch = os.path.basename(patch_file)
patch_id = os.path.splitext(patch)[0]
if patch_id in subcloud_patch_ids:
message = f"Patch {patch_id} is already present in the subcloud."
self.info_log(strategy_step, message)
else:
self.upload_patch(patch_file, strategy_step)
if upload_only:
self.info_log(
strategy_step,
f"{consts.EXTRA_ARGS_UPLOAD_ONLY} option enabled, skipping "
f"execution. Forward to state: {consts.STRATEGY_STATE_COMPLETE}",
)
return consts.STRATEGY_STATE_COMPLETE
# Apply the patch to the subcloud
self.info_log(
strategy_step,
f"Patch {patch_file} will be applied to subcloud",
)
self.get_patching_client(self.region_name).apply([patch_id])
# Now that we have applied/removed/uploaded patches, we need to give
# the patch controller on this subcloud time to determine whether
# each host on that subcloud is patch current.
wait_count = 0
while True:
subcloud_hosts = self.get_patching_client(self.region_name).query_hosts()
self.debug_log(
strategy_step, "query_hosts for subcloud returned %s" % subcloud_hosts
)
for host in subcloud_hosts:
if host["interim_state"]:
# This host is not yet ready.
self.debug_log(
strategy_step,
"Host %s in subcloud in interim state" % host["hostname"],
)
break
else:
# All hosts in the subcloud are updated
break
wait_count += 1
if wait_count >= self.max_queries:
# We have waited too long.
# We log a warning but do not fail the step
message = (
"Applying patches to subcloud taking too long to recover. "
"Continuing..."
)
self.warn_log(strategy_step, message)
break
if self.stopped():
self.info_log(strategy_step, "Exiting because task is stopped")
raise StrategyStoppedException()
# Delay between queries
time.sleep(self.sleep_duration)
return self.next_state