#!/usr/bin/python3 # # hv_set_ifconfig -- take the hv_kvp_daemon generated configuration # file and apply it to the Ubuntu configuration. # # CONFIG example: # HWADDR=11:22:33:44:55:66 # DEVICE=foo1 # DHCP=yes # CONFIG example: # HWADDR=11:22:33:44:55:66 # DEVICE=foo1 # IPADDR=192.168.99.10 # GATEWAY=192.168.99.1 # DNS1=192.168.88.250 # IPADDR2=192.168.99.11 # IPV6ADDR=2001:DB8:99::10 # IPV6NETMASK=64 # IPV6_DEFAULTGW=2001:DB8:99::10 # set interfaces in hv_kvp_daemon style import fileinput import sys import errno import os import shutil import tempfile import subprocess if_filename="/etc/network/interfaces" # Drop our output (XXX?) sys.stdout = open(os.devnull, 'w') sys.stderr = open(os.devnull, 'w') # Confirm we can open the network configuration. try: if_file=open(if_filename,"r+") except IOError as e: exit(e.errno) else: if_file.close() # Usage: hv_set_ifconfig if len(sys.argv) != 2 : exit(errno.EINVAL) # # Here is the format of the ip configuration file: # # HWADDR=macaddr # DEVICE=interface name # BOOTPROTO= (where is "dhcp" if DHCP is configured # or "none" if no boot-time protocol should be used) # kvp=dict(line.strip().split("=") for line in fileinput.input()) # Setting the hwaddress to something azure is not expecting is fatal # to networking. if not "HWADDR" in kvp : exit(errno.EPROTO) # Confirm we have a device specified. if not "DEVICE" in kvp : exit(1) output=[] basename=kvp["DEVICE"] if "DHCP" in kvp and kvp["DHCP"]=="yes" : output += ["auto " + basename] output += ["iface " + basename + " inet dhcp"] output += [""] else: # Matchup the interface specific lines # DNS entries will go with the first interface # and there can be a max of three autolist=[] dns=[] if "DNS1" in kvp : dns+=[kvp["DNS1"]] if "DNS2" in kvp : dns+=[kvp["DNS2"]] if "DNS3" in kvp : dns+=[kvp["DNS3"]] # No real max for the number of interface + aliases ... # only required is the address (but mate everything up that comes in. # IPv4 v4names=[name for name in kvp.keys() if name.startswith("IPADDR")] v4names.sort() if_count=0 for v4 in v4names: ifname=basename suffix="" if if_count : ifname+=":" + str(if_count) suffix="_"+str(if_count) if not ifname in autolist: autolist += [ifname] output += [ "iface " + ifname + " inet static"] output += [ "\t" + "address " + kvp[v4]] if "NETMASK"+suffix in kvp.keys(): output += ["\tnetmask " + kvp["NETMASK"+suffix]] if "GATEWAY"+suffix in kvp.keys(): output += ["\tgateway " + kvp["GATEWAY"+suffix]] if not if_count : output += ["\tdns-nameservers " + ' '.join(dns)] output += [""] if_count+=1 # IPv6 requires a netmask # If an ipv6 exists, you'll want to turn off /proc/sys/net/ipv6/conf/all/autoconf with # echo 0 > /proc/sys/net/ipv6/conf/all/autoconf v6names=[name for name in kvp.keys() if name.startswith("IPV6ADDR")] v6names.sort() if6_count=0 if6_used=0 for v6 in v6names: ifname=basename suffix="" if if6_used : ifname+=":" + str(if6_used) if if6_count : suffix="_" + str(if6_count) if not ifname in autolist: autolist += [ifname] if "IPV6NETMASK"+suffix in kvp.keys(): output += [ "iface " + ifname + " inet6 static"] output += [ "\taddress " + kvp[v6]] output += [ "\tnetmask " + kvp["IPV6NETMASK"+suffix]] if "IPV6_DEFAULTGW"+suffix in kvp.keys(): output += [ "\tgateway " + kvp["IPV6_DEFAULTGW"+suffix] ] if not if_count : output += ["\tdns-nameservers " + ' '.join(dns)] output += [""] if_count += 1 if6_used += 1 if6_count += 1 # Mark this new interface for automatic up. output = ["auto "+" ".join(autolist)] + output print("===================================") print(output) print("===================================") ''' Time to clean out the existing interface file''' # Markers. start_mark = "# The following stanza(s) added by hv_set_ifconfig" end_mark = "#End of hv_set_ifconfig stanzas" f=open(if_filename,"r") flines=f.readlines() f.close() newfile=[] pitchstanza=0 inastanza=0 stanza=[] prev_line=None for line in flines: if line.startswith("auto"): if inastanza: if not pitchstanza: newfile.extend(stanza) stanza=[] inastanza=0 newline="" autoline=line.strip().split(" ") for word in autoline: if (not word == basename) and (not word.startswith(basename+":")): newline+=word + " " newline = newline.strip() if not newline == "auto": newfile += [newline.strip()] elif line.startswith(("iface","mapping","source")): '''Read a stanza''' '''A Stanza can also start with allow- ie allow-hotplug''' if inastanza: if not pitchstanza: newfile.extend(stanza) stanza=[] inastanza=1 pitchstanza=0 autoline=line.strip().split(" ") for word in autoline: if (word == basename) or (word.startswith(basename+":")): pitchstanza=1 if not pitchstanza: stanza+=[line.strip()] elif line.strip() in (start_mark, end_mark): if inastanza: if not pitchstanza: newfile.extend(stanza) stanza=[] inastanza = 0 pitchstanza = 0 # Deduplicate markers. if line != prev_line: newfile += [line.strip()] else: if inastanza: if not pitchstanza: stanza+=[line.strip()] else: if not pitchstanza: newfile += [line.strip()] prev_line=line def emit(line): print(line) output = line + "\n" os.write(fd, output.encode('utf-8')) # Insert the new output at the end and inside the existing markers if found. emitted = False fd, path = tempfile.mkstemp() for line in newfile: if line == end_mark: emit("\n".join(output)) emitted = True emit(line) if not emitted: emit(start_mark) emit("\n".join(output)) emit(end_mark) os.close(fd) shutil.copy(path,if_filename) os.chmod(if_filename,0o644) #print("TMPFILE is at: " + path) #print("Copied file is at: " + if_filename) try: retcode = subprocess.call("ifdown "+basename , shell=True) if retcode < 0: print("Child was terminated by signal", -retcode, file=sys.stderr) else: print("Child returned", retcode, file=sys.stderr) except OSError as e: print("Execution failed:", e, file=sys.stderr) try: retcode = subprocess.call("ifup "+basename , shell=True) if retcode < 0: print("Child was terminated by signal", -retcode, file=sys.stderr) else: print("Child returned", retcode, file=sys.stderr) except OSError as e: print("Execution failed:", e, file=sys.stderr)