Use Ubuntu server with a working trunk VLAN subport
- It adds default vlan_id neutron config option - Add a VLAN device to customized Ubuntu image configured to use DHCP - Make Ubuntu server to use a working trunk VLAN subport connected to a new special network - It pings such VLAN server port from a special CirrOS server connected to the new special network - It fixes existing trunk test by providing a proven working vlan connection. Change-Id: I07053dd264f26e7b3959f4ab1c7a6e054a702e77
This commit is contained in:
parent
094d3c0826
commit
4a275f1625
@ -65,15 +65,9 @@ OPTIONS = [
|
|||||||
cfg.IntOpt('dscp_mark',
|
cfg.IntOpt('dscp_mark',
|
||||||
default=40,
|
default=40,
|
||||||
help="The DSCP marking value for the QoS Policy Rule"),
|
help="The DSCP marking value for the QoS Policy Rule"),
|
||||||
cfg.StrOpt('trunk_subport_segmentation_type',
|
cfg.IntOpt('vlan_id',
|
||||||
default='vlan',
|
|
||||||
help="Trunk subport segmentation type"),
|
|
||||||
cfg.IntOpt('trunk_subport_segmentation_id',
|
|
||||||
default=101,
|
default=101,
|
||||||
help="Trunk subport segmentation ID"),
|
help="VLAN trunk subport segmentation ID"),
|
||||||
cfg.StrOpt('trunk_subport_subnet_cidr',
|
|
||||||
default='192.168.101.0/24',
|
|
||||||
help="The CIDR block for trunk subport subnet")
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,12 +25,13 @@ from tobiko.openstack.stacks import _nova
|
|||||||
from tobiko.openstack.stacks import _octavia
|
from tobiko.openstack.stacks import _octavia
|
||||||
from tobiko.openstack.stacks import _qos
|
from tobiko.openstack.stacks import _qos
|
||||||
from tobiko.openstack.stacks import _ubuntu
|
from tobiko.openstack.stacks import _ubuntu
|
||||||
|
from tobiko.openstack.stacks import _vlan
|
||||||
|
|
||||||
|
|
||||||
CentosFlavorStackFixture = _centos.CentosFlavorStackFixture
|
CentosFlavorStackFixture = _centos.CentosFlavorStackFixture
|
||||||
CentosImageFixture = _centos.CentosImageFixture
|
CentosImageFixture = _centos.CentosImageFixture
|
||||||
CentosServerStackFixture = _centos.CentosServerStackFixture
|
CentosServerStackFixture = _centos.CentosServerStackFixture
|
||||||
Centos7ServerStackFixture = _centos.Centos7ServerStackFixture
|
Centos7ServerStackFixture = _centos.Centos7ServerStackFixture
|
||||||
CentosTrunkServerStackFixture = _centos.CentosTrunkServerStackFixture
|
|
||||||
|
|
||||||
CirrosFlavorStackFixture = _cirros.CirrosFlavorStackFixture
|
CirrosFlavorStackFixture = _cirros.CirrosFlavorStackFixture
|
||||||
CirrosImageFixture = _cirros.CirrosImageFixture
|
CirrosImageFixture = _cirros.CirrosImageFixture
|
||||||
@ -52,7 +53,6 @@ FedoraServerStackFixture = _fedora.FedoraServerStackFixture
|
|||||||
RedHatFlavorStackFixture = _redhat.RedHatFlavorStackFixture
|
RedHatFlavorStackFixture = _redhat.RedHatFlavorStackFixture
|
||||||
RhelImageFixture = _redhat.RhelImageFixture
|
RhelImageFixture = _redhat.RhelImageFixture
|
||||||
RedHatServerStackFixture = _redhat.RedHatServerStackFixture
|
RedHatServerStackFixture = _redhat.RedHatServerStackFixture
|
||||||
RedHatTrunkServerStackFixture = _redhat.RedHatTrunkServerStackFixture
|
|
||||||
|
|
||||||
L3haNetworkStackFixture = _l3ha.L3haNetworkStackFixture
|
L3haNetworkStackFixture = _l3ha.L3haNetworkStackFixture
|
||||||
L3haServerStackFixture = _l3ha.L3haServerStackFixture
|
L3haServerStackFixture = _l3ha.L3haServerStackFixture
|
||||||
@ -80,6 +80,16 @@ ServerGroupStackFixture = _nova.ServerGroupStackFixture
|
|||||||
AffinityServerGroupStackFixture = _nova.AffinityServerGroupStackFixture
|
AffinityServerGroupStackFixture = _nova.AffinityServerGroupStackFixture
|
||||||
AntiAffinityServerGroupStackFixture = _nova.AntiAffinityServerGroupStackFixture
|
AntiAffinityServerGroupStackFixture = _nova.AntiAffinityServerGroupStackFixture
|
||||||
|
|
||||||
|
OctaviaLoadbalancerStackFixture = _octavia.OctaviaLoadbalancerStackFixture
|
||||||
|
OctaviaListenerStackFixture = _octavia.OctaviaListenerStackFixture
|
||||||
|
OctaviaPoolStackFixture = _octavia.OctaviaPoolStackFixture
|
||||||
|
OctaviaMemberServerStackFixture = _octavia.OctaviaMemberServerStackFixture
|
||||||
|
OctaviaServerStackFixture = _octavia.OctaviaServerStackFixture
|
||||||
|
OctaviaClientServerStackFixture = _octavia.OctaviaClientServerStackFixture
|
||||||
|
OctaviaOtherServerStackFixture = _octavia.OctaviaOtherServerStackFixture
|
||||||
|
OctaviaOtherMemberServerStackFixture = (
|
||||||
|
_octavia.OctaviaOtherMemberServerStackFixture)
|
||||||
|
|
||||||
QosNetworkStackFixture = _qos.QosNetworkStackFixture
|
QosNetworkStackFixture = _qos.QosNetworkStackFixture
|
||||||
QosPolicyStackFixture = _qos.QosPolicyStackFixture
|
QosPolicyStackFixture = _qos.QosPolicyStackFixture
|
||||||
QosServerStackFixture = _qos.QosServerStackFixture
|
QosServerStackFixture = _qos.QosServerStackFixture
|
||||||
@ -91,12 +101,5 @@ UbuntuServerStackFixture = _ubuntu.UbuntuServerStackFixture
|
|||||||
UbuntuMinimalServerStackFixture = _ubuntu.UbuntuMinimalServerStackFixture
|
UbuntuMinimalServerStackFixture = _ubuntu.UbuntuMinimalServerStackFixture
|
||||||
UbuntuExternalServerStackFixture = _ubuntu.UbuntuExternalServerStackFixture
|
UbuntuExternalServerStackFixture = _ubuntu.UbuntuExternalServerStackFixture
|
||||||
|
|
||||||
OctaviaLoadbalancerStackFixture = _octavia.OctaviaLoadbalancerStackFixture
|
VlanNetworkStackFixture = _vlan.VlanNetworkStackFixture
|
||||||
OctaviaListenerStackFixture = _octavia.OctaviaListenerStackFixture
|
VlanProxyServerStackFixture = _vlan.VlanProxyServerStackFixture
|
||||||
OctaviaPoolStackFixture = _octavia.OctaviaPoolStackFixture
|
|
||||||
OctaviaMemberServerStackFixture = _octavia.OctaviaMemberServerStackFixture
|
|
||||||
OctaviaServerStackFixture = _octavia.OctaviaServerStackFixture
|
|
||||||
OctaviaClientServerStackFixture = _octavia.OctaviaClientServerStackFixture
|
|
||||||
OctaviaOtherServerStackFixture = _octavia.OctaviaOtherServerStackFixture
|
|
||||||
OctaviaOtherMemberServerStackFixture = (
|
|
||||||
_octavia.OctaviaOtherMemberServerStackFixture)
|
|
||||||
|
@ -71,27 +71,3 @@ class Centos7ServerStackFixture(CentosServerStackFixture):
|
|||||||
|
|
||||||
#: Glance image used to create a Nova server instance
|
#: Glance image used to create a Nova server instance
|
||||||
image_fixture = tobiko.required_setup_fixture(Centos7ImageFixture)
|
image_fixture = tobiko.required_setup_fixture(Centos7ImageFixture)
|
||||||
|
|
||||||
|
|
||||||
class CentosTrunkServerStackFixture(
|
|
||||||
CentosServerStackFixture, _nova.TrunkServerStackFixture):
|
|
||||||
|
|
||||||
interface = 'eth0'
|
|
||||||
|
|
||||||
@property
|
|
||||||
def user_data(self):
|
|
||||||
return ("#cloud-config\n"
|
|
||||||
"write_files:\n"
|
|
||||||
"- path: {path}/ifcfg-{interface}.{index}\n"
|
|
||||||
" owner: \"root\"\n"
|
|
||||||
" permissions: \"777\"\n"
|
|
||||||
" content: |\n"
|
|
||||||
" DEVICE=\"{interface}.{index}\"\n"
|
|
||||||
" BOOTPROTO=\"none\"\n"
|
|
||||||
" ONBOOT=\"yes\"\n"
|
|
||||||
" VLAN=\"yes\"\n"
|
|
||||||
" PERSISTENT_DHCLIENT=\"no\"\n"
|
|
||||||
"runcmd:\n"
|
|
||||||
"- [ sh, -c , \"systemctl restart NetworkManager\" ]".format(
|
|
||||||
path='/etc/sysconfig/network-scripts/',
|
|
||||||
interface=self.interface, index=self.trunk_subport_vlan))
|
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
import tobiko
|
|
||||||
from tobiko import config
|
from tobiko import config
|
||||||
from tobiko.openstack import glance
|
from tobiko.openstack import glance
|
||||||
from tobiko.openstack.stacks import _nova
|
from tobiko.openstack.stacks import _nova
|
||||||
|
@ -218,6 +218,8 @@ class ServerStackFixture(heat.HeatStackFixture, abc.ABC):
|
|||||||
def fixed_ipv6(self):
|
def fixed_ipv6(self):
|
||||||
return self.find_fixed_ip(ip_version=6)
|
return self.find_fixed_ip(ip_version=6)
|
||||||
|
|
||||||
|
has_vlan = False
|
||||||
|
|
||||||
#: Schedule on different host that this Nova server instance ID
|
#: Schedule on different host that this Nova server instance ID
|
||||||
different_host = None
|
different_host = None
|
||||||
|
|
||||||
@ -355,6 +357,12 @@ class ServerStackFixture(heat.HeatStackFixture, abc.ABC):
|
|||||||
requirements['cores'] += (self.flavor_stack.vcpus or 1)
|
requirements['cores'] += (self.flavor_stack.vcpus or 1)
|
||||||
return requirements
|
return requirements
|
||||||
|
|
||||||
|
@property
|
||||||
|
def neutron_required_quota_set(self) -> typing.Dict[str, int]:
|
||||||
|
requirements = super().neutron_required_quota_set
|
||||||
|
requirements['port'] += 1
|
||||||
|
return requirements
|
||||||
|
|
||||||
def assert_is_reachable(self):
|
def assert_is_reachable(self):
|
||||||
ping.assert_reachable_hosts([self.ip_address])
|
ping.assert_reachable_hosts([self.ip_address])
|
||||||
|
|
||||||
@ -535,11 +543,3 @@ class AntiAffinityServerGroupStackFixture(tobiko.SharedFixture):
|
|||||||
@property
|
@property
|
||||||
def scheduler_group(self):
|
def scheduler_group(self):
|
||||||
return self.server_group_stack.anti_affinity_server_group_id
|
return self.server_group_stack.anti_affinity_server_group_id
|
||||||
|
|
||||||
|
|
||||||
@neutron.skip_if_missing_networking_extensions('trunk')
|
|
||||||
class TrunkServerStackFixture(CloudInitServerStackFixture):
|
|
||||||
has_trunk = True
|
|
||||||
segmentation_id = CONF.tobiko.neutron.trunk_subport_segmentation_id
|
|
||||||
segmentation_type = CONF.tobiko.neutron.trunk_subport_segmentation_type
|
|
||||||
trunk_subport_cidr = CONF.tobiko.neutron.trunk_subport_subnet_cidr
|
|
||||||
|
@ -86,8 +86,3 @@ class RedHatServerStackFixture(_centos.CentosServerStackFixture):
|
|||||||
|
|
||||||
#: Flavor used to create a Nova server instance
|
#: Flavor used to create a Nova server instance
|
||||||
flavor_stack = tobiko.required_setup_fixture(RedHatFlavorStackFixture)
|
flavor_stack = tobiko.required_setup_fixture(RedHatFlavorStackFixture)
|
||||||
|
|
||||||
|
|
||||||
class RedHatTrunkServerStackFixture(
|
|
||||||
RedHatServerStackFixture, _centos.CentosTrunkServerStackFixture):
|
|
||||||
pass
|
|
||||||
|
@ -15,10 +15,13 @@ from __future__ import absolute_import
|
|||||||
|
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
import tobiko
|
import tobiko
|
||||||
from tobiko import config
|
from tobiko import config
|
||||||
from tobiko.openstack import glance
|
from tobiko.openstack import glance
|
||||||
from tobiko.openstack.stacks import _nova
|
from tobiko.openstack.stacks import _nova
|
||||||
|
from tobiko.openstack.stacks import _vlan
|
||||||
|
|
||||||
|
|
||||||
CONF = config.CONF
|
CONF = config.CONF
|
||||||
@ -71,6 +74,7 @@ class UbuntuImageFixture(UbuntuMinimalImageFixture,
|
|||||||
- ping
|
- ping
|
||||||
- ncat
|
- ncat
|
||||||
- nginx
|
- nginx
|
||||||
|
- vlan
|
||||||
|
|
||||||
The image will also have below running services:
|
The image will also have below running services:
|
||||||
- nginx HTTP server listening on TCP port 80
|
- nginx HTTP server listening on TCP port 80
|
||||||
@ -86,8 +90,10 @@ class UbuntuImageFixture(UbuntuMinimalImageFixture,
|
|||||||
def install_packages(self) -> typing.List[str]:
|
def install_packages(self) -> typing.List[str]:
|
||||||
return super().install_packages + ['iperf3',
|
return super().install_packages + ['iperf3',
|
||||||
'iputils-ping',
|
'iputils-ping',
|
||||||
|
'nano',
|
||||||
'ncat',
|
'ncat',
|
||||||
'nginx']
|
'nginx',
|
||||||
|
'vlan']
|
||||||
|
|
||||||
# port of running HTTP server
|
# port of running HTTP server
|
||||||
http_port = 80
|
http_port = 80
|
||||||
@ -103,8 +109,44 @@ class UbuntuImageFixture(UbuntuMinimalImageFixture,
|
|||||||
'> /etc/systemd/system/iperf3-server@.service')
|
'> /etc/systemd/system/iperf3-server@.service')
|
||||||
run_commands.append(
|
run_commands.append(
|
||||||
f"systemctl enable iperf3-server@{self.iperf3_port}")
|
f"systemctl enable iperf3-server@{self.iperf3_port}")
|
||||||
|
run_commands.append('echo "8021q" >> /etc/modules')
|
||||||
return run_commands
|
return run_commands
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ethernet_device(self) -> str:
|
||||||
|
return 'ens3'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def vlan_id(self) -> int:
|
||||||
|
return tobiko.tobiko_config().neutron.vlan_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def vlan_device(self) -> str:
|
||||||
|
return f'vlan{self.vlan_id}'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def vlan_config(self) -> typing.Dict[str, typing.Any]:
|
||||||
|
return {
|
||||||
|
'network': {
|
||||||
|
'version': 2,
|
||||||
|
'vlans': {
|
||||||
|
self.vlan_device: {
|
||||||
|
'link': self.ethernet_device,
|
||||||
|
'dhcp4': True,
|
||||||
|
'dhcp6': True,
|
||||||
|
'id': self.vlan_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def write_files(self) -> typing.Dict[str, str]:
|
||||||
|
write_files = super().write_files
|
||||||
|
write_files['/etc/netplan/75-tobiko-vlan.yaml'] = yaml.dump(
|
||||||
|
self.vlan_config)
|
||||||
|
return write_files
|
||||||
|
|
||||||
|
|
||||||
class UbuntuFlavorStackFixture(_nova.FlavorStackFixture):
|
class UbuntuFlavorStackFixture(_nova.FlavorStackFixture):
|
||||||
ram = 128
|
ram = 128
|
||||||
@ -120,7 +162,8 @@ class UbuntuMinimalServerStackFixture(_nova.CloudInitServerStackFixture):
|
|||||||
flavor_stack = tobiko.required_setup_fixture(UbuntuFlavorStackFixture)
|
flavor_stack = tobiko.required_setup_fixture(UbuntuFlavorStackFixture)
|
||||||
|
|
||||||
|
|
||||||
class UbuntuServerStackFixture(UbuntuMinimalServerStackFixture):
|
class UbuntuServerStackFixture(UbuntuMinimalServerStackFixture,
|
||||||
|
_vlan.VlanServerStackFixture):
|
||||||
"""Ubuntu server running an HTTP server
|
"""Ubuntu server running an HTTP server
|
||||||
|
|
||||||
The server has additional commands compared to the minimal one:
|
The server has additional commands compared to the minimal one:
|
||||||
@ -140,6 +183,14 @@ class UbuntuServerStackFixture(UbuntuMinimalServerStackFixture):
|
|||||||
def iperf3_port(self) -> int:
|
def iperf3_port(self) -> int:
|
||||||
return self.image_fixture.iperf3_port
|
return self.image_fixture.iperf3_port
|
||||||
|
|
||||||
|
@property
|
||||||
|
def vlan_id(self) -> int:
|
||||||
|
return self.image_fixture.vlan_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def vlan_device(self) -> str:
|
||||||
|
return self.image_fixture.vlan_device
|
||||||
|
|
||||||
|
|
||||||
class UbuntuExternalServerStackFixture(UbuntuServerStackFixture,
|
class UbuntuExternalServerStackFixture(UbuntuServerStackFixture,
|
||||||
_nova.ExternalServerStackFixture):
|
_nova.ExternalServerStackFixture):
|
||||||
|
108
tobiko/openstack/stacks/_vlan.py
Normal file
108
tobiko/openstack/stacks/_vlan.py
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
# Copyright (c) 2021 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 abc
|
||||||
|
import typing
|
||||||
|
|
||||||
|
import netaddr
|
||||||
|
|
||||||
|
import tobiko
|
||||||
|
from tobiko import config
|
||||||
|
from tobiko.shell import ping
|
||||||
|
from tobiko.shell import ssh
|
||||||
|
from tobiko.openstack import neutron
|
||||||
|
from tobiko.openstack.stacks import _cirros
|
||||||
|
from tobiko.openstack.stacks import _neutron
|
||||||
|
from tobiko.openstack.stacks import _nova
|
||||||
|
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class VlanNetworkStackFixture(_neutron.NetworkStackFixture):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class VlanProxyServerStackFixture(_cirros.CirrosServerStackFixture):
|
||||||
|
network_stack = tobiko.required_fixture(VlanNetworkStackFixture)
|
||||||
|
|
||||||
|
|
||||||
|
@neutron.skip_if_missing_networking_extensions('trunk')
|
||||||
|
class VlanServerStackFixture(_nova.ServerStackFixture, abc.ABC):
|
||||||
|
|
||||||
|
has_vlan = True
|
||||||
|
|
||||||
|
#: stack with the newtwork where the trunk support is attached
|
||||||
|
vlan_network_stack = tobiko.required_fixture(VlanNetworkStackFixture)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def vlan_id(self) -> int:
|
||||||
|
return CONF.tobiko.neutron.vlan_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def vlan_network(self) -> str:
|
||||||
|
return self.vlan_network_stack.network_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def vlan_fixed_ipv4(self):
|
||||||
|
return self.find_vlan_fixed_ip(ip_version=4)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def vlan_fixed_ipv6(self):
|
||||||
|
return self.find_vlan_fixed_ip(ip_version=6)
|
||||||
|
|
||||||
|
def find_vlan_fixed_ip(self,
|
||||||
|
ip_version: int = None,
|
||||||
|
unique=False) -> netaddr.IPAddress:
|
||||||
|
vlan_ips = self.list_vlan_fixed_ips(ip_version=ip_version)
|
||||||
|
if unique:
|
||||||
|
return vlan_ips.unique
|
||||||
|
else:
|
||||||
|
return vlan_ips.first
|
||||||
|
|
||||||
|
def list_vlan_fixed_ips(self,
|
||||||
|
ip_version: int = None) \
|
||||||
|
-> tobiko.Selection[netaddr.IPAddress]:
|
||||||
|
fixed_ips: tobiko.Selection[netaddr.IPAddress] = tobiko.Selection(
|
||||||
|
netaddr.IPAddress(fixed_ip['ip_address'])
|
||||||
|
for fixed_ip in self.vlan_fixed_ips)
|
||||||
|
if ip_version is not None:
|
||||||
|
fixed_ips = fixed_ips.with_attributes(version=ip_version)
|
||||||
|
return fixed_ips
|
||||||
|
|
||||||
|
@property
|
||||||
|
def vlan_ssh_proxy_client(self) -> ssh.SSHClientType:
|
||||||
|
return tobiko.setup_fixture(VlanProxyServerStackFixture).ssh_client
|
||||||
|
|
||||||
|
def assert_vlan_is_reachable(self,
|
||||||
|
ip_version: int = None):
|
||||||
|
fixed_ips = self.list_vlan_fixed_ips(ip_version=ip_version)
|
||||||
|
ping.assert_reachable_hosts(fixed_ips,
|
||||||
|
ssh_client=self.vlan_ssh_proxy_client)
|
||||||
|
|
||||||
|
def assert_vlan_is_unreachable(self,
|
||||||
|
ip_version: int = None):
|
||||||
|
fixed_ips = self.list_vlan_fixed_ips(ip_version=ip_version)
|
||||||
|
ping.assert_unreachable_hosts(fixed_ips,
|
||||||
|
ssh_client=self.vlan_ssh_proxy_client)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def neutron_required_quota_set(self) -> typing.Dict[str, int]:
|
||||||
|
requirements = super().neutron_required_quota_set
|
||||||
|
requirements['port'] += 1
|
||||||
|
requirements['trunk'] += 1
|
||||||
|
return requirements
|
@ -72,23 +72,19 @@ parameters:
|
|||||||
default: ''
|
default: ''
|
||||||
description: Optional user_data to be passed to the server
|
description: Optional user_data to be passed to the server
|
||||||
|
|
||||||
has_trunk:
|
has_vlan:
|
||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
|
|
||||||
trunk_subport_cidr:
|
vlan_network:
|
||||||
type: string
|
type: string
|
||||||
|
description: Network ID where vlan trunk support is attached
|
||||||
default: ''
|
default: ''
|
||||||
|
|
||||||
segmentation_type:
|
vlan_id:
|
||||||
type: string
|
|
||||||
description: Segmentation type for trunk subport
|
|
||||||
default: ''
|
|
||||||
|
|
||||||
segmentation_id:
|
|
||||||
type: number
|
type: number
|
||||||
description: Segmentation ID for trunk subport
|
description: Segmentation ID for vlan trunk subport
|
||||||
default: 0
|
default: 101
|
||||||
|
|
||||||
conditions:
|
conditions:
|
||||||
|
|
||||||
@ -98,8 +94,8 @@ conditions:
|
|||||||
use_extra_dhcp_opts:
|
use_extra_dhcp_opts:
|
||||||
get_param: use_extra_dhcp_opts
|
get_param: use_extra_dhcp_opts
|
||||||
|
|
||||||
has_trunk:
|
has_vlan:
|
||||||
get_param: has_trunk
|
get_param: has_vlan
|
||||||
|
|
||||||
resources:
|
resources:
|
||||||
|
|
||||||
@ -154,34 +150,26 @@ resources:
|
|||||||
floating_network: {get_param: floating_network}
|
floating_network: {get_param: floating_network}
|
||||||
port_id: {get_resource: port}
|
port_id: {get_resource: port}
|
||||||
|
|
||||||
trunk_subport_network:
|
vlan_port:
|
||||||
type: OS::Neutron::Net
|
|
||||||
condition: has_trunk
|
|
||||||
|
|
||||||
trunk_subport_subnet:
|
|
||||||
type: OS::Neutron::Subnet
|
|
||||||
condition: has_trunk
|
|
||||||
properties:
|
|
||||||
network: {get_resource: trunk_subport_network}
|
|
||||||
cidr: {get_param: trunk_subport_cidr}
|
|
||||||
|
|
||||||
trunk_subport:
|
|
||||||
type: OS::Neutron::Port
|
type: OS::Neutron::Port
|
||||||
condition: has_trunk
|
description: Vlan trunk subport
|
||||||
|
condition: has_vlan
|
||||||
properties:
|
properties:
|
||||||
network: {get_resource: trunk_subport_network}
|
network: {get_param: vlan_network}
|
||||||
mac_address: {get_attr: [port, mac_address]}
|
mac_address: {get_attr: [port, mac_address]}
|
||||||
|
port_security_enabled: {get_param: port_security_enabled}
|
||||||
|
security_groups: {get_param: security_groups}
|
||||||
|
|
||||||
trunk:
|
trunk:
|
||||||
type: OS::Neutron::Trunk
|
type: OS::Neutron::Trunk
|
||||||
description: Trunk port connected to the server
|
description: Trunk connected to the server port
|
||||||
condition: has_trunk
|
condition: has_vlan
|
||||||
properties:
|
properties:
|
||||||
port: {get_resource: port}
|
port: {get_resource: port}
|
||||||
sub_ports:
|
sub_ports:
|
||||||
- {port: {get_resource: trunk_subport},
|
- port: {get_resource: vlan_port}
|
||||||
segmentation_type: {get_param: segmentation_type},
|
segmentation_type: vlan
|
||||||
segmentation_id: {get_param: segmentation_id}}
|
segmentation_id: {get_param: vlan_id}
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
|
|
||||||
@ -208,3 +196,12 @@ outputs:
|
|||||||
|
|
||||||
port_id:
|
port_id:
|
||||||
value: {get_resource: port}
|
value: {get_resource: port}
|
||||||
|
|
||||||
|
vlan_port_id:
|
||||||
|
value: {get_resource: vlan_port}
|
||||||
|
condition: has_vlan
|
||||||
|
|
||||||
|
vlan_fixed_ips:
|
||||||
|
description: fixed IP addresses of server vlan port
|
||||||
|
value: {get_attr: [vlan_port, fixed_ips]}
|
||||||
|
condition: has_vlan
|
||||||
|
@ -76,6 +76,22 @@ def list_ip_addresses(ip_version: int = None,
|
|||||||
return ips
|
return ips
|
||||||
|
|
||||||
|
|
||||||
|
def find_ip_address(ip_version: int = None,
|
||||||
|
device: str = None,
|
||||||
|
scope: str = None,
|
||||||
|
unique: bool = False,
|
||||||
|
**execute_params) -> \
|
||||||
|
netaddr.IPAddress:
|
||||||
|
ips = list_ip_addresses(ip_version=ip_version,
|
||||||
|
device=device,
|
||||||
|
scope=scope,
|
||||||
|
**execute_params)
|
||||||
|
if unique:
|
||||||
|
return ips.unique
|
||||||
|
else:
|
||||||
|
return ips.first
|
||||||
|
|
||||||
|
|
||||||
def parse_ip_address(text: str) -> typing.Tuple[netaddr.IPAddress, int]:
|
def parse_ip_address(text: str) -> typing.Tuple[netaddr.IPAddress, int]:
|
||||||
if '/' in text:
|
if '/' in text:
|
||||||
# Remove netmask prefix length
|
# Remove netmask prefix length
|
||||||
|
68
tobiko/tests/functional/openstack/stacks/test_vlan.py
Normal file
68
tobiko/tests/functional/openstack/stacks/test_vlan.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
# 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 testtools
|
||||||
|
|
||||||
|
import tobiko
|
||||||
|
from tobiko.openstack import stacks
|
||||||
|
from tobiko.shell import ip
|
||||||
|
from tobiko.tests.functional.openstack.stacks import test_cirros
|
||||||
|
|
||||||
|
|
||||||
|
class VlanProxyServerStackTest(test_cirros.CirrosServerStackTest):
|
||||||
|
|
||||||
|
#: Stack of resources with a server attached to a floating IP
|
||||||
|
stack = tobiko.required_fixture(stacks.VlanProxyServerStackFixture)
|
||||||
|
|
||||||
|
|
||||||
|
class UbuntuVlanServerTest(testtools.TestCase):
|
||||||
|
|
||||||
|
#: Stack of resources with a server attached to a floating IP
|
||||||
|
stack = tobiko.required_fixture(stacks.UbuntuServerStackFixture)
|
||||||
|
|
||||||
|
def test_vlan_ipv4_fixed_ip(self):
|
||||||
|
self._test_vlan_fixed_ip(ip_version=4)
|
||||||
|
|
||||||
|
def test_vlan_ipv6_fixed_ip(self):
|
||||||
|
self._test_vlan_fixed_ip(ip_version=6)
|
||||||
|
|
||||||
|
def _test_vlan_fixed_ip(self, ip_version: int):
|
||||||
|
expected_ip = self.get_vlan_fixed_ip(ip_version=ip_version)
|
||||||
|
for attempt in tobiko.retry(timeout=600.,
|
||||||
|
interval=10.):
|
||||||
|
try:
|
||||||
|
actual_ip = ip.find_ip_address(
|
||||||
|
device=self.stack.vlan_device,
|
||||||
|
ip_version=ip_version,
|
||||||
|
ssh_client=self.stack.ssh_client,
|
||||||
|
scope='global',
|
||||||
|
unique=True)
|
||||||
|
except tobiko.ObjectNotFound:
|
||||||
|
attempt.check_limits()
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise RuntimeError('Broken retry loop')
|
||||||
|
self.assertEqual(expected_ip, actual_ip)
|
||||||
|
self.stack.assert_vlan_is_reachable(ip_version=ip_version)
|
||||||
|
|
||||||
|
def get_vlan_fixed_ip(self, ip_version: int):
|
||||||
|
try:
|
||||||
|
return self.stack.find_vlan_fixed_ip(ip_version=ip_version)
|
||||||
|
except tobiko.ObjectNotFound:
|
||||||
|
self.skipTest(f"Server {self.stack.server_id} has any "
|
||||||
|
f"IPv{ip_version} address on VLAN device.")
|
@ -20,7 +20,6 @@ import testtools
|
|||||||
|
|
||||||
import tobiko
|
import tobiko
|
||||||
from tobiko import config
|
from tobiko import config
|
||||||
from tobiko.openstack import nova
|
|
||||||
from tobiko.openstack import stacks
|
from tobiko.openstack import stacks
|
||||||
|
|
||||||
|
|
||||||
@ -28,31 +27,33 @@ CONF = config.CONF
|
|||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class CentosRebootTrunkServerStackFixture(
|
class RebootTrunkServerStackFixture(stacks.UbuntuServerStackFixture):
|
||||||
stacks.CentosTrunkServerStackFixture):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class CentosTrunkTest(testtools.TestCase):
|
class TrunkTest(testtools.TestCase):
|
||||||
"""Tests trunk functionality"""
|
"""Tests trunk functionality"""
|
||||||
|
|
||||||
stack = tobiko.required_fixture(CentosRebootTrunkServerStackFixture)
|
stack = tobiko.required_fixture(RebootTrunkServerStackFixture)
|
||||||
|
|
||||||
|
vlan_proxy_stack = tobiko.required_fixture(
|
||||||
|
stacks.VlanProxyServerStackFixture)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def vlan_proxy_ssh_client(self):
|
||||||
|
return self.vlan_proxy_stack.ssh_client
|
||||||
|
|
||||||
|
def test_activate_server(self):
|
||||||
|
self.stack.ensure_server_status('ACTIVE')
|
||||||
|
self.stack.assert_is_reachable()
|
||||||
|
self.stack.assert_vlan_is_reachable(ip_version=4)
|
||||||
|
|
||||||
|
def test_shutoff_server(self):
|
||||||
|
self.stack.ensure_server_status('SHUTOFF')
|
||||||
|
self.stack.assert_is_unreachable()
|
||||||
|
self.stack.assert_vlan_is_unreachable(ip_version=4)
|
||||||
|
|
||||||
@pytest.mark.ovn_migration
|
@pytest.mark.ovn_migration
|
||||||
def test_after_server_reboot(self):
|
def test_shutoff_then_activate_server(self):
|
||||||
self.shutoff_server()
|
self.test_shutoff_server()
|
||||||
self.activate_server()
|
self.test_activate_server()
|
||||||
|
|
||||||
def test_after_server_shutoff(self):
|
|
||||||
self.activate_server()
|
|
||||||
self.shutoff_server()
|
|
||||||
|
|
||||||
def activate_server(self) -> nova.NovaServer:
|
|
||||||
server = self.stack.ensure_server_status('ACTIVE')
|
|
||||||
self.stack.assert_is_reachable()
|
|
||||||
return server
|
|
||||||
|
|
||||||
def shutoff_server(self) -> nova.NovaServer:
|
|
||||||
server = self.stack.ensure_server_status('SHUTOFF')
|
|
||||||
self.stack.assert_is_unreachable()
|
|
||||||
return server
|
|
||||||
|
Loading…
Reference in New Issue
Block a user