Allow sync state CLI commands to read values from netcfg

Change-Id: If777fba32f9256e96e8bcfe5d28d29ca7d617416
diff --git a/pom.xml b/pom.xml
index 02a6093..4cf2ba8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -204,6 +204,11 @@
             <version>2.11</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.apache.karaf.shell</groupId>
+            <artifactId>org.apache.karaf.shell.console</artifactId>
+        </dependency>
+
     </dependencies>
 
     <build>
diff --git a/src/main/java/org/opencord/cordvtn/api/CordVtnConfig.java b/src/main/java/org/opencord/cordvtn/api/CordVtnConfig.java
index 7dea415..fc7f903 100644
--- a/src/main/java/org/opencord/cordvtn/api/CordVtnConfig.java
+++ b/src/main/java/org/opencord/cordvtn/api/CordVtnConfig.java
@@ -79,8 +79,15 @@
 
     @Deprecated
     private static final String OPENSTACK = "openstack";
+    private static final String OPENSTACK_ENDPOINT = "endpoint";
+    private static final String OPENSTACK_TENANT = "tenant";
+    private static final String OPENSTACK_USER = "user";
+    private static final String OPENSTACK_PASSWORD = "password";
     @Deprecated
     private static final String XOS = "xos";
+    private static final String XOS_ENDPOINT = "endpoint";
+    private static final String XOS_USER = "user";
+    private static final String XOS_PASSWORD = "password";
 
     private static final String CONTROLLERS = "controllers";
     private static final int INDEX_IP = 0;
@@ -307,4 +314,60 @@
         String[] ctrl = jsonNode.asText().split(":");
         return Integer.parseInt(ctrl[INDEX_PORT]);
     }
+
+    public String getXosEndpoint() {
+        JsonNode xosObject = object.get(XOS);
+        if (xosObject == null) {
+            return null;
+        }
+        return xosObject.get(XOS_ENDPOINT).asText();
+    }
+
+    public String getXosUsername() {
+        JsonNode xosObject = object.get(XOS);
+        if (xosObject == null) {
+            return null;
+        }
+        return xosObject.get(XOS_USER).asText();
+    }
+
+    public String getXosPassword() {
+        JsonNode xosObject = object.get(XOS);
+        if (xosObject == null) {
+            return null;
+        }
+        return xosObject.get(XOS_PASSWORD).asText();
+    }
+
+    public String getOpenstackEndpoint() {
+        JsonNode xosObject = object.get(OPENSTACK);
+        if (xosObject == null) {
+            return null;
+        }
+        return xosObject.get(OPENSTACK_ENDPOINT).asText();
+    }
+
+    public String getOpenstackTenant() {
+        JsonNode xosObject = object.get(OPENSTACK);
+        if (xosObject == null) {
+            return null;
+        }
+        return xosObject.get(OPENSTACK_TENANT).asText();
+    }
+
+    public String getOpenstackUser() {
+        JsonNode xosObject = object.get(OPENSTACK);
+        if (xosObject == null) {
+            return null;
+        }
+        return xosObject.get(OPENSTACK_USER).asText();
+    }
+
+    public String getOpenstackPassword() {
+        JsonNode xosObject = object.get(OPENSTACK);
+        if (xosObject == null) {
+            return null;
+        }
+        return xosObject.get(OPENSTACK_PASSWORD).asText();
+    }
 }
