diff --git a/hot/software-config/elements/heat-config-puppet/README.rst b/hot/software-config/elements/heat-config-puppet/README.rst index 26225625..5cae8620 100644 --- a/hot/software-config/elements/heat-config-puppet/README.rst +++ b/hot/software-config/elements/heat-config-puppet/README.rst @@ -1,3 +1,9 @@ A hook which invokes ``puppet apply`` on the provided configuration. -Config inputs are passed in as facts, and output values are read from written-out -files. \ No newline at end of file + +Config inputs are passed in as facts and/or using hiera, and output values +are read from written-out files. + +Hook Options: +------------- + use_facter: default True. Set to True to pass puppet inputs via Facter + use_hiera: default False. Set to True to pass puppet inputs via Hiera diff --git a/hot/software-config/elements/heat-config-puppet/install.d/hook-puppet.py b/hot/software-config/elements/heat-config-puppet/install.d/hook-puppet.py index ec4a7866..0171e1f3 100755 --- a/hot/software-config/elements/heat-config-puppet/install.d/hook-puppet.py +++ b/hot/software-config/elements/heat-config-puppet/install.d/hook-puppet.py @@ -23,6 +23,8 @@ WORKING_DIR = os.environ.get('HEAT_PUPPET_WORKING', OUTPUTS_DIR = os.environ.get('HEAT_PUPPET_OUTPUTS', '/var/run/heat-config/heat-config-puppet') PUPPET_CMD = os.environ.get('HEAT_PUPPET_CMD', 'puppet') +HIERA_DATADIR = os.environ.get('HEAT_PUPPET_HIERA_DATADIR', + '/etc/puppet/hieradata') def prepare_dir(path): @@ -45,11 +47,29 @@ def main(argv=sys.argv): c = json.load(sys.stdin) + use_hiera = c['options'].get('enable_hiera', False) + use_facter = c['options'].get('enable_facter', True) + facts = {} + hiera = {} + for input in c['inputs']: input_name = input['name'] - fact_name = 'FACTER_%s' % input_name - facts[fact_name] = input.get('value', '') + input_value = input.get('value', '') + if use_facter: + fact_name = 'FACTER_%s' % input_name + facts[fact_name] = input_value + if use_hiera: + hiera[input_name] = input_value + + if use_hiera: + prepare_dir(HIERA_DATADIR) + hiera_data = os.path.join(HIERA_DATADIR, + 'heat_config_%s.json' % c['name']) + with os.fdopen(os.open(hiera_data, os.O_CREAT | os.O_WRONLY, 0o600), + 'w') as hiera_file: + hiera_file.write(json.dumps(hiera).encode('utf8')) + facts['FACTER_deploy_config_name'] = c['name'] fn = os.path.join(WORKING_DIR, '%s.pp' % c['id']) heat_outputs_path = os.path.join(OUTPUTS_DIR, c['id']) diff --git a/tests/software_config/test_hook_puppet.py b/tests/software_config/test_hook_puppet.py index a7f25344..16ec2f3c 100644 --- a/tests/software_config/test_hook_puppet.py +++ b/tests/software_config/test_hook_puppet.py @@ -23,7 +23,12 @@ class HookPuppetTest(common.RunScriptTest): data = { 'id': '1234', + 'name': 'fake_resource_name', 'group': 'puppet', + 'options': { + 'enable_hiera': True, + 'enable_facter': True, + }, 'inputs': [ {'name': 'foo', 'value': 'bar'}, {'name': 'another', 'value': 'input'} @@ -49,12 +54,14 @@ class HookPuppetTest(common.RunScriptTest): self.working_dir = self.useFixture(fixtures.TempDir()) self.outputs_dir = self.useFixture(fixtures.TempDir()) + self.hiera_datadir = self.useFixture(fixtures.TempDir()) self.test_state_path = self.outputs_dir.join('test_state.json') self.env = os.environ.copy() self.env.update({ 'HEAT_PUPPET_WORKING': self.working_dir.join(), 'HEAT_PUPPET_OUTPUTS': self.outputs_dir.join(), + 'HEAT_PUPPET_HIERA_DATADIR': self.hiera_datadir.join(), 'HEAT_PUPPET_CMD': self.fake_tool_path, 'TEST_STATE_PATH': self.test_state_path, }) @@ -137,3 +144,50 @@ class HookPuppetTest(common.RunScriptTest): state['env']['FACTER_heat_outputs_path']) with open(puppet_script) as f: self.assertEqual('the puppet script', f.read()) + + def test_hook_hiera(self): + + self.env.update({ + 'TEST_RESPONSE': json.dumps({ + 'stdout': 'puppet success', + 'stderr': 'thing happened', + 'files': { + self.outputs_dir.join('1234.first_output'): 'output 1', + self.outputs_dir.join('1234.second_output'): 'output 2', + } + }), + }) + returncode, stdout, stderr = self.run_cmd( + [self.hook_path], self.env, json.dumps(self.data)) + + self.assertEqual(0, returncode, stderr) + self.assertEqual({ + 'deploy_stdout': 'puppet success', + 'deploy_stderr': 'thing happened', + 'deploy_status_code': 0, + 'first_output': 'output 1', + 'second_output': 'output 2', + }, json.loads(stdout)) + + state = self.json_from_file(self.test_state_path) + puppet_script = self.working_dir.join('1234.pp') + hiera_datafile = self.hiera_datadir.join('heat_config_%s.json' + % self.data['name']) + self.assertEqual( + [ + self.fake_tool_path, + 'apply', + '--detailed-exitcodes', + puppet_script + ], + state['args']) + + self.assertEqual(self.outputs_dir.join('1234'), + state['env']['FACTER_heat_outputs_path']) + with open(puppet_script) as f: + self.assertEqual('the puppet script', f.read()) + with open(hiera_datafile) as f: + self.assertEqual({ + 'foo': 'bar', + 'another': 'input', + }, json.loads(f.read()))