~landscape/charms/trusty/neutron-api-leadership-election/trunk

« back to all changes in this revision

Viewing changes to hooks/charmhelpers/contrib/network/ip.py

  • Committer: james.page at ubuntu
  • Date: 2014-12-15 09:14:03 UTC
  • mfrom: (63.1.8 neutron-api)
  • Revision ID: james.page@ubuntu.com-20141215091403-af7ic1lxnnjsh4zu
[corey.bryant,r=james-page] Sort out charmhelpers issues.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
import glob
2
2
import re
3
3
import subprocess
4
 
import sys
5
4
 
6
5
from functools import partial
7
6
 
8
7
from charmhelpers.core.hookenv import unit_get
9
8
from charmhelpers.fetch import apt_install
10
9
from charmhelpers.core.hookenv import (
11
 
    WARNING,
12
 
    ERROR,
13
10
    log
14
11
)
15
12
 
34
31
                         network)
35
32
 
36
33
 
 
34
def no_ip_found_error_out(network):
 
35
    errmsg = ("No IP address found in network: %s" % network)
 
36
    raise ValueError(errmsg)
 
37
 
 
38
 
37
39
def get_address_in_network(network, fallback=None, fatal=False):
38
 
    """
39
 
    Get an IPv4 or IPv6 address within the network from the host.
 
40
    """Get an IPv4 or IPv6 address within the network from the host.
40
41
 
41
42
    :param network (str): CIDR presentation format. For example,
42
43
        '192.168.1.0/24'.
43
44
    :param fallback (str): If no address is found, return fallback.
44
45
    :param fatal (boolean): If no address is found, fallback is not
45
46
        set and fatal is True then exit(1).
46
 
 
47
47
    """
48
 
 
49
 
    def not_found_error_out():
50
 
        log("No IP address found in network: %s" % network,
51
 
            level=ERROR)
52
 
        sys.exit(1)
53
 
 
54
48
    if network is None:
55
49
        if fallback is not None:
56
50
            return fallback
 
51
 
 
52
        if fatal:
 
53
            no_ip_found_error_out(network)
57
54
        else:
58
 
            if fatal:
59
 
                not_found_error_out()
60
 
            else:
61
 
                return None
 
55
            return None
62
56
 
63
57
    _validate_cidr(network)
64
58
    network = netaddr.IPNetwork(network)
70
64
            cidr = netaddr.IPNetwork("%s/%s" % (addr, netmask))
71
65
            if cidr in network:
72
66
                return str(cidr.ip)
 
67
 
73
68
        if network.version == 6 and netifaces.AF_INET6 in addresses:
74
69
            for addr in addresses[netifaces.AF_INET6]:
75
70
                if not addr['addr'].startswith('fe80'):
82
77
        return fallback
83
78
 
84
79
    if fatal:
85
 
        not_found_error_out()
 
80
        no_ip_found_error_out(network)
86
81
 
87
82
    return None
88
83
 
89
84
 
90
85
def is_ipv6(address):
91
 
    '''Determine whether provided address is IPv6 or not'''
 
86
    """Determine whether provided address is IPv6 or not."""
92
87
    try:
93
88
        address = netaddr.IPAddress(address)
94
89
    except netaddr.AddrFormatError:
95
90
        # probably a hostname - so not an address at all!
96
91
        return False
97
 
    else:
98
 
        return address.version == 6
 
92
 
 
93
    return address.version == 6
99
94
 
100
95
 
101
96
def is_address_in_network(network, address):
113
108
    except (netaddr.core.AddrFormatError, ValueError):
114
109
        raise ValueError("Network (%s) is not in CIDR presentation format" %
115
110
                         network)
 
111
 
116
112
    try:
117
113
        address = netaddr.IPAddress(address)
118
114
    except (netaddr.core.AddrFormatError, ValueError):
119
115
        raise ValueError("Address (%s) is not in correct presentation format" %
120
116
                         address)
 
117
 
121
118
    if address in network:
122
119
        return True
123
120
    else:
147
144
                    return iface
148
145
                else:
149
146
                    return addresses[netifaces.AF_INET][0][key]
 
147
 
150
148
        if address.version == 6 and netifaces.AF_INET6 in addresses:
151
149
            for addr in addresses[netifaces.AF_INET6]:
152
150
                if not addr['addr'].startswith('fe80'):
160
158
                            return str(cidr).split('/')[1]
161
159
                        else:
162
160
                            return addr[key]
 
161
 
163
162
    return None
164
163
 
165
164
 
166
165
get_iface_for_address = partial(_get_for_address, key='iface')
167
166
 
 
167
 
168
168
get_netmask_for_address = partial(_get_for_address, key='netmask')
169
169
 
170
170
 
171
171
def format_ipv6_addr(address):
172
 
    """
173
 
    IPv6 needs to be wrapped with [] in url link to parse correctly.
 
172
    """If address is IPv6, wrap it in '[]' otherwise return None.
 
173
 
 
174
    This is required by most configuration files when specifying IPv6
 
175
    addresses.
174
176
    """
175
177
    if is_ipv6(address):
176
 
        address = "[%s]" % address
177
 
    else:
178
 
        log("Not a valid ipv6 address: %s" % address, level=WARNING)
179
 
        address = None
 
178
        return "[%s]" % address
180
179
 
