#!/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) # # IPADDR0=ipaddr1 # IPADDR1=ipaddr2 # IPADDRx=ipaddry (where y = x + 1) # # NETMASK0=netmask1 # NETMASKx=netmasky (where y = x + 1) # # GATEWAY=ipaddr1 # GATEWAYx=ipaddry (where y = x + 1) # # DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc) # # IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be # tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as # IPV6NETMASK. # 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"] # DNS entries will go with the first interface and there can be a max # of three. These will be emitted with the first interface. dns = [] for count in (1, 2, 3): key = "DNS" + str(count) if key in kvp: dns += [kvp[key]] dns_emitted = False # IPV4 may either be dhcp or static. if ("DHCP" in kvp and kvp["DHCP"] == "yes") or \ ("BOOTPROTO" in kvp and kvp["BOOTPROTO"] == "dhcp"): output += ["auto " + basename] output += ["iface " + basename + " inet dhcp"] output += [""] else: autolist = [] # Matchup the interface specific lines # No real max for the number of interface + aliases ... # only required is the address (but mate everything up that comes in. # IPv4 -- ensure we sort by numeric suffixes. v4names = [ int(name[6:]) for name in kvp.keys() if name.startswith("IPADDR") ] v4names.sort() for if_count in v4names: ifname = basename which = str(if_count) if if_count: ifname += ":" + str(if_count) which_gw = which else: which_gw = "" if not ifname in autolist: autolist += [ifname] output += [ "iface " + ifname + " inet static" ] output += [ "\t" + "address " + kvp["IPADDR" + which] ] if "NETMASK" + which in kvp: output += [ "\tnetmask " + kvp["NETMASK" + which] ] if "GATEWAY" + which_gw in kvp: output += ["\tgateway " + kvp["GATEWAY" + which_gw]] if not dns_emitted: dns_emitted = True output += ["\tdns-nameservers " + ' '.join(dns)] output += [""] # 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 = [ int(name[8:]) for name in kvp.keys() if name.startswith("IPV6ADDR") ] v6names.sort() for if6_count in v6names: ifname = basename which = str(if6_count) if if6_count: ifname += ":" + str(if6_count) which_gw = which else: which_gw = "" if not ifname in autolist: autolist += [ifname] if "IPV6NETMASK" + which in kvp: output += [ "iface " + ifname + " inet6 static"] output += [ "\taddress " + kvp["IPV6ADDR" + which]] output += [ "\tnetmask " + kvp["IPV6NETMASK" + which]] if "IPV6_DEFAULTGW" + which_gw in kvp: output += [ "\tgateway " + kvp["IPV6_DEFAULTGW" + which_gw] ] if not dns_emitted: dns_emitted = True output += ["\tdns-nameservers " + ' '.join(dns)] output += [""] # 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)