[ONOS-7905] Add default implementation for kubernetes data model
Change-Id: I08e9266dec2050e8299e4189745608a6e03fd06e
diff --git a/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sIpamCodec.java b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sIpamCodec.java
new file mode 100644
index 0000000..695156c
--- /dev/null
+++ b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sIpamCodec.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2019-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.k8snetworking.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.k8snetworking.api.DefaultK8sIpam;
+import org.onosproject.k8snetworking.api.K8sIpam;
+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;
+
+/**
+ * Kubernetes IPAM codec used for serializing and de-serializing JSON string.
+ */
+public final class K8sIpamCodec extends JsonCodec<K8sIpam> {
+
+ private final Logger log = getLogger(getClass());
+
+ private static final String IP_ADDRESS = "ipAddress";
+ private static final String NETWORK_ID = "networkId";
+
+ private static final String MISSING_MESSAGE = " is required in K8sIPAM";
+
+ @Override
+ public ObjectNode encode(K8sIpam ipam, CodecContext context) {
+ checkNotNull(ipam, "Kubernetes IPAM cannot be null");
+
+ return context.mapper().createObjectNode()
+ .put(IP_ADDRESS, ipam.ipAddress().toString())
+ .put(NETWORK_ID, ipam.networkId());
+ }
+
+ @Override
+ public K8sIpam decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ String ipAddress = nullIsIllegal(json.get(IP_ADDRESS).asText(),
+ IP_ADDRESS + MISSING_MESSAGE);
+ String networkId = nullIsIllegal(json.get(NETWORK_ID).asText(),
+ NETWORK_ID + MISSING_MESSAGE);
+
+ return new DefaultK8sIpam(IpAddress.valueOf(ipAddress), networkId);
+ }
+}
diff --git a/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sNetworkCodec.java b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sNetworkCodec.java
new file mode 100644
index 0000000..e6e646b
--- /dev/null
+++ b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sNetworkCodec.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2019-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.k8snetworking.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.k8snetworking.api.DefaultK8sNetwork;
+import org.onosproject.k8snetworking.api.K8sNetwork;
+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;
+
+/**
+ * Kubernetes network codec used for serializing and de-serializing JSON string.
+ */
+public final class K8sNetworkCodec extends JsonCodec<K8sNetwork> {
+
+ private final Logger log = getLogger(getClass());
+
+ private static final String NETWORK_ID = "networkId";
+ private static final String TYPE = "type";
+ private static final String MTU = "mtu";
+ private static final String SEGMENT_ID = "segmentId";
+ private static final String GATEWAY_IP = "gatewayIp";
+ private static final String CIDR = "cidr";
+
+ private static final String MISSING_MESSAGE = " is required in K8sNetwork";
+
+ @Override
+ public ObjectNode encode(K8sNetwork network, CodecContext context) {
+ checkNotNull(network, "Kubernetes network cannot be null");
+
+ ObjectNode result = context.mapper().createObjectNode()
+ .put(NETWORK_ID, network.networkId())
+ .put(TYPE, network.type().name())
+ .put(SEGMENT_ID, network.segmentId())
+ .put(GATEWAY_IP, network.gatewayIp().toString())
+ .put(CIDR, network.cidr());
+
+ if (network.mtu() != null) {
+ result.put(MTU, network.mtu());
+ }
+
+ return result;
+ }
+
+ @Override
+ public K8sNetwork 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 segmentId = nullIsIllegal(json.get(SEGMENT_ID).asText(),
+ SEGMENT_ID + MISSING_MESSAGE);
+ String gatewayIp = nullIsIllegal(json.get(GATEWAY_IP).asText(),
+ GATEWAY_IP + MISSING_MESSAGE);
+ String cidr = nullIsIllegal(json.get(CIDR).asText(),
+ CIDR + MISSING_MESSAGE);
+
+ DefaultK8sNetwork.Builder networkBuilder = DefaultK8sNetwork.builder()
+ .networkId(networkId)
+ .type(K8sNetwork.Type.valueOf(type))
+ .segmentId(segmentId)
+ .gatewayIp(IpAddress.valueOf(gatewayIp))
+ .cidr(cidr);
+
+ if (json.get(MTU) != null) {
+ networkBuilder.mtu(json.get(MTU).asInt());
+ }
+
+ return networkBuilder.build();
+ }
+}
diff --git a/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sPortCodec.java b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sPortCodec.java
new file mode 100644
index 0000000..9ca74cb
--- /dev/null
+++ b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/codec/K8sPortCodec.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2019-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.k8snetworking.codec;
+
+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.k8snetworking.api.DefaultK8sPort;
+import org.onosproject.k8snetworking.api.K8sPort;
+import org.onosproject.k8snetworking.api.K8sPort.State;
+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;
+
+/**
+ * Kubernetes port codec used for serializing and de-serializing JSON string.
+ */
+public final class K8sPortCodec extends JsonCodec<K8sPort> {
+
+ private final Logger log = getLogger(getClass());
+
+ private static final String NETWORK_ID = "networkId";
+ private static final String PORT_ID = "portId";
+ 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 STATE = "state";
+
+ private static final String MISSING_MESSAGE = " is required in K8sPort";
+
+ @Override
+ public ObjectNode encode(K8sPort port, CodecContext context) {
+ checkNotNull(port, "Kubernetes port cannot be null");
+
+ return context.mapper().createObjectNode()
+ .put(NETWORK_ID, port.networkId())
+ .put(PORT_ID, port.portId())
+ .put(MAC_ADDRESS, port.macAddress().toString())
+ .put(IP_ADDRESS, port.ipAddress().toString())
+ .put(DEVICE_ID, port.deviceId().toString())
+ .put(PORT_NUMBER, port.portNumber().toString())
+ .put(STATE, port.state().name());
+ }
+
+ @Override
+ public K8sPort 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 portId = nullIsIllegal(json.get(PORT_ID).asText(),
+ PORT_ID + MISSING_MESSAGE);
+ String macAddress = nullIsIllegal(json.get(MAC_ADDRESS).asText(),
+ MAC_ADDRESS + MISSING_MESSAGE);
+ String ipAddress = nullIsIllegal(json.get(IP_ADDRESS).asText(),
+ IP_ADDRESS + MISSING_MESSAGE);
+ String deviceId = nullIsIllegal(json.get(DEVICE_ID).asText(),
+ DEVICE_ID + MISSING_MESSAGE);
+ String portNumber = nullIsIllegal(json.get(PORT_NUMBER).asText(),
+ PORT_NUMBER + MISSING_MESSAGE);
+ String state = nullIsIllegal(json.get(STATE).asText(),
+ STATE + MISSING_MESSAGE);
+
+ return DefaultK8sPort.builder()
+ .networkId(networkId)
+ .portId(portId)
+ .macAddress(MacAddress.valueOf(macAddress))
+ .ipAddress(IpAddress.valueOf(ipAddress))
+ .deviceId(DeviceId.deviceId(deviceId))
+ .portNumber(PortNumber.portNumber(portNumber))
+ .state(State.valueOf(state))
+ .build();
+ }
+}
diff --git a/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sIpamCodecTest.java b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sIpamCodecTest.java
new file mode 100644
index 0000000..8335867
--- /dev/null
+++ b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sIpamCodecTest.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2019-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.k8snetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+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.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.codec.impl.CodecManager;
+import org.onosproject.core.CoreService;
+import org.onosproject.k8snetworking.api.DefaultK8sIpam;
+import org.onosproject.k8snetworking.api.K8sIpam;
+
+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.k8snetworking.codec.K8sIpamJsonMatcher.matchesK8sIpam;
+import static org.onosproject.net.NetTestTools.APP_ID;
+
+/**
+ * Unit tests for kubernetes IPAM codec.
+ */
+public class K8sIpamCodecTest {
+
+ MockCodecContext context;
+
+ JsonCodec<K8sIpam> k8sIpamCodec;
+
+ final CoreService mockCoreService = createMock(CoreService.class);
+ private static final String REST_APP_ID = "org.onosproject.rest";
+
+ /**
+ * Initial setup for this unit test.
+ */
+ @Before
+ public void setUp() {
+ context = new MockCodecContext();
+ k8sIpamCodec = new K8sIpamCodec();
+
+ assertThat(k8sIpamCodec, notNullValue());
+
+ expect(mockCoreService.registerApplication(REST_APP_ID))
+ .andReturn(APP_ID).anyTimes();
+ replay(mockCoreService);
+ context.registerService(CoreService.class, mockCoreService);
+ }
+
+ /**
+ * Tests the kubernetes IPAM encoding.
+ */
+ @Test
+ public void testK8sIpamEncode() {
+ K8sIpam ipam = new DefaultK8sIpam(
+ IpAddress.valueOf("10.10.10.10"), "network-1");
+
+ ObjectNode nodeJson = k8sIpamCodec.encode(ipam, context);
+ assertThat(nodeJson, matchesK8sIpam(ipam));
+ }
+
+ /**
+ * Tests the kubernetes IPAM decoding.
+ */
+ @Test
+ public void testK8sIpamDecode() throws IOException {
+ K8sIpam ipam = getK8sIpam("K8sIpam.json");
+
+ assertEquals("10.10.10.2", ipam.ipAddress().toString());
+ assertEquals("network-1", ipam.networkId());
+ }
+
+ /**
+ * Reads in an kubernetes IPAM from the given resource and decodes it.
+ *
+ * @param resourceName resource to use to read the JSON for the rule
+ * @return decoded kubernetes node
+ * @throws IOException if processing the resource fails
+ */
+ private K8sIpam getK8sIpam(String resourceName) throws IOException {
+ InputStream jsonStream = K8sIpamCodecTest.class.getResourceAsStream(resourceName);
+ JsonNode json = context.mapper().readTree(jsonStream);
+ MatcherAssert.assertThat(json, notNullValue());
+ K8sIpam node = k8sIpamCodec.decode((ObjectNode) json, context);
+ assertThat(node, notNullValue());
+ return node;
+ }
+
+ /**
+ * Mock codec context for use in codec unit tests.
+ */
+ private class MockCodecContext implements CodecContext {
+ private final ObjectMapper mapper = new ObjectMapper();
+ private final CodecManager manager = new CodecManager();
+ private final Map<Class<?>, Object> services = new HashMap<>();
+
+ /**
+ * Constructs a new mock codec context.
+ */
+ public MockCodecContext() {
+ manager.activate();
+ }
+
+ @Override
+ public ObjectMapper mapper() {
+ return mapper;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> JsonCodec<T> codec(Class<T> entityClass) {
+ if (entityClass == K8sIpam.class) {
+ return (JsonCodec<T>) k8sIpamCodec;
+ }
+ return manager.getCodec(entityClass);
+ }
+
+ @SuppressWarnings("unchecked")
+ @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/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sIpamJsonMatcher.java b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sIpamJsonMatcher.java
new file mode 100644
index 0000000..81bbf10
--- /dev/null
+++ b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sIpamJsonMatcher.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2019-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.k8snetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onosproject.k8snetworking.api.K8sIpam;
+
+/**
+ * Hamcrest matcher for kubernetes IPAM.
+ */
+public final class K8sIpamJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+ private final K8sIpam ipam;
+
+ private static final String IP_ADDRESS = "ipAddress";
+ private static final String NETWORK_ID = "networkId";
+
+ private K8sIpamJsonMatcher(K8sIpam ipam) {
+ this.ipam = ipam;
+ }
+
+ @Override
+ protected boolean matchesSafely(JsonNode jsonNode, Description description) {
+
+ // check IP address
+ String jsonIpAddress = jsonNode.get(IP_ADDRESS).asText();
+ String ipAddress = ipam.ipAddress().toString();
+ if (!jsonIpAddress.equals(ipAddress)) {
+ description.appendText("IP address was " + jsonIpAddress);
+ return false;
+ }
+
+ // check network ID
+ String jsonNetworkId = jsonNode.get(NETWORK_ID).asText();
+ String networkId = ipam.networkId();
+ if (!jsonNetworkId.equals(networkId)) {
+ description.appendText("Network ID was " + jsonNetworkId);
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(ipam.toString());
+ }
+
+ /**
+ * Factory to allocate kubernetes IPAM matcher.
+ *
+ * @param ipam kubernetes IPAM object we are looking for
+ * @return matcher
+ */
+ public static K8sIpamJsonMatcher matchesK8sIpam(K8sIpam ipam) {
+ return new K8sIpamJsonMatcher(ipam);
+ }
+}
diff --git a/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkCodecTest.java b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkCodecTest.java
new file mode 100644
index 0000000..9d7fd99
--- /dev/null
+++ b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkCodecTest.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2019-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.k8snetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+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.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.codec.impl.CodecManager;
+import org.onosproject.core.CoreService;
+import org.onosproject.k8snetworking.api.DefaultK8sNetwork;
+import org.onosproject.k8snetworking.api.K8sNetwork;
+
+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.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.onosproject.k8snetworking.codec.K8sNetworkJsonMatcher.matchesK8sNetwork;
+import static org.onosproject.net.NetTestTools.APP_ID;
+
+/**
+ * Unit tests for kubernetes network codec.
+ */
+public class K8sNetworkCodecTest {
+
+ MockCodecContext context;
+
+ JsonCodec<K8sNetwork> k8sNetworkCodec;
+
+ final CoreService mockCoreService = createMock(CoreService.class);
+ private static final String REST_APP_ID = "org.onosproject.rest";
+
+ /**
+ * Initial setup for this unit test.
+ */
+ @Before
+ public void setUp() {
+ context = new MockCodecContext();
+ k8sNetworkCodec = new K8sNetworkCodec();
+
+ assertThat(k8sNetworkCodec, notNullValue());
+
+ expect(mockCoreService.registerApplication(REST_APP_ID))
+ .andReturn(APP_ID).anyTimes();
+ replay(mockCoreService);
+ context.registerService(CoreService.class, mockCoreService);
+ }
+
+ /**
+ * Tests the kubernetes network encoding.
+ */
+ @Test
+ public void testK8sNetworkEncode() {
+ K8sNetwork network = DefaultK8sNetwork.builder()
+ .networkId("network-1")
+ .segmentId("1")
+ .type(K8sNetwork.Type.VXLAN)
+ .gatewayIp(IpAddress.valueOf("10.10.10.1"))
+ .cidr("32")
+ .mtu(1500)
+ .build();
+
+ ObjectNode nodeJson = k8sNetworkCodec.encode(network, context);
+ assertThat(nodeJson, matchesK8sNetwork(network));
+ }
+
+ /**
+ * Tests the kubernetes network decoding.
+ */
+ @Test
+ public void testK8sNetworkDecode() throws IOException {
+ K8sNetwork network = getK8sNetwork("K8sNetwork.json");
+
+ assertEquals("network-1", network.networkId());
+ assertEquals("1", network.segmentId());
+ assertEquals("VXLAN", network.type().name());
+ assertEquals("10.10.10.1", network.gatewayIp().toString());
+ assertEquals("32", network.cidr());
+ assertThat(network.mtu(), is(1500));
+ }
+
+ /**
+ * Reads in an kubernetes network from the given resource and decodes it.
+ *
+ * @param resourceName resource to use to read the JSON for the rule
+ * @return decoded kubernetes network
+ * @throws IOException if processing the resource fails
+ */
+ private K8sNetwork getK8sNetwork(String resourceName) throws IOException {
+ InputStream jsonStream = K8sNetworkCodecTest.class.getResourceAsStream(resourceName);
+ JsonNode json = context.mapper().readTree(jsonStream);
+ MatcherAssert.assertThat(json, notNullValue());
+ K8sNetwork network = k8sNetworkCodec.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
+ @SuppressWarnings("unchecked")
+ public <T> JsonCodec<T> codec(Class<T> entityClass) {
+ if (entityClass == K8sNetwork.class) {
+ return (JsonCodec<T>) k8sNetworkCodec;
+ }
+ return manager.getCodec(entityClass);
+ }
+
+ @SuppressWarnings("unchecked")
+ @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/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkJsonMatcher.java b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkJsonMatcher.java
new file mode 100644
index 0000000..435de0f
--- /dev/null
+++ b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sNetworkJsonMatcher.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2019-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.k8snetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onosproject.k8snetworking.api.K8sNetwork;
+
+/**
+ * Hamcrest matcher for kubernetes network.
+ */
+public final class K8sNetworkJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+ private final K8sNetwork network;
+
+ private static final String NETWORK_ID = "networkId";
+ private static final String TYPE = "type";
+ private static final String MTU = "mtu";
+ private static final String SEGMENT_ID = "segmentId";
+ private static final String GATEWAY_IP = "gatewayIp";
+ private static final String CIDR = "cidr";
+
+ private K8sNetworkJsonMatcher(K8sNetwork 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 MTU
+ int jsonMtu = jsonNode.get(MTU).asInt();
+ int mtu = network.mtu();
+ if (jsonMtu != mtu) {
+ description.appendText("MTU was " + jsonMtu);
+ return false;
+ }
+
+ // check segment ID
+ String jsonSegmentId = jsonNode.get(SEGMENT_ID).asText();
+ String segmentId = network.segmentId();
+ if (!jsonSegmentId.equals(segmentId)) {
+ description.appendText("segment ID was " + jsonSegmentId);
+ 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 CIDR
+ String jsonCidr = jsonNode.get(CIDR).asText();
+ String cidr = network.cidr();
+ if (!jsonCidr.equals(cidr)) {
+ description.appendText("CIDR was " + jsonCidr);
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(network.toString());
+ }
+
+ /**
+ * Factory to allocate a kubernetes network matcher.
+ *
+ * @param network kubernetes network object we are looking for
+ * @return matcher
+ */
+ public static K8sNetworkJsonMatcher matchesK8sNetwork(K8sNetwork network) {
+ return new K8sNetworkJsonMatcher(network);
+ }
+}
diff --git a/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sPortCodecTest.java b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sPortCodecTest.java
new file mode 100644
index 0000000..cea53f2
--- /dev/null
+++ b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sPortCodecTest.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2019-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.k8snetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+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.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.k8snetworking.api.DefaultK8sPort;
+import org.onosproject.k8snetworking.api.K8sPort;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+
+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.k8snetworking.api.K8sPort.State.ACTIVE;
+import static org.onosproject.k8snetworking.codec.K8sPortJsonMatcher.matchesK8sPort;
+import static org.onosproject.net.NetTestTools.APP_ID;
+
+/**
+ * Unit tests for kubernetes port codec.
+ */
+public class K8sPortCodecTest {
+
+ MockCodecContext context;
+
+ JsonCodec<K8sPort> k8sPortCodec;
+
+ final CoreService mockCoreService = createMock(CoreService.class);
+ private static final String REST_APP_ID = "org.onosproject.rest";
+
+ /**
+ * Initial setup for this unit test.
+ */
+ @Before
+ public void setUp() {
+ context = new MockCodecContext();
+ k8sPortCodec = new K8sPortCodec();
+
+ assertThat(k8sPortCodec, notNullValue());
+
+ expect(mockCoreService.registerApplication(REST_APP_ID))
+ .andReturn(APP_ID).anyTimes();
+ replay(mockCoreService);
+ context.registerService(CoreService.class, mockCoreService);
+ }
+
+ /**
+ * Tests the kubernetes port encoding.
+ */
+ @Test
+ public void testK8sPortEncode() {
+ K8sPort port = DefaultK8sPort.builder()
+ .networkId("network-1")
+ .portId("port-1")
+ .deviceId(DeviceId.deviceId("of:0000000000000001"))
+ .ipAddress(IpAddress.valueOf("10.10.10.2"))
+ .macAddress(MacAddress.valueOf("00:11:22:33:44:55"))
+ .portNumber(PortNumber.portNumber(1))
+ .state(ACTIVE)
+ .build();
+
+ ObjectNode nodeJson = k8sPortCodec.encode(port, context);
+ assertThat(nodeJson, matchesK8sPort(port));
+ }
+
+ /**
+ * Tests the kubernetes port decoding.
+ */
+ @Test
+ public void testK8sPortDecode() throws IOException {
+ K8sPort port = getK8sPort("K8sPort.json");
+
+ assertEquals("network-1", port.networkId());
+ assertEquals("port-1", port.portId());
+ assertEquals("00:11:22:33:44:55", port.macAddress().toString());
+ assertEquals("10.10.10.10", port.ipAddress().toString());
+ assertEquals("of:0000000000000001", port.deviceId().toString());
+ assertEquals("1", port.portNumber().toString());
+ assertEquals("ACTIVE", port.state().name());
+ }
+
+ /**
+ * Reads in an kubernetes port from the given resource and decodes it.
+ *
+ * @param resourceName resource to use to read the JSON for the rule
+ * @return decoded kubernetes port
+ * @throws IOException if processing the resource fails
+ */
+ private K8sPort getK8sPort(String resourceName) throws IOException {
+ InputStream jsonStream = K8sPortCodecTest.class.getResourceAsStream(resourceName);
+ JsonNode json = context.mapper().readTree(jsonStream);
+ MatcherAssert.assertThat(json, notNullValue());
+ K8sPort port = k8sPortCodec.decode((ObjectNode) json, context);
+ assertThat(port, notNullValue());
+ return 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
+ @SuppressWarnings("unchecked")
+ public <T> JsonCodec<T> codec(Class<T> entityClass) {
+ if (entityClass == K8sPort.class) {
+ return (JsonCodec<T>) k8sPortCodec;
+ }
+ return manager.getCodec(entityClass);
+ }
+
+ @SuppressWarnings("unchecked")
+ @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/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sPortJsonMatcher.java b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sPortJsonMatcher.java
new file mode 100644
index 0000000..b0f327e
--- /dev/null
+++ b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/codec/K8sPortJsonMatcher.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2019-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.k8snetworking.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onosproject.k8snetworking.api.K8sPort;
+
+/**
+ * Hamcrest matcher for kubernetes port.
+ */
+public final class K8sPortJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+ private final K8sPort port;
+
+ private static final String NETWORK_ID = "networkId";
+ private static final String PORT_ID = "portId";
+ 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 STATE = "state";
+
+ private K8sPortJsonMatcher(K8sPort port) {
+ this.port = port;
+ }
+
+ @Override
+ protected boolean matchesSafely(JsonNode jsonNode, Description description) {
+
+ // 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 port ID
+ String jsonPortId = jsonNode.get(PORT_ID).asText();
+ String portId = port.portId();
+ if (!jsonPortId.equals(portId)) {
+ description.appendText("port ID was " + jsonPortId);
+ 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
+ String jsonIpAddress = jsonNode.get(IP_ADDRESS).asText();
+ String ipAddress = port.ipAddress().toString();
+ if (!jsonIpAddress.equals(ipAddress)) {
+ description.appendText("IP address was " + jsonIpAddress);
+ return false;
+ }
+
+ // check device ID
+ String jsonDeviceId = jsonNode.get(DEVICE_ID).asText();
+ String deviceId = port.deviceId().toString();
+ if (!jsonDeviceId.equals(deviceId)) {
+ description.appendText("device ID was " + jsonDeviceId);
+ return false;
+ }
+
+ // check port number
+ String jsonPortNumber = jsonNode.get(PORT_NUMBER).asText();
+ String portNumber = port.portNumber().toString();
+ if (!jsonPortNumber.equals(portNumber)) {
+ description.appendText("port number was " + jsonPortNumber);
+ return false;
+ }
+
+ // check state
+ String jsonState = jsonNode.get(STATE).asText();
+ String state = port.state().name();
+ if (!jsonState.equals(state)) {
+ description.appendText("state was " + jsonState);
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(port.toString());
+ }
+
+ /**
+ * Factory to allocate an kubernetes port matcher.
+ *
+ * @param port kubernetes port object we are looking for
+ * @return matcher
+ */
+ public static K8sPortJsonMatcher matchesK8sPort(K8sPort port) {
+ return new K8sPortJsonMatcher(port);
+ }
+}
diff --git a/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sIpam.json b/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sIpam.json
new file mode 100644
index 0000000..22e1c19
--- /dev/null
+++ b/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sIpam.json
@@ -0,0 +1,4 @@
+{
+ "ipAddress": "10.10.10.2",
+ "networkId": "network-1"
+}
\ No newline at end of file
diff --git a/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sNetwork.json b/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sNetwork.json
new file mode 100644
index 0000000..ce15c92
--- /dev/null
+++ b/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sNetwork.json
@@ -0,0 +1,8 @@
+{
+ "networkId": "network-1",
+ "type": "VXLAN",
+ "mtu": 1500,
+ "segmentId": "1",
+ "gatewayIp": "10.10.10.1",
+ "cidr": "32"
+}
\ No newline at end of file
diff --git a/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sPort.json b/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sPort.json
new file mode 100644
index 0000000..9c0214c
--- /dev/null
+++ b/apps/k8s-networking/app/src/test/resources/org/onosproject/k8snetworking/codec/K8sPort.json
@@ -0,0 +1,9 @@
+{
+ "networkId": "network-1",
+ "portId": "port-1",
+ "macAddress": "00:11:22:33:44:55",
+ "ipAddress": "10.10.10.10",
+ "deviceId": "of:0000000000000001",
+ "portNumber": "1",
+ "state": "ACTIVE"
+}
\ No newline at end of file