3
from functools import partial
5
from charmhelpers.fetch import apt_install
6
from charmhelpers.core.hookenv import (
13
apt_install('python-netifaces')
19
apt_install('python-netaddr')
23
def _validate_cidr(network):
25
netaddr.IPNetwork(network)
26
except (netaddr.core.AddrFormatError, ValueError):
27
raise ValueError("Network (%s) is not in CIDR presentation format" %
31
def get_address_in_network(network, fallback=None, fatal=False):
33
Get an IPv4 or IPv6 address within the network from the host.
35
:param network (str): CIDR presentation format. For example,
37
:param fallback (str): If no address is found, return fallback.
38
:param fatal (boolean): If no address is found, fallback is not
39
set and fatal is True then exit(1).
43
def not_found_error_out():
44
log("No IP address found in network: %s" % network,
49
if fallback is not None:
55
_validate_cidr(network)
56
network = netaddr.IPNetwork(network)
57
for iface in netifaces.interfaces():
58
addresses = netifaces.ifaddresses(iface)
59
if network.version == 4 and netifaces.AF_INET in addresses:
60
addr = addresses[netifaces.AF_INET][0]['addr']
61
netmask = addresses[netifaces.AF_INET][0]['netmask']
62
cidr = netaddr.IPNetwork("%s/%s" % (addr, netmask))
65
if network.version == 6 and netifaces.AF_INET6 in addresses:
66
for addr in addresses[netifaces.AF_INET6]:
67
if not addr['addr'].startswith('fe80'):
68
cidr = netaddr.IPNetwork("%s/%s" % (addr['addr'],
73
if fallback is not None:
83
'''Determine whether provided address is IPv6 or not'''
85
address = netaddr.IPAddress(address)
86
except netaddr.AddrFormatError:
87
# probably a hostname - so not an address at all!
90
return address.version == 6
93
def is_address_in_network(network, address):
95
Determine whether the provided address is within a network range.
97
:param network (str): CIDR presentation format. For example,
99
:param address: An individual IPv4 or IPv6 address without a net
100
mask or subnet prefix. For example, '192.168.1.1'.
101
:returns boolean: Flag indicating whether address is in network.
104
network = netaddr.IPNetwork(network)
105
except (netaddr.core.AddrFormatError, ValueError):
106
raise ValueError("Network (%s) is not in CIDR presentation format" %
109
address = netaddr.IPAddress(address)
110
except (netaddr.core.AddrFormatError, ValueError):
111
raise ValueError("Address (%s) is not in correct presentation format" %
113
if address in network:
119
def _get_for_address(address, key):
120
"""Retrieve an attribute of or the physical interface that
121
the IP address provided could be bound to.
123
:param address (str): An individual IPv4 or IPv6 address without a net
124
mask or subnet prefix. For example, '192.168.1.1'.
125
:param key: 'iface' for the physical interface name or an attribute
126
of the configured interface, for example 'netmask'.
127
:returns str: Requested attribute or None if address is not bindable.
129
address = netaddr.IPAddress(address)
130
for iface in netifaces.interfaces():
131
addresses = netifaces.ifaddresses(iface)
132
if address.version == 4 and netifaces.AF_INET in addresses:
133
addr = addresses[netifaces.AF_INET][0]['addr']
134
netmask = addresses[netifaces.AF_INET][0]['netmask']
135
cidr = netaddr.IPNetwork("%s/%s" % (addr, netmask))
140
return addresses[netifaces.AF_INET][0][key]
141
if address.version == 6 and netifaces.AF_INET6 in addresses:
142
for addr in addresses[netifaces.AF_INET6]:
143
if not addr['addr'].startswith('fe80'):
144
cidr = netaddr.IPNetwork("%s/%s" % (addr['addr'],
154
get_iface_for_address = partial(_get_for_address, key='iface')
156
get_netmask_for_address = partial(_get_for_address, key='netmask')