Skip to content

Commit e00e6e0

Browse files
authored
Merge branch 'develop' into mayansingh/add_acl_support
2 parents 3d7596f + 5a3bc1f commit e00e6e0

13 files changed

Lines changed: 110 additions & 21 deletions

azurelinuxagent/agent.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from azurelinuxagent.common.exception import CGroupsException
3535
from azurelinuxagent.ga import logcollector, cgroupconfigurator
3636
from azurelinuxagent.ga.cgroupcontroller import AGENT_LOG_COLLECTOR
37+
from azurelinuxagent.ga.confidential_vm_info import ConfidentialVMInfo
3738
from azurelinuxagent.ga.cpucontroller import _CpuController
3839
from azurelinuxagent.ga.cgroupapi import create_cgroup_api, InvalidCgroupMountpointException
3940
from azurelinuxagent.ga.firewall_manager import FirewallManager, IpTables
@@ -211,6 +212,12 @@ def collect_logs(self, is_full_mode):
211212
else:
212213
logger.info("Running log collector mode normal")
213214

215+
# Initialize the CVM info before initializing the telemetry, since the CVM info is part of the common parameters for telemetry events.
216+
try:
217+
ConfidentialVMInfo.fetch_and_initialize_cvm_info()
218+
except Exception as ex:
219+
logger.warn("Failed to get virtual machine security type from IMDS, will assume this is not a Confidential Virtual Machine: {0}".format(
220+
ustr(ex)))
214221
LogCollector.initialize_telemetry()
215222

216223
# Check the cgroups unit

azurelinuxagent/common/AgentGlobals.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,30 @@ class AgentGlobals(object):
3030
#
3131
_container_id = GUID_ZERO
3232

33+
#
34+
# The telemetry modules require the information about whether the agent is running in a CVM or not. This variable
35+
# will be updated when the CVM info is initialized in ConfidentialVMInfo. There are three possible values:
36+
# - None
37+
# - True
38+
# - False
39+
# The value is None when the CVM info has not yet been initialized.
40+
#
41+
_is_cvm = None
42+
3343
@staticmethod
3444
def get_container_id():
3545
return AgentGlobals._container_id
3646

3747
@staticmethod
3848
def update_container_id(container_id):
3949
AgentGlobals._container_id = container_id
50+
51+
@staticmethod
52+
def get_is_cvm():
53+
if AgentGlobals._is_cvm is None:
54+
raise Exception("CVM info has not been initialized yet")
55+
return AgentGlobals._is_cvm
56+
57+
@staticmethod
58+
def update_is_cvm(is_cvm):
59+
AgentGlobals._is_cvm = is_cvm

azurelinuxagent/common/event.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,8 +394,11 @@ def __init__(self):
394394

395395
# Parameters from OS
396396
osutil = get_osutil()
397+
# Determining IsCVM requires a network call. Set as uninitialized for now until common parameters are
398+
# initialized with real values in initialize_vminfo_common_parameters()
397399
keyword_name = {
398-
"CpuArchitecture": osutil.get_vm_arch()
400+
"CpuArchitecture": osutil.get_vm_arch(),
401+
"IsCVM": "IsCVM_UNINITIALIZED"
399402
}
400403
self._common_parameters.append(TelemetryEventParam(CommonTelemetryEventSchema.OSVersion, EventLogger._get_os_version()))
401404
self._common_parameters.append(TelemetryEventParam(CommonTelemetryEventSchema.ExecutionMode, AGENT_EXECUTION_MODE))
@@ -463,6 +466,25 @@ def initialize_vminfo_common_parameters(self, protocol):
463466
except Exception as e:
464467
logger.warn("Failed to get IMDS info; will be missing from telemetry: {0}", ustr(e))
465468

