Update Neutron client and its test cases

- split neutron client integration in smaller modules
- add create/delete functions for main resource types
- let create functions add cleanups functions
- split functional test case in smaller modules

Change-Id: I2d7014fbdc3821092cf3d2443ba32abb718a1e64
This commit is contained in:
Federico Ressi 2022-04-22 09:46:26 +02:00
parent 308c8fd77d
commit 1d7b9ae547
21 changed files with 1223 additions and 518 deletions

View File

@ -17,10 +17,12 @@ from tobiko.openstack.neutron import _agent
from tobiko.openstack.neutron import _client
from tobiko.openstack.neutron import _cidr
from tobiko.openstack.neutron import _extension
from tobiko.openstack.neutron import _floating_ip
from tobiko.openstack.neutron import _port
from tobiko.openstack.neutron import _quota_set
from tobiko.openstack.neutron import _network
from tobiko.openstack.neutron import _router
from tobiko.openstack.neutron import _subnet
SERVER = 'neutron-server'
@ -48,31 +50,9 @@ has_ovs = _agent.has_ovs
NeutronClientFixture = _client.NeutronClientFixture
ServiceUnavailable = _client.ServiceUnavailable
NeutronClientException = _client.NeutronClientException
NeutronClientType = _client.NeutronClientType
neutron_client = _client.neutron_client
get_neutron_client = _client.get_neutron_client
find_floating_ip = _client.find_floating_ip
find_subnet = _client.find_subnet
find_port = _client.find_port
list_ports = _client.list_ports
list_floating_ips = _client.list_floating_ips
get_port_extra_dhcp_opts = _client.get_port_extra_dhcp_opts
create_port = _client.create_port
update_port = _client.update_port
delete_port = _client.delete_port
list_subnets = _client.list_subnets
list_subnet_cidrs = _client.list_subnet_cidrs
get_floating_ip = _client.get_floating_ip
create_floating_ip = _client.create_floating_ip
delete_floating_ip = _client.delete_floating_ip
update_floating_ip = _client.update_floating_ip
get_router = _client.get_router
get_port = _client.get_port
get_subnet = _client.get_subnet
NoSuchPort = _client.NoSuchPort
NoSuchFIP = _client.NoSuchFIP
NoSuchRouter = _client.NoSuchRouter
NoSuchSubnet = _client.NoSuchSubnet
new_ipv4_cidr = _cidr.new_ipv4_cidr
new_ipv6_cidr = _cidr.new_ipv6_cidr
@ -80,27 +60,69 @@ new_ipv6_cidr = _cidr.new_ipv6_cidr
get_networking_extensions = _extension.get_networking_extensions
missing_networking_extensions = _extension.missing_networking_extensions
has_networking_extensions = _extension.has_networking_extensions
skip_if_missing_networking_extensions = (
_extension.skip_if_missing_networking_extensions)
find_port_ip_address = _port.find_port_ip_address
list_port_ip_addresses = _port.list_port_ip_addresses
create_floating_ip = _floating_ip.create_floating_ip
delete_floating_ip = _floating_ip.delete_floating_ip
get_floating_ip = _floating_ip.get_floating_ip
get_floating_ip_id = _floating_ip.get_floating_ip_id
find_floating_ip = _floating_ip.find_floating_ip
list_floating_ips = _floating_ip.list_floating_ips
update_floating_ip = _floating_ip.update_floating_ip
FloatingIpType = _floating_ip.FloatingIpType
FloatingIpIdType = _floating_ip.FloatingIpIdType
NoSuchFloatingIp = _floating_ip.NoSuchFloatingIp
create_port = _port.create_port
delete_port = _port.delete_port
get_port = _port.get_port
get_port_id = _port.get_port_id
find_device_ip_address = _port.find_device_ip_address
find_port = _port.find_port
find_port_ip_address = _port.find_port_ip_address
list_ports = _port.list_ports
list_port_ip_addresses = _port.list_port_ip_addresses
list_device_ip_addresses = _port.list_device_ip_addresses
update_port = _port.update_port
PortType = _port.PortType
PortIdType = _port.PortIdType
NoSuchPort = _port.NoSuchPort
get_neutron_quota_set = _quota_set.get_neutron_quota_set
set_neutron_quota_set = _quota_set.set_neutron_quota_set
ensure_neutron_quota_limits = _quota_set.ensure_neutron_quota_limits
EnsureNeutronQuotaLimitsError = _quota_set.EnsureNeutronQuotaLimitsError
NeutronNetworkFixture = _network.NeutronNetworkFixture
NoSuchNetwork = _network.NoSuchNetwork
create_network = _network.create_network
delete_network = _network.delete_network
get_network = _network.get_network
get_network_id = _network.get_network_id
find_network = _network.find_network
list_networks = _network.list_networks
list_network_nameservers = _network.list_network_nameservers
NoSuchNetwork = _network.NoSuchNetwork
NetworkType = _network.NetworkType
NetworkIdType = _network.NetworkIdType
add_router_interface = _router.add_router_interface
create_router = _router.create_router
delete_router = _router.delete_router
get_router = _router.get_router
get_router_id = _router.get_router_id
remove_router_interface = _router.remove_router_interface
wait_for_master_and_backup_agents = _router.wait_for_master_and_backup_agents
RouterType = _router.RouterType
RouterIdType = _router.RouterIdType
NoSuchRouter = _router.NoSuchRouter
create_subnet = _subnet.create_subnet
delete_subnet = _subnet.delete_subnet
get_subnet = _subnet.get_subnet
get_subnet_id = _subnet.get_subnet_id
find_subnet = _subnet.find_subnet
list_subnets = _subnet.list_subnets
list_subnet_cidrs = _subnet.list_subnet_cidrs
SubnetType = _subnet.SubnetType
SubnetIdType = _subnet.SubnetIdType
NoSuchSubnet = _subnet.NoSuchSubnet

View File

@ -22,6 +22,7 @@ from netaddr.strategy import ipv6
import tobiko
from tobiko.openstack.neutron import _client
from tobiko.openstack.neutron import _subnet
def new_ipv4_cidr(seed=None):
@ -62,7 +63,7 @@ class CIDRGeneratorFixture(tobiko.SharedFixture):
self.client = _client.neutron_client(self.client)
def new_cidr(self, seed):
used_cidrs = set(_client.list_subnet_cidrs(client=self.client))
used_cidrs = set(_subnet.list_subnet_cidrs(client=self.client))
for cidr in random_subnets(cidr=self.cidr, prefixlen=self.prefixlen,
seed=seed):
if cidr not in used_cidrs:

View File

