Find an external network when no one is provided

Esternal network ID is stored in a Heat stack to keep the same network
ID for later test case executions.

Remove logic to found for looking for an external network from
DevStack plugin.

Change-Id: Ic7fe03324f4f328488988435530e127cedfab781
This commit is contained in:
Federico Ressi 2020-02-19 15:58:23 +01:00
parent db68499e39
commit 0df9ce7868
11 changed files with 194 additions and 42 deletions

View File

@ -142,12 +142,8 @@ function configure_tobiko_neutron {
# Write floating network
local floating_network=${TOBIKO_NEUTRON_FLOATING_NETWORK}
if [ "${floating_network}" != "" ]; then
local floating_network=$(openstack network show -f value -c name "${floating_network}")
else
local networks=( $( openstack network list -f value -c Name --enable --external) )
local floating_network=${networks[0]}
iniset "${tobiko_conf_file}" neutron floating_network "${floating_network}"
fi
iniset "${tobiko_conf_file}" neutron floating_network "${floating_network}"
}

View File

@ -81,7 +81,7 @@ def filter_by_items(dictionaries, exclude=False, **items):
class ObjectNotFound(_exception.TobikoException):
"Object not found."
"Object not found"
class MultipleObjectsFound(_exception.TobikoException):

View File

@ -38,6 +38,10 @@ get_port = _client.get_port
get_subnet = _client.get_subnet
list_l3_agent_hosting_routers = _client.list_l3_agent_hosting_routers
find_l3_agent_hosting_router = _client.find_l3_agent_hosting_router
NoSuchNetwork = _client.NoSuchNetwork
NoSuchPort = _client.NoSuchPort
NoSuchRouter = _client.NoSuchRouter
NoSuchSubnet = _client.NoSuchSubnet
new_ipv4_cidr = _cidr.new_ipv4_cidr
new_ipv6_cidr = _cidr.new_ipv6_cidr

View File

@ -136,19 +136,32 @@ def get_floating_ip(floating_ip, client=None, **params):
def get_network(network, client=None, **params):
return neutron_client(client).show_network(network, **params)['network']
try:
return neutron_client(client).show_network(network,
**params)['network']
except neutronclient.exceptions.NotFound:
raise NoSuchNetwork(id=network)
def get_port(port, client=None, **params):
return neutron_client(client).show_port(port, **params)['port']
try:
return neutron_client(client).show_port(port, **params)['port']
except neutronclient.exceptions.NotFound:
raise NoSuchPort(id=port)
def get_router(router, client=None, **params):
return neutron_client(client).show_router(router, **params)['router']
try:
return neutron_client(client).show_router(router, **params)['router']
except neutronclient.exceptions.NotFound:
raise NoSuchRouter(id=router)
def get_subnet(subnet, client=None, **params):
return neutron_client(client).show_subnet(subnet, **params)['subnet']
try:
return neutron_client(client).show_subnet(subnet, **params)['subnet']
except neutronclient.exceptions.NotFound:
raise NoSuchSubnet(id=subnet)
def list_l3_agent_hosting_routers(router, client=None, **params):
@ -170,3 +183,19 @@ def find_l3_agent_hosting_router(router, client=None, unique=False,
return agents.first
else:
return default
class NoSuchNetwork(tobiko.ObjectNotFound):
message = "No such network found for {id!r}"
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}"

View File

@ -1,24 +0,0 @@
# Copyright 2019 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 tobiko
class NoSuchNetwork(tobiko.TobikoException):
message = "No such network found for {network!r}"
class MoreNetworksFound(tobiko.TobikoException):
message = "More than one network found for {network!r}: {network_ids!s}"

View File

@ -49,6 +49,10 @@ NetworkWithNetMtuWriteStackFixture = (
_neutron.NetworkWithNetMtuWriteStackFixture)
SecurityGroupsFixture = _neutron.SecurityGroupsFixture
get_floating_network = _neutron.get_floating_network
has_floating_network = _neutron.has_floating_network
skip_if_missing_floating_network = _neutron.skip_if_missing_floating_network
ServerStackFixture = _nova.ServerStackFixture
KeyPairStackFixture = _nova.KeyPairStackFixture
FlavorStackFixture = _nova.FlavorStackFixture

View File

