Share server migration enhancements
A series of enhancements can be performed in the share server migration operation, and share backends might support nondisruptive share server migrations, which was not covered in the previous approach. So in this change, we enhance the operation by: - Added the `is_ip_reusage_supported_on_server_migration` interface, so we can ask drivers if they are capable of reusing network allocations. - Added the `server_migration_mechanism_can_reuse_share_server` driver interface, so share backends can define if they need new share servers being created in the backend to serve as destination. - Skip the destination share server network allocation if the driver is capable of reusing the source share server allocation. Manila will switch the allocations in the migration complete phase. - Added a new parameter to the API called `cleanup_source_server`, which will be used by manila to check if the source share server must be deleted right after the migration is completed. Co-Authored-By: Fabio Oliveira <fabioaurelio1269@gmail.com> Change-Id: I48bafd92fe7a4d4ae0bafd5bf1961dace56b6005
This commit is contained in:
parent
ca9213ef40
commit
680b9f659e
|
@ -171,13 +171,15 @@ REST_API_VERSION_HISTORY = """
|
|||
actions on the share network's endpoint:
|
||||
'update_security_service', 'update_security_service_check' and
|
||||
'add_security_service_check'.
|
||||
* 2.64 - Added 'cleanup_source_server' to share server migration start
|
||||
operation.
|
||||
"""
|
||||
|
||||
# The minimum and maximum versions of the API supported
|
||||
# The default api version request is defined to be the
|
||||
# minimum version of the API supported.
|
||||
_MIN_API_VERSION = "2.0"
|
||||
_MAX_API_VERSION = "2.63"
|
||||
_MAX_API_VERSION = "2.64"
|
||||
DEFAULT_API_VERSION = _MIN_API_VERSION
|
||||
|
||||
|
||||
|
|
|
@ -353,3 +353,9 @@ user documentation.
|
|||
endpoint: 'update_security_service', 'update_security_service_check' and
|
||||
'add_security_service_check'.
|
||||
|
||||
2.64
|
||||
----
|
||||
Added 'cleanup_source_server' to share server migration start operation, so
|
||||
the share drivers can automatically remove the source share server when
|
||||
requested.
|
||||
|
||||
|
|
|
@ -215,12 +215,8 @@ class ShareServerController(share_servers.ShareServerController,
|
|||
|
||||
return identifier, host, share_network, driver_opts, network_subnet
|
||||
|
||||
@wsgi.Controller.api_version('2.57', experimental=True)
|
||||
@wsgi.action("migration_start")
|
||||
@wsgi.Controller.authorize
|
||||
@wsgi.response(http_client.ACCEPTED)
|
||||
def share_server_migration_start(self, req, id, body):
|
||||
"""Migrate a share server to the specified host."""
|
||||
def _share_server_migration_start(
|
||||
self, req, id, body, cleanup_source_server=False):
|
||||
context = req.environ['manila.context']
|
||||
try:
|
||||
share_server = db_api.share_server_get(
|
||||
|
@ -233,7 +229,10 @@ class ShareServerController(share_servers.ShareServerController,
|
|||
if not params:
|
||||
raise exc.HTTPBadRequest(explanation=_("Request is missing body."))
|
||||
|
||||
bool_params = ['writable', 'nondisruptive', 'preserve_snapshots']
|
||||
params['cleanup_source_server'] = cleanup_source_server
|
||||
|
||||
bool_params = ['writable', 'nondisruptive', 'preserve_snapshots',
|
||||
'cleanup_source_server']
|
||||
mandatory_params = bool_params + ['host']
|
||||
|
||||
utils.check_params_exist(mandatory_params, params)
|
||||
|
@ -270,7 +269,8 @@ class ShareServerController(share_servers.ShareServerController,
|
|||
bool_param_values['writable'],
|
||||
bool_param_values['nondisruptive'],
|
||||
bool_param_values['preserve_snapshots'],
|
||||
new_share_network=new_share_network)
|
||||
new_share_network=new_share_network,
|
||||
cleanup_source_server=cleanup_source_server)
|
||||
except exception.ServiceIsDown as e:
|
||||
# NOTE(dviroel): user should check if the host is healthy
|
||||
raise exc.HTTPBadRequest(explanation=e.msg)
|
||||
|
@ -279,6 +279,28 @@ class ShareServerController(share_servers.ShareServerController,
|
|||
# resource have a invalid state.
|
||||
raise exc.HTTPConflict(explanation=e.msg)
|
||||
|
||||
@wsgi.Controller.api_version('2.57', '2.63', experimental=True)
|
||||
@wsgi.action("migration_start")
|
||||
@wsgi.Controller.authorize
|
||||
@wsgi.response(http_client.ACCEPTED)
|
||||
def share_server_migration_start(self, req, id, body):
|
||||
"""Migrate a share server to the specified host."""
|
||||
self._share_server_migration_start(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.64', experimental=True) # noqa
|
||||
@wsgi.action("migration_start")
|
||||
@wsgi.Controller.authorize
|
||||
@wsgi.response(http_client.ACCEPTED)
|
||||
def share_server_migration_start(self, req, id, body): # pylint: disable=function-redefined # noqa F811
|
||||
"""Migrate a share server to the specified host."""
|
||||
body_params = body.get('migration_start')
|
||||
cleanup_source_server = False
|
||||
if body_params:
|
||||
cleanup_source_server = body_params.get(
|
||||
'cleanup_source_server', False)
|
||||
self._share_server_migration_start(
|
||||
req, id, body, cleanup_source_server=cleanup_source_server)
|
||||
|
||||
@wsgi.Controller.api_version('2.57', experimental=True)
|
||||
@wsgi.action("migration_complete")
|
||||
@wsgi.Controller.authorize
|
||||
|
|
|
@ -2579,7 +2579,8 @@ class API(base.Base):
|
|||
|
||||
def share_server_migration_start(
|
||||
self, context, share_server, dest_host, writable, nondisruptive,
|
||||
preserve_snapshots, new_share_network=None):
|
||||
preserve_snapshots, new_share_network=None,
|
||||
cleanup_source_server=False):
|
||||
"""Migrates share server to a new host."""
|
||||
|
||||
shares, types, dest_service, new_share_network_id = (
|
||||
|
@ -2614,7 +2615,7 @@ class API(base.Base):
|
|||
# checks
|
||||
self.share_rpcapi.share_server_migration_start(
|
||||
context, share_server, dest_host, writable, nondisruptive,
|
||||
preserve_snapshots, new_share_network_id)
|
||||
preserve_snapshots, new_share_network_id, cleanup_source_server)
|
||||
|
||||
def share_server_migration_complete(self, context, share_server):
|
||||
"""Invokes 2nd phase of share server migration."""
|
||||
|
|
|
@ -2888,7 +2888,8 @@ class ShareDriver(object):
|
|||
raise NotImplementedError()
|
||||
|
||||
def share_server_migration_start(self, context, src_share_server,
|
||||
dest_share_server, shares, snapshots):
|
||||
dest_share_server, shares, snapshots,
|
||||
cleanup_source_server):
|
||||
"""Starts migration of a given share server to another host.
|
||||
|
||||
.. note::
|
||||
|
@ -2909,6 +2910,18 @@ class ShareDriver(object):
|
|||
migrated.
|
||||
:param snapshots: All snapshots in the source share server that should
|
||||
be migrated.
|
||||
:param cleanup_source_server: whether the backend should delete the
|
||||
source share server right after the operation is completed or not.
|
||||
:return: Dict with migration information to be set in the destination
|
||||
share server.
|
||||
|
||||
Example::
|
||||
|
||||
{
|
||||
'backend_details': {
|
||||
'migration_info_key': 'migration_info_value',
|
||||
}
|
||||
}
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
@ -3312,3 +3325,29 @@ class ShareDriver(object):
|
|||
otherwise.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def is_ip_reusage_supported_on_server_migration(
|
||||
self, source_host, dest_host):
|
||||
"""Check if network allocation can be reused on share migration.
|
||||
|
||||
If the driver supports reusing ip allocations during the share server
|
||||
migration, manila will not allocate new addresses and reuse the
|
||||
existing allocations for the destination share server.
|
||||
|
||||
:param source_host: The host from the share server to be migrated.
|
||||
:param dest_host: The host where the share server will be migrated to.
|
||||
"""
|
||||
return False
|
||||
|
||||
def server_migration_mechanism_can_reuse_share_server(
|
||||
self, source_host, dest_host):
|
||||
"""Check if the share server migration mechanism can reuse the server.
|
||||
|
||||
If the driver does not need a new share server to be created, this
|
||||
function must return False, then manila won't request a new share
|
||||
server to be created in the share back end.
|
||||
|
||||
:param source_host: The host from the share server to be migrated.
|
||||
:param dest_host: The host where the share server will be migrated to.
|
||||
"""
|
||||
return False
|
||||
|
|
|
@ -492,7 +492,8 @@ class ContainerShareDriver(driver.ShareDriver, driver.ExecuteMixin):
|
|||
new_share_network, shares_request_spec)
|
||||
|
||||
def share_server_migration_start(self, context, src_share_server,
|
||||
dest_share_server, shares, snapshots):
|
||||
dest_share_server, shares, snapshots,
|
||||
cleanup_source_server):
|
||||
"""Is called to perform 1st phase of migration of a share server."""
|
||||
LOG.debug(
|
||||
"Migration of share server with ID '%s' has been started.",
|
||||
|
|
|
@ -278,7 +278,8 @@ class LVMHelper(driver.ExecuteMixin):
|
|||
}
|
||||
|
||||
def share_server_migration_start(self, context, src_share_server,
|
||||
dest_share_server, shares, snapshots):
|
||||
dest_share_server, shares, snapshots,
|
||||
cleanup_source_server=False):
|
||||
"""Is called to perform 1st phase of migration of a share server."""
|
||||
|
||||
# NOTE(felipe_rodrigues): Since they are in the same volume group,
|
||||
|
|
|
@ -299,7 +299,8 @@ class NetAppCmodeMultiSvmShareDriver(driver.ShareDriver):
|
|||
new_share_network, shares_request_spec)
|
||||
|
||||
def share_server_migration_start(self, context, src_share_server,
|
||||
dest_share_server, shares, snapshots):
|
||||
dest_share_server, shares, snapshots,
|
||||
cleanup_source_server=False):
|
||||
self.library.share_server_migration_start(
|
||||
context, src_share_server, dest_share_server, shares, snapshots)
|
||||
|
||||
|
|
|
@ -285,7 +285,8 @@ class NetAppCmodeSingleSvmShareDriver(driver.ShareDriver):
|
|||
return self.library.get_share_status(share_instance, share_server)
|
||||
|
||||
def share_server_migration_start(self, context, src_share_server,
|
||||
dest_share_server, shares, snapshots):
|
||||
dest_share_server, shares, snapshots,
|
||||
cleanup_source_server=False):
|
||||
raise NotImplementedError
|
||||
|
||||
def share_server_migration_continue(self, context, src_share_server,
|
||||
|
|
|
@ -830,6 +830,8 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||
# request can use this metadata to take actions.
|
||||
server_metadata['migration_destination'] = True
|
||||
server_metadata['request_host'] = destination_host
|
||||
server_metadata['source_share_server'] = (
|
||||
source_share_server)
|
||||
destination_share_server = (
|
||||
self._create_share_server_in_backend(
|
||||
context, destination_share_server,
|
||||
|
@ -3957,13 +3959,14 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||
|
||||
def _form_server_setup_info(self, context, share_server, share_network,
|
||||
share_network_subnet):
|
||||
share_server_id = share_server['id']
|
||||
# Network info is used by driver for setting up share server
|
||||
# and getting server info on share creation.
|
||||
network_allocations = self.db.network_allocations_get_for_share_server(
|
||||
context, share_server['id'], label='user')
|
||||
context, share_server_id, label='user')
|
||||
admin_network_allocations = (
|
||||
self.db.network_allocations_get_for_share_server(
|
||||
context, share_server['id'], label='admin'))
|
||||
context, share_server_id, label='admin'))
|
||||
# NOTE(vponomaryov): following network_info fields are deprecated:
|
||||
# 'segmentation_id', 'cidr' and 'network_type'.
|
||||
# And they should be used from network allocations directly.
|
||||
|
@ -3982,22 +3985,78 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||
}
|
||||
return network_info
|
||||
|
||||
def _get_setup_server_info_for_share_server_migration(
|
||||
self, share_server, source_share_server):
|
||||
"""Gets info to be used during the share server setup for migration"""
|
||||
|
||||
# Whether the share server migration mechanism is capable of reusing
|
||||
# the same network allocations
|
||||
driver_can_reuse_source_server_allocations_in_migration = (
|
||||
self.driver.is_ip_reusage_supported_on_server_migration(
|
||||
share_server['host'], source_share_server['host']
|
||||
))
|
||||
share_network_subnet_id = share_server['share_network_subnet']['id']
|
||||
|
||||
source_subnet_is_equal_to_dest = (
|
||||
source_share_server['share_network_subnet_id'] ==
|
||||
share_network_subnet_id)
|
||||
|
||||
# NOTE(carloss): Need to check if it is possible to reuse the network
|
||||
# allocation. The driver being able to reuse the allocation in a
|
||||
# migration scenario does not mean that it will in fact be reused. If
|
||||
# a new share network was provided, there is no way to reuse the
|
||||
# allocation.
|
||||
can_reuse_network_allocations = (
|
||||
driver_can_reuse_source_server_allocations_in_migration
|
||||
and source_subnet_is_equal_to_dest)
|
||||
|
||||
need_new_network_allocations = can_reuse_network_allocations is False
|
||||
|
||||
# Whether the migration will be able to reuse the share server or not
|
||||
migration_can_reuse_server = (
|
||||
self.driver.server_migration_mechanism_can_reuse_share_server(
|
||||
source_share_server['host'], share_server['host']))
|
||||
|
||||
return need_new_network_allocations, migration_can_reuse_server
|
||||
|
||||
def _setup_server(self, context, share_server, metadata):
|
||||
try:
|
||||
share_network_subnet = share_server['share_network_subnet']
|
||||
share_network_subnet_id = share_network_subnet['id']
|
||||
share_network_id = share_network_subnet['share_network_id']
|
||||
need_new_network_allocation = True
|
||||
setup_server_in_backend = True
|
||||
share_network = self.db.share_network_get(
|
||||
context, share_network_id)
|
||||
self.driver.allocate_network(context, share_server, share_network,
|
||||
share_network_subnet)
|
||||
self.driver.allocate_admin_network(context, share_server)
|
||||
is_migrating = metadata.get('migration_destination')
|
||||
share_server_to_get_network_info = share_server
|
||||
if is_migrating:
|
||||
source_share_server = metadata.get('source_share_server')
|
||||
need_new_network_allocation, migration_can_reuse_server = (
|
||||
self._get_setup_server_info_for_share_server_migration(
|
||||
share_server, source_share_server))
|
||||
setup_server_in_backend = not migration_can_reuse_server
|
||||
|
||||
if not need_new_network_allocation:
|
||||
share_server_to_get_network_info = source_share_server
|
||||
|
||||
# NOTE(carloss): In case the share driver supports reusing the
|
||||
# network allocations in a migration scenario, we will keep these
|
||||
# allocations only related to the source share server, and when the
|
||||
# migration-complete command is triggered, we switch the
|
||||
# allocations belonging to the source share server and make them
|
||||
# related to the destination share server.
|
||||
if need_new_network_allocation:
|
||||
self.driver.allocate_network(
|
||||
context, share_server, share_network, share_network_subnet)
|
||||
self.driver.allocate_admin_network(context, share_server)
|
||||
|
||||
# Get share_network_subnet in case it was updated.
|
||||
share_network_subnet = self.db.share_network_subnet_get(
|
||||
context, share_network_subnet_id)
|
||||
network_info = self._form_server_setup_info(
|
||||
context, share_server, share_network, share_network_subnet)
|
||||
context, share_server_to_get_network_info, share_network,
|
||||
share_network_subnet)
|
||||
self._validate_segmentation_id(network_info)
|
||||
|
||||
# NOTE(vponomaryov): Save security services data to share server
|
||||
|
@ -4020,20 +4079,25 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||
context, share_server['id'],
|
||||
{'security_service_' + ss_type: jsonutils.dumps(data)})
|
||||
|
||||
server_info = self.driver.setup_server(
|
||||
network_info, metadata=metadata)
|
||||
server_info = None
|
||||
if setup_server_in_backend:
|
||||
server_info = self.driver.setup_server(
|
||||
network_info, metadata=metadata)
|
||||
|
||||
self.driver.update_network_allocation(context, share_server)
|
||||
self.driver.update_admin_network_allocation(context, share_server)
|
||||
if need_new_network_allocation:
|
||||
self.driver.update_network_allocation(context, share_server)
|
||||
self.driver.update_admin_network_allocation(
|
||||
context, share_server)
|
||||
|
||||
identifier = share_server['id']
|
||||
if server_info and isinstance(server_info, dict):
|
||||
self.db.share_server_backend_details_set(
|
||||
context, share_server['id'], server_info)
|
||||
identifier = server_info.get('identifier', share_server['id'])
|
||||
return self.db.share_server_update(
|
||||
context, share_server['id'],
|
||||
{'status': constants.STATUS_ACTIVE,
|
||||
'identifier': server_info.get(
|
||||
'identifier', share_server['id'])})
|
||||
'identifier': identifier})
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
details = getattr(e, "detail_data", {})
|
||||
|
@ -4072,7 +4136,8 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||
self.db.share_server_update(
|
||||
context, share_server['id'],
|
||||
{'status': constants.STATUS_ERROR})
|
||||
self.driver.deallocate_network(context, share_server['id'])
|
||||
if need_new_network_allocation:
|
||||
self.driver.deallocate_network(context, share_server['id'])
|
||||
|
||||
def _validate_segmentation_id(self, network_info):
|
||||
"""Raises exception if the segmentation type is incorrect."""
|
||||
|
@ -4964,7 +5029,8 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||
|
||||
def _share_server_migration_start_driver(
|
||||
self, context, source_share_server, dest_host, writable,
|
||||
nondisruptive, preserve_snapshots, new_share_network_id):
|
||||
nondisruptive, preserve_snapshots, new_share_network_id,
|
||||
cleanup_source_server):
|
||||
|
||||
share_instances = self.db.share_instances_get_all_by_share_server(
|
||||
context, source_share_server['id'], with_share_data=True)
|
||||
|
@ -5036,9 +5102,15 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||
{'task_state': (
|
||||
constants.TASK_STATE_MIGRATION_DRIVER_STARTING)})
|
||||
|
||||
self.driver.share_server_migration_start(
|
||||
server_info = self.driver.share_server_migration_start(
|
||||
context, source_share_server, dest_share_server,
|
||||
share_instances, snapshot_instances)
|
||||
share_instances, snapshot_instances, cleanup_source_server)
|
||||
|
||||
backend_details = (
|
||||
server_info.get('backend_details') if server_info else None)
|
||||
if backend_details:
|
||||
self.db.share_server_backend_details_set(
|
||||
context, dest_share_server['id'], backend_details)
|
||||
|
||||
self.db.share_server_update(
|
||||
context, source_share_server['id'],
|
||||
|
@ -5147,7 +5219,8 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||
@utils.require_driver_initialized
|
||||
def share_server_migration_start(
|
||||
self, context, share_server_id, dest_host, writable,
|
||||
nondisruptive, preserve_snapshots, new_share_network_id=None):
|
||||
nondisruptive, preserve_snapshots, new_share_network_id=None,
|
||||
cleanup_source_server=False):
|
||||
"""Migrates a share server from current host to another host."""
|
||||
LOG.debug("Entered share_server_migration_start method for share "
|
||||
"server %s.", share_server_id)
|
||||
|
@ -5166,7 +5239,8 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||
|
||||
self._share_server_migration_start_driver(
|
||||
context, share_server, dest_host, writable, nondisruptive,
|
||||
preserve_snapshots, new_share_network_id)
|
||||
preserve_snapshots, new_share_network_id, cleanup_source_server
|
||||
)
|
||||
except Exception:
|
||||
LOG.exception(
|
||||
("The driver could not migrate the share server "
|
||||
|
@ -5374,13 +5448,42 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||
dest_sn = self.db.share_network_get(context, dest_sn_id)
|
||||
dest_sns = self.db.share_network_subnet_get(context, dest_sns_id)
|
||||
|
||||
need_new_network_allocations, __ = (
|
||||
self._get_setup_server_info_for_share_server_migration(
|
||||
dest_share_server, source_share_server))
|
||||
|
||||
server_to_get_allocations = (
|
||||
dest_share_server
|
||||
if need_new_network_allocations else source_share_server)
|
||||
|
||||
new_network_allocations = self._form_server_setup_info(
|
||||
context, dest_share_server, dest_sn, dest_sns)
|
||||
context, server_to_get_allocations, dest_sn, dest_sns)
|
||||
|
||||
model_update = self.driver.share_server_migration_complete(
|
||||
context, source_share_server, dest_share_server, share_instances,
|
||||
snapshot_instances, new_network_allocations)
|
||||
|
||||
if not need_new_network_allocations:
|
||||
all_allocations = [
|
||||
new_network_allocations['network_allocations'],
|
||||
new_network_allocations['admin_network_allocations']
|
||||
]
|
||||
for allocations in all_allocations:
|
||||
for allocation in allocations:
|
||||
allocation_id = allocation['id']
|
||||
values = {
|
||||
'share_server_id': dest_share_server['id']
|
||||
}
|
||||
self.db.network_allocation_update(
|
||||
context, allocation_id, values)
|
||||
if (self.driver.server_migration_mechanism_can_reuse_share_server(
|
||||
source_share_server['host'], dest_share_server['host'])):
|
||||
source_backend_details = source_share_server.get("backend_details")
|
||||
if source_backend_details:
|
||||
for k, v in source_backend_details.items():
|
||||
self.db.share_server_backend_details_set(
|
||||
context, dest_share_server['id'], {k: v})
|
||||
|
||||
host_value = share_utils.extract_host(dest_share_server['host'])
|
||||
service = self.db.service_get_by_args(
|
||||
context, host_value, 'manila-share')
|
||||
|
|
|
@ -186,7 +186,8 @@ class ShareAPI(object):
|
|||
|
||||
def share_server_migration_start(self, context, share_server, dest_host,
|
||||
writable, nondisruptive,
|
||||
preserve_snapshots, new_share_network_id):
|
||||
preserve_snapshots, new_share_network_id,
|
||||
cleanup_source_server):
|
||||
host = utils.extract_host(dest_host)
|
||||
call_context = self.client.prepare(server=host, version='1.21')
|
||||
call_context.cast(
|
||||
|
@ -197,7 +198,8 @@ class ShareAPI(object):
|
|||
writable=writable,
|
||||
nondisruptive=nondisruptive,
|
||||
preserve_snapshots=preserve_snapshots,
|
||||
new_share_network_id=new_share_network_id)
|
||||
new_share_network_id=new_share_network_id,
|
||||
cleanup_source_server=cleanup_source_server)
|
||||
|
||||
def share_server_migration_check(self, context, share_server_id, dest_host,
|
||||
writable, nondisruptive,
|
||||
|
|
|
@ -19,6 +19,7 @@ import ddt
|
|||
import webob
|
||||
|
||||
from manila.api import common
|
||||
from manila.api.openstack import api_version_request
|
||||
from manila.api.v2 import share_servers
|
||||
from manila.common import constants
|
||||
from manila import context as ctx_api
|
||||
|
@ -532,20 +533,52 @@ class ShareServerControllerTest(test.TestCase):
|
|||
context, network_subnet['share_network_id'])
|
||||
is_active_mock.assert_called_once_with(share_network)
|
||||
|
||||
def _get_server_migration_request(self, server_id):
|
||||
def _get_server_migration_request(self, server_id, version='2.57'):
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/share-servers/%s/action' % server_id,
|
||||
use_admin_context=True, version='2.57')
|
||||
use_admin_context=True, version=version)
|
||||
req.method = 'POST'
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.api_version_request.experimental = True
|
||||
return req
|
||||
|
||||
def test_share_server_migration_start(self):
|
||||
@ddt.data('2.57', '2.63', '2.64')
|
||||
def test_share_server_migration_start(self, version):
|
||||
server = db_utils.create_share_server(id='fake_server_id',
|
||||
status=constants.STATUS_ACTIVE)
|
||||
req = self._get_server_migration_request(server['id'], version=version)
|
||||
|
||||
mock__share_server_migration_start = self.mock_object(
|
||||
self.controller, '_share_server_migration_start')
|
||||
|
||||
body = {
|
||||
'migration_start': {
|
||||
'host': 'fake_host',
|
||||
'preserve_snapshots': True,
|
||||
'writable': True,
|
||||
'nondisruptive': True,
|
||||
'new_share_network_id': 'fake_net_id'
|
||||
}
|
||||
}
|
||||
|
||||
self.controller.share_server_migration_start(req, server['id'], body)
|
||||
|
||||
if (req.api_version_request ==
|
||||
api_version_request.APIVersionRequest('2.64')):
|
||||
mock__share_server_migration_start.assert_called_once_with(
|
||||
req, server['id'], body,
|
||||
cleanup_source_server=False)
|
||||
else:
|
||||
mock__share_server_migration_start.assert_called_once_with(
|
||||
req, server['id'], body)
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test__share_server_migration_start(self, cleanup_source_server):
|
||||
server = db_utils.create_share_server(id='fake_server_id',
|
||||
status=constants.STATUS_ACTIVE)
|
||||
share_network = db_utils.create_share_network()
|
||||
req = self._get_server_migration_request(server['id'])
|
||||
version = '2.64' if cleanup_source_server else '2.57'
|
||||
req = self._get_server_migration_request(server['id'], version=version)
|
||||
context = req.environ['manila.context']
|
||||
|
||||
self.mock_object(db_api, 'share_network_get', mock.Mock(
|
||||
|
@ -563,16 +596,20 @@ class ShareServerControllerTest(test.TestCase):
|
|||
'writable': True,
|
||||
'nondisruptive': True,
|
||||
'new_share_network_id': 'fake_net_id',
|
||||
'cleanup_source_server': cleanup_source_server
|
||||
}
|
||||
}
|
||||
|
||||
self.controller.share_server_migration_start(req, server['id'], body)
|
||||
self.controller._share_server_migration_start(
|
||||
req, server['id'], body,
|
||||
cleanup_source_server=cleanup_source_server)
|
||||
|
||||
db_api.share_server_get.assert_called_once_with(
|
||||
context, server['id'])
|
||||
share_api.API.share_server_migration_start.assert_called_once_with(
|
||||
context, server, 'fake_host', True, True, True,
|
||||
new_share_network=share_network)
|
||||
new_share_network=share_network,
|
||||
cleanup_source_server=cleanup_source_server)
|
||||
db_api.share_network_get.assert_called_once_with(
|
||||
context, 'fake_net_id')
|
||||
common.check_share_network_is_active.assert_called_once_with(
|
||||
|
@ -583,8 +620,8 @@ class ShareServerControllerTest(test.TestCase):
|
|||
{'api_exception': exception.InvalidShareServer(reason=""),
|
||||
'expected_exception': webob.exc.HTTPConflict})
|
||||
@ddt.unpack
|
||||
def test_share_server_migration_start_conflict(self, api_exception,
|
||||
expected_exception):
|
||||
def test__share_server_migration_start_conflict(self, api_exception,
|
||||
expected_exception):
|
||||
share_network = db_utils.create_share_network()
|
||||
share_network_subnet = db_utils.create_share_network_subnet(
|
||||
share_network_id=share_network['id'])
|
||||
|
@ -598,7 +635,7 @@ class ShareServerControllerTest(test.TestCase):
|
|||
'host': 'fake_host',
|
||||
'preserve_snapshots': True,
|
||||
'writable': True,
|
||||
'nondisruptive': True,
|
||||
'nondisruptive': True
|
||||
}
|
||||
}
|
||||
self.mock_object(share_api.API, 'share_server_migration_start',
|
||||
|
@ -611,7 +648,7 @@ class ShareServerControllerTest(test.TestCase):
|
|||
mock.Mock(return_value=share_network))
|
||||
|
||||
self.assertRaises(expected_exception,
|
||||
self.controller.share_server_migration_start,
|
||||
self.controller._share_server_migration_start,
|
||||
req, server['id'], body)
|
||||
|
||||
db_api.share_server_get.assert_called_once_with(context,
|
||||
|
@ -626,10 +663,11 @@ class ShareServerControllerTest(test.TestCase):
|
|||
migration_start_params['writable'],
|
||||
migration_start_params['nondisruptive'],
|
||||
migration_start_params['preserve_snapshots'],
|
||||
cleanup_source_server=False,
|
||||
new_share_network=None)
|
||||
|
||||
@ddt.data('host', 'body')
|
||||
def test_share_server_migration_start_missing_mandatory(self, param):
|
||||
def test__share_server_migration_start_missing_mandatory(self, param):
|
||||
server = db_utils.create_share_server(
|
||||
id='fake_server_id', status=constants.STATUS_ACTIVE)
|
||||
req = self._get_server_migration_request(server['id'])
|
||||
|
@ -641,7 +679,7 @@ class ShareServerControllerTest(test.TestCase):
|
|||
'preserve_metadata': True,
|
||||
'preserve_snapshots': True,
|
||||
'writable': True,
|
||||
'nondisruptive': True,
|
||||
'nondisruptive': True
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -650,20 +688,20 @@ class ShareServerControllerTest(test.TestCase):
|
|||
else:
|
||||
body['migration_start'].pop(param)
|
||||
|
||||
method = 'share_server_migration_start'
|
||||
|
||||
self.mock_object(share_api.API, method)
|
||||
self.mock_object(share_api.API, 'share_server_migration_start')
|
||||
self.mock_object(db_api, 'share_server_get',
|
||||
mock.Mock(return_value=server))
|
||||
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
getattr(self.controller, method),
|
||||
req, server['id'], body)
|
||||
self.assertRaises(
|
||||
webob.exc.HTTPBadRequest,
|
||||
getattr(self.controller, '_share_server_migration_start'),
|
||||
req, server['id'], body)
|
||||
|
||||
db_api.share_server_get.assert_called_once_with(context,
|
||||
server['id'])
|
||||
|
||||
@ddt.data('nondisruptive', 'writable', 'preserve_snapshots')
|
||||
def test_share_server_migration_start_non_boolean(self, param):
|
||||
def test__share_server_migration_start_non_boolean(self, param):
|
||||
server = db_utils.create_share_server(
|
||||
id='fake_server_id', status=constants.STATUS_ACTIVE)
|
||||
req = self._get_server_migration_request(server['id'])
|
||||
|
@ -674,25 +712,25 @@ class ShareServerControllerTest(test.TestCase):
|
|||
'host': 'fake_host',
|
||||
'preserve_snapshots': True,
|
||||
'writable': True,
|
||||
'nondisruptive': True,
|
||||
'nondisruptive': True
|
||||
}
|
||||
}
|
||||
|
||||
body['migration_start'][param] = None
|
||||
|
||||
method = 'share_server_migration_start'
|
||||
|
||||
self.mock_object(share_api.API, method)
|
||||
self.mock_object(share_api.API, 'share_server_migration_start')
|
||||
self.mock_object(db_api, 'share_server_get',
|
||||
mock.Mock(return_value=server))
|
||||
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
getattr(self.controller, method),
|
||||
req, server['id'], body)
|
||||
self.assertRaises(
|
||||
webob.exc.HTTPBadRequest,
|
||||
getattr(self.controller, '_share_server_migration_start'),
|
||||
req, server['id'], body)
|
||||
|
||||
db_api.share_server_get.assert_called_once_with(context,
|
||||
server['id'])
|
||||
|
||||
def test_share_server_migration_start_share_server_not_found(self):
|
||||
def test__share_server_migration_start_share_server_not_found(self):
|
||||
fake_id = 'fake_server_id'
|
||||
req = self._get_server_migration_request(fake_id)
|
||||
context = req.environ['manila.context']
|
||||
|
@ -704,12 +742,12 @@ class ShareServerControllerTest(test.TestCase):
|
|||
share_server_id=fake_id)))
|
||||
|
||||
self.assertRaises(webob.exc.HTTPNotFound,
|
||||
self.controller.share_server_migration_start,
|
||||
self.controller._share_server_migration_start,
|
||||
req, fake_id, body)
|
||||
db_api.share_server_get.assert_called_once_with(context,
|
||||
fake_id)
|
||||
|
||||
def test_share_server_migration_start_new_share_network_not_found(self):
|
||||
def test__share_server_migration_start_new_share_network_not_found(self):
|
||||
server = db_utils.create_share_server(
|
||||
id='fake_server_id', status=constants.STATUS_ACTIVE)
|
||||
req = self._get_server_migration_request(server['id'])
|
||||
|
@ -730,14 +768,14 @@ class ShareServerControllerTest(test.TestCase):
|
|||
mock.Mock(return_value=server))
|
||||
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self.controller.share_server_migration_start,
|
||||
self.controller._share_server_migration_start,
|
||||
req, server['id'], body)
|
||||
db_api.share_network_get.assert_called_once_with(context,
|
||||
'nonexistent')
|
||||
db_api.share_server_get.assert_called_once_with(context,
|
||||
server['id'])
|
||||
|
||||
def test_share_server_migration_start_host_with_pool(self):
|
||||
def test__share_server_migration_start_host_with_pool(self):
|
||||
server = db_utils.create_share_server(id='fake_server_id',
|
||||
status=constants.STATUS_ACTIVE)
|
||||
req = self._get_server_migration_request(server['id'])
|
||||
|
@ -753,7 +791,7 @@ class ShareServerControllerTest(test.TestCase):
|
|||
}
|
||||
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self.controller.share_server_migration_start,
|
||||
self.controller._share_server_migration_start,
|
||||
req, server['id'], body)
|
||||
|
||||
def test_share_server_migration_check_host_with_pool(self):
|
||||
|
|
|
@ -716,7 +716,8 @@ class DummyDriver(driver.ShareDriver):
|
|||
|
||||
@slow_me_down
|
||||
def share_server_migration_start(self, context, src_share_server,
|
||||
dest_share_server, shares, snapshots):
|
||||
dest_share_server, shares, snapshots,
|
||||
cleanup_source_server=False):
|
||||
"""Is called to perform 1st phase of migration of a share server."""
|
||||
LOG.debug(
|
||||
"Migration of dummy share server with ID '%s' has been started.",
|
||||
|
|
|
@ -5263,6 +5263,7 @@ class ShareAPITestCase(test.TestCase):
|
|||
writable = True
|
||||
nondisruptive = True
|
||||
preserve_snapshots = True
|
||||
cleanup_source_server = False
|
||||
fake_share_network = db_api.share_network_get(
|
||||
self.context, fake_share_network['id'])
|
||||
fake_host = 'test@fake'
|
||||
|
@ -5300,7 +5301,8 @@ class ShareAPITestCase(test.TestCase):
|
|||
self.context, fake_share_server, fake_host, fake_share_network)
|
||||
mock_migration_start.assert_called_once_with(
|
||||
self.context, fake_share_server, fake_host, writable,
|
||||
nondisruptive, preserve_snapshots, fake_share_network['id']
|
||||
nondisruptive, preserve_snapshots, fake_share_network['id'],
|
||||
cleanup_source_server
|
||||
)
|
||||
mock_server_update.assert_called_once_with(
|
||||
self.context, fake_share_server['id'], server_expected_update)
|
||||
|
|
|
@ -587,7 +587,7 @@ class ShareDriverTestCase(test.TestCase):
|
|||
|
||||
self.assertRaises(NotImplementedError,
|
||||
share_driver.share_server_migration_start,
|
||||
None, None, None, None, None)
|
||||
None, None, None, None, None, None)
|
||||
|
||||
def test_share_server_migration_continue(self):
|
||||
driver.CONF.set_default('driver_handles_share_servers', True)
|
||||
|
@ -1343,3 +1343,21 @@ class ShareDriverTestCase(test.TestCase):
|
|||
self.assertEqual(expected['ipv4'], result['ipv4_support'])
|
||||
self.assertIsNotNone(result['ipv6_support'])
|
||||
self.assertEqual(expected['ipv6'], result['ipv6_support'])
|
||||
|
||||
def test_is_ip_reusage_supported_on_server_migration(self):
|
||||
share_driver = self._instantiate_share_driver(None, False)
|
||||
result = share_driver.is_ip_reusage_supported_on_server_migration(
|
||||
'source_host', 'dest_host'
|
||||
)
|
||||
|
||||
self.assertEqual(result, False)
|
||||
|
||||
def test_server_migration_mechanism_can_reuse_share_server(self):
|
||||
share_driver = self._instantiate_share_driver(None, False)
|
||||
result = (
|
||||
share_driver.server_migration_mechanism_can_reuse_share_server(
|
||||
'source_host', 'dest_host'
|
||||
)
|
||||
)
|
||||
|
||||
self.assertEqual(result, False)
|
||||
|
|
|
@ -2832,7 +2832,8 @@ class ShareManagerTestCase(test.TestCase):
|
|||
}
|
||||
fake_metadata = {
|
||||
'migration_destination': True,
|
||||
'request_host': fake_data['fake_dest_host']
|
||||
'request_host': fake_data['fake_dest_host'],
|
||||
'source_share_server': fake_data['source_share_server']
|
||||
}
|
||||
|
||||
mock_subnet_get = self.mock_object(
|
||||
|
@ -3431,9 +3432,129 @@ class ShareManagerTestCase(test.TestCase):
|
|||
delete_all_rules=True, share_server=share_srv)
|
||||
self.assertTrue(manager.LOG.warning.called)
|
||||
|
||||
def test_setup_server(self):
|
||||
@ddt.data(
|
||||
{
|
||||
'same_subnet': False,
|
||||
'can_reuse_ip': False,
|
||||
'can_reuse_share_server': False
|
||||
},
|
||||
{
|
||||
'same_subnet': False,
|
||||
'can_reuse_ip': False,
|
||||
'can_reuse_share_server': True
|
||||
},
|
||||
{
|
||||
'same_subnet': False,
|
||||
'can_reuse_ip': True,
|
||||
'can_reuse_share_server': False
|
||||
},
|
||||
{
|
||||
'same_subnet': False,
|
||||
'can_reuse_ip': True,
|
||||
'can_reuse_share_server': True
|
||||
},
|
||||
{
|
||||
'same_subnet': True,
|
||||
'can_reuse_ip': False,
|
||||
'can_reuse_share_server': False
|
||||
},
|
||||
{
|
||||
'same_subnet': True,
|
||||
'can_reuse_ip': False,
|
||||
'can_reuse_share_server': True
|
||||
},
|
||||
{
|
||||
'same_subnet': True,
|
||||
'can_reuse_ip': True,
|
||||
'can_reuse_share_server': False
|
||||
},
|
||||
{
|
||||
'same_subnet': True,
|
||||
'can_reuse_ip': True,
|
||||
'can_reuse_share_server': True
|
||||
}
|
||||
)
|
||||
@ddt.unpack
|
||||
def test__get_setup_server_info_for_share_server_migration(
|
||||
self, same_subnet, can_reuse_ip, can_reuse_share_server):
|
||||
share_server = {
|
||||
'host': 'fake_host',
|
||||
'share_network_subnet': {
|
||||
'id': 'fake_id' if same_subnet else 'different_fake_id'
|
||||
}
|
||||
}
|
||||
source_share_server = {
|
||||
'host': 'fake_source_host',
|
||||
'share_network_subnet_id': 'fake_id'
|
||||
}
|
||||
|
||||
can_reuse_network_allocations = can_reuse_ip and same_subnet
|
||||
network_allocations_result = can_reuse_network_allocations is False
|
||||
|
||||
self.share_manager.driver = mock.Mock()
|
||||
mock_ip_reusage = self.mock_object(
|
||||
self.share_manager.driver,
|
||||
'is_ip_reusage_supported_on_server_migration',
|
||||
mock.Mock(return_value=can_reuse_ip))
|
||||
mock_share_server_reusage = self.mock_object(
|
||||
self.share_manager.driver,
|
||||
'server_migration_mechanism_can_reuse_share_server',
|
||||
mock.Mock(return_value=can_reuse_share_server))
|
||||
|
||||
(need_new_network_allocations, migration_can_reuse_server) = (
|
||||
self.share_manager.
|
||||
_get_setup_server_info_for_share_server_migration(
|
||||
share_server, source_share_server)
|
||||
)
|
||||
|
||||
mock_ip_reusage.assert_called_once_with(share_server['host'],
|
||||
source_share_server['host'])
|
||||
mock_share_server_reusage.assert_called_once_with(
|
||||
source_share_server['host'], share_server['host'])
|
||||
self.assertEqual(need_new_network_allocations,
|
||||
network_allocations_result)
|
||||
self.assertEqual(migration_can_reuse_server, can_reuse_share_server)
|
||||
|
||||
@ddt.data(
|
||||
{
|
||||
'migration_destination': None,
|
||||
'need_new_network_allocation': True,
|
||||
'setup_server_in_backend': True
|
||||
},
|
||||
{
|
||||
'migration_destination': 'fake-destination',
|
||||
'need_new_network_allocation': False,
|
||||
'setup_server_in_backend': False
|
||||
},
|
||||
{
|
||||
'migration_destination': 'fake-destination',
|
||||
'need_new_network_allocation': False,
|
||||
'setup_server_in_backend': True
|
||||
},
|
||||
{
|
||||
'migration_destination': 'fake-destination',
|
||||
'need_new_network_allocation': True,
|
||||
'setup_server_in_backend': False
|
||||
},
|
||||
{
|
||||
'migration_destination': 'fake-destination',
|
||||
'need_new_network_allocation': True,
|
||||
'setup_server_in_backend': True
|
||||
})
|
||||
@ddt.unpack
|
||||
def test__setup_server(self, migration_destination,
|
||||
need_new_network_allocation,
|
||||
setup_server_in_backend):
|
||||
# Setup required test data
|
||||
metadata = {'fake_metadata_key': 'fake_metadata_value'}
|
||||
source_share_server = {
|
||||
'host': 'fake_source_host',
|
||||
'share_network_subnet_id': 'fake_id'
|
||||
}
|
||||
metadata = {
|
||||
'fake_metadata_key': 'fake_metadata_value',
|
||||
'migration_destination': migration_destination,
|
||||
'source_share_server': source_share_server
|
||||
}
|
||||
share_network = db_utils.create_share_network(id='fake_sn_id')
|
||||
share_net_subnet = db_utils.create_share_network_subnet(
|
||||
id='fake_sns_id', share_network_id=share_network['id']
|
||||
|
@ -3457,18 +3578,27 @@ class ShareManagerTestCase(test.TestCase):
|
|||
network_info['network_type'] = 'fake_network_type'
|
||||
|
||||
# mock required stuff
|
||||
self.mock_object(self.share_manager.db, 'share_network_subnet_get',
|
||||
mock.Mock(return_value=share_net_subnet))
|
||||
self.mock_object(self.share_manager.db, 'share_network_get',
|
||||
mock.Mock(return_value=share_network))
|
||||
self.mock_object(self.share_manager,
|
||||
'_get_setup_server_info_for_share_server_migration',
|
||||
mock.Mock(return_value=(need_new_network_allocation,
|
||||
not setup_server_in_backend)))
|
||||
self.mock_object(self.share_manager.driver, 'allocate_network')
|
||||
self.mock_object(self.share_manager.driver, 'allocate_admin_network')
|
||||
self.mock_object(self.share_manager.db, 'share_network_subnet_get',
|
||||
mock.Mock(return_value=share_net_subnet))
|
||||
self.mock_object(self.share_manager, '_form_server_setup_info',
|
||||
mock.Mock(return_value=network_info))
|
||||
self.mock_object(self.share_manager, '_validate_segmentation_id')
|
||||
self.mock_object(self.share_manager.driver, 'setup_server',
|
||||
mock.Mock(return_value=server_info))
|
||||
self.mock_object(self.share_manager.db,
|
||||
'share_server_backend_details_set')
|
||||
self.mock_object(self.share_manager.driver, 'setup_server',
|
||||
mock.Mock(return_value=server_info))
|
||||
self.mock_object(self.share_manager.driver,
|
||||
'update_network_allocation')
|
||||
self.mock_object(self.share_manager.driver,
|
||||
'update_admin_network_allocation')
|
||||
self.mock_object(self.share_manager.db, 'share_server_update',
|
||||
mock.Mock(return_value=share_server))
|
||||
|
||||
|
@ -3478,45 +3608,92 @@ class ShareManagerTestCase(test.TestCase):
|
|||
|
||||
# verify results
|
||||
self.assertEqual(share_server, result)
|
||||
if migration_destination:
|
||||
(self.share_manager
|
||||
._get_setup_server_info_for_share_server_migration
|
||||
.assert_called_once_with(share_server, source_share_server))
|
||||
|
||||
if need_new_network_allocation:
|
||||
self.share_manager.driver.allocate_network.assert_called_once_with(
|
||||
self.context, share_server, share_network,
|
||||
share_server['share_network_subnet'])
|
||||
(self.share_manager.driver.allocate_admin_network
|
||||
.assert_called_once_with(self.context, share_server))
|
||||
(self.share_manager.driver.update_network_allocation
|
||||
.assert_called_once_with(self.context, share_server))
|
||||
(self.share_manager.driver.update_admin_network_allocation
|
||||
.assert_called_once_with(self.context, share_server))
|
||||
|
||||
if setup_server_in_backend:
|
||||
self.share_manager.driver.setup_server.assert_called_once_with(
|
||||
network_info, metadata=metadata)
|
||||
(self.share_manager.db.share_server_backend_details_set
|
||||
.assert_has_calls([
|
||||
mock.call(self.context, share_server['id'],
|
||||
{'security_service_' + sec_services[0]['type']:
|
||||
jsonutils.dumps(sec_services[0])}),
|
||||
mock.call(self.context, share_server['id'],
|
||||
{'security_service_' + sec_services[1]['type']:
|
||||
jsonutils.dumps(sec_services[1])}),
|
||||
mock.call(self.context, share_server['id'],
|
||||
{'security_service_' + sec_services[2]['type']:
|
||||
jsonutils.dumps(sec_services[2])}),
|
||||
mock.call(self.context, share_server['id'], server_info)
|
||||
]))
|
||||
else:
|
||||
(self.share_manager.db.share_server_backend_details_set
|
||||
.assert_has_calls([
|
||||
mock.call(self.context, share_server['id'],
|
||||
{'security_service_' + sec_services[0]['type']:
|
||||
jsonutils.dumps(sec_services[0])}),
|
||||
mock.call(self.context, share_server['id'],
|
||||
{'security_service_' + sec_services[1]['type']:
|
||||
jsonutils.dumps(sec_services[1])}),
|
||||
mock.call(self.context, share_server['id'],
|
||||
{'security_service_' + sec_services[2]['type']:
|
||||
jsonutils.dumps(sec_services[2])})
|
||||
]))
|
||||
|
||||
if migration_destination and not need_new_network_allocation:
|
||||
self.share_manager._form_server_setup_info.assert_called_once_with(
|
||||
self.context, source_share_server, share_network,
|
||||
share_net_subnet)
|
||||
else:
|
||||
self.share_manager._form_server_setup_info.assert_called_once_with(
|
||||
self.context, share_server, share_network, share_net_subnet)
|
||||
|
||||
self.share_manager.db.share_network_get.assert_called_once_with(
|
||||
self.context, share_net_subnet['share_network_id'])
|
||||
|
||||
self.share_manager.db.share_network_subnet_get.assert_called_once_with(
|
||||
self.context, share_server['share_network_subnet']['id'])
|
||||
self.share_manager.driver.allocate_network.assert_called_once_with(
|
||||
self.context, share_server, share_network,
|
||||
share_server['share_network_subnet'])
|
||||
self.share_manager._form_server_setup_info.assert_called_once_with(
|
||||
self.context, share_server, share_network, share_net_subnet)
|
||||
self.share_manager._validate_segmentation_id.assert_called_once_with(
|
||||
network_info)
|
||||
self.share_manager.driver.setup_server.assert_called_once_with(
|
||||
network_info, metadata=metadata)
|
||||
(self.share_manager.db.share_server_backend_details_set.
|
||||
assert_has_calls([
|
||||
mock.call(self.context, share_server['id'],
|
||||
{'security_service_' + sec_services[0]['type']:
|
||||
jsonutils.dumps(sec_services[0])}),
|
||||
mock.call(self.context, share_server['id'],
|
||||
{'security_service_' + sec_services[1]['type']:
|
||||
jsonutils.dumps(sec_services[1])}),
|
||||
mock.call(self.context, share_server['id'],
|
||||
{'security_service_' + sec_services[2]['type']:
|
||||
jsonutils.dumps(sec_services[2])}),
|
||||
mock.call(self.context, share_server['id'], server_info),
|
||||
]))
|
||||
|
||||
self.share_manager.db.share_server_update.assert_called_once_with(
|
||||
self.context, share_server['id'],
|
||||
{'status': constants.STATUS_ACTIVE,
|
||||
'identifier': share_server['id']})
|
||||
|
||||
def test_setup_server_server_info_not_present(self):
|
||||
@ddt.data(True, False)
|
||||
def test__setup_server_server_info_not_present(self,
|
||||
need_network_allocation):
|
||||
# Setup required test data
|
||||
metadata = {'fake_metadata_key': 'fake_metadata_value'}
|
||||
source_share_server = {
|
||||
'host': 'fake_source_host',
|
||||
'share_network_subnet_id': 'fake_id'
|
||||
}
|
||||
metadata = {
|
||||
'fake_metadata_key': 'fake_metadata_value',
|
||||
'migration_destination': 'fake_detination',
|
||||
'source_share_server': source_share_server
|
||||
}
|
||||
share_network = {'id': 'fake_sn_id'}
|
||||
share_net_subnet = {'id': 'fake_sns_id',
|
||||
'share_network_id': share_network['id']}
|
||||
share_server = {
|
||||
'id': 'fake_id',
|
||||
'host': 'fake_host',
|
||||
'share_network_subnet': share_net_subnet,
|
||||
}
|
||||
network_info = {
|
||||
|
@ -3527,6 +3704,10 @@ class ShareManagerTestCase(test.TestCase):
|
|||
server_info = {}
|
||||
|
||||
# mock required stuff
|
||||
self.mock_object(self.share_manager,
|
||||
'_get_setup_server_info_for_share_server_migration',
|
||||
mock.Mock(
|
||||
return_value=(need_network_allocation, False)))
|
||||
self.mock_object(self.share_manager.db, 'share_network_subnet_get',
|
||||
mock.Mock(return_value=share_net_subnet))
|
||||
self.mock_object(self.share_manager.db, 'share_network_get',
|
||||
|
@ -3538,6 +3719,7 @@ class ShareManagerTestCase(test.TestCase):
|
|||
self.mock_object(self.share_manager.db, 'share_server_update',
|
||||
mock.Mock(return_value=share_server))
|
||||
self.mock_object(self.share_manager.driver, 'allocate_network')
|
||||
self.mock_object(self.share_manager.driver, 'allocate_admin_network')
|
||||
|
||||
# execute method _setup_server
|
||||
result = self.share_manager._setup_server(
|
||||
|
@ -3549,20 +3731,37 @@ class ShareManagerTestCase(test.TestCase):
|
|||
self.context, share_net_subnet['share_network_id'])
|
||||
self.share_manager.db.share_network_subnet_get.assert_called_once_with(
|
||||
self.context, share_server['share_network_subnet']['id'])
|
||||
self.share_manager._form_server_setup_info.assert_called_once_with(
|
||||
self.context, share_server, share_network, share_net_subnet)
|
||||
self.share_manager.driver.setup_server.assert_called_once_with(
|
||||
network_info, metadata=metadata)
|
||||
self.share_manager.db.share_server_update.assert_called_once_with(
|
||||
self.context, share_server['id'],
|
||||
{'status': constants.STATUS_ACTIVE,
|
||||
'identifier': share_server['id']})
|
||||
self.share_manager.driver.allocate_network.assert_called_once_with(
|
||||
self.context, share_server, share_network, share_net_subnet)
|
||||
if need_network_allocation:
|
||||
self.share_manager.driver.allocate_network.assert_called_once_with(
|
||||
self.context, share_server, share_network, share_net_subnet)
|
||||
(self.share_manager.driver.allocate_admin_network
|
||||
.assert_called_once_with(
|
||||
self.context, share_server))
|
||||
self.share_manager._form_server_setup_info.assert_called_once_with(
|
||||
self.context, share_server, share_network, share_net_subnet)
|
||||
else:
|
||||
self.share_manager._form_server_setup_info.assert_called_once_with(
|
||||
self.context, source_share_server, share_network,
|
||||
share_net_subnet)
|
||||
|
||||
def setup_server_raise_exception(self, detail_data_proper):
|
||||
def setup_server_raise_exception(self, detail_data_proper,
|
||||
need_network_allocation):
|
||||
# Setup required test data
|
||||
metadata = {'fake_metadata_key': 'fake_metadata_value'}
|
||||
source_share_server = {
|
||||
'host': 'fake_source_host',
|
||||
'share_network_subnet_id': 'fake_id'
|
||||
}
|
||||
metadata = {
|
||||
'fake_metadata_key': 'fake_metadata_value',
|
||||
'migration_destination': 'fake_detination',
|
||||
'source_share_server': source_share_server
|
||||
}
|
||||
server_info = {'details_key': 'value'}
|
||||
share_network = {'id': 'fake_sn_id'}
|
||||
share_net_subnet = {'id': 'fake_sns_id',
|
||||
|
@ -3584,12 +3783,18 @@ class ShareManagerTestCase(test.TestCase):
|
|||
detail_data = 'not dictionary detail data'
|
||||
|
||||
# Mock required parameters
|
||||
self.mock_object(self.share_manager,
|
||||
'_get_setup_server_info_for_share_server_migration',
|
||||
mock.Mock(
|
||||
return_value=(need_network_allocation, False)))
|
||||
self.mock_object(self.share_manager.db, 'share_network_get',
|
||||
mock.Mock(return_value=share_network))
|
||||
self.mock_object(self.share_manager.db, 'share_network_subnet_get',
|
||||
mock.Mock(return_value=share_net_subnet))
|
||||
self.mock_object(self.share_manager.db, 'share_server_update')
|
||||
for m in ['deallocate_network', 'allocate_network']:
|
||||
methods = ['deallocate_network', 'allocate_network',
|
||||
'allocate_admin_network']
|
||||
for m in methods:
|
||||
self.mock_object(self.share_manager.driver, m)
|
||||
self.mock_object(self.share_manager, '_form_server_setup_info',
|
||||
mock.Mock(return_value=network_info))
|
||||
|
@ -3613,8 +3818,6 @@ class ShareManagerTestCase(test.TestCase):
|
|||
(self.share_manager.db.share_server_backend_details_set.
|
||||
assert_called_once_with(
|
||||
self.context, share_server['id'], server_info))
|
||||
self.share_manager._form_server_setup_info.assert_called_once_with(
|
||||
self.context, share_server, share_network, share_net_subnet)
|
||||
self.share_manager.db.share_server_update.assert_called_once_with(
|
||||
self.context, share_server['id'],
|
||||
{'status': constants.STATUS_ERROR})
|
||||
|
@ -3622,17 +3825,33 @@ class ShareManagerTestCase(test.TestCase):
|
|||
self.context, share_net_subnet['share_network_id'])
|
||||
self.share_manager.db.share_network_subnet_get.assert_called_once_with(
|
||||
self.context, share_server['share_network_subnet']['id'])
|
||||
self.share_manager.driver.allocate_network.assert_has_calls([
|
||||
mock.call(self.context, share_server, share_network,
|
||||
share_net_subnet)])
|
||||
self.share_manager.driver.deallocate_network.assert_has_calls([
|
||||
mock.call(self.context, share_server['id'])])
|
||||
if need_network_allocation:
|
||||
self.share_manager.driver.allocate_network.assert_has_calls([
|
||||
mock.call(self.context, share_server, share_network,
|
||||
share_net_subnet)])
|
||||
self.share_manager.driver.allocate_admin_network.assert_has_calls([
|
||||
mock.call(self.context, share_server)])
|
||||
self.share_manager.driver.deallocate_network.assert_has_calls([
|
||||
mock.call(self.context, share_server['id'])])
|
||||
self.share_manager._form_server_setup_info.assert_called_once_with(
|
||||
self.context, share_server, share_network, share_net_subnet)
|
||||
else:
|
||||
self.share_manager._form_server_setup_info.assert_called_once_with(
|
||||
self.context, source_share_server, share_network,
|
||||
share_net_subnet)
|
||||
|
||||
def test_setup_server_incorrect_detail_data(self):
|
||||
self.setup_server_raise_exception(detail_data_proper=False)
|
||||
@ddt.data(True, False)
|
||||
def test__setup_server_incorrect_detail_data(self,
|
||||
need_network_allocation):
|
||||
self.setup_server_raise_exception(
|
||||
detail_data_proper=False,
|
||||
need_network_allocation=need_network_allocation)
|
||||
|
||||
def test_setup_server_exception_in_driver(self):
|
||||
self.setup_server_raise_exception(detail_data_proper=True)
|
||||
@ddt.data(True, False)
|
||||
def test__setup_server_exception_in_driver(self, need_network_allocation):
|
||||
self.setup_server_raise_exception(
|
||||
detail_data_proper=True,
|
||||
need_network_allocation=need_network_allocation)
|
||||
|
||||
@ddt.data({},
|
||||
{'detail_data': 'fake'},
|
||||
|
@ -3640,7 +3859,7 @@ class ShareManagerTestCase(test.TestCase):
|
|||
{'detail_data': {'server_details': {'fake': 'fake'}}},
|
||||
{'detail_data': {
|
||||
'server_details': {'fake': 'fake', 'fake2': 'fake2'}}},)
|
||||
def test_setup_server_exception_in_cleanup_after_error(self, data):
|
||||
def test__setup_server_exception_in_cleanup_after_error(self, data):
|
||||
|
||||
def get_server_details_from_data(data):
|
||||
d = data.get('detail_data')
|
||||
|
@ -8080,7 +8299,7 @@ class ShareManagerTestCase(test.TestCase):
|
|||
def _setup_server_migration_start_mocks(
|
||||
self, fake_share_instances, fake_snap_instances, fake_old_network,
|
||||
fake_new_network, fake_service, fake_request_spec,
|
||||
fake_driver_result, fake_new_share_server):
|
||||
fake_driver_result, fake_new_share_server, server_info):
|
||||
self.mock_object(db, 'share_instances_get_all_by_share_server',
|
||||
mock.Mock(return_value=fake_share_instances))
|
||||
self.mock_object(db, 'share_snapshot_instance_get_all_with_filters',
|
||||
|
@ -8106,7 +8325,8 @@ class ShareManagerTestCase(test.TestCase):
|
|||
'_cast_access_rules_to_readonly_for_server')
|
||||
self.mock_object(db, 'share_server_update')
|
||||
self.mock_object(self.share_manager.driver,
|
||||
'share_server_migration_start')
|
||||
'share_server_migration_start',
|
||||
mock.Mock(return_value=server_info))
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test__share_server_migration_start_driver(self, writable):
|
||||
|
@ -8127,6 +8347,7 @@ class ShareManagerTestCase(test.TestCase):
|
|||
fake_dest_host = 'fakehost@fakebackend'
|
||||
nondisruptive = False
|
||||
preserve_snapshots = True
|
||||
cleanup_source_server = True
|
||||
fake_driver_result = {
|
||||
'compatible': True,
|
||||
'writable': writable,
|
||||
|
@ -8136,15 +8357,20 @@ class ShareManagerTestCase(test.TestCase):
|
|||
'migration_cancel': False,
|
||||
'migration_get_progress': False
|
||||
}
|
||||
server_info = {
|
||||
'fake_server_info_key': 'fake_server_info_value',
|
||||
'backend_details': {'fake': 'fake'}
|
||||
}
|
||||
|
||||
self._setup_server_migration_start_mocks(
|
||||
fake_share_instances, fake_snap_instances, fake_old_network,
|
||||
fake_new_network, fake_service, fake_request_spec,
|
||||
fake_driver_result, fake_new_share_server)
|
||||
fake_driver_result, fake_new_share_server, server_info)
|
||||
|
||||
result = self.share_manager._share_server_migration_start_driver(
|
||||
self.context, fake_old_share_server, fake_dest_host, writable,
|
||||
nondisruptive, preserve_snapshots, fake_new_network['id']
|
||||
nondisruptive, preserve_snapshots, fake_new_network['id'],
|
||||
cleanup_source_server
|
||||
)
|
||||
|
||||
self.assertTrue(result)
|
||||
|
@ -8183,7 +8409,8 @@ class ShareManagerTestCase(test.TestCase):
|
|||
(self.share_manager.driver.share_server_migration_start.
|
||||
assert_called_once_with(
|
||||
self.context, fake_old_share_server, fake_new_share_server,
|
||||
fake_share_instances, fake_snap_instances))
|
||||
fake_share_instances, fake_snap_instances,
|
||||
cleanup_source_server))
|
||||
if not writable:
|
||||
(self.share_manager._cast_access_rules_to_readonly_for_server.
|
||||
assert_called_once_with(
|
||||
|
@ -8213,6 +8440,7 @@ class ShareManagerTestCase(test.TestCase):
|
|||
nondisruptive = False
|
||||
preserve_snapshots = True
|
||||
writable = True
|
||||
cleanup_source_server = True
|
||||
fake_driver_result = {
|
||||
'compatible': True,
|
||||
'writable': writable,
|
||||
|
@ -8222,11 +8450,15 @@ class ShareManagerTestCase(test.TestCase):
|
|||
'migration_cancel': False,
|
||||
'migration_get_progress': False
|
||||
}
|
||||
server_info = {
|
||||
'fake_server_info_key': 'fake_server_info_value',
|
||||
'backend_details': {'fake': 'fake'}
|
||||
}
|
||||
|
||||
self._setup_server_migration_start_mocks(
|
||||
fake_share_instances, fake_snap_instances, fake_old_network,
|
||||
fake_new_network, fake_service, fake_request_spec,
|
||||
fake_driver_result, fake_new_share_server)
|
||||
fake_driver_result, fake_new_share_server, server_info)
|
||||
mock__reset_read_only = self.mock_object(
|
||||
self.share_manager, '_reset_read_only_access_rules_for_server')
|
||||
|
||||
|
@ -8238,7 +8470,8 @@ class ShareManagerTestCase(test.TestCase):
|
|||
exception.ShareServerMigrationFailed,
|
||||
self.share_manager._share_server_migration_start_driver,
|
||||
self.context, fake_old_share_server, fake_dest_host, writable,
|
||||
nondisruptive, preserve_snapshots, fake_new_network['id']
|
||||
nondisruptive, preserve_snapshots, fake_new_network['id'],
|
||||
cleanup_source_server
|
||||
)
|
||||
|
||||
db.share_instances_get_all_by_share_server.assert_called_once_with(
|
||||
|
@ -8282,7 +8515,8 @@ class ShareManagerTestCase(test.TestCase):
|
|||
(self.share_manager.driver.share_server_migration_start.
|
||||
assert_called_once_with(
|
||||
self.context, fake_old_share_server, fake_new_share_server,
|
||||
fake_share_instances, fake_snap_instances))
|
||||
fake_share_instances, fake_snap_instances,
|
||||
cleanup_source_server))
|
||||
mock__reset_read_only.assert_called_once_with(
|
||||
self.context, fake_share_instances, fake_old_share_server,
|
||||
dest_host=fake_old_share_server['host']
|
||||
|
@ -8416,6 +8650,7 @@ class ShareManagerTestCase(test.TestCase):
|
|||
writable = True
|
||||
nondisruptive = True
|
||||
preserve_snapshots = True
|
||||
cleanup_source_server = True
|
||||
|
||||
mock_server_update = self.mock_object(db, 'share_server_update')
|
||||
mock_server_get = self.mock_object(
|
||||
|
@ -8425,7 +8660,8 @@ class ShareManagerTestCase(test.TestCase):
|
|||
|
||||
self.share_manager.share_server_migration_start(
|
||||
self.context, fake_share_server['id'], fake_dest_host, writable,
|
||||
nondisruptive, preserve_snapshots, fake_share_network['id']
|
||||
nondisruptive, preserve_snapshots, fake_share_network['id'],
|
||||
cleanup_source_server=cleanup_source_server
|
||||
)
|
||||
|
||||
mock_server_update.assert_called_once_with(
|
||||
|
@ -8437,7 +8673,8 @@ class ShareManagerTestCase(test.TestCase):
|
|||
)
|
||||
mock__server_migration_start_driver.assert_called_once_with(
|
||||
self.context, fake_share_server, fake_dest_host, writable,
|
||||
nondisruptive, preserve_snapshots, fake_share_network['id']
|
||||
nondisruptive, preserve_snapshots, fake_share_network['id'],
|
||||
cleanup_source_server
|
||||
)
|
||||
|
||||
@ddt.data(True, False)
|
||||
|
@ -8448,6 +8685,7 @@ class ShareManagerTestCase(test.TestCase):
|
|||
writable = True
|
||||
nondisruptive = True
|
||||
preserve_snapshots = True
|
||||
cleanup_source_server = True
|
||||
self.mock_object(self.share_manager, 'driver')
|
||||
self.share_manager.driver.driver_handles_share_servers = dhss
|
||||
|
||||
|
@ -8460,7 +8698,8 @@ class ShareManagerTestCase(test.TestCase):
|
|||
|
||||
self.share_manager.share_server_migration_start(
|
||||
self.context, fake_share_server['id'], fake_dest_host, writable,
|
||||
nondisruptive, preserve_snapshots, fake_share_network['id']
|
||||
nondisruptive, preserve_snapshots, fake_share_network['id'],
|
||||
cleanup_source_server=cleanup_source_server
|
||||
)
|
||||
|
||||
mock_server_update.assert_has_calls([
|
||||
|
@ -8479,7 +8718,8 @@ class ShareManagerTestCase(test.TestCase):
|
|||
if dhss:
|
||||
mock__server_migration_start_driver.assert_called_once_with(
|
||||
self.context, fake_share_server, fake_dest_host, writable,
|
||||
nondisruptive, preserve_snapshots, fake_share_network['id']
|
||||
nondisruptive, preserve_snapshots, fake_share_network['id'],
|
||||
cleanup_source_server
|
||||
)
|
||||
|
||||
def _setup_migration_continue_mocks(
|
||||
|
@ -8764,14 +9004,35 @@ class ShareManagerTestCase(test.TestCase):
|
|||
'status': constants.STATUS_ACTIVE})
|
||||
|
||||
@ddt.data(
|
||||
{'unmanage_source_server': False,
|
||||
'snapshot_updates': {},
|
||||
'share_updates': {}},
|
||||
{'unmanage_source_server': True,
|
||||
'snapshot_updates': {},
|
||||
'share_updates': {}},
|
||||
{'model_update': {
|
||||
'unmanage_source_server': False,
|
||||
'snapshot_updates': {},
|
||||
'share_updates': {}},
|
||||
'need_network_allocation': False,
|
||||
'can_reuse_server': False},
|
||||
{'model_update': {
|
||||
'unmanage_source_server': True,
|
||||
'snapshot_updates': {},
|
||||
'share_updates': {}},
|
||||
'need_network_allocation': False,
|
||||
'can_reuse_server': True},
|
||||
{'model_update': {
|
||||
'unmanage_source_server': False,
|
||||
'snapshot_updates': {},
|
||||
'share_updates': {}},
|
||||
'need_network_allocation': True,
|
||||
'can_reuse_server': False},
|
||||
{'model_update': {
|
||||
'unmanage_source_server': True,
|
||||
'snapshot_updates': {},
|
||||
'share_updates': {}},
|
||||
'need_network_allocation': True,
|
||||
'can_reuse_server': True}
|
||||
)
|
||||
def test__server_migration_complete_driver(self, model_update):
|
||||
@ddt.unpack
|
||||
def test__server_migration_complete_driver(self, model_update,
|
||||
need_network_allocation,
|
||||
can_reuse_server):
|
||||
fake_share_network = db_utils.create_share_network()
|
||||
fake_share_network_subnet = db_utils.create_share_network_subnet(
|
||||
share_network_id=fake_share_network['id'])
|
||||
|
@ -8785,7 +9046,10 @@ class ShareManagerTestCase(test.TestCase):
|
|||
fake_share_instances = [fake_share['instance']]
|
||||
fake_snapshot_instances = [fake_snapshot['instance']]
|
||||
fake_share_instance_id = fake_share['instance']['id']
|
||||
fake_allocation_data = {}
|
||||
fake_allocation_data = {
|
||||
'network_allocations': [{'id': 'fake_id'}],
|
||||
'admin_network_allocations': [{'id': 'fake_admin_id'}],
|
||||
}
|
||||
model_update['share_updates'][fake_share['instance']['id']] = {
|
||||
'export_locations': {
|
||||
"path": "10.10.10.31:/fake_mount_point",
|
||||
|
@ -8809,19 +9073,40 @@ class ShareManagerTestCase(test.TestCase):
|
|||
'share_network_id': fake_share_network['id'],
|
||||
'availability_zone_id': fake_service['availability_zone_id'],
|
||||
}
|
||||
backend_details = fake_source_share_server.get("backend_details")
|
||||
mock_backend_details_set_calls = []
|
||||
if backend_details:
|
||||
for k, v in backend_details.items():
|
||||
mock_backend_details_set_calls.append(
|
||||
mock.call(
|
||||
self.context, fake_dest_share_server['id'],
|
||||
{k: v})
|
||||
)
|
||||
|
||||
mock_server_update = self.mock_object(db, 'share_server_update')
|
||||
mock_network_get = self.mock_object(
|
||||
db, 'share_network_get', mock.Mock(return_vale=fake_share_network))
|
||||
db, 'share_network_get',
|
||||
mock.Mock(return_value=fake_share_network))
|
||||
mock_subnet_get = self.mock_object(
|
||||
db, 'share_network_subnet_get',
|
||||
mock.Mock(return_value=fake_share_network_subnet))
|
||||
self.mock_object(
|
||||
mock_server_info_share_migration = self.mock_object(
|
||||
self.share_manager,
|
||||
'_get_setup_server_info_for_share_server_migration',
|
||||
mock.Mock(return_value=(need_network_allocation, True)))
|
||||
mock_form_server_setup_info = self.mock_object(
|
||||
self.share_manager, '_form_server_setup_info',
|
||||
mock.Mock(return_value=fake_allocation_data))
|
||||
mock_server_migration_complete = self.mock_object(
|
||||
self.share_manager.driver, 'share_server_migration_complete',
|
||||
mock.Mock(return_value=model_update))
|
||||
mock_network_allocation_update = self.mock_object(
|
||||
db, 'network_allocation_update')
|
||||
self.mock_object(self.share_manager.driver,
|
||||
'server_migration_mechanism_can_reuse_share_server',
|
||||
mock.Mock(return_value=can_reuse_server))
|
||||
mock_share_server_backend_details_set = self.mock_object(
|
||||
db, 'share_server_backend_details_set')
|
||||
mock_service_get_by_args = self.mock_object(
|
||||
db, 'service_get_by_args', mock.Mock(return_value=fake_service))
|
||||
mock_instance_update = self.mock_object(db, 'share_instance_update')
|
||||
|
@ -8854,6 +9139,30 @@ class ShareManagerTestCase(test.TestCase):
|
|||
self.context, fake_share_network['id'])
|
||||
mock_subnet_get.assert_called_once_with(
|
||||
self.context, fake_share_network_subnet['id'])
|
||||
mock_server_info_share_migration.assert_called_once_with(
|
||||
fake_dest_share_server, fake_source_share_server)
|
||||
|
||||
if need_network_allocation:
|
||||
mock_form_server_setup_info.assert_called_once_with(
|
||||
self.context, fake_dest_share_server, fake_share_network,
|
||||
fake_share_network_subnet)
|
||||
elif need_network_allocation and can_reuse_server:
|
||||
mock_share_server_backend_details_set.assert_has_calls(
|
||||
mock_backend_details_set_calls)
|
||||
else:
|
||||
mock_form_server_setup_info.assert_called_once_with(
|
||||
self.context, fake_source_share_server, fake_share_network,
|
||||
fake_share_network_subnet)
|
||||
mock_network_allocation_update.assert_has_calls(
|
||||
[mock.call(
|
||||
self.context,
|
||||
fake_allocation_data['network_allocations'][0]['id'],
|
||||
{'share_server_id': fake_dest_share_server['id']}),
|
||||
mock.call(
|
||||
self.context,
|
||||
fake_allocation_data['admin_network_allocations'][0]['id'],
|
||||
{'share_server_id': fake_dest_share_server['id']})])
|
||||
|
||||
mock_server_migration_complete.assert_called_once_with(
|
||||
self.context, fake_source_share_server, fake_dest_share_server,
|
||||
fake_share_instances, fake_snapshot_instances, fake_allocation_data
|
||||
|
|
|
@ -412,7 +412,8 @@ class ShareRpcAPITestCase(test.TestCase):
|
|||
writable=True,
|
||||
nondisruptive=False,
|
||||
preserve_snapshots=True,
|
||||
new_share_network_id='fake_share_network_id')
|
||||
new_share_network_id='fake_share_network_id',
|
||||
cleanup_source_server=True)
|
||||
|
||||
def test_share_server_migration_check(self):
|
||||
self._test_share_api('share_server_migration_check',
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Added share server migration enhancements. Now is possible to migrate share
|
||||
servers nondisruptively and also allows the user to specify if the source
|
||||
share server will be deleted after the migration ends.
|
Loading…
Reference in New Issue