180fed1afa
Added stress environment var for max_instances. Added tempest var for log_level of rest_client. Change-Id: Ia92536a547cdab4d2496bd9ba9067be3595b79cd xxxxx Change-Id: I8c2f499a41f74c2fe6fb08c80ab6fc31f6b93426
344 lines
13 KiB
Python
344 lines
13 KiB
Python
# Copyright 2011 Quanta Research Cambridge, Inc.
|
|
#
|
|
# 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.
|
|
"""Defines various sub-classes of the `StressTestCase` and
|
|
`PendingAction` class. The sub-classes of StressTestCase implement various
|
|
API calls on the Nova cluster having to do with creating and deleting VMs.
|
|
Each sub-class will have a corresponding PendingAction. These pending
|
|
actions veriy that the API call was successful or not."""
|
|
|
|
|
|
# system imports
|
|
import random
|
|
import time
|
|
|
|
|
|
# local imports
|
|
import test_case
|
|
import pending_action
|
|
from tempest.exceptions import TimeoutException
|
|
|
|
|
|
class TestCreateVM(test_case.StressTestCase):
|
|
"""Create a virtual machine in the Nova cluster."""
|
|
_vm_id = 0
|
|
|
|
def run(self, manager, state, *pargs, **kwargs):
|
|
"""
|
|
Send an HTTP POST request to the nova cluster to build a
|
|
server. Update the state variable to track state of new server
|
|
and set to PENDING state.
|
|
|
|
`manager` : Manager object.
|
|
`state` : `State` object describing our view of state of cluster
|
|
`pargs` : positional arguments
|
|
`kwargs` : keyword arguments, which include:
|
|
`key_name` : name of keypair
|
|
`timeout` : how long to wait before issuing Exception
|
|
`image_ref` : index to image types availablexs
|
|
`flavor_ref`: index to flavor types available
|
|
(default = 1, which is tiny)
|
|
"""
|
|
|
|
# restrict number of instances we can launch
|
|
if len(state.get_instances()) >= state.get_max_instances():
|
|
self._logger.debug("maximum number of instances created: %d" %
|
|
state.get_max_instances())
|
|
return None
|
|
|
|
_key_name = kwargs.get('key_name', '')
|
|
_timeout = int(kwargs.get('timeout',
|
|
manager.config.compute.build_timeout))
|
|
_image_ref = kwargs.get('image_ref', manager.config.compute.image_ref)
|
|
_flavor_ref = kwargs.get('flavor_ref',
|
|
manager.config.compute.flavor_ref)
|
|
|
|
expected_server = {
|
|
'name': 'server' + str(TestCreateVM._vm_id),
|
|
'metadata': {
|
|
'key1': 'value1',
|
|
'key2': 'value2',
|
|
},
|
|
'imageRef': _image_ref,
|
|
'flavorRef': _flavor_ref,
|
|
'adminPass': 'testpwd',
|
|
'key_name': _key_name
|
|
}
|
|
TestCreateVM._vm_id = TestCreateVM._vm_id + 1
|
|
response, body = manager.servers_client.create_server(
|
|
expected_server['name'],
|
|
_image_ref,
|
|
_flavor_ref,
|
|
meta=expected_server['metadata'],
|
|
adminPass=expected_server['adminPass']
|
|
)
|
|
|
|
if (response.status != 202):
|
|
self._logger.error("response: %s" % response)
|
|
self._logger.error("body: %s" % body)
|
|
raise Exception
|
|
|
|
created_server = body
|
|
|
|
self._logger.info('setting machine %s to BUILD' %
|
|
created_server['id'])
|
|
state.set_instance_state(created_server['id'],
|
|
(created_server, 'BUILD'))
|
|
|
|
return VerifyCreateVM(manager,
|
|
state,
|
|
created_server,
|
|
expected_server)
|
|
|
|
|
|
class VerifyCreateVM(pending_action.PendingAction):
|
|
"""Verify that VM was built and is running"""
|
|
def __init__(self, manager,
|
|
state,
|
|
created_server,
|
|
expected_server):
|
|
super(VerifyCreateVM, self).__init__(manager,
|
|
state,
|
|
created_server,
|
|
)
|
|
self._expected = expected_server
|
|
|
|
def retry(self):
|
|
"""
|
|
Check to see that the server was created and is running.
|
|
Update local view of state to indicate that it is running.
|
|
"""
|
|
# don't run create verification
|
|
# if target machine has been deleted or is going to be deleted
|
|
if (self._target['id'] not in self._state.get_instances().keys() or
|
|
self._state.get_instances()[self._target['id']][1] ==
|
|
'TERMINATING'):
|
|
self._logger.info('machine %s is deleted or TERMINATING' %
|
|
self._target['id'])
|
|
return True
|
|
|
|
time_diff = time.time() - self._start_time
|
|
if time_diff > self._timeout:
|
|
self._logger.error('%d exceeded launch server timeout of %d' %
|
|
(time_diff, self._timeout))
|
|
raise TimeoutException
|
|
|
|
admin_pass = self._target['adminPass']
|
|
# Could check more things here.
|
|
if (self._expected['adminPass'] != admin_pass):
|
|
self._logger.error('expected: %s' %
|
|
(self._expected['adminPass']))
|
|
self._logger.error('returned: %s' %
|
|
(admin_pass))
|
|
raise Exception
|
|
|
|
if self._check_for_status('ACTIVE') != 'ACTIVE':
|
|
return False
|
|
|
|
self._logger.info('machine %s: BUILD -> ACTIVE [%.1f secs elapsed]' %
|
|
(self._target['id'], time.time() - self._start_time))
|
|
self._state.set_instance_state(self._target['id'],
|
|
(self._target, 'ACTIVE'))
|
|
return True
|
|
|
|
|
|
class TestKillActiveVM(test_case.StressTestCase):
|
|
"""Class to destroy a random ACTIVE server."""
|
|
def run(self, manager, state, *pargs, **kwargs):
|
|
"""
|
|
Send an HTTP POST request to the nova cluster to destroy
|
|
a random ACTIVE server. Update `state` to indicate TERMINATING.
|
|
|
|
`manager` : Manager object.
|
|
`state` : `State` object describing our view of state of cluster
|
|
`pargs` : positional arguments
|
|
`kwargs` : keyword arguments, which include:
|
|
`timeout` : how long to wait before issuing Exception
|
|
"""
|
|
# check for active instances
|
|
vms = state.get_instances()
|
|
active_vms = [v for k, v in vms.iteritems() if v and v[1] == 'ACTIVE']
|
|
# no active vms, so return null
|
|
if not active_vms:
|
|
self._logger.info('no ACTIVE instances to delete')
|
|
return
|
|
|
|
_timeout = kwargs.get('timeout', manager.config.compute.build_timeout)
|
|
|
|
target = random.choice(active_vms)
|
|
killtarget = target[0]
|
|
manager.servers_client.delete_server(killtarget['id'])
|
|
self._logger.info('machine %s: ACTIVE -> TERMINATING' %
|
|
killtarget['id'])
|
|
state.set_instance_state(killtarget['id'],
|
|
(killtarget, 'TERMINATING'))
|
|
return VerifyKillActiveVM(manager, state,
|
|
killtarget, timeout=_timeout)
|
|
|
|
|
|
class VerifyKillActiveVM(pending_action.PendingAction):
|
|
"""Verify that server was destroyed"""
|
|
|
|
def retry(self):
|
|
"""
|
|
Check to see that the server of interest is destroyed. Update
|
|
state to indicate that server is destroyed by deleting it from local
|
|
view of state.
|
|
"""
|
|
tid = self._target['id']
|
|
# if target machine has been deleted from the state, then it was
|
|
# already verified to be deleted
|
|
if (not tid in self._state.get_instances().keys()):
|
|
return False
|
|
|
|
time_diff = time.time() - self._start_time
|
|
if time_diff > self._timeout:
|
|
self._logger.error('server %s: %d exceeds terminate timeout %d' %
|
|
(tid, time_diff, self._timeout))
|
|
raise TimeoutException
|
|
|
|
try:
|
|
self._manager.servers_client.get_server(tid)
|
|
except Exception:
|
|
# if we get a 404 response, is the machine really gone?
|
|
target = self._target
|
|
self._logger.info('machine %s: DELETED [%.1f secs elapsed]' %
|
|
(target['id'], time.time() - self._start_time))
|
|
self._state.delete_instance_state(target['id'])
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
class TestKillAnyVM(test_case.StressTestCase):
|
|
"""Class to destroy a random server regardless of state."""
|
|
|
|
def run(self, manager, state, *pargs, **kwargs):
|
|
"""
|
|
Send an HTTP POST request to the nova cluster to destroy
|
|
a random server. Update state to TERMINATING.
|
|
|
|
`manager` : Manager object.
|
|
`state` : `State` object describing our view of state of cluster
|
|
`pargs` : positional arguments
|
|
`kwargs` : keyword arguments, which include:
|
|
`timeout` : how long to wait before issuing Exception
|
|
"""
|
|
|
|
vms = state.get_instances()
|
|
# no vms, so return null
|
|
if not vms:
|
|
self._logger.info('no active instances to delete')
|
|
return
|
|
|
|
_timeout = kwargs.get('timeout', manager.config.compute.build_timeout)
|
|
|
|
target = random.choice(vms)
|
|
killtarget = target[0]
|
|
|
|
manager.servers_client.delete_server(killtarget['id'])
|
|
self._state.set_instance_state(killtarget['id'],
|
|
(killtarget, 'TERMINATING'))
|
|
# verify object will do the same thing as the active VM
|
|
return VerifyKillAnyVM(manager, state, killtarget, timeout=_timeout)
|
|
|
|
VerifyKillAnyVM = VerifyKillActiveVM
|
|
|
|
|
|
class TestUpdateVMName(test_case.StressTestCase):
|
|
"""Class to change the name of the active server"""
|
|
def run(self, manager, state, *pargs, **kwargs):
|
|
"""
|
|
Issue HTTP POST request to change the name of active server.
|
|
Update state of server to reflect name changing.
|
|
|
|
`manager` : Manager object.
|
|
`state` : `State` object describing our view of state of cluster
|
|
`pargs` : positional arguments
|
|
`kwargs` : keyword arguments, which include:
|
|
`timeout` : how long to wait before issuing Exception
|
|
"""
|
|
|
|
# select one machine from active ones
|
|
vms = state.get_instances()
|
|
active_vms = [v for k, v in vms.iteritems() if v and v[1] == 'ACTIVE']
|
|
# no active vms, so return null
|
|
if not active_vms:
|
|
self._logger.info('no active instances to update')
|
|
return
|
|
|
|
_timeout = kwargs.get('timeout', manager.config.compute.build_timeout)
|
|
|
|
target = random.choice(active_vms)
|
|
update_target = target[0]
|
|
|
|
# Update name by appending '_updated' to the name
|
|
new_name = update_target['name'] + '_updated'
|
|
(response, body) = \
|
|
manager.servers_client.update_server(update_target['id'],
|
|
name=new_name)
|
|
if (response.status != 200):
|
|
self._logger.error("response: %s " % response)
|
|
self._logger.error("body: %s " % body)
|
|
raise Exception
|
|
|
|
assert(new_name == body['name'])
|
|
|
|
self._logger.info('machine %s: ACTIVE -> UPDATING_NAME' %
|
|
body['id'])
|
|
state.set_instance_state(body['id'],
|
|
(body, 'UPDATING_NAME'))
|
|
|
|
return VerifyUpdateVMName(manager,
|
|
state,
|
|
body,
|
|
timeout=_timeout)
|
|
|
|
|
|
class VerifyUpdateVMName(pending_action.PendingAction):
|
|
"""Check that VM has new name"""
|
|
def retry(self):
|
|
"""
|
|
Check that VM has new name. Update local view of `state` to RUNNING.
|
|
"""
|
|
# don't run update verification
|
|
# if target machine has been deleted or is going to be deleted
|
|
if (not self._target['id'] in self._state.get_instances().keys() or
|
|
self._state.get_instances()[self._target['id']][1] ==
|
|
'TERMINATING'):
|
|
return False
|
|
|
|
if time.time() - self._start_time > self._timeout:
|
|
raise TimeoutException
|
|
|
|
response, body = \
|
|
self._manager.serverse_client.get_server(self._target['id'])
|
|
if (response.status != 200):
|
|
self._logger.error("response: %s " % response)
|
|
self._logger.error("body: %s " % body)
|
|
raise Exception
|
|
|
|
if self._target['name'] != body['name']:
|
|
self._logger.error(self._target['name'] +
|
|
' vs. ' +
|
|
body['name'])
|
|
raise Exception
|
|
|
|
# log the update
|
|
self._logger.info('machine %s: UPDATING_NAME -> ACTIVE' %
|
|
self._target['id'])
|
|
self._state.set_instance_state(self._target['id'],
|
|
(body,
|
|
'ACTIVE'))
|
|
return True
|