summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAngus Salkeld <asalkeld@redhat.com>2013-07-31 10:58:20 +1000
committerAngus Salkeld <asalkeld@redhat.com>2013-07-31 10:58:20 +1000
commitb97fb83dc070cee1d12ea23b1cd7a99da42a6243 (patch)
tree79d82fb85eb8eee1dcd9cc6a576d9b1a7cda2cbe
parent73cebadc073c4dd32d90f2254e325fcd1084b5f4 (diff)
downloadheat-cfntools-b97fb83dc070cee1d12ea23b1cd7a99da42a6243.tar.gz
Add a get_tags() method to the Metadata class
Tags are not properly implemented in nova so we pass the tags to nova as metadata. So we now [w]get the nova metadata. Since this is called repeatedly we cache the metadata. We also add the nova instance id (uuid) as a guest tag. Change-Id: I599f22fd5166e88cb3d21a71ead5f48c5c5a9269
-rw-r--r--heat_cfntools/cfntools/cfn_helper.py30
-rw-r--r--heat_cfntools/tests/test_cfn_helper.py147
2 files changed, 177 insertions, 0 deletions
diff --git a/heat_cfntools/cfntools/cfn_helper.py b/heat_cfntools/cfntools/cfn_helper.py
index 371e990..54f3f87 100644
--- a/heat_cfntools/cfntools/cfn_helper.py
+++ b/heat_cfntools/cfntools/cfn_helper.py
@@ -1059,6 +1059,36 @@ class Metadata(object):
'DescribeStackResourceResult']['StackResourceDetail']
return resource_detail['Metadata']
+ def get_nova_meta(self,
+ cache_path='/var/lib/heat-cfntools/nova_meta.json'):
+ """Get nova's meta_data.json and cache it.
+
+ Since this is called repeatedly return the cached metadata,
+ if we have it.
+ """
+
+ url = 'http://169.254.169.254/openstack/2012-08-10/meta_data.json'
+ if not os.path.exists(cache_path):
+ CommandRunner('wget -O %s %s' % (cache_path, url)).run()
+ try:
+ with open(cache_path) as fd:
+ try:
+ return json.load(fd)
+ except ValueError:
+ pass
+ except IOError:
+ pass
+ return None
+
+ def get_tags(self):
+ """Get the tags for this server."""
+ tags = {}
+ md = self.get_nova_meta()
+ if md is not None:
+ tags.update(md.get('meta', {}))
+ tags['InstanceId'] = md['uuid']
+ return tags
+
def retrieve(
self,
meta_str=None,
diff --git a/heat_cfntools/tests/test_cfn_helper.py b/heat_cfntools/tests/test_cfn_helper.py
index a992cc5..6aec2b0 100644
--- a/heat_cfntools/tests/test_cfn_helper.py
+++ b/heat_cfntools/tests/test_cfn_helper.py
@@ -672,6 +672,153 @@ class TestMetadataRetrieve(testtools.TestCase):
md.cfn_init()
self.assertThat(foo_file.name, ttm.FileContains('bar'))
+ def test_nova_meta_with_cache(self):
+ meta_in = {"uuid": "f9431d18-d971-434d-9044-5b38f5b4646f",
+ "availability_zone": "nova",
+ "hostname": "as-wikidatabase-4ykioj3lgi57.novalocal",
+ "launch_index": 0,
+ "meta": {},
+ "public_keys": {"heat_key": "ssh-rsa etc...\n"},
+ "name": "as-WikiDatabase-4ykioj3lgi57"}
+ md_str = json.dumps(meta_in)
+
+ md = cfn_helper.Metadata('teststack', None)
+ with tempfile.NamedTemporaryFile(mode='w+') as default_file:
+ default_file.write(md_str)
+ default_file.flush()
+ self.assertThat(default_file.name, ttm.FileContains(md_str))
+ meta_out = md.get_nova_meta(cache_path=default_file.name)
+
+ self.assertEqual(meta_in, meta_out)
+
+ def test_nova_meta_wget(self):
+ url = 'http://169.254.169.254/openstack/2012-08-10/meta_data.json'
+ temp_home = tempfile.mkdtemp()
+ cache_path = os.path.join(temp_home, 'meta_data.json')
+
+ def cleanup_temp_home(thome):
+ os.unlink(cache_path)
+ os.rmdir(thome)
+
+ self.m = mox.Mox()
+ self.addCleanup(self.m.UnsetStubs)
+ self.addCleanup(cleanup_temp_home, temp_home)
+
+ meta_in = {"uuid": "f9431d18-d971-434d-9044-5b38f5b4646f",
+ "availability_zone": "nova",
+ "hostname": "as-wikidatabase-4ykioj3lgi57.novalocal",
+ "launch_index": 0,
+ "meta": {"freddy": "is hungry"},
+ "public_keys": {"heat_key": "ssh-rsa etc...\n"},
+ "name": "as-WikiDatabase-4ykioj3lgi57"}
+ md_str = json.dumps(meta_in)
+
+ def write_cache_file(*params, **kwargs):
+ with open(cache_path, 'w+') as cache_file:
+ cache_file.write(md_str)
+ cache_file.flush()
+ self.assertThat(cache_file.name, ttm.FileContains(md_str))
+
+ self.m.StubOutWithMock(subprocess, 'Popen')
+ subprocess.Popen(['su', 'root', '-c',
+ 'wget -O %s %s' % (cache_path, url)],
+ cwd=None, env=None, stderr=-1, stdout=-1)\
+ .WithSideEffects(write_cache_file)\
+ .AndReturn(FakePOpen('Downloaded', '', 0))
+
+ self.m.ReplayAll()
+
+ md = cfn_helper.Metadata('teststack', None)
+ meta_out = md.get_nova_meta(cache_path=cache_path)
+ self.assertEqual(meta_in, meta_out)
+ self.m.VerifyAll()
+
+ def test_nova_meta_wget_corrupt(self):
+ url = 'http://169.254.169.254/openstack/2012-08-10/meta_data.json'
+ temp_home = tempfile.mkdtemp()
+ cache_path = os.path.join(temp_home, 'meta_data.json')
+
+ def cleanup_temp_home(thome):
+ os.unlink(cache_path)
+ os.rmdir(thome)
+
+ self.m = mox.Mox()
+ self.addCleanup(self.m.UnsetStubs)
+ self.addCleanup(cleanup_temp_home, temp_home)
+
+ md_str = "this { is not really json"
+
+ def write_cache_file(*params, **kwargs):
+ with open(cache_path, 'w+') as cache_file:
+ cache_file.write(md_str)
+ cache_file.flush()
+ self.assertThat(cache_file.name, ttm.FileContains(md_str))
+
+ self.m.StubOutWithMock(subprocess, 'Popen')
+ subprocess.Popen(['su', 'root', '-c',
+ 'wget -O %s %s' % (cache_path, url)],
+ cwd=None, env=None, stderr=-1, stdout=-1)\
+ .WithSideEffects(write_cache_file)\
+ .AndReturn(FakePOpen('Downloaded', '', 0))
+
+ self.m.ReplayAll()
+
+ md = cfn_helper.Metadata('teststack', None)
+ meta_out = md.get_nova_meta(cache_path=cache_path)
+ self.assertEqual(None, meta_out)
+ self.m.VerifyAll()
+
+ def test_nova_meta_wget_failed(self):
+ url = 'http://169.254.169.254/openstack/2012-08-10/meta_data.json'
+ temp_home = tempfile.mkdtemp()
+ cache_path = os.path.join(temp_home, 'meta_data.json')
+
+ def cleanup_temp_home(thome):
+ os.rmdir(thome)
+
+ self.m = mox.Mox()
+ self.addCleanup(self.m.UnsetStubs)
+ self.addCleanup(cleanup_temp_home, temp_home)
+
+ self.m.StubOutWithMock(subprocess, 'Popen')
+ subprocess.Popen(['su', 'root', '-c',
+ 'wget -O %s %s' % (cache_path, url)],
+ cwd=None, env=None, stderr=-1, stdout=-1)\
+ .AndReturn(FakePOpen('Failed', '', 1))
+
+ self.m.ReplayAll()
+
+ md = cfn_helper.Metadata('teststack', None)
+ meta_out = md.get_nova_meta(cache_path=cache_path)
+ self.assertEqual(None, meta_out)
+ self.m.VerifyAll()
+
+ def test_get_tags(self):
+ self.m = mox.Mox()
+ self.addCleanup(self.m.UnsetStubs)
+
+ fake_tags = {'foo': 'fee',
+ 'apple': 'red'}
+ md_data = {"uuid": "f9431d18-d971-434d-9044-5b38f5b4646f",
+ "availability_zone": "nova",
+ "hostname": "as-wikidatabase-4ykioj3lgi57.novalocal",
+ "launch_index": 0,
+ "meta": fake_tags,
+ "public_keys": {"heat_key": "ssh-rsa etc...\n"},
+ "name": "as-WikiDatabase-4ykioj3lgi57"}
+ tags_expect = fake_tags
+ tags_expect['InstanceId'] = md_data['uuid']
+
+ md = cfn_helper.Metadata('teststack', None)
+
+ self.m.StubOutWithMock(md, 'get_nova_meta')
+ md.get_nova_meta().AndReturn(md_data)
+ self.m.ReplayAll()
+
+ tags = md.get_tags()
+ self.assertEqual(tags_expect, tags)
+ self.m.VerifyAll()
+
class TestSourcesHandler(MockPopenTestCase):
def test_apply_sources_empty(self):