Support before_end parameter in the REST API

Currently, the action taken before the end of a lease is specified by a
configuration option. This patch enables users to specify the action
through the 'before_end' parameter of the lease creation request.

Change-Id: I90fb90d9d53814791d863f4ce5dab28388d3688d
Partially Implements: blueprint on-end-options
This commit is contained in:
Hiroaki Kobayashi 2017-07-26 12:05:36 +09:00 committed by Pierre Riteau
parent ec854ee613
commit cb187056f8
6 changed files with 138 additions and 20 deletions

View File

@ -0,0 +1,43 @@
# Copyright 2017 OpenStack Foundation.
#
# 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.
"""Add before_end into computehost_reservations table
Revision ID: ba75b766b64e
Revises: 8805be233864
Create Date: 2017-07-26 03:03:19.909249
"""
# revision identifiers, used by Alembic.
revision = 'ba75b766b64e'
down_revision = '8805be233864'
from alembic import op
import sqlalchemy as sa
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('computehost_reservations',
sa.Column('before_end', sa.String(length=36),
nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('computehost_reservations', 'before_end')
# ### end Alembic commands ###

View File

@ -111,6 +111,7 @@ class Reservation(mb.BlazarBase):
res = self.computehost_reservations.to_dict()
d['hypervisor_properties'] = res['hypervisor_properties']
d['resource_properties'] = res['resource_properties']
d['before_end'] = res['before_end']
if res['count_range']:
try:
@ -162,6 +163,7 @@ class ComputeHostReservation(mb.BlazarBase):
count_range = sa.Column(sa.String(36))
hypervisor_properties = sa.Column(MediumText())
status = sa.Column(sa.String(13))
before_end = sa.Column(sa.String(36))
def to_dict(self):
return super(ComputeHostReservation, self).to_dict()

View File

@ -54,6 +54,9 @@ CONF = cfg.CONF
CONF.register_opts(plugin_opts, group=plugin.RESOURCE_TYPE)
before_end_options = ['', 'snapshot', 'default']
class PhysicalHostPlugin(base.BasePlugin, nova.NovaClientWrapper):
"""Plugin for physical host resource."""
resource_type = plugin.RESOURCE_TYPE
@ -95,6 +98,7 @@ class PhysicalHostPlugin(base.BasePlugin, nova.NovaClientWrapper):
'hypervisor_properties': values['hypervisor_properties'],
'count_range': values['count_range'],
'status': 'pending',
'before_end': values['before_end']
}
host_reservation = db_api.host_reservation_create(host_rsrv_values)
for host_id in host_ids:
@ -176,9 +180,11 @@ class PhysicalHostPlugin(base.BasePlugin, nova.NovaClientWrapper):
def before_end(self, resource_id):
"""Take an action before the end of a lease."""
action = CONF[plugin.RESOURCE_TYPE].before_end
host_reservation = db_api.host_reservation_get(resource_id)
action = host_reservation['before_end']
if action == 'default':
action = CONF[plugin.RESOURCE_TYPE].before_end
if action == 'snapshot':
host_reservation = db_api.host_reservation_get(resource_id)
pool = nova.ReservationPool()
client = nova.BlazarNovaClient()
for host in pool.get_computehosts(
@ -412,3 +418,8 @@ class PhysicalHostPlugin(base.BasePlugin, nova.NovaClientWrapper):
raise manager_ex.MissingParameter(param='hypervisor_properties')
if 'resource_properties' not in values:
raise manager_ex.MissingParameter(param='resource_properties')
if 'before_end' not in values:
values['before_end'] = 'default'
if values['before_end'] not in before_end_options:
raise manager_ex.MalformedParameter(param='before_end')

View File

@ -347,7 +347,8 @@ class PhysicalHostPluginTestCase(tests.TestCase):
'resource_properties': '',
'hypervisor_properties': '["=", "$memory_mb", "256"]',
'count_range': '1-1',
'status': 'pending'
'status': 'pending',
'before_end': 'default'
}
host_reservation_create.assert_called_once_with(host_values)
calls = [
@ -409,7 +410,7 @@ class PhysicalHostPluginTestCase(tests.TestCase):
u'441c1476-9f8f-4700-9f30-cd9b6fef3509',
values)
def test_create_reservation_with_invalid_param(self):
def test_create_reservation_with_invalid_param_max(self):
values = {
'lease_id': u'018c1b43-e69e-4aef-a543-09681539cf4c',
'min': u'2',
@ -426,6 +427,24 @@ class PhysicalHostPluginTestCase(tests.TestCase):
u'441c1476-9f8f-4700-9f30-cd9b6fef3509',
values)
def test_create_reservation_with_invalid_param_before_end(self):
values = {
'lease_id': u'018c1b43-e69e-4aef-a543-09681539cf4c',
'min': u'1',
'max': u'2',
'hypervisor_properties': '["=", "$memory_mb", "256"]',
'resource_properties': '',
'before_end': 'invalid',
'start_date': datetime.datetime(2017, 3, 1, 20, 00),
'end_date': datetime.datetime(2017, 3, 2, 20, 00),
'resource_type': plugin.RESOURCE_TYPE,
}
self.assertRaises(
manager_exceptions.MalformedParameter,
self.fake_phys_plugin.reserve_resource,
u'441c1476-9f8f-4700-9f30-cd9b6fef3509',
values)
def test_create_reservation_with_invalid_range(self):
values = {
'lease_id': u'018c1b43-e69e-4aef-a543-09681539cf4c',
@ -695,19 +714,18 @@ class PhysicalHostPluginTestCase(tests.TestCase):
1, 'host1_hostname')
def test_before_end_with_no_action(self):
self.cfg.CONF.set_override('before_end', '',
group='physical:host')
host_reservation_get = self.patch(self.db_api, 'host_reservation_get')
host_reservation_get.return_value = {'before_end': ''}
reservationpool = self.patch(self.nova, 'ReservationPool')
self.fake_phys_plugin.before_end(
u'04de74e8-193a-49d2-9ab8-cba7b49e45e8')
host_reservation_get.assert_not_called()
reservationpool.assert_not_called()
def test_before_end_with_snapshot(self):
self.cfg.CONF.set_override('before_end', 'snapshot',
group='physical:host')
host_reservation_get = self.patch(self.db_api, 'host_reservation_get')
host_reservation_get.return_value = {
'aggregate_id': 1
'aggregate_id': 1,
'before_end': 'snapshot'
}
get_computehosts = self.patch(self.nova.ReservationPool,
'get_computehosts')
@ -863,3 +881,38 @@ class PhysicalHostPluginTestCase(tests.TestCase):
datetime.datetime(2013, 12, 19, 20, 00),
datetime.datetime(2013, 12, 19, 21, 00))
self.assertEqual([], result)
def test_check_params_with_valid_before_end(self):
values = {
'min': 1,
'max': 2,
'resource_properties': '',
'hypervisor_properties': '',
'before_end': 'snapshot'
}
self.fake_phys_plugin._check_params(values)
self.assertEqual(values['before_end'], 'snapshot')
def test_check_params_with_invalid_before_end(self):
values = {
'min': 1,
'max': 2,
'resource_properties': '',
'hypervisor_properties': '',
'before_end': 'invalid'
}
self.assertRaises(manager_exceptions.MalformedParameter,
self.fake_phys_plugin._check_params,
values)
def test_check_params_without_before_end(self):
self.cfg.CONF.set_override('before_end', '',
group='physical:host')
values = {
'min': 1,
'max': 2,
'resource_properties': '',
'hypervisor_properties': ''
}
self.fake_phys_plugin._check_params(values)
self.assertEqual(values['before_end'], 'default')

