Add better distinction of error cases

Add a new NotFoundError exception for use internally, so we can track
specific failure cases.
Also add a new Error class as a central place to store our error
numbers consistently.
In the API protocol, add a "NOTFOUND" error string alongside "ERROR"
to help the admin interface and other callers distinguish error cases
better.
In the admin interface, actually return distinct non-zero errors in
failure cases. Previously, almost all failures would have returned
suceesfully to the calling shell.

Change-Id: Ie382b737a80b7cd41c551e3a4a2a7e0827260bdc
diff --git a/admin.py b/admin.py
index 1e833d1..26964f4 100755
--- a/admin.py
+++ b/admin.py
@@ -27,14 +27,14 @@
 vlandpath = os.path.abspath(os.path.normpath(os.path.dirname(sys.argv[0])))
 sys.path.insert(0, vlandpath)
 
-from errors import InputError, SocketError
+from errors import InputError, SocketError, NotFoundError, Error
 from config.config import VlanConfig
 from ipc.ipc import VlanIpc
 
 prog = "admin"
 version = "0.6-DEV"
 banner = "Linaro VLANd admin interface, version %s" % version
-
+exit = Error.OK
 TRUNK_ID_NONE = -1
 
 def is_positive(text):
@@ -85,8 +85,9 @@
     if 'response' not in ret:
         raise SocketError("Badly-formed response from VLANd server")
     if ret['response'] == "ERROR":
-        print "Input error: VLANd server said \"%s\"" % ret['error']
-        sys.exit(1)
+        raise InputError("VLANd server said \"%s\"" % ret['error'])
+    if ret['response'] == "NOTFOUND":
+        raise NotFoundError("VLANd server said \"%s\"" % ret['error'])
     return ret['data']
 
 config = VlanConfig(filenames=('./vland.cfg',))
@@ -366,71 +367,103 @@
 
 # Now work out what to do
 if args.which == 'status':
-    print 'Config:'
-    print '  knows about %d switch(es)' % len(config.switches)
-    default_vlan_id = call_vland('db_query',
-                                 {'command':'db.get_vlan_id_by_tag',
-                                  'data':
-                                  {'tag': config.vland.default_vlan_tag}})
-    print 'The default vlan tag (%d) is vlan ID %d' % (config.vland.default_vlan_tag, default_vlan_id)
-    stat = call_vland('daemon_query', {'command':'daemon.status', 'data': None})
-    print 'VLANd is running %s' % stat['running']
-    lastmod = datetime.datetime.strptime(stat['last_modified'], '%Y-%m-%dT%H:%M:%S.%f')
-    print 'DB Last modified %s' % lastmod.strftime('%Y-%m-%d %H:%M:%S %Z')
-    print 'DB via VLANd:'
-    switches = call_vland('db_query', {'command':'db.all_switches', 'data':None})
-    print '  knows about %d switch(es)' % len(switches)
-    ports = call_vland('db_query', {'command':'db.all_ports', 'data':None})
-    print '  knows about %d port(s)' % len(ports)
-    vlans = call_vland('db_query', {'command':'db.all_vlans', 'data':None})
-    print '  DB knows about %d vlan(s)' % len(vlans)
+    try:
+        print 'Config:'
+        print '  knows about %d switch(es)' % len(config.switches)
+        default_vlan_id = call_vland('db_query',
+                                     {'command':'db.get_vlan_id_by_tag',
+                                      'data':
+                                     {'tag': config.vland.default_vlan_tag}})
+        print 'The default vlan tag (%d) is vlan ID %d' % (config.vland.default_vlan_tag, default_vlan_id)
+        stat = call_vland('daemon_query', {'command':'daemon.status', 'data': None})
+        print 'VLANd is running %s' % stat['running']
+        lastmod = datetime.datetime.strptime(stat['last_modified'], '%Y-%m-%dT%H:%M:%S.%f')
+        print 'DB Last modified %s' % lastmod.strftime('%Y-%m-%d %H:%M:%S %Z')
+        print 'DB via VLANd:'
+        switches = call_vland('db_query', {'command':'db.all_switches', 'data':None})
+        print '  knows about %d switch(es)' % len(switches)
+        ports = call_vland('db_query', {'command':'db.all_ports', 'data':None})
+        print '  knows about %d port(s)' % len(ports)
+        vlans = call_vland('db_query', {'command':'db.all_vlans', 'data':None})
+        print '  DB knows about %d vlan(s)' % len(vlans)
+    except:
+        exit = Error.FAILED
 elif args.which == 'shutdown':
