From 6a03d60c36f0ca2a5f4c1131d06308c0f1a4f8d9 Mon Sep 17 00:00:00 2001 From: Steve Baker Date: Wed, 30 Jul 2014 11:04:42 +1200 Subject: [PATCH] Move test_server_cfn_init from tempest to heat The only changes required to move this test have been: * Change the imports * Use the DEFAULT CONF group for conf options Change-Id: Ic9474e329b9cef1e96b693f10c320b612f580283 Partial-Blueprint: functional-tests --- heat_integrationtests/scenario/__init__.py | 0 .../scenario/test_server_cfn_init.py | 125 ++++++++++++++++++ .../scenario/test_server_cfn_init.yaml | 82 ++++++++++++ 3 files changed, 207 insertions(+) create mode 100644 heat_integrationtests/scenario/__init__.py create mode 100644 heat_integrationtests/scenario/test_server_cfn_init.py create mode 100644 heat_integrationtests/scenario/test_server_cfn_init.yaml diff --git a/heat_integrationtests/scenario/__init__.py b/heat_integrationtests/scenario/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/heat_integrationtests/scenario/test_server_cfn_init.py b/heat_integrationtests/scenario/test_server_cfn_init.py new file mode 100644 index 0000000000..64b2a3573d --- /dev/null +++ b/heat_integrationtests/scenario/test_server_cfn_init.py @@ -0,0 +1,125 @@ +# 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 json +import logging + +from heat_integrationtests.common import exceptions +from heat_integrationtests.common import test + +LOG = logging.getLogger(__name__) + + +class CfnInitIntegrationTest(test.HeatIntegrationTest): + + def setUp(self): + super(CfnInitIntegrationTest, self).setUp() + if not self.conf.image_ref: + raise self.skipException("No image configured to test") + self.client = self.orchestration_client + self.template_name = 'test_server_cfn_init.yaml' + + def assign_keypair(self): + self.stack_name = self._stack_rand_name() + if self.conf.keypair_name: + self.keypair = None + self.keypair_name = self.conf.keypair_name + else: + self.keypair = self.create_keypair() + self.keypair_name = self.keypair.id + + def launch_stack(self): + net = self._get_default_network() + self.parameters = { + 'key_name': self.keypair_name, + 'flavor': self.conf.instance_type, + 'image': self.conf.image_ref, + 'timeout': self.conf.build_timeout, + 'network': net['id'], + } + + # create the stack + self.template = self._load_template(__file__, self.template_name) + self.client.stacks.create( + stack_name=self.stack_name, + template=self.template, + parameters=self.parameters) + + self.stack = self.client.stacks.get(self.stack_name) + self.stack_identifier = '%s/%s' % (self.stack_name, self.stack.id) + self.addCleanup(self._stack_delete, self.stack_identifier) + + def check_stack(self): + sid = self.stack_identifier + self._wait_for_resource_status( + sid, 'WaitHandle', 'CREATE_COMPLETE') + self._wait_for_resource_status( + sid, 'SmokeSecurityGroup', 'CREATE_COMPLETE') + self._wait_for_resource_status( + sid, 'SmokeKeys', 'CREATE_COMPLETE') + self._wait_for_resource_status( + sid, 'CfnUser', 'CREATE_COMPLETE') + self._wait_for_resource_status( + sid, 'SmokeServer', 'CREATE_COMPLETE') + + server_resource = self.client.resources.get(sid, 'SmokeServer') + server_id = server_resource.physical_resource_id + server = self.compute_client.servers.get(server_id) + server_ip = server.networks[self.conf.network_for_ssh][0] + + if not self._ping_ip_address(server_ip): + self._log_console_output(servers=[server]) + self.fail( + "Timed out waiting for %s to become reachable" % server_ip) + + try: + self._wait_for_resource_status( + sid, 'WaitCondition', 'CREATE_COMPLETE') + except (exceptions.StackResourceBuildErrorException, + exceptions.TimeoutException) as e: + raise e + finally: + # attempt to log the server console regardless of WaitCondition + # going to complete. This allows successful and failed cloud-init + # logs to be compared + self._log_console_output(servers=[server]) + + self._wait_for_stack_status(sid, 'CREATE_COMPLETE') + + stack = self.client.stacks.get(sid) + + # This is an assert of great significance, as it means the following + # has happened: + # - cfn-init read the provided metadata and wrote out a file + # - a user was created and credentials written to the server + # - a cfn-signal was built which was signed with provided credentials + # - the wait condition was fulfilled and the stack has changed state + wait_status = json.loads( + self._stack_output(stack, 'WaitConditionStatus')) + self.assertEqual('smoke test complete', wait_status['smoke_status']) + + if self.keypair: + # Check that the user can authenticate with the generated + # keypair + try: + linux_client = self.get_remote_client( + server_ip, username='ec2-user') + linux_client.validate_authentication() + except (exceptions.ServerUnreachable, + exceptions.SSHTimeout) as e: + self._log_console_output(servers=[server]) + raise e + + def test_server_cfn_init(self): + self.assign_keypair() + self.launch_stack() + self.check_stack() diff --git a/heat_integrationtests/scenario/test_server_cfn_init.yaml b/heat_integrationtests/scenario/test_server_cfn_init.yaml new file mode 100644 index 0000000000..c95aabfcf7 --- /dev/null +++ b/heat_integrationtests/scenario/test_server_cfn_init.yaml @@ -0,0 +1,82 @@ +HeatTemplateFormatVersion: '2012-12-12' +Description: | + Template which uses a wait condition to confirm that a minimal + cfn-init and cfn-signal has worked +Parameters: + key_name: + Type: String + flavor: + Type: String + image: + Type: String + network: + Type: String + timeout: + Type: Number +Resources: + CfnUser: + Type: AWS::IAM::User + SmokeSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Enable only ping and SSH access + SecurityGroupIngress: + - {CidrIp: 0.0.0.0/0, FromPort: '-1', IpProtocol: icmp, ToPort: '-1'} + - {CidrIp: 0.0.0.0/0, FromPort: '22', IpProtocol: tcp, ToPort: '22'} + SmokeKeys: + Type: AWS::IAM::AccessKey + Properties: + UserName: {Ref: CfnUser} + SmokeServer: + Type: OS::Nova::Server + Metadata: + AWS::CloudFormation::Init: + config: + files: + /tmp/smoke-status: + content: smoke test complete + /etc/cfn/cfn-credentials: + content: + Fn::Replace: + - SmokeKeys: {Ref: SmokeKeys} + SecretAccessKey: + 'Fn::GetAtt': [SmokeKeys, SecretAccessKey] + - | + AWSAccessKeyId=SmokeKeys + AWSSecretKey=SecretAccessKey + mode: '000400' + owner: root + group: root + Properties: + image: {Ref: image} + flavor: {Ref: flavor} + key_name: {Ref: key_name} + security_groups: + - {Ref: SmokeSecurityGroup} + networks: + - uuid: {Ref: network} + user_data: + Fn::Replace: + - WaitHandle: {Ref: WaitHandle} + - | + #!/bin/bash -v + /opt/aws/bin/cfn-init + /opt/aws/bin/cfn-signal -e 0 --data "`cat /tmp/smoke-status`" \ + --id smoke_status "WaitHandle" + WaitHandle: + Type: AWS::CloudFormation::WaitConditionHandle + WaitCondition: + Type: AWS::CloudFormation::WaitCondition + DependsOn: SmokeServer + Properties: + Handle: {Ref: WaitHandle} + Timeout: {Ref: timeout} +Outputs: + WaitConditionStatus: + Description: Contents of /tmp/smoke-status on SmokeServer + Value: + Fn::GetAtt: [WaitCondition, Data] + SmokeServerIp: + Description: IP address of server + Value: + Fn::GetAtt: [SmokeServer, first_address]