From ded22fb0a67d31b275782ed1420aedadcf8b8589 Mon Sep 17 00:00:00 2001 From: Ksenija Stanojevic Date: Wed, 7 Aug 2024 19:29:48 -0700 Subject: [PATCH] feat(cloud-init): add support for azure-proxy-agent (#9878) Adds preliminary support for azure-proxy-agent into cloud-init. This is opt-in only with fallbacks if the command isn't available. --- ...rovisionGuestProxyAgent-OVF-setting-.patch | 114 +++++ ...-ProvisionGuestProxyAgent-as-bool-51.patch | 54 +++ ...re-add-support-for-azure-proxy-agent.patch | 413 ++++++++++++++++++ SPECS/cloud-init/cloud-init.spec | 8 +- 4 files changed, 588 insertions(+), 1 deletion(-) create mode 100644 SPECS/cloud-init/0001-feat-azure-Add-ProvisionGuestProxyAgent-OVF-setting-.patch create mode 100644 SPECS/cloud-init/0002-feat-azure-parse-ProvisionGuestProxyAgent-as-bool-51.patch create mode 100644 SPECS/cloud-init/0003-feat-azure-add-support-for-azure-proxy-agent.patch diff --git a/SPECS/cloud-init/0001-feat-azure-Add-ProvisionGuestProxyAgent-OVF-setting-.patch b/SPECS/cloud-init/0001-feat-azure-Add-ProvisionGuestProxyAgent-OVF-setting-.patch new file mode 100644 index 0000000000..e4e66fab0e --- /dev/null +++ b/SPECS/cloud-init/0001-feat-azure-Add-ProvisionGuestProxyAgent-OVF-setting-.patch @@ -0,0 +1,114 @@ +From 402e9331a72d543e779898667488a51ad3e3ec13 Mon Sep 17 00:00:00 2001 +From: Ksenija Stanojevic +Date: Fri, 9 Feb 2024 13:32:19 -0800 +Subject: [PATCH 1/3] feat(azure): Add ProvisionGuestProxyAgent OVF setting + (#4860) + +Add ProvisionGuestProxyAgent Boolean configuration setting into the OvfEnv class. +This PR is only logging the value of ProvisionGuestProxyAgent. +--- + cloudinit/sources/DataSourceAzure.py | 6 ++++++ + cloudinit/sources/helpers/azure.py | 8 ++++++++ + tests/unittests/sources/test_azure.py | 15 +++++++++++++++ + 3 files changed, 29 insertions(+) + +diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py +index 5a82aa34e..dc2b79a3a 100644 +--- a/cloudinit/sources/DataSourceAzure.py ++++ b/cloudinit/sources/DataSourceAzure.py +@@ -1784,6 +1784,12 @@ def read_azure_ovf(contents): + "PreprovisionedVMType: %s" % ovf_env.preprovisioned_vm_type, + logger_func=LOG.info, + ) ++ ++ cfg["ProvisionGuestProxyAgent"] = ovf_env.provision_guest_proxy_agent ++ report_diagnostic_event( ++ "ProvisionGuestProxyAgent: %s" % ovf_env.provision_guest_proxy_agent, ++ logger_func=LOG.info, ++ ) + return (md, ud, cfg) + + +diff --git a/cloudinit/sources/helpers/azure.py b/cloudinit/sources/helpers/azure.py +index 6e5c1f433..2847a9e53 100644 +--- a/cloudinit/sources/helpers/azure.py ++++ b/cloudinit/sources/helpers/azure.py +@@ -1064,6 +1064,7 @@ class OvfEnvXml: + public_keys: Optional[List[dict]] = None, + preprovisioned_vm: bool = False, + preprovisioned_vm_type: Optional[str] = None, ++ provision_guest_proxy_agent: bool = False, + ) -> None: + self.username = username + self.password = password +@@ -1073,6 +1074,7 @@ class OvfEnvXml: + self.public_keys: List[dict] = public_keys or [] + self.preprovisioned_vm = preprovisioned_vm + self.preprovisioned_vm_type = preprovisioned_vm_type ++ self.provision_guest_proxy_agent = provision_guest_proxy_agent + + def __eq__(self, other) -> bool: + return self.__dict__ == other.__dict__ +@@ -1216,6 +1218,12 @@ class OvfEnvXml: + "PreprovisionedVMType", + required=False, + ) ++ self.provision_guest_proxy_agent = self._parse_property( ++ platform_settings, ++ "ProvisionGuestProxyAgent", ++ default=False, ++ required=False, ++ ) + + def _parse_ssh_section(self, config_set): + self.public_keys = [] +diff --git a/tests/unittests/sources/test_azure.py b/tests/unittests/sources/test_azure.py +index 1ddbd3f39..6afde95fd 100644 +--- a/tests/unittests/sources/test_azure.py ++++ b/tests/unittests/sources/test_azure.py +@@ -356,6 +356,7 @@ def construct_ovf_env( + disable_ssh_password_auth=None, + preprovisioned_vm=None, + preprovisioned_vm_type=None, ++ provision_guest_proxy_agent=None, + ): + content = [ + '', +@@ -426,6 +427,11 @@ def construct_ovf_env( + "%s" + % preprovisioned_vm_type + ) ++ if provision_guest_proxy_agent is not None: ++ content.append( ++ "%s" ++ % provision_guest_proxy_agent ++ ) + content += [ + "", + "", +@@ -1316,6 +1322,7 @@ scbus-1 on xpt0 bus 0 + expected_cfg = { + "PreprovisionedVMType": None, + "PreprovisionedVm": False, ++ "ProvisionGuestProxyAgent": False, + "system_info": {"default_user": {"name": "myuser"}}, + } + expected_metadata = { +@@ -2668,6 +2675,14 @@ class TestPreprovisioningReadAzureOvfFlag(CiTestCase): + self.assertTrue(cfg["PreprovisionedVm"]) + self.assertEqual("Savable", cfg["PreprovisionedVMType"]) + ++ def test_read_azure_ovf_with_proxy_guest_agent(self): ++ """The read_azure_ovf method should set ProvisionGuestProxyAgent ++ cfg flag to True.""" ++ content = construct_ovf_env(provision_guest_proxy_agent=True) ++ ret = dsaz.read_azure_ovf(content) ++ cfg = ret[2] ++ self.assertTrue(cfg["ProvisionGuestProxyAgent"]) ++ + + @pytest.mark.parametrize( + "ovf_cfg,imds_md,pps_type", +-- +2.34.1 + diff --git a/SPECS/cloud-init/0002-feat-azure-parse-ProvisionGuestProxyAgent-as-bool-51.patch b/SPECS/cloud-init/0002-feat-azure-parse-ProvisionGuestProxyAgent-as-bool-51.patch new file mode 100644 index 0000000000..1972d43ad4 --- /dev/null +++ b/SPECS/cloud-init/0002-feat-azure-parse-ProvisionGuestProxyAgent-as-bool-51.patch @@ -0,0 +1,54 @@ +From e3ba5800d26065df9ce03ee2ac58ec6f08506423 Mon Sep 17 00:00:00 2001 +From: Ksenija Stanojevic +Date: Fri, 5 Apr 2024 16:52:26 -0700 +Subject: [PATCH 2/3] feat(azure): parse ProvisionGuestProxyAgent as bool + (#5126) + +--- + cloudinit/sources/helpers/azure.py | 1 + + tests/unittests/sources/test_azure.py | 12 ++++++++++-- + 2 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/cloudinit/sources/helpers/azure.py b/cloudinit/sources/helpers/azure.py +index 2847a9e53..165f47429 100644 +--- a/cloudinit/sources/helpers/azure.py ++++ b/cloudinit/sources/helpers/azure.py +@@ -1221,6 +1221,7 @@ class OvfEnvXml: + self.provision_guest_proxy_agent = self._parse_property( + platform_settings, + "ProvisionGuestProxyAgent", ++ parse_bool=True, + default=False, + required=False, + ) +diff --git a/tests/unittests/sources/test_azure.py b/tests/unittests/sources/test_azure.py +index 6afde95fd..255991ec3 100644 +--- a/tests/unittests/sources/test_azure.py ++++ b/tests/unittests/sources/test_azure.py +@@ -2675,13 +2675,21 @@ class TestPreprovisioningReadAzureOvfFlag(CiTestCase): + self.assertTrue(cfg["PreprovisionedVm"]) + self.assertEqual("Savable", cfg["PreprovisionedVMType"]) + +- def test_read_azure_ovf_with_proxy_guest_agent(self): ++ def test_read_azure_ovf_with_proxy_guest_agent_true(self): + """The read_azure_ovf method should set ProvisionGuestProxyAgent + cfg flag to True.""" + content = construct_ovf_env(provision_guest_proxy_agent=True) + ret = dsaz.read_azure_ovf(content) + cfg = ret[2] +- self.assertTrue(cfg["ProvisionGuestProxyAgent"]) ++ assert cfg["ProvisionGuestProxyAgent"] is True ++ ++ def test_read_azure_ovf_with_proxy_guest_agent_false(self): ++ """The read_azure_ovf method should set ProvisionGuestProxyAgent ++ cfg flag to False.""" ++ content = construct_ovf_env(provision_guest_proxy_agent=False) ++ ret = dsaz.read_azure_ovf(content) ++ cfg = ret[2] ++ assert cfg["ProvisionGuestProxyAgent"] is False + + + @pytest.mark.parametrize( +-- +2.34.1 + diff --git a/SPECS/cloud-init/0003-feat-azure-add-support-for-azure-proxy-agent.patch b/SPECS/cloud-init/0003-feat-azure-add-support-for-azure-proxy-agent.patch new file mode 100644 index 0000000000..02f9748658 --- /dev/null +++ b/SPECS/cloud-init/0003-feat-azure-add-support-for-azure-proxy-agent.patch @@ -0,0 +1,413 @@ +From 8932242a65bae5504ba45134091767f215a441fa Mon Sep 17 00:00:00 2001 +From: Ksenija Stanojevic +Date: Mon, 15 Jul 2024 18:48:19 -0700 +Subject: [PATCH 3/3] feat(azure): add support for azure-proxy-agent + +--- + cloudinit/sources/DataSourceAzure.py | 40 ++++ + cloudinit/sources/azure/errors.py | 19 +- + tests/unittests/sources/test_azure.py | 254 ++++++++++++++++++++++++++ + 3 files changed, 312 insertions(+), 1 deletion(-) + +diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py +index dc2b79a3a..c2f74e173 100644 +--- a/cloudinit/sources/DataSourceAzure.py ++++ b/cloudinit/sources/DataSourceAzure.py +@@ -483,6 +483,41 @@ class DataSourceAzure(sources.DataSource): + or self._ephemeral_dhcp_ctx.lease is None + ) + ++ def _check_azure_proxy_agent_status(self) -> None: ++ """Check if azure-proxy-agent is ready for communication with WS/IMDS. ++ If ProvisionGuestProxyAgent is true, query azure-proxy-agent status, ++ waiting up to 120 seconds for the proxy to negotiate with Wireserver ++ and configure an eBPF proxy. Once azure-proxy-agent is ready, ++ it will exit with code 0 and cloud-init can then expect to be able to ++ communicate with these services. ++ Fail deployment if azure-proxy-agent is not found or otherwise returns ++ an error. ++ For more information, check out: ++ https://github.com/azure/guestproxyagent ++ """ ++ try: ++ cmd = [ ++ "azure-proxy-agent", ++ "--status", ++ "--wait", ++ "120", ++ ] ++ out, err = subp.subp(cmd) ++ report_diagnostic_event( ++ "Running azure-proxy-agent %s resulted" ++ "in stderr output: %s with stdout: %s" % (cmd, err, out), ++ logger_func=LOG.debug, ++ ) ++ except subp.ProcessExecutionError as error: ++ if isinstance(error.reason, FileNotFoundError): ++ report_error = errors.ReportableErrorProxyAgentNotFound() ++ self._report_failure(report_error) ++ else: ++ reportable_error = ( ++ errors.ReportableErrorProxyAgentStatusFailure(error) ++ ) ++ self._report_failure(reportable_error) ++ + @azure_ds_telemetry_reporter + def crawl_metadata(self): + """Walk all instance metadata sources returning a dict on success. +@@ -566,6 +601,11 @@ class DataSourceAzure(sources.DataSource): + + imds_md = {} + if self._is_ephemeral_networking_up(): ++ # check if azure-proxy-agent is enabled in the ovf-env.xml file. ++ # azure-proxy-agent feature is opt-in and disabled by default. ++ if cfg.get("ProvisionGuestProxyAgent"): ++ self._check_azure_proxy_agent_status() ++ + imds_md = self.get_metadata_from_imds(report_failure=True) + + if not imds_md and ovf_source is None: +diff --git a/cloudinit/sources/azure/errors.py b/cloudinit/sources/azure/errors.py +index 966725b00..b331cd686 100644 +--- a/cloudinit/sources/azure/errors.py ++++ b/cloudinit/sources/azure/errors.py +@@ -12,7 +12,7 @@ from typing import Any, Dict, List, Optional + + import requests + +-from cloudinit import version ++from cloudinit import subp, version + from cloudinit.sources.azure import identity + from cloudinit.url_helper import UrlError + +@@ -151,3 +151,20 @@ class ReportableErrorUnhandledException(ReportableError): + + self.supporting_data["exception"] = repr(exception) + self.supporting_data["traceback_base64"] = trace_base64 ++ ++ ++class ReportableErrorProxyAgentNotFound(ReportableError): ++ def __init__(self) -> None: ++ super().__init__( ++ "Unable to activate Azure Guest Proxy Agent." ++ "azure-proxy-agent not found" ++ ) ++ ++ ++class ReportableErrorProxyAgentStatusFailure(ReportableError): ++ def __init__(self, exception: subp.ProcessExecutionError) -> None: ++ super().__init__("azure-proxy-agent status failure") ++ ++ self.supporting_data["exit_code"] = exception.exit_code ++ self.supporting_data["stdout"] = exception.stdout ++ self.supporting_data["stderr"] = exception.stderr +diff --git a/tests/unittests/sources/test_azure.py b/tests/unittests/sources/test_azure.py +index 255991ec3..9b6672e1e 100644 +--- a/tests/unittests/sources/test_azure.py ++++ b/tests/unittests/sources/test_azure.py +@@ -1,6 +1,7 @@ + # This file is part of cloud-init. See LICENSE file for license information. + + import copy ++import datetime + import json + import os + import stat +@@ -48,6 +49,16 @@ def mock_wrapping_setup_ephemeral_networking(azure_ds): + yield m + + ++@pytest.fixture ++def mock_wrapping_report_failure(azure_ds): ++ with mock.patch.object( ++ azure_ds, ++ "_report_failure", ++ wraps=azure_ds._report_failure, ++ ) as m: ++ yield m ++ ++ + @pytest.fixture + def mock_azure_helper_readurl(): + with mock.patch( +@@ -253,6 +264,14 @@ def mock_subp_subp(): + yield m + + ++@pytest.fixture ++def mock_timestamp(): ++ timestamp = datetime.datetime.utcnow() ++ with mock.patch.object(errors, "datetime", autospec=True) as m: ++ m.utcnow.return_value = timestamp ++ yield timestamp ++ ++ + @pytest.fixture + def mock_util_ensure_dir(): + with mock.patch( +@@ -3672,6 +3691,91 @@ class TestProvisioning: + } + + def test_no_pps(self): ++ ovf = construct_ovf_env(provision_guest_proxy_agent=False) ++ md, ud, cfg = dsaz.read_azure_ovf(ovf) ++ self.mock_util_mount_cb.return_value = (md, ud, cfg, {}) ++ self.mock_readurl.side_effect = [ ++ mock.MagicMock(contents=json.dumps(self.imds_md).encode()), ++ ] ++ self.mock_azure_get_metadata_from_fabric.return_value = [] ++ ++ self.azure_ds._check_and_get_data() ++ ++ assert self.mock_subp_subp.mock_calls == [] ++ ++ assert self.mock_readurl.mock_calls == [ ++ mock.call( ++ "http://169.254.169.254/metadata/instance?" ++ "api-version=2021-08-01&extended=true", ++ timeout=30, ++ headers_cb=imds.headers_cb, ++ exception_cb=mock.ANY, ++ infinite=True, ++ log_req_resp=True, ++ ), ++ ] ++ ++ # Verify DHCP is setup once. ++ assert self.mock_wrapping_setup_ephemeral_networking.mock_calls == [ ++ mock.call(timeout_minutes=20) ++ ] ++ assert self.mock_net_dhcp_maybe_perform_dhcp_discovery.mock_calls == [ ++ mock.call( ++ self.azure_ds.distro, ++ None, ++ dsaz.dhcp_log_cb, ++ ) ++ ] ++ assert self.azure_ds._wireserver_endpoint == "10.11.12.13" ++ assert self.azure_ds._is_ephemeral_networking_up() is False ++ ++ # Verify DMI usage. ++ assert self.mock_dmi_read_dmi_data.mock_calls == [ ++ mock.call("chassis-asset-tag"), ++ mock.call("system-uuid"), ++ ] ++ assert ( ++ self.azure_ds.metadata["instance-id"] ++ == "50109936-ef07-47fe-ac82-890c853f60d5" ++ ) ++ ++ # Verify IMDS metadata. ++ assert self.azure_ds.metadata["imds"] == self.imds_md ++ ++ # Verify reporting ready once. ++ assert self.mock_azure_get_metadata_from_fabric.mock_calls == [ ++ mock.call( ++ endpoint="10.11.12.13", ++ distro=self.azure_ds.distro, ++ iso_dev="/dev/sr0", ++ pubkey_info=None, ++ ) ++ ] ++ ++ # Verify netlink. ++ assert self.mock_netlink.mock_calls == [] ++ ++ # Verify no reported_ready marker written. ++ assert self.wrapped_util_write_file.mock_calls == [] ++ assert self.patched_reported_ready_marker_path.exists() is False ++ ++ # Verify reports via KVP. ++ assert len(self.mock_kvp_report_failure_to_host.mock_calls) == 0 ++ assert len(self.mock_azure_report_failure_to_fabric.mock_calls) == 0 ++ assert len(self.mock_kvp_report_success_to_host.mock_calls) == 1 ++ ++ # Verify dmesg reported via KVP. ++ assert len(self.mock_report_dmesg_to_kvp.mock_calls) == 1 ++ ++ def test_no_pps_gpa(self): ++ """test full provisioning scope when azure-proxy-agent ++ is enabled and running.""" ++ self.mock_subp_subp.side_effect = [ ++ subp.SubpResult("Guest Proxy Agent running", ""), ++ ] ++ ovf = construct_ovf_env(provision_guest_proxy_agent=True) ++ md, ud, cfg = dsaz.read_azure_ovf(ovf) ++ self.mock_util_mount_cb.return_value = (md, ud, cfg, {}) + self.mock_readurl.side_effect = [ + mock.MagicMock(contents=json.dumps(self.imds_md).encode()), + ] +@@ -3679,6 +3783,11 @@ class TestProvisioning: + + self.azure_ds._check_and_get_data() + ++ assert self.mock_subp_subp.mock_calls == [ ++ mock.call( ++ ["azure-proxy-agent", "--status", "--wait", "120"], ++ ), ++ ] + assert self.mock_readurl.mock_calls == [ + mock.call( + "http://169.254.169.254/metadata/instance?" +@@ -3736,6 +3845,93 @@ class TestProvisioning: + + # Verify reports via KVP. + assert len(self.mock_kvp_report_failure_to_host.mock_calls) == 0 ++ assert len(self.mock_azure_report_failure_to_fabric.mock_calls) == 0 ++ assert len(self.mock_kvp_report_success_to_host.mock_calls) == 1 ++ ++ def test_no_pps_gpa_fail(self): ++ """test full provisioning scope when azure-proxy-agent is enabled and ++ throwing an exception during provisioning.""" ++ self.mock_subp_subp.side_effect = [ ++ subp.ProcessExecutionError( ++ cmd=["failed", "azure-proxy-agent"], ++ stdout="test_stdout", ++ stderr="test_stderr", ++ exit_code=4, ++ ), ++ ] ++ ovf = construct_ovf_env(provision_guest_proxy_agent=True) ++ md, ud, cfg = dsaz.read_azure_ovf(ovf) ++ self.mock_util_mount_cb.return_value = (md, ud, cfg, {}) ++ self.mock_readurl.side_effect = [ ++ mock.MagicMock(contents=json.dumps(self.imds_md).encode()), ++ ] ++ self.mock_azure_get_metadata_from_fabric.return_value = [] ++ ++ self.azure_ds._check_and_get_data() ++ ++ assert self.mock_subp_subp.mock_calls == [ ++ mock.call( ++ ["azure-proxy-agent", "--status", "--wait", "120"], ++ ), ++ ] ++ assert self.mock_readurl.mock_calls == [ ++ mock.call( ++ "http://169.254.169.254/metadata/instance?" ++ "api-version=2021-08-01&extended=true", ++ timeout=30, ++ headers={"Metadata": "true"}, ++ exception_cb=mock.ANY, ++ infinite=True, ++ log_req_resp=True, ++ ), ++ ] ++ ++ # Verify DHCP is setup once. ++ assert self.mock_wrapping_setup_ephemeral_networking.mock_calls == [ ++ mock.call(timeout_minutes=20) ++ ] ++ assert self.mock_net_dhcp_maybe_perform_dhcp_discovery.mock_calls == [ ++ mock.call( ++ self.azure_ds.distro, ++ None, ++ dsaz.dhcp_log_cb, ++ ) ++ ] ++ assert self.azure_ds._wireserver_endpoint == "10.11.12.13" ++ assert self.azure_ds._is_ephemeral_networking_up() is False ++ ++ # Verify DMI usage. ++ assert self.mock_dmi_read_dmi_data.mock_calls == [ ++ mock.call("chassis-asset-tag"), ++ mock.call("system-uuid"), ++ mock.call("system-uuid"), ++ ] ++ assert ( ++ self.azure_ds.metadata["instance-id"] ++ == "50109936-ef07-47fe-ac82-890c853f60d5" ++ ) ++ ++ # Verify IMDS metadata. ++ assert self.azure_ds.metadata["imds"] == self.imds_md ++ ++ ### BACKPORT NOTE: 23.3 _will_ report ready later after failure. ++ ### In newer versions there will be no call to report ready after failure. ++ assert self.mock_azure_get_metadata_from_fabric.mock_calls == [ ++ mock.call( ++ endpoint="10.11.12.13", iso_dev="/dev/sr0", pubkey_info=None ++ ) ++ ] ++ ++ # Verify netlink. ++ assert self.mock_netlink.mock_calls == [] ++ ++ # Verify no reported_ready marker written. ++ assert self.wrapped_util_write_file.mock_calls == [] ++ assert self.patched_reported_ready_marker_path.exists() is False ++ ++ # Verify reports via KVP. ++ assert len(self.mock_kvp_report_failure_to_host.mock_calls) == 1 ++ assert len(self.mock_azure_report_failure_to_fabric.mock_calls) == 1 + assert len(self.mock_kvp_report_success_to_host.mock_calls) == 1 + + def test_running_pps(self): +@@ -4315,6 +4511,64 @@ class TestProvisioning: + assert len(self.mock_kvp_report_success_to_host.mock_calls) == 1 + + ++class TestCheckAzureProxyAgent: ++ @pytest.fixture(autouse=True) ++ def proxy_setup( ++ self, ++ azure_ds, ++ mock_subp_subp, ++ caplog, ++ mock_wrapping_report_failure, ++ mock_timestamp, ++ ): ++ self.azure_ds = azure_ds ++ self.mock_subp_subp = mock_subp_subp ++ self.caplog = caplog ++ self.mock_wrapping_report_failure = mock_wrapping_report_failure ++ self.mock_timestamp = mock_timestamp ++ ++ def test_check_azure_proxy_agent_status(self): ++ self.mock_subp_subp.side_effect = [ ++ subp.SubpResult("Guest Proxy Agent running", ""), ++ ] ++ self.azure_ds._check_azure_proxy_agent_status() ++ assert "Running azure-proxy-agent" in self.caplog.text ++ assert self.mock_wrapping_report_failure.mock_calls == [] ++ ++ def test_check_azure_proxy_agent_status_notfound(self): ++ exception = subp.ProcessExecutionError(reason=FileNotFoundError()) ++ self.mock_subp_subp.side_effect = [ ++ exception, ++ ] ++ self.azure_ds._check_azure_proxy_agent_status() ++ assert "azure-proxy-agent not found" in self.caplog.text ++ assert self.mock_wrapping_report_failure.mock_calls == [ ++ mock.call( ++ errors.ReportableErrorProxyAgentNotFound(), ++ ), ++ ] ++ ++ def test_check_azure_proxy_agent_status_failure(self): ++ exception = subp.ProcessExecutionError( ++ cmd=["failed", "azure-proxy-agent"], ++ stdout="test_stdout", ++ stderr="test_stderr", ++ exit_code=4, ++ ) ++ self.mock_subp_subp.side_effect = [ ++ exception, ++ ] ++ self.azure_ds._check_azure_proxy_agent_status() ++ assert "azure-proxy-agent status failure" in self.caplog.text ++ assert self.mock_wrapping_report_failure.mock_calls == [ ++ mock.call( ++ errors.ReportableErrorProxyAgentStatusFailure( ++ exception=exception ++ ), ++ ), ++ ] ++ ++ + class TestGetMetadataFromImds: + @pytest.mark.parametrize("report_failure", [False, True]) + @pytest.mark.parametrize( +-- +2.34.1 + diff --git a/SPECS/cloud-init/cloud-init.spec b/SPECS/cloud-init/cloud-init.spec index ffe61e76ee..5548b53ade 100644 --- a/SPECS/cloud-init/cloud-init.spec +++ b/SPECS/cloud-init/cloud-init.spec @@ -5,7 +5,7 @@ Summary: Cloud instance init scripts Name: cloud-init Epoch: 1 Version: %{package_version} -Release: 3%{?dist} +Release: 4%{?dist} License: GPLv3 Vendor: Microsoft Corporation Distribution: Mariner @@ -16,6 +16,9 @@ Source1: 10-azure-kvp.cfg Patch0: overrideDatasourceDetection.patch Patch1: exec_cmd_error_handling.patch Patch2: Add-Network-Interface-Renaming-Support-for-CAPM3-Met.patch +Patch3: 0001-feat-azure-Add-ProvisionGuestProxyAgent-OVF-setting-.patch +Patch4: 0002-feat-azure-parse-ProvisionGuestProxyAgent-as-bool-51.patch +Patch5: 0003-feat-azure-add-support-for-azure-proxy-agent.patch %define cl_services cloud-config.service cloud-config.target cloud-final.service cloud-init.service cloud-init.target cloud-init-local.service BuildRequires: automake BuildRequires: dbus @@ -151,6 +154,9 @@ make check %{?_smp_mflags} %config(noreplace) %{_sysconfdir}/cloud/cloud.cfg.d/10-azure-kvp.cfg %changelog +* Mon July 15 2024 Ksenija Stanojevic - 23.3.3-4 +- Add patches to support azure-proxy-agent. + * Wed May 8 2024 Sharath Srikanth Chellappa - 1:23.3-3 - Add patch to add network interface renaming support for CAPM3 Met.