]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - debian/cloud-tools/hv_set_ifconfig
4b4f49f92b228f875c7532a10036457e443c5e0a
[mirror_ubuntu-zesty-kernel.git] / debian / cloud-tools / hv_set_ifconfig
1 #!/usr/bin/python3
2 #
3 # hv_set_ifconfig <config> -- take the hv_kvp_daemon generated configuration
4 # file and apply it to the Ubuntu configuration.
5 #
6
7 # CONFIG example:
8 # HWADDR=11:22:33:44:55:66
9 # DEVICE=foo1
10 # DHCP=yes
11
12 # CONFIG example:
13 # HWADDR=11:22:33:44:55:66
14 # DEVICE=foo1
15 # IPADDR=192.168.99.10
16 # GATEWAY=192.168.99.1
17 # DNS1=192.168.88.250
18 # IPADDR2=192.168.99.11
19 # IPV6ADDR=2001:DB8:99::10
20 # IPV6NETMASK=64
21 # IPV6_DEFAULTGW=2001:DB8:99::10
22
23 # set interfaces in hv_kvp_daemon style
24 import fileinput
25 import sys
26 import errno
27 import os
28 import shutil
29 import tempfile
30 import subprocess
31
32 if_filename="/etc/network/interfaces"
33
34 # Drop our output (XXX?)
35 sys.stdout = open(os.devnull, 'w')
36 sys.stderr = open(os.devnull, 'w')
37
38 # Confirm we can open the network configuration.
39 try:
40 if_file=open(if_filename,"r+")
41 except IOError as e:
42 exit(e.errno)
43 else:
44 if_file.close()
45
46 # Usage: hv_set_ifconfig <config>
47 if len(sys.argv) != 2 :
48 exit(errno.EINVAL)
49
50 #
51 # Here is the format of the ip configuration file:
52 #
53 # HWADDR=macaddr
54 # DEVICE=interface name
55 # BOOTPROTO=<protocol> (where <protocol> is "dhcp" if DHCP is configured
56 # or "none" if no boot-time protocol should be used)
57 #
58 # IPADDR0=ipaddr1
59 # IPADDR1=ipaddr2
60 # IPADDRx=ipaddry (where y = x + 1)
61 #
62 # NETMASK0=netmask1
63 # NETMASKx=netmasky (where y = x + 1)
64 #
65 # GATEWAY=ipaddr1
66 # GATEWAYx=ipaddry (where y = x + 1)
67 #
68 # DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
69 #
70 # IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be
71 # tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
72 # IPV6NETMASK.
73 #
74
75 kvp=dict(line.strip().split("=") for line in fileinput.input())
76
77 # Setting the hwaddress to something azure is not expecting is fatal
78 # to networking.
79 if not "HWADDR" in kvp :
80 exit(errno.EPROTO)
81
82 # Confirm we have a device specified.
83 if not "DEVICE" in kvp :
84 exit(1)
85
86 output=[]
87 basename=kvp["DEVICE"]
88
89 # DNS entries will go with the first interface and there can be a max
90 # of three. These will be emitted with the first interface.
91 dns = []
92 for count in (1, 2, 3):
93 key = "DNS" + str(count)
94 if key in kvp:
95 dns += [kvp[key]]
96 dns_emitted = False
97
98 # IPV4 may either be dhcp or static.
99 if ("DHCP" in kvp and kvp["DHCP"] == "yes") or \
100 ("BOOTPROTO" in kvp and kvp["BOOTPROTO"] == "dhcp"):
101 output += ["auto " + basename]
102 output += ["iface " + basename + " inet dhcp"]
103 output += [""]
104 else:
105 autolist = []
106 # Matchup the interface specific lines
107
108 # No real max for the number of interface + aliases ...
109 # only required is the address (but mate everything up that comes in.
110
111 # IPv4 -- ensure we sort by numeric suffixes.
112 v4names = [ int(name[6:]) for name in kvp.keys() if name.startswith("IPADDR") ]
113 v4names.sort()
114
115 for if_count in v4names:
116 ifname = basename
117 which = str(if_count)
118
119 if if_count:
120 ifname += ":" + str(if_count)
121 which_gw = which
122 else:
123 which_gw = ""
124
125 if not ifname in autolist:
126 autolist += [ifname]
127
128 output += [ "iface " + ifname + " inet static" ]
129 output += [ "\t" + "address " + kvp["IPADDR" + which] ]
130 if "NETMASK" + which in kvp:
131 output += [ "\tnetmask " + kvp["NETMASK" + which] ]
132 if "GATEWAY" + which_gw in kvp:
133 output += ["\tgateway " + kvp["GATEWAY" + which_gw]]
134
135 if not dns_emitted:
136 dns_emitted = True
137 output += ["\tdns-nameservers " + ' '.join(dns)]
138 output += [""]
139
140 # IPv6 requires a netmask
141 # If an ipv6 exists, you'll want to turn off /proc/sys/net/ipv6/conf/all/autoconf with
142 # echo 0 > /proc/sys/net/ipv6/conf/all/autoconf
143 v6names = [ int(name[8:]) for name in kvp.keys() if name.startswith("IPV6ADDR") ]
144 v6names.sort()
145
146 for if6_count in v6names:
147 ifname = basename
148 which = str(if6_count)
149
150 if if6_count:
151 ifname += ":" + str(if6_count)
152 which_gw = which
153 else:
154 which_gw = ""
155
156 if not ifname in autolist:
157 autolist += [ifname]
158
159 if "IPV6NETMASK" + which in kvp:
160 output += [ "iface " + ifname + " inet6 static"]
161 output += [ "\taddress " + kvp["IPV6ADDR" + which]]
162 output += [ "\tnetmask " + kvp["IPV6NETMASK" + which]]
163 if "IPV6_DEFAULTGW" + which_gw in kvp:
164 output += [ "\tgateway " + kvp["IPV6_DEFAULTGW" + which_gw] ]
165 if not dns_emitted:
166 dns_emitted = True
167 output += ["\tdns-nameservers " + ' '.join(dns)]
168 output += [""]
169
170 # Mark this new interface for automatic up.
171 output = ["auto "+" ".join(autolist)] + output
172
173 print("===================================")
174 print(output)
175 print("===================================")
176
177
178 # Time to clean out the existing interface file
179
180 # Markers.
181 start_mark = "# The following stanza(s) added by hv_set_ifconfig"
182 end_mark = "#End of hv_set_ifconfig stanzas"
183
184 f=open(if_filename,"r")
185 flines=f.readlines()
186 f.close()
187 newfile=[]
188 pitchstanza=0
189 inastanza=0
190 stanza=[]
191 prev_line=None
192 for line in flines:
193 if line.startswith("auto"):
194 if inastanza:
195 if not pitchstanza:
196 newfile.extend(stanza)
197 stanza=[]
198 inastanza=0
199 newline=""
200 autoline=line.strip().split(" ")
201 for word in autoline:
202 if (not word == basename) and (not word.startswith(basename+":")):
203 newline+=word + " "
204 newline = newline.strip()
205 if not newline == "auto":
206 newfile += [newline.strip()]
207 elif line.startswith(("iface","mapping","source")):
208 '''Read a stanza'''
209 '''A Stanza can also start with allow- ie allow-hotplug'''
210 if inastanza:
211 if not pitchstanza:
212 newfile.extend(stanza)
213 stanza=[]
214 inastanza=1
215 pitchstanza=0
216 autoline=line.strip().split(" ")
217 for word in autoline:
218 if (word == basename) or (word.startswith(basename+":")):
219 pitchstanza=1
220 if not pitchstanza:
221 stanza+=[line.strip()]
222 elif line.strip() in (start_mark, end_mark):
223 if inastanza:
224 if not pitchstanza:
225 newfile.extend(stanza)
226 stanza=[]
227 inastanza = 0
228 pitchstanza = 0
229 # Deduplicate markers.
230 if line != prev_line:
231 newfile += [line.strip()]
232 else:
233 if inastanza:
234 if not pitchstanza:
235 stanza+=[line.strip()]
236 else:
237 if not pitchstanza:
238 newfile += [line.strip()]
239 prev_line=line
240
241
242
243 def emit(line):
244 print(line)
245 output = line + "\n"
246 os.write(fd, output.encode('utf-8'))
247
248 # Insert the new output at the end and inside the existing markers if found.
249 emitted = False
250 fd, path = tempfile.mkstemp()
251 for line in newfile:
252 if line == end_mark:
253 emit("\n".join(output))
254 emitted = True
255 emit(line)
256 if not emitted:
257 emit(start_mark)
258 emit("\n".join(output))
259 emit(end_mark)
260 os.close(fd)
261
262 shutil.copy(path,if_filename)
263 os.chmod(if_filename,0o644)
264
265 #print("TMPFILE is at: " + path)
266 #print("Copied file is at: " + if_filename)
267
268 try:
269 retcode = subprocess.call("ifdown "+basename , shell=True)
270 if retcode < 0:
271 print("Child was terminated by signal", -retcode, file=sys.stderr)
272 else:
273 print("Child returned", retcode, file=sys.stderr)
274 except OSError as e:
275 print("Execution failed:", e, file=sys.stderr)
276
277 try:
278 retcode = subprocess.call("ifup "+basename , shell=True)
279 if retcode < 0:
280 print("Child was terminated by signal", -retcode, file=sys.stderr)
281 else:
282 print("Child returned", retcode, file=sys.stderr)
283 except OSError as e:
284 print("Execution failed:", e, file=sys.stderr)