181
 
    return address
 
180
    return None
182
181
 
183
182
 
184
183
def get_iface_addr(iface='eth0', inet_type='AF_INET', inc_aliases=False,
185
184
                   fatal=True, exc_list=None):
186
 
    """
187
 
    Return the assigned IP address for a given interface, if any, or [].
188
 
    """
 
185
    """Return the assigned IP address for a given interface, if any."""
189
186
    # Extract nic if passed /dev/ethX
190
187
    if '/' in iface:
191
188
        iface = iface.split('/')[-1]
 
189
 
192
190
    if not exc_list:
193
191
        exc_list = []
 
192
 
194
193
    try:
195
194
        inet_num = getattr(netifaces, inet_type)
196
195
    except AttributeError:
197
 
        raise Exception('Unknown inet type ' + str(inet_type))
 
196
        raise Exception("Unknown inet type '%s'" % str(inet_type))
198
197
 
199
198
    interfaces = netifaces.interfaces()
200
199
    if inc_aliases:
202
201
        for _iface in interfaces:
203
202
            if iface == _iface or _iface.split(':')[0] == iface:
204
203
                ifaces.append(_iface)
 
204
 
205
205
        if fatal and not ifaces:
206
206
            raise Exception("Invalid interface '%s'" % iface)
 
207
 
207
208
        ifaces.sort()
208
209
    else:
209
210
        if iface not in interfaces:
210
211
            if fatal:
211
 
                raise Exception("%s not found " % (iface))
 
212
                raise Exception("Interface '%s' not found " % (iface))
212
213
            else:
213
214
                return []
 
215
 
214
216
        else:
215
217
            ifaces = [iface]
216
218
 
221
223
            for entry in net_info[inet_num]:
222
224
                if 'addr' in entry and entry['addr'] not in exc_list:
223
225
                    addresses.append(entry['addr'])
 
226
 
224
227
    if fatal and not addresses:
225
228
        raise Exception("Interface '%s' doesn't have any %s addresses." %
226
229
                        (iface, inet_type))
227
 
    return addresses
 
230
 
 
231
    return sorted(addresses)
 
232
 
228
233
 
229
234
get_ipv4_addr = partial(get_iface_addr, inet_type='AF_INET')
230
235
 
241
246
                raw = re.match(ll_key, _addr)
242
247
                if raw:
243
248
                    _addr = raw.group(1)
 
249
 
244
250
                if _addr == addr:
245
251
                    log("Address '%s' is configured on iface '%s'" %
246
252
                        (addr, iface))
251
257
 
252
258
 
253
259
def sniff_iface(f):
254
 
    """If no iface provided, inject net iface inferred from unit private
255
 
    address.
 
260
    """Ensure decorated function is called with a value for iface.
 
261
 
 
262
    If no iface provided, inject net iface inferred from unit private address.
256
263
    """
257
264
    def iface_sniffer(*args, **kwargs):
258
265
        if not kwargs.get('iface', None):
295
302
        if global_addrs:
296
303
            # Make sure any found global addresses are not temporary
297
304
            cmd = ['ip', 'addr', 'show', iface]
298
 
            out = subprocess.check_output(cmd)
 
305
            out = subprocess.check_output(cmd).decode('UTF-8')
299
306
            if dynamic_only:
300
307
                key = re.compile("inet6 (.+)/[0-9]+ scope global dynamic.*")
301
308
            else:
317
324
                return addrs
318
325
 
319
326
    if fatal:
320
 
        raise Exception("Interface '%s' doesn't have a scope global "
 
327
        raise Exception("Interface '%s' does not have a scope global "
321
328
                        "non-temporary ipv6 address." % iface)
322
329
 
323
330
    return []
324
331
 
325
332
 
326
333
def get_bridges(vnic_dir='/sys/devices/virtual/net'):
327
 
    """
328
 
    Return a list of bridges on the system or []
329
 
    """
330
 
    b_rgex = vnic_dir + '/*/bridge'
331
 
    return [x.replace(vnic_dir, '').split('/')[1] for x in glob.glob(b_rgex)]
 
334
    """Return a list of bridges on the system."""
 
335
    b_regex = "%s/*/bridge" % vnic_dir
 
336
    return [x.replace(vnic_dir, '').split('/')[1] for x in glob.glob(b_regex)]
332
337
 
333
338
 
334
339
def get_bridge_nics(bridge, vnic_dir='/sys/devices/virtual/net'):
335
 
    """
336
 
    Return a list of nics comprising a given bridge on the system or []
337
 
    """
338
 
    brif_rgex = "%s/%s/brif/*" % (vnic_dir, bridge)
339
 
    return [x.split('/')[-1] for x in glob.glob(brif_rgex)]
 
340
    """Return a list of nics comprising a given bridge on the system."""
 
341
    brif_regex = "%s/%s/brif/*" % (vnic_dir, bridge)
 
342
    return [x.split('/')[-1] for x in glob.glob(brif_regex)]
340
343
 
341
344
 
342
345
def is_bridge_member(nic):
343
 
    """
344
 
    Check if a given nic is a member of a bridge
345
 
    """
 
346
    """Check if a given nic is a member of a bridge."""
346
347
    for bridge in get_bridges():
347
348
        if nic in get_bridge_nics(bridge):
348
349
            return True
 
350
 
349
351
    return False