Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 36 additions & 58 deletions cloudinit/sources/DataSourceAzure.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@
DEFAULT_FS = "ext4"
# DMI chassis-asset-tag is set static for all azure instances
AZURE_CHASSIS_ASSET_TAG = "7783-7084-3265-9085-8269-3286-77"
REPROVISION_MARKER_FILE = "/var/lib/cloud/data/poll_imds"
REPORTED_READY_MARKER_FILE = "/var/lib/cloud/data/reported_ready"
AGENT_SEED_DIR = "/var/lib/waagent"
DEFAULT_PROVISIONING_ISO_DEV = "/dev/sr0"
Expand Down Expand Up @@ -487,50 +486,42 @@ def crawl_metadata(self):
cfg = {}
files = {}

if os.path.isfile(REPROVISION_MARKER_FILE):
metadata_source = "IMDS"
report_diagnostic_event(
"Reprovision marker file already present "
"before crawling Azure metadata: %s" % REPROVISION_MARKER_FILE,
logger_func=LOG.debug,
)
else:
for src in list_possible_azure_ds(self.seed_dir, ddir):
try:
if src.startswith("/dev/"):
if util.is_FreeBSD():
md, userdata_raw, cfg, files = util.mount_cb(
src, load_azure_ds_dir, mtype="udf"
)
else:
md, userdata_raw, cfg, files = util.mount_cb(
src, load_azure_ds_dir
)
# save the device for ejection later
self._iso_dev = src
for src in list_possible_azure_ds(self.seed_dir, ddir):
try:
if src.startswith("/dev/"):
if util.is_FreeBSD():
md, userdata_raw, cfg, files = util.mount_cb(
src, load_azure_ds_dir, mtype="udf"
)
else:
md, userdata_raw, cfg, files = load_azure_ds_dir(src)
ovf_is_accessible = True
metadata_source = src
break
except NonAzureDataSource:
report_diagnostic_event(
"Did not find Azure data source in %s" % src,
logger_func=LOG.debug,
)
continue
except util.MountFailedError:
report_diagnostic_event(
"%s was not mountable" % src, logger_func=LOG.debug
)
md = {"local-hostname": ""}
cfg = {"system_info": {"default_user": {"name": ""}}}
metadata_source = "IMDS"
continue
except BrokenAzureDataSource as exc:
msg = "BrokenAzureDataSource: %s" % exc
report_diagnostic_event(msg, logger_func=LOG.error)
raise sources.InvalidMetaDataException(msg)
md, userdata_raw, cfg, files = util.mount_cb(
src, load_azure_ds_dir
)
# save the device for ejection later
self._iso_dev = src
else:
md, userdata_raw, cfg, files = load_azure_ds_dir(src)
ovf_is_accessible = True
metadata_source = src
break
except NonAzureDataSource:
report_diagnostic_event(
"Did not find Azure data source in %s" % src,
logger_func=LOG.debug,
)
continue
except util.MountFailedError:
report_diagnostic_event(
"%s was not mountable" % src, logger_func=LOG.debug
)
md = {"local-hostname": ""}
cfg = {"system_info": {"default_user": {"name": ""}}}
metadata_source = "IMDS"
continue
except BrokenAzureDataSource as exc:
msg = "BrokenAzureDataSource: %s" % exc
report_diagnostic_event(msg, logger_func=LOG.error)
raise sources.InvalidMetaDataException(msg)