469+
# The KeywordName column is initialized with the CPUArch in EventLogger.__init__(). The security type is
470+
# not yet discovered at that time because it requires a network call, so we update KeywordName here with the
471+
# IsCVM value.
472+
# The security type is initialized by the ConfidentialVMInfo class because it fetches metadata from IMDS with
473+
# the minimum version that supports the security type field. We do not use that minimum version in the IMDS
474+
# request in this method due to inadequate saturation of that version in the fleet. When the ConfidentialVMInfo
475+
# class attributes are initialized, AgentGlobals is also updated with the security type, so we can get the
476+
# security type in this module without introducing dependencies on the ConfidentialVMInfo class.
477+
try:
478+
keyword_name_str = parameters[CommonTelemetryEventSchema.KeywordName].value # Get the current value of keywordName
479+
keyword_name_json = json.loads(keyword_name_str) # Convert the string to JSON
480+
# AgentGlobals.get_is_cvm() raises if cvm info is not initialized so the IsCVM value in the keywordName
481+
# column would remain uninitialized in that case
482+
is_cvm = AgentGlobals.get_is_cvm() # Get the CVM state from AgentGlobals
483+
keyword_name_json["IsCVM"] = is_cvm # Update the security type in the JSON
484+
parameters[CommonTelemetryEventSchema.KeywordName].value = json.dumps(keyword_name_json) # Convert the JSON back to string and update the value of keywordName
485+
except Exception as e:
486+
logger.warn("Failed to update the KeywordName column with IsCVM; will be missing from telemetry: {0}", ustr(e))
487+
466488
def save_event(self, data):
467489
if self.event_dir is None:
468490
logger.warn("Cannot save event -- Event reporter is not initialized.")

azurelinuxagent/ga/confidential_vm_info.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import json
2121

22+
from azurelinuxagent.common.AgentGlobals import AgentGlobals
2223
from azurelinuxagent.common.protocol.imds import ImdsClient
2324
from azurelinuxagent.common.future import ustr
2425
from azurelinuxagent.common.exception import HttpError
@@ -77,10 +78,12 @@ def fetch_and_initialize_cvm_info():
7778
try:
7879
security_type = ConfidentialVMInfo._fetch_security_type_from_imds()
7980
ConfidentialVMInfo._is_confidential_vm = (security_type == SecurityType.ConfidentialVM)
81+
AgentGlobals.update_is_cvm(ConfidentialVMInfo._is_confidential_vm)
8082
except Exception as ex:
8183
# TODO: For now, in the case of IMDS failure, we treat the VM as non-CVM until the next agent service start.
8284
# This should be improved to better distinguish IMDS issues from true security type.
8385
ConfidentialVMInfo._is_confidential_vm = False
86+
AgentGlobals.update_is_cvm(False)
8487
raise ex
8588

8689
@staticmethod

azurelinuxagent/ga/update.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,9 @@ def run(self, debug=False):
357357
)
358358
logger.info(os_info_msg)
359359

360-
# Initialize Confidential VM info but defer sending telemetry until common parameters are initialized
360+
# Initialize Confidential VM info but defer sending telemetry until common parameters are initialized.
361+
# ConfidentialVMInfo.fetch_and_initialize_cvm_info() should be called to initialize AgentGlobals._is_cvm
362+
# before initialize_event_logger_vminfo_common_parameters_and_protocol() is called.
361363
cvm_info_err = None
362364
try:
363365
ConfidentialVMInfo.fetch_and_initialize_cvm_info()

tests/common/test_event.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def setUp(self):
7171
CommonTelemetryEventSchema.EventTid: threading.current_thread().ident,
7272
CommonTelemetryEventSchema.EventPid: os.getpid(),
7373
CommonTelemetryEventSchema.TaskName: threading.current_thread().name,
74-
CommonTelemetryEventSchema.KeywordName: json.dumps({"CpuArchitecture": platform.machine()}),
74+
CommonTelemetryEventSchema.KeywordName: json.dumps({"CpuArchitecture": platform.machine(), "IsCVM": False}),
7575
# common parameters computed from the OS platform
7676
CommonTelemetryEventSchema.OSVersion: EventLoggerTools.get_expected_os_version(),
7777
CommonTelemetryEventSchema.ExecutionMode: AGENT_EXECUTION_MODE,

