Use openstack4j for OpenStack data model and rest client

Change-Id: I4eb52c3c82d847c442420d1287392fe9079bf699
diff --git a/src/main/java/org/onosproject/cordvtn/impl/CordVtn.java b/src/main/java/org/onosproject/cordvtn/impl/CordVtn.java
index 967ca02..24f650d 100644
--- a/src/main/java/org/onosproject/cordvtn/impl/CordVtn.java
+++ b/src/main/java/org/onosproject/cordvtn/impl/CordVtn.java
@@ -67,10 +67,13 @@
 import org.onosproject.net.packet.PacketService;
 import org.onosproject.net.provider.AbstractProvider;
 import org.onosproject.net.provider.ProviderId;
-import org.onosproject.openstackinterface.OpenstackInterfaceService;
-import org.onosproject.openstackinterface.OpenstackNetwork;
-import org.onosproject.openstackinterface.OpenstackPort;
-import org.onosproject.openstackinterface.OpenstackSubnet;
+
+import org.openstack4j.api.OSClient;
+import org.openstack4j.api.exceptions.AuthenticationException;
+import org.openstack4j.model.identity.Access;
+import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.Subnet;
+import org.openstack4j.openstack.OSFactory;
 import org.slf4j.Logger;
 
 import java.util.List;
@@ -130,9 +133,6 @@
     protected GroupService groupService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected OpenstackInterfaceService openstackService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DhcpService dhcpService;
 
     private final ConfigFactory configFactory =
@@ -165,6 +165,8 @@
     private HostProviderService hostProvider;
     private CordVtnRuleInstaller ruleInstaller;
     private CordVtnArpProxy arpProxy;
