Add REST interface for synchronizing openstack states and rules

Change-Id: I42cd8c73130348b204ea7c98c98d5b16cca6c4e8
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncStateCommand.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncStateCommand.java
index f21b79b..37360b1 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncStateCommand.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncStateCommand.java
@@ -15,7 +15,6 @@
  */
 package org.onosproject.openstacknetworking.cli;
 
-import com.fasterxml.jackson.databind.JsonNode;
 import com.google.common.base.Strings;
 import org.apache.karaf.shell.commands.Command;
 import org.onosproject.cli.AbstractShellCommand;
@@ -31,18 +30,15 @@
 import org.openstack4j.model.network.Network;
 import org.openstack4j.model.network.Port;
 import org.openstack4j.model.network.Router;
-import org.openstack4j.model.network.RouterInterface;
 import org.openstack4j.model.network.Subnet;
-import org.openstack4j.openstack.networking.domain.NeutronRouterInterface;
 
-import java.io.IOException;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Collectors;
 
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.addRouterIface;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
-import static org.openstack4j.core.transport.ObjectMapperSingleton.getContext;
 
 /**
  * Synchronizes OpenStack network states.
@@ -155,28 +151,6 @@
         });
     }
 
-    // TODO fix the logic to add router interface to router
-    private void addRouterIface(Port osPort, OpenstackRouterAdminService adminService) {
-        osPort.getFixedIps().forEach(p -> {
-            JsonNode jsonTree = mapper().createObjectNode()
-                    .put("id", osPort.getDeviceId())
-                    .put("tenant_id", osPort.getTenantId())
-                    .put("subnet_id", p.getSubnetId())
-                    .put("port_id", osPort.getId());
-            try {
-                RouterInterface rIface = getContext(NeutronRouterInterface.class)
-                        .readerFor(NeutronRouterInterface.class)
-                        .readValue(jsonTree);
-                if (adminService.routerInterface(rIface.getPortId()) != null) {
-                    adminService.updateRouterInterface(rIface);
-                } else {
-                    adminService.addRouterInterface(rIface);
-                }
-            } catch (IOException ignore) {
-            }
-        });
-    }
-
     private void printNetwork(Network osNet) {
         final String strNet = String.format(NETWORK_FORMAT,
                 osNet.getId(),
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
index 6a42902..2ebf9db 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
@@ -20,6 +20,7 @@
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.onosproject.net.DeviceId;
 import org.onosproject.openstacknetworking.api.InstancePort;
+import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
 import org.onosproject.openstacknode.api.OpenstackAuth;
 import org.onosproject.openstacknode.api.OpenstackAuth.Perspective;
 import org.onosproject.openstacknode.api.OpenstackNode;
@@ -32,7 +33,9 @@
 import org.openstack4j.model.ModelEntity;
 import org.openstack4j.model.common.Identifier;
 import org.openstack4j.model.network.Port;
+import org.openstack4j.model.network.RouterInterface;
 import org.openstack4j.openstack.OSFactory;
+import org.openstack4j.openstack.networking.domain.NeutronRouterInterface;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -41,6 +44,7 @@
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509TrustManager;
+import java.io.IOException;
 import java.io.InputStream;
 import java.security.cert.X509Certificate;
 import java.util.HashMap;
@@ -53,6 +57,7 @@
 import static org.onosproject.openstacknetworking.api.Constants.PCISLOT;
 import static org.onosproject.openstacknetworking.api.Constants.PCI_VENDOR_INFO;
 import static org.onosproject.openstacknetworking.api.Constants.portNamePrefixMap;
+import static org.openstack4j.core.transport.ObjectMapperSingleton.getContext;
 
 /**
  * An utility that used in openstack networking app.
@@ -259,6 +264,34 @@
     }
 
     /**
+     * Adds router interfaces to openstack admin service.
+     * TODO fix the logic to add router interface to router
+     *
+     * @param osPort        port
+     * @param adminService  openstack admin service
+     */
+    public static void addRouterIface(Port osPort, OpenstackRouterAdminService adminService) {
+        osPort.getFixedIps().forEach(p -> {
+            JsonNode jsonTree = new ObjectMapper().createObjectNode()
+                    .put("id", osPort.getDeviceId())
+                    .put("tenant_id", osPort.getTenantId())
+                    .put("subnet_id", p.getSubnetId())
+                    .put("port_id", osPort.getId());
+            try {
+                RouterInterface rIface = getContext(NeutronRouterInterface.class)
+                        .readerFor(NeutronRouterInterface.class)
+                        .readValue(jsonTree);
+                if (adminService.routerInterface(rIface.getPortId()) != null) {
+                    adminService.updateRouterInterface(rIface);
+                } else {
+                    adminService.addRouterInterface(rIface);
+                }
+            } catch (IOException ignore) {
+            }
+        });
+    }
+
+    /**
      * Builds up and a complete endpoint URL from gateway node.
      *
      * @param node gateway node
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackManagementWebResource.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackManagementWebResource.java
new file mode 100644
index 0000000..e991008
--- /dev/null
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackManagementWebResource.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknetworking.web;
+
+import org.onlab.util.ItemNotFoundException;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.openstacknetworking.api.Constants;
+import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
+import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
+import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupAdminService;
+import org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil;
+import org.onosproject.openstacknode.api.NodeState;
+import org.onosproject.openstacknode.api.OpenstackNode;
+import org.onosproject.openstacknode.api.OpenstackNodeAdminService;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
+import org.onosproject.rest.AbstractWebResource;
+import org.openstack4j.api.OSClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Objects;
+import java.util.Optional;
+
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.addRouterIface;
+import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
+
+/**
+ * REST interface for synchronizing openstack network states and rules.
+ */
+@Path("management")
+public class OpenstackManagementWebResource extends AbstractWebResource {
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private static final String DEVICE_OWNER_IFACE = "network:router_interface";
+
+    private final OpenstackSecurityGroupAdminService osSgAdminService =
+            get(OpenstackSecurityGroupAdminService.class);
+    private final OpenstackNetworkAdminService osNetAdminService =
+            get(OpenstackNetworkAdminService.class);
+    private final OpenstackRouterAdminService osRouterAdminService =
+            get(OpenstackRouterAdminService.class);
+    private final OpenstackNodeService osNodeService =
+            get(OpenstackNodeService.class);
+    private final OpenstackNodeAdminService osNodeAdminService =
+            get(OpenstackNodeAdminService.class);
+    private final FlowRuleService flowRuleService = get(FlowRuleService.class);
+    private final CoreService coreService = get(CoreService.class);
+
+    /**
+     * Synchronizes the network states with openstack.
+     *
+     * @return 200 OK with sync result, 404 not found
+     */
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("sync/states")
+    public Response syncStates() {
+
+        Optional<OpenstackNode> node = osNodeService.nodes(CONTROLLER).stream().findFirst();
+        if (!node.isPresent()) {
+            throw new ItemNotFoundException("Auth info is not found");
+        }
+
+        OSClient osClient = OpenstackNetworkingUtil.getConnectedClient(node.get());
+
+        if (osClient == null) {
+            throw new ItemNotFoundException("Auth info is not correct");
+        }
+
+        osClient.networking().securitygroup().list().forEach(osSg -> {
+            if (osSgAdminService.securityGroup(osSg.getId()) != null) {
+                osSgAdminService.updateSecurityGroup(osSg);
+            } else {
+                osSgAdminService.createSecurityGroup(osSg);
+            }
+        });
+
+        osClient.networking().network().list().forEach(osNet -> {
+            if (osNetAdminService.network(osNet.getId()) != null) {
+                osNetAdminService.updateNetwork(osNet);
+            } else {
+                osNetAdminService.createNetwork(osNet);
+            }
+        });
+
+        osClient.networking().subnet().list().forEach(osSubnet -> {
+            if (osNetAdminService.subnet(osSubnet.getId()) != null) {
+                osNetAdminService.updateSubnet(osSubnet);
+            } else {
+                osNetAdminService.createSubnet(osSubnet);
+            }
+        });
+
+        osClient.networking().port().list().forEach(osPort -> {
+            if (osNetAdminService.port(osPort.getId()) != null) {
+                osNetAdminService.updatePort(osPort);
+            } else {
+                osNetAdminService.createPort(osPort);
+            }
+        });
+
+        osClient.networking().router().list().forEach(osRouter -> {
+            if (osRouterAdminService.router(osRouter.getId()) != null) {
+                osRouterAdminService.updateRouter(osRouter);
+            } else {
+                osRouterAdminService.createRouter(osRouter);
+            }
+
+            osNetAdminService.ports().stream()
+                    .filter(osPort -> Objects.equals(osPort.getDeviceId(), osRouter.getId()) &&
+                            Objects.equals(osPort.getDeviceOwner(), DEVICE_OWNER_IFACE))
+                    .forEach(osPort -> addRouterIface(osPort, osRouterAdminService));
+        });
+
+        osClient.networking().floatingip().list().forEach(osFloating -> {
+            if (osRouterAdminService.floatingIp(osFloating.getId()) != null) {
+                osRouterAdminService.updateFloatingIp(osFloating);
+            } else {
+                osRouterAdminService.createFloatingIp(osFloating);
+            }
+        });
+
+        return ok(mapper().createObjectNode()).build();
+    }
+
+    /**
+     * Synchronizes the flow rules.
+     *
+     * @return 200 OK with sync result, 404 not found
+     */
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("sync/rules")
+    public Response syncRules() {
+
+        osNodeService.completeNodes().forEach(osNode -> {
+            OpenstackNode updated = osNode.updateState(NodeState.INIT);
+            osNodeAdminService.updateNode(updated);
+        });
+
+        return ok(mapper().createObjectNode()).build();
+    }
+
+    /**
+     * Purges the network states.
+     *
+     * @return 200 OK with purge result, 404 not found
+     */
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("purge/states")
+    public Response purgeStates() {
+
+        osRouterAdminService.clear();
+        osNetAdminService.clear();
+        osSgAdminService.clear();
+
+        return ok(mapper().createObjectNode()).build();
+    }
+
+    /**
+     * Purges the flow rules installed by openstacknetworking.
+     *
+     * @return 200 OK with purge result, 404 not found
+     */
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("purge/rules")
+    public Response purgeRules() {
+
+        ApplicationId appId = coreService.getAppId(Constants.OPENSTACK_NETWORKING_APP_ID);
+        if (appId == null) {
+            throw new ItemNotFoundException("application not found");
+        }
+        flowRuleService.removeFlowRulesById(appId);
+
+        return ok(mapper().createObjectNode()).build();
+    }
+}
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackNetworkingWebApplication.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackNetworkingWebApplication.java
index 8f9e623..f215efe 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackNetworkingWebApplication.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackNetworkingWebApplication.java
@@ -32,7 +32,8 @@
                 OpenstackRouterWebResource.class,
                 OpenstackSecurityGroupRuleWebResource.class,
                 OpenstackSecurityGroupWebResource.class,
-                OpenstackSubnetWebResource.class
+                OpenstackSubnetWebResource.class,
+                OpenstackManagementWebResource.class
         );
     }
 }