karbor/karbor/tests/unit/protection/test_cinder_protection_plug...

440 lines
17 KiB
Python

# 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.
from cinderclient import exceptions as cinder_exc
import collections
from karbor.common import constants
from karbor.context import RequestContext
from karbor import exception
from karbor.resource import Resource
from karbor.services.protection import bank_plugin
from karbor.services.protection import client_factory
from karbor.services.protection.protection_plugins.volume. \
cinder_protection_plugin import CinderBackupProtectionPlugin
from karbor.services.protection.protection_plugins.volume \
import volume_plugin_cinder_schemas as cinder_schemas
from karbor.services.protection.restore_heat import HeatTemplate
from karbor.tests import base
from karbor.tests.unit.protection import fakes
import mock
from oslo_config import cfg
from oslo_config import fixture
ResourceNode = collections.namedtuple(
"ResourceNode",
["value",
"child_nodes"]
)
Image = collections.namedtuple(
"Image",
["disk_format",
"container_format",
"status"]
)
def call_hooks(operation, checkpoint, resource, context, parameters, **kwargs):
def noop(*args, **kwargs):
pass
hooks = (
'on_prepare_begin',
'on_prepare_finish',
'on_main',
'on_complete',
)
for hook_name in hooks:
hook = getattr(operation, hook_name, noop)
hook(checkpoint, resource, context, parameters, **kwargs)
class FakeCheckpoint(object):
def __init__(self, section):
super(FakeCheckpoint, self).__init__()
self.bank_section = section
self.id = "fake_id"
def get_resource_bank_section(self, resource_id=None):
return self.bank_section
class BackupResponse(object):
def __init__(self, bkup_id, final_status, working_status, time_to_work):
super(BackupResponse, self).__init__()
self._final_status = final_status
self._working_status = working_status
self._time_to_work = time_to_work
self._id = bkup_id
def __call__(self, *args, **kwargs):
res = mock.Mock()
res.id = self._id
if self._time_to_work > 0:
self._time_to_work -= 1
res.status = self._working_status
else:
res.status = self._final_status
if res.status == 'not-found':
raise cinder_exc.NotFound(403)
return res
class RestoreResponse(object):
def __init__(self, volume_id, raise_except=False):
self._volume_id = volume_id
self._raise_except = raise_except
def __call__(self, *args, **kwargs):
if self._raise_except:
raise exception.KarborException()
res = mock.Mock()
res.volume_id = self._volume_id
return res
class CinderProtectionPluginTest(base.TestCase):
def setUp(self):
super(CinderProtectionPluginTest, self).setUp()
plugin_config = cfg.ConfigOpts()
plugin_config_fixture = self.useFixture(fixture.Config(plugin_config))
plugin_config_fixture.load_raw_values(
group='cinder_backup_protection_plugin',
poll_interval=0,
)
self.plugin = CinderBackupProtectionPlugin(plugin_config)
cfg.CONF.set_default('cinder_endpoint',
'http://127.0.0.1:8776/v2',
'cinder_client')
self.cntxt = RequestContext(user_id='demo',
project_id='abcd',
auth_token='efgh')
self.cinder_client = client_factory.ClientFactory.create_client(
"cinder", self.cntxt)
def _get_checkpoint(self):
fake_bank = bank_plugin.Bank(fakes.FakeBankPlugin())
fake_bank_section = bank_plugin.BankSection(
bank=fake_bank,
section="fake"
)
return FakeCheckpoint(fake_bank_section)
def test_get_options_schema(self):
options_schema = self.plugin.get_options_schema(
'OS::Cinder::Volume')
self.assertEqual(options_schema, cinder_schemas.OPTIONS_SCHEMA)
def test_get_restore_schema(self):
options_schema = self.plugin.get_restore_schema(
'OS::Cinder::Volume')
self.assertEqual(options_schema, cinder_schemas.RESTORE_SCHEMA)
def test_get_saved_info_schema(self):
options_schema = self.plugin.get_saved_info_schema(
'OS::Cinder::Volume')
self.assertEqual(options_schema,
cinder_schemas.SAVED_INFO_SCHEMA)
@mock.patch('karbor.services.protection.clients.cinder.create')
def test_protect_succeed(self, mock_cinder_create):
resource = Resource(
id="123",
type=constants.VOLUME_RESOURCE_TYPE,
name="test",
)
checkpoint = self._get_checkpoint()
section = checkpoint.get_resource_bank_section()
operation = self.plugin.get_protect_operation(resource)
section.update_object = mock.MagicMock()
mock_cinder_create.return_value = self.cinder_client
with mock.patch.multiple(
self.cinder_client,
volumes=mock.DEFAULT,
backups=mock.DEFAULT,
volume_snapshots=mock.DEFAULT,
) as mocks:
mocks['volumes'].get.return_value = mock.Mock()
mocks['volumes'].get.return_value.status = 'available'
mocks['backups'].create = BackupResponse(
'456', 'creating', '---', 0)
mocks['backups'].get = BackupResponse(
'456', 'available', 'creating', 2)
mocks['volume_snapshots'].get.return_value = BackupResponse(
'789', 'creating', '---', 0)
mocks['volume_snapshots'].get = BackupResponse(
'789', 'available', 'creating', 2)
call_hooks(operation, checkpoint, resource, self.cntxt, {})
@mock.patch('karbor.services.protection.clients.cinder.create')
def test_protect_fail_backup(self, mock_cinder_create):
resource = Resource(
id="123",
type=constants.VOLUME_RESOURCE_TYPE,
name="test",
)
checkpoint = self._get_checkpoint()
operation = self.plugin.get_protect_operation(resource)
mock_cinder_create.return_value = self.cinder_client
with mock.patch.multiple(
self.cinder_client,
volumes=mock.DEFAULT,
backups=mock.DEFAULT,
volume_snapshots=mock.DEFAULT,
) as mocks:
mocks['volumes'].get.return_value = mock.Mock()
mocks['volumes'].get.return_value.status = 'available'
mocks['backups'].backups.create = BackupResponse(
'456', 'creating', '---', 0)
mocks['backups'].backups.get = BackupResponse(
'456', 'error', 'creating', 2)
mocks['volume_snapshots'].get.return_value = BackupResponse(
'789', 'creating', '---', 0)
mocks['volume_snapshots'].get = BackupResponse(
'789', 'available', 'creating', 2)
self.assertRaises(
exception.CreateBackupFailed,
call_hooks,
operation,
checkpoint,
resource,
self.cntxt,
{}
)
@mock.patch('karbor.services.protection.clients.cinder.create')
def test_protect_fail_snapshot(self, mock_cinder_create):
resource = Resource(
id="123",
type=constants.VOLUME_RESOURCE_TYPE,
name="test",
)
checkpoint = self._get_checkpoint()
operation = self.plugin.get_protect_operation(resource)
mock_cinder_create.return_value = self.cinder_client
with mock.patch.multiple(
self.cinder_client,
volumes=mock.DEFAULT,
backups=mock.DEFAULT,
volume_snapshots=mock.DEFAULT,
) as mocks:
mocks['volumes'].get.return_value = mock.Mock()
mocks['volumes'].get.return_value.status = 'available'
mocks['backups'].backups.create = BackupResponse(
'456', 'creating', '---', 0)
mocks['backups'].backups.get = BackupResponse(
'456', 'available', 'creating', 2)
mocks['volume_snapshots'].get.return_value = BackupResponse(
'789', 'creating', '---', 0)
mocks['volume_snapshots'].get = BackupResponse(
'789', 'error', 'creating', 2)
self.assertRaises(
exception.CreateBackupFailed,
call_hooks,
operation,
checkpoint,
resource,
self.cntxt,
{}
)
@mock.patch('karbor.services.protection.clients.cinder.create')
def test_protect_fail_volume(self, mock_cinder_create):
resource = Resource(
id="123",
type=constants.VOLUME_RESOURCE_TYPE,
name="test",
)
checkpoint = self._get_checkpoint()
operation = self.plugin.get_protect_operation(resource)
mock_cinder_create.return_value = self.cinder_client
with mock.patch.multiple(
self.cinder_client,
volumes=mock.DEFAULT,
backups=mock.DEFAULT,
volume_snapshots=mock.DEFAULT,
) as mocks:
mocks['volumes'].get.return_value = mock.Mock()
mocks['volumes'].get.return_value.status = 'error'
mocks['backups'].backups.create = BackupResponse(
'456', 'creating', '---', 0)
mocks['backups'].backups.get = BackupResponse(
'456', 'error', 'creating', 2)
mocks['volume_snapshots'].get.return_value = BackupResponse(
'789', 'creating', '---', 0)
mocks['volume_snapshots'].get = BackupResponse(
'789', 'available', 'creating', 2)
self.assertRaises(
exception.CreateBackupFailed,
call_hooks,
operation,
checkpoint,
resource,
self.cntxt,
{}
)
@mock.patch('karbor.services.protection.clients.cinder.create')
def test_delete_succeed(self, mock_cinder_create):
resource = Resource(
id="123",
type=constants.VOLUME_RESOURCE_TYPE,
name="test",
)
checkpoint = self._get_checkpoint()
section = checkpoint.get_resource_bank_section()
section.update_object('metadata', {
'backup_id': '456',
})
operation = self.plugin.get_delete_operation(resource)
mock_cinder_create.return_value = self.cinder_client
with mock.patch.object(self.cinder_client, 'backups') as backups:
backups.delete = BackupResponse('456', 'deleting', '---', 0)
backups.get = BackupResponse('456', 'not-found', 'deleting', 2)
call_hooks(operation, checkpoint, resource, self.cntxt, {})
@mock.patch('karbor.services.protection.clients.cinder.create')
def test_delete_fail(self, mock_cinder_create):
resource = Resource(
id="123",
type=constants.VOLUME_RESOURCE_TYPE,
name="test",
)
checkpoint = self._get_checkpoint()
section = checkpoint.get_resource_bank_section()
section.update_object('metadata', {
'backup_id': '456',
})
operation = self.plugin.get_delete_operation(resource)
mock_cinder_create.return_value = self.cinder_client
with mock.patch.object(self.cinder_client, 'backups') as backups:
backups.delete = BackupResponse('456', 'deleting', '---', 0)
backups.get = BackupResponse('456', 'error', 'deleting', 2)
self.assertRaises(
exception.DeleteBackupFailed,
call_hooks,
operation,
checkpoint,
resource,
self.cntxt,
{}
)
@mock.patch('karbor.services.protection.clients.cinder.create')
@mock.patch('karbor.services.protection.protection_plugins.utils.'
'update_resource_restore_result')
def test_restore_succeed(self, mock_update_restore, mock_cinder_create):
resource = Resource(
id="123",
type=constants.VOLUME_RESOURCE_TYPE,
name="fake",
)
checkpoint = self._get_checkpoint()
section = checkpoint.get_resource_bank_section()
section.update_object('metadata', {
'backup_id': '456',
})
parameters = {
"restore_name": "karbor restore volume",
"restore_description": "karbor restore",
}
operation = self.plugin.get_restore_operation(resource)
mock_cinder_create.return_value = self.cinder_client
with mock.patch.multiple(
self.cinder_client,
volumes=mock.DEFAULT,
restores=mock.DEFAULT,
) as mocks:
volume_id = 456
mocks['volumes'].get.return_value = mock.Mock()
mocks['volumes'].get.return_value.status = 'available'
mocks['restores'].restore = RestoreResponse(volume_id)
call_hooks(operation, checkpoint, resource, self.cntxt, parameters,
**{'restore': None, 'heat_template': HeatTemplate()})
mocks['volumes'].update.assert_called_with(
volume_id,
**{'name': parameters['restore_name'],
'description': parameters['restore_description']})
mock_update_restore.assert_called_with(
None, resource.type, volume_id, 'available')
@mock.patch('karbor.services.protection.clients.cinder.create')
def test_restore_fail_volume_0(self, mock_cinder_create):
resource = Resource(
id="123",
type=constants.VOLUME_RESOURCE_TYPE,
name="fake",
)
checkpoint = self._get_checkpoint()
section = checkpoint.get_resource_bank_section()
section.update_object('metadata', {
'backup_id': '456',
})
operation = self.plugin.get_restore_operation(resource)
mock_cinder_create.return_value = self.cinder_client
with mock.patch.multiple(
self.cinder_client,
restores=mock.DEFAULT,
) as mocks:
mocks['restores'].restore = RestoreResponse(0, True)
self.assertRaises(
exception.KarborException, call_hooks,
operation, checkpoint, resource, self.cntxt,
{}, **{'restore': None})
@mock.patch('karbor.services.protection.clients.cinder.create')
@mock.patch('karbor.services.protection.protection_plugins.utils.'
'update_resource_restore_result')
def test_restore_fail_volume_1(self, mock_update_restore,
mock_cinder_create):
resource = Resource(
id="123",
type=constants.VOLUME_RESOURCE_TYPE,
name="fake",
)
checkpoint = self._get_checkpoint()
section = checkpoint.get_resource_bank_section()
section.update_object('metadata', {
'backup_id': '456',
})
operation = self.plugin.get_restore_operation(resource)
mock_cinder_create.return_value = self.cinder_client
with mock.patch.multiple(
self.cinder_client,
volumes=mock.DEFAULT,
restores=mock.DEFAULT,
) as mocks:
volume_id = 456
mocks['volumes'].get.return_value = mock.Mock()
mocks['volumes'].get.return_value.status = 'error'
mocks['restores'].restore = RestoreResponse(volume_id)
self.assertRaises(
exception.RestoreBackupFailed, call_hooks,
operation, checkpoint, resource, self.cntxt,
{}, **{'restore': None})
mock_update_restore.assert_called_with(
None, resource.type, volume_id,
constants.RESOURCE_STATUS_ERROR, 'Error creating volume')
def test_get_supported_resources_types(self):
types = self.plugin.get_supported_resources_types()
self.assertEqual(types,
[constants.VOLUME_RESOURCE_TYPE])