Implement scenario test for the new instance reservation feature

The current instance reservation test scenario is outdated because it
was written for the old instance plugin, which was removed in the Ocata
release.

This patch replaces it with a scenario test for the new instance
reservation feature.

Change-Id: Id6cb3f3a6471eee70000c42694870609068eba75
Closes-Bug: #1714438
This commit is contained in:
Masahito Muroi 2018-09-24 14:42:25 +02:00
parent a81b8ff7ba
commit 8bb95750da
3 changed files with 111 additions and 146 deletions

View File

@ -95,17 +95,49 @@ class ResourceReservationScenarioTest(manager.ScenarioTest):
message = "Timed out waiting for lease to change status to DONE"
raise exceptions.TimeoutException(message)
def remove_image_snapshot(self, image_name):
try:
image = [i for i in self.image_client.list()
if ['name'] == image_name]
self.image_client.delete(image)
except Exception as e:
LOG.info("Unable to delete %(image_name)s snapshot. "
"Exception: %(message)s",
{'image_name': image_name, 'message': str(e)})
def wait_for_lease_status(self, lease_id, status):
def check_lease_status():
try:
lease = self.reservation_client.get_lease(lease_id)['lease']
if lease and lease['status'] == status:
return True
else:
LOG.info("Lease with id %s is not %s, but %s",
lease_id, status, lease['status'])
except Exception as e:
LOG.info("Unable to find lease with id %(lease_id)s. "
"Exception: %(message)s",
{'lease_id': lease_id, 'message': str(e)})
return False
if not test_utils.call_until_true(
check_lease_status,
CONF.resource_reservation.lease_end_timeout,
CONF.resource_reservation.lease_interval):
message = ("Timed out waiting for lease to change status "
"to %s" % status)
raise exceptions.TimeoutException(message)
def is_flavor_enough(self, flavor_id, image_id):
image = self.compute_images_client.show_image(image_id)['image']
flavor = self.flavors_client.show_flavor(flavor_id)['flavor']
return image['minDisk'] <= flavor['disk']
def fetch_one_compute_host(self):
"""Returns the first host listed in nova-compute services."""
compute = next(iter(self.os_admin.services_client.
list_services(binary='nova-compute')['services']))
return compute
def _add_host_once(self):
host = self.fetch_one_compute_host()
hosts = self.reservation_client.list_host()['hosts']
try:
# TODO(masahito): Fix the check not to depend on '0' fixed check.
# When the scenario test covers the monitor resource feature, there
# are multiple compute hosts.
[h for h in hosts if h['hypervisor_hostname'] == host['host']][0]
except IndexError:
self.reservation_client.create_host({'name': host['host']})
return host

View File

@ -43,12 +43,6 @@ class TestHostReservationScenario(rrs.ResourceReservationScenarioTest):
def tearDown(self):
super(TestHostReservationScenario, self).tearDown()
def fetch_one_compute_host(self):
"""Returns a first host listed in nova-compute services."""
compute = next(iter(self.os_admin.services_client.
list_services(binary='nova-compute')['services']))
return compute
def get_lease_body(self, lease_name, host_name):
current_time = datetime.datetime.utcnow()
end_time = current_time + datetime.timedelta(hours=1)
@ -158,15 +152,6 @@ class TestHostReservationScenario(rrs.ResourceReservationScenarioTest):
% (host_name, aggregate_name))
raise exceptions.NotFound(err_msg)
def _add_host_once(self):
host = self.fetch_one_compute_host()
hosts = self.reservation_client.list_host()['hosts']
try:
[h for h in hosts if h['hypervisor_hostname'] == host['host']][0]
except IndexError:
self.reservation_client.create_host({'name': host['host']})
return host
@decorators.attr(type='smoke')
def test_host_reservation(self):

View File

