Rebase
This commit is contained in:
commit
9cc33dd54e
2
Makefile
2
Makefile
@ -15,7 +15,7 @@ bin/charm_helpers_sync.py:
|
||||
> bin/charm_helpers_sync.py
|
||||
|
||||
sync: bin/charm_helpers_sync.py
|
||||
# @$(PYTHON) bin/charm_helpers_sync.py -c charm-helpers-hooks.yaml
|
||||
@$(PYTHON) bin/charm_helpers_sync.py -c charm-helpers-hooks.yaml
|
||||
@$(PYTHON) bin/charm_helpers_sync.py -c charm-helpers-tests.yaml
|
||||
|
||||
test:
|
||||
|
71
config.yaml
71
config.yaml
@ -66,6 +66,71 @@ options:
|
||||
gre
|
||||
vxlan
|
||||
.
|
||||
# Quota configuration settings
|
||||
quota-security-group:
|
||||
default: 10
|
||||
type: int
|
||||
description: |
|
||||
Number of security groups allowed per tenant. A negative value means
|
||||
unlimited.
|
||||
quota-security-group-rule:
|
||||
default: 100
|
||||
type: int
|
||||
description: |
|
||||
Number of security group rules allowed per tenant. A negative value means
|
||||
unlimited
|
||||
quota-network:
|
||||
default: 10
|
||||
type: int
|
||||
description: |
|
||||
Number of networks allowed per tenant. A negative value means unlimited.
|
||||
quota-subnet:
|
||||
default: 10
|
||||
type: int
|
||||
description: |
|
||||
Number of subnets allowed per tenant. A negative value means unlimited.
|
||||
quota-port:
|
||||
default: 50
|
||||
type: int
|
||||
description: |
|
||||
Number of ports allowed per tenant. A negative value means unlimited.
|
||||
quota-vip:
|
||||
default: 10
|
||||
type: int
|
||||
description: |
|
||||
Number of vips allowed per tenant. A negative value means unlimited.
|
||||
quota-pool:
|
||||
default: 10
|
||||
type: int
|
||||
description: |
|
||||
Number of pools allowed per tenant. A negative value means unlimited.
|
||||
quota-member:
|
||||
default: -1
|
||||
type: int
|
||||
description: |
|
||||
Number of pool members allowed per tenant. A negative value means unlimited.
|
||||
The default is unlimited because a member is not a real resource consumer
|
||||
on Openstack. However, on back-end, a member is a resource consumer
|
||||
and that is the reason why quota is possible.
|
||||
quota-health-monitors:
|
||||
default: -1
|
||||
type: int
|
||||
description: |
|
||||
Number of health monitors allowed per tenant. A negative value means
|
||||
unlimited.
|
||||
The default is unlimited because a health monitor is not a real resource
|
||||
consumer on Openstack. However, on back-end, a member is a resource consumer
|
||||
and that is the reason why quota is possible.
|
||||
quota-router:
|
||||
default: 10
|
||||
type: int
|
||||
description: |
|
||||
Number of routers allowed per tenant. A negative value means unlimited.
|
||||
quota-floatingip:
|
||||
default: 50
|
||||
type: int
|
||||
description: |
|
||||
Number of floating IPs allowed per tenant. A negative value means unlimited.
|
||||
# HA configuration settings
|
||||
vip:
|
||||
type: string
|
||||
@ -213,3 +278,9 @@ options:
|
||||
juju-myservice-0
|
||||
If you're running multiple environments with the same services in them
|
||||
this allows you to differentiate between them.
|
||||
nagios_servicegroups:
|
||||
default: ""
|
||||
type: string
|
||||
description: |
|
||||
A comma-separated list of nagios servicegroups.
|
||||
If left empty, the nagios_context will be used as the servicegroup
|
||||
|
@ -17,13 +17,16 @@
|
||||
import glob
|
||||
import re
|
||||
import subprocess
|
||||
import six
|
||||
import socket
|
||||
|
||||
from functools import partial
|
||||
|
||||
from charmhelpers.core.hookenv import unit_get
|
||||
from charmhelpers.fetch import apt_install
|
||||
from charmhelpers.core.hookenv import (
|
||||
log
|
||||
log,
|
||||
WARNING,
|
||||
)
|
||||
|
||||
try:
|
||||
@ -365,3 +368,83 @@ def is_bridge_member(nic):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def is_ip(address):
|
||||
"""
|
||||
Returns True if address is a valid IP address.
|
||||
"""
|
||||
try:
|
||||
# Test to see if already an IPv4 address
|
||||
socket.inet_aton(address)
|
||||
return True
|
||||
except socket.error:
|
||||
return False
|
||||
|
||||
|
||||
def ns_query(address):
|
||||
try:
|
||||
import dns.resolver
|
||||
except ImportError:
|
||||
apt_install('python-dnspython')
|
||||
import dns.resolver
|
||||
|
||||
if isinstance(address, dns.name.Name):
|
||||
rtype = 'PTR'
|
||||
elif isinstance(address, six.string_types):
|
||||
rtype = 'A'
|
||||
else:
|
||||
return None
|
||||
|
||||
answers = dns.resolver.query(address, rtype)
|
||||
if answers:
|
||||
return str(answers[0])
|
||||
return None
|
||||
|
||||
|
||||
def get_host_ip(hostname, fallback=None):
|
||||
"""
|
||||
Resolves the IP for a given hostname, or returns
|
||||
the input if it is already an IP.
|
||||
"""
|
||||
if is_ip(hostname):
|
||||
return hostname
|
||||
|
||||
ip_addr = ns_query(hostname)
|
||||
if not ip_addr:
|
||||
try:
|
||||
ip_addr = socket.gethostbyname(hostname)
|
||||
except:
|
||||
log("Failed to resolve hostname '%s'" % (hostname),
|
||||
level=WARNING)
|
||||
return fallback
|
||||
return ip_addr
|
||||
|
||||
|
||||
def get_hostname(address, fqdn=True):
|
||||
"""
|
||||
Resolves hostname for given IP, or returns the input
|
||||
if it is already a hostname.
|
||||
"""
|
||||
if is_ip(address):
|
||||
try:
|
||||
import dns.reversename
|
||||
except ImportError:
|
||||
apt_install("python-dnspython")
|
||||
import dns.reversename
|
||||
|
||||
rev = dns.reversename.from_address(address)
|
||||
result = ns_query(rev)
|
||||
if not result:
|
||||
return None
|
||||
else:
|
||||
result = address
|
||||
|
||||
if fqdn:
|
||||
# strip trailing .
|
||||
if result.endswith('.'):
|
||||
return result[:-1]
|
||||
else:
|
||||
return result
|
||||
else:
|
||||
return result.split('.')[0]
|
||||
|
@ -21,6 +21,7 @@ from base64 import b64decode
|
||||
from subprocess import check_call
|
||||
|
||||
import six
|
||||
import yaml
|
||||
|
||||
from charmhelpers.fetch import (
|
||||
apt_install,
|
||||
@ -104,9 +105,41 @@ def context_complete(ctxt):
|
||||
def config_flags_parser(config_flags):
|
||||
"""Parses config flags string into dict.
|
||||
|
||||
This parsing method supports a few different formats for the config
|
||||
flag values to be parsed:
|
||||
|
||||
1. A string in the simple format of key=value pairs, with the possibility
|
||||
of specifying multiple key value pairs within the same string. For
|
||||
example, a string in the format of 'key1=value1, key2=value2' will
|
||||
return a dict of:
|
||||
{'key1': 'value1',
|
||||
'key2': 'value2'}.
|
||||
|
||||
2. A string in the above format, but supporting a comma-delimited list
|
||||
of values for the same key. For example, a string in the format of
|
||||
'key1=value1, key2=value3,value4,value5' will return a dict of:
|
||||
{'key1', 'value1',
|
||||
'key2', 'value2,value3,value4'}
|
||||
|
||||
3. A string containing a colon character (:) prior to an equal
|
||||
character (=) will be treated as yaml and parsed as such. This can be
|
||||
used to specify more complex key value pairs. For example,
|
||||
a string in the format of 'key1: subkey1=value1, subkey2=value2' will
|
||||
return a dict of:
|
||||
{'key1', 'subkey1=value1, subkey2=value2'}
|
||||
|
||||
The provided config_flags string may be a list of comma-separated values
|
||||
which themselves may be comma-separated list of values.
|
||||
"""
|
||||
# If we find a colon before an equals sign then treat it as yaml.
|
||||
# Note: limit it to finding the colon first since this indicates assignment
|
||||
# for inline yaml.
|
||||
colon = config_flags.find(':')
|
||||
equals = config_flags.find('=')
|
||||
if colon > 0:
|
||||
if colon < equals or equals < 0:
|
||||
return yaml.safe_load(config_flags)
|
||||
|
||||
if config_flags.find('==') >= 0:
|
||||
log("config_flags is not in expected format (key=value)", level=ERROR)
|
||||
raise OSContextError
|
||||
@ -191,7 +224,7 @@ class SharedDBContext(OSContextGenerator):
|
||||
unit=local_unit())
|
||||
if set_hostname != access_hostname:
|
||||
relation_set(relation_settings={hostname_key: access_hostname})
|
||||
return ctxt # Defer any further hook execution for now....
|
||||
return None # Defer any further hook execution for now....
|
||||
|
||||
password_setting = 'password'
|
||||
if self.relation_prefix:
|
||||
@ -279,9 +312,25 @@ def db_ssl(rdata, ctxt, ssl_dir):
|
||||
class IdentityServiceContext(OSContextGenerator):
|
||||
interfaces = ['identity-service']
|
||||
|
||||
def __init__(self, service=None, service_user=None):
|
||||
self.service = service
|
||||
self.service_user = service_user
|
||||
|
||||
def __call__(self):
|
||||
log('Generating template context for identity-service', level=DEBUG)
|
||||
ctxt = {}
|
||||
|
||||
if self.service and self.service_user:
|
||||
# This is required for pki token signing if we don't want /tmp to
|
||||
# be used.
|
||||
cachedir = '/var/cache/%s' % (self.service)
|
||||
if not os.path.isdir(cachedir):
|
||||
log("Creating service cache dir %s" % (cachedir), level=DEBUG)
|
||||
mkdir(path=cachedir, owner=self.service_user,
|
||||
group=self.service_user, perms=0o700)
|
||||
|
||||
ctxt['signing_dir'] = cachedir
|
||||
|
||||
for rid in relation_ids('identity-service'):
|
||||
for unit in related_units(rid):
|
||||
rdata = relation_get(rid=rid, unit=unit)
|
||||
@ -291,15 +340,16 @@ class IdentityServiceContext(OSContextGenerator):
|
||||
auth_host = format_ipv6_addr(auth_host) or auth_host
|
||||
svc_protocol = rdata.get('service_protocol') or 'http'
|
||||
auth_protocol = rdata.get('auth_protocol') or 'http'
|
||||
ctxt = {'service_port': rdata.get('service_port'),
|
||||
'service_host': serv_host,
|
||||
'auth_host': auth_host,
|
||||
'auth_port': rdata.get('auth_port'),
|
||||
'admin_tenant_name': rdata.get('service_tenant'),
|
||||
'admin_user': rdata.get('service_username'),
|
||||
'admin_password': rdata.get('service_password'),
|
||||
'service_protocol': svc_protocol,
|
||||
'auth_protocol': auth_protocol}
|
||||
ctxt.update({'service_port': rdata.get('service_port'),
|
||||
'service_host': serv_host,
|
||||
'auth_host': auth_host,
|
||||
'auth_port': rdata.get('auth_port'),
|
||||
'admin_tenant_name': rdata.get('service_tenant'),
|
||||
'admin_user': rdata.get('service_username'),
|
||||
'admin_password': rdata.get('service_password'),
|
||||
'service_protocol': svc_protocol,
|
||||
'auth_protocol': auth_protocol})
|
||||
|
||||
if context_complete(ctxt):
|
||||
# NOTE(jamespage) this is required for >= icehouse
|
||||
# so a missing value just indicates keystone needs
|
||||
|
@ -23,12 +23,13 @@ from functools import wraps
|
||||
import subprocess
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
|
||||
import six
|
||||
import yaml
|
||||
|
||||
from charmhelpers.contrib.network import ip
|
||||
|
||||
from charmhelpers.core.hookenv import (
|
||||
config,
|
||||
log as juju_log,
|
||||
@ -421,77 +422,10 @@ def clean_storage(block_device):
|
||||
else:
|
||||
zap_disk(block_device)
|
||||
|
||||
|
||||
def is_ip(address):
|
||||
"""
|
||||
Returns True if address is a valid IP address.
|
||||
"""
|
||||
try:
|
||||
# Test to see if already an IPv4 address
|
||||
socket.inet_aton(address)
|
||||
return True
|
||||
except socket.error:
|
||||
return False
|
||||
|
||||
|
||||
def ns_query(address):
|
||||
try:
|
||||
import dns.resolver
|
||||
except ImportError:
|
||||
apt_install('python-dnspython')
|
||||
import dns.resolver
|
||||
|
||||
if isinstance(address, dns.name.Name):
|
||||
rtype = 'PTR'
|
||||
elif isinstance(address, six.string_types):
|
||||
rtype = 'A'
|
||||
else:
|
||||
return None
|
||||
|
||||
answers = dns.resolver.query(address, rtype)
|
||||
if answers:
|
||||
return str(answers[0])
|
||||
return None
|
||||
|
||||
|
||||
def get_host_ip(hostname):
|
||||
"""
|
||||
Resolves the IP for a given hostname, or returns
|
||||
the input if it is already an IP.
|
||||
"""
|
||||
if is_ip(hostname):
|
||||
return hostname
|
||||
|
||||
return ns_query(hostname)
|
||||
|
||||
|
||||
def get_hostname(address, fqdn=True):
|
||||
"""
|
||||
Resolves hostname for given IP, or returns the input
|
||||
if it is already a hostname.
|
||||
"""
|
||||
if is_ip(address):
|
||||
try:
|
||||
import dns.reversename
|
||||
except ImportError:
|
||||
apt_install('python-dnspython')
|
||||
import dns.reversename
|
||||
|
||||
rev = dns.reversename.from_address(address)
|
||||
result = ns_query(rev)
|
||||
if not result:
|
||||
return None
|
||||
else:
|
||||
result = address
|
||||
|
||||
if fqdn:
|
||||
# strip trailing .
|
||||
if result.endswith('.'):
|
||||
return result[:-1]
|
||||
else:
|
||||
return result
|
||||
else:
|
||||
return result.split('.')[0]
|
||||
is_ip = ip.is_ip
|
||||
ns_query = ip.ns_query
|
||||
get_host_ip = ip.get_host_ip
|
||||
get_hostname = ip.get_hostname
|
||||
|
||||
|
||||
def get_matchmaker_map(mm_file='/etc/oslo/matchmaker_ring.json'):
|
||||
|
@ -45,12 +45,14 @@ class RelationContext(dict):
|
||||
"""
|
||||
name = None
|
||||
interface = None
|
||||
required_keys = []
|
||||
|
||||
def __init__(self, name=None, additional_required_keys=None):
|
||||
if not hasattr(self, 'required_keys'):
|
||||
self.required_keys = []
|
||||
|
||||
if name is not None:
|
||||
self.name = name
|
||||
if additional_required_keys is not None:
|
||||
if additional_required_keys:
|
||||
self.required_keys.extend(additional_required_keys)
|
||||
self.get_data()
|
||||
|
||||
@ -134,7 +136,10 @@ class MysqlRelation(RelationContext):
|
||||
"""
|
||||
name = 'db'
|
||||
interface = 'mysql'
|
||||
required_keys = ['host', 'user', 'password', 'database']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.required_keys = ['host', 'user', 'password', 'database']
|
||||
super(HttpRelation).__init__(self, *args, **kwargs)
|
||||
|
||||
|
||||
class HttpRelation(RelationContext):
|
||||
@ -146,7 +151,10 @@ class HttpRelation(RelationContext):
|
||||
"""
|
||||
name = 'website'
|
||||
interface = 'http'
|
||||
required_keys = ['host', 'port']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.required_keys = ['host', 'port']
|
||||
super(HttpRelation).__init__(self, *args, **kwargs)
|
||||
|
||||
def provide_data(self):
|
||||
return {
|
||||
|
@ -98,6 +98,19 @@ class NeutronCCContext(context.NeutronContext):
|
||||
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')
|
||||
|
||||
for rid in relation_ids('neutron-api'):
|
||||
for unit in related_units(rid):
|
||||
rdata = relation_get(rid=rid, unit=unit)
|
||||
|
@ -401,7 +401,9 @@ def update_nrpe_config():
|
||||
hostname = nrpe.get_nagios_hostname()
|
||||
current_unit = nrpe.get_nagios_unit_name()
|
||||
nrpe_setup = nrpe.NRPE(hostname=hostname)
|
||||
nrpe.copy_nrpe_checks()
|
||||
nrpe.add_init_service_checks(nrpe_setup, services(), current_unit)
|
||||
nrpe.add_haproxy_checks(nrpe_setup, current_unit)
|
||||
nrpe_setup.write()
|
||||
|
||||
|
||||
|
@ -77,7 +77,9 @@ BASE_RESOURCE_MAP = OrderedDict([
|
||||
database=config('database'),
|
||||
ssl_dir=NEUTRON_CONF_DIR),
|
||||
context.PostgresqlDBContext(database=config('database')),
|
||||
neutron_api_context.IdentityServiceContext(),
|
||||
neutron_api_context.IdentityServiceContext(
|
||||
service='neutron',
|
||||
service_user='neutron'),
|
||||
neutron_api_context.NeutronCCContext(),
|
||||
context.SyslogContext(),
|
||||
context.ZeroMQContext(),
|
||||
|
@ -54,13 +54,26 @@ nova_admin_auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/v2.0
|
||||
quota_driver = neutron.db.quota_db.DbQuotaDriver
|
||||
{% if neutron_security_groups -%}
|
||||
quota_items = network,subnet,port,security_group,security_group_rule
|
||||
quota_security_group = {{ quota_security_group }}
|
||||
quota_security_group_rule = {{ quota_security_group_rule }}
|
||||
{% else -%}
|
||||
quota_items = network,subnet,port
|
||||
{% endif -%}
|
||||
quota_network = {{ quota_network }}
|
||||
quota_subnet = {{ quota_subnet }}
|
||||
quota_port = {{ quota_port }}
|
||||
quota_vip = {{ quota_vip }}
|
||||
quota_pool = {{ quota_pool }}
|
||||
quota_member = {{ quota_member }}
|
||||
quota_health_monitors = {{ quota_health_monitors }}
|
||||
quota_router = {{ quota_router }}
|
||||
quota_floatingip = {{ quota_floatingip }}
|
||||
|
||||
[agent]
|
||||
root_helper = sudo /usr/bin/neutron-rootwrap /etc/neutron/rootwrap.conf
|
||||
|
||||
[keystone_authtoken]
|
||||
signing_dir = /var/lib/neutron/keystone-signing
|
||||
signing_dir = {{ signing_dir }}
|
||||
{% if service_host -%}
|
||||
service_protocol = {{ service_protocol }}
|
||||
service_host = {{ service_host }}
|
||||
|
@ -53,13 +53,26 @@ nova_admin_auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/v2.0
|
||||
quota_driver = neutron.db.quota_db.DbQuotaDriver
|
||||
{% if neutron_security_groups -%}
|
||||
quota_items = network,subnet,port,security_group,security_group_rule
|
||||
quota_security_group = {{ quota_security_group }}
|
||||
quota_security_group_rule = {{ quota_security_group_rule }}
|
||||
{% else -%}
|
||||
quota_items = network,subnet,port
|
||||
{% endif -%}
|
||||
quota_network = {{ quota_network }}
|
||||
quota_subnet = {{ quota_subnet }}
|
||||
quota_port = {{ quota_port }}
|
||||
quota_vip = {{ quota_vip }}
|
||||
quota_pool = {{ quota_pool }}
|
||||
quota_member = {{ quota_member }}
|
||||
quota_health_monitors = {{ quota_health_monitors }}
|
||||
quota_router = {{ quota_router }}
|
||||
quota_floatingip = {{ quota_floatingip }}
|
||||
|
||||
[agent]
|
||||
root_helper = sudo /usr/bin/neutron-rootwrap /etc/neutron/rootwrap.conf
|
||||
|
||||
[keystone_authtoken]
|
||||
signing_dir = /var/lib/neutron/keystone-signing
|
||||
signing_dir = {{ signing_dir }}
|
||||
{% if service_host -%}
|
||||
service_protocol = {{ service_protocol }}
|
||||
service_host = {{ service_host }}
|
||||
|
@ -157,6 +157,17 @@ class NeutronCCContextTest(CharmTestCase):
|
||||
'verbose': True,
|
||||
'l2_population': True,
|
||||
'overlay_network_type': 'gre',
|
||||
'quota_floatingip': 50,
|
||||
'quota_health_monitors': -1,
|
||||
'quota_member': -1,
|
||||
'quota_network': 10,
|
||||
'quota_pool': 10,
|
||||
'quota_port': 50,
|
||||
'quota_router': 10,
|
||||
'quota_security_group': 10,
|
||||
'quota_security_group_rule': 100,
|
||||
'quota_subnet': 10,
|
||||
'quota_vip': 10,
|
||||
}
|
||||
napi_ctxt = context.NeutronCCContext()
|
||||
with patch.object(napi_ctxt, '_ensure_packages'):
|
||||
@ -175,6 +186,17 @@ class NeutronCCContextTest(CharmTestCase):
|
||||
'verbose': True,
|
||||
'l2_population': True,
|
||||
'overlay_network_type': 'vxlan',
|
||||
'quota_floatingip': 50,
|
||||
'quota_health_monitors': -1,
|
||||
'quota_member': -1,
|
||||
'quota_network': 10,
|
||||
'quota_pool': 10,
|
||||
'quota_port': 50,
|
||||
'quota_router': 10,
|
||||
'quota_security_group': 10,
|
||||
'quota_security_group_rule': 100,
|
||||
'quota_subnet': 10,
|
||||
'quota_vip': 10,
|
||||
}
|
||||
napi_ctxt = context.NeutronCCContext()
|
||||
with patch.object(napi_ctxt, '_ensure_packages'):
|
||||
|
Loading…
x
Reference in New Issue
Block a user