Merge "Remove _create_port and create_keypair methods"
diff --git a/manila_tempest_tests/common/remote_client.py b/manila_tempest_tests/common/remote_client.py
index 30e64c7..573cdd6 100644
--- a/manila_tempest_tests/common/remote_client.py
+++ b/manila_tempest_tests/common/remote_client.py
@@ -70,8 +70,17 @@
self.server = server
self.servers_client = servers_client
self.log_console = CONF.compute_feature_enabled.console_output
+ kwargs = {}
- self.ssh_client = ssh.Client(ip_address, username, password, pkey=pkey)
+ try:
+ kwargs['ssh_key_type'] = CONF.validation.ssh_key_type
+ except Exception:
+ # Not all versions of tempest support the
+ # "validation.ssh_key_type" config option
+ pass
+
+ self.ssh_client = ssh.Client(
+ ip_address, username, password, pkey=pkey, **kwargs)
@debug_ssh
def exec_command(self, cmd):
diff --git a/manila_tempest_tests/common/waiters.py b/manila_tempest_tests/common/waiters.py
index 24b30de..8a97c8e 100644
--- a/manila_tempest_tests/common/waiters.py
+++ b/manila_tempest_tests/common/waiters.py
@@ -217,3 +217,31 @@
'timeout': client.build_timeout,
})
raise exceptions.TimeoutException(message)
+
+
+def wait_for_subnet_create_check(client, share_network_id,
+ neutron_net_id=None,
+ neutron_subnet_id=None,
+ availability_zone=None):
+ result = client.subnet_create_check(
+ share_network_id, neutron_net_id=neutron_net_id,
+ neutron_subnet_id=neutron_subnet_id,
+ availability_zone=availability_zone)
+ start = int(time.time())
+ while not result['compatible']:
+ time.sleep(client.build_interval)
+ result = client.subnet_create_check(
+ share_network_id, neutron_net_id=neutron_net_id,
+ neutron_subnet_id=neutron_subnet_id,
+ availability_zone=availability_zone)
+ if result['compatible']:
+ break
+ elif int(time.time()) - start >= client.build_timeout or (
+ result['compatible'] is False):
+ message = ('Subnet create check failed within the '
+ 'required time %(timeout)s seconds for share network '
+ '%(share_network)s.' % {
+ 'timeout': client.build_timeout,
+ 'share_network': share_network_id,
+ })
+ raise exceptions.TimeoutException(message)
diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py
index f5022af..b62c409 100644
--- a/manila_tempest_tests/config.py
+++ b/manila_tempest_tests/config.py
@@ -40,7 +40,7 @@
"This value is only used to validate the versions "
"response from Manila."),
cfg.StrOpt("max_api_microversion",
- default="2.69",
+ default="2.71",
help="The maximum api microversion is configured to be the "
"value of the latest microversion supported by Manila."),
cfg.StrOpt("region",
@@ -287,6 +287,16 @@
default=False,
help="Defines whether to run share servers migration tests. "
"Enable this option if the used driver supports it."),
+ cfg.BoolOpt("run_share_server_multiple_subnet_tests",
+ default=False,
+ help="Defines whether to run the share server multiple "
+ "subnets tests. Enable this option if the used driver "
+ "supports it."),
+ cfg.BoolOpt("run_network_allocation_update_tests",
+ default=False,
+ help="Defines whether to run the network allocation update "
+ "tests. Enable this option if the used driver "
+ "supports it."),
cfg.StrOpt("image_with_share_tools",
default="manila-service-image-master",
diff --git a/manila_tempest_tests/services/share/v2/json/shares_client.py b/manila_tempest_tests/services/share/v2/json/shares_client.py
index 6db5393..a87648c 100644
--- a/manila_tempest_tests/services/share/v2/json/shares_client.py
+++ b/manila_tempest_tests/services/share/v2/json/shares_client.py
@@ -1957,6 +1957,29 @@
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
+ def subnet_create_check(
+ self, share_network_id, neutron_net_id=None,
+ neutron_subnet_id=None, availability_zone=None,
+ reset=False, version=LATEST_MICROVERSION):
+ body = {
+ 'share_network_subnet_create_check': {
+ 'neutron_net_id': neutron_net_id,
+ 'neutron_subnet_id': neutron_subnet_id,
+ 'availability_zone': availability_zone,
+ 'reset': reset,
+ }
+ }
+
+ body = json.dumps(body)
+ resp, body = self.post(
+ f'share-networks/{share_network_id}/action',
+ body, headers=EXPERIMENTAL, extra_headers=True,
+ version=version)
+ self.expected_success(202, resp.status)
+
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
###############
def share_server_migration_check(
diff --git a/manila_tempest_tests/tests/api/admin/test_share_instances.py b/manila_tempest_tests/tests/api/admin/test_share_instances.py
index 38c3f49..4f2e454 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_instances.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_instances.py
@@ -95,6 +95,8 @@
expected_keys.append("cast_rules_to_readonly")
if utils.is_microversion_ge(version, '2.54'):
expected_keys.append("progress")
+ if utils.is_microversion_ge(version, '2.71'):
+ expected_keys.append("updated_at")
expected_keys = sorted(expected_keys)
actual_keys = sorted(si.keys())
self.assertEqual(expected_keys, actual_keys,
diff --git a/manila_tempest_tests/tests/api/admin/test_share_servers.py b/manila_tempest_tests/tests/api/admin/test_share_servers.py
index b406a92..01cc9fc 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_servers.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_servers.py
@@ -196,8 +196,13 @@
if utils.is_microversion_ge(CONF.share.max_api_microversion, "2.49"):
keys.append("is_auto_deletable")
keys.append("identifier")
- if utils.is_microversion_ge(CONF.share.max_api_microversion, "2.51"):
+ if utils.is_microversion_ge(
+ CONF.share.max_api_microversion, "2.51") and (
+ utils.is_microversion_lt(
+ CONF.share.max_api_microversion, "2.70")):
keys.append("share_network_subnet_id")
+ if utils.is_microversion_ge(CONF.share.max_api_microversion, "2.70"):
+ keys.append("share_network_subnet_ids")
# all expected keys are present
for key in keys:
self.assertIn(key, server.keys())
diff --git a/manila_tempest_tests/tests/api/admin/test_share_servers_manage.py b/manila_tempest_tests/tests/api/admin/test_share_servers_manage.py
index 126dee1..8fdc22b 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_servers_manage.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_servers_manage.py
@@ -66,6 +66,12 @@
msg = ("Manage share server with share network subnet is "
"supported starting from microversion '2.51'.")
raise self.skipException(msg)
+ check_multiple_subnet = utils.is_microversion_ge(
+ CONF.share.max_api_microversion, '2.70')
+ if check_multiple_subnet:
+ network_subnet = 'share_network_subnet_ids'
+ else:
+ network_subnet = 'share_network_subnet_id'
# 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(
@@ -91,7 +97,7 @@
neutron_subnet_id=share_network['neutron_subnet_id'],
availability_zone=az
)['share_network_subnet']
- params = {'share_network_subnet_id': az_subnet['id']}
+ params = {network_subnet: az_subnet['id']}
# create share
share = self.create_share(
@@ -119,7 +125,7 @@
"identifier",
]
if add_subnet_field:
- keys.append('share_network_subnet_id')
+ keys.append(network_subnet)
# all expected keys are present
for key in keys:
self.assertIn(key, share_server)
@@ -127,9 +133,10 @@
# check that the share server is initially auto-deletable
self.assertIs(True, share_server["is_auto_deletable"])
self.assertIsNotNone(share_server["identifier"])
- if add_subnet_field:
- self.assertEqual(az_subnet["id"],
- share_server["share_network_subnet_id"])
+ if add_subnet_field and check_multiple_subnet:
+ self.assertIn(az_subnet["id"], share_server[network_subnet])
+ elif add_subnet_field and not check_multiple_subnet:
+ self.assertEqual(az_subnet["id"], share_server[network_subnet])
self._unmanage_share_and_wait(share)
diff --git a/manila_tempest_tests/tests/api/test_replication.py b/manila_tempest_tests/tests/api/test_replication.py
index 722f02f..20ba8fe 100644
--- a/manila_tempest_tests/tests/api/test_replication.py
+++ b/manila_tempest_tests/tests/api/test_replication.py
@@ -187,6 +187,145 @@
# Delete subnet
self.shares_v2_client.delete_subnet(self.sn_id, subnet['id'])
+ @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
+ @testtools.skipIf(
+ not CONF.share.multitenancy_enabled, "Only for multitenancy.")
+ @testtools.skipIf(
+ not CONF.share.run_share_server_multiple_subnet_tests,
+ "Share server multiple subnet tests are disabled.")
+ @testtools.skipIf(CONF.share.share_network_id != "",
+ "This test is not suitable for pre-existing "
+ "share networks.")
+ @utils.skip_if_microversion_not_supported("2.70")
+ @decorators.idempotent_id('4235e789-dbd6-47a8-8f2e-d70edf78e532')
+ def test_add_delete_share_replica_multiple_subnets(self):
+ extra_specs = {
+ "replication_type": self.replication_type,
+ "driver_handles_share_servers": CONF.share.multitenancy_enabled,
+ "share_server_multiple_subnet_support": True,
+ }
+ share_type = self.create_share_type(
+ extra_specs=extra_specs, client=self.admin_client)
+ default_subnet = utils.share_network_get_default_subnet(
+ self.share_network)
+ new_share_network_id = self.create_share_network(
+ cleanup_in_class=False)['id']
+ subnet_data = {
+ 'neutron_net_id': default_subnet.get('neutron_net_id'),
+ 'neutron_subnet_id': default_subnet.get('neutron_subnet_id'),
+ 'share_network_id': new_share_network_id,
+ 'availability_zone': self.replica_zone,
+ }
+ subnet1 = self.create_share_network_subnet(**subnet_data)
+ subnet2 = self.create_share_network_subnet(**subnet_data)
+ # Creating a third subnet in share replica az
+ subnet_data.update({'availability_zone': self.share_zone})
+ subnet3 = self.create_share_network_subnet(**subnet_data)
+ # Create the share and share replica
+ share = self.create_share(
+ share_type_id=share_type['id'], cleanup_in_class=False,
+ availability_zone=self.share_zone,
+ share_network_id=new_share_network_id)
+ share = self.admin_client.get_share(share['id'])['share']
+ replica = self.create_share_replica(share['id'], self.replica_zone)
+ replica = self.admin_client.get_share_replica(
+ replica['id'])['share_replica']
+ share_server = self.admin_client.show_share_server(
+ replica['share_server_id'])['share_server']
+ self.assertIn(subnet1['id'],
+ share_server['share_network_subnet_ids'])
+ self.assertIn(subnet2['id'],
+ share_server['share_network_subnet_ids'])
+ # Delete the replica
+ self.delete_share_replica(replica['id'])
+ # Delete share
+ self.shares_v2_client.delete_share(share['id'])
+ self.shares_v2_client.wait_for_resource_deletion(share_id=share['id'])
+ # Delete subnets
+ self.shares_v2_client.delete_subnet(
+ new_share_network_id, subnet1['id'])
+ self.shares_v2_client.delete_subnet(
+ new_share_network_id, subnet2['id'])
+ self.shares_v2_client.delete_subnet(
+ new_share_network_id, subnet3['id'])
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
+ @testtools.skipIf(
+ not CONF.share.multitenancy_enabled, "Only for multitenancy.")
+ @testtools.skipIf(
+ not CONF.share.run_network_allocation_update_tests,
+ "Share server network allocation update tests are disabled.")
+ @testtools.skipIf(CONF.share.share_network_id != "",
+ "This test is not suitable for pre-existing "
+ "share_network.")
+ @utils.skip_if_microversion_not_supported("2.70")
+ @decorators.idempotent_id('26694947-d4a0-46c8-99e8-2e0eca1b6a08')
+ def test_add_delete_share_replica_network_allocation_update(self):
+ extra_specs = {
+ "replication_type": self.replication_type,
+ "driver_handles_share_servers": CONF.share.multitenancy_enabled,
+ "network_allocation_update_support": True,
+ }
+ share_type = self.create_share_type(extra_specs=extra_specs)
+
+ default_subnet = utils.share_network_get_default_subnet(
+ self.share_network)
+ new_share_network_id = self.create_share_network(
+ cleanup_in_class=False)['id']
+ subnet_data = {
+ 'neutron_net_id': default_subnet.get('neutron_net_id'),
+ 'neutron_subnet_id': default_subnet.get('neutron_subnet_id'),
+ 'share_network_id': new_share_network_id,
+ 'availability_zone': self.share_zone,
+ }
+ subnet1 = self.create_share_network_subnet(**subnet_data)
+ subnet_data.update({'availability_zone': self.replica_zone})
+ subnet2 = self.create_share_network_subnet(**subnet_data)
+ # Create the share and share replica
+ share = self.create_share(
+ share_type_id=share_type['id'], cleanup_in_class=False,
+ availability_zone=self.share_zone,
+ share_network_id=new_share_network_id)
+ share = self.admin_client.get_share(share['id'])['share']
+
+ replica = self.create_share_replica(share['id'], self.replica_zone)
+ replica = self.admin_client.get_share_replica(
+ replica['id'])['share_replica']
+
+ # Waits until the check is completed and positive
+ waiters.wait_for_subnet_create_check(
+ self.shares_v2_client, new_share_network_id,
+ neutron_net_id=subnet_data['neutron_net_id'],
+ neutron_subnet_id=subnet_data['neutron_subnet_id'],
+ availability_zone=self.replica_zone)
+ # Creating a third subnet in replica zone to trigger the network
+ # allocation update
+ subnet3 = self.create_share_network_subnet(**subnet_data)
+ waiters.wait_for_resource_status(
+ self.admin_client, replica['share_server_id'],
+ constants.SERVER_STATE_ACTIVE,
+ resource_name="share_server",
+ status_attr="status")
+ share_server = self.admin_client.show_share_server(
+ replica['share_server_id']
+ )['share_server']
+ self.assertIn(subnet2['id'],
+ share_server['share_network_subnet_ids'])
+ self.assertIn(subnet3['id'],
+ share_server['share_network_subnet_ids'])
+ # Delete the replica
+ self.delete_share_replica(replica['id'])
+ # Delete share
+ self.shares_v2_client.delete_share(share['id'])
+ self.shares_v2_client.wait_for_resource_deletion(share_id=share['id'])
+ # Delete subnets
+ self.shares_v2_client.delete_subnet(
+ new_share_network_id, subnet1['id'])
+ self.shares_v2_client.delete_subnet(
+ new_share_network_id, subnet2['id'])
+ self.shares_v2_client.delete_subnet(
+ new_share_network_id, subnet3['id'])
+
@decorators.idempotent_id('00e12b41-b95d-494a-99be-e584aae10f5c')
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
def test_add_access_rule_create_replica_delete_rule(self):
diff --git a/manila_tempest_tests/tests/api/test_share_groups.py b/manila_tempest_tests/tests/api/test_share_groups.py
index 3b56161..b203481 100644
--- a/manila_tempest_tests/tests/api/test_share_groups.py
+++ b/manila_tempest_tests/tests/api/test_share_groups.py
@@ -15,12 +15,14 @@
import ddt
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
import testtools
from testtools import testcase as tc
from manila_tempest_tests.common import constants
+from manila_tempest_tests.common import waiters
from manila_tempest_tests.tests.api import base
from manila_tempest_tests import utils
@@ -263,3 +265,130 @@
# Verify that share always has the same AZ as share group does
self.assertEqual(
share_group['availability_zone'], share['availability_zone'])
+
+ @utils.skip_if_microversion_not_supported("2.70")
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ @testtools.skipUnless(CONF.share.multitenancy_enabled,
+ "Multitenancy is disabled.")
+ @testtools.skipUnless(CONF.share.run_share_server_multiple_subnet_tests,
+ "Share server multiple subnet tests are disabled.")
+ @testtools.skipIf(CONF.share.share_network_id != "",
+ "This test is not suitable for pre-existing "
+ "share networks.")
+ @ddt.data(False, True)
+ @decorators.idempotent_id('17fd1867-03a3-43d0-9be3-daf90b6c5e02')
+ def test_create_sg_and_share_with_multiple_subnets(
+ self, network_allocation_update):
+ if network_allocation_update and not (
+ CONF.share.run_network_allocation_update_tests):
+ raise self.skipException(
+ 'Network allocation update tests are disabled.')
+ extra_specs = {
+ 'driver_handles_share_servers': CONF.share.multitenancy_enabled,
+ 'share_server_multiple_subnet_support': True,
+ }
+ if network_allocation_update:
+ extra_specs['network_allocation_update_support'] = True
+ share_type = self.create_share_type(extra_specs=extra_specs)
+ sg_type_name = data_utils.rand_name("tempest-manila")
+ sg_type = self.create_share_group_type(
+ name=sg_type_name, share_types=share_type['id'],
+ client=self.admin_shares_v2_client)
+ # Get list of existing availability zones, at least one always
+ # should exist
+ azs = self.get_availability_zones_matching_share_type(share_type)
+ if len(azs) == 0:
+ raise self.skipException(
+ "No AZs were found. Make sure there is at least one "
+ "configured.")
+ share_network = self.shares_v2_client.get_share_network(
+ self.shares_v2_client.share_network_id)['share_network']
+ new_share_network_id = self.create_share_network(
+ cleanup_in_class=False)['id']
+
+ default_subnet = utils.share_network_get_default_subnet(
+ share_network)
+ subnet_data = {
+ 'neutron_net_id': default_subnet.get('neutron_net_id'),
+ 'neutron_subnet_id': default_subnet.get('neutron_subnet_id'),
+ 'share_network_id': new_share_network_id,
+ 'availability_zone': azs[0]
+ }
+ subnet1 = self.create_share_network_subnet(**subnet_data)
+ if not network_allocation_update:
+ subnet2 = self.create_share_network_subnet(**subnet_data)
+
+ sg_kwargs = {
+ 'share_group_type_id': sg_type['id'],
+ 'share_type_ids': [share_type['id']],
+ 'share_network_id': new_share_network_id,
+ 'availability_zone': azs[0],
+ 'version': constants.MIN_SHARE_GROUP_MICROVERSION,
+ 'cleanup_in_class': False,
+ }
+
+ # Create share group
+ share_group = self.create_share_group(**sg_kwargs)
+
+ # Get latest share group info
+ share_group = self.shares_v2_client.get_share_group(
+ share_group['id'])['share_group']
+
+ self.assertIn('availability_zone', share_group)
+ self.assertEqual(azs[0], share_group['availability_zone'])
+
+ # Test 'consistent_snapshot_support' as part of 2.33 API change
+ self.assertIn('consistent_snapshot_support', share_group)
+ self.assertIn(
+ share_group['consistent_snapshot_support'], ('host', 'pool', None))
+
+ share_data = {
+ 'share_type_id': share_type['id'],
+ 'share_group_id': share_group['id'],
+ 'share_network_id': new_share_network_id,
+ 'availability_zone': azs[0],
+ 'cleanup_in_class': False,
+ }
+
+ # Create share in share group
+ share = self.create_share(**share_data)
+
+ # Get latest share info
+ share = self.admin_shares_v2_client.get_share(share['id'])['share']
+ # Verify that share always has the same AZ as share group does
+ self.assertEqual(
+ share_group['availability_zone'], share['availability_zone'])
+
+ # Get share server info
+ share_server = self.admin_shares_v2_client.show_share_server(
+ share['share_server_id'])['share_server']
+ if network_allocation_update:
+ waiters.wait_for_subnet_create_check(
+ self.shares_v2_client, new_share_network_id,
+ neutron_net_id=subnet_data['neutron_net_id'],
+ neutron_subnet_id=subnet_data['neutron_subnet_id'],
+ availability_zone=azs[0])
+
+ subnet2 = self.create_share_network_subnet(**subnet_data)
+ waiters.wait_for_resource_status(
+ self.admin_shares_v2_client, share['share_server_id'],
+ constants.SERVER_STATE_ACTIVE,
+ resource_name="share_server",
+ status_attr="status")
+ share_server = self.admin_shares_v2_client.show_share_server(
+ share['share_server_id'])['share_server']
+ # Check if share server has multiple subnets
+ self.assertIn(subnet1['id'], share_server['share_network_subnet_ids'])
+ self.assertIn(subnet2['id'], share_server['share_network_subnet_ids'])
+ # Delete share
+ params = {"share_group_id": share_group['id']}
+ self.shares_v2_client.delete_share(
+ share['id'],
+ params=params,
+ version=constants.MIN_SHARE_GROUP_MICROVERSION)
+ self.shares_client.wait_for_resource_deletion(share_id=share['id'])
+ # Delete subnet
+ self.shares_v2_client.delete_subnet(
+ new_share_network_id, subnet1['id'])
+ self.shares_v2_client.delete_subnet(
+ new_share_network_id, subnet2['id'])
diff --git a/manila_tempest_tests/tests/api/test_share_network_subnets.py b/manila_tempest_tests/tests/api/test_share_network_subnets.py
index 0f651c9..cdf2162 100644
--- a/manila_tempest_tests/tests/api/test_share_network_subnets.py
+++ b/manila_tempest_tests/tests/api/test_share_network_subnets.py
@@ -127,6 +127,8 @@
msg = ("This test needs at least two compatible storage "
"availability zones.")
raise self.skipException(msg)
+ check_multiple_subnet = utils.is_microversion_ge(
+ CONF.share.max_api_microversion, '2.70')
original_share_network = self.shares_v2_client.get_share_network(
self.shares_v2_client.share_network_id
@@ -173,8 +175,12 @@
# Match new subnet content
self.assertDictContainsSubset(data, subnet)
# Match share server subnet
- self.assertEqual(subnet['id'],
- share_server['share_network_subnet_id'])
+ if check_multiple_subnet:
+ self.assertIn(subnet['id'],
+ share_server['share_network_subnet_ids'])
+ else:
+ self.assertIn(subnet['id'],
+ share_server['share_network_subnet_id'])
# Delete share
self.shares_v2_client.delete_share(share['id'])
self.shares_v2_client.wait_for_resource_deletion(share_id=share['id'])
@@ -197,10 +203,11 @@
msg = ("This test needs at least two compatible storage "
"availability zones.")
raise self.skipException(msg)
+ check_multiple_subnet = utils.is_microversion_ge(
+ CONF.share.max_api_microversion, '2.70')
original_share_network = self.shares_v2_client.get_share_network(
- self.shares_v2_client.share_network_id
- )['share_network']
+ self.shares_v2_client.share_network_id)['share_network']
share_net_info = (
utils.share_network_get_default_subnet(original_share_network))
share_network = self.create_share_network(
@@ -254,8 +261,12 @@
# Default subnet was created during share network creation
self.assertIsNone(default_subnet['availability_zone'])
# Match share server subnet
- self.assertEqual(expected_subnet_id,
- share_server['share_network_subnet_id'])
+ if not check_multiple_subnet:
+ self.assertEqual(
+ expected_subnet_id, share_server['share_network_subnet_id'])
+ else:
+ self.assertIn(
+ expected_subnet_id, share_server['share_network_subnet_ids'])
if create_share_with_az:
self.assertEqual(destination_az,
share['availability_zone'])
diff --git a/manila_tempest_tests/tests/api/test_share_network_subnets_negative.py b/manila_tempest_tests/tests/api/test_share_network_subnets_negative.py
index 4af34f2..7b0ca55 100644
--- a/manila_tempest_tests/tests/api/test_share_network_subnets_negative.py
+++ b/manila_tempest_tests/tests/api/test_share_network_subnets_negative.py
@@ -27,6 +27,7 @@
CONF = config.CONF
+LATEST_MICROVERSION = CONF.share.max_api_microversion
@ddt.ddt
@@ -72,6 +73,7 @@
@decorators.idempotent_id('13f397bf-5e3a-42b0-b4f9-9cd2dbbb0955')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@ddt.data(True, False)
+ @utils.skip_if_is_microversion_ge(LATEST_MICROVERSION, "2.70")
def test_add_share_network_subnet_in_same_az_exists(self, is_default):
share_network = self.shares_v2_client.create_share_network(
)['share_network']
@@ -231,7 +233,8 @@
# Get a compatible availability zone
az = self.get_availability_zones_matching_share_type(
self.share_type)[0]
-
+ check_multiple_subnets = utils.is_microversion_ge(
+ CONF.share.max_api_microversion, '2.70')
original_share_network = self.shares_v2_client.get_share_network(
self.shares_v2_client.share_network_id
)['share_network']
@@ -269,8 +272,12 @@
share['share_server_id']
)['share_server']
# Match share server subnet
- self.assertEqual(subnet['id'],
- share_server['share_network_subnet_id'])
+ if check_multiple_subnets:
+ self.assertIn(subnet['id'],
+ share_server['share_network_subnet_ids'])
+ else:
+ self.assertEqual(subnet['id'],
+ share_server['share_network_subnet_id'])
# Assert that the user cannot delete a subnet that contain shares
self.assertRaises(lib_exc.Conflict,
diff --git a/manila_tempest_tests/tests/api/test_share_networks_negative.py b/manila_tempest_tests/tests/api/test_share_networks_negative.py
index 17e0c12..3306068 100644
--- a/manila_tempest_tests/tests/api/test_share_networks_negative.py
+++ b/manila_tempest_tests/tests/api/test_share_networks_negative.py
@@ -195,3 +195,24 @@
self.shares_v2_client.create_share_network,
availability_zone='inexistent-availability-zone',
)
+
+ @utils.skip_if_microversion_not_supported("2.70")
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ @decorators.idempotent_id('f6f47c64-6821-4d4a-aa7d-3b0244158197')
+ def test_check_add_share_network_subnet_share_network_not_found(self):
+ data = self.generate_subnet_data()
+ self.assertRaises(lib_exc.NotFound,
+ self.shares_v2_client.subnet_create_check,
+ 'fake_inexistent_id',
+ **data)
+
+ @utils.skip_if_microversion_not_supported("2.70")
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ @decorators.idempotent_id('d9a487fb-6638-4f93-8b69-3e1a85bfbc7d')
+ def test_check_add_share_network_subnet_az_not_found(self):
+ share_network = self.create_share_network()
+ data = {'availability_zone': 'non-existent-az'}
+
+ self.assertRaises(lib_exc.BadRequest,
+ self.shares_v2_client.subnet_create_check,
+ share_network['id'], **data)
diff --git a/manila_tempest_tests/tests/api/test_share_servers_multiple_subnet.py b/manila_tempest_tests/tests/api/test_share_servers_multiple_subnet.py
new file mode 100644
index 0000000..fccbf03
--- /dev/null
+++ b/manila_tempest_tests/tests/api/test_share_servers_multiple_subnet.py
@@ -0,0 +1,196 @@
+# Copyright 2022 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 import decorators
+import testtools
+from testtools import testcase as tc
+
+from manila_tempest_tests.common import constants
+from manila_tempest_tests.common import waiters
+from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
+
+CONF = config.CONF
+
+
+class ShareServerMultipleSubnetTest(base.BaseSharesMixedTest):
+
+ @classmethod
+ def skip_checks(cls):
+ super(ShareServerMultipleSubnetTest, cls).skip_checks()
+ if not CONF.share.multitenancy_enabled:
+ raise cls.skipException('Multitenancy tests are disabled.')
+ if not CONF.share.run_share_server_multiple_subnet_tests and not (
+ CONF.share.run_network_allocation_update_tests):
+ raise cls.skipException(
+ 'Share server multiple subnets and network allocation '
+ 'update tests are disabled.')
+ if CONF.share.share_network_id != "":
+ raise cls.skipException(
+ 'These tests are not suitable for pre-existing '
+ 'share_network.')
+ utils.check_skip_if_microversion_not_supported("2.70")
+
+ @classmethod
+ def resource_setup(cls):
+ super(ShareServerMultipleSubnetTest, cls).resource_setup()
+ cls.extra_specs = {
+ 'driver_handles_share_servers': CONF.share.multitenancy_enabled,
+ }
+ if CONF.share.run_share_server_multiple_subnet_tests:
+ cls.extra_specs['share_server_multiple_subnet_support'] = True
+ if CONF.share.run_network_allocation_update_tests:
+ cls.extra_specs['network_allocation_update_support'] = True
+ share_type = cls.create_share_type(extra_specs=cls.extra_specs)
+ cls.share_type_id = share_type['id']
+
+ cls.zones = cls.get_availability_zones_matching_share_type(
+ share_type)
+ if len(cls.zones) == 0:
+ msg = ("These tests need at least one compatible "
+ "availability zone.")
+ raise cls.skipException(msg)
+
+ cls.share_network = cls.alt_shares_v2_client.get_share_network(
+ cls.alt_shares_v2_client.share_network_id)['share_network']
+ cls.default_subnet = utils.share_network_get_default_subnet(
+ cls.share_network)
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
+ @testtools.skipIf(
+ not CONF.share.run_share_server_multiple_subnet_tests,
+ "Share network multiple subnets tests are disabled.")
+ @decorators.idempotent_id('5600bd52-ecb4-47d3-a4e8-3e6565cb0b80')
+ def test_create_share_on_multiple_subnets_same_az(self):
+ share_network_id = self.create_share_network(
+ cleanup_in_class=False)["id"]
+ subnet_data = {
+ 'neutron_net_id': self.default_subnet.get('neutron_net_id'),
+ 'neutron_subnet_id': self.default_subnet.get('neutron_subnet_id'),
+ 'share_network_id': share_network_id,
+ 'availability_zone': self.zones[0],
+ }
+ subnet1 = self.create_share_network_subnet(**subnet_data)
+ subnet2 = self.create_share_network_subnet(**subnet_data)
+
+ share = self.create_share(
+ share_type_id=self.share_type_id,
+ share_network_id=share_network_id,
+ availability_zone=self.zones[0])
+ self.assertIn(share['status'], ('creating', 'available'))
+
+ share = self.admin_shares_v2_client.get_share(share['id'])['share']
+ share_server = self.admin_shares_v2_client.show_share_server(
+ share['share_server_id']
+ )['share_server']
+ self.assertIn(subnet1['id'],
+ share_server['share_network_subnet_ids'])
+ self.assertIn(subnet2['id'],
+ share_server['share_network_subnet_ids'])
+
+ # Delete share
+ self.shares_v2_client.delete_share(share['id'])
+ self.shares_v2_client.wait_for_resource_deletion(share_id=share['id'])
+ # Delete the subnets
+ self.shares_v2_client.delete_subnet(share_network_id, subnet1['id'])
+ self.shares_v2_client.delete_subnet(share_network_id, subnet2['id'])
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
+ @testtools.skipIf(
+ not CONF.share.run_network_allocation_update_tests,
+ "Share server network allocation update are disabled.")
+ @decorators.idempotent_id('2a9debd5-47a3-42cc-823b-2b9de435a5e4')
+ def test_create_share_with_network_allocation_update(self):
+ share_network_id = self.create_share_network(
+ cleanup_in_class=False)["id"]
+ subnet_data = {
+ 'neutron_net_id': self.default_subnet.get('neutron_net_id'),
+ 'neutron_subnet_id': self.default_subnet.get('neutron_subnet_id'),
+ 'share_network_id': share_network_id,
+ 'availability_zone': self.zones[0],
+ }
+ subnet1 = self.create_share_network_subnet(**subnet_data)
+
+ share = self.create_share(
+ share_type_id=self.share_type_id,
+ share_network_id=share_network_id,
+ availability_zone=self.zones[0])
+ self.assertIn(share['status'], ('creating', 'available'))
+ share = self.admin_shares_v2_client.get_share(share['id'])['share']
+
+ waiters.wait_for_subnet_create_check(
+ self.shares_v2_client, share_network_id,
+ neutron_net_id=subnet_data['neutron_net_id'],
+ neutron_subnet_id=subnet_data['neutron_subnet_id'],
+ availability_zone=self.zones[0])
+ subnet2 = self.create_share_network_subnet(**subnet_data)
+
+ waiters.wait_for_resource_status(
+ self.admin_shares_v2_client, share['share_server_id'],
+ constants.SERVER_STATE_ACTIVE,
+ resource_name="share_server",
+ status_attr="status")
+ share_server = self.admin_shares_v2_client.show_share_server(
+ share['share_server_id']
+ )['share_server']
+
+ self.assertIn(subnet1['id'],
+ share_server['share_network_subnet_ids'])
+ self.assertIn(subnet2['id'],
+ share_server['share_network_subnet_ids'])
+
+ # Delete share
+ self.shares_v2_client.delete_share(share['id'])
+ self.shares_v2_client.wait_for_resource_deletion(share_id=share['id'])
+ # Delete subnets
+ self.shares_v2_client.delete_subnet(share_network_id, subnet1['id'])
+ self.shares_v2_client.delete_subnet(share_network_id, subnet2['id'])
+
+ @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
+ @testtools.skipIf(
+ not CONF.share.run_network_allocation_update_tests,
+ "Share server network allocation update are disabled.")
+ @decorators.idempotent_id('2624f9a7-660b-4f91-89b8-c026b3bb8d1f')
+ def test_share_network_subnet_create_check(self):
+ """The share network subnet create check compatibility test."""
+
+ share_network_id = self.create_share_network(
+ cleanup_in_class=False)["id"]
+ subnet_data = {
+ 'neutron_net_id': self.default_subnet.get('neutron_net_id'),
+ 'neutron_subnet_id': self.default_subnet.get('neutron_subnet_id'),
+ 'share_network_id': share_network_id,
+ 'availability_zone': self.zones[0],
+ }
+ subnet1 = self.create_share_network_subnet(**subnet_data)
+
+ share = self.create_share(
+ share_type_id=self.share_type_id,
+ share_network_id=share_network_id,
+ availability_zone=self.zones[0]
+ )
+ self.assertIn(share['status'], ('creating', 'available'))
+ waiters.wait_for_subnet_create_check(
+ self.shares_v2_client, share_network_id,
+ neutron_net_id=subnet_data['neutron_net_id'],
+ neutron_subnet_id=subnet_data['neutron_subnet_id'],
+ availability_zone=self.zones[0])
+
+ # Delete share
+ self.shares_v2_client.delete_share(share['id'])
+ self.shares_v2_client.wait_for_resource_deletion(share_id=share['id'])
+ # Delete subnets
+ self.shares_v2_client.delete_subnet(share_network_id, subnet1['id'])
diff --git a/manila_tempest_tests/tests/api/test_share_servers_multiple_subnet_negative.py b/manila_tempest_tests/tests/api/test_share_servers_multiple_subnet_negative.py
new file mode 100644
index 0000000..522f34e
--- /dev/null
+++ b/manila_tempest_tests/tests/api/test_share_servers_multiple_subnet_negative.py
@@ -0,0 +1,90 @@
+# Copyright 2022 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 test_utils
+from tempest.lib import decorators
+from testtools import testcase as tc
+
+from manila_tempest_tests import share_exceptions
+from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
+
+CONF = config.CONF
+
+
+class ShareServerMultipleSubNegativeTest(base.BaseSharesMixedTest):
+
+ @classmethod
+ def skip_checks(cls):
+ super(ShareServerMultipleSubNegativeTest, cls).skip_checks()
+ if not CONF.share.multitenancy_enabled:
+ raise cls.skipException('Multitenancy tests are disabled.')
+ utils.check_skip_if_microversion_not_supported("2.70")
+
+ @classmethod
+ def resource_setup(cls):
+ super(ShareServerMultipleSubNegativeTest, cls).resource_setup()
+ cls.share_network = cls.alt_shares_v2_client.get_share_network(
+ cls.alt_shares_v2_client.share_network_id)['share_network']
+
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+ @decorators.idempotent_id('1e2a9415-b02f-4c02-812d-bedc361f92ce')
+ def test_create_share_multiple_subnets_to_unsupported_backend(self):
+ extra_specs = {
+ 'driver_handles_share_servers': CONF.share.multitenancy_enabled,
+ 'share_server_multiple_subnet_support': False
+ }
+ share_type = self.create_share_type(extra_specs=extra_specs)
+ pools = self.get_pools_matching_share_type(
+ share_type, client=self.admin_shares_v2_client)
+ zones = self.get_availability_zones_matching_share_type(
+ share_type)
+ if not pools or not zones:
+ raise self.skipException("At least one backend that supports "
+ "adding multiple subnets into a share "
+ "network is needed for this test.")
+ extra_specs = {'pool_name': pools[0]['pool'],
+ 'availability_zone': zones[0]}
+ self.admin_shares_v2_client.update_share_type_extra_specs(
+ share_type['id'], extra_specs)
+
+ share_network_id = self.create_share_network(
+ cleanup_in_class=True)["id"]
+ default_subnet = utils.share_network_get_default_subnet(
+ self.share_network)
+ subnet_data = {
+ 'neutron_net_id': default_subnet.get('neutron_net_id'),
+ 'neutron_subnet_id': default_subnet.get('neutron_subnet_id'),
+ 'share_network_id': share_network_id,
+ 'availability_zone': zones[0],
+ 'cleanup_in_class': False
+ }
+ subnet1 = self.create_share_network_subnet(**subnet_data)
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ self.shares_v2_client.delete_subnet,
+ share_network_id, subnet1['id'])
+ subnet2 = self.create_share_network_subnet(**subnet_data)
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ self.shares_v2_client.delete_subnet,
+ share_network_id, subnet2['id'])
+ self.assertRaises(
+ share_exceptions.ShareBuildErrorException,
+ self.create_share,
+ share_type_id=share_type['id'],
+ share_network_id=share_network_id,
+ availability_zone=zones[0],
+ cleanup_in_class=False
+ )
diff --git a/manila_tempest_tests/utils.py b/manila_tempest_tests/utils.py
index d0860f0..5ecfb36 100644
--- a/manila_tempest_tests/utils.py
+++ b/manila_tempest_tests/utils.py
@@ -94,6 +94,16 @@
return lambda f: f
+def skip_if_is_microversion_ge(left, right):
+ """Skip if version for left is greater than or equal to the right one."""
+
+ if is_microversion_ge(left, right):
+ reason = ("Skipped. Test requires microversion "
+ "< than '%s'." % right)
+ return testtools.skip(reason)
+ return lambda f: f
+
+
def check_skip_if_microversion_not_supported(microversion):
"""Callable method for tests that are microversion-specific."""
if not is_microversion_supported(microversion):
diff --git a/zuul.d/manila-tempest-jobs.yaml b/zuul.d/manila-tempest-jobs.yaml
index 494b285..a68aafe 100644
--- a/zuul.d/manila-tempest-jobs.yaml
+++ b/zuul.d/manila-tempest-jobs.yaml
@@ -246,6 +246,8 @@
backend_names: LONDON,PARIS
multi_backend: true
run_share_server_migration_tests: true
+ run_share_server_multiple_subnet_tests: true
+ run_network_allocation_update_tests: true
- job:
name: manila-tempest-plugin-generic
@@ -490,6 +492,8 @@
run_replication_tests: true
run_revert_to_snapshot_tests: true
run_share_server_migration_tests: true
+ run_share_server_multiple_subnet_tests: true
+ run_network_allocation_update_tests: true
- job:
name: manila-tempest-plugin-glusterfs-native