Resync, rebase
This commit is contained in:
commit
c508203a2c
@ -1,4 +1,4 @@
|
||||
branch: lp:~james-page/charm-helpers/multiple-https-networks
|
||||
branch: lp:charm-helpers
|
||||
destination: hooks/charmhelpers
|
||||
include:
|
||||
- core
|
||||
|
13
config.yaml
13
config.yaml
@ -115,4 +115,15 @@ options:
|
||||
192.168.0.0/24)
|
||||
.
|
||||
This network will be used for public endpoints.
|
||||
|
||||
prefer-ipv6:
|
||||
type: boolean
|
||||
default: False
|
||||
description: |
|
||||
If True enables IPv6 support. The charm will expect network interfaces
|
||||
to be configured with an IPv6 address. If set to False (default) IPv4
|
||||
is expected.
|
||||
.
|
||||
NOTE: these charms do not currently support IPv6 privacy extension. In
|
||||
order for this charm to function correctly, the privacy extension must be
|
||||
disabled and a non-temporary address must be configured/available on
|
||||
your network interface.
|
||||
|
@ -1,11 +1,16 @@
|
||||
import glob
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from functools import partial
|
||||
|
||||
from charmhelpers.core.hookenv import unit_get
|
||||
from charmhelpers.fetch import apt_install
|
||||
from charmhelpers.core.hookenv import (
|
||||
ERROR, log,
|
||||
WARNING,
|
||||
ERROR,
|
||||
log
|
||||
)
|
||||
|
||||
try:
|
||||
@ -164,13 +169,14 @@ def format_ipv6_addr(address):
|
||||
if is_ipv6(address):
|
||||
address = "[%s]" % address
|
||||
else:
|
||||
log("Not an valid ipv6 address: %s" % address,
|
||||
level=ERROR)
|
||||
log("Not a valid ipv6 address: %s" % address, level=WARNING)
|
||||
address = None
|
||||
|
||||
return address
|
||||
|
||||
|
||||
def get_iface_addr(iface='eth0', inet_type='AF_INET', inc_aliases=False, fatal=True, exc_list=None):
|
||||
def get_iface_addr(iface='eth0', inet_type='AF_INET', inc_aliases=False,
|
||||
fatal=True, exc_list=None):
|
||||
"""
|
||||
Return the assigned IP address for a given interface, if any, or [].
|
||||
"""
|
||||
@ -210,26 +216,105 @@ def get_iface_addr(iface='eth0', inet_type='AF_INET', inc_aliases=False, fatal=T
|
||||
if 'addr' in entry and entry['addr'] not in exc_list:
|
||||
addresses.append(entry['addr'])
|
||||
if fatal and not addresses:
|
||||
raise Exception("Interface '%s' doesn't have any %s addresses." % (iface, inet_type))
|
||||
raise Exception("Interface '%s' doesn't have any %s addresses." %
|
||||
(iface, inet_type))
|
||||
return addresses
|
||||
|
||||
get_ipv4_addr = partial(get_iface_addr, inet_type='AF_INET')
|
||||
|
||||
|
||||
def get_ipv6_addr(iface='eth0', inc_aliases=False, fatal=True, exc_list=None):
|
||||
def get_iface_from_addr(addr):
|
||||
"""Work out on which interface the provided address is configured."""
|
||||
for iface in netifaces.interfaces():
|
||||
addresses = netifaces.ifaddresses(iface)
|
||||
for inet_type in addresses:
|
||||
for _addr in addresses[inet_type]:
|
||||
_addr = _addr['addr']
|
||||
# link local
|
||||
ll_key = re.compile("(.+)%.*")
|
||||
raw = re.match(ll_key, _addr)
|
||||
if raw:
|
||||
_addr = raw.group(1)
|
||||
if _addr == addr:
|
||||
log("Address '%s' is configured on iface '%s'" %
|
||||
(addr, iface))
|
||||
return iface
|
||||
|
||||
msg = "Unable to infer net iface on which '%s' is configured" % (addr)
|
||||
raise Exception(msg)
|
||||
|
||||
|
||||
def sniff_iface(f):
|
||||
"""If no iface provided, inject net iface inferred from unit private
|
||||
address.
|
||||
"""
|
||||
Return the assigned IPv6 address for a given interface, if any, or [].
|
||||
def iface_sniffer(*args, **kwargs):
|
||||
if not kwargs.get('iface', None):
|
||||
kwargs['iface'] = get_iface_from_addr(unit_get('private-address'))
|
||||
|
||||
return f(*args, **kwargs)
|
||||
|
||||
return iface_sniffer
|
||||
|
||||
|
||||
@sniff_iface
|
||||
def get_ipv6_addr(iface=None, inc_aliases=False, fatal=True, exc_list=None,
|
||||
dynamic_only=True):
|
||||
"""Get assigned IPv6 address for a given interface.
|
||||
|
||||
Returns list of addresses found. If no address found, returns empty list.
|
||||
|
||||
If iface is None, we infer the current primary interface by doing a reverse
|
||||
lookup on the unit private-address.
|
||||
|
||||
We currently only support scope global IPv6 addresses i.e. non-temporary
|
||||
addresses. If no global IPv6 address is found, return the first one found
|
||||
in the ipv6 address list.
|
||||
"""
|
||||
addresses = get_iface_addr(iface=iface, inet_type='AF_INET6',
|
||||
inc_aliases=inc_aliases, fatal=fatal,
|
||||
exc_list=exc_list)
|
||||
remotly_addressable = []
|
||||
for address in addresses:
|
||||
if not address.startswith('fe80'):
|
||||
remotly_addressable.append(address)
|
||||
if fatal and not remotly_addressable:
|
||||
raise Exception("Interface '%s' doesn't have global ipv6 address." % iface)
|
||||
return remotly_addressable
|
||||
|
||||
if addresses:
|
||||
global_addrs = []
|
||||
for addr in addresses:
|
||||
key_scope_link_local = re.compile("^fe80::..(.+)%(.+)")
|
||||
m = re.match(key_scope_link_local, addr)
|
||||
if m:
|
||||
eui_64_mac = m.group(1)
|
||||
iface = m.group(2)
|
||||
else:
|
||||
global_addrs.append(addr)
|
||||
|
||||
if global_addrs:
|
||||
# Make sure any found global addresses are not temporary
|
||||
cmd = ['ip', 'addr', 'show', iface]
|
||||
out = subprocess.check_output(cmd)
|
||||
if dynamic_only:
|
||||
key = re.compile("inet6 (.+)/[0-9]+ scope global dynamic.*")
|
||||
else:
|
||||
key = re.compile("inet6 (.+)/[0-9]+ scope global.*")
|
||||
|
||||
addrs = []
|
||||
for line in out.split('\n'):
|
||||
line = line.strip()
|
||||
m = re.match(key, line)
|
||||
if m and 'temporary' not in line:
|
||||
# Return the first valid address we find
|
||||
for addr in global_addrs:
|
||||
if m.group(1) == addr:
|
||||
if not dynamic_only or \
|
||||
m.group(1).endswith(eui_64_mac):
|
||||
addrs.append(addr)
|
||||
|
||||
if addrs:
|
||||
return addrs
|
||||
|
||||
if fatal:
|
||||
raise Exception("Interface '%s' doesn't have a scope global "
|
||||
"non-temporary ipv6 address." % iface)
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def get_bridges(vnic_dir='/sys/devices/virtual/net'):
|
||||
|
@ -10,32 +10,62 @@ class OpenStackAmuletDeployment(AmuletDeployment):
|
||||
that is specifically for use by OpenStack charms.
|
||||
"""
|
||||
|
||||
def __init__(self, series=None, openstack=None, source=None):
|
||||
def __init__(self, series=None, openstack=None, source=None, stable=True):
|
||||
"""Initialize the deployment environment."""
|
||||
super(OpenStackAmuletDeployment, self).__init__(series)
|
||||
self.openstack = openstack
|
||||
self.source = source
|
||||
self.stable = stable
|
||||
# Note(coreycb): this needs to be changed when new next branches come
|
||||
# out.
|
||||
self.current_next = "trusty"
|
||||
|
||||
def _determine_branch_locations(self, other_services):
|
||||
"""Determine the branch locations for the other services.
|
||||
|
||||
Determine if the local branch being tested is derived from its
|
||||
stable or next (dev) branch, and based on this, use the corresonding
|
||||
stable or next branches for the other_services."""
|
||||
base_charms = ['mysql', 'mongodb', 'rabbitmq-server']
|
||||
|
||||
if self.stable:
|
||||
for svc in other_services:
|
||||
temp = 'lp:charms/{}'
|
||||
svc['location'] = temp.format(svc['name'])
|
||||
else:
|
||||
for svc in other_services:
|
||||
if svc['name'] in base_charms:
|
||||
temp = 'lp:charms/{}'
|
||||
svc['location'] = temp.format(svc['name'])
|
||||
else:
|
||||
temp = 'lp:~openstack-charmers/charms/{}/{}/next'
|
||||
svc['location'] = temp.format(self.current_next,
|
||||
svc['name'])
|
||||
return other_services
|
||||
|
||||
def _add_services(self, this_service, other_services):
|
||||
"""Add services to the deployment and set openstack-origin."""
|
||||
"""Add services to the deployment and set openstack-origin/source."""
|
||||
other_services = self._determine_branch_locations(other_services)
|
||||
|
||||
super(OpenStackAmuletDeployment, self)._add_services(this_service,
|
||||
other_services)
|
||||
name = 0
|
||||
|
||||
services = other_services
|
||||
services.append(this_service)
|
||||
use_source = ['mysql', 'mongodb', 'rabbitmq-server', 'ceph']
|
||||
use_source = ['mysql', 'mongodb', 'rabbitmq-server', 'ceph',
|
||||
'ceph-osd', 'ceph-radosgw']
|
||||
|
||||
if self.openstack:
|
||||
for svc in services:
|
||||
if svc[name] not in use_source:
|
||||
if svc['name'] not in use_source:
|
||||
config = {'openstack-origin': self.openstack}
|
||||
self.d.configure(svc[name], config)
|
||||
self.d.configure(svc['name'], config)
|
||||
|
||||
if self.source:
|
||||
for svc in services:
|
||||
if svc[name] in use_source:
|
||||
if svc['name'] in use_source:
|
||||
config = {'source': self.source}
|
||||
self.d.configure(svc[name], config)
|
||||
self.d.configure(svc['name'], config)
|
||||
|
||||
def _configure_services(self, configs):
|
||||
"""Configure all of the services."""
|
||||
|
@ -187,15 +187,16 @@ class OpenStackAmuletUtils(AmuletUtils):
|
||||
|
||||
f = opener.open("http://download.cirros-cloud.net/version/released")
|
||||
version = f.read().strip()
|
||||
cirros_img = "tests/cirros-{}-x86_64-disk.img".format(version)
|
||||
cirros_img = "cirros-{}-x86_64-disk.img".format(version)
|
||||
local_path = os.path.join('tests', cirros_img)
|
||||
|
||||
if not os.path.exists(cirros_img):
|
||||
if not os.path.exists(local_path):
|
||||
cirros_url = "http://{}/{}/{}".format("download.cirros-cloud.net",
|
||||
version, cirros_img)
|
||||
opener.retrieve(cirros_url, cirros_img)
|
||||
opener.retrieve(cirros_url, local_path)
|
||||
f.close()
|
||||
|
||||
with open(cirros_img) as f:
|
||||
with open(local_path) as f:
|
||||
image = glance.images.create(name=image_name, is_public=True,
|
||||
disk_format='qcow2',
|
||||
container_format='bare', data=f)
|
||||
|
@ -52,8 +52,9 @@ from charmhelpers.contrib.openstack.neutron import (
|
||||
from charmhelpers.contrib.network.ip import (
|
||||
get_address_in_network,
|
||||
get_ipv6_addr,
|
||||
is_address_in_network,
|
||||
get_netmask_for_address
|
||||
get_netmask_for_address,
|
||||
format_ipv6_addr,
|
||||
is_address_in_network
|
||||
)
|
||||
|
||||
CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt'
|
||||
@ -175,8 +176,10 @@ class SharedDBContext(OSContextGenerator):
|
||||
for rid in relation_ids('shared-db'):
|
||||
for unit in related_units(rid):
|
||||
rdata = relation_get(rid=rid, unit=unit)
|
||||
host = rdata.get('db_host')
|
||||
host = format_ipv6_addr(host) or host
|
||||
ctxt = {
|
||||
'database_host': rdata.get('db_host'),
|
||||
'database_host': host,
|
||||
'database': self.database,
|
||||
'database_user': self.user,
|
||||
'database_password': rdata.get(password_setting),
|
||||
@ -252,10 +255,15 @@ class IdentityServiceContext(OSContextGenerator):
|
||||
for rid in relation_ids('identity-service'):
|
||||
for unit in related_units(rid):
|
||||
rdata = relation_get(rid=rid, unit=unit)
|
||||
serv_host = rdata.get('service_host')
|
||||
serv_host = format_ipv6_addr(serv_host) or serv_host
|
||||
auth_host = rdata.get('auth_host')
|
||||
auth_host = format_ipv6_addr(auth_host) or auth_host
|
||||
|
||||
ctxt = {
|
||||
'service_port': rdata.get('service_port'),
|
||||
'service_host': rdata.get('service_host'),
|
||||
'auth_host': rdata.get('auth_host'),
|
||||
'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'),
|
||||
@ -304,11 +312,13 @@ class AMQPContext(OSContextGenerator):
|
||||
for unit in related_units(rid):
|
||||
if relation_get('clustered', rid=rid, unit=unit):
|
||||
ctxt['clustered'] = True
|
||||
ctxt['rabbitmq_host'] = relation_get('vip', rid=rid,
|
||||
unit=unit)
|
||||
vip = relation_get('vip', rid=rid, unit=unit)
|
||||
vip = format_ipv6_addr(vip) or vip
|
||||
ctxt['rabbitmq_host'] = vip
|
||||
else:
|
||||
ctxt['rabbitmq_host'] = relation_get('private-address',
|
||||
rid=rid, unit=unit)
|
||||
host = relation_get('private-address', rid=rid, unit=unit)
|
||||
host = format_ipv6_addr(host) or host
|
||||
ctxt['rabbitmq_host'] = host
|
||||
ctxt.update({
|
||||
'rabbitmq_user': username,
|
||||
'rabbitmq_password': relation_get('password', rid=rid,
|
||||
@ -347,8 +357,9 @@ class AMQPContext(OSContextGenerator):
|
||||
and len(related_units(rid)) > 1:
|
||||
rabbitmq_hosts = []
|
||||
for unit in related_units(rid):
|
||||
rabbitmq_hosts.append(relation_get('private-address',
|
||||
rid=rid, unit=unit))
|
||||
host = relation_get('private-address', rid=rid, unit=unit)
|
||||
host = format_ipv6_addr(host) or host
|
||||
rabbitmq_hosts.append(host)
|
||||
ctxt['rabbitmq_hosts'] = ','.join(rabbitmq_hosts)
|
||||
if not context_complete(ctxt):
|
||||
return {}
|
||||
@ -377,6 +388,7 @@ class CephContext(OSContextGenerator):
|
||||
ceph_addr = \
|
||||
relation_get('ceph-public-address', rid=rid, unit=unit) or \
|
||||
relation_get('private-address', rid=rid, unit=unit)
|
||||
ceph_addr = format_ipv6_addr(ceph_addr) or ceph_addr
|
||||
mon_hosts.append(ceph_addr)
|
||||
|
||||
ctxt = {
|
||||
@ -413,8 +425,9 @@ class HAProxyContext(OSContextGenerator):
|
||||
return {}
|
||||
|
||||
l_unit = local_unit().replace('/', '-')
|
||||
|
||||
if config('prefer-ipv6'):
|
||||
addr = get_ipv6_addr()
|
||||
addr = get_ipv6_addr(exc_list=[config('vip')])[0]
|
||||
else:
|
||||
addr = unit_get('private-address')
|
||||
|
||||
@ -443,7 +456,7 @@ class HAProxyContext(OSContextGenerator):
|
||||
|
||||
# NOTE(jamespage) no split configurations found, just use
|
||||
# private addresses
|
||||
if len(cluster_hosts) < 1:
|
||||
if not cluster_hosts:
|
||||
cluster_hosts[addr] = {}
|
||||
cluster_hosts[addr]['network'] = "{}/{}".format(
|
||||
addr,
|
||||
@ -463,6 +476,11 @@ class HAProxyContext(OSContextGenerator):
|
||||
'frontends': cluster_hosts,
|
||||
}
|
||||
|
||||
if config('haproxy-server-timeout'):
|
||||
ctxt['haproxy_server_timeout'] = config('haproxy-server-timeout')
|
||||
if config('haproxy-client-timeout'):
|
||||
ctxt['haproxy_client_timeout'] = config('haproxy-client-timeout')
|
||||
|
||||
if config('prefer-ipv6'):
|
||||
ctxt['local_host'] = 'ip6-localhost'
|
||||
ctxt['haproxy_host'] = '::'
|
||||
@ -870,3 +888,16 @@ class SyslogContext(OSContextGenerator):
|
||||
'use_syslog': config('use-syslog')
|
||||
}
|
||||
return ctxt
|
||||
|
||||
|
||||
class BindHostContext(OSContextGenerator):
|
||||
|
||||
def __call__(self):
|
||||
if config('prefer-ipv6'):
|
||||
return {
|
||||
'bind_host': '::'
|
||||
}
|
||||
else:
|
||||
return {
|
||||
'bind_host': '0.0.0.0'
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ def resolve_address(endpoint_type=PUBLIC):
|
||||
resolved_address = vip
|
||||
else:
|
||||
if config('prefer-ipv6'):
|
||||
fallback_addr = get_ipv6_addr()
|
||||
fallback_addr = get_ipv6_addr(exc_list=[config('vip')])[0]
|
||||
else:
|
||||
fallback_addr = unit_get(_address_map[endpoint_type]['fallback'])
|
||||
resolved_address = get_address_in_network(
|
||||
|
@ -14,8 +14,17 @@ defaults
|
||||
retries 3
|
||||
timeout queue 1000
|
||||
timeout connect 1000
|
||||
{% if haproxy_client_timeout -%}
|
||||
timeout client {{ haproxy_client_timeout }}
|
||||
{% else -%}
|
||||
timeout client 30000
|
||||
{% endif -%}
|
||||
|
||||
{% if haproxy_server_timeout -%}
|
||||
timeout server {{ haproxy_server_timeout }}
|
||||
{% else -%}
|
||||
timeout server 30000
|
||||
{% endif -%}
|
||||
|
||||
listen stats {{ stat_port }}
|
||||
mode http
|
||||
|
@ -4,6 +4,7 @@
|
||||
from collections import OrderedDict
|
||||
|
||||
import subprocess
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
@ -13,7 +14,9 @@ from charmhelpers.core.hookenv import (
|
||||
log as juju_log,
|
||||
charm_dir,
|
||||
ERROR,
|
||||
INFO
|
||||
INFO,
|
||||
relation_ids,
|
||||
relation_set
|
||||
)
|
||||
|
||||
from charmhelpers.contrib.storage.linux.lvm import (
|
||||
@ -22,6 +25,10 @@ from charmhelpers.contrib.storage.linux.lvm import (
|
||||
remove_lvm_physical_volume,
|
||||
)
|
||||
|
||||
from charmhelpers.contrib.network.ip import (
|
||||
get_ipv6_addr
|
||||
)
|
||||
|
||||
from charmhelpers.core.host import lsb_release, mounts, umount
|
||||
from charmhelpers.fetch import apt_install, apt_cache
|
||||
from charmhelpers.contrib.storage.linux.utils import is_block_device, zap_disk
|
||||
@ -457,3 +464,21 @@ def get_hostname(address, fqdn=True):
|
||||
return result
|
||||
else:
|
||||
return result.split('.')[0]
|
||||
|
||||
|
||||
def sync_db_with_multi_ipv6_addresses(database, database_user,
|
||||
relation_prefix=None):
|
||||
hosts = get_ipv6_addr(dynamic_only=False)
|
||||
|
||||
kwargs = {'database': database,
|
||||
'username': database_user,
|
||||
'hostname': json.dumps(hosts)}
|
||||
|
||||
if relation_prefix:
|
||||
keys = kwargs.keys()
|
||||
for key in keys:
|
||||
kwargs["%s_%s" % (relation_prefix, key)] = kwargs[key]
|
||||
del kwargs[key]
|
||||
|
||||
for rid in relation_ids('shared-db'):
|
||||
relation_set(relation_id=rid, **kwargs)
|
||||
|
@ -8,6 +8,7 @@ from charmhelpers.core.hookenv import (
|
||||
from charmhelpers.contrib.openstack.context import (
|
||||
OSContextGenerator,
|
||||
ApacheSSLContext as SSLContext,
|
||||
BindHostContext
|
||||
)
|
||||
|
||||
from charmhelpers.contrib.hahelpers.cluster import (
|
||||
@ -81,3 +82,15 @@ class LoggingConfigContext(OSContextGenerator):
|
||||
|
||||
def __call__(self):
|
||||
return {'debug': config('debug'), 'verbose': config('verbose')}
|
||||
|
||||
|
||||
class GlanceIPv6Context(BindHostContext):
|
||||
|
||||
def __call__(self):
|
||||
ctxt = super(GlanceIPv6Context, self).__call__()
|
||||
if config('prefer-ipv6'):
|
||||
ctxt['registry_host'] = '[::]'
|
||||
else:
|
||||
ctxt['registry_host'] = '0.0.0.0'
|
||||
|
||||
return ctxt
|
||||
|
@ -16,7 +16,8 @@ from glance_utils import (
|
||||
GLANCE_API_CONF,
|
||||
GLANCE_API_PASTE_INI,
|
||||
HAPROXY_CONF,
|
||||
ceph_config_file)
|
||||
ceph_config_file,
|
||||
setup_ipv6)
|
||||
|
||||
from charmhelpers.core.hookenv import (
|
||||
config,
|
||||
@ -53,7 +54,8 @@ from charmhelpers.contrib.openstack.utils import (
|
||||
configure_installation_source,
|
||||
get_os_codename_package,
|
||||
openstack_upgrade_available,
|
||||
lsb_release, )
|
||||
lsb_release,
|
||||
sync_db_with_multi_ipv6_addresses)
|
||||
|
||||
from charmhelpers.contrib.storage.linux.ceph import ensure_ceph_keyring
|
||||
from charmhelpers.payload.execd import execd_preinstall
|
||||
@ -61,6 +63,8 @@ from charmhelpers.contrib.network.ip import (
|
||||
get_address_in_network,
|
||||
get_netmask_for_address,
|
||||
get_iface_for_address,
|
||||
get_ipv6_addr,
|
||||
is_ipv6
|
||||
)
|
||||
from charmhelpers.contrib.openstack.ip import (
|
||||
canonical_url,
|
||||
@ -105,8 +109,14 @@ def db_joined():
|
||||
juju_log(e, level=ERROR)
|
||||
raise Exception(e)
|
||||
|
||||
relation_set(database=config('database'), username=config('database-user'),
|
||||
hostname=unit_get('private-address'))
|
||||
if config('prefer-ipv6'):
|
||||
sync_db_with_multi_ipv6_addresses(config('database'),
|
||||
config('database-user'))
|
||||
else:
|
||||
host = unit_get('private-address')
|
||||
relation_set(database=config('database'),
|
||||
username=config('database-user'),
|
||||
hostname=host)
|
||||
|
||||
|
||||
@hooks.hook('pgsql-db-relation-joined')
|
||||
@ -275,6 +285,11 @@ def keystone_changed():
|
||||
@hooks.hook('config-changed')
|
||||
@restart_on_change(restart_map(), stopstart=True)
|
||||
def config_changed():
|
||||
if config('prefer-ipv6'):
|
||||
setup_ipv6()
|
||||
sync_db_with_multi_ipv6_addresses(config('database'),
|
||||
config('database-user'))
|
||||
|
||||
if openstack_upgrade_available('glance-common'):
|
||||
juju_log('Upgrading OpenStack release')
|
||||
do_openstack_upgrade(CONFIGS)
|
||||
@ -300,6 +315,10 @@ def cluster_joined(relation_id=None):
|
||||
relation_id=relation_id,
|
||||
relation_settings={'{}-address'.format(addr_type): address}
|
||||
)
|
||||
if config('prefer-ipv6'):
|
||||
private_addr = get_ipv6_addr(exc_list=[config('vip')])[0]
|
||||
relation_set(relation_id=relation_id,
|
||||
relation_settings={'private-address': private_addr})
|
||||
|
||||
|
||||
@hooks.hook('cluster-relation-changed')
|
||||
@ -320,7 +339,7 @@ def upgrade_charm():
|
||||
|
||||
@hooks.hook('ha-relation-joined')
|
||||
def ha_relation_joined():
|
||||
config = get_hacluster_config()
|
||||
cluster_config = get_hacluster_config()
|
||||
|
||||
resources = {
|
||||
'res_glance_haproxy': 'lsb:haproxy'
|
||||
@ -331,14 +350,22 @@ def ha_relation_joined():
|
||||
}
|
||||
|
||||
vip_group = []
|
||||
for vip in config['vip'].split():
|
||||
for vip in cluster_config['vip'].split():
|
||||
if is_ipv6(vip):
|
||||
res_ks_vip = 'ocf:heartbeat:IPv6addr'
|
||||
vip_params = 'ipv6addr'
|
||||
else:
|
||||
res_ks_vip = 'ocf:heartbeat:IPaddr2'
|
||||
vip_params = 'ip'
|
||||
|
||||
iface = get_iface_for_address(vip)
|
||||
if iface is not None:
|
||||
vip_key = 'res_glance_{}_vip'.format(iface)
|
||||
resources[vip_key] = 'ocf:heartbeat:IPaddr2'
|
||||
resources[vip_key] = res_ks_vip
|
||||
resource_params[vip_key] = (
|
||||
'params ip="{vip}" cidr_netmask="{netmask}"'
|
||||
' nic="{iface}"'.format(vip=vip,
|
||||
'params {ip}="{vip}" cidr_netmask="{netmask}"'
|
||||
' nic="{iface}"'.format(ip=vip_params,
|
||||
vip=vip,
|
||||
iface=iface,
|
||||
netmask=get_netmask_for_address(vip))
|
||||
)
|
||||
@ -356,8 +383,8 @@ def ha_relation_joined():
|
||||
}
|
||||
|
||||
relation_set(init_services=init_services,
|
||||
corosync_bindiface=config['ha-bindiface'],
|
||||
corosync_mcastport=config['ha-mcastport'],
|
||||
corosync_bindiface=cluster_config['ha-bindiface'],
|
||||
corosync_mcastport=cluster_config['ha-mcastport'],
|
||||
resources=resources,
|
||||
resource_params=resource_params,
|
||||
clones=clones)
|
||||
|
@ -10,7 +10,8 @@ from collections import OrderedDict
|
||||
from charmhelpers.fetch import (
|
||||
apt_upgrade,
|
||||
apt_update,
|
||||
apt_install, )
|
||||
apt_install,
|
||||
add_source)
|
||||
|
||||
from charmhelpers.core.hookenv import (
|
||||
config,
|
||||
@ -21,7 +22,8 @@ from charmhelpers.core.hookenv import (
|
||||
from charmhelpers.core.host import (
|
||||
mkdir,
|
||||
service_stop,
|
||||
service_start
|
||||
service_start,
|
||||
lsb_release
|
||||
)
|
||||
|
||||
from charmhelpers.contrib.openstack import (
|
||||
@ -80,7 +82,8 @@ CONFIG_FILES = OrderedDict([
|
||||
context.PostgresqlDBContext(),
|
||||
context.IdentityServiceContext(),
|
||||
context.SyslogContext(),
|
||||
glance_contexts.LoggingConfigContext()],
|
||||
glance_contexts.LoggingConfigContext(),
|
||||
glance_contexts.GlanceIPv6Context()],
|
||||
'services': ['glance-registry']
|
||||
}),
|
||||
(GLANCE_API_CONF, {
|
||||
@ -92,7 +95,8 @@ CONFIG_FILES = OrderedDict([
|
||||
glance_contexts.ObjectStoreContext(),
|
||||
glance_contexts.HAProxyContext(),
|
||||
context.SyslogContext(),
|
||||
glance_contexts.LoggingConfigContext()],
|
||||
glance_contexts.LoggingConfigContext(),
|
||||
glance_contexts.GlanceIPv6Context()],
|
||||
'services': ['glance-api']
|
||||
}),
|
||||
(GLANCE_API_PASTE_INI, {
|
||||
@ -236,3 +240,19 @@ def services():
|
||||
for v in restart_map().values():
|
||||
_services = _services + v
|
||||
return list(set(_services))
|
||||
|
||||
|
||||
def setup_ipv6():
|
||||
ubuntu_rel = lsb_release()['DISTRIB_CODENAME'].lower()
|
||||
if ubuntu_rel < "trusty":
|
||||
raise Exception("IPv6 is not supported in the charms for Ubuntu "
|
||||
"versions less than Trusty 14.04")
|
||||
|
||||
# NOTE(xianghui): Need to install haproxy(1.5.3) from trusty-backports
|
||||
# to support ipv6 address, so check is required to make sure not
|
||||
# breaking other versions, IPv6 only support for >= Trusty
|
||||
if ubuntu_rel == 'trusty':
|
||||
add_source('deb http://archive.ubuntu.com/ubuntu trusty-backports'
|
||||
' main')
|
||||
apt_update()
|
||||
apt_install('haproxy/trusty-backports', fatal=True)
|
||||
|
@ -11,7 +11,7 @@ default_store = swift
|
||||
default_store = file
|
||||
{% endif -%}
|
||||
|
||||
bind_host = 0.0.0.0
|
||||
bind_host = {{ bind_host }}
|
||||
|
||||
{% if ext -%}
|
||||
bind_port = {{ ext }}
|
||||
@ -26,7 +26,7 @@ backlog = 4096
|
||||
|
||||
sql_idle_timeout = 3600
|
||||
workers = 1
|
||||
registry_host = 0.0.0.0
|
||||
registry_host = {{ registry_host }}
|
||||
registry_port = 9191
|
||||
registry_client_protocol = http
|
||||
|
||||
|
@ -3,7 +3,7 @@ verbose = {{ verbose }}
|
||||
use_syslog = {{ use_syslog }}
|
||||
debug = {{ debug }}
|
||||
|
||||
bind_host = 0.0.0.0
|
||||
bind_host = {{ bind_host }}
|
||||
bind_port = 9191
|
||||
log_file = /var/log/glance/registry.log
|
||||
backlog = 4096
|
||||
|
@ -16,7 +16,8 @@ class OpenStackAmuletDeployment(AmuletDeployment):
|
||||
self.openstack = openstack
|
||||
self.source = source
|
||||
self.stable = stable
|
||||
# Note(coreycb): this needs to be changed when new next branches come out.
|
||||
# Note(coreycb): this needs to be changed when new next branches come
|
||||
# out.
|
||||
self.current_next = "trusty"
|
||||
|
||||
def _determine_branch_locations(self, other_services):
|
||||
@ -51,7 +52,8 @@ class OpenStackAmuletDeployment(AmuletDeployment):
|
||||
|
||||
services = other_services
|
||||
services.append(this_service)
|
||||
use_source = ['mysql', 'mongodb', 'rabbitmq-server', 'ceph']
|
||||
use_source = ['mysql', 'mongodb', 'rabbitmq-server', 'ceph',
|
||||
'ceph-osd', 'ceph-radosgw']
|
||||
|
||||
if self.openstack:
|
||||
for svc in services:
|
||||
|
@ -70,3 +70,23 @@ class TestGlanceContexts(CharmTestCase):
|
||||
'namespace': 'glance'})
|
||||
self.assertTrue(mock_https.called)
|
||||
mock_unit_get.assert_called_with('private-address')
|
||||
|
||||
@patch('charmhelpers.contrib.openstack.context.config')
|
||||
@patch('glance_contexts.config')
|
||||
def test_glance_ipv6_context_service_enabled(self, mock_config,
|
||||
mock_context_config):
|
||||
mock_config.return_value = True
|
||||
mock_context_config.return_value = True
|
||||
ctxt = contexts.GlanceIPv6Context()
|
||||
self.assertEquals(ctxt(), {'bind_host': '::',
|
||||
'registry_host': '[::]'})
|
||||
|
||||
@patch('charmhelpers.contrib.openstack.context.config')
|
||||
@patch('glance_contexts.config')
|
||||
def test_glance_ipv6_context_service_disabled(self, mock_config,
|
||||
mock_context_config):
|
||||
mock_config.return_value = False
|
||||
mock_context_config.return_value = False
|
||||
ctxt = contexts.GlanceIPv6Context()
|
||||
self.assertEquals(ctxt(), {'bind_host': '0.0.0.0',
|
||||
'registry_host': '0.0.0.0'})
|
||||
|
@ -60,7 +60,9 @@ TO_PATCH = [
|
||||
'filter_installed_packages',
|
||||
'get_hacluster_config',
|
||||
'get_netmask_for_address',
|
||||
'get_iface_for_address'
|
||||
'get_iface_for_address',
|
||||
'get_ipv6_addr',
|
||||
'sync_db_with_multi_ipv6_addresses',
|
||||
]
|
||||
|
||||
|
||||
@ -87,7 +89,8 @@ class GlanceRelationTests(CharmTestCase):
|
||||
|
||||
def test_install_hook_precise_distro(self):
|
||||
self.test_config.set('openstack-origin', 'distro')
|
||||
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'precise'}
|
||||
self.lsb_release.return_value = {'DISTRIB_RELEASE': 12.04,
|
||||
'DISTRIB_CODENAME': 'precise'}
|
||||
self.service_stop.return_value = True
|
||||
relations.install_hook()
|
||||
self.configure_installation_source.assert_called_with(
|
||||
@ -103,6 +106,25 @@ class GlanceRelationTests(CharmTestCase):
|
||||
hostname='glance.foohost.com')
|
||||
self.unit_get.assert_called_with('private-address')
|
||||
|
||||
@patch.object(relations, 'sync_db_with_multi_ipv6_addresses')
|
||||
@patch.object(relations, 'get_ipv6_addr')
|
||||
def test_db_joined_with_ipv6(self, mock_get_ipv6_addr,
|
||||
mock_sync_db):
|
||||
self.test_config.set('prefer-ipv6', True)
|
||||
mock_get_ipv6_addr.return_value = ['2001:db8:1::1']
|
||||
mock_sync_db.return_value = MagicMock()
|
||||
self.is_relation_made.return_value = False
|
||||
relations.db_joined()
|
||||
relation_data = {
|
||||
'database': 'glance',
|
||||
'username': 'glance',
|
||||
}
|
||||
relation_data['hostname'] = '2001:db8:1::1'
|
||||
|
||||
self.sync_db_with_multi_ipv6_addresses.assert_called_with_once(
|
||||
'glance', 'glance')
|
||||
self.get_ipv6_addr.assert_called_once()
|
||||
|
||||
def test_postgresql_db_joined(self):
|
||||
self.unit_get.return_value = 'glance.foohost.com'
|
||||
self.is_relation_made.return_value = False
|
||||
@ -420,6 +442,7 @@ class GlanceRelationTests(CharmTestCase):
|
||||
|
||||
@patch.object(relations, 'CONFIGS')
|
||||
def test_cluster_changed(self, configs):
|
||||
self.test_config.set('prefer-ipv6', False)
|
||||
configs.complete_contexts = MagicMock()
|
||||
configs.complete_contexts.return_value = ['cluster']
|
||||
configs.write = MagicMock()
|
||||
@ -428,6 +451,20 @@ class GlanceRelationTests(CharmTestCase):
|
||||
call('/etc/haproxy/haproxy.cfg')],
|
||||
configs.write.call_args_list)
|
||||
|
||||
@patch.object(relations, 'relation_set')
|
||||
@patch.object(relations, 'CONFIGS')
|
||||
def test_cluster_changed_with_ipv6(self, configs, relation_set):
|
||||
self.test_config.set('prefer-ipv6', True)
|
||||
configs.complete_contexts = MagicMock()
|
||||
configs.complete_contexts.return_value = ['cluster']
|
||||
configs.write = MagicMock()
|
||||
self.get_ipv6_addr.return_value = '2001:db8:1::1'
|
||||
self.relation_ids.return_value = ['cluster:0']
|
||||
relations.cluster_changed()
|
||||
self.assertEquals([call('/etc/glance/glance-api.conf'),
|
||||
call('/etc/haproxy/haproxy.cfg')],
|
||||
configs.write.call_args_list)
|
||||
|
||||
@patch.object(relations, 'CONFIGS')
|
||||
def test_upgrade_charm(self, configs):
|
||||
self.filter_installed_packages.return_value = ['test']
|
||||
@ -461,6 +498,30 @@ class GlanceRelationTests(CharmTestCase):
|
||||
call(**args),
|
||||
])
|
||||
|
||||
def test_ha_relation_joined_with_ipv6(self):
|
||||
self.test_config.set('prefer-ipv6', True)
|
||||
self.get_hacluster_config.return_value = {
|
||||
'ha-bindiface': 'em0',
|
||||
'ha-mcastport': '8080',
|
||||
'vip': '2001:db8:1::1',
|
||||
}
|
||||
self.get_iface_for_address.return_value = 'eth1'
|
||||
self.get_netmask_for_address.return_value = '64'
|
||||
relations.ha_relation_joined()
|
||||
args = {
|
||||
'corosync_bindiface': 'em0',
|
||||
'corosync_mcastport': '8080',
|
||||
'init_services': {'res_glance_haproxy': 'haproxy'},
|
||||
'resources': {'res_glance_eth1_vip': 'ocf:heartbeat:IPv6addr',
|
||||
'res_glance_haproxy': 'lsb:haproxy'},
|
||||
'resource_params': {
|
||||
'res_glance_eth1_vip': 'params ipv6addr="2001:db8:1::1"'
|
||||
' cidr_netmask="64" nic="eth1"',
|
||||
'res_glance_haproxy': 'op monitor interval="5s"'},
|
||||
'clones': {'cl_glance_haproxy': 'res_glance_haproxy'}
|
||||
}
|
||||
self.relation_set.assert_called_with(**args)
|
||||
|
||||
def test_ha_relation_changed_not_clustered(self):
|
||||
self.relation_get.return_value = False
|
||||
relations.ha_relation_changed()
|
||||
|
Loading…
Reference in New Issue
Block a user