report_diagnostic_event(
"Found provisioning metadata in %s" % metadata_source,
Expand Down Expand Up @@ -567,8 +558,6 @@ def crawl_metadata(self):
report_diagnostic_event(msg, logger_func=LOG.error)
raise sources.InvalidMetaDataException(msg)

self._write_reprovision_marker()

if pps_type == PPSType.SAVABLE:
self._wait_for_all_nics_ready()

Expand Down Expand Up @@ -1394,7 +1383,7 @@ def _ppstype_from_imds(self, imds_md: dict) -> Optional[str]:

def _determine_pps_type(self, ovf_cfg: dict, imds_md: dict) -> PPSType:
"""Determine PPS type using OVF, IMDS data, and reprovision marker."""
if os.path.isfile(REPROVISION_MARKER_FILE):
if os.path.isfile(REPORTED_READY_MARKER_FILE):
pps_type = PPSType.UNKNOWN
elif (
ovf_cfg.get("PreprovisionedVMType", None) == PPSType.SAVABLE.value
Expand All @@ -1416,16 +1405,6 @@ def _determine_pps_type(self, ovf_cfg: dict, imds_md: dict) -> PPSType:
)
return pps_type

def _write_reprovision_marker(self):
"""Write reprovision marker file in case system is rebooted."""
LOG.info(
"Creating a marker file to poll imds: %s", REPROVISION_MARKER_FILE
)
util.write_file(
REPROVISION_MARKER_FILE,
"{pid}: {time}\n".format(pid=os.getpid(), time=time()),
)

@azure_ds_telemetry_reporter
def _reprovision(self):
"""Initiate the reprovisioning workflow.
Expand Down Expand Up @@ -1463,7 +1442,6 @@ def _determine_wireserver_pubkey_info(
def _cleanup_markers(self):
"""Cleanup any marker files."""
util.del_file(REPORTED_READY_MARKER_FILE)
util.del_file(REPROVISION_MARKER_FILE)

@azure_ds_telemetry_reporter
def activate(self, cfg, is_new_instance):
Expand Down
86 changes: 73 additions & 13 deletions tests/unittests/sources/test_azure.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,16 +287,6 @@ def patched_reported_ready_marker_path(patched_markers_dir_path):
yield reported_ready_marker


@pytest.fixture
def patched_reprovision_marker_path(patched_markers_dir_path):
reprovision_marker = patched_markers_dir_path / "poll_imds"
with mock.patch(
MOCKPATH + "REPROVISION_MARKER_FILE",
str(patched_reprovision_marker_path),
):
yield reprovision_marker


def construct_valid_ovf_env(
data=None, pubkeys=None, userdata=None, platform_settings=None
):
Expand Down Expand Up @@ -3006,7 +2996,9 @@ def test_determine_pps_with_reprovision_marker(
azure_ds._determine_pps_type(ovf_cfg, imds_md)
== dsaz.PPSType.UNKNOWN
)
assert is_file.mock_calls == [mock.call(dsaz.REPROVISION_MARKER_FILE)]
assert is_file.mock_calls == [
mock.call(dsaz.REPORTED_READY_MARKER_FILE)
]


@mock.patch("os.path.isfile", return_value=False)
Expand Down Expand Up @@ -4104,7 +4096,6 @@ def provisioning_setup(
mock_util_mount_cb,
mock_wrapping_setup_ephemeral_networking,
patched_reported_ready_marker_path,
patched_reprovision_marker_path,
):
self.azure_ds = azure_ds
self.mock_azure_get_metadata_from_fabric = (
Expand Down Expand Up @@ -4135,7 +4126,6 @@ def provisioning_setup(
self.patched_reported_ready_marker_path = (
patched_reported_ready_marker_path
)
self.patched_reprovision_marker_path = patched_reprovision_marker_path

self.imds_md = {
"extended": {"compute": {"ppsType": "None"}},
Expand Down Expand Up @@ -4408,6 +4398,76 @@ def test_savable_pps(self):
mock.call.create_bound_netlink_socket().close(),
]

@pytest.mark.parametrize("pps_type", ["Savable", "Running", "None"])
def test_recovery_pps(self, pps_type):
self.patched_reported_ready_marker_path.write_text("")
self.imds_md["extended"]["compute"]["ppsType"] = pps_type
ovf_data = {"HostName": "myhost", "UserName": "myuser"}

self.mock_readurl.side_effect = [
mock.MagicMock(contents=json.dumps(self.imds_md).encode()),
mock.MagicMock(
contents=construct_valid_ovf_env(data=ovf_data).encode()
),
mock.MagicMock(contents=json.dumps(self.imds_md).encode()),
]
self.mock_azure_get_metadata_from_fabric.return_value = []

self.azure_ds._get_data()

assert self.mock_readurl.mock_calls == [
mock.call(
"http://169.254.169.254/metadata/instance?"
"api-version=2021-08-01&extended=true",
timeout=2,
headers={"Metadata": "true"},
retries=10,
exception_cb=dsaz.imds_readurl_exception_callback,
infinite=False,
),
mock.call(
"http://169.254.169.254/metadata/reprovisiondata?"
"api-version=2019-06-01",
timeout=2,
headers={"Metadata": "true"},
exception_cb=mock.ANY,
infinite=True,
log_req_resp=False,
),
mock.call(
"http://169.254.169.254/metadata/instance?"
"api-version=2021-08-01&extended=true",
timeout=2,
headers={"Metadata": "true"},
retries=10,
exception_cb=dsaz.imds_readurl_exception_callback,
infinite=False,
),
]

# 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(None, dsaz.dhcp_log_cb),
]

# Verify IMDS metadata.
assert self.azure_ds.metadata["imds"] == self.imds_md

# Verify reports ready once.
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 no netlink operations for recovering PPS.
assert self.mock_netlink.mock_calls == []


class TestValidateIMDSMetadata:
@pytest.mark.parametrize(
Expand Down