4d48338c96
Use oslo_messaging_notifications for mitaka or later releases including setting the transport_url to the value provided by the AMQP context. This removes use of deprecated configuration options for ceilometer notifications. This change includes some refactoring to allow the topics to use for notifications to be configured specifically for this charm; future changes can use this to enable/disable designate notifications dynamically. Also includes redux of services check for amulet tests to drop all checks apart from those for the neutron-api units. Change-Id: Ib66371c0c479e0b341055941842e43ac57d4151d
648 lines
23 KiB
Python
648 lines
23 KiB
Python
# Copyright 2016 Canonical Ltd
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import ast
|
|
import re
|
|
|
|
from collections import OrderedDict
|
|
|
|
from charmhelpers.core.hookenv import (
|
|
config,
|
|
relation_ids,
|
|
related_units,
|
|
relation_get,
|
|
log,
|
|
DEBUG,
|
|
ERROR,
|
|
)
|
|
from charmhelpers.contrib.openstack import context
|
|
from charmhelpers.contrib.hahelpers.cluster import (
|
|
determine_api_port,
|
|
determine_apache_port,
|
|
)
|
|
from charmhelpers.contrib.openstack.utils import (
|
|
os_release,
|
|
CompareOpenStackReleases,
|
|
)
|
|
|
|
VLAN = 'vlan'
|
|
VXLAN = 'vxlan'
|
|
GRE = 'gre'
|
|
FLAT = 'flat'
|
|
LOCAL = 'local'
|
|
OVERLAY_NET_TYPES = [VXLAN, GRE]
|
|
NON_OVERLAY_NET_TYPES = [VLAN, FLAT, LOCAL]
|
|
TENANT_NET_TYPES = [VXLAN, GRE, VLAN, FLAT, LOCAL]
|
|
|
|
EXTENSION_DRIVER_PORT_SECURITY = 'port_security'
|
|
EXTENSION_DRIVER_DNS = 'dns'
|
|
|
|
ETC_NEUTRON = '/etc/neutron'
|
|
|
|
NOTIFICATION_TOPICS = [
|
|
'notifications',
|
|
'notifications_designate'
|
|
]
|
|
|
|
# Domain name validation regex which is used to certify that
|
|
# the domain-name consists only of valid characters, is not
|
|
# longer than 63 characters in length for any name segment,
|
|
# and each segment does not begin or end with a hyphen.
|
|
DOMAIN_NAME_REGEX = re.compile(r'^(?!-)[A-Z\d-]{1,63}(?<!-)$',
|
|
re.IGNORECASE)
|
|
|
|
|
|
def get_l2population():
|
|
plugin = config('neutron-plugin')
|
|
return config('l2-population') if plugin == "ovs" else False
|
|
|
|
|
|
def _get_overlay_network_type():
|
|
overlay_networks = config('overlay-network-type').split()
|
|
for overlay_net in overlay_networks:
|
|
if overlay_net not in OVERLAY_NET_TYPES:
|
|
raise ValueError('Unsupported overlay-network-type %s'
|
|
% overlay_net)
|
|
return overlay_networks
|
|
|
|
|
|
def get_overlay_network_type():
|
|
return ','.join(_get_overlay_network_type())
|
|
|
|
|
|
def _get_tenant_network_types():
|
|
default_tenant_network_type = config('default-tenant-network-type')
|
|
tenant_network_types = _get_overlay_network_type()
|
|
tenant_network_types.extend(NON_OVERLAY_NET_TYPES)
|
|
if default_tenant_network_type:
|
|
if (default_tenant_network_type in TENANT_NET_TYPES and
|
|
default_tenant_network_type in tenant_network_types):
|
|
tenant_network_types[:0] = [default_tenant_network_type]
|
|
else:
|
|
raise ValueError('Unsupported or unconfigured '
|
|
'default-tenant-network-type'
|
|
' {}'.format(default_tenant_network_type))
|
|
# Dedupe list but preserve order
|
|
return list(OrderedDict.fromkeys(tenant_network_types))
|
|
|
|
|
|
def get_tenant_network_types():
|
|
'''Get the configured tenant network types
|
|
|
|
@return: comma delimited string of configured tenant
|
|
network types.
|
|
'''
|
|
return ','.join(_get_tenant_network_types())
|
|
|
|
|
|
def get_l3ha():
|
|
if config('enable-l3ha'):
|
|
release = os_release('neutron-server')
|
|
if CompareOpenStackReleases(release) < 'juno':
|
|
log('Disabling L3 HA, enable-l3ha is not valid before Juno')
|
|
return False
|
|
if CompareOpenStackReleases(release) < 'newton' and get_l2population():
|
|
log('Disabling L3 HA, l2-population must be disabled with L3 HA')
|
|
return False
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
|
|
def get_dvr():
|
|
if config('enable-dvr'):
|
|
release = os_release('neutron-server')
|
|
if CompareOpenStackReleases(release) < 'juno':
|
|
log('Disabling DVR, enable-dvr is not valid before Juno')
|
|
return False
|
|
if CompareOpenStackReleases(release) == 'juno':
|
|
if VXLAN not in config('overlay-network-type').split():
|
|
log('Disabling DVR, enable-dvr requires the use of the vxlan '
|
|
'overlay network for OpenStack Juno')
|
|
return False
|
|
if get_l3ha() and CompareOpenStackReleases(release) < 'newton':
|
|
log('Disabling DVR, enable-l3ha must be disabled with dvr')
|
|
return False
|
|
if not get_l2population():
|
|
log('Disabling DVR, l2-population must be enabled to use dvr')
|
|
return False
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
|
|
def get_dns_domain():
|
|
if not config('enable-ml2-dns'):
|
|
log('ML2 DNS Extensions are not enabled.', DEBUG)
|
|
return ""
|
|
|
|
dns_domain = config('dns-domain')
|
|
if not dns_domain:
|
|
log('No dns-domain has been configured', DEBUG)
|
|
return dns_domain
|
|
|
|
release = os_release('neutron-server')
|
|
if CompareOpenStackReleases(release) < 'mitaka':
|
|
log('Internal DNS resolution is not supported before Mitaka')
|
|
return ""
|
|
|
|
# Strip any trailing . at the end
|
|
if dns_domain[-1] == '.':
|
|
dns_domain = dns_domain[:-1]
|
|
|
|
# Ensure that the dns name is only a valid name. Valid entries include
|
|
# a-z, A-Z, 0-9, ., and -. No particular name may be longer than 63
|
|
# characters, each part cannot begin/end with a -. Validate this here in
|
|
# order to prevent other chaos which may prevent neutron services from
|
|
# functioning properly.
|
|
# Note: intentionally not validating the length of the domain name because
|
|
# this is practically difficult to validate reasonably well.
|
|
for level in dns_domain.split('.'):
|
|
if not DOMAIN_NAME_REGEX.match(level):
|
|
msg = "dns-domain '%s' is an invalid domain name." % dns_domain
|
|
log(msg, ERROR)
|
|
raise ValueError(msg)
|
|
|
|
# Make sure it ends with a .
|
|
dns_domain += '.'
|
|
|
|
return dns_domain
|
|
|
|
|
|
def get_ml2_mechanism_drivers():
|
|
"""Build comma delimited list of mechanism drivers for use in Neutron
|
|
ml2_conf.ini. Which drivers to enable are deduced from OpenStack
|
|
release and charm configuration options.
|
|
"""
|
|
mechanism_drivers = [
|
|
'openvswitch',
|
|
]
|
|
|
|
cmp_release = CompareOpenStackReleases(os_release('neutron-server'))
|
|
if (cmp_release == 'kilo' or cmp_release >= 'mitaka'):
|
|
mechanism_drivers.append('hyperv')
|
|
|
|
if get_l2population():
|
|
mechanism_drivers.append('l2population')
|
|
|
|
if (config('enable-sriov') and cmp_release >= 'kilo'):
|
|
mechanism_drivers.append('sriovnicswitch')
|
|
return ','.join(mechanism_drivers)
|
|
|
|
|
|
class ApacheSSLContext(context.ApacheSSLContext):
|
|
|
|
interfaces = ['https']
|
|
external_ports = []
|
|
service_namespace = 'neutron'
|
|
|
|
def __call__(self):
|
|
# late import to work around circular dependency
|
|
from neutron_api_utils import determine_ports
|
|
self.external_ports = determine_ports()
|
|
return super(ApacheSSLContext, self).__call__()
|
|
|
|
|
|
class IdentityServiceContext(context.IdentityServiceContext):
|
|
|
|
def __call__(self):
|
|
ctxt = super(IdentityServiceContext, self).__call__()
|
|
if not ctxt:
|
|
return
|
|
ctxt['region'] = config('region')
|
|
return ctxt
|
|
|
|
|
|
class NeutronCCContext(context.NeutronContext):
|
|
interfaces = []
|
|
|
|
@property
|
|
def network_manager(self):
|
|
return 'neutron'
|
|
|
|
@property
|
|
def plugin(self):
|
|
return config('neutron-plugin')
|
|
|
|
@property
|
|
def neutron_security_groups(self):
|
|
return config('neutron-security-groups')
|
|
|
|
@property
|
|
def neutron_l2_population(self):
|
|
return get_l2population()
|
|
|
|
@property
|
|
def neutron_tenant_network_types(self):
|
|
return get_tenant_network_types()
|
|
|
|
@property
|
|
def neutron_overlay_network_type(self):
|
|
return get_overlay_network_type()
|
|
|
|
@property
|
|
def neutron_dvr(self):
|
|
return get_dvr()
|
|
|
|
@property
|
|
def neutron_l3ha(self):
|
|
return get_l3ha()
|
|
|
|
# Do not need the plugin agent installed on the api server
|
|
def _ensure_packages(self):
|
|
pass
|
|
|
|
# Do not need the flag on the api server
|
|
def _save_flag_file(self):
|
|
pass
|
|
|
|
def get_neutron_api_rel_settings(self):
|
|
settings = {}
|
|
for rid in relation_ids('neutron-api'):
|
|
for unit in related_units(rid):
|
|
rdata = relation_get(rid=rid, unit=unit)
|
|
cell_type = rdata.get('cell_type')
|
|
settings['nova_url'] = rdata.get('nova_url')
|
|
settings['restart_trigger'] = rdata.get('restart_trigger')
|
|
# If there are multiple nova-cloud-controllers joined to this
|
|
# service in a cell deployment then ignore the non-api cell
|
|
# ones
|
|
if cell_type and not cell_type == "api":
|
|
continue
|
|
|
|
if settings['nova_url']:
|
|
return settings
|
|
|
|
return settings
|
|
|
|
def __call__(self):
|
|
from neutron_api_utils import api_port
|
|
ctxt = super(NeutronCCContext, self).__call__()
|
|
if config('neutron-plugin') == 'nsx':
|
|
ctxt['nsx_username'] = config('nsx-username')
|
|
ctxt['nsx_password'] = config('nsx-password')
|
|
ctxt['nsx_tz_uuid'] = config('nsx-tz-uuid')
|
|
ctxt['nsx_l3_uuid'] = config('nsx-l3-uuid')
|
|
if 'nsx-controllers' in config():
|
|
ctxt['nsx_controllers'] = \
|
|
','.join(config('nsx-controllers').split())
|
|
ctxt['nsx_controllers_list'] = \
|
|
config('nsx-controllers').split()
|
|
if config('neutron-plugin') == 'plumgrid':
|
|
ctxt['pg_username'] = config('plumgrid-username')
|
|
ctxt['pg_password'] = config('plumgrid-password')
|
|
ctxt['virtual_ip'] = config('plumgrid-virtual-ip')
|
|
elif config('neutron-plugin') == 'midonet':
|
|
ctxt.update(MidonetContext()())
|
|
identity_context = IdentityServiceContext(service='neutron',
|
|
service_user='neutron')()
|
|
if identity_context is not None:
|
|
ctxt.update(identity_context)
|
|
ctxt['l2_population'] = self.neutron_l2_population
|
|
ctxt['enable_dvr'] = self.neutron_dvr
|
|
ctxt['l3_ha'] = self.neutron_l3ha
|
|
if self.neutron_l3ha:
|
|
max_agents = config('max-l3-agents-per-router')
|
|
min_agents = config('min-l3-agents-per-router')
|
|
if max_agents < min_agents:
|
|
raise ValueError("max-l3-agents-per-router ({}) must be >= "
|
|
"min-l3-agents-per-router "
|
|
"({})".format(max_agents, min_agents))
|
|
|
|
ctxt['max_l3_agents_per_router'] = max_agents
|
|
ctxt['min_l3_agents_per_router'] = min_agents
|
|
|
|
ctxt['dhcp_agents_per_network'] = config('dhcp-agents-per-network')
|
|
ctxt['tenant_network_types'] = self.neutron_tenant_network_types
|
|
ctxt['overlay_network_type'] = self.neutron_overlay_network_type
|
|
ctxt['external_network'] = config('neutron-external-network')
|
|
release = os_release('neutron-server')
|
|
cmp_release = CompareOpenStackReleases(release)
|
|
if config('neutron-plugin') in ['vsp']:
|
|
_config = config()
|
|
for k, v in _config.iteritems():
|
|
if k.startswith('vsd'):
|
|
ctxt[k.replace('-', '_')] = v
|
|
for rid in relation_ids('vsd-rest-api'):
|
|
for unit in related_units(rid):
|
|
rdata = relation_get(rid=rid, unit=unit)
|
|
vsd_ip = rdata.get('vsd-ip-address')
|
|
if cmp_release >= 'kilo':
|
|
cms_id_value = rdata.get('nuage-cms-id')
|
|
log('relation data:cms_id required for'
|
|
' nuage plugin: {}'.format(cms_id_value))
|
|
if cms_id_value is not None:
|
|
ctxt['vsd_cms_id'] = cms_id_value
|
|
log('relation data:vsd-ip-address: {}'.format(vsd_ip))
|
|
if vsd_ip is not None:
|
|
ctxt['vsd_server'] = '{}:8443'.format(vsd_ip)
|
|
if 'vsd_server' not in ctxt:
|
|
ctxt['vsd_server'] = '1.1.1.1:8443'
|
|
ctxt['verbose'] = config('verbose')
|
|
ctxt['debug'] = config('debug')
|
|
ctxt['neutron_bind_port'] = \
|
|
determine_api_port(api_port('neutron-server'),
|
|
singlenode_mode=True)
|
|
ctxt['quota_security_group'] = config('quota-security-group')
|
|
ctxt['quota_security_group_rule'] = \
|
|
config('quota-security-group-rule')
|
|
ctxt['quota_network'] = config('quota-network')
|
|
ctxt['quota_subnet'] = config('quota-subnet')
|
|
ctxt['quota_port'] = config('quota-port')
|
|
ctxt['quota_vip'] = config('quota-vip')
|
|
ctxt['quota_pool'] = config('quota-pool')
|
|
ctxt['quota_member'] = config('quota-member')
|
|
ctxt['quota_health_monitors'] = config('quota-health-monitors')
|
|
ctxt['quota_router'] = config('quota-router')
|
|
ctxt['quota_floatingip'] = config('quota-floatingip')
|
|
|
|
n_api_settings = self.get_neutron_api_rel_settings()
|
|
if n_api_settings:
|
|
ctxt.update(n_api_settings)
|
|
|
|
flat_providers = config('flat-network-providers')
|
|
if flat_providers:
|
|
ctxt['network_providers'] = ','.join(flat_providers.split())
|
|
|
|
vlan_ranges = config('vlan-ranges')
|
|
if vlan_ranges:
|
|
ctxt['vlan_ranges'] = ','.join(vlan_ranges.split())
|
|
|
|
vni_ranges = config('vni-ranges')
|
|
if vni_ranges:
|
|
ctxt['vni_ranges'] = ','.join(vni_ranges.split())
|
|
|
|
extension_drivers = []
|
|
if config('enable-ml2-port-security'):
|
|
extension_drivers.append(EXTENSION_DRIVER_PORT_SECURITY)
|
|
|
|
dns_domain = get_dns_domain()
|
|
if dns_domain:
|
|
extension_drivers.append(EXTENSION_DRIVER_DNS)
|
|
ctxt['dns_domain'] = dns_domain
|
|
if extension_drivers:
|
|
ctxt['extension_drivers'] = ','.join(extension_drivers)
|
|
|
|
ctxt['enable_sriov'] = config('enable-sriov')
|
|
|
|
if cmp_release >= 'mitaka':
|
|
if config('global-physnet-mtu'):
|
|
ctxt['global_physnet_mtu'] = config('global-physnet-mtu')
|
|
if config('path-mtu'):
|
|
ctxt['path_mtu'] = config('path-mtu')
|
|
else:
|
|
ctxt['path_mtu'] = config('global-physnet-mtu')
|
|
|
|
if 'kilo' <= cmp_release <= 'mitaka':
|
|
pci_vendor_devs = config('supported-pci-vendor-devs')
|
|
if pci_vendor_devs:
|
|
ctxt['supported_pci_vendor_devs'] = \
|
|
','.join(pci_vendor_devs.split())
|
|
|
|
ctxt['mechanism_drivers'] = get_ml2_mechanism_drivers()
|
|
|
|
return ctxt
|
|
|
|
|
|
class HAProxyContext(context.HAProxyContext):
|
|
interfaces = ['ceph']
|
|
|
|
def __call__(self):
|
|
'''
|
|
Extends the main charmhelpers HAProxyContext with a port mapping
|
|
specific to this charm.
|
|
Also used to extend nova.conf context with correct api_listening_ports
|
|
'''
|
|
from neutron_api_utils import api_port
|
|
ctxt = super(HAProxyContext, self).__call__()
|
|
|
|
# Apache ports
|
|
a_neutron_api = determine_apache_port(api_port('neutron-server'),
|
|
singlenode_mode=True)
|
|
|
|
port_mapping = {
|
|
'neutron-server': [
|
|
api_port('neutron-server'), a_neutron_api]
|
|
}
|
|
|
|
ctxt['neutron_bind_port'] = determine_api_port(
|
|
api_port('neutron-server'),
|
|
singlenode_mode=True,
|
|
)
|
|
|
|
# for haproxy.conf
|
|
ctxt['service_ports'] = port_mapping
|
|
return ctxt
|
|
|
|
|
|
class EtcdContext(context.OSContextGenerator):
|
|
interfaces = ['etcd-proxy']
|
|
|
|
def __call__(self):
|
|
ctxt = {'cluster': ''}
|
|
cluster_string = ''
|
|
|
|
if not config('neutron-plugin') == 'Calico':
|
|
return ctxt
|
|
|
|
for rid in relation_ids('etcd-proxy'):
|
|
for unit in related_units(rid):
|
|
rdata = relation_get(rid=rid, unit=unit)
|
|
cluster_string = rdata.get('cluster')
|
|
if cluster_string:
|
|
break
|
|
|
|
ctxt['cluster'] = cluster_string
|
|
|
|
return ctxt
|
|
|
|
|
|
class NeutronApiSDNContext(context.SubordinateConfigContext):
|
|
interfaces = 'neutron-plugin-api-subordinate'
|
|
|
|
def __init__(self):
|
|
super(NeutronApiSDNContext, self).__init__(
|
|
interface='neutron-plugin-api-subordinate',
|
|
service='neutron-api',
|
|
config_file='/etc/neutron/neutron.conf')
|
|
|
|
def __call__(self):
|
|
ctxt = super(NeutronApiSDNContext, self).__call__()
|
|
defaults = {
|
|
'core-plugin': {
|
|
'templ_key': 'core_plugin',
|
|
'value': 'neutron.plugins.ml2.plugin.Ml2Plugin',
|
|
},
|
|
'neutron-plugin-config': {
|
|
'templ_key': 'neutron_plugin_config',
|
|
'value': '/etc/neutron/plugins/ml2/ml2_conf.ini',
|
|
},
|
|
'service-plugins': {
|
|
'templ_key': 'service_plugins',
|
|
'value': 'router,firewall,lbaas,vpnaas,metering',
|
|
},
|
|
'restart-trigger': {
|
|
'templ_key': 'restart_trigger',
|
|
'value': '',
|
|
},
|
|
'quota-driver': {
|
|
'templ_key': 'quota_driver',
|
|
'value': '',
|
|
},
|
|
'api-extensions-path': {
|
|
'templ_key': 'api_extensions_path',
|
|
'value': '',
|
|
},
|
|
}
|
|
for rid in relation_ids('neutron-plugin-api-subordinate'):
|
|
for unit in related_units(rid):
|
|
rdata = relation_get(rid=rid, unit=unit)
|
|
plugin = rdata.get('neutron-plugin')
|
|
if not plugin:
|
|
continue
|
|
ctxt['neutron_plugin'] = plugin
|
|
for key in defaults.keys():
|
|
remote_value = rdata.get(key)
|
|
ctxt_key = defaults[key]['templ_key']
|
|
if remote_value:
|
|
ctxt[ctxt_key] = remote_value
|
|
else:
|
|
ctxt[ctxt_key] = defaults[key]['value']
|
|
return ctxt
|
|
return ctxt
|
|
|
|
|
|
class NeutronApiSDNConfigFileContext(context.OSContextGenerator):
|
|
interfaces = ['neutron-plugin-api-subordinate']
|
|
|
|
def __call__(self):
|
|
for rid in relation_ids('neutron-plugin-api-subordinate'):
|
|
for unit in related_units(rid):
|
|
rdata = relation_get(rid=rid, unit=unit)
|
|
neutron_server_plugin_conf = rdata.get('neutron-plugin-config')
|
|
if neutron_server_plugin_conf:
|
|
return {'config': neutron_server_plugin_conf}
|
|
return {'config': '/etc/neutron/plugins/ml2/ml2_conf.ini'}
|
|
|
|
|
|
class NeutronApiApiPasteContext(context.OSContextGenerator):
|
|
interfaces = ['neutron-plugin-api-subordinate']
|
|
|
|
def __validate_middleware(self, middleware):
|
|
'''
|
|
Accepts a list of dicts of the following format:
|
|
{
|
|
'type': 'middleware_type',
|
|
'name': 'middleware_name',
|
|
'config': {
|
|
option_1: value_1,
|
|
# ...
|
|
option_n: value_n
|
|
}
|
|
This validator was meant to be minimalistic - PasteDeploy's
|
|
validator will take care of the rest while our purpose here
|
|
is mainly config rendering - not imposing additional validation
|
|
logic which does not belong here.
|
|
'''
|
|
# types taken from PasteDeploy's wsgi loader
|
|
VALID_TYPES = ['filter', 'filter-app',
|
|
'app', 'application',
|
|
'composite', 'composit', 'pipeline']
|
|
|
|
def types_valid(t, n, c):
|
|
return all((type(t) is str,
|
|
type(n) is str,
|
|
type(c is dict)))
|
|
|
|
def mtype_valid(t):
|
|
return t in VALID_TYPES
|
|
|
|
for m in middleware:
|
|
t, n, c = [m.get(v) for v in ['type', 'name', 'config']]
|
|
# note that dict has to be non-empty
|
|
if not types_valid(t, n, c):
|
|
raise ValueError('Extra middleware key type(s) are'
|
|
' invalid: {}'.format(repr(m)))
|
|
if not mtype_valid(t):
|
|
raise ValueError('Extra middleware type key is not'
|
|
' a valid PasteDeploy middleware '
|
|
'type {}'.format(repr(t)))
|
|
if not c:
|
|
raise ValueError('Extra middleware config dictionary'
|
|
' is empty')
|
|
|
|
def __process_unit(self, rid, unit):
|
|
rdata = relation_get(rid=rid, unit=unit)
|
|
# update extra middleware for all possible plugins
|
|
rdata_middleware = rdata.get('extra_middleware')
|
|
if rdata_middleware:
|
|
try:
|
|
middleware = ast.literal_eval(rdata_middleware)
|
|
except:
|
|
import traceback
|
|
log(traceback.format_exc())
|
|
raise ValueError('Invalid extra middleware data'
|
|
' - check the subordinate charm')
|
|
if middleware:
|
|
return middleware
|
|
else:
|
|
log('extra_middleware specified but not'
|
|
'populated by unit {}, '
|
|
'relation: {}, value: {}'.format(
|
|
unit, rid, repr(middleware)))
|
|
raise ValueError('Invalid extra middleware'
|
|
'specified by a subordinate')
|
|
# no extra middleware
|
|
return list()
|
|
|
|
def __call__(self):
|
|
extra_middleware = []
|
|
for rid in relation_ids('neutron-plugin-api-subordinate'):
|
|
for unit in related_units(rid):
|
|
extra_middleware.extend(self.__process_unit(rid, unit))
|
|
self.__validate_middleware(extra_middleware)
|
|
return {'extra_middleware': extra_middleware}\
|
|
if extra_middleware else {}
|
|
|
|
|
|
class MidonetContext(context.OSContextGenerator):
|
|
|
|
def __init__(self, rel_name='midonet'):
|
|
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 = {
|
|
'midonet_api_ip': rdata.get('host'),
|
|
'midonet_api_port': rdata.get('port'),
|
|
}
|
|
if self.context_complete(ctxt):
|
|
return ctxt
|
|
return {}
|
|
|
|
|
|
class NeutronAMQPContext(context.AMQPContext):
|
|
'''AMQP context with Neutron API sauce'''
|
|
|
|
def __init__(self):
|
|
super(NeutronAMQPContext, self).__init__(ssl_dir=ETC_NEUTRON)
|
|
|
|
def __call__(self):
|
|
context = super(NeutronAMQPContext, self).__call__()
|
|
context['notification_topics'] = ','.join(NOTIFICATION_TOPICS)
|
|
return context
|