
This plugin no longer supports python 2 thus usage of six is no longer needed. Change-Id: Id087aeab1c3e5baf540f99ed843e4c3cfc763006
323 lines
12 KiB
Python
323 lines
12 KiB
Python
# Copyright 2017 NTT 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.
|
|
|
|
import datetime
|
|
import time
|
|
|
|
from oslo_log import log as logging
|
|
from tempest.common import waiters
|
|
from tempest import config
|
|
from tempest.lib import decorators
|
|
from tempest.lib import exceptions
|
|
|
|
from blazar_tempest_plugin.tests.scenario import (
|
|
resource_reservation_scenario as rrs)
|
|
|
|
CONF = config.CONF
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class TestHostReservationScenario(rrs.ResourceReservationScenarioTest):
|
|
"""A Scenario test class that checks host reservation."""
|
|
|
|
MAX_RETRY = 20
|
|
WAIT_TIME = 2
|
|
|
|
def setUp(self):
|
|
super(TestHostReservationScenario, self).setUp()
|
|
self.aggr_client = self.os_admin.aggregates_client
|
|
|
|
def tearDown(self):
|
|
super(TestHostReservationScenario, self).tearDown()
|
|
|
|
def get_lease_body(self, lease_name, host_name):
|
|
current_time = datetime.datetime.utcnow()
|
|
end_time = current_time + datetime.timedelta(hours=1)
|
|
body = {
|
|
"start_date": "now",
|
|
"end_date": end_time.strftime('%Y-%m-%d %H:%M'),
|
|
"name": lease_name,
|
|
"events": [],
|
|
}
|
|
body["reservations"] = [
|
|
{
|
|
"hypervisor_properties": ('["==", "$hypervisor_hostname", "'
|
|
'%s"]' % host_name),
|
|
"max": 1,
|
|
"min": 1,
|
|
"resource_type": 'physical:host',
|
|
"resource_properties": ''
|
|
}
|
|
]
|
|
|
|
return body
|
|
|
|
def get_lease_body_missing_param(self, lease_name, host_name):
|
|
current_time = datetime.datetime.utcnow()
|
|
end_time = current_time + datetime.timedelta(hours=1)
|
|
body = {
|
|
"start_date": "now",
|
|
"end_date": end_time.strftime('%Y-%m-%d %H:%M'),
|
|
"name": lease_name,
|
|
"events": [],
|
|
}
|
|
body["reservations"] = [
|
|
{
|
|
"hypervisor_properties": ('["==", "$hypervisor_hostname", "'
|
|
'%s"]' % host_name),
|
|
"min": '1',
|
|
"resource_type": 'physical:host',
|
|
"resource_properties": ''
|
|
}
|
|
]
|
|
|
|
return body
|
|
|
|
def get_invalid_lease_body(self, lease_name, host_name):
|
|
current_time = datetime.datetime.utcnow()
|
|
end_time = current_time + datetime.timedelta(hours=1)
|
|
body = {
|
|
"start_date": "now",
|
|
"end_date": end_time.strftime('%Y-%m-%d %H:%M'),
|
|
"name": lease_name,
|
|
"events": [],
|
|
}
|
|
body["reservations"] = [
|
|
{
|
|
"hypervisor_properties": ('["==", "$hypervisor_hostname", "'
|
|
'%s"]' % host_name),
|
|
"max": 'foo',
|
|
"min": 'bar',
|
|
"resource_type": 'physical:host',
|
|
"resource_properties": ''
|
|
}
|
|
]
|
|
|
|
return body
|
|
|
|
def get_expiration_lease_body(self, lease_name, host_name):
|
|
current_time = datetime.datetime.utcnow()
|
|
end_time = current_time + datetime.timedelta(seconds=90)
|
|
body = {
|
|
'start_date': "now",
|
|
'end_date': end_time.strftime('%Y-%m-%d %H:%M'),
|
|
'name': lease_name,
|
|
'events': [],
|
|
}
|
|
body['reservations'] = [
|
|
{
|
|
'hypervisor_properties': ('["==", "$hypervisor_hostname", "'
|
|
'%s"]' % host_name),
|
|
'max': 1,
|
|
'min': 1,
|
|
'resource_type': 'physical:host',
|
|
'resource_properties': ''
|
|
}
|
|
]
|
|
|
|
return body
|
|
|
|
def fetch_aggregate_by_name(self, name):
|
|
aggregates = self.aggr_client.list_aggregates()['aggregates']
|
|
try:
|
|
aggr = [aggr for aggr in aggregates if aggr['name'] == name][0]
|
|
except IndexError:
|
|
err_msg = "aggregate with name %s doesn't exist." % name
|
|
raise exceptions.NotFound(err_msg)
|
|
return aggr
|
|
|
|
def wait_until_aggregated(self, aggregate_name, host_name):
|
|
for i in range(self.MAX_RETRY):
|
|
try:
|
|
aggr = self.fetch_aggregate_by_name(aggregate_name)
|
|
self.assertTrue(host_name in aggr['hosts'])
|
|
return
|
|
except Exception:
|
|
pass
|
|
time.sleep(self.WAIT_TIME)
|
|
err_msg = ("hostname %s doesn't exist in aggregate %s."
|
|
% (host_name, aggregate_name))
|
|
raise exceptions.NotFound(err_msg)
|
|
|
|
@decorators.attr(type='smoke')
|
|
def test_host_reservation(self):
|
|
|
|
# Create the host if it doesn't exists
|
|
host = self._add_host_once()
|
|
|
|
# check the host is in freepool
|
|
freepool = self.fetch_aggregate_by_name('freepool')
|
|
self.assertTrue(host['host'] in freepool['hosts'])
|
|
|
|
# try creating a new lease with a missing parameter
|
|
body = self.get_lease_body_missing_param('scenario-1-missing-param',
|
|
host['host'])
|
|
self.assertRaises(exceptions.BadRequest,
|
|
self.reservation_client.create_lease, body)
|
|
|
|
# try creating a new lease with an invalid request
|
|
body = self.get_invalid_lease_body('scenario-1-invalid', host['host'])
|
|
self.assertRaises(exceptions.BadRequest,
|
|
self.reservation_client.create_lease, body)
|
|
|
|
# create new lease and start reservation immediately
|
|
body = self.get_lease_body('scenario-1', host['host'])
|
|
lease = self.reservation_client.create_lease(body)['lease']
|
|
|
|
# check host added to the reservation
|
|
reservation_id = next(iter(lease['reservations']))['id']
|
|
self.wait_until_aggregated(reservation_id, host['host'])
|
|
|
|
# create an instance with reservation id
|
|
create_kwargs = {
|
|
'scheduler_hints': {
|
|
"reservation": reservation_id,
|
|
},
|
|
'image_id': CONF.compute.image_ref,
|
|
'flavor': CONF.compute.flavor_ref,
|
|
}
|
|
server = self.create_server(clients=self.os_admin,
|
|
**create_kwargs)
|
|
# ensure server is located on the requested host
|
|
self.assertEqual(host['host'], server['OS-EXT-SRV-ATTR:host'])
|
|
|
|
# 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,
|
|
server['id'])
|
|
|
|
# create an instance without reservation id, which is expected to fail
|
|
create_kwargs = {
|
|
'image_id': CONF.compute.image_ref,
|
|
'flavor': CONF.compute.flavor_ref,
|
|
}
|
|
server = self.create_server(clients=self.os_admin,
|
|
wait_until=None,
|
|
**create_kwargs)
|
|
waiters.wait_for_server_status(self.os_admin.servers_client,
|
|
server['id'], 'ERROR',
|
|
raise_on_error=False)
|
|
|
|
@decorators.attr(type='smoke')
|
|
def test_lease_expiration(self):
|
|
|
|
# create the host if it doesn't exist
|
|
host = self._add_host_once()
|
|
|
|
# create new lease and start reservation immediately
|
|
body = self.get_expiration_lease_body('scenario-2-expiration',
|
|
host['host'])
|
|
lease = self.reservation_client.create_lease(body)['lease']
|
|
lease_id = lease['id']
|
|
|
|
# check host added to the reservation
|
|
reservation_id = next(iter(lease['reservations']))['id']
|
|
self.wait_until_aggregated(reservation_id, host['host'])
|
|
|
|
create_kwargs = {
|
|
'scheduler_hints': {
|
|
'reservation': reservation_id,
|
|
},
|
|
'image_id': CONF.compute.image_ref,
|
|
'flavor': CONF.compute.flavor_ref,
|
|
}
|
|
server = self.create_server(clients=self.os_admin,
|
|
**create_kwargs)
|
|
|
|
# wait for lease end
|
|
self.wait_for_lease_end(lease_id)
|
|
|
|
# check if the lease has been correctly terminated and
|
|
# the instance is removed
|
|
waiters.wait_for_server_termination(self.os_admin.servers_client,
|
|
server['id'])
|
|
|
|
# check that the host aggregate was deleted
|
|
self.assertRaises(exceptions.NotFound,
|
|
self.fetch_aggregate_by_name, reservation_id)
|
|
|
|
# check that the host is back in the freepool
|
|
freepool = self.fetch_aggregate_by_name('freepool')
|
|
self.assertTrue(host['host'] in freepool['hosts'])
|
|
|
|
# check the reservation status
|
|
lease = self.reservation_client.get_lease(lease_id)['lease']
|
|
self.assertTrue('deleted' in
|
|
next(iter(lease['reservations']))['status'])
|
|
|
|
@decorators.attr(type='smoke')
|
|
def test_update_host_reservation(self):
|
|
|
|
# create the host if it doesn't exist
|
|
host = self._add_host_once()
|
|
|
|
# create new lease and start reservation immediately
|
|
body = self.get_lease_body('scenario-3-update', host['host'])
|
|
lease = self.reservation_client.create_lease(body)['lease']
|
|
lease_id = lease['id']
|
|
|
|
# check host added to the reservation
|
|
reservation_id = next(iter(lease['reservations']))['id']
|
|
self.wait_until_aggregated(reservation_id, host['host'])
|
|
|
|
# check the host aggregate for blazar
|
|
self.fetch_aggregate_by_name(reservation_id)
|
|
|
|
# create an instance with reservation id
|
|
create_kwargs = {
|
|
'scheduler_hints': {
|
|
'reservation': reservation_id,
|
|
},
|
|
'image_id': CONF.compute.image_ref,
|
|
'flavor': CONF.compute.flavor_ref,
|
|
}
|
|
server = self.create_server(clients=self.os_admin,
|
|
wait_until=None,
|
|
**create_kwargs)
|
|
waiters.wait_for_server_status(self.os_admin.servers_client,
|
|
server['id'], 'ACTIVE')
|
|
|
|
# wait enough time for the update API to succeed
|
|
time.sleep(75)
|
|
|
|
# update the lease end_time
|
|
end_time = datetime.datetime.utcnow() + datetime.timedelta(seconds=30)
|
|
body = {
|
|
'end_date': end_time.strftime('%Y-%m-%d %H:%M')
|
|
}
|
|
self.reservation_client.update_lease(lease_id,
|
|
body)['lease']
|
|
|
|
# check if the lease has been correctly terminated and
|
|
# the instance is removed
|
|
waiters.wait_for_server_termination(self.os_admin.servers_client,
|
|
server['id'])
|
|
|
|
# wait long enough for the lease deletion to be complete
|
|
time.sleep(30)
|
|
|
|
# check that the host aggregate was deleted
|
|
self.assertRaises(exceptions.NotFound,
|
|
self.fetch_aggregate_by_name, reservation_id)
|
|
|
|
# check that the host is back in the freepool
|
|
freepool = self.fetch_aggregate_by_name('freepool')
|
|
self.assertTrue(host['host'] in freepool['hosts'])
|
|
|
|
# check the reservation status
|
|
lease = self.reservation_client.get_lease(lease_id)['lease']
|
|
self.assertTrue('deleted' in
|
|
next(iter(lease['reservations']))['status'])
|