Use canonical_url helper for endpoint resolution
This commit is contained in:
parent
11038ef5e7
commit
b1290e9351
2
.bzrignore
Normal file
2
.bzrignore
Normal file
@ -0,0 +1,2 @@
|
||||
.coverage
|
||||
bin
|
@ -1,5 +0,0 @@
|
||||
€}q(U collectorqUcoverage v3.7.1qUlinesq}q(Ui/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/contrib/storage/linux/ceph.pyq]Uh/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/contrib/openstack/neutron.pyq]Ug/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/contrib/storage/__init__.pyq]q KaUf/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/contrib/openstack/utils.pyq
|
||||
]q(KKKKK K
|
||||
KKKKKKKK K"K&K'K(K)K*K+K,K-K1K2K3K4K5K6K7K8K<K=K>K?K@KAKBKCKDKEKFKGKHKIKLKOKTKmKrK{K…K±KÄKÇK×KàM*M<MOMpM‡M“M§M²eUh/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/contrib/storage/linux/lvm.pyq]q
(KK
KK(K3KEKOeUk/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/contrib/openstack/templating.pyq]q(KKKKK
KKKKK-K.K0K7K8K9K:K<K=K>K?K@KAKBKCKFKJKKKUKaKkK´KµKÆKÏKÔKÚKóMMMeUW/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/__init__.pyq]qKaUm/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/contrib/openstack/alternatives.pyq]UM/home/jamespage/src/charms/reference-network/swift-proxy/hooks/swift_hooks.pyq]Um/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/contrib/storage/linux/__init__.pyq]qKaU_/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/fetch/archiveurl.pyq]UY/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/core/fstab.pyq]q(KKK KKKKKK!K)K+K2K7KAKHKPKfKgKnKoeU[/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/core/hookenv.pyq]q(KKKK K
|
||||
KKK
KKKKKKKKK&K/K2K=KFKGKIKNK\K`KdKhKmK{K€K…KŠK<C5A0>K”K™KžKÂKÃKÅKÌKÜKåKîKüKýMM
M M/M0M:M;MDMEMPMQM\M]MhMwM‡MˆM›M¢M©M³M¸M¹MºM½MÐMÒMÖMÚMâMðeU_/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/contrib/__init__.pyq]qKaUs/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/contrib/openstack/templates/__init__.pyq]U_/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/payload/__init__.pyq]UO/home/jamespage/src/charms/reference-network/swift-proxy/hooks/swift_context.pyq]U]/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/fetch/__init__.pyq ]q!(KKKKKKKKKKKKKKKKK K!K"K$K%K&K'K(K)K*K,K-K.K/K0K1K2K4K5K6K7K8K9K:K<K=K>K?K@KAKBKCKJKMKNKOKRKSKVKWKZK[K^K`KbKgKlKoKvK‹KœK«K±K¼KËKêKëKìMM"M(M;eUh/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/contrib/openstack/context.pyq"]Ua/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/contrib/network/ip.pyq#]Uj/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/contrib/storage/linux/utils.pyq$]q%(KKKKKKK(eUg/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/contrib/hahelpers/apache.pyq&]Uh/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/contrib/hahelpers/cluster.pyq']Ui/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/contrib/hahelpers/__init__.pyq(]U\/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/core/__init__.pyq)]q*KaUM/home/jamespage/src/charms/reference-network/swift-proxy/hooks/swift_utils.pyq+]Ui/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/contrib/openstack/__init__.pyq,]q-KaU[/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/fetch/bzrurl.pyq.]U\/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/payload/execd.pyq/]Ug/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/contrib/network/__init__.pyq0]UX/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/core/host.pyq1]q2(KKK K
|
||||
KKK
KKKKKKKK!K&K/K5KBKXKcKnKzKŠK•K›K¡K²KÀKÉKÔKùMMM M&M1M;eUm/home/jamespage/src/charms/reference-network/swift-proxy/hooks/charmhelpers/contrib/storage/linux/loopback.pyq3]q4(KKKKK K-euu.
|
@ -28,7 +28,7 @@ def _validate_cidr(network):
|
||||
|
||||
def get_address_in_network(network, fallback=None, fatal=False):
|
||||
"""
|
||||
Get an IPv4 address within the network from the host.
|
||||
Get an IPv4 or IPv6 address within the network from the host.
|
||||
|
||||
:param network (str): CIDR presentation format. For example,
|
||||
'192.168.1.0/24'.
|
||||
@ -51,14 +51,23 @@ def get_address_in_network(network, fallback=None, fatal=False):
|
||||
not_found_error_out()
|
||||
|
||||
_validate_cidr(network)
|
||||
network = netaddr.IPNetwork(network)
|
||||
for iface in netifaces.interfaces():
|
||||
addresses = netifaces.ifaddresses(iface)
|
||||
if netifaces.AF_INET in addresses:
|
||||
if network.version == 4 and netifaces.AF_INET in addresses:
|
||||
addr = addresses[netifaces.AF_INET][0]['addr']
|
||||
netmask = addresses[netifaces.AF_INET][0]['netmask']
|
||||
cidr = netaddr.IPNetwork("%s/%s" % (addr, netmask))
|
||||
if cidr in netaddr.IPNetwork(network):
|
||||
if cidr in network:
|
||||
return str(cidr.ip)
|
||||
if network.version == 6 and netifaces.AF_INET6 in addresses:
|
||||
for addr in addresses[netifaces.AF_INET6]:
|
||||
if 'fe80' not in addr['addr']:
|
||||
netmask = addr['netmask']
|
||||
cidr = netaddr.IPNetwork("%s/%s" % (addr['addr'],
|
||||
netmask))
|
||||
if cidr in network:
|
||||
return str(cidr.ip)
|
||||
|
||||
if fallback is not None:
|
||||
return fallback
|
||||
@ -69,6 +78,17 @@ def get_address_in_network(network, fallback=None, fatal=False):
|
||||
return None
|
||||
|
||||
|
||||
def is_ipv6(address):
|
||||
'''Determine whether provided address is IPv6 or not'''
|
||||
try:
|
||||
address = netaddr.IPAddress(address)
|
||||
except netaddr.AddrFormatError:
|
||||
# probably a hostname - so not an address at all!
|
||||
return False
|
||||
else:
|
||||
return address.version == 6
|
||||
|
||||
|
||||
def is_address_in_network(network, address):
|
||||
"""
|
||||
Determine whether the provided address is within a network range.
|
||||
@ -93,3 +113,60 @@ def is_address_in_network(network, address):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def _get_for_address(address, key):
|
||||
"""Retrieve an attribute of or the physical interface that
|
||||
the IP address provided could be bound to.
|
||||
|
||||
:param address (str): An individual IPv4 or IPv6 address without a net
|
||||
mask or subnet prefix. For example, '192.168.1.1'.
|
||||
:param key: 'iface' for the physical interface name or an attribute
|
||||
of the configured interface, for example 'netmask'.
|
||||
:returns str: Requested attribute or None if address is not bindable.
|
||||
"""
|
||||
address = netaddr.IPAddress(address)
|
||||
for iface in netifaces.interfaces():
|
||||
addresses = netifaces.ifaddresses(iface)
|
||||
if address.version == 4 and netifaces.AF_INET in addresses:
|
||||
addr = addresses[netifaces.AF_INET][0]['addr']
|
||||
netmask = addresses[netifaces.AF_INET][0]['netmask']
|
||||
cidr = netaddr.IPNetwork("%s/%s" % (addr, netmask))
|
||||
if address in cidr:
|
||||
if key == 'iface':
|
||||
return iface
|
||||
else:
|
||||
return addresses[netifaces.AF_INET][0][key]
|
||||
if address.version == 6 and netifaces.AF_INET6 in addresses:
|
||||
for addr in addresses[netifaces.AF_INET6]:
|
||||
if 'fe80' not in addr['addr']:
|
||||
cidr = netaddr.IPNetwork("%s/%s" % (addr['addr'],
|
||||
addr['netmask']))
|
||||
if address in cidr:
|
||||
if key == 'iface':
|
||||
return iface
|
||||
else:
|
||||
return addr[key]
|
||||
return None
|
||||
|
||||
|
||||
def get_iface_for_address(address):
|
||||
"""Determine the physical interface to which an IP address could be bound
|
||||
|
||||
:param address (str): An individual IPv4 or IPv6 address without a net
|
||||
mask or subnet prefix. For example, '192.168.1.1'.
|
||||
:returns str: Interface name or None if address is not bindable.
|
||||
"""
|
||||
return _get_for_address(address, 'iface')
|
||||
|
||||
|
||||
def get_netmask_for_address(address):
|
||||
"""Determine the netmask of the physical interface to which and IP address
|
||||
could be bound
|
||||
|
||||
:param address (str): An individual IPv4 or IPv6 address without a net
|
||||
mask or subnet prefix. For example, '192.168.1.1'.
|
||||
:returns str: Netmask of configured interface or None if address is
|
||||
not bindable.
|
||||
"""
|
||||
return _get_for_address(address, 'netmask')
|
||||
|
@ -148,7 +148,7 @@ class SharedDBContext(OSContextGenerator):
|
||||
if self.relation_prefix is not None:
|
||||
hostname_key = "{}_hostname".format(self.relation_prefix)
|
||||
else:
|
||||
hostname_key = "hostname"
|
||||
hostname_key = "hostname"
|
||||
access_hostname = get_address_in_network(access_network,
|
||||
unit_get('private-address'))
|
||||
set_hostname = relation_get(attribute=hostname_key,
|
||||
@ -400,7 +400,9 @@ class HAProxyContext(OSContextGenerator):
|
||||
|
||||
cluster_hosts = {}
|
||||
l_unit = local_unit().replace('/', '-')
|
||||
cluster_hosts[l_unit] = unit_get('private-address')
|
||||
cluster_hosts[l_unit] = \
|
||||
get_address_in_network(config('os-internal-network'),
|
||||
unit_get('private-address'))
|
||||
|
||||
for rid in relation_ids('cluster'):
|
||||
for unit in related_units(rid):
|
||||
|
75
hooks/charmhelpers/contrib/openstack/ip.py
Normal file
75
hooks/charmhelpers/contrib/openstack/ip.py
Normal file
@ -0,0 +1,75 @@
|
||||
from charmhelpers.core.hookenv import (
|
||||
config,
|
||||
unit_get,
|
||||
)
|
||||
|
||||
from charmhelpers.contrib.network.ip import (
|
||||
get_address_in_network,
|
||||
is_address_in_network,
|
||||
is_ipv6,
|
||||
)
|
||||
|
||||
from charmhelpers.contrib.hahelpers.cluster import is_clustered
|
||||
|
||||
PUBLIC = 'public'
|
||||
INTERNAL = 'int'
|
||||
ADMIN = 'admin'
|
||||
|
||||
_address_map = {
|
||||
PUBLIC: {
|
||||
'config': 'os-public-network',
|
||||
'fallback': 'public-address'
|
||||
},
|
||||
INTERNAL: {
|
||||
'config': 'os-internal-network',
|
||||
'fallback': 'private-address'
|
||||
},
|
||||
ADMIN: {
|
||||
'config': 'os-admin-network',
|
||||
'fallback': 'private-address'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def canonical_url(configs, endpoint_type=PUBLIC):
|
||||
'''
|
||||
Returns the correct HTTP URL to this host given the state of HTTPS
|
||||
configuration, hacluster and charm configuration.
|
||||
|
||||
:configs OSTemplateRenderer: A config tempating object to inspect for
|
||||
a complete https context.
|
||||
:endpoint_type str: The endpoint type to resolve.
|
||||
|
||||
:returns str: Base URL for services on the current service unit.
|
||||
'''
|
||||
scheme = 'http'
|
||||
if 'https' in configs.complete_contexts():
|
||||
scheme = 'https'
|
||||
address = resolve_address(endpoint_type)
|
||||
if is_ipv6(address):
|
||||
address = "[{}]".format(address)
|
||||
return '%s://%s' % (scheme, address)
|
||||
|
||||
|
||||
def resolve_address(endpoint_type=PUBLIC):
|
||||
resolved_address = None
|
||||
if is_clustered():
|
||||
if config(_address_map[endpoint_type]['config']) is None:
|
||||
# Assume vip is simple and pass back directly
|
||||
resolved_address = config('vip')
|
||||
else:
|
||||
for vip in config('vip').split():
|
||||
if is_address_in_network(
|
||||
config(_address_map[endpoint_type]['config']),
|
||||
vip):
|
||||
resolved_address = vip
|
||||
else:
|
||||
resolved_address = get_address_in_network(
|
||||
config(_address_map[endpoint_type]['config']),
|
||||
unit_get(_address_map[endpoint_type]['fallback'])
|
||||
)
|
||||
if resolved_address is None:
|
||||
raise ValueError('Unable to resolve a suitable IP address'
|
||||
' based on charm state and configuration')
|
||||
else:
|
||||
return resolved_address
|
@ -27,7 +27,12 @@ listen stats :8888
|
||||
|
||||
{% if units -%}
|
||||
{% for service, ports in service_ports.iteritems() -%}
|
||||
listen {{ service }} 0.0.0.0:{{ ports[0] }}
|
||||
listen {{ service }}_ipv4 0.0.0.0:{{ ports[0] }}
|
||||
balance roundrobin
|
||||
{% for unit, address in units.iteritems() -%}
|
||||
server {{ unit }} {{ address }}:{{ ports[1] }} check
|
||||
{% endfor %}
|
||||
listen {{ service }}_ipv6 :::{{ ports[0] }}
|
||||
balance roundrobin
|
||||
{% for unit, address in units.iteritems() -%}
|
||||
server {{ unit }} {{ address }}:{{ ports[1] }} check
|
||||
|
@ -1,25 +0,0 @@
|
||||
|
||||
from netaddr import IPAddress, IPNetwork
|
||||
|
||||
class VIPConfiguration():
|
||||
|
||||
def __init__(self, configuration):
|
||||
self.vip = []
|
||||
for vip in configuration.split():
|
||||
self.vips.append(IPAddress(vip))
|
||||
|
||||
def getVIP(self, network):
|
||||
''' Determine the VIP for the provided network
|
||||
:network str: CIDR presented network, e.g. 192.168.1.1/24
|
||||
:returns str: IP address of VIP in provided network or None
|
||||
'''
|
||||
network = IPNetwork(network)
|
||||
for vip in self.vips:
|
||||
if vip in network:
|
||||
return str(vip)
|
||||
return None
|
||||
|
||||
def getNIC(self, network):
|
||||
''' Determine the physical network interface in use
|
||||
for the specified network'''
|
||||
|
@ -47,7 +47,11 @@ from charmhelpers.fetch import (
|
||||
apt_update
|
||||
)
|
||||
from charmhelpers.payload.execd import execd_preinstall
|
||||
from charmhelpers.contrib.network.ip import get_address_in_network
|
||||
|
||||
from charmhelpers.contrib.openstack.ip import (
|
||||
canonical_url,
|
||||
PUBLIC, INTERNAL, ADMIN
|
||||
)
|
||||
|
||||
extra_pkgs = [
|
||||
"haproxy",
|
||||
@ -93,25 +97,12 @@ def install():
|
||||
def keystone_joined(relid=None):
|
||||
if not cluster.eligible_leader(SWIFT_HA_RES):
|
||||
return
|
||||
if cluster.is_clustered():
|
||||
public_ip, internal_ip, admin_ip = config('vip')
|
||||
else:
|
||||
public_ip = get_address_in_network(config('os-public-network'),
|
||||
unit_get('public-address'))
|
||||
internal_ip = get_address_in_network(config('os-internal-network'),
|
||||
unit_get('private-address'))
|
||||
admin_ip = get_address_in_network(config('os-admin-network'),
|
||||
unit_get('private-address'))
|
||||
port = config('bind-port')
|
||||
if cluster.https():
|
||||
proto = 'https'
|
||||
else:
|
||||
proto = 'http'
|
||||
admin_url = '%s://%s:%s' % (proto, admin_ip, port)
|
||||
internal_url = '%s://%s:%s/v1/AUTH_$(tenant_id)s' % (proto, internal_ip,
|
||||
port)
|
||||
public_url = '%s://%s:%s/v1/AUTH_$(tenant_id)s' % (proto, public_ip,
|
||||
port)
|
||||
admin_url = '%s://%s:%s' % (canonical_url(CONFIGS, ADMIN), port)
|
||||
internal_url = '%s://%s:%s/v1/AUTH_$(tenant_id)s' % \
|
||||
(canonical_url(CONFIGS, INTERNAL), port)
|
||||
public_url = '%s://%s:%s/v1/AUTH_$(tenant_id)s' % \
|
||||
(canonical_url(CONFIGS, PUBLIC), port)
|
||||
relation_set(service='swift',
|
||||
region=config('region'),
|
||||
public_url=public_url,
|
||||
|
Loading…
Reference in New Issue
Block a user