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

« back to all changes in this revision

Viewing changes to cloudinit/sources/helpers/vmware/imc/config_nic.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) 2015 Canonical Ltd.
4
 
#    Copyright (C) 2016 VMware INC.
5
 
#
6
 
#    Author: Sankar Tanguturi <stanguturi@vmware.com>
7
 
#
8
 
#    This program is free software: you can redistribute it and/or modify
9
 
#    it under the terms of the GNU General Public License version 3, as
10
 
#    published by the Free Software Foundation.
11
 
#
12
 
#    This program is distributed in the hope that it will be useful,
13
 
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 
#    GNU General Public License for more details.
16
 
#
17
 
#    You should have received a copy of the GNU General Public License
18
 
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 
 
20
 
import logging
21
 
import os
22
 
import re
23
 
 
24
 
from cloudinit import util
25
 
 
26
 
logger = logging.getLogger(__name__)
27
 
 
28
 
 
29
 
class NicConfigurator(object):
30
 
    def __init__(self, nics):
31
 
        """
32
 
        Initialize the Nic Configurator
33
 
        @param nics (list) an array of nics to configure
34
 
        """
35
 
        self.nics = nics
36
 
        self.mac2Name = {}
37
 
        self.ipv4PrimaryGateway = None
38
 
        self.ipv6PrimaryGateway = None
39
 
        self.find_devices()
40
 
        self._primaryNic = self.get_primary_nic()
41
 
 
42
 
    def get_primary_nic(self):
43
 
        """
44
 
        Retrieve the primary nic if it exists
45
 
        @return (NicBase): the primary nic if exists, None otherwise
46
 
        """
47
 
        primary_nics = [nic for nic in self.nics if nic.primary]
48
 
        if not primary_nics:
49
 
            return None
50
 
        elif len(primary_nics) > 1:
51
 
            raise Exception('There can only be one primary nic',
52
 
                            [nic.mac for nic in primary_nics])
53
 
        else:
54
 
            return primary_nics[0]
55
 
 
56
 
    def find_devices(self):
57
 
        """
58
 
        Create the mac2Name dictionary
59
 
        The mac address(es) are in the lower case
60
 
        """
61
 
        cmd = ['ip', 'addr', 'show']
62
 
        (output, err) = util.subp(cmd)
63
 
        sections = re.split(r'\n\d+: ', '\n' + output)[1:]
64
 
 
65
 
        macPat = r'link/ether (([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2}))'
66
 
        for section in sections:
67
 
            match = re.search(macPat, section)
68
 
            if not match:  # Only keep info about nics
69
 
                continue
70
 
            mac = match.group(1).lower()
71
 
            name = section.split(':', 1)[0]
72
 
            self.mac2Name[mac] = name
73
 
 
74
 
    def gen_one_nic(self, nic):
75
 
        """
76
 
        Return the lines needed to configure a nic
77
 
        @return (str list): the string list to configure the nic
78
 
        @param nic (NicBase): the nic to configure
79
 
        """
80
 
        lines = []
81
 
        name = self.mac2Name.get(nic.mac.lower())
82
 
        if not name:
83
 
            raise ValueError('No known device has MACADDR: %s' % nic.mac)
84
 
 
85
 
        if nic.onboot:
86
 
            lines.append('auto %s' % name)
87
 
 
88
 
        # Customize IPv4
89
 
        lines.extend(self.gen_ipv4(name, nic))
90
 
 
91
 
        # Customize IPv6
92
 
        lines.extend(self.gen_ipv6(name, nic))
93
 
 
94
 
        lines.append('')
95
 
 
96
 
        return lines
97
 
 
98
 
    def gen_ipv4(self, name, nic):
99
 
        """
100
 
        Return the lines needed to configure the IPv4 setting of a nic
101
 
        @return (str list): the string list to configure the gateways
102
 
        @param name (str): name of the nic
103
 
        @param nic (NicBase): the nic to configure
104
 
        """
105
 
        lines = []
106
 
 
107
 
        bootproto = nic.bootProto.lower()
108
 
        if nic.ipv4_mode.lower() == 'disabled':
109
 
            bootproto = 'manual'
110
 
        lines.append('iface %s inet %s' % (name, bootproto))
111
 
 
112
 
        if bootproto != 'static':
113
 
            return lines
114
 
 
115
 
        # Static Ipv4
116
 
        v4 = nic.staticIpv4
117
 
        if v4.ip:
118
 
            lines.append('    address %s' % v4.ip)
119
 
        if v4.netmask:
120
 
            lines.append('    netmask %s' % v4.netmask)
121
 
 
122
 
        # Add the primary gateway
123
 
        if nic.primary and v4.gateways:
124
 
            self.ipv4PrimaryGateway = v4.gateways[0]
