Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
cad78f9
Restore patch mode config on Image Default: Enabled for Apt and Yum P…
rane-rajasi Mar 27, 2025
fa264be
Restore patch mode config on Image Default: Enabled for Zypper Packag…
rane-rajasi Mar 27, 2025
08268a5
Merge branch 'master' into rarane/repairitem/restorepatchmode
rane-rajasi Apr 14, 2025
24e67ff
Restore patch mode config on Image Default: Enabled for Tdnf PackageM…
rane-rajasi Apr 14, 2025
3263c01
Restore patch mode config on Image Default: Addressing PR feedback#2
rane-rajasi Apr 14, 2025
919603f
Restore patch mode config on Image Default: Adding UTs and some code …
rane-rajasi Apr 17, 2025
2176e47
Merge branch 'master' into rarane/repairitem/restorepatchmode
rane-rajasi Apr 17, 2025
e889cc5
Restore patch mode config on Image Default: Addressing Pr feedback: 3.1
rane-rajasi Apr 18, 2025
8fcce09
Restore patch mode config on Image Default: Addressing Pr feedback: 3.2
rane-rajasi Apr 25, 2025
9905c89
Restore patch mode config on Image Default: Addressing Pr feedback: 3.3
rane-rajasi Apr 29, 2025
0bb7b35
Merge branch 'master' into rarane/repairitem/restorepatchmode
rane-rajasi Apr 29, 2025
a6ad98a
Restore patch mode config on Image Default: Addressing PR feedback: #4
rane-rajasi May 2, 2025
a616a57
Merge branch 'master' into rarane/repairitem/restorepatchmode
rane-rajasi May 2, 2025
ac0755a
Restore patch mode config on Image Default: Addressing PR feedback: #4.1
rane-rajasi May 2, 2025
48224d8
Restore patch mode config on Image Default: Refactoring UTs
rane-rajasi May 2, 2025
3a87efe
Restore patch mode config on Image Default: Fixing UT test mock
rane-rajasi May 2, 2025
badaa03
Merge branch 'master' into rarane/repairitem/restorepatchmode
rane-rajasi May 2, 2025
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
2 changes: 2 additions & 0 deletions src/core/src/core_logic/ConfigurePatchingProcessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ def __try_set_patch_mode(self):
# NOTE: this condition will be false for Assessment operations, since patchMode is not sent in the API request
if self.current_auto_os_patch_state != Constants.AutomaticOSPatchStates.DISABLED and self.execution_config.patch_mode == Constants.PatchModes.AUTOMATIC_BY_PLATFORM:
self.package_manager.disable_auto_os_update()
elif self.current_auto_os_patch_state == Constants.AutomaticOSPatchStates.DISABLED and self.execution_config.patch_mode == Constants.PatchModes.IMAGE_DEFAULT:
self.package_manager.revert_auto_os_update_to_system_default()

self.current_auto_os_patch_state = self.package_manager.get_current_auto_os_patch_state()

Expand Down
86 changes: 60 additions & 26 deletions src/core/src/package_managers/AptitudePackageManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,7 @@
# region auto OS updates
def get_current_auto_os_patch_state(self):
""" Gets the current auto OS update patch state on the machine """
self.composite_logger.log("Fetching the current automatic OS patch state on the machine...")
self.composite_logger.log("[APM] Fetching the current automatic OS patch state on the machine...")
if os.path.exists(self.os_patch_configuration_settings_file_path):
self.__get_current_auto_os_updates_setting_on_machine()
if not os.path.exists(self.os_patch_configuration_settings_file_path) or int(self.unattended_upgrade_value) == 0:
Expand All @@ -685,7 +685,7 @@
else:
current_auto_os_patch_state = Constants.AutomaticOSPatchStates.UNKNOWN

self.composite_logger.log_debug("Current Auto OS Patch State is [State={0}]".format(str(current_auto_os_patch_state)))
self.composite_logger.log_debug("[APM] Current Auto OS Patch State is [State={0}]".format(str(current_auto_os_patch_state)))
return current_auto_os_patch_state

def __get_current_auto_os_updates_setting_on_machine(self):
Expand All @@ -700,76 +700,74 @@
self.unattended_upgrade_value = re.search(self.unattended_upgrade + ' *"(.*?)".', str(setting)).group(1)

if self.update_package_list_value == "":
self.composite_logger.log_debug("Machine did not have any value set for [Setting={0}]".format(str(self.update_package_list)))
self.composite_logger.log_debug("[APM] Machine did not have any value set for [Setting={0}]".format(str(self.update_package_list)))

if self.unattended_upgrade_value == "":
self.composite_logger.log_debug("Machine did not have any value set for [Setting={0}]".format(str(self.unattended_upgrade)))
self.composite_logger.log_debug("[APM] Machine did not have any value set for [Setting={0}]".format(str(self.unattended_upgrade)))

except Exception as error:
raise Exception("Error occurred in fetching default auto OS updates from the machine. [Exception={0}]".format(repr(error)))
raise Exception("[APM] Error occurred in fetching default auto OS updates from the machine. [Exception={0}]".format(repr(error)))