tests/ga/test_confidential_vm_info.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import os
1919

20+
from azurelinuxagent.common.AgentGlobals import AgentGlobals
2021
from azurelinuxagent.ga.confidential_vm_info import ConfidentialVMInfo
2122
from tests.lib.tools import AgentTestCase, MagicMock, patch, data_dir
2223

@@ -39,13 +40,17 @@ def test_should_identify_confidential_vm(self):
3940
ConfidentialVMInfo.fetch_and_initialize_cvm_info()
4041
is_cvm = ConfidentialVMInfo.is_confidential_vm()
4142
self.assertTrue(is_cvm)
43+
self.assertTrue(AgentGlobals.get_is_cvm()) # Verify that AgentGlobals was also updated
4244

4345
def test_should_identify_non_confidential_vm(self):
4446
with patch('azurelinuxagent.ga.confidential_vm_info.ImdsClient.get_metadata') as mock_get_metadata:
4547
self._setup_mock_imds_from_file(mock_get_metadata, os.path.join(data_dir, "imds", "trusted_vm_metadata.json"))
4648
ConfidentialVMInfo.fetch_and_initialize_cvm_info()
4749
is_cvm = ConfidentialVMInfo.is_confidential_vm()
4850
self.assertFalse(is_cvm)
51+
# Verify that AgentGlobals was also updated
52+
self.assertFalse(AgentGlobals.get_is_cvm())
53+
self.assertIsNotNone(AgentGlobals.get_is_cvm())
4954

5055
def test_should_return_false_when_imds_unavailable(self):
5156
with patch('azurelinuxagent.ga.confidential_vm_info.ImdsClient.get_metadata') as mock_get_metadata:
@@ -61,6 +66,9 @@ def test_should_return_false_when_imds_unavailable(self):
6166
# After exception, is_confidential_vm should be False
6267
is_cvm = ConfidentialVMInfo.is_confidential_vm()
6368
self.assertFalse(is_cvm)
69+
# Verify that AgentGlobals was also updated
70+
self.assertFalse(AgentGlobals.get_is_cvm())
71+
self.assertIsNotNone(AgentGlobals.get_is_cvm())
6472

6573
def test_should_always_return_false_after_transient_imds_failure(self):
6674
with patch('azurelinuxagent.ga.confidential_vm_info.ImdsClient.get_metadata') as mock_get_metadata:
@@ -78,8 +86,14 @@ def test_should_always_return_false_after_transient_imds_failure(self):
7886
ConfidentialVMInfo.fetch_and_initialize_cvm_info()
7987
first_call = ConfidentialVMInfo.is_confidential_vm()
8088
self.assertFalse(first_call)
89+
# Verify that AgentGlobals was also updated
90+
self.assertFalse(AgentGlobals.get_is_cvm())
91+
self.assertIsNotNone(AgentGlobals.get_is_cvm())
8192
second_call = ConfidentialVMInfo.is_confidential_vm()
8293
self.assertFalse(second_call)
94+
# Verify that AgentGlobals was also updated
95+
self.assertFalse(AgentGlobals.get_is_cvm())
96+
self.assertIsNotNone(AgentGlobals.get_is_cvm())
8397

8498
# Verify IMDS was only called once
8599
self.assertEqual(mock_get_metadata.call_count, 1)

