From b34f82bf11934fc6b938ef997d536a7ccea76c36 Mon Sep 17 00:00:00 2001 From: Ashlee Young Date: Thu, 5 Nov 2015 14:00:42 -0800 Subject: Updates ONOS tree to checkin id ca9cc8e28eba18da77f4fa021fb7c3a3f76e5d44 upstream. Change-Id: I49f8e41733afea8101ec50c0102213c8d18949ae Signed-off-by: Ashlee Young --- .../resources/FlowClassifierWebResource.java | 8 +- .../vtnweb/resources/PortChainWebResource.java | 157 ++++++++++++++++++++ .../vtnweb/resources/PortPairGroupWebResource.java | 163 +++++++++++++++++++++ .../vtnweb/resources/PortPairWebResource.java | 161 ++++++++++++++++++++ .../vtnweb/web/FlowClassifierCodec.java | 134 +++++++++++++++++ .../org/onosproject/vtnweb/web/PortChainCodec.java | 6 +- .../org/onosproject/vtnweb/web/PortPairCodec.java | 94 ++++++++++++ .../onosproject/vtnweb/web/PortPairGroupCodec.java | 95 ++++++++++++ .../vtn/vtnweb/src/main/webapp/WEB-INF/web.xml | 4 + .../onosproject/vtnweb/web/PortPairCodecTest.java | 94 ++++++++++++ .../onosproject/vtnweb/web/SfcCodecContext.java | 77 ++++++++++ .../org/onosproject/vtnweb/web/portPair.json | 9 ++ 12 files changed, 995 insertions(+), 7 deletions(-) create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/PortChainWebResource.java create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/PortPairGroupWebResource.java create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/PortPairWebResource.java create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/FlowClassifierCodec.java create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortPairCodec.java create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortPairGroupCodec.java create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/test/java/org/onosproject/vtnweb/web/PortPairCodecTest.java create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/test/java/org/onosproject/vtnweb/web/SfcCodecContext.java create mode 100644 framework/src/onos/apps/vtn/vtnweb/src/test/resources/org/onosproject/vtnweb/web/portPair.json (limited to 'framework/src/onos/apps/vtn/vtnweb') diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/FlowClassifierWebResource.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/FlowClassifierWebResource.java index 1450e4ef..b5b8252b 100644 --- a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/FlowClassifierWebResource.java +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/FlowClassifierWebResource.java @@ -40,7 +40,7 @@ import org.onosproject.vtnrsc.FlowClassifier; import org.onosproject.vtnrsc.FlowClassifierId; import org.onosproject.rest.AbstractWebResource; import org.onosproject.vtnrsc.flowClassifier.FlowClassifierService; -import org.onosproject.vtnrsc.web.FlowClassifierCodec; +import org.onosproject.vtnweb.web.FlowClassifierCodec; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -82,11 +82,11 @@ public class FlowClassifierWebResource extends AbstractWebResource { @Produces(MediaType.APPLICATION_JSON) public Response getFlowClassifier(@PathParam("flow_id") String id) { - if (!service.hasFlowClassifier(FlowClassifierId.flowClassifierId(UUID.fromString(id)))) { + if (!service.hasFlowClassifier(FlowClassifierId.of(UUID.fromString(id)))) { return Response.status(NOT_FOUND).entity(FLOW_CLASSIFIER_NOT_FOUND).build(); } FlowClassifier flowClassifier = nullIsNotFound( - service.getFlowClassifier(FlowClassifierId.flowClassifierId(UUID.fromString(id))), + service.getFlowClassifier(FlowClassifierId.of(UUID.fromString(id))), FLOW_CLASSIFIER_NOT_FOUND); ObjectNode result = new ObjectMapper().createObjectNode(); @@ -182,7 +182,7 @@ public class FlowClassifierWebResource extends AbstractWebResource { @DELETE public Response deleteFlowClassifier(@PathParam("flow_id") String id) throws IOException { try { - FlowClassifierId flowClassifierId = FlowClassifierId.flowClassifierId(UUID.fromString(id)); + FlowClassifierId flowClassifierId = FlowClassifierId.of(UUID.fromString(id)); service.removeFlowClassifier(flowClassifierId); return Response.status(201).entity("SUCCESS").build(); } catch (Exception e) { diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/PortChainWebResource.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/PortChainWebResource.java new file mode 100644 index 00000000..db12bcc7 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/PortChainWebResource.java @@ -0,0 +1,157 @@ +/* + * Copyright 2014-2015 Open Networking Laboratory + * + * 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.vtnweb.resources; + +import static javax.ws.rs.core.Response.Status.NOT_FOUND; +import static javax.ws.rs.core.Response.Status.OK; +import static org.onlab.util.Tools.nullIsNotFound; + +import java.io.IOException; +import java.io.InputStream; + +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 org.onosproject.rest.AbstractWebResource; +import org.onosproject.vtnrsc.PortChain; +import org.onosproject.vtnrsc.PortChainId; +import org.onosproject.vtnrsc.portchain.PortChainService; +import org.onosproject.vtnweb.web.PortChainCodec; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Query and program port chain. + */ + +@Path("port_chains") +public class PortChainWebResource extends AbstractWebResource { + + private final Logger log = LoggerFactory.getLogger(PortChainWebResource.class); + private final PortChainService service = get(PortChainService.class); + public static final String PORT_CHAIN_NOT_FOUND = "Port chain not found"; + public static final String PORT_CHAIN_ID_EXIST = "Port chain exists"; + public static final String PORT_CHAIN_ID_NOT_EXIST = "Port chain does not exist with identifier"; + + /** + * Get details of all port chains created. + * + * @return 200 OK + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public Response getPortChains() { + Iterable portChains = service.getPortChains(); + ObjectNode result = new ObjectMapper().createObjectNode(); + result.set("port_chains", new PortChainCodec().encode(portChains, this)); + return ok(result).build(); + } + + /** + * Get details of a specified port chain id. + * + * @param id port chain id + * @return 200 OK, 404 if given identifier does not exist + */ + @GET + @Path("{chain_id}") + @Produces(MediaType.APPLICATION_JSON) + public Response getPortPain(@PathParam("chain_id") String id) { + + if (!service.exists(PortChainId.of(id))) { + return Response.status(NOT_FOUND).entity(PORT_CHAIN_NOT_FOUND).build(); + } + PortChain portChain = nullIsNotFound(service.getPortChain(PortChainId.of(id)), + PORT_CHAIN_NOT_FOUND); + ObjectNode result = new ObjectMapper().createObjectNode(); + result.set("port_chain", new PortChainCodec().encode(portChain, this)); + return ok(result).build(); + } + + /** + * Creates a new port chain. + * + * @param stream port chain from JSON + * @return status of the request - CREATED if the JSON is correct, + * BAD_REQUEST if the JSON is invalid + */ + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response createPortChain(InputStream stream) { + try { + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream); + PortChain portChain = codec(PortChain.class).decode(jsonTree, this); + Boolean issuccess = nullIsNotFound(service.createPortChain(portChain), PORT_CHAIN_NOT_FOUND); + return Response.status(OK).entity(issuccess.toString()).build(); + } catch (IOException e) { + log.error("Exception while creating port chain {}.", e.toString()); + throw new IllegalArgumentException(e); + } + } + + /** + * Update details of a specified port chain id. + * + * @param id port chain id + * @param stream port chain json + * @return 200 OK, 404 if given identifier does not exist + */ + @PUT + @Path("{chain_id}") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public Response updatePortPain(@PathParam("chain_id") String id, + final InputStream stream) { + try { + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream); + PortChain portChain = codec(PortChain.class).decode(jsonTree, this); + Boolean result = nullIsNotFound(service.updatePortChain(portChain), PORT_CHAIN_NOT_FOUND); + return Response.status(OK).entity(result.toString()).build(); + } catch (IOException e) { + log.error("Update port chain failed because of exception {}.", e.toString()); + throw new IllegalArgumentException(e); + } + } + + /** + * Delete details of a specified port chain id. + * + * @param id port chain id + */ + @Path("{chain_id}") + @DELETE + public void deletePortPain(@PathParam("chain_id") String id) { + log.debug("Deletes port chain by identifier {}.", id); + PortChainId portChainId = PortChainId.of(id); + + Boolean issuccess = nullIsNotFound(service.removePortChain(portChainId), PORT_CHAIN_NOT_FOUND); + if (!issuccess) { + log.debug("Port Chain identifier {} does not exist", id); + } + } +} diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/PortPairGroupWebResource.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/PortPairGroupWebResource.java new file mode 100644 index 00000000..69daad37 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/PortPairGroupWebResource.java @@ -0,0 +1,163 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * 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.vtnweb.resources; + +import static javax.ws.rs.core.Response.Status.NOT_FOUND; +import static javax.ws.rs.core.Response.Status.OK; +import static org.onlab.util.Tools.nullIsNotFound; + +import java.io.IOException; +import java.io.InputStream; + +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 org.onosproject.rest.AbstractWebResource; +import org.onosproject.vtnrsc.PortPairGroup; +import org.onosproject.vtnrsc.PortPairGroupId; +import org.onosproject.vtnrsc.portpairgroup.PortPairGroupService; +import org.onosproject.vtnweb.web.PortPairGroupCodec; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Query and program port pair group. + */ + +@Path("port_pair_groups") +public class PortPairGroupWebResource extends AbstractWebResource { + + private final Logger log = LoggerFactory.getLogger(PortPairGroupWebResource.class); + private final PortPairGroupService service = get(PortPairGroupService.class); + public static final String PORT_PAIR_GROUP_NOT_FOUND = "Port pair group not found"; + public static final String PORT_PAIR_GROUP_ID_EXIST = "Port pair group exists"; + public static final String PORT_PAIR_GROUP_ID_NOT_EXIST = "Port pair group does not exist with identifier"; + + /** + * Get details of all port pair groups created. + * + * @return 200 OK + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public Response getPortPairGroups() { + Iterable portPairGroups = service.getPortPairGroups(); + ObjectNode result = new ObjectMapper().createObjectNode(); + result.set("port_pair_groups", new PortPairGroupCodec().encode(portPairGroups, this)); + return ok(result).build(); + } + + /** + * Get details of a specified port pair group id. + * + * @param id port pair group id + * @return 200 OK, 404 if given identifier does not exist + */ + @GET + @Path("{group_id}") + @Produces(MediaType.APPLICATION_JSON) + public Response getPortPairGroup(@PathParam("group_id") String id) { + + if (!service.exists(PortPairGroupId.of(id))) { + return Response.status(NOT_FOUND) + .entity(PORT_PAIR_GROUP_NOT_FOUND).build(); + } + PortPairGroup portPairGroup = nullIsNotFound(service.getPortPairGroup(PortPairGroupId.of(id)), + PORT_PAIR_GROUP_NOT_FOUND); + + ObjectNode result = new ObjectMapper().createObjectNode(); + result.set("port_pair_group", new PortPairGroupCodec().encode(portPairGroup, this)); + return ok(result).build(); + } + + /** + * Creates a new port pair group. + * + * @param stream port pair group from JSON + * @return status of the request - CREATED if the JSON is correct, + * BAD_REQUEST if the JSON is invalid + */ + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response createPortPairGroup(InputStream stream) { + + try { + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream); + + PortPairGroup portPairGroup = codec(PortPairGroup.class).decode(jsonTree, this); + Boolean issuccess = nullIsNotFound(service.createPortPairGroup(portPairGroup), + PORT_PAIR_GROUP_NOT_FOUND); + return Response.status(OK).entity(issuccess.toString()).build(); + } catch (IOException e) { + log.error("Exception while creating port pair group {}.", e.toString()); + throw new IllegalArgumentException(e); + } + } + + /** + * Update details of a specified port pair group id. + * + * @param id port pair group id + * @param stream port pair group from json + * @return 200 OK, 404 if given identifier does not exist + */ + @PUT + @Path("{group_id}") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public Response updatePortPairGroup(@PathParam("group_id") String id, + final InputStream stream) { + try { + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream); + PortPairGroup portPairGroup = codec(PortPairGroup.class).decode(jsonTree, this); + Boolean isSuccess = nullIsNotFound(service.updatePortPairGroup(portPairGroup), PORT_PAIR_GROUP_NOT_FOUND); + return Response.status(OK).entity(isSuccess.toString()).build(); + } catch (IOException e) { + log.error("Update port pair group failed because of exception {}.", e.toString()); + throw new IllegalArgumentException(e); + } + } + + /** + * Delete details of a specified port pair group id. + * + * @param id port pair group id + */ + @Path("{group_id}") + @DELETE + public void deletePortPairGroup(@PathParam("group_id") String id) { + log.debug("Deletes port pair group by identifier {}.", id); + PortPairGroupId portPairGroupId = PortPairGroupId.of(id); + Boolean issuccess = nullIsNotFound(service.removePortPairGroup(portPairGroupId), + PORT_PAIR_GROUP_NOT_FOUND); + if (!issuccess) { + log.debug("Port pair group identifier {} does not exist", id); + } + } +} diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/PortPairWebResource.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/PortPairWebResource.java new file mode 100644 index 00000000..8bf459c2 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/resources/PortPairWebResource.java @@ -0,0 +1,161 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * 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.vtnweb.resources; + +import static javax.ws.rs.core.Response.Status.NOT_FOUND; +import static javax.ws.rs.core.Response.Status.OK; +import static org.onlab.util.Tools.nullIsNotFound; + +import java.io.IOException; +import java.io.InputStream; + +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 org.onosproject.rest.AbstractWebResource; +import org.onosproject.vtnrsc.PortPair; +import org.onosproject.vtnrsc.PortPairId; +import org.onosproject.vtnrsc.portpair.PortPairService; +import org.onosproject.vtnweb.web.PortPairCodec; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Query and program port pair. + */ +@Path("port_pairs") +public class PortPairWebResource extends AbstractWebResource { + + private final Logger log = LoggerFactory.getLogger(PortPairWebResource.class); + private final PortPairService service = get(PortPairService.class); + public static final String PORT_PAIR_NOT_FOUND = "Port pair not found"; + public static final String PORT_PAIR_ID_EXIST = "Port pair exists"; + public static final String PORT_PAIR_ID_NOT_EXIST = "Port pair does not exist with identifier"; + + /** + * Get details of all port pairs created. + * + * @return 200 OK + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public Response getPortPairs() { + Iterable portPairs = service.getPortPairs(); + ObjectNode result = new ObjectMapper().createObjectNode(); + result.set("port_pairs", new PortPairCodec().encode(portPairs, this)); + return ok(result).build(); + } + + /** + * Get details of a specified port pair id. + * + * @param id port pair id + * @return 200 OK, 404 if given identifier does not exist + */ + @GET + @Path("{pair_id}") + @Produces(MediaType.APPLICATION_JSON) + public Response getPortPair(@PathParam("portPairId") String id) { + + if (!service.exists(PortPairId.of(id))) { + return Response.status(NOT_FOUND) + .entity(PORT_PAIR_NOT_FOUND).build(); + } + PortPair portPair = nullIsNotFound(service.getPortPair(PortPairId.of(id)), + PORT_PAIR_NOT_FOUND); + + ObjectNode result = new ObjectMapper().createObjectNode(); + result.set("port_pair", new PortPairCodec().encode(portPair, this)); + return ok(result).build(); + } + + /** + * Creates a new port pair. + * + * @param stream port pair from JSON + * @return status of the request - CREATED if the JSON is correct, + * BAD_REQUEST if the JSON is invalid + */ + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response createPortPair(InputStream stream) { + try { + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream); + + PortPair portPair = codec(PortPair.class).decode(jsonTree, this); + Boolean isSuccess = nullIsNotFound(service.createPortPair(portPair), + PORT_PAIR_NOT_FOUND); + return Response.status(OK).entity(isSuccess.toString()).build(); + } catch (IOException e) { + log.error("Exception while creating port pair {}.", e.toString()); + throw new IllegalArgumentException(e); + } + } + + /** + * Update details of a specified port pair id. + * + * @param id port pair id + * @param stream port pair from json + * @return 200 OK, 404 if the given identifier does not exist + */ + @PUT + @Path("{pair_id}") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public Response updatePortPair(@PathParam("pair_id") String id, + final InputStream stream) { + try { + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream); + PortPair portPair = codec(PortPair.class).decode(jsonTree, this); + Boolean isSuccess = nullIsNotFound(service.updatePortPair(portPair), PORT_PAIR_NOT_FOUND); + return Response.status(OK).entity(isSuccess.toString()).build(); + } catch (IOException e) { + log.error("Update port pair failed because of exception {}.", e.toString()); + throw new IllegalArgumentException(e); + } + } + + /** + * Delete details of a specified port pair id. + * + * @param id port pair id + */ + @Path("{pair_id}") + @DELETE + public void deletePortPair(@PathParam("pair_id") String id) { + + PortPairId portPairId = PortPairId.of(id); + Boolean isSuccess = nullIsNotFound(service.removePortPair(portPairId), + PORT_PAIR_NOT_FOUND); + if (!isSuccess) { + log.debug("Port pair identifier {} does not exist", id); + } + } +} diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/FlowClassifierCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/FlowClassifierCodec.java new file mode 100644 index 00000000..4c17633c --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/FlowClassifierCodec.java @@ -0,0 +1,134 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * 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.vtnweb.web; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onlab.util.Tools.nullIsIllegal; + +import java.util.UUID; + +import org.onlab.packet.IpPrefix; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.vtnrsc.DefaultFlowClassifier; +import org.onosproject.vtnrsc.FlowClassifier; +import org.onosproject.vtnrsc.FlowClassifierId; +import org.onosproject.vtnrsc.VirtualPortId; +import org.onosproject.vtnrsc.TenantId; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Flow Classifier JSON codec. + */ +public final class FlowClassifierCodec extends JsonCodec { + + private static final String FLOW_CLASSIFIER_ID = "id"; + private static final String TENANT_ID = "tenant_id"; + private static final String NAME = "name"; + private static final String DESCRIPTION = "description"; + private static final String ETHER_TYPE = "etherType"; + private static final String PROTOCOL = "protocol"; + private static final String MIN_SRC_PORT_RANGE = "source_port_range_min"; + private static final String MAX_SRC_PORT_RANGE = "source_port_range_max"; + private static final String MIN_DST_PORT_RANGE = "destination_port_range_min"; + private static final String MAX_DST_PORT_RANGE = "destination_port_range_max"; + private static final String SRC_IP_PREFIX = "source_ip_prefix"; + private static final String DST_IP_PREFIX = "destination_ip_prefix"; + private static final String SRC_PORT = "logical_source_port"; + private static final String DST_PORT = "logical_destination_port"; + private static final String MISSING_MEMBER_MESSAGE = " member is required in Flow Classifier."; + + @Override + public FlowClassifier decode(ObjectNode json, CodecContext context) { + if (json == null || !json.isObject()) { + return null; + } + + FlowClassifier.Builder resultBuilder = new DefaultFlowClassifier.Builder(); + + String flowClassifierId = nullIsIllegal(json.get(FLOW_CLASSIFIER_ID), + FLOW_CLASSIFIER_ID + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setFlowClassifierId(FlowClassifierId.of(UUID.fromString(flowClassifierId))); + + String tenantId = nullIsIllegal(json.get(TENANT_ID), TENANT_ID + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setTenantId(TenantId.tenantId(tenantId)); + + String flowClassiferName = nullIsIllegal(json.get(NAME), NAME + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setName(flowClassiferName); + + String flowClassiferDescription = nullIsIllegal(json.get(DESCRIPTION), DESCRIPTION + MISSING_MEMBER_MESSAGE) + .asText(); + resultBuilder.setDescription(flowClassiferDescription); + + String etherType = nullIsIllegal(json.get(ETHER_TYPE), ETHER_TYPE + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setEtherType(etherType); + + String protocol = nullIsIllegal(json.get(PROTOCOL), PROTOCOL + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setProtocol(protocol); + + int minSrcPortRange = nullIsIllegal(json.get(MIN_SRC_PORT_RANGE), MIN_SRC_PORT_RANGE + MISSING_MEMBER_MESSAGE) + .asInt(); + resultBuilder.setMinSrcPortRange(minSrcPortRange); + + int maxSrcPortRange = nullIsIllegal(json.get(MAX_SRC_PORT_RANGE), MAX_SRC_PORT_RANGE + MISSING_MEMBER_MESSAGE) + .asInt(); + resultBuilder.setMaxSrcPortRange(maxSrcPortRange); + + int minDstPortRange = nullIsIllegal(json.get(MIN_DST_PORT_RANGE), MIN_DST_PORT_RANGE + MISSING_MEMBER_MESSAGE) + .asInt(); + resultBuilder.setMinDstPortRange(minDstPortRange); + + int maxDstPortRange = nullIsIllegal(json.get(MAX_DST_PORT_RANGE), MAX_DST_PORT_RANGE + MISSING_MEMBER_MESSAGE) + .asInt(); + resultBuilder.setMaxDstPortRange(maxDstPortRange); + + String srcIpPrefix = nullIsIllegal(json.get(SRC_IP_PREFIX), SRC_IP_PREFIX + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setSrcIpPrefix(IpPrefix.valueOf(srcIpPrefix)); + + String dstIpPrefix = nullIsIllegal(json.get(DST_IP_PREFIX), DST_IP_PREFIX + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setDstIpPrefix(IpPrefix.valueOf(dstIpPrefix)); + + String srcPort = nullIsIllegal(json.get(SRC_PORT), SRC_PORT + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setSrcPort(VirtualPortId.portId(srcPort)); + + String dstPort = nullIsIllegal(json.get(DST_PORT), DST_PORT + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setDstPort(VirtualPortId.portId(dstPort)); + + return resultBuilder.build(); + } + + @Override + public ObjectNode encode(FlowClassifier flowClassifier, CodecContext context) { + checkNotNull(flowClassifier, "flowClassifier cannot be null"); + ObjectNode result = context.mapper().createObjectNode() + .put("FLOW_CLASSIFIER_ID", flowClassifier.flowClassifierId().toString()) + .put("TENANT_ID", flowClassifier.tenantId().toString()) + .put("NAME", flowClassifier.name()) + .put("DESCRIPTION", flowClassifier.description()) + .put("ETHER_TYPE", flowClassifier.etherType()) + .put("PROTOCOL", flowClassifier.protocol()) + .put("MIN_SRC_PORT_RANGE", flowClassifier.minSrcPortRange()) + .put("MAX_SRC_PORT_RANGE", flowClassifier.maxSrcPortRange()) + .put("MIN_DST_PORT_RANGE", flowClassifier.minDstPortRange()) + .put("MAX_DST_PORT_RANGE", flowClassifier.maxDstPortRange()) + .put("SRC_IP_PREFIX", flowClassifier.srcIpPrefix().toString()) + .put("DST_IP_PREFIX", flowClassifier.dstIpPrefix().toString()) + .put("SRC_PORT", flowClassifier.srcPort().toString()) + .put("DST_PORT", flowClassifier.dstPort().toString()); + return result; + } +} diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortChainCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortChainCodec.java index 28da5cd1..1e9cf009 100644 --- a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortChainCodec.java +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortChainCodec.java @@ -59,7 +59,7 @@ public final class PortChainCodec extends JsonCodec { String id = nullIsIllegal(json.get(ID), ID + MISSING_MEMBER_MESSAGE).asText(); - resultBuilder.setId(PortChainId.portChainId(id)); + resultBuilder.setId(PortChainId.of(id)); String tenantId = nullIsIllegal(json.get(TENANT_ID), TENANT_ID + MISSING_MEMBER_MESSAGE).asText(); @@ -76,14 +76,14 @@ public final class PortChainCodec extends JsonCodec { ArrayNode arrayNode = (ArrayNode) json.path(PORT_PAIR_GROUPS); if (arrayNode != null) { List list = Lists.newArrayList(); - arrayNode.forEach(i -> list.add(PortPairGroupId.portPairGroupId(i.asText()))); + arrayNode.forEach(i -> list.add(PortPairGroupId.of(i.asText()))); resultBuilder.setPortPairGroups(list); } arrayNode = (ArrayNode) json.path(FLOW_CLASSIFIERS); if (arrayNode != null) { List list = Lists.newArrayList(); - arrayNode.forEach(i -> list.add(FlowClassifierId.flowClassifierId(UUID.fromString(i.asText())))); + arrayNode.forEach(i -> list.add(FlowClassifierId.of(UUID.fromString(i.asText())))); resultBuilder.setFlowClassifiers(list); } diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortPairCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortPairCodec.java new file mode 100644 index 00000000..691536f4 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortPairCodec.java @@ -0,0 +1,94 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * 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.vtnweb.web; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onlab.util.Tools.nullIsIllegal; + +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.core.CoreService; +import org.onosproject.vtnrsc.DefaultPortPair; +import org.onosproject.vtnrsc.PortPair; +import org.onosproject.vtnrsc.PortPairId; +import org.onosproject.vtnrsc.TenantId; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Port Pair JSON codec. + */ +public final class PortPairCodec extends JsonCodec { + + private static final String ID = "id"; + private static final String TENANT_ID = "tenant_id"; + private static final String NAME = "name"; + private static final String DESCRIPTION = "description"; + private static final String INGRESS = "ingress"; + private static final String EGRESS = "egress"; + private static final String MISSING_MEMBER_MESSAGE = + " member is required in PortPair"; + + @Override + public PortPair decode(ObjectNode json, CodecContext context) { + if (json == null || !json.isObject()) { + return null; + } + + PortPair.Builder resultBuilder = new DefaultPortPair.Builder(); + + CoreService coreService = context.getService(CoreService.class); + + String id = nullIsIllegal(json.get(ID), + ID + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setId(PortPairId.of(id)); + + String tenantId = nullIsIllegal(json.get(TENANT_ID), + TENANT_ID + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setTenantId(TenantId.tenantId(tenantId)); + + String name = nullIsIllegal(json.get(NAME), + NAME + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setName(name); + + String description = nullIsIllegal(json.get(DESCRIPTION), + DESCRIPTION + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setDescription(description); + + String ingressPort = nullIsIllegal(json.get(INGRESS), + INGRESS + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setIngress(ingressPort); + + String egressPort = nullIsIllegal(json.get(EGRESS), + EGRESS + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setEgress(egressPort); + + return resultBuilder.build(); + } + + @Override + public ObjectNode encode(PortPair portPair, CodecContext context) { + checkNotNull(portPair, "port pair cannot be null"); + ObjectNode result = context.mapper().createObjectNode() + .put(ID, portPair.portPairId().toString()) + .put(TENANT_ID, portPair.tenantId().toString()) + .put(NAME, portPair.name()) + .put(DESCRIPTION, portPair.description()) + .put(INGRESS, portPair.ingress()) + .put(EGRESS, portPair.egress()); + return result; + } +} diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortPairGroupCodec.java b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortPairGroupCodec.java new file mode 100644 index 00000000..b5ae266b --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/java/org/onosproject/vtnweb/web/PortPairGroupCodec.java @@ -0,0 +1,95 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * 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.vtnweb.web; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onlab.util.Tools.nullIsIllegal; + +import java.util.List; + +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.core.CoreService; +import org.onosproject.vtnrsc.DefaultPortPairGroup; +import org.onosproject.vtnrsc.PortPairGroup; +import org.onosproject.vtnrsc.PortPairGroupId; +import org.onosproject.vtnrsc.PortPairId; +import org.onosproject.vtnrsc.TenantId; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.Lists; + +/** + * Port Pair Group JSON codec. + */ +public final class PortPairGroupCodec extends JsonCodec { + + private static final String ID = "id"; + private static final String TENANT_ID = "tenant_id"; + private static final String NAME = "name"; + private static final String DESCRIPTION = "description"; + private static final String PORT_PAIRS = "port_pairs"; + private static final String MISSING_MEMBER_MESSAGE = + " member is required in PortPairGroup"; + + @Override + public PortPairGroup decode(ObjectNode json, CodecContext context) { + if (json == null || !json.isObject()) { + return null; + } + + PortPairGroup.Builder resultBuilder = new DefaultPortPairGroup.Builder(); + + CoreService coreService = context.getService(CoreService.class); + + String id = nullIsIllegal(json.get(ID), + ID + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setId(PortPairGroupId.of(id)); + + String tenantId = nullIsIllegal(json.get(TENANT_ID), + TENANT_ID + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setTenantId(TenantId.tenantId(tenantId)); + + String name = nullIsIllegal(json.get(NAME), + NAME + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setName(name); + + String description = nullIsIllegal(json.get(DESCRIPTION), + DESCRIPTION + MISSING_MEMBER_MESSAGE).asText(); + resultBuilder.setDescription(description); + + List list = Lists.newArrayList(); + ArrayNode arrayNode = (ArrayNode) json.path(PORT_PAIRS); + arrayNode.forEach(i -> list.add(PortPairId.of(i.asText()))); + resultBuilder.setPortPairs(list); + + return resultBuilder.build(); + } + + @Override + public ObjectNode encode(PortPairGroup portPairGroup, CodecContext context) { + checkNotNull(portPairGroup, "port pair group cannot be null"); + ObjectNode result = context.mapper().createObjectNode() + .put(ID, portPairGroup.portPairGroupId().toString()) + .put(TENANT_ID, portPairGroup.tenantId().toString()) + .put(NAME, portPairGroup.name()) + .put(DESCRIPTION, portPairGroup.description()) + .put(PORT_PAIRS, portPairGroup.portPairs().toString()); + return result; + } +} diff --git a/framework/src/onos/apps/vtn/vtnweb/src/main/webapp/WEB-INF/web.xml b/framework/src/onos/apps/vtn/vtnweb/src/main/webapp/WEB-INF/web.xml index 4cc12455..97337960 100644 --- a/framework/src/onos/apps/vtn/vtnweb/src/main/webapp/WEB-INF/web.xml +++ b/framework/src/onos/apps/vtn/vtnweb/src/main/webapp/WEB-INF/web.xml @@ -33,6 +33,10 @@ org.onosproject.vtnweb.resources.TenantNetworkWebResource, org.onosproject.vtnweb.resources.SubnetWebResource, org.onosproject.vtnweb.resources.VirtualPortWebResource + org.onosproject.vtnweb.resources.FlowClassifierWebResource + org.onosproject.vtnweb.resources.PortChainWebResource + org.onosproject.vtnweb.resources.PortPairGroupWebResource + org.onosproject.vtnweb.resources.PortPairWebResource 1 diff --git a/framework/src/onos/apps/vtn/vtnweb/src/test/java/org/onosproject/vtnweb/web/PortPairCodecTest.java b/framework/src/onos/apps/vtn/vtnweb/src/test/java/org/onosproject/vtnweb/web/PortPairCodecTest.java new file mode 100644 index 00000000..7651e098 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/test/java/org/onosproject/vtnweb/web/PortPairCodecTest.java @@ -0,0 +1,94 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * 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.vtnweb.web; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + +import java.io.IOException; +import java.io.InputStream; + +import org.junit.Before; +import org.junit.Test; +import org.onosproject.codec.JsonCodec; +import org.onosproject.vtnrsc.PortPair; +import org.onosproject.vtnrsc.PortPairId; +import org.onosproject.vtnrsc.TenantId; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Port pair codec unit tests. + */ +public class PortPairCodecTest { + + SfcCodecContext context; + JsonCodec portPairCodec; + /** + * Sets up for each test. Creates a context and fetches the port pair + * codec. + */ + @Before + public void setUp() { + context = new SfcCodecContext(); + portPairCodec = context.codec(PortPair.class); + assertThat(portPairCodec, notNullValue()); + } + + /** + * Reads in a port pair from the given resource and decodes it. + * + * @param resourceName resource to use to read the JSON for the port pair + * @return decoded port pair + * @throws IOException if processing the resource fails + */ + private PortPair getPortPair(String resourceName) throws IOException { + InputStream jsonStream = PortPairCodecTest.class + .getResourceAsStream(resourceName); + ObjectMapper mapper = new ObjectMapper(); + JsonNode json = mapper.readTree(jsonStream); + assertThat(json, notNullValue()); + PortPair portPair = portPairCodec.decode((ObjectNode) json, context); + assertThat(portPair, notNullValue()); + return portPair; + } + + /** + * Checks that a simple port pair decodes properly. + * + * @throws IOException if the resource cannot be processed + */ + @Test + public void codecPortPairTest() throws IOException { + + PortPair portPair = getPortPair("portPair.json"); + + assertThat(portPair, notNullValue()); + + PortPairId portPairId = PortPairId.of("78dcd363-fc23-aeb6-f44b-56dc5e2fb3ae"); + TenantId tenantId = TenantId.tenantId("d382007aa9904763a801f68ecf065cf5"); + + assertThat(portPair.portPairId().toString(), is(portPairId.toString())); + assertThat(portPair.name(), is("PP1")); + assertThat(portPair.tenantId().toString(), is(tenantId.toString())); + assertThat(portPair.description(), is("SF-A")); + assertThat(portPair.ingress().toString(), is("dace4513-24fc-4fae-af4b-321c5e2eb3d1")); + assertThat(portPair.egress().toString(), is("aef3478a-4a56-2a6e-cd3a-9dee4e2ec345")); + } +} diff --git a/framework/src/onos/apps/vtn/vtnweb/src/test/java/org/onosproject/vtnweb/web/SfcCodecContext.java b/framework/src/onos/apps/vtn/vtnweb/src/test/java/org/onosproject/vtnweb/web/SfcCodecContext.java new file mode 100644 index 00000000..fe9d7995 --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/test/java/org/onosproject/vtnweb/web/SfcCodecContext.java @@ -0,0 +1,77 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * 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.vtnweb.web; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.vtnrsc.FlowClassifier; +import org.onosproject.vtnrsc.PortChain; +import org.onosproject.vtnrsc.PortPair; +import org.onosproject.vtnrsc.PortPairGroup; + +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * Mock codec context for use in codec unit tests. + */ +public class SfcCodecContext implements CodecContext { + + private final ObjectMapper mapper = new ObjectMapper(); + private final Map, JsonCodec> codecs = new ConcurrentHashMap<>(); + + /** + * Constructs a new mock codec context. + */ + public SfcCodecContext() { + codecs.clear(); + registerCodec(PortPair.class, new PortPairCodec()); + registerCodec(PortChain.class, new PortChainCodec()); + registerCodec(PortPairGroup.class, new PortPairGroupCodec()); + registerCodec(FlowClassifier.class, new FlowClassifierCodec()); + } + + @Override + public ObjectMapper mapper() { + return mapper; + } + + @SuppressWarnings("unchecked") + @Override + public T getService(Class serviceClass) { + // TODO + return null; + } + + /** + * Registers the specified JSON codec for the given entity class. + * + * @param entityClass entity class + * @param codec JSON codec + * @param entity type + */ + public void registerCodec(Class entityClass, JsonCodec codec) { + codecs.putIfAbsent(entityClass, codec); + } + + @SuppressWarnings("unchecked") + @Override + public JsonCodec codec(Class entityClass) { + return codecs.get(entityClass); + } +} diff --git a/framework/src/onos/apps/vtn/vtnweb/src/test/resources/org/onosproject/vtnweb/web/portPair.json b/framework/src/onos/apps/vtn/vtnweb/src/test/resources/org/onosproject/vtnweb/web/portPair.json new file mode 100644 index 00000000..f858c88c --- /dev/null +++ b/framework/src/onos/apps/vtn/vtnweb/src/test/resources/org/onosproject/vtnweb/web/portPair.json @@ -0,0 +1,9 @@ +{ + "id": "78dcd363-fc23-aeb6-f44b-56dc5e2fb3ae", + "name": "PP1", + "tenant_id": "d382007aa9904763a801f68ecf065cf5", + "description": "SF-A", + "ingress": "dace4513-24fc-4fae-af4b-321c5e2eb3d1", + "egress": "aef3478a-4a56-2a6e-cd3a-9dee4e2ec345" +} + -- cgit 1.2.3-korg