summaryrefslogtreecommitdiff
path: root/debian
diff options
context:
space:
mode:
authorScott Moser <smoser@brickies.net>2017-06-28 12:57:28 -0400
committerScott Moser <smoser@brickies.net>2017-06-28 12:57:28 -0400
commit4d1d47a596b342c6e0bc4f85530d8a477fadd3df (patch)
tree438f3d3e6bac916541b9c69a67c59f6543e4f99f /debian
parent7d886cc182521bd9827db6d941d79f848a9b56e7 (diff)
downloadvyos-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-chassis338
-rw-r--r--debian/patches/series1
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