Heat test ssh to the server.
This is run when the resource creation is complete, but before the stack creation is complete. Change-Id: I05c5624a6f3c4817391de87224d647e260607f3e
This commit is contained in:
parent
0985ca79e1
commit
38d8f09279
|
@ -36,6 +36,7 @@ class BaseOrchestrationTest(tempest.test.BaseTestCase):
|
|||
|
||||
cls.os = os
|
||||
cls.orchestration_client = os.orchestration_client
|
||||
cls.servers_client = os.servers_client
|
||||
cls.keypairs_client = os.keypairs_client
|
||||
cls.stacks = []
|
||||
|
||||
|
@ -108,3 +109,9 @@ class BaseOrchestrationTest(tempest.test.BaseTestCase):
|
|||
condition()
|
||||
return
|
||||
time.sleep(self.build_interval)
|
||||
|
||||
@staticmethod
|
||||
def stack_output(stack, output_key):
|
||||
"""Return a stack output value for a give key."""
|
||||
return next((o['output_value'] for o in stack['outputs']
|
||||
if o['output_key'] == output_key), None)
|
||||
|
|
|
@ -14,9 +14,12 @@
|
|||
|
||||
import json
|
||||
import logging
|
||||
import testtools
|
||||
|
||||
from tempest.api.orchestration import base
|
||||
from tempest.common.utils.data_utils import rand_name
|
||||
from tempest.common.utils.linux.remote_client import RemoteClient
|
||||
import tempest.config
|
||||
from tempest.test import attr
|
||||
|
||||
|
||||
|
@ -25,6 +28,8 @@ LOG = logging.getLogger(__name__)
|
|||
|
||||
class InstanceCfnInitTestJSON(base.BaseOrchestrationTest):
|
||||
_interface = 'json'
|
||||
existing_keypair = (tempest.config.TempestConfig().
|
||||
orchestration.keypair_name is not None)
|
||||
|
||||
template = """
|
||||
HeatTemplateFormatVersion: '2012-12-12'
|
||||
|
@ -101,6 +106,10 @@ Outputs:
|
|||
Description: Contents of /tmp/smoke-status on SmokeServer
|
||||
Value:
|
||||
Fn::GetAtt: [WaitCondition, Data]
|
||||
SmokeServerIp:
|
||||
Description: IP address of server
|
||||
Value:
|
||||
Fn::GetAtt: [SmokeServer, PublicIp]
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
|
@ -113,8 +122,11 @@ Outputs:
|
|||
def setUp(self):
|
||||
super(InstanceCfnInitTestJSON, self).setUp()
|
||||
stack_name = rand_name('heat')
|
||||
keypair_name = (self.orchestration_cfg.keypair_name or
|
||||
self._create_keypair()['name'])
|
||||
if self.orchestration_cfg.keypair_name:
|
||||
keypair_name = self.orchestration_cfg.keypair_name
|
||||
else:
|
||||
self.keypair = self._create_keypair()
|
||||
keypair_name = self.keypair['name']
|
||||
|
||||
# create the stack
|
||||
self.stack_identifier = self.create_stack(
|
||||
|
@ -126,6 +138,29 @@ Outputs:
|
|||
'ImageId': self.orchestration_cfg.image_ref
|
||||
})
|
||||
|
||||
@attr(type='gate')
|
||||
@testtools.skipIf(existing_keypair, 'Server ssh tests are disabled.')
|
||||
def test_can_log_into_created_server(self):
|
||||
|
||||
sid = self.stack_identifier
|
||||
rid = 'SmokeServer'
|
||||
|
||||
# wait for server resource create to complete.
|
||||
self.client.wait_for_resource_status(sid, rid, 'CREATE_COMPLETE')
|
||||
|
||||
resp, body = self.client.get_resource(sid, rid)
|
||||
self.assertEqual('CREATE_COMPLETE', body['resource_status'])
|
||||
|
||||
# fetch the ip address from servers client, since we can't get it
|
||||
# from the stack until stack create is complete
|
||||
resp, server = self.servers_client.get_server(
|
||||
body['physical_resource_id'])
|
||||
|
||||
# Check that the user can authenticate with the generated password
|
||||
linux_client = RemoteClient(
|
||||
server, 'ec2-user', pkey=self.keypair['private_key'])
|
||||
self.assertTrue(linux_client.can_authenticate())
|
||||
|
||||
@attr(type='gate')
|
||||
def test_stack_wait_condition_data(self):
|
||||
|
||||
|
@ -148,5 +183,6 @@ Outputs:
|
|||
# - a user was created and credentials written to the instance
|
||||
# - 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(body['outputs'][0]['output_value'])
|
||||
wait_status = json.loads(
|
||||
self.stack_output(body, 'WaitConditionStatus'))
|
||||
self.assertEqual('smoke test complete', wait_status['00000'])
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
# under the License.
|
||||
|
||||
import json
|
||||
import re
|
||||
import time
|
||||
import urllib
|
||||
|
||||
|
@ -68,24 +69,69 @@ class OrchestrationClient(rest_client.RestClient):
|
|||
body = json.loads(body)
|
||||
return resp, body['stack']
|
||||
|
||||
def list_resources(self, stack_identifier):
|
||||
"""Returns the details of a single resource."""
|
||||
url = "stacks/%s/resources" % stack_identifier
|
||||
resp, body = self.get(url)
|
||||
body = json.loads(body)
|
||||
return resp, body['resources']
|
||||
|
||||
def get_resource(self, stack_identifier, resource_name):
|
||||
"""Returns the details of a single resource."""
|
||||
url = "stacks/%s/resources/%s" % (stack_identifier, resource_name)
|
||||
resp, body = self.get(url)
|
||||
body = json.loads(body)
|
||||
return resp, body['resource']
|
||||
|
||||
def delete_stack(self, stack_identifier):
|
||||
"""Deletes the specified Stack."""
|
||||
return self.delete("stacks/%s" % str(stack_identifier))
|
||||
|
||||
def wait_for_stack_status(self, stack_identifier, status, failure_status=(
|
||||
'CREATE_FAILED',
|
||||
'DELETE_FAILED',
|
||||
'UPDATE_FAILED',
|
||||
'ROLLBACK_FAILED')):
|
||||
"""Waits for a Volume to reach a given status."""
|
||||
stack_status = None
|
||||
def wait_for_resource_status(self, stack_identifier, resource_name,
|
||||
status, failure_pattern='^.*_FAILED$'):
|
||||
"""Waits for a Resource to reach a given status."""
|
||||
start = int(time.time())
|
||||
fail_regexp = re.compile(failure_pattern)
|
||||
|
||||
while stack_status != status:
|
||||
while True:
|
||||
try:
|
||||
resp, body = self.get_resource(
|
||||
stack_identifier, resource_name)
|
||||
except exceptions.NotFound:
|
||||
# ignore this, as the resource may not have
|
||||
# been created yet
|
||||
pass
|
||||
else:
|
||||
resource_name = body['logical_resource_id']
|
||||
resource_status = body['resource_status']
|
||||
if resource_status == status:
|
||||
return
|
||||
if fail_regexp.search(resource_status):
|
||||
raise exceptions.StackBuildErrorException(
|
||||
stack_identifier=stack_identifier,
|
||||
resource_status=resource_status,
|
||||
resource_status_reason=body['resource_status_reason'])
|
||||
|
||||
if int(time.time()) - start >= self.build_timeout:
|
||||
message = ('Resource %s failed to reach %s status within '
|
||||
'the required time (%s s).' %
|
||||
(resource_name, status, self.build_timeout))
|
||||
raise exceptions.TimeoutException(message)
|
||||
time.sleep(self.build_interval)
|
||||
|
||||
def wait_for_stack_status(self, stack_identifier, status,
|
||||
failure_pattern='^.*_FAILED$'):
|
||||
"""Waits for a Stack to reach a given status."""
|
||||
start = int(time.time())
|
||||
fail_regexp = re.compile(failure_pattern)
|
||||
|
||||
while True:
|
||||
resp, body = self.get_stack(stack_identifier)
|
||||
stack_name = body['stack_name']
|
||||
stack_status = body['stack_status']
|
||||
if stack_status in failure_status:
|
||||
if stack_status == status:
|
||||
return
|
||||
if fail_regexp.search(stack_status):
|
||||
raise exceptions.StackBuildErrorException(
|
||||
stack_identifier=stack_identifier,
|
||||
stack_status=stack_status,
|
||||
|
|
Loading…
Reference in New Issue