blob: 96a7cfc21d44a9922b0b16d162cde4f212331009 [file] [log] [blame]
Steve McIntyre844bfd42014-11-27 16:58:31 +00001#! /usr/bin/python
2
Steve McIntyre8e99c5f2018-02-02 15:23:46 +00003# Copyright 2014-2018 Linaro Limited
Steve McIntyre844bfd42014-11-27 16:58:31 +00004#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18# MA 02110-1301, USA.
19#
20# VLANd admin interface
21#
22
Steve McIntyre5694f6d2014-12-18 16:43:30 +000023import os, sys
Steve McIntyre460358a2016-03-12 11:57:53 +000024import argparse
Steve McIntyreea343aa2015-10-23 17:46:17 +010025import datetime, time
Steve McIntyre844bfd42014-11-27 16:58:31 +000026
27vlandpath = os.path.abspath(os.path.normpath(os.path.dirname(sys.argv[0])))
28sys.path.insert(0, vlandpath)
29
Steve McIntyreb01959f2016-03-22 17:02:39 +000030from errors import InputError, SocketError, NotFoundError, Error
Steve McIntyre21f02702014-12-16 18:19:47 +000031from config.config import VlanConfig
32from ipc.ipc import VlanIpc
Steve McIntyre844bfd42014-11-27 16:58:31 +000033
Steve McIntyre53787d22018-02-02 17:08:04 +000034prog = "vland-admin"
Steve McIntyrea6b485d2018-02-02 16:49:55 +000035version = "0.7"
Steve McIntyre844bfd42014-11-27 16:58:31 +000036banner = "Linaro VLANd admin interface, version %s" % version
Steve McIntyref5ef6962016-03-22 17:21:47 +000037exitcode = Error.OK
Steve McIntyrec4890132015-08-07 15:19:11 +010038TRUNK_ID_NONE = -1
39
Steve McIntyreae95fd62014-12-05 16:51:41 +000040def is_positive(text):
Steve McIntyrec6895fc2014-12-19 15:01:08 +000041 if text in ('1', 'y', 'Y', 't', 'T', 'True', 'true'):
Steve McIntyreae95fd62014-12-05 16:51:41 +000042 return True
Steve McIntyrec6895fc2014-12-19 15:01:08 +000043 elif text in ('0', 'n', 'N', 'f', 'F', 'False', 'false'):
Steve McIntyreae95fd62014-12-05 16:51:41 +000044 return False
45 else:
46 raise InputError("Cannot parse \"%s\" as True or False" % text)
47
Steve McIntyrea132c362014-12-05 15:53:21 +000048def dump_switch(switch):
Steve McIntyre018d30c2015-02-09 06:34:57 +000049 print "switch_id:%d name:%s" % (
Steve McIntyre89932392018-02-02 10:15:53 +000050 int(switch['switch_id']),
51 switch['name'])
Steve McIntyrea132c362014-12-05 15:53:21 +000052
Steve McIntyre11e4cbd2014-12-05 16:03:03 +000053def dump_port(port):
Steve McIntyre7d219202018-02-01 16:53:25 +000054 print "port_id:%d name:%s switch_id:%d locked:%s mode:%s base_vlan_id:%d current_vlan_id:%d number:%d trunk_id:%s lock_reason:%s" % (
Steve McIntyre89932392018-02-02 10:15:53 +000055 int(port['port_id']),
56 port['name'],
57 int(port['switch_id']),
58 ("yes" if port['is_locked'] is True else "no"),
59 ("trunk" if port['is_trunk'] is True else "access"),
60 int(port['base_vlan_id']),
61 int(port['current_vlan_id']),
62 int(port['number']),
63 'None' if (TRUNK_ID_NONE == port['trunk_id']) else port['trunk_id'],
64 port['lock_reason'])
Steve McIntyre11e4cbd2014-12-05 16:03:03 +000065
Steve McIntyree41e3f32014-12-05 18:08:21 +000066def dump_vlan(vlan):
Steve McIntyre018d30c2015-02-09 06:34:57 +000067 print "vlan_id:%d name:%s tag:%d is_base_vlan:%s, creation_time:%s" % (
Steve McIntyre89932392018-02-02 10:15:53 +000068 int(vlan['vlan_id']),
69 vlan['name'],
70 int(vlan['tag']),
71 ("yes" if vlan['is_base_vlan'] is True else "no"),
72 vlan['creation_time'])
Steve McIntyree41e3f32014-12-05 18:08:21 +000073
Steve McIntyrec4890132015-08-07 15:19:11 +010074def dump_trunk(trunk):
75 print "trunk_id:%d creation_time:%s" % (
Steve McIntyre89932392018-02-02 10:15:53 +000076 int(trunk['trunk_id']),
77 trunk['creation_time'])
Steve McIntyrec4890132015-08-07 15:19:11 +010078
Steve McIntyref1c04f92014-12-16 18:23:15 +000079def call_vland(msgtype, msg):
80 ipc = VlanIpc()
81 ipc.client_connect('localhost', config.vland.port)
Steve McIntyre53787d22018-02-02 17:08:04 +000082 msg['client_name'] = 'vland-admin'
Steve McIntyref1c04f92014-12-16 18:23:15 +000083 msg['type'] = msgtype
Steve McIntyref1c04f92014-12-16 18:23:15 +000084 ipc.client_send(msg)
85 ret = ipc.client_recv_and_close()
86 if 'response' not in ret:
87 raise SocketError("Badly-formed response from VLANd server")
88 if ret['response'] == "ERROR":
Steve McIntyreb01959f2016-03-22 17:02:39 +000089 raise InputError("VLANd server said \"%s\"" % ret['error'])
90 if ret['response'] == "NOTFOUND":
91 raise NotFoundError("VLANd server said \"%s\"" % ret['error'])
Steve McIntyref1c04f92014-12-16 18:23:15 +000092 return ret['data']
93
Steve McIntyrec12f6312014-12-15 15:00:12 +000094config = VlanConfig(filenames=('./vland.cfg',))
Steve McIntyrec12f6312014-12-15 15:00:12 +000095
Steve McIntyre460358a2016-03-12 11:57:53 +000096parser = argparse.ArgumentParser()
Steve McIntyre844bfd42014-11-27 16:58:31 +000097
Steve McIntyre460358a2016-03-12 11:57:53 +000098####################
Steve McIntyre9cd6c3d2014-12-05 18:10:35 +000099# System commands
Steve McIntyre460358a2016-03-12 11:57:53 +0000100####################
101sp = parser.add_subparsers(title='Sub-commands',
102 help="Commands",
103 dest='subparser_name')
104p_status = sp.add_parser("status",
105 help="Describe current system status")
106p_status.set_defaults(which = "status")
107p_statistics = sp.add_parser("statistics",
108 help="Print some system statistics")
109p_statistics.set_defaults(which = "statistics")
110p_version = sp.add_parser("version",
111 help="Describe the version of this admin interface")
112p_version.set_defaults(which = "version")
113p_vland_version = sp.add_parser("vland_version",
114 help="Describe the version of the running VLANd")
115p_vland_version.set_defaults(which = "vland_version")
116p_probe_switches = sp.add_parser("probe_switches",
117 help="Probe all the configured switches")
118p_probe_switches.set_defaults(which = "probe_switches")
119p_auto_import = sp.add_parser("auto_import_switch",
120 help="Attempt to import a switch's configuration into the VLANd system")
121p_auto_import.add_argument('--name',
122 required = True,
123 help="Import the switch named SWITCH_NAME in vland.cfg")
124p_auto_import.set_defaults(which = "auto_import_switch")
125p_shutdown = sp.add_parser("shutdown",
126 help="Shut down a running VLANd")
127p_shutdown.set_defaults(which = "shutdown")
Steve McIntyre9cd6c3d2014-12-05 18:10:35 +0000128
Steve McIntyre460358a2016-03-12 11:57:53 +0000129####################
Steve McIntyre844bfd42014-11-27 16:58:31 +0000130# Switch commands
Steve McIntyre460358a2016-03-12 11:57:53 +0000131####################
132p_list_all_switches = sp.add_parser("list_all_switches",
133 help="List all the existing switches in the system")
134p_list_all_switches.set_defaults(which = "list_all_switches")
135p_create_switch = sp.add_parser("create_switch",
136 help = "Add a new switch to the system")
137p_create_switch.set_defaults(which = "create_switch")
138p_create_switch.add_argument('--name',
139 required = True,
140 help="The name of the new switch, as described in vland.cfg")
141p_delete_switch = sp.add_parser("delete_switch",
142 help = "Remove an existing switch from the system")
143p_delete_switch.set_defaults(which = "delete_switch")
144p_delete_switch.add_argument('--switch_id',
145 required = True,
146 help = "The ID of the switch to remove")
147p_show_switch = sp.add_parser("show_switch",
148 help = "Show the details of an existing switch in the system")
149p_show_switch.set_defaults(which = "show_switch")
150p_show_switch.add_argument('--switch_id',
151 required = True,
152 help = "The ID of the switch to show")
153p_lookup_switch_by_name = sp.add_parser("lookup_switch_by_name",
154 help = "Lookup a switch ID by name")
155p_lookup_switch_by_name.set_defaults(which = "lookup_switch_by_name")
156p_lookup_switch_by_name.add_argument('--name',
157 required = True,
158 help = "The switch name to search for")
Steve McIntyre844bfd42014-11-27 16:58:31 +0000159
Steve McIntyre460358a2016-03-12 11:57:53 +0000160####################
161# Ports commands
162####################
163p_list_all_ports = sp.add_parser("list_all_ports",
164 help="List all the existing ports in the system")
165p_list_all_ports.set_defaults(which = "list_all_ports")
166p_create_port = sp.add_parser("create_port",
167 help = "Add a new port to the system")
168p_create_port.set_defaults(which = "create_port")
169p_create_port.add_argument('--switch_id',
170 required = True,
171 help="The ID of the switch containing the new port")
172p_create_port.add_argument('--name',
173 required = True,
174 help="The name of the new port")
175p_create_port.add_argument('--number',
176 required = True,
177 help="The human-friendly number for the new port")
178p_delete_port = sp.add_parser("delete_port",
179 help = "Remove an existing port from the system")
180p_delete_port.set_defaults(which = "delete_port")
181p_delete_port.add_argument('--port_id',
182 required = True,
183 help = "The ID of the port to remove")
184p_show_port = sp.add_parser("show_port",
185 help = "Show the details of an existing port in the system")
186p_show_port.set_defaults(which = "show_port")
187p_show_port.add_argument('--port_id',
188 required = True,
189 help = "The ID of the port to show")
190p_lookup_port_by_switch_and_name = sp.add_parser("lookup_port_by_switch_and_name",
191 help = "Lookup a port ID by switch ID and port name")
192p_lookup_port_by_switch_and_name.set_defaults(which = "lookup_port_by_switch_and_name")
193p_lookup_port_by_switch_and_name.add_argument('--switch_id',
194 required = True,
195 help = "The switch ID to search for")
196p_lookup_port_by_switch_and_name.add_argument('--name',
197 required = True,
198 help = "The port name to search for")
199p_lookup_port_by_switch_and_number = sp.add_parser("lookup_port_by_switch_and_number",
200 help = "Lookup a port ID by switch ID and port number")
201p_lookup_port_by_switch_and_number.set_defaults(which = "lookup_port_by_switch_and_number")
202p_lookup_port_by_switch_and_number.add_argument('--switch_id',
203 required = True,
204 help = "The switch ID to search for")
205p_lookup_port_by_switch_and_number.add_argument('--number',
206 required = True,
207 help = "The port number to search for")
208p_lookup_ports_by_switch = sp.add_parser("lookup_ports_by_switch",
209 help = "Lookup port ID(s) by switch ID")
210p_lookup_ports_by_switch.set_defaults(which = "lookup_ports_by_switch")
211p_lookup_ports_by_switch.add_argument('--switch_id',
212 required = True,
213 help = "The switch ID to search for")
214p_lookup_ports_by_current_vlan = sp.add_parser("lookup_ports_by_current_vlan",
215 help = "Lookup port ID(s) by current VLAN ID")
216p_lookup_ports_by_current_vlan.set_defaults(which = "lookup_ports_by_current_vlan")
217p_lookup_ports_by_current_vlan.add_argument('--vlan_id',
218 required = True,
219 help = "The VLAN ID to search for")
220p_lookup_ports_by_base_vlan = sp.add_parser("lookup_ports_by_base_vlan",
221 help = "Lookup port ID(s) by base vlan ID")
222p_lookup_ports_by_base_vlan.set_defaults(which = "lookup_ports_by_base_vlan")
223p_lookup_ports_by_base_vlan.add_argument('--vlan_id',
224 required = True,
225 help = "The VLAN ID to search for")
226p_lookup_ports_by_trunk = sp.add_parser("lookup_ports_by_trunk",
227 help = "Lookup port ID(s) by trunk ID")
228p_lookup_ports_by_trunk.set_defaults(which = "lookup_ports_by_trunk")
229p_lookup_ports_by_trunk.add_argument('--trunk_id',
230 required = True,
231 help = "The trunk ID to search for")
232p_set_port_mode = sp.add_parser("set_port_mode",
233 help = "Set the mode of a port to 'trunk' or 'access'")
234p_set_port_mode.set_defaults(which = "set_port_mode")
235p_set_port_mode.add_argument('--port_id',
236 required = True,
237 help = "The ID of the port to modify")
238p_set_port_mode.add_argument('--mode',
239 required = True,
240 help = "The mode to select ('trunk' or 'access')")
241p_get_port_mode = sp.add_parser("get_port_mode",
242 help = "Get the mode of a port ('trunk' or 'access')")
243p_get_port_mode.set_defaults(which = "get_port_mode")
244p_get_port_mode.add_argument('--port_id',
245 required = True,
246 help = "The ID of the port to query")
247p_lock_port = sp.add_parser("lock_port",
248 help = "Lock the settings on a port")
249p_lock_port.set_defaults(which = "lock_port")
250p_lock_port.add_argument('--port_id',
251 required = True,
252 help = "The ID of the port to lock")
Steve McIntyre7d219202018-02-01 16:53:25 +0000253p_lock_port.add_argument('--reason',
254 required = False,
255 help = "(Optional) The reason for locking the port")
Steve McIntyre460358a2016-03-12 11:57:53 +0000256p_unlock_port = sp.add_parser("unlock_port",
257 help = "Unlock the settings on a port")
258p_unlock_port.set_defaults(which = "unlock_port")
259p_unlock_port.add_argument('--port_id',
260 required = True,
261 help = "The ID of the port to unlock")
262p_set_port_current_vlan = sp.add_parser("set_port_current_vlan",
263 help = "Set the current VLAN assignment for a port")
264p_set_port_current_vlan.set_defaults(which = "set_port_current_vlan")
265p_set_port_current_vlan.add_argument('--port_id',
266 required = True,
267 help = "The ID of the port to modify")
268p_set_port_current_vlan.add_argument('--vlan_id',
269 required = True,
270 help = "The VLAN ID to be used")
271p_get_port_current_vlan = sp.add_parser("get_port_current_vlan",
272 help = "Get the current VLAN assignment for a port")
273p_get_port_current_vlan.set_defaults(which = "get_port_current_vlan")
274p_get_port_current_vlan.add_argument('--port_id',
275 required = True,
276 help = "The ID of the port to query")
277p_set_port_base_vlan = sp.add_parser("set_port_base_vlan",
278 help = "Set the base VLAN assignment for a port")
279p_set_port_base_vlan.set_defaults(which = "set_port_base_vlan")
280p_set_port_base_vlan.add_argument('--port_id',
281 required = True,
282 help = "The ID of the port to modify")
283p_set_port_base_vlan.add_argument('--vlan_id',
284 required = True,
285 help = "The VLAN ID to be used")
286p_get_port_base_vlan = sp.add_parser("get_port_base_vlan",
287 help = "Get the base VLAN assignment for a port")
288p_get_port_base_vlan.set_defaults(which = "get_port_base_vlan")
289p_get_port_base_vlan.add_argument('--port_id',
290 required = True,
291 help = "The ID of the port to query")
292p_restore_port_to_base_vlan = sp.add_parser("restore_port_to_base_vlan",
293 help = "Reset a port back to its base VLAN")
294p_restore_port_to_base_vlan.set_defaults(which = "restore_port_to_base_vlan")
295p_restore_port_to_base_vlan.add_argument('--port_id',
296 required = True,
297 help = "The ID of the port to modify")
Steve McIntyre844bfd42014-11-27 16:58:31 +0000298
Steve McIntyre460358a2016-03-12 11:57:53 +0000299####################
Steve McIntyre844bfd42014-11-27 16:58:31 +0000300# VLAN commands
Steve McIntyre460358a2016-03-12 11:57:53 +0000301####################
302p_list_all_vlans = sp.add_parser("list_all_vlans",
303 help="List all the existing VLANs in the system")
304p_list_all_vlans.set_defaults(which = "list_all_vlans")
305p_create_vlan = sp.add_parser("create_vlan",
306 help = "Add a new VLAN to the system")
307p_create_vlan.set_defaults(which = "create_vlan")
308p_create_vlan.add_argument('--name',
309 required = True,
310 help="The name of the new VLAN")
311p_create_vlan.add_argument('--tag',
312 required = True,
313 help="The tag for the new VLAN (-1 to automatically select)")
314p_create_vlan.add_argument('--is_base_vlan',
315 required = True,
316 help="Is the new VLAN a base VLAN (true/false)")
317p_delete_vlan = sp.add_parser("delete_vlan",
318 help = "Remove an existing VLAN from the system")
319p_delete_vlan.set_defaults(which = "delete_vlan")
320p_delete_vlan.add_argument('--vlan_id',
321 required = True,
322 help = "The ID of the VLAN to remove")
323p_show_vlan = sp.add_parser("show_vlan",
324 help = "Show the details of an existing VLAN in the system")
325p_show_vlan.set_defaults(which = "show_vlan")
326p_show_vlan.add_argument('--vlan_id',
327 required = True,
328 help = "The ID of the VLAN to show")
329p_lookup_vlan_by_tag = sp.add_parser("lookup_vlan_by_tag",
330 help = "Find the VLAN ID of an existing VLAN in the system")
331p_lookup_vlan_by_tag.set_defaults(which = "lookup_vlan_by_tag")
332p_lookup_vlan_by_tag.add_argument('--tag',
333 required = True,
334 help = "The VLAN tag to search for")
335p_show_vlan_tag = sp.add_parser("show_vlan_tag",
336 help = "Print the VLAN tag of an existing VLAN in the system")
337p_show_vlan_tag.set_defaults(which = "show_vlan_tag")
338p_show_vlan_tag.add_argument('--vlan_id',
339 required = True,
340 help = "The VLAN ID to search for")
Steve McIntyre844bfd42014-11-27 16:58:31 +0000341
Steve McIntyre460358a2016-03-12 11:57:53 +0000342####################
343# Trunk commands
344####################
345p_list_all_trunks = sp.add_parser("list_all_trunks",
346 help="List all the existing trunks in the system")
347p_list_all_trunks.set_defaults(which = "list_all_trunks")
348p_create_trunk = sp.add_parser("create_trunk",
349 help = "Add a new trunk to the system, linking two ports")
350p_create_trunk.set_defaults(which = "create_trunk")
351p_create_trunk.add_argument('--port_id1',
352 required = True,
353 help="The ID of the first port to be used")
354p_create_trunk.add_argument('--port_id2',
355 required = True,
356 help="The ID of the second port to be used")
357p_delete_trunk = sp.add_parser("delete_trunk",
358 help = "Remove an existing trunk from the system")
359p_delete_trunk.set_defaults(which = "delete_trunk")
360p_delete_trunk.add_argument('--trunk_id',
361 required = True,
362 help = "The ID of the trunk to remove")
363p_show_trunk = sp.add_parser("show_trunk",
364 help = "Show the details of an existing trunk in the system")
365p_show_trunk.set_defaults(which = "show_trunk")
366p_show_trunk.add_argument('--trunk_id',
367 required = True,
368 help = "The ID of the trunk to show")
Steve McIntyrec4890132015-08-07 15:19:11 +0100369
Steve McIntyre460358a2016-03-12 11:57:53 +0000370args = parser.parse_args()
Steve McIntyrec4890132015-08-07 15:19:11 +0100371
Steve McIntyre460358a2016-03-12 11:57:53 +0000372# Now work out what to do
373if args.which == 'status':
Steve McIntyreb01959f2016-03-22 17:02:39 +0000374 try:
375 print 'Config:'
376 print ' knows about %d switch(es)' % len(config.switches)
377 default_vlan_id = call_vland('db_query',
378 {'command':'db.get_vlan_id_by_tag',
379 'data':
380 {'tag': config.vland.default_vlan_tag}})
381 print 'The default vlan tag (%d) is vlan ID %d' % (config.vland.default_vlan_tag, default_vlan_id)
382 stat = call_vland('daemon_query', {'command':'daemon.status', 'data': None})
383 print 'VLANd is running %s' % stat['running']
384 lastmod = datetime.datetime.strptime(stat['last_modified'], '%Y-%m-%dT%H:%M:%S.%f')
385 print 'DB Last modified %s' % lastmod.strftime('%Y-%m-%d %H:%M:%S %Z')
386 print 'DB via VLANd:'
387 switches = call_vland('db_query', {'command':'db.all_switches', 'data':None})
388 print ' knows about %d switch(es)' % len(switches)
389 ports = call_vland('db_query', {'command':'db.all_ports', 'data':None})
390 print ' knows about %d port(s)' % len(ports)
391 vlans = call_vland('db_query', {'command':'db.all_vlans', 'data':None})
392 print ' DB knows about %d vlan(s)' % len(vlans)
Steve McIntyref5ef6962016-03-22 17:21:47 +0000393 except (InputError, NotFoundError):
394 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000395elif args.which == 'shutdown':
Steve McIntyreb01959f2016-03-22 17:02:39 +0000396 try:
397 print 'Asking VLANd to shutdown'
398 shutdown = call_vland('daemon_query',
399 {'command':'daemon.shutdown',
400 'data': None})
401 for field in shutdown:
402 print '%s: %s' % (field, shutdown[field])
Steve McIntyref5ef6962016-03-22 17:21:47 +0000403 except (InputError, NotFoundError):
404 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000405elif args.which == 'vland_version':
Steve McIntyreb01959f2016-03-22 17:02:39 +0000406 try:
407 ver = call_vland('daemon_query', {'command':'daemon.version', 'data': None})
408 print 'VLANd version %s' % ver['version']
Steve McIntyref5ef6962016-03-22 17:21:47 +0000409 except (InputError, NotFoundError):
410 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000411elif args.which == 'statistics':
Steve McIntyreb01959f2016-03-22 17:02:39 +0000412 try:
413 stats = call_vland('daemon_query', {'command':'daemon.statistics', 'data': None})
414 print 'VLANd uptime: %d seconds' % stats['uptime']
Steve McIntyref5ef6962016-03-22 17:21:47 +0000415 except (InputError, NotFoundError):
416 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000417elif args.which == 'version':
418 print 'VLANd admin interface version %s' % version
419elif args.which == 'auto_import_switch':
420 print 'Attempting to import switch %s' % args.name
421 if args.name not in config.switches:
422 raise InputError("Can't find switch %s in config" % args.name)
Steve McIntyreb01959f2016-03-22 17:02:39 +0000423 try:
424 imp = call_vland('vlan_update',
425 {'command':'api.auto_import_switch',
426 'data':
427 {'switch': args.name}})
428 print 'VLANd imported switch %s successfully: new switch_id %d, %d new ports, %d new VLANs' % (args.name, imp['switch_id'], imp['num_ports_added'], imp['num_vlans_added'])
Steve McIntyref5ef6962016-03-22 17:21:47 +0000429 except (InputError, NotFoundError):
Steve McIntyreb01959f2016-03-22 17:02:39 +0000430 print 'Import failed - see log for details'
Steve McIntyref5ef6962016-03-22 17:21:47 +0000431 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000432elif args.which == 'probe_switches':
433 print 'Asking VLANd to probe all the configured switches'
Steve McIntyreb01959f2016-03-22 17:02:39 +0000434 try:
435 probe = call_vland('daemon_query',
436 {'command':'daemon.probe_switches',
437 'data': None})
438 for field in probe:
439 print '%s: %s' % (field, probe[field])
Steve McIntyref5ef6962016-03-22 17:21:47 +0000440 except (InputError, NotFoundError):
Steve McIntyreb01959f2016-03-22 17:02:39 +0000441 print 'Probe failed - see log for details'
Steve McIntyref5ef6962016-03-22 17:21:47 +0000442 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000443elif args.which == 'list_all_switches':
Steve McIntyreb01959f2016-03-22 17:02:39 +0000444 try:
445 result = call_vland('db_query', {'command':'db.all_switches', 'data':None})
446 for line in result:
447 dump_switch(line)
Steve McIntyref5ef6962016-03-22 17:21:47 +0000448 except (InputError, NotFoundError):
449 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000450elif args.which == 'list_all_ports':
Steve McIntyreb01959f2016-03-22 17:02:39 +0000451 try:
452 result = call_vland('db_query', {'command':'db.all_ports', 'data':None})
453 for line in result:
454 dump_port(line)
Steve McIntyref5ef6962016-03-22 17:21:47 +0000455 except (InputError, NotFoundError):
456 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000457elif args.which == 'list_all_vlans':
Steve McIntyreb01959f2016-03-22 17:02:39 +0000458 try:
459 result = call_vland('db_query', {'command':'db.all_vlans', 'data':None})
460 for line in result:
461 dump_vlan(line)
Steve McIntyref5ef6962016-03-22 17:21:47 +0000462 except (InputError, NotFoundError):
463 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000464elif args.which == 'list_all_trunks':
Steve McIntyreb01959f2016-03-22 17:02:39 +0000465 try:
466 result = call_vland('db_query', {'command':'db.all_trunks', 'data':None})
467 for line in result:
468 dump_trunk(line)
Steve McIntyref5ef6962016-03-22 17:21:47 +0000469 except (InputError, NotFoundError):
470 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000471elif args.which == 'create_switch':
472 try:
473 switch_id = call_vland('db_update',
474 {'command':'db.create_switch',
475 'data':
476 {'name':args.name}})
477 print 'Created switch_id %d' % switch_id
478 except InputError as inst:
479 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000480 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000481elif args.which == 'create_port':
482 try:
483 port_id = call_vland('db_update',
484 {'command':'db.create_port',
485 'data':
486 {'switch_id': args.switch_id,
487 'name': args.name,
488 'number': args.number}})
489 print 'Created port_id %d' % port_id
490 except InputError as inst:
491 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000492 exitcode = Error.FAILED
Steve McIntyreb01959f2016-03-22 17:02:39 +0000493 except NotFoundError as inst:
494 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000495 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000496elif args.which == 'create_vlan':
497 try:
498 (vlan_id, vlan_tag) = call_vland('vlan_update',
499 {'command':'api.create_vlan',
500 'data':
501 {'name': args.name,
502 'tag': args.tag,
503 'is_base_vlan': is_positive(args.is_base_vlan)}})
504 print 'Created VLAN tag %d as vlan_id %d' % (vlan_tag, vlan_id)
505 except InputError as inst:
506 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000507 exitcode = Error.FAILED
Steve McIntyreb01959f2016-03-22 17:02:39 +0000508 except NotFoundError as inst:
509 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000510 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000511elif args.which == 'create_trunk':
512 try:
513 trunk_id = call_vland('db_update',
514 {'command':'db.create_trunk',
515 'data':
516 {'port_id1': args.port_id1,
517 'port_id2': args.port_id2}})
518 print 'Created trunk_id %d' % trunk_id
519 except InputError as inst:
520 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000521 exitcode = Error.FAILED
Steve McIntyreb01959f2016-03-22 17:02:39 +0000522 except NotFoundError as inst:
523 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000524 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000525elif args.which == 'delete_switch':
526 try:
527 switch_id = call_vland('db_update',
528 {'command':'db.delete_switch',
529 'data': {'switch_id': args.switch_id}})
530 print 'Deleted switch_id %s' % switch_id
531 except InputError as inst:
532 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000533 exitcode = Error.FAILED
Steve McIntyreb01959f2016-03-22 17:02:39 +0000534 except NotFoundError as inst:
535 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000536 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000537elif args.which == 'delete_port':
538 try:
539 port_id = call_vland('db_update',
540 {'command':'db.delete_port',
541 'data': {'port_id': args.port_id}})
542 print 'Deleted port_id %s' % port_id
543 except InputError as inst:
544 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000545 exitcode = Error.FAILED
Steve McIntyreb01959f2016-03-22 17:02:39 +0000546 except NotFoundError as inst:
547 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000548 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000549elif args.which == 'delete_vlan':
550 try:
551 vlan_id = call_vland('vlan_update',
552 {'command':'api.delete_vlan',
553 'data': {'vlan_id': args.vlan_id}})
554 print 'Deleted vlan_id %d' % vlan_id
555 except InputError as inst:
556 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000557 exitcode = Error.FAILED
Steve McIntyreb01959f2016-03-22 17:02:39 +0000558 except NotFoundError as inst:
559 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000560 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000561elif args.which == 'delete_trunk':
562 try:
Steve McIntyrea5bf2202018-01-31 14:15:21 +0000563 trunk_id = call_vland('db_update',
Steve McIntyre460358a2016-03-12 11:57:53 +0000564 {'command':'db.delete_trunk',
565 'data': {'trunk_id': args.trunk_id}})
566 print 'Deleted trunk_id %s' % trunk_id
567 except InputError as inst:
568 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000569 exitcode = Error.FAILED
Steve McIntyreb01959f2016-03-22 17:02:39 +0000570 except NotFoundError as inst:
571 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000572 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000573elif args.which == 'lookup_switch_by_name':
574 try:
575 switch_id = call_vland('db_query',
576 {'command':'db.get_switch_id_by_name',
577 'data':{'name':args.name}})
578 if switch_id is not None:
579 print '%d' % switch_id
580 else:
581 print 'No switch found for name %s' % args.name
Steve McIntyref5ef6962016-03-22 17:21:47 +0000582 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000583 except InputError as inst:
584 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000585 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000586elif args.which == 'show_switch':
587 try:
588 this_switch = call_vland('db_query',
589 {'command':'db.get_switch_by_id',
590 'data':
591 {'switch_id': args.switch_id}})
592 if this_switch is not None:
593 dump_switch(this_switch)
594 else:
595 print 'No switch found for switch_id %s' % args.switch_id
596 except InputError as inst:
597 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000598 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000599elif args.which == 'show_port':
600 try:
601 this_port = call_vland('db_query',
602 {'command':'db.get_port_by_id',
603 'data':
604 {'port_id': args.port_id}})
605 if this_port is not None:
606 dump_port(this_port)
607 else:
608 print 'No port found for port_id %s' % args.port_id
Steve McIntyref5ef6962016-03-22 17:21:47 +0000609 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000610 except InputError as inst:
611 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000612 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000613elif args.which == 'lookup_port_by_switch_and_name':
614 try:
615 p = call_vland('db_query',
616 {'command':'db.get_port_by_switch_and_name',
617 'data':
618 {'switch_id': args.switch_id,
619 'name': args.name}})
620 if p is not None:
621 print p
622 else:
623 print 'No port found for switch_id %s, name %s' % (args.switch_id, args.name)
Steve McIntyref5ef6962016-03-22 17:21:47 +0000624 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000625 except InputError as inst:
626 print 'Failed: %s' % inst
627elif args.which == 'lookup_port_by_switch_and_number':
628 try:
629 p = call_vland('db_query',
630 {'command':'db.get_port_by_switch_and_number',
631 'data':
632 {'switch_id': args.switch_id,
633 'number': args.number}})
634 if p is not None:
635 print p
636 else:
637 print 'No port found for switch_id %s, port number %s' % (args.switch_id, args.number)
638 except InputError as inst:
639 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000640 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000641elif args.which == 'lookup_ports_by_switch':
642 try:
643 p = call_vland('db_query',
644 {'command':'db.get_ports_by_switch',
645 'data':
646 {'switch_id': args.switch_id}})
647 if p is not None:
648 for port_id in p:
649 print port_id
650 else:
651 print 'No ports found for switch_id %s' % args.switch_id
Steve McIntyref5ef6962016-03-22 17:21:47 +0000652 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000653 except InputError as inst:
654 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000655 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000656elif args.which == 'lookup_ports_by_current_vlan':
657 try:
658 p = call_vland('db_query',
659 {'command':'db.get_ports_by_current_vlan',
660 'data':
661 {'vlan_id': args.vlan_id}})
662 if p is not None:
663 for port_id in p:
664 print port_id
665 else:
666 print 'No ports found for current vlan_id %s' % args.vlan_id
Steve McIntyref5ef6962016-03-22 17:21:47 +0000667 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000668 except InputError as inst:
669 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000670 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000671elif args.which == 'lookup_ports_by_base_vlan':
672 try:
673 p = call_vland('db_query',
674 {'command':'db.get_ports_by_base_vlan',
675 'data':
676 {'vlan_id': args.vlan_id}})
677 if p is not None:
678 for port_id in p:
679 print port_id
680 else:
681 print 'No ports found for base vlan_id %s' % args.vlan_id
Steve McIntyref5ef6962016-03-22 17:21:47 +0000682 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000683 except InputError as inst:
684 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000685 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000686elif args.which == 'lookup_ports_by_trunk':
687 try:
688 p = call_vland('db_query',
689 {'command':'db.get_ports_by_trunk',
690 'data':
691 {'trunk_id': args.trunk_id}})
692 if p is not None:
693 for port_id in p:
694 print port_id
695 else:
696 print 'No ports found for trunk_id %s' % args.trunk_id
Steve McIntyref5ef6962016-03-22 17:21:47 +0000697 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000698 except InputError as inst:
699 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000700 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000701elif args.which == 'set_port_mode':
702 try:
703 port_id = call_vland('vlan_update',
704 {'command':'api.set_port_mode',
705 'data':
706 {'port_id': args.port_id,
707 'mode': args.mode}})
708 print "Updated mode for port_id %d" % port_id
709 except InputError as inst:
710 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000711 exitcode = Error.FAILED
Steve McIntyreb01959f2016-03-22 17:02:39 +0000712 except NotFoundError as inst:
713 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000714 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000715elif args.which == 'lock_port':
716 try:
717 port_id = call_vland('db_update',
718 {'command':'db.set_port_is_locked',
719 'data':
720 {'port_id': args.port_id,
Steve McIntyre7d219202018-02-01 16:53:25 +0000721 'is_locked': True,
722 'lock_reason': args.reason}})
Steve McIntyre460358a2016-03-12 11:57:53 +0000723 print "Locked port_id %d" % port_id
724 except InputError as inst:
725 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000726 exitcode = Error.FAILED
Steve McIntyreb01959f2016-03-22 17:02:39 +0000727 except NotFoundError as inst:
728 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000729 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000730elif args.which == 'unlock_port':
731 try:
732 port_id = call_vland('db_update',
733 {'command':'db.set_port_is_locked',
734 'data':
735 {'port_id': args.port_id,
Steve McIntyre7d219202018-02-01 16:53:25 +0000736 'is_locked': False,
737 'lock_reason': ""}})
Steve McIntyre460358a2016-03-12 11:57:53 +0000738 print "Unlocked port_id %d" % port_id
739 except InputError as inst:
740 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000741 exitcode = Error.FAILED
Steve McIntyreb01959f2016-03-22 17:02:39 +0000742 except NotFoundError as inst:
743 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000744 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000745elif args.which == 'set_port_current_vlan':
746 try:
747 port_id = call_vland('vlan_update',
748 {'command':'api.set_current_vlan',
749 'data':
750 {'port_id': args.port_id,
751 'vlan_id': args.vlan_id}})
752 print "Set current VLAN on port_id %d" % port_id
753 except InputError as inst:
754 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000755 exitcode = Error.FAILED
Steve McIntyreb01959f2016-03-22 17:02:39 +0000756 except NotFoundError as inst:
757 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000758 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000759elif args.which == 'get_port_current_vlan':
760 try:
761 vlan_id = call_vland('db_query',
762 {'command':'db.get_current_vlan_id_by_port',
763 'data':
764 {'port_id': args.port_id}})
765 if vlan_id is not None:
766 print vlan_id
767 else:
768 print "No current_vlan_id found for port_id %s" % args.port_id
769 except InputError as inst:
770 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000771 exitcode = Error.FAILED
Steve McIntyreb01959f2016-03-22 17:02:39 +0000772 except NotFoundError as inst:
773 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000774 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000775elif args.which == 'set_port_base_vlan':
776 try:
777 port_id = call_vland('db_update',
778 {'command':'db.set_base_vlan',
779 'data':
780 {'port_id': args.port_id,
781 'base_vlan_id': args.vlan_id}})
782 print "Set base VLAN on port_id %d" % port_id
783 except InputError as inst:
784 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000785 exitcode = Error.FAILED
Steve McIntyreb01959f2016-03-22 17:02:39 +0000786 except NotFoundError as inst:
787 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000788 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000789elif args.which == 'get_port_base_vlan':
790 try:
791 vlan_id = call_vland('db_query',
792 {'command':'db.get_base_vlan_id_by_port',
793 'data':
794 {'port_id': args.port_id}})
795 if vlan_id is not None:
796 print vlan_id
797 else:
798 print "No base_vlan_id found for port_id %d" % port_id
799 except InputError as inst:
800 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000801 exitcode = Error.FAILED
Steve McIntyreb01959f2016-03-22 17:02:39 +0000802 except NotFoundError as inst:
803 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000804 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000805elif args.which == 'restore_port_to_base_vlan':
806 try:
807 port_id = call_vland('vlan_update',
808 {'command': 'api.restore_base_vlan',
809 'data':
810 {'port_id': args.port_id}})
811 print "Restored port_id %d back to base VLAN" % port_id
812 except InputError as inst:
813 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000814 exitcode = Error.FAILED
Steve McIntyreb01959f2016-03-22 17:02:39 +0000815 except NotFoundError as inst:
816 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000817 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000818elif args.which == 'show_vlan':
819 try:
820 v = call_vland('db_query',
821 {'command':'db.get_vlan_by_id',
822 'data':
823 {'vlan_id': args.vlan_id}})
824 if v is not None:
825 dump_vlan(v)
826 else:
827 print 'No VLAN found for vlan_id %s' % args.vlan_id
828 except InputError as inst:
829 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000830 exitcode = Error.FAILED
Steve McIntyreb01959f2016-03-22 17:02:39 +0000831 except NotFoundError as inst:
832 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000833 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000834elif args.which == 'lookup_vlan_by_tag':
835 try:
836 vlan_id = call_vland('db_query',
837 {'command':'db.get_vlan_id_by_tag',
838 'data':
839 {'tag': args.tag}})
840 if vlan_id is not None:
841 print vlan_id
842 else:
843 print 'No VLAN found for vlan tag %s' % args.tag
Steve McIntyref5ef6962016-03-22 17:21:47 +0000844 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000845 except InputError as inst:
846 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000847 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000848elif args.which == 'show_vlan_tag':
849 try:
850 vlan_tag = call_vland('db_query',
851 {'command':'db.get_vlan_tag_by_id',
852 'data':
853 {'vlan_id': args.vlan_id}})
854 if vlan_tag is not None:
855 print vlan_tag
856 else:
857 print 'No VLAN found for vlan id %s' % args.vlan_id
Steve McIntyref5ef6962016-03-22 17:21:47 +0000858 exitcode = Error.NOTFOUND
Steve McIntyre460358a2016-03-12 11:57:53 +0000859 except InputError as inst:
860 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000861 exitcode = Error.FAILED
Steve McIntyre460358a2016-03-12 11:57:53 +0000862elif args.which == 'show_trunk':
863 try:
864 this_trunk = call_vland('db_query',
865 {'command':'db.get_trunk_by_id',
866 'data':
867 {'trunk_id': args.trunk_id}})
868 if this_trunk is not None:
869 dump_trunk(this_trunk)
870 else:
871 print 'No port found for port_id %s' % args.trunk_id
872 except InputError as inst:
873 print 'Failed: %s' % inst
Steve McIntyreb01959f2016-03-22 17:02:39 +0000874 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000875 exitcode = Error.FAILED
Steve McIntyreb01959f2016-03-22 17:02:39 +0000876 except NotFoundError as inst:
877 print 'Failed: %s' % inst
Steve McIntyref5ef6962016-03-22 17:21:47 +0000878 exitcode = Error.NOTFOUND
Steve McIntyrea0534a52014-12-05 17:58:40 +0000879else:
Steve McIntyre4a808912014-12-05 15:24:39 +0000880 print 'No recognised command given. Try -h for help'
Steve McIntyreb01959f2016-03-22 17:02:39 +0000881
Steve McIntyref5ef6962016-03-22 17:21:47 +0000882sys.exit(exitcode)