]>
Commit | Line | Data |
---|---|---|
1 | #!/usr/bin/env python | |
2 | # | |
3 | # This file and its contents are supplied under the terms of the | |
4 | # Common Development and Distribution License ("CDDL"), version 1.0. | |
5 | # You may only use this file in accordance with the terms of version | |
6 | # 1.0 of the CDDL. | |
7 | # | |
8 | # A full copy of the text of the CDDL should have accompanied this | |
9 | # source. A copy of the CDDL is also available via the Internet at | |
10 | # http://www.illumos.org/license/CDDL. | |
11 | # | |
12 | ||
13 | # | |
14 | # Copyright 2017 <Michael Rasmussen> | |
15 | # | |
16 | ||
17 | # | |
18 | # The porpuse of this script is to help with basic and/or initial | |
19 | # network configuration for Illumos based distribution. However, | |
20 | # the script is developed specifically for OmniOS so there is no | |
21 | # garaunty that it will work on other Illumos based distributions | |
22 | # than Omnios. | |
23 | # | |
24 | ||
25 | import sys, subprocess, getopt | |
26 | ||
27 | def runcmd(cmd): | |
28 | process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) | |
29 | output, error = process.communicate(); | |
30 | ||
31 | return (output.rstrip(), error.rstrip()) | |
32 | ||
33 | class ParserError(Exception): | |
34 | pass | |
35 | ||
36 | class Parser: | |
37 | """ Parse nic information """ | |
38 | ||
39 | def __init__(self): | |
40 | self.__dladm1 = "dladm show-phys -p -o link,media | sed 's/:/ /g'" | |
41 | self.__dladm2 = "dladm show-phys -p -m -o link,address,inuse | sed 's/:/ /g' | sed 's/\\\[[:space:]]/:/g' | sed 's/\\\//g'" | |
42 | ||
43 | def __parse_nics(self, text): | |
44 | nics = {} | |
45 | for line in text.splitlines(): | |
46 | parts = line.split() | |
47 | #if parts[1] in ('Ethernet', 'Infiniband'): | |
48 | if parts[1] in ('Ethernet'): | |
49 | nics[parts[0]] = [parts[0], parts[1]] | |
50 | ||
51 | return nics | |
52 | ||
53 | def __parse_macs(self, obj, text): | |
54 | list = [] | |
55 | if obj: | |
56 | for line in text.splitlines(): | |
57 | parts = line.split() | |
58 | try: | |
59 | if parts[2] == 'yes': | |
60 | del obj[parts[0]] | |
61 | else: | |
62 | obj[parts[0]].append(parts[1]) | |
63 | except KeyError: | |
64 | pass | |
65 | for k, v in obj.items(): | |
66 | list.append(v) | |
67 | ||
68 | return list | |
69 | ||
70 | def parse(self): | |
71 | (nics, error) = runcmd(self.__dladm1) | |
72 | if error: | |
73 | raise ParserError(error) | |
74 | ||
75 | (macs, error) = runcmd(self.__dladm2) | |
76 | if error: | |
77 | raise ParserError(error) | |
78 | ||
79 | return self.__parse_macs(self.__parse_nics(nics), macs) | |
80 | ||
81 | def get_terminal_width(): | |
82 | try: | |
83 | if sys.version_info >= (2,7): | |
84 | width = int(subprocess.check_output(['tput', 'cols'])) | |
85 | else: | |
86 | (out, err) = runcmd('tput cols') | |
87 | if err: | |
88 | raise OSError(err); | |
89 | width = int(out) | |
90 | except OSError as e: | |
91 | print("Invalid Command 'tput cols': exit status ({1})".format(e.errno)) | |
92 | except subprocess.CalledProcessError as e: | |
93 | print("Command 'tput cols' returned non-zero exit status: ({1})".format(e.returncode)) | |
94 | else: | |
95 | return width | |
96 | ||
97 | def make_menu(interfaces): | |
98 | res = None | |
99 | while not res: | |
100 | sys.stderr.write("\x1b[2J\x1b[H") | |
101 | cols = get_terminal_width() | |
102 | intro = 'The following unconfigured interfaces was discovered' | |
103 | fill = (cols / 2) - (len(intro) / 2) | |
104 | print '{0:^{cols}}'.format('Simple network interface configuration tool', cols=cols) | |
105 | ||
106 | print '{0:<{fill}}{1}'.format('', intro, fill=fill) | |
107 | print '{0:<{fill}}{1:>2} {2:^15} {3:^10} {4:^17}'.format('','#','Interface','Media','MAC',fill=fill) | |
108 | print '{0:<{fill}}{1:-^2} {2:-^15} {3:-^10} {4:-^17}'.format('','','','','',fill=fill) | |
109 | ||
110 | n = 0 | |
111 | for i in interfaces: | |
112 | print '{0:<{fill}}{1:>2} {2:<15} {3:<10} {4:>17}'.format('',n,i[0],i[1],i[2],fill=fill) | |
113 | n += 1 | |
114 | ||
115 | print '{0:<{fill}}{1:<}'.format('','select interface number to configure:',fill=fill), | |
116 | nic = int(raw_input()) | |
117 | if nic >= n or nic < 0: | |
118 | print '{0:<{fill}}{1:<} {2:<}'.format('','Error: Interface: 0 <= # <',n,fill=fill), | |
119 | raw_input(' << Hit any key >>') | |
120 | else: | |
121 | res = interfaces[nic] | |
122 | ||
123 | return res | |
124 | ||
125 | def get_config(): | |
126 | ip = mask = gw = None | |
127 | nettype = raw_input('dhcp or static [dhcp]: ').lower() | |
128 | if nettype == 'static': | |
129 | while not ip: | |
130 | ip = raw_input('Enter IP: ') | |
131 | mask = raw_input('Enter netmask [24]: ') | |
132 | if not mask: | |
133 | mask = 24 | |
134 | gw = raw_input('Enter default route [0=no]: ') | |
135 | if not gw: | |
136 | gw = 0 | |
137 | ||
138 | return (ip,mask,gw) | |
139 | ||
140 | def usage(): | |
141 | print 'Usage: %s [options]' % sys.argv[0] | |
142 | ||
143 | print '%s' % """Options: | |
144 | -h, --help This usage. | |
145 | -a, --address IP for interface. 0 means use DHCP | |
146 | -g, --gateway Default gateway. Optional. | |
147 | -i, --interface Interface to configure. | |
148 | -m, --netmask Netmask to use for interface. Default /24. | |
149 | -n, --nameserver Nameserver to use. Optional.""" | |
150 | ||
151 | def parse_input(): | |
152 | options = () | |
153 | ||
154 | try: | |
155 | opts, args = getopt.gnu_getopt(sys.argv[1:], | |
156 | 'ha:g:i:m:n:', ['help', 'address=', 'gateway=', | |
157 | 'interface=', 'netmask=', 'nameserver=']) | |
158 | except getopt.GetoptError as err: | |
159 | print str(err) | |
160 | usage() | |
161 | sys.exit(2) | |
162 | ||
163 | address = gateway = interface = netmask = nameserver = None | |
164 | ||
165 | if opts: | |
166 | for o, a in opts: | |
167 | if o in ('-h', '--help'): | |
168 | usage() | |
169 | sys.exit(0) | |
170 | if o in ('-a', '--address'): | |
171 | address = a | |
172 | elif o in ('-g', '--gateway'): | |
173 | gateway = a | |
174 | elif o in ('-i', '--interface'): | |
175 | interface = a | |
176 | elif o in ('-m', '--netmask'): | |
177 | netmask = a | |
178 | elif o in ('-n', '--nameserver'): | |
179 | nameserver = a | |
180 | else: | |
181 | assert False, 'Unhandled option' | |
182 | ||
183 | if not address or not interface: | |
184 | print 'Error: missing options' | |
185 | usage() | |
186 | sys.exit(2) | |
187 | if address == '0': | |
188 | address = None | |
189 | if not netmask: | |
190 | netmask = '24' | |
191 | ||
192 | options = (interface, address, netmask, gateway, nameserver) | |
193 | ||
194 | return options | |
195 | ||
196 | def main(): | |
197 | interactive = True | |
198 | ||
199 | options = parse_input() | |
200 | if options: | |
201 | interactive = False | |
202 | ||
203 | p = Parser() | |
204 | try: | |
205 | interfaces = p.parse() | |
206 | if interfaces: | |
207 | if interactive: | |
208 | nic = make_menu(interfaces) | |
209 | else: | |
210 | nic = options | |
211 | found = False | |
212 | for i in interfaces: | |
213 | if nic[0] == i[0]: | |
214 | found = True | |
215 | break | |
216 | if not found: | |
217 | err = '%s: No such interface' % nic[0] | |
218 | raise RuntimeError(err) | |
219 | if nic: | |
220 | if interactive: | |
221 | (ip,mask,gw) = get_config() | |
222 | else: | |
223 | ip = options[1] | |
224 | mask = options[2] | |
225 | gw = options[3] | |
226 | cmd = 'ipadm delete-if %s' % nic[0] | |
227 | runcmd(cmd) | |
228 | cmd = 'ipadm create-if %s' % nic[0] | |
229 | (out, err) = runcmd(cmd) | |
230 | if err: | |
231 | raise RuntimeError(err) | |
232 | if not ip: | |
233 | # use DHCP | |
234 | cmd = 'ipadm create-addr -T dhcp %s/v4' % nic[0] | |
235 | (out, err) = runcmd(cmd) | |
236 | if err: | |
237 | raise RuntimeError(err) | |
238 | else: | |
239 | # use STATIC | |
240 | cmd = 'ipadm create-addr -T static -a %s/%s %s/v4' % (ip, mask, nic[0]) | |
241 | (out, err) = runcmd(cmd) | |
242 | if err: | |
243 | raise RuntimeError(err) | |
244 | if gw: | |
245 | cmd = 'route -p add default %s' % gw | |
246 | (out, err) = runcmd(cmd) | |
247 | if err: | |
248 | raise RuntimeError(err) | |
249 | cmd = 'netstat -rn -finet' | |
250 | (out, err) = runcmd(cmd) | |
251 | if err: | |
252 | raise RuntimeError(err) | |
253 | print 'New route table' | |
254 | print out | |
255 | if interactive: | |
256 | dns = raw_input('Configure DNS [n]? ').lower() | |
257 | else: | |
258 | dns = options[4] | |
259 | if not dns or dns == 'n': | |
260 | pass | |
261 | else: | |
262 | if interactive: | |
263 | dns = None | |
264 | ||
265 | while not dns: | |
266 | dns = raw_input('Enter nameserver: ') | |
267 | ||
268 | cmd = "echo 'nameserver %s' >> /etc/resolv.conf " % dns | |
269 | cmd += '&& cp /etc/nsswitch.conf{,.bak} ' | |
270 | cmd += '&& cp /etc/nsswitch.{dns,conf}' | |
271 | (out, err) = runcmd(cmd) | |
272 | if err: | |
273 | raise RuntimeError(err) | |
274 | else: | |
275 | print "Found no unassigned interfaces" | |
276 | except ParserError as e: | |
277 | print 'Parse Errror: %s' % e | |
278 | except RuntimeError as e: | |
279 | print 'Runtime Error: %s' % e | |
280 | ||
281 | if __name__ == '__main__': | |
282 | try: | |
283 | main() | |
284 | except KeyboardInterrupt: | |
285 | sys.stderr.write("\x1b[2J\x1b[H") | |
286 |