import OL WALinuxAgent-2.13.1.1-2.0.1.el10_1.1

This commit is contained in:
eabdullin 2026-01-13 10:38:26 +00:00
parent d82710401b
commit c9f19a0bca
12 changed files with 1058 additions and 358 deletions

26
.gitignore vendored
View File

@ -1,25 +1 @@
/WALinuxAgent-b3f2619a854455675ae5f2ee14726659e0398af7.tar.gz
/WALinuxAgent-26785b64279913d416767a6288a3b3f970ed4522.tar.gz
/WALinuxAgent-30019ae2c10a5c78f55d4ec342db07366abcc602.tar.gz
/WALinuxAgent-54d4ebde1a626e6bd000abdfd518e150b0495f37.tar.gz
/WALinuxAgent-5bb9df7f2f485dbd5be057bbb657afe54bc1bf1b.tar.gz
/WALinuxAgent-2.2.25.tar.gz
/WALinuxAgent-2.2.32.tar.gz
/WALinuxAgent-2.2.37.tar.gz
/WALinuxAgent-2.2.38.tar.gz
/WALinuxAgent-2.2.40.tar.gz
/WALinuxAgent-2.2.46.tar.gz
/v2.2.48.1.tar.gz
/WALinuxAgent-2.2.52.tar.gz
/v2.2.52.tar.gz
/module-setup.sh
/v2.2.54.2.tar.gz
/v2.3.0.2.tar.gz
/v2.3.1.1.tar.gz
/v2.5.0.2.tar.gz
/v2.7.0.6.tar.gz
/v2.7.1.0.tar.gz
/v2.7.3.0.tar.gz
/v2.8.0.11.tar.gz
/v2.9.0.4.tar.gz
/v2.9.1.1.tar.gz
v2.13.1.1.tar.gz

View File

@ -1,4 +1,4 @@
From dac5101c56b59dbb14d96d4344d6cb2ac047b392 Mon Sep 17 00:00:00 2001
From 2d78c9ebaba4742390e92dc5994391949b90ec4c Mon Sep 17 00:00:00 2001
From: Chris Patterson <cpatterson@microsoft.com>
Date: Thu, 1 Sep 2022 10:45:47 -0400
Subject: [PATCH] waagent.service: set ConditionVirtualization=|microsoft
@ -10,10 +10,10 @@ test setups to add another condition (i.e. run outside of hyperv).
Signed-off-by: Chris Patterson <cpatterson@microsoft.com>
---
bin/waagent2.0 | 1 +
init/redhat/py2/waagent.service | 1 +
init/redhat/waagent.service | 1 +
init/waagent.service | 1 +
bin/waagent2.0 | 1 +
init/redhat/py2/waagent.service | 1 +
init/redhat/waagent.service | 1 +
init/waagent.service | 1 +
4 files changed, 4 insertions(+)
diff --git a/bin/waagent2.0 b/bin/waagent2.0
@ -29,7 +29,7 @@ index 34732677..c84c8c40 100644
[Service]
Type=simple
diff --git a/init/redhat/py2/waagent.service b/init/redhat/py2/waagent.service
index c6d15420..132e7027 100644
index 920e0ec7..46254ec3 100644
--- a/init/redhat/py2/waagent.service
+++ b/init/redhat/py2/waagent.service
@@ -5,6 +5,7 @@ After=network-online.target
@ -41,7 +41,7 @@ index c6d15420..132e7027 100644
[Service]
Type=simple
diff --git a/init/redhat/waagent.service b/init/redhat/waagent.service
index dc11fbb1..7c93b101 100644
index 2c6ac5d8..12d5feee 100644
--- a/init/redhat/waagent.service
+++ b/init/redhat/waagent.service
@@ -5,6 +5,7 @@ After=network-online.target
@ -64,6 +64,3 @@ index e91f1433..aa1f3203 100644
[Service]
Type=simple
--
2.37.3

View File

@ -1,4 +1,4 @@
From 896d0f1edfbfad20c2eecb04fca17e7dc335dfb8 Mon Sep 17 00:00:00 2001
From cb221e0885f794e0ec302cbb77bff927a8d4458a Mon Sep 17 00:00:00 2001
From: Ani Sinha <anisinha@redhat.com>
Date: Mon, 6 May 2024 11:50:49 +0530
Subject: [PATCH] Disable automatic log collector
@ -16,12 +16,16 @@ Jira: https://issues.redhat.com/browse/RHEL-35963
Upstream: RHEL only.
Signed-off-by: Ani Sinha <anisinha@redhat.com>
Patch-name: wla-Disable-automatic-log-collector.patch
Patch-id:
Patch-present-in-specfile: True
---
config/waagent.conf | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/config/waagent.conf b/config/waagent.conf
index 7316dc2d..4a345fc0 100644
index 3c9ad5d4..62d8148e 100644
--- a/config/waagent.conf
+++ b/config/waagent.conf
@@ -70,7 +70,7 @@ Logs.Verbose=n
@ -33,6 +37,3 @@ index 7316dc2d..4a345fc0 100644
# How frequently to collect logs, default is each hour
Logs.CollectPeriod=3600
--
2.39.3

View File

