From c13730095d7f1000feb112f73eb9df3474288e1a Mon Sep 17 00:00:00 2001 From: Kapil Thangavelu Date: Wed, 26 Feb 2014 19:54:45 -0500 Subject: [PATCH 1/9] sync helpers --- .../charmhelpers/contrib/hahelpers/cluster.py | 8 +- .../charmhelpers/contrib/openstack/context.py | 137 ++++++++++++++---- hooks/charmhelpers/contrib/openstack/utils.py | 20 ++- .../contrib/storage/linux/ceph.py | 8 +- .../contrib/storage/linux/utils.py | 2 +- hooks/charmhelpers/core/hookenv.py | 6 + hooks/charmhelpers/core/host.py | 56 ++++++- hooks/charmhelpers/fetch/__init__.py | 48 ++++-- 8 files changed, 226 insertions(+), 59 deletions(-) diff --git a/hooks/charmhelpers/contrib/hahelpers/cluster.py b/hooks/charmhelpers/contrib/hahelpers/cluster.py index 074855f4..bf832f7d 100644 --- a/hooks/charmhelpers/contrib/hahelpers/cluster.py +++ b/hooks/charmhelpers/contrib/hahelpers/cluster.py @@ -126,17 +126,17 @@ def determine_api_port(public_port): return public_port - (i * 10) -def determine_haproxy_port(public_port): +def determine_apache_port(public_port): ''' - Description: Determine correct proxy listening port based on public IP + - existence of HTTPS reverse proxy. + Description: Determine correct apache listening port based on public IP + + state of the cluster. public_port: int: standard public port for given service returns: int: the correct listening port for the HAProxy service ''' i = 0 - if https(): + if len(peer_units()) > 0 or is_clustered(): i += 1 return public_port - (i * 10) diff --git a/hooks/charmhelpers/contrib/openstack/context.py b/hooks/charmhelpers/contrib/openstack/context.py index 8a982ffa..5785b6a1 100644 --- a/hooks/charmhelpers/contrib/openstack/context.py +++ b/hooks/charmhelpers/contrib/openstack/context.py @@ -23,15 +23,13 @@ from charmhelpers.core.hookenv import ( unit_get, unit_private_ip, ERROR, - WARNING, ) from charmhelpers.contrib.hahelpers.cluster import ( + determine_apache_port, determine_api_port, - determine_haproxy_port, https, - is_clustered, - peer_units, + is_clustered ) from charmhelpers.contrib.hahelpers.apache import ( @@ -68,6 +66,43 @@ def context_complete(ctxt): return True +def config_flags_parser(config_flags): + if config_flags.find('==') >= 0: + log("config_flags is not in expected format (key=value)", + level=ERROR) + raise OSContextError + # strip the following from each value. + post_strippers = ' ,' + # we strip any leading/trailing '=' or ' ' from the string then + # split on '='. + split = config_flags.strip(' =').split('=') + limit = len(split) + flags = {} + for i in xrange(0, limit - 1): + current = split[i] + next = split[i + 1] + vindex = next.rfind(',') + if (i == limit - 2) or (vindex < 0): + value = next + else: + value = next[:vindex] + + if i == 0: + key = current + else: + # if this not the first entry, expect an embedded key. + index = current.rfind(',') + if index < 0: + log("invalid config value(s) at index %s" % (i), + level=ERROR) + raise OSContextError + key = current[index + 1:] + + # Add to collection. + flags[key.strip(post_strippers)] = value.rstrip(post_strippers) + return flags + + class OSContextGenerator(object): interfaces = [] @@ -182,10 +217,17 @@ class AMQPContext(OSContextGenerator): # Sufficient information found = break out! break # Used for active/active rabbitmq >= grizzly - ctxt['rabbitmq_hosts'] = [] - for unit in related_units(rid): - ctxt['rabbitmq_hosts'].append(relation_get('private-address', - rid=rid, unit=unit)) + if ('clustered' not in ctxt or relation_get('ha-vip-only') == 'True') and \ + len(related_units(rid)) > 1: + if relation_get('ha_queues'): + ctxt['rabbitmq_ha_queues'] = relation_get('ha_queues') + else: + ctxt['rabbitmq_ha_queues'] = False + rabbitmq_hosts = [] + for unit in related_units(rid): + rabbitmq_hosts.append(relation_get('private-address', + rid=rid, unit=unit)) + ctxt['rabbitmq_hosts'] = ','.join(rabbitmq_hosts) if not context_complete(ctxt): return {} else: @@ -199,10 +241,13 @@ class CephContext(OSContextGenerator): '''This generates context for /etc/ceph/ceph.conf templates''' if not relation_ids('ceph'): return {} + log('Generating template context for ceph') + mon_hosts = [] auth = None key = None + use_syslog = str(config('use-syslog')).lower() for rid in relation_ids('ceph'): for unit in related_units(rid): mon_hosts.append(relation_get('private-address', rid=rid, @@ -214,6 +259,7 @@ class CephContext(OSContextGenerator): 'mon_hosts': ' '.join(mon_hosts), 'auth': auth, 'key': key, + 'use_syslog': use_syslog } if not os.path.isdir('/etc/ceph'): @@ -286,6 +332,7 @@ class ImageServiceContext(OSContextGenerator): class ApacheSSLContext(OSContextGenerator): + """ Generates a context for an apache vhost configuration that configures HTTPS reverse proxying for one or many endpoints. Generated context @@ -341,17 +388,15 @@ class ApacheSSLContext(OSContextGenerator): 'private_address': unit_get('private-address'), 'endpoints': [] } - for ext_port in self.external_ports: - if peer_units() or is_clustered(): - int_port = determine_haproxy_port(ext_port) - else: - int_port = determine_api_port(ext_port) + for api_port in self.external_ports: + ext_port = determine_apache_port(api_port) + int_port = determine_api_port(api_port) portmap = (int(ext_port), int(int_port)) ctxt['endpoints'].append(portmap) return ctxt -class NeutronContext(object): +class NeutronContext(OSContextGenerator): interfaces = [] @property @@ -412,6 +457,22 @@ class NeutronContext(object): return nvp_ctxt + def neutron_ctxt(self): + if https(): + proto = 'https' + else: + proto = 'http' + if is_clustered(): + host = config('vip') + else: + host = unit_get('private-address') + url = '%s://%s:%s' % (proto, host, '9292') + ctxt = { + 'network_manager': self.network_manager, + 'neutron_url': url, + } + return ctxt + def __call__(self): self._ensure_packages() @@ -421,40 +482,44 @@ class NeutronContext(object): if not self.plugin: return {} - ctxt = {'network_manager': self.network_manager} + ctxt = self.neutron_ctxt() if self.plugin == 'ovs': ctxt.update(self.ovs_ctxt()) elif self.plugin == 'nvp': ctxt.update(self.nvp_ctxt()) + alchemy_flags = config('neutron-alchemy-flags') + if alchemy_flags: + flags = config_flags_parser(alchemy_flags) + ctxt['neutron_alchemy_flags'] = flags + self._save_flag_file() return ctxt class OSConfigFlagContext(OSContextGenerator): - ''' - Responsible adding user-defined config-flags in charm config to a - to a template context. - ''' + + """ + Responsible for adding user-defined config-flags in charm config to a + template context. + + NOTE: the value of config-flags may be a comma-separated list of + key=value pairs and some Openstack config files support + comma-separated lists as values. + """ + def __call__(self): config_flags = config('config-flags') - if not config_flags or config_flags in ['None', '']: + if not config_flags: return {} - config_flags = config_flags.split(',') - flags = {} - for flag in config_flags: - if '=' not in flag: - log('Improperly formatted config-flag, expected k=v ' - 'got %s' % flag, level=WARNING) - continue - k, v = flag.split('=') - flags[k.strip()] = v - ctxt = {'user_config_flags': flags} - return ctxt + + flags = config_flags_parser(config_flags) + return {'user_config_flags': flags} class SubordinateConfigContext(OSContextGenerator): + """ Responsible for inspecting relations to subordinates that may be exporting required config via a json blob. @@ -495,6 +560,7 @@ class SubordinateConfigContext(OSContextGenerator): } """ + def __init__(self, service, config_file, interface): """ :param service : Service name key to query in any subordinate @@ -539,3 +605,12 @@ class SubordinateConfigContext(OSContextGenerator): ctxt['sections'] = {} return ctxt + + +class SyslogContext(OSContextGenerator): + + def __call__(self): + ctxt = { + 'use_syslog': config('use-syslog') + } + return ctxt diff --git a/hooks/charmhelpers/contrib/openstack/utils.py b/hooks/charmhelpers/contrib/openstack/utils.py index d66afd74..56d04245 100644 --- a/hooks/charmhelpers/contrib/openstack/utils.py +++ b/hooks/charmhelpers/contrib/openstack/utils.py @@ -41,6 +41,7 @@ UBUNTU_OPENSTACK_RELEASE = OrderedDict([ ('quantal', 'folsom'), ('raring', 'grizzly'), ('saucy', 'havana'), + ('trusty', 'icehouse') ]) @@ -201,7 +202,7 @@ def os_release(package, base='essex'): def import_key(keyid): - cmd = "apt-key adv --keyserver keyserver.ubuntu.com " \ + cmd = "apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 " \ "--recv-keys %s" % keyid try: subprocess.check_call(cmd.split(' ')) @@ -260,6 +261,9 @@ def configure_installation_source(rel): 'havana': 'precise-updates/havana', 'havana/updates': 'precise-updates/havana', 'havana/proposed': 'precise-proposed/havana', + 'icehouse': 'precise-updates/icehouse', + 'icehouse/updates': 'precise-updates/icehouse', + 'icehouse/proposed': 'precise-proposed/icehouse', } try: @@ -411,7 +415,7 @@ def get_host_ip(hostname): return ns_query(hostname) -def get_hostname(address): +def get_hostname(address, fqdn=True): """ Resolves hostname for given IP, or returns the input if it is already a hostname. @@ -430,7 +434,11 @@ def get_hostname(address): if not result: return None - # strip trailing . - if result.endswith('.'): - return result[:-1] - return result + if fqdn: + # strip trailing . + if result.endswith('.'): + return result[:-1] + else: + return result + else: + return result.split('.')[0] diff --git a/hooks/charmhelpers/contrib/storage/linux/ceph.py b/hooks/charmhelpers/contrib/storage/linux/ceph.py index 69b879ca..12417410 100644 --- a/hooks/charmhelpers/contrib/storage/linux/ceph.py +++ b/hooks/charmhelpers/contrib/storage/linux/ceph.py @@ -49,6 +49,9 @@ CEPH_CONF = """[global] auth supported = {auth} keyring = {keyring} mon host = {mon_hosts} + log to syslog = {use_syslog} + err to syslog = {use_syslog} + clog to syslog = {use_syslog} """ @@ -194,7 +197,7 @@ def get_ceph_nodes(): return hosts -def configure(service, key, auth): +def configure(service, key, auth, use_syslog): ''' Perform basic configuration of Ceph ''' create_keyring(service, key) create_key_file(service, key) @@ -202,7 +205,8 @@ def configure(service, key, auth): with open('/etc/ceph/ceph.conf', 'w') as ceph_conf: ceph_conf.write(CEPH_CONF.format(auth=auth, keyring=_keyring_path(service), - mon_hosts=",".join(map(str, hosts)))) + mon_hosts=",".join(map(str, hosts)), + use_syslog=use_syslog)) modprobe('rbd') diff --git a/hooks/charmhelpers/contrib/storage/linux/utils.py b/hooks/charmhelpers/contrib/storage/linux/utils.py index 5b9b6d47..c40218f0 100644 --- a/hooks/charmhelpers/contrib/storage/linux/utils.py +++ b/hooks/charmhelpers/contrib/storage/linux/utils.py @@ -22,4 +22,4 @@ def zap_disk(block_device): :param block_device: str: Full path of block device to clean. ''' - check_call(['sgdisk', '--zap-all', block_device]) + check_call(['sgdisk', '--zap-all', '--mbrtogpt', block_device]) diff --git a/hooks/charmhelpers/core/hookenv.py b/hooks/charmhelpers/core/hookenv.py index bb196dfa..505c202d 100644 --- a/hooks/charmhelpers/core/hookenv.py +++ b/hooks/charmhelpers/core/hookenv.py @@ -8,6 +8,7 @@ import os import json import yaml import subprocess +import sys import UserDict from subprocess import CalledProcessError @@ -149,6 +150,11 @@ def service_name(): return local_unit().split('/')[0] +def hook_name(): + """The name of the currently executing hook""" + return os.path.basename(sys.argv[0]) + + @cached def config(scope=None): """Juju charm configuration""" diff --git a/hooks/charmhelpers/core/host.py b/hooks/charmhelpers/core/host.py index 4a6a4a8c..cfd26847 100644 --- a/hooks/charmhelpers/core/host.py +++ b/hooks/charmhelpers/core/host.py @@ -194,7 +194,7 @@ def file_hash(path): return None -def restart_on_change(restart_map): +def restart_on_change(restart_map, stopstart=False): """Restart services based on configuration files changing This function is used a decorator, for example @@ -219,8 +219,14 @@ def restart_on_change(restart_map): for path in restart_map: if checksums[path] != file_hash(path): restarts += restart_map[path] - for service_name in list(OrderedDict.fromkeys(restarts)): - service('restart', service_name) + services_list = list(OrderedDict.fromkeys(restarts)) + if not stopstart: + for service_name in services_list: + service('restart', service_name) + else: + for action in ['stop', 'start']: + for service_name in services_list: + service(action, service_name) return wrapped_f return wrap @@ -245,3 +251,47 @@ def pwgen(length=None): random_chars = [ random.choice(alphanumeric_chars) for _ in range(length)] return(''.join(random_chars)) + + +def list_nics(nic_type): + '''Return a list of nics of given type(s)''' + if isinstance(nic_type, basestring): + int_types = [nic_type] + else: + int_types = nic_type + interfaces = [] + for int_type in int_types: + cmd = ['ip', 'addr', 'show', 'label', int_type + '*'] + ip_output = subprocess.check_output(cmd).split('\n') + ip_output = (line for line in ip_output if line) + for line in ip_output: + if line.split()[1].startswith(int_type): + interfaces.append(line.split()[1].replace(":", "")) + return interfaces + + +def set_nic_mtu(nic, mtu): + '''Set MTU on a network interface''' + cmd = ['ip', 'link', 'set', nic, 'mtu', mtu] + subprocess.check_call(cmd) + + +def get_nic_mtu(nic): + cmd = ['ip', 'addr', 'show', nic] + ip_output = subprocess.check_output(cmd).split('\n') + mtu = "" + for line in ip_output: + words = line.split() + if 'mtu' in words: + mtu = words[words.index("mtu") + 1] + return mtu + + +def get_nic_hwaddr(nic): + cmd = ['ip', '-o', '-0', 'addr', 'show', nic] + ip_output = subprocess.check_output(cmd) + hwaddr = "" + words = ip_output.split() + if 'link/ether' in words: + hwaddr = words[words.index('link/ether') + 1] + return hwaddr diff --git a/hooks/charmhelpers/fetch/__init__.py b/hooks/charmhelpers/fetch/__init__.py index fa0172a9..07bb707d 100644 --- a/hooks/charmhelpers/fetch/__init__.py +++ b/hooks/charmhelpers/fetch/__init__.py @@ -13,6 +13,7 @@ from charmhelpers.core.hookenv import ( log, ) import apt_pkg +import os CLOUD_ARCHIVE = """# Ubuntu Cloud Archive deb http://ubuntu-cloud.archive.canonical.com/ubuntu {} main @@ -43,8 +44,16 @@ CLOUD_ARCHIVE_POCKETS = { 'precise-havana/updates': 'precise-updates/havana', 'precise-updates/havana': 'precise-updates/havana', 'havana/proposed': 'precise-proposed/havana', - 'precies-havana/proposed': 'precise-proposed/havana', + 'precise-havana/proposed': 'precise-proposed/havana', 'precise-proposed/havana': 'precise-proposed/havana', + # Icehouse + 'icehouse': 'precise-updates/icehouse', + 'precise-icehouse': 'precise-updates/icehouse', + 'precise-icehouse/updates': 'precise-updates/icehouse', + 'precise-updates/icehouse': 'precise-updates/icehouse', + 'icehouse/proposed': 'precise-proposed/icehouse', + 'precise-icehouse/proposed': 'precise-proposed/icehouse', + 'precise-proposed/icehouse': 'precise-proposed/icehouse', } @@ -66,8 +75,10 @@ def filter_installed_packages(packages): def apt_install(packages, options=None, fatal=False): """Install one or more packages""" - options = options or [] - cmd = ['apt-get', '-y'] + if options is None: + options = ['--option=Dpkg::Options::=--force-confold'] + + cmd = ['apt-get', '--assume-yes'] cmd.extend(options) cmd.append('install') if isinstance(packages, basestring): @@ -76,10 +87,14 @@ def apt_install(packages, options=None, fatal=False): cmd.extend(packages) log("Installing {} with options: {}".format(packages, options)) + env = os.environ.copy() + if 'DEBIAN_FRONTEND' not in env: + env['DEBIAN_FRONTEND'] = 'noninteractive' + if fatal: - subprocess.check_call(cmd) + subprocess.check_call(cmd, env=env) else: - subprocess.call(cmd) + subprocess.call(cmd, env=env) def apt_update(fatal=False): @@ -93,7 +108,7 @@ def apt_update(fatal=False): def apt_purge(packages, fatal=False): """Purge one or more packages""" - cmd = ['apt-get', '-y', 'purge'] + cmd = ['apt-get', '--assume-yes', 'purge'] if isinstance(packages, basestring): cmd.append(packages) else: @@ -121,16 +136,18 @@ def apt_hold(packages, fatal=False): def add_source(source, key=None): if (source.startswith('ppa:') or - source.startswith('http:') or + source.startswith('http') or source.startswith('deb ') or - source.startswith('cloud-archive:')): + source.startswith('cloud-archive:')): subprocess.check_call(['add-apt-repository', '--yes', source]) elif source.startswith('cloud:'): apt_install(filter_installed_packages(['ubuntu-cloud-keyring']), fatal=True) pocket = source.split(':')[-1] if pocket not in CLOUD_ARCHIVE_POCKETS: - raise SourceConfigError('Unsupported cloud: source option %s' % pocket) + raise SourceConfigError( + 'Unsupported cloud: source option %s' % + pocket) actual_pocket = CLOUD_ARCHIVE_POCKETS[pocket] with open('/etc/apt/sources.list.d/cloud-archive.list', 'w') as apt: apt.write(CLOUD_ARCHIVE.format(actual_pocket)) @@ -139,7 +156,9 @@ def add_source(source, key=None): with open('/etc/apt/sources.list.d/proposed.list', 'w') as apt: apt.write(PROPOSED_POCKET.format(release)) if key: - subprocess.check_call(['apt-key', 'import', key]) + subprocess.check_call(['apt-key', 'adv', '--keyserver', + 'keyserver.ubuntu.com', '--recv', + key]) class SourceConfigError(Exception): @@ -220,7 +239,9 @@ def install_from_config(config_var_name): class BaseFetchHandler(object): + """Base class for FetchHandler implementations in fetch plugins""" + def can_handle(self, source): """Returns True if the source can be handled. Otherwise returns a string explaining why it cannot""" @@ -248,10 +269,13 @@ def plugins(fetch_handlers=None): for handler_name in fetch_handlers: package, classname = handler_name.rsplit('.', 1) try: - handler_class = getattr(importlib.import_module(package), classname) + handler_class = getattr( + importlib.import_module(package), + classname) plugin_list.append(handler_class()) except (ImportError, AttributeError): # Skip missing plugins so that they can be ommitted from # installation if desired - log("FetchHandler {} not found, skipping plugin".format(handler_name)) + log("FetchHandler {} not found, skipping plugin".format( + handler_name)) return plugin_list From 88b34376fdfe24ac907a23ffbfc36a95ca245c4f Mon Sep 17 00:00:00 2001 From: James Page Date: Thu, 27 Feb 2014 09:37:16 +0000 Subject: [PATCH 2/9] Resync latest ssl-everywhere helpers. --- charm-helpers-sync.yaml | 2 +- .../charmhelpers/contrib/hahelpers/apache.py | 17 ++-- .../charmhelpers/contrib/openstack/context.py | 86 ++++++++++++++----- 3 files changed, 75 insertions(+), 30 deletions(-) diff --git a/charm-helpers-sync.yaml b/charm-helpers-sync.yaml index 123d4de0..ba53189e 100644 --- a/charm-helpers-sync.yaml +++ b/charm-helpers-sync.yaml @@ -1,4 +1,4 @@ -branch: lp:charm-helpers +branch: lp:~openstack-charmers/charm-helpers/ssl-everywhere destination: hooks/charmhelpers include: - core diff --git a/hooks/charmhelpers/contrib/hahelpers/apache.py b/hooks/charmhelpers/contrib/hahelpers/apache.py index 3208a85c..8d5fb8ba 100644 --- a/hooks/charmhelpers/contrib/hahelpers/apache.py +++ b/hooks/charmhelpers/contrib/hahelpers/apache.py @@ -39,14 +39,15 @@ def get_cert(): def get_ca_cert(): - ca_cert = None - log("Inspecting identity-service relations for CA SSL certificate.", - level=INFO) - for r_id in relation_ids('identity-service'): - for unit in relation_list(r_id): - if not ca_cert: - ca_cert = relation_get('ca_cert', - rid=r_id, unit=unit) + ca_cert = config_get('ssl_ca') + if ca_cert is None: + log("Inspecting identity-service relations for CA SSL certificate.", + level=INFO) + for r_id in relation_ids('identity-service'): + for unit in relation_list(r_id): + if ca_cert is None: + ca_cert = relation_get('ca_cert', + rid=r_id, unit=unit) return ca_cert diff --git a/hooks/charmhelpers/contrib/openstack/context.py b/hooks/charmhelpers/contrib/openstack/context.py index 5785b6a1..11ddc0b0 100644 --- a/hooks/charmhelpers/contrib/openstack/context.py +++ b/hooks/charmhelpers/contrib/openstack/context.py @@ -1,5 +1,6 @@ import json import os +import time from base64 import b64decode @@ -113,7 +114,8 @@ class OSContextGenerator(object): class SharedDBContext(OSContextGenerator): interfaces = ['shared-db'] - def __init__(self, database=None, user=None, relation_prefix=None): + def __init__(self, + database=None, user=None, relation_prefix=None, ssl_dir=None): ''' Allows inspecting relation for settings prefixed with relation_prefix. This is useful for parsing access for multiple databases returned via @@ -122,6 +124,7 @@ class SharedDBContext(OSContextGenerator): self.relation_prefix = relation_prefix self.database = database self.user = user + self.ssl_dir = ssl_dir def __call__(self): self.database = self.database or config('database') @@ -139,19 +142,44 @@ class SharedDBContext(OSContextGenerator): for rid in relation_ids('shared-db'): for unit in related_units(rid): - passwd = relation_get(password_setting, rid=rid, unit=unit) + rdata = relation_get(rid=rid, unit=unit) ctxt = { - 'database_host': relation_get('db_host', rid=rid, - unit=unit), + 'database_host': rdata.get('db_host'), 'database': self.database, 'database_user': self.user, - 'database_password': passwd, + 'database_password': rdata.get(password_setting) } if context_complete(ctxt): + db_ssl(rdata, ctxt, self.ssl_dir) return ctxt return {} +def db_ssl(rdata, ctxt, ssl_dir): + if 'ssl_ca' in rdata and ssl_dir: + ca_path = os.path.join(ssl_dir, 'db-client.ca') + with open(ca_path, 'w') as fh: + fh.write(b64decode(rdata['ssl_ca'])) + ctxt['database_ssl_ca'] = ca_path + elif 'ssl_ca' in rdata: + log("Charm not setup for ssl support but ssl ca found") + return ctxt + if 'ssl_cert' in rdata: + cert_path = os.path.join( + ssl_dir, 'db-client.cert') + if not os.path.exists(cert_path): + log("Waiting 1m for ssl client cert validity") + time.sleep(60) + with open(cert_path, 'w') as fh: + fh.write(b64decode(rdata['ssl_cert'])) + ctxt['database_ssl_cert'] = cert_path + key_path = os.path.join(ssl_dir, 'db-client.key') + with open(key_path, 'w') as fh: + fh.write(b64decode(rdata['ssl_key'])) + ctxt['database_ssl_key'] = key_path + return ctxt + + class IdentityServiceContext(OSContextGenerator): interfaces = ['identity-service'] @@ -161,22 +189,19 @@ class IdentityServiceContext(OSContextGenerator): for rid in relation_ids('identity-service'): for unit in related_units(rid): + rdata = relation_get(rid=rid, unit=unit) ctxt = { - 'service_port': relation_get('service_port', rid=rid, - unit=unit), - 'service_host': relation_get('service_host', rid=rid, - unit=unit), - 'auth_host': relation_get('auth_host', rid=rid, unit=unit), - 'auth_port': relation_get('auth_port', rid=rid, unit=unit), - 'admin_tenant_name': relation_get('service_tenant', - rid=rid, unit=unit), - 'admin_user': relation_get('service_username', rid=rid, - unit=unit), - 'admin_password': relation_get('service_password', rid=rid, - unit=unit), - # XXX: Hard-coded http. - 'service_protocol': 'http', - 'auth_protocol': 'http', + 'service_port': rdata.get('service_port'), + 'service_host': rdata.get('service_host'), + 'auth_host': rdata.get('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': + rdata.get('service_protocol') or 'http', + 'auth_protocol': + rdata.get('auth_protocol') or 'http', } if context_complete(ctxt): return ctxt @@ -186,6 +211,9 @@ class IdentityServiceContext(OSContextGenerator): class AMQPContext(OSContextGenerator): interfaces = ['amqp'] + def __init__(self, ssl_dir=None): + self.ssl_dir = ssl_dir + def __call__(self): log('Generating template context for amqp') conf = config() @@ -196,7 +224,6 @@ class AMQPContext(OSContextGenerator): log('Could not generate shared_db context. ' 'Missing required charm config options: %s.' % e) raise OSContextError - ctxt = {} for rid in relation_ids('amqp'): for unit in related_units(rid): @@ -213,7 +240,24 @@ class AMQPContext(OSContextGenerator): unit=unit), 'rabbitmq_virtual_host': vhost, }) + ssl_port = relation_get('ssl_port', rid=rid, unit=unit) + if ssl_port: + ctxt['rabbit_ssl_port'] = ssl_port + ssl_ca = relation_get('ssl_ca', rid=rid, unit=unit) + if ssl_ca: + ctxt['rabbit_ssl_ca'] = ssl_ca + if context_complete(ctxt): + if 'rabbit_ssl_ca' in ctxt: + if not self.ssl_dir: + log(("Charm not setup for ssl support " + "but ssl ca found")) + break + ca_path = os.path.join( + self.ssl_dir, 'rabbit-client-ca.pem') + with open(ca_path, 'w') as fh: + fh.write(b64decode(ctxt['rabbit_ssl_ca'])) + ctxt['rabbit_ssl_ca'] = ca_path # Sufficient information found = break out! break # Used for active/active rabbitmq >= grizzly From a14f20b6826182bb8ec0dd86480641a970bd6055 Mon Sep 17 00:00:00 2001 From: James Page Date: Thu, 27 Feb 2014 11:35:12 +0000 Subject: [PATCH 3/9] Rework to use shared-db common contexts with appropriate prefixes --- hooks/quantum_contexts.py | 25 +--------------------- hooks/quantum_utils.py | 28 +++++++++++++++++-------- templates/folsom/nova.conf | 2 +- templates/folsom/ovs_quantum_plugin.ini | 2 +- templates/havana/nova.conf | 2 +- templates/havana/ovs_neutron_plugin.ini | 2 +- unit_tests/test_quantum_contexts.py | 20 ------------------ unit_tests/test_quantum_hooks.py | 3 +++ 8 files changed, 27 insertions(+), 57 deletions(-) diff --git a/hooks/quantum_contexts.py b/hooks/quantum_contexts.py index b6ae0cf8..2a76f6e0 100644 --- a/hooks/quantum_contexts.py +++ b/hooks/quantum_contexts.py @@ -15,7 +15,7 @@ from charmhelpers.fetch import ( ) from charmhelpers.contrib.openstack.context import ( OSContextGenerator, - context_complete + context_complete, ) from charmhelpers.contrib.openstack.utils import ( get_os_codename_install_source @@ -138,29 +138,6 @@ class QuantumGatewayContext(OSContextGenerator): return ctxt -class QuantumSharedDBContext(OSContextGenerator): - interfaces = ['shared-db'] - - def __call__(self): - for rid in relation_ids('shared-db'): - for unit in related_units(rid): - ctxt = { - 'database_host': relation_get('db_host', rid=rid, - unit=unit), - 'quantum_db': QUANTUM_DB, - 'quantum_user': DB_USER, - 'quantum_password': relation_get('quantum_password', - rid=rid, unit=unit), - 'nova_db': NOVA_DB, - 'nova_user': NOVA_DB_USER, - 'nova_password': relation_get('nova_password', rid=rid, - unit=unit) - } - if context_complete(ctxt): - return ctxt - return {} - - @cached def get_host_ip(hostname=None): try: diff --git a/hooks/quantum_utils.py b/hooks/quantum_utils.py index a7861ee5..28ee0768 100644 --- a/hooks/quantum_utils.py +++ b/hooks/quantum_utils.py @@ -34,7 +34,6 @@ from quantum_contexts import ( QuantumGatewayContext, NetworkServiceContext, L3AgentContext, - QuantumSharedDBContext, ExternalPortContext, ) @@ -42,6 +41,8 @@ from quantum_contexts import ( def valid_plugin(): return config('plugin') in CORE_PLUGIN[networking_name()] +QUANTUM_CONF_DIR = '/etc/quantum' + QUANTUM_OVS_PLUGIN_CONF = \ "/etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini" QUANTUM_NVP_PLUGIN_CONF = \ @@ -51,6 +52,8 @@ QUANTUM_PLUGIN_CONF = { NVP: QUANTUM_NVP_PLUGIN_CONF } +NEUTRON_CONF_DIR = '/etc/neutron' + NEUTRON_OVS_PLUGIN_CONF = \ "/etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini" NEUTRON_NVP_PLUGIN_CONF = \ @@ -142,12 +145,15 @@ NEUTRON_L3_AGENT_CONF = "/etc/neutron/l3_agent.ini" NEUTRON_DHCP_AGENT_CONF = "/etc/neutron/dhcp_agent.ini" NEUTRON_METADATA_AGENT_CONF = "/etc/neutron/metadata_agent.ini" +NOVA_CONF_DIR = '/etc/nova' NOVA_CONF = "/etc/nova/nova.conf" NOVA_CONFIG_FILES = { NOVA_CONF: { - 'hook_contexts': [context.AMQPContext(), - QuantumSharedDBContext(), + 'hook_contexts': [context.AMQPContext(ssl_dir=NOVA_CONF_DIR), + context.SharedDBContext( + relation_prefix=config('database'), + ssl_dir=NOVA_CONF_DIR), NetworkServiceContext(), QuantumGatewayContext()], 'services': ['nova-api-metadata'] @@ -182,7 +188,7 @@ NEUTRON_SHARED_CONFIG_FILES.update(NOVA_CONFIG_FILES) QUANTUM_OVS_CONFIG_FILES = { QUANTUM_CONF: { - 'hook_contexts': [context.AMQPContext(), + 'hook_contexts': [context.AMQPContext(ssl_dir=QUANTUM_CONF_DIR), QuantumGatewayContext()], 'services': ['quantum-l3-agent', 'quantum-dhcp-agent', @@ -195,7 +201,9 @@ QUANTUM_OVS_CONFIG_FILES = { }, # TODO: Check to see if this is actually required QUANTUM_OVS_PLUGIN_CONF: { - 'hook_contexts': [QuantumSharedDBContext(), + 'hook_contexts': [context.SharedDBContext( + relation_prefix=config('neutron-database'), + ssl_dir=QUANTUM_CONF_DIR), QuantumGatewayContext()], 'services': ['quantum-plugin-openvswitch-agent'] }, @@ -208,7 +216,7 @@ QUANTUM_OVS_CONFIG_FILES.update(QUANTUM_SHARED_CONFIG_FILES) NEUTRON_OVS_CONFIG_FILES = { NEUTRON_CONF: { - 'hook_contexts': [context.AMQPContext(), + 'hook_contexts': [context.AMQPContext(ssl_dir=NEUTRON_CONF_DIR), QuantumGatewayContext()], 'services': ['neutron-l3-agent', 'neutron-dhcp-agent', @@ -222,7 +230,9 @@ NEUTRON_OVS_CONFIG_FILES = { }, # TODO: Check to see if this is actually required NEUTRON_OVS_PLUGIN_CONF: { - 'hook_contexts': [QuantumSharedDBContext(), + 'hook_contexts': [context.SharedDBContext( + relation_prefix=config('neutron-database'), + ssl_dir=QUANTUM_CONF_DIR), QuantumGatewayContext()], 'services': ['neutron-plugin-openvswitch-agent'] }, @@ -235,7 +245,7 @@ NEUTRON_OVS_CONFIG_FILES.update(NEUTRON_SHARED_CONFIG_FILES) QUANTUM_NVP_CONFIG_FILES = { QUANTUM_CONF: { - 'hook_contexts': [context.AMQPContext()], + 'hook_contexts': [context.AMQPContext(ssl_dir=QUANTUM_CONF_DIR)], 'services': ['quantum-dhcp-agent', 'quantum-metadata-agent'] }, } @@ -243,7 +253,7 @@ QUANTUM_NVP_CONFIG_FILES.update(QUANTUM_SHARED_CONFIG_FILES) NEUTRON_NVP_CONFIG_FILES = { NEUTRON_CONF: { - 'hook_contexts': [context.AMQPContext()], + 'hook_contexts': [context.AMQPContext(ssl_dir=NEUTRON_CONF_DIR)], 'services': ['neutron-dhcp-agent', 'neutron-metadata-agent'] }, } diff --git a/templates/folsom/nova.conf b/templates/folsom/nova.conf index e58cfb32..baaab6f7 100644 --- a/templates/folsom/nova.conf +++ b/templates/folsom/nova.conf @@ -7,7 +7,7 @@ verbose=True api_paste_config=/etc/nova/api-paste.ini enabled_apis=metadata multi_host=True -sql_connection=mysql://{{ nova_user }}:{{ nova_password }}@{{ database_host }}/{{ nova_db }} +sql_connection = mysql://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %} quantum_metadata_proxy_shared_secret={{ shared_secret }} service_quantum_metadata_proxy=True # Access to message bus diff --git a/templates/folsom/ovs_quantum_plugin.ini b/templates/folsom/ovs_quantum_plugin.ini index 8d6d415a..45043409 100644 --- a/templates/folsom/ovs_quantum_plugin.ini +++ b/templates/folsom/ovs_quantum_plugin.ini @@ -1,5 +1,5 @@ [DATABASE] -sql_connection = mysql://{{ quantum_user }}:{{ quantum_password }}@{{ database_host }}/{{ quantum_db }}?charset=utf8 +sql_connection = mysql://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %} reconnect_interval = 2 [OVS] local_ip = {{ local_ip }} diff --git a/templates/havana/nova.conf b/templates/havana/nova.conf index df66747c..e3634664 100644 --- a/templates/havana/nova.conf +++ b/templates/havana/nova.conf @@ -7,7 +7,7 @@ verbose=True api_paste_config=/etc/nova/api-paste.ini enabled_apis=metadata multi_host=True -sql_connection=mysql://{{ nova_user }}:{{ nova_password }}@{{ database_host }}/{{ nova_db }} +sql_connection = mysql://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %} neutron_metadata_proxy_shared_secret={{ shared_secret }} service_neutron_metadata_proxy=True # Access to message bus diff --git a/templates/havana/ovs_neutron_plugin.ini b/templates/havana/ovs_neutron_plugin.ini index 95bf0a9a..879f5560 100644 --- a/templates/havana/ovs_neutron_plugin.ini +++ b/templates/havana/ovs_neutron_plugin.ini @@ -1,5 +1,5 @@ [DATABASE] -sql_connection = mysql://{{ quantum_user }}:{{ quantum_password }}@{{ database_host }}/{{ quantum_db }}?charset=utf8 +sql_connection = mysql://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %} reconnect_interval = 2 [OVS] local_ip = {{ local_ip }} diff --git a/unit_tests/test_quantum_contexts.py b/unit_tests/test_quantum_contexts.py index 5afc5994..87fcafe2 100644 --- a/unit_tests/test_quantum_contexts.py +++ b/unit_tests/test_quantum_contexts.py @@ -74,26 +74,6 @@ class _TestQuantumContext(CharmTestCase): self.assertEquals(self.context(), self.data_result) -class TestQuantumSharedDBContext(_TestQuantumContext): - def setUp(self): - super(TestQuantumSharedDBContext, self).setUp() - self.context = quantum_contexts.QuantumSharedDBContext() - self.test_relation.set( - {'db_host': '10.5.0.1', - 'nova_password': 'novapass', - 'quantum_password': 'quantumpass'} - ) - self.data_result = { - 'database_host': '10.5.0.1', - 'nova_user': 'nova', - 'nova_password': 'novapass', - 'nova_db': 'nova', - 'quantum_user': 'quantum', - 'quantum_password': 'quantumpass', - 'quantum_db': 'quantum' - } - - class TestNetworkServiceContext(_TestQuantumContext): def setUp(self): super(TestNetworkServiceContext, self).setUp() diff --git a/unit_tests/test_quantum_hooks.py b/unit_tests/test_quantum_hooks.py index 78d1a4f7..0bfd7024 100644 --- a/unit_tests/test_quantum_hooks.py +++ b/unit_tests/test_quantum_hooks.py @@ -1,4 +1,6 @@ from mock import MagicMock, patch, call +import charmhelpers.core.hookenv as hookenv +hookenv.config = MagicMock() import quantum_utils as utils _register_configs = utils.register_configs _restart_map = utils.restart_map @@ -53,6 +55,7 @@ class TestQuantumHooks(CharmTestCase): self.test_config.set('plugin', 'ovs') self.lsb_release.return_value = {'DISTRIB_CODENAME': 'precise'} self.b64decode.side_effect = passthrough + hookenv.config.side_effect = self.test_config.get def _call_hook(self, hookname): hooks.hooks.execute([ From 6cb32f30bb31717979f8782d0a4b8efef0b733ca Mon Sep 17 00:00:00 2001 From: James Page Date: Thu, 27 Feb 2014 11:39:37 +0000 Subject: [PATCH 4/9] Add config options for database data --- config.yaml | 16 ++++++++++++++++ hooks/quantum_utils.py | 8 +++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/config.yaml b/config.yaml index defb8f81..144c469f 100644 --- a/config.yaml +++ b/config.yaml @@ -50,3 +50,19 @@ options: type: string description: RabbitMQ Virtual Host default: openstack + database-user: + default: nova + type: string + description: Username for database access + database: + default: nova + type: string + description: Database name + neutron-database-user: + default: neutron + type: string + description: Username for Neutron database access (if enabled) + neutron-database: + default: neutron + type: string + description: Database name for Neutron (if enabled) diff --git a/hooks/quantum_utils.py b/hooks/quantum_utils.py index 28ee0768..25fa6945 100644 --- a/hooks/quantum_utils.py +++ b/hooks/quantum_utils.py @@ -151,9 +151,7 @@ NOVA_CONF = "/etc/nova/nova.conf" NOVA_CONFIG_FILES = { NOVA_CONF: { 'hook_contexts': [context.AMQPContext(ssl_dir=NOVA_CONF_DIR), - context.SharedDBContext( - relation_prefix=config('database'), - ssl_dir=NOVA_CONF_DIR), + context.SharedDBContext(ssl_dir=NOVA_CONF_DIR), NetworkServiceContext(), QuantumGatewayContext()], 'services': ['nova-api-metadata'] @@ -202,6 +200,8 @@ QUANTUM_OVS_CONFIG_FILES = { # TODO: Check to see if this is actually required QUANTUM_OVS_PLUGIN_CONF: { 'hook_contexts': [context.SharedDBContext( + database=config('neutron-database'), + user=config('neutron-database-user'), relation_prefix=config('neutron-database'), ssl_dir=QUANTUM_CONF_DIR), QuantumGatewayContext()], @@ -231,6 +231,8 @@ NEUTRON_OVS_CONFIG_FILES = { # TODO: Check to see if this is actually required NEUTRON_OVS_PLUGIN_CONF: { 'hook_contexts': [context.SharedDBContext( + database=config('neutron-database'), + user=config('neutron-database-user'), relation_prefix=config('neutron-database'), ssl_dir=QUANTUM_CONF_DIR), QuantumGatewayContext()], From b98744461d8fd35c67d66d23a65e65dfe23fb960 Mon Sep 17 00:00:00 2001 From: James Page Date: Thu, 27 Feb 2014 11:46:17 +0000 Subject: [PATCH 5/9] Fixup relation-set --- hooks/quantum_hooks.py | 18 ++++++++++++------ unit_tests/test_quantum_hooks.py | 5 +++-- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/hooks/quantum_hooks.py b/hooks/quantum_hooks.py index df47e6c4..8310ee24 100755 --- a/hooks/quantum_hooks.py +++ b/hooks/quantum_hooks.py @@ -78,6 +78,11 @@ def install(): def config_changed(): if openstack_upgrade_available(get_common_package()): do_openstack_upgrade(CONFIGS) + # Re-run joined hooks as config might have changed + for r_id in relation_ids('shared-db'): + db_joined(relation_id=r_id) + for r_id in relation_ids('amqp'): + amqp_joined(relation_id=r_id) if valid_plugin(): CONFIGS.write_all() configure_ovs() @@ -97,13 +102,14 @@ def upgrade_charm(): @hooks.hook('shared-db-relation-joined') -def db_joined(): - relation_set(quantum_username=DB_USER, - quantum_database=QUANTUM_DB, +def db_joined(relation_id=None): + relation_set(quantum_username=config('neutron-database-user'), + quantum_database=config('neutron-database'), quantum_hostname=unit_get('private-address'), - nova_username=NOVA_DB_USER, - nova_database=NOVA_DB, - nova_hostname=unit_get('private-address')) + nova_username=config('database-user'), + nova_database=config('database'), + nova_hostname=unit_get('private-address'), + relation_id=relation_id) @hooks.hook('amqp-relation-joined') diff --git a/unit_tests/test_quantum_hooks.py b/unit_tests/test_quantum_hooks.py index 0bfd7024..d827e7e7 100644 --- a/unit_tests/test_quantum_hooks.py +++ b/unit_tests/test_quantum_hooks.py @@ -121,12 +121,13 @@ class TestQuantumHooks(CharmTestCase): self.unit_get.return_value = 'myhostname' self._call_hook('shared-db-relation-joined') self.relation_set.assert_called_with( - quantum_username='quantum', - quantum_database='quantum', + quantum_username='neutron', + quantum_database='neutron', quantum_hostname='myhostname', nova_username='nova', nova_database='nova', nova_hostname='myhostname', + relation_id=None ) def test_amqp_joined(self): From 61dc5c7086db1461e9c25aa5eff4ae257120e553 Mon Sep 17 00:00:00 2001 From: James Page Date: Thu, 27 Feb 2014 11:52:09 +0000 Subject: [PATCH 6/9] Rework to use just a simple db connection - neutron access is not required --- config.yaml | 8 -------- hooks/quantum_hooks.py | 13 +++---------- hooks/quantum_utils.py | 16 ++-------------- templates/folsom/ovs_quantum_plugin.ini | 2 -- templates/havana/ovs_neutron_plugin.ini | 2 -- unit_tests/test_quantum_hooks.py | 12 +++--------- 6 files changed, 8 insertions(+), 45 deletions(-) diff --git a/config.yaml b/config.yaml index 144c469f..17472470 100644 --- a/config.yaml +++ b/config.yaml @@ -58,11 +58,3 @@ options: default: nova type: string description: Database name - neutron-database-user: - default: neutron - type: string - description: Username for Neutron database access (if enabled) - neutron-database: - default: neutron - type: string - description: Database name for Neutron (if enabled) diff --git a/hooks/quantum_hooks.py b/hooks/quantum_hooks.py index 8310ee24..c4782316 100755 --- a/hooks/quantum_hooks.py +++ b/hooks/quantum_hooks.py @@ -93,22 +93,15 @@ def config_changed(): @hooks.hook('upgrade-charm') def upgrade_charm(): - # NOTE(jamespage): Deal with changes to rabbitmq configuration for - # common virtual host across services - for r_id in relation_ids('amqp'): - amqp_joined(relation_id=r_id) install() config_changed() @hooks.hook('shared-db-relation-joined') def db_joined(relation_id=None): - relation_set(quantum_username=config('neutron-database-user'), - quantum_database=config('neutron-database'), - quantum_hostname=unit_get('private-address'), - nova_username=config('database-user'), - nova_database=config('database'), - nova_hostname=unit_get('private-address'), + relation_set(username=config('database-user'), + database=config('database'), + hostname=unit_get('private-address'), relation_id=relation_id) diff --git a/hooks/quantum_utils.py b/hooks/quantum_utils.py index 25fa6945..2905ae8c 100644 --- a/hooks/quantum_utils.py +++ b/hooks/quantum_utils.py @@ -197,14 +197,8 @@ QUANTUM_OVS_CONFIG_FILES = { 'hook_contexts': [NetworkServiceContext()], 'services': ['quantum-l3-agent'] }, - # TODO: Check to see if this is actually required QUANTUM_OVS_PLUGIN_CONF: { - 'hook_contexts': [context.SharedDBContext( - database=config('neutron-database'), - user=config('neutron-database-user'), - relation_prefix=config('neutron-database'), - ssl_dir=QUANTUM_CONF_DIR), - QuantumGatewayContext()], + 'hook_contexts': [QuantumGatewayContext()], 'services': ['quantum-plugin-openvswitch-agent'] }, EXT_PORT_CONF: { @@ -228,14 +222,8 @@ NEUTRON_OVS_CONFIG_FILES = { L3AgentContext()], 'services': ['neutron-l3-agent'] }, - # TODO: Check to see if this is actually required NEUTRON_OVS_PLUGIN_CONF: { - 'hook_contexts': [context.SharedDBContext( - database=config('neutron-database'), - user=config('neutron-database-user'), - relation_prefix=config('neutron-database'), - ssl_dir=QUANTUM_CONF_DIR), - QuantumGatewayContext()], + 'hook_contexts': [QuantumGatewayContext()], 'services': ['neutron-plugin-openvswitch-agent'] }, EXT_PORT_CONF: { diff --git a/templates/folsom/ovs_quantum_plugin.ini b/templates/folsom/ovs_quantum_plugin.ini index 45043409..16f350f3 100644 --- a/templates/folsom/ovs_quantum_plugin.ini +++ b/templates/folsom/ovs_quantum_plugin.ini @@ -1,6 +1,4 @@ [DATABASE] -sql_connection = mysql://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %} -reconnect_interval = 2 [OVS] local_ip = {{ local_ip }} tenant_network_type = gre diff --git a/templates/havana/ovs_neutron_plugin.ini b/templates/havana/ovs_neutron_plugin.ini index 879f5560..615e5d0a 100644 --- a/templates/havana/ovs_neutron_plugin.ini +++ b/templates/havana/ovs_neutron_plugin.ini @@ -1,6 +1,4 @@ [DATABASE] -sql_connection = mysql://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %} -reconnect_interval = 2 [OVS] local_ip = {{ local_ip }} tenant_network_type = gre diff --git a/unit_tests/test_quantum_hooks.py b/unit_tests/test_quantum_hooks.py index d827e7e7..09338d3a 100644 --- a/unit_tests/test_quantum_hooks.py +++ b/unit_tests/test_quantum_hooks.py @@ -110,23 +110,17 @@ class TestQuantumHooks(CharmTestCase): def test_upgrade_charm(self): _install = self.patch('install') _config_changed = self.patch('config_changed') - _amqp_joined = self.patch('amqp_joined') - self.relation_ids.return_value = ['amqp:0'] self._call_hook('upgrade-charm') self.assertTrue(_install.called) self.assertTrue(_config_changed.called) - _amqp_joined.assert_called_with(relation_id='amqp:0') def test_db_joined(self): self.unit_get.return_value = 'myhostname' self._call_hook('shared-db-relation-joined') self.relation_set.assert_called_with( - quantum_username='neutron', - quantum_database='neutron', - quantum_hostname='myhostname', - nova_username='nova', - nova_database='nova', - nova_hostname='myhostname', + username='nova', + database='nova', + hostname='myhostname', relation_id=None ) From 8abd593a87cd1192f1870b2846f1c9ebe129e47e Mon Sep 17 00:00:00 2001 From: James Page Date: Thu, 27 Feb 2014 11:59:09 +0000 Subject: [PATCH 7/9] Grab protocol info from nova-cloud-controller --- hooks/quantum_contexts.py | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/hooks/quantum_contexts.py b/hooks/quantum_contexts.py index 2a76f6e0..b8309ca5 100644 --- a/hooks/quantum_contexts.py +++ b/hooks/quantum_contexts.py @@ -73,29 +73,22 @@ class NetworkServiceContext(OSContextGenerator): def __call__(self): for rid in relation_ids('quantum-network-service'): for unit in related_units(rid): + rdata = relation_get(rid=rid, unit=unit) ctxt = { - 'keystone_host': relation_get('keystone_host', - rid=rid, unit=unit), - 'service_port': relation_get('service_port', rid=rid, - unit=unit), - 'auth_port': relation_get('auth_port', rid=rid, unit=unit), - 'service_tenant': relation_get('service_tenant', - rid=rid, unit=unit), - 'service_username': relation_get('service_username', - rid=rid, unit=unit), - 'service_password': relation_get('service_password', - rid=rid, unit=unit), - 'quantum_host': relation_get('quantum_host', - rid=rid, unit=unit), - 'quantum_port': relation_get('quantum_port', - rid=rid, unit=unit), - 'quantum_url': relation_get('quantum_url', - rid=rid, unit=unit), - 'region': relation_get('region', - rid=rid, unit=unit), - # XXX: Hard-coded http. - 'service_protocol': 'http', - 'auth_protocol': 'http', + '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 From a42b2861b83371b8414db4955779c0d86b51dfc4 Mon Sep 17 00:00:00 2001 From: James Page Date: Thu, 27 Feb 2014 12:02:41 +0000 Subject: [PATCH 8/9] Tidy imports --- hooks/quantum_hooks.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hooks/quantum_hooks.py b/hooks/quantum_hooks.py index c4782316..d822c935 100755 --- a/hooks/quantum_hooks.py +++ b/hooks/quantum_hooks.py @@ -45,10 +45,6 @@ from quantum_utils import ( reassign_agent_resources, stop_services ) -from quantum_contexts import ( - DB_USER, QUANTUM_DB, - NOVA_DB_USER, NOVA_DB, -) hooks = Hooks() CONFIGS = register_configs() From a9cc57727a1d0879c8ea6542126e5332f57d2baf Mon Sep 17 00:00:00 2001 From: James Page Date: Thu, 27 Feb 2014 12:21:53 +0000 Subject: [PATCH 9/9] Fixup agent re-assignment code for https keystone --- hooks/quantum_utils.py | 3 +-- unit_tests/test_quantum_utils.py | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hooks/quantum_utils.py b/hooks/quantum_utils.py index 2905ae8c..81588bf6 100644 --- a/hooks/quantum_utils.py +++ b/hooks/quantum_utils.py @@ -325,8 +325,7 @@ def reassign_agent_resources(): ''' Try to import neutronclient instead for havana+ ''' from neutronclient.v2_0 import client - # TODO: Fixup for https keystone - auth_url = 'http://%(keystone_host)s:%(auth_port)s/v2.0' % env + auth_url = '%(auth_protocol)s://%(keystone_host)s:%(auth_port)s/v2.0' % env quantum = client.Client(username=env['service_username'], password=env['service_password'], tenant_name=env['service_tenant'], diff --git a/unit_tests/test_quantum_utils.py b/unit_tests/test_quantum_utils.py index d85810c6..c2df8ff5 100644 --- a/unit_tests/test_quantum_utils.py +++ b/unit_tests/test_quantum_utils.py @@ -251,7 +251,8 @@ network_context = { 'service_tenant': 'baz', 'region': 'foo-bar', 'keystone_host': 'keystone', - 'auth_port': 5000 + 'auth_port': 5000, + 'auth_protocol': 'https' }