Merge pull request #108 from openstack-charmers/ovn-charm
Teach `basic_overcloud_network` configure job about OVN
This commit is contained in:
@@ -101,8 +101,8 @@ class TestJujuUtils(ut_utils.BaseTestCase):
|
||||
|
||||
# Machine data
|
||||
self.assertEqual(
|
||||
juju_utils.get_machines_for_application(self.application),
|
||||
[self.machine])
|
||||
next(juju_utils.get_machines_for_application(self.application)),
|
||||
self.machine)
|
||||
self.get_application_status.assert_called_once()
|
||||
|
||||
# Subordinate application has no units
|
||||
@@ -115,9 +115,9 @@ class TestJujuUtils(ut_utils.BaseTestCase):
|
||||
self.get_application_status.side_effect = _get_application_status
|
||||
|
||||
self.assertEqual(
|
||||
juju_utils.get_machines_for_application(
|
||||
self.subordinate_application),
|
||||
[self.machine])
|
||||
next(juju_utils.get_machines_for_application(
|
||||
self.subordinate_application)),
|
||||
self.machine)
|
||||
|
||||
def test_get_unit_name_from_host_name(self):
|
||||
unit_mock1 = mock.MagicMock()
|
||||
@@ -151,8 +151,9 @@ class TestJujuUtils(ut_utils.BaseTestCase):
|
||||
self.get_machines_for_application.return_value = [self.machine]
|
||||
|
||||
self.assertEqual(
|
||||
juju_utils.get_machine_uuids_for_application(self.application),
|
||||
[self.machine_data.get("instance-id")])
|
||||
next(juju_utils.get_machine_uuids_for_application(
|
||||
self.application)),
|
||||
self.machine_data.get("instance-id"))
|
||||
self.get_machines_for_application.assert_called_once_with(
|
||||
self.application)
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
import copy
|
||||
import datetime
|
||||
import io
|
||||
import itertools
|
||||
import mock
|
||||
import tenacity
|
||||
|
||||
@@ -159,7 +160,7 @@ class TestOpenStackUtils(ut_utils.BaseTestCase):
|
||||
|
||||
# Already exists
|
||||
network = openstack_utils.create_external_network(
|
||||
self.neutronclient, self.project_id, False)
|
||||
self.neutronclient, self.project_id)
|
||||
self.assertEqual(network, self.network["network"])
|
||||
self.neutronclient.create_network.assert_not_called()
|
||||
|
||||
@@ -169,7 +170,7 @@ class TestOpenStackUtils(ut_utils.BaseTestCase):
|
||||
network_msg = copy.deepcopy(self.network)
|
||||
network_msg["network"].pop("id")
|
||||
network = openstack_utils.create_external_network(
|
||||
self.neutronclient, self.project_id, False)
|
||||
self.neutronclient, self.project_id)
|
||||
self.assertEqual(network, self.network["network"])
|
||||
self.neutronclient.create_network.assert_called_once_with(
|
||||
network_msg)
|
||||
@@ -814,12 +815,13 @@ class TestOpenStackUtils(ut_utils.BaseTestCase):
|
||||
)
|
||||
|
||||
# No machine returned
|
||||
self._get_machines.return_value = []
|
||||
self._get_machines.side_effect = StopIteration
|
||||
with self.assertRaises(exceptions.ApplicationNotFound):
|
||||
openstack_utils.get_current_os_release_pair()
|
||||
self._get_machines.side_effect = None
|
||||
|
||||
# No series returned
|
||||
self._get_machines.return_value = ['6']
|
||||
self._get_machines.return_value = itertools.repeat('6')
|
||||
self._get_machine_series.return_value = None
|
||||
with self.assertRaises(exceptions.SeriesNotFound):
|
||||
openstack_utils.get_current_os_release_pair()
|
||||
@@ -1165,3 +1167,45 @@ class TestOpenStackUtils(ut_utils.BaseTestCase):
|
||||
'OS_PROJECT_NAME': 'services'},
|
||||
scope='PROJECT',
|
||||
verify=None)
|
||||
|
||||
def test_get_gateway_uuids(self):
|
||||
self.patch_object(openstack_utils.juju_utils,
|
||||
'get_machine_uuids_for_application')
|
||||
self.get_machine_uuids_for_application.return_value = 'ret'
|
||||
self.assertEquals(openstack_utils.get_gateway_uuids(), 'ret')
|
||||
self.get_machine_uuids_for_application.assert_called_once_with(
|
||||
'neutron-gateway')
|
||||
|
||||
def test_get_ovs_uuids(self):
|
||||
self.patch_object(openstack_utils.juju_utils,
|
||||
'get_machine_uuids_for_application')
|
||||
self.get_machine_uuids_for_application.return_value = 'ret'
|
||||
self.assertEquals(openstack_utils.get_ovs_uuids(), 'ret')
|
||||
self.get_machine_uuids_for_application.assert_called_once_with(
|
||||
'neutron-openvswitch')
|
||||
|
||||
def test_get_ovn_uuids(self):
|
||||
self.patch_object(openstack_utils.juju_utils,
|
||||
'get_machine_uuids_for_application')
|
||||
self.get_machine_uuids_for_application.return_value = ['ret']
|
||||
self.assertEquals(list(openstack_utils.get_ovn_uuids()),
|
||||
['ret', 'ret'])
|
||||
self.get_machine_uuids_for_application.assert_has_calls([
|
||||
mock.call('ovn-chassis'),
|
||||
mock.call('ovn-dedicated-chassis'),
|
||||
])
|
||||
|
||||
def test_dvr_enabled(self):
|
||||
self.patch_object(openstack_utils, 'get_application_config_option')
|
||||
openstack_utils.dvr_enabled()
|
||||
self.get_application_config_option.assert_called_once_with(
|
||||
'neutron-api', 'enable-dvr')
|
||||
|
||||
def test_ovn_present(self):
|
||||
self.patch_object(openstack_utils.model, 'get_application')
|
||||
self.get_application.side_effect = [None, KeyError]
|
||||
self.assertTrue(openstack_utils.ovn_present())
|
||||
self.get_application.side_effect = [KeyError, None]
|
||||
self.assertTrue(openstack_utils.ovn_present())
|
||||
self.get_application.side_effect = [KeyError, KeyError]
|
||||
self.assertFalse(openstack_utils.ovn_present())
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
"""Setup for Neutron deployments."""
|
||||
|
||||
import functools
|
||||
|
||||
from zaza.openstack.configure import (
|
||||
network,
|
||||
)
|
||||
@@ -25,7 +27,6 @@ from zaza.openstack.utilities import (
|
||||
juju as juju_utils,
|
||||
openstack as openstack_utils,
|
||||
)
|
||||
import zaza.model as model
|
||||
|
||||
|
||||
# The overcloud network configuration settings are declared.
|
||||
@@ -57,12 +58,14 @@ DEFAULT_UNDERCLOUD_NETWORK_CONFIG = {
|
||||
}
|
||||
|
||||
|
||||
def basic_overcloud_network():
|
||||
def basic_overcloud_network(limit_gws=None):
|
||||
"""Run setup for neutron networking.
|
||||
|
||||
Configure the following:
|
||||
The overcloud network using subnet pools
|
||||
|
||||
:param limit_gws: Limit the number of gateways that get a port attached
|
||||
:type limit_gws: int
|
||||
"""
|
||||
cli_utils.setup_logging()
|
||||
|
||||
@@ -74,10 +77,6 @@ def basic_overcloud_network():
|
||||
network_config.update(DEFAULT_UNDERCLOUD_NETWORK_CONFIG)
|
||||
# Environment specific settings
|
||||
network_config.update(generic_utils.get_undercloud_env_vars())
|
||||
# Deployed model settings
|
||||
if (model.get_application_config('neutron-api')
|
||||
.get('enable-dvr').get('value')):
|
||||
network_config.update({"dvr_enabled": True})
|
||||
|
||||
# Get keystone session
|
||||
keystone_session = openstack_utils.get_overcloud_keystone_session()
|
||||
@@ -86,7 +85,20 @@ def basic_overcloud_network():
|
||||
if juju_utils.get_provider_type() == "openstack":
|
||||
undercloud_ks_sess = openstack_utils.get_undercloud_keystone_session()
|
||||
network.setup_gateway_ext_port(network_config,
|
||||
keystone_session=undercloud_ks_sess)
|
||||
keystone_session=undercloud_ks_sess,
|
||||
limit_gws=None)
|
||||
|
||||
# Confugre the overcloud network
|
||||
network.setup_sdn(network_config, keystone_session=keystone_session)
|
||||
|
||||
|
||||
# Configure function to get one gateway with external network
|
||||
overcloud_network_one_gw = functools.partial(
|
||||
basic_overcloud_network,
|
||||
limit_gws=1)
|
||||
|
||||
|
||||
# Configure function to get two gateways with external network
|
||||
overcloud_network_two_gws = functools.partial(
|
||||
basic_overcloud_network,
|
||||
limit_gws=2)
|
||||
|
||||
@@ -129,7 +129,6 @@ def setup_sdn(network_config, keystone_session=None):
|
||||
ext_network = openstack_utils.create_external_network(
|
||||
neutron_client,
|
||||
project_id,
|
||||
network_config.get("dvr_enabled", False),
|
||||
network_config["external_net_name"])
|
||||
openstack_utils.create_external_subnet(
|
||||
neutron_client,
|
||||
@@ -184,7 +183,8 @@ def setup_sdn(network_config, keystone_session=None):
|
||||
openstack_utils.add_neutron_secgroup_rules(neutron_client, project_id)
|
||||
|
||||
|
||||
def setup_gateway_ext_port(network_config, keystone_session=None):
|
||||
def setup_gateway_ext_port(network_config, keystone_session=None,
|
||||
limit_gws=None):
|
||||
"""Perform setup external port on Neutron Gateway.
|
||||
|
||||
For OpenStack on OpenStack scenarios.
|
||||
@@ -193,6 +193,8 @@ def setup_gateway_ext_port(network_config, keystone_session=None):
|
||||
:type network_config: dict
|
||||
:param keystone_session: Keystone session object for undercloud
|
||||
:type keystone_session: keystoneauth1.session.Session object
|
||||
:param limit_gws: Limit the number of gateways that get a port attached
|
||||
:type limit_gws: Optional[int]
|
||||
:returns: None
|
||||
:rtype: None
|
||||
"""
|
||||
@@ -226,9 +228,9 @@ def setup_gateway_ext_port(network_config, keystone_session=None):
|
||||
openstack_utils.configure_gateway_ext_port(
|
||||
nova_client,
|
||||
neutron_client,
|
||||
dvr_mode=network_config.get("dvr_enabled", False),
|
||||
net_id=net_id,
|
||||
add_dataport_to_netplan=add_dataport_to_netplan)
|
||||
add_dataport_to_netplan=add_dataport_to_netplan,
|
||||
limit_gws=limit_gws)
|
||||
|
||||
|
||||
def run_from_cli(**kwargs):
|
||||
|
||||
@@ -81,21 +81,20 @@ def get_machines_for_application(application):
|
||||
|
||||
:param application: Application name
|
||||
:type application: string
|
||||
:returns: List of machines for an application
|
||||
:rtype: list
|
||||
:returns: machines for an application
|
||||
:rtype: Iterator[str]
|
||||
"""
|
||||
status = get_application_status(application)
|
||||
if not status:
|
||||
raise StopIteration
|
||||
|
||||
# libjuju juju status no longer has units for subordinate charms
|
||||
# Use the application it is subordinate-to to find machines
|
||||
if status.get("units") is None and status.get("subordinate-to"):
|
||||
return get_machines_for_application(status.get("subordinate-to")[0])
|
||||
status = get_application_status(status.get("subordinate-to")[0])
|
||||
|
||||
machines = []
|
||||
for unit in status.get("units").keys():
|
||||
machines.append(
|
||||
status.get("units").get(unit).get("machine"))
|
||||
return machines
|
||||
yield status.get("units").get(unit).get("machine")
|
||||
|
||||
|
||||
def get_unit_name_from_host_name(host_name, application):
|
||||
@@ -151,13 +150,11 @@ def get_machine_uuids_for_application(application):
|
||||
|
||||
:param application: Application name
|
||||
:type application: string
|
||||
:returns: List of machine uuuids for an application
|
||||
:rtype: list
|
||||
:returns: machine uuuids for an application
|
||||
:rtype: Iterator[str]
|
||||
"""
|
||||
uuids = []
|
||||
for machine in get_machines_for_application(application):
|
||||
uuids.append(get_machine_status(machine, key="instance-id"))
|
||||
return uuids
|
||||
yield get_machine_status(machine, key="instance-id")
|
||||
|
||||
|
||||
def get_provider_type():
|
||||
|
||||
@@ -46,7 +46,7 @@ from swiftclient import client as swiftclient
|
||||
|
||||
import datetime
|
||||
import io
|
||||
import juju_wait
|
||||
import itertools
|
||||
import logging
|
||||
import os
|
||||
import paramiko
|
||||
@@ -56,9 +56,10 @@ import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import tenacity
|
||||
import urllib
|
||||
import textwrap
|
||||
import urllib
|
||||
|
||||
import zaza
|
||||
from zaza import model
|
||||
from zaza.openstack.utilities import (
|
||||
exceptions,
|
||||
@@ -453,7 +454,7 @@ def get_gateway_uuids():
|
||||
"""Return machine uuids for neutron-gateway(s).
|
||||
|
||||
:returns: List of uuids
|
||||
:rtype: list
|
||||
:rtype: Iterator[str]
|
||||
"""
|
||||
return juju_utils.get_machine_uuids_for_application('neutron-gateway')
|
||||
|
||||
@@ -462,28 +463,65 @@ def get_ovs_uuids():
|
||||
"""Return machine uuids for neutron-openvswitch(s).
|
||||
|
||||
:returns: List of uuids
|
||||
:rtype: list
|
||||
:rtype: Iterator[str]
|
||||
"""
|
||||
return (juju_utils
|
||||
.get_machine_uuids_for_application('neutron-openvswitch'))
|
||||
|
||||
|
||||
def get_ovn_uuids():
|
||||
"""Provide machine uuids for OVN Chassis.
|
||||
|
||||
:returns: List of uuids
|
||||
:rtype: Iterator[str]
|
||||
"""
|
||||
return itertools.chain(
|
||||
juju_utils.get_machine_uuids_for_application('ovn-chassis'),
|
||||
juju_utils.get_machine_uuids_for_application('ovn-dedicated-chassis'),
|
||||
)
|
||||
|
||||
|
||||
def dvr_enabled():
|
||||
"""Check whether DVR is enabled in deployment.
|
||||
|
||||
:returns: True when DVR is enabled, False otherwise
|
||||
:rtype: bool
|
||||
"""
|
||||
return get_application_config_option('neutron-api', 'enable-dvr')
|
||||
|
||||
|
||||
def ovn_present():
|
||||
"""Check whether OVN is present in deployment.
|
||||
|
||||
:returns: True when OVN is present, False otherwise
|
||||
:rtype: bool
|
||||
"""
|
||||
app_presence = []
|
||||
for name in ('ovn-chassis', 'ovn-dedicated-chassis'):
|
||||
try:
|
||||
model.get_application(name)
|
||||
app_presence.append(True)
|
||||
except KeyError:
|
||||
app_presence.append(False)
|
||||
return any(app_presence)
|
||||
|
||||
|
||||
BRIDGE_MAPPINGS = 'bridge-mappings'
|
||||
NEW_STYLE_NETWORKING = 'physnet1:br-ex'
|
||||
|
||||
|
||||
def deprecated_external_networking(dvr_mode=False):
|
||||
def deprecated_external_networking():
|
||||
"""Determine whether deprecated external network mode is in use.
|
||||
|
||||
:param dvr_mode: Using DVR mode or not
|
||||
:type dvr_mode: boolean
|
||||
:returns: True or False
|
||||
:rtype: boolean
|
||||
"""
|
||||
bridge_mappings = None
|
||||
if dvr_mode:
|
||||
if dvr_enabled():
|
||||
bridge_mappings = get_application_config_option('neutron-openvswitch',
|
||||
BRIDGE_MAPPINGS)
|
||||
elif ovn_present():
|
||||
return False
|
||||
else:
|
||||
bridge_mappings = get_application_config_option('neutron-gateway',
|
||||
BRIDGE_MAPPINGS)
|
||||
@@ -520,17 +558,15 @@ def get_admin_net(neutron_client):
|
||||
return net
|
||||
|
||||
|
||||
def add_interface_to_netplan(server_name, mac_address, dvr_mode=None):
|
||||
def add_interface_to_netplan(server_name, mac_address):
|
||||
"""In guest server_name, add nic with mac_address to netplan.
|
||||
|
||||
:param server_name: Hostname of instance
|
||||
:type server_name: string
|
||||
:param mac_address: mac address of nic to be added to netplan
|
||||
:type mac_address: string
|
||||
:param dvr_mode: Using DVR mode or not
|
||||
:type dvr_mode: boolean
|
||||
"""
|
||||
if dvr_mode:
|
||||
if dvr_enabled():
|
||||
application_name = 'neutron-openvswitch'
|
||||
else:
|
||||
application_name = 'neutron-gateway'
|
||||
@@ -578,33 +614,49 @@ def add_interface_to_netplan(server_name, mac_address, dvr_mode=None):
|
||||
model.run_on_unit(unit_name, "sudo netplan apply")
|
||||
|
||||
|
||||
def configure_gateway_ext_port(novaclient, neutronclient,
|
||||
dvr_mode=None, net_id=None,
|
||||
add_dataport_to_netplan=False):
|
||||
def configure_gateway_ext_port(novaclient, neutronclient, net_id=None,
|
||||
add_dataport_to_netplan=False,
|
||||
limit_gws=None):
|
||||
"""Configure the neturong-gateway external port.
|
||||
|
||||
:param novaclient: Authenticated novaclient
|
||||
:type novaclient: novaclient.Client object
|
||||
:param neutronclient: Authenticated neutronclient
|
||||
:type neutronclient: neutronclient.Client object
|
||||
:param dvr_mode: Using DVR mode or not
|
||||
:type dvr_mode: boolean
|
||||
:param net_id: Network ID
|
||||
:type net_id: string
|
||||
:param limit_gws: Limit the number of gateways that get a port attached
|
||||
:type limit_gws: Optional[int]
|
||||
"""
|
||||
if dvr_mode:
|
||||
uuids = get_ovs_uuids()
|
||||
deprecated_extnet_mode = deprecated_external_networking()
|
||||
|
||||
port_config_key = 'data-port'
|
||||
if deprecated_extnet_mode:
|
||||
port_config_key = 'ext-port'
|
||||
|
||||
config = {}
|
||||
if dvr_enabled():
|
||||
uuids = itertools.islice(get_ovs_uuids(), limit_gws)
|
||||
# If dvr, do not attempt to persist nic in netplan
|
||||
# https://github.com/openstack-charmers/zaza-openstack-tests/issues/78
|
||||
add_dataport_to_netplan = False
|
||||
application_names = ['neutron-openvswitch']
|
||||
elif ovn_present():
|
||||
uuids = itertools.islice(get_ovn_uuids(), limit_gws)
|
||||
application_names = ['ovn-chassis']
|
||||
try:
|
||||
ovn_dc_name = 'ovn-dedicated-chassis'
|
||||
next(juju_utils.get_machine_uuids_for_application(ovn_dc_name))
|
||||
application_names.append(ovn_dc_name)
|
||||
except StopIteration:
|
||||
# ovn-dedicated-chassis not in deployment
|
||||
pass
|
||||
port_config_key = 'interface-bridge-mappings'
|
||||
config.update({'ovn-bridge-mappings': 'physnet1:br-ex'})
|
||||
add_dataport_to_netplan = False
|
||||
else:
|
||||
uuids = get_gateway_uuids()
|
||||
|
||||
deprecated_extnet_mode = deprecated_external_networking(dvr_mode)
|
||||
|
||||
config_key = 'data-port'
|
||||
if deprecated_extnet_mode:
|
||||
config_key = 'ext-port'
|
||||
uuids = itertools.islice(get_gateway_uuids(), limit_gws)
|
||||
application_names = ['neutron-gateway']
|
||||
|
||||
if not net_id:
|
||||
net_id = get_admin_net(neutronclient)['id']
|
||||
@@ -633,34 +685,37 @@ def configure_gateway_ext_port(novaclient, neutronclient,
|
||||
if add_dataport_to_netplan:
|
||||
mac_address = get_mac_from_port(port, neutronclient)
|
||||
add_interface_to_netplan(server.name,
|
||||
mac_address=mac_address,
|
||||
dvr_mode=dvr_mode)
|
||||
mac_address=mac_address)
|
||||
ext_br_macs = []
|
||||
for port in neutronclient.list_ports(network_id=net_id)['ports']:
|
||||
if 'ext-port' in port['name']:
|
||||
if deprecated_extnet_mode:
|
||||
ext_br_macs.append(port['mac_address'])
|
||||
elif ovn_present():
|
||||
ext_br_macs.append('{}:br-ex'.format(port['mac_address']))
|
||||
else:
|
||||
ext_br_macs.append('br-ex:{}'.format(port['mac_address']))
|
||||
ext_br_macs.sort()
|
||||
ext_br_macs_str = ' '.join(ext_br_macs)
|
||||
if dvr_mode:
|
||||
application_name = 'neutron-openvswitch'
|
||||
else:
|
||||
application_name = 'neutron-gateway'
|
||||
|
||||
if ext_br_macs:
|
||||
logging.info('Setting {} on {} external port to {}'.format(
|
||||
config_key, application_name, ext_br_macs_str))
|
||||
current_data_port = get_application_config_option(application_name,
|
||||
config_key)
|
||||
if current_data_port == ext_br_macs_str:
|
||||
logging.info('Config already set to value')
|
||||
return
|
||||
model.set_application_config(
|
||||
application_name,
|
||||
configuration={config_key: ext_br_macs_str})
|
||||
juju_wait.wait(wait_for_workload=True)
|
||||
config.update({port_config_key: ext_br_macs_str})
|
||||
for application_name in application_names:
|
||||
logging.info('Setting {} on {}'.format(
|
||||
config, application_name))
|
||||
current_data_port = get_application_config_option(application_name,
|
||||
port_config_key)
|
||||
if current_data_port == ext_br_macs_str:
|
||||
logging.info('Config already set to value')
|
||||
return
|
||||
|
||||
model.set_application_config(
|
||||
application_name,
|
||||
configuration=config)
|
||||
zaza.model.wait_for_agent_status()
|
||||
test_config = zaza.charm_lifecycle.utils.get_charm_config()
|
||||
zaza.model.wait_for_application_states(
|
||||
states=test_config.get('target_deploy_status', {}))
|
||||
|
||||
|
||||
@tenacity.retry(wait=tenacity.wait_exponential(multiplier=1, max=60),
|
||||
@@ -721,16 +776,13 @@ def create_project_network(neutron_client, project_id, net_name='private',
|
||||
return network
|
||||
|
||||
|
||||
def create_external_network(neutron_client, project_id, dvr_mode,
|
||||
net_name='ext_net'):
|
||||
def create_external_network(neutron_client, project_id, net_name='ext_net'):
|
||||
"""Create the external network.
|
||||
|
||||
:param neutron_client: Authenticated neutronclient
|
||||
:type neutron_client: neutronclient.Client object
|
||||
:param project_id: Project ID
|
||||
:type project_id: string
|
||||
:param dvr_mode: Using DVR mode or not
|
||||
:type dvr_mode: boolean
|
||||
:param net_name: Network name
|
||||
:type net_name: string
|
||||
:returns: Network object
|
||||
@@ -1377,10 +1429,9 @@ def get_current_os_release_pair(application='keystone'):
|
||||
:raises: exceptions.SeriesNotFound
|
||||
:raises: exceptions.OSVersionNotFound
|
||||
"""
|
||||
machines = juju_utils.get_machines_for_application(application)
|
||||
if len(machines) >= 1:
|
||||
machine = machines[0]
|
||||
else:
|
||||
try:
|
||||
machine = next(juju_utils.get_machines_for_application(application))
|
||||
except StopIteration:
|
||||
raise exceptions.ApplicationNotFound(application)
|
||||
|
||||
series = juju_utils.get_machine_series(machine)
|
||||
|
||||
Reference in New Issue
Block a user