@ -13,10 +13,8 @@
# under the License.
from __future__ import absolute_import
from collections import abc
import typing
import netaddr
from neutronclient.v2_0 import client as neutronclient
import tobiko
@ -24,6 +22,7 @@ from tobiko.openstack import _client
NeutronClientException = neutronclient.exceptions.NeutronClientException
NotFound = neutronclient.exceptions.NotFound
ServiceUnavailable = neutronclient.exceptions.ServiceUnavailable
@ -42,13 +41,13 @@ class NeutronClientManager(_client.OpenstackClientManager):
CLIENTS = NeutronClientManager()
NeutronClientType = typing.Union[None,
neutronclient.Client,
NeutronClientType = typing.Union[neutronclient.Client,
NeutronClientFixture]
def neutron_client(obj: NeutronClientType) -> neutronclient.Client:
if not obj:
def neutron_client(obj: NeutronClientType = None) \
-> neutronclient.Client:
if obj is None:
return get_neutron_client()
if isinstance(obj, neutronclient.Client):
@ -81,165 +80,3 @@ def get_neutron_client(session=None, shared=True, init_client=None,
init_client=init_client)
tobiko.setup_fixture(client)
return client.client
_RAISE_ERROR = object()
def find_floating_ip(client=None, unique=False, default=_RAISE_ERROR,
**attributes):
"""Look for a port matching some property values"""
floating_ips = list_floating_ips(client=client, **attributes)
if default is _RAISE_ERROR or floating_ips:
if unique:
return floating_ips.unique
else:
return floating_ips.first
else:
return default
def find_port(client=None, unique=False, default=_RAISE_ERROR, **attributes):
"""Look for a port matching some property values"""
ports = list_ports(client=client, **attributes)
if default is _RAISE_ERROR or ports:
if unique:
return ports.unique
else:
return ports.first
else:
return default
def find_subnet(client=None, unique=False, default=_RAISE_ERROR, **attributes):
"""Look for a subnet matching some property values"""
subnets = list_subnets(client=client, **attributes)
if default is _RAISE_ERROR or subnets:
if unique:
return subnets.unique
else:
return subnets.first
else:
return default
def list_ports(client=None, **params):
ports = neutron_client(client).list_ports(**params)['ports']
return tobiko.select(ports)
def list_floating_ips(client=None, retrieve_all=True, **params):
floating_ips = neutron_client(client).list_floatingips(
retrieve_all=retrieve_all, **params)['floatingips']
return tobiko.select(floating_ips)
def get_port_extra_dhcp_opts(port_id, client=None, **params):
port = neutron_client(client).show_port(port_id, **params)['port']
return port['extra_dhcp_opts']
NeutronSubnetType = typing.Dict[str, typing.Any]
def list_subnets(client=None, ip_version: typing.Optional[int] = None,
**params) -> tobiko.Selection[NeutronSubnetType]:
if ip_version is not None:
params['ip_version'] = ip_version
subnets = neutron_client(client).list_subnets(**params)
if isinstance(subnets, abc.Mapping):
subnets = subnets['subnets']
return tobiko.select(subnets)
def list_subnet_cidrs(client=None, **params):
return tobiko.select(netaddr.IPNetwork(subnet['cidr'])
for subnet in list_subnets(client=client, **params))
def get_floating_ip(floating_ip, client=None, **params):
try:
floating_ip = neutron_client(client).show_floatingip(
floating_ip, **params)
except neutronclient.exceptions.NotFound as ex:
raise NoSuchFIP(id=floating_ip) from ex
return floating_ip['floatingip']
def create_floating_ip(floating_network_id=None, client=None, **params):
if floating_network_id is None:
from tobiko.openstack import stacks
floating_network_id = tobiko.setup_fixture(
stacks.FloatingNetworkStackFixture).external_id
if floating_network_id is not None:
params['floating_network_id'] = floating_network_id
floating_ip = neutron_client(client).create_floatingip(
body={'floatingip': params})
return floating_ip['floatingip']
def delete_floating_ip(floating_ip, client=None):
try:
neutron_client(client).delete_floatingip(floating_ip)
except neutronclient.exceptions.NotFound as ex:
raise NoSuchFIP(id=floating_ip) from ex
def update_floating_ip(floating_ip, client=None, **params):
fip = neutron_client(client).update_floatingip(
floating_ip, body={'floatingip': params})
return fip['floatingip']
def get_port(port, client=None, **params):
try:
return neutron_client(client).show_port(port, **params)['port']
except neutronclient.exceptions.NotFound as ex:
raise NoSuchPort(id=port) from ex
def create_port(client=None, **params):
port = neutron_client(client).create_port(body={'port': params})
return port['port']
def update_port(port_id, client=None, **params):
port = neutron_client(client).update_port(port_id, body={'port': params})
return port['port']
def delete_port(port, client=None):
try:
neutron_client(client).delete_port(port)
except neutronclient.exceptions.NotFound as ex:
raise NoSuchPort(id=port) from ex
def get_router(router, client=None, **params):
try:
return neutron_client(client).show_router(router, **params)['router']
except neutronclient.exceptions.NotFound as ex:
raise NoSuchRouter(id=router) from ex
def get_subnet(subnet, client=None, **params):
try:
return neutron_client(client).show_subnet(subnet, **params)['subnet']
except neutronclient.exceptions.NotFound as ex:
raise NoSuchSubnet(id=subnet) from ex
class NoSuchPort(tobiko.ObjectNotFound):
message = "No such port found for {id!r}"
class NoSuchRouter(tobiko.ObjectNotFound):
message = "No such router found for {id!r}"
class NoSuchSubnet(tobiko.ObjectNotFound):
message = "No such subnet found for {id!r}"
class NoSuchFIP(tobiko.ObjectNotFound):
message = "No such floating IP found for {id!r}"

View File

@ -0,0 +1,120 @@
# Copyright 2022 Red Hat
#
# 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 __future__ import absolute_import
import typing
import tobiko
from tobiko.openstack.neutron import _client
from tobiko.openstack.neutron import _network
FloatingIpType = typing.Dict[str, typing.Any]
FloatingIpIdType = typing.Union[str, FloatingIpType]
def get_floating_ip_id(floating_ip: FloatingIpIdType) -> str:
if isinstance(floating_ip, str):
return floating_ip
else:
return floating_ip['id']
def get_floating_ip(floating_ip: FloatingIpType,
client: _client.NeutronClientType = None,
**params):
floating_ip_id = get_floating_ip_id(floating_ip)
try:
return _client.neutron_client(client).show_floatingip(
floating_ip_id, **params)['floatingip']
except _client.NotFound as ex:
raise NoSuchFloatingIp(id=floating_ip_id) from ex
def find_floating_ip(client: _client.NeutronClientType = None,
unique=False,
default: FloatingIpType = None,
**params) -> FloatingIpType:
"""Look for a port matching some property values"""
floating_ips = list_floating_ips(client=client, **params)
if default is None or floating_ips:
if unique:
return floating_ips.unique
else:
return floating_ips.first
else:
return default
def list_floating_ips(client: _client.NeutronClientType = None,
retrieve_all=True,
**params) -> tobiko.Selection[FloatingIpType]:
floating_ips = _client.neutron_client(client).list_floatingips(
retrieve_all=retrieve_all, **params)['floatingips']
return tobiko.select(floating_ips)
def create_floating_ip(network: _network.NetworkIdType = None,
client: _client.NeutronClientType = None,
add_cleanup=True,
**params) -> FloatingIpType:
if 'floating_network_id' not in params:
if network is None:
from tobiko.openstack import stacks
network_id = tobiko.setup_fixture(
stacks.FloatingNetworkStackFixture).external_id
else:
network_id = _network.get_network_id(network)
if network_id is not None:
params['floating_network_id'] = network_id
floating_ip: FloatingIpType = _client.neutron_client(
client).create_floatingip(body={'floatingip': params})['floatingip']
if add_cleanup:
tobiko.add_cleanup(cleanup_floating_ip,
floating_ip=floating_ip,
client=client)
return floating_ip
def cleanup_floating_ip(floating_ip: FloatingIpIdType,
client: _client.NeutronClientType = None):
try:
delete_floating_ip(floating_ip=floating_ip,
client=client)
except NoSuchFloatingIp:
pass
def delete_floating_ip(floating_ip: FloatingIpIdType,
client: _client.NeutronClientType = None):
floating_ip_id = get_floating_ip_id(floating_ip)
try:
_client.neutron_client(client).delete_floatingip(floating_ip_id)
except _client.NotFound as ex:
raise NoSuchFloatingIp(id=floating_ip_id) from ex
def update_floating_ip(floating_ip: FloatingIpIdType,
client: _client.NeutronClientType = None,
**params) -> FloatingIpType:
floating_ip_id = get_floating_ip_id(floating_ip)
try:
return _client.neutron_client(client).update_floatingip(
floating_ip_id, body={'floatingip': params})['floatingip']
except _client.NotFound as ex:
raise NoSuchFloatingIp(id=floating_ip_id) from ex
class NoSuchFloatingIp(tobiko.ObjectNotFound):
message = "No such floating IP found for {id!r}"

View File

@ -19,38 +19,50 @@ import netaddr
import tobiko
from tobiko.openstack.neutron import _client
from tobiko.openstack.neutron import _subnet
NetworkType = typing.Dict[str, typing.Any]
NetworkIdType = typing.Union[str, NetworkType]
class NoSuchNetwork(tobiko.ObjectNotFound):
message = "No such network found for {id!r}"
NeutronNetworkType = typing.Dict[str, typing.Any]
def get_network_id(network: NetworkIdType) -> str:
if isinstance(network, str):
return network
else:
return network['id']
def get_network(network, client=None, **params) -> NeutronNetworkType:
def get_network(network: NetworkIdType,
client: _client.NeutronClientType = None,
**params) -> NetworkType:
network_id = get_network_id(network)
try:
return _client.neutron_client(
client).show_network(network, **params)['network']
return _client.neutron_client(client).show_network(
network_id, **params)['network']
except _client.neutronclient.exceptions.NotFound as ex:
raise NoSuchNetwork(id=network) from ex
raise NoSuchNetwork(id=network_id) from ex
def list_networks(client=None, **params) -> \
tobiko.Selection[NeutronNetworkType]:
def list_networks(client: _client.NeutronClientType = None,
**params) -> \
tobiko.Selection[NetworkType]:
networks = _client.neutron_client(client).list_networks(
**params)['networks']
return tobiko.select(networks)
_RAISE_ERROR = object()
def find_network(client=None, unique=False, default=_RAISE_ERROR,
**attributes) -> NeutronNetworkType:
def find_network(client: _client.NeutronClientType = None,
unique=False,
default: NetworkType = None,
**attributes) -> NetworkType:
"""Look for a network matching some property values"""
networks = list_networks(client=client, **attributes)
if default is _RAISE_ERROR or networks:
if default is None or networks:
if unique:
return networks.unique
else:
@ -59,41 +71,37 @@ def find_network(client=None, unique=False, default=_RAISE_ERROR,
return default
def create_network(client=None, **params) -> NeutronNetworkType:
return _client.neutron_client(client).create_network(
def create_network(client: _client.NeutronClientType = None,
add_cleanup=True,
**params) -> NetworkType:
network = _client.neutron_client(client).create_network(
body={'network': params})['network']
if add_cleanup:
tobiko.add_cleanup(cleanup_network, network=network, client=client)
return network
def delete_network(network, client=None):
return _client.neutron_client(client).delete_network(network=network)
def cleanup_network(network: NetworkIdType,
client: _client.NeutronClientType = None):
try:
delete_network(network=network, client=client)
except NoSuchNetwork:
pass
class NeutronNetworkFixture(_client.HasNeutronClientFixture):
details: typing.Optional[NeutronNetworkType] = None
def __init__(self, name: typing.Optional[str] = None,
obj: _client.NeutronClientType = None):
super(NeutronNetworkFixture, self).__init__(obj=obj)
if name is None:
name = self.fixture_name
self.name: str = name
@property
def id(self):
return self.details['id']
def setup_fixture(self):
super(NeutronNetworkFixture, self).setup_fixture()
self.name = self.fixture_name
self.details = create_network(client=self.client, name=self.name)
self.addCleanup(delete_network, network=self.id, client=self.client)
def delete_network(network: NetworkIdType,
client: _client.NeutronClientType = None):
network_id = get_network_id(network)
try:
_client.neutron_client(client).delete_network(network=network_id)
except _client.NotFound as ex:
raise NoSuchNetwork(id=network_id) from ex
def list_network_nameservers(network_id: typing.Optional[str] = None,
ip_version: typing.Optional[int] = None) -> \
tobiko.Selection[netaddr.IPAddress]:
subnets = _client.list_subnets(network_id=network_id)
subnets = _subnet.list_subnets(network_id=network_id)
nameservers = tobiko.Selection[netaddr.IPAddress](
netaddr.IPAddress(nameserver)
for subnets in subnets

View File

@ -19,16 +19,103 @@ import netaddr
import tobiko
from tobiko.openstack.neutron import _client
from tobiko.openstack.neutron import _network
from tobiko.openstack.neutron import _subnet
from tobiko.shell import ssh
from tobiko.shell import ping
NeutronPortType = typing.Dict[str, typing.Any]
PortType = typing.Dict[str, typing.Any]
PortIdType = typing.Union[str, PortType]
def list_port_ip_addresses(port: NeutronPortType,
subnet_id: typing.Optional[str] = None,
ip_version: typing.Optional[int] = None,
def get_port_id(port: PortIdType) -> str:
if isinstance(port, str):
return port
else:
return port['id']
def get_port(port: PortIdType,
client: _client.NeutronClientType = None,
**params) -> PortType:
port_id = get_port_id(port)
try:
return _client.neutron_client(client).show_port(
port_id, **params)['port']
except _client.NotFound as ex:
raise NoSuchPort(id=port_id) from ex
def create_port(client: _client.NeutronClientType = None,
network: _network.NetworkIdType = None,
add_cleanup=True,
**params) -> PortType:
if 'network_id' not in params:
if network is None:
from tobiko.openstack import stacks
network_id = tobiko.setup_fixture(
stacks.NetworkStackFixture).network_id
else:
network_id = _network.get_network_id(network)
params['network_id'] = network_id
port = _client.neutron_client(client).create_port(
body={'port': params})['port']
if add_cleanup:
tobiko.add_cleanup(cleanup_port, port=port, client=client)
return port
def cleanup_port(port: PortIdType,
client: _client.NeutronClientType = None):
try:
delete_port(port=port, client=client)
except NoSuchPort:
pass
def update_port(port: PortIdType,
client: _client.NeutronClientType = None,
**params) -> PortType:
port_id = get_port_id(port)
reply = _client.neutron_client(client).update_port(port_id,
body={'port': params})
return reply['port']
def delete_port(port: PortIdType,
client: _client.NeutronClientType = None):
port_id = get_port_id(port)
try:
_client.neutron_client(client).delete_port(port_id)
except _client.NotFound as ex:
raise NoSuchPort(id=port_id) from ex
def list_ports(client: _client.NeutronClientType = None,
**params) -> tobiko.Selection[PortType]:
ports = _client.neutron_client(client).list_ports(**params)['ports']
return tobiko.select(ports)
def find_port(client: _client.NeutronClientType = None,
unique=False,
default: PortType = None,
**params):
"""Look for a port matching some property values"""
ports = list_ports(client=client, **params)
if default is None or ports:
if unique:
return ports.unique
else:
return ports.first
else:
return default
def list_port_ip_addresses(port: PortType,
subnet_id: str = None,
ip_version: int = None,
check_connectivity: bool = False,
ssh_client: ssh.SSHClientFixture = None) -> \
tobiko.Selection[netaddr.IPAddress]:
@ -44,7 +131,8 @@ def list_port_ip_addresses(port: NeutronPortType,
return addresses
def find_port_ip_address(port: NeutronPortType, unique: bool = False,
def find_port_ip_address(port: PortType,
unique: bool = False,
**kwargs) -> netaddr.IPAddress:
addresses = list_port_ip_addresses(port=port, **kwargs)
if unique:
@ -54,19 +142,22 @@ def find_port_ip_address(port: NeutronPortType, unique: bool = False,
def list_device_ip_addresses(device_id: str,
network_id: typing.Optional[str] = None,
ip_version: typing.Optional[int] = None,
network_id: str = None,
ip_version: int = None,
check_connectivity: bool = False,
ssh_client: ssh.SSHClientFixture = None,
need_dhcp: typing.Optional[bool] = None,
need_dhcp: bool = None,
client: _client.NeutronClientType = None,
**subnet_params) -> \
tobiko.Selection[netaddr.IPAddress]:
ports = _client.list_ports(device_id=device_id,
network_id=network_id)
ports = list_ports(device_id=device_id,
network_id=network_id,
client=client)
if need_dhcp is not None:
subnet_params['enable_dhcp'] = bool(need_dhcp)
subnets = _client.list_subnets(network_id=network_id,
subnets = _subnet.list_subnets(network_id=network_id,
ip_version=ip_version,
client=client,
**subnet_params)
addresses = tobiko.Selection[netaddr.IPAddress](
port_ip
@ -81,9 +172,15 @@ def list_device_ip_addresses(device_id: str,
return addresses
def find_device_ip_address(device_id: str, unique: bool = False, **kwargs):
def find_device_ip_address(device_id: str,
unique: bool = False,
**kwargs):
addresses = list_device_ip_addresses(device_id=device_id, **kwargs)
if unique:
return addresses.unique
else:
return addresses.first
class NoSuchPort(tobiko.ObjectNotFound):
message = "No such port found for {id!r}"

View File

@ -20,17 +20,78 @@ from oslo_log import log
import tobiko
from tobiko.openstack.neutron import _agent
from tobiko.openstack.neutron import _client
from tobiko.openstack.neutron import _network
from tobiko.openstack.neutron import _port
from tobiko.openstack.neutron import _subnet
LOG = log.getLogger(__name__)
RouterType = typing.Dict[str, typing.Any]
RouterIdType = typing.Union[str, RouterType]
def get_router_id(router: RouterIdType) -> str:
if isinstance(router, str):
return router
else:
return router['id']
def get_router(router: RouterIdType, client=None, **params) -> RouterType:
router_id = get_router_id(router)
try:
return _client.neutron_client(client).show_router(
router_id, **params)['router']
except _client.NotFound as ex:
raise NoSuchRouter(id=router_id) from ex
def create_router(client: _client.NeutronClientType = None,
network: _network.NetworkIdType = None,
add_cleanup=True,
**params) -> RouterType:
if 'external_gateway_info' not in params:
if network is None:
from tobiko.openstack import stacks
network_id = tobiko.setup_fixture(
stacks.FloatingNetworkStackFixture).external_id
else:
network_id = _network.get_network_id(network)
params['external_gateway_info'] = dict(network_id=network_id)
router = _client.neutron_client(client).create_router(
body={'router': params})['router']
if add_cleanup:
tobiko.add_cleanup(cleanup_router, router=router, client=client)
return router
def cleanup_router(router: RouterIdType,
client: _client.NeutronClientType = None):
try:
delete_router(router=router, client=client)
except NoSuchRouter:
pass
def delete_router(router: RouterIdType,
client: _client.NeutronClientType = None):
router_id = get_router_id(router)
try:
_client.neutron_client(client).delete_router(router_id)
except _client.NotFound as ex:
raise NoSuchRouter(id=router_id) from ex
def wait_for_master_and_backup_agents(
router_id: str,
router: RouterIdType,
unique_master: bool = True,
timeout: tobiko.Seconds = None,
interval: tobiko.Seconds = None) -> \
typing.Tuple[typing.Dict, typing.List[typing.Dict]]:
router_id = get_router_id(router)
for attempt in tobiko.retry(timeout=timeout,
interval=interval,
default_timeout=300.,
@ -69,3 +130,58 @@ def wait_for_master_and_backup_agents(
raise RuntimeError("tobiko retry loop ended before break?")
return master_agent, backup_agents
RouterInterfaceType = typing.Dict[str, typing.Any]
def add_router_interface(router: RouterIdType,
subnet: _subnet.SubnetIdType = None,
port: _port.PortIdType = None,
client: _client.NeutronClientType = None,
add_cleanup=True,
**params) -> RouterInterfaceType:
router_id = get_router_id(router)
if 'port_id' not in params and port is not None:
params['port_id'] = _port.get_port_id(port)
elif 'subnet_id' not in params and subnet is not None:
params['subnet_id'] = _subnet.get_subnet_id(subnet)
interface = _client.neutron_client(client).add_interface_router(
router=router_id, body=params)
if add_cleanup:
tobiko.add_cleanup(cleanup_router_interface, router=router,
subnet=subnet, port=port, client=client)
return interface
def cleanup_router_interface(router: RouterIdType,
subnet: _subnet.SubnetIdType = None,
port: _port.PortIdType = None,
client: _client.NeutronClientType = None,
**params):
try:
remove_router_interface(router=router, subnet=subnet,
port=port, client=client, **params)
except tobiko.ObjectNotFound:
pass
def remove_router_interface(router: RouterIdType,
subnet: _subnet.SubnetIdType = None,
port: _port.PortIdType = None,
client: _client.NeutronClientType = None,
**params):
router_id = get_router_id(router)
if 'port_id' not in params and port is not None:
params['port_id'] = _port.get_port_id(port)
elif 'subnet_id' not in params and subnet is not None:
params['subnet_id'] = _subnet.get_subnet_id(subnet)
try:
_client.neutron_client(client).remove_interface_router(
router=router_id, body=params)
except _client.NotFound as ex:
raise tobiko.ObjectNotFound() from ex
class NoSuchRouter(tobiko.ObjectNotFound):
message = "No such router found for {id!r}"

View File

@ -0,0 +1,117 @@
# Copyright 2022 Red Hat
#
# 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 __future__ import absolute_import
from collections import abc
import typing
import netaddr
import tobiko
from tobiko.openstack.neutron import _client
from tobiko.openstack.neutron import _network
SubnetType = typing.Dict[str, typing.Any]
SubnetIdType = typing.Union[str, SubnetType]
def get_subnet_id(subnet: SubnetIdType) -> str:
if isinstance(subnet, str):
return subnet
else:
return subnet['id']
def get_subnet(subnet: SubnetIdType,
client: _client.NeutronClientType = None,
**params) -> SubnetType:
subnet_id = get_subnet_id(subnet)
try:
return _client.neutron_client(client).show_subnet(
subnet_id, **params)['subnet']
except _client.NotFound as ex:
raise NoSuchSubnet(id=subnet_id) from ex
def create_subnet(client: _client.NeutronClientType = None,
network: _network.NetworkIdType = None,
add_cleanup=True,
**params) -> SubnetType:
if 'network_id' not in params:
if network is None:
from tobiko.openstack import stacks
network_id = tobiko.setup_fixture(
stacks.NetworkStackFixture).network_id
else:
network_id = _network.get_network_id(network)
params['network_id'] = network_id
subnet = _client.neutron_client(client).create_subnet(
body={'subnet': params})['subnet']
if add_cleanup:
tobiko.add_cleanup(cleanup_subnet, subnet=subnet, client=client)
return subnet
def cleanup_subnet(subnet: SubnetIdType,
client: _client.NeutronClientType = None):
try:
delete_subnet(subnet=subnet, client=client)
except NoSuchSubnet:
pass
def delete_subnet(subnet: SubnetIdType,
client: _client.NeutronClientType = None):
subnet_id = get_subnet_id(subnet)
try:
_client.neutron_client(client).delete_subnet(subnet_id)
except _client.NotFound as ex:
raise NoSuchSubnet(id=subnet_id) from ex
def list_subnets(client: _client.NeutronClientType = None,
ip_version: int = None,
**params) -> tobiko.Selection[SubnetType]:
if ip_version is not None:
params['ip_version'] = ip_version
subnets = _client.neutron_client(client).list_subnets(**params)
if isinstance(subnets, abc.Mapping):
subnets = subnets['subnets']
return tobiko.select(subnets)
def list_subnet_cidrs(client: _client.NeutronClientType = None,
**params) -> tobiko.Selection[netaddr.IPNetwork]:
return tobiko.select(netaddr.IPNetwork(subnet['cidr'])
for subnet in list_subnets(client=client, **params))
def find_subnet(client: _client.NeutronClientType = None,
unique=False,
default: SubnetType = None,
**params) -> SubnetType:
"""Look for a subnet matching some property values"""
subnets = list_subnets(client=client, **params)
if default is None or subnets:
if unique:
return subnets.unique
else:
return subnets.first
else:
return default
class NoSuchSubnet(tobiko.ObjectNotFound):
message = "No such subnet found for {id!r}"

View File

@ -398,6 +398,10 @@ class ServerStackFixture(heat.HeatStackFixture, abc.ABC):
ssh_client=ssh_client,
timeout=timeout)
@property
def floating_ip_details(self):
return neutron.get_floating_ip(self.floating_ip_id)
user_data = None

View File

@ -177,9 +177,13 @@ outputs:
description: fixed IP addresses of server
value: {get_attr: [port, fixed_ips]}
floating_ip_id:
description: server floating IP ID
value: {get_resource: floating_ip}
floating_ip_address:
description: Floating IP address of server in public network
value: { get_attr: [ floating_ip, floating_ip_address ] }
value: {get_attr: [floating_ip, floating_ip_address ] }
condition: has_floating_ip
port_security_enabled:

View File

@ -0,0 +1,68 @@
# Copyright (c) 2022 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 __future__ import absolute_import
import testtools
from tobiko.openstack import keystone
from tobiko.openstack import neutron
from tobiko.openstack import tests
@keystone.skip_unless_has_keystone_credentials()
class AgentTest(testtools.TestCase):
def test_skip_if_missing_agents(self, count=1, should_skip=False,
**params):
if should_skip:
expected_exception = self.skipException
else:
expected_exception = self.failureException
@neutron.skip_if_missing_networking_agents(count=count, **params)
def method():
raise self.fail('Not skipped')
exception = self.assertRaises(expected_exception, method)
if should_skip:
agents = neutron.list_agents(**params)
message = "missing {!r} agent(s)".format(count - len(agents))
if params:
message += " with {!s}".format(
','.join('{!s}={!r}'.format(k, v)
for k, v in params.items()))
self.assertEqual(message, str(exception))
else:
self.assertEqual('Not skipped', str(exception))
def test_skip_if_missing_agents_with_no_agents(self):
self.test_skip_if_missing_agents(binary='never-never-land',
should_skip=True)
def test_skip_if_missing_agents_with_big_count(self):
self.test_skip_if_missing_agents(count=1000000,
should_skip=True)
def test_neutron_agents_are_alive(self):
agents = tests.test_neutron_agents_are_alive()
# check has agents and they are all alive
self.assertNotEqual([], agents)
self.assertNotEqual([], agents.with_items(alive=True))
def test_find_agents_with_binary(self):
agent = neutron.list_agents().first
agents = neutron.list_agents(binary=agent['binary'])
self.assertIn(agent['id'], {a['id'] for a in agents})

View File

@ -0,0 +1,113 @@
# Copyright (c) 2022 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 __future__ import absolute_import
import testtools
import tobiko
from tobiko.openstack import keystone
from tobiko.openstack import neutron
from tobiko.openstack import stacks
@keystone.skip_unless_has_keystone_credentials()
class FloatingIpTest(testtools.TestCase):
server = tobiko.required_fixture(stacks.CirrosServerStackFixture)
floating_network_stack = tobiko.required_fixture(
stacks.FloatingNetworkStackFixture)
@property
def floating_network_id(self) -> str:
return self.floating_network_stack.external_id
@property
def floating_network_details(self) -> neutron.NetworkType:
return neutron.get_network(self.floating_network_stack.external_id)
def test_create_floating_ip(self,
network: neutron.NetworkIdType = None) -> \
neutron.FloatingIpType:
floating_ip = neutron.create_floating_ip(network=network)
self.assertIsInstance(floating_ip, dict)
if network is None:
floating_network_id = self.floating_network_id
else:
floating_network_id = neutron.get_network_id(network)
self.assertEqual(floating_network_id,
floating_ip['floating_network_id'])
self.assertEqual(floating_ip, neutron.get_floating_ip(floating_ip))
return floating_ip
def test_create_floating_ip_with_network_id(self):
self.test_create_floating_ip(network=self.floating_network_id)
def test_create_floating_ip_with_network_details(self):
self.test_create_floating_ip(network=self.floating_network_details)
def test_delete_floating_ip_with_id(self):
floating_ip = self.test_create_floating_ip()
neutron.delete_floating_ip(floating_ip['id'])
self.assertRaises(neutron.NoSuchFloatingIp,
neutron.get_floating_ip, floating_ip)
def test_delete_floating_ip_with_details(self):
floating_ip = self.test_create_floating_ip()
neutron.delete_floating_ip(floating_ip)
self.assertRaises(neutron.NoSuchFloatingIp,
neutron.get_floating_ip, floating_ip)
def test_delete_floating_ip_with_invalid_id(self):
self.assertRaises(neutron.NoSuchFloatingIp,
neutron.delete_floating_ip, '<invalid-id>')
def test_list_floating_ips(self):
port_id = self.server.port_id
floating_ips = neutron.list_floating_ips()
floating_ip = floating_ips.with_items(port_id=port_id).unique
self.assertEqual(floating_ip['floating_ip_address'],
self.server.floating_ip_address)
def test_list_floating_ip_with_port_id(self):
port_id = self.server.port_id
floating_ip = neutron.list_floating_ips(port_id=port_id).unique
self.assertEqual(floating_ip['floating_ip_address'],
self.server.floating_ip_address)
def test_list_floating_ip_with_floating_ip_address(self):
floating_ip_address = self.server.floating_ip_address
floating_ip = neutron.list_floating_ips(
floating_ip_address=floating_ip_address).unique
self.assertEqual(floating_ip['port_id'],
self.server.port_id)
def test_find_floating_ip_with_port_id(self):
port_id = self.server.port_id
floating_ip = neutron.find_floating_ip(port_id=port_id, unique=True)
self.assertEqual(floating_ip['floating_ip_address'],
self.server.floating_ip_address)
def test_find_floating_ip_with_floating_ip_address(self):
floating_ip_address = self.server.floating_ip_address
floating_ip = neutron.find_floating_ip(
floating_ip_address=floating_ip_address)
self.assertEqual(floating_ip, self.server.floating_ip_details)
def test_find_floating_ip_with_invalid_floating_ip_address(self):
self.assertRaises(tobiko.ObjectNotFound,
neutron.find_floating_ip,
floating_ip_address='1.2.3.4')

View File

@ -0,0 +1,110 @@
# Copyright (c) 2022 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 __future__ import absolute_import
import netaddr
import testtools
import tobiko
from tobiko import config
from tobiko.openstack import keystone
from tobiko.openstack import neutron
from tobiko.openstack import stacks
CONF = config.CONF
@keystone.skip_unless_has_keystone_credentials()
class NetworkTest(testtools.TestCase):
"""Tests network creation"""
#: Stack of resources with a network with a gateway router
stack = tobiko.required_fixture(stacks.NetworkStackFixture)
def test_find_network_with_id(self):
network = neutron.find_network(id=self.stack.network_id)
self.assertEqual(self.stack.network_id, network['id'])
def test_list_networks(self):
networks = neutron.list_networks()
network_ids = {n['id'] for n in networks}
self.assertIn(self.stack.network_id, network_ids)
def test_list_subnets(self):
subnets = neutron.list_subnets()
subnets_ids = {s['id'] for s in subnets}
if self.stack.has_ipv4:
self.assertIn(self.stack.ipv4_subnet_id, subnets_ids)
if self.stack.has_ipv6:
self.assertIn(self.stack.ipv6_subnet_id, subnets_ids)
def test_list_subnet_cidrs(self):
subnets_cidrs = neutron.list_subnet_cidrs()
if self.stack.has_ipv4:
cidr = netaddr.IPNetwork(self.stack.ipv4_subnet_details['cidr'])
self.assertIn(cidr, subnets_cidrs)
if self.stack.has_ipv6:
cidr = netaddr.IPNetwork(self.stack.ipv6_subnet_details['cidr'])
self.assertIn(cidr, subnets_cidrs)
def test_get_network_with_id(self):
return self._test_get_network(network=self.stack.network_id)
def test_get_network_with_details(self):
return self._test_get_network(network=self.stack.network_details)
def _test_get_network(self, network: neutron.NetworkIdType):
observed = neutron.get_network(network)
network_id = neutron.get_network_id(network)
self.assertEqual(network_id, observed['id'])
def test_create_network(self) -> neutron.NetworkType:
network = neutron.create_network(name=self.id())
self.assertIsInstance(network['id'], str)
self.assertNotEqual('', network['id'])
self.assertEqual(self.id(), network['name'])
self.assertEqual(network['id'], neutron.get_network(network)['id'])
return network
def test_delete_network_with_id(self):
network = self.test_create_network()
neutron.delete_network(network['id'])
self.assertRaises(neutron.NoSuchNetwork, neutron.get_network,
network['id'])
def test_delete_network_with_details(self):
network = self.test_create_network()
neutron.delete_network(network)
self.assertRaises(neutron.NoSuchNetwork, neutron.get_network,
network['id'])
def test_delete_network_with_invalid_id(self):
self.assertRaises(neutron.NoSuchNetwork,
neutron.delete_network, '<invalid-id>')
def test_network_stack(self):
network = neutron.get_network(self.stack.network_id)
self.assertEqual(self.stack.port_security_enabled,
network['port_security_enabled'])
if self.stack.has_ipv4:
self.assertIn(self.stack.ipv4_subnet_id, network['subnets'])
else:
self.assertNotIn(self.stack.ipv4_subnet_id, network['subnets'])
if self.stack.has_ipv6:
self.assertIn(self.stack.ipv6_subnet_id, network['subnets'])
else:
self.assertNotIn(self.stack.ipv6_subnet_id, network['subnets'])

View File

@ -0,0 +1,121 @@
# Copyright (c) 2022 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 __future__ import absolute_import
import netaddr
import testtools
import tobiko
from tobiko.openstack import keystone
from tobiko.openstack import neutron
from tobiko.openstack import nova
from tobiko.openstack import stacks
@keystone.skip_unless_has_keystone_credentials()
class PortTest(testtools.TestCase):
#: Stack of resources with a network with a gateway router
stack = tobiko.required_fixture(stacks.CirrosServerStackFixture)
def test_get_port_with_id(self):
return self._test_get_port(port=self.stack.port_id)
def test_get_port_with_details(self):
return self._test_get_port(port=self.stack.port_details)
def _test_get_port(self, port: neutron.PortIdType):
observed = neutron.get_port(port)
port_id = neutron.get_port_id(port)
self.assertEqual(port_id, observed['id'])
def test_create_port(self,
network: neutron.NetworkIdType = None) \
-> neutron.PortType:
port = neutron.create_port(name=self.id(), network=network)
self.assertIsInstance(port['id'], str)
self.assertNotEqual('', port['id'])
self.assertEqual(self.id(), port['name'])
self.assertEqual(port['id'], neutron.get_port(port)['id'])
if network is not None:
self.assertEqual(neutron.get_network_id(network),
port['network_id'])
return port
def test_create_port_with_network_id(self):
network = neutron.create_network()
self.test_create_port(network=network['id'])
def test_create_port_with_network_details(self):
network = neutron.create_network()
self.test_create_port(network=network)
def test_delete_port_with_id(self):
port = self.test_create_port()
neutron.delete_port(port['id'])
self.assertRaises(neutron.NoSuchPort, neutron.get_port,
port['id'])
def test_delete_port_with_details(self):
port = self.test_create_port()
neutron.delete_port(port)
self.assertRaises(neutron.NoSuchPort, neutron.get_port,
port['id'])
def test_delete_network_with_invalid_id(self):
self.assertRaises(neutron.NoSuchPort,
neutron.delete_port, '<invalid-id>')
def test_list_port_addresses(self, ip_version=None):
port = neutron.find_port(device_id=self.stack.server_id)
port_addresses = neutron.list_port_ip_addresses(
port=port,
ip_version=ip_version)
server_addresses = nova.list_server_ip_addresses(
server=self.stack.server_details,
ip_version=ip_version,
address_type='fixed')
self.assertEqual(set(server_addresses), set(port_addresses))
if ip_version:
self.assertEqual(
port_addresses.with_attributes(version=ip_version),
port_addresses)
def test_list_port_addresses_with_ipv4(self):
self.test_list_port_addresses(ip_version=4)
def test_list_port_addresses_with_ipv6(self):
self.test_list_port_addresses(ip_version=6)
def test_find_port_address_with_ip_version(self):
port = neutron.find_port(device_id=self.stack.server_id)
server_addresses = nova.list_server_ip_addresses(
server=self.stack.server_details,
address_type='fixed')
for server_address in server_addresses:
port_address = neutron.find_port_ip_address(
port=port,
ip_version=server_address.version,
unique=True)
self.assertEqual(server_address, port_address)
def test_find_port_address_with_subnet_id(self):
port = neutron.find_port(device_id=self.stack.server_id)
for subnet in neutron.list_subnets(network_id=port['network_id']):
port_address = neutron.find_port_ip_address(
port=port, subnet_id=subnet['id'], unique=True)
cidr = netaddr.IPNetwork(subnet['cidr'])
self.assertIn(port_address, cidr)

View File

@ -0,0 +1,110 @@
# Copyright (c) 2022 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 __future__ import absolute_import
import testtools
import tobiko
from tobiko.openstack import keystone
from tobiko.openstack import neutron
from tobiko.openstack import stacks
@keystone.skip_unless_has_keystone_credentials()
class RouterTest(testtools.TestCase):
"""Tests network creation"""
#: Stack of resources with a network with a gateway router
stack = tobiko.required_fixture(stacks.NetworkStackFixture)
def test_get_router_with_id(self):
if not self.stack.has_gateway:
tobiko.skip_test(f"Stack {self.stack.stack_name} has no gateway "
"router")
router = neutron.get_router(self.stack.gateway_id)
self.assertEqual(self.stack.gateway_id, router['id'])
def test_get_router_with_details(self):
if not self.stack.has_gateway:
tobiko.skip_test(f"Stack {self.stack.stack_name} has no gateway "
"router")
router = neutron.get_router(self.stack.gateway_details)
self.assertEqual(self.stack.gateway_id, router['id'])
def test_create_router(self,
network: neutron.NetworkIdType = None) \
-> neutron.PortType:
router = neutron.create_router(name=self.id(), network=network)
self.assertIsInstance(router['id'], str)
self.assertNotEqual('', router['id'])
self.assertEqual(self.id(), router['name'])
self.assertEqual(router['id'], neutron.get_router(router)['id'])
if network is not None:
self.assertEqual(neutron.get_network_id(network),
router['external_gateway_info']['network_id'])
return router
def test_create_router_with_network_id(self):
network_id = self.stack.floating_network
self.test_create_router(network=network_id)
def test_create_router_with_network_details(self):
network = {'id': self.stack.floating_network}
self.test_create_router(network=network)
def test_delete_router_with_id(self):
router = self.test_create_router()
neutron.delete_router(router['id'])
self.assertRaises(neutron.NoSuchRouter, neutron.get_router,
router['id'])
def test_delete_router_with_details(self):
router = self.test_create_router()
neutron.delete_router(router)
self.assertRaises(neutron.NoSuchRouter, neutron.get_router,
router['id'])
def test_delete_router_with_invalid_id(self):
self.assertRaises(neutron.NoSuchRouter,
neutron.delete_router, '<invalid-id>')
def test_add_router_interface_with_port(self):
port = neutron.create_port(name=self.id())
router = self.test_create_router()
interface = neutron.add_router_interface(router=router, port=port)
self.assertEqual(port['network_id'], interface['network_id'])
return interface
def test_remove_router_interface_with_port(self):
interface = self.test_add_router_interface_with_port()
neutron.remove_router_interface(router=interface['id'],
port=interface['port_id'])
def test_add_router_interface_with_subnet(self):
network = neutron.create_network(name=self.id())
subnet = neutron.create_subnet(name=self.id(),
network=network,
cidr=neutron.new_ipv4_cidr(),
ip_version=4)
router = self.test_create_router()
interface = neutron.add_router_interface(router=router, subnet=subnet)
self.assertEqual(subnet['id'], interface['subnet_id'])
return interface
def test_remove_router_interface_with_subnet(self):
interface = self.test_add_router_interface_with_subnet()
neutron.remove_router_interface(router=interface['id'],
subnet=interface['subnet_id'])

View File

@ -0,0 +1,92 @@
# Copyright (c) 2019 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 __future__ import absolute_import
import netaddr
import testtools
import tobiko
from tobiko.openstack import keystone
from tobiko.openstack import neutron
from tobiko.openstack import stacks
@keystone.skip_unless_has_keystone_credentials()
class SubnetTest(testtools.TestCase):
"""Tests network creation"""
#: Stack of resources with a network with a gateway router
stack = tobiko.required_fixture(stacks.NetworkStackFixture)
def test_list_subnets(self):
subnets = neutron.list_subnets()
subnets_ids = {s['id'] for s in subnets}
if self.stack.has_ipv4:
self.assertIn(self.stack.ipv4_subnet_id, subnets_ids)
if self.stack.has_ipv6:
self.assertIn(self.stack.ipv6_subnet_id, subnets_ids)
def test_list_subnet_cidrs(self):
subnets_cidrs = neutron.list_subnet_cidrs()
if self.stack.has_ipv4:
cidr = netaddr.IPNetwork(self.stack.ipv4_subnet_details['cidr'])
self.assertIn(cidr, subnets_cidrs)
if self.stack.has_ipv6:
cidr = netaddr.IPNetwork(self.stack.ipv6_subnet_details['cidr'])
self.assertIn(cidr, subnets_cidrs)
def test_get_ipv4_subnet(self):
if not self.stack.has_ipv4:
tobiko.skip_test(
"Stack {self.stack.stack_name} has no IPv4 subnet")
subnet = neutron.get_subnet(self.stack.ipv4_subnet_id)
self.assertEqual(self.stack.ipv4_subnet_id, subnet['id'])
self.assertEqual(self.stack.ipv4_subnet_details, subnet)
def test_get_ipv6_subnet(self):
if not self.stack.has_ipv6:
tobiko.skip_test(
"Stack {self.stack.stack_name} has no IPv6 subnet")
subnet = neutron.get_subnet(self.stack.ipv6_subnet_id)
self.assertEqual(self.stack.ipv6_subnet_id, subnet['id'])
self.assertEqual(self.stack.ipv6_subnet_details, subnet)
def test_create_subnet(self):
network = neutron.create_network(name=self.id())
cidr = neutron.new_ipv4_cidr()
subnet = neutron.create_subnet(network=network,
ip_version=4,
cidr=cidr)
self.assertEqual(network['id'], subnet['network_id'])
self.assertEqual(str(cidr), subnet['cidr'])
self.assertEqual(subnet['id'], neutron.get_subnet(subnet=subnet)['id'])
return subnet
def test_delete_subnet_with_id(self):
subnet = self.test_create_subnet()
neutron.delete_subnet(subnet['id'])
self.assertRaises(neutron.NoSuchSubnet,
neutron.get_subnet, subnet=subnet['id'])
def test_delete_subnet_with_details(self):
subnet = self.test_create_subnet()
neutron.delete_subnet(subnet)
self.assertRaises(neutron.NoSuchSubnet,
neutron.get_subnet, subnet=subnet)
def test_delete_subnet_with_invalid_id(self):
self.assertRaises(neutron.NoSuchSubnet, neutron.delete_subnet,
'<invalid-id>')

View File

@ -1,250 +0,0 @@
# Copyright (c) 2019 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 __future__ import absolute_import
import netaddr
import testtools
import tobiko
from tobiko import config
from tobiko.openstack import keystone
from tobiko.openstack import neutron
from tobiko.openstack import nova
from tobiko.openstack import stacks
from tobiko.openstack import tests
CONF = config.CONF
@keystone.skip_unless_has_keystone_credentials()
class NeutronApiTest(testtools.TestCase):
"""Tests network creation"""
#: Stack of resources with a network with a gateway router
stack = tobiko.required_fixture(stacks.NetworkStackFixture)
def test_find_network_with_id(self):
network = neutron.find_network(id=self.stack.network_id)
self.assertEqual(self.stack.network_id, network['id'])
def test_find_floating_network(self):
floating_network = CONF.tobiko.neutron.floating_network
if not floating_network:
tobiko.skip_test('floating_network not configured')
network = neutron.find_network(name=floating_network)
self.assertIn(floating_network, [network['name'], network['id']])
self.assertEqual(self.stack.gateway_network_id, network['id'])
def test_list_networks(self):
networks = neutron.list_networks()
network_ids = {n['id'] for n in networks}
self.assertIn(self.stack.network_id, network_ids)
def test_list_subnets(self):
subnets = neutron.list_subnets()
subnets_ids = {s['id'] for s in subnets}
if self.stack.has_ipv4:
self.assertIn(self.stack.ipv4_subnet_id, subnets_ids)
if self.stack.has_ipv6:
self.assertIn(self.stack.ipv6_subnet_id, subnets_ids)
def test_list_subnet_cidrs(self):
subnets_cidrs = neutron.list_subnet_cidrs()
if self.stack.has_ipv4:
cidr = netaddr.IPNetwork(self.stack.ipv4_subnet_details['cidr'])
self.assertIn(cidr, subnets_cidrs)
if self.stack.has_ipv6:
cidr = netaddr.IPNetwork(self.stack.ipv6_subnet_details['cidr'])
self.assertIn(cidr, subnets_cidrs)
def test_get_network(self):
network = neutron.get_network(self.stack.network_id)
self.assertEqual(self.stack.network_id, network['id'])
self.assertEqual(self.stack.port_security_enabled,
network['port_security_enabled'])
if self.stack.has_ipv4:
self.assertIn(self.stack.ipv4_subnet_id, network['subnets'])
else:
self.assertNotIn(self.stack.ipv4_subnet_id, network['subnets'])
if self.stack.has_ipv6:
self.assertIn(self.stack.ipv6_subnet_id, network['subnets'])
else:
self.assertNotIn(self.stack.ipv6_subnet_id, network['subnets'])
def test_create_network(self):
network = neutron.create_network(name=self.id())
self.addCleanup(neutron.delete_network, network['id'])
self.assertIsInstance(network['id'], str)
self.assertNotEqual('', network['id'])
self.assertEqual(self.id(), network['name'])
observed = neutron.get_network(network['id'])
self.assertEqual(network['id'], observed['id'])
def test_delete_network(self):
network = neutron.create_network(name=self.id())
neutron.delete_network(network['id'])
self.assertRaises(neutron.NoSuchNetwork, neutron.get_network,
network['id'])
def test_get_router(self):
if not self.stack.has_gateway:
tobiko.skip_test(f"Stack {self.stack.stack_name} has no gateway "
"router")
router = neutron.get_router(self.stack.gateway_id)
self.assertEqual(self.stack.gateway_id, router['id'])
def test_get_ipv4_subnet(self):
if not self.stack.has_ipv4:
tobiko.skip_test(
"Stack {self.stack.stack_name} has no IPv4 subnet")
subnet = neutron.get_subnet(self.stack.ipv4_subnet_id)
self.assertEqual(self.stack.ipv4_subnet_id, subnet['id'])
self.assertEqual(self.stack.ipv4_subnet_details, subnet)
def test_get_ipv6_subnet(self):
if not self.stack.has_ipv6:
tobiko.skip_test(
"Stack {self.stack.stack_name} has no IPv6 subnet")
subnet = neutron.get_subnet(self.stack.ipv6_subnet_id)
self.assertEqual(self.stack.ipv6_subnet_id, subnet['id'])
self.assertEqual(self.stack.ipv6_subnet_details, subnet)
def test_find_agents_with_binary(self):
agent = neutron.list_agents().first
agents = neutron.list_agents(binary=agent['binary'])
self.assertIn(agent['id'], {a['id'] for a in agents})
@keystone.skip_unless_has_keystone_credentials()
class PortTest(testtools.TestCase):
#: Stack of resources with a network with a gateway router
stack = tobiko.required_fixture(stacks.CirrosServerStackFixture)
def test_list_port_addresses(self, ip_version=None):
port = neutron.find_port(device_id=self.stack.server_id)
port_addresses = neutron.list_port_ip_addresses(
port=port,
ip_version=ip_version)
server_addresses = nova.list_server_ip_addresses(
server=self.stack.server_details,
ip_version=ip_version,
address_type='fixed')
self.assertEqual(set(server_addresses), set(port_addresses))
if ip_version:
self.assertEqual(
port_addresses.with_attributes(version=ip_version),
port_addresses)
def test_list_port_addresses_with_ipv4(self):
self.test_list_port_addresses(ip_version=4)
def test_list_port_addresses_with_ipv6(self):
self.test_list_port_addresses(ip_version=6)
def test_find_port_address_with_ip_version(self):
port = neutron.find_port(device_id=self.stack.server_id)
server_addresses = nova.list_server_ip_addresses(
server=self.stack.server_details,
address_type='fixed')
for server_address in server_addresses:
port_address = neutron.find_port_ip_address(
port=port,
ip_version=server_address.version,
unique=True)
self.assertEqual(server_address, port_address)
def test_find_port_address_with_subnet_id(self):
port = neutron.find_port(device_id=self.stack.server_id)
for subnet in neutron.list_subnets(network_id=port['network_id']):
port_address = neutron.find_port_ip_address(
port=port, subnet_id=subnet['id'], unique=True)
cidr = netaddr.IPNetwork(subnet['cidr'])
self.assertIn(port_address, cidr)
@keystone.skip_unless_has_keystone_credentials()
class FloatingIpTest(testtools.TestCase):
server = tobiko.required_fixture(stacks.CirrosServerStackFixture)
def test_list_floating_ip(self):
port_id = self.server.port_id
floating_ips = neutron.list_floating_ips()
floating_ip = floating_ips.with_items(port_id=port_id).unique
self.assertEqual(floating_ip['floating_ip_address'],
self.server.floating_ip_address)
def test_list_floating_ip_with_port_id(self):
port_id = self.server.port_id
floating_ip = neutron.list_floating_ips(port_id=port_id).unique
self.assertEqual(floating_ip['floating_ip_address'],
self.server.floating_ip_address)
def test_list_floating_ip_with_floating_ip_address(self):
floating_ip_address = self.server.floating_ip_address
floating_ip = neutron.list_floating_ips(
floating_ip_address=floating_ip_address).unique
self.assertEqual(floating_ip['port_id'],
self.server.port_id)
def test_find_floating_ip_with_port_id(self):
port_id = self.server.port_id
floating_ip = neutron.find_floating_ip(port_id=port_id, unique=True)
self.assertEqual(floating_ip['floating_ip_address'],
self.server.floating_ip_address)
@keystone.skip_unless_has_keystone_credentials()
class AgentTest(testtools.TestCase):
def test_skip_if_missing_agents(self, count=1, should_skip=False,
**params):
if should_skip:
expected_exeption = self.skipException
else:
expected_exeption = self.failureException
@neutron.skip_if_missing_networking_agents(count=count, **params)
def method():
raise self.fail('Not skipped')
exception = self.assertRaises(expected_exeption, method)
if should_skip:
agents = neutron.list_agents(**params)
message = "missing {!r} agent(s)".format(count - len(agents))
if params:
message += " with {!s}".format(
','.join('{!s}={!r}'.format(k, v)
for k, v in params.items()))
self.assertEqual(message, str(exception))
else:
self.assertEqual('Not skipped', str(exception))
def test_skip_if_missing_agents_with_no_agents(self):
self.test_skip_if_missing_agents(binary='never-never-land',
should_skip=True)
def test_skip_if_missing_agents_with_big_count(self):
self.test_skip_if_missing_agents(count=1000000,
should_skip=True)
def test_neutron_agents_are_alive(self):
agents = tests.test_neutron_agents_are_alive()
# check has agents and they are all alive
self.assertNotEqual([], agents)
self.assertNotEqual([], agents.with_items(alive=True))

View File

@ -244,11 +244,8 @@ class TestFloatingIPLogging(testtools.TestCase):
def setUp(self):
super(TestFloatingIPLogging, self).setUp()
net = self.stack.network_id
self.port = neutron.create_port(**{'network_id': net})
self.addCleanup(self.cleanup_port)
self.port = neutron.create_port(network_id=self.stack.network_id)
self.fip = neutron.create_floating_ip()
self.addCleanup(self.cleanup_floatingip)
log_filename = '/var/log/containers/neutron/server.log'
self.log_digger = files.MultihostLogFileDigger(filename=log_filename,
sudo=True)
@ -256,18 +253,6 @@ class TestFloatingIPLogging(testtools.TestCase):
self.log_digger.add_host(hostname=node.hostname,
ssh_client=node.ssh_client)
def cleanup_port(self):
try:
neutron.delete_port(self.port['id'])
except neutron.NoSuchPort:
pass
def cleanup_floatingip(self):
try:
neutron.delete_floating_ip(self.fip['id'])
except neutron.NoSuchFIP:
pass
def test_fip_attach_log(self):
'''Test log that FIP is attached to VM'''
pattern = f'{self.fip["id"]}.*associated'

View File

@ -143,9 +143,8 @@ class ExtraDhcpOptsPortTest(PortTest):
stacks.ExtraDhcpOptsCirrosServerStackFixture)
def test_extra_dhcp_opts(self):
extra_dhcp_options = neutron.get_port_extra_dhcp_opts(
self.stack.port_id)
for option in extra_dhcp_options:
port = neutron.get_port(self.stack.port_id)
for option in port['extra_dhcp_opts']:
if 'domain-name' == option['opt_name']:
domain = option['opt_value'].replace('"', '')
break

View File

@ -66,3 +66,34 @@ class NeutronClientTest(openstack.OpenstackTest):
client = neutron.neutron_client(fixture)
self.assertIsInstance(client, neutronclient.Client)
self.assertIs(client, fixture.client)
def test_get_floating_ip_id_with_str(self):
self.assertEqual('some_id', neutron.get_floating_ip_id('some_id'))
def test_get_floating_ip_id_with_dict(self):
self.assertEqual('some_id',
neutron.get_floating_ip_id({'id': 'some_id'}))
def test_get_network_id_with_str(self):
self.assertEqual('some_id', neutron.get_network_id('some_id'))
def test_get_network_id_with_dict(self):
self.assertEqual('some_id', neutron.get_network_id({'id': 'some_id'}))
def test_get_port_id_with_str(self):
self.assertEqual('some_id', neutron.get_port_id('some_id'))
def test_get_port_id_with_dict(self):
self.assertEqual('some_id', neutron.get_port_id({'id': 'some_id'}))
def test_get_router_id_with_str(self):
self.assertEqual('some_id', neutron.get_router_id('some_id'))
def test_get_router_id_with_dict(self):
self.assertEqual('some_id', neutron.get_router_id({'id': 'some_id'}))
def test_get_subnet_id_with_str(self):
self.assertEqual('some_id', neutron.get_subnet_id('some_id'))
def test_get_subnet_id_with_dict(self):
self.assertEqual('some_id', neutron.get_subnet_id({'id': 'some_id'}))