125
 
            lines.append('    gateway %s metric 0' % self.ipv4PrimaryGateway)
126
 
            return lines
127
 
 
128
 
        # Add routes if there is no primary nic
129
 
        if not self._primaryNic:
130
 
            lines.extend(self.gen_ipv4_route(nic, v4.gateways))
131
 
 
132
 
        return lines
133
 
 
134
 
    def gen_ipv4_route(self, nic, gateways):
135
 
        """
136
 
        Return the lines needed to configure additional Ipv4 route
137
 
        @return (str list): the string list to configure the gateways
138
 
        @param nic (NicBase): the nic to configure
139
 
        @param gateways (str list): the list of gateways
140
 
        """
141
 
        lines = []
142
 
 
143
 
        for gateway in gateways:
144
 
            lines.append('    up route add default gw %s metric 10000' %
145
 
                         gateway)
146
 
 
147
 
        return lines
148
 
 
149
 
    def gen_ipv6(self, name, nic):
150
 
        """
151
 
        Return the lines needed to configure the gateways for a nic
152
 
        @return (str list): the string list to configure the gateways
153
 
        @param name (str): name of the nic
154
 
        @param nic (NicBase): the nic to configure
155
 
        """
156
 
        lines = []
157
 
 
158
 
        if not nic.staticIpv6:
159
 
            return lines
160
 
 
161
 
        # Static Ipv6
162
 
        addrs = nic.staticIpv6
163
 
        lines.append('iface %s inet6 static' % name)
164
 
        lines.append('    address %s' % addrs[0].ip)
165
 
        lines.append('    netmask %s' % addrs[0].netmask)
166
 
 
167
 
        for addr in addrs[1:]:
168
 
            lines.append('    up ifconfig %s inet6 add %s/%s' % (name, addr.ip,
169
 
                                                                 addr.netmask))
170
 
        # Add the primary gateway
171
 
        if nic.primary:
172
 
            for addr in addrs:
173
 
                if addr.gateway:
174
 
                    self.ipv6PrimaryGateway = addr.gateway
175
 
                    lines.append('    gateway %s' % self.ipv6PrimaryGateway)
176
 
                    return lines
177
 
 
178
 
        # Add routes if there is no primary nic
179
 
        if not self._primaryNic:
180
 
            lines.extend(self._genIpv6Route(name, nic, addrs))
181
 
 
182
 
        return lines
183
 
 
184
 
    def _genIpv6Route(self, name, nic, addrs):
185
 
        lines = []
186
 
 
187
 
        for addr in addrs:
188
 
            lines.append('    up route -A inet6 add default gw '
189
 
                         '%s metric 10000' % addr.gateway)
190
 
 
191
 
        return lines
192
 
 
193
 
    def generate(self):
194
 
        """Return the lines that is needed to configure the nics"""
195
 
        lines = []
196
 
        lines.append('iface lo inet loopback')
197
 
        lines.append('auto lo')
198
 
        lines.append('')
199
 
 
200
 
        for nic in self.nics:
201
 
            lines.extend(self.gen_one_nic(nic))
202
 
 
203
 
        return lines
204
 
 
205
 
    def clear_dhcp(self):
206
 
        logger.info('Clearing DHCP leases')
207
 
 
208
 
        # Ignore the return code 1.
209
 
        util.subp(["pkill", "dhclient"], rcs=[0, 1])
210
 
        util.subp(["rm", "-f", "/var/lib/dhcp/*"])
211
 
 
212
 
    def if_down_up(self):
213
 
        names = []
214
 
        for nic in self.nics:
215
 
            name = self.mac2Name.get(nic.mac.lower())
216
 
            names.append(name)
217
 
 
218
 
        for name in names:
219
 
            logger.info('Bring down interface %s' % name)
220
 
            util.subp(["ifdown", "%s" % name])
221
 
 
222
 
        self.clear_dhcp()
223
 
 
224
 
        for name in names:
225
 
            logger.info('Bring up interface %s' % name)
226
 
            util.subp(["ifup", "%s" % name])
227
 
 
228
 
    def configure(self):
229
 
        """
230
 
        Configure the /etc/network/intefaces
231
 
        Make a back up of the original
232
 
        """
233
 
        containingDir = '/etc/network'
234
 
 
235
 
        interfaceFile = os.path.join(containingDir, 'interfaces')
236
 
        originalFile = os.path.join(containingDir,
237
 
                                    'interfaces.before_vmware_customization')
238
 
 
239
 
        if not os.path.exists(originalFile) and os.path.exists(interfaceFile):
240
 
            os.rename(interfaceFile, originalFile)
241
 
 
242
 
        lines = self.generate()
243
 
        with open(interfaceFile, 'w') as fp:
244
 
            for line in lines:
245
 
                fp.write('%s\n' % line)
246
 
 
247
 
        self.if_down_up()