From 7fe7eaf5280dc249dd1f45eeb6db353352353fdc Mon Sep 17 00:00:00 2001
From: Jian Li
* <configs> - * <config name=“...” [manufacturer="..." swVersion="..."]> - * [<property name=“key”>value</key>] + * <config name="..." [manufacturer="..." swVersion="..."]> + * [<property name="key">value</key>] * ... * </config> * ... @@ -203,10 +204,16 @@ public class XmlTelemetryConfigLoader { ImmutableMap.Builderproperties = ImmutableMap.builder(); // note that, we only allow the inheritance from single source - Map parentConfigs = Maps.newHashMap(); + final Map parentConfigs = Maps.newHashMap(); if (!parents.isEmpty()) { TelemetryConfig parent = parents.get(0); - parentConfigs = parent.properties(); + parent.properties().forEach(parentConfigs::put); + } + + for (HierarchicalConfiguration b : config.configurationsAt(PROPERTY)) { + if (parentConfigs.keySet().contains(b.getString(NAME))) { + parentConfigs.remove(b.getString(NAME)); + } } properties.putAll(parentConfigs); @@ -214,6 +221,7 @@ public class XmlTelemetryConfigLoader { for (HierarchicalConfiguration b : config.configurationsAt(PROPERTY)) { properties.put(b.getString(NAME), (String) b.getRootNode().getValue()); } + return properties.build(); } } diff --git a/apps/openstacktelemetry/app/src/main/resources/definitions/dummy.json b/apps/openstacktelemetry/app/src/main/resources/definitions/dummy.json deleted file mode 100644 index 7a73a41bfd..0000000000 --- a/apps/openstacktelemetry/app/src/main/resources/definitions/dummy.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} \ No newline at end of file diff --git a/apps/openstacktelemetry/app/src/main/resources/org/onosproject/openstacktelemetry/impl/kafka-configs.xml b/apps/openstacktelemetry/app/src/main/resources/org/onosproject/openstacktelemetry/impl/kafka-configs.xml index 7429ac2845..48623b6621 100644 --- a/apps/openstacktelemetry/app/src/main/resources/org/onosproject/openstacktelemetry/impl/kafka-configs.xml +++ b/apps/openstacktelemetry/app/src/main/resources/org/onosproject/openstacktelemetry/impl/kafka-configs.xml @@ -34,6 +34,8 @@ sona.flow flowdata -TinaMessageByteBufferCodec ++ org.onosproject.openstacktelemetry.codec.bytebuffer.TinaMessageByteBufferCodec + \ No newline at end of file diff --git a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/TinaFlowInfoByteBufferCodecTest.java b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/bytebuffer/TinaFlowInfoByteBufferCodecTest.java similarity index 92% rename from apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/TinaFlowInfoByteBufferCodecTest.java rename to apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/bytebuffer/TinaFlowInfoByteBufferCodecTest.java index 8f4af77b97..b1f48e4b49 100644 --- a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/TinaFlowInfoByteBufferCodecTest.java +++ b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/bytebuffer/TinaFlowInfoByteBufferCodecTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onosproject.openstacktelemetry.codec; +package org.onosproject.openstacktelemetry.codec.bytebuffer; import com.google.common.testing.EqualsTester; import org.junit.Before; @@ -24,10 +24,10 @@ import org.onlab.packet.MacAddress; import org.onlab.packet.TpPort; import org.onlab.packet.VlanId; import org.onosproject.net.DeviceId; +import org.onosproject.openstacktelemetry.api.DefaultFlowInfo; +import org.onosproject.openstacktelemetry.api.DefaultStatsInfo; import org.onosproject.openstacktelemetry.api.FlowInfo; import org.onosproject.openstacktelemetry.api.StatsInfo; -import org.onosproject.openstacktelemetry.impl.DefaultFlowInfo; -import org.onosproject.openstacktelemetry.impl.DefaultStatsInfo; import java.nio.ByteBuffer; @@ -52,8 +52,7 @@ public final class TinaFlowInfoByteBufferCodecTest { private static final MacAddress DST_MAC_ADDRESS = MacAddress.valueOf("FF:EE:DD:CC:BB:AA"); private FlowInfo info; - private final TinaFlowInfoByteBufferCodec codec = - new TinaFlowInfoByteBufferCodec(); + private final TinaFlowInfoByteBufferCodec codec = new TinaFlowInfoByteBufferCodec(); /** * Initial setup for this unit test. diff --git a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/TinaStatsInfoByteBufferCodecTest.java b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/bytebuffer/TinaStatsInfoByteBufferCodecTest.java similarity index 90% rename from apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/TinaStatsInfoByteBufferCodecTest.java rename to apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/bytebuffer/TinaStatsInfoByteBufferCodecTest.java index f32e5bbcdb..d217aea34a 100644 --- a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/TinaStatsInfoByteBufferCodecTest.java +++ b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/bytebuffer/TinaStatsInfoByteBufferCodecTest.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onosproject.openstacktelemetry.codec; +package org.onosproject.openstacktelemetry.codec.bytebuffer; import com.google.common.testing.EqualsTester; import org.junit.Before; import org.junit.Test; +import org.onosproject.openstacktelemetry.api.DefaultStatsInfo; import org.onosproject.openstacktelemetry.api.StatsInfo; -import org.onosproject.openstacktelemetry.impl.DefaultStatsInfo; import java.nio.ByteBuffer; @@ -39,8 +39,7 @@ public class TinaStatsInfoByteBufferCodecTest { private static final short DROP_PACKETS = 30000; private StatsInfo info; - private final TinaStatsInfoByteBufferCodec codec = - new TinaStatsInfoByteBufferCodec(); + private final TinaStatsInfoByteBufferCodec codec = new TinaStatsInfoByteBufferCodec(); /** * Initial setup for this unit test. diff --git a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultGrpcTelemetryConfigTest.java b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultGrpcTelemetryConfigTest.java index c56247f8e0..89fc1d0533 100644 --- a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultGrpcTelemetryConfigTest.java +++ b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultGrpcTelemetryConfigTest.java @@ -23,7 +23,7 @@ import org.junit.Before; import org.junit.Test; import org.onosproject.openstacktelemetry.api.config.GrpcTelemetryConfig; import org.onosproject.openstacktelemetry.api.config.TelemetryConfig; -import org.onosproject.openstacktelemetry.impl.DefaultTelemetryConfig; +import org.onosproject.openstacktelemetry.api.DefaultTelemetryConfig; import java.util.Map; diff --git a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultInfluxDbTelemetryConfigTest.java b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultInfluxDbTelemetryConfigTest.java index cd4a9737f3..9f8401536c 100644 --- a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultInfluxDbTelemetryConfigTest.java +++ b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultInfluxDbTelemetryConfigTest.java @@ -23,7 +23,7 @@ import org.junit.Before; import org.junit.Test; import org.onosproject.openstacktelemetry.api.config.InfluxDbTelemetryConfig; import org.onosproject.openstacktelemetry.api.config.TelemetryConfig; -import org.onosproject.openstacktelemetry.impl.DefaultTelemetryConfig; +import org.onosproject.openstacktelemetry.api.DefaultTelemetryConfig; import java.util.Map; diff --git a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultKafkaTelemetryConfigTest.java b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultKafkaTelemetryConfigTest.java index ba9b34ba60..999bcf16db 100644 --- a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultKafkaTelemetryConfigTest.java +++ b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultKafkaTelemetryConfigTest.java @@ -23,7 +23,7 @@ import org.junit.Before; import org.junit.Test; import org.onosproject.openstacktelemetry.api.config.KafkaTelemetryConfig; import org.onosproject.openstacktelemetry.api.config.TelemetryConfig; -import org.onosproject.openstacktelemetry.impl.DefaultTelemetryConfig; +import org.onosproject.openstacktelemetry.api.DefaultTelemetryConfig; import java.util.Map; diff --git a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultPrometheusTelemetryConfigTest.java b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultPrometheusTelemetryConfigTest.java index de94f8306e..4a89b74a74 100644 --- a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultPrometheusTelemetryConfigTest.java +++ b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultPrometheusTelemetryConfigTest.java @@ -23,7 +23,7 @@ import org.junit.Before; import org.junit.Test; import org.onosproject.openstacktelemetry.api.config.PrometheusTelemetryConfig; import org.onosproject.openstacktelemetry.api.config.TelemetryConfig; -import org.onosproject.openstacktelemetry.impl.DefaultTelemetryConfig; +import org.onosproject.openstacktelemetry.api.DefaultTelemetryConfig; import java.util.Map; diff --git a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultRestTelemetryConfigTest.java b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultRestTelemetryConfigTest.java index c78bb63383..28b84650ec 100644 --- a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultRestTelemetryConfigTest.java +++ b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/config/DefaultRestTelemetryConfigTest.java @@ -23,7 +23,7 @@ import org.junit.Before; import org.junit.Test; import org.onosproject.openstacktelemetry.api.config.RestTelemetryConfig; import org.onosproject.openstacktelemetry.api.config.TelemetryConfig; -import org.onosproject.openstacktelemetry.impl.DefaultTelemetryConfig; +import org.onosproject.openstacktelemetry.api.DefaultTelemetryConfig; import java.util.Map; diff --git a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/impl/DefaultInfluxRecordTest.java b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/impl/DefaultInfluxRecordTest.java index 866e34d76c..da693803f4 100644 --- a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/impl/DefaultInfluxRecordTest.java +++ b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/impl/DefaultInfluxRecordTest.java @@ -25,6 +25,8 @@ import org.onlab.packet.MacAddress; import org.onlab.packet.TpPort; import org.onlab.packet.VlanId; import org.onosproject.net.DeviceId; +import org.onosproject.openstacktelemetry.api.DefaultFlowInfo; +import org.onosproject.openstacktelemetry.api.DefaultStatsInfo; import org.onosproject.openstacktelemetry.api.FlowInfo; import org.onosproject.openstacktelemetry.api.InfluxRecord; import org.onosproject.openstacktelemetry.api.StatsInfo; diff --git a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/impl/DistributedTelemetryConfigStoreTest.java b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/impl/DistributedTelemetryConfigStoreTest.java index 511fa6ddb5..85f6b413f9 100644 --- a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/impl/DistributedTelemetryConfigStoreTest.java +++ b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/impl/DistributedTelemetryConfigStoreTest.java @@ -22,6 +22,7 @@ import org.junit.Test; import org.onosproject.TestApplicationId; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreServiceAdapter; +import org.onosproject.openstacktelemetry.api.DefaultTelemetryConfig; import org.onosproject.openstacktelemetry.api.config.TelemetryConfig; import org.onosproject.openstacktelemetry.api.config.TelemetryConfig.ConfigType; import org.onosproject.store.service.TestStorageService; diff --git a/apps/openstacktelemetry/web/BUILD b/apps/openstacktelemetry/web/BUILD new file mode 100644 index 0000000000..a677d58fbb --- /dev/null +++ b/apps/openstacktelemetry/web/BUILD @@ -0,0 +1,19 @@ +COMPILE_DEPS = CORE_DEPS + JACKSON + KRYO + REST + [ + "//apps/openstacktelemetry/api:onos-apps-openstacktelemetry-api", +] + +TEST_DEPS = TEST_ADAPTERS + TEST_REST + [ + "//core/api:onos-api-tests", + "//core/common:onos-core-common-tests", + "//web/api:onos-rest-tests", +] + +osgi_jar_with_tests( + api_description = "OpenStack Network Telemetry REST API", + api_package = "org.onosproject.openstacktelemetry.web", + api_title = "OpenStack Network Telemetry REST API", + api_version = "1.0", + test_deps = TEST_DEPS, + web_context = "/onos/openstacktelemetry", + deps = COMPILE_DEPS, +) diff --git a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/codec/FlowInfoJsonCodec.java b/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/codec/rest/FlowInfoJsonCodec.java similarity index 98% rename from apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/codec/FlowInfoJsonCodec.java rename to apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/codec/rest/FlowInfoJsonCodec.java index be51b15453..a6d75ec1e6 100644 --- a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/codec/FlowInfoJsonCodec.java +++ b/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/codec/rest/FlowInfoJsonCodec.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onosproject.openstacktelemetry.codec; +package org.onosproject.openstacktelemetry.codec.rest; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -27,7 +27,7 @@ import org.onosproject.codec.JsonCodec; import org.onosproject.net.DeviceId; import org.onosproject.openstacktelemetry.api.FlowInfo; import org.onosproject.openstacktelemetry.api.StatsInfo; -import org.onosproject.openstacktelemetry.impl.DefaultFlowInfo; +import org.onosproject.openstacktelemetry.api.DefaultFlowInfo; import static com.google.common.base.Preconditions.checkNotNull; import static org.onlab.packet.VlanId.NO_VID; diff --git a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/codec/StatsFlowRuleJsonCodec.java b/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/codec/rest/StatsFlowRuleJsonCodec.java similarity index 80% rename from apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/codec/StatsFlowRuleJsonCodec.java rename to apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/codec/rest/StatsFlowRuleJsonCodec.java index 384987b6a9..3d2b13fc50 100644 --- a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/codec/StatsFlowRuleJsonCodec.java +++ b/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/codec/rest/StatsFlowRuleJsonCodec.java @@ -13,21 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onosproject.openstacktelemetry.codec; +package org.onosproject.openstacktelemetry.codec.rest; import com.fasterxml.jackson.databind.node.ObjectNode; import org.apache.commons.lang3.exception.ExceptionUtils; +import org.onlab.packet.IPv4; +import org.onlab.packet.IpPrefix; import org.onlab.packet.TpPort; import org.onosproject.codec.CodecContext; import org.onosproject.codec.JsonCodec; +import org.onosproject.openstacktelemetry.api.DefaultStatsFlowRule; import org.onosproject.openstacktelemetry.api.StatsFlowRule; -import org.onosproject.openstacktelemetry.impl.DefaultStatsFlowRule; import org.slf4j.Logger; -import org.onlab.packet.IpPrefix; - import static com.google.common.base.Preconditions.checkNotNull; -import static org.onosproject.openstacktelemetry.util.OpenstackTelemetryUtil.getProtocolTypeFromString; import static org.slf4j.LoggerFactory.getLogger; /** @@ -37,6 +36,11 @@ public class StatsFlowRuleJsonCodec extends JsonCodec{ private final Logger log = getLogger(getClass()); + private static final String PROTOCOL_NAME_TCP = "tcp"; + private static final String PROTOCOL_NAME_UDP = "udp"; + private static final String PROTOCOL_NAME_ANY = "any"; + private static final int ARBITRARY_PROTOCOL = 0x0; + public static final String SRC_IP_PREFIX = "srcIpPrefix"; public static final String DST_IP_PREFIX = "dstIpPrefix"; public static final String IP_PROTOCOL = "ipProtocol"; @@ -88,4 +92,21 @@ public class StatsFlowRuleJsonCodec extends JsonCodec { } return null; } + + /** + * Obtains transport protocol type from the given string. + * + * @param str transport protocol name + * @return transport protocol type + */ + private byte getProtocolTypeFromString(String str) { + switch (str.toLowerCase()) { + case PROTOCOL_NAME_TCP: + return IPv4.PROTOCOL_TCP; + case PROTOCOL_NAME_UDP: + return IPv4.PROTOCOL_UDP; + default: + return ARBITRARY_PROTOCOL; + } + } } diff --git a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/codec/StatsInfoJsonCodec.java b/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/codec/rest/StatsInfoJsonCodec.java similarity index 96% rename from apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/codec/StatsInfoJsonCodec.java rename to apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/codec/rest/StatsInfoJsonCodec.java index 905b2ff77f..de8a7ef5ad 100644 --- a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/codec/StatsInfoJsonCodec.java +++ b/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/codec/rest/StatsInfoJsonCodec.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onosproject.openstacktelemetry.codec; +package org.onosproject.openstacktelemetry.codec.rest; import com.fasterxml.jackson.databind.node.ObjectNode; import org.onosproject.codec.CodecContext; import org.onosproject.codec.JsonCodec; import org.onosproject.openstacktelemetry.api.StatsInfo; -import org.onosproject.openstacktelemetry.impl.DefaultStatsInfo; +import org.onosproject.openstacktelemetry.api.DefaultStatsInfo; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/codec/rest/TelemetryConfigJsonCodec.java b/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/codec/rest/TelemetryConfigJsonCodec.java new file mode 100644 index 0000000000..8c0a6e3e9e --- /dev/null +++ b/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/codec/rest/TelemetryConfigJsonCodec.java @@ -0,0 +1,131 @@ +/* + * Copyright 2018-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.openstacktelemetry.codec.rest; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Maps; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.openstacktelemetry.api.DefaultTelemetryConfig; +import org.onosproject.openstacktelemetry.api.config.TelemetryConfig; + +import java.util.Map; +import java.util.stream.IntStream; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onlab.util.Tools.nullIsIllegal; + +/** + * Openstack telemetry config codec used for serializing and de-serializing JSON string. + */ +public final class TelemetryConfigJsonCodec extends JsonCodec { + + private static final String NAME = "name"; + private static final String TYPE = "type"; + private static final String MANUFACTURER = "manufacturer"; + private static final String SW_VERSION = "swVersion"; + private static final String ENABLED = "enabled"; + private static final String PROPS = "props"; + private static final String KEY = "key"; + private static final String VALUE = "value"; + + private static final String MISSING_MESSAGE = " is required in TelemetryConfig"; + + @Override + public ObjectNode encode(TelemetryConfig config, CodecContext context) { + checkNotNull(config, "TelemetryConfig cannot be null"); + + ObjectNode node = context.mapper().createObjectNode() + .put(NAME, config.name()) + .put(TYPE, config.type().name()) + .put(MANUFACTURER, config.manufacturer()) + .put(SW_VERSION, config.swVersion()) + .put(ENABLED, config.enabled()); + + Map props = config.properties(); + ArrayNode propsJson = context.mapper().createArrayNode(); + props.forEach((k, v) -> { + ObjectNode propNode = context.mapper().createObjectNode(); + propNode.put(KEY, k); + propNode.put(VALUE, v); + propsJson.add(propNode); + }); + node.set(PROPS, propsJson); + return node; + } + + @Override + public TelemetryConfig decode(ObjectNode json, CodecContext context) { + if (json == null || !json.isObject()) { + return null; + } + + // parse name + String name = nullIsIllegal(json.get(NAME), + NAME + MISSING_MESSAGE).asText(); + + // parse type + String type = nullIsIllegal(json.get(TYPE), + TYPE + MISSING_MESSAGE).asText(); + + TelemetryConfig.ConfigType configType = configType(type); + + // parse manufacturer + String manufacturer = nullIsIllegal(json.get(MANUFACTURER).asText(), + MANUFACTURER + MISSING_MESSAGE); + + // parse software version + String swVersion = nullIsIllegal(json.get(SW_VERSION), + SW_VERSION + MISSING_MESSAGE).asText(); + + // parse enabled flag + boolean enabled = nullIsIllegal(json.get(ENABLED), + ENABLED + MISSING_MESSAGE).asBoolean(); + + JsonNode propertiesJson = json.get(PROPS); + Map properties = Maps.newConcurrentMap(); + if (propertiesJson != null) { + IntStream.range(0, propertiesJson.size()).forEach(i -> { + ObjectNode propertyJson = get(propertiesJson, i); + properties.put(propertyJson.get(KEY).asText(), + propertyJson.get(VALUE).asText()); + }); + } + + return new DefaultTelemetryConfig(name, configType, + ImmutableList.of(), manufacturer, swVersion, enabled, properties); + } + + private TelemetryConfig.ConfigType configType(String type) { + switch (type.toUpperCase()) { + case "KAFKA" : + return TelemetryConfig.ConfigType.KAFKA; + case "GRPC" : + return TelemetryConfig.ConfigType.GRPC; + case "INFLUXDB" : + return TelemetryConfig.ConfigType.INFLUXDB; + case "PROMETHEUS" : + return TelemetryConfig.ConfigType.PROMETHEUS; + case "REST" : + return TelemetryConfig.ConfigType.REST; + default: + return TelemetryConfig.ConfigType.UNKNOWN; + } + } +} diff --git a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/codec/package-info.java b/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/codec/rest/package-info.java similarity index 92% rename from apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/codec/package-info.java rename to apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/codec/rest/package-info.java index f7f6401ff7..3a699c1dd0 100644 --- a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/codec/package-info.java +++ b/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/codec/rest/package-info.java @@ -17,4 +17,4 @@ /** * Implementations of the codec broker and openstack telemetry entity codecs. */ -package org.onosproject.openstacktelemetry.codec; \ No newline at end of file +package org.onosproject.openstacktelemetry.codec.rest; \ No newline at end of file diff --git a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryCodecRegister.java b/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryCodecRegister.java similarity index 80% rename from apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryCodecRegister.java rename to apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryCodecRegister.java index c8bfeb5d3e..6bd8636f93 100644 --- a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryCodecRegister.java +++ b/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryCodecRegister.java @@ -15,18 +15,20 @@ */ package org.onosproject.openstacktelemetry.web; +import org.onosproject.codec.CodecService; +import org.onosproject.openstacktelemetry.api.FlowInfo; +import org.onosproject.openstacktelemetry.api.StatsFlowRule; +import org.onosproject.openstacktelemetry.api.StatsInfo; +import org.onosproject.openstacktelemetry.api.config.TelemetryConfig; +import org.onosproject.openstacktelemetry.codec.rest.FlowInfoJsonCodec; +import org.onosproject.openstacktelemetry.codec.rest.StatsFlowRuleJsonCodec; +import org.onosproject.openstacktelemetry.codec.rest.StatsInfoJsonCodec; +import org.onosproject.openstacktelemetry.codec.rest.TelemetryConfigJsonCodec; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; -import org.onosproject.codec.CodecService; -import org.onosproject.openstacktelemetry.api.FlowInfo; -import org.onosproject.openstacktelemetry.api.StatsFlowRule; -import org.onosproject.openstacktelemetry.api.StatsInfo; -import org.onosproject.openstacktelemetry.codec.FlowInfoJsonCodec; -import org.onosproject.openstacktelemetry.codec.StatsFlowRuleJsonCodec; -import org.onosproject.openstacktelemetry.codec.StatsInfoJsonCodec; import static org.slf4j.LoggerFactory.getLogger; @@ -46,6 +48,7 @@ public class OpenstackTelemetryCodecRegister { codecService.registerCodec(StatsInfo.class, new StatsInfoJsonCodec()); codecService.registerCodec(FlowInfo.class, new FlowInfoJsonCodec()); codecService.registerCodec(StatsFlowRule.class, new StatsFlowRuleJsonCodec()); + codecService.registerCodec(TelemetryConfig.class, new TelemetryConfigJsonCodec()); log.info("Started"); } @@ -55,6 +58,7 @@ public class OpenstackTelemetryCodecRegister { codecService.unregisterCodec(StatsInfo.class); codecService.unregisterCodec(FlowInfo.class); codecService.unregisterCodec(StatsFlowRule.class); + codecService.unregisterCodec(TelemetryConfig.class); log.info("Stopped"); } diff --git a/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryConfigWebResource.java b/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryConfigWebResource.java new file mode 100644 index 0000000000..7484d04f6c --- /dev/null +++ b/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryConfigWebResource.java @@ -0,0 +1,212 @@ +/* + * Copyright 2018-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.openstacktelemetry.web; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.Maps; +import org.onosproject.openstacktelemetry.api.TelemetryConfigAdminService; +import org.onosproject.openstacktelemetry.api.config.TelemetryConfig; +import org.onosproject.rest.AbstractWebResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import java.util.Map; + +import static org.onlab.util.Tools.nullIsIllegal; +import static org.onlab.util.Tools.nullIsNotFound; + +/** + * Handles REST API call of openstack telemetry configuration. + */ +@Path("config") +public class OpenstackTelemetryConfigWebResource extends AbstractWebResource { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private static final String MESSAGE_CONFIG = "Received config %s request"; + private static final String CONFIG = "config"; + private static final String ADDRESS = "address"; + private static final String QUERY = "QUERY"; + private static final String UPDATE = "UPDATE"; + private static final String DELETE = "DELETE"; + private static final String CONFIG_NAME = "config name"; + private static final String NOT_NULL_MESSAGE = " cannot be null"; + private static final String CONFIG_NOT_FOUND = "Config is not found"; + + private final TelemetryConfigAdminService configService = + get(TelemetryConfigAdminService.class); + + @Context + private UriInfo uriInfo; + + /** + * Updates the telemetry configuration address from the JSON input stream. + * + * @param configName telemetry config name + * @param address telemetry config address + * @return 200 OK with the updated telemetry config, 400 BAD_REQUEST + * if the JSON is malformed, and 304 NOT_MODIFIED without the updated config + * due to incorrect configuration name so that we cannot find the existing config + */ + @PUT + @Path("address/{name}/{address}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response updateConfigAddress(@PathParam("name") String configName, + @PathParam("address") String address) { + log.trace(String.format(MESSAGE_CONFIG, UPDATE)); + + try { + TelemetryConfig config = configService.getConfig( + nullIsIllegal(configName, CONFIG_NAME + NOT_NULL_MESSAGE)); + + if (config == null) { + log.warn("There is no config found to modify for {}", configName); + return Response.notModified().build(); + } else { + Map updatedProperties = + Maps.newHashMap(config.properties()); + updatedProperties.put(ADDRESS, + nullIsIllegal(address, ADDRESS + NOT_NULL_MESSAGE)); + TelemetryConfig updatedConfig = + config.updateProperties(updatedProperties); + + configService.updateTelemetryConfig(updatedConfig); + return Response.ok().build(); + } + + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } + + /** + * Deletes the telemetry configuration by referring to configuration name. + * + * @param configName telemetry configuration name + * @return 204 NO_CONTENT, 400 BAD_REQUEST if the JSON is malformed, + * and 304 NOT_MODIFIED without removing config, due to incorrect + * configuration name so that we cannot find the existing config + */ + @DELETE + @Path("{name}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response deleteTelemetryConfig(@PathParam("name") String configName) { + log.trace(String.format(MESSAGE_CONFIG, DELETE)); + + TelemetryConfig config = configService.getConfig( + nullIsIllegal(configName, CONFIG_NAME + NOT_NULL_MESSAGE)); + + if (config == null) { + log.warn("There is no config found to delete for {}", configName); + return Response.notModified().build(); + } else { + configService.removeTelemetryConfig(configName); + return Response.noContent().build(); + } + } + + /** + * Get details of telemetry config. + * Returns detailed properties of the specified telemetry config. + * + * @param configName telemetry configName + * @return 200 OK with detailed properties of the specific telemetry config + * @onos.rsModel TelemetryConfig + */ + @GET + @Path("{name}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response getConfig(@PathParam("name") String configName) { + log.trace(String.format(MESSAGE_CONFIG, QUERY)); + + final TelemetryConfig config = + nullIsNotFound(configService.getConfig(configName), CONFIG_NOT_FOUND); + final ObjectNode root = codec(TelemetryConfig.class).encode(config, this); + return ok(root).build(); + } + + /** + * Enables the telemetry configuration with the given config name. + * + * @param configName telemetry configuration name + * @return 200 OK with the enabled telemetry config, + * 400 BAD_REQUEST if the JSON is malformed, + * and 304 NOT_MODIFIED without removing config, due to incorrect + * configuration name so that we cannot find the existing config + */ + @PUT + @Path("enable/{name}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response enableConfig(@PathParam("name") String configName) { + log.trace(String.format(MESSAGE_CONFIG, UPDATE)); + + TelemetryConfig config = configService.getConfig( + nullIsIllegal(configName, CONFIG_NAME + NOT_NULL_MESSAGE)); + + if (config == null) { + log.warn("There is no config found to enable for {}", configName); + return Response.notModified().build(); + } else { + TelemetryConfig updatedConfig = config.updateEnabled(true); + configService.updateTelemetryConfig(updatedConfig); + return Response.ok().build(); + } + } + + /** + * Disables the telemetry configuration with the given config name. + * + * @param configName telemetry configuration name + * @return 200 OK with the disabled telemetry config + * 400 BAD_REQUEST if the JSON is malformed, + * and 304 NOT_MODIFIED without removing config, due to incorrect + * configuration name so that we cannot find the existing config + */ + @PUT + @Path("disable/{name}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response disableConfig(@PathParam("name") String configName) { + log.trace(String.format(MESSAGE_CONFIG, UPDATE)); + + TelemetryConfig config = configService.getConfig( + nullIsIllegal(configName, CONFIG_NAME + NOT_NULL_MESSAGE)); + + if (config == null) { + log.warn("There is no config found to disable for {}", configName); + return Response.notModified().build(); + } else { + TelemetryConfig updatedConfig = config.updateEnabled(false); + configService.updateTelemetryConfig(updatedConfig); + return Response.ok().build(); + } + } +} diff --git a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryWebApplication.java b/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryWebApplication.java similarity index 88% rename from apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryWebApplication.java rename to apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryWebApplication.java index 9dc4e185bb..4deff1c773 100644 --- a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryWebApplication.java +++ b/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryWebApplication.java @@ -25,6 +25,7 @@ import java.util.Set; public class OpenstackTelemetryWebApplication extends AbstractWebApplication { @Override public Set > getClasses() { - return getClasses(OpenstackTelemetryWebResource.class); + return getClasses(OpenstackTelemetryWebResource.class, + OpenstackTelemetryConfigWebResource.class); } } diff --git a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryWebResource.java b/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryWebResource.java similarity index 94% rename from apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryWebResource.java rename to apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryWebResource.java index 34f8366032..40b5c93165 100644 --- a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryWebResource.java +++ b/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryWebResource.java @@ -24,7 +24,7 @@ import org.onosproject.codec.JsonCodec; import org.onosproject.openstacktelemetry.api.FlowInfo; import org.onosproject.openstacktelemetry.api.StatsFlowRule; import org.onosproject.openstacktelemetry.api.StatsFlowRuleAdminService; -import org.onosproject.openstacktelemetry.codec.FlowInfoJsonCodec; +import org.onosproject.openstacktelemetry.codec.rest.FlowInfoJsonCodec; import org.onosproject.rest.AbstractWebResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,7 +51,6 @@ import static org.onlab.util.Tools.readTreeFromStream; /** * Handles REST API call of openstack telemetry. */ - @Path("telemetry") public class OpenstackTelemetryWebResource extends AbstractWebResource { @@ -138,18 +137,13 @@ public class OpenstackTelemetryWebResource extends AbstractWebResource { Set flowInfoSet; flowInfoSet = statsFlowRuleService.getOverlayFlowInfos(); - log.info("\n\n======================================================\n" + - "FlowInfo Set: \n{}" + - "\n\n======================================================\n", - flowInfoSet); - JsonCodec flowInfoCodec = new FlowInfoJsonCodec(); ObjectNode nodeJson; int idx = 0; for (FlowInfo flowInfo: flowInfoSet) { nodeJson = flowInfoCodec.encode(flowInfo, this); - root.put("FlowInfo" + String.valueOf(idx++), nodeJson.toString()); + root.put("FlowInfo" + idx++, nodeJson.toString()); } return ok(root).build(); } diff --git a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/web/package-info.java b/apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/web/package-info.java similarity index 100% rename from apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/web/package-info.java rename to apps/openstacktelemetry/web/src/main/java/org/onosproject/openstacktelemetry/web/package-info.java diff --git a/apps/openstacktelemetry/web/src/main/resources/definitions/TelemetryConfig.json b/apps/openstacktelemetry/web/src/main/resources/definitions/TelemetryConfig.json new file mode 100644 index 0000000000..f4d1288f8c --- /dev/null +++ b/apps/openstacktelemetry/web/src/main/resources/definitions/TelemetryConfig.json @@ -0,0 +1,53 @@ +{ + "type": "object", + "required": [ + "name", + "type", + "manufacturer", + "swVersion", + "enabled", + "properties" + ], + "properties": { + "name": { + "type": "string", + "example": "grpc config" + }, + "type": { + "type": "string", + "example": "GRPC" + }, + "manufacturer": { + "type": "string", + "example": "grpc.io" + }, + "swVersion": { + "type": "string", + "example": "1.0" + }, + "enabled": { + "type": "boolean", + "example": true + }, + "props": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string", + "example": "address" + }, + "value": { + "type": "string", + "example": "127.0.0.1" + } + } + } + } + } +} \ No newline at end of file diff --git a/apps/openstacktelemetry/app/src/main/webapp/WEB-INF/web.xml b/apps/openstacktelemetry/web/src/main/webapp/WEB-INF/web.xml similarity index 100% rename from apps/openstacktelemetry/app/src/main/webapp/WEB-INF/web.xml rename to apps/openstacktelemetry/web/src/main/webapp/WEB-INF/web.xml diff --git a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/FlowInfoJsonCodecTest.java b/apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/codec/rest/FlowInfoJsonCodecTest.java similarity index 96% rename from apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/FlowInfoJsonCodecTest.java rename to apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/codec/rest/FlowInfoJsonCodecTest.java index ee84e59f34..4d3cb47229 100644 --- a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/FlowInfoJsonCodecTest.java +++ b/apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/codec/rest/FlowInfoJsonCodecTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onosproject.openstacktelemetry.codec; +package org.onosproject.openstacktelemetry.codec.rest; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -32,8 +32,8 @@ import org.onosproject.core.CoreService; import org.onosproject.net.DeviceId; import org.onosproject.openstacktelemetry.api.FlowInfo; import org.onosproject.openstacktelemetry.api.StatsInfo; -import org.onosproject.openstacktelemetry.impl.DefaultFlowInfo; -import org.onosproject.openstacktelemetry.impl.DefaultStatsInfo; +import org.onosproject.openstacktelemetry.api.DefaultFlowInfo; +import org.onosproject.openstacktelemetry.api.DefaultStatsInfo; import java.util.HashMap; import java.util.Map; @@ -44,7 +44,7 @@ import static org.easymock.EasyMock.replay; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.notNullValue; import static org.onosproject.net.NetTestTools.APP_ID; -import static org.onosproject.openstacktelemetry.codec.FlowInfoJsonMatcher.matchesFlowInfo; +import static org.onosproject.openstacktelemetry.codec.rest.FlowInfoJsonMatcher.matchesFlowInfo; /** * Unit tests for FlowInfo codec. diff --git a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/FlowInfoJsonMatcher.java b/apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/codec/rest/FlowInfoJsonMatcher.java similarity index 99% rename from apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/FlowInfoJsonMatcher.java rename to apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/codec/rest/FlowInfoJsonMatcher.java index 7574054b30..66ab1bad29 100644 --- a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/FlowInfoJsonMatcher.java +++ b/apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/codec/rest/FlowInfoJsonMatcher.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onosproject.openstacktelemetry.codec; +package org.onosproject.openstacktelemetry.codec.rest; import com.fasterxml.jackson.databind.JsonNode; import org.hamcrest.Description; diff --git a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/StatsInfoJsonMatcher.java b/apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/codec/rest/StatsInfoJsonMatcher.java similarity index 98% rename from apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/StatsInfoJsonMatcher.java rename to apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/codec/rest/StatsInfoJsonMatcher.java index ffebaf58da..4ad86fa7af 100644 --- a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/codec/StatsInfoJsonMatcher.java +++ b/apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/codec/rest/StatsInfoJsonMatcher.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onosproject.openstacktelemetry.codec; +package org.onosproject.openstacktelemetry.codec.rest; import com.fasterxml.jackson.databind.JsonNode; import org.hamcrest.Description; diff --git a/apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/codec/rest/TelemetryConfigCodecTest.java b/apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/codec/rest/TelemetryConfigCodecTest.java new file mode 100644 index 0000000000..626aa02cb0 --- /dev/null +++ b/apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/codec/rest/TelemetryConfigCodecTest.java @@ -0,0 +1,175 @@ +/* + * Copyright 2018-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.openstacktelemetry.codec.rest; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Maps; +import org.hamcrest.MatcherAssert; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.codec.impl.CodecManager; +import org.onosproject.core.CoreService; +import org.onosproject.openstacktelemetry.api.DefaultTelemetryConfig; +import org.onosproject.openstacktelemetry.api.config.TelemetryConfig; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertTrue; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.net.NetTestTools.APP_ID; +import static org.onosproject.openstacktelemetry.codec.rest.TelemetryConfigJsonMatcher.matchesTelemetryConfig; + +/** + * Unit tests for TelemetryConfig codec. + */ +public class TelemetryConfigCodecTest { + + MockCodecContext context; + + JsonCodec telemetryConfigCodec; + + final CoreService mockCoreService = createMock(CoreService.class); + private static final String REST_APP_ID = "org.onosproject.rest"; + + @Before + public void setUp() { + context = new MockCodecContext(); + telemetryConfigCodec = new TelemetryConfigJsonCodec(); + + assertThat(telemetryConfigCodec, notNullValue()); + + expect(mockCoreService.registerApplication(REST_APP_ID)) + .andReturn(APP_ID).anyTimes(); + replay(mockCoreService); + context.registerService(CoreService.class, mockCoreService); + } + + /** + * Tests the telemetry config encoding. + */ + @Test + public void testTelemetryConfigEncode() { + + String name = "grpc"; + TelemetryConfig.ConfigType type = TelemetryConfig.ConfigType.GRPC; + String manufacturer = "grpc.io"; + String swVersion = "1.0"; + boolean enabled = true; + + Map properties = Maps.newConcurrentMap(); + properties.put("key1", "value1"); + properties.put("key2", "value2"); + + TelemetryConfig config = new DefaultTelemetryConfig(name, type, + ImmutableList.of(), manufacturer, swVersion, enabled, properties); + + ObjectNode configJson = telemetryConfigCodec.encode(config, context); + assertThat(configJson, matchesTelemetryConfig(config)); + } + + /** + * Tests the telemetry config decoding. + */ + @Test + public void testTelemetryConfigDecode() throws IOException { + TelemetryConfig config = getTelemetryConfig("TelemetryConfig.json"); + + assertEquals(config.name(), "grpc-config"); + assertEquals(config.type().name(), "GRPC"); + assertEquals(config.manufacturer(), "grpc.io"); + assertEquals(config.swVersion(), "1.0"); + assertTrue(config.enabled()); + + config.properties().forEach((k, v) -> { + if (k.equals("address")) { + assertEquals(v, "127.0.0.1"); + } + if (k.equals("port")) { + assertEquals(v, "9092"); + } + }); + } + + /** + * Reads in a telemetry config from the given resource and decodes it. + * + * @param resourceName resource to use to read the JSON for the rule + * @return decoded telemetry config + * @throws IOException if processing the resource fails + */ + private TelemetryConfig getTelemetryConfig(String resourceName) throws IOException { + InputStream jsonStream = TelemetryConfigCodecTest.class.getResourceAsStream(resourceName); + JsonNode json = context.mapper().readTree(jsonStream); + MatcherAssert.assertThat(json, notNullValue()); + TelemetryConfig config = telemetryConfigCodec.decode((ObjectNode) json, context); + assertThat(config, notNullValue()); + return config; + } + + /** + * Mock codec context for use in codec unit tests. + */ + private class MockCodecContext implements CodecContext { + private final ObjectMapper mapper = new ObjectMapper(); + private final CodecManager manager = new CodecManager(); + private final Map , Object> services = new HashMap<>(); + + /** + * Constructs a new mock codec context. + */ + public MockCodecContext() { + manager.activate(); + } + + @Override + public ObjectMapper mapper() { + return mapper; + } + + @SuppressWarnings("unchecked") + @Override + public JsonCodec codec(Class entityClass) { + if (entityClass == TelemetryConfig.class) { + return (JsonCodec ) telemetryConfigCodec; + } + return manager.getCodec(entityClass); + } + + @SuppressWarnings("unchecked") + @Override + public T getService(Class serviceClass) { + return (T) services.get(serviceClass); + } + + // for registering mock services + public void registerService(Class serviceClass, T impl) { + services.put(serviceClass, impl); + } + } +} diff --git a/apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/codec/rest/TelemetryConfigJsonMatcher.java b/apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/codec/rest/TelemetryConfigJsonMatcher.java new file mode 100644 index 0000000000..9bc50a20aa --- /dev/null +++ b/apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/codec/rest/TelemetryConfigJsonMatcher.java @@ -0,0 +1,154 @@ +/* + * Copyright 2018-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.openstacktelemetry.codec.rest; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onosproject.openstacktelemetry.api.config.TelemetryConfig; + +/** + * Hamcrest matcher for TelemetryConfig. + */ +public final class TelemetryConfigJsonMatcher extends TypeSafeDiagnosingMatcher { + + private final TelemetryConfig telemetryConfig; + + private static final String NAME = "name"; + private static final String TYPE = "type"; + private static final String MANUFACTURER = "manufacturer"; + private static final String SW_VERSION = "swVersion"; + private static final String ENABLED = "enabled"; + private static final String PROPS = "props"; + private static final String KEY = "key"; + private static final String VALUE = "value"; + + private TelemetryConfigJsonMatcher(TelemetryConfig telemetryConfig) { + this.telemetryConfig = telemetryConfig; + } + + @Override + protected boolean matchesSafely(JsonNode jsonNode, Description description) { + + // check name + String jsonName = jsonNode.get(NAME).asText(); + String name = telemetryConfig.name(); + if (!jsonName.equals(name)) { + description.appendText("name was " + jsonName); + return false; + } + + // check type + String jsonType = jsonNode.get(TYPE).asText(); + String type = telemetryConfig.type().name(); + if (!jsonType.equalsIgnoreCase(type)) { + description.appendText("type was " + jsonType); + return false; + } + + // check manufacturer + String jsonManufacturer = jsonNode.get(MANUFACTURER).asText(); + String manufacturer = telemetryConfig.manufacturer(); + if (!jsonManufacturer.equals(manufacturer)) { + description.appendText("manufacturer was " + jsonManufacturer); + return false; + } + + // check software version + String jsonSwVersion = jsonNode.get(SW_VERSION).asText(); + String swVersion = telemetryConfig.swVersion(); + if (!jsonSwVersion.equals(swVersion)) { + description.appendText("SW version was " + jsonSwVersion); + return false; + } + + // check enabled + JsonNode jsonEnabled = jsonNode.get(ENABLED); + boolean enabled = telemetryConfig.enabled(); + if (jsonEnabled == null || jsonEnabled.asBoolean() != enabled) { + description.appendText("Enabled was " + jsonEnabled); + return false; + } + + // check properties + JsonNode jsonProperties = jsonNode.get(PROPS); + if (jsonProperties != null) { + if (jsonProperties.size() != telemetryConfig.properties().size()) { + description.appendText("properties size was " + jsonProperties.size()); + return false; + } + + for (String key : telemetryConfig.properties().keySet()) { + boolean keyFound = false; + boolean valueFound = false; + String value = telemetryConfig.properties().get(key); + for (int keyIndex = 0; keyIndex < jsonProperties.size(); keyIndex++) { + ObjectNode jsonProperty = get(jsonProperties, keyIndex); + JsonNode jsonKey = jsonProperty.get(KEY); + JsonNode jsonValue = jsonProperty.get(VALUE); + + if (jsonKey != null && jsonValue != null) { + if (jsonKey.asText().equals(key)) { + keyFound = true; + } + + if (jsonValue.asText().equals(value)) { + valueFound = true; + } + + if (keyFound && valueFound) { + break; + } + } + } + + if (!keyFound) { + description.appendText("Property key not found " + key); + return false; + } + + if (!valueFound) { + description.appendText("Property value not found " + value); + return false; + } + } + } + + return true; + } + + @Override + public void describeTo(Description description) { + description.appendText(telemetryConfig.toString()); + } + + /** + * Factory to allocate an flow info matcher. + * + * @param telemetryConfig telemetry config object we are looking for + * @return matcher + */ + public static TelemetryConfigJsonMatcher + matchesTelemetryConfig(TelemetryConfig telemetryConfig) { + return new TelemetryConfigJsonMatcher(telemetryConfig); + } + + private static ObjectNode get(JsonNode parent, int childIndex) { + JsonNode node = parent.path(childIndex); + return node.isObject() && !node.isNull() ? (ObjectNode) node : null; + } +} diff --git a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryCodecRegisterTest.java b/apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryCodecRegisterTest.java similarity index 84% rename from apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryCodecRegisterTest.java rename to apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryCodecRegisterTest.java index 683e9c1965..6eee6164dc 100644 --- a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryCodecRegisterTest.java +++ b/apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryCodecRegisterTest.java @@ -24,9 +24,11 @@ import org.onosproject.codec.JsonCodec; import org.onosproject.openstacktelemetry.api.FlowInfo; import org.onosproject.openstacktelemetry.api.StatsFlowRule; import org.onosproject.openstacktelemetry.api.StatsInfo; -import org.onosproject.openstacktelemetry.codec.FlowInfoJsonCodec; -import org.onosproject.openstacktelemetry.codec.StatsFlowRuleJsonCodec; -import org.onosproject.openstacktelemetry.codec.StatsInfoJsonCodec; +import org.onosproject.openstacktelemetry.api.config.TelemetryConfig; +import org.onosproject.openstacktelemetry.codec.rest.FlowInfoJsonCodec; +import org.onosproject.openstacktelemetry.codec.rest.StatsFlowRuleJsonCodec; +import org.onosproject.openstacktelemetry.codec.rest.StatsInfoJsonCodec; +import org.onosproject.openstacktelemetry.codec.rest.TelemetryConfigJsonCodec; import java.util.Map; import java.util.Set; @@ -58,12 +60,15 @@ public final class OpenstackTelemetryCodecRegisterTest { codecService.getCodec(FlowInfo.class).getClass().getName()); assertEquals(StatsFlowRuleJsonCodec.class.getName(), codecService.getCodec(StatsFlowRule.class).getClass().getName()); + assertEquals(TelemetryConfigJsonCodec.class.getName(), + codecService.getCodec(TelemetryConfig.class).getClass().getName()); register.deactivate(); assertNull(codecService.getCodec(StatsInfo.class)); assertNull(codecService.getCodec(FlowInfo.class)); assertNull(codecService.getCodec(StatsFlowRule.class)); + assertNull(codecService.getCodec(TelemetryConfig.class)); } private static class TestCodecService implements CodecService { diff --git a/apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryConfigWebResourceTest.java b/apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryConfigWebResourceTest.java new file mode 100644 index 0000000000..ff027bc910 --- /dev/null +++ b/apps/openstacktelemetry/web/src/test/java/org/onosproject/openstacktelemetry/web/OpenstackTelemetryConfigWebResourceTest.java @@ -0,0 +1,217 @@ +/* + * Copyright 2018-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.openstacktelemetry.web; + +import com.google.common.collect.Maps; +import org.glassfish.jersey.server.ResourceConfig; +import org.junit.Before; +import org.junit.Test; +import org.onlab.osgi.ServiceDirectory; +import org.onlab.osgi.TestServiceDirectory; +import org.onosproject.openstacktelemetry.api.DefaultTelemetryConfig; +import org.onosproject.openstacktelemetry.api.TelemetryConfigAdminService; +import org.onosproject.openstacktelemetry.api.config.TelemetryConfig; +import org.onosproject.rest.resources.ResourceTest; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.Map; + +import static junit.framework.TestCase.assertEquals; +import static org.easymock.EasyMock.anyString; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.onosproject.openstacktelemetry.api.config.TelemetryConfig.ConfigType.GRPC; + +/** + * Unit tests for openstack telemetry config REST API. + */ +public class OpenstackTelemetryConfigWebResourceTest extends ResourceTest { + + private static final String NAME = "grpc"; + + private static final TelemetryConfig.ConfigType TYPE = GRPC; + + private static final String MANUFACTURER = "grpc.io"; + + private static final String SW_VERSION = "1.0"; + + private static final Map PROP = Maps.newConcurrentMap(); + + private static final String PROP_KEY_1 = "key11"; + private static final String PROP_KEY_2 = "key12"; + private static final String PROP_VALUE_1 = "value11"; + private static final String PROP_VALUE_2 = "value12"; + + private static final boolean ENABLED = true; + + private final TelemetryConfigAdminService mockConfigAdminService = + createMock(TelemetryConfigAdminService.class); + private static final String PATH = "config"; + + /** + * Constructs an openstack telemetry config resource test instance. + */ + public OpenstackTelemetryConfigWebResourceTest() { + super(ResourceConfig.forApplicationClass(OpenstackTelemetryWebApplication.class)); + } + + private TelemetryConfig telemetryConfig; + + /** + * Sets up the global values for all the tests. + */ + @Before + public void setUpTest() { + ServiceDirectory testDirectory = + new TestServiceDirectory() + .add(TelemetryConfigAdminService.class, + mockConfigAdminService); + setServiceDirectory(testDirectory); + + PROP.put(PROP_KEY_1, PROP_VALUE_1); + PROP.put(PROP_KEY_2, PROP_VALUE_2); + + telemetryConfig = new DefaultTelemetryConfig(NAME, TYPE, null, + MANUFACTURER, SW_VERSION, ENABLED, PROP); + } + + /** + * Tests the results of the REST API PUT method by modifying config address. + */ + @Test + public void testUpdateConfigAddressWithModifyOperation() { + expect(mockConfigAdminService.getConfig(anyString())) + .andReturn(telemetryConfig).once(); + mockConfigAdminService.updateTelemetryConfig(telemetryConfig); + replay(mockConfigAdminService); + + final WebTarget wt = target(); + Response response = wt.path(PATH + "/address/test1/address1") + .request(MediaType.APPLICATION_JSON_TYPE) + .put(Entity.json("")); + final int status = response.getStatus(); + + assertEquals(200, status); + + verify(mockConfigAdminService); + } + + /** + * Tests the results of the REST API PUT method without modifying config address. + */ + @Test + public void testUpdateConfigAddressWithoutOperation() { + expect(mockConfigAdminService.getConfig(anyString())).andReturn(null).once(); + replay(mockConfigAdminService); + + final WebTarget wt = target(); + Response response = wt.path(PATH + "/address/test1/address1") + .request(MediaType.APPLICATION_JSON_TYPE) + .put(Entity.json("")); + final int status = response.getStatus(); + + assertEquals(304, status); + + verify(mockConfigAdminService); + } + + /** + * Tests the results of the REST API DELETE method by removing config. + */ + @Test + public void testDeleteConfigWithModifyOperation() { + expect(mockConfigAdminService.getConfig(anyString())) + .andReturn(telemetryConfig).once(); + mockConfigAdminService.removeTelemetryConfig(anyString()); + replay(mockConfigAdminService); + + final WebTarget wt = target(); + Response response = wt.path(PATH + "/test1") + .request(MediaType.APPLICATION_JSON_TYPE) + .delete(); + final int status = response.getStatus(); + + assertEquals(204, status); + + verify(mockConfigAdminService); + } + + /** + * Tests the results of the REST API DELETE method without removing config. + */ + @Test + public void testDeleteConfigWithoutModifyOperation() { + expect(mockConfigAdminService.getConfig(anyString())).andReturn(null).once(); + replay(mockConfigAdminService); + + final WebTarget wt = target(); + Response response = wt.path(PATH + "/test1") + .request(MediaType.APPLICATION_JSON_TYPE) + .delete(); + final int status = response.getStatus(); + + assertEquals(304, status); + + verify(mockConfigAdminService); + } + + /** + * Tests the results of REST API PUT method with enabling the config. + */ + @Test + public void testEnableConfig() { + expect(mockConfigAdminService.getConfig(anyString())) + .andReturn(telemetryConfig).once(); + mockConfigAdminService.updateTelemetryConfig(telemetryConfig); + replay(mockConfigAdminService); + + final WebTarget wt = target(); + Response response = wt.path(PATH + "/enable/test1") + .request(MediaType.APPLICATION_JSON_TYPE) + .put(Entity.json("")); + final int status = response.getStatus(); + + assertEquals(200, status); + + verify(mockConfigAdminService); + } + + /** + * Tests the results of REST API PUT method with disabling the config. + */ + @Test + public void testDisableConfig() { + expect(mockConfigAdminService.getConfig(anyString())) + .andReturn(telemetryConfig).once(); + mockConfigAdminService.updateTelemetryConfig(telemetryConfig); + replay(mockConfigAdminService); + + final WebTarget wt = target(); + Response response = wt.path(PATH + "/disable/test1") + .request(MediaType.APPLICATION_JSON_TYPE) + .put(Entity.json("")); + final int status = response.getStatus(); + + assertEquals(200, status); + + verify(mockConfigAdminService); + } +} diff --git a/apps/openstacktelemetry/web/src/test/resources/org/onosproject/openstacktelemetry/codec/rest/TelemetryConfig.json b/apps/openstacktelemetry/web/src/test/resources/org/onosproject/openstacktelemetry/codec/rest/TelemetryConfig.json new file mode 100644 index 0000000000..681cad3592 --- /dev/null +++ b/apps/openstacktelemetry/web/src/test/resources/org/onosproject/openstacktelemetry/codec/rest/TelemetryConfig.json @@ -0,0 +1,17 @@ +{ + "name": "grpc-config", + "type": "GRPC", + "manufacturer": "grpc.io", + "swVersion": "1.0", + "enabled": true, + "props": [ + { + "key": "address", + "value": "127.0.0.1" + }, + { + "key": "port", + "value": "9092" + } + ] +} \ No newline at end of file diff --git a/apps/openstacktelemetry/web/src/test/resources/org/onosproject/openstacktelemetry/web/openstack-telemetry-config-address.json b/apps/openstacktelemetry/web/src/test/resources/org/onosproject/openstacktelemetry/web/openstack-telemetry-config-address.json new file mode 100644 index 0000000000..a4132c51c2 --- /dev/null +++ b/apps/openstacktelemetry/web/src/test/resources/org/onosproject/openstacktelemetry/web/openstack-telemetry-config-address.json @@ -0,0 +1,5 @@ +{ + "config": { + "address": "10.10.10.10" + } +} \ No newline at end of file