[ONOS-7952] RemoveBridgeOfDevice worklet implementation for ovs workflow

Change-Id: I4539a2fb7711ab868a8fcaf8476fcfc0667efa4b
diff --git a/apps/workflow/ofoverlay/app/src/main/java/org/onosproject/ofoverlay/impl/OfOverlayWorkflow.java b/apps/workflow/ofoverlay/app/src/main/java/org/onosproject/ofoverlay/impl/OfOverlayWorkflow.java
index ec6a091..cbddfc7 100644
--- a/apps/workflow/ofoverlay/app/src/main/java/org/onosproject/ofoverlay/impl/OfOverlayWorkflow.java
+++ b/apps/workflow/ofoverlay/app/src/main/java/org/onosproject/ofoverlay/impl/OfOverlayWorkflow.java
@@ -126,6 +126,17 @@
                 .build();
         workflowStore.register(workflow);
 
+        uri = URI.create("of-overlay.clean-workflow-nova-waitAll-Bridge-Del");
+        workflow = ImmutableListWorkflow.builder()
+                .id(uri)
+                //.attribute(WorkflowAttribute.REMOVE_AFTER_COMPLETE)
+                .chain(Ovs.DeleteOverlayBridgeConfig.class.getName())
+                .chain(Ovs.DeleteUnderlayBridgeConfig.class.getName())
+                .chain(Ovs.RemoveBridgeOfDevice.class.getName())
+                .chain(Ovs.RemoveOvsdbDevice.class.getName())
+                .build();
+        workflowStore.register(workflow);
+
         uri = URI.create("of-overlay.workflow-ovs-leaf");
         workflow = ImmutableListWorkflow.builder()
                 .id(uri)
diff --git a/apps/workflow/ofoverlay/app/src/main/java/org/onosproject/ofoverlay/impl/Ovs.java b/apps/workflow/ofoverlay/app/src/main/java/org/onosproject/ofoverlay/impl/Ovs.java
index 319bb92..ad56d52 100644
--- a/apps/workflow/ofoverlay/app/src/main/java/org/onosproject/ofoverlay/impl/Ovs.java
+++ b/apps/workflow/ofoverlay/app/src/main/java/org/onosproject/ofoverlay/impl/Ovs.java
@@ -17,6 +17,8 @@
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.fasterxml.jackson.databind.node.TextNode;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
@@ -87,6 +89,7 @@
     private static final String MODEL_SSH_ACCESSINFO = "/sshAccessInfo";
     private static final String MODEL_OF_DEVID_OVERLAY_BRIDGE = "/ofDevIdBrInt";
     private static final String MODEL_OF_DEVID_UNDERLAY_BRIDGE = "/ofDevIdBrPhy";
+    private static final String MODEL_OF_DEVID_FOR_OVERLAY_UNDERLAY_BRIDGE = "/ofDevIdBrIntBrPhy";
     private static final String MODEL_PHY_PORTS = "/physicalPorts";
     private static final String MODEL_VTEP_IP = "/vtepIp";
 
@@ -1320,4 +1323,96 @@
             }
         }
     }
