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:
Roee Agiman 2017-11-16 11:51:56 +02:00
parent c125fd1479
commit 6a0a18a172
4 changed files with 172 additions and 26 deletions

View File

@ -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 = {

View 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'])

View File

@ -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):