Use canonical_url helper for endpoint resolution
This commit is contained in:
		
							
								
								
									
										2
									
								
								.bzrignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								.bzrignore
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
.coverage
 | 
			
		||||
bin
 | 
			
		||||
@@ -1,5 +0,0 @@
 | 
			
		||||
<EFBFBD>}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<EFBFBD>K<EFBFBD>K<EFBFBD>K<EFBFBD>K<EFBFBD>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
 | 
			
		||||
@@ -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,13 +51,22 @@ 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:
 | 
			
		||||
@@ -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')
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user