+
+    private volatile Access osAccess = null;
     private volatile MacAddress privateGatewayMac = MacAddress.NONE;
 
     /**
@@ -250,20 +252,26 @@
 
     @Override
     public void addServiceVm(CordVtnNode node, ConnectPoint connectPoint) {
+        checkNotNull(osAccess, "OpenStack access is not set");
+
+        OSClient osClient = OSFactory.clientFromAccess(osAccess);
         Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port());
-        OpenstackPort vPort = openstackService.port(port);
-        if (vPort == null) {
-            log.warn("Failed to get OpenstackPort for {}", getPortName(port));
+        org.openstack4j.model.network.Port osPort = osClient.networking().port().list()
+                .stream()
+                .filter(p -> p.getId().contains(getPortName(port).substring(3)))
+                .findFirst().orElse(null);
+        if (osPort == null) {
+            log.warn("Failed to get OpenStack port for {}", getPortName(port));
             return;
         }
 
-        MacAddress mac = vPort.macAddress();
+        MacAddress mac = MacAddress.valueOf(osPort.getMacAddress());
         HostId hostId = HostId.hostId(mac);
 
         Host existingHost = hostService.getHost(hostId);
         if (existingHost != null) {
             String serviceId = existingHost.annotations().value(SERVICE_ID);
-            if (serviceId == null || !serviceId.equals(vPort.networkId())) {
+            if (serviceId == null || !serviceId.equals(osPort.getNetworkId())) {
                 // this host is not injected by cordvtn or a stale host, remove it
                 hostProvider.hostVanished(existingHost.id());
             }
@@ -273,15 +281,18 @@
         // event so that the flow rule population for this host can happen.
         // This ensures refreshing data plane by pushing network config always make
         // the data plane synced.
-        Set<IpAddress> fixedIp = Sets.newHashSet(vPort.fixedIps().values());
+        Set<IpAddress> fixedIps = osPort.getFixedIps().stream()
+                .map(ip -> IpAddress.valueOf(ip.getIpAddress()))
+                .collect(Collectors.toSet());
+
         DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
-                .set(SERVICE_ID, vPort.networkId())
-                .set(OPENSTACK_PORT_ID, vPort.id())
+                .set(SERVICE_ID, osPort.getNetworkId())
+                .set(OPENSTACK_PORT_ID, osPort.getId())
                 .set(DATA_PLANE_IP, node.dpIp().ip().toString())
                 .set(DATA_PLANE_INTF, node.dpIntf())
                 .set(CREATED_TIME, String.valueOf(System.currentTimeMillis()));
 
-        String serviceVlan = getServiceVlan(vPort);
+        String serviceVlan = getServiceVlan(osPort);
         if (serviceVlan != null) {
             annotations.set(S_TAG, serviceVlan);
         }
@@ -290,7 +301,7 @@
                 mac,
                 VlanId.NONE,
                 new HostLocation(connectPoint, System.currentTimeMillis()),
-                fixedIp,
+                fixedIps,
                 annotations.build());
 
         hostProvider.hostDetected(hostId, hostDesc, false);
@@ -365,21 +376,30 @@
      * @return map of ip and mac address, or empty map
      */
     private Map<IpAddress, MacAddress> getSubscriberGateways(Host vSgHost) {
-        String vPortId = vSgHost.annotations().value(OPENSTACK_PORT_ID);
+        checkNotNull(osAccess, "OpenStack access is not set");
+
+        String osPortId = vSgHost.annotations().value(OPENSTACK_PORT_ID);
         String serviceVlan = vSgHost.annotations().value(S_TAG);
 
-        OpenstackPort vPort = openstackService.port(vPortId);
-        if (vPort == null) {
-            log.warn("Failed to get OpenStack port {} for VM {}", vPortId, vSgHost.id());
+        OSClient osClient = OSFactory.clientFromAccess(osAccess);
+        org.openstack4j.model.network.Port osPort = osClient.networking().port().get(osPortId);
+        if (osPort == null) {
+            log.warn("Failed to get OpenStack port {} for VM {}", osPortId, vSgHost.id());
             return Maps.newHashMap();
         }
 
-        if (!serviceVlan.equals(getServiceVlan(vPort))) {
-            log.error("Host({}) s-tag does not match with vPort s-tag", vSgHost.id());
+        if (!serviceVlan.equals(getServiceVlan(osPort))) {
+            log.error("Host({}) s-tag does not match with OpenStack port s-tag", vSgHost.id());
             return Maps.newHashMap();
         }
 
-        return vPort.allowedAddressPairs();
+        Map<IpAddress, MacAddress> addressPairs = Maps.newHashMap();
+        osPort.getAllowedAddressPairs()
+                .stream().forEach(p -> addressPairs.put(
+                IpAddress.valueOf(p.getIpAddress()),
+                MacAddress.valueOf(p.getMacAddress())));
+
+        return addressPairs;
     }
 
     /**
@@ -389,16 +409,20 @@
      * @return cord service, or null if it fails to get network from OpenStack
      */
     private CordService getCordService(CordServiceId serviceId) {
-        OpenstackNetwork vNet = openstackService.network(serviceId.id());
-        if (vNet == null) {
+        checkNotNull(osAccess, "OpenStack access is not set");
+
+        OSClient osClient = OSFactory.clientFromAccess(osAccess);
+        Network osNet = osClient.networking().network().get(serviceId.id());
+        if (osNet == null) {
             log.warn("Couldn't find OpenStack network for service {}", serviceId.id());
             return null;
         }
 
-        OpenstackSubnet subnet = vNet.subnets().stream()
+        // here it assumes all cord service networks has only one subnet
+        Subnet osSubnet = osNet.getNeutronSubnets().stream()
                 .findFirst()
                 .orElse(null);
-        if (subnet == null) {
+        if (osSubnet == null) {
             log.warn("Couldn't find OpenStack subnet for service {}", serviceId.id());
             return null;
         }
@@ -406,39 +430,40 @@
         Set<CordServiceId> tServices = Sets.newHashSet();
         // TODO get tenant services from XOS
 
-        Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet)
+        Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(osNet)
                 .stream()
                 .collect(Collectors.toMap(host -> host, this::getTunnelIp));
 
-        return new CordService(vNet, subnet, hosts, tServices);
+        return new CordService(osNet, osSubnet, hosts, tServices);
     }
 
     /**
      * Returns CordService by OpenStack network.
      *
-     * @param vNet OpenStack network
+     * @param osNet OpenStack network
      * @return cord service
      */
-    private CordService getCordService(OpenstackNetwork vNet) {
-        checkNotNull(vNet);
+    private CordService getCordService(Network osNet) {
+        checkNotNull(osNet);
 
-        CordServiceId serviceId = CordServiceId.of(vNet.id());
-        OpenstackSubnet subnet = vNet.subnets().stream()
+        CordServiceId serviceId = CordServiceId.of(osNet.getId());
+        // here it assumes all cord service networks has only one subnet
+        Subnet osSubnet = osNet.getNeutronSubnets().stream()
                 .findFirst()
                 .orElse(null);
-        if (subnet == null) {
-            log.warn("Couldn't find OpenStack subnet for service {}", serviceId);
+        if (osSubnet == null) {
+            log.warn("Couldn't find OpenStack subnet for service {}", serviceId.id());
             return null;
         }
 
         Set<CordServiceId> tServices = Sets.newHashSet();
         // TODO get tenant services from XOS
 
-        Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet)
+        Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(osNet)
                 .stream()
                 .collect(Collectors.toMap(host -> host, this::getTunnelIp));
 
-        return new CordService(vNet, subnet, hosts, tServices);
+        return new CordService(osNet, osSubnet, hosts, tServices);
     }
 
     /**
@@ -465,14 +490,15 @@
     /**
      * Returns s-tag from a given OpenStack port.
      *
-     * @param vPort openstack port
+     * @param osPort openstack port
      * @return s-tag string
      */
-    private String getServiceVlan(OpenstackPort vPort) {
-        checkNotNull(vPort);
+    private String getServiceVlan(org.openstack4j.model.network.Port osPort) {
+        checkNotNull(osPort);
 
-        if (vPort.name() != null && vPort.name().startsWith(S_TAG)) {
-            return vPort.name().split("-")[1];
+        String portName = osPort.getName();
+        if (portName != null && portName.startsWith(S_TAG)) {
+            return portName.split("-")[1];
         } else {
             return null;
         }
@@ -491,15 +517,15 @@
     /**
      * Returns hosts associated with a given OpenStack network.
      *
-     * @param vNet openstack network
+     * @param osNet openstack network
      * @return set of hosts
      */
-    private Set<Host> getHostsWithOpenstackNetwork(OpenstackNetwork vNet) {
-        checkNotNull(vNet);
+    private Set<Host> getHostsWithOpenstackNetwork(Network osNet) {
+        checkNotNull(osNet);
 
-        String vNetId = vNet.id();
+        String osNetId = osNet.getId();
         return StreamSupport.stream(hostService.getHosts().spliterator(), false)
-                .filter(host -> Objects.equals(vNetId, getServiceId(host)))
+                .filter(host -> Objects.equals(osNetId, getServiceId(host)))
                 .collect(Collectors.toSet());
     }
 
@@ -529,21 +555,24 @@
      * @param host host
      */
     private void serviceVmAdded(Host host) {
+        checkNotNull(osAccess, "OpenStack access is not set");
+
         String serviceVlan = host.annotations().value(S_TAG);
         if (serviceVlan != null) {
             virtualSubscriberGatewayAdded(host, serviceVlan);
         }
 
-        String vNetId = host.annotations().value(SERVICE_ID);
-        if (vNetId == null) {
+        String osNetId = host.annotations().value(SERVICE_ID);
+        if (osNetId == null) {
             // ignore this host, it is not the service VM, or it's a vSG
             return;
         }
 
-        OpenstackNetwork vNet = openstackService.network(vNetId);
-        if (vNet == null) {
+        OSClient osClient = OSFactory.clientFromAccess(osAccess);
+        Network osNet = osClient.networking().network().get(osNetId);
+        if (osNet == null) {
             log.warn("Failed to get OpenStack network {} for VM {}.",
-                     vNetId, host.id());
+                     osNetId, host.id());
             return;
         }
 
@@ -551,7 +580,7 @@
                  host.mac(),
                  host.ipAddresses().stream().findFirst().get());
 
-        CordService service = getCordService(vNet);
+        CordService service = getCordService(osNet);
         if (service == null) {
             return;
         }
@@ -573,7 +602,7 @@
         }
 
         registerDhcpLease(host, service);
-        ruleInstaller.populateBasicConnectionRules(host, getTunnelIp(host), vNet);
+        ruleInstaller.populateBasicConnectionRules(host, getTunnelIp(host), osNet);
     }
 
     /**
@@ -582,21 +611,24 @@
      * @param host host
      */
     private void serviceVmRemoved(Host host) {
+        checkNotNull(osAccess, "OpenStack access is not set");
+
         String serviceVlan = host.annotations().value(S_TAG);
         if (serviceVlan != null) {
             virtualSubscriberGatewayRemoved(host);
         }
 
-        String vNetId = host.annotations().value(SERVICE_ID);
-        if (vNetId == null) {
+        String osNetId = host.annotations().value(SERVICE_ID);
+        if (osNetId == null) {
             // ignore it, it's not the service VM or it's a vSG
             return;
         }
 
-        OpenstackNetwork vNet = openstackService.network(vNetId);
-        if (vNet == null) {
+        OSClient osClient = OSFactory.clientFromAccess(osAccess);
+        Network osNet = osClient.networking().network().get(osNetId);
+        if (osNet == null) {
             log.warn("Failed to get OpenStack network {} for VM {}",
-                     vNetId, host.id());
+                     osNetId, host.id());
             return;
         }
 
@@ -607,7 +639,7 @@
         ruleInstaller.removeBasicConnectionRules(host);
         dhcpService.removeStaticMapping(host.mac());
 
-        CordService service = getCordService(vNet);
+        CordService service = getCordService(osNet);
         if (service == null) {
             return;
         }
@@ -617,7 +649,7 @@
                 ruleInstaller.removeManagementNetworkRules(host, service);
                 break;
             case PRIVATE:
-                if (getHostsWithOpenstackNetwork(vNet).isEmpty()) {
+                if (getHostsWithOpenstackNetwork(osNet).isEmpty()) {
                     arpProxy.removeGateway(service.serviceIp());
                 }
             case PUBLIC:
@@ -723,13 +755,38 @@
                 .stream()
                 .forEach(entry -> {
                     arpProxy.addGateway(entry.getKey(), entry.getValue());
-                    log.info("Added public gateway IP {}, MAC {}",
-                             entry.getKey().toString(), entry.getValue().toString());
+                    log.debug("Added public gateway IP {}, MAC {}",
+                              entry.getKey().toString(), entry.getValue().toString());
                 });
         // TODO notice gateway MAC change to VMs holds this gateway IP
     }
 
     /**
+     * Sets OpenStack access information.
+     * Access is the entity returned when authenticated and provides a singleton client
+     * between multiple threads.
+     *
+     * @param osConfig openstack config
+     */
+    private void setOpenstackAccess(CordVtnConfig.OpenStackConfig osConfig) {
+        log.debug("Get OpenStack access with Endpoint: {} Tenant: {} User: {} Passwd: {}",
+                  osConfig.endpoint(),
+                  osConfig.tenant(),
+                  osConfig.user(),
+                  osConfig.password());
+        try {
+            osAccess = OSFactory.builder()
+                    .endpoint(osConfig.endpoint())
+                    .credentials(osConfig.user(), osConfig.password())
+                    .tenantName(osConfig.tenant())
+                    .authenticate()
+                    .getAccess();
+        } catch (AuthenticationException e) {
+            log.error("Failed to get OpenStack Access");
+        }
+    }
+
+    /**
      * Updates configurations.
      */
     private void readConfiguration() {
@@ -739,9 +796,10 @@
             return;
         }
 
+        setOpenstackAccess(config.openstackConfig());
         setPrivateGatewayMac(config.privateGatewayMac());
         setPublicGatewayMac(config.publicGateways());
-   }
+    }
 
     private class InternalHostListener implements HostListener {