def disable_auto_os_update(self):
""" Disables auto OS updates on the machine only if they are enabled and logs the default settings the machine comes with """
try:
self.composite_logger.log_debug("Disabling auto OS updates if they are enabled")
self.composite_logger.log_debug("[APM] Disabling auto OS updates if they are enabled")
self.backup_image_default_patch_configuration_if_not_exists()
self.update_os_patch_configuration_sub_setting(self.update_package_list, "0")
self.update_os_patch_configuration_sub_setting(self.unattended_upgrade, "0")
self.composite_logger.log("Successfully disabled auto OS updates")
self.composite_logger.log("[APM] Successfully disabled auto OS updates")
except Exception as error:
self.composite_logger.log_error("Could not disable auto OS updates. [Error={0}]".format(repr(error)))
self.composite_logger.log_error("[APM] Could not disable auto OS updates. [Error={0}]".format(repr(error)))
raise

def backup_image_default_patch_configuration_if_not_exists(self):
""" Records the default system settings for auto OS updates within patch extension artifacts for future reference.
We only log the default system settings a VM comes with, any subsequent updates will not be recorded"""
try:
image_default_patch_configuration_backup = {}
image_default_patch_configuration_backup_exists = self.image_default_patch_configuration_backup_exists()

# read existing backup since it also contains backup from other update services. We need to preserve any existing data with backup file
if image_default_patch_configuration_backup_exists:
try:
image_default_patch_configuration_backup = json.loads(self.env_layer.file_system.read_with_retry(self.image_default_patch_configuration_backup_path))
except Exception as error:
self.composite_logger.log_error("Unable to read backup for default patch state. Will attempt to re-write. [Exception={0}]".format(repr(error)))
image_default_patch_configuration_backup = self.__get_image_default_patch_configuration_backup()

