From da72c37017784a87bf7876bd5066b3ad44b8d38e Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Tue, 8 Nov 2022 15:09:09 -0800 Subject: [PATCH 01/26] Update version to dummy 1.0.0.0' --- azurelinuxagent/common/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurelinuxagent/common/version.py b/azurelinuxagent/common/version.py index ff9c903b93..9a41c2e109 100644 --- a/azurelinuxagent/common/version.py +++ b/azurelinuxagent/common/version.py @@ -209,7 +209,7 @@ def has_logrotate(): # # When doing a release, be sure to use the actual agent version. Current agent version: 2.4.0.0 # -AGENT_VERSION = '9.9.9.9' +AGENT_VERSION = '1.0.0.0' AGENT_LONG_VERSION = "{0}-{1}".format(AGENT_NAME, AGENT_VERSION) AGENT_DESCRIPTION = """ The Azure Linux Agent supports the provisioning and running of Linux From 59dbd2245d6f55e8e4c0eb494bd0d01dcd44a2e3 Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Tue, 8 Nov 2022 15:40:54 -0800 Subject: [PATCH 02/26] Revert version change --- azurelinuxagent/common/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurelinuxagent/common/version.py b/azurelinuxagent/common/version.py index 9a41c2e109..ff9c903b93 100644 --- a/azurelinuxagent/common/version.py +++ b/azurelinuxagent/common/version.py @@ -209,7 +209,7 @@ def has_logrotate(): # # When doing a release, be sure to use the actual agent version. Current agent version: 2.4.0.0 # -AGENT_VERSION = '1.0.0.0' +AGENT_VERSION = '9.9.9.9' AGENT_LONG_VERSION = "{0}-{1}".format(AGENT_NAME, AGENT_VERSION) AGENT_DESCRIPTION = """ The Azure Linux Agent supports the provisioning and running of Linux From 55e261a8dd695365cf3bb275f221379f969dd76e Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Wed, 7 Dec 2022 18:49:28 -0800 Subject: [PATCH 03/26] Update goalstate to take list of properties to process --- azurelinuxagent/common/protocol/goal_state.py | 93 ++++++++++++------- 1 file changed, 57 insertions(+), 36 deletions(-) diff --git a/azurelinuxagent/common/protocol/goal_state.py b/azurelinuxagent/common/protocol/goal_state.py index 664b70ef1b..8908876ee3 100644 --- a/azurelinuxagent/common/protocol/goal_state.py +++ b/azurelinuxagent/common/protocol/goal_state.py @@ -20,6 +20,7 @@ import re import time import json +from enum import Enum from azurelinuxagent.common import conf from azurelinuxagent.common import logger @@ -48,6 +49,17 @@ _GET_GOAL_STATE_MAX_ATTEMPTS = 6 +class GoalStateProperties(Enum): + """ + Enum for defining the properties that we fetch in the goal state + """ + RoleConfig = "ConfigName" + HostingEnv = "HostingEnvironmentConfig" + SharedConfig = "SharedConfig" + ExtensionsConfig_Certs = "ExtensionsConfig_Certificates" + RemoteAccessInfo = "RemoteAccessInfo" + + class GoalStateInconsistentError(ProtocolError): """ Indicates an inconsistency in the goal state (e.g. missing tenant certificate) @@ -57,7 +69,7 @@ def __init__(self, msg, inner=None): class GoalState(object): - def __init__(self, wire_client, silent=False): + def __init__(self, wire_client, goalstate_properties=GoalStateProperties, silent=False): """ Fetches the goal state using the given wire client. @@ -85,7 +97,7 @@ def __init__(self, wire_client, silent=False): self._certs = EmptyCertificates() self._remote_access = None - self.update(silent=silent) + self.update(goalstate_properties=goalstate_properties, silent=silent) except ProtocolError: raise @@ -160,20 +172,20 @@ def update_host_plugin_headers(wire_client): # Fetching the goal state updates the HostGAPlugin so simply trigger the request GoalState._fetch_goal_state(wire_client) - def update(self, silent=False): + def update(self, goalstate_properties, silent=False): """ Updates the current GoalState instance fetching values from the WireServer/HostGAPlugin as needed """ self.logger.silent = silent try: - self._update(force_update=False) + self._update(goalstate_properties=goalstate_properties, force_update=False) except GoalStateInconsistentError as e: self.logger.warn("Detected an inconsistency in the goal state: {0}", ustr(e)) - self._update(force_update=True) + self._update(goalstate_properties=goalstate_properties, force_update=True) self.logger.info("The goal state is consistent") - def _update(self, force_update): + def _update(self, goalstate_properties, force_update): # # Fetch the goal state from both the HGAP and the WireServer # @@ -226,7 +238,7 @@ def _update(self, force_update): # extensions_config = None if goal_state_updated: - extensions_config = self._fetch_full_wire_server_goal_state(incarnation, xml_doc) + extensions_config = self._fetch_full_wire_server_goal_state(incarnation, xml_doc, goalstate_properties) # # Lastly, decide whether to use the vmSettings or extensionsConfig for the extensions goal state @@ -343,7 +355,7 @@ def _fetch_vm_settings(wire_client, force_update=False): return vm_settings, vm_settings_updated - def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc): + def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc, goalstate_properties=GoalStateProperties): """ Issues HTTP requests (to the WireServer) for each of the URIs in the goal state (ExtensionsConfig, Certificate, Remote Access users, etc) and populates the corresponding properties. @@ -356,40 +368,48 @@ def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc): self.logger.info(message) add_event(op=WALAEventOperation.GoalState, message=message) - role_instance = find(xml_doc, "RoleInstance") - role_instance_id = findtext(role_instance, "InstanceId") - role_config = find(role_instance, "Configuration") - role_config_name = findtext(role_config, "ConfigName") - container = find(xml_doc, "Container") - container_id = findtext(container, "ContainerId") + role_instance_id = None + role_config_name = None + container_id = None + if GoalStateProperties.RoleConfig in goalstate_properties: + role_instance = find(xml_doc, "RoleInstance") + role_instance_id = findtext(role_instance, "InstanceId") + role_config = find(role_instance, "Configuration") + role_config_name = findtext(role_config, "ConfigName") + container = find(xml_doc, "Container") + container_id = findtext(container, "ContainerId") extensions_config_uri = findtext(xml_doc, "ExtensionsConfig") - if extensions_config_uri is None: + if GoalStateProperties.ExtensionsConfig_Certs not in goalstate_properties or extensions_config_uri is None: extensions_config = ExtensionsGoalStateFactory.create_empty(incarnation) else: xml_text = self._wire_client.fetch_config(extensions_config_uri, self._wire_client.get_header()) extensions_config = ExtensionsGoalStateFactory.create_from_extensions_config(incarnation, xml_text, self._wire_client) self._history.save_extensions_config(extensions_config.get_redacted_text()) - hosting_env_uri = findtext(xml_doc, "HostingEnvironmentConfig") - xml_text = self._wire_client.fetch_config(hosting_env_uri, self._wire_client.get_header()) - hosting_env = HostingEnv(xml_text) - self._history.save_hosting_env(xml_text) - - shared_conf_uri = findtext(xml_doc, "SharedConfig") - xml_text = self._wire_client.fetch_config(shared_conf_uri, self._wire_client.get_header()) - shared_config = SharedConfig(xml_text) - self._history.save_shared_conf(xml_text) - # SharedConfig.xml is used by other components (Azsec and Singularity/HPC Infiniband), so save it to the agent's root directory as well - shared_config_file = os.path.join(conf.get_lib_dir(), SHARED_CONF_FILE_NAME) - try: - fileutil.write_file(shared_config_file, xml_text) - except Exception as e: - logger.warn("Failed to save {0}: {1}".format(shared_config, e)) + hosting_env = None + if GoalStateProperties.HostingEnv in goalstate_properties: + hosting_env_uri = findtext(xml_doc, "HostingEnvironmentConfig") + xml_text = self._wire_client.fetch_config(hosting_env_uri, self._wire_client.get_header()) + hosting_env = HostingEnv(xml_text) + self._history.save_hosting_env(xml_text) + + shared_config = None + if GoalStateProperties.SharedConfig in goalstate_properties: + shared_conf_uri = findtext(xml_doc, "SharedConfig") + xml_text = self._wire_client.fetch_config(shared_conf_uri, self._wire_client.get_header()) + shared_config = SharedConfig(xml_text) + self._history.save_shared_conf(xml_text) + # SharedConfig.xml is used by other components (Azsec and Singularity/HPC Infiniband), so save it to the agent's root directory as well + shared_config_file = os.path.join(conf.get_lib_dir(), SHARED_CONF_FILE_NAME) + try: + fileutil.write_file(shared_config_file, xml_text) + except Exception as e: + logger.warn("Failed to save {0}: {1}".format(shared_config, e)) certs = EmptyCertificates() certs_uri = findtext(xml_doc, "Certificates") - if certs_uri is not None: + if GoalStateProperties.ExtensionsConfig_Certs in goalstate_properties and certs_uri is not None: xml_text = self._wire_client.fetch_config(certs_uri, self._wire_client.get_header_for_cert()) certs = Certificates(xml_text, self.logger) # Log and save the certificates summary (i.e. the thumbprint but not the certificate itself) to the goal state history @@ -403,11 +423,12 @@ def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc): self._history.save_certificates(json.dumps(certs.summary)) remote_access = None - remote_access_uri = findtext(container, "RemoteAccessInfo") - if remote_access_uri is not None: - xml_text = self._wire_client.fetch_config(remote_access_uri, self._wire_client.get_header_for_cert()) - remote_access = RemoteAccess(xml_text) - self._history.save_remote_access(xml_text) + if GoalStateProperties.RemoteAccessInfo in goalstate_properties: + remote_access_uri = findtext(container, "RemoteAccessInfo") + if remote_access_uri is not None: + xml_text = self._wire_client.fetch_config(remote_access_uri, self._wire_client.get_header_for_cert()) + remote_access = RemoteAccess(xml_text) + self._history.save_remote_access(xml_text) self._incarnation = incarnation self._role_instance_id = role_instance_id From 908985ee628d46fda899c715e44a8228b8cef29b Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Wed, 7 Dec 2022 18:50:22 -0800 Subject: [PATCH 04/26] Update protocol to not process extensions in goal state update --- azurelinuxagent/common/protocol/wire.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/azurelinuxagent/common/protocol/wire.py b/azurelinuxagent/common/protocol/wire.py index d5aeda71c7..be813e9022 100644 --- a/azurelinuxagent/common/protocol/wire.py +++ b/azurelinuxagent/common/protocol/wire.py @@ -37,7 +37,8 @@ from azurelinuxagent.common.exception import ProtocolNotFoundError, \ ResourceGoneError, ExtensionDownloadError, InvalidContainerError, ProtocolError, HttpError, ExtensionErrorCodes from azurelinuxagent.common.future import httpclient, bytebuffer, ustr -from azurelinuxagent.common.protocol.goal_state import GoalState, TRANSPORT_CERT_FILE_NAME, TRANSPORT_PRV_FILE_NAME +from azurelinuxagent.common.protocol.goal_state import GoalState, TRANSPORT_CERT_FILE_NAME, TRANSPORT_PRV_FILE_NAME, \ + GoalStateProperties from azurelinuxagent.common.protocol.hostplugin import HostPluginProtocol from azurelinuxagent.common.protocol.restapi import DataContract, ProvisionStatus, VMInfo, VMStatus from azurelinuxagent.common.telemetryevent import GuestAgentExtensionEventsSchema @@ -84,7 +85,7 @@ def detect(self): # Initialize the goal state, including all the inner properties logger.info('Initializing goal state during protocol detection') - self.client.update_goal_state(force_update=True) + self.client.update_goal_state(include=[GoalStateProperties.RoleConfig, GoalStateProperties.HostingEnv], force_update=True) def update_goal_state(self, silent=False): self.client.update_goal_state(silent=silent) @@ -778,7 +779,7 @@ def update_host_plugin(self, container_id, role_config_name): self._host_plugin.update_container_id(container_id) self._host_plugin.update_role_config_name(role_config_name) - def update_goal_state(self, force_update=False, silent=False): + def update_goal_state(self, goalstate_properties=GoalStateProperties, force_update=False, silent=False): """ Updates the goal state if the incarnation or etag changed or if 'force_update' is True """ @@ -787,9 +788,9 @@ def update_goal_state(self, force_update=False, silent=False): logger.info("Forcing an update of the goal state.") if self._goal_state is None or force_update: - self._goal_state = GoalState(self, silent=silent) + self._goal_state = GoalState(self, goalstate_properties=goalstate_properties, silent=silent) else: - self._goal_state.update(silent=silent) + self._goal_state.update(goalstate_properties=goalstate_properties, silent=silent) except ProtocolError: raise From 8fc6471a07b0f4875cb770208548b119c13073c0 Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Wed, 7 Dec 2022 18:51:10 -0800 Subject: [PATCH 05/26] Update logcollector to not process extensions when updating goal state --- azurelinuxagent/common/logcollector.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/azurelinuxagent/common/logcollector.py b/azurelinuxagent/common/logcollector.py index b0da848fc5..59b72fbb94 100644 --- a/azurelinuxagent/common/logcollector.py +++ b/azurelinuxagent/common/logcollector.py @@ -34,6 +34,7 @@ # Please note: be careful when adding agent dependencies in this module. # This module uses its own logger and logs to its own file, not to the agent log. +from azurelinuxagent.common.protocol.goal_state import GoalStateProperties from azurelinuxagent.common.protocol.util import get_protocol_util _EXTENSION_LOG_DIR = get_ext_log_dir() @@ -117,8 +118,10 @@ def _set_resource_usage_cgroups(cpu_cgroup_path, memory_cgroup_path): @staticmethod def _initialize_telemetry(): - protocol = get_protocol_util().get_protocol() - protocol.client.update_goal_state(force_update=True) + protocol = get_protocol_util().get_protocol() # fetches full goal state underneath + protocol.client.update_goal_state( + goalstate_properties=[GoalStateProperties.RoleConfig, GoalStateProperties.HostingEnv], + force_update=True) # Initialize the common parameters for telemetry events initialize_event_logger_vminfo_common_parameters(protocol) From 3d370d0cb41bf906806614ac7389bf2df000b567 Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Wed, 7 Dec 2022 18:55:07 -0800 Subject: [PATCH 06/26] Remove comments --- azurelinuxagent/common/logcollector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurelinuxagent/common/logcollector.py b/azurelinuxagent/common/logcollector.py index 59b72fbb94..7f0b1dce98 100644 --- a/azurelinuxagent/common/logcollector.py +++ b/azurelinuxagent/common/logcollector.py @@ -118,7 +118,7 @@ def _set_resource_usage_cgroups(cpu_cgroup_path, memory_cgroup_path): @staticmethod def _initialize_telemetry(): - protocol = get_protocol_util().get_protocol() # fetches full goal state underneath + protocol = get_protocol_util().get_protocol() protocol.client.update_goal_state( goalstate_properties=[GoalStateProperties.RoleConfig, GoalStateProperties.HostingEnv], force_update=True) From d5bb0163fe948dc556521fca6b1b51ff45037824 Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Thu, 8 Dec 2022 14:19:02 -0800 Subject: [PATCH 07/26] Remove import enum --- azurelinuxagent/common/protocol/goal_state.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/azurelinuxagent/common/protocol/goal_state.py b/azurelinuxagent/common/protocol/goal_state.py index 8908876ee3..0e6f2813be 100644 --- a/azurelinuxagent/common/protocol/goal_state.py +++ b/azurelinuxagent/common/protocol/goal_state.py @@ -20,7 +20,6 @@ import re import time import json -from enum import Enum from azurelinuxagent.common import conf from azurelinuxagent.common import logger @@ -49,7 +48,7 @@ _GET_GOAL_STATE_MAX_ATTEMPTS = 6 -class GoalStateProperties(Enum): +class GoalStateProperties(object): """ Enum for defining the properties that we fetch in the goal state """ From 263395979735dec7ddbb1cd7efcc8a28ef7b4664 Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Thu, 8 Dec 2022 14:25:02 -0800 Subject: [PATCH 08/26] Update parameter name to goalstate_properties --- azurelinuxagent/common/protocol/wire.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurelinuxagent/common/protocol/wire.py b/azurelinuxagent/common/protocol/wire.py index be813e9022..4cbb09b0fa 100644 --- a/azurelinuxagent/common/protocol/wire.py +++ b/azurelinuxagent/common/protocol/wire.py @@ -85,7 +85,7 @@ def detect(self): # Initialize the goal state, including all the inner properties logger.info('Initializing goal state during protocol detection') - self.client.update_goal_state(include=[GoalStateProperties.RoleConfig, GoalStateProperties.HostingEnv], force_update=True) + self.client.update_goal_state(goalstate_properties=[GoalStateProperties.RoleConfig, GoalStateProperties.HostingEnv], force_update=True) def update_goal_state(self, silent=False): self.client.update_goal_state(silent=silent) From b8d98a57a810fe0f5a6c2a7fce79b335ccb12a67 Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Thu, 8 Dec 2022 15:29:11 -0800 Subject: [PATCH 09/26] Add default value for goalstate_properties --- azurelinuxagent/common/protocol/goal_state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurelinuxagent/common/protocol/goal_state.py b/azurelinuxagent/common/protocol/goal_state.py index 0e6f2813be..78a1fed1de 100644 --- a/azurelinuxagent/common/protocol/goal_state.py +++ b/azurelinuxagent/common/protocol/goal_state.py @@ -171,7 +171,7 @@ def update_host_plugin_headers(wire_client): # Fetching the goal state updates the HostGAPlugin so simply trigger the request GoalState._fetch_goal_state(wire_client) - def update(self, goalstate_properties, silent=False): + def update(self, goalstate_properties=GoalStateProperties, silent=False): """ Updates the current GoalState instance fetching values from the WireServer/HostGAPlugin as needed """ From e5781297a414ef1f2bc672f6fed674bcbe1127cc Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Thu, 8 Dec 2022 18:05:16 -0800 Subject: [PATCH 10/26] Use integers and bitwise operations for goal state properties --- azurelinuxagent/common/logcollector.py | 2 +- azurelinuxagent/common/protocol/goal_state.py | 33 +++++++++++-------- azurelinuxagent/common/protocol/wire.py | 4 +-- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/azurelinuxagent/common/logcollector.py b/azurelinuxagent/common/logcollector.py index 7f0b1dce98..3799d7cd8d 100644 --- a/azurelinuxagent/common/logcollector.py +++ b/azurelinuxagent/common/logcollector.py @@ -120,7 +120,7 @@ def _set_resource_usage_cgroups(cpu_cgroup_path, memory_cgroup_path): def _initialize_telemetry(): protocol = get_protocol_util().get_protocol() protocol.client.update_goal_state( - goalstate_properties=[GoalStateProperties.RoleConfig, GoalStateProperties.HostingEnv], + goalstate_properties=GoalStateProperties.RoleConfig | GoalStateProperties.HostingEnv, force_update=True) # Initialize the common parameters for telemetry events initialize_event_logger_vminfo_common_parameters(protocol) diff --git a/azurelinuxagent/common/protocol/goal_state.py b/azurelinuxagent/common/protocol/goal_state.py index 78a1fed1de..8a865b0c0b 100644 --- a/azurelinuxagent/common/protocol/goal_state.py +++ b/azurelinuxagent/common/protocol/goal_state.py @@ -52,11 +52,16 @@ class GoalStateProperties(object): """ Enum for defining the properties that we fetch in the goal state """ - RoleConfig = "ConfigName" - HostingEnv = "HostingEnvironmentConfig" - SharedConfig = "SharedConfig" - ExtensionsConfig_Certs = "ExtensionsConfig_Certificates" - RemoteAccessInfo = "RemoteAccessInfo" + RoleConfig = 1 + HostingEnv = 2 + SharedConfig = 4 + ExtensionsConfig_Certs = 8 + RemoteAccessInfo = 16 + + @staticmethod + def default_properties(): + return GoalStateProperties.RoleConfig | GoalStateProperties.HostingEnv | GoalStateProperties.SharedConfig | \ + GoalStateProperties.ExtensionsConfig_Certs | GoalStateProperties.RemoteAccessInfo class GoalStateInconsistentError(ProtocolError): @@ -68,7 +73,7 @@ def __init__(self, msg, inner=None): class GoalState(object): - def __init__(self, wire_client, goalstate_properties=GoalStateProperties, silent=False): + def __init__(self, wire_client, goalstate_properties=GoalStateProperties.default_properties(), silent=False): """ Fetches the goal state using the given wire client. @@ -171,7 +176,7 @@ def update_host_plugin_headers(wire_client): # Fetching the goal state updates the HostGAPlugin so simply trigger the request GoalState._fetch_goal_state(wire_client) - def update(self, goalstate_properties=GoalStateProperties, silent=False): + def update(self, goalstate_properties=GoalStateProperties.default_properties(), silent=False): """ Updates the current GoalState instance fetching values from the WireServer/HostGAPlugin as needed """ @@ -354,7 +359,7 @@ def _fetch_vm_settings(wire_client, force_update=False): return vm_settings, vm_settings_updated - def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc, goalstate_properties=GoalStateProperties): + def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc, goalstate_properties=GoalStateProperties.default_properties()): """ Issues HTTP requests (to the WireServer) for each of the URIs in the goal state (ExtensionsConfig, Certificate, Remote Access users, etc) and populates the corresponding properties. @@ -370,7 +375,7 @@ def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc, goalstate_pro role_instance_id = None role_config_name = None container_id = None - if GoalStateProperties.RoleConfig in goalstate_properties: + if GoalStateProperties.RoleConfig & goalstate_properties: role_instance = find(xml_doc, "RoleInstance") role_instance_id = findtext(role_instance, "InstanceId") role_config = find(role_instance, "Configuration") @@ -379,7 +384,7 @@ def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc, goalstate_pro container_id = findtext(container, "ContainerId") extensions_config_uri = findtext(xml_doc, "ExtensionsConfig") - if GoalStateProperties.ExtensionsConfig_Certs not in goalstate_properties or extensions_config_uri is None: + if not (GoalStateProperties.ExtensionsConfig_Certs & goalstate_properties) or extensions_config_uri is None: extensions_config = ExtensionsGoalStateFactory.create_empty(incarnation) else: xml_text = self._wire_client.fetch_config(extensions_config_uri, self._wire_client.get_header()) @@ -387,14 +392,14 @@ def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc, goalstate_pro self._history.save_extensions_config(extensions_config.get_redacted_text()) hosting_env = None - if GoalStateProperties.HostingEnv in goalstate_properties: + if GoalStateProperties.HostingEnv & goalstate_properties: hosting_env_uri = findtext(xml_doc, "HostingEnvironmentConfig") xml_text = self._wire_client.fetch_config(hosting_env_uri, self._wire_client.get_header()) hosting_env = HostingEnv(xml_text) self._history.save_hosting_env(xml_text) shared_config = None - if GoalStateProperties.SharedConfig in goalstate_properties: + if GoalStateProperties.SharedConfig & goalstate_properties: shared_conf_uri = findtext(xml_doc, "SharedConfig") xml_text = self._wire_client.fetch_config(shared_conf_uri, self._wire_client.get_header()) shared_config = SharedConfig(xml_text) @@ -408,7 +413,7 @@ def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc, goalstate_pro certs = EmptyCertificates() certs_uri = findtext(xml_doc, "Certificates") - if GoalStateProperties.ExtensionsConfig_Certs in goalstate_properties and certs_uri is not None: + if (GoalStateProperties.ExtensionsConfig_Certs & goalstate_properties) and certs_uri is not None: xml_text = self._wire_client.fetch_config(certs_uri, self._wire_client.get_header_for_cert()) certs = Certificates(xml_text, self.logger) # Log and save the certificates summary (i.e. the thumbprint but not the certificate itself) to the goal state history @@ -422,7 +427,7 @@ def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc, goalstate_pro self._history.save_certificates(json.dumps(certs.summary)) remote_access = None - if GoalStateProperties.RemoteAccessInfo in goalstate_properties: + if GoalStateProperties.RemoteAccessInfo & goalstate_properties: remote_access_uri = findtext(container, "RemoteAccessInfo") if remote_access_uri is not None: xml_text = self._wire_client.fetch_config(remote_access_uri, self._wire_client.get_header_for_cert()) diff --git a/azurelinuxagent/common/protocol/wire.py b/azurelinuxagent/common/protocol/wire.py index 4cbb09b0fa..a02d504071 100644 --- a/azurelinuxagent/common/protocol/wire.py +++ b/azurelinuxagent/common/protocol/wire.py @@ -85,7 +85,7 @@ def detect(self): # Initialize the goal state, including all the inner properties logger.info('Initializing goal state during protocol detection') - self.client.update_goal_state(goalstate_properties=[GoalStateProperties.RoleConfig, GoalStateProperties.HostingEnv], force_update=True) + self.client.update_goal_state(goalstate_properties=GoalStateProperties.RoleConfig | GoalStateProperties.HostingEnv, force_update=True) def update_goal_state(self, silent=False): self.client.update_goal_state(silent=silent) @@ -779,7 +779,7 @@ def update_host_plugin(self, container_id, role_config_name): self._host_plugin.update_container_id(container_id) self._host_plugin.update_role_config_name(role_config_name) - def update_goal_state(self, goalstate_properties=GoalStateProperties, force_update=False, silent=False): + def update_goal_state(self, goalstate_properties=GoalStateProperties.default_properties(), force_update=False, silent=False): """ Updates the goal state if the incarnation or etag changed or if 'force_update' is True """ From c642900a3c46bb28c75107c25503fe5e380ea92b Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Mon, 12 Dec 2022 13:51:14 -0800 Subject: [PATCH 11/26] Initialize protocol for logcollector with only necessary goal state properties --- azurelinuxagent/common/logcollector.py | 5 +++-- azurelinuxagent/common/protocol/util.py | 9 +++++---- azurelinuxagent/common/protocol/wire.py | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/azurelinuxagent/common/logcollector.py b/azurelinuxagent/common/logcollector.py index 3799d7cd8d..f880c951e8 100644 --- a/azurelinuxagent/common/logcollector.py +++ b/azurelinuxagent/common/logcollector.py @@ -118,9 +118,10 @@ def _set_resource_usage_cgroups(cpu_cgroup_path, memory_cgroup_path): @staticmethod def _initialize_telemetry(): - protocol = get_protocol_util().get_protocol() + goalstate_properties = GoalStateProperties.RoleConfig | GoalStateProperties.HostingEnv + protocol = get_protocol_util().get_protocol(goalstate_properties=goalstate_properties) protocol.client.update_goal_state( - goalstate_properties=GoalStateProperties.RoleConfig | GoalStateProperties.HostingEnv, + goalstate_properties=goalstate_properties, force_update=True) # Initialize the common parameters for telemetry events initialize_event_logger_vminfo_common_parameters(protocol) diff --git a/azurelinuxagent/common/protocol/util.py b/azurelinuxagent/common/protocol/util.py index 92b691e92b..14d3a8d324 100644 --- a/azurelinuxagent/common/protocol/util.py +++ b/azurelinuxagent/common/protocol/util.py @@ -26,6 +26,7 @@ import azurelinuxagent.common.conf as conf import azurelinuxagent.common.logger as logger import azurelinuxagent.common.utils.fileutil as fileutil +from azurelinuxagent.common.protocol.goal_state import GoalStateProperties from azurelinuxagent.common.singletonperthread import SingletonPerThread from azurelinuxagent.common.exception import ProtocolError, OSUtilError, \ @@ -188,7 +189,7 @@ def _clear_wireserver_endpoint(self): return logger.error("Failed to clear wiresever endpoint: {0}", e) - def _detect_protocol(self): + def _detect_protocol(self, goalstate_properties=GoalStateProperties.default_properties()): """ Probe protocol endpoints in turn. """ @@ -217,7 +218,7 @@ def _detect_protocol(self): try: protocol = WireProtocol(endpoint) - protocol.detect() + protocol.detect(goalstate_properties=goalstate_properties) self._set_wireserver_endpoint(endpoint) return protocol @@ -268,7 +269,7 @@ def clear_protocol(self): finally: self._lock.release() - def get_protocol(self): + def get_protocol(self, goalstate_properties=GoalStateProperties.default_properties()): """ Detect protocol by endpoint. :returns: protocol instance @@ -296,7 +297,7 @@ def get_protocol(self): logger.info("Detect protocol endpoint") - protocol = self._detect_protocol() + protocol = self._detect_protocol(goalstate_properties=goalstate_properties) IOErrorCounter.set_protocol_endpoint(endpoint=protocol.get_endpoint()) self._save_protocol(WIRE_PROTOCOL_NAME) diff --git a/azurelinuxagent/common/protocol/wire.py b/azurelinuxagent/common/protocol/wire.py index a02d504071..b3ddce43ed 100644 --- a/azurelinuxagent/common/protocol/wire.py +++ b/azurelinuxagent/common/protocol/wire.py @@ -73,7 +73,7 @@ def __init__(self, endpoint): raise ProtocolError("WireProtocol endpoint is None") self.client = WireClient(endpoint) - def detect(self): + def detect(self, goalstate_properties=GoalStateProperties.default_properties()): self.client.check_wire_protocol_version() trans_prv_file = os.path.join(conf.get_lib_dir(), @@ -85,7 +85,7 @@ def detect(self): # Initialize the goal state, including all the inner properties logger.info('Initializing goal state during protocol detection') - self.client.update_goal_state(goalstate_properties=GoalStateProperties.RoleConfig | GoalStateProperties.HostingEnv, force_update=True) + self.client.update_goal_state(goalstate_properties=goalstate_properties, force_update=True) def update_goal_state(self, silent=False): self.client.update_goal_state(silent=silent) From 041dee371312841186e9d93b86796f9ec7b58f5f Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Wed, 14 Dec 2022 18:13:04 -0800 Subject: [PATCH 12/26] Separate update into reset and made goal state properties a private member --- azurelinuxagent/common/logcollector.py | 7 +- azurelinuxagent/common/protocol/goal_state.py | 85 ++++++++++++------- azurelinuxagent/common/protocol/util.py | 8 +- azurelinuxagent/common/protocol/wire.py | 32 ++++--- azurelinuxagent/daemon/main.py | 5 +- 5 files changed, 84 insertions(+), 53 deletions(-) diff --git a/azurelinuxagent/common/logcollector.py b/azurelinuxagent/common/logcollector.py index f880c951e8..b4a1bb8795 100644 --- a/azurelinuxagent/common/logcollector.py +++ b/azurelinuxagent/common/logcollector.py @@ -118,11 +118,8 @@ def _set_resource_usage_cgroups(cpu_cgroup_path, memory_cgroup_path): @staticmethod def _initialize_telemetry(): - goalstate_properties = GoalStateProperties.RoleConfig | GoalStateProperties.HostingEnv - protocol = get_protocol_util().get_protocol(goalstate_properties=goalstate_properties) - protocol.client.update_goal_state( - goalstate_properties=goalstate_properties, - force_update=True) + protocol = get_protocol_util().get_protocol() + protocol.client.reset_goal_state(goalstate_properties=GoalStateProperties.RoleConfig | GoalStateProperties.HostingEnv) # Initialize the common parameters for telemetry events initialize_event_logger_vminfo_common_parameters(protocol) diff --git a/azurelinuxagent/common/protocol/goal_state.py b/azurelinuxagent/common/protocol/goal_state.py index 8a865b0c0b..8489af64a5 100644 --- a/azurelinuxagent/common/protocol/goal_state.py +++ b/azurelinuxagent/common/protocol/goal_state.py @@ -52,16 +52,12 @@ class GoalStateProperties(object): """ Enum for defining the properties that we fetch in the goal state """ - RoleConfig = 1 - HostingEnv = 2 - SharedConfig = 4 - ExtensionsConfig_Certs = 8 - RemoteAccessInfo = 16 - - @staticmethod - def default_properties(): - return GoalStateProperties.RoleConfig | GoalStateProperties.HostingEnv | GoalStateProperties.SharedConfig | \ - GoalStateProperties.ExtensionsConfig_Certs | GoalStateProperties.RemoteAccessInfo + RoleConfig = 0x1 + HostingEnv = 0x2 + SharedConfig = 0x4 + ExtensionsConfig_Certs = 0x8 + RemoteAccessInfo = 0x10 + All = RoleConfig | HostingEnv | SharedConfig | ExtensionsConfig_Certs | RemoteAccessInfo class GoalStateInconsistentError(ProtocolError): @@ -73,7 +69,7 @@ def __init__(self, msg, inner=None): class GoalState(object): - def __init__(self, wire_client, goalstate_properties=GoalStateProperties.default_properties(), silent=False): + def __init__(self, wire_client, goal_state_properties=GoalStateProperties.All, silent=False): """ Fetches the goal state using the given wire client. @@ -88,6 +84,7 @@ def __init__(self, wire_client, goalstate_properties=GoalStateProperties.default self._wire_client = wire_client self._history = None self._extensions_goal_state = None # populated from vmSettings or extensionsConfig + self._goal_state_properties = goal_state_properties self.logger = logger.Logger(logger.DEFAULT_LOGGER) self.logger.silent = silent @@ -101,7 +98,7 @@ def __init__(self, wire_client, goalstate_properties=GoalStateProperties.default self._certs = EmptyCertificates() self._remote_access = None - self.update(goalstate_properties=goalstate_properties, silent=silent) + self.update(silent=silent) except ProtocolError: raise @@ -115,35 +112,59 @@ def incarnation(self): @property def container_id(self): - return self._container_id + if not self._goal_state_properties & GoalStateProperties.RoleConfig: + raise ProtocolError("RoleConfig is not in goal state properties") + else: + return self._container_id @property def role_instance_id(self): - return self._role_instance_id + if not self._goal_state_properties & GoalStateProperties.RoleConfig: + raise ProtocolError("RoleConfig is not in goal state properties") + else: + return self._role_instance_id @property def role_config_name(self): - return self._role_config_name + if not self._goal_state_properties & GoalStateProperties.RoleConfig: + raise ProtocolError("RoleConfig is not in goal state properties") + else: + return self._role_config_name @property def extensions_goal_state(self): - return self._extensions_goal_state + if not self._goal_state_properties & GoalStateProperties.ExtensionsConfig_Certs: + raise ProtocolError("ExtensionsConfig is not in goal state properties") + else: + return self._extensions_goal_state @property def certs(self): - return self._certs + if not self._goal_state_properties & GoalStateProperties.ExtensionsConfig_Certs: + raise ProtocolError("Certificates is not in goal state properties") + else: + return self._certs @property def hosting_env(self): - return self._hosting_env + if not self._goal_state_properties & GoalStateProperties.HostingEnv: + raise ProtocolError("HostingEnvironment is not in goal state properties") + else: + return self._hosting_env @property def shared_conf(self): - return self._shared_conf + if not self._goal_state_properties & GoalStateProperties.SharedConfig: + raise ProtocolError("SharedConfig is not in goal state properties") + else: + return self._shared_conf @property def remote_access(self): - return self._remote_access + if not self._goal_state_properties & GoalStateProperties.RemoteAccessInfo: + raise ProtocolError("RemoteAccessInfo is not in goal state properties") + else: + return self._remote_access def fetch_agent_manifest(self, family_name, uris): """ @@ -176,20 +197,20 @@ def update_host_plugin_headers(wire_client): # Fetching the goal state updates the HostGAPlugin so simply trigger the request GoalState._fetch_goal_state(wire_client) - def update(self, goalstate_properties=GoalStateProperties.default_properties(), silent=False): + def update(self, silent=False): """ Updates the current GoalState instance fetching values from the WireServer/HostGAPlugin as needed """ self.logger.silent = silent try: - self._update(goalstate_properties=goalstate_properties, force_update=False) + self._update(force_update=False) except GoalStateInconsistentError as e: self.logger.warn("Detected an inconsistency in the goal state: {0}", ustr(e)) - self._update(goalstate_properties=goalstate_properties, force_update=True) + self._update(force_update=True) self.logger.info("The goal state is consistent") - def _update(self, goalstate_properties, force_update): + def _update(self, force_update): # # Fetch the goal state from both the HGAP and the WireServer # @@ -242,7 +263,7 @@ def _update(self, goalstate_properties, force_update): # extensions_config = None if goal_state_updated: - extensions_config = self._fetch_full_wire_server_goal_state(incarnation, xml_doc, goalstate_properties) + extensions_config = self._fetch_full_wire_server_goal_state(incarnation, xml_doc) # # Lastly, decide whether to use the vmSettings or extensionsConfig for the extensions goal state @@ -359,7 +380,7 @@ def _fetch_vm_settings(wire_client, force_update=False): return vm_settings, vm_settings_updated - def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc, goalstate_properties=GoalStateProperties.default_properties()): + def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc): """ Issues HTTP requests (to the WireServer) for each of the URIs in the goal state (ExtensionsConfig, Certificate, Remote Access users, etc) and populates the corresponding properties. @@ -375,7 +396,7 @@ def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc, goalstate_pro role_instance_id = None role_config_name = None container_id = None - if GoalStateProperties.RoleConfig & goalstate_properties: + if GoalStateProperties.RoleConfig & self._goal_state_properties: role_instance = find(xml_doc, "RoleInstance") role_instance_id = findtext(role_instance, "InstanceId") role_config = find(role_instance, "Configuration") @@ -384,7 +405,7 @@ def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc, goalstate_pro container_id = findtext(container, "ContainerId") extensions_config_uri = findtext(xml_doc, "ExtensionsConfig") - if not (GoalStateProperties.ExtensionsConfig_Certs & goalstate_properties) or extensions_config_uri is None: + if not (GoalStateProperties.ExtensionsConfig_Certs & self._goal_state_properties) or extensions_config_uri is None: extensions_config = ExtensionsGoalStateFactory.create_empty(incarnation) else: xml_text = self._wire_client.fetch_config(extensions_config_uri, self._wire_client.get_header()) @@ -392,14 +413,14 @@ def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc, goalstate_pro self._history.save_extensions_config(extensions_config.get_redacted_text()) hosting_env = None - if GoalStateProperties.HostingEnv & goalstate_properties: + if GoalStateProperties.HostingEnv & self._goal_state_properties: hosting_env_uri = findtext(xml_doc, "HostingEnvironmentConfig") xml_text = self._wire_client.fetch_config(hosting_env_uri, self._wire_client.get_header()) hosting_env = HostingEnv(xml_text) self._history.save_hosting_env(xml_text) shared_config = None - if GoalStateProperties.SharedConfig & goalstate_properties: + if GoalStateProperties.SharedConfig & self._goal_state_properties: shared_conf_uri = findtext(xml_doc, "SharedConfig") xml_text = self._wire_client.fetch_config(shared_conf_uri, self._wire_client.get_header()) shared_config = SharedConfig(xml_text) @@ -413,7 +434,7 @@ def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc, goalstate_pro certs = EmptyCertificates() certs_uri = findtext(xml_doc, "Certificates") - if (GoalStateProperties.ExtensionsConfig_Certs & goalstate_properties) and certs_uri is not None: + if (GoalStateProperties.ExtensionsConfig_Certs & self._goal_state_properties) and certs_uri is not None: xml_text = self._wire_client.fetch_config(certs_uri, self._wire_client.get_header_for_cert()) certs = Certificates(xml_text, self.logger) # Log and save the certificates summary (i.e. the thumbprint but not the certificate itself) to the goal state history @@ -427,7 +448,7 @@ def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc, goalstate_pro self._history.save_certificates(json.dumps(certs.summary)) remote_access = None - if GoalStateProperties.RemoteAccessInfo & goalstate_properties: + if GoalStateProperties.RemoteAccessInfo & self._goal_state_properties: remote_access_uri = findtext(container, "RemoteAccessInfo") if remote_access_uri is not None: xml_text = self._wire_client.fetch_config(remote_access_uri, self._wire_client.get_header_for_cert()) diff --git a/azurelinuxagent/common/protocol/util.py b/azurelinuxagent/common/protocol/util.py index 14d3a8d324..302230c36e 100644 --- a/azurelinuxagent/common/protocol/util.py +++ b/azurelinuxagent/common/protocol/util.py @@ -189,7 +189,7 @@ def _clear_wireserver_endpoint(self): return logger.error("Failed to clear wiresever endpoint: {0}", e) - def _detect_protocol(self, goalstate_properties=GoalStateProperties.default_properties()): + def _detect_protocol(self, goalstate_properties=GoalStateProperties.All): """ Probe protocol endpoints in turn. """ @@ -218,7 +218,7 @@ def _detect_protocol(self, goalstate_properties=GoalStateProperties.default_prop try: protocol = WireProtocol(endpoint) - protocol.detect(goalstate_properties=goalstate_properties) + protocol.detect() self._set_wireserver_endpoint(endpoint) return protocol @@ -269,7 +269,7 @@ def clear_protocol(self): finally: self._lock.release() - def get_protocol(self, goalstate_properties=GoalStateProperties.default_properties()): + def get_protocol(self): """ Detect protocol by endpoint. :returns: protocol instance @@ -297,7 +297,7 @@ def get_protocol(self, goalstate_properties=GoalStateProperties.default_properti logger.info("Detect protocol endpoint") - protocol = self._detect_protocol(goalstate_properties=goalstate_properties) + protocol = self._detect_protocol() IOErrorCounter.set_protocol_endpoint(endpoint=protocol.get_endpoint()) self._save_protocol(WIRE_PROTOCOL_NAME) diff --git a/azurelinuxagent/common/protocol/wire.py b/azurelinuxagent/common/protocol/wire.py index b3ddce43ed..5ea79bc215 100644 --- a/azurelinuxagent/common/protocol/wire.py +++ b/azurelinuxagent/common/protocol/wire.py @@ -73,7 +73,7 @@ def __init__(self, endpoint): raise ProtocolError("WireProtocol endpoint is None") self.client = WireClient(endpoint) - def detect(self, goalstate_properties=GoalStateProperties.default_properties()): + def detect(self): self.client.check_wire_protocol_version() trans_prv_file = os.path.join(conf.get_lib_dir(), @@ -85,7 +85,7 @@ def detect(self, goalstate_properties=GoalStateProperties.default_properties()): # Initialize the goal state, including all the inner properties logger.info('Initializing goal state during protocol detection') - self.client.update_goal_state(goalstate_properties=goalstate_properties, force_update=True) + self.client.reset_goal_state() def update_goal_state(self, silent=False): self.client.update_goal_state(silent=silent) @@ -779,18 +779,30 @@ def update_host_plugin(self, container_id, role_config_name): self._host_plugin.update_container_id(container_id) self._host_plugin.update_role_config_name(role_config_name) - def update_goal_state(self, goalstate_properties=GoalStateProperties.default_properties(), force_update=False, silent=False): + def update_goal_state(self, silent=False): """ - Updates the goal state if the incarnation or etag changed or if 'force_update' is True + Updates the goal state if the incarnation or etag changed """ try: - if force_update and not silent: + if not silent: logger.info("Forcing an update of the goal state.") - if self._goal_state is None or force_update: - self._goal_state = GoalState(self, goalstate_properties=goalstate_properties, silent=silent) - else: - self._goal_state.update(goalstate_properties=goalstate_properties, silent=silent) + self._goal_state.update(silent=silent) + + except ProtocolError: + raise + except Exception as exception: + raise ProtocolError("Error fetching goal state: {0}".format(ustr(exception))) + + def reset_goal_state(self, goal_state_properties=GoalStateProperties.All, silent=False): + """ + Resets the goal state + """ + try: + if not silent: + logger.info("Forcing an update of the goal state.") + + self._goal_state = GoalState(self, goal_state_properties=goal_state_properties, silent=silent) except ProtocolError: raise @@ -926,7 +938,7 @@ def upload_status_blob(self): if extensions_goal_state.status_upload_blob is None: # the status upload blob is in ExtensionsConfig so force a full goal state refresh - self.update_goal_state(force_update=True, silent=True) + self.reset_goal_state(silent=True) extensions_goal_state = self.get_goal_state().extensions_goal_state if extensions_goal_state.status_upload_blob is None: diff --git a/azurelinuxagent/daemon/main.py b/azurelinuxagent/daemon/main.py index c608768a67..1eb58ec99b 100644 --- a/azurelinuxagent/daemon/main.py +++ b/azurelinuxagent/daemon/main.py @@ -28,6 +28,7 @@ from azurelinuxagent.common.event import add_event, WALAEventOperation, initialize_event_logger_vminfo_common_parameters from azurelinuxagent.common.future import ustr from azurelinuxagent.common.osutil import get_osutil +from azurelinuxagent.common.protocol.goal_state import GoalState, GoalStateProperties from azurelinuxagent.common.protocol.util import get_protocol_util from azurelinuxagent.common.rdma import setup_rdma_device from azurelinuxagent.common.utils import textutil @@ -160,9 +161,9 @@ def daemon(self, child_args=None): # current values. protocol = self.protocol_util.get_protocol() - protocol.client.update_goal_state(force_update=True) + goal_state = GoalState(protocol, goal_state_properties=GoalStateProperties.SharedConfig) - setup_rdma_device(nd_version, protocol.client.get_shared_conf()) + setup_rdma_device(nd_version, goal_state.shared_conf) except Exception as e: logger.error("Error setting up rdma device: %s" % e) else: From cbfb6ad38ee7619b8398e5736d92acb15e651105 Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Wed, 14 Dec 2022 18:17:53 -0800 Subject: [PATCH 13/26] Remove goal_state_properties param from _detect_protocol --- azurelinuxagent/common/protocol/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurelinuxagent/common/protocol/util.py b/azurelinuxagent/common/protocol/util.py index 302230c36e..80fc369f66 100644 --- a/azurelinuxagent/common/protocol/util.py +++ b/azurelinuxagent/common/protocol/util.py @@ -189,7 +189,7 @@ def _clear_wireserver_endpoint(self): return logger.error("Failed to clear wiresever endpoint: {0}", e) - def _detect_protocol(self, goalstate_properties=GoalStateProperties.All): + def _detect_protocol(self): """ Probe protocol endpoints in turn. """ From 05f4b79d2cbd39f721f988c963a65bf1d4286433 Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Wed, 14 Dec 2022 18:25:08 -0800 Subject: [PATCH 14/26] Update tests to remove force_update --- tests/ga/test_extension.py | 6 +++--- tests/protocol/test_wire.py | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/ga/test_extension.py b/tests/ga/test_extension.py index 5947e9e669..7c95d07a5d 100644 --- a/tests/ga/test_extension.py +++ b/tests/ga/test_extension.py @@ -3369,7 +3369,7 @@ def http_get_handler(url, *_, **kwargs): # Enabled on_hold property in artifact_blob mock_in_vm_artifacts_profile_response = MockHttpResponse(200, body='{ "onHold": true }'.encode('utf-8')) - protocol.client.update_goal_state(force_update=True) + protocol.client.reset_goal_state() with patch.object(conf, 'get_extensions_enabled', return_value=True): with patch.object(conf, "get_enable_overprovisioning", return_value=True): @@ -3377,7 +3377,7 @@ def http_get_handler(url, *_, **kwargs): # Disabled on_hold property in artifact_blob mock_in_vm_artifacts_profile_response = MockHttpResponse(200, body='{ "onHold": false }'.encode('utf-8')) - protocol.client.update_goal_state(force_update=True) + protocol.client.reset_goal_state() with patch.object(conf, 'get_extensions_enabled', return_value=True): with patch.object(conf, "get_enable_overprovisioning", return_value=True): @@ -3410,7 +3410,7 @@ def http_get_handler(url, *_, **kwargs): return None protocol.set_http_handlers(http_get_handler=http_get_handler) - protocol.client.update_goal_state(force_update=True) + protocol.client.reset_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() diff --git a/tests/protocol/test_wire.py b/tests/protocol/test_wire.py index 7c121f4481..9c9a4ad0cb 100644 --- a/tests/protocol/test_wire.py +++ b/tests/protocol/test_wire.py @@ -271,23 +271,23 @@ def http_get_handler(url, *_, **kwargs): protocol.set_http_handlers(http_get_handler=http_get_handler) mock_response = MockHttpResponse(200, body=None) - protocol.client.update_goal_state(force_update=True) + protocol.client.reset_goal_state() extensions_on_hold = protocol.get_goal_state().extensions_goal_state.on_hold self.assertFalse(extensions_on_hold, "Extensions should not be on hold when the in-vm artifacts profile response body is None") mock_response = MockHttpResponse(200, ' '.encode('utf-8')) - protocol.client.update_goal_state(force_update=True) + protocol.client.reset_goal_state() extensions_on_hold = protocol.get_goal_state().extensions_goal_state.on_hold self.assertFalse(extensions_on_hold, "Extensions should not be on hold when the in-vm artifacts profile response is an empty string") mock_response = MockHttpResponse(200, '{ }'.encode('utf-8')) - protocol.client.update_goal_state(force_update=True) + protocol.client.reset_goal_state() extensions_on_hold = protocol.get_goal_state().extensions_goal_state.on_hold self.assertFalse(extensions_on_hold, "Extensions should not be on hold when the in-vm artifacts profile response is an empty json object") with patch("azurelinuxagent.common.protocol.extensions_goal_state_from_extensions_config.add_event") as add_event: mock_response = MockHttpResponse(200, 'invalid json'.encode('utf-8')) - protocol.client.update_goal_state(force_update=True) + protocol.client.reset_goal_state() extensions_on_hold = protocol.get_goal_state().extensions_goal_state.on_hold self.assertFalse(extensions_on_hold, "Extensions should not be on hold when the in-vm artifacts profile response is not valid json") @@ -780,7 +780,7 @@ def http_get_handler(url, *_, **__): protocol.set_http_handlers(http_get_handler=http_get_handler) HostPluginProtocol.is_default_channel = False - protocol.client.update_goal_state(force_update=True) + protocol.client.reset_goal_state() urls = protocol.get_tracked_urls() self.assertEqual(len(urls), 1, "Unexpected HTTP requests: [{0}]".format(urls)) @@ -799,7 +799,7 @@ def http_get_handler(url, *_, **kwargs): HostPluginProtocol.is_default_channel = False try: - protocol.client.update_goal_state(force_update=True) + protocol.client.reset_goal_state() urls = protocol.get_tracked_urls() self.assertEqual(len(urls), 2, "Invalid number of requests: [{0}]".format(urls)) @@ -832,7 +832,7 @@ def http_get_handler(url, *_, **kwargs): protocol.set_http_handlers(http_get_handler=http_get_handler) - protocol.client.update_goal_state(force_update=True) + protocol.client.reset_goal_state() urls = protocol.get_tracked_urls() self.assertEqual(len(urls), 4, "Invalid number of requests: [{0}]".format(urls)) @@ -864,7 +864,7 @@ def http_get_handler(url, *_, **kwargs): protocol.set_http_handlers(http_get_handler=http_get_handler) - protocol.client.update_goal_state(force_update=True) + protocol.client.reset_goal_state() urls = protocol.get_tracked_urls() self.assertEqual(len(urls), 4, "Invalid number of requests: [{0}]".format(urls)) @@ -1036,7 +1036,7 @@ def test_it_should_update_the_goal_state_and_the_host_plugin_when_the_incarnatio ''' if forced: - protocol.client.update_goal_state(force_update=True) + protocol.client.reset_goal_state() else: protocol.client.update_goal_state() @@ -1090,7 +1090,7 @@ def test_forced_update_should_update_the_goal_state_and_the_host_plugin_when_the protocol.mock_wire_data.set_role_config_name(new_role_config_name) protocol.mock_wire_data.shared_config = new_shared_conf - protocol.client.update_goal_state(force_update=True) + protocol.client.reset_goal_state() self.assertEqual(protocol.client.get_goal_state().incarnation, incarnation) self.assertEqual(protocol.client.get_shared_conf().xml_text, new_shared_conf) From dc2fe693444f02a8177e0a0d693f5c1cf16ac89b Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Wed, 14 Dec 2022 18:30:05 -0800 Subject: [PATCH 15/26] Remove unused import --- azurelinuxagent/common/protocol/util.py | 1 - 1 file changed, 1 deletion(-) diff --git a/azurelinuxagent/common/protocol/util.py b/azurelinuxagent/common/protocol/util.py index 80fc369f66..92b691e92b 100644 --- a/azurelinuxagent/common/protocol/util.py +++ b/azurelinuxagent/common/protocol/util.py @@ -26,7 +26,6 @@ import azurelinuxagent.common.conf as conf import azurelinuxagent.common.logger as logger import azurelinuxagent.common.utils.fileutil as fileutil -from azurelinuxagent.common.protocol.goal_state import GoalStateProperties from azurelinuxagent.common.singletonperthread import SingletonPerThread from azurelinuxagent.common.exception import ProtocolError, OSUtilError, \ From a8c5a7ff69f7686cdedc659ef6560625819330a6 Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Wed, 14 Dec 2022 19:18:20 -0800 Subject: [PATCH 16/26] Remove update_goal_State from wire protocol --- azurelinuxagent/common/protocol/wire.py | 3 -- azurelinuxagent/ga/update.py | 2 +- tests/common/test_event.py | 4 +- tests/ga/test_extension.py | 66 ++++++++++++------------- tests/ga/test_monitor.py | 2 +- tests/ga/test_multi_config_extension.py | 20 ++++---- 6 files changed, 47 insertions(+), 50 deletions(-) diff --git a/azurelinuxagent/common/protocol/wire.py b/azurelinuxagent/common/protocol/wire.py index 5ea79bc215..81bf4157d8 100644 --- a/azurelinuxagent/common/protocol/wire.py +++ b/azurelinuxagent/common/protocol/wire.py @@ -87,9 +87,6 @@ def detect(self): logger.info('Initializing goal state during protocol detection') self.client.reset_goal_state() - def update_goal_state(self, silent=False): - self.client.update_goal_state(silent=silent) - def update_host_plugin_from_goal_state(self): self.client.update_host_plugin_from_goal_state() diff --git a/azurelinuxagent/ga/update.py b/azurelinuxagent/ga/update.py index 8d2c97df20..cd758b972a 100644 --- a/azurelinuxagent/ga/update.py +++ b/azurelinuxagent/ga/update.py @@ -485,7 +485,7 @@ def _try_update_goal_state(self, protocol): try: max_errors_to_log = 3 - protocol.update_goal_state(silent=self._update_goal_state_error_count >= max_errors_to_log) + protocol.client.update_goal_state(silent=self._update_goal_state_error_count >= max_errors_to_log) self._goal_state = protocol.get_goal_state() diff --git a/tests/common/test_event.py b/tests/common/test_event.py index 7191f3c30a..fad21155f2 100644 --- a/tests/common/test_event.py +++ b/tests/common/test_event.py @@ -161,12 +161,12 @@ def create_event_and_return_container_id(): # pylint: disable=inconsistent-retu self.assertEqual(contained_id, 'c6d5526c-5ac2-4200-b6e2-56f2b70c5ab2', "Incorrect container ID") protocol.mock_wire_data.set_container_id('AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE') - protocol.update_goal_state() + protocol.client.update_goal_state() contained_id = create_event_and_return_container_id() self.assertEqual(contained_id, 'AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE', "Incorrect container ID") protocol.mock_wire_data.set_container_id('11111111-2222-3333-4444-555555555555') - protocol.update_goal_state() + protocol.client.update_goal_state() contained_id = create_event_and_return_container_id() self.assertEqual(contained_id, '11111111-2222-3333-4444-555555555555', "Incorrect container ID") diff --git a/tests/ga/test_extension.py b/tests/ga/test_extension.py index 7c95d07a5d..2272a1907b 100644 --- a/tests/ga/test_extension.py +++ b/tests/ga/test_extension.py @@ -510,7 +510,7 @@ def _set_up_update_test_and_update_gs(self, patch_command, *args): test_data.set_incarnation(2) test_data.set_extensions_config_version("1.0.1") test_data.set_manifest_version('1.0.1') - protocol.update_goal_state() + protocol.client.update_goal_state() # Ensure the patched command fails patch_command.return_value = "exit 1" @@ -542,7 +542,7 @@ def test_ext_handler(self, *args): # Test goal state changed test_data.set_incarnation(2) test_data.set_extensions_config_sequence_number(1) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -555,7 +555,7 @@ def test_ext_handler(self, *args): test_data.set_incarnation(3) test_data.set_extensions_config_version("1.1.1") test_data.set_extensions_config_sequence_number(2) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -567,7 +567,7 @@ def test_ext_handler(self, *args): test_data.set_incarnation(4) test_data.set_extensions_config_version("1.2.0") test_data.set_extensions_config_sequence_number(3) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -578,7 +578,7 @@ def test_ext_handler(self, *args): # Test disable test_data.set_incarnation(5) test_data.set_extensions_config_state(ExtensionRequestedState.Disabled) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -588,7 +588,7 @@ def test_ext_handler(self, *args): # Test uninstall test_data.set_incarnation(6) test_data.set_extensions_config_state(ExtensionRequestedState.Uninstall) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -597,7 +597,7 @@ def test_ext_handler(self, *args): # Test uninstall again! test_data.set_incarnation(7) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -620,7 +620,7 @@ def _assert_handler_status_and_manifest_download_count(protocol, test_data, mani # Update Incarnation test_data.set_incarnation(2) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -720,7 +720,7 @@ def test_ext_handler_no_settings(self, *args): # Uninstall the Plugin and make sure Disable called test_data.set_incarnation(2) test_data.set_extensions_config_state(ExtensionRequestedState.Uninstall) - protocol.update_goal_state() + protocol.client.update_goal_state() with enable_invocations(test_ext) as invocation_record: exthandlers_handler.run() @@ -799,7 +799,7 @@ def test_ext_handler_sequencing(self, *args): dep_ext_level_4 = extension_emulator(name="OSTCExtensions.OtherExampleHandlerLinux") test_data.ext_conf = test_data.ext_conf.replace("dependencyLevel=\"2\"", "dependencyLevel=\"3\"") test_data.ext_conf = test_data.ext_conf.replace("dependencyLevel=\"1\"", "dependencyLevel=\"4\"") - protocol.update_goal_state() + protocol.client.update_goal_state() with enable_invocations(dep_ext_level_3, dep_ext_level_4) as invocation_record: exthandlers_handler.run() @@ -826,7 +826,7 @@ def test_ext_handler_sequencing(self, *args): # the last one disabled. test_data.set_incarnation(3) test_data.set_extensions_config_state(ExtensionRequestedState.Disabled) - protocol.update_goal_state() + protocol.client.update_goal_state() with enable_invocations(dep_ext_level_3, dep_ext_level_4) as invocation_record: exthandlers_handler.run() @@ -858,7 +858,7 @@ def test_ext_handler_sequencing(self, *args): dep_ext_level_6 = extension_emulator(name="OSTCExtensions.ExampleHandlerLinux") test_data.ext_conf = test_data.ext_conf.replace("dependencyLevel=\"3\"", "dependencyLevel=\"6\"") test_data.ext_conf = test_data.ext_conf.replace("dependencyLevel=\"4\"", "dependencyLevel=\"5\"") - protocol.update_goal_state() + protocol.client.update_goal_state() with enable_invocations(dep_ext_level_5, dep_ext_level_6) as invocation_record: exthandlers_handler.run() @@ -938,7 +938,7 @@ def mock_fail_extension_commands(args, **kwargs): _assert_event_reported_only_on_incarnation_change(expected_count=1) test_data.set_incarnation(2) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -949,7 +949,7 @@ def mock_fail_extension_commands(args, **kwargs): # Test it recovers on a new goal state if Handler succeeds test_data.set_incarnation(3) test_data.set_extensions_config_sequence_number(1) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -961,7 +961,7 @@ def mock_fail_extension_commands(args, **kwargs): # Update incarnation to confirm extension invocation order test_data.set_incarnation(4) - protocol.update_goal_state() + protocol.client.update_goal_state() dep_ext_level_2 = extension_emulator(name="OSTCExtensions.ExampleHandlerLinux") dep_ext_level_1 = extension_emulator(name="OSTCExtensions.OtherExampleHandlerLinux") @@ -1023,7 +1023,7 @@ def test_ext_handler_rollingupgrade(self, *args): # Test goal state changed test_data.set_incarnation(2) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -1034,7 +1034,7 @@ def test_ext_handler_rollingupgrade(self, *args): # Test minor version bump test_data.set_incarnation(3) test_data.set_extensions_config_version("1.1.0") - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -1045,7 +1045,7 @@ def test_ext_handler_rollingupgrade(self, *args): # Test hotfix version bump test_data.set_incarnation(4) test_data.set_extensions_config_version("1.1.1") - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -1056,7 +1056,7 @@ def test_ext_handler_rollingupgrade(self, *args): # Test disable test_data.set_incarnation(5) test_data.set_extensions_config_state(ExtensionRequestedState.Disabled) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -1066,7 +1066,7 @@ def test_ext_handler_rollingupgrade(self, *args): # Test uninstall test_data.set_incarnation(6) test_data.set_extensions_config_state(ExtensionRequestedState.Uninstall) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -1075,7 +1075,7 @@ def test_ext_handler_rollingupgrade(self, *args): # Test uninstall again! test_data.set_incarnation(7) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -1085,7 +1085,7 @@ def test_ext_handler_rollingupgrade(self, *args): # Test re-install test_data.set_incarnation(8) test_data.set_extensions_config_state(ExtensionRequestedState.Enabled) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -1096,7 +1096,7 @@ def test_ext_handler_rollingupgrade(self, *args): # Test version bump post-re-install test_data.set_incarnation(9) test_data.set_extensions_config_version("1.2.0") - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -1107,7 +1107,7 @@ def test_ext_handler_rollingupgrade(self, *args): # Test rollback test_data.set_incarnation(10) test_data.set_extensions_config_version("1.1.0") - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -1170,7 +1170,7 @@ def test_it_should_not_delete_extension_events_directory_on_extension_uninstall( # Uninstall extensions now test_data.set_extensions_config_state(ExtensionRequestedState.Uninstall) test_data.set_incarnation(2) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -1192,7 +1192,7 @@ def test_it_should_uninstall_unregistered_extensions_properly(self, *args): # Since the installed version is not in PIR anymore, we need to also remove it from manifest file test_data.manifest = test_data.manifest.replace("1.0.0", "9.9.9") test_data.set_incarnation(2) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -1666,7 +1666,7 @@ def test_extensions_deleted(self, *args): test_data.set_incarnation(2) test_data.set_extensions_config_version("1.0.1") test_data.set_manifest_version('1.0.1') - protocol.update_goal_state() + protocol.client.update_goal_state() # Ensure new extension can be enabled exthandlers_handler.run() @@ -1753,7 +1753,7 @@ def test_disable_failure_with_exception_handling(self, patch_get_disable_command # Next incarnation, disable extension test_data.set_incarnation(2) test_data.set_extensions_config_state(ExtensionRequestedState.Disabled) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -1784,7 +1784,7 @@ def test_uninstall_failure(self, patch_get_uninstall_command, *args): # Next incarnation, disable extension test_data.set_incarnation(2) test_data.set_extensions_config_state(ExtensionRequestedState.Uninstall) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -1841,7 +1841,7 @@ def mock_popen(*args, **kwargs): # If the incarnation number changes (there's a new goal state), ensure we go through the entire upgrade # process again. test_data.set_incarnation(3) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -1888,7 +1888,7 @@ def test_extension_upgrade_failure_when_prev_version_disable_fails_and_recovers_ # Force a new goal state incarnation, only then will we attempt the upgrade again test_data.set_incarnation(3) - protocol.update_goal_state() + protocol.client.update_goal_state() # Ensure disable won't fail by making launch_command a no-op with patch('azurelinuxagent.ga.exthandlers.ExtHandlerInstance.launch_command') as patch_launch_command: # pylint: disable=unused-variable @@ -2111,7 +2111,7 @@ def test_uninstall_rc_env_var_should_report_not_run_for_non_update_calls_to_exth # Initiating another run which shouldn't have any failed env variables in it if no failures # Updating Incarnation test_data.set_incarnation(3) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -3355,7 +3355,7 @@ def http_get_handler(url, *_, **kwargs): # Update GoalState protocol.mock_wire_data.set_incarnation(2) - protocol.update_goal_state() + protocol.client.update_goal_state() with patch.object(conf, 'get_extensions_enabled', return_value=False): assert_extensions_called(exthandlers_handler, expected_call_count=0) diff --git a/tests/ga/test_monitor.py b/tests/ga/test_monitor.py index d5700bc91b..5853b23eff 100644 --- a/tests/ga/test_monitor.py +++ b/tests/ga/test_monitor.py @@ -188,7 +188,7 @@ def setUp(self): CGroupsTelemetry.reset() clear_singleton_instances(ProtocolUtil) protocol = WireProtocol('endpoint') - protocol.update_goal_state = MagicMock() + protocol.client.update_goal_state = MagicMock() self.get_protocol = patch('azurelinuxagent.common.protocol.util.ProtocolUtil.get_protocol', return_value=protocol) self.get_protocol.start() diff --git a/tests/ga/test_multi_config_extension.py b/tests/ga/test_multi_config_extension.py index a9a07bd67e..365052f5d4 100644 --- a/tests/ga/test_multi_config_extension.py +++ b/tests/ga/test_multi_config_extension.py @@ -253,7 +253,7 @@ def __setup_and_assert_disable_scenario(self, exthandlers_handler, protocol): self.test_data['ext_conf'] = os.path.join(self._MULTI_CONFIG_TEST_DATA, 'ext_conf_mc_disabled_extensions.xml') protocol.mock_wire_data = WireProtocolData(self.test_data) protocol.mock_wire_data.set_incarnation(2) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -319,7 +319,7 @@ def test_it_should_execute_and_report_multi_config_extensions_properly(self): # Case 3: Uninstall Multi-config handler (with enabled extensions) and single config extension protocol.mock_wire_data.set_incarnation(3) protocol.mock_wire_data.set_extensions_config_state(ExtensionRequestedState.Uninstall) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() self.assertEqual(0, len(protocol.aggregate_status['aggregateStatus']['handlerAggregateStatus']), @@ -333,7 +333,7 @@ def test_it_should_report_unregistered_version_error_per_extension(self): failing_version = "19.12.1221" protocol.mock_wire_data.set_extensions_config_version(failing_version) protocol.mock_wire_data.set_incarnation(2) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() self.assertEqual(no_of_extensions, @@ -411,7 +411,7 @@ def test_it_should_only_disable_enabled_extensions_on_update(self): self.test_data['ext_conf'] = os.path.join(self._MULTI_CONFIG_TEST_DATA, 'ext_conf_mc_update_extensions.xml') protocol.mock_wire_data = WireProtocolData(self.test_data) protocol.mock_wire_data.set_incarnation(2) - protocol.update_goal_state() + protocol.client.update_goal_state() new_version = "1.1.0" new_first_ext = extension_emulator(name="OSTCExtensions.ExampleHandlerLinux.firstExtension", @@ -460,7 +460,7 @@ def test_it_should_retry_update_sequence_per_extension_if_previous_failed(self): self.test_data['ext_conf'] = os.path.join(self._MULTI_CONFIG_TEST_DATA, 'ext_conf_mc_update_extensions.xml') protocol.mock_wire_data = WireProtocolData(self.test_data) protocol.mock_wire_data.set_incarnation(2) - protocol.update_goal_state() + protocol.client.update_goal_state() new_version = "1.1.0" _, fail_action = Actions.generate_unique_fail() @@ -529,7 +529,7 @@ def test_it_should_report_disabled_extension_errors_if_update_failed(self): self.test_data['ext_conf'] = os.path.join(self._MULTI_CONFIG_TEST_DATA, 'ext_conf_mc_update_extensions.xml') protocol.mock_wire_data = WireProtocolData(self.test_data) protocol.mock_wire_data.set_incarnation(2) - protocol.update_goal_state() + protocol.client.update_goal_state() new_version = "1.1.0" fail_code, fail_action = Actions.generate_unique_fail() @@ -655,7 +655,7 @@ def __assert_state_file(handler_name, handler_version, extensions, state, not_pr self.test_data['ext_conf'] = os.path.join(self._MULTI_CONFIG_TEST_DATA, 'ext_conf_mc_disabled_extensions.xml') protocol.mock_wire_data = WireProtocolData(self.test_data) protocol.mock_wire_data.set_incarnation(2) - protocol.update_goal_state() + protocol.client.update_goal_state() ext_handler.run() ext_handler.report_ext_handlers_status() @@ -781,7 +781,7 @@ def mock_popen(cmd, *_, **kwargs): 'ext_conf_mc_update_extensions.xml') protocol.mock_wire_data = WireProtocolData(self.test_data) protocol.mock_wire_data.set_incarnation(2) - protocol.update_goal_state() + protocol.client.update_goal_state() exthandlers_handler.run() exthandlers_handler.report_ext_handlers_status() @@ -961,7 +961,7 @@ def test_it_should_report_status_correctly_for_unsupported_goal_state(self): self.test_data['ext_conf'] = "wire/ext_conf_required_features.xml" protocol.mock_wire_data = WireProtocolData(self.test_data) protocol.mock_wire_data.set_incarnation(2) - protocol.update_goal_state() + protocol.client.update_goal_state() # Assert the extension status is the same as we reported for Incarnation 1. self.__run_and_assert_generic_case(exthandlers_handler, protocol, no_of_extensions=4, with_message=False) @@ -1021,7 +1021,7 @@ def test_it_should_check_every_time_if_handler_supports_mc(self): with self.__setup_generic_test_env() as (exthandlers_handler, protocol, old_exts): protocol.mock_wire_data.set_incarnation(2) - protocol.update_goal_state() + protocol.client.update_goal_state() # Mock manifest to not support multiple extensions with patch('azurelinuxagent.ga.exthandlers.HandlerManifest.supports_multiple_extensions', return_value=False): From 011fbef23f68e511c59f612c154cbeee9c72d4cd Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Wed, 14 Dec 2022 19:24:56 -0800 Subject: [PATCH 17/26] Remove update_goal_State from wire protocol --- tests/protocol/test_hostplugin.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/protocol/test_hostplugin.py b/tests/protocol/test_hostplugin.py index c980433b5a..b85ed7574f 100644 --- a/tests/protocol/test_hostplugin.py +++ b/tests/protocol/test_hostplugin.py @@ -244,7 +244,7 @@ def test_default_channel(self, patch_put, patch_upload, _): with self.create_mock_protocol() as wire_protocol: wire.HostPluginProtocol.is_default_channel = False - wire_protocol.update_goal_state() + wire_protocol.client.update_goal_state() # act wire_protocol.client.upload_status_blob() @@ -277,7 +277,7 @@ def test_fallback_channel_503(self, patch_put, patch_upload, _): with self.create_mock_protocol() as wire_protocol: wire.HostPluginProtocol.is_default_channel = False - wire_protocol.update_goal_state() + wire_protocol.client.update_goal_state() # act wire_protocol.client.upload_status_blob() @@ -311,7 +311,7 @@ def test_fallback_channel_410(self, patch_refresh_host_plugin, patch_put, patch_ with self.create_mock_protocol() as wire_protocol: wire.HostPluginProtocol.is_default_channel = False - wire_protocol.update_goal_state() + wire_protocol.client.update_goal_state() # act wire_protocol.client.upload_status_blob() @@ -345,7 +345,7 @@ def test_fallback_channel_failure(self, patch_put, patch_upload, _): with self.create_mock_protocol() as wire_protocol: wire.HostPluginProtocol.is_default_channel = False - wire_protocol.update_goal_state() + wire_protocol.client.update_goal_state() # act self.assertRaises(wire.ProtocolError, wire_protocol.client.upload_status_blob) From b833735af1781af781af62afa6c2cac4b87c998a Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Wed, 14 Dec 2022 19:32:27 -0800 Subject: [PATCH 18/26] Separate extensionsconfig and certificates property --- azurelinuxagent/common/protocol/goal_state.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/azurelinuxagent/common/protocol/goal_state.py b/azurelinuxagent/common/protocol/goal_state.py index 8489af64a5..e7239343f3 100644 --- a/azurelinuxagent/common/protocol/goal_state.py +++ b/azurelinuxagent/common/protocol/goal_state.py @@ -55,9 +55,10 @@ class GoalStateProperties(object): RoleConfig = 0x1 HostingEnv = 0x2 SharedConfig = 0x4 - ExtensionsConfig_Certs = 0x8 - RemoteAccessInfo = 0x10 - All = RoleConfig | HostingEnv | SharedConfig | ExtensionsConfig_Certs | RemoteAccessInfo + ExtensionsConfig = 0x8 + Certificates = 0x10 + RemoteAccessInfo = 0x20 + All = RoleConfig | HostingEnv | SharedConfig | ExtensionsConfig | Certificates | RemoteAccessInfo class GoalStateInconsistentError(ProtocolError): @@ -133,14 +134,14 @@ def role_config_name(self): @property def extensions_goal_state(self): - if not self._goal_state_properties & GoalStateProperties.ExtensionsConfig_Certs: + if not self._goal_state_properties & GoalStateProperties.ExtensionsConfig: raise ProtocolError("ExtensionsConfig is not in goal state properties") else: return self._extensions_goal_state @property def certs(self): - if not self._goal_state_properties & GoalStateProperties.ExtensionsConfig_Certs: + if not self._goal_state_properties & GoalStateProperties.Certificates: raise ProtocolError("Certificates is not in goal state properties") else: return self._certs @@ -405,7 +406,7 @@ def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc): container_id = findtext(container, "ContainerId") extensions_config_uri = findtext(xml_doc, "ExtensionsConfig") - if not (GoalStateProperties.ExtensionsConfig_Certs & self._goal_state_properties) or extensions_config_uri is None: + if not (GoalStateProperties.ExtensionsConfig & self._goal_state_properties) or extensions_config_uri is None: extensions_config = ExtensionsGoalStateFactory.create_empty(incarnation) else: xml_text = self._wire_client.fetch_config(extensions_config_uri, self._wire_client.get_header()) @@ -434,7 +435,7 @@ def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc): certs = EmptyCertificates() certs_uri = findtext(xml_doc, "Certificates") - if (GoalStateProperties.ExtensionsConfig_Certs & self._goal_state_properties) and certs_uri is not None: + if (GoalStateProperties.Certificates & self._goal_state_properties) and certs_uri is not None: xml_text = self._wire_client.fetch_config(certs_uri, self._wire_client.get_header_for_cert()) certs = Certificates(xml_text, self.logger) # Log and save the certificates summary (i.e. the thumbprint but not the certificate itself) to the goal state history From d762a03aafe942179e3d242152bcbeadcc0b8269 Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Tue, 20 Dec 2022 14:00:19 -0800 Subject: [PATCH 19/26] Address PR comments --- azurelinuxagent/common/protocol/goal_state.py | 25 ++++++++++--------- azurelinuxagent/common/protocol/wire.py | 8 +++--- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/azurelinuxagent/common/protocol/goal_state.py b/azurelinuxagent/common/protocol/goal_state.py index e7239343f3..1e4d5affba 100644 --- a/azurelinuxagent/common/protocol/goal_state.py +++ b/azurelinuxagent/common/protocol/goal_state.py @@ -55,10 +55,10 @@ class GoalStateProperties(object): RoleConfig = 0x1 HostingEnv = 0x2 SharedConfig = 0x4 - ExtensionsConfig = 0x8 + ExtensionsGoalState = 0x8 Certificates = 0x10 RemoteAccessInfo = 0x20 - All = RoleConfig | HostingEnv | SharedConfig | ExtensionsConfig | Certificates | RemoteAccessInfo + All = RoleConfig | HostingEnv | SharedConfig | ExtensionsGoalState | Certificates | RemoteAccessInfo class GoalStateInconsistentError(ProtocolError): @@ -114,14 +114,14 @@ def incarnation(self): @property def container_id(self): if not self._goal_state_properties & GoalStateProperties.RoleConfig: - raise ProtocolError("RoleConfig is not in goal state properties") + raise ProtocolError("ContainerId is not in goal state properties") else: return self._container_id @property def role_instance_id(self): if not self._goal_state_properties & GoalStateProperties.RoleConfig: - raise ProtocolError("RoleConfig is not in goal state properties") + raise ProtocolError("RoleInstanceId is not in goal state properties") else: return self._role_instance_id @@ -134,8 +134,8 @@ def role_config_name(self): @property def extensions_goal_state(self): - if not self._goal_state_properties & GoalStateProperties.ExtensionsConfig: - raise ProtocolError("ExtensionsConfig is not in goal state properties") + if not self._goal_state_properties & GoalStateProperties.ExtensionsGoalState: + raise ProtocolError("ExtensionsGoalState is not in goal state properties") else: return self._extensions_goal_state @@ -228,11 +228,12 @@ def _update(self, force_update): add_event(op=WALAEventOperation.GoalState, message=message) vm_settings, vm_settings_updated = None, False - try: - vm_settings, vm_settings_updated = GoalState._fetch_vm_settings(self._wire_client, force_update=force_update) - except VmSettingsSupportStopped as exception: # If the HGAP stopped supporting vmSettings, we need to use the goal state from the WireServer - self._restore_wire_server_goal_state(incarnation, xml_text, xml_doc, exception) - return + if self._goal_state_properties & GoalStateProperties.ExtensionsGoalState: + try: + vm_settings, vm_settings_updated = GoalState._fetch_vm_settings(self._wire_client, force_update=force_update) + except VmSettingsSupportStopped as exception: # If the HGAP stopped supporting vmSettings, we need to use the goal state from the WireServer + self._restore_wire_server_goal_state(incarnation, xml_text, xml_doc, exception) + return if vm_settings_updated: self.logger.info('') @@ -406,7 +407,7 @@ def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc): container_id = findtext(container, "ContainerId") extensions_config_uri = findtext(xml_doc, "ExtensionsConfig") - if not (GoalStateProperties.ExtensionsConfig & self._goal_state_properties) or extensions_config_uri is None: + if not (GoalStateProperties.ExtensionsGoalState & self._goal_state_properties) or extensions_config_uri is None: extensions_config = ExtensionsGoalStateFactory.create_empty(incarnation) else: xml_text = self._wire_client.fetch_config(extensions_config_uri, self._wire_client.get_header()) diff --git a/azurelinuxagent/common/protocol/wire.py b/azurelinuxagent/common/protocol/wire.py index 81bf4157d8..a1d9975a04 100644 --- a/azurelinuxagent/common/protocol/wire.py +++ b/azurelinuxagent/common/protocol/wire.py @@ -781,10 +781,10 @@ def update_goal_state(self, silent=False): Updates the goal state if the incarnation or etag changed """ try: - if not silent: - logger.info("Forcing an update of the goal state.") - - self._goal_state.update(silent=silent) + if self._goal_state is None: + self._goal_state = GoalState(self, silent=silent) + else: + self._goal_state.update(silent=silent) except ProtocolError: raise From 11f9c3a48f01e6ac36a37d3def99ccd409f2f310 Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Tue, 20 Dec 2022 14:12:48 -0800 Subject: [PATCH 20/26] Add flag to determine if goal state should be init --- azurelinuxagent/common/logcollector.py | 2 +- azurelinuxagent/common/protocol/util.py | 8 ++++---- azurelinuxagent/common/protocol/wire.py | 7 ++++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/azurelinuxagent/common/logcollector.py b/azurelinuxagent/common/logcollector.py index b4a1bb8795..393333c962 100644 --- a/azurelinuxagent/common/logcollector.py +++ b/azurelinuxagent/common/logcollector.py @@ -118,7 +118,7 @@ def _set_resource_usage_cgroups(cpu_cgroup_path, memory_cgroup_path): @staticmethod def _initialize_telemetry(): - protocol = get_protocol_util().get_protocol() + protocol = get_protocol_util().get_protocol(init_goal_state=False) protocol.client.reset_goal_state(goalstate_properties=GoalStateProperties.RoleConfig | GoalStateProperties.HostingEnv) # Initialize the common parameters for telemetry events initialize_event_logger_vminfo_common_parameters(protocol) diff --git a/azurelinuxagent/common/protocol/util.py b/azurelinuxagent/common/protocol/util.py index 92b691e92b..7d7f901681 100644 --- a/azurelinuxagent/common/protocol/util.py +++ b/azurelinuxagent/common/protocol/util.py @@ -188,7 +188,7 @@ def _clear_wireserver_endpoint(self): return logger.error("Failed to clear wiresever endpoint: {0}", e) - def _detect_protocol(self): + def _detect_protocol(self, init_goal_state=True): """ Probe protocol endpoints in turn. """ @@ -217,7 +217,7 @@ def _detect_protocol(self): try: protocol = WireProtocol(endpoint) - protocol.detect() + protocol.detect(init_goal_state=init_goal_state) self._set_wireserver_endpoint(endpoint) return protocol @@ -268,7 +268,7 @@ def clear_protocol(self): finally: self._lock.release() - def get_protocol(self): + def get_protocol(self, init_goal_state=True): """ Detect protocol by endpoint. :returns: protocol instance @@ -296,7 +296,7 @@ def get_protocol(self): logger.info("Detect protocol endpoint") - protocol = self._detect_protocol() + protocol = self._detect_protocol(init_goal_state=init_goal_state) IOErrorCounter.set_protocol_endpoint(endpoint=protocol.get_endpoint()) self._save_protocol(WIRE_PROTOCOL_NAME) diff --git a/azurelinuxagent/common/protocol/wire.py b/azurelinuxagent/common/protocol/wire.py index a1d9975a04..38a3e0621d 100644 --- a/azurelinuxagent/common/protocol/wire.py +++ b/azurelinuxagent/common/protocol/wire.py @@ -73,7 +73,7 @@ def __init__(self, endpoint): raise ProtocolError("WireProtocol endpoint is None") self.client = WireClient(endpoint) - def detect(self): + def detect(self, init_goal_state=True): self.client.check_wire_protocol_version() trans_prv_file = os.path.join(conf.get_lib_dir(), @@ -84,8 +84,9 @@ def detect(self): cryptutil.gen_transport_cert(trans_prv_file, trans_cert_file) # Initialize the goal state, including all the inner properties - logger.info('Initializing goal state during protocol detection') - self.client.reset_goal_state() + if init_goal_state: + logger.info('Initializing goal state during protocol detection') + self.client.reset_goal_state() def update_host_plugin_from_goal_state(self): self.client.update_host_plugin_from_goal_state() From 212a72b904c143371f835dd8bcf1667970d6972d Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Wed, 21 Dec 2022 11:16:47 -0800 Subject: [PATCH 21/26] Add test case for goal_state_properties --- tests/protocol/test_goal_state.py | 35 ++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/tests/protocol/test_goal_state.py b/tests/protocol/test_goal_state.py index d853363c73..0aba517e5c 100644 --- a/tests/protocol/test_goal_state.py +++ b/tests/protocol/test_goal_state.py @@ -14,7 +14,8 @@ from azurelinuxagent.common.protocol.extensions_goal_state_from_extensions_config import ExtensionsGoalStateFromExtensionsConfig from azurelinuxagent.common.protocol.extensions_goal_state_from_vm_settings import ExtensionsGoalStateFromVmSettings from azurelinuxagent.common.protocol import hostplugin -from azurelinuxagent.common.protocol.goal_state import GoalState, GoalStateInconsistentError, _GET_GOAL_STATE_MAX_ATTEMPTS +from azurelinuxagent.common.protocol.goal_state import GoalState, GoalStateInconsistentError, \ + _GET_GOAL_STATE_MAX_ATTEMPTS, GoalStateProperties from azurelinuxagent.common.exception import ProtocolError from azurelinuxagent.common.utils import fileutil from azurelinuxagent.common.utils.archive import ARCHIVE_DIRECTORY_NAME @@ -419,3 +420,35 @@ def http_get_handler(url, *_, **__): for settings in extension.settings: if settings.protectedSettings is not None: self.assertIn(settings.certificateThumbprint, thumbprints, "Certificate is missing from the goal state.") + + def test_it_should_raise_when_goal_state_property_not_initialized(self): + with GoalStateTestCase._create_protocol_ws_and_hgap_in_sync() as protocol: + goal_state = GoalState( + protocol.client, + goal_state_properties=GoalStateProperties.RoleConfig | GoalStateProperties.HostingEnv) + + goal_state.update() + + with self.assertRaises(ProtocolError) as context: + goal_state.extensions_goal_state + + expected_message = "ExtensionsGoalState is not in goal state properties" + self.assertIn(expected_message, str(context.exception)) + + with self.assertRaises(ProtocolError) as context: + goal_state.certs + + expected_message = "Certificates is not in goal state properties" + self.assertIn(expected_message, str(context.exception)) + + with self.assertRaises(ProtocolError) as context: + goal_state.shared_conf + + expected_message = "SharedConfig is not in goal state properties" + self.assertIn(expected_message, str(context.exception)) + + with self.assertRaises(ProtocolError) as context: + goal_state.remote_access + + expected_message = "RemoteAccessInfo is not in goal state properties" + self.assertIn(expected_message, str(context.exception)) From 7805dc18824bf0b61a052c1aba7f80f11d4ec65d Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Wed, 21 Dec 2022 11:22:53 -0800 Subject: [PATCH 22/26] Correct pylint errors --- tests/protocol/test_goal_state.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/protocol/test_goal_state.py b/tests/protocol/test_goal_state.py index 0aba517e5c..ae7c3ddd63 100644 --- a/tests/protocol/test_goal_state.py +++ b/tests/protocol/test_goal_state.py @@ -430,25 +430,25 @@ def test_it_should_raise_when_goal_state_property_not_initialized(self): goal_state.update() with self.assertRaises(ProtocolError) as context: - goal_state.extensions_goal_state + _ = goal_state.extensions_goal_state expected_message = "ExtensionsGoalState is not in goal state properties" self.assertIn(expected_message, str(context.exception)) with self.assertRaises(ProtocolError) as context: - goal_state.certs + _ = goal_state.certs expected_message = "Certificates is not in goal state properties" self.assertIn(expected_message, str(context.exception)) with self.assertRaises(ProtocolError) as context: - goal_state.shared_conf + _ = goal_state.shared_conf expected_message = "SharedConfig is not in goal state properties" self.assertIn(expected_message, str(context.exception)) with self.assertRaises(ProtocolError) as context: - goal_state.remote_access + _ = goal_state.remote_access expected_message = "RemoteAccessInfo is not in goal state properties" self.assertIn(expected_message, str(context.exception)) From b1d21eaa6353e0437fa3c0d2a1b16d0d0f0e9951 Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Wed, 21 Dec 2022 12:39:54 -0800 Subject: [PATCH 23/26] Add reset_goal_state test with goal_state_properties --- tests/protocol/test_goal_state.py | 43 +++++++++++++++++++++++++++++-- tests/protocol/test_wire.py | 13 +++++++++- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/tests/protocol/test_goal_state.py b/tests/protocol/test_goal_state.py index ae7c3ddd63..869da68c8c 100644 --- a/tests/protocol/test_goal_state.py +++ b/tests/protocol/test_goal_state.py @@ -421,20 +421,44 @@ def http_get_handler(url, *_, **__): if settings.protectedSettings is not None: self.assertIn(settings.certificateThumbprint, thumbprints, "Certificate is missing from the goal state.") - def test_it_should_raise_when_goal_state_property_not_initialized(self): + def test_it_should_raise_when_goal_state_properties_not_initialized(self): with GoalStateTestCase._create_protocol_ws_and_hgap_in_sync() as protocol: goal_state = GoalState( protocol.client, - goal_state_properties=GoalStateProperties.RoleConfig | GoalStateProperties.HostingEnv) + goal_state_properties=~GoalStateProperties.All) goal_state.update() + with self.assertRaises(ProtocolError) as context: + _ = goal_state.container_id + + expected_message = "ContainerId is not in goal state properties" + self.assertIn(expected_message, str(context.exception)) + + with self.assertRaises(ProtocolError) as context: + _ = goal_state.role_config_name + + expected_message = "RoleConfig is not in goal state properties" + self.assertIn(expected_message, str(context.exception)) + + with self.assertRaises(ProtocolError) as context: + _ = goal_state.role_instance_id + + expected_message = "RoleInstanceId is not in goal state properties" + self.assertIn(expected_message, str(context.exception)) + with self.assertRaises(ProtocolError) as context: _ = goal_state.extensions_goal_state expected_message = "ExtensionsGoalState is not in goal state properties" self.assertIn(expected_message, str(context.exception)) + with self.assertRaises(ProtocolError) as context: + _ = goal_state.hosting_env + + expected_message = "HostingEnvironment is not in goal state properties" + self.assertIn(expected_message, str(context.exception)) + with self.assertRaises(ProtocolError) as context: _ = goal_state.certs @@ -452,3 +476,18 @@ def test_it_should_raise_when_goal_state_property_not_initialized(self): expected_message = "RemoteAccessInfo is not in goal state properties" self.assertIn(expected_message, str(context.exception)) + + goal_state = GoalState( + protocol.client, + goal_state_properties=GoalStateProperties.All & ~GoalStateProperties.HostingEnv) + + goal_state.update() + + _ = goal_state.container_id, goal_state.role_instance_id, goal_state.role_config_name, \ + goal_state.extensions_goal_state, goal_state.certs, goal_state.shared_conf, goal_state.remote_access + + with self.assertRaises(ProtocolError) as context: + _ = goal_state.hosting_env + + expected_message = "HostingEnvironment is not in goal state properties" + self.assertIn(expected_message, str(context.exception)) diff --git a/tests/protocol/test_wire.py b/tests/protocol/test_wire.py index 9c9a4ad0cb..6924e30ae3 100644 --- a/tests/protocol/test_wire.py +++ b/tests/protocol/test_wire.py @@ -30,6 +30,7 @@ from azurelinuxagent.common.exception import ResourceGoneError, ProtocolError, \ ExtensionDownloadError, HttpError from azurelinuxagent.common.protocol.extensions_goal_state_from_extensions_config import ExtensionsGoalStateFromExtensionsConfig +from azurelinuxagent.common.protocol.goal_state import GoalStateProperties from azurelinuxagent.common.protocol.hostplugin import HostPluginProtocol from azurelinuxagent.common.protocol.wire import WireProtocol, WireClient, \ StatusBlob, VMStatus @@ -991,7 +992,7 @@ def test_download_using_appropriate_channel_should_change_default_channel_when_s class UpdateGoalStateTestCase(HttpRequestPredicates, AgentTestCase): """ - Tests for WireClient.update_goal_state() + Tests for WireClient.update_goal_state() and WireClient.reset_goal_state() """ def test_it_should_update_the_goal_state_and_the_host_plugin_when_the_incarnation_changes(self): @@ -1098,6 +1099,16 @@ def test_forced_update_should_update_the_goal_state_and_the_host_plugin_when_the self.assertEqual(protocol.client.get_host_plugin().container_id, new_container_id) self.assertEqual(protocol.client.get_host_plugin().role_config_name, new_role_config_name) + def test_reset_should_init_provided_goal_state_properties(self): + with mock_wire_protocol(mockwiredata.DATA_FILE) as protocol: + protocol.client.reset_goal_state(goal_state_properties=GoalStateProperties.All & ~GoalStateProperties.Certificates) + + with self.assertRaises(ProtocolError) as context: + _ = protocol.client.get_certs() + + expected_message = "Certificates is not in goal state properties" + self.assertIn(expected_message, str(context.exception)) + class UpdateHostPluginFromGoalStateTestCase(AgentTestCase): """ From c61a0670b43d99f8be4e646ed7a1289fc10610cd Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Wed, 21 Dec 2022 14:23:22 -0800 Subject: [PATCH 24/26] Add reset test cases --- tests/protocol/test_wire.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/protocol/test_wire.py b/tests/protocol/test_wire.py index 6924e30ae3..2a36fc2913 100644 --- a/tests/protocol/test_wire.py +++ b/tests/protocol/test_wire.py @@ -1109,6 +1109,18 @@ def test_reset_should_init_provided_goal_state_properties(self): expected_message = "Certificates is not in goal state properties" self.assertIn(expected_message, str(context.exception)) + def test_reset_should_init_the_goal_state(self): + with mock_wire_protocol(mockwiredata.DATA_FILE) as protocol: + new_container_id = str(uuid.uuid4()) + new_role_config_name = str(uuid.uuid4()) + protocol.mock_wire_data.set_container_id(new_container_id) + protocol.mock_wire_data.set_role_config_name(new_role_config_name) + + protocol.client.reset_goal_state() + + self.assertEqual(protocol.client.get_goal_state().container_id, new_container_id) + self.assertEqual(protocol.client.get_goal_state().role_config_name, new_role_config_name) + class UpdateHostPluginFromGoalStateTestCase(AgentTestCase): """ From dd9d8da85cc2036fad3244c904c23f80d4ea2ba8 Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Thu, 22 Dec 2022 08:30:12 -0800 Subject: [PATCH 25/26] Remove Certificates property in GoalState --- azurelinuxagent/common/protocol/goal_state.py | 14 +++----------- tests/protocol/test_wire.py | 2 +- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/azurelinuxagent/common/protocol/goal_state.py b/azurelinuxagent/common/protocol/goal_state.py index 1e4d5affba..1d82289bb3 100644 --- a/azurelinuxagent/common/protocol/goal_state.py +++ b/azurelinuxagent/common/protocol/goal_state.py @@ -56,9 +56,8 @@ class GoalStateProperties(object): HostingEnv = 0x2 SharedConfig = 0x4 ExtensionsGoalState = 0x8 - Certificates = 0x10 - RemoteAccessInfo = 0x20 - All = RoleConfig | HostingEnv | SharedConfig | ExtensionsGoalState | Certificates | RemoteAccessInfo + RemoteAccessInfo = 0x10 + All = RoleConfig | HostingEnv | SharedConfig | ExtensionsGoalState | RemoteAccessInfo class GoalStateInconsistentError(ProtocolError): @@ -139,13 +138,6 @@ def extensions_goal_state(self): else: return self._extensions_goal_state - @property - def certs(self): - if not self._goal_state_properties & GoalStateProperties.Certificates: - raise ProtocolError("Certificates is not in goal state properties") - else: - return self._certs - @property def hosting_env(self): if not self._goal_state_properties & GoalStateProperties.HostingEnv: @@ -436,7 +428,7 @@ def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc): certs = EmptyCertificates() certs_uri = findtext(xml_doc, "Certificates") - if (GoalStateProperties.Certificates & self._goal_state_properties) and certs_uri is not None: + if (GoalStateProperties.ExtensionsGoalState & self._goal_state_properties) and certs_uri is not None: xml_text = self._wire_client.fetch_config(certs_uri, self._wire_client.get_header_for_cert()) certs = Certificates(xml_text, self.logger) # Log and save the certificates summary (i.e. the thumbprint but not the certificate itself) to the goal state history diff --git a/tests/protocol/test_wire.py b/tests/protocol/test_wire.py index 2a36fc2913..bbf018fc30 100644 --- a/tests/protocol/test_wire.py +++ b/tests/protocol/test_wire.py @@ -1101,7 +1101,7 @@ def test_forced_update_should_update_the_goal_state_and_the_host_plugin_when_the def test_reset_should_init_provided_goal_state_properties(self): with mock_wire_protocol(mockwiredata.DATA_FILE) as protocol: - protocol.client.reset_goal_state(goal_state_properties=GoalStateProperties.All & ~GoalStateProperties.Certificates) + protocol.client.reset_goal_state(goal_state_properties=GoalStateProperties.All & ~GoalStateProperties.ExtensionsGoalState) with self.assertRaises(ProtocolError) as context: _ = protocol.client.get_certs() From 7711ae2681de1853844dbe2b445bd3337e1f2b78 Mon Sep 17 00:00:00 2001 From: "Maddie Ford (SHE/HER)" Date: Thu, 22 Dec 2022 08:34:46 -0800 Subject: [PATCH 26/26] Revert certs change --- azurelinuxagent/common/protocol/goal_state.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/azurelinuxagent/common/protocol/goal_state.py b/azurelinuxagent/common/protocol/goal_state.py index 1d82289bb3..ed96159c8a 100644 --- a/azurelinuxagent/common/protocol/goal_state.py +++ b/azurelinuxagent/common/protocol/goal_state.py @@ -138,6 +138,13 @@ def extensions_goal_state(self): else: return self._extensions_goal_state + @property + def certs(self): + if not self._goal_state_properties & GoalStateProperties.ExtensionsGoalState: + raise ProtocolError("Certificates is not in goal state properties") + else: + return self._certs + @property def hosting_env(self): if not self._goal_state_properties & GoalStateProperties.HostingEnv: