Added test suite and case to cover 'availability zone'
This was required to test advanced scenarios. * Added a new 'admin' folder in 'scenario' folder to test advanced operations. * Added a new file to the 'admin' folder that contains test cases for floating ip with admin privileges. * Added a scenario test that verify valid connection between two instances on a single compute node using availability-zone. * Changed 'base.py' to enable booting an instance with admin privileges. Change-Id: I711a10eef321622c335e35b84e386b01d73b938a
This commit is contained in:
parent
c125fd1479
commit
6a0a18a172
@ -13,6 +13,8 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from tempest.lib.services.compute import availability_zone_client
|
||||||
|
from tempest.lib.services.compute import hypervisor_client
|
||||||
from tempest.lib.services.compute import keypairs_client
|
from tempest.lib.services.compute import keypairs_client
|
||||||
from tempest.lib.services.compute import servers_client
|
from tempest.lib.services.compute import servers_client
|
||||||
from tempest.lib.services.identity.v2 import tenants_client
|
from tempest.lib.services.identity.v2 import tenants_client
|
||||||
@ -74,6 +76,10 @@ class Manager(manager.Manager):
|
|||||||
**params)
|
**params)
|
||||||
self.keypairs_client = keypairs_client.KeyPairsClient(
|
self.keypairs_client = keypairs_client.KeyPairsClient(
|
||||||
self.auth_provider, **params)
|
self.auth_provider, **params)
|
||||||
|
self.hv_client = hypervisor_client.HypervisorClient(
|
||||||
|
self.auth_provider, **params)
|
||||||
|
self.az_client = availability_zone_client.AvailabilityZoneClient(
|
||||||
|
self.auth_provider, **params)
|
||||||
|
|
||||||
def _set_identity_clients(self):
|
def _set_identity_clients(self):
|
||||||
params = {
|
params = {
|
||||||
|
0
neutron_tempest_plugin/scenario/admin/__init__.py
Normal file
0
neutron_tempest_plugin/scenario/admin/__init__.py
Normal file
109
neutron_tempest_plugin/scenario/admin/test_floatingip.py
Normal file
109
neutron_tempest_plugin/scenario/admin/test_floatingip.py
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
# Copyright 2017 Red Hat, 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.common import utils
|
||||||
|
from tempest.common import waiters
|
||||||
|
from tempest.lib.common.utils import data_utils
|
||||||
|
from tempest.lib import decorators
|
||||||
|
|
||||||
|
from neutron_tempest_plugin.common import ssh
|
||||||
|
from neutron_tempest_plugin import config
|
||||||
|
from neutron_tempest_plugin.scenario import base
|
||||||
|
from neutron_tempest_plugin.scenario import constants as const
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class FloatingIpTestCasesAdmin(base.BaseTempestTestCase):
|
||||||
|
credentials = ['primary', 'admin']
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@utils.requires_ext(extension="router", service="network")
|
||||||
|
def resource_setup(cls):
|
||||||
|
super(FloatingIpTestCasesAdmin, cls).resource_setup()
|
||||||
|
cls.network = cls.create_network()
|
||||||
|
cls.create_subnet(cls.network)
|
||||||
|
router = cls.create_router_by_client()
|
||||||
|
cls.create_router_interface(router['id'], cls.subnets[0]['id'])
|
||||||
|
# Create keypair with admin privileges
|
||||||
|
cls.keypair = cls.create_keypair(client=cls.os_admin.keypairs_client)
|
||||||
|
# Create security group with admin privileges
|
||||||
|
cls.secgroup = cls.os_admin.network_client.create_security_group(
|
||||||
|
name=data_utils.rand_name('secgroup'))['security_group']
|
||||||
|
# Execute funcs to achieve ssh and ICMP capabilities
|
||||||
|
funcs = [cls.create_loginable_secgroup_rule,
|
||||||
|
cls.create_pingable_secgroup_rule]
|
||||||
|
for func in funcs:
|
||||||
|
func(secgroup_id=cls.secgroup['id'],
|
||||||
|
client=cls.os_admin.network_client)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resource_cleanup(cls):
|
||||||
|
# Cleanup for security group
|
||||||
|
cls.os_admin.network_client.delete_security_group(
|
||||||
|
security_group_id=cls.secgroup['id'])
|
||||||
|
super(FloatingIpTestCasesAdmin, cls).resource_cleanup()
|
||||||
|
|
||||||
|
def _list_hypervisors(self):
|
||||||
|
# List of hypervisors
|
||||||
|
return self.os_admin.hv_client.list_hypervisors()['hypervisors']
|
||||||
|
|
||||||
|
def _list_availability_zones(self):
|
||||||
|
# List of availability zones
|
||||||
|
func = self.os_admin.az_client.list_availability_zones
|
||||||
|
return func()['availabilityZoneInfo']
|
||||||
|
|
||||||
|
def _create_vms(self, hyper, avail_zone, num_servers=2):
|
||||||
|
servers, fips, server_ssh_clients = ([], [], [])
|
||||||
|
# Create the availability zone with default zone and
|
||||||
|
# a specific mentioned hypervisor.
|
||||||
|
az = avail_zone + ':' + hyper
|
||||||
|
for i in range(num_servers):
|
||||||
|
servers.append(self.create_server(
|
||||||
|
flavor_ref=CONF.compute.flavor_ref,
|
||||||
|
image_ref=CONF.compute.image_ref,
|
||||||
|
key_name=self.keypair['name'],
|
||||||
|
networks=[{'uuid': self.network['id']}],
|
||||||
|
security_groups=[{'name': self.secgroup['name']}],
|
||||||
|
availability_zone=az))
|
||||||
|
for i, server in enumerate(servers):
|
||||||
|
waiters.wait_for_server_status(
|
||||||
|
self.os_admin.servers_client, server['server']['id'],
|
||||||
|
const.SERVER_STATUS_ACTIVE)
|
||||||
|
port = self.client.list_ports(
|
||||||
|
network_id=self.network['id'],
|
||||||
|
device_id=server['server']['id']
|
||||||
|
)['ports'][0]
|
||||||
|
fips.append(self.create_and_associate_floatingip(
|
||||||
|
port['id'], client=self.os_admin.network_client))
|
||||||
|
server_ssh_clients.append(ssh.Client(
|
||||||
|
fips[i]['floating_ip_address'], CONF.validation.image_ssh_user,
|
||||||
|
pkey=self.keypair['private_key']))
|
||||||
|
self.addCleanup(self.os_admin.network_client.delete_floatingip,
|
||||||
|
fips[i]['id'])
|
||||||
|
return server_ssh_clients, fips
|
||||||
|
|
||||||
|
@decorators.idempotent_id('6bba729b-3fb6-494b-9e1e-82bbd89a1045')
|
||||||
|
def test_two_vms_fips(self):
|
||||||
|
"""This test verifies the ability of two instances
|
||||||
|
that were created in the same compute node and same availability zone
|
||||||
|
to reach each other.
|
||||||
|
"""
|
||||||
|
# Get hypervisor list to pass it for vm creation
|
||||||
|
hyper = self._list_hypervisors()[0]['hypervisor_hostname']
|
||||||
|
# Get availability zone list to pass it for vm creation
|
||||||
|
avail_zone = self._list_availability_zones()[0]['zoneName']
|
||||||
|
server_ssh_clients, fips = self._create_vms(hyper, avail_zone)
|
||||||
|
self.check_remote_connectivity(
|
||||||
|
server_ssh_clients[0], fips[1]['floating_ip_address'])
|
@ -42,15 +42,17 @@ class BaseTempestTestCase(base_api.BaseNetworkTest):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def resource_cleanup(cls):
|
def resource_cleanup(cls):
|
||||||
for keypair in cls.keypairs:
|
for keypair in cls.keypairs:
|
||||||
cls.os_primary.keypairs_client.delete_keypair(
|
client = keypair['client']
|
||||||
keypair_name=keypair['name'])
|
client.delete_keypair(
|
||||||
|
keypair_name=keypair['keypair']['name'])
|
||||||
|
|
||||||
super(BaseTempestTestCase, cls).resource_cleanup()
|
super(BaseTempestTestCase, cls).resource_cleanup()
|
||||||
|
|
||||||
def create_server(self, flavor_ref, image_ref, key_name, networks,
|
def create_server(self, flavor_ref, image_ref, key_name, networks,
|
||||||
name=None, security_groups=None):
|
**kwargs):
|
||||||
"""Create a server using tempest lib
|
"""Create a server using tempest lib
|
||||||
All the parameters are the ones used in Compute API
|
All the parameters are the ones used in Compute API
|
||||||
|
* - Kwargs that require admin privileges
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
flavor_ref(str): The flavor of the server to be provisioned.
|
flavor_ref(str): The flavor of the server to be provisioned.
|
||||||
@ -61,30 +63,47 @@ class BaseTempestTestCase(base_api.BaseNetworkTest):
|
|||||||
an interface to be attached to the server. For network
|
an interface to be attached to the server. For network
|
||||||
it should be {'uuid': network_uuid} and for port it should
|
it should be {'uuid': network_uuid} and for port it should
|
||||||
be {'port': port_uuid}
|
be {'port': port_uuid}
|
||||||
|
kwargs:
|
||||||
name(str): Name of the server to be provisioned.
|
name(str): Name of the server to be provisioned.
|
||||||
security_groups(list): List of dictionaries where
|
security_groups(list): List of dictionaries where
|
||||||
the keys is 'name' and the value is the name of
|
the keys is 'name' and the value is the name of
|
||||||
the security group. If it's not passed the default
|
the security group. If it's not passed the default
|
||||||
security group will be used.
|
security group will be used.
|
||||||
|
availability_zone(str)*: The availability zone that
|
||||||
|
the instance will be in.
|
||||||
|
You can request a specific az without actually creating one,
|
||||||
|
Just pass 'X:Y' where X is the default availability
|
||||||
|
zone, and Y is the compute host name.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = name or data_utils.rand_name('server-test')
|
name = kwargs.get('name', data_utils.rand_name('server-test'))
|
||||||
if not security_groups:
|
security_groups = kwargs.get(
|
||||||
security_groups = [{'name': 'default'}]
|
'security_groups', [{'name': 'default'}])
|
||||||
|
availability_zone = kwargs.get('availability_zone')
|
||||||
|
|
||||||
server = self.os_primary.servers_client.create_server(
|
server_args = {
|
||||||
name=name,
|
'name': name,
|
||||||
flavorRef=flavor_ref,
|
'flavorRef': flavor_ref,
|
||||||
imageRef=image_ref,
|
'imageRef': image_ref,
|
||||||
key_name=key_name,
|
'key_name': key_name,
|
||||||
networks=networks,
|
'networks': networks,
|
||||||
security_groups=security_groups)
|
'security_groups': security_groups
|
||||||
|
}
|
||||||
|
|
||||||
|
if availability_zone:
|
||||||
|
server_args['availability_zone'] = availability_zone
|
||||||
|
client = self.os_admin.servers_client
|
||||||
|
else:
|
||||||
|
client = self.os_primary.servers_client
|
||||||
|
|
||||||
|
server = client.create_server(**server_args)
|
||||||
|
|
||||||
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
|
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
|
||||||
waiters.wait_for_server_termination,
|
waiters.wait_for_server_termination,
|
||||||
self.os_primary.servers_client, server['server']['id'])
|
client,
|
||||||
|
server['server']['id'])
|
||||||
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
|
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
|
||||||
self.os_primary.servers_client.delete_server,
|
client.delete_server,
|
||||||
server['server']['id'])
|
server['server']['id'])
|
||||||
return server
|
return server
|
||||||
|
|
||||||
@ -93,12 +112,16 @@ class BaseTempestTestCase(base_api.BaseNetworkTest):
|
|||||||
client = client or cls.os_primary.keypairs_client
|
client = client or cls.os_primary.keypairs_client
|
||||||
name = data_utils.rand_name('keypair-test')
|
name = data_utils.rand_name('keypair-test')
|
||||||
body = client.create_keypair(name=name)
|
body = client.create_keypair(name=name)
|
||||||
cls.keypairs.append(body['keypair'])
|
body.update(client=client)
|
||||||
|
if client is cls.os_primary.keypairs_client:
|
||||||
|
cls.keypairs.append(body)
|
||||||
|
|
||||||
return body['keypair']
|
return body['keypair']
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_secgroup_rules(cls, rule_list, secgroup_id=None):
|
def create_secgroup_rules(cls, rule_list, client=None,
|
||||||
client = cls.os_primary.network_client
|
secgroup_id=None):
|
||||||
|
client = client or cls.os_primary.network_client
|
||||||
if not secgroup_id:
|
if not secgroup_id:
|
||||||
sgs = client.list_security_groups()['security_groups']
|
sgs = client.list_security_groups()['security_groups']
|
||||||
for sg in sgs:
|
for sg in sgs:
|
||||||
@ -114,7 +137,8 @@ class BaseTempestTestCase(base_api.BaseNetworkTest):
|
|||||||
**rule)
|
**rule)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_loginable_secgroup_rule(cls, secgroup_id=None):
|
def create_loginable_secgroup_rule(cls, secgroup_id=None,
|
||||||
|
client=None):
|
||||||
"""This rule is intended to permit inbound ssh
|
"""This rule is intended to permit inbound ssh
|
||||||
|
|
||||||
Allowing ssh traffic traffic from all sources, so no group_id is
|
Allowing ssh traffic traffic from all sources, so no group_id is
|
||||||
@ -128,10 +152,13 @@ class BaseTempestTestCase(base_api.BaseNetworkTest):
|
|||||||
'port_range_min': 22,
|
'port_range_min': 22,
|
||||||
'port_range_max': 22,
|
'port_range_max': 22,
|
||||||
'remote_ip_prefix': '0.0.0.0/0'}]
|
'remote_ip_prefix': '0.0.0.0/0'}]
|
||||||
cls.create_secgroup_rules(rule_list, secgroup_id=secgroup_id)
|
client = client or cls.os_primary.network_client
|
||||||
|
cls.create_secgroup_rules(rule_list, client,
|
||||||
|
secgroup_id=secgroup_id)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_pingable_secgroup_rule(cls, secgroup_id=None):
|
def create_pingable_secgroup_rule(cls, secgroup_id=None,
|
||||||
|
client=None):
|
||||||
"""This rule is intended to permit inbound ping
|
"""This rule is intended to permit inbound ping
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -140,7 +167,9 @@ class BaseTempestTestCase(base_api.BaseNetworkTest):
|
|||||||
'port_range_min': 8, # type
|
'port_range_min': 8, # type
|
||||||
'port_range_max': 0, # code
|
'port_range_max': 0, # code
|
||||||
'remote_ip_prefix': '0.0.0.0/0'}]
|
'remote_ip_prefix': '0.0.0.0/0'}]
|
||||||
cls.create_secgroup_rules(rule_list, secgroup_id=secgroup_id)
|
client = client or cls.os_primary.network_client
|
||||||
|
cls.create_secgroup_rules(rule_list, client,
|
||||||
|
secgroup_id=secgroup_id)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_router_by_client(cls, is_admin=False, **kwargs):
|
def create_router_by_client(cls, is_admin=False, **kwargs):
|
||||||
@ -155,11 +184,13 @@ class BaseTempestTestCase(base_api.BaseNetworkTest):
|
|||||||
cls.routers.append(router)
|
cls.routers.append(router)
|
||||||
return router
|
return router
|
||||||
|
|
||||||
def create_and_associate_floatingip(self, port_id):
|
def create_and_associate_floatingip(self, port_id, client=None):
|
||||||
fip = self.os_primary.network_client.create_floatingip(
|
client = client or self.os_primary.network_client
|
||||||
|
fip = client.create_floatingip(
|
||||||
CONF.network.public_network_id,
|
CONF.network.public_network_id,
|
||||||
port_id=port_id)['floatingip']
|
port_id=port_id)['floatingip']
|
||||||
self.floating_ips.append(fip)
|
if client is self.os_primary.network_client:
|
||||||
|
self.floating_ips.append(fip)
|
||||||
return fip
|
return fip
|
||||||
|
|
||||||
def setup_network_and_server(self, router=None, **kwargs):
|
def setup_network_and_server(self, router=None, **kwargs):
|
||||||
|
Loading…
Reference in New Issue
Block a user