Added sync and purge security group states

- Added list security groups CLI
- Removed unnecessary security group rule store

Change-Id: I62ac652e0af73c5f771f0caec87acd5dfe4abedd
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackPurgeStateCommand.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackPurgeStateCommand.java
index 6f28590..c019c8e 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackPurgeStateCommand.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackPurgeStateCommand.java
@@ -19,6 +19,7 @@
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
 import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
+import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupAdminService;
 
 /**
  * Purges all existing network states.
@@ -29,7 +30,8 @@
 
     @Override
     protected void execute() {
-        get(OpenstackNetworkAdminService.class).clear();
         get(OpenstackRouterAdminService.class).clear();
+        get(OpenstackNetworkAdminService.class).clear();
+        get(OpenstackSecurityGroupAdminService.class).clear();
     }
 }
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSecurityGroupListCommand.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSecurityGroupListCommand.java
new file mode 100644
index 0000000..71afbd2
--- /dev/null
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSecurityGroupListCommand.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.cli;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Lists;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
+import org.openstack4j.core.transport.ObjectMapperSingleton;
+import org.openstack4j.model.network.SecurityGroup;
+import org.openstack4j.openstack.networking.domain.NeutronSecurityGroup;
+
+import java.util.Comparator;
+import java.util.List;
+
+import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
+
+/**
+ * Lists OpenStack security groups.
+ */
+@Command(scope = "onos", name = "openstack-security-groups",
+        description = "Lists all OpenStack security groups")
+public class OpenstackSecurityGroupListCommand extends AbstractShellCommand {
+
+    private static final String FORMAT = "%-40s%-20s";
+
+    @Argument(name = "networkId", description = "Network ID")
+    private String networkId = null;
+
+    @Override
+    protected void execute() {
+        OpenstackSecurityGroupService service =
+                AbstractShellCommand.get(OpenstackSecurityGroupService.class);
+
+        List<SecurityGroup> sgs = Lists.newArrayList(service.securityGroups());
+        sgs.sort(Comparator.comparing(SecurityGroup::getId));
+
+        if (outputJson()) {
+            try {
+                print("%s", mapper().writeValueAsString(json(sgs)));
+            } catch (JsonProcessingException e) {
+                error("Failed to list security groups in JSON format");
+            }
+            return;
+        }
+
+        print("Hint: use --json option to see security group rules as well\n");
+        print(FORMAT, "ID", "Name");
+        for (SecurityGroup sg: service.securityGroups()) {
+            print(FORMAT, sg.getId(), sg.getName());
+        }
+    }
+
+    private JsonNode json(List<SecurityGroup> securityGroups) {
+        ArrayNode result = mapper().enable(INDENT_OUTPUT).createArrayNode();
+        for (SecurityGroup sg: securityGroups) {
+            result.add(writeSecurityGroup(sg));
+        }
+        return result;
+    }
+
+    private ObjectNode writeSecurityGroup(SecurityGroup sg) {
+        try {
+            String strSg = ObjectMapperSingleton.getContext(NeutronSecurityGroup.class)
+                    .writerFor(NeutronSecurityGroup.class)
+                    .writeValueAsString(sg);
+            return (ObjectNode) mapper().readTree(strSg.getBytes());
+        } catch (Exception e) {
+            throw new IllegalArgumentException();
+        }
+    }
+}
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncStateCommand.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncStateCommand.java
index d07591e..3e25973 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncStateCommand.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncStateCommand.java
@@ -24,6 +24,8 @@
 import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
 import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
 import org.onosproject.openstacknetworking.api.OpenstackRouterService;
+import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupAdminService;
+import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
 import org.openstack4j.api.OSClient;
 import org.openstack4j.api.exceptions.AuthenticationException;
 import org.openstack4j.model.identity.Access;
@@ -67,6 +69,7 @@
             required = true, multiValued = false)
     private String password = null;
 
+    private static final String SECURITY_GROUP_FORMAT = "%-40s%-20s";
     private static final String NETWORK_FORMAT = "%-40s%-20s%-20s%-8s";
     private static final String SUBNET_FORMAT = "%-40s%-20s%-20s";
     private static final String PORT_FORMAT = "%-40s%-20s%-20s%-8s";
@@ -78,6 +81,8 @@
 
     @Override
     protected void execute() {
+        OpenstackSecurityGroupAdminService osSgAdminService = get(OpenstackSecurityGroupAdminService.class);
+        OpenstackSecurityGroupService osSgService = get(OpenstackSecurityGroupService.class);
         OpenstackNetworkAdminService osNetAdminService = get(OpenstackNetworkAdminService.class);
         OpenstackNetworkService osNetService = get(OpenstackNetworkService.class);
         OpenstackRouterAdminService osRouterAdminService = get(OpenstackRouterAdminService.class);
@@ -101,7 +106,18 @@
 
         OSClient osClient = OSFactory.clientFromAccess(osAccess);
 
-        print("Synchronizing OpenStack networks...");
+        print("Synchronizing OpenStack security groups");
+        print(SECURITY_GROUP_FORMAT, "ID", "Name");
+        osClient.networking().securitygroup().list().forEach(osSg -> {
+            if (osSgService.securityGroup(osSg.getId()) != null) {
+                osSgAdminService.updateSecurityGroup(osSg);
+            } else {
+                osSgAdminService.createSecurityGroup(osSg);
+            }
+            print(SECURITY_GROUP_FORMAT, osSg.getId(), osSg.getName());
+        });
+
+        print("\nSynchronizing OpenStack networks");
         print(NETWORK_FORMAT, "ID", "Name", "VNI", "Subnets");
         osClient.networking().network().list().forEach(osNet -> {
             if (osNetService.network(osNet.getId()) != null) {
@@ -112,7 +128,7 @@
             printNetwork(osNet);
         });
 
-        print("\nSynchronizing OpenStack subnets...");
+        print("\nSynchronizing OpenStack subnets");
         print(SUBNET_FORMAT, "ID", "Network", "CIDR");
         osClient.networking().subnet().list().forEach(osSubnet -> {
             if (osNetService.subnet(osSubnet.getId()) != null) {
@@ -123,7 +139,7 @@
             printSubnet(osSubnet, osNetService);
         });
 
-        print("\nSynchronizing OpenStack ports...");
+        print("\nSynchronizing OpenStack ports");
         print(PORT_FORMAT, "ID", "Network", "MAC", "Fixed IPs");
         osClient.networking().port().list().forEach(osPort -> {
             if (osNetService.port(osPort.getId()) != null) {
@@ -134,7 +150,7 @@
             printPort(osPort, osNetService);
         });
 
-        print("\nSynchronizing OpenStack routers...");
+        print("\nSynchronizing OpenStack routers");
         print(ROUTER_FORMAT, "ID", "Name", "External", "Internal");
         osClient.networking().router().list().forEach(osRouter -> {
             if (osRouterService.router(osRouter.getId()) != null) {
@@ -153,7 +169,7 @@
             printRouter(osRouter, osNetService);
         });
 
-        print("\nSynchronizing OpenStack floating IPs...");
+        print("\nSynchronizing OpenStack floating IPs");
         print(FLOATING_IP_FORMAT, "ID", "Floating IP", "Fixed IP");
         osClient.networking().floatingip().list().forEach(osFloating -> {
             if (osRouterService.floatingIp(osFloating.getId()) != null) {