diff --git a/src/main/java/org/opencord/cordvtn/api/core/ServiceNetworkAdminService.java b/src/main/java/org/opencord/cordvtn/api/core/ServiceNetworkAdminService.java
index d52213f..0563a88 100644
--- a/src/main/java/org/opencord/cordvtn/api/core/ServiceNetworkAdminService.java
+++ b/src/main/java/org/opencord/cordvtn/api/core/ServiceNetworkAdminService.java
@@ -31,6 +31,39 @@
     void purgeStates();
 
     /**
+     * Request state synchronization from XOS. The XOS connection parameters
+     * will be pulled from the netcfg.
+     */
+    void syncXosState();
+
+    /**
+     * Request state synchronization from XOS using the given XOS connection
+     * parameters.
+     *
+     * @param endpoint XOS REST endpoint
+     * @param user XOS username
+     * @param password XOS password
+     */
+    void syncXosState(String endpoint, String user, String password);
+
+    /**
+     * Synchronize state with Neutron. The Neutron connection parameters will be
+     * pulled from the netcfg.
+     */
+    void syncNeutronState();
+
+    /**
+     * Synchronize state with Neutron using the given Neutron connection
+     * parameters.
+     *
+     * @param endpoint Neutron REST endpoint
+     * @param tenant Neutron tenant
+     * @param user Neutron username
+     * @param password Neutron password
+     */
+    void syncNeutronState(String endpoint, String tenant, String user, String password);
+
+    /**
      * Creates a service network with the given information.
      *
      * @param serviceNetwork the new service network
diff --git a/src/main/java/org/opencord/cordvtn/cli/CordVtnSyncNeutronStatesCommand.java b/src/main/java/org/opencord/cordvtn/cli/CordVtnSyncNeutronStatesCommand.java
index 85cda91..5fdf522 100644
--- a/src/main/java/org/opencord/cordvtn/cli/CordVtnSyncNeutronStatesCommand.java
+++ b/src/main/java/org/opencord/cordvtn/cli/CordVtnSyncNeutronStatesCommand.java
@@ -17,25 +17,9 @@
 
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
+import org.apache.karaf.shell.commands.Option;
 import org.onosproject.cli.AbstractShellCommand;
 import org.opencord.cordvtn.api.core.ServiceNetworkAdminService;
-import org.opencord.cordvtn.api.net.NetworkId;
-import org.opencord.cordvtn.api.net.PortId;
-import org.opencord.cordvtn.api.net.SegmentId;
-import org.opencord.cordvtn.api.net.ServiceNetwork;
-import org.opencord.cordvtn.api.net.ServicePort;
-import org.opencord.cordvtn.impl.DefaultServiceNetwork;
-import org.opencord.cordvtn.impl.DefaultServicePort;
-import org.openstack4j.api.OSClient;
-import org.openstack4j.api.exceptions.AuthenticationException;
-import org.openstack4j.model.identity.Access;
-import org.openstack4j.openstack.OSFactory;
-
-import java.util.List;
-import java.util.stream.Collectors;
 
 /**
  * Synchronizes network states with OpenStack Neutron.
@@ -46,6 +30,10 @@
         description = "Synchronizes network states with Neutron")
 public class CordVtnSyncNeutronStatesCommand extends AbstractShellCommand {
 
+    @Option(name = "-c", aliases = "--config", description = "Use connection values from config",
+            required = false, multiValued = false)
+    private boolean config = false;
+
     @Argument(index = 0, name = "endpoint", description = "OpenStack service endpoint",
             required = true, multiValued = false)
     private String endpoint = null;
@@ -62,101 +50,16 @@
             required = true, multiValued = false)
     private String password = null;
 
-    private static final String PORT_NAME_PREFIX = "tap";
-    private static final String NET_FORMAT = "%-40s%-30s%-20s%-8s%-20s%s";
-    private static final String PORT_FORMAT = "%-40s%-30s%-20s%-18s%-10s%s";
-
     @Override
     protected void execute() {
         ServiceNetworkAdminService snetService =
                 AbstractShellCommand.get(ServiceNetworkAdminService.class);
-        Access osAccess;
-        try {
-            osAccess = OSFactory.builder()
-                    .endpoint(this.endpoint)
-                    .tenantName(this.tenant)
-                    .credentials(this.user, this.password)
-                    .authenticate()
-                    .getAccess();
-        } catch (AuthenticationException e) {
-            print("Authentication failed");
-            return;
-        } catch (Exception e) {
-            print("OpenStack service endpoint is unreachable");
-            return;
+
+        print("Synchronizing neutron state...");
+        if (config) {
+            snetService.syncNeutronState();
+        } else {
+            snetService.syncNeutronState(endpoint, tenant, user, password);
         }
-
-        print("Synchronizing service networks...");
-        print(NET_FORMAT, "ID", "Name", "Type", "VNI", "Subnet", "Service IP");
-        OSClient osClient = OSFactory.clientFromAccess(osAccess);
-        osClient.networking().network().list().forEach(osNet -> {
-            ServiceNetwork snet = DefaultServiceNetwork.builder()
-                    .id(NetworkId.of(osNet.getId()))
-                    .name(osNet.getName())
-                    .type(ServiceNetwork.NetworkType.PRIVATE)
-                    .segmentId(SegmentId.of(Long.valueOf(osNet.getProviderSegID())))
-                    .build();
-            try {
-                if (snetService.serviceNetwork(snet.id()) != null) {
-                    snetService.updateServiceNetwork(snet);
-                } else {
-                    snetService.createServiceNetwork(snet);
-                }
-            } catch (Exception ignore) {
-            }
-        });
-
-        osClient.networking().subnet().list().forEach(osSubnet -> {
-            try {
-                ServiceNetwork snet = DefaultServiceNetwork.builder()
-                        .id(NetworkId.of(osSubnet.getNetworkId()))
-                        .subnet(IpPrefix.valueOf(osSubnet.getCidr()))
-                        .serviceIp(IpAddress.valueOf(osSubnet.getGateway()))
-                        .build();
-                snetService.updateServiceNetwork(snet);
-                ServiceNetwork updated = snetService.serviceNetwork(snet.id());
-                print(NET_FORMAT, updated.id(),
-                      updated.name(),
-                      updated.type(),
-                      updated.segmentId(),
-                      updated.subnet(),
-                      updated.serviceIp());
-            } catch (Exception e) {
-                print(e.getMessage());
-            }
-        });
-
-        print("\nSynchronizing service ports...");
-        print(PORT_FORMAT, "ID", "Name", "MAC", "IP", "VLAN", "WAN IPs");
-        osClient.networking().port().list().forEach(osPort -> {
-            ServicePort.Builder sportBuilder = DefaultServicePort.builder()
-                    .id(PortId.of(osPort.getId()))
-                    .name(PORT_NAME_PREFIX + osPort.getId().substring(0, 11))
-                    .networkId(NetworkId.of(osPort.getNetworkId()));
-
-            if (osPort.getMacAddress() != null) {
-                sportBuilder.mac(MacAddress.valueOf(osPort.getMacAddress()));
-            }
-            if (!osPort.getFixedIps().isEmpty()) {
-                sportBuilder.ip(IpAddress.valueOf(
-                        osPort.getFixedIps().iterator().next().getIpAddress()));
-            }
-            ServicePort sport = sportBuilder.build();
-            if (snetService.servicePort(sport.id()) != null) {
-                snetService.updateServicePort(sport);
-            } else {
-                snetService.createServicePort(sport);
-            }
-            ServicePort updated = snetService.servicePort(sport.id());
-            List<String> floatingIps = updated.addressPairs().stream()
-                    .map(ip -> ip.ip().toString())
-                    .collect(Collectors.toList());
-            print(PORT_FORMAT, updated.id(),
-                    updated.name(),
-                    updated.mac(),
-                    updated.ip(),
-                    updated.vlanId() != null ? updated.vlanId() : "",
-                    floatingIps.isEmpty() ? "" : floatingIps);
-        });
     }
 }
diff --git a/src/main/java/org/opencord/cordvtn/cli/CordVtnSyncXosStatesCommand.java b/src/main/java/org/opencord/cordvtn/cli/CordVtnSyncXosStatesCommand.java
index 687c1a4..4b747b8 100644
--- a/src/main/java/org/opencord/cordvtn/cli/CordVtnSyncXosStatesCommand.java
+++ b/src/main/java/org/opencord/cordvtn/cli/CordVtnSyncXosStatesCommand.java
@@ -17,8 +17,9 @@
 
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
 import org.onosproject.cli.AbstractShellCommand;
-import org.opencord.cordvtn.rest.XosVtnNetworkingClient;
+import org.opencord.cordvtn.api.core.ServiceNetworkAdminService;
 
 /**
  * Synchronizes network states with XOS VTN service.
@@ -29,6 +30,10 @@
         description = "Synchronizes network states with XOS")
 public class CordVtnSyncXosStatesCommand extends AbstractShellCommand {
 
+    @Option(name = "-c", aliases = "--config", description = "Use connection values from config",
+            required = false, multiValued = false)
+    private boolean config = false;
+
     @Argument(index = 0, name = "endpoint", description = "XOS VTN service endpoint",
             required = true, multiValued = false)
     private String endpoint = null;
@@ -43,13 +48,12 @@
 
     @Override
     protected void execute() {
-        XosVtnNetworkingClient client = XosVtnNetworkingClient.builder()
-                .endpoint(endpoint)
-                .user(user)
-                .password(password)
-                .build();
-
         print("Requesting state synchronization");
-        client.requestSync();
+        ServiceNetworkAdminService snService = get(ServiceNetworkAdminService.class);
+        if (config) {
+            snService.syncXosState();
+        } else {
+            snService.syncXosState(endpoint, user, password);
+        }
     }
 }
diff --git a/src/main/java/org/opencord/cordvtn/impl/ServiceNetworkManager.java b/src/main/java/org/opencord/cordvtn/impl/ServiceNetworkManager.java
index 3bb305d..69b6fcb 100644
--- a/src/main/java/org/opencord/cordvtn/impl/ServiceNetworkManager.java
+++ b/src/main/java/org/opencord/cordvtn/impl/ServiceNetworkManager.java
@@ -23,6 +23,9 @@
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.event.ListenerRegistry;
@@ -42,9 +45,15 @@
 import org.opencord.cordvtn.api.core.ServiceNetworkStoreDelegate;
 import org.opencord.cordvtn.api.net.NetworkId;
 import org.opencord.cordvtn.api.net.PortId;
+import org.opencord.cordvtn.api.net.SegmentId;
 import org.opencord.cordvtn.api.net.ServiceNetwork;
 import org.opencord.cordvtn.api.net.ServiceNetwork.DependencyType;
 import org.opencord.cordvtn.api.net.ServicePort;
+import org.opencord.cordvtn.rest.XosVtnNetworkingClient;
+import org.openstack4j.api.OSClient;
+import org.openstack4j.api.exceptions.AuthenticationException;
+import org.openstack4j.model.identity.Access;
+import org.openstack4j.openstack.OSFactory;
 import org.slf4j.Logger;
 
 import java.util.Map;
@@ -95,6 +104,8 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ServiceNetworkStore snetStore;
 
+    private ApplicationId appId;
+
     // TODO add cordvtn config service and move this
     private static final Class<CordVtnConfig> CONFIG_CLASS = CordVtnConfig.class;
     private final ConfigFactory configFactory =
@@ -110,7 +121,7 @@
 
     @Activate
     protected void activate() {
-        coreService.registerApplication(Constants.CORDVTN_APP_ID);
+        appId = coreService.registerApplication(Constants.CORDVTN_APP_ID);
         configRegistry.registerConfigFactory(configFactory);
         snetStore.setDelegate(delegate);
         log.info("Started");
@@ -129,6 +140,104 @@
     }
 
     @Override
+    public void syncXosState() {
+        CordVtnConfig config = configRegistry.getConfig(appId, CONFIG_CLASS);
+        if (config == null) {
+            return;
+        }
+        syncXosState(config.getXosEndpoint(), config.getXosUsername(), config.getXosPassword());
+    }
+
+    @Override
+    public void syncXosState(String endpoint, String user, String password) {
+        checkNotNull(endpoint);
+        checkNotNull(user);
+        checkNotNull(password);
+
+        XosVtnNetworkingClient client = XosVtnNetworkingClient.builder()
+                .endpoint(endpoint)
+                .user(user)
+                .password(password)
+                .build();
+
+        client.requestSync();
+    }
+
+    @Override
+    public void syncNeutronState() {
+        CordVtnConfig config = configRegistry.getConfig(appId, CONFIG_CLASS);
+        if (config == null) {
+            return;
+        }
+        syncNeutronState(config.getOpenstackEndpoint(), config.getOpenstackTenant(),
+                config.getOpenstackUser(), config.getOpenstackPassword());
+    }
+
+    @Override
+    public void syncNeutronState(String endpoint, String tenant, String user, String password) {
+        Access osAccess;
+        try {
+            osAccess = OSFactory.builder()
+                    .endpoint(endpoint)
+                    .tenantName(tenant)
+                    .credentials(user, password)
+                    .authenticate()
+                    .getAccess();
+        } catch (AuthenticationException e) {
+            log.warn("Authentication failed");
+            return;
+        } catch (Exception e) {
+            log.warn("OpenStack service endpoint is unreachable");
+            return;
+        }
+
+        OSClient osClient = OSFactory.clientFromAccess(osAccess);
+        osClient.networking().network().list().forEach(osNet -> {
+            ServiceNetwork snet = DefaultServiceNetwork.builder()
+                    .id(NetworkId.of(osNet.getId()))
+                    .name(osNet.getName())
+                    .type(ServiceNetwork.NetworkType.PRIVATE)
+                    .segmentId(SegmentId.of(Long.valueOf(osNet.getProviderSegID())))
+                    .build();
+            if (serviceNetwork(snet.id()) != null) {
+                updateServiceNetwork(snet);
+            } else {
+                createServiceNetwork(snet);
+            }
+        });
+
+        osClient.networking().subnet().list().forEach(osSubnet -> {
+            ServiceNetwork snet = DefaultServiceNetwork.builder()
+                    .id(NetworkId.of(osSubnet.getNetworkId()))
+                    .subnet(IpPrefix.valueOf(osSubnet.getCidr()))
+                    .serviceIp(IpAddress.valueOf(osSubnet.getGateway()))
+                    .build();
+            updateServiceNetwork(snet);
+        });
+
+        osClient.networking().port().list().forEach(osPort -> {
+            ServicePort.Builder sportBuilder = DefaultServicePort.builder()
+                    .id(PortId.of(osPort.getId()))
+                    .name("tap" + osPort.getId().substring(0, 11))
+                    .networkId(NetworkId.of(osPort.getNetworkId()));
+
+            if (osPort.getMacAddress() != null) {
+                sportBuilder.mac(MacAddress.valueOf(osPort.getMacAddress()));
+            }
+            if (!osPort.getFixedIps().isEmpty()) {
+                sportBuilder.ip(IpAddress.valueOf(
+                        osPort.getFixedIps().iterator().next().getIpAddress()));
+            }
+            ServicePort sport = sportBuilder.build();
+            if (servicePort(sport.id()) != null) {
+                updateServicePort(sport);
+            } else {
+                createServicePort(sport);
+            }
+        });
+    }
+
+    @Override
     public ServiceNetwork serviceNetwork(NetworkId netId) {
         checkNotNull(netId, ERR_NULL_SERVICE_NET_ID);
         return snetStore.serviceNetwork(netId);