Merge "Add tests for share server migration"
This commit is contained in:
commit
2e12123d97
|
@ -97,6 +97,7 @@ MIN_SHARE_ACCESS_METADATA_MICROVERSION = '2.45'
|
||||||
|
|
||||||
# Share servers
|
# Share servers
|
||||||
SERVER_STATE_ACTIVE = 'active'
|
SERVER_STATE_ACTIVE = 'active'
|
||||||
|
SERVER_STATE_INACTIVE = 'inactive'
|
||||||
SERVER_STATE_CREATING = 'creating'
|
SERVER_STATE_CREATING = 'creating'
|
||||||
SERVER_STATE_DELETING = 'deleting'
|
SERVER_STATE_DELETING = 'deleting'
|
||||||
SERVER_STATE_ERROR = 'error'
|
SERVER_STATE_ERROR = 'error'
|
||||||
|
@ -104,3 +105,5 @@ SERVER_STATE_MANAGE_ERROR = 'manage_error'
|
||||||
SERVER_STATE_MANAGE_STARTING = 'manage_starting'
|
SERVER_STATE_MANAGE_STARTING = 'manage_starting'
|
||||||
SERVER_STATE_UNMANAGE_ERROR = 'unmanage_error'
|
SERVER_STATE_UNMANAGE_ERROR = 'unmanage_error'
|
||||||
SERVER_STATE_UNMANAGE_STARTING = 'unmanage_starting'
|
SERVER_STATE_UNMANAGE_STARTING = 'unmanage_starting'
|
||||||
|
STATUS_SERVER_MIGRATING = 'server_migrating'
|
||||||
|
STATUS_SERVER_MIGRATING_TO = 'server_migrating_to'
|
||||||
|
|
|
@ -29,7 +29,7 @@ ShareGroup = [
|
||||||
help="The minimum api microversion is configured to be the "
|
help="The minimum api microversion is configured to be the "
|
||||||
"value of the minimum microversion supported by Manila."),
|
"value of the minimum microversion supported by Manila."),
|
||||||
cfg.StrOpt("max_api_microversion",
|
cfg.StrOpt("max_api_microversion",
|
||||||
default="2.56",
|
default="2.57",
|
||||||
help="The maximum api microversion is configured to be the "
|
help="The maximum api microversion is configured to be the "
|
||||||
"value of the latest microversion supported by Manila."),
|
"value of the latest microversion supported by Manila."),
|
||||||
cfg.StrOpt("region",
|
cfg.StrOpt("region",
|
||||||
|
@ -262,6 +262,10 @@ ShareGroup = [
|
||||||
help="Defines whether to run tests that create share from "
|
help="Defines whether to run tests that create share from "
|
||||||
"snapshots in another pool or az. Enable this "
|
"snapshots in another pool or az. Enable this "
|
||||||
"option if the used driver supports it."),
|
"option if the used driver supports it."),
|
||||||
|
cfg.BoolOpt("run_share_servers_migration_tests",
|
||||||
|
default=False,
|
||||||
|
help="Defines whether to run share servers migration tests. "
|
||||||
|
"Enable this option if the used driver supports it."),
|
||||||
|
|
||||||
cfg.StrOpt("image_with_share_tools",
|
cfg.StrOpt("image_with_share_tools",
|
||||||
default="manila-service-image-master",
|
default="manila-service-image-master",
|
||||||
|
@ -279,6 +283,10 @@ ShareGroup = [
|
||||||
default=1500,
|
default=1500,
|
||||||
help="Time to wait for share migration before "
|
help="Time to wait for share migration before "
|
||||||
"timing out (seconds)."),
|
"timing out (seconds)."),
|
||||||
|
cfg.IntOpt("share_server_migration_timeout",
|
||||||
|
default="1500",
|
||||||
|
help="Time to wait for share server migration before "
|
||||||
|
"timing out (seconds)."),
|
||||||
cfg.StrOpt("default_share_type_name",
|
cfg.StrOpt("default_share_type_name",
|
||||||
help="Default share type name to use in tempest tests."),
|
help="Default share type name to use in tempest tests."),
|
||||||
cfg.StrOpt("backend_replication_type",
|
cfg.StrOpt("backend_replication_type",
|
||||||
|
|
|
@ -578,7 +578,7 @@ class SharesV2Client(shares_client.SharesClient):
|
||||||
time.sleep(self.build_interval)
|
time.sleep(self.build_interval)
|
||||||
body = self.get_snapshot(snapshot_id, version=version)
|
body = self.get_snapshot(snapshot_id, version=version)
|
||||||
snapshot_status = body['status']
|
snapshot_status = body['status']
|
||||||
if snapshot_status == status:
|
if snapshot_status in status:
|
||||||
return
|
return
|
||||||
if 'error' in snapshot_status:
|
if 'error' in snapshot_status:
|
||||||
raise (share_exceptions.
|
raise (share_exceptions.
|
||||||
|
@ -1522,7 +1522,7 @@ class SharesV2Client(shares_client.SharesClient):
|
||||||
time.sleep(self.build_interval)
|
time.sleep(self.build_interval)
|
||||||
body = self.show_share_server(server_id)
|
body = self.show_share_server(server_id)
|
||||||
server_status = body[status_attr]
|
server_status = body[status_attr]
|
||||||
if server_status == status:
|
if server_status in status:
|
||||||
return
|
return
|
||||||
elif constants.STATUS_ERROR in server_status.lower():
|
elif constants.STATUS_ERROR in server_status.lower():
|
||||||
raise share_exceptions.ShareServerBuildErrorException(
|
raise share_exceptions.ShareServerBuildErrorException(
|
||||||
|
@ -2107,3 +2107,90 @@ class SharesV2Client(shares_client.SharesClient):
|
||||||
return body
|
return body
|
||||||
|
|
||||||
###############
|
###############
|
||||||
|
|
||||||
|
def share_server_migration_check(
|
||||||
|
self, share_server_id, host, writable=False,
|
||||||
|
preserve_snapshots=False, nondisruptive=False,
|
||||||
|
new_share_network_id=None, version=LATEST_MICROVERSION):
|
||||||
|
body = {
|
||||||
|
'migration_check': {
|
||||||
|
'host': host,
|
||||||
|
'writable': writable,
|
||||||
|
'preserve_snapshots': preserve_snapshots,
|
||||||
|
'nondisruptive': nondisruptive,
|
||||||
|
'new_share_network_id': new_share_network_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body = json.dumps(body)
|
||||||
|
resp, body = self.post('share-servers/%s/action' % share_server_id,
|
||||||
|
body, headers=EXPERIMENTAL, extra_headers=True,
|
||||||
|
version=version)
|
||||||
|
self.expected_success(200, resp.status)
|
||||||
|
|
||||||
|
return json.loads(body)
|
||||||
|
|
||||||
|
def share_server_migration_start(self, share_server_id, host,
|
||||||
|
writable=False, new_share_network_id=None,
|
||||||
|
preserve_snapshots=False,
|
||||||
|
nondisruptive=False,
|
||||||
|
version=LATEST_MICROVERSION):
|
||||||
|
body = {
|
||||||
|
'migration_start': {
|
||||||
|
'host': host,
|
||||||
|
'writable': writable,
|
||||||
|
'preserve_snapshots': preserve_snapshots,
|
||||||
|
'nondisruptive': nondisruptive,
|
||||||
|
'new_share_network_id': new_share_network_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body = json.dumps(body)
|
||||||
|
resp, body = self.post('share-servers/%s/action' % share_server_id,
|
||||||
|
body, headers=EXPERIMENTAL, extra_headers=True,
|
||||||
|
version=version)
|
||||||
|
self.expected_success(202, resp.status)
|
||||||
|
|
||||||
|
return body
|
||||||
|
|
||||||
|
def share_server_migration_complete(self, share_server_id,
|
||||||
|
version=LATEST_MICROVERSION):
|
||||||
|
body = {
|
||||||
|
'migration_complete': None
|
||||||
|
}
|
||||||
|
|
||||||
|
body = json.dumps(body)
|
||||||
|
resp, body = self.post('share-servers/%s/action' % share_server_id,
|
||||||
|
body, headers=EXPERIMENTAL, extra_headers=True,
|
||||||
|
version=version)
|
||||||
|
self.expected_success(200, resp.status)
|
||||||
|
|
||||||
|
return body
|
||||||
|
|
||||||
|
def share_server_migration_cancel(self, share_server_id,
|
||||||
|
version=LATEST_MICROVERSION):
|
||||||
|
body = {
|
||||||
|
'migration_cancel': None
|
||||||
|
}
|
||||||
|
|
||||||
|
body = json.dumps(body)
|
||||||
|
resp, body = self.post('share-servers/%s/action' % share_server_id,
|
||||||
|
body, headers=EXPERIMENTAL, extra_headers=True,
|
||||||
|
version=version)
|
||||||
|
self.expected_success(202, resp.status)
|
||||||
|
|
||||||
|
return body
|
||||||
|
|
||||||
|
def share_server_migration_get_progress(self, share_server_id,
|
||||||
|
version=LATEST_MICROVERSION):
|
||||||
|
body = {
|
||||||
|
'migration_get_progress': None
|
||||||
|
}
|
||||||
|
|
||||||
|
body = json.dumps(body)
|
||||||
|
resp, body = self.post('share-servers/%s/action' % share_server_id,
|
||||||
|
body, headers=EXPERIMENTAL, extra_headers=True,
|
||||||
|
version=version)
|
||||||
|
self.expected_sucess(200, resp.status)
|
||||||
|
|
||||||
|
return json.loads(body)
|
||||||
|
|
|
@ -80,3 +80,8 @@ class ShareReplicationTypeException(exceptions.TempestException):
|
||||||
class ShareServerBuildErrorException(exceptions.TempestException):
|
class ShareServerBuildErrorException(exceptions.TempestException):
|
||||||
message = ("Share server %(server_id)s failed to build and is in ERROR "
|
message = ("Share server %(server_id)s failed to build and is in ERROR "
|
||||||
"status")
|
"status")
|
||||||
|
|
||||||
|
|
||||||
|
class ShareServerMigrationException(exceptions.TempestException):
|
||||||
|
message = ("Share server %(server_id)s failed to migrate and is in ERROR "
|
||||||
|
"status")
|
||||||
|
|
|
@ -0,0 +1,407 @@
|
||||||
|
# Copyright 2020 NetApp 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
|
||||||
|
from tempest import config
|
||||||
|
from tempest.lib import decorators
|
||||||
|
from tempest.lib import exceptions
|
||||||
|
from testtools import testcase as tc
|
||||||
|
|
||||||
|
from manila_tempest_tests.common import constants
|
||||||
|
from manila_tempest_tests.tests.api import base
|
||||||
|
from manila_tempest_tests import utils
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class MigrationShareServerBase(base.BaseSharesAdminTest):
|
||||||
|
protocol = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def skip_checks(cls):
|
||||||
|
super(MigrationShareServerBase, cls).skip_checks()
|
||||||
|
if cls.protocol not in CONF.share.enable_protocols:
|
||||||
|
raise cls.skipException('%s tests are disabled.' % cls.protocol)
|
||||||
|
if not CONF.share.multitenancy_enabled:
|
||||||
|
raise cls.skipException('Multitenancy tests are disabled.')
|
||||||
|
if not CONF.share.run_share_servers_migration_tests:
|
||||||
|
raise cls.skipException(
|
||||||
|
'Share servers migration tests are disabled.')
|
||||||
|
utils.check_skip_if_microversion_lt('2.57')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resource_setup(cls):
|
||||||
|
super(MigrationShareServerBase, cls).resource_setup()
|
||||||
|
cls.all_hosts = cls.shares_v2_client.list_pools(detail=True)
|
||||||
|
cls.backends = set()
|
||||||
|
for pool in cls.all_hosts['pools']:
|
||||||
|
if pool['capabilities'].get('driver_handles_share_servers'):
|
||||||
|
cls.backends.add(pool['name'].split('#')[0])
|
||||||
|
|
||||||
|
if len(cls.backends) < 2:
|
||||||
|
msg = ("Could not find the necessary backends. At least two"
|
||||||
|
" are needed to run the tests of share server migration")
|
||||||
|
raise cls.skipException(msg)
|
||||||
|
|
||||||
|
# create share type (generic)
|
||||||
|
cls.share_type = cls._create_share_type()
|
||||||
|
|
||||||
|
def _setup_migration(self, share):
|
||||||
|
"""Initial share server migration setup."""
|
||||||
|
|
||||||
|
share = self.shares_v2_client.get_share(share['id'])
|
||||||
|
server_id = share['share_server_id']
|
||||||
|
|
||||||
|
# (andrer) Verify if have at least one backend compatible with
|
||||||
|
# the specified share server.
|
||||||
|
dest_host, compatible = self._choose_matching_backend_for_share_server(
|
||||||
|
server_id)
|
||||||
|
|
||||||
|
snapshot = False
|
||||||
|
if compatible['supported_capabilities']['preserve_snapshots']:
|
||||||
|
snapshot = self.create_snapshot_wait_for_active(
|
||||||
|
share['id'], cleanup_in_class=False)['id']
|
||||||
|
|
||||||
|
# (andrer) Check the share export locations.
|
||||||
|
old_exports = self.shares_v2_client.list_share_export_locations(
|
||||||
|
share['id'])
|
||||||
|
self.assertNotEmpty(old_exports)
|
||||||
|
old_exports = [x['path'] for x in old_exports
|
||||||
|
if x['is_admin_only'] is False]
|
||||||
|
self.assertNotEmpty(old_exports)
|
||||||
|
|
||||||
|
# (andrer) Create the access rules, considering NFS and CIFS
|
||||||
|
# protocols.
|
||||||
|
access_rules = self._get_access_rule_data_for_protocols()
|
||||||
|
self.shares_v2_client.create_access_rule(
|
||||||
|
share['id'], access_type=access_rules[0].get('access_type'),
|
||||||
|
access_to=access_rules[0].get('access_to'),
|
||||||
|
access_level=access_rules[0].get('access_level'))
|
||||||
|
|
||||||
|
self.shares_v2_client.wait_for_share_status(
|
||||||
|
share['id'], constants.RULE_STATE_ACTIVE,
|
||||||
|
status_attr='access_rules_status')
|
||||||
|
|
||||||
|
if self.protocol == 'nfs':
|
||||||
|
self.shares_v2_client.create_access_rule(
|
||||||
|
share['id'], access_type=access_rules[1].get('access_type'),
|
||||||
|
access_to=access_rules[1].get('access_to'),
|
||||||
|
access_level=access_rules[1].get('access_level'))
|
||||||
|
|
||||||
|
self.shares_v2_client.wait_for_share_status(
|
||||||
|
share['id'], constants.RULE_STATE_ACTIVE,
|
||||||
|
status_attr='access_rules_status')
|
||||||
|
|
||||||
|
share = self.shares_v2_client.get_share(share['id'])
|
||||||
|
|
||||||
|
return share, server_id, dest_host, snapshot
|
||||||
|
|
||||||
|
def _validate_instances_states(self, share, instance_status,
|
||||||
|
snapshot_id):
|
||||||
|
"""Validates the share and snapshot status."""
|
||||||
|
statuses = ((instance_status,)
|
||||||
|
if not isinstance(instance_status, (tuple, list, set))
|
||||||
|
else instance_status)
|
||||||
|
|
||||||
|
share = self.shares_v2_client.get_share(share['id'])
|
||||||
|
self.assertIn(share['status'], statuses)
|
||||||
|
|
||||||
|
if snapshot_id:
|
||||||
|
snapshot = self.shares_v2_client.get_snapshot(snapshot_id)
|
||||||
|
self.assertIn(snapshot['status'], statuses)
|
||||||
|
|
||||||
|
def _validate_share_server_migration_complete(
|
||||||
|
self, share, dest_host, src_server_id, dest_server_id,
|
||||||
|
snapshot_id=None, share_network_id=None,
|
||||||
|
version=CONF.share.max_api_microversion):
|
||||||
|
"""Validates the share server migration complete. """
|
||||||
|
|
||||||
|
# Check the export locations
|
||||||
|
new_exports = self.shares_v2_client.list_share_export_locations(
|
||||||
|
share['id'], version=version)
|
||||||
|
self.assertNotEmpty(new_exports)
|
||||||
|
new_exports = [x['path'] for x in new_exports if
|
||||||
|
x['is_admin_only'] is False]
|
||||||
|
self.assertNotEmpty(new_exports)
|
||||||
|
|
||||||
|
# Check the share host, share_network, share_server and status.
|
||||||
|
share = self.shares_v2_client.get_share(share['id'])
|
||||||
|
self.assertEqual(share['host'].split('#')[0], dest_host)
|
||||||
|
self.assertEqual(share_network_id, share['share_network_id'])
|
||||||
|
self.assertEqual(dest_server_id, share['share_server_id'])
|
||||||
|
self.assertEqual(share['status'], constants.STATUS_AVAILABLE)
|
||||||
|
|
||||||
|
# Check the snapshot status if possible.
|
||||||
|
if snapshot_id:
|
||||||
|
self.shares_v2_client.wait_for_snapshot_status(
|
||||||
|
snapshot_id, constants.STATUS_AVAILABLE)
|
||||||
|
|
||||||
|
# Check the share server destination status.
|
||||||
|
dest_server = self.shares_v2_client.show_share_server(dest_server_id)
|
||||||
|
self.assertIn(dest_server['task_state'],
|
||||||
|
constants.TASK_STATE_MIGRATION_SUCCESS)
|
||||||
|
|
||||||
|
# Check if the access rules are in the share.
|
||||||
|
rules = self.shares_v2_client.list_access_rules(share['id'])
|
||||||
|
if self.protocol == 'cifs':
|
||||||
|
expected_rules = [{
|
||||||
|
'state': constants.RULE_STATE_ACTIVE,
|
||||||
|
'access_to': CONF.share.username_for_user_rules,
|
||||||
|
'access_type': 'user',
|
||||||
|
'access_level': 'rw',
|
||||||
|
}]
|
||||||
|
elif self.protocol == 'nfs':
|
||||||
|
expected_rules = [{
|
||||||
|
'state': constants.RULE_STATE_ACTIVE,
|
||||||
|
'access_to': '50.50.50.50',
|
||||||
|
'access_type': 'ip',
|
||||||
|
'access_level': 'rw',
|
||||||
|
}, {
|
||||||
|
'state': constants.RULE_STATE_ACTIVE,
|
||||||
|
'access_to': '51.51.51.51',
|
||||||
|
'access_type': 'ip',
|
||||||
|
'access_level': 'ro',
|
||||||
|
}]
|
||||||
|
|
||||||
|
filtered_rules = [{'state': rule['state'],
|
||||||
|
'access_to': rule['access_to'],
|
||||||
|
'access_level': rule['access_level'],
|
||||||
|
'access_type': rule['access_type']}
|
||||||
|
for rule in rules]
|
||||||
|
|
||||||
|
for r in expected_rules:
|
||||||
|
self.assertIn(r, filtered_rules)
|
||||||
|
self.assertEqual(len(expected_rules), len(filtered_rules))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _choose_matching_backend_for_share_server(self, server_id):
|
||||||
|
"""Choose a compatible host for the share server migration."""
|
||||||
|
for backend in self.backends:
|
||||||
|
# This try is necessary since if you try migrate the share server
|
||||||
|
# using the same backend and share network will raise an exception.
|
||||||
|
try:
|
||||||
|
compatibility = (
|
||||||
|
self.admin_shares_v2_client.share_server_migration_check(
|
||||||
|
share_server_id=server_id, host=backend))
|
||||||
|
except exceptions.Conflict or exceptions.ServerFault:
|
||||||
|
continue
|
||||||
|
if compatibility['compatible']:
|
||||||
|
return backend, compatibility
|
||||||
|
|
||||||
|
raise self.skipException(
|
||||||
|
"Not found compatible host for the share server migration.")
|
||||||
|
|
||||||
|
def _choose_incompatible_backend_for_share_server(self, server_id):
|
||||||
|
"""Choose a not compatible host for the share server migration."""
|
||||||
|
for backend in self.backends:
|
||||||
|
# This try is necessary since if you try migrate the share server
|
||||||
|
# using the same backend and share network will raise an exception.
|
||||||
|
try:
|
||||||
|
compatibility = (
|
||||||
|
self.admin_shares_v2_client.share_server_migration_check(
|
||||||
|
share_server_id=server_id, host=backend))
|
||||||
|
except exceptions.Conflict or exceptions.ServerFault:
|
||||||
|
continue
|
||||||
|
if not compatibility['compatible']:
|
||||||
|
return backend, compatibility
|
||||||
|
|
||||||
|
raise self.skipException(
|
||||||
|
"Not found incompatible host for the share server migration.")
|
||||||
|
|
||||||
|
def _get_share_server_destination_for_migration(self, src_server_id):
|
||||||
|
"""Find the destination share server choosed for the migration."""
|
||||||
|
params = {'source_share_server_id': src_server_id,
|
||||||
|
'status': constants.STATUS_SERVER_MIGRATING_TO}
|
||||||
|
dest_server = self.admin_shares_v2_client.list_share_servers(
|
||||||
|
search_opts=params)
|
||||||
|
dest_server_id = dest_server[0]['id'] if dest_server else None
|
||||||
|
|
||||||
|
return dest_server_id
|
||||||
|
|
||||||
|
def _get_access_rule_data_for_protocols(self):
|
||||||
|
"""Return fake data for access rules based on configured protocol."""
|
||||||
|
if self.protocol == 'nfs':
|
||||||
|
return [{
|
||||||
|
'access_type': 'ip',
|
||||||
|
'access_to': '50.50.50.50',
|
||||||
|
'access_level': 'rw',
|
||||||
|
}, {
|
||||||
|
'access_type': 'ip',
|
||||||
|
'access_to': '51.51.51.51',
|
||||||
|
'access_level': 'ro',
|
||||||
|
}]
|
||||||
|
elif self.protocol == 'cifs':
|
||||||
|
return [{
|
||||||
|
'access_type': 'user',
|
||||||
|
'access_to': CONF.share.username_for_user_rules,
|
||||||
|
'access_level': 'rw',
|
||||||
|
}]
|
||||||
|
else:
|
||||||
|
message = "Unrecognized protocol and access rules configuration"
|
||||||
|
raise self.skipException(message)
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
|
class ShareServerMigrationBasicNFS(MigrationShareServerBase):
|
||||||
|
protocol = "nfs"
|
||||||
|
|
||||||
|
@decorators.idempotent_id('5b84bcb6-17d8-4073-8e02-53b54aee6f8b')
|
||||||
|
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||||
|
def test_share_server_migration_cancel(self):
|
||||||
|
"""Test the share server migration cancel."""
|
||||||
|
share_network_id = self.provide_share_network(
|
||||||
|
self.shares_v2_client, self.networks_client)
|
||||||
|
share = self.create_share(share_protocol=self.protocol,
|
||||||
|
share_type_id=self.share_type['id'],
|
||||||
|
share_network_id=share_network_id,
|
||||||
|
cleanup_in_class=False)
|
||||||
|
share = self.shares_v2_client.get_share(share['id'])
|
||||||
|
|
||||||
|
# Initial migration setup.
|
||||||
|
share, src_server_id, dest_host, snapshot_id = self._setup_migration(
|
||||||
|
share)
|
||||||
|
|
||||||
|
preserve_snapshots = True if snapshot_id else False
|
||||||
|
|
||||||
|
# Start share server migration.
|
||||||
|
self.shares_v2_client.share_server_migration_start(
|
||||||
|
src_server_id, dest_host, preserve_snapshots=preserve_snapshots)
|
||||||
|
|
||||||
|
task_state = constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE
|
||||||
|
self.shares_v2_client.wait_for_share_server_status(
|
||||||
|
src_server_id, task_state, status_attr='task_state')
|
||||||
|
# Get for the destination share server.
|
||||||
|
dest_server_id = self._get_share_server_destination_for_migration(
|
||||||
|
src_server_id)
|
||||||
|
|
||||||
|
dest_server = self.shares_v2_client.show_share_server(dest_server_id)
|
||||||
|
self.assertEqual(dest_host, dest_server['host'])
|
||||||
|
self.assertEqual(share_network_id, dest_server['share_network_id'])
|
||||||
|
|
||||||
|
# Validate the share instances status.
|
||||||
|
share_status = constants.STATUS_SERVER_MIGRATING
|
||||||
|
self._validate_instances_states(share, share_status, snapshot_id)
|
||||||
|
|
||||||
|
# Cancel the share server migration.
|
||||||
|
self.shares_v2_client.share_server_migration_cancel(src_server_id)
|
||||||
|
|
||||||
|
# Wait for the migration cancelled status.
|
||||||
|
task_state = constants.TASK_STATE_MIGRATION_CANCELLED
|
||||||
|
self.shares_v2_client.wait_for_share_server_status(
|
||||||
|
src_server_id, task_state, status_attr='task_state')
|
||||||
|
|
||||||
|
# After the cancel operation, we need to validate again the resources.
|
||||||
|
share_status = constants.STATUS_AVAILABLE
|
||||||
|
self._validate_instances_states(share, share_status, snapshot_id)
|
||||||
|
|
||||||
|
@decorators.idempotent_id('99e439a8-a716-4205-bf5b-af50128cb908')
|
||||||
|
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||||
|
@ddt.data(False, True)
|
||||||
|
def test_share_server_migration_complete(self, new_share_network):
|
||||||
|
"""Test the share server migration complete."""
|
||||||
|
share_network_id = self.provide_share_network(
|
||||||
|
self.shares_v2_client, self.networks_client)
|
||||||
|
dest_share_network_id = share_network_id
|
||||||
|
if new_share_network:
|
||||||
|
src_share_network = self.shares_v2_client.get_share_network(
|
||||||
|
share_network_id)
|
||||||
|
share_net_info = (
|
||||||
|
utils.share_network_get_default_subnet(src_share_network))
|
||||||
|
dest_share_network_id = self.create_share_network(
|
||||||
|
neutron_net_id=share_net_info['neutron_net_id'],
|
||||||
|
neutron_subnet_id=share_net_info['neutron_subnet_id'],
|
||||||
|
cleanup_in_class=False)['id']
|
||||||
|
|
||||||
|
share = self.create_share(share_protocol=self.protocol,
|
||||||
|
share_type_id=self.share_type['id'],
|
||||||
|
share_network_id=share_network_id,
|
||||||
|
cleanup_in_class=False)
|
||||||
|
share = self.shares_v2_client.get_share(share['id'])
|
||||||
|
|
||||||
|
# Initial migration setup.
|
||||||
|
share, src_server_id, dest_host, snapshot_id = self._setup_migration(
|
||||||
|
share)
|
||||||
|
|
||||||
|
preserve_snapshots = True if snapshot_id else False
|
||||||
|
|
||||||
|
# Start share server migration.
|
||||||
|
self.shares_v2_client.share_server_migration_start(
|
||||||
|
src_server_id, dest_host,
|
||||||
|
new_share_network_id=dest_share_network_id,
|
||||||
|
preserve_snapshots=preserve_snapshots)
|
||||||
|
|
||||||
|
task_state = constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE
|
||||||
|
self.shares_v2_client.wait_for_share_server_status(
|
||||||
|
src_server_id, task_state, status_attr='task_state')
|
||||||
|
# Get for the destination share server.
|
||||||
|
dest_server_id = self._get_share_server_destination_for_migration(
|
||||||
|
src_server_id)
|
||||||
|
|
||||||
|
dest_server = self.shares_v2_client.show_share_server(dest_server_id)
|
||||||
|
self.assertEqual(dest_host, dest_server['host'])
|
||||||
|
self.assertEqual(dest_share_network_id,
|
||||||
|
dest_server['share_network_id'])
|
||||||
|
|
||||||
|
share_status = constants.STATUS_SERVER_MIGRATING
|
||||||
|
self._validate_instances_states(share, share_status, snapshot_id)
|
||||||
|
|
||||||
|
# Share server migration complete.
|
||||||
|
self.shares_v2_client.share_server_migration_complete(src_server_id)
|
||||||
|
|
||||||
|
# It's necessary wait for the migration success state and
|
||||||
|
# active status.
|
||||||
|
task_state = [constants.TASK_STATE_MIGRATION_SUCCESS,
|
||||||
|
constants.SERVER_STATE_INACTIVE]
|
||||||
|
self.shares_v2_client.wait_for_share_server_status(
|
||||||
|
src_server_id, task_state, status_attr='task_state')
|
||||||
|
|
||||||
|
# Validate the share server migration complete.
|
||||||
|
share = self.shares_v2_client.get_share(share['id'])
|
||||||
|
self._validate_share_server_migration_complete(
|
||||||
|
share, dest_host, src_server_id, dest_server_id,
|
||||||
|
snapshot_id=snapshot_id, share_network_id=dest_share_network_id)
|
||||||
|
|
||||||
|
@decorators.idempotent_id('52e154eb-2d39-45af-b5c1-49ea569ab804')
|
||||||
|
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||||
|
@ddt.data(True, False)
|
||||||
|
def test_share_server_migration_check(self, compatible):
|
||||||
|
"""The share server migration check compatibility tests."""
|
||||||
|
share = self.create_share(share_protocol=self.protocol,
|
||||||
|
share_type_id=self.share_type['id'],
|
||||||
|
cleanup_in_class=False)
|
||||||
|
share = self.shares_v2_client.get_share(share['id'])
|
||||||
|
# Find a backend compatible or not for the share server
|
||||||
|
# check compatibility operation.
|
||||||
|
if compatible:
|
||||||
|
dest_host, result = self._choose_matching_backend_for_share_server(
|
||||||
|
server_id=share['share_server_id'])
|
||||||
|
self.assertTrue(result['compatible'])
|
||||||
|
self.assertEqual(result['requested_capabilities']['host'],
|
||||||
|
dest_host)
|
||||||
|
else:
|
||||||
|
dest_host, result = (
|
||||||
|
self._choose_incompatible_backend_for_share_server(
|
||||||
|
server_id=share['share_server_id']))
|
||||||
|
if dest_host is None:
|
||||||
|
raise self.skipException(
|
||||||
|
"Not found any compatible destination host for the share "
|
||||||
|
"server %s." % share['share_server_id'])
|
||||||
|
self.assertFalse(result['compatible'])
|
||||||
|
self.assertEqual(result['requested_capabilities'].get('host'),
|
||||||
|
dest_host)
|
||||||
|
|
||||||
|
|
||||||
|
class ShareServerMigrationBasicCIFS(ShareServerMigrationBasicNFS):
|
||||||
|
protocol = "cifs"
|
|
@ -0,0 +1,335 @@
|
||||||
|
# Copyright 2020 NetApp 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.
|
||||||
|
|
||||||
|
from tempest import config
|
||||||
|
from tempest.lib.common.utils import data_utils
|
||||||
|
from tempest.lib import decorators
|
||||||
|
from tempest.lib import exceptions as lib_exc
|
||||||
|
from testtools import testcase as tc
|
||||||
|
|
||||||
|
|
||||||
|
from manila_tempest_tests.common import constants
|
||||||
|
from manila_tempest_tests.tests.api.admin import test_share_servers_migration
|
||||||
|
from manila_tempest_tests.tests.api import base
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class MigrationShareServerNegative(
|
||||||
|
test_share_servers_migration.MigrationShareServerBase):
|
||||||
|
protocool = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _setup_migration(self, cleanup_in_class=True):
|
||||||
|
"""Setup migration for negative tests."""
|
||||||
|
extra_specs = {
|
||||||
|
'driver_handles_share_servers': CONF.share.multitenancy_enabled}
|
||||||
|
if CONF.share.capability_snapshot_support:
|
||||||
|
extra_specs['snapshot_support'] = True
|
||||||
|
share_type = self.create_share_type(
|
||||||
|
name=data_utils.rand_name("tempest-share-type"),
|
||||||
|
extra_specs=extra_specs,
|
||||||
|
cleanup_in_class=cleanup_in_class)
|
||||||
|
share = self.create_share(share_protocol=self.protocol,
|
||||||
|
share_type_id=share_type['share_type']['id'],
|
||||||
|
cleanup_in_class=cleanup_in_class)
|
||||||
|
share = self.shares_v2_client.get_share(share['id'])
|
||||||
|
share_server_id = share['share_server_id']
|
||||||
|
dest_host, compatible = self._choose_matching_backend_for_share_server(
|
||||||
|
share_server_id)
|
||||||
|
|
||||||
|
return share, share_server_id, dest_host
|
||||||
|
|
||||||
|
|
||||||
|
class ShareServerMigrationInvalidParametersNFS(MigrationShareServerNegative):
|
||||||
|
"""Tests related to share server not found."""
|
||||||
|
protocol = "nfs"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resource_setup(cls):
|
||||||
|
super(ShareServerMigrationInvalidParametersNFS, cls).resource_setup()
|
||||||
|
cls.share = cls.create_share(
|
||||||
|
share_protocol=cls.protocol,
|
||||||
|
share_type_id=cls.share_type['id'])
|
||||||
|
cls.share = cls.shares_v2_client.get_share(cls.share['id'])
|
||||||
|
cls.share_server_id = cls.share['share_server_id']
|
||||||
|
cls.fake_server_id = 'fake_server_id'
|
||||||
|
cls.fake_host = 'fake_host@fake_backend'
|
||||||
|
|
||||||
|
@decorators.idempotent_id('1be6ec2a-3118-4033-9cdb-ea6d199d97f4')
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_share_server_invalid_server_migration_check(self):
|
||||||
|
"""Not found share server in migration check."""
|
||||||
|
self.assertRaises(lib_exc.NotFound,
|
||||||
|
self.shares_v2_client.share_server_migration_check,
|
||||||
|
self.fake_server_id,
|
||||||
|
self.fake_host)
|
||||||
|
|
||||||
|
@decorators.idempotent_id('2aeffcfa-4e68-40e4-8a75-03b017503501')
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_share_server_invalid_server_migration_cancel(self):
|
||||||
|
"""Not found share server in migration cancel."""
|
||||||
|
self.assertRaises(lib_exc.NotFound,
|
||||||
|
self.shares_v2_client.share_server_migration_cancel,
|
||||||
|
self.fake_server_id)
|
||||||
|
|
||||||
|
@decorators.idempotent_id('52d23980-80e7-40de-8dba-1bb1382ef995')
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_share_server_invalid_server_migration_start(self):
|
||||||
|
"""Not found share server in migration start."""
|
||||||
|
self.assertRaises(lib_exc.NotFound,
|
||||||
|
self.shares_v2_client.share_server_migration_start,
|
||||||
|
self.fake_server_id,
|
||||||
|
self.fake_host)
|
||||||
|
|
||||||
|
@decorators.idempotent_id('47795631-eb50-424b-9fac-d2ee832cd01c')
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_share_server_invalid_server_migration_get_progress(self):
|
||||||
|
"""Not found share server in migration get progress."""
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.BadRequest,
|
||||||
|
self.shares_v2_client.share_server_migration_get_progress,
|
||||||
|
self.fake_server_id)
|
||||||
|
|
||||||
|
@decorators.idempotent_id('3b464298-a4e4-417b-92d6-acfbd30ac45b')
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_share_server_invalid_server_migration_complete(self):
|
||||||
|
"""Not found share server in migration """
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.NotFound,
|
||||||
|
self.shares_v2_client.share_server_migration_complete,
|
||||||
|
self.fake_server_id)
|
||||||
|
|
||||||
|
@decorators.idempotent_id('2d25cf84-0b5c-4a9f-ae20-9bec09bb6914')
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_share_server_invalid_host_migration_start(self):
|
||||||
|
"""Not found share server in migration start."""
|
||||||
|
self.assertRaises(lib_exc.NotFound,
|
||||||
|
self.shares_v2_client.share_server_migration_start,
|
||||||
|
self.share_server_id,
|
||||||
|
self.fake_host)
|
||||||
|
|
||||||
|
@decorators.idempotent_id('e7e2c19c-a0ed-41ab-b666-b2beae4a690c')
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_share_server_invalid_host_migration_check(self):
|
||||||
|
"""Not found share server in migration check."""
|
||||||
|
self.assertRaises(lib_exc.NotFound,
|
||||||
|
self.shares_v2_client.share_server_migration_check,
|
||||||
|
self.share_server_id,
|
||||||
|
self.fake_host)
|
||||||
|
|
||||||
|
|
||||||
|
class ShareServerErrorStatusOperationNFS(MigrationShareServerNegative):
|
||||||
|
protocol = "nfs"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resource_setup(cls):
|
||||||
|
super(ShareServerErrorStatusOperationNFS, cls).resource_setup()
|
||||||
|
cls.share = cls.create_share(
|
||||||
|
share_protocol=cls.protocol,
|
||||||
|
share_type_id=cls.share_type['id'])
|
||||||
|
cls.share = cls.shares_v2_client.get_share(cls.share['id'])
|
||||||
|
cls.share_server_id = cls.share['share_server_id']
|
||||||
|
cls.shares_v2_client.share_server_reset_state(
|
||||||
|
cls.share_server_id, status=constants.STATUS_ERROR)
|
||||||
|
cls.fake_host = 'fake_host@fake_backend'
|
||||||
|
|
||||||
|
@decorators.idempotent_id('1f8d75c1-aa3c-465a-b2dd-9ad33933944f')
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_share_server_invalid_operation_migration_check(self):
|
||||||
|
"""Share server migration check invalid operation."""
|
||||||
|
self.assertRaises(lib_exc.Conflict,
|
||||||
|
self.shares_v2_client.share_server_migration_check,
|
||||||
|
self.share_server_id,
|
||||||
|
self.fake_host)
|
||||||
|
|
||||||
|
@decorators.idempotent_id('c256c5f5-b4d1-47b7-a1f4-af21f19ce600')
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_share_server_invalid_operation_migration_start(self):
|
||||||
|
"""Share server migration start invalid operation."""
|
||||||
|
self.assertRaises(lib_exc.Conflict,
|
||||||
|
self.shares_v2_client.share_server_migration_start,
|
||||||
|
self.share_server_id,
|
||||||
|
self.fake_host)
|
||||||
|
|
||||||
|
@decorators.idempotent_id('d2830fe4-8d13-40d2-b987-18d414bb6196')
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_share_server_invalid_operation_migration_get_progress(self):
|
||||||
|
"""Share server migration get progress invalid operation."""
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.BadRequest,
|
||||||
|
self.shares_v2_client.share_server_migration_get_progress,
|
||||||
|
self.share_server_id,
|
||||||
|
self.fake_host)
|
||||||
|
|
||||||
|
@decorators.idempotent_id('245f39d7-bcbc-4711-afd7-651a5535a880')
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_share_server_invalid_operation_migration_cancel(self):
|
||||||
|
"""Share server migration cancel invalid operation."""
|
||||||
|
self.assertRaises(lib_exc.BadRequest,
|
||||||
|
self.shares_v2_client.share_server_migration_cancel,
|
||||||
|
self.share_server_id,
|
||||||
|
self.fake_host)
|
||||||
|
|
||||||
|
@decorators.idempotent_id('3db45440-2c70-4fa4-b5eb-75e3cb0204f8')
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_share_server_invalid_operation_migration_complete(self):
|
||||||
|
"""Share server migration complete invalid operation."""
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.BadRequest,
|
||||||
|
self.shares_v2_client.share_server_migration_complete,
|
||||||
|
self.share_server_id,
|
||||||
|
self.fake_host)
|
||||||
|
|
||||||
|
|
||||||
|
class ShareServerMigrationStartNegativesNFS(MigrationShareServerNegative):
|
||||||
|
protocol = "nfs"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resource_setup(cls):
|
||||||
|
super(ShareServerMigrationStartNegativesNFS, cls).resource_setup()
|
||||||
|
cls.share, cls.server_id, cls.dest_host = cls._setup_migration()
|
||||||
|
cls.shares_v2_client.share_server_migration_start(
|
||||||
|
cls.server_id, cls.dest_host)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resource_cleanup(cls):
|
||||||
|
states = [constants.TASK_STATE_MIGRATION_DRIVER_IN_PROGRESS,
|
||||||
|
constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE]
|
||||||
|
cls.shares_v2_client.wait_for_share_server_status(
|
||||||
|
cls.server_id, status=states, status_attr="task_state")
|
||||||
|
cls.shares_v2_client.share_server_migration_cancel(cls.server_id)
|
||||||
|
cls.shares_v2_client.wait_for_share_status(cls.share['id'],
|
||||||
|
status="available")
|
||||||
|
super(ShareServerMigrationStartNegativesNFS, cls).resource_cleanup()
|
||||||
|
|
||||||
|
@decorators.idempotent_id('5b904db3-fc36-4c35-a8ef-cf6b80315388')
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_share_server_migration_start_try_create_snapshot(self):
|
||||||
|
"""Try create snap during a server migration."""
|
||||||
|
if not CONF.share.capability_snapshot_support:
|
||||||
|
raise self.skipException(
|
||||||
|
'Snapshot tests are disabled or unsupported.')
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.BadRequest,
|
||||||
|
self.shares_v2_client.create_snapshot,
|
||||||
|
self.share['id']
|
||||||
|
)
|
||||||
|
|
||||||
|
@decorators.idempotent_id('93882b54-78d4-4c4e-95b5-993de0cdb25d')
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_share_server_migration_start_try_create_access_rule(self):
|
||||||
|
"""Try create access rule during a server migration."""
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.BadRequest,
|
||||||
|
self.shares_v2_client.create_access_rule,
|
||||||
|
self.share['id']
|
||||||
|
)
|
||||||
|
|
||||||
|
@decorators.idempotent_id('7c74a4a8-61b2-4c55-bc4b-02eac73d2c6e')
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_share_server_migration_start_try_delete_share_network(self):
|
||||||
|
"""Try delete share network during a server migration."""
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.Conflict,
|
||||||
|
self.shares_v2_client.delete_share_network,
|
||||||
|
self.share['share_network_id']
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ShareServerMigrationStartInvalidStatesNFS(MigrationShareServerNegative):
|
||||||
|
protocol = "nfs"
|
||||||
|
|
||||||
|
@decorators.idempotent_id('bcec0503-b2a9-4514-bf3f-a30d55f41e78')
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_share_server_migration_start_invalid_network(self):
|
||||||
|
"""Try server migration start with invalid network."""
|
||||||
|
share, share_server_id, dest_host = self._setup_migration(
|
||||||
|
cleanup_in_class=False)
|
||||||
|
share_network = self.create_share_network(cleanup_in_class=False)
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.ServerFault,
|
||||||
|
self.shares_v2_client.share_server_migration_start,
|
||||||
|
share_server_id,
|
||||||
|
dest_host,
|
||||||
|
new_share_network_id=share_network)
|
||||||
|
|
||||||
|
@decorators.idempotent_id('11374277-efcf-4992-ad94-c8f4a393d41b')
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_share_server_migration_start_invalid_share_state(self):
|
||||||
|
"""Try server migration start with invalid share state."""
|
||||||
|
share, share_server_id, dest_host = self._setup_migration(
|
||||||
|
cleanup_in_class=False)
|
||||||
|
self.shares_v2_client.reset_state(share['id'])
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.Conflict,
|
||||||
|
self.shares_v2_client.share_server_migration_start,
|
||||||
|
share_server_id,
|
||||||
|
dest_host
|
||||||
|
)
|
||||||
|
|
||||||
|
@decorators.idempotent_id('ebe8da5b-ee9c-48c7-a7e4-9e71839f813f')
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_share_server_migration_start_with_share_replica(self):
|
||||||
|
"""Try server migration start with share replica."""
|
||||||
|
if not CONF.share.backend_replication_type or (
|
||||||
|
not CONF.share.run_replication_tests):
|
||||||
|
raise self.skipException(
|
||||||
|
'Share replica tests are disabled or unsupported.')
|
||||||
|
extra_specs = {
|
||||||
|
'driver_handles_share_servers': CONF.share.multitenancy_enabled,
|
||||||
|
'replication_type': CONF.share.backend_replication_type
|
||||||
|
}
|
||||||
|
share_type = self.shares_v2_client.create_share_type(
|
||||||
|
name=data_utils.rand_name("tempest-share-type"),
|
||||||
|
extra_specs=extra_specs,
|
||||||
|
cleanup_in_class=False)
|
||||||
|
share = self.create_share(share_type_id=share_type['share_type']['id'],
|
||||||
|
share_protocol=self.protocol,
|
||||||
|
cleanup_in_class=False)
|
||||||
|
share = self.shares_v2_client.get_share(share['id'])
|
||||||
|
share_server_id = share['share_server_id']
|
||||||
|
dest_host, _ = self._choose_matching_backend_for_share_server(
|
||||||
|
share_server_id)
|
||||||
|
self.create_share_replica(
|
||||||
|
share['id'],
|
||||||
|
cleanup_in_class=False)
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.Conflict,
|
||||||
|
self.shares_v2_client.share_server_migration_start,
|
||||||
|
share_server_id,
|
||||||
|
dest_host
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ShareServerMigrationInvalidParametersCIFS(
|
||||||
|
ShareServerMigrationInvalidParametersNFS):
|
||||||
|
protocol = "cifs"
|
||||||
|
|
||||||
|
|
||||||
|
class ShareServerErrorStatusOperationCIFS(ShareServerErrorStatusOperationNFS):
|
||||||
|
protocol = "cifs"
|
||||||
|
|
||||||
|
|
||||||
|
class ShareServerMigrationStartNegativesCIFS(
|
||||||
|
ShareServerMigrationStartNegativesNFS):
|
||||||
|
protocol = "cifs"
|
||||||
|
|
||||||
|
|
||||||
|
class ShareServerMigrationInvalidStatesCIFS(
|
||||||
|
ShareServerMigrationStartInvalidStatesNFS):
|
||||||
|
protocol = "cifs"
|
|
@ -677,8 +677,9 @@ class BaseSharesTest(test.BaseTestCase):
|
||||||
return rep_domain, pools_in_rep_domain
|
return rep_domain, pools_in_rep_domain
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_share_replica(cls, share_id, availability_zone, client=None,
|
def create_share_replica(cls, share_id, availability_zone=None,
|
||||||
cleanup_in_class=False, cleanup=True,
|
client=None, cleanup_in_class=False,
|
||||||
|
cleanup=True,
|
||||||
version=CONF.share.max_api_microversion):
|
version=CONF.share.max_api_microversion):
|
||||||
client = client or cls.shares_v2_client
|
client = client or cls.shares_v2_client
|
||||||
replica = client.create_share_replica(
|
replica = client.create_share_replica(
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
MANILA_DEFAULT_SHARE_TYPE_EXTRA_SPECS: 'snapshot_support=True create_share_from_snapshot_support=True'
|
MANILA_DEFAULT_SHARE_TYPE_EXTRA_SPECS: 'snapshot_support=True create_share_from_snapshot_support=True'
|
||||||
MANILA_CONFIGURE_DEFAULT_TYPES: true
|
MANILA_CONFIGURE_DEFAULT_TYPES: true
|
||||||
MANILA_SHARE_MIGRATION_PERIOD_TASK_INTERVAL: 1
|
MANILA_SHARE_MIGRATION_PERIOD_TASK_INTERVAL: 1
|
||||||
|
MANILA_SERVER_MIGRATION_PERIOD_TASK_INTERVAL: 10
|
||||||
MANILA_REPLICA_STATE_UPDATE_INTERVAL: 10
|
MANILA_REPLICA_STATE_UPDATE_INTERVAL: 10
|
||||||
|
|
||||||
|
|
||||||
|
@ -106,6 +107,7 @@
|
||||||
MANILA_INSTALL_TEMPEST_PLUGIN_SYSTEMWIDE: false
|
MANILA_INSTALL_TEMPEST_PLUGIN_SYSTEMWIDE: false
|
||||||
MANILA_SERVICE_IMAGE_ENABLED: false
|
MANILA_SERVICE_IMAGE_ENABLED: false
|
||||||
MANILA_SHARE_MIGRATION_PERIOD_TASK_INTERVAL: 1
|
MANILA_SHARE_MIGRATION_PERIOD_TASK_INTERVAL: 1
|
||||||
|
MANILA_SERVER_MIGRATION_PERIOD_TASK_INTERVAL: 10
|
||||||
MANILA_REPLICA_STATE_UPDATE_INTERVAL: 10
|
MANILA_REPLICA_STATE_UPDATE_INTERVAL: 10
|
||||||
devstack_services:
|
devstack_services:
|
||||||
tls-proxy: true
|
tls-proxy: true
|
||||||
|
@ -241,6 +243,7 @@
|
||||||
multitenancy_enabled: true
|
multitenancy_enabled: true
|
||||||
backend_names: LONDON,PARIS
|
backend_names: LONDON,PARIS
|
||||||
multi_backend: true
|
multi_backend: true
|
||||||
|
run_share_servers_migration_tests: true
|
||||||
|
|
||||||
- job:
|
- job:
|
||||||
name: manila-tempest-plugin-generic
|
name: manila-tempest-plugin-generic
|
||||||
|
@ -480,6 +483,7 @@
|
||||||
run_mount_snapshot_tests: true
|
run_mount_snapshot_tests: true
|
||||||
run_replication_tests: true
|
run_replication_tests: true
|
||||||
run_revert_to_snapshot_tests: true
|
run_revert_to_snapshot_tests: true
|
||||||
|
run_share_servers_migration_tests: true
|
||||||
|
|
||||||
- job:
|
- job:
|
||||||
name: manila-tempest-plugin-glusterfs-native
|
name: manila-tempest-plugin-glusterfs-native
|
||||||
|
|
Loading…
Reference in New Issue