[dosaboy,r=james-page] Support mtu from neutron-api, add support for bridge mapping configuration.
This commit is contained in:
commit
9af23e724c
17
config.yaml
17
config.yaml
@ -25,8 +25,10 @@ options:
|
||||
type: string
|
||||
default:
|
||||
description: |
|
||||
The data port will be added to br-data and will allow usage of flat or VLAN
|
||||
network types
|
||||
Space-delimited list of bridge:port mappings. Ports will be added to
|
||||
their corresponding bridge. The bridges will allow usage of flat or
|
||||
VLAN network types with Neutron and should match this defined in
|
||||
bridge-mappings.
|
||||
disable-security-groups:
|
||||
type: boolean
|
||||
default: false
|
||||
@ -36,6 +38,17 @@ options:
|
||||
.
|
||||
BE CAREFUL - this option allows you to disable all port level security within
|
||||
an OpenStack cloud.
|
||||
bridge-mappings:
|
||||
type: string
|
||||
default: 'physnet1:br-data'
|
||||
description: |
|
||||
Space-delimited list of ML2 data bridge mappings with format
|
||||
<provider>:<bridge>.
|
||||
vlan-ranges:
|
||||
type: string
|
||||
default: "physnet1:1000:2000"
|
||||
description: |
|
||||
Space-delimited list of network provider vlan id ranges.
|
||||
# Network configuration options
|
||||
# by default all access is over 'private-address'
|
||||
os-data-network:
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
from base64 import b64decode
|
||||
from subprocess import check_call
|
||||
@ -48,6 +49,8 @@ from charmhelpers.core.hookenv import (
|
||||
from charmhelpers.core.sysctl import create as sysctl_create
|
||||
|
||||
from charmhelpers.core.host import (
|
||||
list_nics,
|
||||
get_nic_hwaddr,
|
||||
mkdir,
|
||||
write_file,
|
||||
)
|
||||
@ -65,12 +68,18 @@ from charmhelpers.contrib.hahelpers.apache import (
|
||||
from charmhelpers.contrib.openstack.neutron import (
|
||||
neutron_plugin_attribute,
|
||||
)
|
||||
from charmhelpers.contrib.openstack.ip import (
|
||||
resolve_address,
|
||||
INTERNAL,
|
||||
)
|
||||
from charmhelpers.contrib.network.ip import (
|
||||
get_address_in_network,
|
||||
get_ipv4_addr,
|
||||
get_ipv6_addr,
|
||||
get_netmask_for_address,
|
||||
format_ipv6_addr,
|
||||
is_address_in_network,
|
||||
is_bridge_member,
|
||||
)
|
||||
from charmhelpers.contrib.openstack.utils import get_host_ip
|
||||
|
||||
@ -727,7 +736,14 @@ class ApacheSSLContext(OSContextGenerator):
|
||||
'endpoints': [],
|
||||
'ext_ports': []}
|
||||
|
||||
for cn in self.canonical_names():
|
||||
cns = self.canonical_names()
|
||||
if cns:
|
||||
for cn in cns:
|
||||
self.configure_cert(cn)
|
||||
else:
|
||||
# Expect cert/key provided in config (currently assumed that ca
|
||||
# uses ip for cn)
|
||||
cn = resolve_address(endpoint_type=INTERNAL)
|
||||
self.configure_cert(cn)
|
||||
|
||||
addresses = self.get_network_addresses()
|
||||
@ -883,6 +899,48 @@ class NeutronContext(OSContextGenerator):
|
||||
return ctxt
|
||||
|
||||
|
||||
class NeutronPortContext(OSContextGenerator):
|
||||
NIC_PREFIXES = ['eth', 'bond']
|
||||
|
||||
def resolve_ports(self, ports):
|
||||
"""Resolve NICs not yet bound to bridge(s)
|
||||
|
||||
If hwaddress provided then returns resolved hwaddress otherwise NIC.
|
||||
"""
|
||||
if not ports:
|
||||
return None
|
||||
|
||||
hwaddr_to_nic = {}
|
||||
hwaddr_to_ip = {}
|
||||
for nic in list_nics(self.NIC_PREFIXES):
|
||||
hwaddr = get_nic_hwaddr(nic)
|
||||
hwaddr_to_nic[hwaddr] = nic
|
||||
addresses = get_ipv4_addr(nic, fatal=False)
|
||||
addresses += get_ipv6_addr(iface=nic, fatal=False)
|
||||
hwaddr_to_ip[hwaddr] = addresses
|
||||
|
||||
resolved = []
|
||||
mac_regex = re.compile(r'([0-9A-F]{2}[:-]){5}([0-9A-F]{2})', re.I)
|
||||
for entry in ports:
|
||||
if re.match(mac_regex, entry):
|
||||
# NIC is in known NICs and does NOT hace an IP address
|
||||
if entry in hwaddr_to_nic and not hwaddr_to_ip[entry]:
|
||||
# If the nic is part of a bridge then don't use it
|
||||
if is_bridge_member(hwaddr_to_nic[entry]):
|
||||
continue
|
||||
|
||||
# Entry is a MAC address for a valid interface that doesn't
|
||||
# have an IP address assigned yet.
|
||||
resolved.append(hwaddr_to_nic[entry])
|
||||
else:
|
||||
# If the passed entry is not a MAC address, assume it's a valid
|
||||
# interface, and that the user put it there on purpose (we can
|
||||
# trust it to be the real external network).
|
||||
resolved.append(entry)
|
||||
|
||||
return resolved
|
||||
|
||||
|
||||
class OSConfigFlagContext(OSContextGenerator):
|
||||
"""Provides support for user-defined config flags.
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
# Various utilies for dealing with Neutron and the renaming from Quantum.
|
||||
|
||||
import six
|
||||
from subprocess import check_output
|
||||
|
||||
from charmhelpers.core.hookenv import (
|
||||
@ -237,3 +238,72 @@ def network_manager():
|
||||
else:
|
||||
# ensure accurate naming for all releases post-H
|
||||
return 'neutron'
|
||||
|
||||
|
||||
def parse_mappings(mappings):
|
||||
parsed = {}
|
||||
if mappings:
|
||||
mappings = mappings.split(' ')
|
||||
for m in mappings:
|
||||
p = m.partition(':')
|
||||
if p[1] == ':':
|
||||
parsed[p[0].strip()] = p[2].strip()
|
||||
|
||||
return parsed
|
||||
|
||||
|
||||
def parse_bridge_mappings(mappings):
|
||||
"""Parse bridge mappings.
|
||||
|
||||
Mappings must be a space-delimited list of provider:bridge mappings.
|
||||
|
||||
Returns dict of the form {provider:bridge}.
|
||||
"""
|
||||
return parse_mappings(mappings)
|
||||
|
||||
|
||||
def parse_data_port_mappings(mappings, default_bridge='br-data'):
|
||||
"""Parse data port mappings.
|
||||
|
||||
Mappings must be a space-delimited list of bridge:port mappings.
|
||||
|
||||
Returns dict of the form {bridge:port}.
|
||||
"""
|
||||
_mappings = parse_mappings(mappings)
|
||||
if not _mappings:
|
||||
if not mappings:
|
||||
return {}
|
||||
|
||||
# For backwards-compatibility we need to support port-only provided in
|
||||
# config.
|
||||
_mappings = {default_bridge: mappings.split(' ')[0]}
|
||||
|
||||
bridges = _mappings.keys()
|
||||
ports = _mappings.values()
|
||||
if len(set(bridges)) != len(bridges):
|
||||
raise Exception("It is not allowed to have more than one port "
|
||||
"configured on the same bridge")
|
||||
|
||||
if len(set(ports)) != len(ports):
|
||||
raise Exception("It is not allowed to have the same port configured "
|
||||
"on more than one bridge")
|
||||
|
||||
return _mappings
|
||||
|
||||
|
||||
def parse_vlan_range_mappings(mappings):
|
||||
"""Parse vlan range mappings.
|
||||
|
||||
Mappings must be a space-delimited list of provider:start:end mappings.
|
||||
|
||||
Returns dict of the form {provider: (start, end)}.
|
||||
"""
|
||||
_mappings = parse_mappings(mappings)
|
||||
if not _mappings:
|
||||
return {}
|
||||
|
||||
mappings = {}
|
||||
for p, r in six.iteritems(_mappings):
|
||||
mappings[p] = tuple(r.split(':'))
|
||||
|
||||
return mappings
|
||||
|
@ -566,3 +566,29 @@ class Hooks(object):
|
||||
def charm_dir():
|
||||
"""Return the root directory of the current charm"""
|
||||
return os.environ.get('CHARM_DIR')
|
||||
|
||||
|
||||
@cached
|
||||
def action_get(key=None):
|
||||
"""Gets the value of an action parameter, or all key/value param pairs"""
|
||||
cmd = ['action-get']
|
||||
if key is not None:
|
||||
cmd.append(key)
|
||||
cmd.append('--format=json')
|
||||
action_data = json.loads(subprocess.check_output(cmd).decode('UTF-8'))
|
||||
return action_data
|
||||
|
||||
|
||||
def action_set(values):
|
||||
"""Sets the values to be returned after the action finishes"""
|
||||
cmd = ['action-set']
|
||||
for k, v in list(values.items()):
|
||||
cmd.append('{}={}'.format(k, v))
|
||||
subprocess.check_call(cmd)
|
||||
|
||||
|
||||
def action_fail(message):
|
||||
"""Sets the action status to failed and sets the error message.
|
||||
|
||||
The results set by action_set are preserved."""
|
||||
subprocess.check_call(['action-fail', message])
|
||||
|
@ -339,12 +339,16 @@ def lsb_release():
|
||||
def pwgen(length=None):
|
||||
"""Generate a random pasword."""
|
||||
if length is None:
|
||||
# A random length is ok to use a weak PRNG
|
||||
length = random.choice(range(35, 45))
|
||||
alphanumeric_chars = [
|
||||
l for l in (string.ascii_letters + string.digits)
|
||||
if l not in 'l0QD1vAEIOUaeiou']
|
||||
# Use a crypto-friendly PRNG (e.g. /dev/urandom) for making the
|
||||
# actual password
|
||||
random_generator = random.SystemRandom()
|
||||
random_chars = [
|
||||
random.choice(alphanumeric_chars) for _ in range(length)]
|
||||
random_generator.choice(alphanumeric_chars) for _ in range(length)]
|
||||
return(''.join(random_chars))
|
||||
|
||||
|
||||
|
@ -139,7 +139,7 @@ class MysqlRelation(RelationContext):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.required_keys = ['host', 'user', 'password', 'database']
|
||||
super(HttpRelation).__init__(self, *args, **kwargs)
|
||||
RelationContext.__init__(self, *args, **kwargs)
|
||||
|
||||
|
||||
class HttpRelation(RelationContext):
|
||||
@ -154,7 +154,7 @@ class HttpRelation(RelationContext):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.required_keys = ['host', 'port']
|
||||
super(HttpRelation).__init__(self, *args, **kwargs)
|
||||
RelationContext.__init__(self, *args, **kwargs)
|
||||
|
||||
def provide_data(self):
|
||||
return {
|
||||
|
@ -5,17 +5,25 @@ from charmhelpers.core.hookenv import (
|
||||
config,
|
||||
unit_get,
|
||||
)
|
||||
from charmhelpers.core.host import list_nics, get_nic_hwaddr
|
||||
from charmhelpers.core.strutils import bool_from_string
|
||||
from charmhelpers.contrib.openstack import context
|
||||
from charmhelpers.core.host import service_running, service_start
|
||||
from charmhelpers.core.host import (
|
||||
service_running,
|
||||
service_start,
|
||||
service_restart,
|
||||
)
|
||||
from charmhelpers.contrib.network.ovs import add_bridge, add_bridge_port
|
||||
from charmhelpers.contrib.openstack.utils import get_host_ip
|
||||
from charmhelpers.contrib.network.ip import get_address_in_network
|
||||
import re
|
||||
|
||||
from charmhelpers.contrib.openstack.neutron import (
|
||||
parse_bridge_mappings,
|
||||
parse_data_port_mappings,
|
||||
parse_vlan_range_mappings,
|
||||
)
|
||||
from charmhelpers.core.host import (
|
||||
get_nic_hwaddr,
|
||||
)
|
||||
OVS_BRIDGE = 'br-int'
|
||||
DATA_BRIDGE = 'br-data'
|
||||
|
||||
|
||||
def _neutron_api_settings():
|
||||
@ -27,25 +35,48 @@ def _neutron_api_settings():
|
||||
'l2_population': True,
|
||||
'overlay_network_type': 'gre',
|
||||
}
|
||||
|
||||
for rid in relation_ids('neutron-plugin-api'):
|
||||
for unit in related_units(rid):
|
||||
rdata = relation_get(rid=rid, unit=unit)
|
||||
if 'l2-population' not in rdata:
|
||||
continue
|
||||
neutron_settings = {
|
||||
'l2_population': bool_from_string(rdata['l2-population']),
|
||||
'overlay_network_type': rdata['overlay-network-type'],
|
||||
'neutron_security_groups': bool_from_string(
|
||||
rdata['neutron-security-groups']
|
||||
),
|
||||
}
|
||||
if 'l2-population' in rdata:
|
||||
neutron_settings.update({
|
||||
'l2_population': bool_from_string(rdata['l2-population']),
|
||||
'overlay_network_type': rdata['overlay-network-type'],
|
||||
'neutron_security_groups':
|
||||
bool_from_string(rdata['neutron-security-groups'])
|
||||
})
|
||||
|
||||
# Override with configuration if set to true
|
||||
if config('disable-security-groups'):
|
||||
neutron_settings['neutron_security_groups'] = False
|
||||
return neutron_settings
|
||||
|
||||
net_dev_mtu = rdata.get('network-device-mtu')
|
||||
if net_dev_mtu:
|
||||
neutron_settings['network_device_mtu'] = net_dev_mtu
|
||||
|
||||
return neutron_settings
|
||||
|
||||
|
||||
class DataPortContext(context.NeutronPortContext):
|
||||
|
||||
def __call__(self):
|
||||
ports = config('data-port')
|
||||
if ports:
|
||||
portmap = parse_data_port_mappings(ports)
|
||||
ports = portmap.values()
|
||||
resolved = self.resolve_ports(ports)
|
||||
normalized = {get_nic_hwaddr(port): port for port in resolved
|
||||
if port not in ports}
|
||||
normalized.update({port: port for port in resolved
|
||||
if port in ports})
|
||||
if resolved:
|
||||
return {bridge: normalized[port] for bridge, port in
|
||||
portmap.iteritems() if port in normalized.keys()}
|
||||
|
||||
return None
|
||||
|
||||
|
||||
class OVSPluginContext(context.NeutronContext):
|
||||
interfaces = []
|
||||
|
||||
@ -62,31 +93,23 @@ class OVSPluginContext(context.NeutronContext):
|
||||
neutron_api_settings = _neutron_api_settings()
|
||||
return neutron_api_settings['neutron_security_groups']
|
||||
|
||||
def get_data_port(self):
|
||||
data_ports = config('data-port')
|
||||
if not data_ports:
|
||||
return None
|
||||
hwaddrs = {}
|
||||
for nic in list_nics(['eth', 'bond']):
|
||||
hwaddrs[get_nic_hwaddr(nic).lower()] = nic
|
||||
mac_regex = re.compile(r'([0-9A-F]{2}[:-]){5}([0-9A-F]{2})', re.I)
|
||||
for entry in data_ports.split():
|
||||
entry = entry.strip().lower()
|
||||
if re.match(mac_regex, entry):
|
||||
if entry in hwaddrs:
|
||||
return hwaddrs[entry]
|
||||
else:
|
||||
return entry
|
||||
return None
|
||||
|
||||
def _ensure_bridge(self):
|
||||
if not service_running('openvswitch-switch'):
|
||||
service_start('openvswitch-switch')
|
||||
|
||||
add_bridge(OVS_BRIDGE)
|
||||
add_bridge(DATA_BRIDGE)
|
||||
data_port = self.get_data_port()
|
||||
if data_port:
|
||||
add_bridge_port(DATA_BRIDGE, data_port, promisc=True)
|
||||
|
||||
portmaps = DataPortContext()()
|
||||
bridgemaps = parse_bridge_mappings(config('bridge-mappings'))
|
||||
for provider, br in bridgemaps.iteritems():
|
||||
add_bridge(br)
|
||||
|
||||
if not portmaps or br not in portmaps:
|
||||
continue
|
||||
|
||||
add_bridge_port(br, portmaps[br], promisc=True)
|
||||
|
||||
service_restart('os-charm-phy-nic-mtu')
|
||||
|
||||
def ovs_ctxt(self):
|
||||
# In addition to generating config context, ensure the OVS service
|
||||
@ -112,4 +135,40 @@ class OVSPluginContext(context.NeutronContext):
|
||||
ovs_ctxt['use_syslog'] = conf['use-syslog']
|
||||
ovs_ctxt['verbose'] = conf['verbose']
|
||||
ovs_ctxt['debug'] = conf['debug']
|
||||
|
||||
net_dev_mtu = neutron_api_settings.get('network_device_mtu')
|
||||
if net_dev_mtu:
|
||||
# neutron.conf
|
||||
ovs_ctxt['network_device_mtu'] = net_dev_mtu
|
||||
# ml2 conf
|
||||
ovs_ctxt['veth_mtu'] = net_dev_mtu
|
||||
|
||||
mappings = config('bridge-mappings')
|
||||
if mappings:
|
||||
ovs_ctxt['bridge_mappings'] = mappings
|
||||
|
||||
vlan_ranges = config('vlan-ranges')
|
||||
vlan_range_mappings = parse_vlan_range_mappings(config('vlan-ranges'))
|
||||
if vlan_ranges:
|
||||
providers = vlan_range_mappings.keys()
|
||||
ovs_ctxt['network_providers'] = ' '.join(providers)
|
||||
ovs_ctxt['vlan_ranges'] = vlan_ranges
|
||||
|
||||
return ovs_ctxt
|
||||
|
||||
|
||||
class PhyNICMTUContext(DataPortContext):
|
||||
"""Context used to apply settings to neutron data-port devices"""
|
||||
|
||||
def __call__(self):
|
||||
ctxt = {}
|
||||
mappings = super(PhyNICMTUContext, self).__call__()
|
||||
if mappings and mappings.values():
|
||||
ports = mappings.values()
|
||||
neutron_api_settings = _neutron_api_settings()
|
||||
mtu = neutron_api_settings.get('network_device_mtu')
|
||||
if mtu:
|
||||
ctxt['devs'] = '\\n'.join(ports)
|
||||
ctxt['mtu'] = mtu
|
||||
|
||||
return ctxt
|
||||
|
@ -13,6 +13,8 @@ NEUTRON_CONF_DIR = "/etc/neutron"
|
||||
NEUTRON_CONF = '%s/neutron.conf' % NEUTRON_CONF_DIR
|
||||
NEUTRON_DEFAULT = '/etc/default/neutron-server'
|
||||
ML2_CONF = '%s/plugins/ml2/ml2_conf.ini' % NEUTRON_CONF_DIR
|
||||
PHY_NIC_MTU_CONF = '/etc/init/os-charm-phy-nic-mtu.conf'
|
||||
TEMPLATES = 'templates/'
|
||||
|
||||
BASE_RESOURCE_MAP = OrderedDict([
|
||||
(NEUTRON_CONF, {
|
||||
@ -24,8 +26,11 @@ BASE_RESOURCE_MAP = OrderedDict([
|
||||
'services': ['neutron-plugin-openvswitch-agent'],
|
||||
'contexts': [neutron_ovs_context.OVSPluginContext()],
|
||||
}),
|
||||
(PHY_NIC_MTU_CONF, {
|
||||
'services': ['os-charm-phy-nic-mtu'],
|
||||
'contexts': [neutron_ovs_context.PhyNICMTUContext()],
|
||||
}),
|
||||
])
|
||||
TEMPLATES = 'templates/'
|
||||
|
||||
|
||||
def determine_packages():
|
||||
|
@ -16,19 +16,22 @@ tunnel_id_ranges = 1:1000
|
||||
vni_ranges = 1001:2000
|
||||
|
||||
[ml2_type_vlan]
|
||||
network_vlan_ranges = physnet1:1000:2000
|
||||
network_vlan_ranges = {{ vlan_ranges }}
|
||||
|
||||
[ml2_type_flat]
|
||||
flat_networks = physnet1
|
||||
flat_networks = {{ network_providers }}
|
||||
|
||||
[ovs]
|
||||
enable_tunneling = True
|
||||
local_ip = {{ local_ip }}
|
||||
bridge_mappings = physnet1:br-data
|
||||
bridge_mappings = {{ bridge_mappings }}
|
||||
|
||||
[agent]
|
||||
tunnel_types = {{ overlay_network_type }}
|
||||
l2_population = {{ l2_population }}
|
||||
{% if veth_mtu -%}
|
||||
veth_mtu = {{ veth_mtu }}
|
||||
{% endif %}
|
||||
|
||||
[securitygroup]
|
||||
{% if neutron_security_groups -%}
|
||||
|
@ -1,4 +1,4 @@
|
||||
# grizzly
|
||||
# icehouse
|
||||
###############################################################################
|
||||
# [ WARNING ]
|
||||
# Configuration file maintained by Juju. Local changes may be overwritten.
|
||||
@ -12,6 +12,7 @@ state_path = /var/lib/neutron
|
||||
lock_path = $state_path/lock
|
||||
bind_host = 0.0.0.0
|
||||
bind_port = 9696
|
||||
network_device_mtu = {{ network_device_mtu }}
|
||||
|
||||
{% if core_plugin -%}
|
||||
core_plugin = {{ core_plugin }}
|
||||
|
22
templates/os-charm-phy-nic-mtu.conf
Normal file
22
templates/os-charm-phy-nic-mtu.conf
Normal file
@ -0,0 +1,22 @@
|
||||
description "Enabling Quantum external networking port"
|
||||
|
||||
start on runlevel [2345]
|
||||
|
||||
task
|
||||
|
||||
script
|
||||
devs="{{ devs }}"
|
||||
mtu="{{ mtu }}"
|
||||
tmpfile=`mktemp`
|
||||
echo $devs > $tmpfile
|
||||
if [ -n "$mtu" ]; then
|
||||
while read -r dev; do
|
||||
[ -n "$dev" ] || continue
|
||||
rc=0
|
||||
# Try all devices before exiting with error
|
||||
ip link set $dev mtu $mtu || rc=$?
|
||||
done < $tmpfile
|
||||
rm $tmpfile
|
||||
[ $rc = 0 ] || exit $rc
|
||||
fi
|
||||
end script
|
@ -14,8 +14,6 @@ TO_PATCH = [
|
||||
'service_running',
|
||||
'service_start',
|
||||
'get_host_ip',
|
||||
'get_nic_hwaddr',
|
||||
'list_nics',
|
||||
]
|
||||
|
||||
|
||||
@ -32,34 +30,45 @@ class OVSPluginContextTest(CharmTestCase):
|
||||
def tearDown(self):
|
||||
super(OVSPluginContextTest, self).tearDown()
|
||||
|
||||
def test_data_port_name(self):
|
||||
self.test_config.set('data-port', 'em1')
|
||||
self.assertEquals(context.OVSPluginContext().get_data_port(), 'em1')
|
||||
@patch('charmhelpers.contrib.openstack.context.NeutronPortContext.'
|
||||
'resolve_ports')
|
||||
def test_data_port_name(self, mock_resolve_ports):
|
||||
self.test_config.set('data-port', 'br-data:em1')
|
||||
mock_resolve_ports.side_effect = lambda ports: ports
|
||||
self.assertEquals(context.DataPortContext()(),
|
||||
{'br-data': 'em1'})
|
||||
|
||||
def test_data_port_mac(self):
|
||||
@patch.object(context, 'get_nic_hwaddr')
|
||||
@patch('charmhelpers.contrib.openstack.context.get_nic_hwaddr')
|
||||
@patch('charmhelpers.contrib.openstack.context.list_nics')
|
||||
def test_data_port_mac(self, list_nics, get_nic_hwaddr, get_nic_hwaddr2):
|
||||
machine_machs = {
|
||||
'em1': 'aa:aa:aa:aa:aa:aa',
|
||||
'eth0': 'bb:bb:bb:bb:bb:bb',
|
||||
}
|
||||
get_nic_hwaddr2.side_effect = lambda nic: machine_machs[nic]
|
||||
absent_mac = "cc:cc:cc:cc:cc:cc"
|
||||
config_macs = "%s %s" % (absent_mac, machine_machs['em1'])
|
||||
config_macs = ("br-d1:%s br-d2:%s" %
|
||||
(absent_mac, machine_machs['em1']))
|
||||
self.test_config.set('data-port', config_macs)
|
||||
list_nics.return_value = machine_machs.keys()
|
||||
get_nic_hwaddr.side_effect = lambda nic: machine_machs[nic]
|
||||
self.assertEquals(context.DataPortContext()(),
|
||||
{'br-d2': 'em1'})
|
||||
|
||||
def get_hwaddr(eth):
|
||||
return machine_machs[eth]
|
||||
self.get_nic_hwaddr.side_effect = get_hwaddr
|
||||
self.list_nics.return_value = machine_machs.keys()
|
||||
self.assertEquals(context.OVSPluginContext().get_data_port(), 'em1')
|
||||
@patch('charmhelpers.contrib.openstack.context.NeutronPortContext.'
|
||||
'resolve_ports')
|
||||
def test_ensure_bridge_data_port_present(self, mock_resolve_ports):
|
||||
self.test_config.set('data-port', 'br-data:em1')
|
||||
self.test_config.set('bridge-mappings', 'phybr1:br-data')
|
||||
|
||||
@patch.object(context.OVSPluginContext, 'get_data_port')
|
||||
def test_ensure_bridge_data_port_present(self, get_data_port):
|
||||
def add_port(bridge, port, promisc):
|
||||
if bridge == 'br-data' and port == 'em1' and promisc is True:
|
||||
self.bridge_added = True
|
||||
return
|
||||
self.bridge_added = False
|
||||
|
||||
get_data_port.return_value = 'em1'
|
||||
mock_resolve_ports.side_effect = lambda ports: ports
|
||||
self.add_bridge_port.side_effect = add_port
|
||||
context.OVSPluginContext()._ensure_bridge()
|
||||
self.assertEquals(self.bridge_added, True)
|
||||
@ -90,6 +99,7 @@ class OVSPluginContextTest(CharmTestCase):
|
||||
self.relation_ids.return_value = ['rid2']
|
||||
self.test_relation.set({'neutron-security-groups': 'True',
|
||||
'l2-population': 'True',
|
||||
'network-device-mtu': 1500,
|
||||
'overlay-network-type': 'gre',
|
||||
})
|
||||
self.get_host_ip.return_value = '127.0.0.15'
|
||||
@ -100,6 +110,8 @@ class OVSPluginContextTest(CharmTestCase):
|
||||
'neutron_security_groups': True,
|
||||
'verbose': True,
|
||||
'local_ip': '127.0.0.15',
|
||||
'network_device_mtu': 1500,
|
||||
'veth_mtu': 1500,
|
||||
'config': 'neutron.randomconfig',
|
||||
'use_syslog': True,
|
||||
'network_manager': 'neutron',
|
||||
@ -109,6 +121,9 @@ class OVSPluginContextTest(CharmTestCase):
|
||||
'neutron_url': 'https://127.0.0.13:9696',
|
||||
'l2_population': True,
|
||||
'overlay_network_type': 'gre',
|
||||
'network_providers': 'physnet1',
|
||||
'bridge_mappings': 'physnet1:br-data',
|
||||
'vlan_ranges': 'physnet1:1000:2000',
|
||||
}
|
||||
self.assertEquals(expect, napi_ctxt())
|
||||
self.service_start.assertCalled()
|
||||
@ -133,6 +148,7 @@ class OVSPluginContextTest(CharmTestCase):
|
||||
return "neutron.randomdriver"
|
||||
if section == "config":
|
||||
return "neutron.randomconfig"
|
||||
|
||||
_npa.side_effect = mock_npa
|
||||
_config.return_value = 'ovs'
|
||||
_unit_get.return_value = '127.0.0.13'
|
||||
@ -143,6 +159,7 @@ class OVSPluginContextTest(CharmTestCase):
|
||||
self.relation_ids.return_value = ['rid2']
|
||||
self.test_relation.set({'neutron-security-groups': 'True',
|
||||
'l2-population': 'True',
|
||||
'network-device-mtu': 1500,
|
||||
'overlay-network-type': 'gre',
|
||||
})
|
||||
self.get_host_ip.return_value = '127.0.0.15'
|
||||
@ -153,6 +170,8 @@ class OVSPluginContextTest(CharmTestCase):
|
||||
'neutron_security_groups': False,
|
||||
'verbose': True,
|
||||
'local_ip': '127.0.0.15',
|
||||
'veth_mtu': 1500,
|
||||
'network_device_mtu': 1500,
|
||||
'config': 'neutron.randomconfig',
|
||||
'use_syslog': True,
|
||||
'network_manager': 'neutron',
|
||||
@ -162,6 +181,9 @@ class OVSPluginContextTest(CharmTestCase):
|
||||
'neutron_url': 'https://127.0.0.13:9696',
|
||||
'l2_population': True,
|
||||
'overlay_network_type': 'gre',
|
||||
'network_providers': 'physnet1',
|
||||
'bridge_mappings': 'physnet1:br-data',
|
||||
'vlan_ranges': 'physnet1:1000:2000',
|
||||
}
|
||||
self.assertEquals(expect, napi_ctxt())
|
||||
self.service_start.assertCalled()
|
||||
|
@ -71,7 +71,8 @@ class TestNeutronOVSUtils(CharmTestCase):
|
||||
templating.OSConfigRenderer.side_effect = _mock_OSConfigRenderer
|
||||
_regconfs = nutils.register_configs()
|
||||
confs = ['/etc/neutron/neutron.conf',
|
||||
'/etc/neutron/plugins/ml2/ml2_conf.ini']
|
||||
'/etc/neutron/plugins/ml2/ml2_conf.ini',
|
||||
'/etc/init/os-charm-phy-nic-mtu.conf']
|
||||
self.assertItemsEqual(_regconfs.configs, confs)
|
||||
|
||||
def test_resource_map(self):
|
||||
@ -85,8 +86,9 @@ class TestNeutronOVSUtils(CharmTestCase):
|
||||
expect = OrderedDict([
|
||||
(nutils.NEUTRON_CONF, ['neutron-plugin-openvswitch-agent']),
|
||||
(ML2CONF, ['neutron-plugin-openvswitch-agent']),
|
||||
(nutils.PHY_NIC_MTU_CONF, ['os-charm-phy-nic-mtu'])
|
||||
])
|
||||
self.assertTrue(len(expect) == len(_restart_map))
|
||||
self.assertEqual(expect, _restart_map)
|
||||
for item in _restart_map:
|
||||
self.assertTrue(item in _restart_map)
|
||||
self.assertTrue(expect[item] == _restart_map[item])
|
||||
|
Loading…
Reference in New Issue
Block a user