View File

@ -95,7 +95,8 @@ are mentioned.
"hypervisor_properties": "[\"==\", \"$hypervisor_hostname\", \"compute\"]",
"resource_properties": "",
"id": "087bc740-6d2d-410b-9d47-c7b2b55a9d36",
"resource_type": "physical:host"
"resource_type": "physical:host",
"before_end": "default"
}
],
"created_at": "2017-02-21 14:50:38",
@ -168,7 +169,8 @@ are mentioned.
"max": 1,
"min": 1,
"resource_type": "physical:host",
"resource_properties": ""
"resource_properties": "",
"before_end": "default"
}
],
"events": []
@ -202,7 +204,8 @@ are mentioned.
"created_at": "2017-02-21 14:50:38",
"updated_at": null,
"id": "087bc740-6d2d-410b-9d47-c7b2b55a9d36",
"resource_type": "physical:host"
"resource_type": "physical:host",
"before_end": "default"
}
],
"created_at": "2017-02-21 14:50:38",
@ -290,7 +293,8 @@ are mentioned.
"hypervisor_properties": "[\"==\", \"$hypervisor_hostname\", \"compute\"]",
"resource_properties": "",
"id": "087bc740-6d2d-410b-9d47-c7b2b55a9d36",
"resource_type": "physical:host"
"resource_type": "physical:host",
"before_end": "default"
}
],
"created_at": "2017-02-21 14:50:38",
@ -384,7 +388,8 @@ are mentioned.
"hypervisor_properties": "[\"==\", \"$hypervisor_hostname\", \"compute\"]",
"resource_properties": "",
"id": "087bc740-6d2d-410b-9d47-c7b2b55a9d36",
"resource_type": "physical:host"
"resource_type": "physical:host",
"before_end": "default"
}
],
"created_at": "2017-02-21 14:50:38",

View File

@ -1,13 +1,17 @@
---
features:
- Blazar gets to support before_end actions. Actions like notification and
snapshot can be taken at a specific time prior to the end of a lease.
- Blazar gets to support before_end actions. Actions like snapshot can be
taken at a specific time prior to the end of a lease.
The time which triggers actions can be specified by the API parameter
*before_end_date* and the default interval can be configured by a new
configuration option *minutes_before_end_lease* in the [manager] section.
An action *snapshot* is currently supported by the physical host plugin.
The action can be configured by the new configuration option *before_end*
in the [physical:host] section.
The system default action for physical host plugin can be configured by a
new configuration option *before_end* in the [physical:host] section.
It can be also specified by a new API parameter *before_end* in a
reservation. The value of this parameter can be *snapshot*, *default*, or
blank. A system default action will be taken if *default* is specified or
no *before_end* parameter included. If blank ("") is explicitly specified,
no action will be taken.
upgrade:
- The API parameter *before_end_notification* has been renamed
*before_end_date* which is used for setting the time for triggering actions