[gnuoy,r=james-page] Add support for Neutron DVR
This commit is contained in:
commit
be6b39e892
@ -60,3 +60,12 @@ options:
|
|||||||
.
|
.
|
||||||
This network will be used for tenant network traffic in overlay
|
This network will be used for tenant network traffic in overlay
|
||||||
networks.
|
networks.
|
||||||
|
ext-port:
|
||||||
|
type: string
|
||||||
|
default:
|
||||||
|
description: |
|
||||||
|
A space-separated list of external ports to use for routing of instance
|
||||||
|
traffic to the external public network. Valid values are either MAC
|
||||||
|
addresses (in which case only MAC addresses for interfaces without an IP
|
||||||
|
address already assigned will be used), or interfaces (eth0)
|
||||||
|
|
||||||
|
@ -320,14 +320,15 @@ def db_ssl(rdata, ctxt, ssl_dir):
|
|||||||
|
|
||||||
|
|
||||||
class IdentityServiceContext(OSContextGenerator):
|
class IdentityServiceContext(OSContextGenerator):
|
||||||
interfaces = ['identity-service']
|
|
||||||
|
|
||||||
def __init__(self, service=None, service_user=None):
|
def __init__(self, service=None, service_user=None, rel_name='identity-service'):
|
||||||
self.service = service
|
self.service = service
|
||||||
self.service_user = service_user
|
self.service_user = service_user
|
||||||
|
self.rel_name = rel_name
|
||||||
|
self.interfaces = [self.rel_name]
|
||||||
|
|
||||||
def __call__(self):
|
def __call__(self):
|
||||||
log('Generating template context for identity-service', level=DEBUG)
|
log('Generating template context for ' + self.rel_name, level=DEBUG)
|
||||||
ctxt = {}
|
ctxt = {}
|
||||||
|
|
||||||
if self.service and self.service_user:
|
if self.service and self.service_user:
|
||||||
@ -341,7 +342,7 @@ class IdentityServiceContext(OSContextGenerator):
|
|||||||
|
|
||||||
ctxt['signing_dir'] = cachedir
|
ctxt['signing_dir'] = cachedir
|
||||||
|
|
||||||
for rid in relation_ids('identity-service'):
|
for rid in relation_ids(self.rel_name):
|
||||||
for unit in related_units(rid):
|
for unit in related_units(rid):
|
||||||
rdata = relation_get(rid=rid, unit=unit)
|
rdata = relation_get(rid=rid, unit=unit)
|
||||||
serv_host = rdata.get('service_host')
|
serv_host = rdata.get('service_host')
|
||||||
|
@ -1,25 +1,23 @@
|
|||||||
|
import os
|
||||||
|
import uuid
|
||||||
from charmhelpers.core.hookenv import (
|
from charmhelpers.core.hookenv import (
|
||||||
config,
|
config,
|
||||||
|
relation_get,
|
||||||
|
relation_ids,
|
||||||
|
related_units,
|
||||||
unit_get,
|
unit_get,
|
||||||
)
|
)
|
||||||
|
from charmhelpers.contrib.openstack.ip import resolve_address
|
||||||
from charmhelpers.contrib.openstack import context
|
from charmhelpers.contrib.openstack import context
|
||||||
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.openstack.utils import get_host_ip
|
||||||
from charmhelpers.contrib.network.ip import get_address_in_network
|
from charmhelpers.contrib.network.ip import get_address_in_network
|
||||||
from charmhelpers.contrib.openstack.context import (
|
from charmhelpers.contrib.openstack.context import (
|
||||||
|
OSContextGenerator,
|
||||||
NeutronAPIContext,
|
NeutronAPIContext,
|
||||||
DataPortContext,
|
|
||||||
)
|
)
|
||||||
from charmhelpers.contrib.openstack.neutron import (
|
from charmhelpers.contrib.openstack.neutron import (
|
||||||
parse_bridge_mappings,
|
|
||||||
parse_vlan_range_mappings,
|
parse_vlan_range_mappings,
|
||||||
)
|
)
|
||||||
OVS_BRIDGE = 'br-int'
|
|
||||||
|
|
||||||
|
|
||||||
class OVSPluginContext(context.NeutronContext):
|
class OVSPluginContext(context.NeutronContext):
|
||||||
@ -40,24 +38,6 @@ class OVSPluginContext(context.NeutronContext):
|
|||||||
neutron_api_settings = NeutronAPIContext()()
|
neutron_api_settings = NeutronAPIContext()()
|
||||||
return neutron_api_settings['neutron_security_groups']
|
return neutron_api_settings['neutron_security_groups']
|
||||||
|
|
||||||
def _ensure_bridge(self):
|
|
||||||
if not service_running('openvswitch-switch'):
|
|
||||||
service_start('openvswitch-switch')
|
|
||||||
|
|
||||||
add_bridge(OVS_BRIDGE)
|
|
||||||
|
|
||||||
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):
|
def ovs_ctxt(self):
|
||||||
# In addition to generating config context, ensure the OVS service
|
# In addition to generating config context, ensure the OVS service
|
||||||
# is running and the OVS bridge exists. Also need to ensure
|
# is running and the OVS bridge exists. Also need to ensure
|
||||||
@ -66,8 +46,6 @@ class OVSPluginContext(context.NeutronContext):
|
|||||||
if not ovs_ctxt:
|
if not ovs_ctxt:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
self._ensure_bridge()
|
|
||||||
|
|
||||||
conf = config()
|
conf = config()
|
||||||
ovs_ctxt['local_ip'] = \
|
ovs_ctxt['local_ip'] = \
|
||||||
get_address_in_network(config('os-data-network'),
|
get_address_in_network(config('os-data-network'),
|
||||||
@ -75,6 +53,7 @@ class OVSPluginContext(context.NeutronContext):
|
|||||||
neutron_api_settings = NeutronAPIContext()()
|
neutron_api_settings = NeutronAPIContext()()
|
||||||
ovs_ctxt['neutron_security_groups'] = self.neutron_security_groups
|
ovs_ctxt['neutron_security_groups'] = self.neutron_security_groups
|
||||||
ovs_ctxt['l2_population'] = neutron_api_settings['l2_population']
|
ovs_ctxt['l2_population'] = neutron_api_settings['l2_population']
|
||||||
|
ovs_ctxt['distributed_routing'] = neutron_api_settings['enable_dvr']
|
||||||
ovs_ctxt['overlay_network_type'] = \
|
ovs_ctxt['overlay_network_type'] = \
|
||||||
neutron_api_settings['overlay_network_type']
|
neutron_api_settings['overlay_network_type']
|
||||||
# TODO: We need to sort out the syslog and debug/verbose options as a
|
# TODO: We need to sort out the syslog and debug/verbose options as a
|
||||||
@ -102,3 +81,62 @@ class OVSPluginContext(context.NeutronContext):
|
|||||||
ovs_ctxt['vlan_ranges'] = vlan_ranges
|
ovs_ctxt['vlan_ranges'] = vlan_ranges
|
||||||
|
|
||||||
return ovs_ctxt
|
return ovs_ctxt
|
||||||
|
|
||||||
|
|
||||||
|
class L3AgentContext(OSContextGenerator):
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
neutron_api_settings = NeutronAPIContext()()
|
||||||
|
ctxt = {}
|
||||||
|
if neutron_api_settings['enable_dvr']:
|
||||||
|
ctxt['agent_mode'] = 'dvr'
|
||||||
|
else:
|
||||||
|
ctxt['agent_mode'] = 'legacy'
|
||||||
|
return ctxt
|
||||||
|
|
||||||
|
|
||||||
|
SHARED_SECRET = "/etc/neutron/secret.txt"
|
||||||
|
|
||||||
|
|
||||||
|
def get_shared_secret():
|
||||||
|
secret = None
|
||||||
|
if not os.path.exists(SHARED_SECRET):
|
||||||
|
secret = str(uuid.uuid4())
|
||||||
|
with open(SHARED_SECRET, 'w') as secret_file:
|
||||||
|
secret_file.write(secret)
|
||||||
|
else:
|
||||||
|
with open(SHARED_SECRET, 'r') as secret_file:
|
||||||
|
secret = secret_file.read().strip()
|
||||||
|
return secret
|
||||||
|
|
||||||
|
|
||||||
|
class DVRSharedSecretContext(OSContextGenerator):
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
if NeutronAPIContext()()['enable_dvr']:
|
||||||
|
ctxt = {
|
||||||
|
'shared_secret': get_shared_secret(),
|
||||||
|
'local_ip': resolve_address(),
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
ctxt = {}
|
||||||
|
return ctxt
|
||||||
|
|
||||||
|
|
||||||
|
class APIIdentityServiceContext(context.IdentityServiceContext):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(APIIdentityServiceContext,
|
||||||
|
self).__init__(rel_name='neutron-plugin-api')
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
ctxt = super(APIIdentityServiceContext, self).__call__()
|
||||||
|
if not ctxt:
|
||||||
|
return
|
||||||
|
for rid in relation_ids('neutron-plugin-api'):
|
||||||
|
for unit in related_units(rid):
|
||||||
|
rdata = relation_get(rid=rid, unit=unit)
|
||||||
|
ctxt['region'] = rdata.get('region')
|
||||||
|
if ctxt['region']:
|
||||||
|
return ctxt
|
||||||
|
return ctxt
|
||||||
|
@ -8,6 +8,7 @@ from charmhelpers.core.hookenv import (
|
|||||||
config,
|
config,
|
||||||
log,
|
log,
|
||||||
relation_set,
|
relation_set,
|
||||||
|
relation_ids,
|
||||||
)
|
)
|
||||||
|
|
||||||
from charmhelpers.core.host import (
|
from charmhelpers.core.host import (
|
||||||
@ -15,13 +16,18 @@ from charmhelpers.core.host import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from charmhelpers.fetch import (
|
from charmhelpers.fetch import (
|
||||||
apt_install, apt_update
|
apt_install, apt_update, apt_purge
|
||||||
)
|
)
|
||||||
|
|
||||||
from neutron_ovs_utils import (
|
from neutron_ovs_utils import (
|
||||||
|
DVR_PACKAGES,
|
||||||
|
configure_ovs,
|
||||||
determine_packages,
|
determine_packages,
|
||||||
|
determine_dvr_packages,
|
||||||
|
get_shared_secret,
|
||||||
register_configs,
|
register_configs,
|
||||||
restart_map,
|
restart_map,
|
||||||
|
use_dvr,
|
||||||
)
|
)
|
||||||
|
|
||||||
hooks = Hooks()
|
hooks = Hooks()
|
||||||
@ -37,13 +43,40 @@ def install():
|
|||||||
|
|
||||||
|
|
||||||
@hooks.hook('neutron-plugin-relation-changed')
|
@hooks.hook('neutron-plugin-relation-changed')
|
||||||
@hooks.hook('neutron-plugin-api-relation-changed')
|
|
||||||
@hooks.hook('config-changed')
|
@hooks.hook('config-changed')
|
||||||
@restart_on_change(restart_map())
|
@restart_on_change(restart_map())
|
||||||
def config_changed():
|
def config_changed():
|
||||||
|
if determine_dvr_packages():
|
||||||
|
apt_update()
|
||||||
|
apt_install(determine_dvr_packages(), fatal=True)
|
||||||
|
configure_ovs()
|
||||||
CONFIGS.write_all()
|
CONFIGS.write_all()
|
||||||
|
|
||||||
|
|
||||||
|
@hooks.hook('neutron-plugin-api-relation-changed')
|
||||||
|
@restart_on_change(restart_map())
|
||||||
|
def neutron_plugin_api_changed():
|
||||||
|
if use_dvr():
|
||||||
|
apt_update()
|
||||||
|
apt_install(DVR_PACKAGES, fatal=True)
|
||||||
|
else:
|
||||||
|
apt_purge(DVR_PACKAGES, fatal=True)
|
||||||
|
configure_ovs()
|
||||||
|
CONFIGS.write_all()
|
||||||
|
# If dvr setting has changed, need to pass that on
|
||||||
|
for rid in relation_ids('neutron-plugin'):
|
||||||
|
neutron_plugin_joined(relation_id=rid)
|
||||||
|
|
||||||
|
|
||||||
|
@hooks.hook('neutron-plugin-relation-joined')
|
||||||
|
def neutron_plugin_joined(relation_id=None):
|
||||||
|
secret = get_shared_secret() if use_dvr() else None
|
||||||
|
rel_data = {
|
||||||
|
'metadata-shared-secret': secret,
|
||||||
|
}
|
||||||
|
relation_set(relation_id=relation_id, **rel_data)
|
||||||
|
|
||||||
|
|
||||||
@hooks.hook('amqp-relation-joined')
|
@hooks.hook('amqp-relation-joined')
|
||||||
def amqp_joined(relation_id=None):
|
def amqp_joined(relation_id=None):
|
||||||
relation_set(relation_id=relation_id,
|
relation_set(relation_id=relation_id,
|
||||||
|
@ -7,12 +7,36 @@ from charmhelpers.contrib.openstack.utils import (
|
|||||||
os_release,
|
os_release,
|
||||||
)
|
)
|
||||||
import neutron_ovs_context
|
import neutron_ovs_context
|
||||||
|
from charmhelpers.contrib.network.ovs import (
|
||||||
|
add_bridge,
|
||||||
|
add_bridge_port,
|
||||||
|
full_restart,
|
||||||
|
)
|
||||||
|
from charmhelpers.core.hookenv import (
|
||||||
|
config,
|
||||||
|
)
|
||||||
|
from charmhelpers.contrib.openstack.neutron import (
|
||||||
|
parse_bridge_mappings,
|
||||||
|
)
|
||||||
|
from charmhelpers.contrib.openstack.context import (
|
||||||
|
ExternalPortContext,
|
||||||
|
DataPortContext,
|
||||||
|
)
|
||||||
|
from charmhelpers.core.host import (
|
||||||
|
service_restart,
|
||||||
|
service_running,
|
||||||
|
)
|
||||||
|
|
||||||
NOVA_CONF_DIR = "/etc/nova"
|
NOVA_CONF_DIR = "/etc/nova"
|
||||||
NEUTRON_CONF_DIR = "/etc/neutron"
|
NEUTRON_CONF_DIR = "/etc/neutron"
|
||||||
NEUTRON_CONF = '%s/neutron.conf' % NEUTRON_CONF_DIR
|
NEUTRON_CONF = '%s/neutron.conf' % NEUTRON_CONF_DIR
|
||||||
NEUTRON_DEFAULT = '/etc/default/neutron-server'
|
NEUTRON_DEFAULT = '/etc/default/neutron-server'
|
||||||
|
NEUTRON_L3_AGENT_CONF = "/etc/neutron/l3_agent.ini"
|
||||||
|
NEUTRON_FWAAS_CONF = "/etc/neutron/fwaas_driver.ini"
|
||||||
ML2_CONF = '%s/plugins/ml2/ml2_conf.ini' % NEUTRON_CONF_DIR
|
ML2_CONF = '%s/plugins/ml2/ml2_conf.ini' % NEUTRON_CONF_DIR
|
||||||
|
EXT_PORT_CONF = '/etc/init/ext-port.conf'
|
||||||
|
NEUTRON_METADATA_AGENT_CONF = "/etc/neutron/metadata_agent.ini"
|
||||||
|
DVR_PACKAGES = ['neutron-l3-agent']
|
||||||
PHY_NIC_MTU_CONF = '/etc/init/os-charm-phy-nic-mtu.conf'
|
PHY_NIC_MTU_CONF = '/etc/init/os-charm-phy-nic-mtu.conf'
|
||||||
TEMPLATES = 'templates/'
|
TEMPLATES = 'templates/'
|
||||||
|
|
||||||
@ -31,10 +55,41 @@ BASE_RESOURCE_MAP = OrderedDict([
|
|||||||
'contexts': [context.PhyNICMTUContext()],
|
'contexts': [context.PhyNICMTUContext()],
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
|
DVR_RESOURCE_MAP = OrderedDict([
|
||||||
|
(NEUTRON_L3_AGENT_CONF, {
|
||||||
|
'services': ['neutron-l3-agent'],
|
||||||
|
'contexts': [neutron_ovs_context.L3AgentContext()],
|
||||||
|
}),
|
||||||
|
(NEUTRON_FWAAS_CONF, {
|
||||||
|
'services': ['neutron-l3-agent'],
|
||||||
|
'contexts': [neutron_ovs_context.L3AgentContext()],
|
||||||
|
}),
|
||||||
|
(EXT_PORT_CONF, {
|
||||||
|
'services': ['neutron-l3-agent'],
|
||||||
|
'contexts': [context.ExternalPortContext()],
|
||||||
|
}),
|
||||||
|
(NEUTRON_METADATA_AGENT_CONF, {
|
||||||
|
'services': ['neutron-metadata-agent'],
|
||||||
|
'contexts': [neutron_ovs_context.DVRSharedSecretContext(),
|
||||||
|
neutron_ovs_context.APIIdentityServiceContext()],
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
TEMPLATES = 'templates/'
|
||||||
|
INT_BRIDGE = "br-int"
|
||||||
|
EXT_BRIDGE = "br-ex"
|
||||||
|
DATA_BRIDGE = 'br-data'
|
||||||
|
|
||||||
|
|
||||||
|
def determine_dvr_packages():
|
||||||
|
if use_dvr():
|
||||||
|
return DVR_PACKAGES
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
def determine_packages():
|
def determine_packages():
|
||||||
return neutron_plugin_attribute('ovs', 'packages', 'neutron')
|
pkgs = neutron_plugin_attribute('ovs', 'packages', 'neutron')
|
||||||
|
pkgs.extend(determine_dvr_packages())
|
||||||
|
return pkgs
|
||||||
|
|
||||||
|
|
||||||
def register_configs(release=None):
|
def register_configs(release=None):
|
||||||
@ -52,6 +107,10 @@ def resource_map():
|
|||||||
hook execution.
|
hook execution.
|
||||||
'''
|
'''
|
||||||
resource_map = deepcopy(BASE_RESOURCE_MAP)
|
resource_map = deepcopy(BASE_RESOURCE_MAP)
|
||||||
|
if use_dvr():
|
||||||
|
resource_map.update(DVR_RESOURCE_MAP)
|
||||||
|
dvr_services = ['neutron-metadata-agent', 'neutron-l3-agent']
|
||||||
|
resource_map[NEUTRON_CONF]['services'] += dvr_services
|
||||||
return resource_map
|
return resource_map
|
||||||
|
|
||||||
|
|
||||||
@ -61,3 +120,38 @@ def restart_map():
|
|||||||
state.
|
state.
|
||||||
'''
|
'''
|
||||||
return {k: v['services'] for k, v in resource_map().iteritems()}
|
return {k: v['services'] for k, v in resource_map().iteritems()}
|
||||||
|
|
||||||
|
|
||||||
|
def configure_ovs():
|
||||||
|
if not service_running('openvswitch-switch'):
|
||||||
|
full_restart()
|
||||||
|
add_bridge(INT_BRIDGE)
|
||||||
|
add_bridge(EXT_BRIDGE)
|
||||||
|
ext_port_ctx = None
|
||||||
|
if use_dvr():
|
||||||
|
ext_port_ctx = ExternalPortContext()()
|
||||||
|
if ext_port_ctx and ext_port_ctx['ext_port']:
|
||||||
|
add_bridge_port(EXT_BRIDGE, ext_port_ctx['ext_port'])
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
# Ensure this runs so that mtu is applied to data-port interfaces if
|
||||||
|
# provided.
|
||||||
|
service_restart('os-charm-phy-nic-mtu')
|
||||||
|
|
||||||
|
|
||||||
|
def get_shared_secret():
|
||||||
|
ctxt = neutron_ovs_context.DVRSharedSecretContext()()
|
||||||
|
if 'shared_secret' in ctxt:
|
||||||
|
return ctxt['shared_secret']
|
||||||
|
|
||||||
|
|
||||||
|
def use_dvr():
|
||||||
|
return context.NeutronAPIContext()()['enable_dvr']
|
||||||
|
16
templates/ext-port.conf
Normal file
16
templates/ext-port.conf
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
description "Enabling Neutron external networking port"
|
||||||
|
|
||||||
|
start on runlevel [2345]
|
||||||
|
|
||||||
|
task
|
||||||
|
|
||||||
|
script
|
||||||
|
EXT_PORT="{{ ext_port }}"
|
||||||
|
MTU="{{ ext_port_mtu }}"
|
||||||
|
if [ -n "$EXT_PORT" ]; then
|
||||||
|
ip link set $EXT_PORT up
|
||||||
|
if [ -n "$MTU" ]; then
|
||||||
|
ip link set $EXT_PORT mtu $MTU
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
end script
|
7
templates/juno/fwaas_driver.ini
Normal file
7
templates/juno/fwaas_driver.ini
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
###############################################################################
|
||||||
|
# [ WARNING ]
|
||||||
|
# Configuration file maintained by Juju. Local changes may be overwritten.
|
||||||
|
###############################################################################
|
||||||
|
[fwaas]
|
||||||
|
driver = neutron.services.firewall.drivers.linux.iptables_fwaas.IptablesFwaasDriver
|
||||||
|
enabled = True
|
7
templates/juno/l3_agent.ini
Normal file
7
templates/juno/l3_agent.ini
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
###############################################################################
|
||||||
|
# [ WARNING ]
|
||||||
|
# Configuration file maintained by Juju. Local changes may be overwritten.
|
||||||
|
###############################################################################
|
||||||
|
[DEFAULT]
|
||||||
|
interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver
|
||||||
|
agent_mode = {{ agent_mode }}
|
20
templates/juno/metadata_agent.ini
Normal file
20
templates/juno/metadata_agent.ini
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
###############################################################################
|
||||||
|
# [ WARNING ]
|
||||||
|
# Configuration file maintained by Juju. Local changes may be overwritten.
|
||||||
|
###############################################################################
|
||||||
|
# Metadata service seems to cache neutron api url from keystone so trigger
|
||||||
|
# restart if it changes: {{ quantum_url }}
|
||||||
|
|
||||||
|
[DEFAULT]
|
||||||
|
auth_url = {{ service_protocol }}://{{ service_host }}:{{ service_port }}/v2.0
|
||||||
|
auth_region = {{ region }}
|
||||||
|
admin_tenant_name = {{ admin_tenant_name }}
|
||||||
|
admin_user = {{ admin_user }}
|
||||||
|
admin_password = {{ admin_password }}
|
||||||
|
root_helper = sudo neutron-rootwrap /etc/neutron/rootwrap.conf
|
||||||
|
state_path = /var/lib/neutron
|
||||||
|
# Gateway runs a metadata API server locally
|
||||||
|
#nova_metadata_ip = {{ local_ip }}
|
||||||
|
nova_metadata_port = 8775
|
||||||
|
metadata_proxy_shared_secret = {{ shared_secret }}
|
||||||
|
cache_url = memory://?default_ttl=5
|
43
templates/juno/ml2_conf.ini
Normal file
43
templates/juno/ml2_conf.ini
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# juno
|
||||||
|
###############################################################################
|
||||||
|
# [ WARNING ]
|
||||||
|
# Configuration file maintained by Juju. Local changes may be overwritten.
|
||||||
|
# Config managed by neutron-openvswitch charm
|
||||||
|
###############################################################################
|
||||||
|
[ml2]
|
||||||
|
type_drivers = gre,vxlan,vlan,flat
|
||||||
|
tenant_network_types = gre,vxlan,vlan,flat
|
||||||
|
mechanism_drivers = openvswitch,hyperv,l2population
|
||||||
|
|
||||||
|
[ml2_type_gre]
|
||||||
|
tunnel_id_ranges = 1:1000
|
||||||
|
|
||||||
|
[ml2_type_vxlan]
|
||||||
|
vni_ranges = 1001:2000
|
||||||
|
|
||||||
|
[ml2_type_vlan]
|
||||||
|
network_vlan_ranges = {{ vlan_ranges }}
|
||||||
|
|
||||||
|
[ml2_type_flat]
|
||||||
|
flat_networks = {{ network_providers }}
|
||||||
|
|
||||||
|
[ovs]
|
||||||
|
enable_tunneling = True
|
||||||
|
local_ip = {{ local_ip }}
|
||||||
|
bridge_mappings = {{ bridge_mappings }}
|
||||||
|
|
||||||
|
[agent]
|
||||||
|
tunnel_types = {{ overlay_network_type }}
|
||||||
|
l2_population = {{ l2_population }}
|
||||||
|
enable_distributed_routing = {{ distributed_routing }}
|
||||||
|
{% if veth_mtu -%}
|
||||||
|
veth_mtu = {{ veth_mtu }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
[securitygroup]
|
||||||
|
{% if neutron_security_groups -%}
|
||||||
|
enable_security_group = True
|
||||||
|
firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver
|
||||||
|
{% else -%}
|
||||||
|
enable_security_group = False
|
||||||
|
{% endif -%}
|
8
templates/kilo/fwaas_driver.ini
Normal file
8
templates/kilo/fwaas_driver.ini
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# kilo
|
||||||
|
###############################################################################
|
||||||
|
# [ WARNING ]
|
||||||
|
# Configuration file maintained by Juju. Local changes may be overwritten.
|
||||||
|
###############################################################################
|
||||||
|
[fwaas]
|
||||||
|
driver = neutron_fwaas.services.firewall.drivers.linux.iptables_fwaas.IptablesFwaasDriver
|
||||||
|
enabled = True
|
@ -1,20 +1,26 @@
|
|||||||
|
|
||||||
from test_utils import CharmTestCase
|
from test_utils import CharmTestCase
|
||||||
|
from test_utils import patch_open
|
||||||
from mock import patch
|
from mock import patch
|
||||||
import neutron_ovs_context as context
|
import neutron_ovs_context as context
|
||||||
import charmhelpers
|
import charmhelpers
|
||||||
|
|
||||||
TO_PATCH = [
|
TO_PATCH = [
|
||||||
|
'resolve_address',
|
||||||
'config',
|
'config',
|
||||||
'unit_get',
|
'unit_get',
|
||||||
'add_bridge',
|
|
||||||
'add_bridge_port',
|
|
||||||
'service_running',
|
|
||||||
'service_start',
|
|
||||||
'service_restart',
|
|
||||||
'get_host_ip',
|
'get_host_ip',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def fake_context(settings):
|
||||||
|
def outer():
|
||||||
|
def inner():
|
||||||
|
return settings
|
||||||
|
return inner
|
||||||
|
return outer
|
||||||
|
|
||||||
|
|
||||||
class OVSPluginContextTest(CharmTestCase):
|
class OVSPluginContextTest(CharmTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -34,8 +40,10 @@ class OVSPluginContextTest(CharmTestCase):
|
|||||||
self.test_config.set('data-port', 'br-data:em1')
|
self.test_config.set('data-port', 'br-data:em1')
|
||||||
config.side_effect = self.test_config.get
|
config.side_effect = self.test_config.get
|
||||||
mock_resolve_ports.side_effect = lambda ports: ports
|
mock_resolve_ports.side_effect = lambda ports: ports
|
||||||
self.assertEquals(context.DataPortContext()(),
|
self.assertEquals(
|
||||||
{'br-data': 'em1'})
|
charmhelpers.contrib.openstack.context.DataPortContext()(),
|
||||||
|
{'br-data': 'em1'}
|
||||||
|
)
|
||||||
|
|
||||||
@patch('charmhelpers.contrib.openstack.context.config')
|
@patch('charmhelpers.contrib.openstack.context.config')
|
||||||
@patch('charmhelpers.contrib.openstack.context.get_nic_hwaddr')
|
@patch('charmhelpers.contrib.openstack.context.get_nic_hwaddr')
|
||||||
@ -52,28 +60,10 @@ class OVSPluginContextTest(CharmTestCase):
|
|||||||
config.side_effect = self.test_config.get
|
config.side_effect = self.test_config.get
|
||||||
list_nics.return_value = machine_machs.keys()
|
list_nics.return_value = machine_machs.keys()
|
||||||
get_nic_hwaddr.side_effect = lambda nic: machine_machs[nic]
|
get_nic_hwaddr.side_effect = lambda nic: machine_machs[nic]
|
||||||
self.assertEquals(context.DataPortContext()(),
|
self.assertEquals(
|
||||||
{'br-d2': 'em1'})
|
charmhelpers.contrib.openstack.context.DataPortContext()(),
|
||||||
|
{'br-d2': 'em1'}
|
||||||
@patch('charmhelpers.contrib.openstack.context.config')
|
)
|
||||||
@patch('charmhelpers.contrib.openstack.context.NeutronPortContext.'
|
|
||||||
'resolve_ports')
|
|
||||||
def test_ensure_bridge_data_port_present(self, mock_resolve_ports, config):
|
|
||||||
self.test_config.set('data-port', 'br-data:em1')
|
|
||||||
self.test_config.set('bridge-mappings', 'phybr1:br-data')
|
|
||||||
config.side_effect = self.test_config.get
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
@patch.object(charmhelpers.contrib.openstack.context, 'relation_get')
|
@patch.object(charmhelpers.contrib.openstack.context, 'relation_get')
|
||||||
@patch.object(charmhelpers.contrib.openstack.context, 'relation_ids')
|
@patch.object(charmhelpers.contrib.openstack.context, 'relation_ids')
|
||||||
@ -107,14 +97,15 @@ class OVSPluginContextTest(CharmTestCase):
|
|||||||
'l2-population': 'True',
|
'l2-population': 'True',
|
||||||
'network-device-mtu': 1500,
|
'network-device-mtu': 1500,
|
||||||
'overlay-network-type': 'gre',
|
'overlay-network-type': 'gre',
|
||||||
|
'enable-dvr': 'True',
|
||||||
}
|
}
|
||||||
_rget.side_effect = lambda *args, **kwargs: rdata
|
_rget.side_effect = lambda *args, **kwargs: rdata
|
||||||
self.get_host_ip.return_value = '127.0.0.15'
|
self.get_host_ip.return_value = '127.0.0.15'
|
||||||
self.service_running.return_value = False
|
|
||||||
napi_ctxt = context.OVSPluginContext()
|
napi_ctxt = context.OVSPluginContext()
|
||||||
expect = {
|
expect = {
|
||||||
'neutron_alchemy_flags': {},
|
'neutron_alchemy_flags': {},
|
||||||
'neutron_security_groups': True,
|
'neutron_security_groups': True,
|
||||||
|
'distributed_routing': True,
|
||||||
'verbose': True,
|
'verbose': True,
|
||||||
'local_ip': '127.0.0.15',
|
'local_ip': '127.0.0.15',
|
||||||
'network_device_mtu': 1500,
|
'network_device_mtu': 1500,
|
||||||
@ -133,7 +124,6 @@ class OVSPluginContextTest(CharmTestCase):
|
|||||||
'vlan_ranges': 'physnet1:1000:2000',
|
'vlan_ranges': 'physnet1:1000:2000',
|
||||||
}
|
}
|
||||||
self.assertEquals(expect, napi_ctxt())
|
self.assertEquals(expect, napi_ctxt())
|
||||||
self.service_start.assertCalled()
|
|
||||||
|
|
||||||
@patch.object(charmhelpers.contrib.openstack.context, 'relation_get')
|
@patch.object(charmhelpers.contrib.openstack.context, 'relation_get')
|
||||||
@patch.object(charmhelpers.contrib.openstack.context, 'relation_ids')
|
@patch.object(charmhelpers.contrib.openstack.context, 'relation_ids')
|
||||||
@ -176,9 +166,9 @@ class OVSPluginContextTest(CharmTestCase):
|
|||||||
}
|
}
|
||||||
_rget.side_effect = lambda *args, **kwargs: rdata
|
_rget.side_effect = lambda *args, **kwargs: rdata
|
||||||
self.get_host_ip.return_value = '127.0.0.15'
|
self.get_host_ip.return_value = '127.0.0.15'
|
||||||
self.service_running.return_value = False
|
|
||||||
napi_ctxt = context.OVSPluginContext()
|
napi_ctxt = context.OVSPluginContext()
|
||||||
expect = {
|
expect = {
|
||||||
|
'distributed_routing': False,
|
||||||
'neutron_alchemy_flags': {},
|
'neutron_alchemy_flags': {},
|
||||||
'neutron_security_groups': False,
|
'neutron_security_groups': False,
|
||||||
'verbose': True,
|
'verbose': True,
|
||||||
@ -199,4 +189,95 @@ class OVSPluginContextTest(CharmTestCase):
|
|||||||
'vlan_ranges': 'physnet1:1000:2000',
|
'vlan_ranges': 'physnet1:1000:2000',
|
||||||
}
|
}
|
||||||
self.assertEquals(expect, napi_ctxt())
|
self.assertEquals(expect, napi_ctxt())
|
||||||
self.service_start.assertCalled()
|
|
||||||
|
|
||||||
|
class L3AgentContextTest(CharmTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(L3AgentContextTest, self).setUp(context, TO_PATCH)
|
||||||
|
self.config.side_effect = self.test_config.get
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
super(L3AgentContextTest, self).tearDown()
|
||||||
|
|
||||||
|
@patch.object(charmhelpers.contrib.openstack.context, 'relation_get')
|
||||||
|
@patch.object(charmhelpers.contrib.openstack.context, 'relation_ids')
|
||||||
|
@patch.object(charmhelpers.contrib.openstack.context, 'related_units')
|
||||||
|
def test_dvr_enabled(self, _runits, _rids, _rget):
|
||||||
|
_runits.return_value = ['unit1']
|
||||||
|
_rids.return_value = ['rid2']
|
||||||
|
rdata = {
|
||||||
|
'neutron-security-groups': 'True',
|
||||||
|
'enable-dvr': 'True',
|
||||||
|
'l2-population': 'True',
|
||||||
|
'overlay-network-type': 'vxlan',
|
||||||
|
'network-device-mtu': 1500,
|
||||||
|
}
|
||||||
|
_rget.side_effect = lambda *args, **kwargs: rdata
|
||||||
|
self.assertEquals(context.L3AgentContext()(), {'agent_mode': 'dvr'})
|
||||||
|
|
||||||
|
@patch.object(charmhelpers.contrib.openstack.context, 'relation_get')
|
||||||
|
@patch.object(charmhelpers.contrib.openstack.context, 'relation_ids')
|
||||||
|
@patch.object(charmhelpers.contrib.openstack.context, 'related_units')
|
||||||
|
def test_dvr_disabled(self, _runits, _rids, _rget):
|
||||||
|
_runits.return_value = ['unit1']
|
||||||
|
_rids.return_value = ['rid2']
|
||||||
|
rdata = {
|
||||||
|
'neutron-security-groups': 'True',
|
||||||
|
'enable-dvr': 'False',
|
||||||
|
'l2-population': 'True',
|
||||||
|
'overlay-network-type': 'vxlan',
|
||||||
|
'network-device-mtu': 1500,
|
||||||
|
}
|
||||||
|
_rget.side_effect = lambda *args, **kwargs: rdata
|
||||||
|
self.assertEquals(context.L3AgentContext()(), {'agent_mode': 'legacy'})
|
||||||
|
|
||||||
|
|
||||||
|
class DVRSharedSecretContext(CharmTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(DVRSharedSecretContext, self).setUp(context,
|
||||||
|
TO_PATCH)
|
||||||
|
self.config.side_effect = self.test_config.get
|
||||||
|
|
||||||
|
@patch('os.path')
|
||||||
|
@patch('uuid.uuid4')
|
||||||
|
def test_secret_created_stored(self, _uuid4, _path):
|
||||||
|
_path.exists.return_value = False
|
||||||
|
_uuid4.return_value = 'secret_thing'
|
||||||
|
with patch_open() as (_open, _file):
|
||||||
|
self.assertEquals(context.get_shared_secret(),
|
||||||
|
'secret_thing')
|
||||||
|
_open.assert_called_with(
|
||||||
|
context.SHARED_SECRET.format('quantum'), 'w')
|
||||||
|
_file.write.assert_called_with('secret_thing')
|
||||||
|
|
||||||
|
@patch('os.path')
|
||||||
|
def test_secret_retrieved(self, _path):
|
||||||
|
_path.exists.return_value = True
|
||||||
|
with patch_open() as (_open, _file):
|
||||||
|
_file.read.return_value = 'secret_thing\n'
|
||||||
|
self.assertEquals(context.get_shared_secret(),
|
||||||
|
'secret_thing')
|
||||||
|
_open.assert_called_with(
|
||||||
|
context.SHARED_SECRET.format('quantum'), 'r')
|
||||||
|
|
||||||
|
@patch.object(context, 'NeutronAPIContext')
|
||||||
|
@patch.object(context, 'get_shared_secret')
|
||||||
|
def test_shared_secretcontext_dvr(self, _shared_secret,
|
||||||
|
_NeutronAPIContext):
|
||||||
|
_NeutronAPIContext.side_effect = fake_context({'enable_dvr': True})
|
||||||
|
_shared_secret.return_value = 'secret_thing'
|
||||||
|
self.resolve_address.return_value = '10.0.0.10'
|
||||||
|
self.assertEquals(context.DVRSharedSecretContext()(),
|
||||||
|
{'shared_secret': 'secret_thing',
|
||||||
|
'local_ip': '10.0.0.10'})
|
||||||
|
|
||||||
|
@patch.object(context, 'NeutronAPIContext')
|
||||||
|
@patch.object(context, 'get_shared_secret')
|
||||||
|
def test_shared_secretcontext_nodvr(self, _shared_secret,
|
||||||
|
_NeutronAPIContext):
|
||||||
|
_NeutronAPIContext.side_effect = fake_context({'enable_dvr': False})
|
||||||
|
_shared_secret.return_value = 'secret_thing'
|
||||||
|
self.resolve_address.return_value = '10.0.0.10'
|
||||||
|
self.assertEquals(context.DVRSharedSecretContext()(), {})
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
from mock import MagicMock, patch, call
|
from mock import MagicMock, patch, call
|
||||||
from test_utils import CharmTestCase
|
from test_utils import CharmTestCase
|
||||||
|
|
||||||
|
|
||||||
with patch('charmhelpers.core.hookenv.config') as config:
|
with patch('charmhelpers.core.hookenv.config') as config:
|
||||||
config.return_value = 'neutron'
|
config.return_value = 'neutron'
|
||||||
import neutron_ovs_utils as utils
|
import neutron_ovs_utils as utils
|
||||||
@ -21,11 +20,17 @@ utils.restart_map = _map
|
|||||||
TO_PATCH = [
|
TO_PATCH = [
|
||||||
'apt_update',
|
'apt_update',
|
||||||
'apt_install',
|
'apt_install',
|
||||||
|
'apt_purge',
|
||||||
'config',
|
'config',
|
||||||
'CONFIGS',
|
'CONFIGS',
|
||||||
'determine_packages',
|
'determine_packages',
|
||||||
|
'determine_dvr_packages',
|
||||||
|
'get_shared_secret',
|
||||||
'log',
|
'log',
|
||||||
|
'relation_ids',
|
||||||
'relation_set',
|
'relation_set',
|
||||||
|
'configure_ovs',
|
||||||
|
'use_dvr',
|
||||||
]
|
]
|
||||||
NEUTRON_CONF_DIR = "/etc/neutron"
|
NEUTRON_CONF_DIR = "/etc/neutron"
|
||||||
|
|
||||||
@ -56,6 +61,36 @@ class NeutronOVSHooksTests(CharmTestCase):
|
|||||||
def test_config_changed(self):
|
def test_config_changed(self):
|
||||||
self._call_hook('config-changed')
|
self._call_hook('config-changed')
|
||||||
self.assertTrue(self.CONFIGS.write_all.called)
|
self.assertTrue(self.CONFIGS.write_all.called)
|
||||||
|
self.configure_ovs.assert_called_with()
|
||||||
|
|
||||||
|
def test_config_changed_dvr(self):
|
||||||
|
self.determine_dvr_packages.return_value = ['dvr']
|
||||||
|
self._call_hook('config-changed')
|
||||||
|
self.apt_update.assert_called_with()
|
||||||
|
self.assertTrue(self.CONFIGS.write_all.called)
|
||||||
|
self.apt_install.assert_has_calls([
|
||||||
|
call(['dvr'], fatal=True),
|
||||||
|
])
|
||||||
|
self.configure_ovs.assert_called_with()
|
||||||
|
|
||||||
|
@patch.object(hooks, 'neutron_plugin_joined')
|
||||||
|
def test_neutron_plugin_api(self, _plugin_joined):
|
||||||
|
self.relation_ids.return_value = ['rid']
|
||||||
|
self._call_hook('neutron-plugin-api-relation-changed')
|
||||||
|
self.configure_ovs.assert_called_with()
|
||||||
|
self.assertTrue(self.CONFIGS.write_all.called)
|
||||||
|
_plugin_joined.assert_called_with(relation_id='rid')
|
||||||
|
|
||||||
|
def test_neutron_plugin_joined(self):
|
||||||
|
self.get_shared_secret.return_value = 'secret'
|
||||||
|
self._call_hook('neutron-plugin-relation-joined')
|
||||||
|
rel_data = {
|
||||||
|
'metadata-shared-secret': 'secret',
|
||||||
|
}
|
||||||
|
self.relation_set.assert_called_with(
|
||||||
|
relation_id=None,
|
||||||
|
**rel_data
|
||||||
|
)
|
||||||
|
|
||||||
def test_amqp_joined(self):
|
def test_amqp_joined(self):
|
||||||
self._call_hook('amqp-relation-joined')
|
self._call_hook('amqp-relation-joined')
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
|
|
||||||
from mock import MagicMock, patch
|
from mock import MagicMock, patch, call
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import charmhelpers.contrib.openstack.templating as templating
|
import charmhelpers.contrib.openstack.templating as templating
|
||||||
|
|
||||||
templating.OSConfigRenderer = MagicMock()
|
templating.OSConfigRenderer = MagicMock()
|
||||||
|
|
||||||
import neutron_ovs_utils as nutils
|
import neutron_ovs_utils as nutils
|
||||||
|
import neutron_ovs_context
|
||||||
|
|
||||||
from test_utils import (
|
from test_utils import (
|
||||||
CharmTestCase,
|
CharmTestCase,
|
||||||
@ -15,8 +16,15 @@ import charmhelpers.core.hookenv as hookenv
|
|||||||
|
|
||||||
|
|
||||||
TO_PATCH = [
|
TO_PATCH = [
|
||||||
|
'add_bridge',
|
||||||
|
'add_bridge_port',
|
||||||
|
'config',
|
||||||
'os_release',
|
'os_release',
|
||||||
'neutron_plugin_attribute',
|
'neutron_plugin_attribute',
|
||||||
|
'full_restart',
|
||||||
|
'service_restart',
|
||||||
|
'service_running',
|
||||||
|
'ExternalPortContext',
|
||||||
]
|
]
|
||||||
|
|
||||||
head_pkg = 'linux-headers-3.15.0-5-generic'
|
head_pkg = 'linux-headers-3.15.0-5-generic'
|
||||||
@ -38,26 +46,39 @@ def _mock_npa(plugin, attr, net_manager=None):
|
|||||||
return plugins[plugin][attr]
|
return plugins[plugin][attr]
|
||||||
|
|
||||||
|
|
||||||
|
class DummyContext():
|
||||||
|
|
||||||
|
def __init__(self, return_value):
|
||||||
|
self.return_value = return_value
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
return self.return_value
|
||||||
|
|
||||||
|
|
||||||
class TestNeutronOVSUtils(CharmTestCase):
|
class TestNeutronOVSUtils(CharmTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestNeutronOVSUtils, self).setUp(nutils, TO_PATCH)
|
super(TestNeutronOVSUtils, self).setUp(nutils, TO_PATCH)
|
||||||
self.neutron_plugin_attribute.side_effect = _mock_npa
|
self.neutron_plugin_attribute.side_effect = _mock_npa
|
||||||
|
self.config.side_effect = self.test_config.get
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
# Reset cached cache
|
# Reset cached cache
|
||||||
hookenv.cache = {}
|
hookenv.cache = {}
|
||||||
|
|
||||||
|
@patch.object(nutils, 'use_dvr')
|
||||||
@patch.object(charmhelpers.contrib.openstack.neutron, 'os_release')
|
@patch.object(charmhelpers.contrib.openstack.neutron, 'os_release')
|
||||||
@patch.object(charmhelpers.contrib.openstack.neutron, 'headers_package')
|
@patch.object(charmhelpers.contrib.openstack.neutron, 'headers_package')
|
||||||
def test_determine_packages(self, _head_pkgs, _os_rel):
|
def test_determine_packages(self, _head_pkgs, _os_rel, _use_dvr):
|
||||||
|
_use_dvr.return_value = False
|
||||||
_os_rel.return_value = 'trusty'
|
_os_rel.return_value = 'trusty'
|
||||||
_head_pkgs.return_value = head_pkg
|
_head_pkgs.return_value = head_pkg
|
||||||
pkg_list = nutils.determine_packages()
|
pkg_list = nutils.determine_packages()
|
||||||
expect = [['neutron-plugin-openvswitch-agent'], [head_pkg]]
|
expect = [['neutron-plugin-openvswitch-agent'], [head_pkg]]
|
||||||
self.assertItemsEqual(pkg_list, expect)
|
self.assertItemsEqual(pkg_list, expect)
|
||||||
|
|
||||||
def test_register_configs(self):
|
@patch.object(nutils, 'use_dvr')
|
||||||
|
def test_register_configs(self, _use_dvr):
|
||||||
class _mock_OSConfigRenderer():
|
class _mock_OSConfigRenderer():
|
||||||
def __init__(self, templates_dir=None, openstack_release=None):
|
def __init__(self, templates_dir=None, openstack_release=None):
|
||||||
self.configs = []
|
self.configs = []
|
||||||
@ -67,6 +88,7 @@ class TestNeutronOVSUtils(CharmTestCase):
|
|||||||
self.configs.append(config)
|
self.configs.append(config)
|
||||||
self.ctxts.append(ctxt)
|
self.ctxts.append(ctxt)
|
||||||
|
|
||||||
|
_use_dvr.return_value = False
|
||||||
self.os_release.return_value = 'trusty'
|
self.os_release.return_value = 'trusty'
|
||||||
templating.OSConfigRenderer.side_effect = _mock_OSConfigRenderer
|
templating.OSConfigRenderer.side_effect = _mock_OSConfigRenderer
|
||||||
_regconfs = nutils.register_configs()
|
_regconfs = nutils.register_configs()
|
||||||
@ -75,12 +97,28 @@ class TestNeutronOVSUtils(CharmTestCase):
|
|||||||
'/etc/init/os-charm-phy-nic-mtu.conf']
|
'/etc/init/os-charm-phy-nic-mtu.conf']
|
||||||
self.assertItemsEqual(_regconfs.configs, confs)
|
self.assertItemsEqual(_regconfs.configs, confs)
|
||||||
|
|
||||||
def test_resource_map(self):
|
@patch.object(nutils, 'use_dvr')
|
||||||
|
def test_resource_map(self, _use_dvr):
|
||||||
|
_use_dvr.return_value = False
|
||||||
_map = nutils.resource_map()
|
_map = nutils.resource_map()
|
||||||
|
svcs = ['neutron-plugin-openvswitch-agent']
|
||||||
confs = [nutils.NEUTRON_CONF]
|
confs = [nutils.NEUTRON_CONF]
|
||||||
[self.assertIn(q_conf, _map.keys()) for q_conf in confs]
|
[self.assertIn(q_conf, _map.keys()) for q_conf in confs]
|
||||||
|
self.assertEqual(_map[nutils.NEUTRON_CONF]['services'], svcs)
|
||||||
|
|
||||||
def test_restart_map(self):
|
@patch.object(nutils, 'use_dvr')
|
||||||
|
def test_resource_map_dvr(self, _use_dvr):
|
||||||
|
_use_dvr.return_value = True
|
||||||
|
_map = nutils.resource_map()
|
||||||
|
svcs = ['neutron-plugin-openvswitch-agent', 'neutron-metadata-agent',
|
||||||
|
'neutron-l3-agent']
|
||||||
|
confs = [nutils.NEUTRON_CONF]
|
||||||
|
[self.assertIn(q_conf, _map.keys()) for q_conf in confs]
|
||||||
|
self.assertEqual(_map[nutils.NEUTRON_CONF]['services'], svcs)
|
||||||
|
|
||||||
|
@patch.object(nutils, 'use_dvr')
|
||||||
|
def test_restart_map(self, _use_dvr):
|
||||||
|
_use_dvr.return_value = False
|
||||||
_restart_map = nutils.restart_map()
|
_restart_map = nutils.restart_map()
|
||||||
ML2CONF = "/etc/neutron/plugins/ml2/ml2_conf.ini"
|
ML2CONF = "/etc/neutron/plugins/ml2/ml2_conf.ini"
|
||||||
expect = OrderedDict([
|
expect = OrderedDict([
|
||||||
@ -92,3 +130,79 @@ class TestNeutronOVSUtils(CharmTestCase):
|
|||||||
for item in _restart_map:
|
for item in _restart_map:
|
||||||
self.assertTrue(item in _restart_map)
|
self.assertTrue(item in _restart_map)
|
||||||
self.assertTrue(expect[item] == _restart_map[item])
|
self.assertTrue(expect[item] == _restart_map[item])
|
||||||
|
|
||||||
|
@patch.object(nutils, 'use_dvr')
|
||||||
|
@patch('charmhelpers.contrib.openstack.context.config')
|
||||||
|
def test_configure_ovs_ovs_data_port(self, mock_config, _use_dvr):
|
||||||
|
_use_dvr.return_value = False
|
||||||
|
mock_config.side_effect = self.test_config.get
|
||||||
|
self.config.side_effect = self.test_config.get
|
||||||
|
self.ExternalPortContext.return_value = \
|
||||||
|
DummyContext(return_value=None)
|
||||||
|
# Test back-compatibility i.e. port but no bridge (so br-data is
|
||||||
|
# assumed)
|
||||||
|
self.test_config.set('data-port', 'eth0')
|
||||||
|
nutils.configure_ovs()
|
||||||
|
self.add_bridge.assert_has_calls([
|
||||||
|
call('br-int'),
|
||||||
|
call('br-ex'),
|
||||||
|
call('br-data')
|
||||||
|
])
|
||||||
|
self.assertTrue(self.add_bridge_port.called)
|
||||||
|
|
||||||
|
# Now test with bridge:port format
|
||||||
|
self.test_config.set('data-port', 'br-foo:eth0')
|
||||||
|
self.add_bridge.reset_mock()
|
||||||
|
self.add_bridge_port.reset_mock()
|
||||||
|
nutils.configure_ovs()
|
||||||
|
self.add_bridge.assert_has_calls([
|
||||||
|
call('br-int'),
|
||||||
|
call('br-ex'),
|
||||||
|
call('br-data')
|
||||||
|
])
|
||||||
|
# Not called since we have a bogus bridge in data-ports
|
||||||
|
self.assertFalse(self.add_bridge_port.called)
|
||||||
|
|
||||||
|
@patch.object(nutils, 'use_dvr')
|
||||||
|
@patch('charmhelpers.contrib.openstack.context.config')
|
||||||
|
def test_configure_ovs_starts_service_if_required(self, mock_config,
|
||||||
|
_use_dvr):
|
||||||
|
_use_dvr.return_value = False
|
||||||
|
mock_config.side_effect = self.test_config.get
|
||||||
|
self.config.return_value = 'ovs'
|
||||||
|
self.service_running.return_value = False
|
||||||
|
nutils.configure_ovs()
|
||||||
|
self.assertTrue(self.full_restart.called)
|
||||||
|
|
||||||
|
@patch.object(nutils, 'use_dvr')
|
||||||
|
@patch('charmhelpers.contrib.openstack.context.config')
|
||||||
|
def test_configure_ovs_doesnt_restart_service(self, mock_config, _use_dvr):
|
||||||
|
_use_dvr.return_value = False
|
||||||
|
mock_config.side_effect = self.test_config.get
|
||||||
|
self.config.side_effect = self.test_config.get
|
||||||
|
self.service_running.return_value = True
|
||||||
|
nutils.configure_ovs()
|
||||||
|
self.assertFalse(self.full_restart.called)
|
||||||
|
|
||||||
|
@patch.object(nutils, 'use_dvr')
|
||||||
|
@patch('charmhelpers.contrib.openstack.context.config')
|
||||||
|
def test_configure_ovs_ovs_ext_port(self, mock_config, _use_dvr):
|
||||||
|
_use_dvr.return_value = True
|
||||||
|
mock_config.side_effect = self.test_config.get
|
||||||
|
self.config.side_effect = self.test_config.get
|
||||||
|
self.test_config.set('ext-port', 'eth0')
|
||||||
|
self.ExternalPortContext.return_value = \
|
||||||
|
DummyContext(return_value={'ext_port': 'eth0'})
|
||||||
|
nutils.configure_ovs()
|
||||||
|
self.add_bridge.assert_has_calls([
|
||||||
|
call('br-int'),
|
||||||
|
call('br-ex'),
|
||||||
|
call('br-data')
|
||||||
|
])
|
||||||
|
self.add_bridge_port.assert_called_with('br-ex', 'eth0')
|
||||||
|
|
||||||
|
@patch.object(neutron_ovs_context, 'DVRSharedSecretContext')
|
||||||
|
def test_get_shared_secret(self, _dvr_secret_ctxt):
|
||||||
|
_dvr_secret_ctxt.return_value = \
|
||||||
|
DummyContext(return_value={'shared_secret': 'supersecret'})
|
||||||
|
self.assertEqual(nutils.get_shared_secret(), 'supersecret')
|
||||||
|
Loading…
Reference in New Issue
Block a user