heat-templates/tests/software_config/test_hook_puppet.py
Martin Mágr 2636f415b8 Improve handling of Puppet output
Currently the output of Puppet run is written to os-collect-config log only.
If the run gets stuck, we have zero output from it, and have no chance
of guessing where it got stuck. This patch is fixing this issue and also adds
support for running Puppet in debug mode.

Due to big amount of data stdout and stderr in response during debug mode,
both are trimmed so that we won't exceed  max_json_body_size(1048576).

Resolves-bug: rhbz#1242396

Change-Id: Ie92d1714a8d7e59d347474039be999bd3a2b542f
2015-10-05 08:13:17 +00:00

233 lines
7.9 KiB
Python

#
# 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 copy
import json
import os
import fixtures
from tests.software_config import common
class HookPuppetTest(common.RunScriptTest):
data = {
'id': '1234',
'creation_time': '2015-07-16T11:40:20',
'name': 'fake_resource_name',
'group': 'puppet',
'options': {
'enable_hiera': True,
'enable_facter': True,
'enable_debug': True,
},
'inputs': [
{'name': 'foo', 'value': 'bar'},
{'name': 'another', 'value': 'input'}
],
'outputs': [
{'name': 'first_output'},
{'name': 'second_output'}
],
'config': 'the puppet script'
}
def setUp(self):
super(HookPuppetTest, self).setUp()
self.hook_path = self.relative_path(
__file__,
'../..',
'hot/software-config/elements',
'heat-config-puppet/install.d/hook-puppet.py')
self.fake_tool_path = self.relative_path(
__file__,
'config-tool-fake.py')
self.working_dir = self.useFixture(fixtures.TempDir())
self.outputs_dir = self.useFixture(fixtures.TempDir())
self.log_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_LOGDIR': self.log_dir.join(),
'HEAT_PUPPET_HIERA_DATADIR': self.hiera_datadir.join(),
'HEAT_PUPPET_CMD': self.fake_tool_path,
'TEST_STATE_PATH': self.test_state_path,
})
def test_hook(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')
self.assertEqual(
[
self.fake_tool_path,
'apply',
'--detailed-exitcodes',
'--debug',
puppet_script
],
state['args'])
self.assertEqual('bar', state['env']['FACTER_foo'])
self.assertEqual('input', state['env']['FACTER_another'])
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())
def test_hook_no_debug(self):
self.data['options']['enable_debug'] = False
self.env.update({
'TEST_RESPONSE': json.dumps({
'stdout': 'success',
'stderr': '',
}),
})
returncode, stdout, stderr = self.run_cmd(
[self.hook_path], self.env, json.dumps(self.data))
state = self.json_from_file(self.test_state_path)
puppet_script = self.working_dir.join('1234.pp')
self.assertEqual(
[
self.fake_tool_path,
'apply',
'--detailed-exitcodes',
puppet_script
],
state['args'])
self.data['options']['enable_debug'] = True
def test_hook_puppet_failed(self):
self.env.update({
'TEST_RESPONSE': json.dumps({
'stdout': 'puppet failed',
'stderr': 'bad thing happened',
'returncode': 4
}),
})
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 failed',
'deploy_stderr': 'bad thing happened',
'deploy_status_code': 4,
}, json.loads(stdout))
state = self.json_from_file(self.test_state_path)
puppet_script = self.working_dir.join('1234.pp')
self.assertEqual(
[
self.fake_tool_path,
'apply',
'--detailed-exitcodes',
'--debug',
puppet_script
],
state['args'])
self.assertEqual('bar', state['env']['FACTER_foo'])
self.assertEqual('input', state['env']['FACTER_another'])
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())
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',
}
}),
})
modulepath = self.working_dir.join()
data = copy.deepcopy(self.data)
data['options']['modulepath'] = modulepath
data['options']['tags'] = 'package,file'
returncode, stdout, stderr = self.run_cmd(
[self.hook_path], self.env, json.dumps(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',
'--modulepath',
modulepath,
'--tags',
'package,file',
'--debug',
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()))