Extract web and codec into a separated web pkg in kubevirt-net app
Change-Id: If15fe4391009a09a79e60965d90fac26d5bad7fe
diff --git a/apps/kubevirt-networking/web/BUILD b/apps/kubevirt-networking/web/BUILD
new file mode 100644
index 0000000..06edea6
--- /dev/null
+++ b/apps/kubevirt-networking/web/BUILD
@@ -0,0 +1,21 @@
+COMPILE_DEPS = CORE_DEPS + JACKSON + KRYO + REST + [
+ "//apps/kubevirt-node/api:onos-apps-kubevirt-node-api",
+ "//apps/kubevirt-networking/api:onos-apps-kubevirt-networking-api",
+]
+
+TEST_DEPS = TEST_ADAPTERS + TEST_REST + [
+ "//core/api:onos-api-tests",
+ "//core/common:onos-core-common-tests",
+ "//web/api:onos-rest-tests",
+ "@minimal_json//jar",
+]
+
+osgi_jar_with_tests(
+ api_description = "REST API for KubeVirt Networking",
+ api_package = "org.onosproject.kubevirtnetworking.web",
+ api_title = "KubeVirt Networking API",
+ api_version = "1.0",
+ test_deps = TEST_DEPS,
+ web_context = "/onos/kubevirtnetworking",
+ deps = COMPILE_DEPS,
+)
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpCodec.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpCodec.java
new file mode 100644
index 0000000..fd530a1
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpCodec.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.IpAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.kubevirtnetworking.api.DefaultKubevirtFloatingIp;
+import org.onosproject.kubevirtnetworking.api.KubevirtFloatingIp;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Kubevirt floating IP codec used for serializing and de-serializing JSON string.
+ */
+public final class KubevirtFloatingIpCodec extends JsonCodec<KubevirtFloatingIp> {
+
+ private final Logger log = getLogger(getClass());
+
+ private static final String ID = "id";
+ private static final String ROUTER_NAME = "routerName";
+ private static final String POD_NAME = "podName";
+ private static final String VM_NAME = "vmName";
+ private static final String NETWORK_NAME = "networkName";
+ private static final String FLOATING_IP = "floatingIp";
+ private static final String FIXED_IP = "fixedIp";
+
+ private static final String MISSING_MESSAGE = " is required in KubevirtFloatingIp";
+
+ @Override
+ public ObjectNode encode(KubevirtFloatingIp fip, CodecContext context) {
+ checkNotNull(fip, "Kubevirt floating IP cannot be null");
+
+ ObjectNode result = context.mapper().createObjectNode()
+ .put(ID, fip.id())
+ .put(ROUTER_NAME, fip.routerName())
+ .put(NETWORK_NAME, fip.networkName())
+ .put(FLOATING_IP, fip.floatingIp().toString());
+
+ if (fip.podName() != null) {
+ result.put(POD_NAME, fip.podName());
+ }
+
+ if (fip.vmName() != null) {
+ result.put(VM_NAME, fip.vmName());
+ }
+
+ if (fip.fixedIp() != null) {
+ result.put(FIXED_IP, fip.fixedIp().toString());
+ }
+
+ return result;
+ }
+
+ @Override
+ public KubevirtFloatingIp decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ String id = nullIsIllegal(json.get(ID).asText(), ID + MISSING_MESSAGE);
+ String routerName = nullIsIllegal(json.get(ROUTER_NAME).asText(),
+ ROUTER_NAME + MISSING_MESSAGE);
+ String floatingIp = nullIsIllegal(json.get(FLOATING_IP).asText(),
+ FLOATING_IP + MISSING_MESSAGE);
+ String networkName = nullIsIllegal(json.get(NETWORK_NAME).asText(),
+ NETWORK_NAME + MISSING_MESSAGE);
+
+ KubevirtFloatingIp.Builder builder = DefaultKubevirtFloatingIp.builder()
+ .id(id)
+ .routerName(routerName)
+ .networkName(networkName)
+ .floatingIp(IpAddress.valueOf(floatingIp));
+
+ JsonNode podName = json.get(POD_NAME);
+ if (podName != null) {
+ builder.podName(podName.asText());
+ }
+
+ JsonNode vmName = json.get(VM_NAME);
+ if (vmName != null) {
+ builder.vmName(vmName.asText());
+ }
+
+ JsonNode fixedIp = json.get(FIXED_IP);
+ if (fixedIp != null) {
+ builder.fixedIp(IpAddress.valueOf(fixedIp.asText()));
+ }
+
+ return builder.build();
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtHostRouteCodec.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtHostRouteCodec.java
new file mode 100644
index 0000000..2d73979
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtHostRouteCodec.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.kubevirtnetworking.api.KubevirtHostRoute;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Kubevirt host route codec used for serializing and de-serializing JSON string.
+ */
+public final class KubevirtHostRouteCodec extends JsonCodec<KubevirtHostRoute> {
+
+ private final Logger log = getLogger(getClass());
+
+ private static final String DESTINATION = "destination";
+ private static final String NEXTHOP = "nexthop";
+
+ private static final String MISSING_MESSAGE = " is required in KubevirtHostRoute";
+
+ @Override
+ public ObjectNode encode(KubevirtHostRoute hostRoute, CodecContext context) {
+ checkNotNull(hostRoute, "Kubernetes network cannot be null");
+
+ ObjectNode result = context.mapper().createObjectNode()
+ .put(DESTINATION, hostRoute.destination().toString());
+
+ if (hostRoute.nexthop() != null) {
+ result.put(NEXTHOP, hostRoute.nexthop().toString());
+ }
+
+ return result;
+ }
+
+ @Override
+ public KubevirtHostRoute decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ String destination = nullIsIllegal(json.get(DESTINATION).asText(),
+ DESTINATION + MISSING_MESSAGE);
+ JsonNode nexthopJson = json.get(NEXTHOP);
+ IpAddress nexthop = null;
+
+ if (nexthopJson != null) {
+ nexthop = IpAddress.valueOf(nexthopJson.asText());
+ }
+
+ return new KubevirtHostRoute(IpPrefix.valueOf(destination), nexthop);
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtIpPoolCodec.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtIpPoolCodec.java
new file mode 100644
index 0000000..8f5522c
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtIpPoolCodec.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.IpAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.kubevirtnetworking.api.KubevirtIpPool;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Kubevirt IP pool codec used for serializing and de-serializing JSON string.
+ */
+public final class KubevirtIpPoolCodec extends JsonCodec<KubevirtIpPool> {
+
+ private final Logger log = getLogger(getClass());
+
+ private static final String START = "start";
+ private static final String END = "end";
+
+ private static final String MISSING_MESSAGE = " is required in KubevirtIpPool";
+
+ @Override
+ public ObjectNode encode(KubevirtIpPool ipPool, CodecContext context) {
+ checkNotNull(ipPool, "Kubevirt IP pool cannot be null");
+
+ return context.mapper().createObjectNode()
+ .put(START, ipPool.start().toString())
+ .put(END, ipPool.end().toString());
+ }
+
+ @Override
+ public KubevirtIpPool decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ String start = nullIsIllegal(json.get(START).asText(), START + MISSING_MESSAGE);
+ String end = nullIsIllegal(json.get(END).asText(), END + MISSING_MESSAGE);
+
+ return new KubevirtIpPool(IpAddress.valueOf(start), IpAddress.valueOf(end));
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtLoadBalancerCodec.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtLoadBalancerCodec.java
new file mode 100644
index 0000000..c11d829
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtLoadBalancerCodec.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.IpAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.kubevirtnetworking.api.DefaultKubevirtLoadBalancer;
+import org.onosproject.kubevirtnetworking.api.KubevirtLoadBalancer;
+import org.onosproject.kubevirtnetworking.api.KubevirtLoadBalancerRule;
+import org.slf4j.Logger;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.IntStream;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+import static org.slf4j.LoggerFactory.getLogger;
+
+public final class KubevirtLoadBalancerCodec extends JsonCodec<KubevirtLoadBalancer> {
+
+ private final Logger log = getLogger(getClass());
+
+ private static final String NAME = "name";
+ private static final String DESCRIPTION = "description";
+ private static final String VIP = "vip";
+ private static final String NETWORK_ID = "networkId";
+ private static final String MEMBERS = "members";
+ private static final String RULES = "rules";
+
+ private static final String MISSING_MESSAGE = " is required in KubevirtLoadBalancer";
+
+ @Override
+ public ObjectNode encode(KubevirtLoadBalancer lb, CodecContext context) {
+ checkNotNull(lb, "Kubevirt load balancer cannot be null");
+
+ ObjectNode result = context.mapper().createObjectNode()
+ .put(NAME, lb.name())
+ .put(VIP, lb.vip().toString())
+ .put(NETWORK_ID, lb.networkId());
+
+ if (lb.description() != null) {
+ result.put(DESCRIPTION, lb.description());
+ }
+
+ if (lb.members() != null && !lb.members().isEmpty()) {
+ ArrayNode members = context.mapper().createArrayNode();
+ for (IpAddress ip : lb.members()) {
+ members.add(ip.toString());
+ }
+ result.set(MEMBERS, members);
+ }
+
+ if (lb.rules() != null && !lb.rules().isEmpty()) {
+ ArrayNode rules = context.mapper().createArrayNode();
+ for (KubevirtLoadBalancerRule rule : lb.rules()) {
+ ObjectNode ruleJson = context.codec(
+ KubevirtLoadBalancerRule.class).encode(rule, context);
+ rules.add(ruleJson);
+ }
+ result.set(RULES, rules);
+ }
+
+ return result;
+ }
+
+ @Override
+ public KubevirtLoadBalancer decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ String name = nullIsIllegal(json.get(NAME).asText(), NAME + MISSING_MESSAGE);
+ IpAddress vip = IpAddress.valueOf(nullIsIllegal(json.get(VIP).asText(),
+ VIP + MISSING_MESSAGE));
+ String networkId = nullIsIllegal(json.get(NETWORK_ID).asText(),
+ NETWORK_ID + MISSING_MESSAGE);
+
+ KubevirtLoadBalancer.Builder builder = DefaultKubevirtLoadBalancer.builder()
+ .name(name)
+ .vip(vip)
+ .networkId(networkId);
+
+ JsonNode description = json.get(DESCRIPTION);
+ if (description != null) {
+ builder.description(description.asText());
+ }
+
+ ArrayNode membersJson = (ArrayNode) json.get(MEMBERS);
+ if (membersJson != null) {
+ Set<IpAddress> members = new HashSet<>();
+ for (JsonNode memberJson : membersJson) {
+ members.add(IpAddress.valueOf(memberJson.asText()));
+ }
+ builder.members(members);
+ }
+
+ JsonNode rulesJson = json.get(RULES);
+ if (rulesJson != null) {
+ Set<KubevirtLoadBalancerRule> rules = new HashSet<>();
+ IntStream.range(0, rulesJson.size())
+ .forEach(i -> {
+ ObjectNode ruleJson = get(rulesJson, i);
+ KubevirtLoadBalancerRule rule = context.codec(
+ KubevirtLoadBalancerRule.class).decode(ruleJson, context);
+ rules.add(rule);
+ });
+ builder.rules(rules);
+ }
+
+ return builder.build();
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtLoadBalancerRuleCodec.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtLoadBalancerRuleCodec.java
new file mode 100644
index 0000000..582d4d3
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtLoadBalancerRuleCodec.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.kubevirtnetworking.api.DefaultKubevirtLoadBalancerRule;
+import org.onosproject.kubevirtnetworking.api.KubevirtLoadBalancerRule;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Kubevirt load balancer rule codec used for serializing and de-serializing JSON string.
+ */
+public final class KubevirtLoadBalancerRuleCodec extends JsonCodec<KubevirtLoadBalancerRule> {
+
+ private final Logger log = getLogger(getClass());
+
+ private static final String PROTOCOL = "protocol";
+ private static final String PORT_RANGE_MAX = "portRangeMax";
+ private static final String PORT_RANGE_MIN = "portRangeMin";
+ private static final String TCP = "TCP";
+ private static final String UDP = "UDP";
+
+ private static final String MISSING_MESSAGE = " is required in KubevirtLoadBalancerRule";
+
+ @Override
+ public ObjectNode encode(KubevirtLoadBalancerRule rule, CodecContext context) {
+ checkNotNull(rule, "Kubevirt load balancer rule cannot be null");
+
+ ObjectNode result = context.mapper().createObjectNode().put(PROTOCOL, rule.protocol());
+
+ if (rule.protocol().equalsIgnoreCase(TCP) || rule.protocol().equalsIgnoreCase(UDP)) {
+ result.put(PORT_RANGE_MAX, rule.portRangeMax()).put(PORT_RANGE_MIN, rule.portRangeMin());
+ }
+ return result;
+ }
+
+ @Override
+ public KubevirtLoadBalancerRule decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ KubevirtLoadBalancerRule.Builder builder = DefaultKubevirtLoadBalancerRule.builder();
+
+ JsonNode protocolJson = json.get(PROTOCOL);
+ String protocol = "";
+ if (protocolJson != null) {
+ protocol = protocolJson.asText();
+ }
+ builder.protocol(protocol);
+
+ if (protocol.equalsIgnoreCase(TCP) || protocol.equalsIgnoreCase(UDP)) {
+ Integer portRangeMax = json.get(PORT_RANGE_MAX).asInt();
+ Integer portRangeMin = json.get(PORT_RANGE_MIN).asInt();
+ builder.portRangeMax(portRangeMax).portRangeMin(portRangeMin);
+ }
+
+ return builder.build();
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtNetworkCodec.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtNetworkCodec.java
new file mode 100644
index 0000000..2d8a07c
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtNetworkCodec.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.IpAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.kubevirtnetworking.api.DefaultKubevirtNetwork;
+import org.onosproject.kubevirtnetworking.api.KubevirtHostRoute;
+import org.onosproject.kubevirtnetworking.api.KubevirtIpPool;
+import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
+import org.slf4j.Logger;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.IntStream;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Kubevirt network codec used for serializing and de-serializing JSON string.
+ */
+public final class KubevirtNetworkCodec extends JsonCodec<KubevirtNetwork> {
+
+ private final Logger log = getLogger(getClass());
+
+ private static final String NETWORK_ID = "networkId";
+ private static final String TYPE = "type";
+ private static final String NAME = "name";
+ private static final String MTU = "mtu";
+ private static final String SEGMENT_ID = "segmentId";
+ private static final String GATEWAY_IP = "gatewayIp";
+ private static final String DEFAULT_ROUTE = "defaultRoute";
+ private static final String CIDR = "cidr";
+ private static final String HOST_ROUTES = "hostRoutes";
+ private static final String IP_POOL = "ipPool";
+ private static final String DNSES = "dnses";
+
+ private static final String MISSING_MESSAGE = " is required in KubevirtNetwork";
+
+ @Override
+ public ObjectNode encode(KubevirtNetwork network, CodecContext context) {
+ checkNotNull(network, "Kubevirt network cannot be null");
+
+ ObjectNode result = context.mapper().createObjectNode()
+ .put(NETWORK_ID, network.networkId())
+ .put(TYPE, network.type().name())
+ .put(NAME, network.name())
+ .put(MTU, network.mtu())
+ .put(GATEWAY_IP, network.gatewayIp().toString())
+ .put(DEFAULT_ROUTE, network.defaultRoute())
+ .put(CIDR, network.cidr());
+
+ if (network.segmentId() != null) {
+ result.put(SEGMENT_ID, network.segmentId());
+ }
+
+ if (network.hostRoutes() != null && !network.hostRoutes().isEmpty()) {
+ ArrayNode hostRoutes = context.mapper().createArrayNode();
+ network.hostRoutes().forEach(hostRoute -> {
+ ObjectNode hostRouteJson =
+ context.codec(KubevirtHostRoute.class).encode(hostRoute, context);
+ hostRoutes.add(hostRouteJson);
+ });
+ result.set(HOST_ROUTES, hostRoutes);
+ }
+
+ if (network.ipPool() != null) {
+ ObjectNode ipPoolJson = context.codec(KubevirtIpPool.class).encode(network.ipPool(), context);
+ result.set(IP_POOL, ipPoolJson);
+ }
+
+ if (network.dnses() != null && !network.dnses().isEmpty()) {
+ ArrayNode dnses = context.mapper().createArrayNode();
+ network.dnses().forEach(dns -> {
+ dnses.add(dns.toString());
+ });
+ result.set(DNSES, dnses);
+ }
+
+ return result;
+ }
+
+ @Override
+ public KubevirtNetwork decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ String networkId = nullIsIllegal(json.get(NETWORK_ID).asText(),
+ NETWORK_ID + MISSING_MESSAGE);
+ String type = nullIsIllegal(json.get(TYPE).asText(),
+ TYPE + MISSING_MESSAGE);
+ String name = nullIsIllegal(json.get(NAME).asText(),
+ NAME + MISSING_MESSAGE);
+ Integer mtu = nullIsIllegal(json.get(MTU).asInt(),
+ MTU + MISSING_MESSAGE);
+ String gatewayIp = nullIsIllegal(json.get(GATEWAY_IP).asText(),
+ GATEWAY_IP + MISSING_MESSAGE);
+ boolean defaultRoute = nullIsIllegal(json.get(DEFAULT_ROUTE).asBoolean(),
+ DEFAULT_ROUTE + MISSING_MESSAGE);
+ String cidr = nullIsIllegal(json.get(CIDR).asText(),
+ CIDR + MISSING_MESSAGE);
+
+ KubevirtNetwork.Builder networkBuilder = DefaultKubevirtNetwork.builder()
+ .networkId(networkId)
+ .type(KubevirtNetwork.Type.valueOf(type))
+ .name(name)
+ .mtu(mtu)
+ .gatewayIp(IpAddress.valueOf(gatewayIp))
+ .defaultRoute(defaultRoute)
+ .cidr(cidr);
+
+ if (!type.equals(KubevirtNetwork.Type.FLAT.name())) {
+ JsonNode segmentIdJson = json.get(SEGMENT_ID);
+ if (segmentIdJson != null) {
+ networkBuilder.segmentId(segmentIdJson.asText());
+ }
+ }
+
+ JsonNode ipPoolJson = json.get(IP_POOL);
+ if (ipPoolJson != null) {
+ final JsonCodec<KubevirtIpPool>
+ ipPoolCodec = context.codec(KubevirtIpPool.class);
+ networkBuilder.ipPool(ipPoolCodec.decode(
+ (ObjectNode) ipPoolJson.deepCopy(), context));
+ }
+
+ // parse host routes
+ Set<KubevirtHostRoute> hostRoutes = new HashSet<>();
+ JsonNode hostRoutesJson = json.get(HOST_ROUTES);
+ if (hostRoutesJson != null) {
+ final JsonCodec<KubevirtHostRoute>
+ hostRouteCodec = context.codec(KubevirtHostRoute.class);
+
+ IntStream.range(0, hostRoutesJson.size()).forEach(i -> {
+ ObjectNode routeJson = get(hostRoutesJson, i);
+ hostRoutes.add(hostRouteCodec.decode(routeJson, context));
+ });
+ }
+ networkBuilder.hostRoutes(hostRoutes);
+
+ // parse DNSes
+ Set<IpAddress> dnses = new HashSet<>();
+ JsonNode dnsesJson = json.get(DNSES);
+ if (dnsesJson != null) {
+ for (int i = 0; i < dnsesJson.size(); i++) {
+ JsonNode dnsJson = dnsesJson.get(i);
+ if (dnsJson != null) {
+ dnses.add(IpAddress.valueOf(dnsJson.asText()));
+ }
+ }
+ }
+ networkBuilder.dnses(dnses);
+
+ log.trace("Network is {}", networkBuilder.build().toString());
+
+ return networkBuilder.build();
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtPortCodec.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtPortCodec.java
new file mode 100644
index 0000000..281855e
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtPortCodec.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.kubevirtnetworking.api.DefaultKubevirtPort;
+import org.onosproject.kubevirtnetworking.api.KubevirtPort;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+import static org.slf4j.LoggerFactory.getLogger;
+
+public final class KubevirtPortCodec extends JsonCodec<KubevirtPort> {
+
+ private final Logger log = getLogger(getClass());
+
+ private static final String VM_NAME = "vmName";
+ private static final String NETWORK_ID = "networkId";
+ private static final String MAC_ADDRESS = "macAddress";
+ private static final String IP_ADDRESS = "ipAddress";
+ private static final String DEVICE_ID = "deviceId";
+ private static final String PORT_NUMBER = "portNumber";
+ private static final String SECURITY_GROUPS = "securityGroups";
+
+ private static final String MISSING_MESSAGE = " is required in KubevirtPort";
+
+ @Override
+ public ObjectNode encode(KubevirtPort port, CodecContext context) {
+ checkNotNull(port, "Kubevirt port cannot be null");
+
+ ObjectNode result = context.mapper().createObjectNode()
+ .put(VM_NAME, port.vmName())
+ .put(NETWORK_ID, port.networkId())
+ .put(MAC_ADDRESS, port.macAddress().toString());
+
+ if (port.ipAddress() != null) {
+ result.put(IP_ADDRESS, port.ipAddress().toString());
+ }
+
+ if (port.deviceId() != null) {
+ result.put(DEVICE_ID, port.deviceId().toString());
+ }
+
+ if (port.portNumber() != null) {
+ result.put(PORT_NUMBER, port.portNumber().toString());
+ }
+
+ if (port.securityGroups() != null) {
+ ArrayNode sgIds = context.mapper().createArrayNode();
+ for (String sgId : port.securityGroups()) {
+ sgIds.add(sgId);
+ }
+ result.set(SECURITY_GROUPS, sgIds);
+ }
+
+ return result;
+ }
+
+ @Override
+ public KubevirtPort decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ String vmName = nullIsIllegal(json.get(VM_NAME).asText(),
+ VM_NAME + MISSING_MESSAGE);
+
+ String networkId = nullIsIllegal(json.get(NETWORK_ID).asText(),
+ NETWORK_ID + MISSING_MESSAGE);
+
+ String macAddress = nullIsIllegal(json.get(MAC_ADDRESS).asText(),
+ MAC_ADDRESS + MISSING_MESSAGE);
+
+ KubevirtPort.Builder builder = DefaultKubevirtPort.builder()
+ .vmName(vmName)
+ .networkId(networkId)
+ .macAddress(MacAddress.valueOf(macAddress));
+
+ JsonNode ipAddressJson = json.get(IP_ADDRESS);
+ if (ipAddressJson != null) {
+ final IpAddress ipAddress = IpAddress.valueOf(ipAddressJson.asText());
+ builder.ipAddress(ipAddress);
+ }
+
+ JsonNode deviceIdJson = json.get(DEVICE_ID);
+ if (deviceIdJson != null) {
+ final DeviceId deviceId = DeviceId.deviceId(deviceIdJson.asText());
+ builder.deviceId(deviceId);
+ }
+
+ JsonNode portNumberJson = json.get(PORT_NUMBER);
+ if (portNumberJson != null) {
+ final PortNumber portNumber = PortNumber.portNumber(portNumberJson.asText());
+ builder.portNumber(portNumber);
+ }
+
+ log.trace("Port is {}", builder.build().toString());
+
+ return builder.build();
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtRouterCodec.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtRouterCodec.java
new file mode 100644
index 0000000..5ca4ab6
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtRouterCodec.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+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.ImmutableMap;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.kubevirtnetworking.api.DefaultKubevirtRouter;
+import org.onosproject.kubevirtnetworking.api.KubevirtPeerRouter;
+import org.onosproject.kubevirtnetworking.api.KubevirtRouter;
+import org.slf4j.Logger;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Kubevirt router codec used for serializing and de-serializing JSON string.
+ */
+public final class KubevirtRouterCodec extends JsonCodec<KubevirtRouter> {
+
+ private final Logger log = getLogger(getClass());
+
+ private static final String NAME = "name";
+ private static final String DESCRIPTION = "description";
+ private static final String ENABLE_SNAT = "enableSnat";
+ private static final String INTERNAL = "internal";
+ private static final String EXTERNAL = "external";
+ private static final String PEER_ROUTER = "peerRouter";
+ private static final String IP_ADDRESS = "ip";
+ private static final String MAC_ADDRESS = "mac";
+ private static final String NETWORK = "network";
+ private static final String GATEWAY = "gateway";
+
+ private static final String MISSING_MESSAGE = " is required in KubevirtRouter";
+
+ @Override
+ public ObjectNode encode(KubevirtRouter router, CodecContext context) {
+ checkNotNull(router, "Kubevirt router cannot be null");
+
+ ObjectNode result = context.mapper().createObjectNode()
+ .put(NAME, router.name())
+ .put(ENABLE_SNAT, router.enableSnat())
+ .put(MAC_ADDRESS, router.mac().toString());
+
+ if (router.description() != null) {
+ result.put(DESCRIPTION, router.description());
+ }
+
+ if (router.internal() != null && !router.internal().isEmpty()) {
+ ArrayNode internal = context.mapper().createArrayNode();
+ router.internal().forEach(internal::add);
+
+ result.set(INTERNAL, internal);
+ }
+
+ if (router.external() != null && !router.external().isEmpty()) {
+ ArrayNode external = context.mapper().createArrayNode();
+ router.external().forEach((k, v) -> {
+ ObjectNode item = context.mapper().createObjectNode();
+ item.put(IP_ADDRESS, k);
+ item.put(NETWORK, v);
+ external.add(item);
+ });
+ result.set(EXTERNAL, external);
+ }
+
+ if (router.peerRouter() != null) {
+ ObjectNode peerRouter = context.mapper().createObjectNode();
+ peerRouter.put(IP_ADDRESS, router.peerRouter().ipAddress().toString());
+
+ if (router.peerRouter().macAddress() != null) {
+ peerRouter.put(MAC_ADDRESS, router.peerRouter().macAddress().toString());
+ }
+
+ result.set(PEER_ROUTER, peerRouter);
+ }
+
+ if (router.electedGateway() != null) {
+ result.put(GATEWAY, router.electedGateway());
+ }
+
+ return result;
+ }
+
+ @Override
+ public KubevirtRouter decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ String name = nullIsIllegal(json.get(NAME).asText(),
+ NAME + MISSING_MESSAGE);
+
+ String vrouterMac = nullIsIllegal(json.get(MAC_ADDRESS).asText(),
+ MAC_ADDRESS + MISSING_MESSAGE);
+
+ KubevirtRouter.Builder builder = DefaultKubevirtRouter.builder()
+ .name(name)
+ .mac(MacAddress.valueOf(vrouterMac));
+
+ JsonNode descriptionJson = json.get(DESCRIPTION);
+ if (descriptionJson != null) {
+ builder.description(descriptionJson.asText());
+ }
+
+ JsonNode enableSnatJson = json.get(ENABLE_SNAT);
+ if (enableSnatJson != null) {
+ builder.enableSnat(enableSnatJson.asBoolean());
+ }
+ JsonNode electedGwJson = json.get(GATEWAY);
+ if (electedGwJson != null) {
+ builder.electedGateway(electedGwJson.asText());
+ }
+
+ ArrayNode internalJson = (ArrayNode) json.get(INTERNAL);
+ Set<String> internal = new HashSet<>();
+ if (internalJson != null) {
+ for (int i = 0; i < internalJson.size(); i++) {
+ internal.add(internalJson.get(i).asText());
+ }
+ builder.internal(internal);
+ }
+
+ ObjectNode externalJson = (ObjectNode) json.get(EXTERNAL);
+ if (externalJson != null) {
+ Map<String, String> external = ImmutableMap.of(
+ externalJson.get(IP_ADDRESS).asText(),
+ externalJson.get(NETWORK).asText());
+ builder.external(external);
+ }
+
+ ObjectNode peerRouterJson = (ObjectNode) json.get(PEER_ROUTER);
+ if (peerRouterJson != null) {
+ JsonNode ipJson = peerRouterJson.get(IP_ADDRESS);
+ JsonNode macJson = peerRouterJson.get(MAC_ADDRESS);
+
+ if (ipJson != null && macJson != null) {
+ IpAddress ip = IpAddress.valueOf(ipJson.asText());
+ MacAddress mac = MacAddress.valueOf(macJson.asText());
+ KubevirtPeerRouter peer = new KubevirtPeerRouter(ip, mac);
+ builder.peerRouter(peer);
+ }
+
+ // if mac address is not specified, we will not add mac address to peer router
+ if (ipJson != null && macJson == null) {
+ IpAddress ip = IpAddress.valueOf(ipJson.asText());
+ KubevirtPeerRouter peer = new KubevirtPeerRouter(ip, null);
+ builder.peerRouter(peer);
+ }
+ }
+
+ return builder.build();
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtSecurityGroupCodec.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtSecurityGroupCodec.java
new file mode 100644
index 0000000..fe290f9
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtSecurityGroupCodec.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.kubevirtnetworking.api.DefaultKubevirtSecurityGroup;
+import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroup;
+import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroupRule;
+import org.slf4j.Logger;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.IntStream;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Kubevirt security group codec used for serializing and de-serializing JSON string.
+ */
+public final class KubevirtSecurityGroupCodec extends JsonCodec<KubevirtSecurityGroup> {
+
+ private final Logger log = getLogger(getClass());
+
+ private static final String ID = "id";
+ private static final String NAME = "name";
+ private static final String DESCRIPTION = "description";
+ private static final String RULES = "rules";
+
+ private static final String MISSING_MESSAGE = " is required in KubevirtSecurityGroup";
+
+ @Override
+ public ObjectNode encode(KubevirtSecurityGroup sg, CodecContext context) {
+ checkNotNull(sg, "Kubevirt Security Group cannot be null");
+
+ ObjectNode result = context.mapper().createObjectNode()
+ .put(ID, sg.id())
+ .put(NAME, sg.name());
+
+ if (sg.description() != null) {
+ result.put(DESCRIPTION, sg.description());
+ }
+
+ if (sg.rules() != null && !sg.rules().isEmpty()) {
+ ArrayNode rules = context.mapper().createArrayNode();
+ sg.rules().forEach(rule -> {
+ ObjectNode ruleJson = context.codec(
+ KubevirtSecurityGroupRule.class).encode(rule, context);
+ rules.add(ruleJson);
+ });
+ result.set(RULES, rules);
+ }
+
+ return result;
+ }
+
+ @Override
+ public KubevirtSecurityGroup decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ String id = nullIsIllegal(json.get(ID).asText(), ID + MISSING_MESSAGE);
+ String name = nullIsIllegal(json.get(NAME).asText(), NAME + MISSING_MESSAGE);
+
+ KubevirtSecurityGroup.Builder builder = DefaultKubevirtSecurityGroup.builder()
+ .id(id)
+ .name(name);
+
+ JsonNode description = json.get(DESCRIPTION);
+ if (description != null) {
+ builder.description(description.asText());
+ }
+
+ JsonNode rulesJson = json.get(RULES);
+ if (rulesJson != null) {
+ Set<KubevirtSecurityGroupRule> rules = new HashSet<>();
+ IntStream.range(0, rulesJson.size())
+ .forEach(i -> {
+ ObjectNode ruleJson = get(rulesJson, i);
+ KubevirtSecurityGroupRule rule = context.codec(
+ KubevirtSecurityGroupRule.class).decode(ruleJson, context);
+ rules.add(rule);
+ });
+ builder.rules(rules);
+ }
+
+ return builder.build();
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtSecurityGroupRuleCodec.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtSecurityGroupRuleCodec.java
new file mode 100644
index 0000000..b63b555
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtSecurityGroupRuleCodec.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.kubevirtnetworking.api.DefaultKubevirtSecurityGroupRule;
+import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroupRule;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Kubevirt security group rule codec used for serializing and de-serializing JSON string.
+ */
+public final class KubevirtSecurityGroupRuleCodec extends JsonCodec<KubevirtSecurityGroupRule> {
+
+ private final Logger log = getLogger(getClass());
+
+ private static final String ID = "id";
+ private static final String SECURITY_GROUP_ID = "securityGroupId";
+ private static final String DIRECTION = "direction";
+ private static final String ETHER_TYPE = "etherType";
+ private static final String PORT_RANGE_MAX = "portRangeMax";
+ private static final String PORT_RANGE_MIN = "portRangeMin";
+ private static final String PROTOCOL = "protocol";
+ private static final String REMOTE_IP_PREFIX = "remoteIpPrefix";
+ private static final String REMOTE_GROUP_ID = "remoteGroupId";
+
+ private static final String MISSING_MESSAGE = " is required in KubevirtSecurityGroupRule";
+
+ @Override
+ public ObjectNode encode(KubevirtSecurityGroupRule sgRule, CodecContext context) {
+ checkNotNull(sgRule, "Kubevirt security group rule cannot be null");
+
+ ObjectNode result = context.mapper().createObjectNode()
+ .put(ID, sgRule.id())
+ .put(SECURITY_GROUP_ID, sgRule.securityGroupId())
+ .put(DIRECTION, sgRule.direction());
+
+ if (sgRule.etherType() != null) {
+ result.put(ETHER_TYPE, sgRule.etherType());
+ }
+
+ if (sgRule.portRangeMax() != null) {
+ result.put(PORT_RANGE_MAX, sgRule.portRangeMax());
+ }
+
+ if (sgRule.portRangeMin() != null) {
+ result.put(PORT_RANGE_MIN, sgRule.portRangeMin());
+ }
+
+ if (sgRule.protocol() != null) {
+ result.put(PROTOCOL, sgRule.protocol());
+ }
+
+ if (sgRule.remoteIpPrefix() != null) {
+ result.put(REMOTE_IP_PREFIX, sgRule.remoteIpPrefix().toString());
+ }
+
+ if (sgRule.remoteGroupId() != null) {
+ result.put(REMOTE_GROUP_ID, sgRule.remoteGroupId());
+ }
+
+ return result;
+ }
+
+ @Override
+ public KubevirtSecurityGroupRule decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ String id = nullIsIllegal(json.get(ID).asText(), ID + MISSING_MESSAGE);
+ String securityGroupId = nullIsIllegal(json.get(SECURITY_GROUP_ID).asText(),
+ SECURITY_GROUP_ID + MISSING_MESSAGE);
+ String direction = nullIsIllegal(json.get(DIRECTION).asText(),
+ DIRECTION + MISSING_MESSAGE);
+
+ KubevirtSecurityGroupRule.Builder builder = DefaultKubevirtSecurityGroupRule.builder()
+ .id(id)
+ .securityGroupId(securityGroupId)
+ .direction(direction);
+
+ JsonNode etherType = json.get(ETHER_TYPE);
+ if (etherType != null) {
+ builder.etherType(etherType.asText());
+ }
+
+ JsonNode portRangeMax = json.get(PORT_RANGE_MAX);
+ if (portRangeMax != null) {
+ builder.portRangeMax(portRangeMax.asInt());
+ }
+
+ JsonNode portRangeMin = json.get(PORT_RANGE_MIN);
+ if (portRangeMin != null) {
+ builder.portRangeMin(portRangeMin.asInt());
+ }
+
+ JsonNode protocol = json.get(PROTOCOL);
+ if (protocol != null) {
+ builder.protocol(protocol.asText());
+ }
+
+ JsonNode remoteIpPrefix = json.get(REMOTE_IP_PREFIX);
+ if (remoteIpPrefix != null) {
+ builder.remoteIpPrefix(IpPrefix.valueOf(remoteIpPrefix.asText()));
+ }
+
+ JsonNode remoteGroupId = json.get(REMOTE_GROUP_ID);
+ if (remoteGroupId != null) {
+ builder.remoteGroupId(remoteGroupId.asText());
+ }
+
+ return builder.build();
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/package-info.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/package-info.java
new file mode 100644
index 0000000..91d8c00
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/codec/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2020-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.
+ */
+
+/**
+ * Implementations of the codec broker and KubeVirt networking entity JSON codecs.
+ */
+package org.onosproject.kubevirtnetworking.codec;
\ No newline at end of file
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtFloatingIpsWebResource.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtFloatingIpsWebResource.java
new file mode 100644
index 0000000..ec41622
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtFloatingIpsWebResource.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.web;
+
+import org.onosproject.kubevirtnetworking.api.KubevirtFloatingIp;
+import org.onosproject.kubevirtnetworking.api.KubevirtRouterService;
+import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * Handles REST API call for kubevirt floating IPs.
+ */
+@Path("floating-ip")
+public class KubevirtFloatingIpsWebResource extends AbstractWebResource {
+
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+
+ private static final String FLOATING_IPS = "floating-ips";
+
+ /**
+ * Returns set of all floating IPs.
+ *
+ * @return 200 OK with set of all floating IPs
+ * @onos.rsModel KubevirtFloatingIps
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getFloatingIps() {
+ KubevirtRouterService service = get(KubevirtRouterService.class);
+ final Iterable<KubevirtFloatingIp> fips = service.floatingIps();
+ return ok(encodeArray(KubevirtFloatingIp.class, FLOATING_IPS, fips)).build();
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtLoadBalancerWebResource.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtLoadBalancerWebResource.java
new file mode 100644
index 0000000..8fa61a2
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtLoadBalancerWebResource.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.web;
+
+import org.onosproject.kubevirtnetworking.api.KubevirtLoadBalancer;
+import org.onosproject.kubevirtnetworking.api.KubevirtLoadBalancerService;
+import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * Handles REST API call for kubevirt load balancer.
+ */
+@Path("loadbalancer")
+public class KubevirtLoadBalancerWebResource extends AbstractWebResource {
+
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+ private static final String LOAD_BALANCERS = "loadBalancers";
+
+ /**
+ * Returns set of all load balancers.
+ *
+ * @return 200 OK with set of all load balancers
+ * @onos.rsModel KubevirtLoadBalancers
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getLoadBalancers() {
+ KubevirtLoadBalancerService service = get(KubevirtLoadBalancerService.class);
+ final Iterable<KubevirtLoadBalancer> lbs = service.loadBalancers();
+ return ok(encodeArray(KubevirtLoadBalancer.class, LOAD_BALANCERS, lbs)).build();
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtMm5WebResource.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtMm5WebResource.java
new file mode 100644
index 0000000..ef8f707
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtMm5WebResource.java
@@ -0,0 +1,485 @@
+/*
+ * Copyright 2022-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.kubevirtnetworking.web;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.kubevirtnetworking.api.KubevirtFloatingIp;
+import org.onosproject.kubevirtnetworking.api.KubevirtInstance;
+import org.onosproject.kubevirtnetworking.api.KubevirtInstanceService;
+import org.onosproject.kubevirtnetworking.api.KubevirtLoadBalancer;
+import org.onosproject.kubevirtnetworking.api.KubevirtLoadBalancerService;
+import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
+import org.onosproject.kubevirtnetworking.api.KubevirtNetworkService;
+import org.onosproject.kubevirtnetworking.api.KubevirtRouter;
+import org.onosproject.kubevirtnetworking.api.KubevirtRouterService;
+import org.onosproject.kubevirtnode.api.KubevirtNode;
+import org.onosproject.kubevirtnode.api.KubevirtNodeService;
+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.POST;
+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.io.InputStream;
+
+/**
+ * Handles REST API for communication with MEC Orchestrator.
+ */
+@Path("api/mm5/v1")
+public class KubevirtMm5WebResource extends AbstractWebResource {
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+
+ private static final String RECEIVED_REQUEST = "Received %s request";
+ private static final String QUERY_STATUS_LEG = "LEG status query";
+ private static final String QUERY_STATUS_VR = "VR status query";
+
+ private static final String QUERY_GET_NETWORK = "get network query";
+ private static final String QUERY_CREATE_NETWORK = "create network query";
+ private static final String QUERY_UPDATE_NETWORK = "update network query";
+ private static final String QUERY_DELETE_NETWORK = "delete network query";
+
+ private static final String QUERY_GET_VR = "get virtual router query";
+ private static final String QUERY_CREATE_VR = "create virtual router query";
+ private static final String QUERY_UPDATE_VR = "update virtual router query";
+ private static final String QUERY_DELETE_VR = "delete virtual router query";
+
+ private static final String QUERY_GET_FIP = "get floating ip query";
+ private static final String QUERY_CREATE_FIP = "create floating ip query";
+ private static final String QUERY_UPDATE_FIP = "update floating ip query";
+ private static final String QUERY_DELETE_FIP = "delete floating ip query";
+
+ private static final String QUERY_GET_LB = "get LoadBalancer query";
+ private static final String QUERY_CREATE_LB = "create LoadBalancer query";
+ private static final String QUERY_UPDATE_LB = "update LoadBalancer query";
+ private static final String QUERY_DELETE_LB = "delete LoadBalancer query";
+
+ private static final String QUERY_GET_INSTANCE = "get instance query";
+ private static final String QUERY_CREATE_INSTANCE = "create instance query";
+ private static final String QUERY_UPDATE_INSTANCE = "update floating ip query";
+ private static final String QUERY_DELETE_INSTANCE = "delete floating ip query";
+
+ private static final String NODE_NAME = "nodeName";
+ private static final String STATE = "state";
+ private static final String ACTIVE = "ACTIVE";
+ private static final String INACTIVE = "INACTIVE";
+
+ private static final String NETWORKS = "networks";
+ private static final String INSTANCES = "instances";
+ private static final String VIRTUAL_ROUTERS = "virtualRouters";
+ private static final String LOAD_BALANCERS = "loadBalancers";
+ private static final String FLOATING_IPS = "floatingIps";
+
+ private static final String UP = "up";
+ private static final String DOWN = "down";
+ private static final String NONE = "none";
+
+ private static final String VR_NAME = "vrName";
+
+ @Context
+ private UriInfo uriInfo;
+
+ /**
+ * Obtains the status of the virtual router.
+ *
+ * @param vrName virtual router name
+ * @return the state of the virtual router in Json
+ */
+ @GET
+ @Path("status/vr/{vrName}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response vrStatus(@PathParam(VR_NAME) String vrName) {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_STATUS_VR));
+
+ KubevirtRouterService service = get(KubevirtRouterService.class);
+
+ KubevirtRouter router = service.routers().stream()
+ .filter(r -> r.name().equals(vrName))
+ .findAny().orElse(null);
+
+ if (router == null) {
+ return Response.status(Response.Status.NOT_FOUND).build();
+ } else {
+ ObjectNode jsonResult = mapper().createObjectNode();
+
+ jsonResult.put(VR_NAME, router.name());
+
+ if (router.electedGateway() == null) {
+ jsonResult.put("merName", NONE);
+ jsonResult.put("status", DOWN);
+ } else {
+ jsonResult.put("merName", router.electedGateway());
+ jsonResult.put("status", UP);
+ }
+
+ jsonResult.put("timeUpdated", System.currentTimeMillis());
+ return ok(jsonResult).build();
+ }
+ }
+
+ /**
+ * Obtains the state of the leg node.
+ *
+ * @param nodeName leg host name
+ * @return the state of the leg node in Json
+ */
+ @PUT
+ @Path("state/mer/{nodeName}")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response legStatus(@PathParam("nodeName") String nodeName) {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_STATUS_LEG));
+
+ KubevirtNodeService service = get(KubevirtNodeService.class);
+
+ ObjectNode jsonResult = mapper().createObjectNode();
+ jsonResult.put(NODE_NAME, nodeName);
+
+ boolean isActive = service.completeNodes().stream()
+ .anyMatch(node -> node.type().equals(KubevirtNode.Type.GATEWAY) &&
+ node.hostname().equals(nodeName));
+ if (isActive) {
+ jsonResult.put(STATE, ACTIVE);
+ } else {
+ jsonResult.put(STATE, INACTIVE);
+ }
+ return ok(jsonResult).build();
+ }
+
+ /**
+ * Obtains the network information in Json Array.
+ *
+ * @return network information in Json
+ */
+ @GET
+ @Path("network")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getNetwork() {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_GET_NETWORK));
+
+ KubevirtNetworkService service = get(KubevirtNetworkService.class);
+ final Iterable<KubevirtNetwork> networks = service.networks();
+ return ok(encodeArray(KubevirtNetwork.class, NETWORKS, networks)).build();
+ }
+
+ /**
+ * Creates the kubevirt network with specified input stream.
+ *
+ * @param inputStream network Json input stream
+ * @return 200 OK if succeeded
+ */
+ @POST
+ @Path("network")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response createNetwork(InputStream inputStream) {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_CREATE_NETWORK));
+ //Just sends 200 OK for now.
+ return ok(mapper().createObjectNode()).build();
+ }
+
+ /**
+ * Updates the kubevirt network with the specified input stream.
+ *
+ * @param inputStream network Json input stream
+ * @return 200 OK if succeeded
+ */
+ @PUT
+ @Path("network/{networkName}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response updateNetwork(InputStream inputStream) {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_UPDATE_NETWORK));
+ //Just sends 200 OK for now.
+ return ok(mapper().createObjectNode()).build();
+ }
+
+ /**
+ * Deletes the kubevirt network with the specified input stream.
+ *
+ * @param inputStream network Json input stream
+ * @return 200 OK if succeeded
+ */
+ @DELETE
+ @Path("network/{networkName}")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response deleteNetwork(InputStream inputStream) {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_DELETE_NETWORK));
+ //Just sends 200 OK for now.
+ return ok(mapper().createObjectNode()).build();
+ }
+
+ /**
+ * Obtains the instance information in Json Array.
+ *
+ * @return instance information in Json
+ */
+ @GET
+ @Path("instance")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getInstance() {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_GET_INSTANCE));
+
+ KubevirtInstanceService service = get(KubevirtInstanceService.class);
+ final Iterable<KubevirtInstance> instances = service.instances();
+ return ok(encodeArray(KubevirtInstance.class, INSTANCES, instances)).build();
+ }
+
+ /**
+ * Creates the instance with specified input stream.
+ *
+ * @param inputStream instance Json insput stream
+ * @return 200 OK if succeeded
+ */
+ @POST
+ @Path("instance")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response createInstance(InputStream inputStream) {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_CREATE_INSTANCE));
+ //Just sends 200 OK for now.
+ return ok(mapper().createObjectNode()).build();
+ }
+
+ /**
+ * Updates the instance with specified input stream.
+ *
+ * @param inputStream instance Json insput stream
+ * @return 200 OK if succeeded
+ */
+ @PUT
+ @Path("instance/{instanceName}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response updateInstance(InputStream inputStream) {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_UPDATE_INSTANCE));
+ //Just sends 200 OK for now.
+ return ok(mapper().createObjectNode()).build();
+ }
+
+ /**
+ * Deletes the instance with specified input stream.
+ *
+ * @param inputStream inputStream instance Json insput stream
+ * @return 200 OK if succeeded
+ */
+ @DELETE
+ @Path("instance/{instanceName}")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response deleteInstance(InputStream inputStream) {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_DELETE_INSTANCE));
+ //Just sends 200 OK for now.
+ return ok(mapper().createObjectNode()).build();
+ }
+
+ /**
+ * Obtains the virtual router in Json array.
+ *
+ * @return virtual router information in Json
+ */
+ @GET
+ @Path("vr")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getVirtualRouter() {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_GET_VR));
+
+ KubevirtRouterService service = get(KubevirtRouterService.class);
+ final Iterable<KubevirtRouter> routers = service.routers();
+ return ok(encodeArray(KubevirtRouter.class, VIRTUAL_ROUTERS, routers)).build();
+ }
+
+ /**
+ * Creates the virtual router with specified input stream.
+ *
+ * @param inputStream virtual router Json inputstream
+ * @return 200 OK if succeeded
+ */
+ @POST
+ @Path("vr")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response createVirtualRouter(InputStream inputStream) {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_CREATE_VR));
+ //Just sends 200 OK for now.
+ return ok(mapper().createObjectNode()).build();
+ }
+
+ /**
+ * Updates the virtual router with specified input stream.
+ *
+ * @param inputStream virtual router Json inputstream
+ * @return 200 OK if succeeded
+ */
+ @PUT
+ @Path("vr/{vrName}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response updateVirtualRouter(InputStream inputStream) {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_UPDATE_VR));
+ //Just sends 200 OK for now.
+ return ok(mapper().createObjectNode()).build();
+ }
+
+ /**
+ * Deletes the virtual router with specified input stream.
+ *
+ * @param inputStream virtual router Json inputstream
+ * @return 200 OK if succeeded
+ */
+ @DELETE
+ @Path("vr/{vrName}")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response deleteVirtualRouter(InputStream inputStream) {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_DELETE_VR));
+ //Just sends 200 OK for now.
+ return ok(mapper().createObjectNode()).build();
+ }
+
+ /**
+ * Obtains the floating ip in Json array.
+ *
+ * @return floating ip information in Json
+ */
+ @GET
+ @Path("fip")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getFloatingIp() {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_GET_FIP));
+
+ KubevirtRouterService service = get(KubevirtRouterService.class);
+ final Iterable<KubevirtFloatingIp> fips = service.floatingIps();
+ return ok(encodeArray(KubevirtFloatingIp.class, FLOATING_IPS, fips)).build();
+ }
+
+ /**
+ * Creates the floating ip with specified input stream.
+ *
+ * @param inputStream floating ip Json inputstream
+ * @return 200 OK if succeeded
+ */
+ @POST
+ @Path("fip")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response createFloatingIp(InputStream inputStream) {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_CREATE_FIP));
+ //Just sends 200 OK for now.
+ return ok(mapper().createObjectNode()).build();
+ }
+
+ /**
+ * Updates the floating ip with specified input stream.
+ *
+ * @param inputStream floating ip Json inputstream
+ * @return 200 OK if succeeded
+ */
+ @PUT
+ @Path("fip/{fipName}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response updateFloatingIp(InputStream inputStream) {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_UPDATE_FIP));
+ //Just sends 200 OK for now.
+ return ok(mapper().createObjectNode()).build();
+ }
+
+ /**
+ * Deletes the floating ip with specified input stream.
+ *
+ * @param inputStream floating ip Json inputstream
+ * @return 200 OK if succeeded
+ */
+ @DELETE
+ @Path("fip/{fipName}")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response deleteFloatingIp(InputStream inputStream) {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_DELETE_FIP));
+ //Just sends 200 OK for now.
+ return ok(mapper().createObjectNode()).build();
+ }
+
+ /**
+ * Obtains the loadbalaner in Json array.
+ *
+ * @return loadbalancer information in Json
+ */
+ @GET
+ @Path("lb")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getLoadBalancer() {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_GET_LB));
+
+ KubevirtLoadBalancerService service = get(KubevirtLoadBalancerService.class);
+ final Iterable<KubevirtLoadBalancer> lbs = service.loadBalancers();
+ return ok(encodeArray(KubevirtLoadBalancer.class, LOAD_BALANCERS, lbs)).build();
+ }
+
+ /**
+ * Creates the loadbalander with specified input stream.
+ *
+ * @param inputStream loadbalancer Json inputstream
+ * @return 200 OK if succeeded
+ */
+ @POST
+ @Path("lb")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response createLoadBalancer(InputStream inputStream) {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_CREATE_LB));
+ //Just sends 200 OK for now.
+ return ok(mapper().createObjectNode()).build();
+ }
+
+ /**
+ * Updates the loadbalander with specified input stream.
+ *
+ * @param inputStream loadbalancer Json inputstream
+ * @return 200 OK if succeeded
+ */
+ @PUT
+ @Path("lb/{lbName}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response updateLoadBalancer(InputStream inputStream) {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_UPDATE_LB));
+ //Just sends 200 OK for now.
+ return ok(mapper().createObjectNode()).build();
+ }
+
+ /**
+ * Deletes the loadbalander with specified input stream.
+ *
+ * @param inputStream loadbalancer Json inputstream
+ * @return 200 OK if succeeded
+ */
+ @DELETE
+ @Path("lb/{lbName}")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response deleteLoadBalancer(InputStream inputStream) {
+ log.trace(String.format(RECEIVED_REQUEST, QUERY_DELETE_LB));
+ //Just sends 200 OK for now.
+ return ok(mapper().createObjectNode()).build();
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtNetworkWebResource.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtNetworkWebResource.java
new file mode 100644
index 0000000..4e8f5df
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtNetworkWebResource.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2020-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.kubevirtnetworking.web;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
+import org.onosproject.kubevirtnetworking.api.KubevirtNetworkAdminService;
+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.POST;
+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.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import static org.onlab.util.Tools.nullIsNotFound;
+import static org.onlab.util.Tools.readTreeFromStream;
+
+/**
+ * Handles REST API call from CNI plugin.
+ */
+@Path("network")
+public class KubevirtNetworkWebResource extends AbstractWebResource {
+
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+
+ private static final String MESSAGE = "Received network %s request";
+ private static final String NETWORK_NOT_FOUND = "Network is not found for";
+ private static final String NETWORK_INVALID = "Invalid networkId in network update request";
+
+ private static final String RESULT = "result";
+
+ /**
+ * Creates a network from the JSON input stream.
+ *
+ * @param input network JSON input stream
+ * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
+ * is invalid or duplicated network already exists
+ * @onos.rsModel KubevirtNetwork
+ */
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response createNetwork(InputStream input) {
+ log.trace(String.format(MESSAGE, "CREATE"));
+ KubevirtNetworkAdminService service = get(KubevirtNetworkAdminService.class);
+ URI location;
+
+ try {
+ ObjectNode jsonTree = readTreeFromStream(mapper(), input);
+ final KubevirtNetwork network =
+ codec(KubevirtNetwork.class).decode(jsonTree, this);
+ service.createNetwork(network);
+ location = new URI(network.networkId());
+ } catch (IOException | URISyntaxException e) {
+ throw new IllegalArgumentException(e);
+ }
+
+ return Response.created(location).build();
+ }
+
+ /**
+ * Updates the network with the specified identifier.
+ *
+ * @param id network identifier
+ * @param input network JSON input stream
+ * @return 200 OK with the updated network, 400 BAD_REQUEST if the requested
+ * network does not exist
+ * @onos.rsModel KubevirtNetwork
+ */
+ @PUT
+ @Path("{id}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response updateNetwork(@PathParam("id") String id, InputStream input) {
+ log.trace(String.format(MESSAGE, "UPDATED"));
+ KubevirtNetworkAdminService service = get(KubevirtNetworkAdminService.class);
+
+ try {
+ ObjectNode jsonTree = readTreeFromStream(mapper(), input);
+ JsonNode specifiedNetworkId = jsonTree.get("networkId");
+
+ if (specifiedNetworkId != null && !specifiedNetworkId.asText().equals(id)) {
+ throw new IllegalArgumentException(NETWORK_INVALID);
+ }
+
+ final KubevirtNetwork network =
+ codec(KubevirtNetwork.class).decode(jsonTree, this);
+ service.updateNetwork(network);
+ } catch (IOException e) {
+ throw new IllegalArgumentException(e);
+ }
+
+ return Response.ok().build();
+ }
+
+ /**
+ * Removes the network with the given id.
+ *
+ * @param id network identifier
+ * @return 204 NO_CONTENT, 400 BAD_REQUEST if the network does not exist
+ */
+ @DELETE
+ @Path("{id}")
+ public Response removeNetwork(@PathParam("id") String id) {
+ log.trace(String.format(MESSAGE, "DELETE " + id));
+ KubevirtNetworkAdminService service = get(KubevirtNetworkAdminService.class);
+
+ service.removeNetwork(id);
+ return Response.noContent().build();
+ }
+
+ /**
+ * Checks whether the network exists with given network id.
+ *
+ * @param id network identifier
+ * @return 200 OK with true/false result
+ */
+ @GET
+ @Path("exist/{id}")
+ public Response hasNetwork(@PathParam("id") String id) {
+ log.trace(String.format(MESSAGE, "QUERY " + id));
+
+ KubevirtNetworkAdminService service = get(KubevirtNetworkAdminService.class);
+
+ ObjectNode root = mapper().createObjectNode();
+ KubevirtNetwork network = service.network(id);
+
+ if (network == null) {
+ root.put(RESULT, false);
+ } else {
+ root.put(RESULT, true);
+ }
+
+ return Response.ok(root).build();
+ }
+
+ /**
+ * Returns set of all networks.
+ *
+ * @return 200 OK with set of all networks
+ * @onos.rsModel KubevirtNetworks
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getNetworks() {
+ KubevirtNetworkAdminService service = get(KubevirtNetworkAdminService.class);
+ final Iterable<KubevirtNetwork> networks = service.networks();
+ return ok(encodeArray(KubevirtNetwork.class, "networks", networks)).build();
+ }
+
+ /**
+ * Returns the network with the specified identifier.
+ *
+ * @param id network identifier
+ * @return 200 OK with a network, 404 not found
+ * @onos.rsModel KubevirtNetwork
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("{id}")
+ public Response getNetworkById(@PathParam("id") String id) {
+ KubevirtNetworkAdminService service = get(KubevirtNetworkAdminService.class);
+ final KubevirtNetwork network = nullIsNotFound(service.network(id),
+ NETWORK_NOT_FOUND + id);
+ return ok(codec(KubevirtNetwork.class).encode(network, this)).build();
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtNetworkingCodecRegister.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtNetworkingCodecRegister.java
new file mode 100644
index 0000000..0280c6a
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtNetworkingCodecRegister.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.web;
+
+import org.onosproject.codec.CodecService;
+import org.onosproject.kubevirtnetworking.api.KubevirtFloatingIp;
+import org.onosproject.kubevirtnetworking.api.KubevirtHostRoute;
+import org.onosproject.kubevirtnetworking.api.KubevirtIpPool;
+import org.onosproject.kubevirtnetworking.api.KubevirtLoadBalancer;
+import org.onosproject.kubevirtnetworking.api.KubevirtLoadBalancerRule;
+import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
+import org.onosproject.kubevirtnetworking.api.KubevirtPort;
+import org.onosproject.kubevirtnetworking.api.KubevirtRouter;
+import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroup;
+import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroupRule;
+import org.onosproject.kubevirtnetworking.codec.KubevirtFloatingIpCodec;
+import org.onosproject.kubevirtnetworking.codec.KubevirtHostRouteCodec;
+import org.onosproject.kubevirtnetworking.codec.KubevirtIpPoolCodec;
+import org.onosproject.kubevirtnetworking.codec.KubevirtLoadBalancerCodec;
+import org.onosproject.kubevirtnetworking.codec.KubevirtLoadBalancerRuleCodec;
+import org.onosproject.kubevirtnetworking.codec.KubevirtNetworkCodec;
+import org.onosproject.kubevirtnetworking.codec.KubevirtPortCodec;
+import org.onosproject.kubevirtnetworking.codec.KubevirtRouterCodec;
+import org.onosproject.kubevirtnetworking.codec.KubevirtSecurityGroupCodec;
+import org.onosproject.kubevirtnetworking.codec.KubevirtSecurityGroupRuleCodec;
+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.slf4j.Logger;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of the JSON codec brokering service for KubevirtNetworking.
+ */
+@Component(immediate = true)
+public class KubevirtNetworkingCodecRegister {
+
+ private final Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected CodecService codecService;
+
+ @Activate
+ protected void activate() {
+
+ codecService.registerCodec(KubevirtHostRoute.class, new KubevirtHostRouteCodec());
+ codecService.registerCodec(KubevirtIpPool.class, new KubevirtIpPoolCodec());
+ codecService.registerCodec(KubevirtNetwork.class, new KubevirtNetworkCodec());
+ codecService.registerCodec(KubevirtPort.class, new KubevirtPortCodec());
+ codecService.registerCodec(KubevirtRouter.class, new KubevirtRouterCodec());
+ codecService.registerCodec(KubevirtFloatingIp.class, new KubevirtFloatingIpCodec());
+ codecService.registerCodec(KubevirtSecurityGroup.class, new KubevirtSecurityGroupCodec());
+ codecService.registerCodec(KubevirtSecurityGroupRule.class, new KubevirtSecurityGroupRuleCodec());
+ codecService.registerCodec(KubevirtLoadBalancer.class, new KubevirtLoadBalancerCodec());
+ codecService.registerCodec(KubevirtLoadBalancerRule.class, new KubevirtLoadBalancerRuleCodec());
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ protected void deactivate() {
+
+ codecService.unregisterCodec(KubevirtHostRoute.class);
+ codecService.unregisterCodec(KubevirtIpPool.class);
+ codecService.unregisterCodec(KubevirtNetwork.class);
+ codecService.unregisterCodec(KubevirtPort.class);
+ codecService.unregisterCodec(KubevirtRouter.class);
+ codecService.unregisterCodec(KubevirtFloatingIp.class);
+ codecService.unregisterCodec(KubevirtSecurityGroup.class);
+ codecService.unregisterCodec(KubevirtSecurityGroupRule.class);
+ codecService.unregisterCodec(KubevirtLoadBalancer.class);
+ codecService.unregisterCodec(KubevirtLoadBalancerRule.class);
+
+ log.info("Stopped");
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtNetworkingWebApplication.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtNetworkingWebApplication.java
new file mode 100644
index 0000000..dc2afbc
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtNetworkingWebApplication.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020-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.kubevirtnetworking.web;
+
+import org.onlab.rest.AbstractWebApplication;
+
+import java.util.Set;
+
+/**
+ * KubeVirt networking REST APIs web application.
+ */
+public class KubevirtNetworkingWebApplication extends AbstractWebApplication {
+ @Override
+ public Set<Class<?>> getClasses() {
+ return getClasses(
+ KubevirtNetworkWebResource.class,
+ KubevirtRouterWebResource.class,
+ KubevirtFloatingIpsWebResource.class,
+ KubevirtSecurityGroupWebResource.class,
+ KubevirtLoadBalancerWebResource.class,
+ KubevirtMm5WebResource.class
+ );
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtRouterWebResource.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtRouterWebResource.java
new file mode 100644
index 0000000..8a40f51
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtRouterWebResource.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.web;
+
+import org.onosproject.kubevirtnetworking.api.KubevirtRouter;
+import org.onosproject.kubevirtnetworking.api.KubevirtRouterService;
+import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * Handles REST API call for kubevirt router.
+ */
+@Path("router")
+public class KubevirtRouterWebResource extends AbstractWebResource {
+
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+ private static final String ROUTERS = "routers";
+
+ /**
+ * Returns set of all routers.
+ *
+ * @return 200 OK with set of all routers
+ * @onos.rsModel KubevirtRouters
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getRouters() {
+ KubevirtRouterService service = get(KubevirtRouterService.class);
+ final Iterable<KubevirtRouter> routers = service.routers();
+ return ok(encodeArray(KubevirtRouter.class, ROUTERS, routers)).build();
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtSecurityGroupWebResource.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtSecurityGroupWebResource.java
new file mode 100644
index 0000000..02acd87
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/KubevirtSecurityGroupWebResource.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.web;
+
+import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroup;
+import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroupService;
+import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * Handles REST API call for kubevirt security group.
+ */
+@Path("security-group")
+public class KubevirtSecurityGroupWebResource extends AbstractWebResource {
+
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+ private static final String SECURITY_GROUPS = "security-groups";
+
+ /**
+ * Returns set of all security groups.
+ *
+ * @return 200 OK with set of all security groups
+ * @onos.rsModel KubevirtSecurityGroups
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getSecurityGroups() {
+ KubevirtSecurityGroupService service = get(KubevirtSecurityGroupService.class);
+ final Iterable<KubevirtSecurityGroup> sgs = service.securityGroups();
+ return ok(encodeArray(KubevirtSecurityGroup.class, SECURITY_GROUPS, sgs)).build();
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/package-info.java b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/package-info.java
new file mode 100644
index 0000000..538bf6b
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/java/org/onosproject/kubevirtnetworking/web/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2022-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.
+ */
+
+/**
+ * KubeVirt networking web implementation.
+ */
+package org.onosproject.kubevirtnetworking.web;
\ No newline at end of file
diff --git a/apps/kubevirt-networking/web/src/main/resources/definitions/KubevirtFloatingIps.json b/apps/kubevirt-networking/web/src/main/resources/definitions/KubevirtFloatingIps.json
new file mode 100644
index 0000000..07a45e2
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/resources/definitions/KubevirtFloatingIps.json
@@ -0,0 +1,60 @@
+{
+ "type": "object",
+ "title": "floatingips",
+ "required": [
+ "floatingips"
+ ],
+ "properties": {
+ "floatingips": {
+ "type": "array",
+ "xml": {
+ "name": "floatingips",
+ "wrapped": true
+ },
+ "items": {
+ "type": "object",
+ "description": "A floating IP object.",
+ "required": [
+ "id",
+ "routerName",
+ "networkName",
+ "floatingIp",
+ "podName",
+ "fixedIp"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "example": "6a073105-c735-4e53-8d74-64191c6985fe",
+ "description": "The ID of floating IP."
+ },
+ "routerName": {
+ "type": "string",
+ "example": "router-1",
+ "description": "Name of router."
+ },
+ "networkName": {
+ "type": "string",
+ "example": "flat-1",
+ "description": "Name of network."
+ },
+ "floatingIp": {
+ "type": "string",
+ "example": "10.10.10.5",
+ "description": "Floating IP address."
+ },
+ "podName": {
+ "type": "string",
+ "example": "pod-1",
+ "description": "Name of POD associated with this floating IP"
+ },
+ "fixedIp": {
+ "type": "string",
+ "example": "20.20.20.5",
+ "description": "Fixed IP address."
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/apps/kubevirt-networking/web/src/main/resources/definitions/KubevirtLoadBalancers.json b/apps/kubevirt-networking/web/src/main/resources/definitions/KubevirtLoadBalancers.json
new file mode 100644
index 0000000..f06aedf
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/resources/definitions/KubevirtLoadBalancers.json
@@ -0,0 +1,94 @@
+{
+ "type": "object",
+ "title": "loadBalancers",
+ "required": [
+ "loadBalancers"
+ ],
+ "properties": {
+ "loadBalancers": {
+ "type": "array",
+ "xml": {
+ "name": "loadBalancers",
+ "wrapped": true
+ },
+ "items": {
+ "type": "object",
+ "description": "A load balancer object.",
+ "required": [
+ "name",
+ "description",
+ "networkId",
+ "vip",
+ "members",
+ "rules"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "example": "lb-1",
+ "description": "The name of load balancer."
+ },
+ "description": {
+ "type": "string",
+ "example": "Example load balancer",
+ "description": "The description of load balancer."
+ },
+ "networkId": {
+ "type": "string",
+ "example": "net-1",
+ "description": "The name of network where the load balancer is attached to."
+ },
+ "vip": {
+ "type": "string",
+ "example": "10.10.10.10",
+ "description": "The virtual IP address of the load balancer."
+ },
+ "members": {
+ "type": "array",
+ "xml": {
+ "name": "members",
+ "wrapped": true
+ },
+ "items": {
+ "type": "string",
+ "example": "10.10.10.11",
+ "description": "IP address of member instance."
+ }
+ },
+ "rules": {
+ "type": "array",
+ "description": "A list of load balancer rule objects.",
+ "items": {
+ "type": "object",
+ "description": "A load balancer rule object.",
+ "required": [
+ "portRangeMax",
+ "portRangeMin",
+ "protocol"
+ ],
+ "properties": {
+ "portRangeMax": {
+ "type": "integer",
+ "format": "int32",
+ "example": 80,
+ "description": "The maximum port number in the range that is matched by the rule."
+ },
+ "portRangeMin": {
+ "type": "integer",
+ "format": "int32",
+ "example": 80,
+ "description": "The minimum port number in the range that is matched by the rule."
+ },
+ "protocol": {
+ "type": "string",
+ "example": "tcp",
+ "description": "The IP protocol can be represented by a string, an integer, or null."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/apps/kubevirt-networking/web/src/main/resources/definitions/KubevirtNetwork.json b/apps/kubevirt-networking/web/src/main/resources/definitions/KubevirtNetwork.json
new file mode 100644
index 0000000..5653ae8
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/resources/definitions/KubevirtNetwork.json
@@ -0,0 +1,50 @@
+{
+ "type": "object",
+ "description": "A network object.",
+ "required": [
+ "networkId",
+ "type",
+ "name",
+ "segmentId",
+ "gatewayIp",
+ "cidr",
+ "mtu"
+ ],
+ "properties": {
+ "networkId": {
+ "type": "string",
+ "example": "sona-network",
+ "description": "The ID of the attached network."
+ },
+ "type": {
+ "type": "string",
+ "example": "VXLAN",
+ "description": "Type of kubernetes network."
+ },
+ "name": {
+ "type": "string",
+ "example": "sona-network",
+ "description": "The name of network."
+ },
+ "segmentId": {
+ "type": "string",
+ "example": "1",
+ "description": "Segment ID of tenant network."
+ },
+ "gatewayIp": {
+ "type": "string",
+ "example": "10.10.10.1",
+ "description": "The IP address of the gateway."
+ },
+ "cidr": {
+ "type": "string",
+ "example": "10.10.10.0/24",
+ "description": "The CIDR of this network."
+ },
+ "mtu": {
+ "type": "integer",
+ "example": 1500,
+ "description": "The Maximum Transmission Unit of this network."
+ }
+ }
+}
\ No newline at end of file
diff --git a/apps/kubevirt-networking/web/src/main/resources/definitions/KubevirtNetworks.json b/apps/kubevirt-networking/web/src/main/resources/definitions/KubevirtNetworks.json
new file mode 100644
index 0000000..5ce66f0
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/resources/definitions/KubevirtNetworks.json
@@ -0,0 +1,66 @@
+{
+ "type": "object",
+ "title": "networks",
+ "required": [
+ "networks"
+ ],
+ "properties": {
+ "networks": {
+ "type": "array",
+ "xml": {
+ "name": "networks",
+ "wrapped": true
+ },
+ "items": {
+ "type": "object",
+ "description": "A network object.",
+ "required": [
+ "networkId",
+ "type",
+ "name",
+ "segmentId",
+ "gatewayIp",
+ "cidr",
+ "mtu"
+ ],
+ "properties": {
+ "networkId": {
+ "type": "string",
+ "example": "sona-network",
+ "description": "The ID of the attached network."
+ },
+ "type": {
+ "type": "string",
+ "example": "VXLAN",
+ "description": "Type of kubernetes network."
+ },
+ "name": {
+ "type": "string",
+ "example": "sona-network",
+ "description": "The name of network."
+ },
+ "segmentId": {
+ "type": "string",
+ "example": "1",
+ "description": "Segment ID of tenant network."
+ },
+ "gatewayIp": {
+ "type": "string",
+ "example": "10.10.10.1",
+ "description": "The IP address of the gateway."
+ },
+ "cidr": {
+ "type": "string",
+ "example": "10.10.10.0/24",
+ "description": "The CIDR of this network."
+ },
+ "mtu": {
+ "type": "integer",
+ "example": 1500,
+ "description": "The Maximum Transmission Unit of this network."
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/apps/kubevirt-networking/web/src/main/resources/definitions/KubevirtRouters.json b/apps/kubevirt-networking/web/src/main/resources/definitions/KubevirtRouters.json
new file mode 100644
index 0000000..835dfea
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/resources/definitions/KubevirtRouters.json
@@ -0,0 +1,97 @@
+{
+ "type": "object",
+ "title": "routers",
+ "required": [
+ "routers"
+ ],
+ "properties": {
+ "routers": {
+ "type": "array",
+ "xml": {
+ "name": "routers",
+ "wrapped": true
+ },
+ "items": {
+ "type": "object",
+ "description": "A router object.",
+ "required": [
+ "name",
+ "enableSnat",
+ "mac",
+ "internal",
+ "external",
+ "peerRouter"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "example": "router-1",
+ "description": "The name of router."
+ },
+ "enableSnat": {
+ "type": "boolean",
+ "example": "true",
+ "description": "Enable SNAT flag."
+ },
+ "mac": {
+ "type": "string",
+ "example": "11:22:33:44:55:66",
+ "description": "The MAC address of virtual router."
+ },
+ "internal": {
+ "type": "array",
+ "xml": {
+ "name": "internal",
+ "wrapped": true
+ },
+ "items": {
+ "type": "string",
+ "example": "vxlan-1",
+ "description": "name of internal network"
+ }
+ },
+ "external": {
+ "type": "object",
+ "description": "external networks",
+ "required": [
+ "ip",
+ "name"
+ ],
+ "properties": {
+ "ipaddress": {
+ "type": "string",
+ "example": "10.10.10.5",
+ "description": "Router IP address of the external network"
+ },
+ "name": {
+ "type": "string",
+ "example": "flat",
+ "description": "Name of the external network"
+ }
+ }
+ },
+ "peerRouter": {
+ "type": "object",
+ "description": "peer router",
+ "required": [
+ "ip",
+ "mac"
+ ],
+ "properties": {
+ "ipaddress": {
+ "type": "string",
+ "example": "10.10.10.1",
+ "description": "IP address of the peer router"
+ },
+ "mac": {
+ "type": "string",
+ "example": "11:22:33:44:55:66",
+ "description": "MAC address of the peer router"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/apps/kubevirt-networking/web/src/main/resources/definitions/KubevirtSecurityGroups.json b/apps/kubevirt-networking/web/src/main/resources/definitions/KubevirtSecurityGroups.json
new file mode 100644
index 0000000..bd724c9
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/resources/definitions/KubevirtSecurityGroups.json
@@ -0,0 +1,103 @@
+{
+ "type": "object",
+ "description": "A security_group object.",
+ "required": [
+ "securityGroup"
+ ],
+ "properties": {
+ "securityGroup": {
+ "type": "object",
+ "required": [
+ "id",
+ "description",
+ "name",
+ "securityGroupRules"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "example": "2076db17-a522-4506-91de-c6dd8e837028",
+ "description": "The ID of the security group."
+ },
+ "description": {
+ "type": "string",
+ "example": "security group for webservers",
+ "description": "A human-readable description for the resource."
+ },
+ "name": {
+ "type": "string",
+ "example": "new-webservers",
+ "description": "Human-readable name of the resource."
+ },
+ "securityGroupRules": {
+ "type": "array",
+ "description": "A list of security_group_rule objects.",
+ "items": {
+ "type": "object",
+ "description": "A security group rule object.",
+ "required": [
+ "id",
+ "securityGroupId",
+ "direction",
+ "etherType",
+ "portRangeMax",
+ "portRangeMin",
+ "protocol",
+ "remoteIpPrefix",
+ "remoteGroupId"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "example": "2bc0accf-312e-429a-956e-e4407625eb62",
+ "description": "The ID of this security group rule."
+ },
+ "securityGroupId": {
+ "type": "string",
+ "example": "a7734e61-b545-452d-a3cd-0189cbd9747a",
+ "description": "The security group ID to associate with this security group rule."
+ },
+ "direction": {
+ "type": "string",
+ "example": "ingress",
+ "description": "Ingress or egress, which is the direction in which the metering rule is applied."
+ },
+ "etherType": {
+ "type": "string",
+ "example": "IPv4",
+ "description": "Must be IPv4 or IPv6, and addresses represented in CIDR must match the ingress or egress rules."
+ },
+ "portRangeMax": {
+ "type": "integer",
+ "format": "int32",
+ "example": 80,
+ "description": "The maximum port number in the range that is matched by the security group rule."
+ },
+ "portRangeMin": {
+ "type": "integer",
+ "format": "int32",
+ "example": 80,
+ "description": "The minimum port number in the range that is matched by the security group rule."
+ },
+ "protocol": {
+ "type": "string",
+ "example": "tcp",
+ "description": "The IP protocol can be represented by a string, an integer, or null."
+ },
+ "remoteIpPrefix": {
+ "type": "string",
+ "example": "",
+ "description": "The remote IP prefix to associate with this metering rule packet."
+ },
+ "remoteGroupId": {
+ "type": "string",
+ "example": "85cc3048-abc3-43cc-89b3-377341426ac5",
+ "description": "The remote group UUID to associate with this security group rule."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/apps/kubevirt-networking/web/src/main/webapp/WEB-INF/web.xml b/apps/kubevirt-networking/web/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..0b4876a
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2020-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.
+ -->
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ id="ONOS" version="2.5">
+ <display-name>KubeVirt Networking REST API v1.0</display-name>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Secured</web-resource-name>
+ <url-pattern>/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>admin</role-name>
+ <role-name>viewer</role-name>
+ </auth-constraint>
+ </security-constraint>
+
+ <security-role>
+ <role-name>admin</role-name>
+ <role-name>viewer</role-name>
+ </security-role>
+
+ <login-config>
+ <auth-method>BASIC</auth-method>
+ <realm-name>karaf</realm-name>
+ </login-config>
+
+ <servlet>
+ <servlet-name>JAX-RS Service</servlet-name>
+ <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
+ <init-param>
+ <param-name>javax.ws.rs.Application</param-name>
+ <param-value>org.onosproject.kubevirtnetworking.web.KubevirtNetworkingWebApplication</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>JAX-RS Service</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+</web-app>
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpCodecTest.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpCodecTest.java
new file mode 100644
index 0000000..216f3e0
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpCodecTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.hamcrest.MatcherAssert;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.codec.impl.MockCodecContext;
+import org.onosproject.core.CoreService;
+import org.onosproject.kubevirtnetworking.api.DefaultKubevirtFloatingIp;
+import org.onosproject.kubevirtnetworking.api.KubevirtFloatingIp;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import static junit.framework.TestCase.assertEquals;
+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.kubevirtnetworking.codec.KubevirtFloatingIpJsonMatcher.matchesKubevirtFloatingIp;
+import static org.onosproject.net.NetTestTools.APP_ID;
+
+/**
+ * Unit tests for KubevirtFloatingIp codec.
+ */
+public final class KubevirtFloatingIpCodecTest {
+
+ MockCodecContext context;
+
+ JsonCodec<KubevirtFloatingIp> kubevirtFloatingIpCodec;
+
+ final CoreService mockCoreService = createMock(CoreService.class);
+ private static final String REST_APP_ID = "org.onosproject.rest";
+
+ @Before
+ public void setUp() {
+ context = new MockCodecContext();
+ kubevirtFloatingIpCodec = new KubevirtFloatingIpCodec();
+
+ assertThat(kubevirtFloatingIpCodec, notNullValue());
+ expect(mockCoreService.registerApplication(REST_APP_ID))
+ .andReturn(APP_ID).anyTimes();
+ replay(mockCoreService);
+ context.registerService(CoreService.class, mockCoreService);
+ }
+
+ /**
+ * Tests the kubevirt floating IP encoding.
+ */
+ @Test
+ public void testKubevirtFloatingIpEncode() {
+ KubevirtFloatingIp floatingIp = DefaultKubevirtFloatingIp.builder()
+ .id("fip-id")
+ .routerName("router-1")
+ .networkName("flat-1")
+ .floatingIp(IpAddress.valueOf("10.10.10.10"))
+ .podName("pod-1")
+ .vmName("vm-1")
+ .fixedIp(IpAddress.valueOf("20.20.20.20"))
+ .build();
+
+ ObjectNode floatingIpJson = kubevirtFloatingIpCodec.encode(floatingIp, context);
+ assertThat(floatingIpJson, matchesKubevirtFloatingIp(floatingIp));
+ }
+
+ @Test
+ public void testKubevirtFloatingIpDecode() throws IOException {
+ KubevirtFloatingIp floatingIp = getKubevirtFloatingIp("KubevirtFloatingIp.json");
+
+ assertEquals("fip-1", floatingIp.id());
+ assertEquals("router-1", floatingIp.routerName());
+ assertEquals("flat-1", floatingIp.networkName());
+ assertEquals("10.10.10.10", floatingIp.floatingIp().toString());
+ assertEquals("pod-1", floatingIp.podName());
+ assertEquals("vm-1", floatingIp.vmName());
+ assertEquals("20.20.20.20", floatingIp.fixedIp().toString());
+ }
+
+ private KubevirtFloatingIp getKubevirtFloatingIp(String resourceName) throws IOException {
+ InputStream jsonStream = KubevirtFloatingIpCodecTest.class.getResourceAsStream(resourceName);
+ JsonNode json = context.mapper().readTree(jsonStream);
+ MatcherAssert.assertThat(json, notNullValue());
+ KubevirtFloatingIp fip = kubevirtFloatingIpCodec.decode((ObjectNode) json, context);
+ assertThat(fip, notNullValue());
+ return fip;
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpJsonMatcher.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpJsonMatcher.java
new file mode 100644
index 0000000..41d8cfe
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpJsonMatcher.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onosproject.kubevirtnetworking.api.KubevirtFloatingIp;
+
+/**
+ * Hamcrest matcher for kubevirt router interface.
+ */
+public final class KubevirtFloatingIpJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+ private final KubevirtFloatingIp floatingIp;
+ private static final String ID = "id";
+ private static final String ROUTER_NAME = "routerName";
+ private static final String NETWORK_NAME = "networkName";
+ private static final String POD_NAME = "podName";
+ private static final String VM_NAME = "vmName";
+ private static final String FLOATING_IP = "floatingIp";
+ private static final String FIXED_IP = "fixedIp";
+
+ private KubevirtFloatingIpJsonMatcher(KubevirtFloatingIp floatingIp) {
+ this.floatingIp = floatingIp;
+ }
+
+ @Override
+ protected boolean matchesSafely(JsonNode jsonNode, Description description) {
+
+ // check ID
+ String jsonId = jsonNode.get(ID).asText();
+ String id = floatingIp.id();
+ if (!jsonId.equals(id)) {
+ description.appendText("ID was " + jsonId);
+ return false;
+ }
+
+ // check router name
+ String jsonRouterName = jsonNode.get(ROUTER_NAME).asText();
+ String routerName = floatingIp.routerName();
+ if (!jsonRouterName.equals(routerName)) {
+ description.appendText("Router name was " + jsonRouterName);
+ return false;
+ }
+
+ // check network name
+ String jsonNetworkName = jsonNode.get(NETWORK_NAME).asText();
+ String networkName = floatingIp.networkName();
+ if (!jsonNetworkName.equals(networkName)) {
+ description.appendText("Network name was " + jsonNetworkName);
+ return false;
+ }
+
+ // check floating IP
+ String jsonFip = jsonNode.get(FLOATING_IP).asText();
+ String fip = floatingIp.floatingIp().toString();
+ if (!jsonFip.equals(fip)) {
+ description.appendText("Floating IP was " + jsonFip);
+ return false;
+ }
+
+ // check POD name
+ JsonNode jsonPodName = jsonNode.get(POD_NAME);
+ if (jsonPodName != null) {
+ if (!floatingIp.podName().equals(jsonPodName.asText())) {
+ description.appendText("POD name was " + jsonPodName);
+ return false;
+ }
+ }
+
+ JsonNode jsonVmName = jsonNode.get(VM_NAME);
+ if (jsonVmName != null) {
+ if (!floatingIp.vmName().equals(jsonVmName.asText())) {
+ description.appendText("VM name was " + jsonVmName);
+ return false;
+ }
+ }
+
+
+ // check fixed IP
+ JsonNode jsonFixedIp = jsonNode.get(FIXED_IP);
+ if (jsonFixedIp != null) {
+ if (!floatingIp.fixedIp().toString().equals(jsonFixedIp.asText())) {
+ description.appendText("Fixed IP was " + jsonFixedIp);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(floatingIp.toString());
+ }
+
+ /**
+ * Factory to allocate a kubevirt floating IP matcher.
+ *
+ * @param fip kubevirt floating IP object we are looking for
+ * @return matcher
+ */
+ public static KubevirtFloatingIpJsonMatcher matchesKubevirtFloatingIp(KubevirtFloatingIp fip) {
+ return new KubevirtFloatingIpJsonMatcher(fip);
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtHostRouteJsonMatcher.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtHostRouteJsonMatcher.java
new file mode 100644
index 0000000..4603980
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtHostRouteJsonMatcher.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onosproject.kubevirtnetworking.api.KubevirtHostRoute;
+
+/**
+ * Hamcrest matcher for kubevirt host route interface.
+ */
+public final class KubevirtHostRouteJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+ private final KubevirtHostRoute hostRoute;
+
+ private static final String DESTINATION = "destination";
+ private static final String NEXTHOP = "nexthop";
+
+ private KubevirtHostRouteJsonMatcher(KubevirtHostRoute hostRoute) {
+ this.hostRoute = hostRoute;
+ }
+
+ @Override
+ protected boolean matchesSafely(JsonNode jsonNode, Description description) {
+ // check destination
+ String jsonDestination = jsonNode.get(DESTINATION).asText();
+ String destination = hostRoute.destination().toString();
+ if (!jsonDestination.equals(destination)) {
+ description.appendText("destination was " + jsonDestination);
+ return false;
+ }
+
+ // check nexthop
+ JsonNode jsonNexthop = jsonNode.get(NEXTHOP);
+ if (jsonNexthop != null) {
+ String nexthop = hostRoute.nexthop().toString();
+ if (!jsonNexthop.asText().equals(nexthop)) {
+ description.appendText("nexthop was " + jsonNexthop);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(description.toString());
+ }
+
+ /**
+ * Factory to allocate an kubevirt host route matcher.
+ *
+ * @param route kubevirt host route object we are looking for
+ * @return matcher
+ */
+ public static KubevirtHostRouteJsonMatcher matchesKubevirtHostRoute(KubevirtHostRoute route) {
+ return new KubevirtHostRouteJsonMatcher(route);
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtIpPoolJsonMatcher.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtIpPoolJsonMatcher.java
new file mode 100644
index 0000000..6217335
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtIpPoolJsonMatcher.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onosproject.kubevirtnetworking.api.KubevirtIpPool;
+
+/**
+ * Hamcrest matcher for kubevirt IP pool interface.
+ */
+public final class KubevirtIpPoolJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+ private final KubevirtIpPool ipPool;
+ private static final String START = "start";
+ private static final String END = "end";
+
+ private KubevirtIpPoolJsonMatcher(KubevirtIpPool ipPool) {
+ this.ipPool = ipPool;
+ }
+
+ @Override
+ protected boolean matchesSafely(JsonNode jsonNode, Description description) {
+ // check start
+ String jsonStart = jsonNode.get(START).asText();
+ String start = ipPool.start().toString();
+ if (!jsonStart.equals(start)) {
+ description.appendText("start was " + jsonStart);
+ return false;
+ }
+
+ // check end
+ String jsonEnd = jsonNode.get(END).asText();
+ String end = ipPool.end().toString();
+ if (!jsonEnd.equals(end)) {
+ description.appendText("end was " + jsonEnd);
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(ipPool.toString());
+ }
+
+ /**
+ * Factory to allocate an kubevirt IP pool matcher.
+ *
+ * @param ipPool kubevirt IP pool object we are looking for
+ * @return matcher
+ */
+ public static KubevirtIpPoolJsonMatcher matchesKubevirtIpPool(KubevirtIpPool ipPool) {
+ return new KubevirtIpPoolJsonMatcher(ipPool);
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtLoadBalancerCodecTest.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtLoadBalancerCodecTest.java
new file mode 100644
index 0000000..cd86402
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtLoadBalancerCodecTest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableSet;
+import org.hamcrest.MatcherAssert;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.codec.impl.CodecManager;
+import org.onosproject.core.CoreService;
+import org.onosproject.kubevirtnetworking.api.DefaultKubevirtLoadBalancer;
+import org.onosproject.kubevirtnetworking.api.DefaultKubevirtLoadBalancerRule;
+import org.onosproject.kubevirtnetworking.api.KubevirtLoadBalancer;
+import org.onosproject.kubevirtnetworking.api.KubevirtLoadBalancerRule;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+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.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onosproject.kubevirtnetworking.codec.KubevirtLoadBalancerJsonMatcher.matchesKubevirtLoadBalancer;
+import static org.onosproject.net.NetTestTools.APP_ID;
+
+/**
+ * Unit tests for KubevirtLoadBalancer codec.
+ */
+public final class KubevirtLoadBalancerCodecTest {
+
+ MockCodecContext context;
+
+ JsonCodec<KubevirtLoadBalancer> kubevirtLoadBalancerCodec;
+ JsonCodec<KubevirtLoadBalancerRule> kubevirtLoadBalancerRuleCodec;
+
+ private static final KubevirtLoadBalancerRule RULE1 = DefaultKubevirtLoadBalancerRule.builder()
+ .protocol("tcp")
+ .portRangeMax(8000)
+ .portRangeMin(7000)
+ .build();
+ private static final KubevirtLoadBalancerRule RULE2 = DefaultKubevirtLoadBalancerRule.builder()
+ .protocol("udp")
+ .portRangeMax(9000)
+ .portRangeMin(8000)
+ .build();
+
+ private static final KubevirtLoadBalancerRule RULE3 = DefaultKubevirtLoadBalancerRule.builder()
+ .protocol("icmp")
+ .build();
+
+ final CoreService mockCoreService = createMock(CoreService.class);
+ private static final String REST_APP_ID = "org.onosproject.rest";
+
+ @Before
+ public void setUp() {
+ context = new MockCodecContext();
+ kubevirtLoadBalancerCodec = new KubevirtLoadBalancerCodec();
+ kubevirtLoadBalancerRuleCodec = new KubevirtLoadBalancerRuleCodec();
+
+ assertThat(kubevirtLoadBalancerCodec, notNullValue());
+ assertThat(kubevirtLoadBalancerRuleCodec, notNullValue());
+
+ expect(mockCoreService.registerApplication(REST_APP_ID))
+ .andReturn(APP_ID).anyTimes();
+ replay(mockCoreService);
+ context.registerService(CoreService.class, mockCoreService);
+ }
+
+ /**
+ * Tests the kubevirt load balancer encoding.
+ */
+ @Test
+ public void testKubevirtLoadBalancerEncode() {
+ KubevirtLoadBalancer lb = DefaultKubevirtLoadBalancer.builder()
+ .name("lb-1")
+ .networkId("net-1")
+ .vip(IpAddress.valueOf("10.10.10.10"))
+ .members(ImmutableSet.of(IpAddress.valueOf("10.10.10.11"),
+ IpAddress.valueOf("10.10.10.12")))
+ .rules(ImmutableSet.of(RULE1, RULE2, RULE3))
+ .description("network load balancer")
+ .build();
+
+ ObjectNode lbJson = kubevirtLoadBalancerCodec.encode(lb, context);
+ assertThat(lbJson, matchesKubevirtLoadBalancer(lb));
+ }
+
+ /**
+ * Tests the kubevirt load balancer decoding.
+ */
+ @Test
+ public void testKubevirtLoadBalancerDecode() throws IOException {
+ KubevirtLoadBalancer lb = getKubevirtLoadBalancer("KubevirtLoadBalancer.json");
+
+ assertThat(lb.name(), is("lb-1"));
+ assertThat(lb.description(), is("Example Load Balancer"));
+ assertThat(lb.networkId(), is("net-1"));
+ assertThat(lb.vip(), is(IpAddress.valueOf("10.10.10.10")));
+
+ Set<IpAddress> expectedMembers = ImmutableSet.of(IpAddress.valueOf("10.10.10.11"),
+ IpAddress.valueOf("10.10.10.12"));
+ Set<IpAddress> realMembers = lb.members();
+ assertThat(true, is(expectedMembers.containsAll(realMembers)));
+ assertThat(true, is(realMembers.containsAll(expectedMembers)));
+
+ Set<KubevirtLoadBalancerRule> expectedRules = ImmutableSet.of(RULE1, RULE2, RULE3);
+ Set<KubevirtLoadBalancerRule> realRules = lb.rules();
+ assertThat(true, is(expectedRules.containsAll(realRules)));
+ assertThat(true, is(realRules.containsAll(expectedRules)));
+ }
+
+ private KubevirtLoadBalancer getKubevirtLoadBalancer(String resourceName) throws IOException {
+ InputStream jsonStream = KubevirtLoadBalancerCodecTest.class.getResourceAsStream(resourceName);
+ JsonNode json = context.mapper().readTree(jsonStream);
+ MatcherAssert.assertThat(json, notNullValue());
+ KubevirtLoadBalancer lb = kubevirtLoadBalancerCodec.decode((ObjectNode) json, context);
+ assertThat(lb, notNullValue());
+ return lb;
+ }
+
+ private class MockCodecContext implements CodecContext {
+
+ private final ObjectMapper mapper = new ObjectMapper();
+ private final CodecManager manager = new CodecManager();
+ private final Map<Class<?>, Object> services = new HashMap<>();
+
+ /**
+ * Constructs a new mock codec context.
+ */
+ public MockCodecContext() {
+ manager.activate();
+ }
+
+ @Override
+ public ObjectMapper mapper() {
+ return mapper;
+ }
+
+ @Override
+ public <T> JsonCodec<T> codec(Class<T> entityClass) {
+ if (entityClass == KubevirtLoadBalancerRule.class) {
+ return (JsonCodec<T>) kubevirtLoadBalancerRuleCodec;
+ }
+ return manager.getCodec(entityClass);
+ }
+
+ @Override
+ public <T> T getService(Class<T> serviceClass) {
+ return (T) services.get(serviceClass);
+ }
+
+ // for registering mock services
+ public <T> void registerService(Class<T> serviceClass, T impl) {
+ services.put(serviceClass, impl);
+ }
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtLoadBalancerJsonMatcher.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtLoadBalancerJsonMatcher.java
new file mode 100644
index 0000000..9122bd0
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtLoadBalancerJsonMatcher.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onlab.packet.IpAddress;
+import org.onosproject.kubevirtnetworking.api.KubevirtLoadBalancer;
+import org.onosproject.kubevirtnetworking.api.KubevirtLoadBalancerRule;
+
+/**
+ * Hamcrest matcher for load balancer.
+ */
+public final class KubevirtLoadBalancerJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+ private static final String NAME = "name";
+ private static final String DESCRIPTION = "description";
+ private static final String VIP = "vip";
+ private static final String NETWORK_ID = "networkId";
+ private static final String MEMBERS = "members";
+ private static final String RULES = "rules";
+
+ private final KubevirtLoadBalancer lb;
+
+ private KubevirtLoadBalancerJsonMatcher(KubevirtLoadBalancer lb) {
+ this.lb = lb;
+ }
+
+ @Override
+ protected boolean matchesSafely(JsonNode jsonNode, Description description) {
+ // check name
+ String jsonName = jsonNode.get(NAME).asText();
+ String name = lb.name();
+ if (!jsonName.equals(name)) {
+ description.appendText("Name was " + jsonName);
+ return false;
+ }
+
+ // check description
+ JsonNode jsonDescription = jsonNode.get(DESCRIPTION);
+ if (jsonDescription != null) {
+ String myDescription = lb.description();
+ if (!jsonDescription.asText().equals(myDescription)) {
+ description.appendText("Description was " + jsonDescription);
+ return false;
+ }
+ }
+
+ // check VIP
+ String jsonVip = jsonNode.get(VIP).asText();
+ String vip = lb.vip().toString();
+ if (!jsonVip.equals(vip)) {
+ description.appendText("VIP was " + jsonVip);
+ return false;
+ }
+
+ // check network ID
+ String jsonNetworkId = jsonNode.get(NETWORK_ID).asText();
+ String networkId = lb.networkId();
+ if (!jsonNetworkId.equals(networkId)) {
+ description.appendText("NetworkId was " + jsonNetworkId);
+ return false;
+ }
+
+ // check members
+ ArrayNode jsonMembers = (ArrayNode) jsonNode.get(MEMBERS);
+ if (jsonMembers != null) {
+ // check size of members array
+ if (jsonMembers.size() != lb.members().size()) {
+ description.appendText("Members was " + jsonMembers.size());
+ return false;
+ }
+
+ for (JsonNode jsonMember : jsonMembers) {
+ IpAddress member = IpAddress.valueOf(jsonMember.asText());
+ if (!lb.members().contains(member)) {
+ description.appendText("Member not found " + jsonMember.toString());
+ return false;
+ }
+ }
+ }
+
+ ArrayNode jsonRules = (ArrayNode) jsonNode.get(RULES);
+ if (jsonRules != null) {
+ // check size of rules array
+ if (jsonRules.size() != lb.rules().size()) {
+ description.appendText("Rules was " + jsonRules.size());
+ return false;
+ }
+
+ // check rules
+ for (KubevirtLoadBalancerRule rule : lb.rules()) {
+ boolean ruleFound = false;
+ for (int ruleIndex = 0; ruleIndex < jsonRules.size(); ruleIndex++) {
+ KubevirtLoadBalancerRuleJsonMatcher ruleMatcher =
+ KubevirtLoadBalancerRuleJsonMatcher
+ .matchesKubevirtLoadBalancerRule(rule);
+ if (ruleMatcher.matches(jsonRules.get(ruleIndex))) {
+ ruleFound = true;
+ break;
+ }
+ }
+
+ if (!ruleFound) {
+ description.appendText("Rule not found " + rule.toString());
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(lb.toString());
+ }
+
+ /**
+ * Factory to allocate a kubevirt load balancer matcher.
+ *
+ * @param lb kubevirt load balancer object we are looking for
+ * @return matcher
+ */
+ public static KubevirtLoadBalancerJsonMatcher
+ matchesKubevirtLoadBalancer(KubevirtLoadBalancer lb) {
+ return new KubevirtLoadBalancerJsonMatcher(lb);
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtLoadBalancerRuleJsonMatcher.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtLoadBalancerRuleJsonMatcher.java
new file mode 100644
index 0000000..404d1ee
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtLoadBalancerRuleJsonMatcher.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onosproject.kubevirtnetworking.api.KubevirtLoadBalancerRule;
+
+/**
+ * Hamcrest matcher for kubevirt load balancer.
+ */
+public final class KubevirtLoadBalancerRuleJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+ private final KubevirtLoadBalancerRule rule;
+
+ private static final String PROTOCOL = "protocol";
+ private static final String PORT_RANGE_MAX = "portRangeMax";
+ private static final String PORT_RANGE_MIN = "portRangeMin";
+
+ private KubevirtLoadBalancerRuleJsonMatcher(KubevirtLoadBalancerRule rule) {
+ this.rule = rule;
+ }
+
+ @Override
+ protected boolean matchesSafely(JsonNode jsonNode, Description description) {
+ // check protocol
+ JsonNode jsonProtocol = jsonNode.get(PROTOCOL);
+ if (jsonProtocol != null) {
+ String protocol = rule.protocol();
+ if (!jsonProtocol.asText().equals(protocol)) {
+ description.appendText("Protocol was " + jsonProtocol);
+ return false;
+ }
+ }
+
+ // check port range max
+ JsonNode jsonPortRangeMax = jsonNode.get(PORT_RANGE_MAX);
+ if (jsonPortRangeMax != null) {
+ int portRangeMax = rule.portRangeMax();
+ if (portRangeMax != jsonPortRangeMax.asInt()) {
+ description.appendText("PortRangeMax was " + jsonPortRangeMax);
+ return false;
+ }
+ }
+
+ // check port range min
+ JsonNode jsonPortRangeMin = jsonNode.get(PORT_RANGE_MIN);
+ if (jsonPortRangeMin != null) {
+ int portRangeMin = rule.portRangeMin();
+ if (portRangeMin != jsonPortRangeMin.asInt()) {
+ description.appendText("PortRangeMin was " + jsonPortRangeMin);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(rule.toString());
+ }
+
+ /**
+ * Factory to allocate an kubevirt load balancer rule matcher.
+ *
+ * @param rule kubevirt load balancer rule object we are looking for
+ * @return matcher
+ */
+ public static KubevirtLoadBalancerRuleJsonMatcher
+ matchesKubevirtLoadBalancerRule(KubevirtLoadBalancerRule rule) {
+ return new KubevirtLoadBalancerRuleJsonMatcher(rule);
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtNetworkCodecTest.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtNetworkCodecTest.java
new file mode 100644
index 0000000..667ca4b
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtNetworkCodecTest.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableSet;
+import org.hamcrest.MatcherAssert;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.codec.impl.CodecManager;
+import org.onosproject.core.CoreService;
+import org.onosproject.kubevirtnetworking.api.DefaultKubevirtNetwork;
+import org.onosproject.kubevirtnetworking.api.KubevirtHostRoute;
+import org.onosproject.kubevirtnetworking.api.KubevirtIpPool;
+import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+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.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onosproject.kubevirtnetworking.codec.KubevirtNetworkJsonMatcher.matchesKubevirtNetwork;
+import static org.onosproject.net.NetTestTools.APP_ID;
+
+/**
+ * Unit tests for KubevirtNetwork codec.
+ */
+public final class KubevirtNetworkCodecTest {
+
+ MockCodecContext context;
+
+ JsonCodec<KubevirtNetwork> kubevirtNetworkCodec;
+ JsonCodec<KubevirtHostRoute> kubevirtHostRouteCodec;
+ JsonCodec<KubevirtIpPool> kubevirtIpPoolCodec;
+
+ final CoreService mockCoreService = createMock(CoreService.class);
+ private static final String REST_APP_ID = "org.onosproject.rest";
+
+ @Before
+ public void setUp() {
+ context = new MockCodecContext();
+ kubevirtNetworkCodec = new KubevirtNetworkCodec();
+ kubevirtHostRouteCodec = new KubevirtHostRouteCodec();
+ kubevirtIpPoolCodec = new KubevirtIpPoolCodec();
+
+ assertThat(kubevirtNetworkCodec, notNullValue());
+ assertThat(kubevirtHostRouteCodec, notNullValue());
+ assertThat(kubevirtIpPoolCodec, notNullValue());
+
+ expect(mockCoreService.registerApplication(REST_APP_ID))
+ .andReturn(APP_ID).anyTimes();
+ replay(mockCoreService);
+ context.registerService(CoreService.class, mockCoreService);
+ }
+
+ /**
+ * Tests the kubevirt network encoding.
+ */
+ @Test
+ public void testKubevirtNetworkEncode() {
+ KubevirtHostRoute hostRoute1 = new KubevirtHostRoute(IpPrefix.valueOf("10.10.10.0/24"),
+ IpAddress.valueOf("20.20.20.1"));
+ KubevirtHostRoute hostRoute2 = new KubevirtHostRoute(IpPrefix.valueOf("20.20.20.0/24"),
+ IpAddress.valueOf("10.10.10.1"));
+
+ KubevirtIpPool ipPool = new KubevirtIpPool(IpAddress.valueOf("10.10.10.100"),
+ IpAddress.valueOf("10.10.10.200"));
+
+ KubevirtNetwork network = DefaultKubevirtNetwork.builder()
+ .networkId("net-1")
+ .name("net-1")
+ .type(KubevirtNetwork.Type.FLAT)
+ .gatewayIp(IpAddress.valueOf("10.10.10.1"))
+ .defaultRoute(true)
+ .mtu(1500)
+ .cidr("10.10.10.0/24")
+ .hostRoutes(ImmutableSet.of(hostRoute1, hostRoute2))
+ .ipPool(ipPool)
+ .dnses(ImmutableSet.of(IpAddress.valueOf("8.8.8.8")))
+ .build();
+
+ ObjectNode networkJson = kubevirtNetworkCodec.encode(network, context);
+ assertThat(networkJson, matchesKubevirtNetwork(network));
+ }
+
+ /**
+ * Tests the kubevirt network decoding.
+ *
+ * @throws IOException io exception
+ */
+ @Test
+ public void testKubevirtNetworkDecode() throws IOException {
+ KubevirtNetwork network = getKubevirtNetwork("KubevirtNetwork.json");
+
+ assertThat(network.networkId(), is("network-1"));
+ assertThat(network.name(), is("network-1"));
+ assertThat(network.type().name(), is("FLAT"));
+ assertThat(network.cidr(), is("10.10.0.0/24"));
+ assertThat(network.gatewayIp().toString(), is("10.10.0.1"));
+ assertThat(network.defaultRoute(), is(true));
+ assertThat(network.ipPool().start().toString(), is("10.10.10.100"));
+ assertThat(network.ipPool().end().toString(), is("10.10.10.200"));
+ assertThat(network.dnses().size(), is(1));
+ KubevirtHostRoute route = network.hostRoutes().stream().findFirst().orElse(null);
+ assertThat(route, is(new KubevirtHostRoute(IpPrefix.valueOf("10.10.10.0/24"),
+ IpAddress.valueOf("10.10.10.1"))));
+ }
+
+ private KubevirtNetwork getKubevirtNetwork(String resourceName) throws IOException {
+ InputStream jsonStream = KubevirtNetworkCodecTest.class.getResourceAsStream(resourceName);
+ JsonNode json = context.mapper().readTree(jsonStream);
+ MatcherAssert.assertThat(json, notNullValue());
+ KubevirtNetwork network = kubevirtNetworkCodec.decode((ObjectNode) json, context);
+ assertThat(network, notNullValue());
+ return network;
+ }
+
+ private class MockCodecContext implements CodecContext {
+
+ private final ObjectMapper mapper = new ObjectMapper();
+ private final CodecManager manager = new CodecManager();
+ private final Map<Class<?>, Object> services = new HashMap<>();
+
+ /**
+ * Constructs a new mock codec context.
+ */
+ public MockCodecContext() {
+ manager.activate();
+ }
+
+ @Override
+ public ObjectMapper mapper() {
+ return mapper;
+ }
+
+ @Override
+ public <T> JsonCodec<T> codec(Class<T> entityClass) {
+ if (entityClass == KubevirtHostRoute.class) {
+ return (JsonCodec<T>) kubevirtHostRouteCodec;
+ }
+
+ if (entityClass == KubevirtIpPool.class) {
+ return (JsonCodec<T>) kubevirtIpPoolCodec;
+ }
+
+ return manager.getCodec(entityClass);
+ }
+
+ @Override
+ public <T> T getService(Class<T> serviceClass) {
+ return (T) services.get(serviceClass);
+ }
+
+ // for registering mock services
+ public <T> void registerService(Class<T> serviceClass, T impl) {
+ services.put(serviceClass, impl);
+ }
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtNetworkJsonArrayMatcher.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtNetworkJsonArrayMatcher.java
new file mode 100644
index 0000000..6701c7b
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtNetworkJsonArrayMatcher.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.eclipsesource.json.JsonArray;
+import com.eclipsesource.json.JsonObject;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
+import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
+
+public final class KubevirtNetworkJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
+
+ private final KubevirtNetwork network;
+ private String reason = "";
+
+ public KubevirtNetworkJsonArrayMatcher(KubevirtNetwork network) {
+ this.network = network;
+ }
+
+ @Override
+ protected boolean matchesSafely(JsonArray json) {
+ boolean networkFound = false;
+ for (int jsonNetworkIndex = 0; jsonNetworkIndex < json.size(); jsonNetworkIndex++) {
+ final JsonObject jsonNode = json.get(jsonNetworkIndex).asObject();
+
+ final String networkId = network.networkId();
+ final String jsonNetworkId = jsonNode.get("networkId").asString();
+ if (jsonNetworkId.equals(networkId)) {
+ networkFound = true;
+ }
+ }
+
+ if (!networkFound) {
+ reason = "Network with networkId " + network.networkId() + " not found";
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(reason);
+ }
+
+ /**
+ * Factory to allocate a network array matcher.
+ *
+ * @param network network object we are looking for
+ * @return matcher
+ */
+ public static KubevirtNetworkJsonArrayMatcher hasNetwork(KubevirtNetwork network) {
+ return new KubevirtNetworkJsonArrayMatcher(network);
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtNetworkJsonMatcher.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtNetworkJsonMatcher.java
new file mode 100644
index 0000000..7cbc587
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtNetworkJsonMatcher.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onlab.packet.IpAddress;
+import org.onosproject.kubevirtnetworking.api.KubevirtHostRoute;
+import org.onosproject.kubevirtnetworking.api.KubevirtIpPool;
+import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
+
+/**
+ * Hamcrest matcher for kubevirt network.
+ */
+public final class KubevirtNetworkJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+ private final KubevirtNetwork network;
+ private static final String NETWORK_ID = "networkId";
+ private static final String TYPE = "type";
+ private static final String NAME = "name";
+ private static final String MTU = "mtu";
+ private static final String SEGMENT_ID = "segmentId";
+ private static final String GATEWAY_IP = "gatewayIp";
+ private static final String DEFAULT_ROUTE = "defaultRoute";
+ private static final String CIDR = "cidr";
+ private static final String HOST_ROUTES = "hostRoutes";
+ private static final String IP_POOL = "ipPool";
+ private static final String DNSES = "dnses";
+
+ private KubevirtNetworkJsonMatcher(KubevirtNetwork network) {
+ this.network = network;
+ }
+
+ @Override
+ protected boolean matchesSafely(JsonNode jsonNode, Description description) {
+ // check network ID
+ String jsonNetworkId = jsonNode.get(NETWORK_ID).asText();
+ String networkId = network.networkId();
+ if (!jsonNetworkId.equals(networkId)) {
+ description.appendText("network ID was " + jsonNetworkId);
+ return false;
+ }
+
+ // check type
+ String jsonType = jsonNode.get(TYPE).asText();
+ String type = network.type().name();
+ if (!jsonType.equals(type)) {
+ description.appendText("network type was " + jsonType);
+ return false;
+ }
+
+ // check name
+ String jsonName = jsonNode.get(NAME).asText();
+ String name = network.name();
+ if (!jsonName.equals(name)) {
+ description.appendText("network name was " + jsonName);
+ return false;
+ }
+
+ // check MTU
+ int jsonMtu = jsonNode.get(MTU).asInt();
+ int mtu = network.mtu();
+ if (jsonMtu != mtu) {
+ description.appendText("network MTU was " + jsonMtu);
+ return false;
+ }
+
+ // check gateway IP
+ String jsonGatewayIp = jsonNode.get(GATEWAY_IP).asText();
+ String gatewayIp = network.gatewayIp().toString();
+ if (!jsonGatewayIp.equals(gatewayIp)) {
+ description.appendText("gateway IP was " + jsonGatewayIp);
+ return false;
+ }
+
+ // check default route
+ boolean jsonDefaultRoute = jsonNode.get(DEFAULT_ROUTE).asBoolean();
+ boolean defaultRoute = network.defaultRoute();
+ if (jsonDefaultRoute != defaultRoute) {
+ description.appendText("Default route was " + jsonDefaultRoute);
+ return false;
+ }
+
+ // check CIDR
+ String jsonCidr = jsonNode.get(CIDR).asText();
+ String cidr = network.cidr();
+ if (!jsonCidr.equals(cidr)) {
+ description.appendText("CIDR was " + jsonCidr);
+ return false;
+ }
+
+ // check segment ID
+ JsonNode jsonSegmentId = jsonNode.get(SEGMENT_ID);
+ if (jsonSegmentId != null) {
+ String segmentId = network.segmentId();
+ if (!jsonSegmentId.asText().equals(segmentId)) {
+ description.appendText("segment ID was " + jsonSegmentId.asText());
+ return false;
+ }
+ }
+
+ // check ip pool
+ JsonNode jsonIpPool = jsonNode.get(IP_POOL);
+ if (jsonIpPool != null) {
+ KubevirtIpPool ipPool = network.ipPool();
+ KubevirtIpPoolJsonMatcher ipPoolMatcher =
+ KubevirtIpPoolJsonMatcher.matchesKubevirtIpPool(ipPool);
+ if (ipPoolMatcher.matches(jsonIpPool)) {
+ return true;
+ } else {
+ description.appendText("IP pool was " + jsonIpPool.toString());
+ return false;
+ }
+ }
+
+ // check host routes
+ JsonNode jsonHostRoutes = jsonNode.get(HOST_ROUTES);
+ if (jsonHostRoutes != null) {
+ if (jsonHostRoutes.size() != network.hostRoutes().size()) {
+ description.appendText("host routes size was " + jsonHostRoutes.size());
+ return false;
+ }
+
+ for (KubevirtHostRoute hostRoute : network.hostRoutes()) {
+ boolean routeFound = false;
+ for (int routeIndex = 0; routeIndex < jsonHostRoutes.size(); routeIndex++) {
+ KubevirtHostRouteJsonMatcher routeMatcher =
+ KubevirtHostRouteJsonMatcher.matchesKubevirtHostRoute(hostRoute);
+ if (routeMatcher.matches(jsonHostRoutes.get(routeIndex))) {
+ routeFound = true;
+ break;
+ }
+ }
+
+ if (!routeFound) {
+ description.appendText("Host route not found " + hostRoute.toString());
+ return false;
+ }
+ }
+ }
+
+ // check dnses
+ JsonNode jsonDnses = jsonNode.get(DNSES);
+ if (jsonDnses != null) {
+ if (jsonDnses.size() != network.dnses().size()) {
+ description.appendText("DNSes size was " + jsonDnses.size());
+ return false;
+ }
+
+
+ for (IpAddress dns : network.dnses()) {
+ boolean dnsFound = false;
+ for (int dnsIndex = 0; dnsIndex < jsonDnses.size(); dnsIndex++) {
+ String jsonDns = jsonDnses.get(dnsIndex).asText();
+ if (jsonDns.equals(dns.toString())) {
+ dnsFound = true;
+ break;
+ }
+ }
+
+ if (!dnsFound) {
+ description.appendText("DNS not found " + dns.toString());
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(network.toString());
+ }
+
+ /**
+ * Factory to allocate an kubevirt network matcher.
+ *
+ * @param network kubevirt network object we are looking for
+ * @return matcher
+ */
+ public static KubevirtNetworkJsonMatcher
+ matchesKubevirtNetwork(KubevirtNetwork network) {
+ return new KubevirtNetworkJsonMatcher(network);
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtPortCodecTest.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtPortCodecTest.java
new file mode 100644
index 0000000..5c21a28
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtPortCodecTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.codec.impl.CodecManager;
+import org.onosproject.core.CoreService;
+import org.onosproject.kubevirtnetworking.api.DefaultKubevirtPort;
+import org.onosproject.kubevirtnetworking.api.KubevirtPort;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+
+import java.util.HashMap;
+import java.util.Map;
+
+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.kubevirtnetworking.codec.KubevirtPortJsonMatcher.matchesKubevirtPort;
+import static org.onosproject.net.NetTestTools.APP_ID;
+
+/**
+ * Unit tests for KubevirtPort codec.
+ */
+public final class KubevirtPortCodecTest {
+
+ MockCodecContext context;
+
+ JsonCodec<KubevirtPort> kubevirtPortCodec;
+
+ final CoreService mockCoreService = createMock(CoreService.class);
+ private static final String REST_APP_ID = "org.onosproject.rest";
+
+ @Before
+ public void setUp() {
+ context = new MockCodecContext();
+ kubevirtPortCodec = new KubevirtPortCodec();
+
+ assertThat(kubevirtPortCodec, notNullValue());
+
+ expect(mockCoreService.registerApplication(REST_APP_ID))
+ .andReturn(APP_ID).anyTimes();
+ replay(mockCoreService);
+ context.registerService(CoreService.class, mockCoreService);
+ }
+
+ /**
+ * Tests the kubevirt port encoding.
+ */
+ @Test
+ public void testKubevirtPortEncode() {
+ KubevirtPort port = DefaultKubevirtPort.builder()
+ .vmName("test-vm-1")
+ .networkId("net-1")
+ .macAddress(MacAddress.valueOf("11:22:33:44:55:66"))
+ .ipAddress(IpAddress.valueOf("10.10.10.100"))
+ .deviceId(DeviceId.deviceId("of:foo"))
+ .portNumber(PortNumber.portNumber("1"))
+ .build();
+ ObjectNode portJson = kubevirtPortCodec.encode(port, context);
+ assertThat(portJson, matchesKubevirtPort(port));
+ }
+
+ private class MockCodecContext implements CodecContext {
+
+ private final ObjectMapper mapper = new ObjectMapper();
+ private final CodecManager manager = new CodecManager();
+ private final Map<Class<?>, Object> services = new HashMap<>();
+
+ /**
+ * Constructs a new mock codec context.
+ */
+ public MockCodecContext() {
+ manager.activate();
+ }
+
+ @Override
+ public ObjectMapper mapper() {
+ return mapper;
+ }
+
+ @Override
+ public <T> JsonCodec<T> codec(Class<T> entityClass) {
+ return manager.getCodec(entityClass);
+ }
+
+ @Override
+ public <T> T getService(Class<T> serviceClass) {
+ return (T) services.get(serviceClass);
+ }
+
+ // for registering mock services
+ public <T> void registerService(Class<T> serviceClass, T impl) {
+ services.put(serviceClass, impl);
+ }
+ }
+}
+
+
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtPortJsonMatcher.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtPortJsonMatcher.java
new file mode 100644
index 0000000..1fc6207
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtPortJsonMatcher.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onlab.packet.IpAddress;
+import org.onosproject.kubevirtnetworking.api.KubevirtPort;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+
+/**
+ * Hamcrest matcher for kubevirt port.
+ */
+public final class KubevirtPortJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+ private final KubevirtPort port;
+
+ private static final String VM_NAME = "vmName";
+ private static final String NETWORK_ID = "networkId";
+ private static final String MAC_ADDRESS = "macAddress";
+ private static final String IP_ADDRESS = "ipAddress";
+ private static final String DEVICE_ID = "deviceId";
+ private static final String PORT_NUMBER = "portNumber";
+
+ private KubevirtPortJsonMatcher(KubevirtPort port) {
+ this.port = port;
+ }
+
+ @Override
+ protected boolean matchesSafely(JsonNode jsonNode, Description description) {
+ // check VM name
+ String jsonVmName = jsonNode.get(VM_NAME).asText();
+ String vmName = port.vmName();
+ if (!jsonVmName.equals(vmName)) {
+ description.appendText("VM name was " + jsonVmName);
+ return false;
+ }
+
+ // check network ID
+ String jsonNetworkId = jsonNode.get(NETWORK_ID).asText();
+ String networkId = port.networkId();
+ if (!jsonNetworkId.equals(networkId)) {
+ description.appendText("network ID was " + jsonNetworkId);
+ return false;
+ }
+
+ // check MAC address
+ String jsonMacAddress = jsonNode.get(MAC_ADDRESS).asText();
+ String macAddress = port.macAddress().toString();
+ if (!jsonMacAddress.equals(macAddress)) {
+ description.appendText("MAC address was " + jsonMacAddress);
+ return false;
+ }
+
+ // check IP address
+ JsonNode jsonIpAddress = jsonNode.get(IP_ADDRESS);
+ if (jsonIpAddress != null) {
+ IpAddress ipAddress = port.ipAddress();
+ if (!jsonIpAddress.asText().equals(ipAddress.toString())) {
+ description.appendText("IP address was " + jsonIpAddress.asText());
+ return false;
+ }
+ }
+
+ // check device ID
+ JsonNode jsonDeviceId = jsonNode.get(DEVICE_ID);
+ if (jsonDeviceId != null) {
+ DeviceId deviceId = port.deviceId();
+ if (!jsonDeviceId.asText().equals(deviceId.toString())) {
+ description.appendText("Device ID was " + jsonDeviceId.asText());
+ return false;
+ }
+ }
+
+ // check port number
+ JsonNode jsonPortNumber = jsonNode.get(PORT_NUMBER);
+ if (jsonPortNumber != null) {
+ PortNumber portNUmber = port.portNumber();
+ if (!jsonPortNumber.asText().equals(portNUmber.toString())) {
+ description.appendText("Port number was " + jsonPortNumber.asText());
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(port.toString());
+ }
+ /**
+ * Factory to allocate an kubevirt port matcher.
+ *
+ * @param port kubevirt port object we are looking for
+ * @return matcher
+ */
+ public static KubevirtPortJsonMatcher matchesKubevirtPort(KubevirtPort port) {
+ return new KubevirtPortJsonMatcher(port);
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtRouterCodecTest.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtRouterCodecTest.java
new file mode 100644
index 0000000..1ff8951
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtRouterCodecTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import org.hamcrest.MatcherAssert;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.codec.impl.MockCodecContext;
+import org.onosproject.core.CoreService;
+import org.onosproject.kubevirtnetworking.api.DefaultKubevirtRouter;
+import org.onosproject.kubevirtnetworking.api.KubevirtPeerRouter;
+import org.onosproject.kubevirtnetworking.api.KubevirtRouter;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+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.kubevirtnetworking.codec.KubevirtRouterJsonMatcher.matchesKubevirtRouter;
+import static org.onosproject.net.NetTestTools.APP_ID;
+
+/**
+ * Unit tests for KubevirtRouter codec.
+ */
+public final class KubevirtRouterCodecTest {
+
+ MockCodecContext context;
+
+ JsonCodec<KubevirtRouter> kubevirtRouterCodec;
+
+ final CoreService mockCoreService = createMock(CoreService.class);
+ private static final String REST_APP_ID = "org.onosproject.rest";
+
+ @Before
+ public void setUp() {
+ context = new MockCodecContext();
+ kubevirtRouterCodec = new KubevirtRouterCodec();
+
+ assertThat(kubevirtRouterCodec, notNullValue());
+ expect(mockCoreService.registerApplication(REST_APP_ID))
+ .andReturn(APP_ID).anyTimes();
+ replay(mockCoreService);
+ context.registerService(CoreService.class, mockCoreService);
+ }
+
+ /**
+ * Tests the kubevirt router encoding.
+ */
+ @Test
+ public void testKubevirtRouterEncode() {
+ KubevirtPeerRouter peerRouter = new KubevirtPeerRouter(IpAddress.valueOf("10.10.10.10"),
+ MacAddress.valueOf("11:22:33:44:55:66"));
+
+ KubevirtRouter router = DefaultKubevirtRouter.builder()
+ .name("router-1")
+ .enableSnat(true)
+ .mac(MacAddress.valueOf("11:22:33:44:55:66"))
+ .description("router-1")
+ .internal(ImmutableSet.of("vlan-1"))
+ .external(ImmutableMap.of("10.10.10.20", "flat-1"))
+ .peerRouter(peerRouter)
+ .electedGateway("gatewayNode")
+ .build();
+
+ ObjectNode routerJson = kubevirtRouterCodec.encode(router, context);
+ assertThat(routerJson, matchesKubevirtRouter(router));
+ }
+
+ @Test
+ public void testKubevirtRouterDecode() throws IOException {
+ KubevirtRouter router = getKubevirtRouter("KubevirtRouter.json");
+
+ assertEquals("router-1", router.name());
+ assertEquals("Example Virtual Router", router.description());
+ assertTrue(router.enableSnat());
+ assertEquals("11:22:33:44:55:66", router.mac().toString());
+ assertEquals("192.168.10.5",
+ router.external().keySet().stream().findAny().orElse(null));
+ assertEquals("external-network", router.external().get("192.168.10.5"));
+ assertTrue(router.internal().contains("vxlan-network-1"));
+ assertTrue(router.internal().contains("vxlan-network-2"));
+ assertEquals("192.168.10.1", router.peerRouter().ipAddress().toString());
+ assertEquals("gatewayNode", router.electedGateway());
+ }
+
+ private KubevirtRouter getKubevirtRouter(String resourceName) throws IOException {
+ InputStream jsonStream = KubevirtRouterCodecTest.class.getResourceAsStream(resourceName);
+ JsonNode json = context.mapper().readTree(jsonStream);
+ MatcherAssert.assertThat(json, notNullValue());
+ KubevirtRouter router = kubevirtRouterCodec.decode((ObjectNode) json, context);
+ assertThat(router, notNullValue());
+ return router;
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtRouterJsonMatcher.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtRouterJsonMatcher.java
new file mode 100644
index 0000000..a855f42
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtRouterJsonMatcher.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onosproject.kubevirtnetworking.api.KubevirtRouter;
+
+/**
+ * Hamcrest matcher for kubevirt router interface.
+ */
+public final class KubevirtRouterJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+ private final KubevirtRouter router;
+ private static final String NAME = "name";
+ private static final String DESCRIPTION = "description";
+ private static final String ENABLE_SNAT = "enableSnat";
+ private static final String INTERNAL = "internal";
+ private static final String EXTERNAL = "external";
+ private static final String PEER_ROUTER = "peerRouter";
+ private static final String IP_ADDRESS = "ip";
+ private static final String MAC_ADDRESS = "mac";
+ private static final String NETWORK = "network";
+
+ private KubevirtRouterJsonMatcher(KubevirtRouter router) {
+ this.router = router;
+ }
+
+ @Override
+ protected boolean matchesSafely(JsonNode jsonNode, Description description) {
+
+ // check name
+ String jsonName = jsonNode.get(NAME).asText();
+ String name = router.name();
+ if (!jsonName.equals(name)) {
+ description.appendText("Name was " + jsonName);
+ return false;
+ }
+
+ // check description
+ JsonNode jsonDescription = jsonNode.get(DESCRIPTION);
+ if (jsonDescription != null) {
+ String myDescription = router.description();
+ if (!jsonDescription.asText().equals(myDescription)) {
+ description.appendText("Description was " + jsonDescription);
+ return false;
+ }
+ }
+
+ // check enable snat
+ JsonNode jsonEnableSnat = jsonNode.get(ENABLE_SNAT);
+ if (jsonEnableSnat != null) {
+ boolean enableSnat = router.enableSnat();
+ if (jsonEnableSnat.asBoolean() != enableSnat) {
+ description.appendText("EnableSNAT was " + jsonEnableSnat);
+ return false;
+ }
+ }
+
+ // check vrouter MAC
+ String jsonMac = jsonNode.get(MAC_ADDRESS).asText();
+ String mac = router.mac().toString();
+ if (!jsonMac.equals(mac)) {
+ description.appendText("MAC was " + jsonMac);
+ return false;
+ }
+
+ // check internal
+ JsonNode jsonInternal = jsonNode.get(INTERNAL);
+ if (jsonInternal != null) {
+ if (jsonInternal.size() != router.internal().size()) {
+ description.appendText("Internal networks size was " + jsonInternal.size());
+ return false;
+ }
+
+ for (int networkIndex = 0; networkIndex < jsonInternal.size(); networkIndex++) {
+ boolean networkFound = false;
+ String jsonNetwork = jsonInternal.get(networkIndex).asText();
+ if (router.internal().contains(jsonNetwork)) {
+ networkFound = true;
+ }
+
+ if (!networkFound) {
+ description.appendText("network not found " + jsonNetwork);
+ return false;
+ }
+ }
+ }
+
+ // check external
+ ArrayNode jsonExternal = (ArrayNode) jsonNode.get(EXTERNAL);
+ if (jsonExternal != null) {
+ if (jsonExternal.size() != router.external().size()) {
+ description.appendText("External networks size was " + jsonExternal.size());
+ return false;
+ }
+
+ for (int itemIndex = 0; itemIndex < jsonExternal.size(); itemIndex++) {
+ boolean itemFound = false;
+ ObjectNode jsonItem = (ObjectNode) jsonExternal.get(itemIndex);
+ String jsonIp = jsonItem.get(IP_ADDRESS).asText();
+ String jsonNetwork = jsonItem.get(NETWORK).asText();
+
+ if (router.external().containsKey(jsonIp)) {
+ if (router.external().get(jsonIp).equals(jsonNetwork)) {
+ itemFound = true;
+ }
+ }
+
+ if (!itemFound) {
+ description.appendText("External not found " + jsonItem.toString());
+ return false;
+ }
+ }
+ }
+
+ // check peer router
+ ObjectNode jsonPeerRouter = (ObjectNode) jsonNode.get(PEER_ROUTER);
+ if (jsonPeerRouter != null) {
+ JsonNode jsonIp = jsonPeerRouter.get(IP_ADDRESS);
+
+ if (jsonIp != null) {
+ if (!jsonIp.asText().equals(router.peerRouter().ipAddress().toString())) {
+ description.appendText("Peer router IP was " + jsonIp);
+ return false;
+ }
+ }
+
+ JsonNode jsonProuterMac = jsonPeerRouter.get(MAC_ADDRESS);
+
+ if (jsonProuterMac != null) {
+ if (!jsonProuterMac.asText().equals(router.peerRouter().macAddress().toString())) {
+ description.appendText("Peer router MAC was " + jsonMac);
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(router.toString());
+ }
+
+ /**
+ * Factory to allocate a kubevirt router matcher.
+ *
+ * @param router kubevirt router object we are looking for
+ * @return matcher
+ */
+ public static KubevirtRouterJsonMatcher matchesKubevirtRouter(KubevirtRouter router) {
+ return new KubevirtRouterJsonMatcher(router);
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtSecurityGroupCodecTest.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtSecurityGroupCodecTest.java
new file mode 100644
index 0000000..51bdeb5
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtSecurityGroupCodecTest.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableSet;
+import org.hamcrest.MatcherAssert;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.codec.impl.CodecManager;
+import org.onosproject.core.CoreService;
+import org.onosproject.kubevirtnetworking.api.DefaultKubevirtSecurityGroup;
+import org.onosproject.kubevirtnetworking.api.DefaultKubevirtSecurityGroupRule;
+import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroup;
+import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroupRule;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import static junit.framework.TestCase.assertEquals;
+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.kubevirtnetworking.codec.KubevirtSecurityGroupJsonMatcher.matchesKubevirtSecurityGroup;
+import static org.onosproject.net.NetTestTools.APP_ID;
+
+/**
+ * Unit tests for KubevirtSecurityGroup codec.
+ */
+public final class KubevirtSecurityGroupCodecTest {
+
+ MockCodecContext context;
+
+ JsonCodec<KubevirtSecurityGroup> kubevirtSecurityGroupCodec;
+ JsonCodec<KubevirtSecurityGroupRule> kubevirtSecurityGroupRuleCodec;
+
+ final CoreService mockCoreService = createMock(CoreService.class);
+ private static final String REST_APP_ID = "org.onosproject.rest";
+
+ @Before
+ public void setUp() {
+ context = new MockCodecContext();
+ kubevirtSecurityGroupCodec = new KubevirtSecurityGroupCodec();
+ kubevirtSecurityGroupRuleCodec = new KubevirtSecurityGroupRuleCodec();
+
+ assertThat(kubevirtSecurityGroupCodec, notNullValue());
+ assertThat(kubevirtSecurityGroupRuleCodec, notNullValue());
+ expect(mockCoreService.registerApplication(REST_APP_ID))
+ .andReturn(APP_ID).anyTimes();
+ replay(mockCoreService);
+ context.registerService(CoreService.class, mockCoreService);
+ }
+
+ /**
+ * Tests the kubevirt security group encoding.
+ */
+ @Test
+ public void testKubevirtSecurityGroupEncode() {
+ KubevirtSecurityGroupRule rule = DefaultKubevirtSecurityGroupRule.builder()
+ .id("sgr-1")
+ .securityGroupId("sg-1")
+ .direction("ingress")
+ .etherType("IPv4")
+ .portRangeMin(0)
+ .portRangeMax(80)
+ .protocol("tcp")
+ .remoteIpPrefix(IpPrefix.valueOf("0.0.0.0/0"))
+ .remoteGroupId("g-1")
+ .build();
+
+ KubevirtSecurityGroup sg = DefaultKubevirtSecurityGroup.builder()
+ .id("sg-1")
+ .name("sg")
+ .description("example-sg")
+ .rules(ImmutableSet.of(rule))
+ .build();
+
+ ObjectNode sgJson = kubevirtSecurityGroupCodec.encode(sg, context);
+ assertThat(sgJson, matchesKubevirtSecurityGroup(sg));
+ }
+
+ /**
+ * Tests the kubevirt security group decoding.
+ */
+ @Test
+ public void testKubevirtSecurityGroupDecode() throws IOException {
+ KubevirtSecurityGroup sg = getKubevirtSecurityGroup("KubevirtSecurityGroup.json");
+ KubevirtSecurityGroupRule rule = sg.rules().stream().findAny().orElse(null);
+
+ assertEquals("sg-1", sg.id());
+ assertEquals("sg", sg.name());
+ assertEquals("example-sg", sg.description());
+
+ assertEquals("sgr-1", rule.id());
+ assertEquals("sg-1", rule.securityGroupId());
+ assertEquals("ingress", rule.direction());
+ assertEquals("IPv4", rule.etherType());
+ assertEquals((Integer) 80, rule.portRangeMax());
+ assertEquals((Integer) 0, rule.portRangeMin());
+ assertEquals("tcp", rule.protocol());
+ assertEquals("0.0.0.0/0", rule.remoteIpPrefix().toString());
+ assertEquals("g-1", rule.remoteGroupId());
+ }
+
+ private KubevirtSecurityGroup getKubevirtSecurityGroup(String resourceName) throws IOException {
+ InputStream jsonStream = KubevirtSecurityGroupCodecTest.class.getResourceAsStream(resourceName);
+ JsonNode json = context.mapper().readTree(jsonStream);
+ MatcherAssert.assertThat(json, notNullValue());
+ KubevirtSecurityGroup sg = kubevirtSecurityGroupCodec.decode((ObjectNode) json, context);
+ assertThat(sg, notNullValue());
+ return sg;
+ }
+
+ private class MockCodecContext implements CodecContext {
+
+ private final ObjectMapper mapper = new ObjectMapper();
+ private final CodecManager manager = new CodecManager();
+ private final Map<Class<?>, Object> services = new HashMap<>();
+
+ /**
+ * Constructs a new mock codec context.
+ */
+ public MockCodecContext() {
+ manager.activate();
+ }
+
+ @Override
+ public ObjectMapper mapper() {
+ return mapper;
+ }
+
+ @Override
+ public <T> JsonCodec<T> codec(Class<T> entityClass) {
+ if (entityClass == KubevirtSecurityGroupRule.class) {
+ return (JsonCodec<T>) kubevirtSecurityGroupRuleCodec;
+ }
+
+ return manager.getCodec(entityClass);
+ }
+
+ @Override
+ public <T> T getService(Class<T> serviceClass) {
+ return (T) services.get(serviceClass);
+ }
+
+ // for registering mock services
+ public <T> void registerService(Class<T> serviceClass, T impl) {
+ services.put(serviceClass, impl);
+ }
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtSecurityGroupJsonMatcher.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtSecurityGroupJsonMatcher.java
new file mode 100644
index 0000000..ea04c60
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtSecurityGroupJsonMatcher.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroup;
+import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroupRule;
+
+/**
+ * Hamcrest matcher for security group.
+ */
+public final class KubevirtSecurityGroupJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+ private static final String ID = "id";
+ private static final String NAME = "name";
+ private static final String DESCRIPTION = "description";
+ private static final String RULES = "rules";
+
+ private final KubevirtSecurityGroup sg;
+
+ private KubevirtSecurityGroupJsonMatcher(KubevirtSecurityGroup sg) {
+ this.sg = sg;
+ }
+
+ @Override
+ protected boolean matchesSafely(JsonNode jsonNode, Description description) {
+ // check sg ID
+ String jsonId = jsonNode.get(ID).asText();
+ String id = sg.id();
+ if (!jsonId.equals(id)) {
+ description.appendText("ID was " + jsonId);
+ return false;
+ }
+
+ // check sg name
+ String jsonName = jsonNode.get(NAME).asText();
+ String name = sg.name();
+ if (!jsonName.equals(name)) {
+ description.appendText("Name was " + jsonName);
+ return false;
+ }
+
+ // check description
+ JsonNode jsonDescription = jsonNode.get(DESCRIPTION);
+ if (jsonDescription != null) {
+ String myDescription = sg.description();
+ if (!jsonDescription.asText().equals(myDescription)) {
+ description.appendText("Description was " + jsonDescription);
+ return false;
+ }
+ }
+
+ JsonNode jsonSgr = jsonNode.get(RULES);
+ if (jsonSgr != null) {
+ // check size of rule array
+ if (jsonSgr.size() != sg.rules().size()) {
+ description.appendText("Rules was " + jsonSgr.size());
+ return false;
+ }
+
+ // check rules
+ for (KubevirtSecurityGroupRule sgr : sg.rules()) {
+ boolean ruleFound = false;
+ for (int ruleIndex = 0; ruleIndex < jsonSgr.size(); ruleIndex++) {
+ KubevirtSecurityGroupRuleJsonMatcher ruleMatcher =
+ KubevirtSecurityGroupRuleJsonMatcher
+ .matchesKubevirtSecurityGroupRule(sgr);
+ if (ruleMatcher.matches(jsonSgr.get(ruleIndex))) {
+ ruleFound = true;
+ break;
+ }
+ }
+
+ if (!ruleFound) {
+ description.appendText("Rule not found " + sgr.toString());
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(sg.toString());
+ }
+
+ /**
+ * Factory to allocate a kubevirt security group matcher.
+ *
+ * @param sg kubevirt security group object we are looking for
+ * @return matcher
+ */
+ public static KubevirtSecurityGroupJsonMatcher
+ matchesKubevirtSecurityGroup(KubevirtSecurityGroup sg) {
+ return new KubevirtSecurityGroupJsonMatcher(sg);
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtSecurityGroupRuleJsonMatcher.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtSecurityGroupRuleJsonMatcher.java
new file mode 100644
index 0000000..81ba374
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtSecurityGroupRuleJsonMatcher.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroupRule;
+
+/**
+ * Hamcrest matcher for kubevirt port.
+ */
+public final class KubevirtSecurityGroupRuleJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+ private final KubevirtSecurityGroupRule rule;
+
+ private static final String ID = "id";
+ private static final String SECURITY_GROUP_ID = "securityGroupId";
+ private static final String DIRECTION = "direction";
+ private static final String ETHER_TYPE = "etherType";
+ private static final String PORT_RANGE_MAX = "portRangeMax";
+ private static final String PORT_RANGE_MIN = "portRangeMin";
+ private static final String PROTOCOL = "protocol";
+ private static final String REMOTE_IP_PREFIX = "remoteIpPrefix";
+ private static final String REMOTE_GROUP_ID = "remoteGroupId";
+
+ private KubevirtSecurityGroupRuleJsonMatcher(KubevirtSecurityGroupRule rule) {
+ this.rule = rule;
+ }
+
+ @Override
+ protected boolean matchesSafely(JsonNode jsonNode, Description description) {
+ // check rule ID
+ String jsonId = jsonNode.get(ID).asText();
+ String id = rule.id();
+ if (!jsonId.equals(id)) {
+ description.appendText("Rule ID was " + jsonId);
+ return false;
+ }
+
+ // check security group ID
+ String jsonSecurityGroupId = jsonNode.get(SECURITY_GROUP_ID).asText();
+ String securityGroupId = rule.securityGroupId();
+ if (!jsonSecurityGroupId.equals(securityGroupId)) {
+ description.appendText("Security group ID was " + jsonSecurityGroupId);
+ return false;
+ }
+
+ // check direction
+ String jsonDirection = jsonNode.get(DIRECTION).asText();
+ String direction = rule.direction();
+ if (!jsonDirection.equals(direction)) {
+ description.appendText("Direction was " + jsonDirection);
+ return false;
+ }
+
+ // check ether type
+ JsonNode jsonEtherType = jsonNode.get(ETHER_TYPE);
+ if (jsonEtherType != null) {
+ String etherType = rule.etherType();
+ if (!jsonEtherType.asText().equals(etherType)) {
+ description.appendText("EtherType was " + jsonEtherType);
+ return false;
+ }
+ }
+
+ // check port range max
+ JsonNode jsonPortRangeMax = jsonNode.get(PORT_RANGE_MAX);
+ if (jsonPortRangeMax != null) {
+ int portRangeMax = rule.portRangeMax();
+ if (portRangeMax != jsonPortRangeMax.asInt()) {
+ description.appendText("PortRangeMax was " + jsonPortRangeMax);
+ return false;
+ }
+ }
+
+ // check port range min
+ JsonNode jsonPortRangeMin = jsonNode.get(PORT_RANGE_MIN);
+ if (jsonPortRangeMin != null) {
+ int portRangeMin = rule.portRangeMin();
+ if (portRangeMin != jsonPortRangeMin.asInt()) {
+ description.appendText("PortRangeMin was " + jsonPortRangeMin);
+ return false;
+ }
+ }
+
+ // check protocol
+ JsonNode jsonProtocol = jsonNode.get(PROTOCOL);
+ if (jsonProtocol != null) {
+ String protocol = rule.protocol();
+ if (!jsonProtocol.asText().equals(protocol)) {
+ description.appendText("Protocol was " + jsonProtocol);
+ return false;
+ }
+ }
+
+ // check remote IP prefix
+ JsonNode jsonRemoteIpPrefix = jsonNode.get(REMOTE_IP_PREFIX);
+ if (jsonRemoteIpPrefix != null) {
+ IpPrefix remoteIpPrefix = rule.remoteIpPrefix();
+ if (!jsonRemoteIpPrefix.asText().equals(remoteIpPrefix.toString())) {
+ description.appendText("Remote IP prefix was " + jsonRemoteIpPrefix);
+ return false;
+ }
+ }
+
+ // check remote group ID
+ JsonNode jsonRemoteGroupId = jsonNode.get(REMOTE_GROUP_ID);
+ if (jsonRemoteGroupId != null) {
+ String remoteGroupId = rule.remoteGroupId();
+ if (!jsonRemoteGroupId.asText().equals(remoteGroupId)) {
+ description.appendText("Remote group ID was " + jsonRemoteGroupId);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(rule.toString());
+ }
+
+ /**
+ * Factory to allocate an kubevirt security group rule matcher.
+ *
+ * @param rule kubevirt security group rule object we are looking for
+ * @return matcher
+ */
+ public static KubevirtSecurityGroupRuleJsonMatcher
+ matchesKubevirtSecurityGroupRule(KubevirtSecurityGroupRule rule) {
+ return new KubevirtSecurityGroupRuleJsonMatcher(rule);
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/web/KubevirtMm5WebResourceTest.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/web/KubevirtMm5WebResourceTest.java
new file mode 100644
index 0000000..c1415fd
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/web/KubevirtMm5WebResourceTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2022-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.kubevirtnetworking.web;
+
+import com.eclipsesource.json.Json;
+import com.eclipsesource.json.JsonArray;
+import com.eclipsesource.json.JsonObject;
+import com.google.common.collect.ImmutableSet;
+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.onlab.packet.IpAddress;
+import org.onosproject.codec.CodecService;
+import org.onosproject.codec.impl.CodecManager;
+import org.onosproject.kubevirtnetworking.api.DefaultKubevirtNetwork;
+import org.onosproject.kubevirtnetworking.api.DefaultKubevirtRouter;
+import org.onosproject.kubevirtnetworking.api.KubevirtHostRoute;
+import org.onosproject.kubevirtnetworking.api.KubevirtIpPool;
+import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
+import org.onosproject.kubevirtnetworking.api.KubevirtNetworkService;
+import org.onosproject.kubevirtnetworking.api.KubevirtRouter;
+import org.onosproject.kubevirtnetworking.api.KubevirtRouterService;
+import org.onosproject.kubevirtnetworking.codec.KubevirtHostRouteCodec;
+import org.onosproject.kubevirtnetworking.codec.KubevirtIpPoolCodec;
+import org.onosproject.kubevirtnetworking.codec.KubevirtNetworkCodec;
+import org.onosproject.kubevirtnode.api.DefaultKubevirtNode;
+import org.onosproject.kubevirtnode.api.KubevirtNode;
+import org.onosproject.kubevirtnode.api.KubevirtNodeService;
+import org.onosproject.kubevirtnode.api.KubevirtNodeState;
+import org.onosproject.net.DeviceId;
+import org.onosproject.rest.resources.ResourceTest;
+
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
+
+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.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.Assert.assertThat;
+
+public class KubevirtMm5WebResourceTest extends ResourceTest {
+
+ final KubevirtRouterService mockRouterService = createMock(KubevirtRouterService.class);
+ final KubevirtNodeService mockNodeService = createMock(KubevirtNodeService.class);
+ final KubevirtNetworkService mockNetworkService = createMock(KubevirtNetworkService.class);
+
+ private static final String VR_STATUS_PATH = "api/mm5/v1/status/vr/";
+ private static final String NETWORK_PATH = "api/mm5/v1/network";
+
+ private static final String ROUTER_NAME = "router1";
+ private static final String HOST_NAME = "hostname1";
+
+
+ private static final KubevirtNetwork NETWORK_1 = DefaultKubevirtNetwork.builder()
+ .networkId("network")
+ .name("network")
+ .type(KubevirtNetwork.Type.FLAT)
+ .cidr("10.10.10.0/24")
+ .mtu(1500)
+ .gatewayIp(IpAddress.valueOf("10.10.10.1"))
+ .defaultRoute(true)
+ .ipPool(new KubevirtIpPool(IpAddress.valueOf("10.10.10.100"),
+ IpAddress.valueOf("10.10.10.200")))
+ .build();
+
+ private static final KubevirtNode NODE_1 = DefaultKubevirtNode.builder()
+ .hostname(HOST_NAME)
+ .type(KubevirtNode.Type.GATEWAY)
+ .dataIp(IpAddress.valueOf("10.134.34.222"))
+ .managementIp(IpAddress.valueOf("10.134.231.30"))
+ .intgBridge(DeviceId.deviceId("of:00000000000000a1"))
+ .tunBridge(DeviceId.deviceId("of:00000000000000a2"))
+ .state(KubevirtNodeState.COMPLETE)
+ .build();
+
+
+ private static final KubevirtRouter ROUTER_1 = DefaultKubevirtRouter.builder()
+ .name(ROUTER_NAME).build();
+
+ /**
+ * Constructs a kubevirt mm5 resource test instance.
+ */
+ public KubevirtMm5WebResourceTest() {
+ super(ResourceConfig.forApplicationClass(KubevirtNetworkingWebApplication.class));
+ }
+
+ /**
+ * Sets up the global values for all the tests.
+ */
+ @Before
+ public void setUpTest() {
+ final CodecManager codecService = new CodecManager();
+ codecService.activate();
+ codecService.registerCodec(KubevirtNetwork.class, new KubevirtNetworkCodec());
+ codecService.registerCodec(KubevirtHostRoute.class, new KubevirtHostRouteCodec());
+ codecService.registerCodec(KubevirtIpPool.class, new KubevirtIpPoolCodec());
+
+ ServiceDirectory testDirectory =
+ new TestServiceDirectory()
+ .add(KubevirtNodeService.class, mockNodeService)
+ .add(KubevirtNetworkService.class, mockNetworkService)
+ .add(KubevirtRouterService.class, mockRouterService)
+ .add(CodecService.class, codecService);
+
+ setServiceDirectory(testDirectory);
+ }
+
+ @Test
+ public void testVrStatusWithExistingRouterOperation() {
+ expect(mockRouterService.routers()).andReturn(ImmutableSet.of(ROUTER_1)).anyTimes();
+ replay(mockRouterService);
+
+ final WebTarget wt = target();
+
+ final String stringResponse = wt.path(VR_STATUS_PATH + ROUTER_NAME).request().get(String.class);
+ final Response response = wt.path(VR_STATUS_PATH + ROUTER_NAME).request().get();
+
+ final JsonObject result = Json.parse(stringResponse).asObject();
+
+ assertThat(result, notNullValue());
+ assertThat(result.names(), hasSize(4));
+ assertThat(response.getStatus(), is(200));
+
+ verify(mockRouterService);
+ }
+
+ @Test
+ public void testVrStatusWithNonRouterOperation() {
+ expect(mockRouterService.routers()).andReturn(ImmutableSet.of(ROUTER_1)).anyTimes();
+ replay(mockRouterService);
+
+ final WebTarget wt = target();
+
+ final Response response = wt.path(VR_STATUS_PATH + "anyRouter").request().get();
+ assertThat(response.getStatus(), is(404));
+
+ verify(mockRouterService);
+ }
+
+ @Test
+ public void testGetNetworkOperation() {
+ expect(mockNetworkService.networks()).andReturn(ImmutableSet.of(NETWORK_1)).anyTimes();
+ replay(mockNetworkService);
+
+ final WebTarget wt = target();
+
+ final String response = wt.path(NETWORK_PATH).request().get(String.class);
+ final JsonObject result = Json.parse(response).asObject();
+
+ assertThat(result, notNullValue());
+ assertThat(result.names(), hasSize(1));
+ assertThat(result.names().get(0), is("networks"));
+
+ final JsonArray jsonNodes = result.get("networks").asArray();
+ assertThat(jsonNodes, notNullValue());
+ assertThat(jsonNodes.size(), is(1));
+
+ verify(mockNetworkService);
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/web/KubevirtNetworkWebResourceTest.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/web/KubevirtNetworkWebResourceTest.java
new file mode 100644
index 0000000..b453dad
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/web/KubevirtNetworkWebResourceTest.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.web;
+
+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.onlab.packet.IpAddress;
+import org.onosproject.codec.CodecService;
+import org.onosproject.codec.impl.CodecManager;
+import org.onosproject.kubevirtnetworking.api.DefaultKubevirtNetwork;
+import org.onosproject.kubevirtnetworking.api.KubevirtHostRoute;
+import org.onosproject.kubevirtnetworking.api.KubevirtIpPool;
+import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
+import org.onosproject.kubevirtnetworking.api.KubevirtNetworkAdminService;
+import org.onosproject.kubevirtnetworking.codec.KubevirtHostRouteCodec;
+import org.onosproject.kubevirtnetworking.codec.KubevirtIpPoolCodec;
+import org.onosproject.kubevirtnetworking.codec.KubevirtNetworkCodec;
+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.io.InputStream;
+
+import static org.easymock.EasyMock.anyObject;
+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.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Unit tests for kubevirt network REST API.
+ */
+public class KubevirtNetworkWebResourceTest extends ResourceTest {
+
+ final KubevirtNetworkAdminService mockAdminService = createMock(KubevirtNetworkAdminService.class);
+ private static final String PATH = "network";
+
+ private KubevirtNetwork network;
+
+ /**
+ * Constructs a kubernetes networking resource test instance.
+ */
+ public KubevirtNetworkWebResourceTest() {
+ super(ResourceConfig.forApplicationClass(KubevirtNetworkingWebApplication.class));
+ }
+
+ /**
+ * Sets up the global values for all the tests.
+ */
+ @Before
+ public void setUpTest() {
+ final CodecManager codecService = new CodecManager();
+ codecService.activate();
+ codecService.registerCodec(KubevirtHostRoute.class, new KubevirtHostRouteCodec());
+ codecService.registerCodec(KubevirtIpPool.class, new KubevirtIpPoolCodec());
+ codecService.registerCodec(KubevirtNetwork.class, new KubevirtNetworkCodec());
+ ServiceDirectory testDirectory =
+ new TestServiceDirectory()
+ .add(KubevirtNetworkAdminService.class, mockAdminService)
+ .add(CodecService.class, codecService);
+ setServiceDirectory(testDirectory);
+
+ network = DefaultKubevirtNetwork.builder()
+ .networkId("network")
+ .name("network")
+ .type(KubevirtNetwork.Type.FLAT)
+ .cidr("10.10.10.0/24")
+ .mtu(1500)
+ .gatewayIp(IpAddress.valueOf("10.10.10.1"))
+ .defaultRoute(true)
+ .ipPool(new KubevirtIpPool(IpAddress.valueOf("10.10.10.100"),
+ IpAddress.valueOf("10.10.10.200")))
+ .build();
+ }
+
+ /**
+ * Tests the results of the REST API POST method with creating new network operation.
+ */
+ @Test
+ public void testCreateNetworkWithCreateOperation() {
+ mockAdminService.createNetwork(anyObject());
+ replay(mockAdminService);
+
+ final WebTarget wt = target();
+ InputStream jsonStream = KubevirtNetworkWebResourceTest.class
+ .getResourceAsStream("kubevirt-network.json");
+ Response response = wt.path(PATH).request(MediaType.APPLICATION_JSON_TYPE)
+ .post(Entity.json(jsonStream));
+ final int status = response.getStatus();
+
+ assertThat(status, is(201));
+
+ verify(mockAdminService);
+ }
+
+ /**
+ * Tests the results of the REST API PUT method with modifying the network.
+ */
+ @Test
+ public void testUpdateNetworkWithModifyOperation() {
+ mockAdminService.updateNetwork(anyObject());
+ replay(mockAdminService);
+
+ String location = PATH + "/network";
+
+ final WebTarget wt = target();
+ InputStream jsonStream = KubevirtNetworkWebResourceTest.class
+ .getResourceAsStream("kubevirt-network.json");
+ Response response = wt.path(location)
+ .request(MediaType.APPLICATION_JSON_TYPE)
+ .put(Entity.json(jsonStream));
+ final int status = response.getStatus();
+
+ assertThat(status, is(200));
+
+ verify(mockAdminService);
+ }
+
+ /**
+ * Tests the results of the REST API DELETE method with deleting the network.
+ */
+ @Test
+ public void testDeleteNetworkWithDeletionOperation() {
+ mockAdminService.removeNetwork(anyString());
+ replay(mockAdminService);
+
+ String location = PATH + "/network";
+
+ final WebTarget wt = target();
+ Response response = wt.path(location).request(
+ MediaType.APPLICATION_JSON_TYPE).delete();
+
+ final int status = response.getStatus();
+
+ assertThat(status, is(204));
+
+ verify(mockAdminService);
+ }
+
+ /**
+ * Tests the results of checking network existence.
+ */
+ @Test
+ public void testHasNetworkWithValidNetwork() {
+ expect(mockAdminService.network(anyString())).andReturn(network);
+ replay(mockAdminService);
+
+ String location = PATH + "/exist/network";
+
+ final WebTarget wt = target();
+ String response = wt.path(location).request(
+ MediaType.APPLICATION_JSON_TYPE).get(String.class);
+
+ assertThat(response, is("{\"result\":true}"));
+
+ verify((mockAdminService));
+ }
+
+ /**
+ * Tests the results of checking network existence.
+ */
+ @Test
+ public void testHasNetworkWithNullNetwork() {
+ expect(mockAdminService.network(anyString())).andReturn(null);
+ replay(mockAdminService);
+
+ String location = PATH + "/exist/network";
+
+ final WebTarget wt = target();
+ String response = wt.path(location).request(
+ MediaType.APPLICATION_JSON_TYPE).get(String.class);
+
+ assertThat(response, is("{\"result\":false}"));
+
+ verify((mockAdminService));
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/web/KubevirtNetworkingCodecRegisterTest.java b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/web/KubevirtNetworkingCodecRegisterTest.java
new file mode 100644
index 0000000..c3784ba
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/java/org/onosproject/kubevirtnetworking/web/KubevirtNetworkingCodecRegisterTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2021-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.kubevirtnetworking.web;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import org.junit.Test;
+import org.onlab.junit.TestUtils;
+import org.onosproject.codec.CodecService;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.kubevirtnetworking.api.KubevirtHostRoute;
+import org.onosproject.kubevirtnetworking.api.KubevirtIpPool;
+import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
+import org.onosproject.kubevirtnetworking.codec.KubevirtHostRouteCodec;
+import org.onosproject.kubevirtnetworking.codec.KubevirtIpPoolCodec;
+import org.onosproject.kubevirtnetworking.codec.KubevirtNetworkCodec;
+
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit tests for kubevirt networking codec register.
+ */
+public class KubevirtNetworkingCodecRegisterTest {
+
+ /**
+ * Tests codec register activation and deactivation.
+ */
+ @Test
+ public void testActivateDeactivate() {
+ KubevirtNetworkingCodecRegister register = new KubevirtNetworkingCodecRegister();
+ CodecService codecService = new TestCodecService();
+
+ TestUtils.setField(register, "codecService", codecService);
+ register.activate();
+
+ assertEquals(KubevirtNetworkCodec.class.getName(),
+ codecService.getCodec(KubevirtNetwork.class).getClass().getName());
+ assertEquals(KubevirtHostRouteCodec.class.getName(),
+ codecService.getCodec(KubevirtHostRoute.class).getClass().getName());
+ assertEquals(KubevirtIpPoolCodec.class.getName(),
+ codecService.getCodec(KubevirtIpPool.class).getClass().getName());
+
+ register.deactivate();
+ }
+
+ private static class TestCodecService implements CodecService {
+
+ private Map<String, JsonCodec> codecMap = Maps.newConcurrentMap();
+
+ @Override
+ public Set<Class<?>> getCodecs() {
+ return ImmutableSet.of();
+ }
+
+ @Override
+ public <T> JsonCodec<T> getCodec(Class<T> entityClass) {
+ return codecMap.get(entityClass.getName());
+ }
+
+ @Override
+ public <T> void registerCodec(Class<T> entityClass, JsonCodec<T> codec) {
+ codecMap.put(entityClass.getName(), codec);
+ }
+
+ @Override
+ public void unregisterCodec(Class<?> entityClass) {
+ codecMap.remove(entityClass.getName());
+ }
+ }
+}
diff --git a/apps/kubevirt-networking/web/src/test/resources/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIp.json b/apps/kubevirt-networking/web/src/test/resources/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIp.json
new file mode 100644
index 0000000..93819ce
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/resources/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIp.json
@@ -0,0 +1,9 @@
+{
+ "id": "fip-1",
+ "routerName": "router-1",
+ "networkName": "flat-1",
+ "floatingIp": "10.10.10.10",
+ "podName": "pod-1",
+ "vmName": "vm-1",
+ "fixedIp": "20.20.20.20"
+}
\ No newline at end of file
diff --git a/apps/kubevirt-networking/web/src/test/resources/org/onosproject/kubevirtnetworking/codec/KubevirtLoadBalancer.json b/apps/kubevirt-networking/web/src/test/resources/org/onosproject/kubevirtnetworking/codec/KubevirtLoadBalancer.json
new file mode 100644
index 0000000..806fd73
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/resources/org/onosproject/kubevirtnetworking/codec/KubevirtLoadBalancer.json
@@ -0,0 +1,25 @@
+{
+ "name": "lb-1",
+ "description": "Example Load Balancer",
+ "networkId": "net-1",
+ "vip": "10.10.10.10",
+ "members": [
+ "10.10.10.11",
+ "10.10.10.12"
+ ],
+ "rules": [
+ {
+ "protocol": "tcp",
+ "portRangeMax": 8000,
+ "portRangeMin": 7000
+ },
+ {
+ "protocol": "udp",
+ "portRangeMax": 9000,
+ "portRangeMin": 8000
+ },
+ {
+ "protocol" : "icmp"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/apps/kubevirt-networking/web/src/test/resources/org/onosproject/kubevirtnetworking/codec/KubevirtNetwork.json b/apps/kubevirt-networking/web/src/test/resources/org/onosproject/kubevirtnetworking/codec/KubevirtNetwork.json
new file mode 100644
index 0000000..293cfcb
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/resources/org/onosproject/kubevirtnetworking/codec/KubevirtNetwork.json
@@ -0,0 +1,22 @@
+{
+ "networkId": "network-1",
+ "name": "network-1",
+ "type": "FLAT",
+ "mtu": 1500,
+ "cidr": "10.10.0.0/24",
+ "gatewayIp": "10.10.0.1",
+ "defaultRoute": true,
+ "ipPool": {
+ "start": "10.10.10.100",
+ "end": "10.10.10.200"
+ },
+ "hostRoutes": [
+ {
+ "destination": "10.10.10.0/24",
+ "nexthop": "10.10.10.1"
+ }
+ ],
+ "dnses": [
+ "8.8.8.8"
+ ]
+}
\ No newline at end of file
diff --git a/apps/kubevirt-networking/web/src/test/resources/org/onosproject/kubevirtnetworking/codec/KubevirtRouter.json b/apps/kubevirt-networking/web/src/test/resources/org/onosproject/kubevirtnetworking/codec/KubevirtRouter.json
new file mode 100644
index 0000000..5d9d53c
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/resources/org/onosproject/kubevirtnetworking/codec/KubevirtRouter.json
@@ -0,0 +1,18 @@
+{
+ "name": "router-1",
+ "description": "Example Virtual Router",
+ "enableSnat": true,
+ "mac": "11:22:33:44:55:66",
+ "external": {
+ "ip": "192.168.10.5",
+ "network": "external-network"
+ },
+ "internal": [
+ "vxlan-network-1",
+ "vxlan-network-2"
+ ],
+ "peerRouter": {
+ "ip": "192.168.10.1"
+ },
+ "gateway": "gatewayNode"
+}
\ No newline at end of file
diff --git a/apps/kubevirt-networking/web/src/test/resources/org/onosproject/kubevirtnetworking/codec/KubevirtSecurityGroup.json b/apps/kubevirt-networking/web/src/test/resources/org/onosproject/kubevirtnetworking/codec/KubevirtSecurityGroup.json
new file mode 100644
index 0000000..365f5a3
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/resources/org/onosproject/kubevirtnetworking/codec/KubevirtSecurityGroup.json
@@ -0,0 +1,18 @@
+{
+ "id": "sg-1",
+ "name": "sg",
+ "description": "example-sg",
+ "rules": [
+ {
+ "id": "sgr-1",
+ "securityGroupId": "sg-1",
+ "direction": "ingress",
+ "etherType": "IPv4",
+ "portRangeMax": 80,
+ "portRangeMin": 0,
+ "protocol": "tcp",
+ "remoteIpPrefix": "0.0.0.0/0",
+ "remoteGroupId": "g-1"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/apps/kubevirt-networking/web/src/test/resources/org/onosproject/kubevirtnetworking/web/kubevirt-network.json b/apps/kubevirt-networking/web/src/test/resources/org/onosproject/kubevirtnetworking/web/kubevirt-network.json
new file mode 100644
index 0000000..c65236c
--- /dev/null
+++ b/apps/kubevirt-networking/web/src/test/resources/org/onosproject/kubevirtnetworking/web/kubevirt-network.json
@@ -0,0 +1,13 @@
+{
+ "networkId": "network",
+ "name": "network",
+ "type": "FLAT",
+ "mtu": 1500,
+ "cidr": "10.10.10.0/24",
+ "gatewayIp": "10.10.10.1",
+ "defaultRoute": true,
+ "ipPool": {
+ "start": "10.10.10.100",
+ "end": "10.10.10.200"
+ }
+}
\ No newline at end of file