Support openstack controller node status check feature

Change-Id: I285b977ae32dd6d140aca7f25b00962db77b1054
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 9f3f4a7..f21b79b 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
@@ -22,15 +22,10 @@
 import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
 import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
 import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupAdminService;
-import org.onosproject.openstacknode.api.OpenstackAuth;
+import org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil;
 import org.onosproject.openstacknode.api.OpenstackNode;
 import org.onosproject.openstacknode.api.OpenstackNodeService;
 import org.openstack4j.api.OSClient;
-import org.openstack4j.api.client.IOSClientBuilder;
-import org.openstack4j.api.exceptions.AuthenticationException;
-import org.openstack4j.api.types.Facing;
-import org.openstack4j.core.transport.Config;
-import org.openstack4j.model.common.Identifier;
 import org.openstack4j.model.network.IP;
 import org.openstack4j.model.network.NetFloatingIP;
 import org.openstack4j.model.network.Network;
@@ -38,16 +33,9 @@
 import org.openstack4j.model.network.Router;
 import org.openstack4j.model.network.RouterInterface;
 import org.openstack4j.model.network.Subnet;
-import org.openstack4j.openstack.OSFactory;
 import org.openstack4j.openstack.networking.domain.NeutronRouterInterface;
 
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
 import java.io.IOException;
-import java.security.cert.X509Certificate;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
@@ -63,8 +51,6 @@
         description = "Synchronizes all OpenStack network states")
 public class OpenstackSyncStateCommand extends AbstractShellCommand {
 
-    private static final String DOMAIN_DEFUALT = "default";
-
     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";
@@ -75,9 +61,6 @@
     private static final String DEVICE_OWNER_GW = "network:router_gateway";
     private static final String DEVICE_OWNER_IFACE = "network:router_interface";
 
-    private static final String KEYSTONE_V2 = "v2.0";
-    private static final String KEYSTONE_V3 = "v3";
-
     @Override
     protected void execute() {
         OpenstackSecurityGroupAdminService osSgAdminService = get(OpenstackSecurityGroupAdminService.class);
@@ -92,51 +75,9 @@
             return;
         }
 
-        OpenstackAuth auth = node.get().authentication();
-        String endpoint = buildEndpoint(node.get());
-        OpenstackAuth.Perspective perspective = auth.perspective();
+        OSClient osClient = OpenstackNetworkingUtil.getConnectedClient(node.get());
 
-        log.info("Access the ENDPOINT: {}, with AUTH_INFO username: {}, password: {}, project: {}",
-                endpoint, auth.username(), auth.password(), auth.project());
-
-        OSClient osClient;
-        Config config = getSslConfig();
-
-        try {
-            if (endpoint.contains(KEYSTONE_V2)) {
-                IOSClientBuilder.V2 builder = OSFactory.builderV2()
-                        .endpoint(endpoint)
-                        .tenantName(auth.project())
-                        .credentials(auth.username(), auth.password())
-                        .withConfig(config);
-
-                if (perspective != null) {
-                    builder.perspective(getFacing(perspective));
-                }
-
-                osClient = builder.authenticate();
-            } else if (endpoint.contains(KEYSTONE_V3)) {
-
-                Identifier project = Identifier.byName(auth.project());
-                Identifier domain = Identifier.byName(DOMAIN_DEFUALT);
-
-                IOSClientBuilder.V3 builder = OSFactory.builderV3()
-                        .endpoint(endpoint)
-                        .credentials(auth.username(), auth.password(), domain)
-                        .scopeToProject(project, domain)
-                        .withConfig(config);
-
-                if (perspective != null) {
-                    builder.perspective(getFacing(perspective));
-                }
-
-                osClient = builder.authenticate();
-            } else {
-                print("Unrecognized keystone version type");
-                return;
-            }
-        } catch (AuthenticationException e) {
-            print("Authentication failed");
+        if (osClient == null) {
             return;
         }
 
@@ -236,27 +177,6 @@
         });
     }
 
-    private String buildEndpoint(OpenstackNode node) {
-
-        OpenstackAuth auth = node.authentication();
-
-        StringBuilder endpointSb = new StringBuilder();
-        endpointSb.append(auth.protocol().name().toLowerCase());
-        endpointSb.append("://");
-        endpointSb.append(node.endPoint());
-        endpointSb.append(":");
-        endpointSb.append(auth.port());
-        endpointSb.append("/");
-
-        // in case the version is v3, we need to append identity path into endpoint
-        if (auth.version().equals("v3")) {
-            endpointSb.append("identity/");
-        }
-
-        endpointSb.append(auth.version());
-        return endpointSb.toString();
-    }
-
     private void printNetwork(Network osNet) {
         final String strNet = String.format(NETWORK_FORMAT,
                 osNet.getId(),
@@ -317,54 +237,4 @@
                         "" : floatingIp.getFixedIpAddress());
         print(strFloating);
     }