@ -1,8 +1,8 @@
From 8cc6f62bd1be39e60be6ae606ea4beb76ae24d7c Mon Sep 17 00:00:00 2001
From b0c1a1641973b0444045a4906d80e0b16ff755e7 Mon Sep 17 00:00:00 2001
From: Mohammed Gamal <mgamal@redhat.com>
Date: Fri, 29 Jul 2022 13:07:13 +0200
Subject: [PATCH 1/4] redhat: Use NetworkManager to set DHCP hostnames on
recent RHEL distros
Subject: [PATCH] redhat: Use NetworkManager to set DHCP hostnames on recent
RHEL distros
RH-Author: Ani Sinha <anisinha@redhat.com>
RH-MergeRequest: 13: sync c10s branch from c9s
@ -32,18 +32,22 @@ Patch-name: wla-redhat-Use-NetworkManager-to-set-DHCP-hostnames-on-r.patch
Patch-id:
Patch-present-in-specfile: True
(cherry picked from commit 8400a993c6c27f8f8fc598f81e2c329dc8255805)
Patch-name: wla-redhat-Use-NetworkManager-to-set-DHCP-hostnames-on-r.patch
Patch-id:
Patch-present-in-specfile: True
---
azurelinuxagent/common/osutil/redhat.py | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/azurelinuxagent/common/osutil/redhat.py b/azurelinuxagent/common/osutil/redhat.py
index 312dd160..4b46a97a 100644
index a9a10347..b85b2d42 100644
--- a/azurelinuxagent/common/osutil/redhat.py
+++ b/azurelinuxagent/common/osutil/redhat.py
@@ -164,3 +164,15 @@ class RedhatOSModernUtil(RedhatOSUtil):
time.sleep(wait)
else:
logger.warn("exceeded restart retries")
@@ -272,3 +272,15 @@ class RedhatOSModernUtil(RedhatOSUtil):
# NetworkManager restart in RedhatOSModernUtil because the issue was not reproduced on these versions.
shellutil.run("service NetworkManager restart")
DefaultOSUtil.publish_hostname(self, hostname)
+
+ def set_dhcp_hostname(self, hostname):
+ """
@ -56,6 +60,3 @@ index 312dd160..4b46a97a 100644
+
+ if return_code != 0:
+ logger.error("failed to set DHCP hostname for interface {0}: return code {1}".format(ifname, return_code))
--
2.39.3

View File

@ -1,4 +1,4 @@
From dd3a8f78ef32aed2f1267dd7dd495c65edd259a1 Mon Sep 17 00:00:00 2001
From c17811fbdb131a4cca41a847e8b666f432dbe4a8 Mon Sep 17 00:00:00 2001
From: Vitaly Kuznetsov <vkuznets@redhat.com>
Date: Mon, 6 Jan 2025 17:13:11 +0100
Subject: [PATCH] redhat: Add a udev rule to avoid managing slave NICs with
@ -18,6 +18,10 @@ eventually. For the time being, just put the required udev rule into
WALinuxAgent package.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Patch-name: wla-redhat-Add-a-udev-rule-to-avoid-managing-slave-NICs-.patch
Patch-id:
Patch-present-in-specfile: True
---
config/10-azure-unmanaged-sriov.rules | 6 ++++++
setup.py | 3 ++-
@ -37,7 +41,7 @@ index 00000000..7eefcb26
+# NM_UNMANAGED=1 for NetworkManager
+SUBSYSTEM=="net", ACTION!="remove", DRIVERS=="mana|mlx4_core|mlx5_core", ATTR{flags}=="0x?[89ABCDEF]??", ENV{AZURE_UNMANAGED_SRIOV}="1", ENV{ID_NET_MANAGED_BY}="unmanaged", ENV{NM_UNMANAGED}="1"
diff --git a/setup.py b/setup.py
index 8f5d92b4..f76aff30 100755
index e83f5989..cf6e90b5 100755
--- a/setup.py
+++ b/setup.py
@@ -82,7 +82,8 @@ def set_openbsd_rc_files(data_files, dest="/etc/rc.d/", src=None):
@ -50,6 +54,3 @@ index 8f5d92b4..f76aff30 100755
"config/99-azure-product-uuid.rules"]
data_files.append((dest, src))
--
2.39.3

View File

@ -0,0 +1,28 @@
From 246586f31209b70667b494db30c847c5b87fe7a3 Mon Sep 17 00:00:00 2001
From: Darren Archibald <darren.archibald@oracle.com>
Date: Wed, 21 Sep 2022 05:40:34 -0700
Subject: [PATCH] Add Oracle support
Add oracle support to fix waagent.service build issue
Signed-off-by: Darren Archibald <darren.archibald@oracle.com>
---
setup.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup.py b/setup.py
index e4d7cf7..82ec9fe 100755
--- a/setup.py
+++ b/setup.py
@@ -96,7 +96,7 @@
systemd_dir_path = osutil.get_systemd_unit_file_install_path()
agent_bin_path = osutil.get_agent_bin_path()
- if name in ('redhat', 'rhel', 'centos', 'almalinux', 'cloudlinux', 'rocky'):
+ if name in ('redhat', 'rhel', 'centos', 'almalinux', 'cloudlinux', 'rocky', 'oracle'):
if version.startswith("8") or version.startswith("9"):
# redhat8+ default to py3
set_bin_files(data_files, dest=agent_bin_path,
--
2.27.0

View File

@ -2,24 +2,25 @@
%global dracut_modname 97walinuxagent
Name: WALinuxAgent
Version: 2.9.1.1
Release: 9%{?dist}.1
Version: 2.13.1.1
Release: 2.0.1%{?dist}.1
Summary: The Microsoft Azure Linux Agent
License: Apache-2.0
URL: https://github.com/Azure/%{name}
Source0: https://github.com/Azure/%{name}/archive/v%{version}.tar.gz
Source1: module-setup.sh
Patch1: 0001-waagent.service-set-ConditionVirtualization-microsof.patch
# For RHEL-35963 - [Azure][WALA] Consider to disable Log collector [rhel-10]
Patch2: wla-Disable-automatic-log-collector.patch
# For RHEL-40966 - [Azure][WALA][RHEL-10] Provisioning failed if no ifcfg-eth0
Patch3: wla-redhat-Use-NetworkManager-to-set-DHCP-hostnames-on-r.patch
# For RHEL-46713 - [Azure][RHEL-10][WALA] waagent -collect-logs doesn't work and the log is confusing
Patch4: wla-skip-cgorup-monitor-2939.patch
# For RHEL-68796 - Please add `mana` to 99-azure-unmanaged-devices.conf of Azure image
Patch5: wla-redhat-Add-a-udev-rule-to-avoid-managing-slave-NICs-.patch
Patch1: 0001-waagent.service-set-ConditionVirtualization-microsof.patch
Patch2: 0002-Disable-automatic-log-collector.patch
Patch3: 0003-redhat-Use-NetworkManager-to-set-DHCP-hostnames-on-r.patch
Patch4: 0004-redhat-Add-a-udev-rule-to-avoid-managing-slave-NICs-.patch
# For RHEL-109465 - [Azure][RHEL-10][WALA][Image mode] Cannot find 'service' command
Patch5: wla-Use-systemctl-instead-of-service-to-manager-services.patch
# For RHEL-96792 - [Azure][WALA][RHEL-10] Missing man page
Patch6: wla-docs-add-waagent-manpage-3401.patch
# For RHEL-129954 - Update walagent to 2.14 to support FIPS 140-3 on Azure [rhel-10.1.z]
Patch7: wla-Jira-https-issues.redhat.com-browse-RHEL-129954.patch
Patch1000: 0100-add-oracle-support.patch
BuildArch: noarch
@ -109,6 +110,7 @@ rm -rf %{_unitdir}/waagent.service.d/
%files
%doc LICENSE.txt NOTICE README.md
%{_mandir}/man1/waagent.1.gz
%ghost %{_localstatedir}/log/waagent.log
%ghost %{_unitdir}/waagent-network-setup.service
%dir %attr(0700, root, root) %{_sharedstatedir}/waagent
@ -131,7 +133,28 @@ rm -rf %{_unitdir}/waagent.service.d/
%endif
%changelog
* Tue Mar 25 2025 Miroslav Rezanina <mrezanin@redhat.com> - 2.9.1.1-9.1
* Tue Jan 06 2026 EL Errata <el-errata_ww@oracle.com> - 2.13.1.1-2.0.1
- Add oracle support to fix waagent.service build issue
* Fri Nov 28 2025 Miroslav Rezanina <mrezanin@redhat.com> - 2.13.1.1-2.el10_1.1
- wla-Jira-https-issues.redhat.com-browse-RHEL-129954.patch [RHEL-129954]
- Resolves: RHEL-129954
(Update walagent to 2.14 to support FIPS 140-3 on Azure [rhel-10.1.z])
* Thu Aug 21 2025 Miroslav Rezanina <mrezanin@redhat.com> - 2.13.1.1-2
- wla-Use-systemctl-instead-of-service-to-manager-services.patch [RHEL-109465]
- wla-docs-add-waagent-manpage-3401.patch [RHEL-96792]
- Resolves: RHEL-109465
([Azure][RHEL-10][WALA][Image mode] Cannot find 'service' command)
- Resolves: RHEL-96792
([Azure][WALA][RHEL-10] Missing man page)
* Thu May 22 2025 Vitaly Kuznetsov <vkuznets@redhat.com> - 2.13.1.1-1
- Rebase to 2.13.1.1 [RHEL-86509]
- Resolves: RHEL-86509
(Rebase to v2.13.1.1)
* Tue Mar 25 2025 Miroslav Rezanina <mrezanin@redhat.com> - 2.9.1.1-10
- wla-redhat-Explicitly-list-udev-rule-requirements-in-the.patch [RHEL-84073]
- wla-redhat-Include-10-azure-unmanaged-sriov.rules-into-i.patch [RHEL-84073]
- Resolves: RHEL-84073

View File

@ -1 +1 @@
3f44aecc16ac545db4b550586f168dbbdef34289aad6775973517bf645e5a1d486864c01e974f03a71b3e946c14e1ca140673a75c1cd602aac28725eaa68e83d v2.9.1.1.tar.gz
SHA512 (v2.13.1.1.tar.gz) = 3cb65495955c746bf112e794cbeb11f47ace72e4272c3cd16eb8d478c0b3b0323890b52c592b68775efafb8c6f267b3614e66f09d6a6dee066b603297676cd38

View File

@ -0,0 +1,706 @@
From 0e90372ba24091860266bb0a3c33fc20e38a1a97 Mon Sep 17 00:00:00 2001
From: Norberto Arrieta <narrieta@users.noreply.github.com>
Date: Tue, 4 Mar 2025 12:55:27 -0800
Subject: [PATCH] Jira: https://issues.redhat.com/browse/RHEL-129954
RH-Author: yuxisun <None>
RH-MergeRequest: 23: Support for FIPS 140-3 (#3324)
RH-Jira: RHEL-129954
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/1] da147f85a89d1375c0f4d7e36fffd0f68b231770
Support for FIPS 140-3 (#3324)
When fetching certificates from WireServer, the Agent uses DES_EDE3_CBC. The PFX it receives has a MAC computed using PKCS12KDF. Both are deprecated on FIPS 140-3.
This PR switches to AES128_CBC for communication with the WireServer (a subsequent PR will change it to AES256_CBC) and skips MAC verification when it is not needed.
The changes also include some minor cleanup to remove data structures that are not used.
Upstream PR: https://github.com/Azure/WALinuxAgent/pull/3324
Signed-off-by: Yuxin Sun <yuxisun@redhat.com>
---
azurelinuxagent/common/event.py | 20 ++
azurelinuxagent/common/protocol/goal_state.py | 216 +++++++++++-------
azurelinuxagent/common/protocol/restapi.py | 24 --
azurelinuxagent/common/protocol/wire.py | 18 +-
azurelinuxagent/common/utils/cryptutil.py | 46 ++--
azurelinuxagent/ga/update.py | 1 +
tests/common/protocol/test_goal_state.py | 81 ++++++-
tests/common/protocol/test_hostplugin.py | 35 ++-
tests/common/protocol/test_wire.py | 8 +-
tests/ga/test_update.py | 2 +-
10 files changed, 275 insertions(+), 176 deletions(-)
diff --git a/azurelinuxagent/common/event.py b/azurelinuxagent/common/event.py
index 6b9521ca..9b8a926e 100644
--- a/azurelinuxagent/common/event.py
+++ b/azurelinuxagent/common/event.py
@@ -93,6 +93,7 @@ class WALAEventOperation:
FetchGoalState = "FetchGoalState"
Firewall = "Firewall"
GoalState = "GoalState"
+ GoalStateCertificates = "GoalStateCertificates"
GoalStateUnsupportedFeatures = "GoalStateUnsupportedFeatures"
HealthCheck = "HealthCheck"
HealthObservation = "HealthObservation"
@@ -733,6 +734,25 @@ def error(op, fmt, *args):
add_event(op=op, message=fmt.format(*args), is_success=False, log_event=False)
+class LogEvent(object):
+ """
+ Helper class that allows the use of info()/warn()/error() using a specific instance of a logger.
+ """
+ def __init__(self, logger_):
+ self._logger = logger_
+
+ def info(self, op, fmt, *args):
+ self._logger.info(fmt, *args)
+ add_event(op=op, message=fmt.format(*args), is_success=True)
+
+ def warn(self, op, fmt, *args):
+ self._logger.warn(fmt, *args)
+ add_event(op=op, message="[WARNING] " + fmt.format(*args), is_success=False, log_event=False)
+
+ def error(self, op, fmt, *args):
+ self._logger.error(fmt, *args)
+ add_event(op=op, message=fmt.format(*args), is_success=False, log_event=False)
+
def add_log_event(level, message, forced=False, reporter=__event_logger__):
"""
:param level: LoggerLevel of the log event
diff --git a/azurelinuxagent/common/protocol/goal_state.py b/azurelinuxagent/common/protocol/goal_state.py
index f94f3ae5..2556cc73 100644
--- a/azurelinuxagent/common/protocol/goal_state.py
+++ b/azurelinuxagent/common/protocol/goal_state.py
@@ -24,15 +24,14 @@ import json
from azurelinuxagent.common import conf
from azurelinuxagent.common import logger
from azurelinuxagent.common.AgentGlobals import AgentGlobals
-from azurelinuxagent.common.datacontract import set_properties
-from azurelinuxagent.common.event import add_event, WALAEventOperation
+from azurelinuxagent.common.event import add_event, WALAEventOperation, LogEvent
from azurelinuxagent.common.exception import ProtocolError, ResourceGoneError
from azurelinuxagent.common.future import ustr
from azurelinuxagent.common.protocol.extensions_goal_state_factory import ExtensionsGoalStateFactory
from azurelinuxagent.common.protocol.extensions_goal_state import VmSettingsParseError, GoalStateSource
from azurelinuxagent.common.protocol.hostplugin import VmSettingsNotSupported, VmSettingsSupportStopped
-from azurelinuxagent.common.protocol.restapi import Cert, CertList, RemoteAccessUser, RemoteAccessUsersList, ExtHandlerPackage, ExtHandlerPackageList
-from azurelinuxagent.common.utils import fileutil
+from azurelinuxagent.common.protocol.restapi import RemoteAccessUser, RemoteAccessUsersList, ExtHandlerPackage, ExtHandlerPackageList
+from azurelinuxagent.common.utils import fileutil, shellutil
from azurelinuxagent.common.utils.archive import GoalStateHistory, SHARED_CONF_FILE_NAME
from azurelinuxagent.common.utils.cryptutil import CryptUtil
from azurelinuxagent.common.utils.textutil import parse_doc, findall, find, findtext, getattrib, gettext
@@ -41,6 +40,7 @@ from azurelinuxagent.common.utils.textutil import parse_doc, findall, find, find
GOAL_STATE_URI = "http://{0}/machine/?comp=goalstate"
CERTS_FILE_NAME = "Certificates.xml"
P7M_FILE_NAME = "Certificates.p7m"
+PFX_FILE_NAME = "Certificates.pfx"
PEM_FILE_NAME = "Certificates.pem"
TRANSPORT_CERT_FILE_NAME = "TransportCert.pem"
TRANSPORT_PRV_FILE_NAME = "TransportPrivate.pem"
@@ -282,16 +282,8 @@ class GoalState(object):
self._check_and_download_missing_certs_on_disk()
def _download_certificates(self, certs_uri):
- 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
- for c in certs.summary:
- message = "Downloaded certificate {0}".format(c)
- self.logger.info(message)
- add_event(op=WALAEventOperation.GoalState, message=message)
- if len(certs.warnings) > 0:
- self.logger.warn(certs.warnings)
- add_event(op=WALAEventOperation.GoalState, message=certs.warnings)
+ certs = Certificates(self._wire_client, certs_uri, self.logger)
+ # Save the certificates summary (i.e. the thumbprints but not the certificates themselves) to the goal state history
if self._save_to_history:
self._history.save_certificates(json.dumps(certs.summary))
return certs
@@ -511,31 +503,83 @@ class SharedConfig(object):
self.xml_text = xml_text
-class Certificates(object):
- def __init__(self, xml_text, my_logger):
- self.cert_list = CertList()
- self.summary = [] # debugging info
- self.warnings = []
+class Certificates(LogEvent):
+ def __init__(self, wire_client, uri, logger_):
+ super(Certificates, self).__init__(logger_)
+ self.summary = []
+ self._crypt_util = CryptUtil(conf.get_openssl_cmd())
- # Save the certificates
- local_file = os.path.join(conf.get_lib_dir(), CERTS_FILE_NAME)
- fileutil.write_file(local_file, xml_text)
+ try:
+ pfx_file = self._download_certificates_pfx(wire_client, uri)
+ if pfx_file is None: # The response from the WireServer may not have any certificates
+ return
- # Separate the certificates into individual files.
- xml_doc = parse_doc(xml_text)
- data = findtext(xml_doc, "Data")
- if data is None:
- return
+ try:
+ pem_file = self._convert_certificates_pfx_to_pem(pfx_file)
+ finally:
+ self._remove_file(pfx_file)
- # if the certificates format is not Pkcs7BlobWithPfxContents do not parse it
- certificate_format = findtext(xml_doc, "Format")
- if certificate_format and certificate_format != "Pkcs7BlobWithPfxContents":
- message = "The Format is not Pkcs7BlobWithPfxContents. Format is {0}".format(certificate_format)
- my_logger.warn(message)
- add_event(op=WALAEventOperation.GoalState, message=message)
- return
+ self.summary = self._extract_certificate(pem_file)
+
+ for c in self.summary:
+ self.info(WALAEventOperation.GoalStateCertificates, "Downloaded certificate {0}", c)
+
+ except Exception as e:
+ self.error(WALAEventOperation.GoalStateCertificates, "Error fetching the goal state certificates: {0}", ustr(e))
+
+ def _remove_file(self, file):
+ if os.path.exists(file):
+ try:
+ os.remove(file)
+ except Exception as e:
+ self.warn(WALAEventOperation.GoalStateCertificates, "Failed to remove {0}: {1}", file, ustr(e))
+
+ def _download_certificates_pfx(self, wire_client, uri):
+ """
+ Downloads the certificates from the WireServer and saves them to a pfx file.
+ Returns the full path of the pfx file, or None, if the WireServer response does not have a "Data" element
+ """
+ trans_prv_file = os.path.join(conf.get_lib_dir(), TRANSPORT_PRV_FILE_NAME)
+ trans_cert_file = os.path.join(conf.get_lib_dir(), TRANSPORT_CERT_FILE_NAME)
+ xml_file = os.path.join(conf.get_lib_dir(), CERTS_FILE_NAME)
+ pfx_file = os.path.join(conf.get_lib_dir(), PFX_FILE_NAME)
+
+ for cypher in ["AES128_CBC", "DES_EDE3_CBC"]:
+ headers = wire_client.get_headers_for_encrypted_request(cypher)
+
+ try:
+ xml_text = wire_client.fetch_config(uri, headers)
+ except Exception as e:
+ self.warn(WALAEventOperation.GoalStateCertificates, "Error in Certificates request [cypher: {0}]: {1}", cypher, ustr(e))
+ continue
- cryptutil = CryptUtil(conf.get_openssl_cmd())
+ fileutil.write_file(xml_file, xml_text)
+
+ xml_doc = parse_doc(xml_text)
+ data = findtext(xml_doc, "Data")
+ if data is None:
+ self.info(WALAEventOperation.GoalStateCertificates, "The Data element of the Certificates response is empty")
+ return None
+ certificate_format = findtext(xml_doc, "Format")
+ if certificate_format and certificate_format != "Pkcs7BlobWithPfxContents":
+ self.warn(WALAEventOperation.GoalStateCertificates, "The Certificates format is not Pkcs7BlobWithPfxContents; skipping. Format is {0}", certificate_format)
+ return None
+
+ p7m_file = Certificates._create_p7m_file(data)
+
+ try:
+ self._crypt_util.decrypt_certificates_p7m(p7m_file, trans_prv_file, trans_cert_file, pfx_file)
+ except shellutil.CommandError as e:
+ self.warn(WALAEventOperation.GoalState, "Error in transport decryption [cypher: {0}]: {1}", cypher, ustr(e))
+ self._remove_file(pfx_file)
+ continue
+
+ return pfx_file
+
+ raise Exception("Cannot download certificates using any of the supported cyphers")
+
+ @staticmethod
+ def _create_p7m_file(data):
p7m_file = os.path.join(conf.get_lib_dir(), P7M_FILE_NAME)
p7m = ("MIME-Version:1.0\n" # pylint: disable=W1308
"Content-Disposition: attachment; filename=\"{0}\"\n"
@@ -543,68 +587,72 @@ class Certificates(object):
"Content-Transfer-Encoding: base64\n"
"\n"
"{2}").format(p7m_file, p7m_file, data)
-
fileutil.write_file(p7m_file, p7m)
+ return p7m_file
- trans_prv_file = os.path.join(conf.get_lib_dir(), TRANSPORT_PRV_FILE_NAME)
- trans_cert_file = os.path.join(conf.get_lib_dir(), TRANSPORT_CERT_FILE_NAME)
+ def _convert_certificates_pfx_to_pem(self, pfx_file):
+ """
+ Convert the pfx file to pem file.
+ """
pem_file = os.path.join(conf.get_lib_dir(), PEM_FILE_NAME)
- # decrypt certificates
- cryptutil.decrypt_p7m(p7m_file, trans_prv_file, trans_cert_file, pem_file)
+ for nomacver in [True, False]:
+ try:
+ self._crypt_util.convert_pfx_to_pem(pfx_file, nomacver, pem_file)
+ return pem_file
+ except shellutil.CommandError as e:
+ self._remove_file(pem_file) # An error may leave an empty pem file, which can produce a failure on some versions of open SSL (e.g. 3.2.2) on the next invocation
+ self.warn(WALAEventOperation.GoalState, "Error converting PFX to PEM [-nomacver: {0}]: {1}", nomacver, ustr(e))
+ continue
+
+ raise Exception("Cannot convert PFX to PEM")
+
+ def _extract_certificate(self, pem_file):
+ """
+ Parse the certificates and private keys from the pem file and store them in the certificates directory.
+ """
# The parsing process use public key to match prv and crt.
- buf = []
- prvs = {}
- thumbprints = {}
+ private_keys = {} # map of private keys indexed by public key
+ thumbprints = {} # map of thumbprints indexed by public key
+ buffer = [] # buffer for reading lines belonging to a certificate or private key
index = 0
- v1_cert_list = []
-
- # Ensure pem_file exists before read the certs data since decrypt_p7m may clear the pem_file wen decryption fails
- if os.path.exists(pem_file):
- with open(pem_file) as pem:
- for line in pem.readlines():
- buf.append(line)
- if re.match(r'[-]+END.*KEY[-]+', line):
- tmp_file = Certificates._write_to_tmp_file(index, 'prv', buf)
- pub = cryptutil.get_pubkey_from_prv(tmp_file)
- prvs[pub] = tmp_file
- buf = []
- index += 1
- elif re.match(r'[-]+END.*CERTIFICATE[-]+', line):
- tmp_file = Certificates._write_to_tmp_file(index, 'crt', buf)
- pub = cryptutil.get_pubkey_from_crt(tmp_file)
- thumbprint = cryptutil.get_thumbprint_from_crt(tmp_file)
- thumbprints[pub] = thumbprint
- # Rename crt with thumbprint as the file name
- crt = "{0}.crt".format(thumbprint)
- v1_cert_list.append({
- "name": None,
- "thumbprint": thumbprint
- })
- os.rename(tmp_file, os.path.join(conf.get_lib_dir(), crt))
- buf = []
- index += 1
+
+ with open(pem_file) as pem:
+ for line in pem.readlines():
+ buffer.append(line)
+ if re.match(r'[-]+END.*KEY[-]+', line):
+ tmp_file = Certificates._write_to_tmp_file(index, 'prv', buffer)
+ pub = self._crypt_util.get_pubkey_from_prv(tmp_file)
+ private_keys[pub] = tmp_file
+ buffer = []
+ index += 1
+ elif re.match(r'[-]+END.*CERTIFICATE[-]+', line):
+ tmp_file = Certificates._write_to_tmp_file(index, 'crt', buffer)
+ pub = self._crypt_util.get_pubkey_from_crt(tmp_file)
+ thumbprint = self._crypt_util.get_thumbprint_from_crt(tmp_file)
+ thumbprints[pub] = thumbprint
+ # Rename crt with thumbprint as the file name
+ crt = "{0}.crt".format(thumbprint)
+ os.rename(tmp_file, os.path.join(conf.get_lib_dir(), crt))
+ buffer = []
+ index += 1
# Rename prv key with thumbprint as the file name
- for pubkey in prvs:
+ for pubkey in private_keys:
thumbprint = thumbprints[pubkey]
if thumbprint:
- tmp_file = prvs[pubkey]
+ tmp_file = private_keys[pubkey]
prv = "{0}.prv".format(thumbprint)
os.rename(tmp_file, os.path.join(conf.get_lib_dir(), prv))
else:
- # Since private key has *no* matching certificate,
- # it will not be named correctly
- self.warnings.append("Found NO matching cert/thumbprint for private key!")
+ # Since private key has *no* matching certificate, it will not be named correctly
+ self.warn(WALAEventOperation.GoalState, "Found a private key with no matching cert/thumbprint!")
+ certificates = []
for pubkey, thumbprint in thumbprints.items():
- has_private_key = pubkey in prvs
- self.summary.append({"thumbprint": thumbprint, "hasPrivateKey": has_private_key})
-
- for v1_cert in v1_cert_list:
- cert = Cert()
- set_properties("certs", cert, v1_cert)
- self.cert_list.certificates.append(cert)
+ has_private_key = pubkey in private_keys
+ certificates.append({"thumbprint": thumbprint, "hasPrivateKey": has_private_key})
+ return certificates
@staticmethod
def _write_to_tmp_file(index, suffix, buf):
@@ -614,9 +662,7 @@ class Certificates(object):
class EmptyCertificates:
def __init__(self):
- self.cert_list = CertList()
- self.summary = [] # debugging info
- self.warnings = []
+ self.summary = []
class RemoteAccess(object):
"""
diff --git a/azurelinuxagent/common/protocol/restapi.py b/azurelinuxagent/common/protocol/restapi.py
index 54e020c1..7e563b4a 100644
--- a/azurelinuxagent/common/protocol/restapi.py
+++ b/azurelinuxagent/common/protocol/restapi.py
@@ -43,30 +43,6 @@ class VMInfo(DataContract):
self.tenantName = tenantName
-class CertificateData(DataContract):
- def __init__(self, certificateData=None):
- self.certificateData = certificateData
-
-
-class Cert(DataContract):
- def __init__(self,
- name=None,
- thumbprint=None,
- certificateDataUri=None,
- storeName=None,
- storeLocation=None):
- self.name = name
- self.thumbprint = thumbprint
- self.certificateDataUri = certificateDataUri
- self.storeLocation = storeLocation
- self.storeName = storeName
-
-
-class CertList(DataContract):
- def __init__(self):
- self.certificates = DataContractList(Cert)
-
-
class VMAgentFamily(object):
def __init__(self, name):
self.name = name
diff --git a/azurelinuxagent/common/protocol/wire.py b/azurelinuxagent/common/protocol/wire.py
index 00a01f09..0277b7f0 100644
--- a/azurelinuxagent/common/protocol/wire.py
+++ b/azurelinuxagent/common/protocol/wire.py
@@ -115,8 +115,7 @@ class WireProtocol(DataContract):
return vminfo
def get_certs(self):
- certificates = self.client.get_certs()
- return certificates.cert_list
+ return self.client.get_certs()
def get_goal_state(self):
return self.client.get_goal_state()
@@ -1140,13 +1139,11 @@ class WireClient(object):
"Content-Type": "text/xml;charset=utf-8"
}
- def get_header_for_cert(self):
- return self._get_header_for_encrypted_request("DES_EDE3_CBC")
-
def get_header_for_remote_access(self):
- return self._get_header_for_encrypted_request("AES128_CBC")
+ return self.get_headers_for_encrypted_request("AES128_CBC")
- def _get_header_for_encrypted_request(self, cypher):
+ @staticmethod
+ def get_headers_for_encrypted_request(cypher):
trans_cert_file = os.path.join(conf.get_lib_dir(), TRANSPORT_CERT_FILE_NAME)
try:
content = fileutil.read_file(trans_cert_file)
@@ -1154,12 +1151,15 @@ class WireClient(object):
raise ProtocolError("Failed to read {0}: {1}".format(trans_cert_file, e))
cert = get_bytes_from_pem(content)
- return {
+ headers = {
"x-ms-agent-name": "WALinuxAgent",
"x-ms-version": PROTOCOL_VERSION,
- "x-ms-cipher-name": cypher,
"x-ms-guest-agent-public-x509-cert": cert
}
+ if cypher is not None: # the cypher header is optional, currently defaults to AES128_CBC
+ headers["x-ms-cipher-name"] = cypher
+
+ return headers
def get_host_plugin(self):
if self._host_plugin is None:
diff --git a/azurelinuxagent/common/utils/cryptutil.py b/azurelinuxagent/common/utils/cryptutil.py
index 00126e25..789a9486 100644
--- a/azurelinuxagent/common/utils/cryptutil.py
+++ b/azurelinuxagent/common/utils/cryptutil.py
@@ -86,36 +86,22 @@ class CryptUtil(object):
thumbprint = thumbprint.rstrip().split('=')[1].replace(':', '').upper()
return thumbprint
- def decrypt_p7m(self, p7m_file, trans_prv_file, trans_cert_file, pem_file):
-
- def _cleanup_files(files_to_cleanup):
- for file_path in files_to_cleanup:
- if os.path.exists(file_path):
- try:
- os.remove(file_path)
- logger.info("Removed file {0}", file_path)
- except Exception as e:
- logger.error("Failed to remove file {0}: {1}", file_path, ustr(e))
-
- if not os.path.exists(p7m_file):
- raise IOError(errno.ENOENT, "File not found", p7m_file)
- elif not os.path.exists(trans_prv_file):
- raise IOError(errno.ENOENT, "File not found", trans_prv_file)
- else:
- try:
- shellutil.run_pipe([
- [self.openssl_cmd, "cms", "-decrypt", "-in", p7m_file, "-inkey", trans_prv_file, "-recip", trans_cert_file],
- [self.openssl_cmd, "pkcs12", "-nodes", "-password", "pass:", "-out", pem_file]])
- except shellutil.CommandError as command_error:
- logger.error("Failed to decrypt {0} (return code: {1})\n[stdout]\n{2}\n[stderr]\n{3}",
- p7m_file, command_error.returncode, command_error.stdout, command_error.stderr)
- # If the decryption fails, old version of openssl overwrite the output file(if exist) with empty data while
- # new version of openssl(3.2.2) does not overwrite the output file, So output file may contain old certs data.
- # Correcting the behavior by removing the temporary output files since having empty/no data is makes sense when decryption fails
- # otherwise we end up processing old certs again.
- files_to_remove = [p7m_file, pem_file]
- logger.info("Removing temporary state certificate files {0}", files_to_remove)
- _cleanup_files(files_to_remove)
+ def decrypt_certificates_p7m(self, p7m_file, trans_prv_file, trans_cert_file, pfx_file):
+ umask = None
+ try:
+ umask = os.umask(0o077)
+ with open(pfx_file, "wb") as pfx_file_:
+ shellutil.run_command([self.openssl_cmd, "cms", "-decrypt", "-in", p7m_file, "-inkey", trans_prv_file, "-recip", trans_cert_file], stdout=pfx_file_)
+ finally:
+ if umask is not None:
+ os.umask(umask)
+
+ def convert_pfx_to_pem(self, pfx_file, nomacver, pem_file):
+ command = [self.openssl_cmd, "pkcs12", "-nodes", "-password", "pass:", "-in", pfx_file, "-out", pem_file]
+ if nomacver:
+ command.append("-nomacver")
+
+ shellutil.run_command(command)
def crt_to_ssh(self, input_file, output_file):
with open(output_file, "ab") as file_out:
diff --git a/azurelinuxagent/ga/update.py b/azurelinuxagent/ga/update.py
index 7ab19101..f806ff26 100644
--- a/azurelinuxagent/ga/update.py
+++ b/azurelinuxagent/ga/update.py
@@ -85,6 +85,7 @@ READONLY_FILE_GLOBS = [
"*.p7m",
"*.pem",
"*.prv",
+ "Certificates.xml",
"ovf-env.xml"
]
diff --git a/tests/common/protocol/test_goal_state.py b/tests/common/protocol/test_goal_state.py
index a5f89587..9b70ce05 100644
--- a/tests/common/protocol/test_goal_state.py
+++ b/tests/common/protocol/test_goal_state.py
@@ -6,6 +6,7 @@ import datetime
import glob
import os
import re
+import subprocess
import shutil
import time
@@ -492,9 +493,85 @@ class GoalStateTestCase(AgentTestCase, HttpRequestPredicates):
goal_state = GoalState(protocol.client)
- self.assertEqual(0, len(goal_state.certs.summary), "Cert list should be empty")
- self.assertEqual(1, http_get_handler.certificate_requests, "There should have been exactly 1 requests for the goal state certificates")
+ self.assertEqual(0, len(goal_state.certs.summary), "Certificates should be empty")
+ self.assertEqual(2, http_get_handler.certificate_requests, "There should have been exactly 2 requests for the goal state certificates") # 1 for the initial request, 1 for the retry with an older cypher
+ def test_goal_state_should_try_legacy_cypher_and_then_fail_when_no_cyphers_are_supported_by_the_wireserver(self):
+ cyphers = []
+ def http_get_handler(url, *_, **kwargs):
+ if HttpRequestPredicates.is_certificates_request(url):
+ cypher = kwargs["headers"].get("x-ms-cipher-name")
+ if cypher is None:
+ raise Exception("x-ms-cipher-name header is missing from the Certificates request")
+ cyphers.append(cypher)
+ return MockHttpResponse(status=400, body="unsupported cypher: {0}".format(cypher).encode('utf-8'))
+ return None
+
+ with mock_wire_protocol(wire_protocol_data.DATA_FILE) as protocol:
+ with patch("azurelinuxagent.common.event.LogEvent.error") as log_error_patch:
+ protocol.set_http_handlers(http_get_handler=http_get_handler)
+ goal_state = GoalState(protocol.client)
+
+ log_error_args, _ = log_error_patch.call_args
+
+ self.assertEqual(cyphers, ["AES128_CBC", "DES_EDE3_CBC"], "There should have been 2 requests for the goal state certificates (AES128_CBC and DES_EDE3_CBC)")
+ self.assertEqual(log_error_args[0], "GoalStateCertificates", "An error fetching the goal state Certificates should have been reported")
+ self.assertEqual(0, len(goal_state.certs.summary), "Certificates should be empty")
+ self.assertFalse(os.path.exists(os.path.join(conf.get_lib_dir(), "Certificates.pfx")), "The Certificates.pfx file should not have been created")
+
+ def test_goal_state_should_try_legacy_cypher_and_then_fail_when_no_cyphers_are_supported_by_openssl(self):
+ cyphers = []
+ def http_get_handler(url, *_, **kwargs):
+ if HttpRequestPredicates.is_certificates_request(url):
+ cyphers.append(kwargs["headers"].get("x-ms-cipher-name"))
+ return None
+
+ original_popen = subprocess.Popen
+ openssl = conf.get_openssl_cmd()
+ decrypt_calls = []
+ def mock_fail_popen(command, *args, **kwargs):
+ if len(command) > 3 and command[0:3] == [openssl, "cms", "-decrypt"]:
+ decrypt_calls.append(command)
+ command[1] = "fake_openssl_command" # force an error on the openssl to simulate a decryption failure
+ return original_popen(command, *args, **kwargs)
+
+ with mock_wire_protocol(wire_protocol_data.DATA_FILE) as protocol:
+ protocol.set_http_handlers(http_get_handler=http_get_handler)
+ with patch("azurelinuxagent.common.event.LogEvent.error") as log_error_patch:
+ with patch("azurelinuxagent.ga.cgroupapi.subprocess.Popen", mock_fail_popen):
+ goal_state = GoalState(protocol.client)
+
+ log_error_args, _ = log_error_patch.call_args
+
+ self.assertEqual(cyphers, ["AES128_CBC", "DES_EDE3_CBC"], "There should have been 2 requests for the goal state certificates (AES128_CBC and DES_EDE3_CBC)")
+ self.assertEqual(2, len(decrypt_calls), "There should have been 2 calls to 'openssl cms -decrypt'")
+ self.assertEqual(log_error_args[0], "GoalStateCertificates", "An error fetching the goal state Certificates should have been reported")
+ self.assertEqual(0, len(goal_state.certs.summary), "Certificates should be empty")
+ self.assertFalse(os.path.exists(os.path.join(conf.get_lib_dir(), "Certificates.pfx")), "The Certificates.pfx file should not have been created")
+
+ def test_goal_state_should_try_without_and_with_mac_verification_then_fail_when_the_pfx_cannot_be_converted(self):
+ original_popen = subprocess.Popen
+ openssl = conf.get_openssl_cmd()
+ nomacver = []
+
+ def mock_fail_popen(command, *args, **kwargs):
+ if len(command) > 2 and command[0] == openssl and command[1] == "pkcs12":
+ nomacver.append("-nomacver" in command)
+ # force an error on the openssl to simulate the conversion failure
+ command[1] = "fake_openssl_command"
+ return original_popen(command, *args, **kwargs)
+
+
+ with mock_wire_protocol(wire_protocol_data.DATA_FILE) as protocol:
+ with patch("azurelinuxagent.common.event.LogEvent.error") as log_error_patch:
+ with patch("azurelinuxagent.ga.cgroupapi.subprocess.Popen", mock_fail_popen):
+ goal_state = GoalState(protocol.client)
+
+ log_error_args, _ = log_error_patch.call_args
+
+ self.assertEqual(nomacver, [True, False], "There should have been 2 attempts to parse the PFX (with and without -nomacver)")
+ self.assertEqual(log_error_args[0], "GoalStateCertificates", "An error fetching the goal state Certificates should have been reported")
+ self.assertEqual(0, len(goal_state.certs.summary), "Certificates should be empty")
def test_it_should_raise_when_goal_state_properties_not_initialized(self):
with GoalStateTestCase._create_protocol_ws_and_hgap_in_sync() as protocol:
diff --git a/tests/common/protocol/test_hostplugin.py b/tests/common/protocol/test_hostplugin.py
index 4c97c73f..7d94139b 100644
--- a/tests/common/protocol/test_hostplugin.py
+++ b/tests/common/protocol/test_hostplugin.py
@@ -365,8 +365,7 @@ class TestHostPlugin(HttpRequestPredicates, AgentTestCase):
# ensure host plugin is not set as default
self.assertFalse(wire.HostPluginProtocol.is_default_channel)
- @patch("azurelinuxagent.common.event.add_event")
- def test_put_status_error_reporting(self, patch_add_event):
+ def test_put_status_error_reporting(self):
"""
Validate the telemetry when uploading status fails
"""
@@ -377,22 +376,22 @@ class TestHostPlugin(HttpRequestPredicates, AgentTestCase):
put_error = wire.HttpError("put status http error")
with patch.object(restutil, "http_put", side_effect=put_error):
- with patch.object(wire.HostPluginProtocol,
- "ensure_initialized", return_value=True):
- self.assertRaises(wire.ProtocolError, wire_protocol_client.upload_status_blob)
-
- # The agent tries to upload via HostPlugin and that fails due to
- # http_put having a side effect of "put_error"
- #
- # The agent tries to upload using a direct connection, and that succeeds.
- self.assertEqual(1, wire_protocol_client.status_blob.upload.call_count) # pylint: disable=no-member
- # The agent never touches the default protocol is this code path, so no change.
- self.assertFalse(wire.HostPluginProtocol.is_default_channel)
- # The agent never logs telemetry event for direct fallback
- self.assertEqual(1, patch_add_event.call_count)
- self.assertEqual('ReportStatus', patch_add_event.call_args[1]['op'])
- self.assertTrue('Falling back to direct' in patch_add_event.call_args[1]['message'])
- self.assertEqual(True, patch_add_event.call_args[1]['is_success'])
+ with patch.object(wire.HostPluginProtocol, "ensure_initialized", return_value=True):
+ with patch("azurelinuxagent.common.event.add_event") as patch_add_event:
+ self.assertRaises(wire.ProtocolError, wire_protocol_client.upload_status_blob)
+
+ # The agent tries to upload via HostPlugin and that fails due to
+ # http_put having a side effect of "put_error"
+ #
+ # The agent tries to upload using a direct connection, and that succeeds.
+ self.assertEqual(1, wire_protocol_client.status_blob.upload.call_count) # pylint: disable=no-member
+ # The agent never touches the default protocol is this code path, so no change.
+ self.assertFalse(wire.HostPluginProtocol.is_default_channel)
+ # The agent never logs telemetry event for direct fallback
+ self.assertEqual(1, patch_add_event.call_count)
+ self.assertEqual('ReportStatus', patch_add_event.call_args[1]['op'])
+ self.assertTrue('Falling back to direct' in patch_add_event.call_args[1]['message'])
+ self.assertEqual(True, patch_add_event.call_args[1]['is_success'])
def test_validate_http_request_when_uploading_status(self):
"""Validate correct set of data is sent to HostGAPlugin when reporting VM status"""
diff --git a/tests/common/protocol/test_wire.py b/tests/common/protocol/test_wire.py
index c3dc9461..bec4634f 100644
--- a/tests/common/protocol/test_wire.py
+++ b/tests/common/protocol/test_wire.py
@@ -497,12 +497,6 @@ class TestWireProtocol(AgentTestCase, HttpRequestPredicates):
client.report_event(self._get_telemetry_events_generator(event_list), flush=True)
self.assertEqual(mock_http_request.call_count, 3)
- def test_get_header_for_cert_should_use_triple_des(self, *_):
- with mock_wire_protocol(wire_protocol_data.DATA_FILE) as protocol:
- headers = protocol.client.get_header_for_cert()
- self.assertIn("x-ms-cipher-name", headers)
- self.assertEqual(headers["x-ms-cipher-name"], "DES_EDE3_CBC", "Unexpected x-ms-cipher-name")
-
def test_get_header_for_remote_access_should_use_aes128(self, *_):
with mock_wire_protocol(wire_protocol_data.DATA_FILE) as protocol:
headers = protocol.client.get_header_for_remote_access()
@@ -1096,7 +1090,7 @@ class UpdateGoalStateTestCase(HttpRequestPredicates, AgentTestCase):
self.assertEqual(protocol.client.get_hosting_env().deployment_name, new_hosting_env_deployment_name)
self.assertEqual(protocol.client.get_shared_conf().xml_text, new_shared_conf)
self.assertEqual(sequence_number, new_sequence_number)
- self.assertEqual(len(protocol.client.get_certs().cert_list.certificates), 0)
+ self.assertEqual(len(protocol.client.get_certs().summary), 0)
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)
diff --git a/tests/ga/test_update.py b/tests/ga/test_update.py
index 167e69dc..376e9fc0 100644
--- a/tests/ga/test_update.py
+++ b/tests/ga/test_update.py
@@ -2059,7 +2059,7 @@ class TryUpdateGoalStateTestCase(HttpRequestPredicates, AgentTestCase):
# Double check the certificates are correct
goal_state = protocol.get_goal_state()
- thumbprints = [c.thumbprint for c in goal_state.certs.cert_list.certificates]
+ thumbprints = [c["thumbprint"] for c in goal_state.certs.summary]
for extension in goal_state.extensions_goal_state.extensions:
for settings in extension.settings:
--
2.47.3

View File

@ -0,0 +1,54 @@
From 93376d3c37882f246c51843ff1b327600f074f81 Mon Sep 17 00:00:00 2001
From: Yuxin Sun <yuxisun@redhat.com>
Date: Fri, 27 Jun 2025 01:34:20 +0800
Subject: [PATCH 1/2] Use systemctl instead of service to manager services in
new RHEL versions (#3403)
RH-Author: yuxisun <None>
RH-MergeRequest: 20: Use systemctl instead of service to manager services in new RHEL versions (#3403)
RH-Jira: RHEL-109465
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Commit: [1/1] 95bb66dad7fda08c89a88ca347e55ec18f75d8e8 (yuxisun/WALinuxAgent-src)
Signed-off-by: Yuxin Sun <yuxisun@redhat.com>
(cherry picked from commit a6cfdfdc3e04884a08cd6dd20fa035b687943fe9)
---
azurelinuxagent/common/osutil/redhat.py | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/azurelinuxagent/common/osutil/redhat.py b/azurelinuxagent/common/osutil/redhat.py
index b85b2d42..cf2d2f78 100644
--- a/azurelinuxagent/common/osutil/redhat.py
+++ b/azurelinuxagent/common/osutil/redhat.py
@@ -245,6 +245,18 @@ class RedhatOSModernUtil(RedhatOSUtil):
def __init__(self): # pylint: disable=W0235
super(RedhatOSModernUtil, self).__init__()
+ def restart_ssh_service(self):
+ return shellutil.run("systemctl condrestart sshd", chk_err=False)
+
+ def stop_agent_service(self):
+ return shellutil.run("systemctl stop {0}".format(self.service_name), chk_err=False)
+
+ def start_agent_service(self):
+ return shellutil.run("systemctl start {0}".format(self.service_name), chk_err=False)
+
+ def restart_network_manager(self):
+ shellutil.run("systemctl restart NetworkManager")
+
def restart_if(self, ifname, retries=3, wait=5):
"""
Restart an interface by bouncing the link. systemd-networkd observes
@@ -270,7 +282,7 @@ class RedhatOSModernUtil(RedhatOSUtil):
# RedhatOSUtil was updated to conditionally run NetworkManager restart in response to a race condition between
# NetworkManager restart and the agent restarting the network interface during publish_hostname. Keeping the
# NetworkManager restart in RedhatOSModernUtil because the issue was not reproduced on these versions.
- shellutil.run("service NetworkManager restart")
+ self.restart_network_manager()
DefaultOSUtil.publish_hostname(self, hostname)
def set_dhcp_hostname(self, hostname):
--
2.39.3

