|
|
c36ff1 |
From 2ece71923a37a5e1107c80f091a1cc620943fbf2 Mon Sep 17 00:00:00 2001
|
|
|
c36ff1 |
From: Anh Vo <anhvo@microsoft.com>
|
|
|
c36ff1 |
Date: Fri, 23 Apr 2021 10:18:05 -0400
|
|
|
c36ff1 |
Subject: [PATCH 4/7] Azure: eject the provisioning iso before reporting ready
|
|
|
c36ff1 |
(#861)
|
|
|
c36ff1 |
|
|
|
c36ff1 |
RH-Author: Eduardo Otubo <otubo@redhat.com>
|
|
|
c36ff1 |
RH-MergeRequest: 18: Add support for userdata on Azure from IMDS
|
|
|
c36ff1 |
RH-Commit: [4/7] 63e379a4406530c0c15c733f8eee35421079508b (otubo/cloud-init-src)
|
|
|
c36ff1 |
RH-Bugzilla: 2042351
|
|
|
c36ff1 |
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
c36ff1 |
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
|
|
|
c36ff1 |
|
|
|
c36ff1 |
Due to hyper-v implementations, iso ejection is more efficient if performed
|
|
|
c36ff1 |
from within the guest. The code will attempt to perform a best-effort ejection.
|
|
|
c36ff1 |
Failure during ejection will not prevent reporting ready from happening. If iso
|
|
|
c36ff1 |
ejection is successful, later iso ejection from the platform will be a no-op.
|
|
|
c36ff1 |
In the event the iso ejection from the guest fails, iso ejection will still happen at
|
|
|
c36ff1 |
the platform level.
|
|
|
c36ff1 |
---
|
|
|
c36ff1 |
cloudinit/sources/DataSourceAzure.py | 22 +++++++++++++++---
|
|
|
c36ff1 |
cloudinit/sources/helpers/azure.py | 23 ++++++++++++++++---
|
|
|
c36ff1 |
.../test_datasource/test_azure_helper.py | 13 +++++++++--
|
|
|
c36ff1 |
3 files changed, 50 insertions(+), 8 deletions(-)
|
|
|
c36ff1 |
|
|
|
c36ff1 |
diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py
|
|
|
c36ff1 |
index 020b7006..39e67c4f 100755
|
|
|
c36ff1 |
--- a/cloudinit/sources/DataSourceAzure.py
|
|
|
c36ff1 |
+++ b/cloudinit/sources/DataSourceAzure.py
|
|
|
c36ff1 |
@@ -332,6 +332,7 @@ class DataSourceAzure(sources.DataSource):
|
|
|
c36ff1 |
dsname = 'Azure'
|
|
|
c36ff1 |
_negotiated = False
|
|
|
c36ff1 |
_metadata_imds = sources.UNSET
|
|
|
c36ff1 |
+ _ci_pkl_version = 1
|
|
|
c36ff1 |
|
|
|
c36ff1 |
def __init__(self, sys_cfg, distro, paths):
|
|
|
c36ff1 |
sources.DataSource.__init__(self, sys_cfg, distro, paths)
|
|
|
c36ff1 |
@@ -346,8 +347,13 @@ class DataSourceAzure(sources.DataSource):
|
|
|
c36ff1 |
# Regenerate network config new_instance boot and every boot
|
|
|
c36ff1 |
self.update_events['network'].add(EventType.BOOT)
|
|
|
c36ff1 |
self._ephemeral_dhcp_ctx = None
|
|
|
c36ff1 |
-
|
|
|
c36ff1 |
self.failed_desired_api_version = False
|
|
|
c36ff1 |
+ self.iso_dev = None
|
|
|
c36ff1 |
+
|
|
|
c36ff1 |
+ def _unpickle(self, ci_pkl_version: int) -> None:
|
|
|
c36ff1 |
+ super()._unpickle(ci_pkl_version)
|
|
|
c36ff1 |
+ if "iso_dev" not in self.__dict__:
|
|
|
c36ff1 |
+ self.iso_dev = None
|
|
|
c36ff1 |
|
|
|
c36ff1 |
def __str__(self):
|
|
|
c36ff1 |
root = sources.DataSource.__str__(self)
|
|
|
c36ff1 |
@@ -459,6 +465,13 @@ class DataSourceAzure(sources.DataSource):
|
|
|
c36ff1 |
'%s was not mountable' % cdev, logger_func=LOG.warning)
|
|
|
c36ff1 |
continue
|
|
|
c36ff1 |
|
|
|
c36ff1 |
+ report_diagnostic_event("Found provisioning metadata in %s" % cdev,
|
|
|
c36ff1 |
+ logger_func=LOG.debug)
|
|
|
c36ff1 |
+
|
|
|
c36ff1 |
+ # save the iso device for ejection before reporting ready
|
|
|
c36ff1 |
+ if cdev.startswith("/dev"):
|
|
|
c36ff1 |
+ self.iso_dev = cdev
|
|
|
c36ff1 |
+
|
|
|
c36ff1 |
perform_reprovision = reprovision or self._should_reprovision(ret)
|
|
|
c36ff1 |
perform_reprovision_after_nic_attach = (
|
|
|
c36ff1 |
reprovision_after_nic_attach or
|
|
|
c36ff1 |
@@ -1226,7 +1239,9 @@ class DataSourceAzure(sources.DataSource):
|
|
|
c36ff1 |
@return: The success status of sending the ready signal.
|
|
|
c36ff1 |
"""
|
|
|
c36ff1 |
try:
|
|
|
c36ff1 |
- get_metadata_from_fabric(None, lease['unknown-245'])
|
|
|
c36ff1 |
+ get_metadata_from_fabric(fallback_lease_file=None,
|
|
|
c36ff1 |
+ dhcp_opts=lease['unknown-245'],
|
|
|
c36ff1 |
+ iso_dev=self.iso_dev)
|
|
|
c36ff1 |
return True
|
|
|
c36ff1 |
except Exception as e:
|
|
|
c36ff1 |
report_diagnostic_event(
|
|
|
c36ff1 |
@@ -1332,7 +1347,8 @@ class DataSourceAzure(sources.DataSource):
|
|
|
c36ff1 |
metadata_func = partial(get_metadata_from_fabric,
|
|
|
c36ff1 |
fallback_lease_file=self.
|
|
|
c36ff1 |
dhclient_lease_file,
|
|
|
c36ff1 |
- pubkey_info=pubkey_info)
|
|
|
c36ff1 |
+ pubkey_info=pubkey_info,
|
|
|
c36ff1 |
+ iso_dev=self.iso_dev)
|
|
|
c36ff1 |
|
|
|
c36ff1 |
LOG.debug("negotiating with fabric via agent command %s",
|
|
|
c36ff1 |
self.ds_cfg['agent_command'])
|
|
|
c36ff1 |
diff --git a/cloudinit/sources/helpers/azure.py b/cloudinit/sources/helpers/azure.py
|
|
|
c36ff1 |
index 03e7156b..ad476076 100755
|
|
|
c36ff1 |
--- a/cloudinit/sources/helpers/azure.py
|
|
|
c36ff1 |
+++ b/cloudinit/sources/helpers/azure.py
|
|
|
c36ff1 |
@@ -865,7 +865,19 @@ class WALinuxAgentShim:
|
|
|
c36ff1 |
return endpoint_ip_address
|
|
|
c36ff1 |
|
|
|
c36ff1 |
@azure_ds_telemetry_reporter
|
|
|
c36ff1 |
- def register_with_azure_and_fetch_data(self, pubkey_info=None) -> dict:
|
|
|
c36ff1 |
+ def eject_iso(self, iso_dev) -> None:
|
|
|
c36ff1 |
+ try:
|
|
|
c36ff1 |
+ LOG.debug("Ejecting the provisioning iso")
|
|
|
c36ff1 |
+ subp.subp(['eject', iso_dev])
|
|
|
c36ff1 |
+ except Exception as e:
|
|
|
c36ff1 |
+ report_diagnostic_event(
|
|
|
c36ff1 |
+ "Failed ejecting the provisioning iso: %s" % e,
|
|
|
c36ff1 |
+ logger_func=LOG.debug)
|
|
|
c36ff1 |
+
|
|
|
c36ff1 |
+ @azure_ds_telemetry_reporter
|
|
|
c36ff1 |
+ def register_with_azure_and_fetch_data(self,
|
|
|
c36ff1 |
+ pubkey_info=None,
|
|
|
c36ff1 |
+ iso_dev=None) -> dict:
|
|
|
c36ff1 |
"""Gets the VM's GoalState from Azure, uses the GoalState information
|
|
|
c36ff1 |
to report ready/send the ready signal/provisioning complete signal to
|
|
|
c36ff1 |
Azure, and then uses pubkey_info to filter and obtain the user's
|
|
|
c36ff1 |
@@ -891,6 +903,10 @@ class WALinuxAgentShim:
|
|
|
c36ff1 |
ssh_keys = self._get_user_pubkeys(goal_state, pubkey_info)
|
|
|
c36ff1 |
health_reporter = GoalStateHealthReporter(
|
|
|
c36ff1 |
goal_state, self.azure_endpoint_client, self.endpoint)
|
|
|
c36ff1 |
+
|
|
|
c36ff1 |
+ if iso_dev is not None:
|
|
|
c36ff1 |
+ self.eject_iso(iso_dev)
|
|
|
c36ff1 |
+
|
|
|
c36ff1 |
health_reporter.send_ready_signal()
|
|
|
c36ff1 |
return {'public-keys': ssh_keys}
|
|
|
c36ff1 |
|
|
|
c36ff1 |
@@ -1046,11 +1062,12 @@ class WALinuxAgentShim:
|
|
|
c36ff1 |
|
|
|
c36ff1 |
@azure_ds_telemetry_reporter
|
|
|
c36ff1 |
def get_metadata_from_fabric(fallback_lease_file=None, dhcp_opts=None,
|
|
|
c36ff1 |
- pubkey_info=None):
|
|
|
c36ff1 |
+ pubkey_info=None, iso_dev=None):
|
|
|
c36ff1 |
shim = WALinuxAgentShim(fallback_lease_file=fallback_lease_file,
|
|
|
c36ff1 |
dhcp_options=dhcp_opts)
|
|
|
c36ff1 |
try:
|
|
|
c36ff1 |
- return shim.register_with_azure_and_fetch_data(pubkey_info=pubkey_info)
|
|
|
c36ff1 |
+ return shim.register_with_azure_and_fetch_data(
|
|
|
c36ff1 |
+ pubkey_info=pubkey_info, iso_dev=iso_dev)
|
|
|
c36ff1 |
finally:
|
|
|
c36ff1 |
shim.clean_up()
|
|
|
c36ff1 |
|
|
|
c36ff1 |
diff --git a/tests/unittests/test_datasource/test_azure_helper.py b/tests/unittests/test_datasource/test_azure_helper.py
|
|
|
c36ff1 |
index 63482c6c..552c7905 100644
|
|
|
c36ff1 |
--- a/tests/unittests/test_datasource/test_azure_helper.py
|
|
|
c36ff1 |
+++ b/tests/unittests/test_datasource/test_azure_helper.py
|
|
|
c36ff1 |
@@ -1009,6 +1009,14 @@ class TestWALinuxAgentShim(CiTestCase):
|
|
|
c36ff1 |
self.GoalState.return_value.container_id = self.test_container_id
|
|
|
c36ff1 |
self.GoalState.return_value.instance_id = self.test_instance_id
|
|
|
c36ff1 |
|
|
|
c36ff1 |
+ def test_eject_iso_is_called(self):
|
|
|
c36ff1 |
+ shim = wa_shim()
|
|
|
c36ff1 |
+ with mock.patch.object(
|
|
|
c36ff1 |
+ shim, 'eject_iso', autospec=True
|
|
|
c36ff1 |
+ ) as m_eject_iso:
|
|
|
c36ff1 |
+ shim.register_with_azure_and_fetch_data(iso_dev="/dev/sr0")
|
|
|
c36ff1 |
+ m_eject_iso.assert_called_once_with("/dev/sr0")
|
|
|
c36ff1 |
+
|
|
|
c36ff1 |
def test_http_client_does_not_use_certificate_for_report_ready(self):
|
|
|
c36ff1 |
shim = wa_shim()
|
|
|
c36ff1 |
shim.register_with_azure_and_fetch_data()
|
|
|
c36ff1 |
@@ -1283,13 +1291,14 @@ class TestGetMetadataGoalStateXMLAndReportReadyToFabric(CiTestCase):
|
|
|
c36ff1 |
|
|
|
c36ff1 |
def test_calls_shim_register_with_azure_and_fetch_data(self):
|
|
|
c36ff1 |
m_pubkey_info = mock.MagicMock()
|
|
|
c36ff1 |
- azure_helper.get_metadata_from_fabric(pubkey_info=m_pubkey_info)
|
|
|
c36ff1 |
+ azure_helper.get_metadata_from_fabric(
|
|
|
c36ff1 |
+ pubkey_info=m_pubkey_info, iso_dev="/dev/sr0")
|
|
|
c36ff1 |
self.assertEqual(
|
|
|
c36ff1 |
1,
|
|
|
c36ff1 |
self.m_shim.return_value
|
|
|
c36ff1 |
.register_with_azure_and_fetch_data.call_count)
|
|
|
c36ff1 |
self.assertEqual(
|
|
|
c36ff1 |
- mock.call(pubkey_info=m_pubkey_info),
|
|
|
c36ff1 |
+ mock.call(iso_dev="/dev/sr0", pubkey_info=m_pubkey_info),
|
|
|
c36ff1 |
self.m_shim.return_value
|
|
|
c36ff1 |
.register_with_azure_and_fetch_data.call_args)
|
|
|
c36ff1 |
|
|
|
c36ff1 |
--
|
|
|
c36ff1 |
2.27.0
|
|
|
c36ff1 |
|