Don't fail on missing Delete interfaces

On the DELETE HTTP request, don't immediately fail if
the specified bus does't provide the delete interface on
the specified path, just skip it instead.

Only return the 403 error if nothing at all ended up being
deleted on the request.

This allows multiple services to host the same object path while
only requiring one to support the delete interface.  The others
will just listen for the interfaces removed signal to remove
their objects.

Resolves openbmc/openbmc#3181

Tested:
  * Issue a -X DELETE with curl on a path provided by multiple
    services where only 1 provides the delete interface.
  * Issue a -X POST .../action/delete with curl with the same
    test setup.
  * Issue a -X DELETE with curl on a path without a
    delete interface and get a 403 back.

Change-Id: Ib76c80081361160e617ddfe8b48e3e4588abce67
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/module/obmc/wsgi/apps/rest_dbus.py b/module/obmc/wsgi/apps/rest_dbus.py
index 2d98817..ffbab94 100644
--- a/module/obmc/wsgi/apps/rest_dbus.py
+++ b/module/obmc/wsgi/apps/rest_dbus.py
@@ -600,15 +600,18 @@
                 path, p, v)
 
     def do_delete(self, path):
-        for bus_info in request.route_data['map'][path].items():
-            if self.bus_missing_delete(path, *bus_info):
-                abort(403, _4034_msg % ('resource', 'removed', path))
+        deleted = False
+        for bus, interfaces in request.route_data['map'][path].items():
+            if self.bus_has_delete(interfaces):
+                self.delete_on_bus(path, bus)
+                deleted = True
 
-        for bus in request.route_data['map'][path].keys():
-            self.delete_on_bus(path, bus)
+        #It's OK if some objects didn't have a Delete, but not all
+        if not deleted:
+            abort(403, _4034_msg % ('resource', 'removed', path))
 
-    def bus_missing_delete(self, path, bus, interfaces):
-        return DELETE_IFACE not in interfaces
+    def bus_has_delete(self, interfaces):
+        return DELETE_IFACE in interfaces
 
     def delete_on_bus(self, path, bus):
         obj = self.bus.get_object(bus, path, introspect=False)