Rebase on trunk helpers

This commit is contained in:
James Page 2014-07-24 11:33:09 +01:00
parent 62dd6aa7dd
commit 32e85a148f
7 changed files with 92 additions and 40 deletions

View File

@ -1,4 +1,4 @@
branch: lp:~james-page/charm-helpers/network-splits
branch: lp:charm-helpers
destination: hooks/charmhelpers
include:
- core

View File

@ -146,12 +146,12 @@ def get_hacluster_config():
Obtains all relevant configuration from charm configuration required
for initiating a relation to hacluster:
ha-bindiface, ha-mcastport, vip, vip_iface, vip_cidr
ha-bindiface, ha-mcastport, vip
returns: dict: A dict containing settings keyed by setting name.
raises: HAIncompleteConfig if settings are missing.
'''
settings = ['ha-bindiface', 'ha-mcastport', 'vip', 'vip_iface', 'vip_cidr']
settings = ['ha-bindiface', 'ha-mcastport', 'vip']
conf = {}
for setting in settings:
conf[setting] = config_get(setting)
@ -163,7 +163,7 @@ def get_hacluster_config():
return conf
def canonical_url(configs, vip_setting='vip', address=None):
def canonical_url(configs, vip_setting='vip'):
'''
Returns the correct HTTP URL to this host given the state of HTTPS
configuration and hacluster.
@ -180,5 +180,5 @@ def canonical_url(configs, vip_setting='vip', address=None):
if is_clustered():
addr = config_get(vip_setting)
else:
addr = address or unit_get('private-address')
addr = unit_get('private-address')
return '%s://%s' % (scheme, addr)

View File

@ -1,5 +1,7 @@
import sys
from functools import partial
from charmhelpers.fetch import apt_install
from charmhelpers.core.hookenv import (
ERROR, log,
@ -28,7 +30,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 +53,21 @@ 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 not addr['addr'].startswith('fe80'):
cidr = netaddr.IPNetwork("%s/%s" % (addr['addr'],
addr['netmask']))
if cidr in network:
return str(cidr.ip)
if fallback is not None:
@ -69,6 +79,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 +114,43 @@ 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 not addr['addr'].startswith('fe80'):
cidr = netaddr.IPNetwork("%s/%s" % (addr['addr'],
addr['netmask']))
if address in cidr:
if key == 'iface':
return iface
else:
return addr[key]
return None
get_iface_for_address = partial(_get_for_address, key='iface')
get_netmask_for_address = partial(_get_for_address, key='netmask')

View File

@ -21,12 +21,16 @@ def del_bridge(name):
subprocess.check_call(["ovs-vsctl", "--", "--if-exists", "del-br", name])
def add_bridge_port(name, port):
def add_bridge_port(name, port, promisc=False):
''' Add a port to the named openvswitch bridge '''
log('Adding port {} to bridge {}'.format(port, name))
subprocess.check_call(["ovs-vsctl", "--", "--may-exist", "add-port",
name, port])
subprocess.check_call(["ip", "link", "set", port, "up"])
if promisc:
subprocess.check_call(["ip", "link", "set", port, "promisc", "on"])
else:
subprocess.check_call(["ip", "link", "set", port, "promisc", "off"])
def del_bridge_port(name, port):
@ -35,6 +39,7 @@ def del_bridge_port(name, port):
subprocess.check_call(["ovs-vsctl", "--", "--if-exists", "del-port",
name, port])
subprocess.check_call(["ip", "link", "set", port, "down"])
subprocess.check_call(["ip", "link", "set", port, "promisc", "off"])
def set_manager(manager):

View File

@ -25,6 +25,7 @@ from charmhelpers.core.hookenv import (
unit_get,
unit_private_ip,
ERROR,
INFO
)
from charmhelpers.contrib.hahelpers.cluster import (
@ -400,7 +401,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):
@ -712,7 +715,7 @@ class SubordinateConfigContext(OSContextGenerator):
self.interface = interface
def __call__(self):
ctxt = {}
ctxt = {'sections': {}}
for rid in relation_ids(self.interface):
for unit in related_units(rid):
sub_config = relation_get('subordinate_configuration',
@ -738,10 +741,14 @@ class SubordinateConfigContext(OSContextGenerator):
sub_config = sub_config[self.config_file]
for k, v in sub_config.iteritems():
if k == 'sections':
for section, config_dict in v.iteritems():
log("adding section '%s'" % (section))
ctxt[k][section] = config_dict
else:
ctxt[k] = v
if not ctxt:
ctxt['sections'] = {}
log("%d section(s) found" % (len(ctxt['sections'])), level=INFO)
return ctxt

View File

@ -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'''

View File

@ -322,6 +322,10 @@ def cmp_pkgrevno(package, revno, pkgcache=None):
import apt_pkg
if not pkgcache:
apt_pkg.init()
# Force Apt to build its cache in memory. That way we avoid race
# conditions with other applications building the cache in the same
# place.
apt_pkg.config.set("Dir::Cache::pkgcache", "")
pkgcache = apt_pkg.Cache()
pkg = pkgcache[package]
return apt_pkg.version_compare(pkg.current_ver.ver_str, revno)