412 lines
15 KiB
Python
412 lines
15 KiB
Python
# Copyright 2015 Hitachi Data Systems inc.
|
|
# 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 ddt
|
|
import mock
|
|
|
|
import time
|
|
|
|
from manila.common import constants
|
|
from manila import context
|
|
from manila import db
|
|
from manila import exception
|
|
from manila.share import api as share_api
|
|
from manila.share import migration
|
|
from manila import test
|
|
from manila.tests import db_utils
|
|
from manila import utils
|
|
|
|
|
|
@ddt.ddt
|
|
class ShareMigrationHelperTestCase(test.TestCase):
|
|
"""Tests ShareMigrationHelper."""
|
|
|
|
def setUp(self):
|
|
super(ShareMigrationHelperTestCase, self).setUp()
|
|
self.share = db_utils.create_share()
|
|
self.share_instance = db_utils.create_share_instance(
|
|
share_id=self.share['id'],
|
|
share_network_id='fake_network_id')
|
|
self.context = context.get_admin_context()
|
|
self.helper = migration.ShareMigrationHelper(
|
|
self.context, db, self.share)
|
|
|
|
def test_delete_instance_and_wait(self):
|
|
|
|
# mocks
|
|
self.mock_object(share_api.API, 'delete_instance')
|
|
self.mock_object(db, 'share_instance_get',
|
|
mock.Mock(side_effect=[self.share_instance,
|
|
exception.NotFound()]))
|
|
self.mock_object(time, 'sleep')
|
|
|
|
# run
|
|
self.helper.delete_instance_and_wait(self.share_instance)
|
|
|
|
# asserts
|
|
share_api.API.delete_instance.assert_called_once_with(
|
|
self.context, self.share_instance, True)
|
|
|
|
db.share_instance_get.assert_has_calls([
|
|
mock.call(self.context, self.share_instance['id']),
|
|
mock.call(self.context, self.share_instance['id'])])
|
|
|
|
time.sleep.assert_called_once_with(1)
|
|
|
|
def test_delete_instance_and_wait_timeout(self):
|
|
|
|
# mocks
|
|
self.mock_object(share_api.API, 'delete_instance')
|
|
|
|
self.mock_object(db, 'share_instance_get',
|
|
mock.Mock(side_effect=[self.share_instance, None]))
|
|
self.mock_object(time, 'sleep')
|
|
|
|
now = time.time()
|
|
timeout = now + 310
|
|
|
|
self.mock_object(time, 'time',
|
|
mock.Mock(side_effect=[now, timeout]))
|
|
|
|
# run
|
|
self.assertRaises(exception.ShareMigrationFailed,
|
|
self.helper.delete_instance_and_wait,
|
|
self.share_instance)
|
|
|
|
# asserts
|
|
share_api.API.delete_instance.assert_called_once_with(
|
|
self.context, self.share_instance, True)
|
|
|
|
db.share_instance_get.assert_called_once_with(
|
|
self.context, self.share_instance['id'])
|
|
|
|
time.time.assert_has_calls([mock.call(), mock.call()])
|
|
|
|
def test_delete_instance_and_wait_not_found(self):
|
|
|
|
# mocks
|
|
self.mock_object(share_api.API, 'delete_instance')
|
|
self.mock_object(db, 'share_instance_get',
|
|
mock.Mock(side_effect=exception.NotFound))
|
|
|
|
# run
|
|
self.helper.delete_instance_and_wait(self.share_instance)
|
|
|
|
# asserts
|
|
share_api.API.delete_instance.assert_called_once_with(
|
|
self.context, self.share_instance, True)
|
|
|
|
db.share_instance_get.assert_called_once_with(
|
|
self.context, self.share_instance['id'])
|
|
|
|
def test_create_instance_and_wait(self):
|
|
|
|
host = 'fake_host'
|
|
|
|
share_instance_creating = db_utils.create_share_instance(
|
|
share_id=self.share['id'], status=constants.STATUS_CREATING,
|
|
share_network_id='fake_network_id')
|
|
share_instance_available = db_utils.create_share_instance(
|
|
share_id=self.share['id'], status=constants.STATUS_AVAILABLE,
|
|
share_network_id='fake_network_id')
|
|
|
|
# mocks
|
|
self.mock_object(share_api.API, 'create_instance',
|
|
mock.Mock(return_value=share_instance_creating))
|
|
self.mock_object(db, 'share_instance_get',
|
|
mock.Mock(side_effect=[share_instance_creating,
|
|
share_instance_available]))
|
|
self.mock_object(time, 'sleep')
|
|
|
|
# run
|
|
self.helper.create_instance_and_wait(
|
|
self.share, host, 'fake_net_id', 'fake_az_id', 'fake_type_id')
|
|
|
|
# asserts
|
|
share_api.API.create_instance.assert_called_once_with(
|
|
self.context, self.share, 'fake_net_id', 'fake_host', 'fake_az_id',
|
|
share_type_id='fake_type_id')
|
|
|
|
db.share_instance_get.assert_has_calls([
|
|
mock.call(self.context, share_instance_creating['id'],
|
|
with_share_data=True),
|
|
mock.call(self.context, share_instance_creating['id'],
|
|
with_share_data=True)])
|
|
|
|
time.sleep.assert_called_once_with(1)
|
|
|
|
def test_create_instance_and_wait_status_error(self):
|
|
|
|
host = 'fake_host'
|
|
|
|
share_instance_error = db_utils.create_share_instance(
|
|
share_id=self.share['id'], status=constants.STATUS_ERROR,
|
|
share_network_id='fake_network_id')
|
|
|
|
# mocks
|
|
self.mock_object(share_api.API, 'create_instance',
|
|
mock.Mock(return_value=share_instance_error))
|
|
self.mock_object(self.helper, 'cleanup_new_instance')
|
|
self.mock_object(db, 'share_instance_get',
|
|
mock.Mock(return_value=share_instance_error))
|
|
|
|
# run
|
|
self.assertRaises(
|
|
exception.ShareMigrationFailed,
|
|
self.helper.create_instance_and_wait, self.share,
|
|
host, 'fake_net_id', 'fake_az_id', 'fake_type_id')
|
|
|
|
# asserts
|
|
share_api.API.create_instance.assert_called_once_with(
|
|
self.context, self.share, 'fake_net_id', 'fake_host', 'fake_az_id',
|
|
share_type_id='fake_type_id')
|
|
|
|
db.share_instance_get.assert_called_once_with(
|
|
self.context, share_instance_error['id'], with_share_data=True)
|
|
|
|
self.helper.cleanup_new_instance.assert_called_once_with(
|
|
share_instance_error)
|
|
|
|
def test_create_instance_and_wait_timeout(self):
|
|
|
|
host = 'fake_host'
|
|
|
|
share_instance_creating = db_utils.create_share_instance(
|
|
share_id=self.share['id'], status=constants.STATUS_CREATING,
|
|
share_network_id='fake_network_id')
|
|
|
|
# mocks
|
|
self.mock_object(share_api.API, 'create_instance',
|
|
mock.Mock(return_value=share_instance_creating))
|
|
|
|
self.mock_object(self.helper, 'cleanup_new_instance')
|
|
|
|
self.mock_object(db, 'share_instance_get',
|
|
mock.Mock(return_value=share_instance_creating))
|
|
self.mock_object(time, 'sleep')
|
|
|
|
now = time.time()
|
|
timeout = now + 310
|
|
|
|
self.mock_object(time, 'time', mock.Mock(side_effect=[now, timeout]))
|
|
|
|
# run
|
|
self.assertRaises(
|
|
exception.ShareMigrationFailed,
|
|
self.helper.create_instance_and_wait, self.share,
|
|
host, 'fake_net_id', 'fake_az_id', 'fake_type_id')
|
|
|
|
# asserts
|
|
share_api.API.create_instance.assert_called_once_with(
|
|
self.context, self.share, 'fake_net_id', 'fake_host', 'fake_az_id',
|
|
share_type_id='fake_type_id')
|
|
|
|
db.share_instance_get.assert_called_once_with(
|
|
self.context, share_instance_creating['id'], with_share_data=True)
|
|
|
|
time.time.assert_has_calls([mock.call(), mock.call()])
|
|
|
|
self.helper.cleanup_new_instance.assert_called_once_with(
|
|
share_instance_creating)
|
|
|
|
@ddt.data(constants.STATUS_ACTIVE, constants.STATUS_ERROR,
|
|
constants.STATUS_CREATING)
|
|
def test_wait_for_share_server(self, status):
|
|
|
|
server = db_utils.create_share_server(status=status)
|
|
|
|
# mocks
|
|
self.mock_object(db, 'share_server_get',
|
|
mock.Mock(return_value=server))
|
|
|
|
# run
|
|
if status == constants.STATUS_ACTIVE:
|
|
result = self.helper.wait_for_share_server('fake_server_id')
|
|
self.assertEqual(server, result)
|
|
elif status == constants.STATUS_ERROR:
|
|
self.assertRaises(
|
|
exception.ShareServerNotCreated,
|
|
self.helper.wait_for_share_server, 'fake_server_id')
|
|
else:
|
|
self.mock_object(time, 'sleep')
|
|
self.assertRaises(
|
|
exception.ShareServerNotReady,
|
|
self.helper.wait_for_share_server, 'fake_server_id')
|
|
|
|
# asserts
|
|
db.share_server_get.assert_called_with(self.context, 'fake_server_id')
|
|
|
|
def test_change_to_read_only_with_ro_support(self):
|
|
|
|
share_instance = db_utils.create_share_instance(
|
|
share_id=self.share['id'], status=constants.STATUS_AVAILABLE)
|
|
|
|
access = db_utils.create_access(share_id=self.share['id'],
|
|
access_to='fake_ip',
|
|
access_level='rw')
|
|
|
|
server = db_utils.create_share_server(share_id=self.share['id'])
|
|
|
|
# mocks
|
|
share_driver = mock.Mock()
|
|
self.mock_object(share_driver, 'update_access')
|
|
|
|
self.mock_object(db, 'share_access_get_all_for_instance',
|
|
mock.Mock(return_value=[access]))
|
|
|
|
# run
|
|
self.helper.change_to_read_only(share_instance, server, True,
|
|
share_driver)
|
|
|
|
# asserts
|
|
db.share_access_get_all_for_instance.assert_called_once_with(
|
|
self.context, share_instance['id'])
|
|
share_driver.update_access.assert_called_once_with(
|
|
self.context, share_instance, [access], add_rules=[],
|
|
delete_rules=[], share_server=server)
|
|
|
|
def test_change_to_read_only_without_ro_support(self):
|
|
|
|
share_instance = db_utils.create_share_instance(
|
|
share_id=self.share['id'], status=constants.STATUS_AVAILABLE)
|
|
|
|
access = db_utils.create_access(share_id=self.share['id'],
|
|
access_to='fake_ip',
|
|
access_level='rw')
|
|
|
|
server = db_utils.create_share_server(share_id=self.share['id'])
|
|
|
|
# mocks
|
|
share_driver = mock.Mock()
|
|
self.mock_object(share_driver, 'update_access')
|
|
|
|
self.mock_object(db, 'share_access_get_all_for_instance',
|
|
mock.Mock(return_value=[access]))
|
|
|
|
# run
|
|
self.helper.change_to_read_only(share_instance, server, False,
|
|
share_driver)
|
|
|
|
# asserts
|
|
db.share_access_get_all_for_instance.assert_called_once_with(
|
|
self.context, share_instance['id'])
|
|
share_driver.update_access.assert_called_once_with(
|
|
self.context, share_instance, [], add_rules=[],
|
|
delete_rules=[access], share_server=server)
|
|
|
|
def test_revert_access_rules(self):
|
|
|
|
share_instance = db_utils.create_share_instance(
|
|
share_id=self.share['id'], status=constants.STATUS_AVAILABLE)
|
|
|
|
access = db_utils.create_access(share_id=self.share['id'],
|
|
access_to='fake_ip',
|
|
access_level='rw')
|
|
|
|
server = db_utils.create_share_server(share_id=self.share['id'])
|
|
|
|
# mocks
|
|
share_driver = mock.Mock()
|
|
self.mock_object(share_driver, 'update_access')
|
|
|
|
self.mock_object(db, 'share_access_get_all_for_instance',
|
|
mock.Mock(return_value=[access]))
|
|
|
|
# run
|
|
self.helper.revert_access_rules(share_instance, server, share_driver)
|
|
|
|
# asserts
|
|
db.share_access_get_all_for_instance.assert_called_once_with(
|
|
self.context, share_instance['id'])
|
|
share_driver.update_access.assert_called_once_with(
|
|
self.context, share_instance, [access], add_rules=[],
|
|
delete_rules=[], share_server=server)
|
|
|
|
def test_apply_new_access_rules(self):
|
|
|
|
new_share_instance = db_utils.create_share_instance(
|
|
share_id=self.share['id'], status=constants.STATUS_AVAILABLE,
|
|
access_rules_status='active')
|
|
|
|
access = db_utils.create_access(share_id=self.share['id'],
|
|
access_to='fake_ip',
|
|
access_level='rw')
|
|
|
|
# mocks
|
|
self.mock_object(db, 'share_instance_get',
|
|
mock.Mock(return_value=new_share_instance))
|
|
self.mock_object(db, 'share_instance_access_copy')
|
|
self.mock_object(db, 'share_access_get_all_for_instance',
|
|
mock.Mock(return_value=[access]))
|
|
self.mock_object(share_api.API, 'allow_access_to_instance')
|
|
self.mock_object(utils, 'wait_for_access_update')
|
|
|
|
# run
|
|
self.helper.apply_new_access_rules(new_share_instance)
|
|
|
|
# asserts
|
|
db.share_instance_get.assert_called_once_with(
|
|
self.context, new_share_instance['id'], with_share_data=True)
|
|
db.share_instance_access_copy(self.context, self.share['id'],
|
|
new_share_instance['id'])
|
|
db.share_access_get_all_for_instance.assert_called_once_with(
|
|
self.context, new_share_instance['id'])
|
|
share_api.API.allow_access_to_instance.assert_called_with(
|
|
self.context, new_share_instance, [access])
|
|
utils.wait_for_access_update.assert_called_with(
|
|
self.context, db, new_share_instance,
|
|
self.helper.migration_wait_access_rules_timeout)
|
|
|
|
@ddt.data(None, Exception('fake'))
|
|
def test_cleanup_new_instance(self, exc):
|
|
|
|
# mocks
|
|
self.mock_object(self.helper, 'delete_instance_and_wait',
|
|
mock.Mock(side_effect=exc))
|
|
|
|
self.mock_object(migration.LOG, 'warning')
|
|
|
|
# run
|
|
self.helper.cleanup_new_instance(self.share_instance)
|
|
|
|
# asserts
|
|
self.helper.delete_instance_and_wait.assert_called_once_with(
|
|
self.share_instance)
|
|
|
|
if exc:
|
|
self.assertEqual(1, migration.LOG.warning.call_count)
|
|
|
|
@ddt.data(None, Exception('fake'))
|
|
def test_cleanup_access_rules(self, exc):
|
|
|
|
# mocks
|
|
server = db_utils.create_share_server()
|
|
share_driver = mock.Mock()
|
|
self.mock_object(self.helper, 'revert_access_rules',
|
|
mock.Mock(side_effect=exc))
|
|
|
|
self.mock_object(migration.LOG, 'warning')
|
|
|
|
# run
|
|
self.helper.cleanup_access_rules(self.share_instance, server,
|
|
share_driver)
|
|
|
|
# asserts
|
|
self.helper.revert_access_rules.assert_called_once_with(
|
|
self.share_instance, server, share_driver)
|
|
|
|
if exc:
|
|
self.assertEqual(1, migration.LOG.warning.call_count)
|