Merge "Remove the heat tests"
This commit is contained in:
commit
72d54b6877
releasenotes/notes
tempest/api/orchestration
__init__.pybase.py
stacks
__init__.py
templates
cinder_basic.yamlcinder_basic_delete_retain.yamlneutron_basic.yamlnon_empty_stack.yamlnova_keypair.jsonnova_keypair.yamlrandom_string.yamlswift_basic.yaml
test_environment.pytest_limits.pytest_neutron_resources.pytest_non_empty_stack.pytest_nova_keypair_resources.pytest_resource_types.pytest_soft_conf.pytest_stacks.pytest_swift_resources.pytest_templates.pytest_templates_negative.pytest_volumes.py@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
upgrade:
|
||||||
|
- The Heat API tests have been removed from tempest, they were unmaintained.
|
||||||
|
The future direction of api test for heat is their in-tree Gabbi tests
|
@ -1,169 +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 os.path
|
|
||||||
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
from tempest import config
|
|
||||||
from tempest.lib.common.utils import data_utils
|
|
||||||
from tempest.lib.common.utils import test_utils
|
|
||||||
import tempest.test
|
|
||||||
|
|
||||||
CONF = config.CONF
|
|
||||||
|
|
||||||
|
|
||||||
class BaseOrchestrationTest(tempest.test.BaseTestCase):
|
|
||||||
"""Base test case class for all Orchestration API tests."""
|
|
||||||
|
|
||||||
credentials = ['primary']
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def skip_checks(cls):
|
|
||||||
super(BaseOrchestrationTest, cls).skip_checks()
|
|
||||||
if not CONF.service_available.heat:
|
|
||||||
raise cls.skipException("Heat support is required")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def setup_credentials(cls):
|
|
||||||
super(BaseOrchestrationTest, cls).setup_credentials()
|
|
||||||
stack_owner_role = CONF.orchestration.stack_owner_role
|
|
||||||
cls.os = cls.get_client_manager(roles=[stack_owner_role])
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def setup_clients(cls):
|
|
||||||
super(BaseOrchestrationTest, cls).setup_clients()
|
|
||||||
cls.orchestration_client = cls.os_primary.orchestration_client
|
|
||||||
cls.client = cls.orchestration_client
|
|
||||||
cls.servers_client = cls.os_primary.servers_client
|
|
||||||
cls.keypairs_client = cls.os_primary.keypairs_client
|
|
||||||
cls.networks_client = cls.os_primary.networks_client
|
|
||||||
cls.images_v2_client = cls.os_primary.image_client_v2
|
|
||||||
cls.volumes_client = cls.os_primary.volumes_v2_client
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def resource_setup(cls):
|
|
||||||
super(BaseOrchestrationTest, cls).resource_setup()
|
|
||||||
cls.build_timeout = CONF.orchestration.build_timeout
|
|
||||||
cls.build_interval = CONF.orchestration.build_interval
|
|
||||||
cls.stacks = []
|
|
||||||
cls.keypairs = []
|
|
||||||
cls.images = []
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def create_stack(cls, stack_name, template_data, parameters=None,
|
|
||||||
environment=None, files=None):
|
|
||||||
if parameters is None:
|
|
||||||
parameters = {}
|
|
||||||
body = cls.client.create_stack(
|
|
||||||
stack_name,
|
|
||||||
template=template_data,
|
|
||||||
parameters=parameters,
|
|
||||||
environment=environment,
|
|
||||||
files=files)
|
|
||||||
stack_id = body.response['location'].split('/')[-1]
|
|
||||||
stack_identifier = '%s/%s' % (stack_name, stack_id)
|
|
||||||
cls.stacks.append(stack_identifier)
|
|
||||||
return stack_identifier
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _clear_stacks(cls):
|
|
||||||
for stack_identifier in cls.stacks:
|
|
||||||
test_utils.call_and_ignore_notfound_exc(
|
|
||||||
cls.client.delete_stack, stack_identifier)
|
|
||||||
|
|
||||||
for stack_identifier in cls.stacks:
|
|
||||||
test_utils.call_and_ignore_notfound_exc(
|
|
||||||
cls.client.wait_for_stack_status, stack_identifier,
|
|
||||||
'DELETE_COMPLETE')
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _create_keypair(cls, name_start='keypair-heat-'):
|
|
||||||
kp_name = data_utils.rand_name(name_start)
|
|
||||||
body = cls.keypairs_client.create_keypair(name=kp_name)['keypair']
|
|
||||||
cls.keypairs.append(kp_name)
|
|
||||||
return body
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _clear_keypairs(cls):
|
|
||||||
for kp_name in cls.keypairs:
|
|
||||||
try:
|
|
||||||
cls.keypairs_client.delete_keypair(kp_name)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _create_image(cls, name_start='image-heat-', container_format='bare',
|
|
||||||
disk_format='iso'):
|
|
||||||
image_name = data_utils.rand_name(name_start)
|
|
||||||
body = cls.images_v2_client.create_image(image_name,
|
|
||||||
container_format,
|
|
||||||
disk_format)
|
|
||||||
image_id = body['id']
|
|
||||||
cls.images.append(image_id)
|
|
||||||
return body
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _clear_images(cls):
|
|
||||||
for image_id in cls.images:
|
|
||||||
test_utils.call_and_ignore_notfound_exc(
|
|
||||||
cls.images_v2_client.delete_image, image_id)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def read_template(cls, name, ext='yaml'):
|
|
||||||
loc = ["stacks", "templates", "%s.%s" % (name, ext)]
|
|
||||||
fullpath = os.path.join(os.path.dirname(__file__), *loc)
|
|
||||||
|
|
||||||
with open(fullpath, "r") as f:
|
|
||||||
content = f.read()
|
|
||||||
return content
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def load_template(cls, name, ext='yaml'):
|
|
||||||
loc = ["stacks", "templates", "%s.%s" % (name, ext)]
|
|
||||||
fullpath = os.path.join(os.path.dirname(__file__), *loc)
|
|
||||||
|
|
||||||
with open(fullpath, "r") as f:
|
|
||||||
return yaml.safe_load(f)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def resource_cleanup(cls):
|
|
||||||
cls._clear_stacks()
|
|
||||||
cls._clear_keypairs()
|
|
||||||
cls._clear_images()
|
|
||||||
super(BaseOrchestrationTest, cls).resource_cleanup()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def stack_output(stack, output_key):
|
|
||||||
"""Return a stack output value for a given key."""
|
|
||||||
return next((o['output_value'] for o in stack['outputs']
|
|
||||||
if o['output_key'] == output_key), None)
|
|
||||||
|
|
||||||
def assert_fields_in_dict(self, obj, *fields):
|
|
||||||
for field in fields:
|
|
||||||
self.assertIn(field, obj)
|
|
||||||
|
|
||||||
def list_resources(self, stack_identifier):
|
|
||||||
"""Get a dict mapping of resource names to types."""
|
|
||||||
resources = self.client.list_resources(stack_identifier)['resources']
|
|
||||||
self.assertIsInstance(resources, list)
|
|
||||||
for res in resources:
|
|
||||||
self.assert_fields_in_dict(res, 'logical_resource_id',
|
|
||||||
'resource_type', 'resource_status',
|
|
||||||
'updated_time')
|
|
||||||
|
|
||||||
return dict((r['resource_name'], r['resource_type'])
|
|
||||||
for r in resources)
|
|
||||||
|
|
||||||
def get_stack_output(self, stack_identifier, output_key):
|
|
||||||
body = self.client.show_stack(stack_identifier)['stack']
|
|
||||||
return self.stack_output(body, output_key)
|
|
@ -1,33 +0,0 @@
|
|||||||
heat_template_version: 2013-05-23
|
|
||||||
|
|
||||||
parameters:
|
|
||||||
volume_size:
|
|
||||||
type: number
|
|
||||||
default: 1
|
|
||||||
|
|
||||||
resources:
|
|
||||||
volume:
|
|
||||||
type: OS::Cinder::Volume
|
|
||||||
properties:
|
|
||||||
size: { get_param: volume_size }
|
|
||||||
description: a descriptive description
|
|
||||||
name: volume_name
|
|
||||||
|
|
||||||
outputs:
|
|
||||||
status:
|
|
||||||
description: status
|
|
||||||
value: { get_attr: ['volume', 'status'] }
|
|
||||||
|
|
||||||
size:
|
|
||||||
description: size
|
|
||||||
value: { get_attr: ['volume', 'size'] }
|
|
||||||
|
|
||||||
display_description:
|
|
||||||
description: display_description
|
|
||||||
value: { get_attr: ['volume', 'display_description'] }
|
|
||||||
|
|
||||||
display_name:
|
|
||||||
value: { get_attr: ['volume', 'display_name'] }
|
|
||||||
|
|
||||||
volume_id:
|
|
||||||
value: { get_resource: volume }
|
|
@ -1,34 +0,0 @@
|
|||||||
heat_template_version: 2013-05-23
|
|
||||||
|
|
||||||
parameters:
|
|
||||||
volume_size:
|
|
||||||
type: number
|
|
||||||
default: 1
|
|
||||||
|
|
||||||
resources:
|
|
||||||
volume:
|
|
||||||
deletion_policy: 'Retain'
|
|
||||||
type: OS::Cinder::Volume
|
|
||||||
properties:
|
|
||||||
size: { get_param: volume_size }
|
|
||||||
description: a descriptive description
|
|
||||||
name: volume_name
|
|
||||||
|
|
||||||
outputs:
|
|
||||||
status:
|
|
||||||
description: status
|
|
||||||
value: { get_attr: ['volume', 'status'] }
|
|
||||||
|
|
||||||
size:
|
|
||||||
description: size
|
|
||||||
value: { get_attr: ['volume', 'size'] }
|
|
||||||
|
|
||||||
display_description:
|
|
||||||
description: display_description
|
|
||||||
value: { get_attr: ['volume', 'display_description'] }
|
|
||||||
|
|
||||||
display_name:
|
|
||||||
value: { get_attr: ['volume', 'display_name'] }
|
|
||||||
|
|
||||||
volume_id:
|
|
||||||
value: { get_resource: volume }
|
|
@ -1,72 +0,0 @@
|
|||||||
heat_template_version: '2013-05-23'
|
|
||||||
description: |
|
|
||||||
Template which creates single EC2 instance
|
|
||||||
parameters:
|
|
||||||
KeyName:
|
|
||||||
type: string
|
|
||||||
InstanceType:
|
|
||||||
type: string
|
|
||||||
ImageId:
|
|
||||||
type: string
|
|
||||||
SubNetCidr:
|
|
||||||
type: string
|
|
||||||
ExternalNetworkId:
|
|
||||||
type: string
|
|
||||||
DNSServers:
|
|
||||||
type: comma_delimited_list
|
|
||||||
timeout:
|
|
||||||
type: number
|
|
||||||
resources:
|
|
||||||
Network:
|
|
||||||
type: OS::Neutron::Net
|
|
||||||
properties:
|
|
||||||
name: NewNetwork
|
|
||||||
Subnet:
|
|
||||||
type: OS::Neutron::Subnet
|
|
||||||
properties:
|
|
||||||
network_id: {Ref: Network}
|
|
||||||
name: NewSubnet
|
|
||||||
ip_version: 4
|
|
||||||
cidr: { get_param: SubNetCidr }
|
|
||||||
dns_nameservers: { get_param: DNSServers }
|
|
||||||
Router:
|
|
||||||
type: OS::Neutron::Router
|
|
||||||
properties:
|
|
||||||
name: NewRouter
|
|
||||||
admin_state_up: true
|
|
||||||
external_gateway_info:
|
|
||||||
network: {get_param: ExternalNetworkId}
|
|
||||||
RouterInterface:
|
|
||||||
type: OS::Neutron::RouterInterface
|
|
||||||
properties:
|
|
||||||
router_id: {get_resource: Router}
|
|
||||||
subnet_id: {get_resource: Subnet}
|
|
||||||
Server:
|
|
||||||
type: OS::Nova::Server
|
|
||||||
metadata:
|
|
||||||
Name: SmokeServerNeutron
|
|
||||||
properties:
|
|
||||||
image: {get_param: ImageId}
|
|
||||||
flavor: {get_param: InstanceType}
|
|
||||||
key_name: {get_param: KeyName}
|
|
||||||
networks:
|
|
||||||
- network: {get_resource: Network}
|
|
||||||
user_data_format: RAW
|
|
||||||
user_data:
|
|
||||||
str_replace:
|
|
||||||
template: |
|
|
||||||
#!/bin/sh -v
|
|
||||||
|
|
||||||
SIGNAL_DATA='{"Status": "SUCCESS", "Reason": "SmokeServerNeutron created", "Data": "Application has completed configuration.", "UniqueId": "00000"}'
|
|
||||||
while ! curl --insecure --fail -X PUT -H 'Content-Type:' --data-binary "$SIGNAL_DATA" \
|
|
||||||
'wait_handle' ; do sleep 3; done
|
|
||||||
params:
|
|
||||||
wait_handle: {get_resource: WaitHandleNeutron}
|
|
||||||
WaitHandleNeutron:
|
|
||||||
type: AWS::CloudFormation::WaitConditionHandle
|
|
||||||
WaitCondition:
|
|
||||||
type: AWS::CloudFormation::WaitCondition
|
|
||||||
depends_on: Server
|
|
||||||
properties:
|
|
||||||
Handle: {get_resource: WaitHandleNeutron}
|
|
||||||
Timeout: {get_param: timeout}
|
|
@ -1,36 +0,0 @@
|
|||||||
HeatTemplateFormatVersion: '2012-12-12'
|
|
||||||
Description: |
|
|
||||||
Template which creates some simple resources
|
|
||||||
Parameters:
|
|
||||||
trigger:
|
|
||||||
Type: String
|
|
||||||
Default: not_yet
|
|
||||||
image:
|
|
||||||
Type: String
|
|
||||||
flavor:
|
|
||||||
Type: String
|
|
||||||
Resources:
|
|
||||||
fluffy:
|
|
||||||
Type: AWS::AutoScaling::LaunchConfiguration
|
|
||||||
Metadata:
|
|
||||||
kittens:
|
|
||||||
- Tom
|
|
||||||
- Stinky
|
|
||||||
Properties:
|
|
||||||
ImageId: {Ref: image}
|
|
||||||
InstanceType: {Ref: flavor}
|
|
||||||
UserData:
|
|
||||||
Fn::Replace:
|
|
||||||
- variable_a: {Ref: trigger}
|
|
||||||
variable_b: bee
|
|
||||||
- |
|
|
||||||
A == variable_a
|
|
||||||
B == variable_b
|
|
||||||
Outputs:
|
|
||||||
fluffy:
|
|
||||||
Description: "fluffies irc nick"
|
|
||||||
Value:
|
|
||||||
Fn::Replace:
|
|
||||||
- nick: {Ref: fluffy}
|
|
||||||
- |
|
|
||||||
#nick
|
|
@ -1,48 +0,0 @@
|
|||||||
{
|
|
||||||
"AWSTemplateFormatVersion" : "2010-09-09",
|
|
||||||
"Description" : "Template which create two key pairs.",
|
|
||||||
"Parameters" : {
|
|
||||||
"KeyPairName1": {
|
|
||||||
"Type": "String",
|
|
||||||
"Default": "testkey1"
|
|
||||||
},
|
|
||||||
"KeyPairName2": {
|
|
||||||
"Type": "String",
|
|
||||||
"Default": "testkey2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Resources" : {
|
|
||||||
"KeyPairSavePrivate": {
|
|
||||||
"Type": "OS::Nova::KeyPair",
|
|
||||||
"Properties": {
|
|
||||||
"name" : { "Ref" : "KeyPairName1" },
|
|
||||||
"save_private_key": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"KeyPairDontSavePrivate": {
|
|
||||||
"Type": "OS::Nova::KeyPair",
|
|
||||||
"Properties": {
|
|
||||||
"name" : { "Ref" : "KeyPairName2" },
|
|
||||||
"save_private_key": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Outputs": {
|
|
||||||
"KeyPair_PublicKey": {
|
|
||||||
"Description": "Public Key of generated keypair.",
|
|
||||||
"Value": { "Fn::GetAtt" : ["KeyPairSavePrivate", "public_key"] }
|
|
||||||
},
|
|
||||||
"KeyPair_PrivateKey": {
|
|
||||||
"Description": "Private Key of generated keypair.",
|
|
||||||
"Value": { "Fn::GetAtt" : ["KeyPairSavePrivate", "private_key"] }
|
|
||||||
},
|
|
||||||
"KeyPairDontSavePrivate_PublicKey": {
|
|
||||||
"Description": "Public Key of generated keypair.",
|
|
||||||
"Value": { "Fn::GetAtt" : ["KeyPairDontSavePrivate", "public_key"] }
|
|
||||||
},
|
|
||||||
"KeyPairDontSavePrivate_PrivateKey": {
|
|
||||||
"Description": "Private Key of generated keypair.",
|
|
||||||
"Value": { "Fn::GetAtt" : ["KeyPairDontSavePrivate", "private_key"] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
heat_template_version: 2013-05-23
|
|
||||||
|
|
||||||
description: >
|
|
||||||
Template which creates two key pairs.
|
|
||||||
|
|
||||||
parameters:
|
|
||||||
KeyPairName1:
|
|
||||||
type: string
|
|
||||||
default: testkey
|
|
||||||
|
|
||||||
KeyPairName2:
|
|
||||||
type: string
|
|
||||||
default: testkey2
|
|
||||||
|
|
||||||
resources:
|
|
||||||
KeyPairSavePrivate:
|
|
||||||
type: OS::Nova::KeyPair
|
|
||||||
properties:
|
|
||||||
name: { get_param: KeyPairName1 }
|
|
||||||
save_private_key: true
|
|
||||||
|
|
||||||
KeyPairDontSavePrivate:
|
|
||||||
type: OS::Nova::KeyPair
|
|
||||||
properties:
|
|
||||||
name: { get_param: KeyPairName2 }
|
|
||||||
save_private_key: false
|
|
||||||
|
|
||||||
outputs:
|
|
||||||
KeyPair_PublicKey:
|
|
||||||
description: Public Key of generated keypair
|
|
||||||
value: { get_attr: [KeyPairSavePrivate, public_key] }
|
|
||||||
|
|
||||||
KeyPair_PrivateKey:
|
|
||||||
description: Private Key of generated keypair
|
|
||||||
value: { get_attr: [KeyPairSavePrivate, private_key] }
|
|
||||||
|
|
||||||
KeyPairDontSavePrivate_PublicKey:
|
|
||||||
description: Public Key of generated keypair
|
|
||||||
value: { get_attr: [KeyPairDontSavePrivate, public_key] }
|
|
||||||
|
|
||||||
KeyPairDontSavePrivate_PrivateKey:
|
|
||||||
description: Private Key of generated keypair
|
|
||||||
value: { get_attr: [KeyPairDontSavePrivate, private_key] }
|
|
@ -1,18 +0,0 @@
|
|||||||
heat_template_version: 2013-05-23
|
|
||||||
|
|
||||||
parameters:
|
|
||||||
random_length:
|
|
||||||
type: number
|
|
||||||
default: 10
|
|
||||||
|
|
||||||
resources:
|
|
||||||
random:
|
|
||||||
type: OS::Heat::RandomString
|
|
||||||
properties:
|
|
||||||
length: {get_param: random_length}
|
|
||||||
|
|
||||||
outputs:
|
|
||||||
random_length:
|
|
||||||
value: {get_param: random_length}
|
|
||||||
random_value:
|
|
||||||
value: {get_attr: [random, value]}
|
|
@ -1,23 +0,0 @@
|
|||||||
heat_template_version: 2013-05-23
|
|
||||||
description: Template which creates a Swift container resource
|
|
||||||
|
|
||||||
resources:
|
|
||||||
SwiftContainerWebsite:
|
|
||||||
deletion_policy: "Delete"
|
|
||||||
type: OS::Swift::Container
|
|
||||||
properties:
|
|
||||||
X-Container-Read: ".r:*"
|
|
||||||
X-Container-Meta:
|
|
||||||
web-index: "index.html"
|
|
||||||
web-error: "error.html"
|
|
||||||
|
|
||||||
SwiftContainer:
|
|
||||||
type: OS::Swift::Container
|
|
||||||
|
|
||||||
outputs:
|
|
||||||
WebsiteURL:
|
|
||||||
description: "URL for website hosted on S3"
|
|
||||||
value: { get_attr: [SwiftContainer, WebsiteURL] }
|
|
||||||
DomainName:
|
|
||||||
description: "Domain of Swift host"
|
|
||||||
value: { get_attr: [SwiftContainer, DomainName] }
|
|
@ -1,92 +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 tempest.api.orchestration import base
|
|
||||||
from tempest.lib.common.utils import data_utils
|
|
||||||
from tempest.lib import decorators
|
|
||||||
|
|
||||||
|
|
||||||
class StackEnvironmentTest(base.BaseOrchestrationTest):
|
|
||||||
|
|
||||||
@decorators.idempotent_id('37d4346b-1abd-4442-b7b1-2a4e5749a1e3')
|
|
||||||
def test_environment_parameter(self):
|
|
||||||
"""Test passing a stack parameter via the environment."""
|
|
||||||
stack_name = data_utils.rand_name('heat')
|
|
||||||
template = self.read_template('random_string')
|
|
||||||
environment = {'parameters': {'random_length': 20}}
|
|
||||||
|
|
||||||
stack_identifier = self.create_stack(stack_name, template,
|
|
||||||
environment=environment)
|
|
||||||
self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
|
|
||||||
|
|
||||||
random_len = self.get_stack_output(stack_identifier, 'random_length')
|
|
||||||
self.assertEqual(20, random_len)
|
|
||||||
|
|
||||||
random_value = self.get_stack_output(stack_identifier, 'random_value')
|
|
||||||
self.assertEqual(20, len(random_value))
|
|
||||||
|
|
||||||
@decorators.idempotent_id('73bce717-ad22-4853-bbef-6ed89b632701')
|
|
||||||
def test_environment_provider_resource(self):
|
|
||||||
"""Test passing resource_registry defining a provider resource."""
|
|
||||||
stack_name = data_utils.rand_name('heat')
|
|
||||||
template = '''
|
|
||||||
heat_template_version: 2013-05-23
|
|
||||||
resources:
|
|
||||||
random:
|
|
||||||
type: My:Random::String
|
|
||||||
outputs:
|
|
||||||
random_value:
|
|
||||||
value: {get_attr: [random, random_value]}
|
|
||||||
'''
|
|
||||||
environment = {'resource_registry':
|
|
||||||
{'My:Random::String': 'my_random.yaml'}}
|
|
||||||
files = {'my_random.yaml': self.read_template('random_string')}
|
|
||||||
|
|
||||||
stack_identifier = self.create_stack(stack_name, template,
|
|
||||||
environment=environment,
|
|
||||||
files=files)
|
|
||||||
self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
|
|
||||||
|
|
||||||
# random_string.yaml specifies a length of 10
|
|
||||||
random_value = self.get_stack_output(stack_identifier, 'random_value')
|
|
||||||
random_string_template = self.load_template('random_string')
|
|
||||||
expected_length = random_string_template['parameters'][
|
|
||||||
'random_length']['default']
|
|
||||||
self.assertEqual(expected_length, len(random_value))
|
|
||||||
|
|
||||||
@decorators.idempotent_id('9d682e5a-f4bb-47d5-8472-9d3cacb855df')
|
|
||||||
def test_files_provider_resource(self):
|
|
||||||
"""Test untyped defining of a provider resource via "files"."""
|
|
||||||
# It's also possible to specify the filename directly in the template.
|
|
||||||
# without adding the type alias to resource_registry
|
|
||||||
stack_name = data_utils.rand_name('heat')
|
|
||||||
template = '''
|
|
||||||
heat_template_version: 2013-05-23
|
|
||||||
resources:
|
|
||||||
random:
|
|
||||||
type: my_random.yaml
|
|
||||||
outputs:
|
|
||||||
random_value:
|
|
||||||
value: {get_attr: [random, random_value]}
|
|
||||||
'''
|
|
||||||
files = {'my_random.yaml': self.read_template('random_string')}
|
|
||||||
|
|
||||||
stack_identifier = self.create_stack(stack_name, template,
|
|
||||||
files=files)
|
|
||||||
self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
|
|
||||||
|
|
||||||
# random_string.yaml specifies a length of 10
|
|
||||||
random_value = self.get_stack_output(stack_identifier, 'random_value')
|
|
||||||
random_string_template = self.load_template('random_string')
|
|
||||||
expected_length = random_string_template['parameters'][
|
|
||||||
'random_length']['default']
|
|
||||||
self.assertEqual(expected_length, len(random_value))
|
|
@ -1,49 +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 tempest.api.orchestration import base
|
|
||||||
from tempest import config
|
|
||||||
from tempest.lib.common.utils import data_utils
|
|
||||||
from tempest.lib import decorators
|
|
||||||
from tempest.lib import exceptions as lib_exc
|
|
||||||
|
|
||||||
CONF = config.CONF
|
|
||||||
|
|
||||||
|
|
||||||
class TestServerStackLimits(base.BaseOrchestrationTest):
|
|
||||||
|
|
||||||
@decorators.idempotent_id('ec9bed71-c460-45c9-ab98-295caa9fd76b')
|
|
||||||
def test_exceed_max_template_size_fails(self):
|
|
||||||
stack_name = data_utils.rand_name('heat')
|
|
||||||
fill = 'A' * CONF.orchestration.max_template_size
|
|
||||||
template = '''
|
|
||||||
HeatTemplateFormatVersion: '2012-12-12'
|
|
||||||
Description: '%s'
|
|
||||||
Outputs:
|
|
||||||
Foo: bar''' % fill
|
|
||||||
ex = self.assertRaises(lib_exc.BadRequest, self.create_stack,
|
|
||||||
stack_name, template)
|
|
||||||
self.assertIn('exceeds maximum allowed size', str(ex))
|
|
||||||
|
|
||||||
@decorators.idempotent_id('d1b83e73-7cad-4a22-9839-036548c5387c')
|
|
||||||
def test_exceed_max_resources_per_stack(self):
|
|
||||||
stack_name = data_utils.rand_name('heat')
|
|
||||||
# Create a big template, one resource more than the limit
|
|
||||||
template = 'heat_template_version: \'2013-05-23\'\nresources:\n'
|
|
||||||
rsrc_snippet = ' random%s:\n type: \'OS::Heat::RandomString\'\n'
|
|
||||||
num_resources = CONF.orchestration.max_resources_per_stack + 1
|
|
||||||
for i in range(num_resources):
|
|
||||||
template += rsrc_snippet % i
|
|
||||||
|
|
||||||
ex = self.assertRaises(lib_exc.BadRequest, self.create_stack,
|
|
||||||
stack_name, template)
|
|
||||||
self.assertIn('Maximum resources per stack exceeded', str(ex))
|
|
@ -1,196 +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 netaddr
|
|
||||||
from oslo_log import log as logging
|
|
||||||
|
|
||||||
from tempest.api.orchestration import base
|
|
||||||
from tempest import config
|
|
||||||
from tempest.lib.common.utils import data_utils
|
|
||||||
from tempest.lib import decorators
|
|
||||||
from tempest.lib import exceptions
|
|
||||||
from tempest import test
|
|
||||||
|
|
||||||
CONF = config.CONF
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class NeutronResourcesTestJSON(base.BaseOrchestrationTest):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def skip_checks(cls):
|
|
||||||
super(NeutronResourcesTestJSON, cls).skip_checks()
|
|
||||||
if not CONF.service_available.neutron:
|
|
||||||
raise cls.skipException("Neutron support is required")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def setup_credentials(cls):
|
|
||||||
cls.set_network_resources()
|
|
||||||
super(NeutronResourcesTestJSON, cls).setup_credentials()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def setup_clients(cls):
|
|
||||||
super(NeutronResourcesTestJSON, cls).setup_clients()
|
|
||||||
cls.subnets_client = cls.os_primary.subnets_client
|
|
||||||
cls.ports_client = cls.os_primary.ports_client
|
|
||||||
cls.routers_client = cls.os_primary.routers_client
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def resource_setup(cls):
|
|
||||||
super(NeutronResourcesTestJSON, cls).resource_setup()
|
|
||||||
cls.neutron_basic_template = cls.load_template('neutron_basic')
|
|
||||||
cls.stack_name = data_utils.rand_name('heat')
|
|
||||||
template = cls.read_template('neutron_basic')
|
|
||||||
cls.keypair_name = (CONF.orchestration.keypair_name or
|
|
||||||
cls._create_keypair()['name'])
|
|
||||||
cls.external_network_id = CONF.network.public_network_id
|
|
||||||
|
|
||||||
tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
|
|
||||||
mask_bits = CONF.network.project_network_mask_bits
|
|
||||||
cls.subnet_cidr = tenant_cidr.subnet(mask_bits).next()
|
|
||||||
|
|
||||||
# create the stack
|
|
||||||
cls.stack_identifier = cls.create_stack(
|
|
||||||
cls.stack_name,
|
|
||||||
template,
|
|
||||||
parameters={
|
|
||||||
'KeyName': cls.keypair_name,
|
|
||||||
'InstanceType': CONF.orchestration.instance_type,
|
|
||||||
'ImageId': CONF.compute.image_ref,
|
|
||||||
'ExternalNetworkId': cls.external_network_id,
|
|
||||||
'timeout': CONF.orchestration.build_timeout,
|
|
||||||
'DNSServers': CONF.network.dns_servers,
|
|
||||||
'SubNetCidr': str(cls.subnet_cidr)
|
|
||||||
})
|
|
||||||
cls.stack_id = cls.stack_identifier.split('/')[1]
|
|
||||||
try:
|
|
||||||
cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
|
|
||||||
resources = (cls.client.list_resources(cls.stack_identifier)
|
|
||||||
['resources'])
|
|
||||||
except exceptions.TimeoutException:
|
|
||||||
if CONF.compute_feature_enabled.console_output:
|
|
||||||
# attempt to log the server console to help with debugging
|
|
||||||
# the cause of the server not signalling the waitcondition
|
|
||||||
# to heat.
|
|
||||||
body = cls.client.show_resource(cls.stack_identifier,
|
|
||||||
'Server')
|
|
||||||
server_id = body.get('physical_resource_id')
|
|
||||||
if server_id:
|
|
||||||
LOG.debug('Console output for %s', server_id)
|
|
||||||
output = cls.servers_client.get_console_output(
|
|
||||||
server_id)['output']
|
|
||||||
LOG.debug(output)
|
|
||||||
else:
|
|
||||||
LOG.debug('Server resource is %s', body)
|
|
||||||
raise # original exception
|
|
||||||
|
|
||||||
cls.test_resources = {}
|
|
||||||
for resource in resources:
|
|
||||||
cls.test_resources[resource['logical_resource_id']] = resource
|
|
||||||
|
|
||||||
@decorators.idempotent_id('f9e2664c-bc44-4eef-98b6-495e4f9d74b3')
|
|
||||||
def test_created_resources(self):
|
|
||||||
"""Verifies created neutron resources."""
|
|
||||||
resources = [('Network', self.neutron_basic_template['resources'][
|
|
||||||
'Network']['type']),
|
|
||||||
('Subnet', self.neutron_basic_template['resources'][
|
|
||||||
'Subnet']['type']),
|
|
||||||
('RouterInterface', self.neutron_basic_template[
|
|
||||||
'resources']['RouterInterface']['type']),
|
|
||||||
('Server', self.neutron_basic_template['resources'][
|
|
||||||
'Server']['type'])]
|
|
||||||
for resource_name, resource_type in resources:
|
|
||||||
resource = self.test_resources.get(resource_name, None)
|
|
||||||
self.assertIsInstance(resource, dict)
|
|
||||||
self.assertEqual(resource_name, resource['logical_resource_id'])
|
|
||||||
self.assertEqual(resource_type, resource['resource_type'])
|
|
||||||
self.assertEqual('CREATE_COMPLETE', resource['resource_status'])
|
|
||||||
|
|
||||||
@decorators.idempotent_id('c572b915-edb1-4e90-b196-c7199a6848c0')
|
|
||||||
@test.services('network')
|
|
||||||
def test_created_network(self):
|
|
||||||
"""Verifies created network."""
|
|
||||||
network_id = self.test_resources.get('Network')['physical_resource_id']
|
|
||||||
body = self.networks_client.show_network(network_id)
|
|
||||||
network = body['network']
|
|
||||||
self.assertIsInstance(network, dict)
|
|
||||||
self.assertEqual(network_id, network['id'])
|
|
||||||
self.assertEqual(self.neutron_basic_template['resources'][
|
|
||||||
'Network']['properties']['name'], network['name'])
|
|
||||||
|
|
||||||
@decorators.idempotent_id('e8f84b96-f9d7-4684-ad5f-340203e9f2c2')
|
|
||||||
@test.services('network')
|
|
||||||
def test_created_subnet(self):
|
|
||||||
"""Verifies created subnet."""
|
|
||||||
subnet_id = self.test_resources.get('Subnet')['physical_resource_id']
|
|
||||||
body = self.subnets_client.show_subnet(subnet_id)
|
|
||||||
subnet = body['subnet']
|
|
||||||
network_id = self.test_resources.get('Network')['physical_resource_id']
|
|
||||||
self.assertEqual(subnet_id, subnet['id'])
|
|
||||||
self.assertEqual(network_id, subnet['network_id'])
|
|
||||||
self.assertEqual(self.neutron_basic_template['resources'][
|
|
||||||
'Subnet']['properties']['name'], subnet['name'])
|
|
||||||
self.assertEqual(sorted(CONF.network.dns_servers),
|
|
||||||
sorted(subnet['dns_nameservers']))
|
|
||||||
self.assertEqual(self.neutron_basic_template['resources'][
|
|
||||||
'Subnet']['properties']['ip_version'], subnet['ip_version'])
|
|
||||||
self.assertEqual(str(self.subnet_cidr), subnet['cidr'])
|
|
||||||
|
|
||||||
@decorators.idempotent_id('96af4c7f-5069-44bc-bdcf-c0390f8a67d1')
|
|
||||||
@test.services('network')
|
|
||||||
def test_created_router(self):
|
|
||||||
"""Verifies created router."""
|
|
||||||
router_id = self.test_resources.get('Router')['physical_resource_id']
|
|
||||||
body = self.routers_client.show_router(router_id)
|
|
||||||
router = body['router']
|
|
||||||
self.assertEqual(self.neutron_basic_template['resources'][
|
|
||||||
'Router']['properties']['name'], router['name'])
|
|
||||||
self.assertEqual(self.external_network_id,
|
|
||||||
router['external_gateway_info']['network_id'])
|
|
||||||
self.assertEqual(True, router['admin_state_up'])
|
|
||||||
|
|
||||||
@decorators.idempotent_id('89f605bd-153e-43ee-a0ed-9919b63423c5')
|
|
||||||
@test.services('network')
|
|
||||||
def test_created_router_interface(self):
|
|
||||||
"""Verifies created router interface."""
|
|
||||||
router_id = self.test_resources.get('Router')['physical_resource_id']
|
|
||||||
network_id = self.test_resources.get('Network')['physical_resource_id']
|
|
||||||
subnet_id = self.test_resources.get('Subnet')['physical_resource_id']
|
|
||||||
body = self.ports_client.list_ports()
|
|
||||||
ports = body['ports']
|
|
||||||
router_ports = filter(lambda port: port['device_id'] ==
|
|
||||||
router_id, ports)
|
|
||||||
created_network_ports = filter(lambda port: port['network_id'] ==
|
|
||||||
network_id, router_ports)
|
|
||||||
self.assertEqual(1, len(created_network_ports))
|
|
||||||
router_interface = created_network_ports[0]
|
|
||||||
fixed_ips = router_interface['fixed_ips']
|
|
||||||
subnet_fixed_ips = filter(lambda port: port['subnet_id'] ==
|
|
||||||
subnet_id, fixed_ips)
|
|
||||||
self.assertEqual(1, len(subnet_fixed_ips))
|
|
||||||
router_interface_ip = subnet_fixed_ips[0]['ip_address']
|
|
||||||
self.assertEqual(str(self.subnet_cidr.iter_hosts().next()),
|
|
||||||
router_interface_ip)
|
|
||||||
|
|
||||||
@decorators.idempotent_id('75d85316-4ac2-4c0e-a1a9-edd2148fc10e')
|
|
||||||
@test.services('compute', 'network')
|
|
||||||
def test_created_server(self):
|
|
||||||
"""Verifies created sever."""
|
|
||||||
server_id = self.test_resources.get('Server')['physical_resource_id']
|
|
||||||
server = self.servers_client.show_server(server_id)['server']
|
|
||||||
self.assertEqual(self.keypair_name, server['key_name'])
|
|
||||||
self.assertEqual('ACTIVE', server['status'])
|
|
||||||
network = server['addresses'][self.neutron_basic_template['resources'][
|
|
||||||
'Network']['properties']['name']][0]
|
|
||||||
self.assertEqual(4, network['version'])
|
|
||||||
self.assertIn(netaddr.IPAddress(network['addr']), self.subnet_cidr)
|
|
@ -1,150 +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 tempest.api.orchestration import base
|
|
||||||
from tempest import config
|
|
||||||
from tempest.lib.common.utils import data_utils
|
|
||||||
from tempest.lib import decorators
|
|
||||||
|
|
||||||
CONF = config.CONF
|
|
||||||
|
|
||||||
|
|
||||||
class StacksTestJSON(base.BaseOrchestrationTest):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def resource_setup(cls):
|
|
||||||
super(StacksTestJSON, cls).resource_setup()
|
|
||||||
cls.stack_name = data_utils.rand_name('heat')
|
|
||||||
template = cls.read_template('non_empty_stack')
|
|
||||||
image_id = (CONF.compute.image_ref or
|
|
||||||
cls._create_image()['id'])
|
|
||||||
flavor = CONF.orchestration.instance_type
|
|
||||||
# create the stack
|
|
||||||
cls.stack_identifier = cls.create_stack(
|
|
||||||
cls.stack_name,
|
|
||||||
template,
|
|
||||||
parameters={
|
|
||||||
'trigger': 'start',
|
|
||||||
'image': image_id,
|
|
||||||
'flavor': flavor
|
|
||||||
})
|
|
||||||
cls.stack_id = cls.stack_identifier.split('/')[1]
|
|
||||||
cls.resource_name = 'fluffy'
|
|
||||||
cls.resource_type = 'AWS::AutoScaling::LaunchConfiguration'
|
|
||||||
cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
|
|
||||||
|
|
||||||
def _list_stacks(self, expected_num=None, **filter_kwargs):
|
|
||||||
stacks = self.client.list_stacks(params=filter_kwargs)['stacks']
|
|
||||||
self.assertIsInstance(stacks, list)
|
|
||||||
if expected_num is not None:
|
|
||||||
self.assertEqual(expected_num, len(stacks))
|
|
||||||
return stacks
|
|
||||||
|
|
||||||
@decorators.idempotent_id('065c652a-720d-4760-9132-06aedeb8e3ab')
|
|
||||||
def test_stack_list(self):
|
|
||||||
"""Created stack should be in the list of existing stacks."""
|
|
||||||
stacks = self._list_stacks()
|
|
||||||
stacks_names = map(lambda stack: stack['stack_name'], stacks)
|
|
||||||
self.assertIn(self.stack_name, stacks_names)
|
|
||||||
|
|
||||||
@decorators.idempotent_id('992f96e3-41ee-4ff6-91c7-bcfb670c0919')
|
|
||||||
def test_stack_show(self):
|
|
||||||
"""Getting details about created stack should be possible."""
|
|
||||||
stack = self.client.show_stack(self.stack_name)['stack']
|
|
||||||
self.assertIsInstance(stack, dict)
|
|
||||||
self.assert_fields_in_dict(stack, 'stack_name', 'id', 'links',
|
|
||||||
'parameters', 'outputs', 'disable_rollback',
|
|
||||||
'stack_status_reason', 'stack_status',
|
|
||||||
'creation_time', 'updated_time',
|
|
||||||
'capabilities', 'notification_topics',
|
|
||||||
'timeout_mins', 'template_description')
|
|
||||||
self.assert_fields_in_dict(stack['parameters'], 'AWS::StackId',
|
|
||||||
'trigger', 'AWS::Region', 'AWS::StackName')
|
|
||||||
self.assertEqual(True, stack['disable_rollback'],
|
|
||||||
'disable_rollback should default to True')
|
|
||||||
self.assertEqual(self.stack_name, stack['stack_name'])
|
|
||||||
self.assertEqual(self.stack_id, stack['id'])
|
|
||||||
self.assertEqual('fluffy', stack['outputs'][0]['output_key'])
|
|
||||||
|
|
||||||
@decorators.idempotent_id('fe719f7a-305a-44d8-bbb5-c91e93d9da17')
|
|
||||||
def test_suspend_resume_stack(self):
|
|
||||||
"""Suspend and resume a stack."""
|
|
||||||
self.client.suspend_stack(self.stack_identifier)
|
|
||||||
self.client.wait_for_stack_status(self.stack_identifier,
|
|
||||||
'SUSPEND_COMPLETE')
|
|
||||||
self.client.resume_stack(self.stack_identifier)
|
|
||||||
self.client.wait_for_stack_status(self.stack_identifier,
|
|
||||||
'RESUME_COMPLETE')
|
|
||||||
|
|
||||||
@decorators.idempotent_id('c951d55e-7cce-4c1f-83a0-bad735437fa6')
|
|
||||||
def test_list_resources(self):
|
|
||||||
"""Get list of created resources for the stack should be possible."""
|
|
||||||
resources = self.list_resources(self.stack_identifier)
|
|
||||||
self.assertEqual({self.resource_name: self.resource_type}, resources)
|
|
||||||
|
|
||||||
@decorators.idempotent_id('2aba03b3-392f-4237-900b-1f5a5e9bd962')
|
|
||||||
def test_show_resource(self):
|
|
||||||
"""Getting details about created resource should be possible."""
|
|
||||||
resource = self.client.show_resource(self.stack_identifier,
|
|
||||||
self.resource_name)['resource']
|
|
||||||
self.assertIsInstance(resource, dict)
|
|
||||||
self.assert_fields_in_dict(resource, 'resource_name', 'description',
|
|
||||||
'links', 'logical_resource_id',
|
|
||||||
'resource_status', 'updated_time',
|
|
||||||
'required_by', 'resource_status_reason',
|
|
||||||
'physical_resource_id', 'resource_type')
|
|
||||||
self.assertEqual(self.resource_name, resource['logical_resource_id'])
|
|
||||||
self.assertEqual(self.resource_type, resource['resource_type'])
|
|
||||||
|
|
||||||
@decorators.idempotent_id('898070a9-eba5-4fae-b7d6-cf3ffa03090f')
|
|
||||||
def test_resource_metadata(self):
|
|
||||||
"""Getting metadata for created resources should be possible."""
|
|
||||||
metadata = self.client.show_resource_metadata(
|
|
||||||
self.stack_identifier,
|
|
||||||
self.resource_name)['metadata']
|
|
||||||
self.assertIsInstance(metadata, dict)
|
|
||||||
self.assertEqual(['Tom', 'Stinky'], metadata.get('kittens', None))
|
|
||||||
|
|
||||||
@decorators.idempotent_id('46567533-0a7f-483b-8942-fa19e0f17839')
|
|
||||||
def test_list_events(self):
|
|
||||||
"""Getting list of created events for the stack should be possible."""
|
|
||||||
events = self.client.list_events(self.stack_identifier)['events']
|
|
||||||
self.assertIsInstance(events, list)
|
|
||||||
|
|
||||||
for event in events:
|
|
||||||
self.assert_fields_in_dict(event, 'logical_resource_id', 'id',
|
|
||||||
'resource_status_reason',
|
|
||||||
'resource_status', 'event_time')
|
|
||||||
|
|
||||||
resource_statuses = [event['resource_status'] for event in events]
|
|
||||||
self.assertIn('CREATE_IN_PROGRESS', resource_statuses)
|
|
||||||
self.assertIn('CREATE_COMPLETE', resource_statuses)
|
|
||||||
|
|
||||||
@decorators.idempotent_id('92465723-1673-400a-909d-4773757a3f21')
|
|
||||||
def test_show_event(self):
|
|
||||||
"""Getting details about an event should be possible."""
|
|
||||||
events = self.client.list_resource_events(self.stack_identifier,
|
|
||||||
self.resource_name)['events']
|
|
||||||
self.assertNotEqual([], events)
|
|
||||||
events.sort(key=lambda event: event['event_time'])
|
|
||||||
event_id = events[0]['id']
|
|
||||||
event = self.client.show_event(self.stack_identifier,
|
|
||||||
self.resource_name, event_id)['event']
|
|
||||||
self.assertIsInstance(event, dict)
|
|
||||||
self.assert_fields_in_dict(event, 'resource_name', 'event_time',
|
|
||||||
'links', 'logical_resource_id',
|
|
||||||
'resource_status', 'resource_status_reason',
|
|
||||||
'physical_resource_id', 'id',
|
|
||||||
'resource_properties', 'resource_type')
|
|
||||||
self.assertEqual(self.resource_name, event['resource_name'])
|
|
||||||
self.assertEqual('state changed', event['resource_status_reason'])
|
|
||||||
self.assertEqual(self.resource_name, event['logical_resource_id'])
|
|
@ -1,92 +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 tempest.api.orchestration import base
|
|
||||||
from tempest.lib.common.utils import data_utils
|
|
||||||
from tempest.lib import decorators
|
|
||||||
|
|
||||||
|
|
||||||
class NovaKeyPairResourcesYAMLTest(base.BaseOrchestrationTest):
|
|
||||||
_tpl_type = 'yaml'
|
|
||||||
_resource = 'resources'
|
|
||||||
_type = 'type'
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def resource_setup(cls):
|
|
||||||
super(NovaKeyPairResourcesYAMLTest, cls).resource_setup()
|
|
||||||
cls.stack_name = data_utils.rand_name('heat')
|
|
||||||
template = cls.read_template('nova_keypair', ext=cls._tpl_type)
|
|
||||||
|
|
||||||
# create the stack, avoid any duplicated key.
|
|
||||||
cls.stack_identifier = cls.create_stack(
|
|
||||||
cls.stack_name,
|
|
||||||
template,
|
|
||||||
parameters={
|
|
||||||
'KeyPairName1': cls.stack_name + '_1',
|
|
||||||
'KeyPairName2': cls.stack_name + '_2'
|
|
||||||
})
|
|
||||||
|
|
||||||
cls.stack_id = cls.stack_identifier.split('/')[1]
|
|
||||||
cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
|
|
||||||
resources = (cls.client.list_resources(cls.stack_identifier)
|
|
||||||
['resources'])
|
|
||||||
cls.test_resources = {}
|
|
||||||
for resource in resources:
|
|
||||||
cls.test_resources[resource['logical_resource_id']] = resource
|
|
||||||
|
|
||||||
@decorators.idempotent_id('b476eac2-a302-4815-961f-18c410a2a537')
|
|
||||||
def test_created_resources(self):
|
|
||||||
"""Verifies created keypair resource."""
|
|
||||||
|
|
||||||
nova_keypair_template = self.load_template('nova_keypair',
|
|
||||||
ext=self._tpl_type)
|
|
||||||
resources = [('KeyPairSavePrivate',
|
|
||||||
nova_keypair_template[self._resource][
|
|
||||||
'KeyPairSavePrivate'][self._type]),
|
|
||||||
('KeyPairDontSavePrivate',
|
|
||||||
nova_keypair_template[self._resource][
|
|
||||||
'KeyPairDontSavePrivate'][self._type])]
|
|
||||||
|
|
||||||
for resource_name, resource_type in resources:
|
|
||||||
resource = self.test_resources.get(resource_name, None)
|
|
||||||
self.assertIsInstance(resource, dict)
|
|
||||||
self.assertEqual(resource_name, resource['logical_resource_id'])
|
|
||||||
self.assertEqual(resource_type, resource['resource_type'])
|
|
||||||
self.assertEqual('CREATE_COMPLETE', resource['resource_status'])
|
|
||||||
|
|
||||||
@decorators.idempotent_id('8d77dec7-91fd-45a6-943d-5abd45e338a4')
|
|
||||||
def test_stack_keypairs_output(self):
|
|
||||||
stack = self.client.show_stack(self.stack_name)['stack']
|
|
||||||
self.assertIsInstance(stack, dict)
|
|
||||||
|
|
||||||
output_map = {}
|
|
||||||
for outputs in stack['outputs']:
|
|
||||||
output_map[outputs['output_key']] = outputs['output_value']
|
|
||||||
# Test that first key generated public and private keys
|
|
||||||
self.assertIn('KeyPair_PublicKey', output_map)
|
|
||||||
self.assertIn("Generated", output_map['KeyPair_PublicKey'])
|
|
||||||
self.assertIn('KeyPair_PrivateKey', output_map)
|
|
||||||
self.assertIn('-----BEGIN', output_map['KeyPair_PrivateKey'])
|
|
||||||
# Test that second key generated public key, and private key is not
|
|
||||||
# in the output due to save_private_key = false
|
|
||||||
self.assertIn('KeyPairDontSavePrivate_PublicKey', output_map)
|
|
||||||
self.assertIn('Generated',
|
|
||||||
output_map['KeyPairDontSavePrivate_PublicKey'])
|
|
||||||
self.assertIn(u'KeyPairDontSavePrivate_PrivateKey', output_map)
|
|
||||||
private_key = output_map['KeyPairDontSavePrivate_PrivateKey']
|
|
||||||
self.assertEqual(0, len(private_key))
|
|
||||||
|
|
||||||
|
|
||||||
class NovaKeyPairResourcesAWSTest(NovaKeyPairResourcesYAMLTest):
|
|
||||||
_tpl_type = 'json'
|
|
||||||
_resource = 'Resources'
|
|
||||||
_type = 'Type'
|
|
@ -1,49 +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 tempest.api.orchestration import base
|
|
||||||
from tempest.lib import decorators
|
|
||||||
|
|
||||||
|
|
||||||
class ResourceTypesTest(base.BaseOrchestrationTest):
|
|
||||||
|
|
||||||
@decorators.attr(type='smoke')
|
|
||||||
@decorators.idempotent_id('7123d082-3577-4a30-8f00-f805327c4ffd')
|
|
||||||
def test_resource_type_list(self):
|
|
||||||
"""Verify it is possible to list resource types."""
|
|
||||||
resource_types = self.client.list_resource_types()['resource_types']
|
|
||||||
self.assertIsInstance(resource_types, list)
|
|
||||||
self.assertIn('OS::Nova::Server', resource_types)
|
|
||||||
|
|
||||||
@decorators.attr(type='smoke')
|
|
||||||
@decorators.idempotent_id('0e85a483-828b-4a28-a0e3-f0a21809192b')
|
|
||||||
def test_resource_type_show(self):
|
|
||||||
"""Verify it is possible to get schema about resource types."""
|
|
||||||
resource_types = self.client.list_resource_types()['resource_types']
|
|
||||||
self.assertNotEmpty(resource_types)
|
|
||||||
|
|
||||||
for resource_type in resource_types:
|
|
||||||
type_schema = self.client.show_resource_type(resource_type)
|
|
||||||
self.assert_fields_in_dict(type_schema, 'properties',
|
|
||||||
'attributes', 'resource_type')
|
|
||||||
self.assertEqual(resource_type, type_schema['resource_type'])
|
|
||||||
|
|
||||||
@decorators.attr(type='smoke')
|
|
||||||
@decorators.idempotent_id('8401821d-65fe-4d43-9fa3-57d5ce3a35c7')
|
|
||||||
def test_resource_type_template(self):
|
|
||||||
"""Verify it is possible to get template about resource types."""
|
|
||||||
type_template = self.client.show_resource_type_template(
|
|
||||||
'OS::Nova::Server')
|
|
||||||
self.assert_fields_in_dict(
|
|
||||||
type_template,
|
|
||||||
'Outputs',
|
|
||||||
'Parameters', 'Resources')
|
|
@ -1,169 +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 tempest.api.orchestration import base
|
|
||||||
from tempest.lib.common.utils import data_utils
|
|
||||||
from tempest.lib import decorators
|
|
||||||
from tempest.lib import exceptions as lib_exc
|
|
||||||
|
|
||||||
|
|
||||||
class TestSoftwareConfig(base.BaseOrchestrationTest):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(TestSoftwareConfig, self).setUp()
|
|
||||||
self.configs = []
|
|
||||||
# Add 2 sets of software configuration
|
|
||||||
self.configs.append(self._config_create('a'))
|
|
||||||
self.configs.append(self._config_create('b'))
|
|
||||||
# Create a deployment using config a's id
|
|
||||||
self._deployment_create(self.configs[0]['id'])
|
|
||||||
|
|
||||||
def _config_create(self, suffix):
|
|
||||||
configuration = {'group': 'script',
|
|
||||||
'inputs': [],
|
|
||||||
'outputs': [],
|
|
||||||
'options': {}}
|
|
||||||
configuration['name'] = 'heat_soft_config_%s' % suffix
|
|
||||||
configuration['config'] = '#!/bin/bash echo init-%s' % suffix
|
|
||||||
api_config = self.client.create_software_config(**configuration)
|
|
||||||
configuration['id'] = api_config['software_config']['id']
|
|
||||||
self.addCleanup(self._config_delete, configuration['id'])
|
|
||||||
self._validate_config(configuration, api_config)
|
|
||||||
return configuration
|
|
||||||
|
|
||||||
def _validate_config(self, configuration, api_config):
|
|
||||||
# Assert all expected keys are present with matching data
|
|
||||||
for k in configuration:
|
|
||||||
self.assertEqual(configuration[k],
|
|
||||||
api_config['software_config'][k])
|
|
||||||
|
|
||||||
def _deployment_create(self, config_id):
|
|
||||||
self.server_id = data_utils.rand_name('dummy-server')
|
|
||||||
self.action = 'ACTION_0'
|
|
||||||
self.status = 'STATUS_0'
|
|
||||||
self.input_values = {}
|
|
||||||
self.output_values = []
|
|
||||||
self.status_reason = 'REASON_0'
|
|
||||||
self.signal_transport = 'NO_SIGNAL'
|
|
||||||
self.deployment = self.client.create_software_deploy(
|
|
||||||
self.server_id, config_id, self.action, self.status,
|
|
||||||
self.input_values, self.output_values, self.status_reason,
|
|
||||||
self.signal_transport)
|
|
||||||
self.deployment_id = self.deployment['software_deployment']['id']
|
|
||||||
self.addCleanup(self._deployment_delete, self.deployment_id)
|
|
||||||
|
|
||||||
def _deployment_delete(self, deploy_id):
|
|
||||||
self.client.delete_software_deploy(deploy_id)
|
|
||||||
# Testing that it is really gone
|
|
||||||
self.assertRaises(
|
|
||||||
lib_exc.NotFound, self.client.show_software_deployment,
|
|
||||||
self.deployment_id)
|
|
||||||
|
|
||||||
def _config_delete(self, config_id):
|
|
||||||
self.client.delete_software_config(config_id)
|
|
||||||
# Testing that it is really gone
|
|
||||||
self.assertRaises(
|
|
||||||
lib_exc.NotFound, self.client.show_software_config, config_id)
|
|
||||||
|
|
||||||
@decorators.attr(type='smoke')
|
|
||||||
@decorators.idempotent_id('136162ed-9445-4b9c-b7fc-306af8b5da99')
|
|
||||||
def test_get_software_config(self):
|
|
||||||
"""Testing software config get."""
|
|
||||||
for conf in self.configs:
|
|
||||||
api_config = self.client.show_software_config(conf['id'])
|
|
||||||
self._validate_config(conf, api_config)
|
|
||||||
|
|
||||||
@decorators.attr(type='smoke')
|
|
||||||
@decorators.idempotent_id('1275c835-c967-4a2c-8d5d-ad533447ed91')
|
|
||||||
def test_get_deployment_list(self):
|
|
||||||
"""Getting a list of all deployments"""
|
|
||||||
deploy_list = self.client.list_software_deployments()
|
|
||||||
deploy_ids = [deploy['id'] for deploy in
|
|
||||||
deploy_list['software_deployments']]
|
|
||||||
self.assertIn(self.deployment_id, deploy_ids)
|
|
||||||
|
|
||||||
@decorators.attr(type='smoke')
|
|
||||||
@decorators.idempotent_id('fe7cd9f9-54b1-429c-a3b7-7df8451db913')
|
|
||||||
def test_get_deployment_metadata(self):
|
|
||||||
"""Testing deployment metadata get"""
|
|
||||||
metadata = self.client.show_software_deployment_metadata(
|
|
||||||
self.server_id)
|
|
||||||
conf_ids = [conf['id'] for conf in metadata['metadata']]
|
|
||||||
self.assertIn(self.configs[0]['id'], conf_ids)
|
|
||||||
|
|
||||||
def _validate_deployment(self, action, status, reason, config_id):
|
|
||||||
deployment = self.client.show_software_deployment(self.deployment_id)
|
|
||||||
self.assertEqual(action, deployment['software_deployment']['action'])
|
|
||||||
self.assertEqual(status, deployment['software_deployment']['status'])
|
|
||||||
self.assertEqual(reason,
|
|
||||||
deployment['software_deployment']['status_reason'])
|
|
||||||
self.assertEqual(config_id,
|
|
||||||
deployment['software_deployment']['config_id'])
|
|
||||||
|
|
||||||
@decorators.attr(type='smoke')
|
|
||||||
@decorators.idempotent_id('f29d21f3-ed75-47cf-8cdc-ef1bdeb4c674')
|
|
||||||
def test_software_deployment_create_validate(self):
|
|
||||||
"""Testing software deployment was created as expected."""
|
|
||||||
# Asserting that all fields were created
|
|
||||||
self.assert_fields_in_dict(
|
|
||||||
self.deployment['software_deployment'], 'action', 'config_id',
|
|
||||||
'id', 'input_values', 'output_values', 'server_id', 'status',
|
|
||||||
'status_reason')
|
|
||||||
# Testing get for this deployment and verifying parameters
|
|
||||||
self._validate_deployment(self.action, self.status,
|
|
||||||
self.status_reason, self.configs[0]['id'])
|
|
||||||
|
|
||||||
@decorators.attr(type='smoke')
|
|
||||||
@decorators.idempotent_id('2ac43ab3-34f2-415d-be2e-eabb4d14ee32')
|
|
||||||
def test_software_deployment_update_no_metadata_change(self):
|
|
||||||
"""Testing software deployment update without metadata change."""
|
|
||||||
metadata = self.client.show_software_deployment_metadata(
|
|
||||||
self.server_id)
|
|
||||||
# Updating values without changing the configuration ID
|
|
||||||
new_action = 'ACTION_1'
|
|
||||||
new_status = 'STATUS_1'
|
|
||||||
new_reason = 'REASON_1'
|
|
||||||
self.client.update_software_deploy(
|
|
||||||
self.deployment_id, self.server_id, self.configs[0]['id'],
|
|
||||||
new_action, new_status, self.input_values, self.output_values,
|
|
||||||
new_reason, self.signal_transport)
|
|
||||||
# Verifying get and that the deployment was updated as expected
|
|
||||||
self._validate_deployment(new_action, new_status,
|
|
||||||
new_reason, self.configs[0]['id'])
|
|
||||||
|
|
||||||
# Metadata should not be changed at this point
|
|
||||||
test_metadata = self.client.show_software_deployment_metadata(
|
|
||||||
self.server_id)
|
|
||||||
for key in metadata['metadata'][0]:
|
|
||||||
self.assertEqual(
|
|
||||||
metadata['metadata'][0][key],
|
|
||||||
test_metadata['metadata'][0][key])
|
|
||||||
|
|
||||||
@decorators.attr(type='smoke')
|
|
||||||
@decorators.idempotent_id('92c48944-d79d-4595-a840-8e1a581c1a72')
|
|
||||||
def test_software_deployment_update_with_metadata_change(self):
|
|
||||||
"""Testing software deployment update with metadata change."""
|
|
||||||
metadata = self.client.show_software_deployment_metadata(
|
|
||||||
self.server_id)
|
|
||||||
self.client.update_software_deploy(
|
|
||||||
self.deployment_id, self.server_id, self.configs[1]['id'],
|
|
||||||
self.action, self.status, self.input_values,
|
|
||||||
self.output_values, self.status_reason, self.signal_transport)
|
|
||||||
self._validate_deployment(self.action, self.status,
|
|
||||||
self.status_reason, self.configs[1]['id'])
|
|
||||||
# Metadata should now be changed
|
|
||||||
new_metadata = self.client.show_software_deployment_metadata(
|
|
||||||
self.server_id)
|
|
||||||
# Its enough to test the ID in this case
|
|
||||||
meta_id = metadata['metadata'][0]['id']
|
|
||||||
test_id = new_metadata['metadata'][0]['id']
|
|
||||||
self.assertNotEqual(meta_id, test_id)
|
|
@ -1,59 +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 tempest.api.orchestration import base
|
|
||||||
from tempest.lib.common.utils import data_utils
|
|
||||||
from tempest.lib import decorators
|
|
||||||
|
|
||||||
|
|
||||||
class StacksTestJSON(base.BaseOrchestrationTest):
|
|
||||||
empty_template = "HeatTemplateFormatVersion: '2012-12-12'\n"
|
|
||||||
|
|
||||||
@decorators.attr(type='smoke')
|
|
||||||
@decorators.idempotent_id('d35d628c-07f6-4674-85a1-74db9919e986')
|
|
||||||
def test_stack_list_responds(self):
|
|
||||||
stacks = self.client.list_stacks()['stacks']
|
|
||||||
self.assertIsInstance(stacks, list)
|
|
||||||
|
|
||||||
@decorators.attr(type='smoke')
|
|
||||||
@decorators.idempotent_id('10498bd5-a83e-4b62-a817-ce24afe938fe')
|
|
||||||
def test_stack_crud_no_resources(self):
|
|
||||||
stack_name = data_utils.rand_name('heat')
|
|
||||||
|
|
||||||
# create the stack
|
|
||||||
stack_identifier = self.create_stack(
|
|
||||||
stack_name, self.empty_template)
|
|
||||||
stack_id = stack_identifier.split('/')[1]
|
|
||||||
|
|
||||||
# wait for create complete (with no resources it should be instant)
|
|
||||||
self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
|
|
||||||
|
|
||||||
# check for stack in list
|
|
||||||
stacks = self.client.list_stacks()['stacks']
|
|
||||||
list_ids = list([stack['id'] for stack in stacks])
|
|
||||||
self.assertIn(stack_id, list_ids)
|
|
||||||
|
|
||||||
# fetch the stack
|
|
||||||
stack = self.client.show_stack(stack_identifier)['stack']
|
|
||||||
self.assertEqual('CREATE_COMPLETE', stack['stack_status'])
|
|
||||||
|
|
||||||
# fetch the stack by name
|
|
||||||
stack = self.client.show_stack(stack_name)['stack']
|
|
||||||
self.assertEqual('CREATE_COMPLETE', stack['stack_status'])
|
|
||||||
|
|
||||||
# fetch the stack by id
|
|
||||||
stack = self.client.show_stack(stack_id)['stack']
|
|
||||||
self.assertEqual('CREATE_COMPLETE', stack['stack_status'])
|
|
||||||
|
|
||||||
# delete the stack
|
|
||||||
self.client.delete_stack(stack_identifier)
|
|
||||||
self.client.wait_for_stack_status(stack_identifier, 'DELETE_COMPLETE')
|
|
@ -1,120 +0,0 @@
|
|||||||
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
|
|
||||||
#
|
|
||||||
# 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 tempest.api.orchestration import base
|
|
||||||
from tempest import config
|
|
||||||
from tempest.lib.common.utils import data_utils
|
|
||||||
from tempest.lib import decorators
|
|
||||||
from tempest import test
|
|
||||||
|
|
||||||
|
|
||||||
CONF = config.CONF
|
|
||||||
|
|
||||||
|
|
||||||
class SwiftResourcesTestJSON(base.BaseOrchestrationTest):
|
|
||||||
@classmethod
|
|
||||||
def skip_checks(cls):
|
|
||||||
super(SwiftResourcesTestJSON, cls).skip_checks()
|
|
||||||
if not CONF.service_available.swift:
|
|
||||||
raise cls.skipException("Swift support is required")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def setup_credentials(cls):
|
|
||||||
super(SwiftResourcesTestJSON, cls).setup_credentials()
|
|
||||||
stack_owner_role = CONF.orchestration.stack_owner_role
|
|
||||||
operator_role = CONF.object_storage.operator_role
|
|
||||||
cls.os = cls.get_client_manager(
|
|
||||||
roles=[stack_owner_role, operator_role])
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def setup_clients(cls):
|
|
||||||
super(SwiftResourcesTestJSON, cls).setup_clients()
|
|
||||||
cls.account_client = cls.os_primary.account_client
|
|
||||||
cls.container_client = cls.os_primary.container_client
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def resource_setup(cls):
|
|
||||||
super(SwiftResourcesTestJSON, cls).resource_setup()
|
|
||||||
cls.stack_name = data_utils.rand_name('heat')
|
|
||||||
template = cls.read_template('swift_basic')
|
|
||||||
# create the stack
|
|
||||||
cls.stack_identifier = cls.create_stack(
|
|
||||||
cls.stack_name,
|
|
||||||
template)
|
|
||||||
cls.stack_id = cls.stack_identifier.split('/')[1]
|
|
||||||
cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
|
|
||||||
cls.test_resources = {}
|
|
||||||
resources = (cls.client.list_resources(cls.stack_identifier)
|
|
||||||
['resources'])
|
|
||||||
for resource in resources:
|
|
||||||
cls.test_resources[resource['logical_resource_id']] = resource
|
|
||||||
|
|
||||||
@decorators.idempotent_id('1a6fe69e-4be4-4990-9a7a-84b6f18019cb')
|
|
||||||
def test_created_resources(self):
|
|
||||||
"""Created stack should be in the list of existing stacks."""
|
|
||||||
swift_basic_template = self.load_template('swift_basic')
|
|
||||||
resources = [('SwiftContainer', swift_basic_template['resources'][
|
|
||||||
'SwiftContainer']['type']),
|
|
||||||
('SwiftContainerWebsite', swift_basic_template[
|
|
||||||
'resources']['SwiftContainerWebsite']['type'])]
|
|
||||||
for resource_name, resource_type in resources:
|
|
||||||
resource = self.test_resources.get(resource_name)
|
|
||||||
self.assertIsInstance(resource, dict)
|
|
||||||
self.assertEqual(resource_type, resource['resource_type'])
|
|
||||||
self.assertEqual(resource_name, resource['logical_resource_id'])
|
|
||||||
self.assertEqual('CREATE_COMPLETE', resource['resource_status'])
|
|
||||||
|
|
||||||
@decorators.idempotent_id('bd438b18-5494-4d5a-9ce6-d2a942ec5060')
|
|
||||||
@test.services('object_storage')
|
|
||||||
def test_created_containers(self):
|
|
||||||
params = {'format': 'json'}
|
|
||||||
_, container_list = \
|
|
||||||
self.account_client.list_account_containers(params=params)
|
|
||||||
created_containers = [cont for cont in container_list
|
|
||||||
if cont['name'].startswith(self.stack_name)]
|
|
||||||
self.assertEqual(2, len(created_containers))
|
|
||||||
|
|
||||||
@decorators.idempotent_id('73d0c093-9922-44a0-8b1d-1fc092dee367')
|
|
||||||
@test.services('object_storage')
|
|
||||||
def test_acl(self):
|
|
||||||
acl_headers = ('x-container-meta-web-index', 'x-container-read')
|
|
||||||
|
|
||||||
swcont = self.test_resources.get(
|
|
||||||
'SwiftContainer')['physical_resource_id']
|
|
||||||
swcont_website = self.test_resources.get(
|
|
||||||
'SwiftContainerWebsite')['physical_resource_id']
|
|
||||||
|
|
||||||
headers, _ = self.container_client.list_container_metadata(swcont)
|
|
||||||
for h in acl_headers:
|
|
||||||
self.assertNotIn(h, headers)
|
|
||||||
headers, _ = self.container_client.list_container_metadata(
|
|
||||||
swcont_website)
|
|
||||||
for h in acl_headers:
|
|
||||||
self.assertIn(h, headers)
|
|
||||||
|
|
||||||
@decorators.idempotent_id('fda06135-6777-4594-aefa-0f6107169698')
|
|
||||||
@test.services('object_storage')
|
|
||||||
def test_metadata(self):
|
|
||||||
swift_basic_template = self.load_template('swift_basic')
|
|
||||||
metadatas = swift_basic_template['resources']['SwiftContainerWebsite'][
|
|
||||||
'properties']['X-Container-Meta']
|
|
||||||
swcont_website = self.test_resources.get(
|
|
||||||
'SwiftContainerWebsite')['physical_resource_id']
|
|
||||||
headers, _ = self.container_client.list_container_metadata(
|
|
||||||
swcont_website)
|
|
||||||
|
|
||||||
for meta in metadatas:
|
|
||||||
header_meta = "x-container-meta-%s" % meta
|
|
||||||
self.assertIn(header_meta, headers)
|
|
||||||
self.assertEqual(headers[header_meta], metadatas[meta])
|
|
@ -1,61 +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 tempest.api.orchestration import base
|
|
||||||
from tempest.lib.common.utils import data_utils
|
|
||||||
from tempest.lib import decorators
|
|
||||||
|
|
||||||
|
|
||||||
class TemplateYAMLTestJSON(base.BaseOrchestrationTest):
|
|
||||||
template = """
|
|
||||||
HeatTemplateFormatVersion: '2012-12-12'
|
|
||||||
Description: |
|
|
||||||
Template which creates only a new user
|
|
||||||
Resources:
|
|
||||||
CfnUser:
|
|
||||||
Type: AWS::IAM::User
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def resource_setup(cls):
|
|
||||||
super(TemplateYAMLTestJSON, cls).resource_setup()
|
|
||||||
cls.stack_name = data_utils.rand_name('heat')
|
|
||||||
cls.stack_identifier = cls.create_stack(cls.stack_name, cls.template)
|
|
||||||
cls.client.wait_for_stack_status(cls.stack_identifier,
|
|
||||||
'CREATE_COMPLETE')
|
|
||||||
cls.stack_id = cls.stack_identifier.split('/')[1]
|
|
||||||
cls.parameters = {}
|
|
||||||
|
|
||||||
@decorators.idempotent_id('47430699-c368-495e-a1db-64c26fd967d7')
|
|
||||||
def test_show_template(self):
|
|
||||||
"""Getting template used to create the stack."""
|
|
||||||
self.client.show_template(self.stack_identifier)
|
|
||||||
|
|
||||||
@decorators.idempotent_id('ed53debe-8727-46c5-ab58-eba6090ec4de')
|
|
||||||
def test_validate_template(self):
|
|
||||||
"""Validating template passing it content."""
|
|
||||||
self.client.validate_template(self.template,
|
|
||||||
self.parameters)
|
|
||||||
|
|
||||||
|
|
||||||
class TemplateAWSTestJSON(TemplateYAMLTestJSON):
|
|
||||||
template = """
|
|
||||||
{
|
|
||||||
"AWSTemplateFormatVersion" : "2010-09-09",
|
|
||||||
"Description" : "Template which creates only a new user",
|
|
||||||
"Resources" : {
|
|
||||||
"CfnUser" : {
|
|
||||||
"Type" : "AWS::IAM::User"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
@ -1,60 +0,0 @@
|
|||||||
# Copyright 2014 NEC Corporation. All rights reserved.
|
|
||||||
#
|
|
||||||
# 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 tempest.api.orchestration import base
|
|
||||||
from tempest.lib import decorators
|
|
||||||
from tempest.lib import exceptions as lib_exc
|
|
||||||
|
|
||||||
|
|
||||||
class TemplateYAMLNegativeTestJSON(base.BaseOrchestrationTest):
|
|
||||||
template = """
|
|
||||||
HeatTemplateFormatVersion: '2012-12-12'
|
|
||||||
Description: |
|
|
||||||
Template which creates only a new user
|
|
||||||
Resources:
|
|
||||||
CfnUser:
|
|
||||||
Type: AWS::IAM::User
|
|
||||||
"""
|
|
||||||
|
|
||||||
invalid_template_url = 'http:///template.yaml'
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def resource_setup(cls):
|
|
||||||
super(TemplateYAMLNegativeTestJSON, cls).resource_setup()
|
|
||||||
cls.parameters = {}
|
|
||||||
|
|
||||||
@decorators.attr(type=['negative'])
|
|
||||||
@decorators.idempotent_id('5586cbca-ddc4-4152-9db8-fa1ce5fc1876')
|
|
||||||
def test_validate_template_url(self):
|
|
||||||
"""Validating template passing url to it."""
|
|
||||||
self.assertRaises(lib_exc.BadRequest,
|
|
||||||
self.client.validate_template_url,
|
|
||||||
template_url=self.invalid_template_url,
|
|
||||||
parameters=self.parameters)
|
|
||||||
|
|
||||||
|
|
||||||
class TemplateAWSNegativeTestJSON(TemplateYAMLNegativeTestJSON):
|
|
||||||
template = """
|
|
||||||
{
|
|
||||||
"AWSTemplateFormatVersion" : "2010-09-09",
|
|
||||||
"Description" : "Template which creates only a new user",
|
|
||||||
"Resources" : {
|
|
||||||
"CfnUser" : {
|
|
||||||
"Type" : "AWS::IAM::User"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
invalid_template_url = 'http:///template.template'
|
|
@ -1,116 +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 tempest.api.orchestration import base
|
|
||||||
from tempest import config
|
|
||||||
from tempest.lib.common.utils import data_utils
|
|
||||||
from tempest.lib import decorators
|
|
||||||
from tempest.lib import exceptions as lib_exc
|
|
||||||
from tempest import test
|
|
||||||
|
|
||||||
|
|
||||||
CONF = config.CONF
|
|
||||||
|
|
||||||
|
|
||||||
class CinderResourcesTest(base.BaseOrchestrationTest):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def skip_checks(cls):
|
|
||||||
super(CinderResourcesTest, cls).skip_checks()
|
|
||||||
if not CONF.service_available.cinder:
|
|
||||||
raise cls.skipException('Cinder support is required')
|
|
||||||
|
|
||||||
def _cinder_verify(self, volume_id, template):
|
|
||||||
self.assertIsNotNone(volume_id)
|
|
||||||
volume = self.volumes_client.show_volume(volume_id)['volume']
|
|
||||||
self.assertEqual('available', volume.get('status'))
|
|
||||||
self.assertEqual(CONF.volume.volume_size, volume.get('size'))
|
|
||||||
|
|
||||||
self.assertEqual(template['resources']['volume']['properties'][
|
|
||||||
'description'], volume.get('description'))
|
|
||||||
self.assertEqual(template['resources']['volume']['properties'][
|
|
||||||
'name'], volume.get('name'))
|
|
||||||
|
|
||||||
def _outputs_verify(self, stack_identifier, template):
|
|
||||||
self.assertEqual('available',
|
|
||||||
self.get_stack_output(stack_identifier, 'status'))
|
|
||||||
self.assertEqual(str(CONF.volume.volume_size),
|
|
||||||
self.get_stack_output(stack_identifier, 'size'))
|
|
||||||
self.assertEqual(template['resources']['volume']['properties'][
|
|
||||||
'description'], self.get_stack_output(stack_identifier,
|
|
||||||
'display_description'))
|
|
||||||
self.assertEqual(template['resources']['volume']['properties'][
|
|
||||||
'name'], self.get_stack_output(stack_identifier, 'display_name'))
|
|
||||||
|
|
||||||
@decorators.idempotent_id('c3243329-7bdd-4730-b402-4d19d50c41d8')
|
|
||||||
@test.services('volume')
|
|
||||||
def test_cinder_volume_create_delete(self):
|
|
||||||
"""Create and delete a volume via OS::Cinder::Volume."""
|
|
||||||
stack_name = data_utils.rand_name('heat')
|
|
||||||
template = self.read_template('cinder_basic')
|
|
||||||
stack_identifier = self.create_stack(
|
|
||||||
stack_name,
|
|
||||||
template,
|
|
||||||
parameters={
|
|
||||||
'volume_size': CONF.volume.volume_size
|
|
||||||
})
|
|
||||||
self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
|
|
||||||
|
|
||||||
# Verify with cinder that the volume exists, with matching details
|
|
||||||
volume_id = self.get_stack_output(stack_identifier, 'volume_id')
|
|
||||||
cinder_basic_template = self.load_template('cinder_basic')
|
|
||||||
self._cinder_verify(volume_id, cinder_basic_template)
|
|
||||||
|
|
||||||
# Verify the stack outputs are as expected
|
|
||||||
self._outputs_verify(stack_identifier, cinder_basic_template)
|
|
||||||
|
|
||||||
# Delete the stack and ensure the volume is gone
|
|
||||||
self.client.delete_stack(stack_identifier)
|
|
||||||
self.client.wait_for_stack_status(stack_identifier, 'DELETE_COMPLETE')
|
|
||||||
self.assertRaises(lib_exc.NotFound,
|
|
||||||
self.volumes_client.show_volume,
|
|
||||||
volume_id)
|
|
||||||
|
|
||||||
def _cleanup_volume(self, volume_id):
|
|
||||||
"""Cleanup the volume direct with cinder."""
|
|
||||||
self.volumes_client.delete_volume(volume_id)
|
|
||||||
self.volumes_client.wait_for_resource_deletion(volume_id)
|
|
||||||
|
|
||||||
@decorators.idempotent_id('ea8b3a46-b932-4c18-907a-fe23f00b33f8')
|
|
||||||
@test.services('volume')
|
|
||||||
def test_cinder_volume_create_delete_retain(self):
|
|
||||||
"""Ensure the 'Retain' deletion policy is respected."""
|
|
||||||
stack_name = data_utils.rand_name('heat')
|
|
||||||
template = self.read_template('cinder_basic_delete_retain')
|
|
||||||
stack_identifier = self.create_stack(
|
|
||||||
stack_name,
|
|
||||||
template,
|
|
||||||
parameters={
|
|
||||||
'volume_size': CONF.volume.volume_size
|
|
||||||
})
|
|
||||||
self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
|
|
||||||
|
|
||||||
# Verify with cinder that the volume exists, with matching details
|
|
||||||
volume_id = self.get_stack_output(stack_identifier, 'volume_id')
|
|
||||||
self.addCleanup(self._cleanup_volume, volume_id)
|
|
||||||
retain_template = self.load_template('cinder_basic_delete_retain')
|
|
||||||
self._cinder_verify(volume_id, retain_template)
|
|
||||||
|
|
||||||
# Verify the stack outputs are as expected
|
|
||||||
self._outputs_verify(stack_identifier, retain_template)
|
|
||||||
|
|
||||||
# Delete the stack and ensure the volume is *not* gone
|
|
||||||
self.client.delete_stack(stack_identifier)
|
|
||||||
self.client.wait_for_stack_status(stack_identifier, 'DELETE_COMPLETE')
|
|
||||||
self._cinder_verify(volume_id, retain_template)
|
|
||||||
|
|
||||||
# Volume cleanup happens via addCleanup calling _cleanup_volume
|
|
Loading…
x
Reference in New Issue
Block a user