3
# Copyright (C) 2015 Canonical Ltd.
4
# Copyright (C) 2016 VMware INC.
6
# Author: Sankar Tanguturi <stanguturi@vmware.com>
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.
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.
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/>.
24
from cloudinit import util
26
logger = logging.getLogger(__name__)
29
class NicConfigurator(object):
30
def __init__(self, nics):
32
Initialize the Nic Configurator
33
@param nics (list) an array of nics to configure
37
self.ipv4PrimaryGateway = None
38
self.ipv6PrimaryGateway = None
40
self._primaryNic = self.get_primary_nic()
42
def get_primary_nic(self):
44
Retrieve the primary nic if it exists
45
@return (NicBase): the primary nic if exists, None otherwise
47
primary_nics = [nic for nic in self.nics if nic.primary]
50
elif len(primary_nics) > 1:
51
raise Exception('There can only be one primary nic',
52
[nic.mac for nic in primary_nics])
54
return primary_nics[0]
56
def find_devices(self):
58
Create the mac2Name dictionary
59
The mac address(es) are in the lower case
61
cmd = ['ip', 'addr', 'show']
62
(output, err) = util.subp(cmd)
63
sections = re.split(r'\n\d+: ', '\n' + output)[1:]
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
70
mac = match.group(1).lower()
71
name = section.split(':', 1)[0]
72
self.mac2Name[mac] = name
74
def gen_one_nic(self, nic):
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
81
name = self.mac2Name.get(nic.mac.lower())
83
raise ValueError('No known device has MACADDR: %s' % nic.mac)
86
lines.append('auto %s' % name)
89
lines.extend(self.gen_ipv4(name, nic))
92
lines.extend(self.gen_ipv6(name, nic))
98
def gen_ipv4(self, name, nic):
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
107
bootproto = nic.bootProto.lower()
108
if nic.ipv4_mode.lower() == 'disabled':
110
lines.append('iface %s inet %s' % (name, bootproto))
112
if bootproto != 'static':
118
lines.append(' address %s' % v4.ip)
120
lines.append(' netmask %s' % v4.netmask)
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)
128
# Add routes if there is no primary nic
129
if not self._primaryNic:
130
lines.extend(self.gen_ipv4_route(nic, v4.gateways))
134
def gen_ipv4_route(self, nic, gateways):
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
143
for gateway in gateways:
144
lines.append(' up route add default gw %s metric 10000' %
149
def gen_ipv6(self, name, nic):
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
158
if not nic.staticIpv6:
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)
167
for addr in addrs[1:]:
168
lines.append(' up ifconfig %s inet6 add %s/%s' % (name, addr.ip,
170
# Add the primary gateway
174
self.ipv6PrimaryGateway = addr.gateway
175
lines.append(' gateway %s' % self.ipv6PrimaryGateway)
178
# Add routes if there is no primary nic
179
if not self._primaryNic:
180
lines.extend(self._genIpv6Route(name, nic, addrs))
184
def _genIpv6Route(self, name, nic, addrs):
188
lines.append(' up route -A inet6 add default gw '
189
'%s metric 10000' % addr.gateway)
194
"""Return the lines that is needed to configure the nics"""
196
lines.append('iface lo inet loopback')
197
lines.append('auto lo')
200
for nic in self.nics:
201
lines.extend(self.gen_one_nic(nic))
205
def clear_dhcp(self):
206
logger.info('Clearing DHCP leases')
208
# Ignore the return code 1.
209
util.subp(["pkill", "dhclient"], rcs=[0, 1])
210
util.subp(["rm", "-f", "/var/lib/dhcp/*"])
212
def if_down_up(self):
214
for nic in self.nics:
215
name = self.mac2Name.get(nic.mac.lower())
219
logger.info('Bring down interface %s' % name)
220
util.subp(["ifdown", "%s" % name])
225
logger.info('Bring up interface %s' % name)
226
util.subp(["ifup", "%s" % name])
230
Configure the /etc/network/intefaces
231
Make a back up of the original
233
containingDir = '/etc/network'
235
interfaceFile = os.path.join(containingDir, 'interfaces')
236
originalFile = os.path.join(containingDir,
237
'interfaces.before_vmware_customization')
239
if not os.path.exists(originalFile) and os.path.exists(interfaceFile):
240
os.rename(interfaceFile, originalFile)
242
lines = self.generate()
243
with open(interfaceFile, 'w') as fp:
245
fp.write('%s\n' % line)