]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - debian/cloud-tools/hv_set_ifconfig
UBUNTU: [debian] Initial debian and ubuntu directories
[mirror_ubuntu-bionic-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 autolist = []
87 output=[]
88 basename=kvp["DEVICE"]
89
90 # DNS entries will go with the first interface and there can be a max
91 # of three. These will be emitted with the first interface.
92 dns = []
93 for count in (1, 2, 3):
94 key = "DNS" + str(count)
95 if key in kvp:
96 dns += [kvp[key]]
97 dns_emitted = False
98
99 # IPV4 may either be dhcp or static.
100 if ("DHCP" in kvp and kvp["DHCP"] == "yes") or \
101 ("BOOTPROTO" in kvp and kvp["BOOTPROTO"] == "dhcp"):
102 autolist.append(basename)
103 output += ["iface " + basename + " inet dhcp"]
104 output += [""]
105 else:
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 if len(autolist):
172 output = ["auto "+" ".join(autolist)] + output
173
174 print("===================================")
175 print(output)
176 print("===================================")
177
178
179 # Time to clean out the existing interface file
180
181 # Markers.
182 start_mark = "# The following stanza(s) added by hv_set_ifconfig"
183 end_mark = "#End of hv_set_ifconfig stanzas"
184
185 f=open(if_filename,"r")
186 flines=f.readlines()
187 f.close()
188 newfile=[]
189 pitchstanza=0
190 inastanza=0
191 stanza=[]
192 prev_line=None
193 for line in flines:
194 if line.startswith("auto"):
195 if inastanza:
196 if not pitchstanza:
197 newfile.extend(stanza)
198 stanza=[]
199 inastanza=0
200 newline=""
201 autoline=line.strip().split(" ")
202 for word in autoline:
203 if (not word == basename) and (not word.startswith(basename+":")):
204 newline+=word + " "
205 newline = newline.strip()
206 if not newline == "auto":
207 newfile += [newline.strip()]
208 elif line.startswith(("iface","mapping","source")):
209 '''Read a stanza'''
210 '''A Stanza can also start with allow- ie allow-hotplug'''
211 if inastanza:
212 if not pitchstanza:
213 newfile.extend(stanza)
214 stanza=[]
215 inastanza=1
216 pitchstanza=0
217 autoline=line.strip().split(" ")
218 for word in autoline:
219 if (word == basename) or (word.startswith(basename+":")):
220 pitchstanza=1
221 if not pitchstanza:
222 stanza+=[line.strip()]
223 elif line.strip() in (start_mark, end_mark):
224 if inastanza:
225 if not pitchstanza:
226 newfile.extend(stanza)
227 stanza=[]
228 inastanza = 0
229 pitchstanza = 0
230 # Deduplicate markers.
231 if line != prev_line:
232 newfile += [line.strip()]
233 else:
234 if inastanza:
235 if not pitchstanza:
236 stanza+=[line.strip()]
237 else:
238 if not pitchstanza:
239 newfile += [line.strip()]
240 prev_line=line
241
242 # Include pending stanza if any.
243 if inastanza and not pitchstanza:
244 newfile.extend(stanza)
245
246
247 def emit(line):
248 print(line)
249 output = line + "\n"
250 os.write(fd, output.encode('utf-8'))
251
252 # Insert the new output at the end and inside the existing markers if found.
253 emitted = False
254 fd, path = tempfile.mkstemp()
255 for line in newfile:
256 if line == end_mark:
257 emit("\n".join(output))
258 emitted = True
259 emit(line)
260 if not emitted:
261 emit(start_mark)
262 emit("\n".join(output))
263 emit(end_mark)
264 os.close(fd)
265
266 shutil.copy(path,if_filename)
267 os.chmod(if_filename,0o644)
268
269 #print("TMPFILE is at: " + path)
270 #print("Copied file is at: " + if_filename)
271
272 try:
273 retcode = subprocess.call("ifdown "+basename , shell=True)
274 if retcode < 0:
275 print("Child was terminated by signal", -retcode, file=sys.stderr)
276 else:
277 print("Child returned", retcode, file=sys.stderr)
278 except OSError as e:
279 print("Execution failed:", e, file=sys.stderr)
280
281 try:
282 retcode = subprocess.call("ifup "+basename , shell=True)
283 if retcode < 0:
284 print("Child was terminated by signal", -retcode, file=sys.stderr)
285 else:
286 print("Child returned", retcode, file=sys.stderr)
287 except OSError as e:
288 print("Execution failed:", e, file=sys.stderr)