~cloud-init-dev/cloud-init/trunk

« back to all changes in this revision

Viewing changes to cloudinit/distros/net_util.py

  • Committer: Scott Moser
  • Date: 2016-08-10 15:06:15 UTC
  • Revision ID: smoser@ubuntu.com-20160810150615-ma2fv107w3suy1ma
README: Mention move of revision control to git.

cloud-init development has moved its revision control to git.
It is available at 
  https://code.launchpad.net/cloud-init

Clone with 
  git clone https://git.launchpad.net/cloud-init
or
  git clone git+ssh://git.launchpad.net/cloud-init

For more information see
  https://git.launchpad.net/cloud-init/tree/HACKING.rst

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# vi: ts=4 expandtab
2
 
#
3
 
#    Copyright (C) 2012 Canonical Ltd.
4
 
#    Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P.
5
 
#    Copyright (C) 2012 Yahoo! Inc.
6
 
#
7
 
#    Author: Scott Moser <scott.moser@canonical.com>
8
 
#    Author: Juerg Haefliger <juerg.haefliger@hp.com>
9
 
#    Author: Joshua Harlow <harlowja@yahoo-inc.com>
10
 
#
11
 
#    This program is free software: you can redistribute it and/or modify
12
 
#    it under the terms of the GNU General Public License version 3, as
13
 
#    published by the Free Software Foundation.
14
 
#
15
 
#    This program is distributed in the hope that it will be useful,
16
 
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 
#    GNU General Public License for more details.
19
 
#
20
 
#    You should have received a copy of the GNU General Public License
21
 
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 
 
23
 
 
24
 
# This is a util function to translate debian based distro interface blobs as
25
 
# given in /etc/network/interfaces to an *somewhat* agnostic format for
26
 
# distributions that use other formats.
27
 
#
28
 
# TODO(harlowja) remove when we have python-netcf active...
29
 
#
30
 
# The format is the following:
31
 
# {
32
 
#    <device-name>: {
33
 
#        # All optional (if not existent in original format)
34
 
#        "netmask": <ip>,
35
 
#        "broadcast": <ip>,
36
 
#        "gateway": <ip>,
37
 
#        "address": <ip>,
38
 
#        "bootproto": "static"|"dhcp",
39
 
#        "dns-search": <hostname>,
40
 
#        "hwaddress": <mac-address>,
41
 
#        "auto": True (or non-existent),
42
 
#        "dns-nameservers": [<ip/hostname>, ...],
43
 
#    }
44
 
# }
45
 
#
46
 
# Things to note, comments are removed, if a ubuntu/debian interface is
47
 
# marked as auto then only then first segment (?) is retained, ie
48
 
# 'auto eth0 eth0:1' just marks eth0 as auto (not eth0:1).
49
 
#
50
 
# Example input:
51
 
#
52
 
# auto lo
53
 
# iface lo inet loopback
54
 
#
55
 
# auto eth0
56
 
# iface eth0 inet static
57
 
#         address 10.0.0.1
58
 
#         netmask 255.255.252.0
59
 
#         broadcast 10.0.0.255
60
 
#         gateway 10.0.0.2
61
 
#         dns-nameservers 98.0.0.1 98.0.0.2
62
 
#
63
 
# Example output:
64
 
# {
65
 
#     "lo": {
66
 
#         "auto": true
67
 
#     },
68
 
#     "eth0": {
69
 
#         "auto": true,
70
 
#         "dns-nameservers": [
71
 
#             "98.0.0.1",
72
 
#             "98.0.0.2"
73
 
#         ],
74
 
#         "broadcast": "10.0.0.255",
75
 
#         "netmask": "255.255.252.0",
76
 
#         "bootproto": "static",
77
 
#         "address": "10.0.0.1",
78
 
#         "gateway": "10.0.0.2"
79
 
#     }
80
 
# }
81
 
 
82
 
def translate_network(settings):
83
 
    # Get the standard cmd, args from the ubuntu format
84
 
    entries = []
85
 
    for line in settings.splitlines():
86
 
        line = line.strip()
87
 
        if not line or line.startswith("#"):
88
 
            continue