-
-    private Config getSslConfig() {
-        // we bypass the SSL certification verification for now
-        // TODO: verify server side SSL using a given certification
-        Config config = Config.newConfig().withSSLVerificationDisabled();
-
-        TrustManager[] trustAllCerts = new TrustManager[]{
-                new X509TrustManager() {
-                    public X509Certificate[] getAcceptedIssuers() {
-                        return null;
-                    }
-
-                    public void checkClientTrusted(X509Certificate[] certs, String authType) {
-                    }
-
-                    public void checkServerTrusted(X509Certificate[] certs, String authType) {
-                    }
-                }
-        };
-
-        HostnameVerifier allHostsValid = (hostname, session) -> true;
-
-        try {
-            SSLContext sc = SSLContext.getInstance("SSL");
-            sc.init(null, trustAllCerts, new java.security.SecureRandom());
-            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
-            HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
-
-            config.withSSLContext(sc);
-        } catch (Exception e) {
-            print("Failed to access OpenStack service");
-            return null;
-        }
-
-        return config;
-    }
-
-    private Facing getFacing(OpenstackAuth.Perspective perspective) {
-
-        switch (perspective) {
-            case PUBLIC:
-                return Facing.PUBLIC;
-            case ADMIN:
-                return Facing.ADMIN;
-            case INTERNAL:
-                return Facing.INTERNAL;
-            default:
-                return null;
-        }
-    }
 }
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
index 2919072..0319d40 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
@@ -701,7 +701,7 @@
         public boolean isRelevant(OpenstackNodeEvent event) {
             // do not allow to proceed without leadership
             NodeId leader = leadershipService.getLeader(appId.name());
-            return Objects.equals(localNodeId, leader);
+            return Objects.equals(localNodeId, leader) && event.subject().type() == GATEWAY;
         }
 
         @Override
@@ -709,17 +709,13 @@
             OpenstackNode osNode = event.subject();
             switch (event.type()) {
                 case OPENSTACK_NODE_COMPLETE:
-                    if (osNode.type().equals(GATEWAY)) {
-                        setDefaultArpRule(osNode, true);
-                        setFloatingIpArpRuleForGateway(osNode, true);
-                    }
+                    setDefaultArpRule(osNode, true);
+                    setFloatingIpArpRuleForGateway(osNode, true);
 
                     break;
                 case OPENSTACK_NODE_INCOMPLETE:
-                    if (osNode.type().equals(GATEWAY)) {
-                        setDefaultArpRule(osNode, false);
-                        setFloatingIpArpRuleForGateway(osNode, false);
-                    }
+                    setDefaultArpRule(osNode, false);
+                    setFloatingIpArpRuleForGateway(osNode, false);
                     break;
                 default:
                     break;
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
index ee8688d..dda949f 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
@@ -698,13 +698,6 @@
                     });
                     break;
                 case OPENSTACK_NODE_INCOMPLETE:
-
-                    // we only purge the routing related rules stored in each
-                    // compute node when gateway node becomes unavailable
-                    if (!event.subject().type().equals(GATEWAY))  {
-                        return;
-                    }
-
                     eventExecutor.execute(() -> {
                         for (NetFloatingIP fip : osRouterService.floatingIps()) {
                             if (Strings.isNullOrEmpty(fip.getPortId())) {
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
index 32c6785..f6b8e50 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
@@ -424,7 +424,7 @@
         public boolean isRelevant(OpenstackNodeEvent event) {
             // do not allow to proceed without leadership
             NodeId leader = leadershipService.getLeader(appId.name());
-            return Objects.equals(localNodeId, leader);
+            return Objects.equals(localNodeId, leader) && event.subject().type() == COMPUTE;
         }
 
         @Override
@@ -432,14 +432,10 @@
             OpenstackNode osNode = event.subject();
             switch (event.type()) {
                 case OPENSTACK_NODE_COMPLETE:
-                    if (osNode.type().equals(COMPUTE)) {
-                        setDefaultArpRule(osNode, true);
-                    }
+                    setDefaultArpRule(osNode, true);
                     break;
                 case OPENSTACK_NODE_INCOMPLETE:
-                    if (osNode.type().equals(COMPUTE)) {
-                        setDefaultArpRule(osNode, false);
-                    }
+                    setDefaultArpRule(osNode, false);
                     break;
                 default:
                     break;
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java
index 65afbf8..2cc9671 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java
@@ -82,7 +82,7 @@
 import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC_STR;
 import static org.onosproject.openstacknetworking.api.Constants.DHCP_ARP_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_DHCP_RULE;
-import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
+import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -420,7 +420,7 @@
         public boolean isRelevant(OpenstackNodeEvent event) {
             // do not allow to proceed without leadership
             NodeId leader = leadershipService.getLeader(appId.name());
-            return Objects.equals(localNodeId, leader);
+            return Objects.equals(localNodeId, leader) && event.subject().type() == COMPUTE;
         }
 
         @Override
@@ -442,9 +442,6 @@
         }
 
         private void setDhcpRule(OpenstackNode openstackNode, boolean install) {
-            if (openstackNode.type().equals(GATEWAY)) {
-                return;
-            }
             TrafficSelector selector = DefaultTrafficSelector.builder()
                     .matchEthType(Ethernet.TYPE_IPV4)
                     .matchIPProtocol(IPv4.PROTOCOL_UDP)
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
index 538a5fd..e7492bf 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
@@ -68,6 +68,7 @@
 import static org.onosproject.openstacknetworking.impl.HostBasedInstancePort.ANNOTATION_CREATE_TIME;
 import static org.onosproject.openstacknetworking.impl.HostBasedInstancePort.ANNOTATION_NETWORK_ID;
 import static org.onosproject.openstacknetworking.impl.HostBasedInstancePort.ANNOTATION_PORT_ID;
+import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
 
 @Service
 @Component(immediate = true)
@@ -297,6 +298,10 @@
 
         @Override
         public boolean isRelevant(OpenstackNodeEvent event) {
+
+            if (event.subject().type() == CONTROLLER) {
+                return false;
+            }
             // do not allow to proceed without mastership
             Device device = deviceService.getDevice(event.subject().intgBridge());
             if (device == null) {
@@ -325,7 +330,6 @@
                     // not reacts to the events other than complete and incomplete states
                     break;
                 default:
-                    log.warn("Unsupported openstack node event type");
                     break;
             }
         }
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 7111820..58f3c33 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
@@ -19,14 +19,29 @@
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.onosproject.net.DeviceId;
+import org.onosproject.openstacknode.api.OpenstackAuth;
+import org.onosproject.openstacknode.api.OpenstackAuth.Perspective;
 import org.onosproject.openstacknode.api.OpenstackNode;
+import org.openstack4j.api.OSClient;
+import org.openstack4j.api.client.IOSClientBuilder;
+import org.openstack4j.api.exceptions.AuthenticationException;
+import org.openstack4j.api.types.Facing;
+import org.openstack4j.core.transport.Config;
 import org.openstack4j.core.transport.ObjectMapperSingleton;
 import org.openstack4j.model.ModelEntity;
 import org.openstack4j.model.network.Port;
+import org.openstack4j.model.common.Identifier;
+import org.openstack4j.openstack.OSFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
 import java.io.InputStream;
+import java.security.cert.X509Certificate;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
@@ -46,10 +61,17 @@
     protected static final Logger log = LoggerFactory.getLogger(OpenstackNetworkingUtil.class);
 
     private static final int HEX_RADIX = 16;
-    private static final int ZERO_FUNCTION_NUMBER = 0;
+    private static final String ZERO_FUNCTION_NUMBER = "0";
     private static final String PREFIX_DEVICE_NUMBER = "s";
     private static final String PREFIX_FUNCTION_NUMBER = "f";
 
+    // keystone endpoint related variables
+    private static final String DOMAIN_DEFAULT = "default";
+    private static final String KEYSTONE_V2 = "v2.0";
+    private static final String KEYSTONE_V3 = "v3";
+    private static final String IDENTITY_PATH = "identity/";
+    private static final String SSL_TYPE = "SSL";
+
     /**
      * Prevents object instantiation from external.
      */
@@ -116,23 +138,56 @@
         return getGwByIndex(gws, gwIndex);
     }
 
-    private static OpenstackNode getGwByIndex(Set<OpenstackNode> gws, int index) {
-        Map<String, OpenstackNode> hashMap = new HashMap<>();
-        gws.forEach(gw -> hashMap.put(gw.hostname(), gw));
-        TreeMap<String, OpenstackNode> treeMap = new TreeMap<>(hashMap);
-        Iterator<String> iteratorKey = treeMap.keySet().iterator();
+    /**
+     * Obtains a connected openstack client.
+     *
+     * @param osNode openstack node
+     * @return a connected openstack client
+     */
+    public static OSClient getConnectedClient(OpenstackNode osNode) {
+        OpenstackAuth auth = osNode.authentication();
+        String endpoint = buildEndpoint(osNode);
+        Perspective perspective = auth.perspective();
 
-        int intIndex = 0;
-        OpenstackNode gw = null;
-        while (iteratorKey.hasNext()) {
-            String key = iteratorKey.next();
+        Config config = getSslConfig();
 
-            if (intIndex == index) {
-                gw = treeMap.get(key);
+        try {
+            if (endpoint.contains(KEYSTONE_V2)) {
+                IOSClientBuilder.V2 builder = OSFactory.builderV2()
+                        .endpoint(endpoint)
+                        .tenantName(auth.project())
+                        .credentials(auth.username(), auth.password())
+                        .withConfig(config);
+
+                if (perspective != null) {
+                    builder.perspective(getFacing(perspective));
+                }
+
+                return builder.authenticate();
+            } else if (endpoint.contains(KEYSTONE_V3)) {
+
+                Identifier project = Identifier.byName(auth.project());
+                Identifier domain = Identifier.byName(DOMAIN_DEFAULT);
+
+                IOSClientBuilder.V3 builder = OSFactory.builderV3()
+                        .endpoint(endpoint)
+                        .credentials(auth.username(), auth.password(), domain)
+                        .scopeToProject(project, domain)
+                        .withConfig(config);
+
+                if (perspective != null) {
+                    builder.perspective(getFacing(perspective));
+                }
+
+                return builder.authenticate();
+            } else {
+                log.warn("Unrecognized keystone version type");
+                return null;
             }
-            intIndex++;
+        } catch (AuthenticationException e) {
+            log.error("Authentication failed due to {}", e.toString());
+            return null;
         }
-        return gw;
     }
 
     /**
@@ -142,10 +197,17 @@
      * @return interface name
      */
     public static String getIntfNameFromPciAddress(Port port) {
+
+        if (port.getProfile() == null) {
+            log.error("Port profile is not found");
+            return null;
+        }
+
         if (port.getProfile() != null && port.getProfile().get(PCISLOT) == null) {
             log.error("Failed to retrieve the interface name because of no pci_slot information from the port");
             return null;
         }
+
         String busNumHex = port.getProfile().get(PCISLOT).toString().split(":")[1];
         String busNumDecimal = String.valueOf(Integer.parseInt(busNumHex, HEX_RADIX));
 
@@ -168,10 +230,7 @@
             return null;
         }
         String portNamePrefix = PORT_NAME_PREFIX_MAP.get(vendorInfoForPort);
-        if (vendorInfoForPort == null) {
-            log.error("Failed to retrieve the interface name because of no prefix information from the port");
-            return null;
-        }
+
         if (functionNumDecimal.equals(ZERO_FUNCTION_NUMBER)) {
             intfName = portNamePrefix + busNumDecimal + PREFIX_DEVICE_NUMBER + deviceNumDecimal;
         } else {
@@ -181,4 +240,121 @@
 
         return intfName;
     }
+
+    /**
+     * Builds up and a complete endpoint URL from gateway node.
+     *
+     * @param node gateway node
+     * @return a complete endpoint URL
+     */
+    private static String buildEndpoint(OpenstackNode node) {
+
+        OpenstackAuth auth = node.authentication();
+
+        StringBuilder endpointSb = new StringBuilder();
+        endpointSb.append(auth.protocol().name().toLowerCase());
+        endpointSb.append("://");
+        endpointSb.append(node.endPoint());
+        endpointSb.append(":");
+        endpointSb.append(auth.port());
+        endpointSb.append("/");
+
+        // in case the version is v3, we need to append identity path into endpoint
+        if (auth.version().equals(KEYSTONE_V3)) {
+            endpointSb.append(IDENTITY_PATH);
+        }
+
+        endpointSb.append(auth.version());
+        return endpointSb.toString();
+    }
+
+    /**
+     * Obtains the SSL config without verifying the certification.
+     *
+     * @return SSL config
+     */
+    private static Config getSslConfig() {
+        // we bypass the SSL certification verification for now
+        // TODO: verify server side SSL using a given certification
+        Config config = Config.newConfig().withSSLVerificationDisabled();
+
+        TrustManager[] trustAllCerts = new TrustManager[]{
+                new X509TrustManager() {
+                    public X509Certificate[] getAcceptedIssuers() {
+                        return null;
+                    }
+
+                    public void checkClientTrusted(X509Certificate[] certs,
+                                                   String authType) {
+                    }
+
+                    public void checkServerTrusted(X509Certificate[] certs,
+                                                   String authType) {
+                    }
+                }
+        };
+
+        HostnameVerifier allHostsValid = (hostname, session) -> true;
+
+        try {
+            SSLContext sc = SSLContext.getInstance(SSL_TYPE);
+            sc.init(null, trustAllCerts,
+                    new java.security.SecureRandom());
+            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+            HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
+
+            config.withSSLContext(sc);
+        } catch (Exception e) {
+            log.error("Failed to access OpenStack service due to {}", e.toString());
+            return null;
+        }
+
+        return config;
+    }
+
+    /**
+     * Obtains the facing object with given openstack perspective.
+     *
+     * @param perspective keystone perspective
+     * @return facing object
+     */
+    private static Facing getFacing(Perspective perspective) {
+
+        switch (perspective) {
+            case PUBLIC:
+                return Facing.PUBLIC;
+            case ADMIN:
+                return Facing.ADMIN;
+            case INTERNAL:
+                return Facing.INTERNAL;
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * Obtains gateway instance by giving index number.
+     *
+     * @param gws       a collection of gateway nodes
+     * @param index     index number
+     * @return gateway instance
+     */
+    private static OpenstackNode getGwByIndex(Set<OpenstackNode> gws, int index) {
+        Map<String, OpenstackNode> hashMap = new HashMap<>();
+        gws.forEach(gw -> hashMap.put(gw.hostname(), gw));
+        TreeMap<String, OpenstackNode> treeMap = new TreeMap<>(hashMap);
+        Iterator<String> iteratorKey = treeMap.keySet().iterator();
+
+        int intIndex = 0;
+        OpenstackNode gw = null;
+        while (iteratorKey.hasNext()) {
+            String key = iteratorKey.next();
+
+            if (intIndex == index) {
+                gw = treeMap.get(key);
+            }
+            intIndex++;
+        }
+        return gw;
+    }
 }
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/package-info.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/package-info.java
index 4b6cfb8..8d590eb 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/package-info.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/package-info.java
@@ -15,6 +15,6 @@
  */
 
 /**
- * Openstack utility package.
+ * Openstack networking utility package.
  */
 package org.onosproject.openstacknetworking.util;
\ No newline at end of file
diff --git a/apps/openstacknode/api/BUCK b/apps/openstacknode/api/BUCK
index 1099c27..4f335f3 100644
--- a/apps/openstacknode/api/BUCK
+++ b/apps/openstacknode/api/BUCK
@@ -1,3 +1,5 @@
+include_defs('//apps/openstacknetworking/openstack4j.bucklet')
+
 COMPILE_DEPS = [
     '//lib:CORE_DEPS',
     '//lib:org.apache.karaf.shell.console',
@@ -15,5 +17,7 @@
 
 osgi_jar_with_tests (
     deps = COMPILE_DEPS,
-    test_deps = TEST_DEPS
+    test_deps = TEST_DEPS,
+
+    import_packages = INCLUDE_PACKAGES + ',' + EXCLUDE_PACKAGES  + ',' + ALL_PACKAGES,
 )
diff --git a/apps/openstacknode/api/pom.xml b/apps/openstacknode/api/pom.xml
index cd9bbca..a08e109 100644
--- a/apps/openstacknode/api/pom.xml
+++ b/apps/openstacknode/api/pom.xml
@@ -35,5 +35,32 @@
             <groupId>org.onosproject</groupId>
             <artifactId>onos-api</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>org.pacesys</groupId>
+            <artifactId>openstack4j-core</artifactId>
+            <version>${openstack4j.version}</version>
+        </dependency>
     </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>
+                            ${project.groupId}.${project.artifactId}
+                        </Bundle-SymbolicName>
+                        <Import-Package>
+                            !org.openstack4j.*,
+                            *
+                        </Import-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
 </project>
diff --git a/apps/openstacknode/app/BUCK b/apps/openstacknode/app/BUCK
index 4612f6a..a80ba98 100644
--- a/apps/openstacknode/app/BUCK
+++ b/apps/openstacknode/app/BUCK
@@ -1,3 +1,5 @@
+include_defs('//apps/openstacknode/openstack4j.bucklet')
+
 COMPILE_DEPS = [
     '//lib:CORE_DEPS',
     '//lib:JACKSON',
@@ -10,6 +12,14 @@
     '//protocols/ovsdb/rfc:onos-protocols-ovsdb-rfc',
     '//core/store/serializers:onos-core-serializers',
     '//apps/openstacknode/api:onos-apps-openstacknode-api',
+    '//lib:openstack4j-core',
+    '//lib:openstack4j-http-connector',
+    '//lib:openstack4j-httpclient',
+    '//lib:json-patch',
+    '//lib:jackson-coreutils',
+    '//lib:btf',
+    '//lib:msg-simple',
+    '//lib:snakeyaml',
 ]
 
 TEST_DEPS = [
@@ -28,5 +38,9 @@
     api_version = '1.0',
     api_description = 'REST API for OpenStack Node',
     api_package = 'org.onosproject.openstacknode.web',
+
+    # dependency embedding
+    import_packages = INCLUDE_PACKAGES + ',' + EXCLUDE_PACKAGES  + ',' + ALL_PACKAGES,
+    bundle_classpath = get_openstack4j_deps_path() + get_jackson_deps_path()
 )
 
diff --git a/apps/openstacknode/app/pom.xml b/apps/openstacknode/app/pom.xml
index 5d2ff79..401824f 100644
--- a/apps/openstacknode/app/pom.xml
+++ b/apps/openstacknode/app/pom.xml
@@ -132,6 +132,47 @@
         </dependency>
 
         <dependency>
+            <groupId>org.pacesys</groupId>
+            <artifactId>openstack4j-core</artifactId>
+            <version>${openstack4j.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.pacesys.openstack4j.connectors</groupId>
+            <artifactId>openstack4j-http-connector</artifactId>
+            <version>${openstack4j.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.pacesys.openstack4j.connectors</groupId>
+            <artifactId>openstack4j-httpclient</artifactId>
+            <version>${openstack4j.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.fge</groupId>
+            <artifactId>json-patch</artifactId>
+            <version>${json-patch.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.fge</groupId>
+            <artifactId>jackson-coreutils</artifactId>
+            <version>${jackson-coreutils.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.fge</groupId>
+            <artifactId>btf</artifactId>
+            <version>${btf.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.fge</groupId>
+            <artifactId>msg-simple</artifactId>
+            <version>${msg-simple.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.yaml</groupId>
+            <artifactId>snakeyaml</artifactId>
+            <version>${snakeyaml.version}</version>
+        </dependency>
+
+        <dependency>
             <groupId>org.glassfish.jersey.core</groupId>
             <artifactId>jersey-client</artifactId>
             <scope>test</scope>
@@ -184,6 +225,28 @@
     <build>
         <plugins>
             <plugin>
+                <groupId>org.onosproject</groupId>
+                <artifactId>onos-maven-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-scr-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>generate-scr-srcdescriptor</id>
+                        <goals>
+                            <goal>scr</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <supportedProjectTypes>
+                        <supportedProjectType>bundle</supportedProjectType>
+                        <supportedProjectType>war</supportedProjectType>
+                    </supportedProjectTypes>
+                </configuration>
+            </plugin>
+            <plugin>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
                 <extensions>true</extensions>
@@ -197,13 +260,26 @@
                         <Bundle-SymbolicName>
                             ${project.groupId}.${project.artifactId}
                         </Bundle-SymbolicName>
+                        <Web-ContextPath>${web.context}</Web-ContextPath>
                         <Import-Package>
+                            !org.apache.http.*,
+                            !com.fasterxml.jackson.dataformat.*,
+                            !javax.annotation,
                             *,org.glassfish.jersey.servlet
                         </Import-Package>
-                        <Web-ContextPath>${web.context}</Web-ContextPath>
+                        <Embed-Dependency>
+                            openstack4j-core,
+                            openstack4j-http-connector,
+                            openstack4j-httpclient,
+                            json-patch,
+                            jackson-coreutils,
+                            btf,
+                            msg-simple,
+                            snakeyaml
+                        </Embed-Dependency>
                     </instructions>
                 </configuration>
             </plugin>
         </plugins>
     </build>
-</project>
+</project>
\ No newline at end of file
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNode.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNode.java
index 73c8e1b..e6592b0 100644
--- a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNode.java
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNode.java
@@ -398,9 +398,6 @@
                 }
             } else {
                 checkArgument(endPoint != null, NOT_NULL_MSG, "endpoint URL");
-
-                // we force controller node to have COMPLETE state for now
-                state = NodeState.COMPLETE;
             }
 
             if (type == NodeType.GATEWAY && uplinkPort == null) {
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandler.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandler.java
index 6064267..ba7e8ec 100644
--- a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandler.java
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNodeHandler.java
@@ -60,6 +60,7 @@
 import org.onosproject.openstacknode.api.OpenstackNodeService;
 import org.onosproject.openstacknode.api.OpenstackPhyInterface;
 import org.onosproject.ovsdb.controller.OvsdbController;
+import org.openstack4j.api.OSClient;
 import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
 
@@ -80,8 +81,11 @@
 import static org.onosproject.openstacknode.api.NodeState.COMPLETE;
 import static org.onosproject.openstacknode.api.NodeState.DEVICE_CREATED;
 import static org.onosproject.openstacknode.api.NodeState.INCOMPLETE;
+import static org.onosproject.openstacknode.api.NodeState.INIT;
+import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
 import static org.onosproject.openstacknode.api.OpenstackNodeService.APP_ID;
+import static org.onosproject.openstacknode.util.OpenstackNodeUtil.getConnectedClient;
 import static org.onosproject.openstacknode.util.OpenstackNodeUtil.isOvsdbConnected;
 import static org.slf4j.LoggerFactory.getLogger;
 
@@ -422,11 +426,39 @@
      * @param osNode openstack node
      */
     private void bootstrapNode(OpenstackNode osNode) {
-        if (isCurrentStateDone(osNode)) {
-            setState(osNode, osNode.state().nextState());
+        if (osNode.type() == CONTROLLER) {
+            if (osNode.state() == INIT && checkEndpoint(osNode)) {
+                setState(osNode, COMPLETE);
+            }
         } else {
-            log.trace("Processing {} state for {}", osNode.state(), osNode.hostname());
-            osNode.state().process(this, osNode);
+            if (isCurrentStateDone(osNode)) {
+                setState(osNode, osNode.state().nextState());
+            } else {
+                log.trace("Processing {} state for {}", osNode.state(), osNode.hostname());
+                osNode.state().process(this, osNode);
+            }
+        }
+    }
+
+    /**
+     * Checks the validity of the given endpoint.
+     *
+     * @param osNode gateway node
+     * @return validity result
+     */
+    private boolean checkEndpoint(OpenstackNode osNode) {
+        if (osNode == null) {
+            log.warn("Keystone auth info has not been configured. " +
+                     "Please specify auth info via network-cfg.json.");
+            return false;
+        }
+
+        OSClient client = getConnectedClient(osNode);
+
+        if (client == null) {
+            return false;
+        } else {
+            return client.getSupportedServices().size() != 0;
         }
     }
 
@@ -442,7 +474,8 @@
             NodeId leader = leadershipService.getLeader(appId.name());
             return Objects.equals(localNode, leader) &&
                     event.subject().type() == Device.Type.CONTROLLER &&
-                    osNodeService.node(event.subject().id()) != null;
+                    osNodeService.node(event.subject().id()) != null &&
+                    osNodeService.node(event.subject().id()).type() != CONTROLLER;
         }
 
         @Override
@@ -483,7 +516,8 @@
             NodeId leader = leadershipService.getLeader(appId.name());
             return Objects.equals(localNode, leader) &&
                     event.subject().type() == Device.Type.SWITCH &&
-                    osNodeService.node(event.subject().id()) != null;
+                    osNodeService.node(event.subject().id()) != null &&
+                    osNodeService.node(event.subject().id()).type() != CONTROLLER;
         }
 
         @Override
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DistributedOpenstackNodeStore.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DistributedOpenstackNodeStore.java
index be49135..4b40775 100644
--- a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DistributedOpenstackNodeStore.java
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DistributedOpenstackNodeStore.java
@@ -166,23 +166,6 @@
         @Override
         public void event(MapEvent<String, OpenstackNode> event) {
 
-            OpenstackNode node;
-
-            if (event.type() == INSERT || event.type() == UPDATE) {
-                node = event.newValue().value();
-            } else {
-                node = event.oldValue().value();
-            }
-
-            // we do not notify the controller node related event
-            // controller node event should be handled in different way
-            if (node.type() == CONTROLLER) {
-                // TODO: need to find a way to check the controller node availability
-                log.info("node {} is detected", node.hostname());
-
-                return;
-            }
-
             switch (event.type()) {
                 case INSERT:
                     log.debug("OpenStack node created {}", event.newValue());
@@ -198,6 +181,13 @@
                                 OPENSTACK_NODE_UPDATED,
                                 event.newValue().value()
                         ));
+
+                        // if the event is about controller node, we will not
+                        // process COMPLETE and INCOMPLETE state
+                        if (isControllerNode(event)) {
+                            return;
+                        }
+
                         if (event.newValue().value().state() == COMPLETE) {
                             notifyDelegate(new OpenstackNodeEvent(
                                     OPENSTACK_NODE_COMPLETE,
@@ -223,5 +213,25 @@
                     break;
             }
         }
+
+        /**
+         * Checks the openstack node whether a controller node or not with
+         * the given MapEvent.
+         *
+         * @param event map event
+         * @return controller node indicator flag
+         */
+        private boolean isControllerNode(MapEvent<String, OpenstackNode> event) {
+
+            OpenstackNode node;
+
+            if (event.type() == INSERT || event.type() == UPDATE) {
+                node = event.newValue().value();
+            } else {
+                node = event.oldValue().value();
+            }
+
+            return node.type() == CONTROLLER;
+        }
     }
 }
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/util/OpenstackNodeUtil.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/util/OpenstackNodeUtil.java
index 79526e6..8e1de52 100644
--- a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/util/OpenstackNodeUtil.java
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/util/OpenstackNodeUtil.java
@@ -16,21 +16,44 @@
 package org.onosproject.openstacknode.util;
 
 import org.onosproject.net.device.DeviceService;
+import org.onosproject.openstacknode.api.OpenstackAuth;
+import org.onosproject.openstacknode.api.OpenstackAuth.Perspective;
 import org.onosproject.openstacknode.api.OpenstackNode;
 import org.onosproject.ovsdb.controller.OvsdbClientService;
 import org.onosproject.ovsdb.controller.OvsdbController;
 import org.onosproject.ovsdb.controller.OvsdbNodeId;
+import org.openstack4j.api.OSClient;
+import org.openstack4j.api.client.IOSClientBuilder;
+import org.openstack4j.api.exceptions.AuthenticationException;
+import org.openstack4j.api.types.Facing;
+import org.openstack4j.core.transport.Config;
+import org.openstack4j.model.common.Identifier;
+import org.openstack4j.openstack.OSFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.security.cert.X509Certificate;
+
 /**
  * An utility that used in openstack node app.
  */
 public final class OpenstackNodeUtil {
     protected static final Logger log = LoggerFactory.getLogger(OpenstackNodeUtil.class);
 
+    // keystone endpoint related variables
+    private static final String DOMAIN_DEFAULT = "default";
+    private static final String KEYSTONE_V2 = "v2.0";
+    private static final String KEYSTONE_V3 = "v3";
+    private static final String IDENTITY_PATH = "identity/";
+    private static final String SSL_TYPE = "SSL";
+
     /**
-     * Prevents object instantiation from external.
+     * Prevents object installation from external.
      */
     private OpenstackNodeUtil() {
     }
@@ -55,4 +78,147 @@
                 client != null &&
                 client.isConnected();
     }
+
+    /**
+     * Obtains a connected openstack client.
+     *
+     * @param osNode openstack node
+     * @return a connected openstack client
+     */
+    public static OSClient getConnectedClient(OpenstackNode osNode) {
+        OpenstackAuth auth = osNode.authentication();
+        String endpoint = buildEndpoint(osNode);
+        Perspective perspective = auth.perspective();
+
+        Config config = getSslConfig();
+
+        try {
+            if (endpoint.contains(KEYSTONE_V2)) {
+                IOSClientBuilder.V2 builder = OSFactory.builderV2()
+                        .endpoint(endpoint)
+                        .tenantName(auth.project())
+                        .credentials(auth.username(), auth.password())
+                        .withConfig(config);
+
+                if (perspective != null) {
+                    builder.perspective(getFacing(perspective));
+                }
+
+                return builder.authenticate();
+            } else if (endpoint.contains(KEYSTONE_V3)) {
+
+                Identifier project = Identifier.byName(auth.project());
+                Identifier domain = Identifier.byName(DOMAIN_DEFAULT);
+
+                IOSClientBuilder.V3 builder = OSFactory.builderV3()
+                        .endpoint(endpoint)
+                        .credentials(auth.username(), auth.password(), domain)
+                        .scopeToProject(project, domain)
+                        .withConfig(config);
+
+                if (perspective != null) {
+                    builder.perspective(getFacing(perspective));
+                }
+
+                return builder.authenticate();
+            } else {
+                log.warn("Unrecognized keystone version type");
+                return null;
+            }
+        } catch (AuthenticationException e) {
+            log.error("Authentication failed due to {}", e.toString());
+            return null;
+        }
+    }
+
+    /**
+     * Builds up and a complete endpoint URL from gateway node.
+     *
+     * @param node gateway node
+     * @return a complete endpoint URL
+     */
+    private static String buildEndpoint(OpenstackNode node) {
+
+        OpenstackAuth auth = node.authentication();
+
+        StringBuilder endpointSb = new StringBuilder();
+        endpointSb.append(auth.protocol().name().toLowerCase());
+        endpointSb.append("://");
+        endpointSb.append(node.endPoint());
+        endpointSb.append(":");
+        endpointSb.append(auth.port());
+        endpointSb.append("/");
+
+        // in case the version is v3, we need to append identity path into endpoint
+        if (auth.version().equals(KEYSTONE_V3)) {
+            endpointSb.append(IDENTITY_PATH);
+        }
+
+        endpointSb.append(auth.version());
+        return endpointSb.toString();
+    }
+
+    /**
+     * Obtains the SSL config without verifying the certification.
+     *
+     * @return SSL config
+     */
+    private static Config getSslConfig() {
+        // we bypass the SSL certification verification for now
+        // TODO: verify server side SSL using a given certification
+        Config config = Config.newConfig().withSSLVerificationDisabled();
+
+        TrustManager[] trustAllCerts = new TrustManager[]{
+                new X509TrustManager() {
+                    public X509Certificate[] getAcceptedIssuers() {
+                        return null;
+                    }
+
+                    public void checkClientTrusted(X509Certificate[] certs,
+                                                   String authType) {
+                    }
+
+                    public void checkServerTrusted(X509Certificate[] certs,
+                                                   String authType) {
+                    }
+                }
+        };
+
+        HostnameVerifier allHostsValid = (hostname, session) -> true;
+
+        try {
+            SSLContext sc = SSLContext.getInstance(SSL_TYPE);
+            sc.init(null, trustAllCerts,
+                    new java.security.SecureRandom());
+            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+            HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
+
+            config.withSSLContext(sc);
+        } catch (Exception e) {
+            log.error("Failed to access OpenStack service due to {}", e.toString());
+            return null;
+        }
+
+        return config;
+    }
+
+    /**
+     * Obtains the facing object with given openstack perspective.
+     *
+     * @param perspective keystone perspective
+     * @return facing object
+     */
+    private static Facing getFacing(Perspective perspective) {
+
+        switch (perspective) {
+            case PUBLIC:
+                return Facing.PUBLIC;
+            case ADMIN:
+                return Facing.ADMIN;
+            case INTERNAL:
+                return Facing.INTERNAL;
+            default:
+                return null;
+        }
+    }
 }
diff --git a/apps/openstacknode/app/src/main/resources/deps/btf-1.2.jar b/apps/openstacknode/app/src/main/resources/deps/btf-1.2.jar
new file mode 100644
index 0000000..bbeee88
--- /dev/null
+++ b/apps/openstacknode/app/src/main/resources/deps/btf-1.2.jar
Binary files differ
diff --git a/apps/openstacknode/app/src/main/resources/deps/jackson-coreutils-1.6.jar b/apps/openstacknode/app/src/main/resources/deps/jackson-coreutils-1.6.jar
new file mode 100644
index 0000000..ee7b43d
--- /dev/null
+++ b/apps/openstacknode/app/src/main/resources/deps/jackson-coreutils-1.6.jar
Binary files differ
diff --git a/apps/openstacknode/app/src/main/resources/deps/json-patch-1.9.jar b/apps/openstacknode/app/src/main/resources/deps/json-patch-1.9.jar
new file mode 100644
index 0000000..36569b6
--- /dev/null
+++ b/apps/openstacknode/app/src/main/resources/deps/json-patch-1.9.jar
Binary files differ
diff --git a/apps/openstacknode/app/src/main/resources/deps/msg-simple-1.1.jar b/apps/openstacknode/app/src/main/resources/deps/msg-simple-1.1.jar
new file mode 100644
index 0000000..db74210
--- /dev/null
+++ b/apps/openstacknode/app/src/main/resources/deps/msg-simple-1.1.jar
Binary files differ
diff --git a/apps/openstacknode/app/src/main/resources/deps/openstack4j-core-3.1.0.jar b/apps/openstacknode/app/src/main/resources/deps/openstack4j-core-3.1.0.jar
new file mode 100644
index 0000000..c03203f
--- /dev/null
+++ b/apps/openstacknode/app/src/main/resources/deps/openstack4j-core-3.1.0.jar
Binary files differ
diff --git a/apps/openstacknode/app/src/main/resources/deps/openstack4j-http-connector-3.1.0.jar b/apps/openstacknode/app/src/main/resources/deps/openstack4j-http-connector-3.1.0.jar
new file mode 100644
index 0000000..cbe8476
--- /dev/null
+++ b/apps/openstacknode/app/src/main/resources/deps/openstack4j-http-connector-3.1.0.jar
Binary files differ
diff --git a/apps/openstacknode/app/src/main/resources/deps/openstack4j-httpclient-3.1.0.jar b/apps/openstacknode/app/src/main/resources/deps/openstack4j-httpclient-3.1.0.jar
new file mode 100644
index 0000000..964b15a
--- /dev/null
+++ b/apps/openstacknode/app/src/main/resources/deps/openstack4j-httpclient-3.1.0.jar
Binary files differ
diff --git a/apps/openstacknode/app/src/main/resources/deps/snakeyaml-1.15.jar b/apps/openstacknode/app/src/main/resources/deps/snakeyaml-1.15.jar
new file mode 100644
index 0000000..34084e3
--- /dev/null
+++ b/apps/openstacknode/app/src/main/resources/deps/snakeyaml-1.15.jar
Binary files differ
diff --git a/apps/openstacknode/openstack4j.bucklet b/apps/openstacknode/openstack4j.bucklet
new file mode 100644
index 0000000..6de5d52
--- /dev/null
+++ b/apps/openstacknode/openstack4j.bucklet
@@ -0,0 +1,41 @@
+INCLUDE_PACKAGES = 'com.google.common.net,com.google.common.io,com.fasterxml.jackson.annotation'
+EXCLUDE_PACKAGES = '!org.openstack4j,!org.openstack4j.*'
+ALL_PACKAGES = '*'
+
+def get_openstack4j_deps_path():
+
+    WEB_INF_PATH = 'WEB-INF/classes/deps/'
+    OPENSTACK4J_DEPS = [
+        'openstack4j-core',
+        'openstack4j-http-connector',
+        'openstack4j-httpclient',
+    ]
+    OPENSTACK4J_VER = '3.1.0'
+
+    openstack_deps_path = ''
+
+    for dep in OPENSTACK4J_DEPS:
+        name = dep + '-' + OPENSTACK4J_VER + '.jar'
+        path = WEB_INF_PATH + name
+        openstack_deps_path = openstack_deps_path + path + ','
+
+    return openstack_deps_path
+
+def get_jackson_deps_path():
+
+    WEB_INF_PATH = 'WEB-INF/classes/deps/'
+    JACKSON_DEPS_WITH_VER = [
+        'json-patch-1.9.jar',
+        'jackson-coreutils-1.6.jar',
+        'msg-simple-1.1.jar',
+        'btf-1.2.jar',
+        'snakeyaml-1.15.jar'
+    ]
+
+    jackson_deps_path = ''
+
+    for dep in JACKSON_DEPS_WITH_VER:
+        path = WEB_INF_PATH + dep
+        jackson_deps_path = jackson_deps_path + path + ','
+
+    return jackson_deps_path
\ No newline at end of file
diff --git a/apps/openstacknode/pom.xml b/apps/openstacknode/pom.xml
index 379bd79..86b8962 100644
--- a/apps/openstacknode/pom.xml
+++ b/apps/openstacknode/pom.xml
@@ -30,6 +30,15 @@
 
     <description>SONA Openstack Node Bootstrap Application</description>
 
+    <properties>
+        <openstack4j.version>3.1.0</openstack4j.version>
+        <json-patch.version>1.9</json-patch.version>
+        <jackson-coreutils.version>1.6</jackson-coreutils.version>
+        <btf.version>1.2</btf.version>
+        <msg-simple.version>1.1</msg-simple.version>
+        <snakeyaml.version>1.15</snakeyaml.version>
+    </properties>
+
     <modules>
         <module>api</module>
         <module>app</module>