ONOS-6245:Intent_mini_summary
Change-Id: I35fe2b5b3f2a24680bbef93ee31e4655b972ff45
diff --git a/core/api/src/main/java/org/onosproject/net/intent/util/IntentMiniSummary.java b/core/api/src/main/java/org/onosproject/net/intent/util/IntentMiniSummary.java
new file mode 100644
index 0000000..99e2ae9
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/intent/util/IntentMiniSummary.java
@@ -0,0 +1,255 @@
+/*
+ * 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.net.intent.util;
+
+import org.onlab.util.Tools;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.IntentState;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.MoreObjects.firstNonNull;
+
+/**
+ * Lists the summary of intents and their states.
+ */
+public final class IntentMiniSummary {
+
+ private String intentType;
+ private int total = 0;
+ private int installReq = 0;
+ private int compiling = 0;
+ private int installing = 0;
+ private int installed = 0;
+ private int recompiling = 0;
+ private int withdrawReq = 0;
+ private int withdrawing = 0;
+ private int withdrawn = 0;
+ private int failed = 0;
+ private int unknownState = 0;
+
+ IntentMiniSummary(Intent intent, IntentService intentService) {
+ // remove "Intent" from intentType label
+ this.intentType = intentType(intent);
+ update(intentService.getIntentState(intent.key()));
+ }
+
+ IntentMiniSummary(String intentType) {
+ // remove "Intent" from intentType label
+ this.intentType = intentType;
+ }
+
+ public IntentMiniSummary() {
+
+ }
+
+ private static String intentType(Intent intent) {
+ return intent.getClass().getSimpleName().replace("Intent", "");
+ }
+
+ /**
+ * Returns intent Type.
+ * @return intentType
+ */
+ public String getIntentType() {
+ return intentType;
+ }
+
+ /**
+ * Returns total intent count.
+ * @return total
+ */
+ public int getTotal() {
+ return total;
+ }
+
+ /**
+ * Returns InstallReq intent count.
+ * @return InstallReq
+ */
+ public int getInstallReq() {
+ return installReq;
+ }
+
+ /**
+ * Returns Compiling intent count.
+ * @return Compiling
+ */
+ public int getCompiling() {
+ return compiling;
+ }
+
+ /**
+ * Returns Installing intent count.
+ * @return Installing
+ */
+ public int getInstalling() {
+ return installing;
+ }
+
+ /**
+ * Returns Installed intent count.
+ * @return Installed
+ */
+ public int getInstalled() {
+ return installed;
+ }
+
+ /**
+ * Returns Recompiling intent count.
+ * @return Recompiling
+ */
+ public int getRecompiling() {
+ return recompiling;
+ }
+
+ /**
+ * Returns WithdrawReq intent count.
+ * @return WithdrawReq
+ */
+ public int getWithdrawReq() {
+ return withdrawReq;
+ }
+
+ /**
+ * Returns Withdrawing intent count.
+ * @return Withdrawing
+ */
+ public int getWithdrawing() {
+ return withdrawing;
+ }
+
+ /**
+ * Returns Withdrawn intent count.
+ * @return Withdrawn
+ */
+ public int getWithdrawn() {
+ return withdrawn;
+ }
+
+ /**
+ * Returns Failed intent count.
+ * @return Failed
+ */
+ public int getFailed() {
+ return failed;
+ }
+
+ /**
+ * Returns unknownState intent count.
+ * @return unknownState
+ */
+ public int getUnknownState() {
+ return unknownState;
+ }
+
+ /**
+ * Updates the Intent Summary.
+ *
+ * @param intentState the state of the intent
+ */
+ public void update(IntentState intentState) {
+ total++;
+ switch (intentState) {
+ case INSTALL_REQ:
+ installReq++;
+ break;
+ case COMPILING:
+ compiling++;
+ break;
+ case INSTALLING:
+ installing++;
+ break;
+ case INSTALLED:
+ installed++;
+ break;
+ case RECOMPILING:
+ recompiling++;
+ break;
+ case WITHDRAW_REQ:
+ withdrawReq++;
+ break;
+ case WITHDRAWING:
+ withdrawing++;
+ break;
+ case WITHDRAWN:
+ withdrawn++;
+ break;
+ case FAILED:
+ failed++;
+ break;
+ default:
+ unknownState++;
+ break;
+ }
+ }
+
+ /**
+ * Build summary of intents per intent type.
+ *
+ * @param intents to summarize
+ * @param intentService to get IntentState
+ * @return summaries per Intent type
+ */
+ public Map<String, IntentMiniSummary> summarize(Iterable<Intent> intents, IntentService intentService) {
+ Map<String, List<Intent>> perIntent = Tools.stream(intents)
+ .collect(Collectors.groupingBy(IntentMiniSummary::intentType));
+
+ List<IntentMiniSummary> collect = perIntent.values().stream()
+ .map(il ->
+ il.stream()
+ .map(intent -> new IntentMiniSummary(intent, intentService))
+ .reduce(new IntentMiniSummary(), this::merge)
+ ).collect(Collectors.toList());
+
+ Map<String, IntentMiniSummary> summaries = new HashMap<>();
+
+ // individual
+ collect.forEach(is -> summaries.put(is.intentType, is));
+
+ // all summarised
+ summaries.put("All", collect.stream()
+ .reduce(new IntentMiniSummary("All"), this::merge));
+ return summaries;
+ }
+
+ /**
+ * Merges 2 {@link IntentMiniSummary} together.
+ *
+ * @param a element to merge
+ * @param b element to merge
+ * @return merged {@link IntentMiniSummary}
+ */
+ IntentMiniSummary merge(IntentMiniSummary a, IntentMiniSummary b) {
+ IntentMiniSummary m = new IntentMiniSummary(firstNonNull(a.getIntentType(), b.getIntentType()));
+ m.total = a.total + b.total;
+ m.installReq = a.installReq + b.installReq;
+ m.compiling = a.compiling + b.compiling;
+ m.installing = a.installing + b.installing;
+ m.installed = a.installed + b.installed;
+ m.recompiling = a.recompiling + b.recompiling;
+ m.withdrawing = a.withdrawing + b.withdrawing;
+ m.withdrawReq = a.withdrawReq + b.withdrawReq;
+ m.withdrawn = a.withdrawn + b.withdrawn;
+ m.failed = a.failed + b.failed;
+ m.unknownState = a.unknownState + b.unknownState;
+ return m;
+ }
+}
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/CodecManager.java b/core/common/src/main/java/org/onosproject/codec/impl/CodecManager.java
index 570d696..2251ff2 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/CodecManager.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/CodecManager.java
@@ -77,6 +77,7 @@
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.PointToPointIntent;
import org.onosproject.net.intent.SinglePointToMultiPointIntent;
+import org.onosproject.net.intent.util.IntentMiniSummary;
import org.onosproject.net.key.DeviceKey;
import org.onosproject.net.mcast.McastRoute;
import org.onosproject.net.meter.Band;
@@ -122,6 +123,7 @@
registerCodec(Host.class, new HostCodec());
registerCodec(HostLocation.class, new HostLocationCodec());
registerCodec(HostToHostIntent.class, new HostToHostIntentCodec());
+ registerCodec(IntentMiniSummary.class, new IntentMiniSummaryCodec());
registerCodec(PointToPointIntent.class, new PointToPointIntentCodec());
registerCodec(SinglePointToMultiPointIntent.class, new SinglePointToMultiPointIntentCodec());
registerCodec(Intent.class, new IntentCodec());
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/IntentMiniSummaryCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/IntentMiniSummaryCodec.java
new file mode 100644
index 0000000..aeca1e2
--- /dev/null
+++ b/core/common/src/main/java/org/onosproject/codec/impl/IntentMiniSummaryCodec.java
@@ -0,0 +1,60 @@
+/*
+ * 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.codec.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.net.intent.util.IntentMiniSummary;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Intent MiniSummary JSON codec.
+ */
+public class IntentMiniSummaryCodec extends JsonCodec<IntentMiniSummary> {
+ private static final String TOTAL = "total";
+ private static final String INSTALLREQ = "installReq";
+ private static final String COMPILING = "compiling";
+ private static final String INSTALLING = "installing";
+ private static final String INSTALLED = "installed";
+ private static final String RECOMPILING = "recompiling";
+ private static final String WITHDRAWREQ = "withdrawReq";
+ private static final String WITHDRAWING = "withdrawing";
+ private static final String WITHDRAWN = "withdrawn";
+ private static final String FAILED = "failed";
+ private static final String UNKNOWNSTATE = "unknownState";
+
+ @Override
+ public ObjectNode encode(IntentMiniSummary intentminisummary, CodecContext context) {
+ checkNotNull(intentminisummary, "intentminisummary cannot be null");
+ ObjectMapper mapper = new ObjectMapper();
+ ObjectNode result = mapper.createObjectNode()
+ .put(TOTAL, intentminisummary.getTotal())
+ .put(INSTALLED, intentminisummary.getInstalled())
+ .put(FAILED, intentminisummary.getFailed())
+ .put(INSTALLREQ, intentminisummary.getInstallReq())
+ .put(INSTALLING, intentminisummary.getInstalling())
+ .put(COMPILING, intentminisummary.getCompiling())
+ .put(RECOMPILING, intentminisummary.getRecompiling())
+ .put(WITHDRAWREQ, intentminisummary.getWithdrawReq())
+ .put(WITHDRAWING, intentminisummary.getWithdrawing())
+ .put(WITHDRAWN, intentminisummary.getWithdrawn())
+ .put(UNKNOWNSTATE, intentminisummary.getUnknownState());
+ return result;
+ }
+}
diff --git a/web/api/src/main/java/org/onosproject/rest/resources/IntentsWebResource.java b/web/api/src/main/java/org/onosproject/rest/resources/IntentsWebResource.java
index 409dcc3..675581d 100644
--- a/web/api/src/main/java/org/onosproject/rest/resources/IntentsWebResource.java
+++ b/web/api/src/main/java/org/onosproject/rest/resources/IntentsWebResource.java
@@ -31,6 +31,7 @@
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.intent.Key;
import org.onosproject.net.intent.util.IntentFilter;
+import org.onosproject.net.intent.util.IntentMiniSummary;
import org.onosproject.rest.AbstractWebResource;
import org.slf4j.Logger;
@@ -49,6 +50,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -97,6 +99,29 @@
return ok(root).build();
}
+
+ /**
+ * Gets Summary of all intents.
+ * Returns Summary of the intents in the system.
+ *
+ * @return 200 OK with Summary of all the intents in the system
+ * @onos.rsModel Minisummary
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("minisummary")
+ public Response getIntentSummary() {
+ final Iterable<Intent> intents = get(IntentService.class).getIntents();
+ ObjectNode root = mapper().createObjectNode();
+ IntentMiniSummary intentminisummary = new IntentMiniSummary();
+ Map<String, IntentMiniSummary> map = intentminisummary.summarize(intents, get(IntentService.class));
+ map.values().stream().forEach(intentsummary -> {
+ root.put(intentsummary.getIntentType(), codec(IntentMiniSummary.class).encode(intentsummary, this));
+ });
+ return ok(root).build();
+ }
+
+
/**
* Gets intent intallables by application ID and key.
* @param appId application identifier
diff --git a/web/api/src/main/resources/definitions/Minisummary.json b/web/api/src/main/resources/definitions/Minisummary.json
new file mode 100644
index 0000000..9bf1c33
--- /dev/null
+++ b/web/api/src/main/resources/definitions/Minisummary.json
@@ -0,0 +1,70 @@
+{
+ "type": "object",
+ "title":"All",
+ "required": [
+ "All"
+ ],
+ "properties": {
+ "All": {
+ "required": [
+ "total",
+ "installed",
+ "failed",
+ "installReq",
+ "installing",
+ "compiling",
+ "recompiling",
+ "withdrawReq",
+ "withdrawing",
+ "withdrawn",
+ "unknownState"
+ ],
+ "properties": {
+ "total": {
+ "type": "integer",
+ "example": 1
+ },
+ "installed": {
+ "type": "integer",
+ "example": 0
+ },
+ "failed": {
+ "type": "integer",
+ "example": 0
+ },
+ "installReq": {
+ "type": "integer",
+ "example": 0
+ },
+ "installing": {
+ "type": "integer",
+ "example": 0
+ },
+ "compiling": {
+ "type": "integer",
+ "example": 0
+ },
+ "recompiling": {
+ "type": "integer",
+ "example": 0
+ },
+ "withdrawReq": {
+ "type": "integer",
+ "example": 0
+ },
+ "withdrawing": {
+ "type": "integer",
+ "example": 0
+ },
+ "withdrawn": {
+ "type": "integer",
+ "example": 0
+ },
+ "unknownState": {
+ "type": "integer",
+ "example": 0
+ }
+ }
+ }
+ }
+}
diff --git a/web/api/src/test/java/org/onosproject/rest/resources/IntentsResourceTest.java b/web/api/src/test/java/org/onosproject/rest/resources/IntentsResourceTest.java
index c9c5c1f..ea1fc47 100644
--- a/web/api/src/test/java/org/onosproject/rest/resources/IntentsResourceTest.java
+++ b/web/api/src/test/java/org/onosproject/rest/resources/IntentsResourceTest.java
@@ -65,6 +65,7 @@
import org.onosproject.net.intent.MockIdGenerator;
import org.onosproject.net.provider.ProviderId;
+
import javax.ws.rs.NotFoundException;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
@@ -476,7 +477,7 @@
/**
* Factory to allocate an IntentRelatedFlows matcher.
*
- * @param pathEntries list of path conatining flow entries of a particular intent
+ * @param pathEntries list of path conatining flow entries of a particular intent
* @param expectedAppId expected app id we are looking for
* @return matcher
*/
@@ -735,7 +736,7 @@
.andReturn(IntentState.INSTALLED)
.anyTimes();
// Register the services needed for the test
- final CodecManager codecService = new CodecManager();
+ final CodecManager codecService = new CodecManager();
codecService.activate();
ServiceDirectory testDirectory =
new TestServiceDirectory()
@@ -1116,4 +1117,30 @@
assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
}
+ @Test
+ public void testIntentsMiniSummary() {
+ final Intent intent1 = new MockIntent(1L, Collections.emptyList());
+ final HashSet<NetworkResource> resources = new HashSet<>();
+ resources.add(new MockResource(1));
+ resources.add(new MockResource(2));
+ resources.add(new MockResource(3));
+ final Intent intent2 = new MockIntent(2L, resources);
+ intents.add(intent1);
+ intents.add(intent2);
+ final WebTarget wt = target();
+ replay(mockIntentService);
+ final String response = wt.path("intents/minisummary").request().get(String.class);
+ assertThat(response, containsString("{\"All\":{"));
+ final JsonObject result = Json.parse(response).asObject();
+ assertThat(result, notNullValue());
+ assertThat(result.names(), hasSize(2));
+ assertThat(result.names().get(0), containsString("All"));
+ JsonObject jsonIntents = (JsonObject) result.get("All");
+ assertThat(jsonIntents, notNullValue());
+ assertThat(jsonIntents.get("total").toString(), containsString("2"));
+ jsonIntents = (JsonObject) result.get("Mock");
+ assertThat(jsonIntents, notNullValue());
+ assertThat(jsonIntents.get("installed").toString(), containsString("2"));
+ }
}
+