diff options
author | Scott Moser <smoser@brickies.net> | 2017-06-28 12:57:28 -0400 |
---|---|---|
committer | Scott Moser <smoser@brickies.net> | 2017-06-28 12:57:28 -0400 |
commit | 4d1d47a596b342c6e0bc4f85530d8a477fadd3df (patch) | |
tree | 438f3d3e6bac916541b9c69a67c59f6543e4f99f /debian | |
parent | 7d886cc182521bd9827db6d941d79f848a9b56e7 (diff) | |
download | vyos-cloud-init-4d1d47a596b342c6e0bc4f85530d8a477fadd3df.tar.gz vyos-cloud-init-4d1d47a596b342c6e0bc4f85530d8a477fadd3df.zip |
cherry pick 5fb49bac
LP: #1693939
Diffstat (limited to 'debian')
-rw-r--r-- | debian/patches/cpick-5fb49bac-azure-identify-platform-by-well-known-value-in-chassis | 338 | ||||
-rw-r--r-- | debian/patches/series | 1 |
2 files changed, 339 insertions, 0 deletions
diff --git a/debian/patches/cpick-5fb49bac-azure-identify-platform-by-well-known-value-in-chassis b/debian/patches/cpick-5fb49bac-azure-identify-platform-by-well-known-value-in-chassis new file mode 100644 index 00000000..4bcda2d0 --- /dev/null +++ b/debian/patches/cpick-5fb49bac-azure-identify-platform-by-well-known-value-in-chassis @@ -0,0 +1,338 @@ +From 5fb49bacf7441d8d20a7b4e0e7008ca586f5ebab Mon Sep 17 00:00:00 2001 +From: Chad Smith <chad.smith@canonical.com> +Date: Tue, 30 May 2017 10:28:05 -0600 +Subject: [PATCH] azure: identify platform by well known value in chassis asset + tag. + +Azure sets a known chassis asset tag to 7783-7084-3265-9085-8269-3286-77. +We can inspect this in both ds-identify and DataSource.get_data to +determine whether we are on Azure. + +Added unit tests to cover these changes +and some minor tweaks to Exception error message content to give more +context on malformed or missing ovf-env.xml files. + +LP: #1693939 +--- + cloudinit/sources/DataSourceAzure.py | 9 +++- + tests/unittests/test_datasource/test_azure.py | 66 +++++++++++++++++++++++++-- + tests/unittests/test_ds_identify.py | 39 ++++++++++++++++ + tools/ds-identify | 35 +++++++++----- + 4 files changed, 134 insertions(+), 15 deletions(-) + +--- a/cloudinit/sources/DataSourceAzure.py ++++ b/cloudinit/sources/DataSourceAzure.py +@@ -36,6 +36,8 @@ RESOURCE_DISK_PATH = '/dev/disk/cloud/az + DEFAULT_PRIMARY_NIC = 'eth0' + LEASE_FILE = '/var/lib/dhcp/dhclient.eth0.leases' + 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' + + + def find_storvscid_from_sysctl_pnpinfo(sysctl_out, deviceid): +@@ -320,6 +322,11 @@ class DataSourceAzureNet(sources.DataSou + # azure removes/ejects the cdrom containing the ovf-env.xml + # file on reboot. So, in order to successfully reboot we + # need to look in the datadir and consider that valid ++ asset_tag = util.read_dmi_data('chassis-asset-tag') ++ if asset_tag != AZURE_CHASSIS_ASSET_TAG: ++ LOG.debug("Non-Azure DMI asset tag '%s' discovered.", asset_tag) ++ return False ++ asset_tag = util.read_dmi_data('chassis-asset-tag') + ddir = self.ds_cfg['data_dir'] + + candidates = [self.seed_dir] +@@ -694,7 +701,7 @@ def read_azure_ovf(contents): + try: + dom = minidom.parseString(contents) + except Exception as e: +- raise BrokenAzureDataSource("invalid xml: %s" % e) ++ raise BrokenAzureDataSource("Invalid ovf-env.xml: %s" % e) + + results = find_child(dom.documentElement, + lambda n: n.localName == "ProvisioningSection") +--- a/tests/unittests/test_datasource/test_azure.py ++++ b/tests/unittests/test_datasource/test_azure.py +@@ -76,7 +76,9 @@ def construct_valid_ovf_env(data=None, p + return content + + +-class TestAzureDataSource(TestCase): ++class TestAzureDataSource(CiTestCase): ++ ++ with_logs = True + + def setUp(self): + super(TestAzureDataSource, self).setUp() +@@ -160,6 +162,12 @@ scbus-1 on xpt0 bus 0 + + self.instance_id = 'test-instance-id' + ++ def _dmi_mocks(key): ++ if key == 'system-uuid': ++ return self.instance_id ++ elif key == 'chassis-asset-tag': ++ return '7783-7084-3265-9085-8269-3286-77' ++ + self.apply_patches([ + (dsaz, 'list_possible_azure_ds_devs', dsdevs), + (dsaz, 'invoke_agent', _invoke_agent), +@@ -170,7 +178,7 @@ scbus-1 on xpt0 bus 0 + (dsaz, 'set_hostname', mock.MagicMock()), + (dsaz, 'get_metadata_from_fabric', self.get_metadata_from_fabric), + (dsaz.util, 'read_dmi_data', mock.MagicMock( +- return_value=self.instance_id)), ++ side_effect=_dmi_mocks)), + ]) + + dsrc = dsaz.DataSourceAzureNet( +@@ -241,6 +249,23 @@ fdescfs /dev/fd fdes + res = get_path_dev_freebsd('/etc', mnt_list) + self.assertIsNotNone(res) + ++ @mock.patch('cloudinit.sources.DataSourceAzure.util.read_dmi_data') ++ def test_non_azure_dmi_chassis_asset_tag(self, m_read_dmi_data): ++ """Report non-azure when DMI's chassis asset tag doesn't match. ++ ++ Return False when the asset tag doesn't match Azure's static ++ AZURE_CHASSIS_ASSET_TAG. ++ """ ++ # Return a non-matching asset tag value ++ nonazure_tag = dsaz.AZURE_CHASSIS_ASSET_TAG + 'X' ++ m_read_dmi_data.return_value = nonazure_tag ++ dsrc = dsaz.DataSourceAzureNet( ++ {}, distro=None, paths=self.paths) ++ self.assertFalse(dsrc.get_data()) ++ self.assertEqual( ++ "Non-Azure DMI asset tag '{0}' discovered.\n".format(nonazure_tag), ++ self.logs.getvalue()) ++ + def test_basic_seed_dir(self): + odata = {'HostName': "myhost", 'UserName': "myuser"} + data = {'ovfcontent': construct_valid_ovf_env(data=odata), +@@ -531,9 +556,17 @@ class TestAzureBounce(TestCase): + self.patches.enter_context( + mock.patch.object(dsaz, 'get_metadata_from_fabric', + mock.MagicMock(return_value={}))) ++ ++ def _dmi_mocks(key): ++ if key == 'system-uuid': ++ return 'test-instance-id' ++ elif key == 'chassis-asset-tag': ++ return '7783-7084-3265-9085-8269-3286-77' ++ raise RuntimeError('should not get here') ++ + self.patches.enter_context( + mock.patch.object(dsaz.util, 'read_dmi_data', +- mock.MagicMock(return_value='test-instance-id'))) ++ mock.MagicMock(side_effect=_dmi_mocks))) + + def setUp(self): + super(TestAzureBounce, self).setUp() +@@ -696,6 +729,33 @@ class TestAzureBounce(TestCase): + self.assertEqual(0, self.set_hostname.call_count) + + ++class TestLoadAzureDsDir(CiTestCase): ++ """Tests for load_azure_ds_dir.""" ++ ++ def setUp(self): ++ self.source_dir = self.tmp_dir() ++ super(TestLoadAzureDsDir, self).setUp() ++ ++ def test_missing_ovf_env_xml_raises_non_azure_datasource_error(self): ++ """load_azure_ds_dir raises an error When ovf-env.xml doesn't exit.""" ++ with self.assertRaises(dsaz.NonAzureDataSource) as context_manager: ++ dsaz.load_azure_ds_dir(self.source_dir) ++ self.assertEqual( ++ 'No ovf-env file found', ++ str(context_manager.exception)) ++ ++ def test_wb_invalid_ovf_env_xml_calls_read_azure_ovf(self): ++ """load_azure_ds_dir calls read_azure_ovf to parse the xml.""" ++ ovf_path = os.path.join(self.source_dir, 'ovf-env.xml') ++ with open(ovf_path, 'wb') as stream: ++ stream.write(b'invalid xml') ++ with self.assertRaises(dsaz.BrokenAzureDataSource) as context_manager: ++ dsaz.load_azure_ds_dir(self.source_dir) ++ self.assertEqual( ++ 'Invalid ovf-env.xml: syntax error: line 1, column 0', ++ str(context_manager.exception)) ++ ++ + class TestReadAzureOvf(TestCase): + def test_invalid_xml_raises_non_azure_ds(self): + invalid_xml = "<foo>" + construct_valid_ovf_env(data={}) +--- a/tests/unittests/test_ds_identify.py ++++ b/tests/unittests/test_ds_identify.py +@@ -39,9 +39,11 @@ RC_FOUND = 0 + RC_NOT_FOUND = 1 + DS_NONE = 'None' + ++P_CHASSIS_ASSET_TAG = "sys/class/dmi/id/chassis_asset_tag" + P_PRODUCT_NAME = "sys/class/dmi/id/product_name" + P_PRODUCT_SERIAL = "sys/class/dmi/id/product_serial" + P_PRODUCT_UUID = "sys/class/dmi/id/product_uuid" ++P_SEED_DIR = "var/lib/cloud/seed" + P_DSID_CFG = "etc/cloud/ds-identify.cfg" + + MOCK_VIRT_IS_KVM = {'name': 'detect_virt', 'RET': 'kvm', 'ret': 0} +@@ -160,6 +162,30 @@ class TestDsIdentify(CiTestCase): + _print_run_output(rc, out, err, cfg, files) + return rc, out, err, cfg, files + ++ def test_wb_print_variables(self): ++ """_print_info reports an array of discovered variables to stderr.""" ++ data = VALID_CFG['Azure-dmi-detection'] ++ _, _, err, _, _ = self._call_via_dict(data) ++ expected_vars = [ ++ 'DMI_PRODUCT_NAME', 'DMI_SYS_VENDOR', 'DMI_PRODUCT_SERIAL', ++ 'DMI_PRODUCT_UUID', 'PID_1_PRODUCT_NAME', 'DMI_CHASSIS_ASSET_TAG', ++ 'FS_LABELS', 'KERNEL_CMDLINE', 'VIRT', 'UNAME_KERNEL_NAME', ++ 'UNAME_KERNEL_RELEASE', 'UNAME_KERNEL_VERSION', 'UNAME_MACHINE', ++ 'UNAME_NODENAME', 'UNAME_OPERATING_SYSTEM', 'DSNAME', 'DSLIST', ++ 'MODE', 'ON_FOUND', 'ON_MAYBE', 'ON_NOTFOUND'] ++ for var in expected_vars: ++ self.assertIn('{0}='.format(var), err) ++ ++ def test_azure_dmi_detection_from_chassis_asset_tag(self): ++ """Azure datasource is detected from DMI chassis-asset-tag""" ++ self._test_ds_found('Azure-dmi-detection') ++ ++ def test_azure_seed_file_detection(self): ++ """Azure datasource is detected due to presence of a seed file. ++ ++ The seed file tested is /var/lib/cloud/seed/azure/ovf-env.xml.""" ++ self._test_ds_found('Azure-seed-detection') ++ + def test_aws_ec2_hvm(self): + """EC2: hvm instances use dmi serial and uuid starting with 'ec2'.""" + self._test_ds_found('Ec2-hvm') +@@ -254,6 +280,19 @@ def _print_run_output(rc, out, err, cfg, + + + VALID_CFG = { ++ 'Azure-dmi-detection': { ++ 'ds': 'Azure', ++ 'files': { ++ P_CHASSIS_ASSET_TAG: '7783-7084-3265-9085-8269-3286-77\n', ++ } ++ }, ++ 'Azure-seed-detection': { ++ 'ds': 'Azure', ++ 'files': { ++ P_CHASSIS_ASSET_TAG: 'No-match\n', ++ os.path.join(P_SEED_DIR, 'azure', 'ovf-env.xml'): 'present\n', ++ } ++ }, + 'Ec2-hvm': { + 'ds': 'Ec2', + 'mocks': [{'name': 'detect_virt', 'RET': 'kvm', 'ret': 0}], +--- a/tools/ds-identify ++++ b/tools/ds-identify +@@ -85,6 +85,7 @@ DI_MAIN=${DI_MAIN:-main} + + DI_DEFAULT_POLICY="search,found=all,maybe=all,notfound=${DI_DISABLED}" + DI_DEFAULT_POLICY_NO_DMI="search,found=all,maybe=all,notfound=${DI_ENABLED}" ++DI_DMI_CHASSIS_ASSET_TAG="" + DI_DMI_PRODUCT_NAME="" + DI_DMI_SYS_VENDOR="" + DI_DMI_PRODUCT_SERIAL="" +@@ -258,6 +259,12 @@ read_kernel_cmdline() { + DI_KERNEL_CMDLINE="$cmdline" + } + ++read_dmi_chassis_asset_tag() { ++ cached "${DI_DMI_CHASSIS_ASSET_TAG}" && return ++ get_dmi_field chassis_asset_tag ++ DI_DMI_CHASSIS_ASSET_TAG="$_RET" ++} ++ + read_dmi_sys_vendor() { + cached "${DI_DMI_SYS_VENDOR}" && return + get_dmi_field sys_vendor +@@ -385,6 +392,14 @@ read_pid1_product_name() { + DI_PID_1_PRODUCT_NAME="$product_name" + } + ++dmi_chassis_asset_tag_matches() { ++ is_container && return 1 ++ case "${DI_DMI_CHASSIS_ASSET_TAG}" in ++ $1) return 0;; ++ esac ++ return 1 ++} ++ + dmi_product_name_matches() { + is_container && return 1 + case "${DI_DMI_PRODUCT_NAME}" in +@@ -401,11 +416,6 @@ dmi_product_serial_matches() { + return 1 + } + +-dmi_product_name_is() { +- is_container && return 1 +- [ "${DI_DMI_PRODUCT_NAME}" = "$1" ] +-} +- + dmi_sys_vendor_is() { + is_container && return 1 + [ "${DI_DMI_SYS_VENDOR}" = "$1" ] +@@ -477,7 +487,7 @@ dscheck_CloudStack() { + + dscheck_CloudSigma() { + # http://paste.ubuntu.com/23624795/ +- dmi_product_name_is "CloudSigma" && return $DS_FOUND ++ dmi_product_name_matches "CloudSigma" && return $DS_FOUND + return $DS_NOT_FOUND + } + +@@ -653,6 +663,8 @@ dscheck_Azure() { + # UUID="112D211272645f72" LABEL="rd_rdfe_stable.161212-1209" + # TYPE="udf">/dev/sr0</device> + # ++ local azure_chassis="7783-7084-3265-9085-8269-3286-77" ++ dmi_chassis_asset_tag_matches "${azure_chassis}" && return $DS_FOUND + check_seed_dir azure ovf-env.xml && return ${DS_FOUND} + + [ "${DI_VIRT}" = "microsoft" ] || return ${DS_NOT_FOUND} +@@ -785,7 +797,7 @@ dscheck_Ec2() { + } + + dscheck_GCE() { +- if dmi_product_name_is "Google Compute Engine"; then ++ if dmi_product_name_matches "Google Compute Engine"; then + return ${DS_FOUND} + fi + # product name is not guaranteed (LP: #1674861) +@@ -806,10 +818,10 @@ dscheck_OpenStack() { + return ${DS_NOT_FOUND} + fi + local nova="OpenStack Nova" compute="OpenStack Compute" +- if dmi_product_name_is "$nova"; then ++ if dmi_product_name_matches "$nova"; then + return ${DS_FOUND} + fi +- if dmi_product_name_is "$compute"; then ++ if dmi_product_name_matches "$compute"; then + # RDO installed nova (LP: #1675349). + return ${DS_FOUND} + fi +@@ -887,6 +899,7 @@ collect_info() { + read_config + read_datasource_list + read_dmi_sys_vendor ++ read_dmi_chassis_asset_tag + read_dmi_product_name + read_dmi_product_serial + read_dmi_product_uuid +@@ -901,7 +914,7 @@ print_info() { + _print_info() { + local n="" v="" vars="" + vars="DMI_PRODUCT_NAME DMI_SYS_VENDOR DMI_PRODUCT_SERIAL" +- vars="$vars DMI_PRODUCT_UUID PID_1_PRODUCT_NAME" ++ vars="$vars DMI_PRODUCT_UUID PID_1_PRODUCT_NAME DMI_CHASSIS_ASSET_TAG" + vars="$vars FS_LABELS KERNEL_CMDLINE VIRT" + vars="$vars UNAME_KERNEL_NAME UNAME_KERNEL_RELEASE UNAME_KERNEL_VERSION" + vars="$vars UNAME_MACHINE UNAME_NODENAME UNAME_OPERATING_SYSTEM" diff --git a/debian/patches/series b/debian/patches/series index 7669c82f..9331318f 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1,3 @@ azure-use-walinux-agent.patch +cpick-5fb49bac-azure-identify-platform-by-well-known-value-in-chassis ds-identify-behavior-xenial.patch |