Adding Gluon App code to support EVPN
Change-Id: I24aee104482a166e412e5e7b42ea1dbf518d51c6
diff --git a/apps/gluon/BUCK b/apps/gluon/BUCK
new file mode 100755
index 0000000..a2ddcd9
--- /dev/null
+++ b/apps/gluon/BUCK
@@ -0,0 +1,36 @@
+COMPILE_DEPS = [
+ '//lib:CORE_DEPS',
+ '//cli:onos-cli',
+ '//lib:httpclient-osgi',
+ '//lib:httpcore-osgi',
+ '//lib:org.apache.httpcomponents.httpasyncclient-osgi',
+ '//lib:org.apache.httpcomponents.httpcore-nio',
+ '//lib:org.apache.karaf.shell.console',
+ '//lib:org.apache.karaf.jaas',
+
+]
+TEST_DEPS = [
+ '//lib:TEST',
+]
+
+BUNDLES = [
+ ':onos-apps-gluon',
+ '//lib:httpclient-osgi',
+ '//lib:httpcore-osgi',
+ '//lib:org.apache.httpcomponents.httpasyncclient-osgi',
+ '//lib:org.apache.httpcomponents.httpcore-nio',
+]
+
+osgi_jar_with_tests (
+ deps = COMPILE_DEPS,
+ test_deps = TEST_DEPS,
+)
+
+onos_app (
+ app_name = 'org.onosproject.gluon',
+ title = 'Gluon Shim Application',
+ category = 'Monitoring',
+ url = 'http://onosproject.org',
+ included_bundles = BUNDLES,
+ description = 'To fetch data from Gluon Server over Http session.',
+)
\ No newline at end of file
diff --git a/apps/gluon/features.xml b/apps/gluon/features.xml
new file mode 100755
index 0000000..ae6bf2b
--- /dev/null
+++ b/apps/gluon/features.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+ ~ Copyright 2017-present Open Networking Foundation
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
+ <feature name="${project.artifactId}" version="${project.version}"
+ description="${project.description}">
+ <feature>onos-api</feature>
+ </feature>
+</features>
diff --git a/apps/gluon/pom.xml b/apps/gluon/pom.xml
new file mode 100755
index 0000000..cd39c33
--- /dev/null
+++ b/apps/gluon/pom.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2017-present Open Networking Foundation
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-apps</artifactId>
+ <version>1.11.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>onos-app-gluon</artifactId>
+ <packaging>bundle</packaging>
+
+ <description>ONOS GLUON application</description>
+ <url>http://onosproject.org</url>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <onos.version>1.11.0-SNAPSHOT</onos.version>
+ <onos.app.name>onos-app-gluon</onos.app.name>
+ <onos.app.origin>Huawei Technology India Pvt Ltd</onos.app.origin>
+ <onos.app.title>Gluon App</onos.app.title>
+ <onos.app.url>http://onosproject.org</onos.app.url>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ <version>${onos.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-osgi</artifactId>
+ <version>${onos.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ <version>${onos.version}</version>
+ <scope>test</scope>
+ <classifier>tests</classifier>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ <version>1.9.12</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.karaf.shell</groupId>
+ <artifactId>org.apache.karaf.shell.console</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-cli</artifactId>
+ <version>1.11.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpasyncclient</artifactId>
+ <version>4.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpcore</artifactId>
+ <version>4.4.4</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-core-net</artifactId>
+ <version>1.11.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/apps/gluon/src/main/java/org/onosproject/gluon/manager/GluonManager.java b/apps/gluon/src/main/java/org/onosproject/gluon/manager/GluonManager.java
new file mode 100755
index 0000000..11f3738
--- /dev/null
+++ b/apps/gluon/src/main/java/org/onosproject/gluon/manager/GluonManager.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.gluon.manager;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.core.CoreService;
+import org.onosproject.gluon.rsc.GluonConfig;
+import org.onosproject.gluon.rsc.GluonServer;
+import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.NetworkConfigRegistry;
+import org.onosproject.net.config.basics.SubjectFactories;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Gluon Shim Application.
+ */
+@Component(immediate = true)
+public class GluonManager {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private static final String APP_ID = "org.onosproject.gluon";
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected NetworkConfigRegistry configRegistry;
+
+
+ private final ConfigFactory configFactory =
+ new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY,
+ GluonConfig.class, "gluon") {
+ @Override
+ public GluonConfig createConfig() {
+ return new GluonConfig();
+ }
+ };
+
+ public static Map<String, GluonServer> serverMap = new LinkedHashMap<>();
+
+ @Activate
+ public void activate() {
+ coreService.registerApplication(APP_ID);
+ configRegistry.registerConfigFactory(configFactory);
+ log.info("Gluon app Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ configRegistry.unregisterConfigFactory(configFactory);
+ log.info("Gluon app Stopped");
+ }
+
+ /**
+ * Creating gluon server object.
+ *
+ * @param etcduri server url
+ * @param targetProtonKey server key type, default net-l3vpn
+ * @param mode server mode start or stop
+ * @param version running server version
+ */
+ public static void createServer(String etcduri, String targetProtonKey,
+ String mode, String version) {
+ new GluonServer(etcduri, targetProtonKey, mode, version);
+ }
+
+ /**
+ * Deleting gluon server from server list.
+ *
+ * @param etcduri server url
+ */
+ public static void deleteServer(String etcduri) {
+ for (Map.Entry<String, GluonServer> server : serverMap.entrySet()) {
+ if (etcduri.equals(server.getKey())) {
+ serverMap.remove(etcduri);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Add server into map.
+ *
+ * @param etcduri server url
+ * @param gluonObject store server object
+ */
+ public static void addServer(String etcduri, GluonServer gluonObject) {
+ serverMap.put(etcduri, gluonObject);
+ }
+
+ /**
+ * Returns serverMap size.
+ *
+ * @return total number of servers
+ */
+ public static int getTotalServers() {
+ return serverMap.size();
+ }
+
+ /**
+ * Returns all server IPs.
+ *
+ * @return serverMap
+ */
+ public static Map<String, GluonServer> getAllServersIP() {
+ return serverMap;
+ }
+
+
+}
\ No newline at end of file
diff --git a/apps/gluon/src/main/java/org/onosproject/gluon/manager/package-info.java b/apps/gluon/src/main/java/org/onosproject/gluon/manager/package-info.java
new file mode 100755
index 0000000..d20ea1a
--- /dev/null
+++ b/apps/gluon/src/main/java/org/onosproject/gluon/manager/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Gluon Shim Application manager class.
+ */
+package org.onosproject.gluon.manager;
\ No newline at end of file
diff --git a/apps/gluon/src/main/java/org/onosproject/gluon/rsc/GluonConfig.java b/apps/gluon/src/main/java/org/onosproject/gluon/rsc/GluonConfig.java
new file mode 100755
index 0000000..70f944a
--- /dev/null
+++ b/apps/gluon/src/main/java/org/onosproject/gluon/rsc/GluonConfig.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.gluon.rsc;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.onosproject.net.config.Config;
+
+/**
+ * Representation of a Etcd response.
+ */
+public class GluonConfig extends Config<String> {
+ public String action;
+ public String key;
+ public JsonNode value;
+ long modifiedIndex;
+ long createdIndex;
+
+ public GluonConfig() {
+ }
+
+ /**
+ * Gluon configuration data model.
+ *
+ * @param action operation type
+ * @param key proton key
+ * @param value proton value
+ * @param mIndex modified time
+ * @param cIndex created time
+ */
+ public GluonConfig(String action, String key, JsonNode value, long mIndex,
+ long cIndex) {
+ this.action = action;
+ this.key = key;
+ this.value = value;
+ this.modifiedIndex = mIndex;
+ this.createdIndex = cIndex;
+ }
+
+ /**
+ * Sets the etcdresponse used by network config.
+ *
+ * @param gluonConfig Etcdresponse data after parsing
+ */
+ public void setEtcdResponse(GluonConfig gluonConfig) {
+ object.put(gluonConfig.key, gluonConfig.value);
+ }
+
+ @Override
+ public String toString() {
+ return "GluonConfig{" +
+ "action='" + action + '\'' +
+ ", key='" + key + '\'' +
+ ", value=" + value +
+ ", modifiedIndex=" + modifiedIndex +
+ ", createdIndex=" + createdIndex +
+ '}';
+ }
+}
diff --git a/apps/gluon/src/main/java/org/onosproject/gluon/rsc/GluonConstants.java b/apps/gluon/src/main/java/org/onosproject/gluon/rsc/GluonConstants.java
new file mode 100755
index 0000000..3b41030
--- /dev/null
+++ b/apps/gluon/src/main/java/org/onosproject/gluon/rsc/GluonConstants.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.gluon.rsc;
+
+/**
+ * Gluon application related constants.
+ */
+
+public final class GluonConstants {
+
+ protected GluonConstants() {
+ }
+
+ /**
+ * String constants.
+ */
+ public static final String KEYS = "/keys";
+ public static final String PROTON = "/proton/";
+ public static final String MODE_STOP = "stop";
+ public static final String MODE_START = "start";
+ public static final String ACTION_SET = "set";
+ public static final String ACTION_GET = "get";
+ public static final String ACTION_DEL = "delete";
+ public static final String GLUON_HTTP = "http://";
+ public static final String KEY_TYPE = "net-l3vpn";
+ public static final String GLUON_ACTION = "action";
+ public static final String GLUON_KEY = "key";
+ public static final String GLUON_NODE = "node";
+ public static final String GLUON_NODES = "nodes";
+ public static final String GLUON_VALUE = "value";
+ public static final String GLUON_MOD_INDEX = "modifiedIndex";
+ public static final String GLUON_CREATE_INDEX = "createdIndex";
+ public static final String GLUON_DEFAULT_PORT = "2379";
+
+ /**
+ * INFO Constants.
+ */
+ public static final String BATCH_SERVICE_STATUS =
+ "executorBatchService shutdown status: {}";
+ public static final String REAL_TIME_SERVICE_STATUS =
+ "executorRealTimeService shutdown status: {}";
+ public static final String SERVER_RUNNING =
+ "Server is already running";
+ public static final String ACTIVE_SERVER =
+ "Number of active servers: {}";
+ public static final String NO_SUBKEYS_AVAIL =
+ "No subKeys available. Nothing to smooth";
+ public static final String SERVER_STOPPED =
+ "Server has stopped successfully";
+ public static final String NO_SERVER_AVAIL =
+ "Server is unavailable";
+ public static final String NO_SERVER_AVAIL_ON_PORT =
+ "Server is unavailable on specified port";
+ public static final String REAL_TIME_PROCESSING =
+ "Started Real time etcd monitoring for {}";
+ public static final String BATCH_PROCESSING =
+ "Started Batch time etcd monitoring for {}";
+ public static final String BATCH_QUERING =
+ "Sending Batch time etcd request for {}";
+ public static final String BATCH_STOPPED =
+ "Stopped Batch time etcd monitoring for {}";
+ public static final String REAL_TIME_RECEIVED =
+ "Received RealTime etcd monitor data {}";
+ public static final String BATCH_RECEIVED =
+ "Received batch etcd monitor data {}";
+ public static final String SUBKEYS_RECEIVED =
+ "Recieved subkeys {}";
+ public static final String INVALID_ACTION =
+ "Invalid action has been received";
+ public static final String DATA_UPDATED =
+ "Gluon data updated to network config datastore";
+ public static final String DATA_REMOVED =
+ "Gluon data removed from network config datastore";
+ public static final String SERVER_POOL =
+ "Server IP is not available in server pool";
+ public static final String PROTON_KEY_SUPPORT =
+ "Currently only net-l3vpn type supported";
+ public static final String WRONG_INPUT = "Either server is not available " +
+ "or wrong input";
+ public static final String WRONG_INPUT_TYPE = "Wrong format type";
+ public static final String INVALID_MODE = "Invalid mode";
+ public static final String WRONG_IP_FORMAT = "Wrong IP address format";
+ public static final String INVALID_RANGE = "Wrong port range <1-65535>";
+ public static final String PROCESSING_FAILED = "Error occurred while " +
+ "processing";
+
+ /**
+ * ERROR Constants.
+ */
+ public static final String E_BATCH_PROCESSING =
+ "Batch mode etcd monitor failed with error {}";
+ public static final String E_BATCH_PROCESSING_URL =
+ "Batch mode etcd monitor failed for {}";
+ public static final String E_SUBKEYS_PROCESSING =
+ "Error observed while fetching subkeys for {}";
+ public static final String E_REAL_TIME_PROCESSING =
+ "Real time etcd monitor failed with error {}";
+ public static final String E_CLIENT_STOP =
+ "http client unable to stop with error {}";
+
+ /**
+ * Integer Constants.
+ */
+ public static final int STATUS_CODE = 200;
+
+}
diff --git a/apps/gluon/src/main/java/org/onosproject/gluon/rsc/GluonServer.java b/apps/gluon/src/main/java/org/onosproject/gluon/rsc/GluonServer.java
new file mode 100755
index 0000000..f4f400e
--- /dev/null
+++ b/apps/gluon/src/main/java/org/onosproject/gluon/rsc/GluonServer.java
@@ -0,0 +1,537 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.gluon.rsc;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.http.HttpResponse;
+import org.apache.http.StatusLine;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.concurrent.FutureCallback;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
+import org.apache.http.impl.nio.client.HttpAsyncClients;
+import org.apache.http.util.EntityUtils;
+import org.onlab.osgi.DefaultServiceDirectory;
+import org.onosproject.net.config.NetworkConfigService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.gluon.manager.GluonManager.addServer;
+import static org.onosproject.gluon.manager.GluonManager.deleteServer;
+import static org.onosproject.gluon.manager.GluonManager.getAllServersIP;
+import static org.onosproject.gluon.rsc.GluonConstants.ACTION_DEL;
+import static org.onosproject.gluon.rsc.GluonConstants.ACTION_GET;
+import static org.onosproject.gluon.rsc.GluonConstants.ACTION_SET;
+import static org.onosproject.gluon.rsc.GluonConstants.ACTIVE_SERVER;
+import static org.onosproject.gluon.rsc.GluonConstants.BATCH_PROCESSING;
+import static org.onosproject.gluon.rsc.GluonConstants.BATCH_QUERING;
+import static org.onosproject.gluon.rsc.GluonConstants.BATCH_RECEIVED;
+import static org.onosproject.gluon.rsc.GluonConstants.BATCH_SERVICE_STATUS;
+import static org.onosproject.gluon.rsc.GluonConstants.BATCH_STOPPED;
+import static org.onosproject.gluon.rsc.GluonConstants.DATA_REMOVED;
+import static org.onosproject.gluon.rsc.GluonConstants.DATA_UPDATED;
+import static org.onosproject.gluon.rsc.GluonConstants.E_BATCH_PROCESSING;
+import static org.onosproject.gluon.rsc.GluonConstants.E_BATCH_PROCESSING_URL;
+import static org.onosproject.gluon.rsc.GluonConstants.E_CLIENT_STOP;
+import static org.onosproject.gluon.rsc.GluonConstants.E_REAL_TIME_PROCESSING;
+import static org.onosproject.gluon.rsc.GluonConstants.E_SUBKEYS_PROCESSING;
+import static org.onosproject.gluon.rsc.GluonConstants.GLUON_ACTION;
+import static org.onosproject.gluon.rsc.GluonConstants.GLUON_CREATE_INDEX;
+import static org.onosproject.gluon.rsc.GluonConstants.GLUON_KEY;
+import static org.onosproject.gluon.rsc.GluonConstants.GLUON_MOD_INDEX;
+import static org.onosproject.gluon.rsc.GluonConstants.GLUON_NODE;
+import static org.onosproject.gluon.rsc.GluonConstants.GLUON_NODES;
+import static org.onosproject.gluon.rsc.GluonConstants.GLUON_VALUE;
+import static org.onosproject.gluon.rsc.GluonConstants.INVALID_ACTION;
+import static org.onosproject.gluon.rsc.GluonConstants.KEYS;
+import static org.onosproject.gluon.rsc.GluonConstants.MODE_START;
+import static org.onosproject.gluon.rsc.GluonConstants.MODE_STOP;
+import static org.onosproject.gluon.rsc.GluonConstants.NO_SERVER_AVAIL;
+import static org.onosproject.gluon.rsc.GluonConstants.NO_SUBKEYS_AVAIL;
+import static org.onosproject.gluon.rsc.GluonConstants.PROCESSING_FAILED;
+import static org.onosproject.gluon.rsc.GluonConstants.PROTON;
+import static org.onosproject.gluon.rsc.GluonConstants.REAL_TIME_PROCESSING;
+import static org.onosproject.gluon.rsc.GluonConstants.REAL_TIME_RECEIVED;
+import static org.onosproject.gluon.rsc.GluonConstants.REAL_TIME_SERVICE_STATUS;
+import static org.onosproject.gluon.rsc.GluonConstants.SERVER_RUNNING;
+import static org.onosproject.gluon.rsc.GluonConstants.SERVER_STOPPED;
+import static org.onosproject.gluon.rsc.GluonConstants.STATUS_CODE;
+import static org.onosproject.gluon.rsc.GluonConstants.SUBKEYS_RECEIVED;
+
+
+public class GluonServer {
+
+ private static String protonKeyUri;
+ private static String serverUri;
+
+ private static CloseableHttpAsyncClient httpClient;
+
+ //store gluon server supported subkeys
+ private List<String> subKeys = new LinkedList<>();
+
+ // Lists of gluon servers
+ public Map<String, GluonServer> serverMap = getAllServersIP();
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ // Real time executor thread
+ private final ExecutorService executorRealTimeService = Executors
+ .newSingleThreadExecutor(groupedThreads("EtcdRealTimeMonitor",
+ "executor-%d", log));
+ // Batch executor thread
+ private final ExecutorService executorBatchService = Executors
+ .newSingleThreadExecutor(groupedThreads("EtcdBatchMonitor",
+ "executor-%d", log));
+
+ // Statistics counter
+ private int setCount = 0;
+ private int delCount = 0;
+ private int getCount = 0;
+ // Server etcd version
+ public String version;
+
+ /**
+ * To get Gluon server running version, needs to create at-least one object.
+ */
+ public GluonServer() {
+ }
+
+ /**
+ * Realising server functionality.
+ *
+ * @param etcduri server url
+ * @param targetProtonKey server key type, default net-l3vpn
+ * @param mode server mode start or stop
+ * @param version running server version
+ */
+ public GluonServer(String etcduri, String targetProtonKey,
+ String mode, String version) {
+ this.version = version;
+
+ switch (mode) {
+ // Handling stop mode
+ case MODE_STOP:
+ // return if server is not available into the server list
+ if (!serverMap.containsKey(etcduri)) {
+ log.debug(NO_SERVER_AVAIL);
+ return;
+ }
+ try {
+ // stop batch service executor thread
+ log.debug(BATCH_SERVICE_STATUS,
+ executorBatchService.isShutdown());
+ executorBatchService.shutdown();
+ // stop real time service executor thread
+ log.debug(REAL_TIME_SERVICE_STATUS,
+ executorRealTimeService.isShutdown());
+ executorRealTimeService.shutdown();
+ // closing http client
+ httpClient.close();
+ } catch (IOException io) {
+ log.error(E_CLIENT_STOP, io.getMessage());
+ }
+ // deletes server from gluon server list
+ deleteServer(etcduri);
+ log.debug(SERVER_STOPPED);
+ return;
+ // Handling start mode
+ case MODE_START:
+ if (serverMap.containsKey(etcduri)) {
+ //Returns user CLI if server is already running
+ // and logs all server info into log files
+ log.info(SERVER_RUNNING);
+ log.debug(ACTIVE_SERVER, serverMap.size());
+ return;
+ }
+ // Store gluon manager object and gluon server url
+ addServer(etcduri, this);
+ // Preparing server uri
+ serverUri = etcduri + "/v2" + KEYS;
+ // Preparing server subkeys uri
+ protonKeyUri = PROTON + targetProtonKey;
+ // Starts http client
+ RequestConfig requestConfig = RequestConfig.custom().build();
+ httpClient = HttpAsyncClients.custom()
+ .setDefaultRequestConfig(requestConfig).build();
+ httpClient.start();
+
+ // Start thread to handle and process RealTime data
+ handleRealTimeData(null);
+
+ // Start thread to handle and process batch data,
+ // iff subkeys are available
+ getAllProtonSubkeys(serverUri + protonKeyUri);
+ if (getProtonSubkeys().isEmpty()) {
+ log.debug(NO_SUBKEYS_AVAIL);
+ return;
+ }
+ // handle RealTime data
+ handleBatchData(0);
+ return;
+ default:
+ log.debug(INVALID_ACTION);
+
+ }
+ }
+
+ /**
+ * Handles real time data which is received from Gluon server.
+ *
+ * @param index, It will be used in recursive call of
+ * real time monitoring method.
+ * modified index receive from GluonConfig config file
+ */
+ private void handleRealTimeData(Long index) {
+ String realTimeUri = serverUri + protonKeyUri +
+ "/?wait=true&recursive=true";
+ if (index != null) {
+ realTimeUri += "&waitIndex=" + index;
+ }
+ HttpGet request = new HttpGet(URI.create(realTimeUri));
+ log.info(REAL_TIME_PROCESSING, realTimeUri);
+ // Starts real time executor thread
+ executorRealTimeService.execute(new Runnable() {
+ public void run() {
+ try {
+ httpClient.execute(
+ request, new FutureCallback<HttpResponse>() {
+
+ @Override
+ public void completed(HttpResponse result) {
+ StatusLine statusLine =
+ result.getStatusLine();
+ int statusCode = statusLine.getStatusCode();
+ if (statusCode ==
+ STATUS_CODE &&
+ result.getEntity() != null) {
+ try {
+ String json = EntityUtils
+ .toString(result.getEntity());
+ GluonConfig response =
+ processRealTimeResponse(json);
+ // Recursive call to handle
+ // real time data
+ handleRealTimeData(
+ response.modifiedIndex + 1);
+ } catch (IOException e) {
+ failed(e);
+ }
+ } else {
+ log.error(E_REAL_TIME_PROCESSING);
+ }
+ }
+
+ @Override
+ public void cancelled() {
+ log.debug("Nothing to do with " +
+ "this overridden method");
+ }
+
+ @Override
+ public void failed(Exception e) {
+ log.error(E_REAL_TIME_PROCESSING,
+ e.getMessage());
+ }
+ });
+ } catch (Exception e) {
+ log.error(E_REAL_TIME_PROCESSING, e.getMessage());
+ }
+ }
+ });
+ }
+
+
+ /**
+ * Handles batch data which is received from Gluon server.
+ *
+ * @param subKeyIndex gets all proton subkey value
+ */
+ private void handleBatchData(int subKeyIndex) {
+ String currBatchUri = serverUri + getProtonSubkeys().get(subKeyIndex);
+ HttpGet request = new HttpGet(URI.create(currBatchUri));
+
+ if (0 == subKeyIndex) {
+ log.debug(BATCH_PROCESSING, protonKeyUri);
+ }
+ log.info(BATCH_QUERING, currBatchUri);
+ // Starts batch executor thread
+ executorBatchService.execute(new Runnable() {
+ public void run() {
+ try {
+ httpClient.execute(request, new FutureCallback<HttpResponse>() {
+ @Override
+ public void completed(HttpResponse result) {
+ StatusLine statusLine = result.getStatusLine();
+ int statusCode = statusLine.getStatusCode();
+ if (statusCode == STATUS_CODE &&
+ result.getEntity() != null) {
+ try {
+ String json = EntityUtils
+ .toString(result.getEntity());
+ processBatchResponse(json);
+ // Stop batch executor thread
+ // once all gluon server subkeys processed
+ if (subKeyIndex ==
+ ((getProtonSubkeys().size()) - 1)) {
+ cancelled();
+ return;
+ }
+
+ handleBatchData(subKeyIndex + 1);
+ } catch (IOException e) {
+ failed(e);
+ }
+ } else {
+ log.error(E_BATCH_PROCESSING_URL, currBatchUri);
+ }
+ }
+
+ @Override
+ public void cancelled() {
+ executorBatchService.shutdown();
+ log.debug(BATCH_STOPPED, protonKeyUri);
+ }
+
+ @Override
+ public void failed(Exception e) {
+ log.error(E_BATCH_PROCESSING, e.getMessage());
+ }
+ });
+ } catch (Exception e) {
+ log.error(E_BATCH_PROCESSING, e.getMessage());
+ }
+ }
+ });
+ }
+
+ /**
+ * Parse and process real time json data which is received from Gluon server.
+ *
+ * @param result real time json data
+ * @return GluonConfig response
+ */
+ public GluonConfig processRealTimeResponse(String result) {
+ ObjectMapper mapper = new ObjectMapper();
+ GluonConfig response = null;
+ try {
+ log.info(REAL_TIME_RECEIVED, result);
+ JsonNode jsonNode = mapper.readTree(result);
+ String action = jsonNode.get(GLUON_ACTION).asText();
+ String key = jsonNode.get(GLUON_NODE).get(GLUON_KEY).asText();
+ long mIndex = jsonNode.get(GLUON_NODE)
+ .get(GLUON_MOD_INDEX).asLong();
+ long cIndex = jsonNode.get(GLUON_NODE)
+ .get(GLUON_CREATE_INDEX).asLong();
+ if (action.equals(ACTION_SET)) {
+ String value = jsonNode.get(GLUON_NODE)
+ .get(GLUON_VALUE).asText();
+ JsonNode modifyValue = mapper.readTree(value.replace("\\", ""));
+ response = new GluonConfig(action, key, modifyValue, mIndex,
+ cIndex);
+ setCount++;
+ } else if (action.equals(ACTION_DEL)) {
+ response = new GluonConfig(action, key, null, mIndex, cIndex);
+ delCount++;
+ } else {
+ log.debug(INVALID_ACTION);
+ }
+ } catch (IOException e) {
+ log.error(E_REAL_TIME_PROCESSING, e.getMessage());
+ }
+ processEtcdResponse(response);
+ return response;
+ }
+
+ /**
+ * Parse and process batch json data which is received from Gluon server.
+ *
+ * @param result batch json data
+ * @return GluonConfig response
+ */
+ public GluonConfig processBatchResponse(String result) {
+ ObjectMapper mapper = new ObjectMapper();
+ GluonConfig response = null;
+ try {
+ log.debug(BATCH_RECEIVED, result);
+ JsonNode jsonNode = mapper.readTree(result);
+ log.info("JSON NODE VALUE ARE: {}", jsonNode);
+ String action = jsonNode.get(GLUON_ACTION).asText();
+ JsonNode nodes = jsonNode.get(GLUON_NODE).get(GLUON_NODES);
+ if (null != nodes) {
+ for (JsonNode confNode : nodes) {
+ String key = confNode.get(GLUON_KEY).asText();
+ long mIndex = confNode.get(GLUON_MOD_INDEX).asLong();
+ long cIndex = confNode.get(GLUON_CREATE_INDEX).asLong();
+ String value = confNode.get(GLUON_VALUE).asText();
+ log.info("JSON NODE VALUE ARE 2: {}", value);
+ JsonNode modifyValue = mapper.readTree(value.replace("\\", ""));
+ log.info("JSON NODE MODIFY VALUE ARE 2: {}", modifyValue);
+ response = new GluonConfig(action, key,
+ modifyValue, mIndex, cIndex);
+ getCount++;
+ processEtcdResponse(response);
+
+ }
+ }
+ } catch (IOException e) {
+ log.error(E_BATCH_PROCESSING, e.getMessage());
+ }
+ return response;
+ }
+
+ /**
+ * Gets all the proton subkeys from Gluon server.
+ *
+ * @param subKeyUrl get every proton subkey Url
+ */
+ public void getAllProtonSubkeys(String subKeyUrl) {
+ HttpClient client = HttpClientBuilder.create().build();
+ HttpGet request = new HttpGet(subKeyUrl);
+ ObjectMapper mapper = new ObjectMapper();
+ try {
+ HttpResponse result = client.execute(request);
+ StatusLine statusLine = result.getStatusLine();
+ int statusCode = statusLine.getStatusCode();
+ if (statusCode == STATUS_CODE && result.getEntity() != null) {
+ String json = EntityUtils
+ .toString(result.getEntity());
+ log.debug(SUBKEYS_RECEIVED, json);
+ JsonNode jsonNode = mapper.readTree(json);
+ JsonNode nodes = jsonNode.get(GLUON_NODE).get(GLUON_NODES);
+
+ for (JsonNode confNode : nodes) {
+ String key = confNode.get(GLUON_KEY).asText();
+ storeProtonSubkey(key);
+ }
+ }
+ } catch (IOException e) {
+ log.error(E_SUBKEYS_PROCESSING, subKeyUrl);
+ }
+ return;
+ }
+
+ /**
+ * Gets all the proton subkeys from Gluon server.
+ *
+ * @param uri get every proton subkey Url
+ * @return version server version
+ */
+ public String getGluonServerVersion(String uri) {
+ HttpClient client = HttpClientBuilder.create().build();
+ HttpGet request = new HttpGet(uri);
+ ObjectMapper mapper = new ObjectMapper();
+ String version = null;
+ try {
+ HttpResponse result = client.execute(request);
+ StatusLine statusLine = result.getStatusLine();
+ int statusCode = statusLine.getStatusCode();
+ if (statusCode == STATUS_CODE && result.getEntity() != null) {
+ String json = EntityUtils
+ .toString(result.getEntity());
+ JsonNode jsonNode = mapper.readTree(json);
+ version = jsonNode.get("etcdserver").asText();
+ }
+ } catch (IOException e) {
+ log.error(PROCESSING_FAILED);
+ }
+ return version;
+ }
+
+ /**
+ * Gluon data updating and deleting into/from NetworkConfig datastore.
+ * config.apply will raise GluonConfig.class event for add,
+ * get and delete operations.
+ *
+ * @param gluonConfigMessage Etcdresponse data after parsing
+ */
+ public void processEtcdResponse(GluonConfig gluonConfigMessage) {
+
+ NetworkConfigService configService =
+ DefaultServiceDirectory.getService(NetworkConfigService.class);
+ if (gluonConfigMessage.action.equals(ACTION_SET) ||
+ gluonConfigMessage.action.equals(ACTION_GET)) {
+ GluonConfig config = configService
+ .addConfig(gluonConfigMessage.key, GluonConfig.class);
+ config.setEtcdResponse(gluonConfigMessage);
+ config.apply();
+ log.info(DATA_UPDATED);
+ } else if (gluonConfigMessage.action.equals(ACTION_DEL)) {
+ configService.removeConfig(gluonConfigMessage.key,
+ GluonConfig.class);
+ log.info(DATA_REMOVED);
+ } else {
+ log.info(INVALID_ACTION);
+ }
+ }
+
+ /**
+ * Returns set statistics.
+ *
+ * @return setCount
+ */
+ public int getSetCount() {
+ return setCount;
+ }
+
+ /**
+ * Returns get statistics.
+ *
+ * @return getCount
+ */
+ public int getGetCount() {
+ return getCount;
+ }
+
+ /**
+ * Returns delete statistics.
+ *
+ * @return delCount
+ */
+ public int getDelCount() {
+ return delCount;
+ }
+
+ /**
+ * Returns proton subkeys.
+ *
+ * @return subkeys
+ */
+ public List<String> getProtonSubkeys() {
+ return subKeys;
+ }
+
+ /**
+ * store proton subkeys.
+ *
+ * @param keys proton subkey
+ */
+ public void storeProtonSubkey(String keys) {
+ subKeys.add(keys);
+ }
+}
+
diff --git a/apps/gluon/src/main/java/org/onosproject/gluon/rsc/cli/GluonServerCommand.java b/apps/gluon/src/main/java/org/onosproject/gluon/rsc/cli/GluonServerCommand.java
new file mode 100755
index 0000000..6dec71f
--- /dev/null
+++ b/apps/gluon/src/main/java/org/onosproject/gluon/rsc/cli/GluonServerCommand.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.gluon.rsc.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.gluon.rsc.GluonServer;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.onosproject.gluon.manager.GluonManager.createServer;
+import static org.onosproject.gluon.rsc.GluonConstants.GLUON_DEFAULT_PORT;
+import static org.onosproject.gluon.rsc.GluonConstants.GLUON_HTTP;
+import static org.onosproject.gluon.rsc.GluonConstants.INVALID_MODE;
+import static org.onosproject.gluon.rsc.GluonConstants.INVALID_RANGE;
+import static org.onosproject.gluon.rsc.GluonConstants.KEY_TYPE;
+import static org.onosproject.gluon.rsc.GluonConstants.MODE_START;
+import static org.onosproject.gluon.rsc.GluonConstants.MODE_STOP;
+import static org.onosproject.gluon.rsc.GluonConstants.NO_SERVER_AVAIL;
+import static org.onosproject.gluon.rsc.GluonConstants.NO_SERVER_AVAIL_ON_PORT;
+import static org.onosproject.gluon.rsc.GluonConstants.PROTON_KEY_SUPPORT;
+import static org.onosproject.gluon.rsc.GluonConstants.WRONG_INPUT;
+import static org.onosproject.gluon.rsc.GluonConstants.WRONG_INPUT_TYPE;
+import static org.onosproject.gluon.rsc.GluonConstants.WRONG_IP_FORMAT;
+
+
+/**
+ * To monitor Gluon etcd server.
+ */
+@Command(scope = "onos", name = "gluon",
+ description = "Support for reading Gluon data via etcd client")
+public class GluonServerCommand extends AbstractShellCommand {
+
+ @Option(name = "-m", aliases = "--mode",
+ description = "Gluon server monitoring mode: start; stop",
+ required = false, multiValued = false)
+ String mode = MODE_START;
+
+ @Option(name = "-i", aliases = "--server-ip",
+ description = "Gluon server ip address",
+ required = true, multiValued = false)
+ String ipAddress = null;
+
+ @Option(name = "-p", aliases = "--port", description = "Gluon server port",
+ required = false, multiValued = false)
+ String port = GLUON_DEFAULT_PORT;
+
+ @Option(name = "-k", aliases = "--key",
+ description = "Proton key : net-l3vpn",
+ required = false, multiValued = false)
+ String protonKey = KEY_TYPE;
+
+ public String version = null;
+
+ @Override
+ public void execute() {
+ try {
+ if (ipAddress != null && isValidIP(ipAddress) && isValidPort(port)
+ && isValidMode(mode) && isValidProtonKey(protonKey)
+ && isSeverReachable()) {
+ String url = GLUON_HTTP + ipAddress + ":" + port;
+ if (isEtcdSeverAvailable()) {
+ //Gets gluon server running version
+ version = gluonServerVersion();
+ createServer(url, protonKey, mode, version);
+ } else {
+ log.info(NO_SERVER_AVAIL_ON_PORT);
+ return;
+ }
+ } else {
+ log.info(WRONG_INPUT);
+ }
+ } catch (Exception e) {
+ print(null, e.getMessage());
+ }
+ }
+
+ /**
+ * Returns boolean if given IP format is valid.
+ *
+ * @param ipAddr Ip Address
+ * @return boolean
+ */
+ public boolean isValidIP(String ipAddr) {
+ boolean isIPaddrValid;
+ Pattern pattern = Pattern.compile("^(\\d{1,3})\\" +
+ ".(\\d{1,3})\\" +
+ ".(\\d{1,3})\\.(\\d{1,3})$");
+ Matcher matcher = pattern.matcher(ipAddr);
+ if (matcher.find()) {
+ isIPaddrValid = true;
+ } else {
+ print(WRONG_IP_FORMAT);
+ isIPaddrValid = false;
+ }
+ return isIPaddrValid;
+ }
+
+ /**
+ * Returns boolean if given port value is valid.
+ *
+ * @param portValue port number
+ * @return boolean
+ */
+ public boolean isValidPort(String portValue) {
+ boolean isPortValid = false;
+ try {
+ Integer portNum = Integer.parseInt(portValue);
+ if (portNum >= 0 && portNum <= 65535) {
+ isPortValid = true;
+ } else {
+ print(INVALID_RANGE);
+ isPortValid = false;
+ }
+ } catch (NumberFormatException nfe) {
+ print(WRONG_INPUT_TYPE);
+ }
+ return isPortValid;
+ }
+
+ /**
+ * Returns boolean if given mode is valid.
+ *
+ * @param mode server mode
+ * @return boolean
+ */
+ public boolean isValidMode(String mode) {
+ boolean isValidMode;
+ if (mode.equalsIgnoreCase(MODE_START) ||
+ mode.equalsIgnoreCase(MODE_STOP)) {
+ isValidMode = true;
+ } else {
+ print(INVALID_MODE);
+ isValidMode = false;
+ }
+ return isValidMode;
+ }
+
+ /**
+ * Returns boolean if given mode is valid.
+ *
+ * @param key key
+ * @return boolean
+ */
+ public boolean isValidProtonKey(String key) {
+ boolean isValidProtonKey = true;
+ if (!KEY_TYPE.equalsIgnoreCase(key)) {
+ print(PROTON_KEY_SUPPORT);
+ isValidProtonKey = false;
+ }
+ return isValidProtonKey;
+ }
+
+ /**
+ * Returns version of gluon server.
+ *
+ * @return String
+ */
+
+ public String gluonServerVersion() {
+ String serverUrl = GLUON_HTTP + this.ipAddress + ":" +
+ this.port + "/version";
+ GluonServer gluonServer = new GluonServer();
+ String gluonversion = gluonServer.getGluonServerVersion(serverUrl);
+ String[] versionArray = gluonversion.split("\\.");
+ version = versionArray[0];
+ return version;
+ }
+
+ /**
+ * Returns reachability of Gluon server.
+ *
+ * @return isSeverReachable
+ */
+ public boolean isSeverReachable() {
+ boolean isSeverReachable = false;
+ try {
+ InetAddress inet = InetAddress.getByName(ipAddress);
+ if (inet.isReachable(5000)) {
+ isSeverReachable = true;
+ } else {
+ isSeverReachable = false;
+ print(NO_SERVER_AVAIL);
+ }
+ } catch (IOException e) {
+ isSeverReachable = false;
+ log.error("Check server process is failed with {} ",
+ e.getMessage());
+ }
+ return isSeverReachable;
+ }
+
+ /**
+ * Returns availability of Gluon server.
+ *
+ * @return isServerAvailable
+ */
+ public boolean isEtcdSeverAvailable() {
+ String serverUrl = GLUON_HTTP + ipAddress + ":" + port;
+ boolean isServerAvailable;
+ try {
+ URL url = new URL(serverUrl);
+ URLConnection connection = url.openConnection();
+ connection.connect();
+ isServerAvailable = true;
+ } catch (IOException e) {
+ print(NO_SERVER_AVAIL_ON_PORT);
+ isServerAvailable = false;
+ }
+ return isServerAvailable;
+ }
+}
diff --git a/apps/gluon/src/main/java/org/onosproject/gluon/rsc/cli/GluonServerListCommand.java b/apps/gluon/src/main/java/org/onosproject/gluon/rsc/cli/GluonServerListCommand.java
new file mode 100755
index 0000000..3ef4a43
--- /dev/null
+++ b/apps/gluon/src/main/java/org/onosproject/gluon/rsc/cli/GluonServerListCommand.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.gluon.rsc.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.gluon.manager.GluonManager;
+import org.onosproject.gluon.rsc.GluonServer;
+
+import java.util.Map;
+
+import static org.onosproject.gluon.manager.GluonManager.getAllServersIP;
+import static org.onosproject.gluon.rsc.GluonConstants.ACTIVE_SERVER;
+import static org.onosproject.gluon.rsc.GluonConstants.GLUON_DEFAULT_PORT;
+import static org.onosproject.gluon.rsc.GluonConstants.GLUON_HTTP;
+import static org.onosproject.gluon.rsc.GluonConstants.SERVER_POOL;
+
+/**
+ * Supports for querying Gluon Servers list and statistics.
+ */
+@Command(scope = "onos", name = "gluon-server-list",
+ description = "Gluon server list")
+public class GluonServerListCommand extends AbstractShellCommand {
+
+ @Option(name = "-i", aliases = "--server-ip",
+ description = "Supports for querying Gluon server statistics",
+ required = false, multiValued = false)
+ String ipAddress = null;
+
+ @Option(name = "-p", aliases = "--port", description = "Gluon server port",
+ required = false, multiValued = false)
+ String port = GLUON_DEFAULT_PORT;
+
+ protected Map<String, GluonServer> serverMap = getAllServersIP();
+
+ private static final String SERVER_STATISTICS =
+ "Server %s details:\nVersion: %s\nPort: %s\nReal time data:\n" +
+ "\tSet Statistics : %s\n\tDelete Statistics: %s\n" +
+ "Batch data:\n\tGet Statistics : %s";
+
+
+ @Override
+ public void execute() {
+ try {
+ String serverUrl = GLUON_HTTP + ipAddress + ":" + port;
+ if (ipAddress != null && checkServerPool(serverUrl)) {
+ for (Map.Entry<String,
+ GluonServer> server : serverMap.entrySet()) {
+
+ if (serverUrl.equals(server.getKey())) {
+ //Gets Etcd object reference
+ GluonServer gluonServer = server.getValue();
+ //Gets Etcd version from server list
+ print(SERVER_STATISTICS, ipAddress, gluonServer.version,
+ port, gluonServer.getSetCount(),
+ gluonServer.getDelCount(),
+ gluonServer.getGetCount());
+ }
+ }
+ } else {
+ int totalServers = GluonManager.getTotalServers();
+ log.info(ACTIVE_SERVER, totalServers);
+ print("Number of active servers: " + totalServers);
+ printServersIP();
+ }
+ } catch (Exception e) {
+ print(null, e.getMessage());
+ }
+ }
+
+ /**
+ * Prints all servers IPs in table format.
+ */
+ protected void printServersIP() {
+ int countServer = 1;
+ for (Map.Entry<String, GluonServer> server : serverMap.entrySet()) {
+ String serverUrl = server.getKey();
+ String[] serverIP = serverUrl.split("//");
+ print("Server %d: %s", countServer, serverIP[1]);
+ countServer++;
+ }
+ }
+
+ /**
+ * Returns boolean if given IP available in server pool.
+ *
+ * @param ipAddr Ip Address
+ * @return boolean
+ */
+ protected boolean checkServerPool(String ipAddr) {
+ boolean isServerAvailable;
+ if (serverMap.containsKey(ipAddr)) {
+ isServerAvailable = true;
+ } else {
+ print(SERVER_POOL);
+ isServerAvailable = false;
+ }
+ return isServerAvailable;
+ }
+}
diff --git a/apps/gluon/src/main/java/org/onosproject/gluon/rsc/cli/package-info.java b/apps/gluon/src/main/java/org/onosproject/gluon/rsc/cli/package-info.java
new file mode 100755
index 0000000..274ff4d
--- /dev/null
+++ b/apps/gluon/src/main/java/org/onosproject/gluon/rsc/cli/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Gluon Shim Application Command line interface package.
+ */
+package org.onosproject.gluon.rsc.cli;
\ No newline at end of file
diff --git a/apps/gluon/src/main/java/org/onosproject/gluon/rsc/package-info.java b/apps/gluon/src/main/java/org/onosproject/gluon/rsc/package-info.java
new file mode 100755
index 0000000..f2506ea
--- /dev/null
+++ b/apps/gluon/src/main/java/org/onosproject/gluon/rsc/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Gluon Shim Application resource package.
+ */
+package org.onosproject.gluon.rsc;
\ No newline at end of file
diff --git a/apps/gluon/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/gluon/src/main/resources/OSGI-INF/blueprint/shell-config.xml
new file mode 100755
index 0000000..82809d2
--- /dev/null
+++ b/apps/gluon/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -0,0 +1,27 @@
+<!--
+ ~ Copyright 2017-present Open Networking Foundation
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+ <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+ <command>
+ <action class="org.onosproject.gluon.rsc.cli.GluonServerCommand"/>
+ </command>
+
+ <command>
+ <action class="org.onosproject.gluon.rsc.cli.GluonServerListCommand"/>
+ </command>
+ </command-bundle>
+</blueprint>
diff --git a/apps/pom.xml b/apps/pom.xml
index 7978976..3351e39 100644
--- a/apps/pom.xml
+++ b/apps/pom.xml
@@ -89,6 +89,7 @@
<module>yang</module>
<module>openroadm</module>
<module>netconf/client</module>
+ <module>gluon</module>
</modules>
<properties>
diff --git a/lib/BUCK b/lib/BUCK
index 1013dcf..e3b6a78 100644
--- a/lib/BUCK
+++ b/lib/BUCK
@@ -933,6 +933,33 @@
)
remote_jar (
+ name = 'org.apache.httpcomponents.httpasyncclient-osgi',
+ out = 'httpasyncclient-osgi-4.1.2.jar',
+ url = 'mvn:org.apache.httpcomponents:httpasyncclient-osgi:jar:4.1.2',
+ sha1 = '17eccd8d9f2803ee95e80ee8283155432600e17b',
+ maven_coords = 'org.apache.httpcomponents:httpasyncclient-osgi:4.1.2',
+ visibility = [ 'PUBLIC' ],
+)
+
+remote_jar (
+ name = 'org.apache.httpcomponents.httpcore-nio',
+ out = 'httpcore-nio-4.4.4.jar',
+ url = 'mvn:org.apache.httpcomponents:httpcore-nio:jar:4.4.4',
+ sha1 = '16badfc2d99db264c486ba8c57ae577301a58bd9',
+ maven_coords = 'org.apache.httpcomponents:httpcore-nio:jar:NON-OSGI:4.4.4',
+ visibility = [ 'PUBLIC' ],
+)
+
+remote_jar (
+ name = 'org.apache.karaf.jaas',
+ out = 'org.apache.karaf.jaas.modules-3.0.5.jar',
+ url = 'mvn:org.apache.karaf.jaas:org.apache.karaf.jaas.modules:jar:3.0.5',
+ sha1 = '008ff2ef5fa49f346789dfa8919c0537b6261864',
+ maven_coords = 'org.apache.karaf.jaas:org.apache.karaf.jaas.modules:3.0.5',
+ visibility = [ 'PUBLIC' ],
+)
+
+remote_jar (
name = 'org.apache.karaf.system.core',
out = 'org.apache.karaf.system.core-3.0.8.jar',
url = 'mvn:org.apache.karaf.system:org.apache.karaf.system.core:jar:3.0.8',
diff --git a/lib/deps.json b/lib/deps.json
index 5dd2f70..b5675dd 100644
--- a/lib/deps.json
+++ b/lib/deps.json
@@ -196,6 +196,9 @@
"org.apache.felix.scr.annotations": "mvn:org.apache.felix:org.apache.felix.scr.annotations:1.9.12",
"org.apache.karaf.features.core": "mvn:org.apache.karaf.features:org.apache.karaf.features.core:3.0.8",
"org.apache.karaf.shell.console": "mvn:org.apache.karaf.shell:org.apache.karaf.shell.console:3.0.8",
+ "org.apache.httpcomponents.httpasyncclient-osgi": "mvn:org.apache.httpcomponents:httpasyncclient-osgi:4.1.2",
+ "org.apache.httpcomponents.httpcore-nio": "mvn:org.apache.httpcomponents:httpcore-nio:4.4.4",
+ "org.apache.karaf.jaas": "mvn:org.apache.karaf.jaas:org.apache.karaf.jaas.modules:3.0.5",
"org.apache.karaf.system.core": "mvn:org.apache.karaf.system:org.apache.karaf.system.core:3.0.8",
"org.apache.servicemix.bundles.snmp4j": "mvn:org.apache.servicemix.bundles:org.apache.servicemix.bundles.snmp4j:2.3.4_1",
"org.osgi.compendium": "mvn:org.osgi:org.osgi.compendium:5.0.0",
diff --git a/modules.defs b/modules.defs
index b18fcbe..350fc38 100644
--- a/modules.defs
+++ b/modules.defs
@@ -208,6 +208,7 @@
'//apps/l3vpn:onos-apps-l3vpn-oar',
'//apps/openroadm:onos-apps-openroadm-oar',
'//apps/artemis:onos-apps-artemis-oar',
+ '//apps/gluon:onos-apps-gluon-oar',
]
PROTOCOL_APPS = [