+
+    /**
+     * Work-let class for removing underlay bridge and overlay openflow device.
+     */
+    public static class RemoveBridgeOfDevice extends AbstractWorklet {
+
+        @JsonDataModel(path = MODEL_MGMT_IP)
+        String strMgmtIp;
+
+        @JsonDataModel(path = MODEL_OF_DEVID_FOR_OVERLAY_UNDERLAY_BRIDGE, optional = true)
+        ObjectNode ofDevId;
+
+        @Override
+        public boolean isNext(WorkflowContext context) throws WorkflowException {
+
+            boolean isOfDevicePresent = true;
+
+            if (ofDevId == null) {
+                ofDevId = JsonNodeFactory.instance.objectNode();
+                ofDevId.put(String.valueOf(DEVID_IDX_BRIDGE_OVERLAY), OvsUtil.buildOfDeviceId(
+                        IpAddress.valueOf(strMgmtIp), DEVID_IDX_BRIDGE_OVERLAY).toString());
+                ofDevId.put(String.valueOf(DEVID_IDX_BRIDGE_UNDERLAY_NOVA), OvsUtil.buildOfDeviceId(
+                        IpAddress.valueOf(strMgmtIp), DEVID_IDX_BRIDGE_UNDERLAY_NOVA).toString());
+            }
+
+            if (context.getService(DeviceService.class).
+                    getDevice(DeviceId.deviceId(
+                            ofDevId.get(String.valueOf(DEVID_IDX_BRIDGE_OVERLAY)).asText())) == null) {
+                isOfDevicePresent = false;
+            }
+            if (context.getService(DeviceService.class).
+                    getDevice(DeviceId.deviceId(
+                            ofDevId.get(String.valueOf(DEVID_IDX_BRIDGE_UNDERLAY_NOVA)).asText())) == null) {
+                isOfDevicePresent = false;
+            }
+
+            return isOfDevicePresent;
+        }
+
+        @Override
+        public void process(WorkflowContext context) throws WorkflowException {
+
+            DeviceAdminService adminService = context.getService(DeviceAdminService.class);
+            String ofDevIdOverlay;
+            String ofDevIdUnderlay;
+
+            if (ofDevId == null) {
+                ofDevId = JsonNodeFactory.instance.objectNode();
+                ofDevId.put(String.valueOf(DEVID_IDX_BRIDGE_OVERLAY), OvsUtil.buildOfDeviceId(
+                        IpAddress.valueOf(strMgmtIp), DEVID_IDX_BRIDGE_OVERLAY).toString());
+                ofDevId.put(String.valueOf(DEVID_IDX_BRIDGE_UNDERLAY_NOVA), OvsUtil.buildOfDeviceId(
+                        IpAddress.valueOf(strMgmtIp), DEVID_IDX_BRIDGE_UNDERLAY_NOVA).toString());
+            }
+
+            ofDevIdOverlay = ofDevId.get(String.valueOf(DEVID_IDX_BRIDGE_OVERLAY)).asText();
+            ofDevIdUnderlay = ofDevId.get(String.valueOf(DEVID_IDX_BRIDGE_UNDERLAY_NOVA)).asText();
+
+            Set<String> eventHints = Sets.newHashSet(ofDevIdOverlay, ofDevIdUnderlay);
+
+            context.waitAnyCompletion(DeviceEvent.class, eventHints,
+                                      () -> {
+                                                adminService.removeDevice(DeviceId.deviceId(ofDevIdOverlay));
+                                                adminService.removeDevice(DeviceId.deviceId(ofDevIdUnderlay));
+                                            },
+                                   TIMEOUT_DEVICE_CREATION_MS
+            );
+        }
+
+        @Override
+        public boolean isCompleted(WorkflowContext context, Event event)throws WorkflowException {
+            if (!(event instanceof DeviceEvent)) {
+                return false;
+            }
+            DeviceEvent deviceEvent = (DeviceEvent) event;
+            switch (deviceEvent.type()) {
+                case DEVICE_REMOVED:
+                    log.trace("GOT DEVICE REMOVED EVENT FOR DEVICE {}", event.subject());
+                    return !isNext(context);
+                default:
+                    return false;
+            }
+        }
+
+        @Override
+        public void timeout(WorkflowContext context) throws WorkflowException {
+            if (!isNext(context)) {
+                context.completed(); //Complete the job of worklet by timeout
+            } else {
+                super.timeout(context);
+            }
+        }
+    }
 }
diff --git a/apps/workflow/ofoverlay/test-cfg/network-cfg-ovs-waitAll-rm-bridge-wf.json b/apps/workflow/ofoverlay/test-cfg/network-cfg-ovs-waitAll-rm-bridge-wf.json
new file mode 100755
index 0000000..c9e387e
--- /dev/null
+++ b/apps/workflow/ofoverlay/test-cfg/network-cfg-ovs-waitAll-rm-bridge-wf.json
@@ -0,0 +1,34 @@
+{
+    "apps": {
+        "org.onosproject.workflow": {
+          "workflow" : {
+            "rpc" : [
+              {
+                "op"   : "workflow.invoke",
+                "params" : {
+                  "workplace" : "Nova-000",
+                  "id"        : "of-overlay.clean-workflow-nova-waitAll-Bridge-Del",
+                  "data"      : {
+
+                    "mgmtIp" : "192.168.10.8",
+                    "ovsdbPort" : 6641,
+
+                    "sshAccessInfo" : {
+                      "remoteIp" : "192.168.10.8",
+                      "port"     : 22,
+                      "user"     : "root",
+                      "password" : "iloveyou",
+                      "keyfile"  : "~/.ssh/id_rsa"
+                    }
+                  }
+                },
+                "id" : "00001@10.0.0.1"
+              }
+
+            ]
+
+          }
+
+        }
+    }
+}