Skip to content

Commit

Permalink
Bug fix for fetching a goal state with empty certificates property (A…
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinclark19a authored Apr 29, 2022
1 parent 8d7237f commit 8e9c1b5
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 2 deletions.
9 changes: 7 additions & 2 deletions azurelinuxagent/common/protocol/goal_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def __init__(self, wire_client, silent=False):
self._container_id = None
self._hosting_env = None
self._shared_conf = None
self._certs = None
self._certs = EmptyCertificates()
self._remote_access = None

self.update(silent=silent)
Expand Down Expand Up @@ -348,7 +348,7 @@ def _fetch_full_wire_server_goal_state(self, incarnation, xml_doc):
shared_conf = SharedConfig(xml_text)
self._history.save_shared_conf(xml_text)

certs = None
certs = EmptyCertificates()
certs_uri = findtext(xml_doc, "Certificates")
if certs_uri is not None:
xml_text = self._wire_client.fetch_config(certs_uri, self._wire_client.get_header_for_cert())
Expand Down Expand Up @@ -506,6 +506,11 @@ def _write_to_tmp_file(index, suffix, buf):
fileutil.write_file(file_name, "".join(buf))
return file_name

class EmptyCertificates:
def __init__(self):
self.cert_list = CertList()
self.summary = [] # debugging info
self.warnings = []

class RemoteAccess(object):
"""
Expand Down
27 changes: 27 additions & 0 deletions tests/data/wire/goal_state_no_certs.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<GoalState xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="goalstate10.xsd">
<Version>2010-12-15</Version>
<Incarnation>1</Incarnation>
<Machine>
<ExpectedState>Started</ExpectedState>
<LBProbePorts>
<Port>16001</Port>
</LBProbePorts>
</Machine>
<Container>
<ContainerId>c6d5526c-5ac2-4200-b6e2-56f2b70c5ab2</ContainerId>
<RoleInstanceList>
<RoleInstance>
<InstanceId>b61f93d0-e1ed-40b2-b067-22c243233448.MachineRole_IN_0</InstanceId>
<State>Started</State>
<Configuration>
<HostingEnvironmentConfig>http://168.63.129.16:80/machine/865a6683-91d8-450f-99ae/bc8b9d47%2Db5ed%2D4704%2D85d9%2Dfd74cc967ec2.%5Fcanary?comp=config&amp;type=hostingEnvironmentConfig&amp;incarnation=1</HostingEnvironmentConfig>
<SharedConfig>http://168.63.129.16:80/machine/865a6683-91d8-450f-99ae/bc8b9d47%2Db5ed%2D4704%2D85d9%2Dfd74cc967ec2.%5Fcanary?comp=config&amp;type=sharedConfig&amp;incarnation=1</SharedConfig>
<ExtensionsConfig>http://168.63.129.16:80/machine/865a6683-91d8-450f-99ae/bc8b9d47%2Db5ed%2D4704%2D85d9%2Dfd74cc967ec2.%5Fcanary?comp=config&amp;type=extensionsConfig&amp;incarnation=1</ExtensionsConfig>
<FullConfig>http://168.63.129.16:80/machine/865a6683-91d8-450f-99ae/bc8b9d47%2Db5ed%2D4704%2D85d9%2Dfd74cc967ec2.%5Fcanary?comp=config&amp;type=fullConfig&amp;incarnation=1</FullConfig>
<ConfigName>bc8b9d47-b5ed-4704-85d9-fd74cc967ec2.5.bc8b9d47-b5ed-4704-85d9-fd74cc967ec2.5._canary.1.xml</ConfigName>
</Configuration>
</RoleInstance>
</RoleInstanceList>
</Container>
</GoalState>
47 changes: 47 additions & 0 deletions tests/ga/test_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -1564,6 +1564,53 @@ def _get_test_ext_handler_instance(protocol, name="OSTCExtensions.ExampleHandler
eh = Extension(name=name)
eh.version = version
return ExtHandlerInstance(eh, protocol)

def test_update_handler_recovers_from_error_with_no_certs(self):
data = DATA_FILE.copy()
data['goal_state'] = 'wire/goal_state_no_certs.xml'

def fail_gs_fetch(url, *_, **__):
if HttpRequestPredicates.is_goal_state_request(url):
return MockHttpResponse(status=500)
return None

with mock_wire_protocol(data) as protocol:

def fail_fetch_on_second_iter(iteration):
if iteration == 2:
protocol.set_http_handlers(http_get_handler=fail_gs_fetch)
if iteration > 2: # Zero out the fail handler for subsequent iterations.
protocol.set_http_handlers(http_get_handler=None)

with mock_update_handler(protocol, 3, on_new_iteration=fail_fetch_on_second_iter) as update_handler:
with patch("azurelinuxagent.ga.update.logger.error") as patched_error:
with patch("azurelinuxagent.ga.update.logger.info") as patched_info:
def match_unexpected_errors():
unexpected_msg_fragment = "Error fetching the goal state:"

matching_errors = []
for (args, _) in filter(lambda a: len(a) > 0, patched_error.call_args_list):
if unexpected_msg_fragment in args[0]:
matching_errors.append(args[0])

if len(matching_errors) > 1:
self.fail("Guest Agent did not recover, with new error(s): {}"\
.format(matching_errors[1:]))

def match_expected_info():
expected_msg_fragment = "Fetching the goal state recovered from previous errors"

for (call_args, _) in filter(lambda a: len(a) > 0, patched_info.call_args_list):
if expected_msg_fragment in call_args[0]:
break
else:
self.fail("Expected the guest agent to recover with '{}', but it didn't"\
.format(expected_msg_fragment))

update_handler.run(debug=True)
match_unexpected_errors() # Match on errors first, they can provide more info.
match_expected_info()


def test_it_should_recreate_handler_env_on_service_startup(self):
iterations = 5
Expand Down

0 comments on commit 8e9c1b5

Please sign in to comment.