View File

@ -0,0 +1,201 @@
From 079c5ced40fe1a9153af56d86a2094060ee9aa3e Mon Sep 17 00:00:00 2001
From: Li Tian <94442129+litian1992@users.noreply.github.com>
Date: Tue, 5 Aug 2025 03:18:10 +0800
Subject: [PATCH 2/2] docs: add waagent manpage (#3401)
RH-Author: Li Tian <None>
RH-MergeRequest: 21: redhat: docs: add waagent manpage (RHEL-10) (#3401)
RH-Jira: RHEL-96792
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/1] 7084e622fbea114a2bf70f5125a40f4ab26415a5 (litian1/WALinuxAgent)
* docs: add waagent manpage
Add also man page handler in setup.py
---------
Signed-off-by: Li Tian <litian@redhat.com>
Co-authored-by: maddieford <93676569+maddieford@users.noreply.github.com>
(cherry picked from commit 7f9b5568b6572745b7d0776de0ff6fb70a28dba0)
Signed-off-by: Li Tian <litian@redhat.com>
---
.distro/WALinuxAgent.spec | 1 +
doc/man/waagent.1 | 117 ++++++++++++++++++++++++++++++++++++++
setup.py | 14 +++++
3 files changed, 132 insertions(+)
create mode 100644 doc/man/waagent.1
diff --git a/doc/man/waagent.1 b/doc/man/waagent.1
new file mode 100644
index 00000000..b1d8e9eb
--- /dev/null
+++ b/doc/man/waagent.1
@@ -0,0 +1,117 @@
+.TH WAAGENT 1 "June 2025" "Azure Linux Agent" "System Administration"
+.SH NAME
+waagent \- Azure Linux VM Agent
+.SH SYNOPSIS
+.B waagent
+[-verbose] [-force] [-help] [\fISUBCOMMAND\fR]...
+
+.SH DESCRIPTION
+The Azure Linux Agent (waagent) manages virtual machine interaction with the Azure fabric controller.
+
+Most subcommands are not meant to be run directly by the user. However, some subcommands may be useful for debugging (such as collect-logs, version, and show-configuration) and deprovisioning.
+
+.SH SUBCOMMANDS
+.TP
+\fB-collect-logs\fR
+Runs the log collector utility that collects relevant agent logs for debugging and stores them in the agent folder on disk. Exact location will be shown when run. Use flag \fB-full\fR for more exhaustive log collection.
+
+.TP
+\fB-configuration-path FILE\fR
+Used together with \fB-start\fR or \fB-daemon\fR to specify configuration file. Default to /etc/waagent.conf.
+
+.TP
+\fB-daemon -start\fR
+Run waagent as a daemon in background.
+
+.TP
+\fB-deprovision\fR
+Attempt to clean the system and make it suitable for re-provisioning. WARNING: Deprovision does not guarantee that the image is cleared of all sensitive information and suitable for redistribution.
+
+.TP
+\fB-deprovision+user\fR
+Same as \fB-deprovision\fR, but also removes the last provisioned user account.
+
+.TP
+\fB-register-service\fR
+Register waagent as a service and enable it.
+
+.TP
+\fB-run-exthandlers\fR
+Run check for updates to waagent and extension handler. Note that outputs to /dev/console will be temporarily suspended.
+
+.TP
+\fB-setup-firewall=IP\fR
+Set up firewall rules for endpoint \fBIP\fR.
+
+.TP
+\fB-show-configuration\fR
+Print the current configuration, including values read from waagent.conf.
+
+.TP
+\fB-help\fR
+Display usage information.
+
+.TP
+\fB-version\fR
+Show the current version of the agent.
+
+.SH CONFIGURATION
+The agent is configured via this file by default:
+
+.B /etc/waagent.conf
+
+This file contains key=value settings that control agent behavior, including provisioning, disk formatting, resource limits, and certificate handling.
+
+Example entries:
+.RS
+Provisioning.Enabled=y
+ResourceDisk.Format=y
+ResourceDisk.MountPoint=/mnt/resource
+RSA.KeyLength=2048
+Logs.Verbose=y
+.RE
+
+.SH FILES AND DIRECTORIES
+.TP
+\fB/etc/waagent.conf\fR
+Main configuration file.
+
+.TP
+\fB/var/lib/waagent\fR
+State files and provisioning artifacts.
+
+.TP
+\fB/var/log/waagent.log\fR
+Agent log file.
+
+.SH SERVICES
+On systemd systems, the agent runs as:
+.RS
+.B systemctl start <waagent.service|walinuxagent.service>
+.B systemctl enable <waagent.service|walinuxagent.service>
+.RE
+
+.SH EXIT STATUS
+Zero on success, non-zero on error.
+
+.SH EXAMPLES
+.TP
+Deprovision before capturing an image:
+.RS
+waagent -deprovision+user && rm -rf /var/lib/waagent && shutdown -h now
+.RE
+
+.SH SEE ALSO
+.BR systemctl (1),
+.BR cloud-init (1)
+
+.SH HOMEPAGE
+.B https://github.com/Azure/WALinuxAgent
+
+.B https://learn.microsoft.com/en-us/azure/virtual-machines/extensions/agent-linux
+
+.SH COPYRIGHT
+Copyright 2018 Microsoft Corporation
+
+.SH AUTHORS
+Microsoft Azure Linux Team
diff --git a/setup.py b/setup.py
index cf6e90b5..9ed135fb 100755
--- a/setup.py
+++ b/setup.py
@@ -17,7 +17,9 @@
# limitations under the License.
#
+import gzip
import os
+import shutil
import subprocess
import sys
@@ -87,6 +89,16 @@ def set_udev_files(data_files, dest="/etc/udev/rules.d/", src=None):
"config/99-azure-product-uuid.rules"]
data_files.append((dest, src))
+def set_man_files(data_files, dest="/usr/share/man/man1", src=None):
+ if src is None:
+ src = ["doc/man/waagent.1"]
+ src_gz = []
+ for file in src:
+ with open(file, 'rb') as f_in, gzip.open(file+".gz", 'wb') as f_out:
+ shutil.copyfileobj(f_in, f_out)
+ src_gz.append(file+".gz")
+ data_files.append((dest, src_gz))
+
def get_data_files(name, version, fullname): # pylint: disable=R0912
"""
@@ -107,6 +119,7 @@ def get_data_files(name, version, fullname): # pylint: disable=R0912
set_conf_files(data_files)
set_logrotate_files(data_files)
set_udev_files(data_files)
+ set_man_files(data_files)
if version.startswith("8") or version.startswith("9"):
# redhat 8+ uses systemd and python3
set_systemd_files(data_files, dest=systemd_dir_path,
@@ -255,6 +268,7 @@ def get_data_files(name, version, fullname): # pylint: disable=R0912
set_logrotate_files(data_files)
set_udev_files(data_files)
set_systemd_files(data_files, dest=systemd_dir_path)
+ set_man_files(data_files)
else:
# Use default setting
set_bin_files(data_files, dest=agent_bin_path)
--
2.39.3

View File

@ -1,288 +0,0 @@
From 3747dabadea2fe288e6991723e5364179b2906dd Mon Sep 17 00:00:00 2001
From: Nageswara Nandigam <84482346+nagworld9@users.noreply.github.com>
Date: Mon, 9 Oct 2023 11:14:30 -0700
Subject: [PATCH] skip cgorup monitor (#2939)
RH-Author: Ani Sinha <anisinha@redhat.com>
RH-MergeRequest: 14: skip cgorup monitor (#2939)
RH-Jira: RHEL-46713
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
RH-Commit: [1/1] 613c87b13204159b6b33214d0cf02ed25bcd67e7 (anisinha/centos-wa-linux-agent)
(cherry picked from commit 5bad0b4b19c907386b80ec18ad1423cdb7f3a050)
Signed-off-by: Ani Sinha <anisinha@redhat.com>
Conflicts:
azurelinuxagent/agent.py
azurelinuxagent/common/logcollector.py
tests/common/test_logcollector.py
All due to libraries being moved around in upstream.
---
azurelinuxagent/agent.py | 30 +++++++++++++++++++-------
azurelinuxagent/common/logcollector.py | 15 +------------
azurelinuxagent/ga/collect_logs.py | 10 ++++-----
tests/common/test_logcollector.py | 16 +++++++-------
tests/test_agent.py | 8 +++----
5 files changed, 40 insertions(+), 39 deletions(-)
diff --git a/azurelinuxagent/agent.py b/azurelinuxagent/agent.py
index 8c303482..0fb681e6 100644
--- a/azurelinuxagent/agent.py
+++ b/azurelinuxagent/agent.py
@@ -30,6 +30,7 @@ import sys
import threading
from azurelinuxagent.common import cgroupconfigurator, logcollector
from azurelinuxagent.common.cgroupapi import SystemdCgroupsApi
+from azurelinuxagent.common.cgroup import AGENT_LOG_COLLECTOR, CpuCgroup, MemoryCgroup
import azurelinuxagent.common.conf as conf
import azurelinuxagent.common.event as event
@@ -204,11 +205,10 @@ class Agent(object):
logger.info("Running log collector mode normal")
# Check the cgroups unit
- cpu_cgroup_path, memory_cgroup_path, log_collector_monitor = None, None, None
- if CollectLogsHandler.should_validate_cgroups():
- cgroups_api = SystemdCgroupsApi()
- cpu_cgroup_path, memory_cgroup_path = cgroups_api.get_process_cgroup_paths("self")
-
+ log_collector_monitor = None
+ cgroups_api = SystemdCgroupsApi()
+ cpu_cgroup_path, memory_cgroup_path = cgroups_api.get_process_cgroup_paths("self")
+ if CollectLogsHandler.is_enabled_monitor_cgroups_check():
cpu_slice_matches = (cgroupconfigurator.LOGCOLLECTOR_SLICE in cpu_cgroup_path)
memory_slice_matches = (cgroupconfigurator.LOGCOLLECTOR_SLICE in memory_cgroup_path)
@@ -221,10 +221,24 @@ class Agent(object):
sys.exit(logcollector.INVALID_CGROUPS_ERRCODE)
+ def initialize_cgroups_tracking(cpu_cgroup_path, memory_cgroup_path):
+ cpu_cgroup = CpuCgroup(AGENT_LOG_COLLECTOR, cpu_cgroup_path)
+ msg = "Started tracking cpu cgroup {0}".format(cpu_cgroup)
+ logger.info(msg)
+ cpu_cgroup.initialize_cpu_usage()
+ memory_cgroup = MemoryCgroup(AGENT_LOG_COLLECTOR, memory_cgroup_path)
+ msg = "Started tracking memory cgroup {0}".format(memory_cgroup)
+ logger.info(msg)
+ return [cpu_cgroup, memory_cgroup]
+
try:
- log_collector = LogCollector(is_full_mode, cpu_cgroup_path, memory_cgroup_path)
- log_collector_monitor = get_log_collector_monitor_handler(log_collector.cgroups)
- log_collector_monitor.run()
+ log_collector = LogCollector(is_full_mode)
+ # Running log collector resource(CPU, Memory) monitoring only if agent starts the log collector.
+ # If Log collector start by any other means, then it will not be monitored.
+ if CollectLogsHandler.is_enabled_monitor_cgroups_check():
+ tracked_cgroups = initialize_cgroups_tracking(cpu_cgroup_path, memory_cgroup_path)
+ log_collector_monitor = get_log_collector_monitor_handler(tracked_cgroups)
+ log_collector_monitor.run()
archive = log_collector.collect_logs_and_get_archive()
logger.info("Log collection successfully completed. Archive can be found at {0} "
"and detailed log output can be found at {1}".format(archive, OUTPUT_RESULTS_FILE_PATH))
diff --git a/azurelinuxagent/common/logcollector.py b/azurelinuxagent/common/logcollector.py
index fe62a7db..5f45a7de 100644
--- a/azurelinuxagent/common/logcollector.py
+++ b/azurelinuxagent/common/logcollector.py
@@ -26,7 +26,6 @@ import zipfile
from datetime import datetime
from heapq import heappush, heappop
-from azurelinuxagent.common.cgroup import CpuCgroup, AGENT_LOG_COLLECTOR, MemoryCgroup
from azurelinuxagent.common.conf import get_lib_dir, get_ext_log_dir, get_agent_log_file
from azurelinuxagent.common.event import initialize_event_logger_vminfo_common_parameters
from azurelinuxagent.common.future import ustr
@@ -71,14 +70,13 @@ class LogCollector(object):
_TRUNCATED_FILE_PREFIX = "truncated_"
- def __init__(self, is_full_mode=False, cpu_cgroup_path=None, memory_cgroup_path=None):
+ def __init__(self, is_full_mode=False):
self._is_full_mode = is_full_mode
self._manifest = MANIFEST_FULL if is_full_mode else MANIFEST_NORMAL
self._must_collect_files = self._expand_must_collect_files()
self._create_base_dirs()
self._set_logger()
self._initialize_telemetry()
- self.cgroups = self._set_resource_usage_cgroups(cpu_cgroup_path, memory_cgroup_path)
@staticmethod
def _mkdir(dirname):
@@ -105,17 +103,6 @@ class LogCollector(object):
_LOGGER.addHandler(_f_handler)
_LOGGER.setLevel(logging.INFO)
- @staticmethod
- def _set_resource_usage_cgroups(cpu_cgroup_path, memory_cgroup_path):
- cpu_cgroup = CpuCgroup(AGENT_LOG_COLLECTOR, cpu_cgroup_path)
- msg = "Started tracking cpu cgroup {0}".format(cpu_cgroup)
- _LOGGER.info(msg)
- cpu_cgroup.initialize_cpu_usage()
- memory_cgroup = MemoryCgroup(AGENT_LOG_COLLECTOR, memory_cgroup_path)
- msg = "Started tracking memory cgroup {0}".format(memory_cgroup)
- _LOGGER.info(msg)
- return [cpu_cgroup, memory_cgroup]
-
@staticmethod
def _initialize_telemetry():
protocol = get_protocol_util().get_protocol(init_goal_state=False)
diff --git a/azurelinuxagent/ga/collect_logs.py b/azurelinuxagent/ga/collect_logs.py
index 95c42f3a..4f42e149 100644
--- a/azurelinuxagent/ga/collect_logs.py
+++ b/azurelinuxagent/ga/collect_logs.py
@@ -83,16 +83,16 @@ class CollectLogsHandler(ThreadHandlerInterface):
return CollectLogsHandler._THREAD_NAME
@staticmethod
- def enable_cgroups_validation():
+ def enable_monitor_cgroups_check():
os.environ[CollectLogsHandler.__CGROUPS_FLAG_ENV_VARIABLE] = "1"
@staticmethod
- def disable_cgroups_validation():
+ def disable_monitor_cgroups_check():
if CollectLogsHandler.__CGROUPS_FLAG_ENV_VARIABLE in os.environ:
del os.environ[CollectLogsHandler.__CGROUPS_FLAG_ENV_VARIABLE]
@staticmethod
- def should_validate_cgroups():
+ def is_enabled_monitor_cgroups_check():
if CollectLogsHandler.__CGROUPS_FLAG_ENV_VARIABLE in os.environ:
return os.environ[CollectLogsHandler.__CGROUPS_FLAG_ENV_VARIABLE] == "1"
return False
@@ -147,7 +147,7 @@ class CollectLogsHandler(ThreadHandlerInterface):
time.sleep(_INITIAL_LOG_COLLECTION_DELAY)
try:
- CollectLogsHandler.enable_cgroups_validation()
+ CollectLogsHandler.enable_monitor_cgroups_check()
if self.protocol_util is None or self.protocol is None:
self.init_protocols()
@@ -162,7 +162,7 @@ class CollectLogsHandler(ThreadHandlerInterface):
except Exception as e:
logger.error("An error occurred in the log collection thread; will exit the thread.\n{0}", ustr(e))
finally:
- CollectLogsHandler.disable_cgroups_validation()
+ CollectLogsHandler.disable_monitor_cgroups_check()
def collect_and_send_logs(self):
if self._collect_logs():
diff --git a/tests/common/test_logcollector.py b/tests/common/test_logcollector.py
index 521e0f23..bf402cc7 100644
--- a/tests/common/test_logcollector.py
+++ b/tests/common/test_logcollector.py
@@ -212,7 +212,7 @@ diskinfo,""".format(folder_to_list, file_to_collect)
with patch("azurelinuxagent.common.logcollector.MANIFEST_NORMAL", manifest):
with patch('azurelinuxagent.common.logcollector.LogCollector._initialize_telemetry'):
- log_collector = LogCollector(cpu_cgroup_path="dummy_cpu_path", memory_cgroup_path="dummy_memory_path")
+ log_collector = LogCollector()
archive = log_collector.collect_logs_and_get_archive()
with open(self.output_results_file_path, "r") as fh:
@@ -241,7 +241,7 @@ copy,{0}
with patch("azurelinuxagent.common.logcollector.MANIFEST_FULL", manifest):
with patch('azurelinuxagent.common.logcollector.LogCollector._initialize_telemetry'):
- log_collector = LogCollector(is_full_mode=True, cpu_cgroup_path="dummy_cpu_path", memory_cgroup_path="dummy_memory_path")
+ log_collector = LogCollector(is_full_mode=True)
archive = log_collector.collect_logs_and_get_archive()
self._assert_archive_created(archive)
@@ -255,7 +255,7 @@ copy,{0}
# and combined they do not cross the archive size threshold.
with patch('azurelinuxagent.common.logcollector.LogCollector._initialize_telemetry'):
- log_collector = LogCollector(cpu_cgroup_path="dummy_cpu_path", memory_cgroup_path="dummy_memory_path")
+ log_collector = LogCollector()
archive = log_collector.collect_logs_and_get_archive()
self._assert_archive_created(archive)
@@ -277,7 +277,7 @@ copy,{0}
# Set the size limit so that some files are too large to collect in full.
with patch("azurelinuxagent.common.logcollector._FILE_SIZE_LIMIT", SMALL_FILE_SIZE):
with patch('azurelinuxagent.common.logcollector.LogCollector._initialize_telemetry'):
- log_collector = LogCollector(cpu_cgroup_path="dummy_cpu_path", memory_cgroup_path="dummy_memory_path")
+ log_collector = LogCollector()
archive = log_collector.collect_logs_and_get_archive()
self._assert_archive_created(archive)
@@ -311,7 +311,7 @@ copy,{0}
with patch("azurelinuxagent.common.logcollector._UNCOMPRESSED_ARCHIVE_SIZE_LIMIT", 10 * 1024 * 1024):
with patch("azurelinuxagent.common.logcollector._MUST_COLLECT_FILES", must_collect_files):
with patch('azurelinuxagent.common.logcollector.LogCollector._initialize_telemetry'):
- log_collector = LogCollector(cpu_cgroup_path="dummy_cpu_path", memory_cgroup_path="dummy_memory_path")
+ log_collector = LogCollector()
archive = log_collector.collect_logs_and_get_archive()
self._assert_archive_created(archive)
@@ -362,7 +362,7 @@ copy,{0}
# Ensure the archive reflects the state of files on the disk at collection time. If a file was updated, it
# needs to be updated in the archive, deleted if removed from disk, and added if not previously seen.
with patch('azurelinuxagent.common.logcollector.LogCollector._initialize_telemetry'):
- log_collector = LogCollector(cpu_cgroup_path="dummy_cpu_path", memory_cgroup_path="dummy_memory_path")
+ log_collector = LogCollector()
first_archive = log_collector.collect_logs_and_get_archive()
self._assert_archive_created(first_archive)
@@ -433,7 +433,7 @@ copy,{0}
with patch("azurelinuxagent.common.logcollector._MUST_COLLECT_FILES", must_collect_files):
with patch("azurelinuxagent.common.logcollector._FILE_SIZE_LIMIT", SMALL_FILE_SIZE):
with patch('azurelinuxagent.common.logcollector.LogCollector._initialize_telemetry'):
- log_collector = LogCollector(cpu_cgroup_path="dummy_cpu_path", memory_cgroup_path="dummy_memory_path")
+ log_collector = LogCollector()
archive = log_collector.collect_logs_and_get_archive()
self._assert_archive_created(archive)
@@ -455,7 +455,7 @@ copy,{0}
with patch("azurelinuxagent.common.logcollector._MUST_COLLECT_FILES", must_collect_files):
with patch("azurelinuxagent.common.logcollector._FILE_SIZE_LIMIT", SMALL_FILE_SIZE):
with patch('azurelinuxagent.common.logcollector.LogCollector._initialize_telemetry'):
- log_collector = LogCollector(cpu_cgroup_path="dummy_cpu_path", memory_cgroup_path="dummy_memory_path")
+ log_collector = LogCollector()
second_archive = log_collector.collect_logs_and_get_archive()
expected_files = [
diff --git a/tests/test_agent.py b/tests/test_agent.py
index f0f773f0..f5e87c87 100644
--- a/tests/test_agent.py
+++ b/tests/test_agent.py
@@ -231,7 +231,7 @@ class TestAgent(AgentTestCase):
@patch("azurelinuxagent.agent.LogCollector")
def test_calls_collect_logs_on_valid_cgroups(self, mock_log_collector):
try:
- CollectLogsHandler.enable_cgroups_validation()
+ CollectLogsHandler.enable_monitor_cgroups_check()
mock_log_collector.run = Mock()
def mock_cgroup_paths(*args, **kwargs):
@@ -246,12 +246,12 @@ class TestAgent(AgentTestCase):
mock_log_collector.assert_called_once()
finally:
- CollectLogsHandler.disable_cgroups_validation()
+ CollectLogsHandler.disable_monitor_cgroups_check()
@patch("azurelinuxagent.agent.LogCollector")
def test_doesnt_call_collect_logs_on_invalid_cgroups(self, mock_log_collector):
try:
- CollectLogsHandler.enable_cgroups_validation()
+ CollectLogsHandler.enable_monitor_cgroups_check()
mock_log_collector.run = Mock()
def mock_cgroup_paths(*args, **kwargs):
@@ -270,7 +270,7 @@ class TestAgent(AgentTestCase):
mock_exit.assert_called_once_with(logcollector.INVALID_CGROUPS_ERRCODE)
self.assertEqual(exit_error, re)
finally:
- CollectLogsHandler.disable_cgroups_validation()
+ CollectLogsHandler.disable_monitor_cgroups_check()
def test_it_should_parse_setup_firewall_properly(self):
--
2.39.3