Remove the old instance reservation plugin
The old instance reservation feature is not supported from the Ocata release of Blazar, since it relies on the v2 API of Nova with has been removed. Additionally, the Blazar project has started to implement a new instance reservation feature which doesn't rely on deprecated Nova APIs. This patch removes the old instance reservation plugin. If a deployer specifies 'basic.vm.plugin' in the plugins config parameter, the blazar-manager service will fail to start. Partially implements: blueprint new-instance-reservation Change-Id: If5b0efb4910b05cc3c2881bb705953528895f277
This commit is contained in:
parent
ad40cd1e28
commit
31f88379b8
@ -78,7 +78,7 @@ class Lease(base._Base):
|
||||
project_id=u'bd9431c18d694ad3803a8d4a6b89fd36',
|
||||
trust_id=u'35b17138b3644e6aa1318f3099c5be68',
|
||||
reservations=[{u'resource_id': u'1234',
|
||||
u'resource_type': u'virtual:instance'}],
|
||||
u'resource_type': u'physical:host'}],
|
||||
events=[],
|
||||
before_end_notification=u'2014-02-01 10:37',
|
||||
action=u'START',
|
||||
|
@ -78,6 +78,13 @@ class ManagerService(service_utils.RPCServer):
|
||||
invoke_on_load=False
|
||||
)
|
||||
|
||||
invalid_plugins = (set(config_plugins) -
|
||||
set([ext.name for ext
|
||||
in extension_manager.extensions]))
|
||||
if invalid_plugins:
|
||||
raise common_ex.BlazarException('Invalid plugin names are '
|
||||
'specified: %s' % invalid_plugins)
|
||||
|
||||
for ext in extension_manager.extensions:
|
||||
try:
|
||||
plugin_obj = ext.plugin()
|
||||
|
@ -22,7 +22,6 @@ import blazar.db.migration.cli
|
||||
import blazar.manager
|
||||
import blazar.manager.service
|
||||
import blazar.notification.notifier
|
||||
import blazar.plugins.instances.vm_plugin
|
||||
import blazar.plugins.oshosts.host_plugin
|
||||
import blazar.utils.openstack.keystone
|
||||
import blazar.utils.openstack.nova
|
||||
@ -46,8 +45,6 @@ def list_opts():
|
||||
blazar.manager.service.manager_opts)),
|
||||
('notifications', blazar.notification.notifier.notification_opts),
|
||||
('nova', blazar.utils.openstack.nova.nova_opts),
|
||||
(blazar.plugins.instances.RESOURCE_TYPE,
|
||||
blazar.plugins.instances.vm_plugin.plugin_opts),
|
||||
(blazar.plugins.oshosts.RESOURCE_TYPE,
|
||||
blazar.plugins.oshosts.host_plugin.plugin_opts),
|
||||
]
|
||||
|
@ -1 +0,0 @@
|
||||
RESOURCE_TYPE = u'virtual:instance'
|
@ -1,117 +0,0 @@
|
||||
# Copyright (c) 2013 Mirantis 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.
|
||||
|
||||
import eventlet
|
||||
from novaclient import exceptions as nova_exceptions
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from blazar import exceptions as blazar_exceptions
|
||||
from blazar.plugins import base
|
||||
from blazar.plugins import instances as plugin
|
||||
from blazar.utils.openstack import nova
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
plugin_opts = [
|
||||
cfg.StrOpt('on_end',
|
||||
default='create_image, delete',
|
||||
help='Actions which we will use in the end of the lease'),
|
||||
cfg.StrOpt('on_start',
|
||||
default='on_start',
|
||||
help='Actions which we will use at the start of the lease'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(plugin_opts, group=plugin.RESOURCE_TYPE)
|
||||
|
||||
|
||||
class VMPlugin(base.BasePlugin, nova.NovaClientWrapper):
|
||||
"""Base plugin for VM reservation."""
|
||||
resource_type = plugin.RESOURCE_TYPE
|
||||
title = "Basic VM Plugin"
|
||||
description = ("This is basic plugin for VM management. "
|
||||
"It can start, snapshot and suspend VMs")
|
||||
|
||||
def reserve_resource(self, reservation_id, values):
|
||||
return None
|
||||
|
||||
def on_start(self, resource_id):
|
||||
try:
|
||||
self.nova.servers.unshelve(resource_id)
|
||||
except nova_exceptions.Conflict:
|
||||
LOG.error("Instance have been unshelved")
|
||||
|
||||
def on_end(self, resource_id):
|
||||
actions = self._split_actions(CONF[plugin.RESOURCE_TYPE].on_end)
|
||||
|
||||
# actions will be processed in following order:
|
||||
# - create image from VM
|
||||
# - suspend VM
|
||||
# - delete VM
|
||||
# this order guarantees there will be no situations like
|
||||
# creating snapshot or suspending already deleted instance
|
||||
|
||||
if 'create_image' in actions:
|
||||
with eventlet.timeout.Timeout(600, blazar_exceptions.Timeout):
|
||||
try:
|
||||
self.nova.servers.create_image(resource_id)
|
||||
eventlet.sleep(5)
|
||||
while not self._check_active(resource_id):
|
||||
eventlet.sleep(1)
|
||||
except nova_exceptions.NotFound:
|
||||
LOG.error('Instance %s has been already deleted. '
|
||||
'Cannot create image.' % resource_id)
|
||||
except blazar_exceptions.Timeout:
|
||||
LOG.error('Image create failed with timeout. Take a look '
|
||||
'at nova.')
|
||||
except nova_exceptions.Conflict as e:
|
||||
LOG.warning('Instance is in a invalid state for'
|
||||
'create_image. Take a look at nova.'
|
||||
'(Request-ID: %s)' % e.request_id)
|
||||
|
||||
if 'suspend' in actions:
|
||||
try:
|
||||
self.nova.servers.suspend(resource_id)
|
||||
except nova_exceptions.NotFound:
|
||||
LOG.error('Instance %s has been already deleted. '
|
||||
'Cannot suspend instance.' % resource_id)
|
||||
|
||||
if 'delete' in actions:
|
||||
try:
|
||||
self.nova.servers.delete(resource_id)
|
||||
except nova_exceptions.NotFound:
|
||||
LOG.error('Instance %s has been already deleted. '
|
||||
'Cannot delete instance.' % resource_id)
|
||||
|
||||
def _check_active(self, resource_id):
|
||||
instance = self.nova.servers.get(resource_id)
|
||||
task_state = getattr(instance, 'OS-EXT-STS:task_state', None)
|
||||
if task_state is None:
|
||||
return True
|
||||
|
||||
if task_state.upper() in ['IMAGE_SNAPSHOT', 'IMAGE_PENDING_UPLOAD',
|
||||
'IMAGE_UPLOADING']:
|
||||
return False
|
||||
else:
|
||||
LOG.error('Nova reported unexpected task status %s for '
|
||||
'instance %s' % (task_state, resource_id))
|
||||
raise blazar_exceptions.TaskFailed()
|
||||
|
||||
def _split_actions(self, actions):
|
||||
try:
|
||||
return actions.replace(' ', '').split(',')
|
||||
except AttributeError:
|
||||
raise blazar_exceptions.WrongFormat()
|
@ -20,7 +20,6 @@ import uuid
|
||||
from blazar.db import exceptions as db_exceptions
|
||||
from blazar.db.sqlalchemy import api as db_api
|
||||
from blazar.db.sqlalchemy import models
|
||||
from blazar.plugins import instances as vm_plugin
|
||||
from blazar.plugins import oshosts as host_plugin
|
||||
from blazar import tests
|
||||
|
||||
@ -47,13 +46,6 @@ def _get_fake_phys_reservation_values(id=_get_fake_random_uuid(),
|
||||
'trust_id': 'exxee111qwwwwe'}
|
||||
|
||||
|
||||
def _get_fake_virt_reservation_values(lease_id=_get_fake_lease_uuid(),
|
||||
resource_id=None):
|
||||
return {'lease_id': lease_id,
|
||||
'resource_id': '5678' if not resource_id else resource_id,
|
||||
'resource_type': vm_plugin.RESOURCE_TYPE}
|
||||
|
||||
|
||||
def _get_fake_event_values(id=_get_fake_random_uuid(),
|
||||
lease_id=_get_fake_lease_uuid(),
|
||||
event_type='fake_event_type',
|
||||
@ -70,25 +62,6 @@ def _get_datetime(value='2030-01-01 00:00'):
|
||||
return datetime.datetime.strptime(value, '%Y-%m-%d %H:%M')
|
||||
|
||||
|
||||
def _get_fake_virt_lease_values(id=_get_fake_lease_uuid(),
|
||||
name='fake_virt_lease',
|
||||
start_date=_get_datetime('2030-01-01 00:00'),
|
||||
end_date=_get_datetime('2030-01-02 00:00'),
|
||||
resource_id=None):
|
||||
return {'id': id,
|
||||
'name': name,
|
||||
'user_id': _get_fake_random_uuid(),
|
||||
'project_id': _get_fake_random_uuid(),
|
||||
'start_date': start_date,
|
||||
'end_date': end_date,
|
||||
'trust': 'trust',
|
||||
'reservations': [_get_fake_virt_reservation_values(
|
||||
lease_id=id,
|
||||
resource_id=resource_id)],
|
||||
'events': []
|
||||
}
|
||||
|
||||
|
||||
def _get_fake_phys_lease_values(id=_get_fake_lease_uuid(),
|
||||
name='fake_phys_lease',
|
||||
start_date=_get_datetime('2030-01-01 00:00'),
|
||||
@ -121,12 +94,6 @@ def _get_fake_host_allocation_values(
|
||||
return values
|
||||
|
||||
|
||||
def _create_virtual_lease(values=_get_fake_virt_lease_values(),
|
||||
random=False):
|
||||
"""Creating fake lease having a single virtual resource."""
|
||||
return db_api.lease_create(values)
|
||||
|
||||
|
||||
def _create_physical_lease(values=_get_fake_phys_lease_values(),
|
||||
random=False):
|
||||
"""Creating fake lease having a single physical resource."""
|
||||
@ -208,23 +175,10 @@ class SQLAlchemyDBApiTestCase(tests.DBTestCase):
|
||||
super(SQLAlchemyDBApiTestCase, self).setUp()
|
||||
|
||||
def test_model_query(self):
|
||||
lease = db_api.lease_create(_get_fake_virt_lease_values())
|
||||
lease = db_api.lease_create(_get_fake_phys_lease_values())
|
||||
query = db_api.model_query(models.Lease)
|
||||
self.assertEqual([lease.to_dict()], [l.to_dict() for l in query.all()])
|
||||
|
||||
def test_create_virt_lease(self):
|
||||
"""Check virtual lease create
|
||||
|
||||
Create a virtual lease and verify that all tables have been
|
||||
populated.
|
||||
"""
|
||||
|
||||
result = db_api.lease_create(_get_fake_virt_lease_values())
|
||||
self.assertEqual(result['name'],
|
||||
_get_fake_virt_lease_values()['name'])
|
||||
self.assertEqual(0, len(db_api.event_get_all()))
|
||||
self.assertEqual(1, len(db_api.reservation_get_all()))
|
||||
|
||||
def test_create_phys_lease(self):
|
||||
"""Check physical lease create
|
||||
|
||||
@ -373,12 +327,14 @@ class SQLAlchemyDBApiTestCase(tests.DBTestCase):
|
||||
Create two reservations and verify that we can find reservation per
|
||||
resource_id or resource_type.
|
||||
"""
|
||||
db_api.reservation_create(_get_fake_phys_reservation_values())
|
||||
db_api.reservation_create(_get_fake_virt_reservation_values())
|
||||
db_api.reservation_create(
|
||||
_get_fake_phys_reservation_values(id='1', resource_id='1234'))
|
||||
db_api.reservation_create(
|
||||
_get_fake_phys_reservation_values(id='2', resource_id='5678'))
|
||||
self.assertEqual(2, len(db_api.reservation_get_all_by_values()))
|
||||
self.assertEqual(1, len(db_api.reservation_get_all_by_values(
|
||||
resource_id='5678')))
|
||||
self.assertEqual(1, len(db_api.reservation_get_all_by_values(
|
||||
self.assertEqual(2, len(db_api.reservation_get_all_by_values(
|
||||
resource_type=host_plugin.RESOURCE_TYPE)))
|
||||
|
||||
def test_reservation_update(self):
|
||||
|
@ -96,9 +96,13 @@ class ServiceTestCase(tests.TestCase):
|
||||
'PhysicalHostPlugin')
|
||||
|
||||
self.ext_manager = self.patch(self.enabled, 'EnabledExtensionManager')
|
||||
self.ext_manager.return_value.extensions = [
|
||||
FakeExtension('dummy.vm.plugin', FakePlugin),
|
||||
]
|
||||
self.fake_notifier = self.patch(self.notifier_api,
|
||||
'send_lease_notification')
|
||||
|
||||
cfg.CONF.set_override('plugins', ['dummy.vm.plugin'], group='manager')
|
||||
self.manager = self.service.ManagerService()
|
||||
|
||||
self.lease_id = '11-22-33'
|
||||
@ -150,8 +154,8 @@ class ServiceTestCase(tests.TestCase):
|
||||
pass
|
||||
|
||||
def test_multiple_plugins_same_resource_type(self):
|
||||
config = self.patch(cfg, "CONF")
|
||||
config.manager.plugins = ['fake.plugin.1', 'fake.plugin.2']
|
||||
config = self.patch(cfg.CONF, "manager")
|
||||
config.plugins = ['fake.plugin.1', 'fake.plugin.2']
|
||||
self.ext_manager.return_value.extensions = [
|
||||
FakeExtension("fake.plugin.1", FakePlugin),
|
||||
FakeExtension("fake.plugin.2", FakePlugin)]
|
||||
@ -160,8 +164,8 @@ class ServiceTestCase(tests.TestCase):
|
||||
self.manager._get_plugins)
|
||||
|
||||
def test_plugins_that_fail_to_init(self):
|
||||
config = self.patch(cfg, "CONF")
|
||||
config.manager.plugins = ['fake.plugin.1', 'fake.plugin.2']
|
||||
config = self.patch(cfg.CONF, "manager")
|
||||
config.plugins = ['fake.plugin.1', 'fake.plugin.2']
|
||||
self.ext_manager.return_value.extensions = [
|
||||
FakeExtension("fake.plugin.1", FakePlugin),
|
||||
FakeExtension("fake.plugin.2", FakePluginRaisesException)]
|
||||
@ -171,10 +175,11 @@ class ServiceTestCase(tests.TestCase):
|
||||
self.assertNotIn("fake:plugin:raise", plugins)
|
||||
|
||||
def test_get_bad_config_plugins(self):
|
||||
config = self.patch(cfg, "CONF")
|
||||
config.manager.plugins = ['foo.plugin']
|
||||
config = self.patch(cfg.CONF, "manager")
|
||||
config.plugins = ['foo.plugin']
|
||||
|
||||
self.assertEqual({}, self.manager._get_plugins())
|
||||
self.assertRaises(exceptions.BlazarException,
|
||||
self.manager._get_plugins)
|
||||
|
||||
def test_setup_actions(self):
|
||||
actions = {'virtual:instance':
|
||||
|
@ -1,108 +0,0 @@
|
||||
# Copyright (c) 2013 Mirantis 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.
|
||||
|
||||
import sys
|
||||
|
||||
import eventlet
|
||||
from novaclient import exceptions as nova_exceptions
|
||||
from oslo_log import log as logging
|
||||
import testtools
|
||||
|
||||
from blazar import exceptions as blazar_exceptions
|
||||
from blazar.plugins.instances import vm_plugin
|
||||
from blazar import tests
|
||||
from blazar.utils.openstack import nova
|
||||
|
||||
|
||||
class VMPluginTestCase(tests.TestCase):
|
||||
def setUp(self):
|
||||
super(VMPluginTestCase, self).setUp()
|
||||
self.nova = nova
|
||||
self.exc = blazar_exceptions
|
||||
self.logging = logging
|
||||
self.sys = sys
|
||||
|
||||
# To speed up the test run
|
||||
self.eventlet = eventlet
|
||||
self.eventlet_sleep = self.patch(self.eventlet, 'sleep')
|
||||
|
||||
self.fake_id = '1'
|
||||
|
||||
self.nova_wrapper = self.patch(self.nova.NovaClientWrapper, 'nova')
|
||||
self.plugin = vm_plugin.VMPlugin()
|
||||
|
||||
def test_on_start_ok(self):
|
||||
self.plugin.on_start(self.fake_id)
|
||||
|
||||
self.nova_wrapper.servers.unshelve.assert_called_once_with('1')
|
||||
|
||||
@testtools.skip('Will be released later')
|
||||
def test_on_start_fail(self):
|
||||
def raise_exception(resource_id):
|
||||
raise blazar_exceptions.Conflict(409)
|
||||
|
||||
self.nova_wrapper.servers.unshelve.side_effect = raise_exception
|
||||
self.plugin.on_start(self.fake_id)
|
||||
|
||||
def test_on_end_create_image_ok(self):
|
||||
self.patch(self.plugin, '_split_actions').return_value = (
|
||||
['create_image'])
|
||||
self.patch(self.plugin, '_check_active').return_value = True
|
||||
|
||||
self.plugin.on_end(self.fake_id)
|
||||
|
||||
self.nova_wrapper.servers.create_image.assert_called_once_with('1')
|
||||
|
||||
def test_on_end_suspend_ok(self):
|
||||
self.patch(self.plugin, '_split_actions').return_value = ['suspend']
|
||||
|
||||
self.plugin.on_end(self.fake_id)
|
||||
self.nova_wrapper.servers.suspend.assert_called_once_with('1')
|
||||
|
||||
def test_on_end_delete_ok(self):
|
||||
self.patch(self.plugin, '_split_actions').return_value = ['delete']
|
||||
|
||||
self.plugin.on_end(self.fake_id)
|
||||
self.nova_wrapper.servers.delete.assert_called_once_with('1')
|
||||
|
||||
def test_on_end_create_image_instance_or_not_found(self):
|
||||
def raise_exception(resource_id):
|
||||
raise nova_exceptions.NotFound(404)
|
||||
|
||||
self.nova_wrapper.servers.create_image.side_effect = raise_exception
|
||||
|
||||
self.plugin.on_end(self.fake_id)
|
||||
self.nova_wrapper.servers.delete.assert_called_once_with('1')
|
||||
|
||||
def test_on_end_create_image_ko_invalid_vm_state(self):
|
||||
def raise_exception(resource_id):
|
||||
raise nova_exceptions.Conflict(409)
|
||||
|
||||
self.nova_wrapper.servers.create_image.side_effect = raise_exception
|
||||
|
||||
self.plugin.on_end(self.fake_id)
|
||||
self.nova_wrapper.servers.delete.assert_called_once_with('1')
|
||||
|
||||
@testtools.skip('Will be released later')
|
||||
def test_on_end_timeout(self):
|
||||
self.patch(self.plugin, '_split_actions').return_value = (
|
||||
['create_image'])
|
||||
self.assertRaises(self.exc.Timeout,
|
||||
self.plugin.on_end,
|
||||
self.fake_id)
|
||||
|
||||
@testtools.skip('Will be released later')
|
||||
def test_check_active(self):
|
||||
pass
|
@ -60,7 +60,7 @@ function configure_blazar {
|
||||
iniset $BLAZAR_CONF_FILE DEFAULT debug $BLAZAR_DEBUG
|
||||
iniset $BLAZAR_CONF_FILE DEFAULT verbose $BLAZAR_VERBOSE
|
||||
|
||||
iniset $BLAZAR_CONF_FILE manager plugins basic.vm.plugin,physical.host.plugin
|
||||
iniset $BLAZAR_CONF_FILE manager plugins physical.host.plugin
|
||||
|
||||
iniset $BLAZAR_CONF_FILE api api_v2_controllers oshosts,leases
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
upgrade:
|
||||
- |
|
||||
The previous instance reservation plugin, named 'basic.vm.plugin' in
|
||||
blazar.conf, is completely removed from Blazar. Deployments including
|
||||
this plugin in blazar.conf must be updated by removing it from the
|
||||
plugins list. Otherwise, the blazar-manager service will fail to start
|
||||
with an exception about invalid plugin names.
|
@ -41,7 +41,6 @@ console_scripts =
|
||||
blazar.resource.plugins =
|
||||
dummy.vm.plugin=blazar.plugins.dummy_vm_plugin:DummyVMPlugin
|
||||
physical.host.plugin=blazar.plugins.oshosts.host_plugin:PhysicalHostPlugin
|
||||
basic.vm.plugin=blazar.plugins.instances.vm_plugin:VMPlugin
|
||||
|
||||
# Remove this alias when the deprecation period of "climate" is over
|
||||
climate.api.v2.controllers.extensions =
|
||||
|
Loading…
Reference in New Issue
Block a user