@ -15,6 +15,8 @@
# under the License.
from __future__ import absolute_import
import json
import netaddr
from oslo_log import log
@ -25,10 +27,45 @@ from tobiko.openstack import neutron
from tobiko.openstack.stacks import _hot
LOG = log.getLogger(__name__)
CONF = config.CONF
LOG = log.getLogger(__name__)
class FloatingNetworkStackFixture(heat.HeatStackFixture):
template = _hot.heat_template_file('neutron/floating_network.yaml')
@property
def external_name(self):
return tobiko.tobiko_config().neutron.floating_network
_external_network = None
@property
def external_network(self):
network = self._external_network
if network is None:
self._external_network = network = find_external_network(
name=self.external_name) or {}
return network
@property
def external_id(self):
network = self.external_network
return network and network['id'] or None
@property
def has_external_id(self):
return bool(self.external_id)
@property
def network_details(self):
return neutron.get_network(self.network_id)
@neutron.skip_if_missing_networking_extensions('port-security')
class NetworkStackFixture(heat.HeatStackFixture):
"""Heat stack for creating internal network with a router to external"""
@ -68,10 +105,18 @@ class NetworkStackFixture(heat.HeatStackFixture):
"""Extra network creation parameters"""
return {}
floating_network_stack = tobiko.required_setup_fixture(
FloatingNetworkStackFixture)
@property
def floating_network(self):
"""Network ID where the Neutron floating IPs are created"""
return self.floating_network_stack.network_id
@property
def gateway_network(self):
"""Floating IP network where the Neutron floating IPs are created"""
return CONF.tobiko.neutron.floating_network
"""Network ID where gateway routes packages to"""
return self.floating_network
ha = False
@ -200,3 +245,48 @@ class SecurityGroupsFixture(heat.HeatStackFixture):
"""
#: Heat template file
template = _hot.heat_template_file('neutron/security_groups.yaml')
def find_external_network(name=None):
network = None
if name:
try:
network = neutron.get_network(name)
except neutron.NoSuchNetwork:
LOG.debug('No such network with ID %r', name)
if not network:
params = {'router:external': True, "status": "ACTIVE"}
if name:
params['name'] = name
try:
network = neutron.find_network(**params)
except tobiko.ObjectNotFound:
LOG.exception('No such network (%s):',
json.dumps(params, sort_keys=True))
if name:
message = ('No such external network with name or ID '
'{!r}').format(name)
raise ValueError(message)
if network:
LOG.debug('Found external network %r:\n%s',
network['name'], json.dumps(network, indent=4,
sort_keys=True))
return network
def get_floating_network_id():
return tobiko.setup_fixture(FloatingNetworkStackFixture).network_id
def get_floating_network():
return tobiko.setup_fixture(FloatingNetworkStackFixture).network_details
def has_floating_network():
return tobiko.setup_fixture(FloatingNetworkStackFixture).has_network
skip_if_missing_floating_network = tobiko.skip_unless(
'Floating network not found', has_floating_network)

View File

@ -129,12 +129,13 @@ class ServerStackFixture(heat.HeatStackFixture):
def network(self):
return self.network_stack.network_id
#: Floating IP network where the Neutron floating IP is created
floating_network = CONF.tobiko.neutron.floating_network
#: Floating IP network where the Neutron floating IP are created
@property
def floating_network(self):
return self.network_stack.floating_network
@property
def has_floating_ip(self):
"""Whenever to allocate floating IP for the server"""
return bool(self.floating_network)
@property

View File

@ -0,0 +1,40 @@
heat_template_version: newton
description: |
Creates an network with a subnet and a gateway router to an external network
if given
parameters:
external_id:
description: Default value to be assigned to network ports
type: string
default: '<no-external-id>'
has_external_id:
description: Extra network creation parameters
type: boolean
default: false
conditions:
has_network:
get_param: has_external_id
resources:
network:
type: OS::Neutron::Net
external_id: {get_param: external_id}
condition: has_network
outputs:
network_id:
description: Network ID
value: {get_resource: network}
has_network:
description: Whenever has a floating network
value: {get_param: has_external_id}

View File

@ -75,9 +75,7 @@ parameters:
gateway_network:
description: Optional gateway network to route packages to
type: string
default:
constraints:
- custom_constraint: neutron.network
default: '<no-gateway-network>'
gateway_value_specs:
description: Extra gateway router creation parameters

View File

@ -96,3 +96,17 @@ class L3HaNetworkTestCase(NetworkTestCase):
#: Stack of resources with a network with a gateway router
stack = tobiko.required_setup_fixture(stacks.L3haNetworkStackFixture)
class FloatingNetworkStackTest(testtools.TestCase):
@stacks.skip_if_missing_floating_network
def test_get_floating_network(self):
network = stacks.get_floating_network()
self.assertTrue(network['id'])
self.assertIs(True, network['router:external'])
self.assertEqual('ACTIVE', network['status'])
@stacks.skip_if_missing_floating_network
def test_has_floating_network(self):
self.assertIs(True, stacks.has_floating_network())