From cb187056f8348d93c0385c96eb638255f8ce8ba1 Mon Sep 17 00:00:00 2001 From: Hiroaki Kobayashi Date: Wed, 26 Jul 2017 12:05:36 +0900 Subject: [PATCH] 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 --- ...766b64e_add_before_end_into_computehost.py | 43 ++++++++++++ blazar/db/sqlalchemy/models.py | 2 + blazar/plugins/oshosts/host_plugin.py | 15 +++- .../plugins/test_physical_host_plugin.py | 69 ++++++++++++++++--- doc/source/restapi/rest_api_v1.0.rst | 15 ++-- .../before-end-actions-7e53e740e006195a.yaml | 14 ++-- 6 files changed, 138 insertions(+), 20 deletions(-) create mode 100644 blazar/db/migration/alembic_migrations/versions/ba75b766b64e_add_before_end_into_computehost.py diff --git a/blazar/db/migration/alembic_migrations/versions/ba75b766b64e_add_before_end_into_computehost.py b/blazar/db/migration/alembic_migrations/versions/ba75b766b64e_add_before_end_into_computehost.py new file mode 100644 index 00000000..b7fb6397 --- /dev/null +++ b/blazar/db/migration/alembic_migrations/versions/ba75b766b64e_add_before_end_into_computehost.py @@ -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 ### diff --git a/blazar/db/sqlalchemy/models.py b/blazar/db/sqlalchemy/models.py index 99b47d0a..97dc0e58 100644 --- a/blazar/db/sqlalchemy/models.py +++ b/blazar/db/sqlalchemy/models.py @@ -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() diff --git a/blazar/plugins/oshosts/host_plugin.py b/blazar/plugins/oshosts/host_plugin.py index a001fea4..93398929 100644 --- a/blazar/plugins/oshosts/host_plugin.py +++ b/blazar/plugins/oshosts/host_plugin.py @@ -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') diff --git a/blazar/tests/plugins/test_physical_host_plugin.py b/blazar/tests/plugins/test_physical_host_plugin.py index e1fda608..d4995b9c 100644 --- a/blazar/tests/plugins/test_physical_host_plugin.py +++ b/blazar/tests/plugins/test_physical_host_plugin.py @@ -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') diff --git a/doc/source/restapi/rest_api_v1.0.rst b/doc/source/restapi/rest_api_v1.0.rst index 857a3804..eaa7b5be 100644 --- a/doc/source/restapi/rest_api_v1.0.rst +++ b/doc/source/restapi/rest_api_v1.0.rst @@ -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", diff --git a/releasenotes/notes/before-end-actions-7e53e740e006195a.yaml b/releasenotes/notes/before-end-actions-7e53e740e006195a.yaml index 625caf15..a793dcc1 100644 --- a/releasenotes/notes/before-end-actions-7e53e740e006195a.yaml +++ b/releasenotes/notes/before-end-actions-7e53e740e006195a.yaml @@ -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