Merge "Integration test for software-config tools"
This commit is contained in:
commit
69a3599767
@ -85,6 +85,9 @@ IntegrationTestGroup = [
|
|||||||
cfg.IntOpt('tenant_network_mask_bits',
|
cfg.IntOpt('tenant_network_mask_bits',
|
||||||
default=28,
|
default=28,
|
||||||
help="The mask bits for tenant ipv4 subnets"),
|
help="The mask bits for tenant ipv4 subnets"),
|
||||||
|
cfg.BoolOpt('skip_software_config_tests',
|
||||||
|
default=True,
|
||||||
|
help="Skip software config deployment tests"),
|
||||||
cfg.IntOpt('volume_size',
|
cfg.IntOpt('volume_size',
|
||||||
default=1,
|
default=1,
|
||||||
help='Default size in GB for volumes created by volumes tests'),
|
help='Default size in GB for volumes created by volumes tests'),
|
||||||
|
@ -311,6 +311,7 @@ class HeatIntegrationTest(testscenarios.WithScenarios,
|
|||||||
|
|
||||||
stack = self.client.stacks.get(name)
|
stack = self.client.stacks.get(name)
|
||||||
stack_identifier = '%s/%s' % (name, stack.id)
|
stack_identifier = '%s/%s' % (name, stack.id)
|
||||||
|
if expected_status:
|
||||||
self._wait_for_stack_status(stack_identifier, expected_status)
|
self._wait_for_stack_status(stack_identifier, expected_status)
|
||||||
return stack_identifier
|
return stack_identifier
|
||||||
|
|
||||||
|
@ -67,6 +67,9 @@
|
|||||||
# The mask bits for tenant ipv4 subnets (integer value)
|
# The mask bits for tenant ipv4 subnets (integer value)
|
||||||
#tenant_network_mask_bits = 28
|
#tenant_network_mask_bits = 28
|
||||||
|
|
||||||
|
# Skip software config deployment tests (boolean value)
|
||||||
|
#skip_software_config_tests = true
|
||||||
|
|
||||||
# Default size in GB for volumes created by volumes tests (integer value)
|
# Default size in GB for volumes created by volumes tests (integer value)
|
||||||
#volume_size = 1
|
#volume_size = 1
|
||||||
|
|
||||||
|
@ -0,0 +1,174 @@
|
|||||||
|
heat_template_version: 2014-10-16
|
||||||
|
parameters:
|
||||||
|
key_name:
|
||||||
|
type: string
|
||||||
|
flavor:
|
||||||
|
type: string
|
||||||
|
image:
|
||||||
|
type: string
|
||||||
|
network:
|
||||||
|
type: string
|
||||||
|
signal_transport:
|
||||||
|
type: string
|
||||||
|
default: CFN_SIGNAL
|
||||||
|
dep1_foo:
|
||||||
|
default: fooooo
|
||||||
|
type: string
|
||||||
|
dep1_bar:
|
||||||
|
default: baaaaa
|
||||||
|
type: string
|
||||||
|
dep2a_bar:
|
||||||
|
type: string
|
||||||
|
default: barrr
|
||||||
|
dep3_foo:
|
||||||
|
default: fo
|
||||||
|
type: string
|
||||||
|
dep3_bar:
|
||||||
|
default: ba
|
||||||
|
type: string
|
||||||
|
|
||||||
|
resources:
|
||||||
|
|
||||||
|
the_sg:
|
||||||
|
type: OS::Neutron::SecurityGroup
|
||||||
|
properties:
|
||||||
|
name: the_sg
|
||||||
|
description: Ping and SSH
|
||||||
|
rules:
|
||||||
|
- protocol: icmp
|
||||||
|
- protocol: tcp
|
||||||
|
port_range_min: 22
|
||||||
|
port_range_max: 22
|
||||||
|
|
||||||
|
cfg1:
|
||||||
|
type: OS::Heat::SoftwareConfig
|
||||||
|
properties:
|
||||||
|
group: script
|
||||||
|
inputs:
|
||||||
|
- name: foo
|
||||||
|
- name: bar
|
||||||
|
outputs:
|
||||||
|
- name: result
|
||||||
|
config: {get_file: cfg1.sh}
|
||||||
|
|
||||||
|
cfg2a:
|
||||||
|
type: OS::Heat::StructuredConfig
|
||||||
|
properties:
|
||||||
|
group: cfn-init
|
||||||
|
inputs:
|
||||||
|
- name: bar
|
||||||
|
config:
|
||||||
|
config:
|
||||||
|
files:
|
||||||
|
/tmp/cfn-init-foo:
|
||||||
|
content:
|
||||||
|
get_input: bar
|
||||||
|
mode: '000644'
|
||||||
|
|
||||||
|
cfg2b:
|
||||||
|
type: OS::Heat::SoftwareConfig
|
||||||
|
properties:
|
||||||
|
group: script
|
||||||
|
outputs:
|
||||||
|
- name: result
|
||||||
|
config: |
|
||||||
|
#!/bin/sh
|
||||||
|
echo -n "The file /tmp/cfn-init-foo contains `cat /tmp/cfn-init-foo` for server $deploy_server_id during $deploy_action" > $heat_outputs_path.result
|
||||||
|
|
||||||
|
cfg3:
|
||||||
|
type: OS::Heat::SoftwareConfig
|
||||||
|
properties:
|
||||||
|
group: puppet
|
||||||
|
inputs:
|
||||||
|
- name: foo
|
||||||
|
- name: bar
|
||||||
|
outputs:
|
||||||
|
- name: result
|
||||||
|
config: {get_file: cfg3.pp}
|
||||||
|
|
||||||
|
dep1:
|
||||||
|
type: OS::Heat::SoftwareDeployment
|
||||||
|
properties:
|
||||||
|
config:
|
||||||
|
get_resource: cfg1
|
||||||
|
server:
|
||||||
|
get_resource: server
|
||||||
|
input_values:
|
||||||
|
foo: {get_param: dep1_foo}
|
||||||
|
bar: {get_param: dep1_bar}
|
||||||
|
signal_transport: {get_param: signal_transport}
|
||||||
|
|
||||||
|
dep2a:
|
||||||
|
type: OS::Heat::StructuredDeployment
|
||||||
|
properties:
|
||||||
|
name: 10_dep2a
|
||||||
|
signal_transport: NO_SIGNAL
|
||||||
|
config:
|
||||||
|
get_resource: cfg2a
|
||||||
|
server:
|
||||||
|
get_resource: server
|
||||||
|
input_values:
|
||||||
|
bar: {get_param: dep2a_bar}
|
||||||
|
|
||||||
|
dep2b:
|
||||||
|
type: OS::Heat::SoftwareDeployment
|
||||||
|
properties:
|
||||||
|
name: 20_dep2b
|
||||||
|
config:
|
||||||
|
get_resource: cfg2b
|
||||||
|
server:
|
||||||
|
get_resource: server
|
||||||
|
signal_transport: {get_param: signal_transport}
|
||||||
|
|
||||||
|
dep3:
|
||||||
|
type: OS::Heat::SoftwareDeployment
|
||||||
|
properties:
|
||||||
|
config:
|
||||||
|
get_resource: cfg3
|
||||||
|
server:
|
||||||
|
get_resource: server
|
||||||
|
input_values:
|
||||||
|
foo: {get_param: dep3_foo}
|
||||||
|
bar: {get_param: dep3_bar}
|
||||||
|
signal_transport: {get_param: signal_transport}
|
||||||
|
|
||||||
|
cfg_user_data:
|
||||||
|
type: OS::Heat::SoftwareConfig
|
||||||
|
properties:
|
||||||
|
config: |
|
||||||
|
#!/bin/sh
|
||||||
|
echo "user data script"
|
||||||
|
|
||||||
|
server:
|
||||||
|
type: OS::Nova::Server
|
||||||
|
properties:
|
||||||
|
image: {get_param: image}
|
||||||
|
flavor: {get_param: flavor}
|
||||||
|
key_name: {get_param: key_name}
|
||||||
|
security_groups:
|
||||||
|
- {get_resource: the_sg}
|
||||||
|
networks:
|
||||||
|
- network: {get_param: network}
|
||||||
|
user_data_format: SOFTWARE_CONFIG
|
||||||
|
software_config_transport: POLL_TEMP_URL
|
||||||
|
user_data: {get_resource: cfg_user_data}
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
res1:
|
||||||
|
value:
|
||||||
|
result: {get_attr: [dep1, result]}
|
||||||
|
stdout: {get_attr: [dep1, deploy_stdout]}
|
||||||
|
stderr: {get_attr: [dep1, deploy_stderr]}
|
||||||
|
status_code: {get_attr: [dep1, deploy_status_code]}
|
||||||
|
res2:
|
||||||
|
value:
|
||||||
|
result: {get_attr: [dep2b, result]}
|
||||||
|
stdout: {get_attr: [dep2b, deploy_stdout]}
|
||||||
|
stderr: {get_attr: [dep2b, deploy_stderr]}
|
||||||
|
status_code: {get_attr: [dep2b, deploy_status_code]}
|
||||||
|
res3:
|
||||||
|
value:
|
||||||
|
result: {get_attr: [dep3, result]}
|
||||||
|
stdout: {get_attr: [dep3, deploy_stdout]}
|
||||||
|
stderr: {get_attr: [dep3, deploy_stderr]}
|
||||||
|
status_code: {get_attr: [dep3, deploy_status_code]}
|
158
heat_integrationtests/scenario/test_server_software_config.py
Normal file
158
heat_integrationtests/scenario/test_server_software_config.py
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
# 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 six
|
||||||
|
|
||||||
|
from heat_integrationtests.common import exceptions
|
||||||
|
from heat_integrationtests.common import test
|
||||||
|
|
||||||
|
CFG1_SH = '''#!/bin/sh
|
||||||
|
echo "Writing to /tmp/$bar"
|
||||||
|
echo $foo > /tmp/$bar
|
||||||
|
echo -n "The file /tmp/$bar contains `cat /tmp/$bar` for server \
|
||||||
|
$deploy_server_id during $deploy_action" > $heat_outputs_path.result
|
||||||
|
echo "Written to /tmp/$bar"
|
||||||
|
echo "Output to stderr" 1>&2
|
||||||
|
'''
|
||||||
|
|
||||||
|
CFG3_PP = '''file {'barfile':
|
||||||
|
ensure => file,
|
||||||
|
mode => 0644,
|
||||||
|
path => "/tmp/$::bar",
|
||||||
|
content => "$::foo",
|
||||||
|
}
|
||||||
|
file {'output_result':
|
||||||
|
ensure => file,
|
||||||
|
path => "$::heat_outputs_path.result",
|
||||||
|
mode => 0644,
|
||||||
|
content => "The file /tmp/$::bar contains $::foo for server \
|
||||||
|
$::deploy_server_id during $::deploy_action",
|
||||||
|
}'''
|
||||||
|
|
||||||
|
|
||||||
|
class SoftwareConfigIntegrationTest(test.HeatIntegrationTest):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(SoftwareConfigIntegrationTest, self).setUp()
|
||||||
|
if self.conf.skip_software_config_tests:
|
||||||
|
self.skipTest('Testing software config disabled in conf, '
|
||||||
|
'skipping')
|
||||||
|
self.client = self.orchestration_client
|
||||||
|
self.template_name = 'test_server_software_config.yaml'
|
||||||
|
self.sub_dir = 'templates'
|
||||||
|
self.stack_name = self._stack_rand_name()
|
||||||
|
self.maxDiff = None
|
||||||
|
|
||||||
|
def launch_stack(self):
|
||||||
|
net = self._get_default_network()
|
||||||
|
self.parameters = {
|
||||||
|
'key_name': self.keypair_name,
|
||||||
|
'flavor': self.conf.instance_type,
|
||||||
|
'image': self.conf.image_ref,
|
||||||
|
'network': net['id']
|
||||||
|
}
|
||||||
|
|
||||||
|
# create the stack
|
||||||
|
self.template = self._load_template(__file__, self.template_name,
|
||||||
|
self.sub_dir)
|
||||||
|
self.stack_create(
|
||||||
|
stack_name=self.stack_name,
|
||||||
|
template=self.template,
|
||||||
|
parameters=self.parameters,
|
||||||
|
files={
|
||||||
|
'cfg1.sh': CFG1_SH,
|
||||||
|
'cfg3.pp': CFG3_PP
|
||||||
|
},
|
||||||
|
expected_status=None)
|
||||||
|
|
||||||
|
self.stack = self.client.stacks.get(self.stack_name)
|
||||||
|
self.stack_identifier = '%s/%s' % (self.stack_name, self.stack.id)
|
||||||
|
|
||||||
|
def check_stack(self):
|
||||||
|
sid = self.stack_identifier
|
||||||
|
for res in ('cfg2a', 'cfg2b', 'cfg1', 'cfg3', 'server'):
|
||||||
|
self._wait_for_resource_status(
|
||||||
|
sid, res, 'CREATE_COMPLETE')
|
||||||
|
|
||||||
|
server_resource = self.client.resources.get(sid, 'server')
|
||||||
|
server_id = server_resource.physical_resource_id
|
||||||
|
server = self.compute_client.servers.get(server_id)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# wait for each deployment to contribute their
|
||||||
|
# config to resource
|
||||||
|
for res in ('dep2b', 'dep1', 'dep3'):
|
||||||
|
self._wait_for_resource_status(
|
||||||
|
sid, res, 'CREATE_IN_PROGRESS')
|
||||||
|
|
||||||
|
server_metadata = self.client.resources.metadata(sid, 'server')
|
||||||
|
deployments = dict((d['name'], d) for d in
|
||||||
|
server_metadata['deployments'])
|
||||||
|
|
||||||
|
for res in ('dep2a', 'dep2b', 'dep1', 'dep3'):
|
||||||
|
self._wait_for_resource_status(
|
||||||
|
sid, res, 'CREATE_COMPLETE')
|
||||||
|
except (exceptions.StackResourceBuildErrorException,
|
||||||
|
exceptions.TimeoutException) as e:
|
||||||
|
self._log_console_output(servers=[server])
|
||||||
|
raise e
|
||||||
|
|
||||||
|
self._wait_for_stack_status(sid, 'CREATE_COMPLETE')
|
||||||
|
|
||||||
|
complete_server_metadata = self.client.resources.metadata(
|
||||||
|
sid, 'server')
|
||||||
|
# ensure any previously available deployments haven't changed so
|
||||||
|
# config isn't re-triggered
|
||||||
|
complete_deployments = dict((d['name'], d) for d in
|
||||||
|
complete_server_metadata['deployments'])
|
||||||
|
for k, v in six.iteritems(deployments):
|
||||||
|
self.assertEqual(v, complete_deployments[k])
|
||||||
|
|
||||||
|
stack = self.client.stacks.get(sid)
|
||||||
|
|
||||||
|
res1 = self._stack_output(stack, 'res1')
|
||||||
|
self.assertEqual(
|
||||||
|
'The file %s contains %s for server %s during %s' % (
|
||||||
|
'/tmp/baaaaa', 'fooooo', server_id, 'CREATE'),
|
||||||
|
res1['result'])
|
||||||
|
self.assertEqual(0, res1['status_code'])
|
||||||
|
self.assertEqual('Output to stderr\n', res1['stderr'])
|
||||||
|
self.assertTrue(len(res1['stdout']) > 0)
|
||||||
|
|
||||||
|
res2 = self._stack_output(stack, 'res2')
|
||||||
|
self.assertEqual(
|
||||||
|
'The file %s contains %s for server %s during %s' % (
|
||||||
|
'/tmp/cfn-init-foo', 'barrr', server_id, 'CREATE'),
|
||||||
|
res2['result'])
|
||||||
|
self.assertEqual(0, res2['status_code'])
|
||||||
|
self.assertEqual('', res2['stderr'])
|
||||||
|
self.assertEqual('', res2['stdout'])
|
||||||
|
|
||||||
|
res3 = self._stack_output(stack, 'res3')
|
||||||
|
self.assertEqual(
|
||||||
|
'The file %s contains %s for server %s during %s' % (
|
||||||
|
'/tmp/ba', 'fo', server_id, 'CREATE'),
|
||||||
|
res3['result'])
|
||||||
|
self.assertEqual(0, res3['status_code'])
|
||||||
|
self.assertEqual('', res3['stderr'])
|
||||||
|
self.assertTrue(len(res1['stdout']) > 0)
|
||||||
|
|
||||||
|
dep1_resource = self.client.resources.get(sid, 'dep1')
|
||||||
|
dep1_id = dep1_resource.physical_resource_id
|
||||||
|
dep1_dep = self.client.software_deployments.get(dep1_id)
|
||||||
|
self.assertIsNotNone(dep1_dep.updated_time)
|
||||||
|
self.assertNotEqual(dep1_dep.updated_time, dep1_dep.creation_time)
|
||||||
|
|
||||||
|
def test_server_software_config(self):
|
||||||
|
self.assign_keypair()
|
||||||
|
self.launch_stack()
|
||||||
|
self.check_stack()
|
Loading…
Reference in New Issue
Block a user