tests/ga/test_send_telemetry_events.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ def http_post_handler(url, body, **__):
7777
protocol_util.get_protocol = Mock(return_value=protocol)
7878
send_telemetry_events_handler = get_send_telemetry_events_handler(protocol_util)
7979
send_telemetry_events_handler.event_calls = []
80+
ConfidentialVMInfo = MagicMock()
81+
ConfidentialVMInfo.is_confidential_vm = Mock(return_vale=False)
8082
with patch("azurelinuxagent.ga.send_telemetry_events.SendTelemetryEventsHandler._MIN_EVENTS_TO_BATCH",
8183
batching_queue_limit):
8284
with patch("azurelinuxagent.ga.send_telemetry_events.SendTelemetryEventsHandler._MAX_TIMEOUT", timeout):
@@ -383,7 +385,7 @@ def test_it_should_enqueue_and_send_events_properly(self, mock_lib_dir, *_):
383385
'<Param Name="ImageOrigin" Value="2468" T="mt:uint64" />' \
384386
']]></Event>'.format(AGENT_VERSION, TestSendTelemetryEventsHandler._TEST_EVENT_OPERATION, CURRENT_AGENT, test_opcodename, test_eventtid,
385387
test_eventpid, test_taskname, osversion, int(osutil.get_total_mem()),
386-
osutil.get_processor_cores(), json.dumps({"CpuArchitecture": platform.machine()})).encode('utf-8')
388+
osutil.get_processor_cores(), json.dumps({"CpuArchitecture": platform.machine(), "IsCVM": False})).encode('utf-8')
387389

388390
self.assertIn(sample_message, collected_event)
389391

tests/lib/event_logger_tools.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ def initialize_event_logger(event_dir):
5555

5656
with mock_wire_protocol(wire_protocol_data.DATA_FILE) as mock_protocol:
5757
with tools.patch("azurelinuxagent.common.event.get_imds_client", return_value=mock_imds_client):
58-
event.initialize_event_logger_vminfo_common_parameters_and_protocol(mock_protocol)
58+
with tools.patch("azurelinuxagent.common.AgentGlobals.AgentGlobals.get_is_cvm", return_value=False):
59+
event.initialize_event_logger_vminfo_common_parameters_and_protocol(mock_protocol)
5960

6061
@staticmethod
6162
def get_expected_os_version():

tests_e2e/orchestrator/lib/agent_test_result.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,29 @@
2020

2121
# Disable those warnings, since 'lisa' is an external, non-standard, dependency
2222
# E0401: Unable to import 'lisa' (import-error)
23-
# etc
24-
from lisa import ( # pylint: disable=E0401
25-
notifier
26-
)
23+
from lisa import notifier # pylint: disable=E0401
2724
from lisa.messages import TestStatus, TestResultMessage # pylint: disable=E0401
25+
26+
from typing import Optional
27+
2828
from azurelinuxagent.common.future import UTC
2929

3030

31+
class AgentTestResultMessage(TestResultMessage):
32+
def __init__(self, suite_name: str, test_name: str, status: TestStatus):
33+
super().__init__()
34+
self.type: str = "AgentTestResultMessage"
35+
self.id_: str = str(uuid.uuid4())
36+
self.status: TestStatus = status
37+
self.suite_full_name: str = suite_name
38+
self.suite_name: str = suite_name
39+
self.full_name: str = test_name
40+
self.name: str = test_name
41+
self.elapsed: float = 0
42+
self.message: str = ""
43+
self.stacktrace: Optional[str] = None
44+
45+
3146
class AgentTestResult:
3247
@staticmethod
3348
def report(
@@ -42,15 +57,7 @@ def report(
4257
Reports a test result to the junit notifier
4358
"""
4459
# The junit notifier requires an initial RUNNING message in order to register the test in its internal cache.
45-
msg: TestResultMessage = TestResultMessage()
46-
msg.type = "AgentTestResultMessage"
47-
msg.id_ = str(uuid.uuid4())
48-
msg.status = TestStatus.RUNNING
49-
msg.suite_full_name = suite_name
50-
msg.suite_name = msg.suite_full_name
51-
msg.full_name = test_name
52-
msg.name = msg.full_name
53-
msg.elapsed = 0
60+
msg: AgentTestResultMessage = AgentTestResultMessage(suite_name, test_name, TestStatus.RUNNING)
5461

5562
notifier.notify(msg)
5663

0 commit comments

Comments
 (0)