-    print 'Asking VLANd to shutdown'
-    shutdown = call_vland('daemon_query',
-                          {'command':'daemon.shutdown',
-                           'data': None})
-    for field in shutdown:
-        print '%s: %s' % (field, shutdown[field])
+    try:
+        print 'Asking VLANd to shutdown'
+        shutdown = call_vland('daemon_query',
+                            {'command':'daemon.shutdown',
+                            'data': None})
+        for field in shutdown:
+            print '%s: %s' % (field, shutdown[field])
+    except:
+        exit = Error.FAILED                
 elif args.which == 'vland_version':
-    ver = call_vland('daemon_query', {'command':'daemon.version', 'data': None})
-    print 'VLANd version %s' % ver['version']
+    try:
+        ver = call_vland('daemon_query', {'command':'daemon.version', 'data': None})
+        print 'VLANd version %s' % ver['version']
+    except:
+        exit = Error.FAILED        
 elif args.which == 'statistics':
-    stats = call_vland('daemon_query', {'command':'daemon.statistics', 'data': None})
-    print 'VLANd uptime: %d seconds' % stats['uptime']
+    try:
+        stats = call_vland('daemon_query', {'command':'daemon.statistics', 'data': None})
+        print 'VLANd uptime: %d seconds' % stats['uptime']
+    except:
+        exit = Error.FAILED        
 elif args.which == 'version':
     print 'VLANd admin interface version %s' % version
 elif args.which == 'auto_import_switch':
     print 'Attempting to import switch %s' % args.name
     if args.name not in config.switches:
         raise InputError("Can't find switch %s in config" % args.name)
-    imp = call_vland('vlan_update',
-                     {'command':'api.auto_import_switch',
-                      'data':
-                      {'switch': args.name}})
-    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'])
+    try:
+        imp = call_vland('vlan_update',
+                        {'command':'api.auto_import_switch',
+                        'data':
+                        {'switch': args.name}})
+        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'])
+    except:
+        print 'Import failed - see log for details'
+        exit = Error.FAILED
 elif args.which == 'probe_switches':
     print 'Asking VLANd to probe all the configured switches'
-    probe = call_vland('daemon_query',
-                       {'command':'daemon.probe_switches',
-                        'data': None})
-    for field in probe:
-        print '%s: %s' % (field, probe[field])
+    try:
+        probe = call_vland('daemon_query',
+                            {'command':'daemon.probe_switches',
+                            'data': None})
+        for field in probe:
+            print '%s: %s' % (field, probe[field])
+    except:
+        print 'Probe failed - see log for details'
+        exit = Error.FAILED
 elif args.which == 'list_all_switches':
-    result = call_vland('db_query', {'command':'db.all_switches', 'data':None})
-    for line in result:
-        dump_switch(line)
+    try:
+        result = call_vland('db_query', {'command':'db.all_switches', 'data':None})
+        for line in result:
+            dump_switch(line)
+    except:
+        exit = Error.FAILED        
 elif args.which == 'list_all_ports':
-    result = call_vland('db_query', {'command':'db.all_ports', 'data':None})
-    for line in result:
-        dump_port(line)
+    try:
+        result = call_vland('db_query', {'command':'db.all_ports', 'data':None})
+        for line in result:
+            dump_port(line)
+    except:
+        exit = Error.FAILED
 elif args.which == 'list_all_vlans':