89
 
        split_up = line.split(None, 1)
90
 
        if len(split_up) <= 1:
91
 
            continue
92
 
        entries.append(split_up)
93
 
    # Figure out where each iface section is
94
 
    ifaces = []
95
 
    consume = {}
96
 
    for (cmd, args) in entries:
97
 
        if cmd == 'iface':
98
 
            if consume:
99
 
                ifaces.append(consume)
100
 
                consume = {}
101
 
            consume[cmd] = args
102
 
        else:
103
 
            consume[cmd] = args
104
 
    # Check if anything left over to consume
105
 
    absorb = False
106
 
    for (cmd, args) in consume.items():
107
 
        if cmd == 'iface':
108
 
            absorb = True
109
 
    if absorb:
110
 
        ifaces.append(consume)
111
 
    # Now translate
112
 
    real_ifaces = {}
113
 
    for info in ifaces:
114
 
        if 'iface' not in info:
115
 
            continue
116
 
        iface_details = info['iface'].split(None)
117
 
        # Check if current device *may* have an ipv6 IP
118
 
        use_ipv6 = False
119
 
        if 'inet6' in iface_details:
120
 
            use_ipv6 = True
121
 
        dev_name = None
122
 
        if len(iface_details) >= 1:
123
 
            dev = iface_details[0].strip().lower()
124
 
            if dev:
125
 
                dev_name = dev
126
 
        if not dev_name:
127
 
            continue
128
 
        iface_info = {}
129
 
        iface_info['ipv6'] = {}
130
 
        if len(iface_details) >= 3:
131
 
            proto_type = iface_details[2].strip().lower()
132
 
            # Seems like this can be 'loopback' which we don't
133
 
            # really care about
134
 
            if proto_type in ['dhcp', 'static']:
135
 
                iface_info['bootproto'] = proto_type
136
 
        # These can just be copied over
137
 
        if use_ipv6:
138
 
            for k in ['address', 'gateway']:
139
 
                if k in info:
140
 
                    val = info[k].strip().lower()
141
 
                    if val:
142
 
                        iface_info['ipv6'][k] = val
143
 
        else:
144
 
            for k in ['netmask', 'address', 'gateway', 'broadcast']:
145
 
                if k in info:
146
 
                    val = info[k].strip().lower()
147
 
                    if val:
148
 
                        iface_info[k] = val
149
 
            # Name server info provided??
150
 
            if 'dns-nameservers' in info:
151
 
                iface_info['dns-nameservers'] = info['dns-nameservers'].split()
152
 
            # Name server search info provided??
153
 
            if 'dns-search' in info:
154
 
                iface_info['dns-search'] = info['dns-search'].split()
155
 
            # Is any mac address spoofing going on??
156
 
            if 'hwaddress' in info:
157
 
                hw_info = info['hwaddress'].lower().strip()
158
 
                hw_split = hw_info.split(None, 1)
159
 
                if len(hw_split) == 2 and hw_split[0].startswith('ether'):
160
 
                    hw_addr = hw_split[1]
161
 
                    if hw_addr:
162
 
                        iface_info['hwaddress'] = hw_addr
163
 
        # If ipv6 is enabled, device will have multiple IPs, so we need to
164
 
        # update the dictionary instead of overwriting it...
165
 
        if dev_name in real_ifaces:
166
 
            real_ifaces[dev_name].update(iface_info)
167
 
        else:
168
 
            real_ifaces[dev_name] = iface_info
169
 
    # Check for those that should be started on boot via 'auto'
170
 
    for (cmd, args) in entries:
171
 
        args = args.split(None)
172
 
        if not args:
173
 
            continue
174
 
        dev_name = args[0].strip().lower()
175
 
        if cmd == 'auto':
176
 
            # Seems like auto can be like 'auto eth0 eth0:1' so just get the
177
 
            # first part out as the device name
178
 
            if dev_name in real_ifaces:
179
 
                real_ifaces[dev_name]['auto'] = True
180
 
        if cmd == 'iface' and 'inet6' in args:
181
 
            real_ifaces[dev_name]['inet6'] = True
182
 
    return real_ifaces