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:
parent
308c8fd77d
commit
1d7b9ae547
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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}"
|
||||
|
|
|
@ -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}"
|
|
@ -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
|
||||
|
|
|
@ -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}"
|
||||
|
|
|
@ -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}"
|
||||
|
|
|
@ -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}"
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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})
|
|
@ -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')
|
|
@ -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'])
|
|
@ -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)
|
|
@ -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'])
|
|
@ -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>')
|
|
@ -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))
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'}))
|
||||
|
|
Loading…
Reference in New Issue