Remove tests for Interop Tests for add-on trademark program
Remove tests which been planned to added to add-on trademark program. We now maintain these tests in heat tempest plugin. Change-Id: I458d39f988019c4f1d62c7e39a325a2082a98561
This commit is contained in:
parent
41cc012b34
commit
d2bf5ecf6a
@ -1,55 +0,0 @@
|
||||
defaults:
|
||||
request_headers:
|
||||
X-Auth-Token: $ENVIRON['OS_TOKEN']
|
||||
|
||||
tests:
|
||||
- name: environment with parameter
|
||||
POST: /stacks
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
data:
|
||||
files: {}
|
||||
disable_rollback: true
|
||||
parameters: {}
|
||||
stack_name: $ENVIRON['PREFIX']-envstack
|
||||
environment:
|
||||
parameters:
|
||||
test_val: test
|
||||
template:
|
||||
heat_template_version: '2016-04-08'
|
||||
parameters:
|
||||
test_val:
|
||||
type: string
|
||||
resources:
|
||||
test:
|
||||
type: OS::Heat::TestResource
|
||||
properties:
|
||||
value: {get_param: test_val}
|
||||
outputs:
|
||||
output_value:
|
||||
value: {get_attr: [test, output]}
|
||||
|
||||
status: 201
|
||||
response_headers:
|
||||
location: //stacks/$ENVIRON['PREFIX']-envstack/[a-f0-9-]+/
|
||||
|
||||
- name: poll for envstack CREATE_COMPLETE
|
||||
GET: $LOCATION
|
||||
redirects: True
|
||||
poll:
|
||||
count: 5
|
||||
delay: 1.0
|
||||
response_json_paths:
|
||||
$.stack.stack_status: CREATE_COMPLETE
|
||||
|
||||
- name: get stack output
|
||||
GET: $LAST_URL/outputs/output_value
|
||||
redirects: True
|
||||
status: 200
|
||||
response_json_paths:
|
||||
$.output.output_value: test
|
||||
|
||||
- name: delete envstack
|
||||
DELETE: /stacks/$ENVIRON['PREFIX']-envstack
|
||||
redirects: True
|
||||
status: 204
|
@ -1,90 +0,0 @@
|
||||
defaults:
|
||||
request_headers:
|
||||
X-Auth-Token: $ENVIRON['OS_TOKEN']
|
||||
|
||||
tests:
|
||||
- name: create stack with resources
|
||||
POST: /stacks
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
data:
|
||||
files: {}
|
||||
disable_rollback: true
|
||||
parameters: {}
|
||||
stack_name: $ENVIRON['PREFIX']-rsrcstack
|
||||
template:
|
||||
heat_template_version: '2016-04-08'
|
||||
parameters:
|
||||
test_val:
|
||||
type: string
|
||||
default: test
|
||||
resources:
|
||||
test:
|
||||
type: OS::Heat::TestResource
|
||||
properties:
|
||||
value: {get_param: test_val}
|
||||
|
||||
status: 201
|
||||
response_headers:
|
||||
location: //stacks/$ENVIRON['PREFIX']-rsrcstack/[a-f0-9-]+/
|
||||
|
||||
- name: poll for rsrcstack CREATE_COMPLETE
|
||||
GET: $LOCATION
|
||||
redirects: True
|
||||
poll:
|
||||
count: 5
|
||||
delay: 1.0
|
||||
response_json_paths:
|
||||
$.stack.stack_status: CREATE_COMPLETE
|
||||
|
||||
- name: list resources
|
||||
GET: $LAST_URL/resources
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
status: 200
|
||||
response_json_paths:
|
||||
$.resources[0].logical_resource_id: test
|
||||
$.resources[0].resource_status: CREATE_COMPLETE
|
||||
|
||||
- name: list filtered resources
|
||||
GET: $LAST_URL
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
query_parameters:
|
||||
type: OS::Nova::Server
|
||||
status: 200
|
||||
response_json_paths:
|
||||
$.resources: []
|
||||
|
||||
- name: show resource
|
||||
GET: $LAST_URL/test
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
status: 200
|
||||
response_json_paths:
|
||||
$.resource.attributes.output: test
|
||||
|
||||
- name: mark resource unhealthy
|
||||
PATCH: $LAST_URL
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
data:
|
||||
mark_unhealthy: true
|
||||
resource_status_reason: 'resource deleted'
|
||||
status: 200
|
||||
|
||||
- name: show unhealthy resource
|
||||
GET: $LAST_URL
|
||||
status: 200
|
||||
response_json_paths:
|
||||
$.resource.resource_status: CHECK_FAILED
|
||||
$.resource.resource_status_reason: 'resource deleted'
|
||||
|
||||
- name: signal resource
|
||||
POST: $LAST_URL/signal
|
||||
status: 400
|
||||
|
||||
- name: delete stack with resources
|
||||
DELETE: /stacks/$ENVIRON['PREFIX']-rsrcstack
|
||||
redirects: True
|
||||
status: 204
|
@ -1,24 +0,0 @@
|
||||
defaults:
|
||||
request_headers:
|
||||
X-Auth-Token: $ENVIRON['OS_TOKEN']
|
||||
|
||||
tests:
|
||||
- name: list resource types
|
||||
GET: /resource_types
|
||||
status: 200
|
||||
|
||||
- name: show resource type
|
||||
GET: /resource_types/OS::Heat::TestResource
|
||||
status: 200
|
||||
response_json_paths:
|
||||
$.support_status.status: SUPPORTED
|
||||
$.properties.wait_secs.default: 0
|
||||
|
||||
- name: resource type template
|
||||
GET: /resource_types/OS::Heat::TestResource/template
|
||||
query_parameters:
|
||||
template_type: hot
|
||||
status: 200
|
||||
response_json_paths:
|
||||
$.resources.TestResource.type: OS::Heat::TestResource
|
||||
$.heat_template_version: '2016-10-14'
|
@ -1,162 +0,0 @@
|
||||
defaults:
|
||||
request_headers:
|
||||
X-Auth-Token: $ENVIRON['OS_TOKEN']
|
||||
|
||||
tests:
|
||||
- name: stack list
|
||||
GET: /stacks
|
||||
status: 200
|
||||
response_headers:
|
||||
content-type: application/json
|
||||
|
||||
- name: create empty stack
|
||||
POST: /stacks
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
data:
|
||||
files: {}
|
||||
disable_rollback: true
|
||||
parameters: {}
|
||||
stack_name: $ENVIRON['PREFIX']-empty
|
||||
environment: {}
|
||||
template:
|
||||
heat_template_version: '2016-04-08'
|
||||
|
||||
status: 201
|
||||
response_headers:
|
||||
location: //stacks/$ENVIRON['PREFIX']-empty/[a-f0-9-]+/
|
||||
|
||||
|
||||
- name: poll for empty CREATE_COMPLETE
|
||||
GET: $LOCATION
|
||||
redirects: True
|
||||
poll:
|
||||
count: 5
|
||||
delay: 1.0
|
||||
response_json_paths:
|
||||
$.stack.stack_status: CREATE_COMPLETE
|
||||
|
||||
- name: show empty stack
|
||||
GET: $LAST_URL
|
||||
redirects: True
|
||||
status: 200
|
||||
|
||||
- name: delete empty stack
|
||||
DELETE: $LAST_URL
|
||||
redirects: True
|
||||
status: 204
|
||||
|
||||
- name: create stack
|
||||
POST: /stacks
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
data:
|
||||
files: {}
|
||||
disable_rollback: true
|
||||
parameters: {'test_val': value}
|
||||
stack_name: $ENVIRON['PREFIX']-stack
|
||||
template:
|
||||
heat_template_version: pike
|
||||
parameters:
|
||||
test_val:
|
||||
type: string
|
||||
resources:
|
||||
test:
|
||||
type: OS::Heat::TestResource
|
||||
properties:
|
||||
value: {get_param: test_val}
|
||||
outputs:
|
||||
output_value:
|
||||
value: {get_attr: [test, output]}
|
||||
|
||||
status: 201
|
||||
response_headers:
|
||||
location: //stacks/$ENVIRON['PREFIX']-stack/[a-f0-9-]+/
|
||||
|
||||
- name: poll for stack CREATE_COMPLETE
|
||||
GET: $LOCATION
|
||||
redirects: True
|
||||
poll:
|
||||
count: 5
|
||||
delay: 1.0
|
||||
response_json_paths:
|
||||
$.stack.stack_status: CREATE_COMPLETE
|
||||
|
||||
- name: show stack
|
||||
GET: $LAST_URL
|
||||
redirects: True
|
||||
status: 200
|
||||
|
||||
- name: update stack
|
||||
PUT: $LAST_URL
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
data:
|
||||
files: {}
|
||||
disable_rollback: true
|
||||
parameters: {'test_val': new_value}
|
||||
stack_name: $ENVIRON['PREFIX']-stack
|
||||
template:
|
||||
heat_template_version: pike
|
||||
parameters:
|
||||
test_val:
|
||||
type: string
|
||||
resources:
|
||||
test:
|
||||
type: OS::Heat::TestResource
|
||||
properties:
|
||||
value: {get_param: test_val}
|
||||
action_wait_secs:
|
||||
update: 1
|
||||
outputs:
|
||||
output_value:
|
||||
value: {get_attr: [test, output]}
|
||||
|
||||
status: 202
|
||||
|
||||
- name: poll for stack UPDATE_COMPLETE
|
||||
GET: $LAST_URL
|
||||
redirects: True
|
||||
poll:
|
||||
count: 5
|
||||
delay: 1.0
|
||||
response_json_paths:
|
||||
$.stack.stack_status: UPDATE_COMPLETE
|
||||
|
||||
- name: patch update stack
|
||||
PATCH: $LAST_URL
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
data:
|
||||
parameters: {'test_val': new_patched_value}
|
||||
|
||||
status: 202
|
||||
|
||||
- name: poll for stack patch UPDATE_COMPLETE
|
||||
GET: $LAST_URL
|
||||
redirects: True
|
||||
poll:
|
||||
count: 5
|
||||
delay: 1.0
|
||||
response_json_paths:
|
||||
$.stack.stack_status: UPDATE_COMPLETE
|
||||
$.stack.updated_time: /^(?!$HISTORY['poll for stack UPDATE_COMPLETE'].$RESPONSE['$.stack.updated_time'])/
|
||||
|
||||
- name: list stack outputs
|
||||
GET: $LAST_URL/outputs
|
||||
redirects: True
|
||||
status: 200
|
||||
response_json_paths:
|
||||
$.outputs[0].output_key: output_value
|
||||
|
||||
- name: get stack output
|
||||
GET: $LAST_URL/output_value
|
||||
redirects: True
|
||||
status: 200
|
||||
response_json_paths:
|
||||
$.output.output_value: new_patched_value
|
||||
|
||||
- name: delete stack
|
||||
DELETE: /stacks/$ENVIRON['PREFIX']-stack
|
||||
redirects: True
|
||||
status: 204
|
@ -1,37 +0,0 @@
|
||||
defaults:
|
||||
request_headers:
|
||||
X-Auth-Token: $ENVIRON['OS_TOKEN']
|
||||
|
||||
tests:
|
||||
- name: list template versions
|
||||
GET: /template_versions
|
||||
status: 200
|
||||
response_json_paths:
|
||||
$.template_versions[?(@.version='heat_template_version.2017-02-24')].type: hot
|
||||
|
||||
- name: list template functions
|
||||
GET: /template_versions/heat_template_version.2016-10-14/functions
|
||||
status: 200
|
||||
response_json_paths:
|
||||
$.template_functions[?(@.functions='get_file')].description:
|
||||
A function for including a file inline.
|
||||
|
||||
- name: template validate
|
||||
POST: /validate
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
data:
|
||||
template:
|
||||
heat_template_version: '2016-04-08'
|
||||
parameters:
|
||||
test_val:
|
||||
type: string
|
||||
resources:
|
||||
test:
|
||||
type: OS::Heat::TestResource
|
||||
properties:
|
||||
value: {get_param: test_val}
|
||||
outputs:
|
||||
output_value:
|
||||
value: {get_attr: [test, output]}
|
||||
status: 200
|
@ -1,44 +0,0 @@
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""A test module to exercise the Heat API with gabbi. """
|
||||
|
||||
import os
|
||||
|
||||
from gabbi import driver
|
||||
from six.moves.urllib import parse as urlparse
|
||||
|
||||
from heat_integrationtests.common import clients
|
||||
from heat_integrationtests.common import config
|
||||
from heat_integrationtests.common import test
|
||||
|
||||
TESTS_DIR = 'gabbits'
|
||||
|
||||
|
||||
def load_tests(loader, tests, pattern):
|
||||
"""Provide a TestSuite to the discovery process."""
|
||||
test_dir = os.path.join(os.path.dirname(__file__), TESTS_DIR)
|
||||
|
||||
conf = config.init_conf().heat_plugin
|
||||
if conf.auth_url is None:
|
||||
# It's not configured, let's not load tests
|
||||
return
|
||||
manager = clients.ClientManager(conf)
|
||||
endpoint = manager.identity_client.get_endpoint_url(
|
||||
'orchestration', conf.region)
|
||||
host = urlparse.urlparse(endpoint).hostname
|
||||
os.environ['OS_TOKEN'] = manager.identity_client.auth_token
|
||||
os.environ['PREFIX'] = test.rand_name('api')
|
||||
|
||||
return driver.build_tests(test_dir, loader, host=host,
|
||||
url=endpoint, test_loader_name=__name__)
|
@ -1,83 +0,0 @@
|
||||
# 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.
|
||||
|
||||
from heat_integrationtests.functional import functional_base
|
||||
|
||||
|
||||
class ExternalReferencesTest(functional_base.FunctionalTestsBase):
|
||||
|
||||
TEMPLATE = '''
|
||||
heat_template_version: 2016-10-14
|
||||
resources:
|
||||
test1:
|
||||
type: OS::Heat::TestResource
|
||||
'''
|
||||
TEMPLATE_WITH_EX_REF = '''
|
||||
heat_template_version: 2016-10-14
|
||||
resources:
|
||||
test1:
|
||||
type: OS::Heat::TestResource
|
||||
external_id: foobar
|
||||
outputs:
|
||||
str:
|
||||
value: {get_resource: test1}
|
||||
'''
|
||||
|
||||
def test_create_with_external_ref(self):
|
||||
stack_name = self._stack_rand_name()
|
||||
stack_identifier = self.stack_create(
|
||||
stack_name=stack_name,
|
||||
template=self.TEMPLATE_WITH_EX_REF,
|
||||
files={},
|
||||
disable_rollback=True,
|
||||
parameters={},
|
||||
environment={}
|
||||
)
|
||||
|
||||
stack = self.client.stacks.get(stack_identifier)
|
||||
|
||||
self._wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
|
||||
expected_resources = {'test1': 'OS::Heat::TestResource'}
|
||||
self.assertEqual(expected_resources,
|
||||
self.list_resources(stack_identifier))
|
||||
stack = self.client.stacks.get(stack_identifier)
|
||||
self.assertEqual(
|
||||
[{'description': 'No description given',
|
||||
'output_key': 'str',
|
||||
'output_value': 'foobar'}], stack.outputs)
|
||||
|
||||
def test_update_with_external_ref(self):
|
||||
stack_name = self._stack_rand_name()
|
||||
stack_identifier = self.stack_create(
|
||||
stack_name=stack_name,
|
||||
template=self.TEMPLATE,
|
||||
files={},
|
||||
disable_rollback=True,
|
||||
parameters={},
|
||||
environment={}
|
||||
)
|
||||
stack = self.client.stacks.get(stack_identifier)
|
||||
|
||||
self._wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
|
||||
expected_resources = {'test1': 'OS::Heat::TestResource'}
|
||||
self.assertEqual(expected_resources,
|
||||
self.list_resources(stack_identifier))
|
||||
stack = self.client.stacks.get(stack_identifier)
|
||||
self.assertEqual([], stack.outputs)
|
||||
|
||||
stack_name = stack_identifier.split('/')[0]
|
||||
kwargs = {'stack_id': stack_identifier, 'stack_name': stack_name,
|
||||
'template': self.TEMPLATE_WITH_EX_REF, 'files': {},
|
||||
'disable_rollback': True, 'parameters': {}, 'environment': {}
|
||||
}
|
||||
self.client.stacks.update(**kwargs)
|
||||
self._wait_for_stack_status(stack_identifier, 'UPDATE_FAILED')
|
@ -1,281 +0,0 @@
|
||||
# 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 yaml
|
||||
|
||||
from heat_integrationtests.functional import functional_base
|
||||
|
||||
|
||||
class HooksTest(functional_base.FunctionalTestsBase):
|
||||
|
||||
def setUp(self):
|
||||
super(HooksTest, self).setUp()
|
||||
self.template = {'heat_template_version': '2014-10-16',
|
||||
'resources': {
|
||||
'foo_step1': {'type': 'OS::Heat::RandomString'},
|
||||
'foo_step2': {'type': 'OS::Heat::RandomString',
|
||||
'depends_on': 'foo_step1'},
|
||||
'foo_step3': {'type': 'OS::Heat::RandomString',
|
||||
'depends_on': 'foo_step2'}}}
|
||||
|
||||
def test_hook_pre_create(self):
|
||||
env = {'resource_registry':
|
||||
{'resources':
|
||||
{'foo_step2':
|
||||
{'hooks': 'pre-create'}}}}
|
||||
# Note we don't wait for CREATE_COMPLETE, because we need to
|
||||
# signal to clear the hook before create will complete
|
||||
stack_identifier = self.stack_create(
|
||||
template=self.template,
|
||||
environment=env,
|
||||
expected_status='CREATE_IN_PROGRESS')
|
||||
self._wait_for_resource_status(
|
||||
stack_identifier, 'foo_step1', 'CREATE_COMPLETE')
|
||||
self._wait_for_resource_status(
|
||||
stack_identifier, 'foo_step2', 'INIT_COMPLETE')
|
||||
ev = self.wait_for_event_with_reason(
|
||||
stack_identifier,
|
||||
reason='CREATE paused until Hook pre-create is cleared',
|
||||
rsrc_name='foo_step2')
|
||||
self.assertEqual('INIT_COMPLETE', ev[0].resource_status)
|
||||
self.client.resources.signal(stack_identifier, 'foo_step2',
|
||||
data={'unset_hook': 'pre-create'})
|
||||
ev = self.wait_for_event_with_reason(
|
||||
stack_identifier,
|
||||
reason='Hook pre-create is cleared',
|
||||
rsrc_name='foo_step2')
|
||||
self.assertEqual('INIT_COMPLETE', ev[0].resource_status)
|
||||
self._wait_for_resource_status(
|
||||
stack_identifier, 'foo_step2', 'CREATE_COMPLETE')
|
||||
self._wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
|
||||
|
||||
def test_hook_pre_update_nochange(self):
|
||||
env = {'resource_registry':
|
||||
{'resources':
|
||||
{'foo_step2':
|
||||
{'hooks': 'pre-update'}}}}
|
||||
stack_identifier = self.stack_create(
|
||||
template=self.template,
|
||||
environment=env)
|
||||
res_before = self.client.resources.get(stack_identifier, 'foo_step2')
|
||||
# Note we don't wait for UPDATE_COMPLETE, because we need to
|
||||
# signal to clear the hook before update will complete
|
||||
self.update_stack(
|
||||
stack_identifier,
|
||||
template=self.template,
|
||||
environment=env,
|
||||
expected_status='UPDATE_IN_PROGRESS')
|
||||
|
||||
# Note when a hook is specified, the resource status doesn't change
|
||||
# when we hit the hook, so we look for the event, then assert the
|
||||
# state is unchanged.
|
||||
self._wait_for_resource_status(
|
||||
stack_identifier, 'foo_step2', 'CREATE_COMPLETE')
|
||||
ev = self.wait_for_event_with_reason(
|
||||
stack_identifier,
|
||||
reason='UPDATE paused until Hook pre-update is cleared',
|
||||
rsrc_name='foo_step2')
|
||||
self.assertEqual('CREATE_COMPLETE', ev[0].resource_status)
|
||||
self.client.resources.signal(stack_identifier, 'foo_step2',
|
||||
data={'unset_hook': 'pre-update'})
|
||||
ev = self.wait_for_event_with_reason(
|
||||
stack_identifier,
|
||||
reason='Hook pre-update is cleared',
|
||||
rsrc_name='foo_step2')
|
||||
self.assertEqual('CREATE_COMPLETE', ev[0].resource_status)
|
||||
self._wait_for_resource_status(
|
||||
stack_identifier, 'foo_step2', 'CREATE_COMPLETE')
|
||||
self._wait_for_stack_status(stack_identifier, 'UPDATE_COMPLETE')
|
||||
res_after = self.client.resources.get(stack_identifier, 'foo_step2')
|
||||
self.assertEqual(res_before.physical_resource_id,
|
||||
res_after.physical_resource_id)
|
||||
|
||||
def test_hook_pre_update_replace(self):
|
||||
env = {'resource_registry':
|
||||
{'resources':
|
||||
{'foo_step2':
|
||||
{'hooks': 'pre-update'}}}}
|
||||
stack_identifier = self.stack_create(
|
||||
template=self.template,
|
||||
environment=env)
|
||||
res_before = self.client.resources.get(stack_identifier, 'foo_step2')
|
||||
# Note we don't wait for UPDATE_COMPLETE, because we need to
|
||||
# signal to clear the hook before update will complete
|
||||
self.template['resources']['foo_step2']['properties'] = {'length': 10}
|
||||
self.update_stack(
|
||||
stack_identifier,
|
||||
template=self.template,
|
||||
environment=env,
|
||||
expected_status='UPDATE_IN_PROGRESS')
|
||||
|
||||
# Note when a hook is specified, the resource status doesn't change
|
||||
# when we hit the hook, so we look for the event, then assert the
|
||||
# state is unchanged.
|
||||
self._wait_for_resource_status(
|
||||
stack_identifier, 'foo_step2', 'CREATE_COMPLETE')
|
||||
ev = self.wait_for_event_with_reason(
|
||||
stack_identifier,
|
||||
reason='UPDATE paused until Hook pre-update is cleared',
|
||||
rsrc_name='foo_step2')
|
||||
self.assertEqual('CREATE_COMPLETE', ev[0].resource_status)
|
||||
self.client.resources.signal(stack_identifier, 'foo_step2',
|
||||
data={'unset_hook': 'pre-update'})
|
||||
ev = self.wait_for_event_with_reason(
|
||||
stack_identifier,
|
||||
reason='Hook pre-update is cleared',
|
||||
rsrc_name='foo_step2')
|
||||
self.assertEqual('CREATE_COMPLETE', ev[0].resource_status)
|
||||
self._wait_for_resource_status(
|
||||
stack_identifier, 'foo_step2', 'CREATE_COMPLETE')
|
||||
self._wait_for_stack_status(stack_identifier, 'UPDATE_COMPLETE')
|
||||
res_after = self.client.resources.get(stack_identifier, 'foo_step2')
|
||||
self.assertNotEqual(res_before.physical_resource_id,
|
||||
res_after.physical_resource_id)
|
||||
|
||||
def test_hook_pre_update_in_place(self):
|
||||
env = {'resource_registry':
|
||||
{'resources':
|
||||
{'rg':
|
||||
{'hooks': 'pre-update'}}}}
|
||||
template = {'heat_template_version': '2014-10-16',
|
||||
'resources': {
|
||||
'rg': {
|
||||
'type': 'OS::Heat::ResourceGroup',
|
||||
'properties': {
|
||||
'count': 1,
|
||||
'resource_def': {
|
||||
'type': 'OS::Heat::RandomString'}}}}}
|
||||
# Note we don't wait for CREATE_COMPLETE, because we need to
|
||||
# signal to clear the hook before create will complete
|
||||
stack_identifier = self.stack_create(
|
||||
template=template,
|
||||
environment=env)
|
||||
res_before = self.client.resources.get(stack_identifier, 'rg')
|
||||
template['resources']['rg']['properties']['count'] = 2
|
||||
self.update_stack(
|
||||
stack_identifier,
|
||||
template=template,
|
||||
environment=env,
|
||||
expected_status='UPDATE_IN_PROGRESS')
|
||||
|
||||
# Note when a hook is specified, the resource status doesn't change
|
||||
# when we hit the hook, so we look for the event, then assert the
|
||||
# state is unchanged.
|
||||
self._wait_for_resource_status(
|
||||
stack_identifier, 'rg', 'CREATE_COMPLETE')
|
||||
ev = self.wait_for_event_with_reason(
|
||||
stack_identifier,
|
||||
reason='UPDATE paused until Hook pre-update is cleared',
|
||||
rsrc_name='rg')
|
||||
self.assertEqual('CREATE_COMPLETE', ev[0].resource_status)
|
||||
self.client.resources.signal(stack_identifier, 'rg',
|
||||
data={'unset_hook': 'pre-update'})
|
||||
|
||||
ev = self.wait_for_event_with_reason(
|
||||
stack_identifier,
|
||||
reason='Hook pre-update is cleared',
|
||||
rsrc_name='rg')
|
||||
self.assertEqual('CREATE_COMPLETE', ev[0].resource_status)
|
||||
self._wait_for_stack_status(stack_identifier, 'UPDATE_COMPLETE')
|
||||
res_after = self.client.resources.get(stack_identifier, 'rg')
|
||||
self.assertEqual(res_before.physical_resource_id,
|
||||
res_after.physical_resource_id)
|
||||
|
||||
def test_hook_pre_create_nested(self):
|
||||
files = {'nested.yaml': yaml.safe_dump(self.template)}
|
||||
env = {'resource_registry':
|
||||
{'resources':
|
||||
{'nested':
|
||||
{'foo_step2':
|
||||
{'hooks': 'pre-create'}}}}}
|
||||
template = {'heat_template_version': '2014-10-16',
|
||||
'resources': {
|
||||
'nested': {'type': 'nested.yaml'}}}
|
||||
# Note we don't wait for CREATE_COMPLETE, because we need to
|
||||
# signal to clear the hook before create will complete
|
||||
stack_identifier = self.stack_create(
|
||||
template=template,
|
||||
environment=env,
|
||||
files=files,
|
||||
expected_status='CREATE_IN_PROGRESS')
|
||||
self._wait_for_resource_status(stack_identifier, 'nested',
|
||||
'CREATE_IN_PROGRESS')
|
||||
nested_identifier = self.assert_resource_is_a_stack(
|
||||
stack_identifier, 'nested', wait=True)
|
||||
self._wait_for_resource_status(
|
||||
nested_identifier, 'foo_step1', 'CREATE_COMPLETE')
|
||||
self._wait_for_resource_status(
|
||||
nested_identifier, 'foo_step2', 'INIT_COMPLETE')
|
||||
ev = self.wait_for_event_with_reason(
|
||||
nested_identifier,
|
||||
reason='CREATE paused until Hook pre-create is cleared',
|
||||
rsrc_name='foo_step2')
|
||||
self.assertEqual('INIT_COMPLETE', ev[0].resource_status)
|
||||
self.client.resources.signal(nested_identifier, 'foo_step2',
|
||||
data={'unset_hook': 'pre-create'})
|
||||
ev = self.wait_for_event_with_reason(
|
||||
nested_identifier,
|
||||
reason='Hook pre-create is cleared',
|
||||
rsrc_name='foo_step2')
|
||||
self.assertEqual('INIT_COMPLETE', ev[0].resource_status)
|
||||
self._wait_for_resource_status(
|
||||
nested_identifier, 'foo_step2', 'CREATE_COMPLETE')
|
||||
self._wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
|
||||
|
||||
def test_hook_pre_create_wildcard(self):
|
||||
env = {'resource_registry':
|
||||
{'resources':
|
||||
{'foo_*':
|
||||
{'hooks': 'pre-create'}}}}
|
||||
# Note we don't wait for CREATE_COMPLETE, because we need to
|
||||
# signal to clear the hook before create will complete
|
||||
stack_identifier = self.stack_create(
|
||||
template=self.template,
|
||||
environment=env,
|
||||
expected_status='CREATE_IN_PROGRESS')
|
||||
self._wait_for_resource_status(
|
||||
stack_identifier, 'foo_step1', 'INIT_COMPLETE')
|
||||
self.wait_for_event_with_reason(
|
||||
stack_identifier,
|
||||
reason='CREATE paused until Hook pre-create is cleared',
|
||||
rsrc_name='foo_step1')
|
||||
self.client.resources.signal(stack_identifier, 'foo_step1',
|
||||
data={'unset_hook': 'pre-create'})
|
||||
self.wait_for_event_with_reason(
|
||||
stack_identifier,
|
||||
reason='Hook pre-create is cleared',
|
||||
rsrc_name='foo_step1')
|
||||
self._wait_for_resource_status(
|
||||
stack_identifier, 'foo_step2', 'INIT_COMPLETE')
|
||||
self.wait_for_event_with_reason(
|
||||
stack_identifier,
|
||||
reason='CREATE paused until Hook pre-create is cleared',
|
||||
rsrc_name='foo_step2')
|
||||
self.client.resources.signal(stack_identifier, 'foo_step2',
|
||||
data={'unset_hook': 'pre-create'})
|
||||
self.wait_for_event_with_reason(
|
||||
stack_identifier,
|
||||
reason='Hook pre-create is cleared',
|
||||
rsrc_name='foo_step2')
|
||||
self._wait_for_resource_status(
|
||||
stack_identifier, 'foo_step3', 'INIT_COMPLETE')
|
||||
self.wait_for_event_with_reason(
|
||||
stack_identifier,
|
||||
reason='CREATE paused until Hook pre-create is cleared',
|
||||
rsrc_name='foo_step3')
|
||||
self.client.resources.signal(stack_identifier, 'foo_step3',
|
||||
data={'unset_hook': 'pre-create'})
|
||||
self.wait_for_event_with_reason(
|
||||
stack_identifier,
|
||||
reason='Hook pre-create is cleared',
|
||||
rsrc_name='foo_step3')
|
||||
self._wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
|
@ -1,237 +0,0 @@
|
||||
# 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.
|
||||
|
||||
from heat_integrationtests.functional import functional_base
|
||||
from heatclient import exc
|
||||
import six
|
||||
|
||||
|
||||
class StackPreviewTest(functional_base.FunctionalTestsBase):
|
||||
template = '''
|
||||
heat_template_version: 2015-04-30
|
||||
parameters:
|
||||
incomming:
|
||||
type: string
|
||||
resources:
|
||||
one:
|
||||
type: OS::Heat::TestResource
|
||||
properties:
|
||||
value: fred
|
||||
two:
|
||||
type: OS::Heat::TestResource
|
||||
properties:
|
||||
value: {get_param: incomming}
|
||||
depends_on: one
|
||||
outputs:
|
||||
main_out:
|
||||
value: {get_attr: [two, output]}
|
||||
'''
|
||||
env = '''
|
||||
parameters:
|
||||
incomming: abc
|
||||
'''
|
||||
|
||||
def setUp(self):
|
||||
super(StackPreviewTest, self).setUp()
|
||||
self.client = self.orchestration_client
|
||||
self.project_id = self.identity_client.project_id
|
||||
|
||||
def _assert_resource(self, res, stack_name):
|
||||
self.assertEqual(stack_name, res['stack_name'])
|
||||
self.assertEqual('INIT', res['resource_action'])
|
||||
self.assertEqual('COMPLETE', res['resource_status'])
|
||||
for field in ('resource_status_reason', 'physical_resource_id',
|
||||
'description'):
|
||||
self.assertIn(field, res)
|
||||
self.assertEqual('', res[field])
|
||||
# 'creation_time' and 'updated_time' are None when preview
|
||||
for field in ('creation_time', 'updated_time'):
|
||||
self.assertIn(field, res)
|
||||
self.assertIsNone(res[field])
|
||||
self.assertIn('output', res['attributes'])
|
||||
|
||||
# resource_identity
|
||||
self.assertEqual(stack_name,
|
||||
res['resource_identity']['stack_name'])
|
||||
self.assertEqual('None', res['resource_identity']['stack_id'])
|
||||
self.assertEqual(self.project_id,
|
||||
res['resource_identity']['tenant'])
|
||||
self.assertEqual('/resources/%s' % res['resource_name'],
|
||||
res['resource_identity']['path'])
|
||||
# stack_identity
|
||||
self.assertEqual(stack_name,
|
||||
res['stack_identity']['stack_name'])
|
||||
self.assertEqual('None', res['stack_identity']['stack_id'])
|
||||
self.assertEqual(self.project_id,
|
||||
res['stack_identity']['tenant'])
|
||||
self.assertEqual('', res['stack_identity']['path'])
|
||||
|
||||
def _assert_results(self, result, stack_name):
|
||||
# global stuff.
|
||||
self.assertEqual(stack_name, result['stack_name'])
|
||||
self.assertTrue(result['disable_rollback'])
|
||||
self.assertEqual('None', result['id'])
|
||||
self.assertIsNone(result['parent'])
|
||||
self.assertEqual('No description', result['template_description'])
|
||||
|
||||
# parameters
|
||||
self.assertEqual('None', result['parameters']['OS::stack_id'])
|
||||
self.assertEqual(stack_name, result['parameters']['OS::stack_name'])
|
||||
self.assertEqual('abc', result['parameters']['incomming'])
|
||||
|
||||
def test_basic_pass(self):
|
||||
stack_name = self._stack_rand_name()
|
||||
result = self.client.stacks.preview(
|
||||
template=self.template,
|
||||
stack_name=stack_name,
|
||||
disable_rollback=True,
|
||||
environment=self.env).to_dict()
|
||||
|
||||
self._assert_results(result, stack_name)
|
||||
for res in result['resources']:
|
||||
self._assert_resource(res, stack_name)
|
||||
self.assertEqual('OS::Heat::TestResource',
|
||||
res['resource_type'])
|
||||
|
||||
# common properties
|
||||
self.assertFalse(res['properties']['fail'])
|
||||
self.assertEqual(0, res['properties']['wait_secs'])
|
||||
self.assertFalse(res['properties']['update_replace'])
|
||||
|
||||
if res['resource_name'] == 'one':
|
||||
self.assertEqual('fred', res['properties']['value'])
|
||||
self.assertEqual(['two'], res['required_by'])
|
||||
if res['resource_name'] == 'two':
|
||||
self.assertEqual('abc', res['properties']['value'])
|
||||
self.assertEqual([], res['required_by'])
|
||||
|
||||
def test_basic_fail(self):
|
||||
stack_name = self._stack_rand_name()
|
||||
|
||||
# break the template so it fails validation.
|
||||
wont_work = self.template.replace('get_param: incomming',
|
||||
'get_param: missing')
|
||||
excp = self.assertRaises(exc.HTTPBadRequest,
|
||||
self.client.stacks.preview,
|
||||
template=wont_work,
|
||||
stack_name=stack_name,
|
||||
disable_rollback=True,
|
||||
environment=self.env)
|
||||
|
||||
self.assertIn('Property error: : resources.two.properties.value: '
|
||||
': The Parameter (missing) was not provided.',
|
||||
six.text_type(excp))
|
||||
|
||||
def test_nested_pass(self):
|
||||
"""Nested stacks need to recurse down the stacks."""
|
||||
main_template = '''
|
||||
heat_template_version: 2015-04-30
|
||||
parameters:
|
||||
incomming:
|
||||
type: string
|
||||
resources:
|
||||
main:
|
||||
type: nested.yaml
|
||||
properties:
|
||||
value: {get_param: incomming}
|
||||
outputs:
|
||||
main_out:
|
||||
value: {get_attr: [main, output]}
|
||||
'''
|
||||
nested_template = '''
|
||||
heat_template_version: 2015-04-30
|
||||
parameters:
|
||||
value:
|
||||
type: string
|
||||
resources:
|
||||
nested:
|
||||
type: OS::Heat::TestResource
|
||||
properties:
|
||||
value: {get_param: value}
|
||||
outputs:
|
||||
output:
|
||||
value: {get_attr: [nested, output]}
|
||||
'''
|
||||
stack_name = self._stack_rand_name()
|
||||
result = self.client.stacks.preview(
|
||||
disable_rollback=True,
|
||||
stack_name=stack_name,
|
||||
template=main_template,
|
||||
files={'nested.yaml': nested_template},
|
||||
environment=self.env).to_dict()
|
||||
|
||||
self._assert_results(result, stack_name)
|
||||
|
||||
# nested resources return a list of their resources.
|
||||
res = result['resources'][0][0]
|
||||
nested_stack_name = '%s-%s' % (stack_name,
|
||||
res['parent_resource'])
|
||||
|
||||
self._assert_resource(res, nested_stack_name)
|
||||
self.assertEqual('OS::Heat::TestResource',
|
||||
res['resource_type'])
|
||||
|
||||
self.assertFalse(res['properties']['fail'])
|
||||
self.assertEqual(0, res['properties']['wait_secs'])
|
||||
self.assertFalse(res['properties']['update_replace'])
|
||||
|
||||
self.assertEqual('abc', res['properties']['value'])
|
||||
self.assertEqual([], res['required_by'])
|
||||
|
||||
def test_res_group_with_nested_template(self):
|
||||
main_template = '''
|
||||
heat_template_version: 2015-04-30
|
||||
resources:
|
||||
fixed_network:
|
||||
type: "OS::Neutron::Net"
|
||||
rg:
|
||||
type: "OS::Heat::ResourceGroup"
|
||||
properties:
|
||||
count: 1
|
||||
resource_def:
|
||||
type: nested.yaml
|
||||
properties:
|
||||
fixed_network_id: {get_resource: fixed_network}
|
||||
'''
|
||||
nested_template = '''
|
||||
heat_template_version: 2015-04-30
|
||||
|
||||
parameters:
|
||||
fixed_network_id:
|
||||
type: string
|
||||
resources:
|
||||
port:
|
||||
type: "OS::Neutron::Port"
|
||||
properties:
|
||||
network_id:
|
||||
get_param: fixed_network_id
|
||||
|
||||
'''
|
||||
stack_name = self._stack_rand_name()
|
||||
result = self.client.stacks.preview(
|
||||
disable_rollback=True,
|
||||
stack_name=stack_name,
|
||||
template=main_template,
|
||||
files={'nested.yaml': nested_template}).to_dict()
|
||||
|
||||
resource_names = []
|
||||
|
||||
def get_resource_names(resources):
|
||||
for item in resources:
|
||||
if isinstance(item, dict):
|
||||
resource_names.append(item['resource_name'])
|
||||
else:
|
||||
get_resource_names(item)
|
||||
get_resource_names(result['resources'])
|
||||
# ensure that fixed network and port here
|
||||
self.assertIn('fixed_network', resource_names)
|
||||
self.assertIn('port', resource_names)
|
@ -1,50 +0,0 @@
|
||||
# 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.
|
||||
|
||||
from heat_integrationtests.functional import functional_base
|
||||
|
||||
|
||||
test_template_depend = {
|
||||
'heat_template_version': '2013-05-23',
|
||||
'resources': {
|
||||
'test1': {
|
||||
'type': 'OS::Heat::TestResource',
|
||||
'properties': {
|
||||
'value': 'Test1',
|
||||
}
|
||||
},
|
||||
'test2': {
|
||||
'type': 'OS::Heat::TestResource',
|
||||
'depends_on': ['test1'],
|
||||
'properties': {
|
||||
'value': 'Test2',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ResourcesList(functional_base.FunctionalTestsBase):
|
||||
|
||||
def test_filtering_with_depend(self):
|
||||
stack_identifier = self.stack_create(template=test_template_depend)
|
||||
[test2] = self.client.resources.list(stack_identifier,
|
||||
filters={'name': 'test2'})
|
||||
|
||||
self.assertEqual('CREATE_COMPLETE', test2.resource_status)
|
||||
|
||||
def test_required_by(self):
|
||||
stack_identifier = self.stack_create(template=test_template_depend)
|
||||
[test1] = self.client.resources.list(stack_identifier,
|
||||
filters={'name': 'test1'})
|
||||
|
||||
self.assertEqual(['test2'], test1.required_by)
|
@ -12,174 +12,17 @@
|
||||
|
||||
import json
|
||||
import os
|
||||
import requests
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import yaml
|
||||
|
||||
from oslo_utils import timeutils
|
||||
|
||||
from heat_integrationtests.common import exceptions
|
||||
from heat_integrationtests.common import test
|
||||
from heat_integrationtests.functional import functional_base
|
||||
|
||||
|
||||
class ParallelDeploymentsTest(functional_base.FunctionalTestsBase):
|
||||
server_template = '''
|
||||
heat_template_version: "2013-05-23"
|
||||
parameters:
|
||||
flavor:
|
||||
type: string
|
||||
image:
|
||||
type: string
|
||||
network:
|
||||
type: string
|
||||
resources:
|
||||
server:
|
||||
type: OS::Nova::Server
|
||||
properties:
|
||||
image: {get_param: image}
|
||||
flavor: {get_param: flavor}
|
||||
user_data_format: SOFTWARE_CONFIG
|
||||
networks: [{network: {get_param: network}}]
|
||||
outputs:
|
||||
server:
|
||||
value: {get_resource: server}
|
||||
'''
|
||||
|
||||
config_template = '''
|
||||
heat_template_version: "2013-05-23"
|
||||
parameters:
|
||||
server:
|
||||
type: string
|
||||
resources:
|
||||
config:
|
||||
type: OS::Heat::SoftwareConfig
|
||||
properties:
|
||||
'''
|
||||
|
||||
deployment_snippet = '''
|
||||
type: OS::Heat::SoftwareDeployments
|
||||
properties:
|
||||
config: {get_resource: config}
|
||||
servers: {'0': {get_param: server}}
|
||||
'''
|
||||
|
||||
enable_cleanup = True
|
||||
|
||||
def test_deployments_metadata(self):
|
||||
parms = {'flavor': self.conf.minimal_instance_type,
|
||||
'network': self.conf.fixed_network_name,
|
||||
'image': self.conf.minimal_image_ref}
|
||||
stack_identifier = self.stack_create(
|
||||
parameters=parms,
|
||||
template=self.server_template,
|
||||
enable_cleanup=self.enable_cleanup)
|
||||
server_stack = self.client.stacks.get(stack_identifier)
|
||||
server = server_stack.outputs[0]['output_value']
|
||||
|
||||
config_stacks = []
|
||||
# add up to 3 stacks each with up to 3 deployments
|
||||
deploy_count = 0
|
||||
deploy_count = self.deploy_many_configs(
|
||||
stack_identifier,
|
||||
server,
|
||||
config_stacks,
|
||||
2,
|
||||
5,
|
||||
deploy_count)
|
||||
self.deploy_many_configs(
|
||||
stack_identifier,
|
||||
server,
|
||||
config_stacks,
|
||||
3,
|
||||
3,
|
||||
deploy_count)
|
||||
|
||||
self.signal_deployments(stack_identifier)
|
||||
for config_stack in config_stacks:
|
||||
self._wait_for_stack_status(config_stack, 'CREATE_COMPLETE')
|
||||
|
||||
def test_deployments_timeout_failed(self):
|
||||
parms = {'flavor': self.conf.minimal_instance_type,
|
||||
'network': self.conf.fixed_network_name,
|
||||
'image': self.conf.minimal_image_ref}
|
||||
stack_identifier = self.stack_create(
|
||||
parameters=parms,
|
||||
template=self.server_template,
|
||||
enable_cleanup=self.enable_cleanup)
|
||||
server_stack = self.client.stacks.get(stack_identifier)
|
||||
server = server_stack.outputs[0]['output_value']
|
||||
config_stack = self.deploy_config(server, 3, 1)
|
||||
self._wait_for_stack_status(config_stack, 'CREATE_FAILED')
|
||||
kwargs = {'server_id': server}
|
||||
|
||||
def check_deployment_status():
|
||||
sd_list = self.client.software_deployments.list(**kwargs)
|
||||
for sd in sd_list:
|
||||
if sd.status != 'FAILED':
|
||||
return False
|
||||
return True
|
||||
|
||||
self.assertTrue(test.call_until_true(
|
||||
20, 0, check_deployment_status))
|
||||
|
||||
def deploy_many_configs(self, stack, server, config_stacks,
|
||||
stack_count, deploys_per_stack,
|
||||
deploy_count_start):
|
||||
for a in range(stack_count):
|
||||
config_stacks.append(
|
||||
self.deploy_config(server, deploys_per_stack))
|
||||
|
||||
new_count = deploy_count_start + stack_count * deploys_per_stack
|
||||
self.wait_for_deploy_metadata_set(stack, new_count)
|
||||
return new_count
|
||||
|
||||
def deploy_config(self, server, deploy_count, timeout=None):
|
||||
parms = {'server': server}
|
||||
template = yaml.safe_load(self.config_template)
|
||||
resources = template['resources']
|
||||
resources['config']['properties'] = {'config': 'x' * 10000}
|
||||
for a in range(deploy_count):
|
||||
resources['dep_%s' % a] = yaml.safe_load(self.deployment_snippet)
|
||||
return self.stack_create(
|
||||
parameters=parms,
|
||||
template=template,
|
||||
enable_cleanup=self.enable_cleanup,
|
||||
expected_status=None,
|
||||
timeout=timeout)
|
||||
|
||||
def wait_for_deploy_metadata_set(self, stack, deploy_count):
|
||||
build_timeout = self.conf.build_timeout
|
||||
build_interval = self.conf.build_interval
|
||||
|
||||
start = timeutils.utcnow()
|
||||
while timeutils.delta_seconds(start,
|
||||
timeutils.utcnow()) < build_timeout:
|
||||
server_metadata = self.client.resources.metadata(
|
||||
stack, 'server')
|
||||
if len(server_metadata['deployments']) == deploy_count:
|
||||
return
|
||||
time.sleep(build_interval)
|
||||
|
||||
message = ('Deployment resources failed to be created within '
|
||||
'the required time (%s s).' %
|
||||
(build_timeout))
|
||||
raise exceptions.TimeoutException(message)
|
||||
|
||||
def signal_deployments(self, stack_identifier):
|
||||
server_metadata = self.client.resources.metadata(
|
||||
stack_identifier, 'server')
|
||||
for dep in server_metadata['deployments']:
|
||||
iv = dict((i['name'], i['value']) for i in dep['inputs'])
|
||||
sigurl = iv.get('deploy_signal_id')
|
||||
requests.post(sigurl, data='{}',
|
||||
headers={'content-type': 'application/json'},
|
||||
verify=self.verify_cert)
|
||||
|
||||
|
||||
class ZaqarSignalTransportTest(functional_base.FunctionalTestsBase):
|
||||
server_template = '''
|
||||
heat_template_version: "2013-05-23"
|
||||
|
@ -1,109 +0,0 @@
|
||||
# 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.
|
||||
|
||||
from heat_integrationtests.functional import functional_base
|
||||
|
||||
|
||||
class StackEventsTest(functional_base.FunctionalTestsBase):
|
||||
|
||||
template = '''
|
||||
heat_template_version: 2014-10-16
|
||||
parameters:
|
||||
resources:
|
||||
test_resource:
|
||||
type: OS::Heat::TestResource
|
||||
properties:
|
||||
value: 'test1'
|
||||
fail: False
|
||||
update_replace: False
|
||||
wait_secs: 0
|
||||
outputs:
|
||||
resource_id:
|
||||
description: 'ID of resource'
|
||||
value: { get_resource: test_resource }
|
||||
'''
|
||||
|
||||
def _verify_event_fields(self, event, event_characteristics):
|
||||
self.assertIsNotNone(event_characteristics)
|
||||
self.assertIsNotNone(event.event_time)
|
||||
self.assertIsNotNone(event.links)
|
||||
self.assertIsNotNone(event.logical_resource_id)
|
||||
self.assertIsNotNone(event.resource_status)
|
||||
self.assertIn(event.resource_status, event_characteristics[1])
|
||||
self.assertIsNotNone(event.resource_status_reason)
|
||||
self.assertIsNotNone(event.id)
|
||||
|
||||
def test_event(self):
|
||||
parameters = {}
|
||||
|
||||
test_stack_name = self._stack_rand_name()
|
||||
stack_identifier = self.stack_create(
|
||||
stack_name=test_stack_name,
|
||||
template=self.template,
|
||||
parameters=parameters
|
||||
)
|
||||
|
||||
expected_status = ['CREATE_IN_PROGRESS', 'CREATE_COMPLETE']
|
||||
event_characteristics = {
|
||||
test_stack_name: ('OS::Heat::Stack', expected_status),
|
||||
'test_resource': ('OS::Heat::TestResource', expected_status)}
|
||||
|
||||
# List stack events
|
||||
# API: GET /v1/{tenant_id}/stacks/{stack_name}/{stack_id}/events
|
||||
stack_events = self.client.events.list(stack_identifier)
|
||||
|
||||
for stack_event in stack_events:
|
||||
# Key on an expected/valid resource name
|
||||
self._verify_event_fields(
|
||||
stack_event,
|
||||
event_characteristics[stack_event.resource_name])
|
||||
|
||||
# Test the event filtering API based on this resource_name
|
||||
# /v1/{tenant_id}/stacks/{stack_name}/{stack_id}/resources/{resource_name}/events
|
||||
resource_events = self.client.events.list(
|
||||
stack_identifier,
|
||||
stack_event.resource_name)
|
||||
|
||||
# Resource events are a subset of the original stack event list
|
||||
self.assertLess(len(resource_events), len(stack_events))
|
||||
|
||||
# Get the event details for each resource event
|
||||
for resource_event in resource_events:
|
||||
# A resource_event should be in the original stack event list
|
||||
self.assertIn(resource_event, stack_events)
|
||||
# Given a filtered list, the resource names should be identical
|
||||
self.assertEqual(
|
||||
resource_event.resource_name,
|
||||
stack_event.resource_name)
|
||||
# Verify all fields, keying off the resource_name
|
||||
self._verify_event_fields(
|
||||
resource_event,
|
||||
event_characteristics[resource_event.resource_name])
|
||||
|
||||
# Exercise the event details API
|
||||
# /v1/{tenant_id}/stacks/{stack_name}/{stack_id}/resources/{resource_name}/events/{event_id}
|
||||
event_details = self.client.events.get(
|
||||
stack_identifier,
|
||||
resource_event.resource_name,
|
||||
resource_event.id)
|
||||
self._verify_event_fields(
|
||||
event_details,
|
||||
event_characteristics[event_details.resource_name])
|
||||
# The names should be identical to the non-detailed event
|
||||
self.assertEqual(
|
||||
resource_event.resource_name,
|
||||
event_details.resource_name)
|
||||
# Verify the extra field in the detail results
|
||||
self.assertIsNotNone(event_details.resource_type)
|
||||
self.assertEqual(
|
||||
event_characteristics[event_details.resource_name][0],
|
||||
event_details.resource_type)
|
@ -1,155 +0,0 @@
|
||||
# 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.
|
||||
|
||||
from heat_integrationtests.functional import functional_base
|
||||
|
||||
|
||||
class StackOutputsTest(functional_base.FunctionalTestsBase):
|
||||
|
||||
template = '''
|
||||
heat_template_version: 2015-10-15
|
||||
resources:
|
||||
test_resource_a:
|
||||
type: OS::Heat::TestResource
|
||||
properties:
|
||||
value: 'a'
|
||||
test_resource_b:
|
||||
type: OS::Heat::TestResource
|
||||
properties:
|
||||
value: 'b'
|
||||
outputs:
|
||||
resource_output_a:
|
||||
description: 'Output of resource a'
|
||||
value: { get_attr: [test_resource_a, output] }
|
||||
resource_output_b:
|
||||
description: 'Output of resource b'
|
||||
value: { get_attr: [test_resource_b, output] }
|
||||
'''
|
||||
|
||||
def test_outputs(self):
|
||||
stack_identifier = self.stack_create(
|
||||
template=self.template
|
||||
)
|
||||
expected_list = [{u'output_key': u'resource_output_a',
|
||||
u'description': u'Output of resource a'},
|
||||
{u'output_key': u'resource_output_b',
|
||||
u'description': u'Output of resource b'}]
|
||||
|
||||
actual_list = self.client.stacks.output_list(
|
||||
stack_identifier)['outputs']
|
||||
sorted_actual_list = sorted(actual_list, key=lambda x: x['output_key'])
|
||||
self.assertEqual(expected_list, sorted_actual_list)
|
||||
|
||||
expected_output_a = {
|
||||
u'output_value': u'a', u'output_key': u'resource_output_a',
|
||||
u'description': u'Output of resource a'}
|
||||
expected_output_b = {
|
||||
u'output_value': u'b', u'output_key': u'resource_output_b',
|
||||
u'description': u'Output of resource b'}
|
||||
actual_output_a = self.client.stacks.output_show(
|
||||
stack_identifier, 'resource_output_a')['output']
|
||||
actual_output_b = self.client.stacks.output_show(
|
||||
stack_identifier, 'resource_output_b')['output']
|
||||
self.assertEqual(expected_output_a, actual_output_a)
|
||||
self.assertEqual(expected_output_b, actual_output_b)
|
||||
|
||||
before_template = '''
|
||||
heat_template_version: 2015-10-15
|
||||
resources:
|
||||
test_resource_a:
|
||||
type: OS::Heat::TestResource
|
||||
properties:
|
||||
value: 'foo'
|
||||
outputs:
|
||||
'''
|
||||
|
||||
after_template = '''
|
||||
heat_template_version: 2015-10-15
|
||||
resources:
|
||||
test_resource_a:
|
||||
type: OS::Heat::TestResource
|
||||
properties:
|
||||
value: 'foo'
|
||||
test_resource_b:
|
||||
type: OS::Heat::TestResource
|
||||
properties:
|
||||
value: {get_attr: [test_resource_a, output]}
|
||||
outputs:
|
||||
output_value:
|
||||
description: 'Output of resource b'
|
||||
value: {get_attr: [test_resource_b, output]}
|
||||
'''
|
||||
|
||||
def test_outputs_update_new_resource(self):
|
||||
stack_identifier = self.stack_create(template=self.before_template)
|
||||
self.update_stack(stack_identifier, template=self.after_template)
|
||||
|
||||
expected_output_value = {
|
||||
u'output_value': u'foo', u'output_key': u'output_value',
|
||||
u'description': u'Output of resource b'}
|
||||
actual_output_value = self.client.stacks.output_show(
|
||||
stack_identifier, 'output_value')['output']
|
||||
self.assertEqual(expected_output_value, actual_output_value)
|
||||
|
||||
nested_template = '''
|
||||
heat_template_version: 2015-10-15
|
||||
resources:
|
||||
parent:
|
||||
type: 1.yaml
|
||||
outputs:
|
||||
resource_output_a:
|
||||
value: { get_attr: [parent, resource_output_a] }
|
||||
description: 'parent a'
|
||||
resource_output_b:
|
||||
value: { get_attr: [parent, resource_output_b] }
|
||||
description: 'parent b'
|
||||
'''
|
||||
error_template = '''
|
||||
heat_template_version: 2015-10-15
|
||||
resources:
|
||||
test_resource_a:
|
||||
type: OS::Heat::TestResource
|
||||
properties:
|
||||
value: 'a'
|
||||
test_resource_b:
|
||||
type: OS::Heat::TestResource
|
||||
properties:
|
||||
value: 'b'
|
||||
outputs:
|
||||
resource_output_a:
|
||||
description: 'Output of resource a'
|
||||
value: { get_attr: [test_resource_a, output] }
|
||||
resource_output_b:
|
||||
description: 'Output of resource b'
|
||||
value: { get_param: foo }
|
||||
'''
|
||||
|
||||
def test_output_error_nested(self):
|
||||
stack_identifier = self.stack_create(
|
||||
template=self.nested_template,
|
||||
files={'1.yaml': self.error_template}
|
||||
)
|
||||
self.update_stack(stack_identifier, template=self.nested_template,
|
||||
files={'1.yaml': self.error_template})
|
||||
expected_list = [{u'output_key': u'resource_output_a',
|
||||
u'output_value': u'a',
|
||||
u'description': u'parent a'},
|
||||
{u'output_key': u'resource_output_b',
|
||||
u'output_value': None,
|
||||
u'output_error': u'Error in parent output '
|
||||
u'resource_output_b: The Parameter'
|
||||
u' (foo) was not provided.',
|
||||
u'description': u'parent b'}]
|
||||
|
||||
actual_list = self.client.stacks.get(stack_identifier).outputs
|
||||
sorted_actual_list = sorted(actual_list, key=lambda x: x['output_key'])
|
||||
self.assertEqual(expected_list, sorted_actual_list)
|
@ -1,77 +0,0 @@
|
||||
# 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.
|
||||
|
||||
from heat_integrationtests.functional import functional_base
|
||||
|
||||
|
||||
class StackTagTest(functional_base.FunctionalTestsBase):
|
||||
|
||||
template = '''
|
||||
heat_template_version: 2014-10-16
|
||||
description:
|
||||
foo
|
||||
parameters:
|
||||
input:
|
||||
type: string
|
||||
default: test
|
||||
resources:
|
||||
not-used:
|
||||
type: OS::Heat::TestResource
|
||||
properties:
|
||||
wait_secs: 1
|
||||
value: {get_param: input}
|
||||
'''
|
||||
|
||||
def test_stack_tag(self):
|
||||
# Stack create with stack tags
|
||||
tags = 'foo,bar'
|
||||
stack_identifier = self.stack_create(
|
||||
template=self.template,
|
||||
tags=tags
|
||||
)
|
||||
|
||||
# Ensure property tag is populated and matches given tags
|
||||
stack = self.client.stacks.get(stack_identifier)
|
||||
self.assertEqual(['foo', 'bar'], stack.tags)
|
||||
|
||||
# Update tags
|
||||
updated_tags = 'tag1,tag2'
|
||||
self.update_stack(
|
||||
stack_identifier,
|
||||
template=self.template,
|
||||
tags=updated_tags,
|
||||
parameters={'input': 'next'})
|
||||
|
||||
# Ensure property tag is populated and matches updated tags
|
||||
updated_stack = self.client.stacks.get(stack_identifier)
|
||||
self.assertEqual(['tag1', 'tag2'], updated_stack.tags)
|
||||
|
||||
# Delete tags
|
||||
self.update_stack(
|
||||
stack_identifier,
|
||||
template=self.template,
|
||||
parameters={'input': 'none'}
|
||||
)
|
||||
|
||||
# Ensure property tag is not populated
|
||||
empty_tags_stack = self.client.stacks.get(stack_identifier)
|
||||
self.assertIsNone(empty_tags_stack.tags)
|
||||
|
||||
def test_hidden_stack(self):
|
||||
# Stack create with hidden stack tag
|
||||
tags = 'foo,hidden'
|
||||
self.stack_create(
|
||||
template=self.template,
|
||||
tags=tags)
|
||||
# Ensure stack does not exist when we do a stack list
|
||||
for stack in self.client.stacks.list():
|
||||
self.assertNotIn('hidden', stack.tags, "Hidden stack can be seen")
|
@ -1,292 +0,0 @@
|
||||
# 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 heatclient import exc
|
||||
|
||||
from heat_integrationtests.functional import functional_base
|
||||
|
||||
|
||||
class StackTemplateValidateTest(functional_base.FunctionalTestsBase):
|
||||
|
||||
random_template = '''
|
||||
heat_template_version: 2014-10-16
|
||||
description: the stack description
|
||||
parameters:
|
||||
aparam:
|
||||
type: number
|
||||
default: 10
|
||||
description: the param description
|
||||
resources:
|
||||
myres:
|
||||
type: OS::Heat::RandomString
|
||||
properties:
|
||||
length: {get_param: aparam}
|
||||
'''
|
||||
|
||||
parent_template = '''
|
||||
heat_template_version: 2014-10-16
|
||||
description: the parent template
|
||||
parameters:
|
||||
pparam:
|
||||
type: number
|
||||
default: 5
|
||||
description: the param description
|
||||
resources:
|
||||
nres:
|
||||
type: mynested.yaml
|
||||
properties:
|
||||
aparam: {get_param: pparam}
|
||||
'''
|
||||
|
||||
parent_template_noprop = '''
|
||||
heat_template_version: 2014-10-16
|
||||
description: the parent template
|
||||
resources:
|
||||
nres:
|
||||
type: mynested.yaml
|
||||
'''
|
||||
|
||||
random_template_groups = '''
|
||||
heat_template_version: 2014-10-16
|
||||
description: the stack description
|
||||
parameters:
|
||||
aparam:
|
||||
type: number
|
||||
default: 10
|
||||
description: the param description
|
||||
bparam:
|
||||
type: string
|
||||
default: foo
|
||||
cparam:
|
||||
type: string
|
||||
default: secret
|
||||
hidden: true
|
||||
parameter_groups:
|
||||
- label: str_params
|
||||
description: The string params
|
||||
parameters:
|
||||
- bparam
|
||||
- cparam
|
||||
resources:
|
||||
myres:
|
||||
type: OS::Heat::RandomString
|
||||
properties:
|
||||
length: {get_param: aparam}
|
||||
'''
|
||||
|
||||
def test_template_validate_basic(self):
|
||||
ret = self.client.stacks.validate(template=self.random_template)
|
||||
expected = {'Description': 'the stack description',
|
||||
'Parameters': {
|
||||
'aparam': {'Default': 10,
|
||||
'Description': 'the param description',
|
||||
'Label': 'aparam',
|
||||
'NoEcho': 'false',
|
||||
'Type': 'Number'}},
|
||||
'Environment': {
|
||||
'event_sinks': [],
|
||||
'parameter_defaults': {},
|
||||
'parameters': {},
|
||||
'resource_registry': {u'resources': {}}}}
|
||||
self.assertEqual(expected, ret)
|
||||
|
||||
def test_template_validate_override_default(self):
|
||||
env = {'parameters': {'aparam': 5}}
|
||||
ret = self.client.stacks.validate(template=self.random_template,
|
||||
environment=env)
|
||||
expected = {'Description': 'the stack description',
|
||||
'Parameters': {
|
||||
'aparam': {'Default': 10,
|
||||
'Value': 5,
|
||||
'Description': 'the param description',
|
||||
'Label': 'aparam',
|
||||
'NoEcho': 'false',
|
||||
'Type': 'Number'}},
|
||||
'Environment': {
|
||||
'event_sinks': [],
|
||||
'parameter_defaults': {},
|
||||
'parameters': {'aparam': 5},
|
||||
'resource_registry': {u'resources': {}}}}
|
||||
self.assertEqual(expected, ret)
|
||||
|
||||
def test_template_validate_override_none(self):
|
||||
env = {'resource_registry': {
|
||||
'OS::Heat::RandomString': 'OS::Heat::None'}}
|
||||
ret = self.client.stacks.validate(template=self.random_template,
|
||||
environment=env)
|
||||
expected = {'Description': 'the stack description',
|
||||
'Parameters': {
|
||||
'aparam': {'Default': 10,
|
||||
'Description': 'the param description',
|
||||
'Label': 'aparam',
|
||||
'NoEcho': 'false',
|
||||
'Type': 'Number'}},
|
||||
'Environment': {
|
||||
'event_sinks': [],
|
||||
'parameter_defaults': {},
|
||||
'parameters': {},
|
||||
'resource_registry': {
|
||||
'OS::Heat::RandomString': 'OS::Heat::None',
|
||||
u'resources': {}}}}
|
||||
self.assertEqual(expected, ret)
|
||||
|
||||
def test_template_validate_basic_required_param(self):
|
||||
tmpl = self.random_template.replace('default: 10', '')
|
||||
ret = self.client.stacks.validate(template=tmpl)
|
||||
expected = {'Description': 'the stack description',
|
||||
'Parameters': {
|
||||
'aparam': {'Description': 'the param description',
|
||||
'Label': 'aparam',
|
||||
'NoEcho': 'false',
|
||||
'Type': 'Number'}},
|
||||
'Environment': {
|
||||
'event_sinks': [],
|
||||
'parameter_defaults': {},
|
||||
'parameters': {},
|
||||
'resource_registry': {u'resources': {}}}}
|
||||
self.assertEqual(expected, ret)
|
||||
|
||||
def test_template_validate_fail_version(self):
|
||||
fail_template = self.random_template.replace('2014-10-16', 'invalid')
|
||||
ex = self.assertRaises(exc.HTTPBadRequest,
|
||||
self.client.stacks.validate,
|
||||
template=fail_template)
|
||||
self.assertIn('The template version is invalid', six.text_type(ex))
|
||||
|
||||
def test_template_validate_parameter_groups(self):
|
||||
ret = self.client.stacks.validate(template=self.random_template_groups)
|
||||
expected = {'Description': 'the stack description',
|
||||
'ParameterGroups':
|
||||
[{'description': 'The string params',
|
||||
'label': 'str_params',
|
||||
'parameters': ['bparam', 'cparam']}],
|
||||
'Parameters':
|
||||
{'aparam':
|
||||
{'Default': 10,
|
||||
'Description': 'the param description',
|
||||
'Label': 'aparam',
|
||||
'NoEcho': 'false',
|
||||
'Type': 'Number'},
|
||||
'bparam':
|
||||
{'Default': 'foo',
|
||||
'Description': '',
|
||||
'Label': 'bparam',
|
||||
'NoEcho': 'false',
|
||||
'Type': 'String'},
|
||||
'cparam':
|
||||
{'Default': 'secret',
|
||||
'Description': '',
|
||||
'Label': 'cparam',
|
||||
'NoEcho': 'true',
|
||||
'Type': 'String'}},
|
||||
'Environment': {
|
||||
'event_sinks': [],
|
||||
'parameter_defaults': {},
|
||||
'parameters': {},
|
||||
'resource_registry': {u'resources': {}}}}
|
||||
self.assertEqual(expected, ret)
|
||||
|
||||
def test_template_validate_nested_off(self):
|
||||
files = {'mynested.yaml': self.random_template}
|
||||
ret = self.client.stacks.validate(template=self.parent_template,
|
||||
files=files)
|
||||
expected = {'Description': 'the parent template',
|
||||
'Parameters': {
|
||||
'pparam': {'Default': 5,
|
||||
'Description': 'the param description',
|
||||
'Label': 'pparam',
|
||||
'NoEcho': 'false',
|
||||
'Type': 'Number'}},
|
||||
'Environment': {
|
||||
'event_sinks': [],
|
||||
'parameter_defaults': {},
|
||||
'parameters': {},
|
||||
'resource_registry': {
|
||||
u'mynested.yaml': u'mynested.yaml',
|
||||
u'resources': {}}}}
|
||||
self.assertEqual(expected, ret)
|
||||
|
||||
def test_template_validate_nested_on(self):
|
||||
files = {'mynested.yaml': self.random_template}
|
||||
ret = self.client.stacks.validate(template=self.parent_template_noprop,
|
||||
files=files,
|
||||
show_nested=True)
|
||||
expected = {'Description': 'the parent template',
|
||||
'Parameters': {},
|
||||
'NestedParameters': {
|
||||
'nres': {'Description': 'the stack description',
|
||||
'Parameters': {'aparam': {'Default': 10,
|
||||
'Description':
|
||||
'the param '
|
||||
'description',
|
||||
'Label': 'aparam',
|
||||
'NoEcho': 'false',
|
||||
'Type': 'Number'}},
|
||||
'Type': 'mynested.yaml'}},
|
||||
'Environment': {
|
||||
'event_sinks': [],
|
||||
'parameter_defaults': {},
|
||||
'parameters': {},
|
||||
'resource_registry': {
|
||||
u'mynested.yaml': u'mynested.yaml',
|
||||
u'resources': {}}}}
|
||||
self.assertEqual(expected, ret)
|
||||
|
||||
def test_template_validate_nested_on_multiple(self):
|
||||
# parent_template -> nested_template -> random_template
|
||||
nested_template = self.random_template.replace(
|
||||
'OS::Heat::RandomString', 'mynested2.yaml')
|
||||
files = {'mynested.yaml': nested_template,
|
||||
'mynested2.yaml': self.random_template}
|
||||
ret = self.client.stacks.validate(template=self.parent_template,
|
||||
files=files,
|
||||
show_nested=True)
|
||||
|
||||
n_param2 = {'myres': {'Description': 'the stack description',
|
||||
'Parameters': {'aparam': {'Default': 10,
|
||||
'Description':
|
||||
'the param '
|
||||
'description',
|
||||
'Label': 'aparam',
|
||||
'NoEcho': 'false',
|
||||
'Type': 'Number'}},
|
||||
'Type': 'mynested2.yaml'}}
|
||||
expected = {'Description': 'the parent template',
|
||||
'Parameters': {
|
||||
'pparam': {'Default': 5,
|
||||
'Description': 'the param description',
|
||||
'Label': 'pparam',
|
||||
'NoEcho': 'false',
|
||||
'Type': 'Number'}},
|
||||
'NestedParameters': {
|
||||
'nres': {'Description': 'the stack description',
|
||||
'Parameters': {'aparam': {'Default': 10,
|
||||
'Description':
|
||||
'the param '
|
||||
'description',
|
||||
'Label': 'aparam',
|
||||
'Value': 5,
|
||||
'NoEcho': 'false',
|
||||
'Type': 'Number'}},
|
||||
'NestedParameters': n_param2,
|
||||
'Type': 'mynested.yaml'}},
|
||||
'Environment': {
|
||||
'event_sinks': [],
|
||||
'parameter_defaults': {},
|
||||
'parameters': {},
|
||||
'resource_registry': {
|
||||
u'mynested.yaml': u'mynested.yaml',
|
||||
'resources': {}}}}
|
||||
self.assertEqual(expected, ret)
|
31
heat_integrationtests/functional/test_template_versions.py
Normal file
31
heat_integrationtests/functional/test_template_versions.py
Normal file
@ -0,0 +1,31 @@
|
||||
# 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.
|
||||
|
||||
|
||||
from heat_integrationtests.functional import functional_base
|
||||
|
||||
|
||||
class TemplateVersionTest(functional_base.FunctionalTestsBase):
|
||||
"""This will test list template versions"""
|
||||
|
||||
def test_template_version(self):
|
||||
template_versions = self.client.template_versions.list()
|
||||
supported_template_versions = ["2013-05-23", "2014-10-16",
|
||||
"2015-04-30", "2015-10-15",
|
||||
"2012-12-12", "2010-09-09",
|
||||
"2016-04-08", "2016-10-14", "newton",
|
||||
"2017-02-24", "ocata",
|
||||
"2017-09-01", "pike",
|
||||
"2018-03-02", "queens"]
|
||||
for template in template_versions:
|
||||
self.assertIn(template.version.split(".")[1],
|
||||
supported_template_versions)
|
@ -1,72 +0,0 @@
|
||||
# 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.
|
||||
|
||||
|
||||
from heat_integrationtests.functional import functional_base
|
||||
|
||||
|
||||
class TemplateAPITest(functional_base.FunctionalTestsBase):
|
||||
"""This will test the following template calls:
|
||||
|
||||
1. Get the template content for the specific stack
|
||||
2. List template versions
|
||||
3. List resource types
|
||||
4. Show resource details for OS::Heat::TestResource
|
||||
"""
|
||||
|
||||
template = {
|
||||
'heat_template_version': '2014-10-16',
|
||||
'description': 'Test Template APIs',
|
||||
'resources': {
|
||||
'test1': {
|
||||
'type': 'OS::Heat::TestResource',
|
||||
'properties': {
|
||||
'update_replace': False,
|
||||
'wait_secs': 0,
|
||||
'value': 'Test1',
|
||||
'fail': False,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def test_get_stack_template(self):
|
||||
stack_identifier = self.stack_create(
|
||||
template=self.template
|
||||
)
|
||||
template_from_client = self.client.stacks.template(stack_identifier)
|
||||
self.assertEqual(self.template, template_from_client)
|
||||
|
||||
def test_template_version(self):
|
||||
template_versions = self.client.template_versions.list()
|
||||
supported_template_versions = ["2013-05-23", "2014-10-16",
|
||||
"2015-04-30", "2015-10-15",
|
||||
"2012-12-12", "2010-09-09",
|
||||
"2016-04-08", "2016-10-14", "newton",
|
||||
"2017-02-24", "ocata",
|
||||
"2017-09-01", "pike",
|
||||
"2018-03-02", "queens"]
|
||||
for template in template_versions:
|
||||
self.assertIn(template.version.split(".")[1],
|
||||
supported_template_versions)
|
||||
|
||||
def test_resource_types(self):
|
||||
resource_types = self.client.resource_types.list()
|
||||
self.assertTrue(any(resource.resource_type == "OS::Heat::TestResource"
|
||||
for resource in resource_types))
|
||||
|
||||
def test_show_resource_template(self):
|
||||
resource_details = self.client.resource_types.get(
|
||||
resource_type="OS::Heat::TestResource"
|
||||
)
|
||||
self.assertEqual("OS::Heat::TestResource",
|
||||
resource_details['resource_type'])
|
@ -1,122 +0,0 @@
|
||||
# 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.
|
||||
|
||||
from heat_integrationtests.functional import functional_base
|
||||
|
||||
|
||||
class StackUnicodeTemplateTest(functional_base.FunctionalTestsBase):
|
||||
|
||||
random_template = u'''
|
||||
heat_template_version: 2014-10-16
|
||||
description: \u8fd9\u662f\u4e00\u4e2a\u63cf\u8ff0
|
||||
parameters:
|
||||
\u53c2\u6570:
|
||||
type: number
|
||||
default: 10
|
||||
label: \u6807\u7b7e
|
||||
description: \u8fd9\u662f\u4e00\u4e2a\u63cf\u8ff0
|
||||
resources:
|
||||
\u8d44\u6e90:
|
||||
type: OS::Heat::RandomString
|
||||
properties:
|
||||
length: {get_param: \u53c2\u6570}
|
||||
outputs:
|
||||
\u8f93\u51fa:
|
||||
description: \u8fd9\u662f\u4e00\u4e2a\u63cf\u8ff0
|
||||
value: {get_attr: [\u8d44\u6e90, value]}
|
||||
'''
|
||||
|
||||
def _assert_results(self, result):
|
||||
self.assertTrue(result['disable_rollback'])
|
||||
self.assertIsNone(result['parent'])
|
||||
self.assertEqual(u'\u8fd9\u662f\u4e00\u4e2a\u63cf\u8ff0',
|
||||
result['template_description'])
|
||||
self.assertEqual(u'10', result['parameters'][u'\u53c2\u6570'])
|
||||
|
||||
def _assert_preview_results(self, result):
|
||||
self._assert_results(result)
|
||||
res = result['resources'][0]
|
||||
self.assertEqual('/resources/%s' % res['resource_name'],
|
||||
res['resource_identity']['path'])
|
||||
|
||||
def _assert_create_results(self, result):
|
||||
self._assert_results(result)
|
||||
output = result['outputs'][0]
|
||||
self.assertEqual(u'\u8fd9\u662f\u4e00\u4e2a\u63cf\u8ff0',
|
||||
output['description'])
|
||||
self.assertEqual(u'\u8f93\u51fa', output['output_key'])
|
||||
self.assertIsNotNone(output['output_value'])
|
||||
|
||||
def _assert_resource_results(self, result):
|
||||
self.assertEqual(u'\u8d44\u6e90', result['resource_name'])
|
||||
self.assertEqual('OS::Heat::RandomString',
|
||||
result['resource_type'])
|
||||
|
||||
def test_template_validate_basic(self):
|
||||
ret = self.client.stacks.validate(template=self.random_template)
|
||||
expected = {
|
||||
'Description': u'\u8fd9\u662f\u4e00\u4e2a\u63cf\u8ff0',
|
||||
'Parameters': {
|
||||
u'\u53c2\u6570': {
|
||||
'Default': 10,
|
||||
'Description': u'\u8fd9\u662f\u4e00\u4e2a\u63cf\u8ff0',
|
||||
'Label': u'\u6807\u7b7e',
|
||||
'NoEcho': 'false',
|
||||
'Type': 'Number'}
|
||||
},
|
||||
'Environment': {
|
||||
'event_sinks': [],
|
||||
'parameter_defaults': {},
|
||||
'parameters': {},
|
||||
'resource_registry': {u'resources': {}}
|
||||
}
|
||||
}
|
||||
self.assertEqual(expected, ret)
|
||||
|
||||
def test_template_validate_override_default(self):
|
||||
env = {'parameters': {u'\u53c2\u6570': 5}}
|
||||
ret = self.client.stacks.validate(template=self.random_template,
|
||||
environment=env)
|
||||
expected = {
|
||||
'Description': u'\u8fd9\u662f\u4e00\u4e2a\u63cf\u8ff0',
|
||||
'Parameters': {
|
||||
u'\u53c2\u6570': {
|
||||
'Default': 10,
|
||||
'Value': 5,
|
||||
'Description': u'\u8fd9\u662f\u4e00\u4e2a\u63cf\u8ff0',
|
||||
'Label': u'\u6807\u7b7e',
|
||||
'NoEcho': 'false',
|
||||
'Type': 'Number'}
|
||||
},
|
||||
'Environment': {
|
||||
'event_sinks': [],
|
||||
'parameter_defaults': {},
|
||||
'parameters': {u'\u53c2\u6570': 5},
|
||||
'resource_registry': {u'resources': {}}
|
||||
}
|
||||
}
|
||||
self.assertEqual(expected, ret)
|
||||
|
||||
def test_stack_preview(self):
|
||||
result = self.client.stacks.preview(
|
||||
template=self.random_template,
|
||||
stack_name=self._stack_rand_name(),
|
||||
disable_rollback=True).to_dict()
|
||||
self._assert_preview_results(result)
|
||||
|
||||
def test_create_stack(self):
|
||||
stack_identifier = self.stack_create(template=self.random_template)
|
||||
stack = self.client.stacks.get(stack_identifier)
|
||||
self._assert_create_results(stack.to_dict())
|
||||
rl = self.client.resources.list(stack_identifier)
|
||||
self.assertEqual(1, len(rl))
|
||||
self._assert_resource_results(rl[0].to_dict())
|
@ -21,6 +21,6 @@ sudo -E $DEST/heat/heat_integrationtests/prepare_test_env.sh
|
||||
sudo -E $DEST/heat/heat_integrationtests/prepare_test_network.sh
|
||||
|
||||
cd $DEST/tempest
|
||||
sudo tox -evenv-tempest -- stestr --test-path=$DEST/heat/heat_integrationtests --top-dir=$DEST/heat --group_regex='heat_(?:tempest_plugin\.tests|integrationtests)\.api\.test_heat_api[._]([^_]+)' run
|
||||
sudo tox -evenv-tempest -- stestr --test-path=$DEST/heat/heat_integrationtests --top-dir=$DEST/heat --group_regex='heat_tempest_plugin\.tests\.api\.test_heat_api[._]([^_]+)' run
|
||||
|
||||
sudo -E $DEST/heat/heat_integrationtests/cleanup_test_env.sh
|
||||
|
@ -1,110 +0,0 @@
|
||||
heat_template_version: 2014-10-16
|
||||
|
||||
description: >
|
||||
This HOT template that just defines a single server.
|
||||
Contains just base features to verify base heat support.
|
||||
|
||||
parameters:
|
||||
key_name:
|
||||
type: string
|
||||
default: key-01
|
||||
description: Name of an existing key pair to use for the server
|
||||
flavor:
|
||||
type: string
|
||||
description: Flavor for the server to be created
|
||||
default: m1.small
|
||||
constraints:
|
||||
- custom_constraint: nova.flavor
|
||||
image:
|
||||
type: string
|
||||
description: Image ID or image name to use for the server
|
||||
constraints:
|
||||
- custom_constraint: glance.image
|
||||
vol_size:
|
||||
type: number
|
||||
description: The size of the Cinder volume
|
||||
default: 1
|
||||
private_net_name:
|
||||
type: string
|
||||
default: private-net-01
|
||||
description: Name of private network to be created
|
||||
private_net_cidr:
|
||||
type: string
|
||||
default: 192.168.101.0/24
|
||||
description: Private network address (CIDR notation)
|
||||
private_net_gateway:
|
||||
type: string
|
||||
default: 192.168.101.1
|
||||
description: Private network gateway address
|
||||
private_net_pool_start:
|
||||
type: string
|
||||
default: 192.168.101.2
|
||||
description: Start of private network IP address allocation pool
|
||||
private_net_pool_end:
|
||||
type: string
|
||||
default: 192.168.101.127
|
||||
description: End of private network IP address allocation pool
|
||||
echo_foo:
|
||||
default: fooooo
|
||||
type: string
|
||||
|
||||
resources:
|
||||
private_net:
|
||||
type: OS::Neutron::Net
|
||||
properties:
|
||||
name: { get_param: private_net_name }
|
||||
|
||||
private_subnet:
|
||||
type: OS::Neutron::Subnet
|
||||
properties:
|
||||
network_id: { get_resource: private_net }
|
||||
cidr: { get_param: private_net_cidr }
|
||||
gateway_ip: { get_param: private_net_gateway }
|
||||
allocation_pools:
|
||||
- start: { get_param: private_net_pool_start }
|
||||
end: { get_param: private_net_pool_end }
|
||||
|
||||
server_port:
|
||||
type: OS::Neutron::Port
|
||||
properties:
|
||||
network_id: { get_resource: private_net }
|
||||
fixed_ips:
|
||||
- subnet_id: { get_resource: private_subnet }
|
||||
|
||||
key:
|
||||
type: OS::Nova::KeyPair
|
||||
properties:
|
||||
name: { get_param: key_name }
|
||||
|
||||
server:
|
||||
type: OS::Nova::Server
|
||||
properties:
|
||||
key_name: { get_resource: key }
|
||||
image: { get_param: image }
|
||||
flavor: { get_param: flavor }
|
||||
networks:
|
||||
- port: { get_resource: server_port }
|
||||
user_data:
|
||||
str_replace:
|
||||
template: |
|
||||
#!/bin/bash
|
||||
echo echo_foo
|
||||
params:
|
||||
echo_foo: { get_param: echo_foo }
|
||||
|
||||
vol:
|
||||
type: OS::Cinder::Volume
|
||||
properties:
|
||||
size: { get_param: vol_size }
|
||||
|
||||
vol_att:
|
||||
type: OS::Cinder::VolumeAttachment
|
||||
properties:
|
||||
instance_uuid: { get_resource: server }
|
||||
volume_id: { get_resource: vol }
|
||||
mountpoint: /dev/vdb
|
||||
|
||||
outputs:
|
||||
server_networks:
|
||||
description: The networks of the deployed server
|
||||
value: { get_attr: [server, networks] }
|
@ -1,73 +0,0 @@
|
||||
# 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.
|
||||
|
||||
from heat_integrationtests.common import test
|
||||
from heat_integrationtests.scenario import scenario_base
|
||||
from heatclient.common import template_utils
|
||||
|
||||
|
||||
class BasicResourcesTest(scenario_base.ScenarioTestsBase):
|
||||
|
||||
def setUp(self):
|
||||
super(BasicResourcesTest, self).setUp()
|
||||
if not self.conf.image_ref:
|
||||
raise self.skipException("No image configured to test")
|
||||
if not self.conf.instance_type:
|
||||
raise self.skipException("No flavor configured to test")
|
||||
|
||||
def check_stack(self):
|
||||
sid = self.stack_identifier
|
||||
# Check that stack were created
|
||||
self._wait_for_stack_status(sid, '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)
|
||||
self.assertEqual(server.id, server_id)
|
||||
|
||||
stack = self.client.stacks.get(sid)
|
||||
|
||||
server_networks = self._stack_output(stack, 'server_networks')
|
||||
self.assertIn(self.private_net_name, server_networks)
|
||||
|
||||
def test_base_resources_integration(self):
|
||||
"""Define test for base resources interation from core porjects
|
||||
|
||||
The alternative scenario is the following:
|
||||
1. Create a stack with basic resources from core projects.
|
||||
2. Check that all stack resources are created successfully.
|
||||
3. Wait for deployment.
|
||||
4. Check that stack was created.
|
||||
5. Check stack outputs.
|
||||
"""
|
||||
|
||||
self.private_net_name = test.rand_name('heat-net')
|
||||
parameters = {
|
||||
'key_name': test.rand_name('heat-key'),
|
||||
'flavor': self.conf.instance_type,
|
||||
'image': self.conf.image_ref,
|
||||
'vol_size': self.conf.volume_size,
|
||||
'private_net_name': self.private_net_name
|
||||
}
|
||||
|
||||
env_files, env = template_utils.process_environment_and_files(
|
||||
self.conf.boot_config_env)
|
||||
|
||||
# Launch stack
|
||||
self.stack_identifier = self.launch_stack(
|
||||
template_name='test_base_resources.yaml',
|
||||
parameters=parameters,
|
||||
expected_status=None,
|
||||
environment=env
|
||||
)
|
||||
|
||||
# Check stack
|
||||
self.check_stack()
|
@ -27,4 +27,3 @@ reno>=2.5.0 # Apache-2.0
|
||||
os-collect-config>=5.0.0 # Apache-2.0
|
||||
paramiko>=2.0.0 # LGPLv2.1+
|
||||
tempest>=17.1.0 # Apache-2.0
|
||||
gabbi>=1.35.0 # Apache-2.0
|
||||
|
Loading…
Reference in New Issue
Block a user