+#!/usr/bin/env python
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 <Michael Rasmussen>
+#
+
+#
+# The porpuse of this script is to help with basic and/or initial
+# network configuration for Illumos based distribution. However,
+# the script is developed specifically for OmniOS so there is no
+# garaunty that it will work on other Illumos based distributions
+# than Omnios.
+#
+
+import sys, subprocess, getopt
+
+def runcmd(cmd):
+ process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+ output, error = process.communicate();
+
+ return (output.rstrip(), error.rstrip())
+
+class ParserError(Exception):
+ pass
+
+class Parser:
+ """ Parse nic information """
+
+ def __init__(self):
+ self.__dladm1 = "dladm show-phys -p -o link,media | sed 's/:/ /g'"
+ self.__dladm2 = "dladm show-phys -p -m -o link,address,inuse | sed 's/:/ /g' | sed 's/\\\[[:space:]]/:/g' | sed 's/\\\//g'"
+
+ def __parse_nics(self, text):
+ nics = {}
+ for line in text.splitlines():
+ parts = line.split()
+ #if parts[1] in ('Ethernet', 'Infiniband'):
+ if parts[1] in ('Ethernet'):
+ nics[parts[0]] = [parts[0], parts[1]]
+
+ return nics
+
+ def __parse_macs(self, obj, text):
+ list = []
+ if obj:
+ for line in text.splitlines():
+ parts = line.split()
+ try:
+ if parts[2] == 'yes':
+ del obj[parts[0]]
+ else:
+ obj[parts[0]].append(parts[1])
+ except KeyError:
+ pass
+ for k, v in obj.items():
+ list.append(v)
+
+ return list
+
+ def parse(self):
+ (nics, error) = runcmd(self.__dladm1)
+ if error:
+ raise ParserError(error)
+
+ (macs, error) = runcmd(self.__dladm2)
+ if error:
+ raise ParserError(error)
+
+ return self.__parse_macs(self.__parse_nics(nics), macs)
+
+def get_terminal_width():
+ try:
+ if sys.version_info >= (2,7):
+ width = int(subprocess.check_output(['tput', 'cols']))
+ else:
+ (out, err) = runcmd('tput cols')
+ if err:
+ raise OSError(err);
+ width = int(out)
+ except OSError as e:
+ print("Invalid Command 'tput cols': exit status ({1})".format(e.errno))
+ except subprocess.CalledProcessError as e:
+ print("Command 'tput cols' returned non-zero exit status: ({1})".format(e.returncode))
+ else:
+ return width
+
+def make_menu(interfaces):
+ res = None
+ while not res:
+ sys.stderr.write("\x1b[2J\x1b[H")
+ cols = get_terminal_width()
+ intro = 'The following unconfigured interfaces was discovered'
+ fill = (cols / 2) - (len(intro) / 2)
+ print '{0:^{cols}}'.format('Simple network interface configuration tool', cols=cols)
+ print
+ print '{0:<{fill}}{1}'.format('', intro, fill=fill)
+ print '{0:<{fill}}{1:>2} {2:^15} {3:^10} {4:^17}'.format('','#','Interface','Media','MAC',fill=fill)
+ print '{0:<{fill}}{1:-^2} {2:-^15} {3:-^10} {4:-^17}'.format('','','','','',fill=fill)
+
+ n = 0
+ for i in interfaces:
+ print '{0:<{fill}}{1:>2} {2:<15} {3:<10} {4:>17}'.format('',n,i[0],i[1],i[2],fill=fill)
+ n += 1
+ print
+ print '{0:<{fill}}{1:<}'.format('','select interface number to configure:',fill=fill),
+ nic = int(raw_input())
+ if nic >= n or nic < 0:
+ print '{0:<{fill}}{1:<} {2:<}'.format('','Error: Interface: 0 <= # <',n,fill=fill),
+ raw_input(' << Hit any key >>')
+ else:
+ res = interfaces[nic]
+
+ return res
+
+def get_config():
+ ip = mask = gw = None
+ nettype = raw_input('dhcp or static [dhcp]: ').lower()
+ if nettype == 'static':
+ while not ip:
+ ip = raw_input('Enter IP: ')
+ mask = raw_input('Enter netmask [24]: ')
+ if not mask:
+ mask = 24
+ gw = raw_input('Enter default route [0=no]: ')
+ if not gw:
+ gw = 0
+
+ return (ip,mask,gw)
+
+def usage():
+ print 'Usage: %s [options]' % sys.argv[0]
+ print
+ print '%s' % """Options:
+ -h, --help This usage.
+ -a, --address IP for interface. 0 means use DHCP
+ -g, --gateway Default gateway. Optional.
+ -i, --interface Interface to configure.
+ -m, --netmask Netmask to use for interface. Default /24.
+ -n, --nameserver Nameserver to use. Optional.
+ -r, --record Output create commands to stdout."""
+
+def parse_input():
+ options = ()
+
+ try:
+ opts, args = getopt.gnu_getopt(sys.argv[1:],
+ 'ha:g:i:m:n:r', ['help', 'address=', 'gateway=',
+ 'interface=', 'netmask=', 'nameserver=', 'record'])
+ except getopt.GetoptError as err:
+ print str(err)
+ usage()
+ sys.exit(2)
+
+ address = gateway = interface = netmask = nameserver = None
+ record = False
+
+ if opts:
+ for o, a in opts:
+ if o in ('-h', '--help'):
+ usage()
+ sys.exit(0)
+ if o in ('-a', '--address'):
+ address = a
+ elif o in ('-g', '--gateway'):
+ gateway = a
+ elif o in ('-i', '--interface'):
+ interface = a
+ elif o in ('-m', '--netmask'):
+ netmask = a
+ elif o in ('-n', '--nameserver'):
+ nameserver = a
+ elif o in ('-r', '--record'):
+ record = True
+ else:
+ assert False, 'Unhandled option'
+
+ if (record):
+ if (bool(address) ^ bool(interface)):
+ print 'Error: missing options'
+ usage()
+ sys.exit(2)
+ else:
+ if not address or not interface or error:
+ print 'Error: missing options'
+ usage()
+ sys.exit(2)
+
+ if address == '0':
+ address = None
+ if not netmask:
+ netmask = '24'
+
+ options = (interface, address, netmask, gateway, nameserver, record)
+
+ return options
+
+def main():
+ interactive = True
+ record = False
+ output = ''
+
+ options = parse_input()
+ if options:
+ record = options[5]
+ if (options[0]):
+ interactive = False
+
+ p = Parser()
+ try:
+ interfaces = p.parse()
+ if interfaces:
+ if interactive:
+ nic = make_menu(interfaces)
+ else:
+ nic = options
+ found = False
+ for i in interfaces:
+ if nic[0] == i[0]:
+ found = True
+ break
+ if not found:
+ err = '%s: No such interface' % nic[0]
+ raise RuntimeError(err)
+ if nic:
+ if interactive:
+ (ip,mask,gw) = get_config()
+ else:
+ ip = options[1]
+ mask = options[2]
+ gw = options[3]
+ cmd = 'ipadm delete-if %s' % nic[0]
+ if record:
+ output += cmd
+ else:
+ runcmd(cmd)
+ cmd = 'ipadm create-if %s' % nic[0]
+ if record:
+ output += "\n" + cmd
+ else:
+ (out, err) = runcmd(cmd)
+ if err:
+ raise RuntimeError(err)
+ if not ip:
+ # use DHCP
+ cmd = 'ipadm create-addr -T dhcp %s/v4' % nic[0]
+ if record:
+ output += "\n" + cmd
+ else:
+ (out, err) = runcmd(cmd)
+ if err:
+ raise RuntimeError(err)
+ else:
+ # use STATIC
+ cmd = 'ipadm create-addr -T static -a %s/%s %s/v4' % (ip, mask, nic[0])
+ if record:
+ output += "\n" + cmd
+ else:
+ (out, err) = runcmd(cmd)
+ if err:
+ raise RuntimeError(err)
+ if gw:
+ cmd = 'route -p add default %s' % gw
+ if record:
+ output += "\n" + cmd
+ else:
+ (out, err) = runcmd(cmd)
+ if err:
+ raise RuntimeError(err)
+ if not record:
+ cmd = 'netstat -rn -finet'
+ (out, err) = runcmd(cmd)
+ if err:
+ raise RuntimeError(err)
+ print 'New route table'
+ print out
+ if interactive:
+ dns = raw_input('Configure DNS [n]? ').lower()
+ else:
+ dns = options[4]
+ if not dns or dns == 'n':
+ pass
+ else:
+ if interactive:
+ dns = None
+ print
+ while not dns:
+ dns = raw_input('Enter nameserver: ')
+
+ cmd = "echo 'nameserver %s' >> /etc/resolv.conf " % dns
+ cmd += '&& cp /etc/nsswitch.conf{,.bak} '
+ cmd += '&& cp /etc/nsswitch.{dns,conf}'
+ if record:
+ output += "\n" + cmd
+ else:
+ (out, err) = runcmd(cmd)
+ if err:
+ raise RuntimeError(err)
+ if record:
+ print output
+ else:
+ print "Found no unassigned interfaces"
+ except ParserError as e:
+ print 'Parse Errror: %s' % e
+ except RuntimeError as e:
+ print 'Runtime Error: %s' % e
+
+if __name__ == '__main__':
+ try:
+ main()
+ except KeyboardInterrupt:
+ sys.stderr.write("\x1b[2J\x1b[H")
+