Rebase, resync
This commit is contained in:
commit
300247b84a
17
config.yaml
17
config.yaml
@ -25,8 +25,10 @@ options:
|
|||||||
type: string
|
type: string
|
||||||
default:
|
default:
|
||||||
description: |
|
description: |
|
||||||
The data port will be added to br-data and will allow usage of flat or VLAN
|
Space-delimited list of bridge:port mappings. Ports will be added to
|
||||||
network types
|
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:
|
disable-security-groups:
|
||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
@ -36,6 +38,17 @@ options:
|
|||||||
.
|
.
|
||||||
BE CAREFUL - this option allows you to disable all port level security within
|
BE CAREFUL - this option allows you to disable all port level security within
|
||||||
an OpenStack cloud.
|
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
|
# Network configuration options
|
||||||
# by default all access is over 'private-address'
|
# by default all access is over 'private-address'
|
||||||
os-data-network:
|
os-data-network:
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
# along with charm-helpers. If not, see <http://www.gnu.org/licenses/>.
|
# along with charm-helpers. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
from collections import OrderedDict
|
||||||
from charmhelpers.contrib.amulet.deployment import (
|
from charmhelpers.contrib.amulet.deployment import (
|
||||||
AmuletDeployment
|
AmuletDeployment
|
||||||
)
|
)
|
||||||
@ -100,12 +101,34 @@ class OpenStackAmuletDeployment(AmuletDeployment):
|
|||||||
"""
|
"""
|
||||||
(self.precise_essex, self.precise_folsom, self.precise_grizzly,
|
(self.precise_essex, self.precise_folsom, self.precise_grizzly,
|
||||||
self.precise_havana, self.precise_icehouse,
|
self.precise_havana, self.precise_icehouse,
|
||||||
self.trusty_icehouse) = range(6)
|
self.trusty_icehouse, self.trusty_juno, self.trusty_kilo) = range(8)
|
||||||
releases = {
|
releases = {
|
||||||
('precise', None): self.precise_essex,
|
('precise', None): self.precise_essex,
|
||||||
('precise', 'cloud:precise-folsom'): self.precise_folsom,
|
('precise', 'cloud:precise-folsom'): self.precise_folsom,
|
||||||
('precise', 'cloud:precise-grizzly'): self.precise_grizzly,
|
('precise', 'cloud:precise-grizzly'): self.precise_grizzly,
|
||||||
('precise', 'cloud:precise-havana'): self.precise_havana,
|
('precise', 'cloud:precise-havana'): self.precise_havana,
|
||||||
('precise', 'cloud:precise-icehouse'): self.precise_icehouse,
|
('precise', 'cloud:precise-icehouse'): self.precise_icehouse,
|
||||||
('trusty', None): self.trusty_icehouse}
|
('trusty', None): self.trusty_icehouse,
|
||||||
|
('trusty', 'cloud:trusty-juno'): self.trusty_juno,
|
||||||
|
('trusty', 'cloud:trusty-kilo'): self.trusty_kilo}
|
||||||
return releases[(self.series, self.openstack)]
|
return releases[(self.series, self.openstack)]
|
||||||
|
|
||||||
|
def _get_openstack_release_string(self):
|
||||||
|
"""Get openstack release string.
|
||||||
|
|
||||||
|
Return a string representing the openstack release.
|
||||||
|
"""
|
||||||
|
releases = OrderedDict([
|
||||||
|
('precise', 'essex'),
|
||||||
|
('quantal', 'folsom'),
|
||||||
|
('raring', 'grizzly'),
|
||||||
|
('saucy', 'havana'),
|
||||||
|
('trusty', 'icehouse'),
|
||||||
|
('utopic', 'juno'),
|
||||||
|
('vivid', 'kilo'),
|
||||||
|
])
|
||||||
|
if self.openstack:
|
||||||
|
os_origin = self.openstack.split(':')[1]
|
||||||
|
return os_origin.split('%s-' % self.series)[1].split('/')[0]
|
||||||
|
else:
|
||||||
|
return releases[self.series]
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import time
|
import time
|
||||||
from base64 import b64decode
|
from base64 import b64decode
|
||||||
from subprocess import check_call
|
from subprocess import check_call
|
||||||
@ -46,8 +47,11 @@ from charmhelpers.core.hookenv import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from charmhelpers.core.sysctl import create as sysctl_create
|
from charmhelpers.core.sysctl import create as sysctl_create
|
||||||
|
from charmhelpers.core.strutils import bool_from_string
|
||||||
|
|
||||||
from charmhelpers.core.host import (
|
from charmhelpers.core.host import (
|
||||||
|
list_nics,
|
||||||
|
get_nic_hwaddr,
|
||||||
mkdir,
|
mkdir,
|
||||||
write_file,
|
write_file,
|
||||||
)
|
)
|
||||||
@ -64,16 +68,22 @@ from charmhelpers.contrib.hahelpers.apache import (
|
|||||||
)
|
)
|
||||||
from charmhelpers.contrib.openstack.neutron import (
|
from charmhelpers.contrib.openstack.neutron import (
|
||||||
neutron_plugin_attribute,
|
neutron_plugin_attribute,
|
||||||
|
parse_data_port_mappings,
|
||||||
|
)
|
||||||
|
from charmhelpers.contrib.openstack.ip import (
|
||||||
|
resolve_address,
|
||||||
|
INTERNAL,
|
||||||
)
|
)
|
||||||
from charmhelpers.contrib.network.ip import (
|
from charmhelpers.contrib.network.ip import (
|
||||||
get_address_in_network,
|
get_address_in_network,
|
||||||
|
get_ipv4_addr,
|
||||||
get_ipv6_addr,
|
get_ipv6_addr,
|
||||||
get_netmask_for_address,
|
get_netmask_for_address,
|
||||||
format_ipv6_addr,
|
format_ipv6_addr,
|
||||||
is_address_in_network,
|
is_address_in_network,
|
||||||
|
is_bridge_member,
|
||||||
)
|
)
|
||||||
from charmhelpers.contrib.openstack.utils import get_host_ip
|
from charmhelpers.contrib.openstack.utils import get_host_ip
|
||||||
|
|
||||||
CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt'
|
CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt'
|
||||||
ADDRESS_TYPES = ['admin', 'internal', 'public']
|
ADDRESS_TYPES = ['admin', 'internal', 'public']
|
||||||
|
|
||||||
@ -727,7 +737,14 @@ class ApacheSSLContext(OSContextGenerator):
|
|||||||
'endpoints': [],
|
'endpoints': [],
|
||||||
'ext_ports': []}
|
'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)
|
self.configure_cert(cn)
|
||||||
|
|
||||||
addresses = self.get_network_addresses()
|
addresses = self.get_network_addresses()
|
||||||
@ -883,6 +900,48 @@ class NeutronContext(OSContextGenerator):
|
|||||||
return ctxt
|
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):
|
class OSConfigFlagContext(OSContextGenerator):
|
||||||
"""Provides support for user-defined config flags.
|
"""Provides support for user-defined config flags.
|
||||||
|
|
||||||
@ -1104,3 +1163,145 @@ class SysctlContext(OSContextGenerator):
|
|||||||
sysctl_create(sysctl_dict,
|
sysctl_create(sysctl_dict,
|
||||||
'/etc/sysctl.d/50-{0}.conf'.format(charm_name()))
|
'/etc/sysctl.d/50-{0}.conf'.format(charm_name()))
|
||||||
return {'sysctl': sysctl_dict}
|
return {'sysctl': sysctl_dict}
|
||||||
|
|
||||||
|
|
||||||
|
class NeutronAPIContext(OSContextGenerator):
|
||||||
|
'''
|
||||||
|
Inspects current neutron-plugin-api relation for neutron settings. Return
|
||||||
|
defaults if it is not present.
|
||||||
|
'''
|
||||||
|
interfaces = ['neutron-plugin-api']
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
self.neutron_defaults = {
|
||||||
|
'l2_population': {
|
||||||
|
'rel_key': 'l2-population',
|
||||||
|
'default': False,
|
||||||
|
},
|
||||||
|
'overlay_network_type': {
|
||||||
|
'rel_key': 'overlay-network-type',
|
||||||
|
'default': 'gre',
|
||||||
|
},
|
||||||
|
'neutron_security_groups': {
|
||||||
|
'rel_key': 'neutron-security-groups',
|
||||||
|
'default': False,
|
||||||
|
},
|
||||||
|
'network_device_mtu': {
|
||||||
|
'rel_key': 'network-device-mtu',
|
||||||
|
'default': None,
|
||||||
|
},
|
||||||
|
'enable_dvr': {
|
||||||
|
'rel_key': 'enable-dvr',
|
||||||
|
'default': False,
|
||||||
|
},
|
||||||
|
'enable_l3ha': {
|
||||||
|
'rel_key': 'enable-l3ha',
|
||||||
|
'default': False,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ctxt = self.get_neutron_options({})
|
||||||
|
for rid in relation_ids('neutron-plugin-api'):
|
||||||
|
for unit in related_units(rid):
|
||||||
|
rdata = relation_get(rid=rid, unit=unit)
|
||||||
|
if 'l2-population' in rdata:
|
||||||
|
ctxt.update(self.get_neutron_options(rdata))
|
||||||
|
|
||||||
|
return ctxt
|
||||||
|
|
||||||
|
def get_neutron_options(self, rdata):
|
||||||
|
settings = {}
|
||||||
|
for nkey in self.neutron_defaults.keys():
|
||||||
|
defv = self.neutron_defaults[nkey]['default']
|
||||||
|
rkey = self.neutron_defaults[nkey]['rel_key']
|
||||||
|
if rkey in rdata.keys():
|
||||||
|
if type(defv) is bool:
|
||||||
|
settings[nkey] = bool_from_string(rdata[rkey])
|
||||||
|
else:
|
||||||
|
settings[nkey] = rdata[rkey]
|
||||||
|
else:
|
||||||
|
settings[nkey] = defv
|
||||||
|
return settings
|
||||||
|
|
||||||
|
|
||||||
|
class ExternalPortContext(NeutronPortContext):
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
ctxt = {}
|
||||||
|
ports = config('ext-port')
|
||||||
|
if ports:
|
||||||
|
ports = [p.strip() for p in ports.split()]
|
||||||
|
ports = self.resolve_ports(ports)
|
||||||
|
if ports:
|
||||||
|
ctxt = {"ext_port": ports[0]}
|
||||||
|
napi_settings = NeutronAPIContext()()
|
||||||
|
mtu = napi_settings.get('network_device_mtu')
|
||||||
|
if mtu:
|
||||||
|
ctxt['ext_port_mtu'] = mtu
|
||||||
|
|
||||||
|
return ctxt
|
||||||
|
|
||||||
|
|
||||||
|
class DataPortContext(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
|
||||||
|
six.iteritems(portmap) if port in normalized.keys()}
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class PhyNICMTUContext(DataPortContext):
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
ctxt = {}
|
||||||
|
mappings = super(PhyNICMTUContext, self).__call__()
|
||||||
|
if mappings and mappings.values():
|
||||||
|
ports = mappings.values()
|
||||||
|
napi_settings = NeutronAPIContext()()
|
||||||
|
mtu = napi_settings.get('network_device_mtu')
|
||||||
|
if mtu:
|
||||||
|
ctxt["devs"] = '\\n'.join(ports)
|
||||||
|
ctxt['mtu'] = mtu
|
||||||
|
|
||||||
|
return ctxt
|
||||||
|
|
||||||
|
|
||||||
|
class NetworkServiceContext(OSContextGenerator):
|
||||||
|
|
||||||
|
def __init__(self, rel_name='quantum-network-service'):
|
||||||
|
self.rel_name = rel_name
|
||||||
|
self.interfaces = [rel_name]
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
for rid in relation_ids(self.rel_name):
|
||||||
|
for unit in related_units(rid):
|
||||||
|
rdata = relation_get(rid=rid, unit=unit)
|
||||||
|
ctxt = {
|
||||||
|
'keystone_host': rdata.get('keystone_host'),
|
||||||
|
'service_port': rdata.get('service_port'),
|
||||||
|
'auth_port': rdata.get('auth_port'),
|
||||||
|
'service_tenant': rdata.get('service_tenant'),
|
||||||
|
'service_username': rdata.get('service_username'),
|
||||||
|
'service_password': rdata.get('service_password'),
|
||||||
|
'quantum_host': rdata.get('quantum_host'),
|
||||||
|
'quantum_port': rdata.get('quantum_port'),
|
||||||
|
'quantum_url': rdata.get('quantum_url'),
|
||||||
|
'region': rdata.get('region'),
|
||||||
|
'service_protocol':
|
||||||
|
rdata.get('service_protocol') or 'http',
|
||||||
|
'auth_protocol':
|
||||||
|
rdata.get('auth_protocol') or 'http',
|
||||||
|
}
|
||||||
|
if context_complete(ctxt):
|
||||||
|
return ctxt
|
||||||
|
return {}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
# Various utilies for dealing with Neutron and the renaming from Quantum.
|
# Various utilies for dealing with Neutron and the renaming from Quantum.
|
||||||
|
|
||||||
|
import six
|
||||||
from subprocess import check_output
|
from subprocess import check_output
|
||||||
|
|
||||||
from charmhelpers.core.hookenv import (
|
from charmhelpers.core.hookenv import (
|
||||||
@ -237,3 +238,72 @@ def network_manager():
|
|||||||
else:
|
else:
|
||||||
# ensure accurate naming for all releases post-H
|
# ensure accurate naming for all releases post-H
|
||||||
return 'neutron'
|
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
|
||||||
|
13
hooks/charmhelpers/contrib/openstack/templates/git.upstart
Normal file
13
hooks/charmhelpers/contrib/openstack/templates/git.upstart
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
description "{{ service_description }}"
|
||||||
|
author "Juju {{ service_name }} Charm <juju@localhost>"
|
||||||
|
|
||||||
|
start on runlevel [2345]
|
||||||
|
stop on runlevel [!2345]
|
||||||
|
|
||||||
|
respawn
|
||||||
|
|
||||||
|
exec start-stop-daemon --start --chuid {{ user_name }} \
|
||||||
|
--chdir {{ start_dir }} --name {{ process_name }} \
|
||||||
|
--exec {{ executable_name }} -- \
|
||||||
|
--config-file={{ config_file }} \
|
||||||
|
--log-file={{ log_file }}
|
@ -0,0 +1,9 @@
|
|||||||
|
{% if auth_host -%}
|
||||||
|
[keystone_authtoken]
|
||||||
|
identity_uri = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/{{ auth_admin_prefix }}
|
||||||
|
auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }}/{{ service_admin_prefix }}
|
||||||
|
admin_tenant_name = {{ admin_tenant_name }}
|
||||||
|
admin_user = {{ admin_user }}
|
||||||
|
admin_password = {{ admin_password }}
|
||||||
|
signing_dir = {{ signing_dir }}
|
||||||
|
{% endif -%}
|
@ -0,0 +1,22 @@
|
|||||||
|
{% if rabbitmq_host or rabbitmq_hosts -%}
|
||||||
|
[oslo_messaging_rabbit]
|
||||||
|
rabbit_userid = {{ rabbitmq_user }}
|
||||||
|
rabbit_virtual_host = {{ rabbitmq_virtual_host }}
|
||||||
|
rabbit_password = {{ rabbitmq_password }}
|
||||||
|
{% if rabbitmq_hosts -%}
|
||||||
|
rabbit_hosts = {{ rabbitmq_hosts }}
|
||||||
|
{% if rabbitmq_ha_queues -%}
|
||||||
|
rabbit_ha_queues = True
|
||||||
|
rabbit_durable_queues = False
|
||||||
|
{% endif -%}
|
||||||
|
{% else -%}
|
||||||
|
rabbit_host = {{ rabbitmq_host }}
|
||||||
|
{% endif -%}
|
||||||
|
{% if rabbit_ssl_port -%}
|
||||||
|
rabbit_use_ssl = True
|
||||||
|
rabbit_port = {{ rabbit_ssl_port }}
|
||||||
|
{% if rabbit_ssl_ca -%}
|
||||||
|
kombu_ssl_ca_certs = {{ rabbit_ssl_ca }}
|
||||||
|
{% endif -%}
|
||||||
|
{% endif -%}
|
||||||
|
{% endif -%}
|
@ -3,12 +3,12 @@
|
|||||||
rpc_backend = zmq
|
rpc_backend = zmq
|
||||||
rpc_zmq_host = {{ zmq_host }}
|
rpc_zmq_host = {{ zmq_host }}
|
||||||
{% if zmq_redis_address -%}
|
{% if zmq_redis_address -%}
|
||||||
rpc_zmq_matchmaker = oslo.messaging._drivers.matchmaker_redis.MatchMakerRedis
|
rpc_zmq_matchmaker = redis
|
||||||
matchmaker_heartbeat_freq = 15
|
matchmaker_heartbeat_freq = 15
|
||||||
matchmaker_heartbeat_ttl = 30
|
matchmaker_heartbeat_ttl = 30
|
||||||
[matchmaker_redis]
|
[matchmaker_redis]
|
||||||
host = {{ zmq_redis_address }}
|
host = {{ zmq_redis_address }}
|
||||||
{% else -%}
|
{% else -%}
|
||||||
rpc_zmq_matchmaker = oslo.messaging._drivers.matchmaker_ring.MatchMakerRing
|
rpc_zmq_matchmaker = ring
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
{% endif -%}
|
{% endif -%}
|
@ -30,6 +30,10 @@ import yaml
|
|||||||
|
|
||||||
from charmhelpers.contrib.network import ip
|
from charmhelpers.contrib.network import ip
|
||||||
|
|
||||||
|
from charmhelpers.core import (
|
||||||
|
unitdata,
|
||||||
|
)
|
||||||
|
|
||||||
from charmhelpers.core.hookenv import (
|
from charmhelpers.core.hookenv import (
|
||||||
config,
|
config,
|
||||||
log as juju_log,
|
log as juju_log,
|
||||||
@ -330,6 +334,21 @@ def configure_installation_source(rel):
|
|||||||
error_out("Invalid openstack-release specified: %s" % rel)
|
error_out("Invalid openstack-release specified: %s" % rel)
|
||||||
|
|
||||||
|
|
||||||
|
def config_value_changed(option):
|
||||||
|
"""
|
||||||
|
Determine if config value changed since last call to this function.
|
||||||
|
"""
|
||||||
|
hook_data = unitdata.HookData()
|
||||||
|
with hook_data():
|
||||||
|
db = unitdata.kv()
|
||||||
|
current = config(option)
|
||||||
|
saved = db.get(option)
|
||||||
|
db.set(option, current)
|
||||||
|
if saved is None:
|
||||||
|
return False
|
||||||
|
return current != saved
|
||||||
|
|
||||||
|
|
||||||
def save_script_rc(script_path="scripts/scriptrc", **env_vars):
|
def save_script_rc(script_path="scripts/scriptrc", **env_vars):
|
||||||
"""
|
"""
|
||||||
Write an rc file in the charm-delivered directory containing
|
Write an rc file in the charm-delivered directory containing
|
||||||
@ -469,82 +488,95 @@ def os_requires_version(ostack_release, pkg):
|
|||||||
|
|
||||||
|
|
||||||
def git_install_requested():
|
def git_install_requested():
|
||||||
"""Returns true if openstack-origin-git is specified."""
|
"""
|
||||||
return config('openstack-origin-git') != "None"
|
Returns true if openstack-origin-git is specified.
|
||||||
|
"""
|
||||||
|
return config('openstack-origin-git') is not None
|
||||||
|
|
||||||
|
|
||||||
requirements_dir = None
|
requirements_dir = None
|
||||||
|
|
||||||
|
|
||||||
def git_clone_and_install(file_name, core_project):
|
def git_clone_and_install(projects_yaml, core_project):
|
||||||
"""Clone/install all OpenStack repos specified in yaml config file."""
|
"""
|
||||||
global requirements_dir
|
Clone/install all specified OpenStack repositories.
|
||||||
|
|
||||||
if file_name == "None":
|
The expected format of projects_yaml is:
|
||||||
|
repositories:
|
||||||
|
- {name: keystone,
|
||||||
|
repository: 'git://git.openstack.org/openstack/keystone.git',
|
||||||
|
branch: 'stable/icehouse'}
|
||||||
|
- {name: requirements,
|
||||||
|
repository: 'git://git.openstack.org/openstack/requirements.git',
|
||||||
|
branch: 'stable/icehouse'}
|
||||||
|
directory: /mnt/openstack-git
|
||||||
|
|
||||||
|
The directory key is optional.
|
||||||
|
"""
|
||||||
|
global requirements_dir
|
||||||
|
parent_dir = '/mnt/openstack-git'
|
||||||
|
|
||||||
|
if not projects_yaml:
|
||||||
return
|
return
|
||||||
|
|
||||||
yaml_file = os.path.join(charm_dir(), file_name)
|
projects = yaml.load(projects_yaml)
|
||||||
|
_git_validate_projects_yaml(projects, core_project)
|
||||||
|
|
||||||
# clone/install the requirements project first
|
if 'directory' in projects.keys():
|
||||||
installed = _git_clone_and_install_subset(yaml_file,
|
parent_dir = projects['directory']
|
||||||
whitelist=['requirements'])
|
|
||||||
if 'requirements' not in installed:
|
|
||||||
error_out('requirements git repository must be specified')
|
|
||||||
|
|
||||||
# clone/install all other projects except requirements and the core project
|
for p in projects['repositories']:
|
||||||
blacklist = ['requirements', core_project]
|
repo = p['repository']
|
||||||
_git_clone_and_install_subset(yaml_file, blacklist=blacklist,
|
branch = p['branch']
|
||||||
update_requirements=True)
|
if p['name'] == 'requirements':
|
||||||
|
repo_dir = _git_clone_and_install_single(repo, branch, parent_dir,
|
||||||
# clone/install the core project
|
update_requirements=False)
|
||||||
whitelist = [core_project]
|
requirements_dir = repo_dir
|
||||||
installed = _git_clone_and_install_subset(yaml_file, whitelist=whitelist,
|
else:
|
||||||
update_requirements=True)
|
repo_dir = _git_clone_and_install_single(repo, branch, parent_dir,
|
||||||
if core_project not in installed:
|
update_requirements=True)
|
||||||
error_out('{} git repository must be specified'.format(core_project))
|
|
||||||
|
|
||||||
|
|
||||||
def _git_clone_and_install_subset(yaml_file, whitelist=[], blacklist=[],
|
def _git_validate_projects_yaml(projects, core_project):
|
||||||
update_requirements=False):
|
"""
|
||||||
"""Clone/install subset of OpenStack repos specified in yaml config file."""
|
Validate the projects yaml.
|
||||||
global requirements_dir
|
"""
|
||||||
installed = []
|
_git_ensure_key_exists('repositories', projects)
|
||||||
|
|
||||||
with open(yaml_file, 'r') as fd:
|
for project in projects['repositories']:
|
||||||
projects = yaml.load(fd)
|
_git_ensure_key_exists('name', project.keys())
|
||||||
for proj, val in projects.items():
|
_git_ensure_key_exists('repository', project.keys())
|
||||||
# The project subset is chosen based on the following 3 rules:
|
_git_ensure_key_exists('branch', project.keys())
|
||||||
# 1) If project is in blacklist, we don't clone/install it, period.
|
|
||||||
# 2) If whitelist is empty, we clone/install everything else.
|
if projects['repositories'][0]['name'] != 'requirements':
|
||||||
# 3) If whitelist is not empty, we clone/install everything in the
|
error_out('{} git repo must be specified first'.format('requirements'))
|
||||||
# whitelist.
|
|
||||||
if proj in blacklist:
|
if projects['repositories'][-1]['name'] != core_project:
|
||||||
continue
|
error_out('{} git repo must be specified last'.format(core_project))
|
||||||
if whitelist and proj not in whitelist:
|
|
||||||
continue
|
|
||||||
repo = val['repository']
|
|
||||||
branch = val['branch']
|
|
||||||
repo_dir = _git_clone_and_install_single(repo, branch,
|
|
||||||
update_requirements)
|
|
||||||
if proj == 'requirements':
|
|
||||||
requirements_dir = repo_dir
|
|
||||||
installed.append(proj)
|
|
||||||
return installed
|
|
||||||
|
|
||||||
|
|
||||||
def _git_clone_and_install_single(repo, branch, update_requirements=False):
|
def _git_ensure_key_exists(key, keys):
|
||||||
"""Clone and install a single git repository."""
|
"""
|
||||||
dest_parent_dir = "/mnt/openstack-git/"
|
Ensure that key exists in keys.
|
||||||
dest_dir = os.path.join(dest_parent_dir, os.path.basename(repo))
|
"""
|
||||||
|
if key not in keys:
|
||||||
|
error_out('openstack-origin-git key \'{}\' is missing'.format(key))
|
||||||
|
|
||||||
if not os.path.exists(dest_parent_dir):
|
|
||||||
juju_log('Host dir not mounted at {}. '
|
def _git_clone_and_install_single(repo, branch, parent_dir, update_requirements):
|
||||||
'Creating directory there instead.'.format(dest_parent_dir))
|
"""
|
||||||
os.mkdir(dest_parent_dir)
|
Clone and install a single git repository.
|
||||||
|
"""
|
||||||
|
dest_dir = os.path.join(parent_dir, os.path.basename(repo))
|
||||||
|
|
||||||
|
if not os.path.exists(parent_dir):
|
||||||
|
juju_log('Directory already exists at {}. '
|
||||||
|
'No need to create directory.'.format(parent_dir))
|
||||||
|
os.mkdir(parent_dir)
|
||||||
|
|
||||||
if not os.path.exists(dest_dir):
|
if not os.path.exists(dest_dir):
|
||||||
juju_log('Cloning git repo: {}, branch: {}'.format(repo, branch))
|
juju_log('Cloning git repo: {}, branch: {}'.format(repo, branch))
|
||||||
repo_dir = install_remote(repo, dest=dest_parent_dir, branch=branch)
|
repo_dir = install_remote(repo, dest=parent_dir, branch=branch)
|
||||||
else:
|
else:
|
||||||
repo_dir = dest_dir
|
repo_dir = dest_dir
|
||||||
|
|
||||||
@ -561,16 +593,39 @@ def _git_clone_and_install_single(repo, branch, update_requirements=False):
|
|||||||
|
|
||||||
|
|
||||||
def _git_update_requirements(package_dir, reqs_dir):
|
def _git_update_requirements(package_dir, reqs_dir):
|
||||||
"""Update from global requirements.
|
"""
|
||||||
|
Update from global requirements.
|
||||||
|
|
||||||
Update an OpenStack git directory's requirements.txt and
|
Update an OpenStack git directory's requirements.txt and
|
||||||
test-requirements.txt from global-requirements.txt."""
|
test-requirements.txt from global-requirements.txt.
|
||||||
|
"""
|
||||||
orig_dir = os.getcwd()
|
orig_dir = os.getcwd()
|
||||||
os.chdir(reqs_dir)
|
os.chdir(reqs_dir)
|
||||||
cmd = "python update.py {}".format(package_dir)
|
cmd = ['python', 'update.py', package_dir]
|
||||||
try:
|
try:
|
||||||
subprocess.check_call(cmd.split(' '))
|
subprocess.check_call(cmd)
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
package = os.path.basename(package_dir)
|
package = os.path.basename(package_dir)
|
||||||
error_out("Error updating {} from global-requirements.txt".format(package))
|
error_out("Error updating {} from global-requirements.txt".format(package))
|
||||||
os.chdir(orig_dir)
|
os.chdir(orig_dir)
|
||||||
|
|
||||||
|
|
||||||
|
def git_src_dir(projects_yaml, project):
|
||||||
|
"""
|
||||||
|
Return the directory where the specified project's source is located.
|
||||||
|
"""
|
||||||
|
parent_dir = '/mnt/openstack-git'
|
||||||
|
|
||||||
|
if not projects_yaml:
|
||||||
|
return
|
||||||
|
|
||||||
|
projects = yaml.load(projects_yaml)
|
||||||
|
|
||||||
|
if 'directory' in projects.keys():
|
||||||
|
parent_dir = projects['directory']
|
||||||
|
|
||||||
|
for p in projects['repositories']:
|
||||||
|
if p['name'] == project:
|
||||||
|
return os.path.join(parent_dir, os.path.basename(p['repository']))
|
||||||
|
|
||||||
|
return None
|
||||||
|
@ -566,3 +566,29 @@ class Hooks(object):
|
|||||||
def charm_dir():
|
def charm_dir():
|
||||||
"""Return the root directory of the current charm"""
|
"""Return the root directory of the current charm"""
|
||||||
return os.environ.get('CHARM_DIR')
|
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):
|
def pwgen(length=None):
|
||||||
"""Generate a random pasword."""
|
"""Generate a random pasword."""
|
||||||
if length is None:
|
if length is None:
|
||||||
|
# A random length is ok to use a weak PRNG
|
||||||
length = random.choice(range(35, 45))
|
length = random.choice(range(35, 45))
|
||||||
alphanumeric_chars = [
|
alphanumeric_chars = [
|
||||||
l for l in (string.ascii_letters + string.digits)
|
l for l in (string.ascii_letters + string.digits)
|
||||||
if l not in 'l0QD1vAEIOUaeiou']
|
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_chars = [
|
||||||
random.choice(alphanumeric_chars) for _ in range(length)]
|
random_generator.choice(alphanumeric_chars) for _ in range(length)]
|
||||||
return(''.join(random_chars))
|
return(''.join(random_chars))
|
||||||
|
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ class MysqlRelation(RelationContext):
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.required_keys = ['host', 'user', 'password', 'database']
|
self.required_keys = ['host', 'user', 'password', 'database']
|
||||||
super(HttpRelation).__init__(self, *args, **kwargs)
|
RelationContext.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class HttpRelation(RelationContext):
|
class HttpRelation(RelationContext):
|
||||||
@ -154,7 +154,7 @@ class HttpRelation(RelationContext):
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.required_keys = ['host', 'port']
|
self.required_keys = ['host', 'port']
|
||||||
super(HttpRelation).__init__(self, *args, **kwargs)
|
RelationContext.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
def provide_data(self):
|
def provide_data(self):
|
||||||
return {
|
return {
|
||||||
|
@ -443,7 +443,7 @@ class HookData(object):
|
|||||||
data = hookenv.execution_environment()
|
data = hookenv.execution_environment()
|
||||||
self.conf = conf_delta = self.kv.delta(data['conf'], 'config')
|
self.conf = conf_delta = self.kv.delta(data['conf'], 'config')
|
||||||
self.rels = rels_delta = self.kv.delta(data['rels'], 'rels')
|
self.rels = rels_delta = self.kv.delta(data['rels'], 'rels')
|
||||||
self.kv.set('env', data['env'])
|
self.kv.set('env', dict(data['env']))
|
||||||
self.kv.set('unit', data['unit'])
|
self.kv.set('unit', data['unit'])
|
||||||
self.kv.set('relid', data.get('relid'))
|
self.kv.set('relid', data.get('relid'))
|
||||||
return conf_delta, rels_delta
|
return conf_delta, rels_delta
|
||||||
|
@ -1,49 +1,25 @@
|
|||||||
from charmhelpers.core.hookenv import (
|
from charmhelpers.core.hookenv import (
|
||||||
relation_ids,
|
|
||||||
related_units,
|
|
||||||
relation_get,
|
|
||||||
config,
|
config,
|
||||||
unit_get,
|
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.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.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
|
||||||
import re
|
from charmhelpers.contrib.openstack.context import (
|
||||||
|
NeutronAPIContext,
|
||||||
|
DataPortContext,
|
||||||
|
)
|
||||||
|
from charmhelpers.contrib.openstack.neutron import (
|
||||||
|
parse_bridge_mappings,
|
||||||
|
parse_vlan_range_mappings,
|
||||||
|
)
|
||||||
OVS_BRIDGE = 'br-int'
|
OVS_BRIDGE = 'br-int'
|
||||||
DATA_BRIDGE = 'br-data'
|
|
||||||
|
|
||||||
|
|
||||||
def neutron_api_settings():
|
|
||||||
'''
|
|
||||||
Inspects current neutron-plugin relation
|
|
||||||
'''
|
|
||||||
neutron_settings = {
|
|
||||||
'neutron_security_groups': False,
|
|
||||||
'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']
|
|
||||||
),
|
|
||||||
}
|
|
||||||
# Override with configuration if set to true
|
|
||||||
if config('disable-security-groups'):
|
|
||||||
neutron_settings['neutron_security_groups'] = False
|
|
||||||
return neutron_settings
|
|
||||||
return neutron_settings
|
|
||||||
|
|
||||||
|
|
||||||
class OVSPluginContext(context.NeutronContext):
|
class OVSPluginContext(context.NeutronContext):
|
||||||
@ -59,34 +35,28 @@ class OVSPluginContext(context.NeutronContext):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def neutron_security_groups(self):
|
def neutron_security_groups(self):
|
||||||
napi_settings = neutron_api_settings()
|
if config('disable-security-groups'):
|
||||||
return napi_settings['neutron_security_groups']
|
return False
|
||||||
|
neutron_api_settings = NeutronAPIContext()()
|
||||||
def get_data_port(self):
|
return neutron_api_settings['neutron_security_groups']
|
||||||
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):
|
def _ensure_bridge(self):
|
||||||
if not service_running('openvswitch-switch'):
|
if not service_running('openvswitch-switch'):
|
||||||
service_start('openvswitch-switch')
|
service_start('openvswitch-switch')
|
||||||
|
|
||||||
add_bridge(OVS_BRIDGE)
|
add_bridge(OVS_BRIDGE)
|
||||||
add_bridge(DATA_BRIDGE)
|
|
||||||
data_port = self.get_data_port()
|
portmaps = DataPortContext()()
|
||||||
if data_port:
|
bridgemaps = parse_bridge_mappings(config('bridge-mappings'))
|
||||||
add_bridge_port(DATA_BRIDGE, data_port, promisc=True)
|
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
|
||||||
@ -102,14 +72,33 @@ class OVSPluginContext(context.NeutronContext):
|
|||||||
ovs_ctxt['local_ip'] = \
|
ovs_ctxt['local_ip'] = \
|
||||||
get_address_in_network(config('os-data-network'),
|
get_address_in_network(config('os-data-network'),
|
||||||
get_host_ip(unit_get('private-address')))
|
get_host_ip(unit_get('private-address')))
|
||||||
napi_settings = neutron_api_settings()
|
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'] = napi_settings['l2_population']
|
ovs_ctxt['l2_population'] = neutron_api_settings['l2_population']
|
||||||
ovs_ctxt['overlay_network_type'] = \
|
ovs_ctxt['overlay_network_type'] = \
|
||||||
napi_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
|
||||||
# general context helper
|
# general context helper
|
||||||
ovs_ctxt['use_syslog'] = conf['use-syslog']
|
ovs_ctxt['use_syslog'] = conf['use-syslog']
|
||||||
ovs_ctxt['verbose'] = conf['verbose']
|
ovs_ctxt['verbose'] = conf['verbose']
|
||||||
ovs_ctxt['debug'] = conf['debug']
|
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
|
return ovs_ctxt
|
||||||
|
@ -13,6 +13,8 @@ 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'
|
||||||
ML2_CONF = '%s/plugins/ml2/ml2_conf.ini' % NEUTRON_CONF_DIR
|
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([
|
BASE_RESOURCE_MAP = OrderedDict([
|
||||||
(NEUTRON_CONF, {
|
(NEUTRON_CONF, {
|
||||||
@ -26,8 +28,11 @@ BASE_RESOURCE_MAP = OrderedDict([
|
|||||||
'services': ['neutron-plugin-openvswitch-agent'],
|
'services': ['neutron-plugin-openvswitch-agent'],
|
||||||
'contexts': [neutron_ovs_context.OVSPluginContext()],
|
'contexts': [neutron_ovs_context.OVSPluginContext()],
|
||||||
}),
|
}),
|
||||||
|
(PHY_NIC_MTU_CONF, {
|
||||||
|
'services': ['os-charm-phy-nic-mtu'],
|
||||||
|
'contexts': [context.PhyNICMTUContext()],
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
TEMPLATES = 'templates/'
|
|
||||||
|
|
||||||
|
|
||||||
def determine_packages():
|
def determine_packages():
|
||||||
|
@ -16,19 +16,22 @@ tunnel_id_ranges = 1:1000
|
|||||||
vni_ranges = 1001:2000
|
vni_ranges = 1001:2000
|
||||||
|
|
||||||
[ml2_type_vlan]
|
[ml2_type_vlan]
|
||||||
network_vlan_ranges = physnet1:1000:2000
|
network_vlan_ranges = {{ vlan_ranges }}
|
||||||
|
|
||||||
[ml2_type_flat]
|
[ml2_type_flat]
|
||||||
flat_networks = physnet1
|
flat_networks = {{ network_providers }}
|
||||||
|
|
||||||
[ovs]
|
[ovs]
|
||||||
enable_tunneling = True
|
enable_tunneling = True
|
||||||
local_ip = {{ local_ip }}
|
local_ip = {{ local_ip }}
|
||||||
bridge_mappings = physnet1:br-data
|
bridge_mappings = {{ bridge_mappings }}
|
||||||
|
|
||||||
[agent]
|
[agent]
|
||||||
tunnel_types = {{ overlay_network_type }}
|
tunnel_types = {{ overlay_network_type }}
|
||||||
l2_population = {{ l2_population }}
|
l2_population = {{ l2_population }}
|
||||||
|
{% if veth_mtu -%}
|
||||||
|
veth_mtu = {{ veth_mtu }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
[securitygroup]
|
[securitygroup]
|
||||||
{% if neutron_security_groups -%}
|
{% if neutron_security_groups -%}
|
||||||
|
@ -12,7 +12,9 @@ state_path = /var/lib/neutron
|
|||||||
lock_path = $state_path/lock
|
lock_path = $state_path/lock
|
||||||
bind_host = 0.0.0.0
|
bind_host = 0.0.0.0
|
||||||
bind_port = 9696
|
bind_port = 9696
|
||||||
|
{% if network_device_mtu -%}
|
||||||
|
network_device_mtu = {{ network_device_mtu }}
|
||||||
|
{% endif -%}
|
||||||
{% if core_plugin -%}
|
{% if core_plugin -%}
|
||||||
core_plugin = {{ core_plugin }}
|
core_plugin = {{ core_plugin }}
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
|
@ -27,8 +27,6 @@ notification_topics = notifications
|
|||||||
|
|
||||||
{% include "parts/rabbitmq" %}
|
{% include "parts/rabbitmq" %}
|
||||||
|
|
||||||
{% include "zeromq" %}
|
|
||||||
|
|
||||||
[QUOTAS]
|
[QUOTAS]
|
||||||
|
|
||||||
[DEFAULT_SERVICETYPE]
|
[DEFAULT_SERVICETYPE]
|
||||||
|
42
templates/kilo/neutron.conf
Normal file
42
templates/kilo/neutron.conf
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# icehouse
|
||||||
|
###############################################################################
|
||||||
|
# [ WARNING ]
|
||||||
|
# Configuration file maintained by Juju. Local changes may be overwritten.
|
||||||
|
# Config managed by neutron-openvswitch charm
|
||||||
|
###############################################################################
|
||||||
|
[DEFAULT]
|
||||||
|
verbose = {{ verbose }}
|
||||||
|
debug = {{ debug }}
|
||||||
|
use_syslog = {{ use_syslog }}
|
||||||
|
state_path = /var/lib/neutron
|
||||||
|
bind_host = 0.0.0.0
|
||||||
|
bind_port = 9696
|
||||||
|
{% if network_device_mtu -%}
|
||||||
|
network_device_mtu = {{ network_device_mtu }}
|
||||||
|
{% endif -%}
|
||||||
|
{% if core_plugin -%}
|
||||||
|
core_plugin = {{ core_plugin }}
|
||||||
|
{% endif -%}
|
||||||
|
|
||||||
|
api_paste_config = /etc/neutron/api-paste.ini
|
||||||
|
auth_strategy = keystone
|
||||||
|
notification_driver = neutron.openstack.common.notifier.rpc_notifier
|
||||||
|
default_notification_level = INFO
|
||||||
|
notification_topics = notifications
|
||||||
|
|
||||||
|
{% include "section-zeromq" %}
|
||||||
|
|
||||||
|
{% include "section-rabbitmq-oslo" %}
|
||||||
|
|
||||||
|
[QUOTAS]
|
||||||
|
|
||||||
|
[DEFAULT_SERVICETYPE]
|
||||||
|
|
||||||
|
[AGENT]
|
||||||
|
root_helper = sudo neutron-rootwrap /etc/neutron/rootwrap.conf
|
||||||
|
|
||||||
|
[keystone_authtoken]
|
||||||
|
signing_dir = /var/lib/neutron/keystone-signing
|
||||||
|
|
||||||
|
[oslo_concurrency]
|
||||||
|
lock_path = $state_path/lock
|
@ -1,14 +0,0 @@
|
|||||||
{% if zmq_host -%}
|
|
||||||
# ZeroMQ configuration (restart-nonce: {{ zmq_nonce }})
|
|
||||||
rpc_backend = zmq
|
|
||||||
rpc_zmq_host = {{ zmq_host }}
|
|
||||||
{% if zmq_redis_address -%}
|
|
||||||
rpc_zmq_matchmaker = oslo_messaging._drivers.matchmaker_redis.MatchMakerRedis
|
|
||||||
matchmaker_heartbeat_freq = 15
|
|
||||||
matchmaker_heartbeat_ttl = 30
|
|
||||||
[matchmaker_redis]
|
|
||||||
host = {{ zmq_redis_address }}
|
|
||||||
{% else -%}
|
|
||||||
rpc_zmq_matchmaker = oslo_messaging._drivers.matchmaker_ring.MatchMakerRing
|
|
||||||
{% endif -%}
|
|
||||||
{% endif -%}
|
|
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
|
@ -15,6 +15,7 @@
|
|||||||
# along with charm-helpers. If not, see <http://www.gnu.org/licenses/>.
|
# along with charm-helpers. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
from collections import OrderedDict
|
||||||
from charmhelpers.contrib.amulet.deployment import (
|
from charmhelpers.contrib.amulet.deployment import (
|
||||||
AmuletDeployment
|
AmuletDeployment
|
||||||
)
|
)
|
||||||
@ -100,12 +101,34 @@ class OpenStackAmuletDeployment(AmuletDeployment):
|
|||||||
"""
|
"""
|
||||||
(self.precise_essex, self.precise_folsom, self.precise_grizzly,
|
(self.precise_essex, self.precise_folsom, self.precise_grizzly,
|
||||||
self.precise_havana, self.precise_icehouse,
|
self.precise_havana, self.precise_icehouse,
|
||||||
self.trusty_icehouse) = range(6)
|
self.trusty_icehouse, self.trusty_juno, self.trusty_kilo) = range(8)
|
||||||
releases = {
|
releases = {
|
||||||
('precise', None): self.precise_essex,
|
('precise', None): self.precise_essex,
|
||||||
('precise', 'cloud:precise-folsom'): self.precise_folsom,
|
('precise', 'cloud:precise-folsom'): self.precise_folsom,
|
||||||
('precise', 'cloud:precise-grizzly'): self.precise_grizzly,
|
('precise', 'cloud:precise-grizzly'): self.precise_grizzly,
|
||||||
('precise', 'cloud:precise-havana'): self.precise_havana,
|
('precise', 'cloud:precise-havana'): self.precise_havana,
|
||||||
('precise', 'cloud:precise-icehouse'): self.precise_icehouse,
|
('precise', 'cloud:precise-icehouse'): self.precise_icehouse,
|
||||||
('trusty', None): self.trusty_icehouse}
|
('trusty', None): self.trusty_icehouse,
|
||||||
|
('trusty', 'cloud:trusty-juno'): self.trusty_juno,
|
||||||
|
('trusty', 'cloud:trusty-kilo'): self.trusty_kilo}
|
||||||
return releases[(self.series, self.openstack)]
|
return releases[(self.series, self.openstack)]
|
||||||
|
|
||||||
|
def _get_openstack_release_string(self):
|
||||||
|
"""Get openstack release string.
|
||||||
|
|
||||||
|
Return a string representing the openstack release.
|
||||||
|
"""
|
||||||
|
releases = OrderedDict([
|
||||||
|
('precise', 'essex'),
|
||||||
|
('quantal', 'folsom'),
|
||||||
|
('raring', 'grizzly'),
|
||||||
|
('saucy', 'havana'),
|
||||||
|
('trusty', 'icehouse'),
|
||||||
|
('utopic', 'juno'),
|
||||||
|
('vivid', 'kilo'),
|
||||||
|
])
|
||||||
|
if self.openstack:
|
||||||
|
os_origin = self.openstack.split(':')[1]
|
||||||
|
return os_origin.split('%s-' % self.series)[1].split('/')[0]
|
||||||
|
else:
|
||||||
|
return releases[self.series]
|
||||||
|
@ -4,18 +4,14 @@ from mock import patch
|
|||||||
import neutron_ovs_context as context
|
import neutron_ovs_context as context
|
||||||
import charmhelpers
|
import charmhelpers
|
||||||
TO_PATCH = [
|
TO_PATCH = [
|
||||||
'relation_get',
|
|
||||||
'relation_ids',
|
|
||||||
'related_units',
|
|
||||||
'config',
|
'config',
|
||||||
'unit_get',
|
'unit_get',
|
||||||
'add_bridge',
|
'add_bridge',
|
||||||
'add_bridge_port',
|
'add_bridge_port',
|
||||||
'service_running',
|
'service_running',
|
||||||
'service_start',
|
'service_start',
|
||||||
|
'service_restart',
|
||||||
'get_host_ip',
|
'get_host_ip',
|
||||||
'get_nic_hwaddr',
|
|
||||||
'list_nics',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -23,7 +19,6 @@ class OVSPluginContextTest(CharmTestCase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(OVSPluginContextTest, self).setUp(context, TO_PATCH)
|
super(OVSPluginContextTest, self).setUp(context, TO_PATCH)
|
||||||
self.relation_get.side_effect = self.test_relation.get
|
|
||||||
self.config.side_effect = self.test_config.get
|
self.config.side_effect = self.test_config.get
|
||||||
self.test_config.set('debug', True)
|
self.test_config.set('debug', True)
|
||||||
self.test_config.set('verbose', True)
|
self.test_config.set('verbose', True)
|
||||||
@ -32,38 +27,57 @@ class OVSPluginContextTest(CharmTestCase):
|
|||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
super(OVSPluginContextTest, self).tearDown()
|
super(OVSPluginContextTest, self).tearDown()
|
||||||
|
|
||||||
def test_data_port_name(self):
|
@patch('charmhelpers.contrib.openstack.context.config')
|
||||||
self.test_config.set('data-port', 'em1')
|
@patch('charmhelpers.contrib.openstack.context.NeutronPortContext.'
|
||||||
self.assertEquals(context.OVSPluginContext().get_data_port(), 'em1')
|
'resolve_ports')
|
||||||
|
def test_data_port_name(self, mock_resolve_ports, config):
|
||||||
|
self.test_config.set('data-port', 'br-data:em1')
|
||||||
|
config.side_effect = self.test_config.get
|
||||||
|
mock_resolve_ports.side_effect = lambda ports: ports
|
||||||
|
self.assertEquals(context.DataPortContext()(),
|
||||||
|
{'br-data': 'em1'})
|
||||||
|
|
||||||
def test_data_port_mac(self):
|
@patch('charmhelpers.contrib.openstack.context.config')
|
||||||
|
@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, config):
|
||||||
machine_machs = {
|
machine_machs = {
|
||||||
'em1': 'aa:aa:aa:aa:aa:aa',
|
'em1': 'aa:aa:aa:aa:aa:aa',
|
||||||
'eth0': 'bb:bb:bb:bb:bb:bb',
|
'eth0': 'bb:bb:bb:bb:bb:bb',
|
||||||
}
|
}
|
||||||
absent_mac = "cc:cc:cc:cc:cc:cc"
|
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)
|
self.test_config.set('data-port', config_macs)
|
||||||
|
config.side_effect = self.test_config.get
|
||||||
|
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):
|
@patch('charmhelpers.contrib.openstack.context.config')
|
||||||
return machine_machs[eth]
|
@patch('charmhelpers.contrib.openstack.context.NeutronPortContext.'
|
||||||
self.get_nic_hwaddr.side_effect = get_hwaddr
|
'resolve_ports')
|
||||||
self.list_nics.return_value = machine_machs.keys()
|
def test_ensure_bridge_data_port_present(self, mock_resolve_ports, config):
|
||||||
self.assertEquals(context.OVSPluginContext().get_data_port(), 'em1')
|
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
|
||||||
|
|
||||||
@patch.object(context.OVSPluginContext, 'get_data_port')
|
|
||||||
def test_ensure_bridge_data_port_present(self, get_data_port):
|
|
||||||
def add_port(bridge, port, promisc):
|
def add_port(bridge, port, promisc):
|
||||||
|
|
||||||
if bridge == 'br-data' and port == 'em1' and promisc is True:
|
if bridge == 'br-data' and port == 'em1' and promisc is True:
|
||||||
self.bridge_added = True
|
self.bridge_added = True
|
||||||
return
|
return
|
||||||
self.bridge_added = False
|
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
|
self.add_bridge_port.side_effect = add_port
|
||||||
context.OVSPluginContext()._ensure_bridge()
|
context.OVSPluginContext()._ensure_bridge()
|
||||||
self.assertEquals(self.bridge_added, True)
|
self.assertEquals(self.bridge_added, True)
|
||||||
|
|
||||||
|
@patch.object(charmhelpers.contrib.openstack.context, 'relation_get')
|
||||||
|
@patch.object(charmhelpers.contrib.openstack.context, 'relation_ids')
|
||||||
|
@patch.object(charmhelpers.contrib.openstack.context, 'related_units')
|
||||||
@patch.object(charmhelpers.contrib.openstack.context, 'config')
|
@patch.object(charmhelpers.contrib.openstack.context, 'config')
|
||||||
@patch.object(charmhelpers.contrib.openstack.context, 'unit_get')
|
@patch.object(charmhelpers.contrib.openstack.context, 'unit_get')
|
||||||
@patch.object(charmhelpers.contrib.openstack.context, 'is_clustered')
|
@patch.object(charmhelpers.contrib.openstack.context, 'is_clustered')
|
||||||
@ -75,7 +89,7 @@ class OVSPluginContextTest(CharmTestCase):
|
|||||||
@patch.object(charmhelpers.contrib.openstack.context, 'unit_private_ip')
|
@patch.object(charmhelpers.contrib.openstack.context, 'unit_private_ip')
|
||||||
def test_neutroncc_context_api_rel(self, _unit_priv_ip, _npa, _ens_pkgs,
|
def test_neutroncc_context_api_rel(self, _unit_priv_ip, _npa, _ens_pkgs,
|
||||||
_save_ff, _https, _is_clus, _unit_get,
|
_save_ff, _https, _is_clus, _unit_get,
|
||||||
_config):
|
_config, _runits, _rids, _rget):
|
||||||
def mock_npa(plugin, section, manager):
|
def mock_npa(plugin, section, manager):
|
||||||
if section == "driver":
|
if section == "driver":
|
||||||
return "neutron.randomdriver"
|
return "neutron.randomdriver"
|
||||||
@ -86,12 +100,15 @@ class OVSPluginContextTest(CharmTestCase):
|
|||||||
_unit_get.return_value = '127.0.0.13'
|
_unit_get.return_value = '127.0.0.13'
|
||||||
_unit_priv_ip.return_value = '127.0.0.14'
|
_unit_priv_ip.return_value = '127.0.0.14'
|
||||||
_is_clus.return_value = False
|
_is_clus.return_value = False
|
||||||
self.related_units.return_value = ['unit1']
|
_runits.return_value = ['unit1']
|
||||||
self.relation_ids.return_value = ['rid2']
|
_rids.return_value = ['rid2']
|
||||||
self.test_relation.set({'neutron-security-groups': 'True',
|
rdata = {
|
||||||
'l2-population': 'True',
|
'neutron-security-groups': 'True',
|
||||||
'overlay-network-type': 'gre',
|
'l2-population': 'True',
|
||||||
})
|
'network-device-mtu': 1500,
|
||||||
|
'overlay-network-type': 'gre',
|
||||||
|
}
|
||||||
|
_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
|
self.service_running.return_value = False
|
||||||
napi_ctxt = context.OVSPluginContext()
|
napi_ctxt = context.OVSPluginContext()
|
||||||
@ -100,6 +117,8 @@ class OVSPluginContextTest(CharmTestCase):
|
|||||||
'neutron_security_groups': True,
|
'neutron_security_groups': True,
|
||||||
'verbose': True,
|
'verbose': True,
|
||||||
'local_ip': '127.0.0.15',
|
'local_ip': '127.0.0.15',
|
||||||
|
'network_device_mtu': 1500,
|
||||||
|
'veth_mtu': 1500,
|
||||||
'config': 'neutron.randomconfig',
|
'config': 'neutron.randomconfig',
|
||||||
'use_syslog': True,
|
'use_syslog': True,
|
||||||
'network_manager': 'neutron',
|
'network_manager': 'neutron',
|
||||||
@ -109,10 +128,16 @@ class OVSPluginContextTest(CharmTestCase):
|
|||||||
'neutron_url': 'https://127.0.0.13:9696',
|
'neutron_url': 'https://127.0.0.13:9696',
|
||||||
'l2_population': True,
|
'l2_population': True,
|
||||||
'overlay_network_type': 'gre',
|
'overlay_network_type': 'gre',
|
||||||
|
'network_providers': 'physnet1',
|
||||||
|
'bridge_mappings': 'physnet1:br-data',
|
||||||
|
'vlan_ranges': 'physnet1:1000:2000',
|
||||||
}
|
}
|
||||||
self.assertEquals(expect, napi_ctxt())
|
self.assertEquals(expect, napi_ctxt())
|
||||||
self.service_start.assertCalled()
|
self.service_start.assertCalled()
|
||||||
|
|
||||||
|
@patch.object(charmhelpers.contrib.openstack.context, 'relation_get')
|
||||||
|
@patch.object(charmhelpers.contrib.openstack.context, 'relation_ids')
|
||||||
|
@patch.object(charmhelpers.contrib.openstack.context, 'related_units')
|
||||||
@patch.object(charmhelpers.contrib.openstack.context, 'config')
|
@patch.object(charmhelpers.contrib.openstack.context, 'config')
|
||||||
@patch.object(charmhelpers.contrib.openstack.context, 'unit_get')
|
@patch.object(charmhelpers.contrib.openstack.context, 'unit_get')
|
||||||
@patch.object(charmhelpers.contrib.openstack.context, 'is_clustered')
|
@patch.object(charmhelpers.contrib.openstack.context, 'is_clustered')
|
||||||
@ -127,24 +152,29 @@ class OVSPluginContextTest(CharmTestCase):
|
|||||||
_ens_pkgs, _save_ff,
|
_ens_pkgs, _save_ff,
|
||||||
_https, _is_clus,
|
_https, _is_clus,
|
||||||
_unit_get,
|
_unit_get,
|
||||||
_config):
|
_config, _runits,
|
||||||
|
_rids, _rget):
|
||||||
def mock_npa(plugin, section, manager):
|
def mock_npa(plugin, section, manager):
|
||||||
if section == "driver":
|
if section == "driver":
|
||||||
return "neutron.randomdriver"
|
return "neutron.randomdriver"
|
||||||
if section == "config":
|
if section == "config":
|
||||||
return "neutron.randomconfig"
|
return "neutron.randomconfig"
|
||||||
|
|
||||||
_npa.side_effect = mock_npa
|
_npa.side_effect = mock_npa
|
||||||
_config.return_value = 'ovs'
|
_config.return_value = 'ovs'
|
||||||
_unit_get.return_value = '127.0.0.13'
|
_unit_get.return_value = '127.0.0.13'
|
||||||
_unit_priv_ip.return_value = '127.0.0.14'
|
_unit_priv_ip.return_value = '127.0.0.14'
|
||||||
_is_clus.return_value = False
|
_is_clus.return_value = False
|
||||||
self.test_config.set('disable-security-groups', True)
|
self.test_config.set('disable-security-groups', True)
|
||||||
self.related_units.return_value = ['unit1']
|
_runits.return_value = ['unit1']
|
||||||
self.relation_ids.return_value = ['rid2']
|
_rids.return_value = ['rid2']
|
||||||
self.test_relation.set({'neutron-security-groups': 'True',
|
rdata = {
|
||||||
'l2-population': 'True',
|
'neutron-security-groups': 'True',
|
||||||
'overlay-network-type': 'gre',
|
'l2-population': 'True',
|
||||||
})
|
'network-device-mtu': 1500,
|
||||||
|
'overlay-network-type': 'gre',
|
||||||
|
}
|
||||||
|
_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
|
self.service_running.return_value = False
|
||||||
napi_ctxt = context.OVSPluginContext()
|
napi_ctxt = context.OVSPluginContext()
|
||||||
@ -153,6 +183,8 @@ class OVSPluginContextTest(CharmTestCase):
|
|||||||
'neutron_security_groups': False,
|
'neutron_security_groups': False,
|
||||||
'verbose': True,
|
'verbose': True,
|
||||||
'local_ip': '127.0.0.15',
|
'local_ip': '127.0.0.15',
|
||||||
|
'veth_mtu': 1500,
|
||||||
|
'network_device_mtu': 1500,
|
||||||
'config': 'neutron.randomconfig',
|
'config': 'neutron.randomconfig',
|
||||||
'use_syslog': True,
|
'use_syslog': True,
|
||||||
'network_manager': 'neutron',
|
'network_manager': 'neutron',
|
||||||
@ -162,6 +194,9 @@ class OVSPluginContextTest(CharmTestCase):
|
|||||||
'neutron_url': 'https://127.0.0.13:9696',
|
'neutron_url': 'https://127.0.0.13:9696',
|
||||||
'l2_population': True,
|
'l2_population': True,
|
||||||
'overlay_network_type': 'gre',
|
'overlay_network_type': 'gre',
|
||||||
|
'network_providers': 'physnet1',
|
||||||
|
'bridge_mappings': 'physnet1:br-data',
|
||||||
|
'vlan_ranges': 'physnet1:1000:2000',
|
||||||
}
|
}
|
||||||
self.assertEquals(expect, napi_ctxt())
|
self.assertEquals(expect, napi_ctxt())
|
||||||
self.service_start.assertCalled()
|
self.service_start.assertCalled()
|
||||||
|
@ -71,7 +71,8 @@ class TestNeutronOVSUtils(CharmTestCase):
|
|||||||
templating.OSConfigRenderer.side_effect = _mock_OSConfigRenderer
|
templating.OSConfigRenderer.side_effect = _mock_OSConfigRenderer
|
||||||
_regconfs = nutils.register_configs()
|
_regconfs = nutils.register_configs()
|
||||||
confs = ['/etc/neutron/neutron.conf',
|
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)
|
self.assertItemsEqual(_regconfs.configs, confs)
|
||||||
|
|
||||||
def test_resource_map(self):
|
def test_resource_map(self):
|
||||||
@ -85,8 +86,9 @@ class TestNeutronOVSUtils(CharmTestCase):
|
|||||||
expect = OrderedDict([
|
expect = OrderedDict([
|
||||||
(nutils.NEUTRON_CONF, ['neutron-plugin-openvswitch-agent']),
|
(nutils.NEUTRON_CONF, ['neutron-plugin-openvswitch-agent']),
|
||||||
(ML2CONF, ['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:
|
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])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user