From c42f3e46a75a61d65f341d356d37bc58357240c4 Mon Sep 17 00:00:00 2001 From: Clint Byrum Date: Wed, 3 Jul 2013 17:00:05 -0700 Subject: [PATCH] Add heat_local for locally injected metadata. Functionality has been added, but it is not called in main. --- os_collect_config/collect.py | 6 ++ os_collect_config/exc.py | 4 ++ os_collect_config/heat_local.py | 56 +++++++++++++++++ os_collect_config/tests/test_heat_local.py | 72 ++++++++++++++++++++++ 4 files changed, 138 insertions(+) create mode 100644 os_collect_config/heat_local.py create mode 100644 os_collect_config/tests/test_heat_local.py diff --git a/os_collect_config/collect.py b/os_collect_config/collect.py index 9b6220f..d30c58d 100644 --- a/os_collect_config/collect.py +++ b/os_collect_config/collect.py @@ -24,6 +24,7 @@ from os_collect_config import cfn from os_collect_config import common from os_collect_config import ec2 from os_collect_config import exc +from os_collect_config import heat_local from oslo.config import cfg opts = [ @@ -48,10 +49,15 @@ def setup_conf(): cfn_group = cfg.OptGroup(name='cfn', title='CloudFormation API Metadata options') + heat_local_group = cfg.OptGroup(name='heat-local', + title='Heat Local Metadata options') + CONF.register_group(ec2_group) CONF.register_group(cfn_group) + CONF.register_group(heat_local_group) CONF.register_cli_opts(ec2.opts, group='ec2') CONF.register_cli_opts(cfn.opts, group='cfn') + CONF.register_cli_opts(heat_local.opts, group='heat_local') CONF.register_cli_opts(opts) diff --git a/os_collect_config/exc.py b/os_collect_config/exc.py index b983398..d8bf515 100644 --- a/os_collect_config/exc.py +++ b/os_collect_config/exc.py @@ -12,3 +12,7 @@ class CfnMetadataNotAvailable(SourceNotAvailable): class CfnMetadataNotConfigured(SourceNotAvailable): """The cfn metadata service is not fully configured.""" + + +class HeatLocalMetadataNotAvailable(SourceNotAvailable): + """The local Heat metadata is not available.""" diff --git a/os_collect_config/heat_local.py b/os_collect_config/heat_local.py new file mode 100644 index 0000000..9d00a52 --- /dev/null +++ b/os_collect_config/heat_local.py @@ -0,0 +1,56 @@ +# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import os +from oslo.config import cfg + +from openstack.common import log +from os_collect_config import exc + +HEAT_METADATA_PATH = ['/var/lib/heat-cfntools/cfn-init-data'] +CONF = cfg.CONF + +opts = [ + cfg.MultiStrOpt('path', + default=HEAT_METADATA_PATH, + help='Local path(s) to read for Metadata.') +] +name = 'heat_local' +logger = log.getLogger(__name__) + + +class Collector(object): + def __init__(self, requests_impl=None): + pass + + def collect(self): + final_content = None + for path in cfg.CONF.heat_local.path: + if os.path.exists(path): + with open(path) as metadata: + try: + value = json.loads(metadata.read()) + except ValueError as e: + logger.info('%s is not valid JSON (%s)' % (path, e)) + continue + if final_content: + final_content.update(value) + else: + final_content = value + if not final_content: + logger.warn('Local metadata not found') + raise exc.HeatLocalMetadataNotAvailable + return final_content diff --git a/os_collect_config/tests/test_heat_local.py b/os_collect_config/tests/test_heat_local.py new file mode 100644 index 0000000..0e2bd98 --- /dev/null +++ b/os_collect_config/tests/test_heat_local.py @@ -0,0 +1,72 @@ +# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import fixtures +import json +import os.path +from oslo.config import cfg +import tempfile +import testtools +from testtools import matchers + +from os_collect_config import collect +from os_collect_config import exc +from os_collect_config import heat_local + + +META_DATA = {u'localstrA': u'A', + u'localint9': 9, + u'localmap_xy': { + u'x': 42, + u'y': 'foo', + }} + + +class TestHeatLocal(testtools.TestCase): + def setUp(self): + super(TestHeatLocal, self).setUp() + self.log = self.useFixture(fixtures.FakeLogger()) + collect.setup_conf() + self.orig_cfg_CONF = cfg.CONF + + def tearDown(self): + cfg.CONF = self.orig_cfg_CONF + cfg.CONF.reset() + super(TestHeatLocal, self).tearDown() + + def _call_collect(self, temp_name): + cfg.CONF.heat_local.path = [temp_name] + return heat_local.Collector().collect() + + def test_collect_heat_local(self): + with tempfile.NamedTemporaryFile() as md: + md.write(json.dumps(META_DATA)) + md.flush() + local_md = self._call_collect(md.name) + + self.assertThat(local_md, matchers.IsInstance(dict)) + + for k in ('localstrA', 'localint9', 'localmap_xy'): + self.assertIn(k, local_md) + self.assertEquals(local_md[k], META_DATA[k]) + + self.assertEquals('', self.log.output) + + def test_collect_ec2_nofile(self): + tdir = self.useFixture(fixtures.TempDir()) + test_path = os.path.join(tdir.path, 'does-not-exist.json') + self.assertRaises(exc.HeatLocalMetadataNotAvailable, + self._call_collect, test_path) + self.assertIn('Local metadata not found', self.log.output)