-    result = call_vland('db_query', {'command':'db.all_vlans', 'data':None})
-    for line in result:
-        dump_vlan(line)
+    try:
+        result = call_vland('db_query', {'command':'db.all_vlans', 'data':None})
+        for line in result:
+            dump_vlan(line)
+    except:
+        exit = Error.FAILED        
 elif args.which == 'list_all_trunks':
-    result = call_vland('db_query', {'command':'db.all_trunks', 'data':None})
-    for line in result:
-        dump_trunk(line)
+    try:
+        result = call_vland('db_query', {'command':'db.all_trunks', 'data':None})
+        for line in result:
+            dump_trunk(line)
+    except:
+        exit = Error.FAILED        
 elif args.which == 'create_switch':
     try:
         switch_id = call_vland('db_update',
@@ -440,6 +473,7 @@
         print 'Created switch_id %d' % switch_id
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
 elif args.which == 'create_port':
     try:
         port_id = call_vland('db_update',
@@ -451,6 +485,10 @@
         print 'Created port_id %d' % port_id
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
+    except NotFoundError as inst:
+        print 'Failed: %s' % inst
+        exit = Error.NOTFOUND
 elif args.which == 'create_vlan':
     try:
         (vlan_id, vlan_tag) = call_vland('vlan_update',
@@ -462,6 +500,10 @@
         print 'Created VLAN tag %d as vlan_id %d' % (vlan_tag, vlan_id)
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
+    except NotFoundError as inst:
+        print 'Failed: %s' % inst
+        exit = Error.NOTFOUND
 elif args.which == 'create_trunk':
     try:
         trunk_id = call_vland('db_update',
@@ -472,6 +514,10 @@
         print 'Created trunk_id %d' % trunk_id
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
+    except NotFoundError as inst:
+        print 'Failed: %s' % inst
+        exit = Error.NOTFOUND
 elif args.which == 'delete_switch':
     try:
         switch_id = call_vland('db_update',
@@ -480,6 +526,10 @@
         print 'Deleted switch_id %s' % switch_id
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
+    except NotFoundError as inst:
+        print 'Failed: %s' % inst
+        exit = Error.NOTFOUND
 elif args.which == 'delete_port':
     try:
         port_id = call_vland('db_update',
@@ -488,6 +538,10 @@
         print 'Deleted port_id %s' % port_id
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
+    except NotFoundError as inst:
+        print 'Failed: %s' % inst
+        exit = Error.NOTFOUND
 elif args.which == 'delete_vlan':
     try:
         vlan_id = call_vland('vlan_update',
@@ -496,6 +550,10 @@
         print 'Deleted vlan_id %d' % vlan_id
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
+    except NotFoundError as inst:
+        print 'Failed: %s' % inst
+        exit = Error.NOTFOUND
 elif args.which == 'delete_trunk':
     try:
         port_id = call_vland('db_update',
@@ -504,6 +562,10 @@
         print 'Deleted trunk_id %s' % trunk_id
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
+    except NotFoundError as inst:
+        print 'Failed: %s' % inst
+        exit = Error.NOTFOUND
 elif args.which == 'lookup_switch_by_name':
     try:
         switch_id = call_vland('db_query',
@@ -513,8 +575,10 @@
             print '%d' % switch_id
         else:
             print 'No switch found for name %s' % args.name
+            exit = Error.NOTFOUND
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
 elif args.which == 'show_switch':
     try:
         this_switch = call_vland('db_query',
@@ -527,6 +591,7 @@
             print 'No switch found for switch_id %s' % args.switch_id
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
 elif args.which == 'show_port':
     try:
         this_port = call_vland('db_query',
@@ -537,8 +602,10 @@
             dump_port(this_port)
         else:
             print 'No port found for port_id %s' % args.port_id
+            exit = Error.NOTFOUND
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
 elif args.which == 'lookup_port_by_switch_and_name':
     try:
         p = call_vland('db_query',
@@ -550,6 +617,7 @@
             print p
         else:
             print 'No port found for switch_id %s, name %s' % (args.switch_id, args.name)
+            exit = Error.NOTFOUND
     except InputError as inst:
         print 'Failed: %s' % inst
 elif args.which == 'lookup_port_by_switch_and_number':
@@ -565,6 +633,7 @@
             print 'No port found for switch_id %s, port number %s' % (args.switch_id, args.number)
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
 elif args.which == 'lookup_ports_by_switch':
     try:
         p = call_vland('db_query',
@@ -576,8 +645,10 @@
                 print port_id
         else:
             print 'No ports found for switch_id %s' % args.switch_id
+            exit = Error.NOTFOUND
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
 elif args.which == 'lookup_ports_by_current_vlan':
     try:
         p = call_vland('db_query',
@@ -589,8 +660,10 @@
                 print port_id
         else:
             print 'No ports found for current vlan_id %s' % args.vlan_id
+            exit = Error.NOTFOUND
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
 elif args.which == 'lookup_ports_by_base_vlan':
     try:
         p = call_vland('db_query',
@@ -602,8 +675,10 @@
                 print port_id
         else:
             print 'No ports found for base vlan_id %s' % args.vlan_id
+            exit = Error.NOTFOUND
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
 elif args.which == 'lookup_ports_by_trunk':
     try:
         p = call_vland('db_query',
@@ -615,8 +690,10 @@
                 print port_id
         else:
             print 'No ports found for trunk_id %s' % args.trunk_id
+            exit = Error.NOTFOUND
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
 elif args.which == 'set_port_mode':
     try:
         port_id = call_vland('vlan_update',
@@ -627,6 +704,10 @@
         print "Updated mode for port_id %d" % port_id
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
+    except NotFoundError as inst:
+        print 'Failed: %s' % inst
+        exit = Error.NOTFOUND
 elif args.which == 'lock_port':
     try:
         port_id = call_vland('db_update',
@@ -637,6 +718,10 @@
         print "Locked port_id %d" % port_id
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
+    except NotFoundError as inst:
+        print 'Failed: %s' % inst
+        exit = Error.NOTFOUND
 elif args.which == 'unlock_port':
     try:
         port_id = call_vland('db_update',
@@ -647,6 +732,10 @@
         print "Unlocked port_id %d" % port_id
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
+    except NotFoundError as inst:
+        print 'Failed: %s' % inst
+        exit = Error.NOTFOUND
 elif args.which == 'set_port_current_vlan':
     try:
         port_id = call_vland('vlan_update',
@@ -657,6 +746,10 @@
         print "Set current VLAN on port_id %d" % port_id
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
+    except NotFoundError as inst:
+        print 'Failed: %s' % inst
+        exit = Error.NOTFOUND
 elif args.which == 'get_port_current_vlan':
     try:
         vlan_id = call_vland('db_query',
@@ -669,6 +762,10 @@
             print "No current_vlan_id found for port_id %s" % args.port_id
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
+    except NotFoundError as inst:
+        print 'Failed: %s' % inst
+        exit = Error.NOTFOUND
 elif args.which == 'set_port_base_vlan':
     try:
         port_id = call_vland('db_update',
@@ -679,6 +776,10 @@
         print "Set base VLAN on port_id %d" % port_id
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
+    except NotFoundError as inst:
+        print 'Failed: %s' % inst
+        exit = Error.NOTFOUND
 elif args.which == 'get_port_base_vlan':
     try:
         vlan_id = call_vland('db_query',
@@ -691,6 +792,10 @@
             print "No base_vlan_id found for port_id %d" % port_id
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
+    except NotFoundError as inst:
+        print 'Failed: %s' % inst
+        exit = Error.NOTFOUND
 elif args.which == 'restore_port_to_base_vlan':
     try:
         port_id = call_vland('vlan_update',
@@ -700,6 +805,10 @@
         print "Restored port_id %d back to base VLAN" % port_id
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
+    except NotFoundError as inst:
+        print 'Failed: %s' % inst
+        exit = Error.NOTFOUND
 elif args.which == 'show_vlan':
     try:
         v = call_vland('db_query',
@@ -712,6 +821,10 @@
             print 'No VLAN found for vlan_id %s' % args.vlan_id
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
+    except NotFoundError as inst:
+        print 'Failed: %s' % inst
+        exit = Error.NOTFOUND
 elif args.which == 'lookup_vlan_by_tag':
     try:
         vlan_id = call_vland('db_query',
@@ -722,8 +835,10 @@
             print vlan_id
         else:
             print 'No VLAN found for vlan tag %s' % args.tag
+            exit = Error.NOTFOUND
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
 elif args.which == 'show_vlan_tag':
     try:
         vlan_tag = call_vland('db_query',
@@ -734,8 +849,10 @@
             print vlan_tag
         else:
             print 'No VLAN found for vlan id %s' % args.vlan_id
+            exit = Error.NOTFOUND
     except InputError as inst:
         print 'Failed: %s' % inst
+        exit = Error.FAILED
 elif args.which == 'show_trunk':
     try:
         this_trunk = call_vland('db_query',
@@ -748,6 +865,12 @@
             print 'No port found for port_id %s' % args.trunk_id
     except InputError as inst:
         print 'Failed: %s' % inst
-
+        print 'Failed: %s' % inst
+        exit = Error.FAILED
+    except NotFoundError as inst:
+        print 'Failed: %s' % inst
+        exit = Error.NOTFOUND
 else:
     print 'No recognised command given. Try -h for help'
+
+sys.exit(exit)
diff --git a/db/db.py b/db/db.py
index 21ead71..010fb84 100644
--- a/db/db.py
+++ b/db/db.py
@@ -31,7 +31,7 @@
     sys.path.insert(0, vlandpath)
     sys.path.insert(0, "%s/.." % vlandpath)
 
-from errors import CriticalError, InputError
+from errors import CriticalError, InputError, NotFoundError
 
 class VlanDB:
     def __init__(self, db_name="vland", username="vland", readonly=True):
@@ -104,12 +104,12 @@
 
         switch = self.get_switch_by_id(switch_id)
         if switch is None:
-            raise InputError("Switch ID %d does not exist" % int(switch_id))
+            raise NotFoundError("Switch ID %d does not exist" % int(switch_id))
 
         for vlan_id in (current_vlan_id, base_vlan_id):
             vlan = self.get_vlan_by_id(vlan_id)
             if vlan is None:
-                raise InputError("VLAN ID %d does not exist" % int(vlan_id))
+                raise NotFoundError("VLAN ID %d does not exist" % int(vlan_id))
 
         port_id = self.get_port_by_switch_and_name(switch_id, name)
         if port_id is not None:
@@ -186,7 +186,7 @@
         for port_id in (port_id1, port_id2):
             port = self.get_port_by_id(int(port_id))
             if port is None:
-                raise InputError("Port ID %d does not exist" % int(port_id))
+                raise NotFoundError("Port ID %d does not exist" % int(port_id))
             if not port.is_trunk:
                 raise InputError("Port ID %d is not in trunk mode" % int(port_id))
             if port.is_locked:
@@ -233,7 +233,7 @@
     def delete_switch(self, switch_id):
         switch = self.get_switch_by_id(switch_id)
         if switch is None:
-            raise InputError("Switch ID %d does not exist" % int(switch_id))
+            raise NotFoundError("Switch ID %d does not exist" % int(switch_id))
         ports = self.get_ports_by_switch(switch_id)
         if ports is not None:
             raise InputError("Cannot delete switch ID %d when it still has %d ports" %
@@ -249,7 +249,7 @@
     def delete_port(self, port_id):
         port = self.get_port_by_id(port_id)
         if port is None:
-            raise InputError("Port ID %d does not exist" % int(port_id))
+            raise NotFoundError("Port ID %d does not exist" % int(port_id))
         if port.is_locked:
             raise InputError("Cannot delete port ID %d as it is locked" % int(port_id))
         self._delete_row("port", "port_id", port_id)
@@ -263,7 +263,7 @@
     def delete_vlan(self, vlan_id):
         vlan = self.get_vlan_by_id(vlan_id)
         if vlan is None:
-            raise InputError("VLAN ID %d does not exist" % int(vlan_id))
+            raise NotFoundError("VLAN ID %d does not exist" % int(vlan_id))
         ports = self.get_ports_by_current_vlan(vlan_id)
         if ports is not None:
             raise InputError("Cannot delete VLAN ID %d when it still has %d ports" %
@@ -284,7 +284,7 @@
     def delete_trunk(self, trunk_id):
         trunk = self.get_trunk_by_id(trunk_id)
         if trunk is None:
-            raise InputError("Trunk ID %d does not exist" % int(trunk_id))
+            raise NotFoundError("Trunk ID %d does not exist" % int(trunk_id))
         ports = self.get_ports_by_trunk(trunk_id)
         for port_id in ports:
             self._set_port_trunk(port_id, TRUNK_ID_NONE)
@@ -581,7 +581,7 @@
     def set_port_is_locked(self, port_id, is_locked):
         port = self.get_port_by_id(port_id)
         if port is None:
-            raise InputError("Port ID %d does not exist" % int(port_id))
+            raise NotFoundError("Port ID %d does not exist" % int(port_id))
         try:
             sql = "UPDATE port SET is_locked=%s WHERE port_id=%s RETURNING port_id"
             data = (is_locked, port_id)
@@ -599,7 +599,7 @@
     def set_port_mode(self, port_id, mode):
         port = self.get_port_by_id(port_id)
         if port is None:
-            raise InputError("Port ID %d does not exist" % int(port_id))
+            raise NotFoundError("Port ID %d does not exist" % int(port_id))
         if mode == "access":
             is_trunk = False
         elif mode == "trunk":
@@ -629,14 +629,14 @@
     def set_current_vlan(self, port_id, vlan_id):
         port = self.get_port_by_id(port_id)
         if port is None:
-            raise InputError("Port ID %d does not exist" % int(port_id))
+            raise NotFoundError("Port ID %d does not exist" % int(port_id))
 
         if port.is_trunk or port.is_locked:
             raise CriticalError("The port is locked")
 
         vlan = self.get_vlan_by_id(vlan_id)
         if vlan is None:
-            raise InputError("VLAN ID %d does not exist" % int(vlan_id))
+            raise NotFoundError("VLAN ID %d does not exist" % int(vlan_id))
 
         try:
             sql = "UPDATE port SET current_vlan_id=%s WHERE port_id=%s RETURNING port_id"
@@ -661,14 +661,14 @@
     def set_base_vlan(self, port_id, vlan_id):
         port = self.get_port_by_id(port_id)
         if port is None:
-            raise InputError("Port ID %d does not exist" % int(port_id))
+            raise NotFoundError("Port ID %d does not exist" % int(port_id))
 
         if port.is_trunk or port.is_locked:
             raise CriticalError("The port is locked")
 
         vlan = self.get_vlan_by_id(vlan_id)
         if vlan is None:
-            raise InputError("VLAN ID %d does not exist" % int(vlan_id))
+            raise NotFoundError("VLAN ID %d does not exist" % int(vlan_id))
         if not vlan.is_base_vlan:
             raise InputError("VLAN ID %d is not a base VLAN" % int(vlan_id))
 
@@ -692,7 +692,7 @@
     def _set_port_trunk(self, port_id, trunk_id):
         port = self.get_port_by_id(port_id)
         if port is None:
-            raise InputError("Port ID %d does not exist" % int(port_id))
+            raise NotFoundError("Port ID %d does not exist" % int(port_id))
         if port.is_locked:
             raise CriticalError("The port is locked")
         try:
diff --git a/errors.py b/errors.py
index aec4619..25518e5 100644
--- a/errors.py
+++ b/errors.py
@@ -28,6 +28,11 @@
     The critical error
     """
 
+class NotFoundError(VlandError):
+    """
+    Couldn't find object
+    """
+
 class InputError(VlandError):
     """
     Invalid input
@@ -48,3 +53,7 @@
     CLI communication failure
     """
 
+class Error:
+    OK = 0
+    FAILED = 1
+    NOTFOUND = 2
diff --git a/util.py b/util.py
index 25d8d9b..c110380 100644
--- a/util.py
+++ b/util.py
@@ -20,7 +20,7 @@
 
 import logging
 import time
-from errors import CriticalError, InputError, ConfigError, SocketError
+from errors import CriticalError, NotFoundError, InputError, ConfigError, SocketError
 
 class VlanUtil:
     """VLANd utility functions"""
@@ -118,7 +118,7 @@
             else:
                 raise InputError("Unknown db_query command \"%s\"" % command)
 
-        except InputError as e:
+        except (InputError, NotFoundError) as e:
             logging.error('perform_db_query(%s) got error %s', command, e)
             raise
         except ValueError as e:
@@ -152,7 +152,7 @@
             else:
                 raise InputError("Unknown daemon_query command \"%s\"" % command)
 
-        except InputError as e:
+        except (InputError, NotFoundError) as e:
             logging.error('perform_daemon_query(%s) got error %s', command, e)
             raise
         except ValueError as e:
@@ -195,7 +195,7 @@
             else:
                 raise InputError("Unknown db_update command \"%s\"" % command)
 
-        except InputError as e:
+        except (InputError, NotFoundError) as e:
             logging.error('perform_db_update(%s) got error %s', command, e)
             raise
         except ValueError as e:
@@ -230,7 +230,7 @@
             else:
                 raise InputError("Unknown query command \"%s\"" % command)
 
-        except InputError as e:
+        except (InputError, NotFoundError) as e:
             logging.error('perform_vlan_update(%s) got error %s', command, e)
             raise
         except ValueError as e:
@@ -266,7 +266,7 @@
             logging.debug('Adding DB record first: name %s, tag %d, is_base_vlan %d', name, tag, is_base_vlan)
             vlan_id = db.create_vlan(name, tag, is_base_vlan)
             logging.debug('Added VLAN tag %d, name %s to the database, created VLAN ID %d', tag, name, vlan_id)
-        except InputError:
+        except (InputError, NotFoundError):
             logging.debug('DB creation failed')
             raise
 
@@ -371,7 +371,7 @@
         logging.debug('Checking for ports using VLAN ID %d', vlan_id)
         vlan = db.get_vlan_by_id(vlan_id)
         if vlan is None:
-            raise InputError("VLAN ID %d does not exist" % vlan_id)
+            raise NotFoundError("VLAN ID %d does not exist" % vlan_id)
         vlan_tag = vlan.tag
         ports = db.get_ports_by_current_vlan(vlan_id)
         if ports is not None:
@@ -461,7 +461,7 @@
             logging.debug('Removing DB record: VLAN ID %d', vlan_id)
             vlan_id = db.delete_vlan(vlan_id)
             logging.debug('Removed VLAN ID %d from the database OK', vlan_id)
-        except InputError:
+        except (InputError, NotFoundError):
             logging.debug('DB deletion failed')
             raise
 
@@ -491,7 +491,7 @@
             raise InputError("Port mode '%s' is not a valid option: try 'access' or 'trunk'" % mode)
         port = db.get_port_by_id(port_id)
         if port is None:
-            raise InputError("Port ID %d does not exist" % port_id)
+            raise NotFoundError("Port ID %d does not exist" % port_id)
         if port.is_locked:
             raise InputError("Port ID %d is locked" % port_id)
         if mode == 'trunk' and port.is_trunk:
@@ -580,7 +580,7 @@
         # 1. Sanity checks!
         port = db.get_port_by_id(port_id)
         if port is None:
-            raise InputError("Port ID %d does not exist" % port_id)
+            raise NotFoundError("Port ID %d does not exist" % port_id)
         if port.is_locked:
             raise InputError("Port ID %d is locked" % port_id)
         if port.is_trunk:
@@ -588,7 +588,7 @@
 
         vlan = db.get_vlan_by_id(vlan_id)
         if vlan is None:
-            raise InputError("VLAN ID %d does not exist" % vlan_id)
+            raise NotFoundError("VLAN ID %d does not exist" % vlan_id)
 
         # Get the right driver
         switch_name = db.get_switch_name_by_id(port.switch_id)
@@ -640,7 +640,7 @@
         # 1. Sanity checks!
         port = db.get_port_by_id(port_id)
         if port is None:
-            raise InputError("Port ID %d does not exist" % port_id)
+            raise NotFoundError("Port ID %d does not exist" % port_id)
         if port.is_trunk:
             raise InputError("Port ID %d is not an access port" % port_id)
         if port.is_locked:
@@ -708,7 +708,7 @@
             raise InputError("Switch name %s already exists in the DB (ID %d)" % (switch_name, switch_id))
 
         if not switch_name in config.switches:
-            raise InputError("Switch name %s not defined in config" % switch_name)
+            raise NotFoundError("Switch name %s not defined in config" % switch_name)
 
         # 2. Now start reading config from the switch
         try:
diff --git a/vland.py b/vland.py
index 0822af6..8c87d35 100755
--- a/vland.py
+++ b/vland.py
@@ -30,7 +30,7 @@
 from config.config import VlanConfig
 from db.db import VlanDB
 from ipc.ipc import VlanIpc
-from errors import InputError, SocketError
+from errors import InputError, NotFoundError, SocketError
 from util import VlanUtil
 from visualisation.visualisation import Visualisation
 
@@ -148,6 +148,10 @@
             print e
             response['response'] = 'ERROR'
             response['error'] = e.__str__()
+        except NotFoundError as e:
+            print e
+            response['response'] = 'NOTFOUND'
+            response['error'] = e.__str__()
 
     # Next - simple queries about daemon state only. Should be safe!
     if json_data['type'] == 'daemon_query':
@@ -159,6 +163,10 @@
             print e
             response['response'] = 'ERROR'
             response['error'] = e.__str__()
+        except NotFoundError as e:
+            print e
+            response['response'] = 'NOTFOUND'
+            response['error'] = e.__str__()
 
     # Next, calls that manipulate objects in the database only
     # (switches and ports). These are safe and don't need actual
@@ -175,6 +183,10 @@
             print e
             response['response'] = 'ERROR'
             response['error'] = e.__str__()
+        except NotFoundError as e:
+            print e
+            response['response'] = 'NOTFOUND'
+            response['error'] = e.__str__()
 
     # Next, calls that may manipulate switch state *as well* as state
     # in the database - changes to VLAN setup.
@@ -190,6 +202,10 @@
             print e
             response['response'] = 'ERROR'
             response['error'] = e.__str__()
+        except NotFoundError as e:
+            print e
+            response['response'] = 'NOTFOUND'
+            response['error'] = e.__str__()
 
     # Finally, IPC interface for more complex API calls.
     # NOT IMPLEMENTED YET