@ -15,13 +15,9 @@
import datetime
import dateutil.parser
from oslo_log import log as logging
from oslo_serialization import jsonutils as json
from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest import exceptions
from tempest.lib import decorators
from blazar_tempest_plugin.tests.scenario import (
@ -33,25 +29,10 @@ LOG = logging.getLogger(__name__)
# same as the one at blazar/manager/service
LEASE_DATE_FORMAT = "%Y-%m-%d %H:%M"
LEASE_MIN_DURATION = 2
# TODO(cmart): LEASE_IMAGE_PREFIX should be extracted from CONF
LEASE_IMAGE_PREFIX = 'reserved_'
class TestInstanceReservationScenario(rrs.ResourceReservationScenarioTest):
"""Test that checks the instance reservation scenario.
The following is the scenario outline:
1) Create an instance with the hint parameters
2) check vm was shelved
3) check vm became active
4) check that a new lease is created on blazar
5) check its param
6) wait lease end
7) make sure VM was snapshoted and removed
"""
"""A scenario test class that checks the instance reservation feature."""
def setUp(self):
super(TestInstanceReservationScenario, self).setUp()
@ -67,115 +48,82 @@ class TestInstanceReservationScenario(rrs.ResourceReservationScenarioTest):
image=self.image_ref, flavor=self.flavor_ref
)
)
self.host = self._add_host_once()
def tearDown(self):
super(TestInstanceReservationScenario, self).tearDown()
def add_keypair(self):
self.keypair = self.create_keypair()
def get_lease_body(self, lease_name):
current_time = datetime.datetime.utcnow()
end_time = current_time + datetime.timedelta(hours=1)
body = {
"start_date": "now",
"end_date": end_time.strftime(LEASE_DATE_FORMAT),
"name": lease_name,
"events": [],
}
body["reservations"] = [
{
"resource_type": 'virtual:instance',
'vcpus': 1,
'memory_mb': 1024,
'disk_gb': 10,
'amount': 1,
'affinity': False,
'resource_properties': '',
}
]
return body
def boot_server_with_lease_data(self, lease_data, wait):
self.add_keypair()
@decorators.attr(type='smoke')
def test_instance_reservation(self):
body = self.get_lease_body('instance-scenario')
lease = self.reservation_client.create_lease(body)['lease']
reservation = next(iter(lease['reservations']))
# Create server with lease_data
self.wait_for_lease_status(lease['id'], 'ACTIVE')
# create an instance within the reservation
create_kwargs = {
'key_name': self.keypair['name'],
'scheduler_hints': lease_data
}
'image_id': CONF.compute.image_ref,
'flavor': reservation['id'],
'scheduler_hints': {
'group': reservation['server_group_id']
},
}
server1 = self.create_server(clients=self.os_admin,
**create_kwargs)
server = self.create_server(image_id=self.image_ref,
flavor=self.flavor_ref,
wait_until=wait,
**create_kwargs)
self.server_id = server['id']
self.server_name = server['name']
# create another instance within the reservation, which is expected to
# fail because we are over the reserved capacity
create_kwargs = {
'image_id': CONF.compute.image_ref,
'flavor': reservation['id'],
'scheduler_hints': {
'group': reservation['server_group_id']
},
}
server2 = self.create_server(clients=self.os_admin,
wait_until=None,
**create_kwargs)
waiters.wait_for_server_status(self.os_admin.servers_client,
server2['id'], 'ERROR',
raise_on_error=False)
def check_lease_creation(self, expected_lease_data):
server = self.servers_client.show_server(self.server_id)['server']
expected_lease_params = json.loads(expected_lease_data['lease_params'])
# create an instance without specifying a reservation, which is
# expected to fail
create_kwargs = {
'image_id': CONF.compute.image_ref,
'flavor': CONF.compute.flavor_ref,
}
server3 = self.create_server(clients=self.os_admin,
wait_until=None,
**create_kwargs)
waiters.wait_for_server_status(self.os_admin.servers_client,
server3['id'], 'ERROR',
raise_on_error=False)
# compare lease_data with data passed as parameter
lease = self.get_lease_by_name(expected_lease_params['name'])
# check lease dates!! (Beware of date format)
lease_start_date = dateutil.parser.parse(lease['start_date'])
lease_start_date = lease_start_date.strftime(LEASE_DATE_FORMAT)
lease_end_date = dateutil.parser.parse(lease['end_date'])
lease_end_date = lease_end_date.strftime(LEASE_DATE_FORMAT)
self.assertEqual(expected_lease_params['start'], lease_start_date)
self.assertEqual(expected_lease_params['end'], lease_end_date)
# check lease events!
events = lease['events']
self.assertTrue(len(events) >= 3)
self.assertFalse(
len([evt for evt in events if evt['event_type'] != 'start_lease'
and evt['event_type'] != 'end_lease'
and evt['event_type'] != 'before_end_lease']) > 0)
# check that only one reservation was made and it is for a vm
# compare the resource id from the lease with the server.id attribute!
reservations = lease['reservations']
self.assertTrue(len(reservations) == 1)
self.assertEqual(server['id'], reservations[0]['resource_id'])
self.assertEqual("virtual:instance",
lease['reservations'][0]['resource_type'])
def check_server_is_snapshoted(self):
image_name = LEASE_IMAGE_PREFIX + self.server_name
try:
images_list = self.image_client.list()
self.assertNotEmpty(
[image for image in images_list if image.name == image_name])
except Exception as e:
message = ("Unable to find image with name '%s'. "
"Exception: %s" % (image_name, str(e)))
raise exceptions.NotFound(message)
def check_server_status(self, expected_status):
server = self.servers_client.show_server(self.server_id)['server']
self.assertEqual(expected_status, server['status'])
# TODO(cmart): add blazar to services after pushing this code into tempest
@decorators.skip_because('Instance reservation is not supported yet.',
bug='1659200')
@decorators.attr(type='slow')
@utils.services('compute', 'network')
def test_server_basic_resource_reservation_operation(self):
start_date = datetime.datetime.utcnow() + datetime.timedelta(minutes=1)
end_date = start_date + datetime.timedelta(minutes=LEASE_MIN_DURATION)
start_date = start_date.strftime(LEASE_DATE_FORMAT)
end_date = end_date.strftime(LEASE_DATE_FORMAT)
lease_name = 'scenario_test'
lease_data = {
'lease_params': '{"name": "%s",'
'"start": "%s",'
'"end": "%s"}'
% (lease_name, start_date, end_date)}
# boot the server and don't wait until it is active
self.boot_server_with_lease_data(lease_data, wait=False)
self.check_server_status('SHELVED_OFFLOADED')
# now, wait until the server is active
waiters.wait_for_server_status(self.servers_client,
self.server_id, 'ACTIVE')
self.check_lease_creation(lease_data)
# wait for lease end
created_lease = self.get_lease_by_name(lease_name)
self.wait_for_lease_end(created_lease['id'])
# check server final status
self.check_server_is_snapshoted()
waiters.wait_for_server_termination(self.servers_client,
self.server_id)
# remove created snapshot
image_name = LEASE_IMAGE_PREFIX + self.server_name
self.remove_image_snapshot(image_name)
# remove created lease
self.delete_lease(created_lease['id'])
# delete the lease, which should trigger termination of the instance
self.reservation_client.delete_lease(lease['id'])
waiters.wait_for_server_termination(self.os_admin.servers_client,
server1['id'])