summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cloudinit/sources/DataSourceAzure.py44
-rw-r--r--tests/unittests/test_datasource/test_azure.py23
2 files changed, 65 insertions, 2 deletions
diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py
index c90d7b07..0a5caebe 100644
--- a/cloudinit/sources/DataSourceAzure.py
+++ b/cloudinit/sources/DataSourceAzure.py
@@ -114,7 +114,8 @@ class DataSourceAzureNet(sources.DataSource):
# claim the datasource even if the command failed
util.logexc(LOG, "agent command '%s' failed.", mycfg['cmd'])
- wait_for = [os.path.join(mycfg['datadir'], "SharedConfig.xml")]
+ shcfgxml = os.path.join(mycfg['datadir'], "SharedConfig.xml")
+ wait_for = [shcfgxml]
fp_files = []
for pk in self.cfg.get('_pubkeys', []):
@@ -129,6 +130,14 @@ class DataSourceAzureNet(sources.DataSource):
LOG.debug("waited %.3f seconds for %d files to appear",
time.time() - start, len(wait_for))
+ if shcfgxml in missing:
+ LOG.warn("SharedConfig.xml missing, using static instance-id")
+ else:
+ try:
+ self.metadata['instance-id'] = iid_from_shared_config(shcfgxml)
+ except ValueError as e:
+ LOG.warn("failed to get instance id in %s: %s" % (shcfgxml, e))
+
pubkeys = pubkeys_from_crt_files(fp_files)
self.metadata['public-keys'] = pubkeys
@@ -252,6 +261,20 @@ def load_azure_ovf_pubkeys(sshnode):
return found
+def single_node_at_path(node, pathlist):
+ curnode = node
+ for tok in pathlist:
+ results = find_child(curnode, lambda n: n.localName == tok)
+ if len(results) == 0:
+ raise ValueError("missing %s token in %s" % (tok, str(pathlist)))
+ if len(results) > 1:
+ raise ValueError("found %s nodes of type %s looking for %s" %
+ (len(results), tok, str(pathlist)))
+ curnode = results[0]
+
+ return curnode
+
+
def read_azure_ovf(contents):
try:
dom = minidom.parseString(contents)
@@ -362,6 +385,25 @@ def load_azure_ds_dir(source_dir):
return (md, ud, cfg, {'ovf-env.xml': contents})
+def iid_from_shared_config(path):
+ with open(path, "rb") as fp:
+ content = fp.read()
+ return iid_from_shared_config_content(content)
+
+
+def iid_from_shared_config_content(content):
+ """
+ find INSTANCE_ID in:
+ <?xml version="1.0" encoding="utf-8"?>
+ <SharedConfig version="1.0.0.0" goalStateIncarnation="1">
+ <Deployment name="INSTANCE_ID" guid="{...}" incarnation="0">
+ <Service name="..." guid="{00000000-0000-0000-0000-000000000000}" />
+ """
+ dom = minidom.parseString(content)
+ depnode = single_node_at_path(dom, ["SharedConfig", "Deployment"])
+ return depnode.attributes.get('name').value
+
+
class BrokenAzureDataSource(Exception):
pass
diff --git a/tests/unittests/test_datasource/test_azure.py b/tests/unittests/test_datasource/test_azure.py
index c79c25d8..2e8583f9 100644
--- a/tests/unittests/test_datasource/test_azure.py
+++ b/tests/unittests/test_datasource/test_azure.py
@@ -99,6 +99,10 @@ class TestAzureDataSource(MockerTestCase):
data['pubkey_files'] = flist
return ["pubkey_from: %s" % f for f in flist]
+ def _iid_from_shared_config(path):
+ data['iid_from_shared_cfg'] = path
+ return 'i-my-azure-id'
+
if data.get('ovfcontent') is not None:
populate_dir(os.path.join(self.paths.seed_dir, "azure"),
{'ovf-env.xml': data['ovfcontent']})
@@ -112,7 +116,9 @@ class TestAzureDataSource(MockerTestCase):
(mod, 'write_files', _write_files),
(mod, 'wait_for_files', _wait_for_files),
(mod, 'pubkeys_from_crt_files',
- _pubkeys_from_crt_files)])
+ _pubkeys_from_crt_files),
+ (mod, 'iid_from_shared_config',
+ _iid_from_shared_config), ])
dsrc = mod.DataSourceAzureNet(
data.get('sys_cfg', {}), distro=None, paths=self.paths)
@@ -131,6 +137,7 @@ class TestAzureDataSource(MockerTestCase):
self.assertEqual(dsrc.metadata['local-hostname'], odata['HostName'])
self.assertTrue('ovf-env.xml' in data['files'])
self.assertEqual(0700, data['datadir_mode'])
+ self.assertEqual(dsrc.metadata['instance-id'], 'i-my-azure-id')
def test_user_cfg_set_agent_command(self):
cfg = {'agent_command': "my_command"}
@@ -227,6 +234,20 @@ class TestReadAzureOvf(MockerTestCase):
self.assertIn(mypk, cfg['_pubkeys'])
+class TestReadAzureSharedConfig(MockerTestCase):
+ def test_valid_content(self):
+ xml = """<?xml version="1.0" encoding="utf-8"?>
+ <SharedConfig>
+ <Deployment name="MY_INSTANCE_ID">
+ <Service name="myservice"/>
+ <ServiceInstance name="INSTANCE_ID.0" guid="{abcd-uuid}" />
+ </Deployment>
+ <Incarnation number="1"/>
+ </SharedConfig>"""
+ ret = DataSourceAzure.iid_from_shared_config_content(xml)
+ self.assertEqual("MY_INSTANCE_ID", ret)
+
+
def apply_patches(patches):
ret = []
for (ref, name, replace) in patches: