Add functional tests for manage/unmanage of shares in DHSS=True
This patch adds functional tests for managing/unmanaging share servers, shares, and snapshots in DHSS=True. Change-Id: I452c2a99b186f53d737cb7fbd7eabfcfd9b249d6 Partially-implements: bp manage-unmanage-with-share-servers
This commit is contained in:
parent
b4e00216fb
commit
370569423e
|
@ -15,6 +15,10 @@ STATUS_ERROR = 'error'
|
||||||
STATUS_AVAILABLE = 'available'
|
STATUS_AVAILABLE = 'available'
|
||||||
STATUS_ERROR_DELETING = 'error_deleting'
|
STATUS_ERROR_DELETING = 'error_deleting'
|
||||||
STATUS_MIGRATING = 'migrating'
|
STATUS_MIGRATING = 'migrating'
|
||||||
|
STATUS_MANAGE_ERROR = 'manage_error'
|
||||||
|
STATUS_MIGRATING_TO = 'migrating_to'
|
||||||
|
STATUS_CREATING = 'creating'
|
||||||
|
STATUS_DELETING = 'deleting'
|
||||||
|
|
||||||
TEMPEST_MANILA_PREFIX = 'tempest-manila'
|
TEMPEST_MANILA_PREFIX = 'tempest-manila'
|
||||||
|
|
||||||
|
@ -85,3 +89,13 @@ SHARE_GROUP_TYPE_REQUIRED_KEYS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
MIN_SHARE_ACCESS_METADATA_MICROVERSION = '2.45'
|
MIN_SHARE_ACCESS_METADATA_MICROVERSION = '2.45'
|
||||||
|
|
||||||
|
# Share servers
|
||||||
|
SERVER_STATE_ACTIVE = 'active'
|
||||||
|
SERVER_STATE_CREATING = 'creating'
|
||||||
|
SERVER_STATE_DELETING = 'deleting'
|
||||||
|
SERVER_STATE_ERROR = 'error'
|
||||||
|
SERVER_STATE_MANAGE_ERROR = 'manage_error'
|
||||||
|
SERVER_STATE_MANAGE_STARTING = 'manage_starting'
|
||||||
|
SERVER_STATE_UNMANAGE_ERROR = 'unmanage_error'
|
||||||
|
SERVER_STATE_UNMANAGE_STARTING = 'unmanage_starting'
|
||||||
|
|
|
@ -30,7 +30,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.48",
|
default="2.49",
|
||||||
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",
|
||||||
|
|
|
@ -436,7 +436,7 @@ class SharesV2Client(shares_client.SharesClient):
|
||||||
def manage_share(self, service_host, protocol, export_path,
|
def manage_share(self, service_host, protocol, export_path,
|
||||||
share_type_id, name=None, description=None,
|
share_type_id, name=None, description=None,
|
||||||
is_public=False, version=LATEST_MICROVERSION,
|
is_public=False, version=LATEST_MICROVERSION,
|
||||||
url=None):
|
url=None, share_server_id=None):
|
||||||
post_body = {
|
post_body = {
|
||||||
"share": {
|
"share": {
|
||||||
"export_path": export_path,
|
"export_path": export_path,
|
||||||
|
@ -448,6 +448,8 @@ class SharesV2Client(shares_client.SharesClient):
|
||||||
"is_public": is_public,
|
"is_public": is_public,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if share_server_id is not None:
|
||||||
|
post_body['share']['share_server_id'] = share_server_id
|
||||||
if url is None:
|
if url is None:
|
||||||
if utils.is_microversion_gt(version, "2.6"):
|
if utils.is_microversion_gt(version, "2.6"):
|
||||||
url = 'shares/manage'
|
url = 'shares/manage'
|
||||||
|
@ -548,6 +550,8 @@ 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:
|
||||||
|
return
|
||||||
if 'error' in snapshot_status:
|
if 'error' in snapshot_status:
|
||||||
raise (share_exceptions.
|
raise (share_exceptions.
|
||||||
SnapshotBuildErrorException(snapshot_id=snapshot_id))
|
SnapshotBuildErrorException(snapshot_id=snapshot_id))
|
||||||
|
@ -596,6 +600,12 @@ class SharesV2Client(shares_client.SharesClient):
|
||||||
self.expected_success(202, resp.status)
|
self.expected_success(202, resp.status)
|
||||||
return body
|
return body
|
||||||
|
|
||||||
|
def snapshot_reset_state(self, snapshot_id,
|
||||||
|
status=constants.STATUS_AVAILABLE,
|
||||||
|
version=LATEST_MICROVERSION):
|
||||||
|
self.reset_state(snapshot_id, status=status, s_type='snapshots',
|
||||||
|
version=version)
|
||||||
|
|
||||||
###############
|
###############
|
||||||
|
|
||||||
def revert_to_snapshot(self, share_id, snapshot_id,
|
def revert_to_snapshot(self, share_id, snapshot_id,
|
||||||
|
@ -1368,6 +1378,64 @@ class SharesV2Client(shares_client.SharesClient):
|
||||||
(sg_snapshot_name, status, self.build_timeout))
|
(sg_snapshot_name, status, self.build_timeout))
|
||||||
raise exceptions.TimeoutException(message)
|
raise exceptions.TimeoutException(message)
|
||||||
|
|
||||||
|
###############
|
||||||
|
|
||||||
|
def manage_share_server(self, host, share_network_id, identifier,
|
||||||
|
driver_options=None, version=LATEST_MICROVERSION):
|
||||||
|
body = {
|
||||||
|
'share_server': {
|
||||||
|
'host': host,
|
||||||
|
'share_network_id': share_network_id,
|
||||||
|
'identifier': identifier,
|
||||||
|
'driver_options': driver_options if driver_options else {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body = json.dumps(body)
|
||||||
|
resp, body = self.post('share-servers/manage', body,
|
||||||
|
extra_headers=True, version=version)
|
||||||
|
self.expected_success(202, resp.status)
|
||||||
|
return self._parse_resp(body)
|
||||||
|
|
||||||
|
def unmanage_share_server(self, share_server_id,
|
||||||
|
version=LATEST_MICROVERSION):
|
||||||
|
body = json.dumps({'unmanage': None})
|
||||||
|
resp, body = self.post('share-servers/%s/action' % share_server_id,
|
||||||
|
body, extra_headers=True, version=version)
|
||||||
|
self.expected_success(202, resp.status)
|
||||||
|
return self._parse_resp(body)
|
||||||
|
|
||||||
|
def wait_for_share_server_status(self, server_id, status,
|
||||||
|
status_attr='status'):
|
||||||
|
"""Waits for a share to reach a given status."""
|
||||||
|
body = self.show_share_server(server_id)
|
||||||
|
server_status = body[status_attr]
|
||||||
|
start = int(time.time())
|
||||||
|
|
||||||
|
while server_status != status:
|
||||||
|
time.sleep(self.build_interval)
|
||||||
|
body = self.show_share_server(server_id)
|
||||||
|
server_status = body[status_attr]
|
||||||
|
if server_status == status:
|
||||||
|
return
|
||||||
|
elif constants.STATUS_ERROR in server_status.lower():
|
||||||
|
raise share_exceptions.ShareServerBuildErrorException(
|
||||||
|
server_id=server_id)
|
||||||
|
|
||||||
|
if int(time.time()) - start >= self.build_timeout:
|
||||||
|
message = ("Share server's %(status_attr)s failed to "
|
||||||
|
"transition to %(status)s within the required "
|
||||||
|
"time %(seconds)s." %
|
||||||
|
{"status_attr": status_attr, "status": status,
|
||||||
|
"seconds": self.build_timeout})
|
||||||
|
raise exceptions.TimeoutException(message)
|
||||||
|
|
||||||
|
def share_server_reset_state(self, share_server_id,
|
||||||
|
status=constants.SERVER_STATE_ACTIVE,
|
||||||
|
version=LATEST_MICROVERSION):
|
||||||
|
self.reset_state(share_server_id, status=status,
|
||||||
|
s_type='share-servers', version=version)
|
||||||
|
|
||||||
###############
|
###############
|
||||||
|
|
||||||
def migrate_share(self, share_id, host,
|
def migrate_share(self, share_id, host,
|
||||||
|
|
|
@ -75,3 +75,8 @@ class ResourceReleaseFailed(exceptions.TempestException):
|
||||||
class ShareReplicationTypeException(exceptions.TempestException):
|
class ShareReplicationTypeException(exceptions.TempestException):
|
||||||
message = ("Option backend_replication_type is set to incorrect value: "
|
message = ("Option backend_replication_type is set to incorrect value: "
|
||||||
"%(replication_type)s")
|
"%(replication_type)s")
|
||||||
|
|
||||||
|
|
||||||
|
class ShareServerBuildErrorException(exceptions.TempestException):
|
||||||
|
message = ("Share server %(server_id)s failed to build and is in ERROR "
|
||||||
|
"status")
|
||||||
|
|
|
@ -13,19 +13,20 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import six
|
import ddt
|
||||||
from tempest import config
|
from tempest import config
|
||||||
from tempest.lib.common.utils import data_utils
|
from tempest.lib.common.utils import data_utils
|
||||||
from tempest.lib import exceptions as lib_exc
|
|
||||||
import testtools
|
import testtools
|
||||||
from testtools import testcase as tc
|
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.tests.api import base
|
||||||
from manila_tempest_tests import utils
|
from manila_tempest_tests import utils
|
||||||
|
|
||||||
CONF = config.CONF
|
CONF = config.CONF
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
class ManageNFSShareTest(base.BaseSharesAdminTest):
|
class ManageNFSShareTest(base.BaseSharesAdminTest):
|
||||||
protocol = 'nfs'
|
protocol = 'nfs'
|
||||||
|
|
||||||
|
@ -34,36 +35,23 @@ class ManageNFSShareTest(base.BaseSharesAdminTest):
|
||||||
# won't be deleted.
|
# won't be deleted.
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@testtools.skipIf(
|
|
||||||
CONF.share.multitenancy_enabled,
|
|
||||||
"Only for driver_handles_share_servers = False driver mode.")
|
|
||||||
@testtools.skipUnless(
|
@testtools.skipUnless(
|
||||||
CONF.share.run_manage_unmanage_tests,
|
CONF.share.run_manage_unmanage_tests,
|
||||||
"Manage/unmanage tests are disabled.")
|
"Manage/unmanage tests are disabled.")
|
||||||
def resource_setup(cls):
|
def resource_setup(cls):
|
||||||
super(ManageNFSShareTest, cls).resource_setup()
|
|
||||||
if cls.protocol not in CONF.share.enable_protocols:
|
if cls.protocol not in CONF.share.enable_protocols:
|
||||||
message = "%s tests are disabled" % cls.protocol
|
message = "%s tests are disabled" % cls.protocol
|
||||||
raise cls.skipException(message)
|
raise cls.skipException(message)
|
||||||
|
|
||||||
# Create share types
|
utils.skip_if_manage_not_supported_for_version()
|
||||||
|
|
||||||
|
super(ManageNFSShareTest, cls).resource_setup()
|
||||||
|
|
||||||
|
# Create share type
|
||||||
cls.st_name = data_utils.rand_name("manage-st-name")
|
cls.st_name = data_utils.rand_name("manage-st-name")
|
||||||
cls.st_name_invalid = data_utils.rand_name("manage-st-name-invalid")
|
|
||||||
cls.extra_specs = {
|
cls.extra_specs = {
|
||||||
'storage_protocol': CONF.share.capability_storage_protocol,
|
'storage_protocol': CONF.share.capability_storage_protocol,
|
||||||
'driver_handles_share_servers': False,
|
'driver_handles_share_servers': CONF.share.multitenancy_enabled,
|
||||||
'snapshot_support': six.text_type(
|
|
||||||
CONF.share.capability_snapshot_support),
|
|
||||||
'create_share_from_snapshot_support': six.text_type(
|
|
||||||
CONF.share.capability_create_share_from_snapshot_support)
|
|
||||||
}
|
|
||||||
cls.extra_specs_invalid = {
|
|
||||||
'storage_protocol': CONF.share.capability_storage_protocol,
|
|
||||||
'driver_handles_share_servers': True,
|
|
||||||
'snapshot_support': six.text_type(
|
|
||||||
CONF.share.capability_snapshot_support),
|
|
||||||
'create_share_from_snapshot_support': six.text_type(
|
|
||||||
CONF.share.capability_create_share_from_snapshot_support),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cls.st = cls.create_share_type(
|
cls.st = cls.create_share_type(
|
||||||
|
@ -71,15 +59,12 @@ class ManageNFSShareTest(base.BaseSharesAdminTest):
|
||||||
cleanup_in_class=True,
|
cleanup_in_class=True,
|
||||||
extra_specs=cls.extra_specs)
|
extra_specs=cls.extra_specs)
|
||||||
|
|
||||||
cls.st_invalid = cls.create_share_type(
|
|
||||||
name=cls.st_name_invalid,
|
|
||||||
cleanup_in_class=True,
|
|
||||||
extra_specs=cls.extra_specs_invalid)
|
|
||||||
|
|
||||||
def _test_manage(self, is_public=False,
|
def _test_manage(self, is_public=False,
|
||||||
version=CONF.share.max_api_microversion,
|
version=CONF.share.max_api_microversion,
|
||||||
check_manage=False):
|
check_manage=False):
|
||||||
|
|
||||||
|
utils.skip_if_manage_not_supported_for_version(version)
|
||||||
|
|
||||||
share = self._create_share_for_manage()
|
share = self._create_share_for_manage()
|
||||||
|
|
||||||
name = "Name for 'managed' share that had ID %s" % share['id']
|
name = "Name for 'managed' share that had ID %s" % share['id']
|
||||||
|
@ -97,16 +82,19 @@ class ManageNFSShareTest(base.BaseSharesAdminTest):
|
||||||
self.assertNotIn(share['id'], share_ids)
|
self.assertNotIn(share['id'], share_ids)
|
||||||
|
|
||||||
# Manage share
|
# Manage share
|
||||||
managed_share = self.shares_v2_client.manage_share(
|
manage_params = {
|
||||||
service_host=share['host'],
|
'service_host': share['host'],
|
||||||
export_path=share['export_locations'][0],
|
'export_path': share['export_locations'][0],
|
||||||
protocol=share['share_proto'],
|
'protocol': share['share_proto'],
|
||||||
share_type_id=self.st['share_type']['id'],
|
'share_type_id': self.st['share_type']['id'],
|
||||||
name=name,
|
'name': name,
|
||||||
description=description,
|
'description': description,
|
||||||
is_public=is_public,
|
'is_public': is_public,
|
||||||
version=version,
|
'version': version,
|
||||||
)
|
}
|
||||||
|
if CONF.share.multitenancy_enabled:
|
||||||
|
manage_params['share_server_id'] = share['share_server_id']
|
||||||
|
managed_share = self.shares_v2_client.manage_share(**manage_params)
|
||||||
|
|
||||||
# Add managed share to cleanup queue
|
# Add managed share to cleanup queue
|
||||||
self.method_resources.insert(
|
self.method_resources.insert(
|
||||||
|
@ -115,7 +103,7 @@ class ManageNFSShareTest(base.BaseSharesAdminTest):
|
||||||
|
|
||||||
# Wait for success
|
# Wait for success
|
||||||
self.shares_v2_client.wait_for_share_status(managed_share['id'],
|
self.shares_v2_client.wait_for_share_status(managed_share['id'],
|
||||||
'available')
|
constants.STATUS_AVAILABLE)
|
||||||
|
|
||||||
# Verify data of managed share
|
# Verify data of managed share
|
||||||
self.assertEqual(name, managed_share['name'])
|
self.assertEqual(name, managed_share['name'])
|
||||||
|
@ -141,31 +129,7 @@ class ManageNFSShareTest(base.BaseSharesAdminTest):
|
||||||
self.assertNotIn('user_id', managed_share)
|
self.assertNotIn('user_id', managed_share)
|
||||||
|
|
||||||
# Delete share
|
# Delete share
|
||||||
self.shares_v2_client.delete_share(managed_share['id'])
|
self._delete_share_and_wait(managed_share)
|
||||||
self.shares_v2_client.wait_for_resource_deletion(
|
|
||||||
share_id=managed_share['id'])
|
|
||||||
self.assertRaises(lib_exc.NotFound,
|
|
||||||
self.shares_v2_client.get_share,
|
|
||||||
managed_share['id'])
|
|
||||||
|
|
||||||
def _create_share_for_manage(self):
|
|
||||||
creation_data = {
|
|
||||||
'share_type_id': self.st['share_type']['id'],
|
|
||||||
'share_protocol': self.protocol,
|
|
||||||
}
|
|
||||||
|
|
||||||
share = self.create_share(**creation_data)
|
|
||||||
share = self.shares_v2_client.get_share(share['id'])
|
|
||||||
|
|
||||||
if utils.is_microversion_ge(CONF.share.max_api_microversion, "2.9"):
|
|
||||||
el = self.shares_v2_client.list_share_export_locations(share["id"])
|
|
||||||
share["export_locations"] = el
|
|
||||||
|
|
||||||
return share
|
|
||||||
|
|
||||||
def _unmanage_share_and_wait(self, share):
|
|
||||||
self.shares_v2_client.unmanage_share(share['id'])
|
|
||||||
self.shares_v2_client.wait_for_resource_deletion(share_id=share['id'])
|
|
||||||
|
|
||||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||||
@base.skip_if_microversion_not_supported("2.5")
|
@base.skip_if_microversion_not_supported("2.5")
|
||||||
|
@ -186,55 +150,6 @@ class ManageNFSShareTest(base.BaseSharesAdminTest):
|
||||||
def test_manage(self):
|
def test_manage(self):
|
||||||
self._test_manage(check_manage=True)
|
self._test_manage(check_manage=True)
|
||||||
|
|
||||||
@testtools.skipUnless(
|
|
||||||
CONF.share.multitenancy_enabled,
|
|
||||||
"Will be re-enabled along with the updated tests of Manage-Unmanage "
|
|
||||||
"with Share Server patch")
|
|
||||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
|
||||||
def test_manage_invalid(self):
|
|
||||||
# Try to manage share with invalid parameters, it should not succeed
|
|
||||||
# because the scheduler will reject it. If it succeeds, then this test
|
|
||||||
# case failed. Then, in order to remove the resource from backend, we
|
|
||||||
# need to manage it again, properly, so we can delete it. Consequently
|
|
||||||
# the second part of this test also tests that manage operation with a
|
|
||||||
# proper share type works.
|
|
||||||
|
|
||||||
def _delete_share(share_id):
|
|
||||||
self.shares_v2_client.reset_state(share_id)
|
|
||||||
self.shares_v2_client.delete_share(share_id)
|
|
||||||
self.shares_v2_client.wait_for_resource_deletion(share_id=share_id)
|
|
||||||
self.assertRaises(lib_exc.NotFound,
|
|
||||||
self.shares_v2_client.get_share,
|
|
||||||
share_id)
|
|
||||||
|
|
||||||
share = self._create_share_for_manage()
|
|
||||||
|
|
||||||
self._unmanage_share_and_wait(share)
|
|
||||||
|
|
||||||
managed_share = self.shares_v2_client.manage_share(
|
|
||||||
service_host=share['host'],
|
|
||||||
export_path=share['export_locations'][0],
|
|
||||||
protocol=share['share_proto'],
|
|
||||||
share_type_id=self.st_invalid['share_type']['id'])
|
|
||||||
self.addCleanup(_delete_share, managed_share['id'])
|
|
||||||
|
|
||||||
self.shares_v2_client.wait_for_share_status(
|
|
||||||
managed_share['id'], 'manage_error')
|
|
||||||
managed_share = self.shares_v2_client.get_share(managed_share['id'])
|
|
||||||
self.assertEqual(1, int(managed_share['size']))
|
|
||||||
|
|
||||||
# Delete resource from backend. We need to manage the share properly
|
|
||||||
# so it can be removed.
|
|
||||||
managed_share = self.shares_v2_client.manage_share(
|
|
||||||
service_host=share['host'],
|
|
||||||
export_path=share['export_locations'][0],
|
|
||||||
protocol=share['share_proto'],
|
|
||||||
share_type_id=self.st['share_type']['id'])
|
|
||||||
self.addCleanup(_delete_share, managed_share['id'])
|
|
||||||
|
|
||||||
self.shares_v2_client.wait_for_share_status(
|
|
||||||
managed_share['id'], 'available')
|
|
||||||
|
|
||||||
|
|
||||||
class ManageCIFSShareTest(ManageNFSShareTest):
|
class ManageCIFSShareTest(ManageNFSShareTest):
|
||||||
protocol = 'cifs'
|
protocol = 'cifs'
|
||||||
|
|
|
@ -0,0 +1,306 @@
|
||||||
|
# Copyright 2019 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 exceptions as lib_exc
|
||||||
|
import testtools
|
||||||
|
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 ManageNFSShareNegativeTest(base.BaseSharesAdminTest):
|
||||||
|
protocol = 'nfs'
|
||||||
|
|
||||||
|
# NOTE(lseki): be careful running these tests using generic driver
|
||||||
|
# because cinder volumes will stay attached to service Nova VM and
|
||||||
|
# won't be deleted.
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@testtools.skipUnless(
|
||||||
|
CONF.share.run_manage_unmanage_tests,
|
||||||
|
"Manage/unmanage tests are disabled.")
|
||||||
|
def resource_setup(cls):
|
||||||
|
if cls.protocol not in CONF.share.enable_protocols:
|
||||||
|
message = "%s tests are disabled" % cls.protocol
|
||||||
|
raise cls.skipException(message)
|
||||||
|
|
||||||
|
utils.skip_if_manage_not_supported_for_version()
|
||||||
|
|
||||||
|
super(ManageNFSShareNegativeTest, cls).resource_setup()
|
||||||
|
|
||||||
|
# Create share type
|
||||||
|
cls.st_name = data_utils.rand_name("manage-st-name")
|
||||||
|
cls.extra_specs = {
|
||||||
|
'storage_protocol': CONF.share.capability_storage_protocol,
|
||||||
|
'driver_handles_share_servers': CONF.share.multitenancy_enabled,
|
||||||
|
'snapshot_support': CONF.share.capability_snapshot_support,
|
||||||
|
}
|
||||||
|
|
||||||
|
cls.st = cls.create_share_type(
|
||||||
|
name=cls.st_name,
|
||||||
|
cleanup_in_class=True,
|
||||||
|
extra_specs=cls.extra_specs)
|
||||||
|
|
||||||
|
def _manage_share_for_cleanup_and_wait(self, params,
|
||||||
|
state=constants.STATUS_AVAILABLE):
|
||||||
|
# Manage the share, schedule its deletion upon tearDown and wait for
|
||||||
|
# the expected state.
|
||||||
|
# Return the managed share object.
|
||||||
|
managed_share = self.shares_v2_client.manage_share(**params)
|
||||||
|
self.addCleanup(self._reset_state_and_delete_share,
|
||||||
|
managed_share)
|
||||||
|
self.shares_v2_client.wait_for_share_status(
|
||||||
|
managed_share['id'], state)
|
||||||
|
|
||||||
|
return managed_share
|
||||||
|
|
||||||
|
def _get_manage_params_from_share(self, share, invalid_params=None):
|
||||||
|
valid_params = {
|
||||||
|
'service_host': share['host'],
|
||||||
|
'protocol': share['share_proto'],
|
||||||
|
'share_type_id': share['share_type'],
|
||||||
|
}
|
||||||
|
if CONF.share.multitenancy_enabled:
|
||||||
|
valid_params['share_server_id'] = share['share_server_id']
|
||||||
|
|
||||||
|
if utils.is_microversion_ge(CONF.share.max_api_microversion, "2.9"):
|
||||||
|
el = self.shares_v2_client.list_share_export_locations(share["id"])
|
||||||
|
valid_params['export_path'] = el[0]['path']
|
||||||
|
|
||||||
|
if invalid_params:
|
||||||
|
valid_params.update(invalid_params)
|
||||||
|
|
||||||
|
return valid_params
|
||||||
|
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_manage_invalid_param_raises_exception(self):
|
||||||
|
# Try to manage share with invalid parameters, it should not succeed
|
||||||
|
# because the api will reject it. If it succeeds, then this test case
|
||||||
|
# failed. Then, in order to remove the resource from backend, we need
|
||||||
|
# to manage it again, properly, so we can delete it. Consequently the
|
||||||
|
# second part of this test also tests that manage operation with a
|
||||||
|
# proper share type that works.
|
||||||
|
|
||||||
|
share = self._create_share_for_manage()
|
||||||
|
|
||||||
|
valid_params = self._get_manage_params_from_share(share)
|
||||||
|
self._unmanage_share_and_wait(share)
|
||||||
|
|
||||||
|
test_set = [
|
||||||
|
('service_host', 'invalid_host#invalid_pool', lib_exc.NotFound),
|
||||||
|
('share_type_id', 'invalid_share_type_id', lib_exc.NotFound),
|
||||||
|
]
|
||||||
|
if CONF.share.multitenancy_enabled:
|
||||||
|
test_set.append(
|
||||||
|
('share_server_id', 'invalid_server_id', lib_exc.BadRequest)
|
||||||
|
)
|
||||||
|
|
||||||
|
for invalid_key, invalid_value, expected_exception in test_set:
|
||||||
|
# forge a bad param
|
||||||
|
invalid_params = valid_params.copy()
|
||||||
|
invalid_params.update({
|
||||||
|
invalid_key: invalid_value
|
||||||
|
})
|
||||||
|
|
||||||
|
# the attempt to manage with bad param should fail and raise an
|
||||||
|
# exception
|
||||||
|
self.assertRaises(
|
||||||
|
expected_exception,
|
||||||
|
self.shares_v2_client.manage_share,
|
||||||
|
**invalid_params
|
||||||
|
)
|
||||||
|
|
||||||
|
# manage it properly and schedule cleanup upon tearDown
|
||||||
|
self._manage_share_for_cleanup_and_wait(valid_params)
|
||||||
|
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_manage_invalid_param_manage_error(self):
|
||||||
|
# Try to manage share with invalid parameters, it should not succeed.
|
||||||
|
# If it succeeds, then this test case failed. Then, in order to remove
|
||||||
|
# the resource from backend, we need to manage it again, properly, so
|
||||||
|
# we can delete it. Consequently the second part of this test also
|
||||||
|
# tests that manage operation with a proper share type works.
|
||||||
|
share = self._create_share_for_manage()
|
||||||
|
|
||||||
|
valid_params = self._get_manage_params_from_share(share)
|
||||||
|
self._unmanage_share_and_wait(share)
|
||||||
|
|
||||||
|
for invalid_key, invalid_value in (
|
||||||
|
('export_path', 'invalid_export'),
|
||||||
|
('protocol', 'invalid_protocol'),
|
||||||
|
):
|
||||||
|
|
||||||
|
# forge a bad param
|
||||||
|
invalid_params = valid_params.copy()
|
||||||
|
invalid_params.update({invalid_key: invalid_value})
|
||||||
|
|
||||||
|
# the attempt to manage the share with invalid params should fail
|
||||||
|
# and leave it in manage_error state
|
||||||
|
invalid_share = self.shares_v2_client.manage_share(
|
||||||
|
**invalid_params
|
||||||
|
)
|
||||||
|
self.shares_v2_client.wait_for_share_status(
|
||||||
|
invalid_share['id'], constants.STATUS_MANAGE_ERROR)
|
||||||
|
|
||||||
|
# cleanup
|
||||||
|
self._unmanage_share_and_wait(invalid_share)
|
||||||
|
|
||||||
|
# manage it properly and schedule cleanup upon tearDown
|
||||||
|
self._manage_share_for_cleanup_and_wait(valid_params)
|
||||||
|
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_manage_share_duplicate(self):
|
||||||
|
share = self._create_share_for_manage()
|
||||||
|
|
||||||
|
manage_params = self._get_manage_params_from_share(share)
|
||||||
|
self._unmanage_share_and_wait(share)
|
||||||
|
|
||||||
|
# manage the share for the first time
|
||||||
|
managed_share = self._manage_share_for_cleanup_and_wait(manage_params)
|
||||||
|
|
||||||
|
# update managed share's reference
|
||||||
|
managed_share = self.shares_v2_client.get_share(managed_share['id'])
|
||||||
|
manage_params = self._get_manage_params_from_share(managed_share)
|
||||||
|
|
||||||
|
# the second attempt to manage the same share should fail
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.Conflict,
|
||||||
|
self.shares_v2_client.manage_share,
|
||||||
|
**manage_params
|
||||||
|
)
|
||||||
|
|
||||||
|
@testtools.skipUnless(CONF.share.multitenancy_enabled,
|
||||||
|
'Multitenancy tests are disabled.')
|
||||||
|
@utils.skip_if_microversion_not_supported("2.49")
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_manage_share_without_share_server_id(self):
|
||||||
|
share = self._create_share_for_manage()
|
||||||
|
manage_params = self._get_manage_params_from_share(share)
|
||||||
|
share_server_id = manage_params.pop('share_server_id')
|
||||||
|
self._unmanage_share_and_wait(share)
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.BadRequest,
|
||||||
|
self.shares_v2_client.manage_share,
|
||||||
|
**manage_params)
|
||||||
|
|
||||||
|
manage_params['share_server_id'] = share_server_id
|
||||||
|
self._manage_share_for_cleanup_and_wait(manage_params)
|
||||||
|
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_delete_share_in_manage_error(self):
|
||||||
|
share = self._create_share_for_manage()
|
||||||
|
|
||||||
|
valid_params = self._get_manage_params_from_share(share)
|
||||||
|
|
||||||
|
# forge bad param to have a share in manage_error state
|
||||||
|
invalid_params = valid_params.copy()
|
||||||
|
invalid_params.update({'export_path': 'invalid'})
|
||||||
|
invalid_share = self.shares_v2_client.manage_share(**invalid_params)
|
||||||
|
|
||||||
|
self.shares_v2_client.wait_for_share_status(
|
||||||
|
invalid_share['id'], constants.STATUS_MANAGE_ERROR)
|
||||||
|
self._unmanage_share_and_wait(share)
|
||||||
|
|
||||||
|
# the attempt to delete a share in manage_error should raise an
|
||||||
|
# exception
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.Forbidden,
|
||||||
|
self.shares_v2_client.delete_share,
|
||||||
|
invalid_share['id']
|
||||||
|
)
|
||||||
|
|
||||||
|
# cleanup
|
||||||
|
self.shares_v2_client.unmanage_share(invalid_share['id'])
|
||||||
|
self._manage_share_for_cleanup_and_wait(valid_params)
|
||||||
|
|
||||||
|
@testtools.skipUnless(CONF.share.run_snapshot_tests,
|
||||||
|
'Snapshot tests are disabled.')
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_unmanage_share_with_snapshot(self):
|
||||||
|
# A share with snapshot cannot be unmanaged
|
||||||
|
share = self._create_share_for_manage()
|
||||||
|
|
||||||
|
snap = self.create_snapshot_wait_for_active(share["id"])
|
||||||
|
snap = self.shares_v2_client.get_snapshot(snap['id'])
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.Forbidden,
|
||||||
|
self.shares_v2_client.unmanage_share,
|
||||||
|
share['id']
|
||||||
|
)
|
||||||
|
|
||||||
|
# cleanup
|
||||||
|
self._delete_snapshot_and_wait(snap)
|
||||||
|
self._delete_share_and_wait(share)
|
||||||
|
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_unmanage_share_transitional_state(self):
|
||||||
|
# A share in transitional state cannot be unmanaged
|
||||||
|
share = self._create_share_for_manage()
|
||||||
|
for state in (constants.STATUS_CREATING,
|
||||||
|
constants.STATUS_DELETING,
|
||||||
|
constants.STATUS_MIGRATING,
|
||||||
|
constants.STATUS_MIGRATING_TO):
|
||||||
|
self.shares_v2_client.reset_state(share['id'], state)
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.Forbidden,
|
||||||
|
self.shares_v2_client.unmanage_share,
|
||||||
|
share['id']
|
||||||
|
)
|
||||||
|
|
||||||
|
# cleanup
|
||||||
|
self._reset_state_and_delete_share(share)
|
||||||
|
|
||||||
|
@testtools.skipUnless(CONF.share.multitenancy_enabled,
|
||||||
|
'Multitenancy tests are disabled.')
|
||||||
|
@utils.skip_if_microversion_not_supported("2.48")
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_unmanage_share_with_server_unsupported(self):
|
||||||
|
share = self._create_share_for_manage()
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.Forbidden,
|
||||||
|
self.shares_v2_client.unmanage_share,
|
||||||
|
share['id'], version="2.48")
|
||||||
|
|
||||||
|
self._delete_share_and_wait(share)
|
||||||
|
|
||||||
|
|
||||||
|
class ManageCIFSShareNegativeTest(ManageNFSShareNegativeTest):
|
||||||
|
protocol = 'cifs'
|
||||||
|
|
||||||
|
|
||||||
|
class ManageGLUSTERFSShareNegativeTest(ManageNFSShareNegativeTest):
|
||||||
|
protocol = 'glusterfs'
|
||||||
|
|
||||||
|
|
||||||
|
class ManageHDFSShareNegativeTest(ManageNFSShareNegativeTest):
|
||||||
|
protocol = 'hdfs'
|
||||||
|
|
||||||
|
|
||||||
|
class ManageCephFSShareNegativeTest(ManageNFSShareNegativeTest):
|
||||||
|
protocol = 'cephfs'
|
||||||
|
|
||||||
|
|
||||||
|
class ManageMapRFSShareNegativeTest(ManageNFSShareNegativeTest):
|
||||||
|
protocol = 'maprfs'
|
|
@ -22,7 +22,9 @@ from tempest.lib import exceptions as lib_exc
|
||||||
import testtools
|
import testtools
|
||||||
from testtools import testcase as tc
|
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.tests.api import base
|
||||||
|
from manila_tempest_tests import utils
|
||||||
|
|
||||||
CONF = config.CONF
|
CONF = config.CONF
|
||||||
|
|
||||||
|
@ -168,6 +170,9 @@ class ShareServersAdminTest(base.BaseSharesAdminTest):
|
||||||
"updated_at",
|
"updated_at",
|
||||||
"backend_details",
|
"backend_details",
|
||||||
]
|
]
|
||||||
|
if utils.is_microversion_ge(CONF.share.max_api_microversion, "2.49"):
|
||||||
|
keys.append("is_auto_deletable")
|
||||||
|
keys.append("identifier")
|
||||||
# all expected keys are present
|
# all expected keys are present
|
||||||
for key in keys:
|
for key in keys:
|
||||||
self.assertIn(key, server.keys())
|
self.assertIn(key, server.keys())
|
||||||
|
@ -261,3 +266,65 @@ class ShareServersAdminTest(base.BaseSharesAdminTest):
|
||||||
if delete_share_network:
|
if delete_share_network:
|
||||||
self.shares_v2_client.wait_for_resource_deletion(
|
self.shares_v2_client.wait_for_resource_deletion(
|
||||||
sn_id=new_sn["id"])
|
sn_id=new_sn["id"])
|
||||||
|
|
||||||
|
@testtools.skipIf(CONF.share.share_network_id != "",
|
||||||
|
"This test is not suitable for pre-existing "
|
||||||
|
"share_network.")
|
||||||
|
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
@utils.skip_if_microversion_not_supported("2.49")
|
||||||
|
def test_share_server_reset_state(self):
|
||||||
|
# Get network and subnet from existing share_network and reuse it
|
||||||
|
# to be able to delete share_server after test ends.
|
||||||
|
new_sn = self.create_share_network(
|
||||||
|
neutron_net_id=self.share_network['neutron_net_id'],
|
||||||
|
neutron_subnet_id=self.share_network['neutron_subnet_id'])
|
||||||
|
share = self.create_share(
|
||||||
|
share_type_id=self.share_type_id,
|
||||||
|
share_network_id=new_sn['id']
|
||||||
|
)
|
||||||
|
share = self.shares_v2_client.get_share(share['id'])
|
||||||
|
|
||||||
|
# obtain share server
|
||||||
|
share_server = self.shares_v2_client.show_share_server(
|
||||||
|
share['share_server_id']
|
||||||
|
)
|
||||||
|
|
||||||
|
for state in (constants.SERVER_STATE_ACTIVE,
|
||||||
|
constants.SERVER_STATE_CREATING,
|
||||||
|
constants.SERVER_STATE_DELETING,
|
||||||
|
constants.SERVER_STATE_ERROR,
|
||||||
|
constants.SERVER_STATE_MANAGE_ERROR,
|
||||||
|
constants.SERVER_STATE_MANAGE_STARTING,
|
||||||
|
constants.SERVER_STATE_UNMANAGE_ERROR,
|
||||||
|
constants.SERVER_STATE_UNMANAGE_STARTING):
|
||||||
|
|
||||||
|
# leave it in a new state
|
||||||
|
self.shares_v2_client.share_server_reset_state(
|
||||||
|
share_server['id'],
|
||||||
|
status=state,
|
||||||
|
)
|
||||||
|
self.shares_v2_client.wait_for_share_server_status(
|
||||||
|
share_server['id'],
|
||||||
|
status=state
|
||||||
|
)
|
||||||
|
|
||||||
|
# bring the share server back in the active state
|
||||||
|
self.shares_v2_client.share_server_reset_state(
|
||||||
|
share_server['id'],
|
||||||
|
status=constants.SERVER_STATE_ACTIVE,
|
||||||
|
)
|
||||||
|
self.shares_v2_client.wait_for_share_server_status(
|
||||||
|
share_server['id'],
|
||||||
|
status=constants.SERVER_STATE_ACTIVE
|
||||||
|
)
|
||||||
|
|
||||||
|
# delete share
|
||||||
|
self.shares_v2_client.delete_share(share["id"])
|
||||||
|
self.shares_v2_client.wait_for_resource_deletion(
|
||||||
|
share_id=share["id"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# delete share network. This will trigger share server deletion
|
||||||
|
self.shares_v2_client.delete_share_network(new_sn["id"])
|
||||||
|
self.shares_v2_client.wait_for_resource_deletion(
|
||||||
|
sn_id=new_sn['id'])
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
# Copyright 2019 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
|
||||||
|
import testtools
|
||||||
|
from testtools import testcase as tc
|
||||||
|
|
||||||
|
from manila_tempest_tests.tests.api import base
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
|
||||||
|
|
||||||
|
@base.skip_if_microversion_lt("2.49")
|
||||||
|
@testtools.skipUnless(
|
||||||
|
CONF.share.multitenancy_enabled,
|
||||||
|
'Multitenancy tests are disabled.')
|
||||||
|
@testtools.skipUnless(
|
||||||
|
CONF.share.run_manage_unmanage_tests,
|
||||||
|
'Manage/unmanage tests are disabled.')
|
||||||
|
class ManageShareServersTest(base.BaseSharesAdminTest):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resource_setup(cls):
|
||||||
|
super(ManageShareServersTest, cls).resource_setup()
|
||||||
|
|
||||||
|
# create share type
|
||||||
|
cls.st_name = data_utils.rand_name("manage-st-name")
|
||||||
|
cls.extra_specs = {
|
||||||
|
'storage_protocol': CONF.share.capability_storage_protocol,
|
||||||
|
'driver_handles_share_servers': CONF.share.multitenancy_enabled,
|
||||||
|
}
|
||||||
|
cls.share_type = cls.create_share_type(
|
||||||
|
name=cls.st_name,
|
||||||
|
cleanup_in_class=True,
|
||||||
|
extra_specs=cls.extra_specs)
|
||||||
|
|
||||||
|
@testtools.skipIf(CONF.share.share_network_id != "",
|
||||||
|
"This test is not suitable for pre-existing "
|
||||||
|
"share_network.")
|
||||||
|
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||||
|
def test_manage_share_server(self):
|
||||||
|
|
||||||
|
# create a new share network to make sure that a new share server
|
||||||
|
# will be created
|
||||||
|
original_share_network = self.shares_v2_client.get_share_network(
|
||||||
|
self.shares_v2_client.share_network_id
|
||||||
|
)
|
||||||
|
share_network = self.create_share_network(
|
||||||
|
neutron_net_id=original_share_network['neutron_net_id'],
|
||||||
|
neutron_subnet_id=original_share_network['neutron_subnet_id'],
|
||||||
|
cleanup_in_class=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# create share
|
||||||
|
share = self.create_share(
|
||||||
|
share_type_id=self.share_type['share_type']['id'],
|
||||||
|
share_network_id=share_network['id']
|
||||||
|
)
|
||||||
|
share = self.shares_v2_client.get_share(share['id'])
|
||||||
|
el = self.shares_v2_client.list_share_export_locations(share['id'])
|
||||||
|
share['export_locations'] = el
|
||||||
|
share_server = self.shares_v2_client.show_share_server(
|
||||||
|
share['share_server_id']
|
||||||
|
)
|
||||||
|
|
||||||
|
keys = [
|
||||||
|
"id",
|
||||||
|
"host",
|
||||||
|
"project_id",
|
||||||
|
"status",
|
||||||
|
"share_network_name",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
"backend_details",
|
||||||
|
"is_auto_deletable",
|
||||||
|
"identifier",
|
||||||
|
]
|
||||||
|
# all expected keys are present
|
||||||
|
for key in keys:
|
||||||
|
self.assertIn(key, share_server)
|
||||||
|
|
||||||
|
# check that the share server is initially auto-deletable
|
||||||
|
self.assertIs(True, share_server["is_auto_deletable"])
|
||||||
|
self.assertIsNotNone(share_server["identifier"])
|
||||||
|
|
||||||
|
self._unmanage_share_and_wait(share)
|
||||||
|
|
||||||
|
# Starting from microversion 2.49, any share server that has ever had
|
||||||
|
# an unmanaged share will never be auto-deleted.
|
||||||
|
share_server = self.shares_v2_client.show_share_server(
|
||||||
|
share_server['id']
|
||||||
|
)
|
||||||
|
self.assertIs(False, share_server['is_auto_deletable'])
|
||||||
|
|
||||||
|
# unmanage share server and manage it again
|
||||||
|
self._unmanage_share_server_and_wait(share_server)
|
||||||
|
managed_share_server = self._manage_share_server(share_server)
|
||||||
|
managed_share = self._manage_share(
|
||||||
|
share,
|
||||||
|
name="managed share that had ID %s" % share['id'],
|
||||||
|
description="description for managed share",
|
||||||
|
share_server_id=managed_share_server['id']
|
||||||
|
)
|
||||||
|
|
||||||
|
# check managed share server
|
||||||
|
managed_share_server = self.shares_v2_client.show_share_server(
|
||||||
|
managed_share_server['id']
|
||||||
|
)
|
||||||
|
|
||||||
|
# all expected keys are present in the managed share server
|
||||||
|
for key in keys:
|
||||||
|
self.assertIn(key, managed_share_server)
|
||||||
|
|
||||||
|
# check that managed share server is used by the managed share
|
||||||
|
self.assertEqual(
|
||||||
|
managed_share['share_server_id'],
|
||||||
|
managed_share_server['id']
|
||||||
|
)
|
||||||
|
|
||||||
|
# check that the managed share server is still not auto-deletable
|
||||||
|
self.assertIs(False, managed_share_server["is_auto_deletable"])
|
||||||
|
|
||||||
|
# delete share
|
||||||
|
self._delete_share_and_wait(managed_share)
|
||||||
|
|
||||||
|
# delete share server
|
||||||
|
self._delete_share_server_and_wait(managed_share_server['id'])
|
|
@ -0,0 +1,320 @@
|
||||||
|
# Copyright 2019 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.common.utils import data_utils
|
||||||
|
from tempest.lib import exceptions as lib_exc
|
||||||
|
import testtools
|
||||||
|
from testtools import testcase as tc
|
||||||
|
|
||||||
|
from manila_tempest_tests.common import constants
|
||||||
|
from manila_tempest_tests import share_exceptions
|
||||||
|
from manila_tempest_tests.tests.api import base
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
|
||||||
|
|
||||||
|
@base.skip_if_microversion_lt("2.49")
|
||||||
|
@testtools.skipUnless(
|
||||||
|
CONF.share.multitenancy_enabled,
|
||||||
|
'Multitenancy tests are disabled')
|
||||||
|
@testtools.skipUnless(
|
||||||
|
CONF.share.run_manage_unmanage_tests,
|
||||||
|
'Manage/unmanage tests are disabled.')
|
||||||
|
@ddt.ddt
|
||||||
|
class ManageShareServersNegativeTest(base.BaseSharesAdminTest):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resource_setup(cls):
|
||||||
|
super(ManageShareServersNegativeTest, cls).resource_setup()
|
||||||
|
|
||||||
|
# create share type
|
||||||
|
cls.st_name = data_utils.rand_name("manage-st-name")
|
||||||
|
cls.extra_specs = {
|
||||||
|
'storage_protocol': CONF.share.capability_storage_protocol,
|
||||||
|
'driver_handles_share_servers': CONF.share.multitenancy_enabled,
|
||||||
|
}
|
||||||
|
cls.share_type = cls.create_share_type(
|
||||||
|
name=cls.st_name,
|
||||||
|
cleanup_in_class=True,
|
||||||
|
extra_specs=cls.extra_specs)
|
||||||
|
cls.original_share_network = cls.shares_v2_client.get_share_network(
|
||||||
|
cls.shares_v2_client.share_network_id)
|
||||||
|
|
||||||
|
def _create_share_with_new_share_network(self):
|
||||||
|
share_network = self.create_share_network(
|
||||||
|
neutron_net_id=self.original_share_network['neutron_net_id'],
|
||||||
|
neutron_subnet_id=self.original_share_network['neutron_subnet_id'],
|
||||||
|
cleanup_in_class=True
|
||||||
|
)
|
||||||
|
share = self.create_share(
|
||||||
|
share_type_id=self.share_type['share_type']['id'],
|
||||||
|
share_network_id=share_network['id']
|
||||||
|
)
|
||||||
|
return self.shares_v2_client.get_share(share['id'])
|
||||||
|
|
||||||
|
@ddt.data(
|
||||||
|
('host', 'invalid_host'),
|
||||||
|
('share_network_id', 'invalid_share_network_id'),
|
||||||
|
)
|
||||||
|
@ddt.unpack
|
||||||
|
@testtools.skipIf(CONF.share.share_network_id != "",
|
||||||
|
"This test is not suitable for pre-existing "
|
||||||
|
"share_network.")
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_manage_share_server_invalid_params(self, param, invalid_value):
|
||||||
|
|
||||||
|
# create share
|
||||||
|
share = self._create_share_with_new_share_network()
|
||||||
|
el = self.shares_v2_client.list_share_export_locations(share['id'])
|
||||||
|
share['export_locations'] = el
|
||||||
|
share_server = self.shares_v2_client.show_share_server(
|
||||||
|
share['share_server_id']
|
||||||
|
)
|
||||||
|
|
||||||
|
self._unmanage_share_and_wait(share)
|
||||||
|
self._unmanage_share_server_and_wait(share_server)
|
||||||
|
|
||||||
|
# forge invalid params
|
||||||
|
invalid_params = share_server.copy()
|
||||||
|
invalid_params[param] = invalid_value
|
||||||
|
|
||||||
|
# try to manage in the wrong way
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.BadRequest,
|
||||||
|
self._manage_share_server,
|
||||||
|
share_server,
|
||||||
|
invalid_params
|
||||||
|
)
|
||||||
|
|
||||||
|
# manage in the correct way
|
||||||
|
managed_share_server = self._manage_share_server(share_server)
|
||||||
|
managed_share = self._manage_share(
|
||||||
|
share,
|
||||||
|
name="managed share that had ID %s" % share['id'],
|
||||||
|
description="description for managed share",
|
||||||
|
share_server_id=managed_share_server['id']
|
||||||
|
)
|
||||||
|
|
||||||
|
# delete share
|
||||||
|
self._delete_share_and_wait(managed_share)
|
||||||
|
|
||||||
|
# delete share server
|
||||||
|
self._delete_share_server_and_wait(managed_share_server['id'])
|
||||||
|
|
||||||
|
@testtools.skipIf(CONF.share.share_network_id != "",
|
||||||
|
"This test is not suitable for pre-existing "
|
||||||
|
"share_network.")
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_delete_share_server_invalid_state(self):
|
||||||
|
|
||||||
|
# create share
|
||||||
|
share = self._create_share_with_new_share_network()
|
||||||
|
|
||||||
|
for state in (constants.SERVER_STATE_MANAGE_STARTING,
|
||||||
|
constants.SERVER_STATE_CREATING,
|
||||||
|
constants.SERVER_STATE_DELETING):
|
||||||
|
# leave it in the wrong state
|
||||||
|
self.shares_v2_client.share_server_reset_state(
|
||||||
|
share['share_server_id'],
|
||||||
|
status=state,
|
||||||
|
)
|
||||||
|
|
||||||
|
# try to delete
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.Forbidden,
|
||||||
|
self.shares_v2_client.delete_share_server,
|
||||||
|
share['share_server_id'],
|
||||||
|
)
|
||||||
|
|
||||||
|
# put it in the correct state
|
||||||
|
self.shares_v2_client.share_server_reset_state(
|
||||||
|
share['share_server_id'],
|
||||||
|
status=constants.SERVER_STATE_ACTIVE,
|
||||||
|
)
|
||||||
|
self.shares_v2_client.wait_for_share_server_status(
|
||||||
|
share['share_server_id'],
|
||||||
|
constants.SERVER_STATE_ACTIVE,
|
||||||
|
)
|
||||||
|
|
||||||
|
# delete share
|
||||||
|
self._delete_share_and_wait(share)
|
||||||
|
|
||||||
|
# delete share server
|
||||||
|
self._delete_share_server_and_wait(share['share_server_id'])
|
||||||
|
|
||||||
|
@testtools.skipIf(CONF.share.share_network_id != "",
|
||||||
|
"This test is not suitable for pre-existing "
|
||||||
|
"share_network.")
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_unmanage_share_server_invalid_state(self):
|
||||||
|
|
||||||
|
# create share
|
||||||
|
share = self._create_share_with_new_share_network()
|
||||||
|
|
||||||
|
for state in (constants.SERVER_STATE_MANAGE_STARTING,
|
||||||
|
constants.SERVER_STATE_CREATING,
|
||||||
|
constants.SERVER_STATE_DELETING):
|
||||||
|
# leave it in the wrong state
|
||||||
|
self.shares_v2_client.share_server_reset_state(
|
||||||
|
share['share_server_id'],
|
||||||
|
status=state,
|
||||||
|
)
|
||||||
|
|
||||||
|
# try to unmanage
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.BadRequest,
|
||||||
|
self.shares_v2_client.unmanage_share_server,
|
||||||
|
share['share_server_id'],
|
||||||
|
)
|
||||||
|
|
||||||
|
# put it in the correct state
|
||||||
|
self.shares_v2_client.share_server_reset_state(
|
||||||
|
share['share_server_id'],
|
||||||
|
status=constants.SERVER_STATE_ACTIVE,
|
||||||
|
)
|
||||||
|
self.shares_v2_client.wait_for_share_server_status(
|
||||||
|
share['share_server_id'],
|
||||||
|
constants.SERVER_STATE_ACTIVE,
|
||||||
|
)
|
||||||
|
|
||||||
|
# delete share
|
||||||
|
self._delete_share_and_wait(share)
|
||||||
|
|
||||||
|
# delete share server
|
||||||
|
self._delete_share_server_and_wait(share['share_server_id'])
|
||||||
|
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_share_server_reset_state_invalid_state(self):
|
||||||
|
|
||||||
|
# create share
|
||||||
|
share = self.create_share(
|
||||||
|
share_type_id=self.share_type['share_type']['id'])
|
||||||
|
share = self.shares_v2_client.get_share(share['id'])
|
||||||
|
|
||||||
|
# try to change it to wrong state
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.BadRequest,
|
||||||
|
self.shares_v2_client.share_server_reset_state,
|
||||||
|
share['share_server_id'],
|
||||||
|
status='invalid_state',
|
||||||
|
)
|
||||||
|
|
||||||
|
# delete share
|
||||||
|
self._delete_share_and_wait(share)
|
||||||
|
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_unmanage_share_server_with_share(self):
|
||||||
|
|
||||||
|
# create share
|
||||||
|
share = self.create_share(
|
||||||
|
share_type_id=self.share_type['share_type']['id'])
|
||||||
|
share = self.shares_v2_client.get_share(share['id'])
|
||||||
|
|
||||||
|
# try to unmanage
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.BadRequest,
|
||||||
|
self.shares_v2_client.unmanage_share_server,
|
||||||
|
share['share_server_id'],
|
||||||
|
)
|
||||||
|
|
||||||
|
# delete share
|
||||||
|
self._delete_share_and_wait(share)
|
||||||
|
|
||||||
|
@testtools.skipIf(CONF.share.share_network_id != "",
|
||||||
|
"This test is not suitable for pre-existing "
|
||||||
|
"share_network.")
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_manage_share_server_invalid_identifier(self):
|
||||||
|
# create share
|
||||||
|
share = self._create_share_with_new_share_network()
|
||||||
|
el = self.shares_v2_client.list_share_export_locations(share['id'])
|
||||||
|
share['export_locations'] = el
|
||||||
|
share_server = self.shares_v2_client.show_share_server(
|
||||||
|
share['share_server_id']
|
||||||
|
)
|
||||||
|
|
||||||
|
self._unmanage_share_and_wait(share)
|
||||||
|
self._unmanage_share_server_and_wait(share_server)
|
||||||
|
|
||||||
|
# forge invalid params
|
||||||
|
invalid_params = share_server.copy()
|
||||||
|
invalid_params['identifier'] = 'invalid_id'
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
share_exceptions.ShareServerBuildErrorException,
|
||||||
|
self._manage_share_server,
|
||||||
|
invalid_params
|
||||||
|
)
|
||||||
|
|
||||||
|
# manage in the correct way
|
||||||
|
managed_share_server = self._manage_share_server(share_server)
|
||||||
|
managed_share_server = self.shares_v2_client.show_share_server(
|
||||||
|
managed_share_server['id']
|
||||||
|
)
|
||||||
|
managed_share = self._manage_share(
|
||||||
|
share,
|
||||||
|
name="managed share that had ID %s" % share['id'],
|
||||||
|
description="description for managed share",
|
||||||
|
share_server_id=managed_share_server['id']
|
||||||
|
)
|
||||||
|
|
||||||
|
# delete share
|
||||||
|
self._delete_share_and_wait(managed_share)
|
||||||
|
|
||||||
|
# delete share server
|
||||||
|
self._delete_share_server_and_wait(managed_share_server['id'])
|
||||||
|
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_manage_share_server_double_manage(self):
|
||||||
|
|
||||||
|
# create share
|
||||||
|
share = self.create_share(
|
||||||
|
share_type_id=self.share_type['share_type']['id'])
|
||||||
|
share = self.shares_v2_client.get_share(share['id'])
|
||||||
|
|
||||||
|
share_server = self.shares_v2_client.show_share_server(
|
||||||
|
share['share_server_id'])
|
||||||
|
|
||||||
|
# try with more data around the identifier
|
||||||
|
invalid_params = share_server.copy()
|
||||||
|
invalid_params['identifier'] = (
|
||||||
|
'foo_' + share_server['identifier'] + '_bar')
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.BadRequest,
|
||||||
|
self._manage_share_server,
|
||||||
|
invalid_params)
|
||||||
|
|
||||||
|
# try with part of the identifier
|
||||||
|
invalid_params['identifier'] = share_server['identifier'].split("-")[2]
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.BadRequest,
|
||||||
|
self._manage_share_server,
|
||||||
|
invalid_params)
|
||||||
|
|
||||||
|
# try with same identifier but underscores
|
||||||
|
invalid_params['identifier'] = (
|
||||||
|
share_server['identifier'].replace("-", "_"))
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.BadRequest,
|
||||||
|
self._manage_share_server,
|
||||||
|
invalid_params)
|
||||||
|
|
||||||
|
# delete share
|
||||||
|
self._delete_share_and_wait(share)
|
|
@ -14,13 +14,13 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import ddt
|
import ddt
|
||||||
import six
|
|
||||||
from tempest import config
|
from tempest import config
|
||||||
from tempest.lib.common.utils import data_utils
|
from tempest.lib.common.utils import data_utils
|
||||||
from tempest.lib import exceptions as lib_exc
|
from tempest.lib import exceptions as lib_exc
|
||||||
import testtools
|
import testtools
|
||||||
from testtools import testcase as tc
|
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.tests.api import base
|
||||||
from manila_tempest_tests import utils
|
from manila_tempest_tests import utils
|
||||||
|
|
||||||
|
@ -36,27 +36,24 @@ class ManageNFSSnapshotTest(base.BaseSharesAdminTest):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@base.skip_if_microversion_lt("2.12")
|
@base.skip_if_microversion_lt("2.12")
|
||||||
@testtools.skipIf(
|
|
||||||
CONF.share.multitenancy_enabled,
|
|
||||||
"Only for driver_handles_share_servers = False driver mode.")
|
|
||||||
@testtools.skipUnless(
|
@testtools.skipUnless(
|
||||||
CONF.share.run_manage_unmanage_snapshot_tests,
|
CONF.share.run_manage_unmanage_snapshot_tests,
|
||||||
"Manage/unmanage snapshot tests are disabled.")
|
"Manage/unmanage snapshot tests are disabled.")
|
||||||
def resource_setup(cls):
|
def resource_setup(cls):
|
||||||
super(ManageNFSSnapshotTest, cls).resource_setup()
|
|
||||||
if cls.protocol not in CONF.share.enable_protocols:
|
if cls.protocol not in CONF.share.enable_protocols:
|
||||||
message = "%s tests are disabled" % cls.protocol
|
message = "%s tests are disabled" % cls.protocol
|
||||||
raise cls.skipException(message)
|
raise cls.skipException(message)
|
||||||
|
|
||||||
|
utils.skip_if_manage_not_supported_for_version()
|
||||||
|
|
||||||
|
super(ManageNFSSnapshotTest, cls).resource_setup()
|
||||||
|
|
||||||
# Create share type
|
# Create share type
|
||||||
cls.st_name = data_utils.rand_name("tempest-manage-st-name")
|
cls.st_name = data_utils.rand_name("tempest-manage-st-name")
|
||||||
cls.extra_specs = {
|
cls.extra_specs = {
|
||||||
'storage_protocol': CONF.share.capability_storage_protocol,
|
'storage_protocol': CONF.share.capability_storage_protocol,
|
||||||
'driver_handles_share_servers': False,
|
'driver_handles_share_servers': CONF.share.multitenancy_enabled,
|
||||||
'snapshot_support': six.text_type(
|
'snapshot_support': CONF.share.capability_snapshot_support,
|
||||||
CONF.share.capability_snapshot_support),
|
|
||||||
'create_share_from_snapshot_support': six.text_type(
|
|
||||||
CONF.share.capability_create_share_from_snapshot_support)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cls.st = cls.create_share_type(
|
cls.st = cls.create_share_type(
|
||||||
|
@ -76,6 +73,8 @@ class ManageNFSSnapshotTest(base.BaseSharesAdminTest):
|
||||||
snapshot['id'])
|
snapshot['id'])
|
||||||
description = "Description for 'managed' snapshot"
|
description = "Description for 'managed' snapshot"
|
||||||
|
|
||||||
|
utils.skip_if_manage_not_supported_for_version(version)
|
||||||
|
|
||||||
# Manage snapshot
|
# Manage snapshot
|
||||||
share_id = snapshot['share_id']
|
share_id = snapshot['share_id']
|
||||||
snapshot = self.shares_v2_client.manage_snapshot(
|
snapshot = self.shares_v2_client.manage_snapshot(
|
||||||
|
@ -96,8 +95,10 @@ class ManageNFSSnapshotTest(base.BaseSharesAdminTest):
|
||||||
'client': self.shares_v2_client})
|
'client': self.shares_v2_client})
|
||||||
|
|
||||||
# Wait for success
|
# Wait for success
|
||||||
self.shares_v2_client.wait_for_snapshot_status(snapshot['id'],
|
self.shares_v2_client.wait_for_snapshot_status(
|
||||||
'available')
|
snapshot['id'],
|
||||||
|
constants.STATUS_AVAILABLE
|
||||||
|
)
|
||||||
|
|
||||||
# Verify manage snapshot API response
|
# Verify manage snapshot API response
|
||||||
expected_keys = ["status", "links", "share_id", "name",
|
expected_keys = ["status", "links", "share_id", "name",
|
||||||
|
@ -135,6 +136,8 @@ class ManageNFSSnapshotTest(base.BaseSharesAdminTest):
|
||||||
version as well as versions 2.12 (when the API was introduced) and
|
version as well as versions 2.12 (when the API was introduced) and
|
||||||
2.16.
|
2.16.
|
||||||
"""
|
"""
|
||||||
|
utils.skip_if_manage_not_supported_for_version(version)
|
||||||
|
|
||||||
# Skip in case specified version is not supported
|
# Skip in case specified version is not supported
|
||||||
self.skip_if_microversion_not_supported(version)
|
self.skip_if_microversion_not_supported(version)
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,9 @@ from tempest.lib import exceptions as lib_exc
|
||||||
import testtools
|
import testtools
|
||||||
from testtools import testcase as tc
|
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.tests.api import base
|
||||||
|
from manila_tempest_tests import utils
|
||||||
|
|
||||||
CONF = config.CONF
|
CONF = config.CONF
|
||||||
|
|
||||||
|
@ -30,27 +32,25 @@ class ManageNFSSnapshotNegativeTest(base.BaseSharesAdminTest):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@base.skip_if_microversion_lt("2.12")
|
@base.skip_if_microversion_lt("2.12")
|
||||||
@testtools.skipIf(
|
|
||||||
CONF.share.multitenancy_enabled,
|
|
||||||
"Only for driver_handles_share_servers = False driver mode.")
|
|
||||||
@testtools.skipUnless(
|
@testtools.skipUnless(
|
||||||
CONF.share.run_manage_unmanage_snapshot_tests,
|
CONF.share.run_manage_unmanage_snapshot_tests,
|
||||||
"Manage/unmanage snapshot tests are disabled.")
|
"Manage/unmanage snapshot tests are disabled.")
|
||||||
def resource_setup(cls):
|
def resource_setup(cls):
|
||||||
super(ManageNFSSnapshotNegativeTest, cls).resource_setup()
|
|
||||||
if cls.protocol not in CONF.share.enable_protocols:
|
if cls.protocol not in CONF.share.enable_protocols:
|
||||||
message = "%s tests are disabled" % cls.protocol
|
message = "%s tests are disabled" % cls.protocol
|
||||||
raise cls.skipException(message)
|
raise cls.skipException(message)
|
||||||
|
|
||||||
|
utils.skip_if_manage_not_supported_for_version()
|
||||||
|
|
||||||
|
super(ManageNFSSnapshotNegativeTest, cls).resource_setup()
|
||||||
|
|
||||||
# Create share type
|
# Create share type
|
||||||
cls.st_name = data_utils.rand_name("tempest-manage-st-name")
|
cls.st_name = data_utils.rand_name("tempest-manage-st-name")
|
||||||
cls.extra_specs = {
|
cls.extra_specs = {
|
||||||
'storage_protocol': CONF.share.capability_storage_protocol,
|
'storage_protocol': CONF.share.capability_storage_protocol,
|
||||||
'driver_handles_share_servers': False,
|
'driver_handles_share_servers': CONF.share.multitenancy_enabled,
|
||||||
'snapshot_support': six.text_type(
|
'snapshot_support': six.text_type(
|
||||||
CONF.share.capability_snapshot_support),
|
CONF.share.capability_snapshot_support),
|
||||||
'create_share_from_snapshot_support': six.text_type(
|
|
||||||
CONF.share.capability_create_share_from_snapshot_support),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cls.st = cls.create_share_type(
|
cls.st = cls.create_share_type(
|
||||||
|
@ -66,12 +66,13 @@ class ManageNFSSnapshotNegativeTest(base.BaseSharesAdminTest):
|
||||||
|
|
||||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
def test_manage_not_found(self):
|
def test_manage_not_found(self):
|
||||||
# Manage snapshot fails
|
# Manage non-existing snapshot fails
|
||||||
self.assertRaises(lib_exc.NotFound,
|
self.assertRaises(
|
||||||
self.shares_v2_client.manage_snapshot,
|
lib_exc.NotFound,
|
||||||
'fake-share-id',
|
self.shares_v2_client.manage_snapshot,
|
||||||
'fake-vol-snap-id',
|
'fake-share-id',
|
||||||
driver_options={})
|
'fake-provider-location',
|
||||||
|
)
|
||||||
|
|
||||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
def test_manage_already_exists(self):
|
def test_manage_already_exists(self):
|
||||||
|
@ -79,24 +80,74 @@ class ManageNFSSnapshotNegativeTest(base.BaseSharesAdminTest):
|
||||||
|
|
||||||
# Create snapshot
|
# Create snapshot
|
||||||
snap = self.create_snapshot_wait_for_active(self.share['id'])
|
snap = self.create_snapshot_wait_for_active(self.share['id'])
|
||||||
get_snap = self.shares_v2_client.get_snapshot(snap['id'])
|
snap = self.shares_v2_client.get_snapshot(snap['id'])
|
||||||
self.assertEqual(self.share['id'], get_snap['share_id'])
|
self.assertEqual(self.share['id'], snap['share_id'])
|
||||||
self.assertIsNotNone(get_snap['provider_location'])
|
self.assertIsNotNone(snap['provider_location'])
|
||||||
|
|
||||||
# Manage snapshot fails
|
# Manage snapshot fails
|
||||||
self.assertRaises(lib_exc.Conflict,
|
self.assertRaises(
|
||||||
self.shares_v2_client.manage_snapshot,
|
lib_exc.Conflict,
|
||||||
self.share['id'],
|
self.shares_v2_client.manage_snapshot,
|
||||||
get_snap['provider_location'],
|
self.share['id'],
|
||||||
driver_options={})
|
snap['provider_location']
|
||||||
|
)
|
||||||
|
|
||||||
# Delete snapshot
|
# Delete snapshot
|
||||||
self.shares_v2_client.delete_snapshot(get_snap['id'])
|
self._delete_snapshot_and_wait(snap)
|
||||||
|
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_manage_invalid_provider_location(self):
|
||||||
|
# Manage a snapshot with wrong provider location fails
|
||||||
|
|
||||||
|
# Create snapshot
|
||||||
|
snap = self.create_snapshot_wait_for_active(self.share['id'])
|
||||||
|
snap = self.shares_v2_client.get_snapshot(snap['id'])
|
||||||
|
|
||||||
|
# Unmanage snapshot
|
||||||
|
self.shares_v2_client.unmanage_snapshot(snap['id'])
|
||||||
self.shares_client.wait_for_resource_deletion(
|
self.shares_client.wait_for_resource_deletion(
|
||||||
snapshot_id=get_snap['id'])
|
snapshot_id=snap['id']
|
||||||
self.assertRaises(lib_exc.NotFound,
|
)
|
||||||
self.shares_v2_client.get_snapshot,
|
|
||||||
get_snap['id'])
|
# Manage snapshot with invalid provider location leaves it in
|
||||||
|
# manage_error state
|
||||||
|
invalid_snap = self.shares_v2_client.manage_snapshot(
|
||||||
|
self.share['id'],
|
||||||
|
'invalid_provider_location',
|
||||||
|
driver_options={}
|
||||||
|
)
|
||||||
|
self.shares_v2_client.wait_for_snapshot_status(
|
||||||
|
invalid_snap['id'],
|
||||||
|
constants.STATUS_MANAGE_ERROR
|
||||||
|
)
|
||||||
|
self.shares_v2_client.unmanage_snapshot(invalid_snap['id'])
|
||||||
|
|
||||||
|
# Manage it properly and delete
|
||||||
|
managed_snap = self.shares_v2_client.manage_snapshot(
|
||||||
|
self.share['id'],
|
||||||
|
snap['provider_location']
|
||||||
|
)
|
||||||
|
self.shares_v2_client.wait_for_snapshot_status(
|
||||||
|
managed_snap['id'],
|
||||||
|
constants.STATUS_AVAILABLE
|
||||||
|
)
|
||||||
|
self._delete_snapshot_and_wait(managed_snap)
|
||||||
|
|
||||||
|
@testtools.skipUnless(CONF.share.multitenancy_enabled,
|
||||||
|
'Multitenancy tests are disabled.')
|
||||||
|
@utils.skip_if_microversion_not_supported("2.48")
|
||||||
|
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||||
|
def test_unmanage_snapshot_with_server_unsupported(self):
|
||||||
|
share = self._create_share_for_manage()
|
||||||
|
snap = self.create_snapshot_wait_for_active(share["id"])
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
lib_exc.Forbidden,
|
||||||
|
self.shares_v2_client.unmanage_snapshot,
|
||||||
|
snap['id'], version="2.48")
|
||||||
|
|
||||||
|
self._delete_snapshot_and_wait(snap)
|
||||||
|
self._delete_share_and_wait(share)
|
||||||
|
|
||||||
|
|
||||||
class ManageCIFSSnapshotNegativeTest(ManageNFSSnapshotNegativeTest):
|
class ManageCIFSSnapshotNegativeTest(ManageNFSSnapshotNegativeTest):
|
||||||
|
|
|
@ -1115,6 +1115,88 @@ class BaseSharesAdminTest(BaseSharesTest):
|
||||||
name=share_group_type_name, share_types=[cls.share_type_id],
|
name=share_group_type_name, share_types=[cls.share_type_id],
|
||||||
client=cls.admin_shares_v2_client)
|
client=cls.admin_shares_v2_client)
|
||||||
|
|
||||||
|
def _create_share_for_manage(self):
|
||||||
|
creation_data = {
|
||||||
|
'share_type_id': self.st['share_type']['id'],
|
||||||
|
'share_protocol': self.protocol,
|
||||||
|
}
|
||||||
|
|
||||||
|
share = self.create_share(**creation_data)
|
||||||
|
share = self.shares_v2_client.get_share(share['id'])
|
||||||
|
|
||||||
|
if utils.is_microversion_ge(CONF.share.max_api_microversion, "2.9"):
|
||||||
|
el = self.shares_v2_client.list_share_export_locations(share["id"])
|
||||||
|
share["export_locations"] = el
|
||||||
|
|
||||||
|
return share
|
||||||
|
|
||||||
|
def _unmanage_share_and_wait(self, share):
|
||||||
|
self.shares_v2_client.unmanage_share(share['id'])
|
||||||
|
self.shares_v2_client.wait_for_resource_deletion(share_id=share['id'])
|
||||||
|
|
||||||
|
def _reset_state_and_delete_share(self, share):
|
||||||
|
self.shares_v2_client.reset_state(share['id'])
|
||||||
|
self._delete_share_and_wait(share)
|
||||||
|
|
||||||
|
def _delete_snapshot_and_wait(self, snap):
|
||||||
|
self.shares_v2_client.delete_snapshot(snap['id'])
|
||||||
|
self.shares_v2_client.wait_for_resource_deletion(
|
||||||
|
snapshot_id=snap['id']
|
||||||
|
)
|
||||||
|
self.assertRaises(exceptions.NotFound,
|
||||||
|
self.shares_v2_client.get_snapshot,
|
||||||
|
snap['id'])
|
||||||
|
|
||||||
|
def _delete_share_and_wait(self, share):
|
||||||
|
self.shares_v2_client.delete_share(share['id'])
|
||||||
|
self.shares_v2_client.wait_for_resource_deletion(share_id=share['id'])
|
||||||
|
self.assertRaises(exceptions.NotFound,
|
||||||
|
self.shares_v2_client.get_share,
|
||||||
|
share['id'])
|
||||||
|
|
||||||
|
def _manage_share(self, share, name, description, share_server_id):
|
||||||
|
managed_share = self.shares_v2_client.manage_share(
|
||||||
|
service_host=share['host'],
|
||||||
|
export_path=share['export_locations'][0],
|
||||||
|
protocol=share['share_proto'],
|
||||||
|
share_type_id=self.share_type['share_type']['id'],
|
||||||
|
name=name,
|
||||||
|
description=description,
|
||||||
|
share_server_id=share_server_id
|
||||||
|
)
|
||||||
|
self.shares_v2_client.wait_for_share_status(
|
||||||
|
managed_share['id'], constants.STATUS_AVAILABLE
|
||||||
|
)
|
||||||
|
|
||||||
|
return managed_share
|
||||||
|
|
||||||
|
def _unmanage_share_server_and_wait(self, server):
|
||||||
|
self.shares_v2_client.unmanage_share_server(server['id'])
|
||||||
|
self.shares_v2_client.wait_for_resource_deletion(
|
||||||
|
server_id=server['id']
|
||||||
|
)
|
||||||
|
|
||||||
|
def _manage_share_server(self, share_server, fields=None):
|
||||||
|
params = fields or {}
|
||||||
|
managed_share_server = self.shares_v2_client.manage_share_server(
|
||||||
|
params.get('host', share_server['host']),
|
||||||
|
params.get('share_network_id', share_server['share_network_id']),
|
||||||
|
params.get('identifier', share_server['identifier']),
|
||||||
|
)
|
||||||
|
self.shares_v2_client.wait_for_share_server_status(
|
||||||
|
managed_share_server['id'],
|
||||||
|
constants.SERVER_STATE_ACTIVE,
|
||||||
|
)
|
||||||
|
|
||||||
|
return managed_share_server
|
||||||
|
|
||||||
|
def _delete_share_server_and_wait(self, share_server_id):
|
||||||
|
self.shares_v2_client.delete_share_server(
|
||||||
|
share_server_id
|
||||||
|
)
|
||||||
|
self.shares_v2_client.wait_for_resource_deletion(
|
||||||
|
server_id=share_server_id)
|
||||||
|
|
||||||
|
|
||||||
class BaseSharesMixedTest(BaseSharesTest):
|
class BaseSharesMixedTest(BaseSharesTest):
|
||||||
"""Base test case class for all Shares API tests with all user roles."""
|
"""Base test case class for all Shares API tests with all user roles."""
|
||||||
|
|
|
@ -168,3 +168,12 @@ def get_configured_extra_specs(variation=None):
|
||||||
CONF.share.capability_create_share_from_snapshot_support)
|
CONF.share.capability_create_share_from_snapshot_support)
|
||||||
|
|
||||||
return extra_specs
|
return extra_specs
|
||||||
|
|
||||||
|
|
||||||
|
def skip_if_manage_not_supported_for_version(
|
||||||
|
version=CONF.share.max_api_microversion):
|
||||||
|
if (is_microversion_lt(version, "2.49")
|
||||||
|
and CONF.share.multitenancy_enabled):
|
||||||
|
raise testtools.TestCase.skipException(
|
||||||
|
"Share manage tests with multitenancy are disabled for "
|
||||||
|
"microversion < 2.49")
|
||||||
|
|
Loading…
Reference in New Issue