# verify if existing backup is valid if not, write to backup
is_backup_valid = image_default_patch_configuration_backup_exists and self.is_image_default_patch_configuration_backup_valid(image_default_patch_configuration_backup)
is_backup_valid = self.is_image_default_patch_configuration_backup_valid(image_default_patch_configuration_backup)
if is_backup_valid:
self.composite_logger.log_debug("Since extension has a valid backup, no need to log the current settings again. [Default Auto OS update settings={0}] [File path={1}]"
self.composite_logger.log_debug("[APM] Since extension has a valid backup, no need to log the current settings again. [Default Auto OS update settings={0}] [File path={1}]"
.format(str(image_default_patch_configuration_backup), self.image_default_patch_configuration_backup_path))
else:
self.composite_logger.log_debug("Since the backup is invalid or does not exist, will add a new backup with the current auto OS update settings")
self.composite_logger.log_debug("[APM] Since the backup is invalid or does not exist, will add a new backup with the current auto OS update settings")
self.__get_current_auto_os_updates_setting_on_machine()

backup_image_default_patch_configuration_json = {
self.update_package_list: self.update_package_list_value,
self.unattended_upgrade: self.unattended_upgrade_value
}

self.composite_logger.log_debug("Logging default system configuration settings for auto OS updates. [Settings={0}] [Log file path={1}]"
self.composite_logger.log_debug("[APM] Logging default system configuration settings for auto OS updates. [Settings={0}] [Log file path={1}]"
.format(str(backup_image_default_patch_configuration_json), self.image_default_patch_configuration_backup_path))
self.env_layer.file_system.write_with_retry(self.image_default_patch_configuration_backup_path, '{0}'.format(json.dumps(backup_image_default_patch_configuration_json)), mode='w+')
except Exception as error:
error_message = "Exception during fetching and logging default auto update settings on the machine. [Exception={0}]".format(repr(error))
error_message = "[APM] Exception during fetching and logging default auto update settings on the machine. [Exception={0}]".format(repr(error))
self.composite_logger.log_error(error_message)
self.status_handler.add_error_to_status(error_message, Constants.PatchOperationErrorCodes.DEFAULT_ERROR)
raise

def is_image_default_patch_configuration_backup_valid(self, image_default_patch_configuration_backup):
if self.update_package_list in image_default_patch_configuration_backup and self.unattended_upgrade in image_default_patch_configuration_backup:
self.composite_logger.log_debug("Extension already has a valid backup of the default system configuration settings for auto OS updates.")
self.composite_logger.log_debug("[APM] Extension already has a valid backup of the default system configuration settings for auto OS updates.")
return True
else:
self.composite_logger.log_error("Extension does not have a valid backup of the default system configuration settings for auto OS updates.")
self.composite_logger.log_error("[APM] Extension does not have a valid backup of the default system configuration settings for auto OS updates.")
return False

def update_os_patch_configuration_sub_setting(self, patch_configuration_sub_setting, value="0", patch_configuration_sub_setting_pattern_to_match=""):
""" Updates (or adds if it doesn't exist) the given patch_configuration_sub_setting with the given value in os_patch_configuration_settings_file """
try:
# note: adding space between the patch_configuration_sub_setting and value since, we will have to do that if we have to add a patch_configuration_sub_setting that did not exist before
self.composite_logger.log("Updating system configuration settings for auto OS updates. [Patch Configuration Sub Setting={0}] [Value={1}]".format(str(patch_configuration_sub_setting), value))
self.composite_logger.log("[APM] Updating system configuration settings for auto OS updates. [PatchConfigurationSubSetting={0}][Value={1}]".format(str(patch_configuration_sub_setting), value))

if value == '':
self.composite_logger.log_debug("[APM] We won't update the system configuration settings since new configuration value to update does not an acceptable value. [PatchConfigurationSubSetting={0}][ValueToUpdate={1}]"
.format(str(patch_configuration_sub_setting), value))
return

os_patch_configuration_settings = self.env_layer.file_system.read_with_retry(self.os_patch_configuration_settings_file_path)
patch_configuration_sub_setting_to_update = patch_configuration_sub_setting + ' "' + value + '";'
patch_configuration_sub_setting_found_in_file = False
Expand All @@ -789,10 +787,46 @@

self.env_layer.file_system.write_with_retry(self.os_patch_configuration_settings_file_path, '{0}'.format(updated_patch_configuration_sub_setting.lstrip()), mode='w+')
except Exception as error:
error_msg = "Error occurred while updating system configuration settings for auto OS updates. [Patch Configuration={0}] [Error={1}]".format(str(patch_configuration_sub_setting), repr(error))
error_msg = "[APM] Error occurred while updating system configuration settings for auto OS updates. [Patch Configuration={0}] [Error={1}]".format(str(patch_configuration_sub_setting), repr(error))

Check warning on line 790 in src/core/src/package_managers/AptitudePackageManager.py

View check run for this annotation

Codecov / codecov/patch

src/core/src/package_managers/AptitudePackageManager.py#L790

Added line #L790 was not covered by tests
self.composite_logger.log_error(error_msg)
self.status_handler.add_error_to_status(error_msg, Constants.PatchOperationErrorCodes.DEFAULT_ERROR)
raise

def revert_auto_os_update_to_system_default(self):
""" Reverts the auto OS update patch state on the machine to its system default value, if one exists in our backup file """
# type () -> None
self.composite_logger.log("[APM] Reverting the current automatic OS patch state on the machine to its system default value before patchmode was set to 'AutomaticByPlatform'")

if not os.path.exists(self.os_patch_configuration_settings_file_path):
self.composite_logger.log_debug("[APM] Automatic OS patch config file not found on the VM. We won't be able to revert auto OS patch settings to their system default values")
return

self.__get_current_auto_os_updates_setting_on_machine()
self.composite_logger.log_debug("[APM] Logging current configuration settings for auto OS updates. [{0}={1}][{2}={3}]"
.format(str(self.update_package_list), str(self.update_package_list_value), str(self.unattended_upgrade), str(self.unattended_upgrade_value)))

image_default_patch_configuration_backup = self.__get_image_default_patch_configuration_backup()
self.composite_logger.log_debug("[APM] Logging system default configuration settings for auto OS updates. [Settings={0}]".format(str(image_default_patch_configuration_backup)))
is_backup_valid = self.is_image_default_patch_configuration_backup_valid(image_default_patch_configuration_backup)

if is_backup_valid:
self.update_os_patch_configuration_sub_setting(self.update_package_list, image_default_patch_configuration_backup[self.update_package_list])
self.update_os_patch_configuration_sub_setting(self.unattended_upgrade, image_default_patch_configuration_backup[self.unattended_upgrade])
self.composite_logger.log_debug("[APM] Successfully reverted auto OS updates to system default config")
else:
self.composite_logger.log_debug("[APM] Since the backup is invalid or does not exist, we won't be able to revert auto OS patch settings to their system default value")

def __get_image_default_patch_configuration_backup(self):
""" Get image_default_patch_configuration_backup file"""
image_default_patch_configuration_backup = {}

# read existing backup since it also contains backup from other update services. We need to preserve any existing data with backup file
if self.image_default_patch_configuration_backup_exists():
try:
image_default_patch_configuration_backup = json.loads(self.env_layer.file_system.read_with_retry(self.image_default_patch_configuration_backup_path))
except Exception as error:
self.composite_logger.log_error("[APM] Unable to read backup for default patch state. [Exception={0}]".format(repr(error)))

Check warning on line 828 in src/core/src/package_managers/AptitudePackageManager.py

View check run for this annotation

Codecov / codecov/patch

src/core/src/package_managers/AptitudePackageManager.py#L827-L828

Added lines #L827 - L828 were not covered by tests
return image_default_patch_configuration_backup
# endregion

# region Reboot Management
Expand Down
3 changes: 3 additions & 0 deletions src/core/src/package_managers/PackageManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,9 @@
@abstractmethod
def update_os_patch_configuration_sub_setting(self, patch_configuration_sub_setting, value, patch_configuration_sub_setting_pattern_to_match):
pass

def revert_auto_os_update_to_system_default(self):
pass

Check warning on line 435 in src/core/src/package_managers/PackageManager.py

View check run for this annotation

Codecov / codecov/patch

src/core/src/package_managers/PackageManager.py#L435

Added line #L435 was not covered by tests
# endregion

# region Handling known errors
Expand Down
Loading