blob: a9d2c9e13eb67cbd69cbe0314a963db18e7418e5 [file] [log] [blame]
Sean Condon0e89bda2017-03-21 14:23:19 +00001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Sean Condon081290d2017-11-02 13:15:08 +000016package org.onosproject.cfm.rest;
Sean Condon0e89bda2017-03-21 14:23:19 +000017
18import java.io.InputStream;
19import java.net.URI;
20import java.util.Collection;
Sean Condon96b896d2017-12-11 12:44:29 -080021import java.util.Optional;
Sean Condon0e89bda2017-03-21 14:23:19 +000022
23import javax.ws.rs.Consumes;
24import javax.ws.rs.DELETE;
25import javax.ws.rs.GET;
26import javax.ws.rs.POST;
27import javax.ws.rs.PUT;
28import javax.ws.rs.Path;
29import javax.ws.rs.PathParam;
30import javax.ws.rs.Produces;
31import javax.ws.rs.core.MediaType;
32import javax.ws.rs.core.Response;
33
34import org.onosproject.cfm.web.MepCodec;
35import org.onosproject.codec.JsonCodec;
36import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceAssociation;
37import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
38import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
39import org.onosproject.incubator.net.l2monitoring.cfm.MepEntry;
40import org.onosproject.incubator.net.l2monitoring.cfm.MepLbCreate;
41import org.onosproject.incubator.net.l2monitoring.cfm.MepLtCreate;
42import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
43import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
44import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
45import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
46import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
47import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
48import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
49import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepService;
50import org.onosproject.rest.AbstractWebResource;
51import org.slf4j.Logger;
52import org.slf4j.LoggerFactory;
53
54import com.fasterxml.jackson.databind.JsonNode;
55import com.fasterxml.jackson.databind.ObjectMapper;
56import com.fasterxml.jackson.databind.node.ArrayNode;
57import com.fasterxml.jackson.databind.node.ObjectNode;
58
59/**
60 * Layer 2 CFM Maintenance Association Endpoint (MEP) web resource.
61 */
62@Path("md/{md_name}/ma/{ma_name}/mep")
63public class MepWebResource extends AbstractWebResource {
64 private final Logger log = LoggerFactory.getLogger(getClass());
65
66 /**
67 * Get all MEPs by MD name, MA name.
68 *
69 * @param mdName The name of a Maintenance Domain
70 * @param maName The name of a Maintenance Association belonging to the MD
71 * @return 200 OK with a list of MEPS or 500 on error
72 */
73 @GET
74 @Produces(MediaType.APPLICATION_JSON)
75 @Consumes(MediaType.APPLICATION_JSON)
76 public Response getAllMepsForMa(@PathParam("md_name") String mdName,
77 @PathParam("ma_name") String maName) {
78 log.debug("GET all Meps called for MA {}", mdName + "/" + maName);
79 try {
80 MdId mdId = MdIdCharStr.asMdId(mdName);
81 MaIdShort maId = MaIdCharStr.asMaId(maName);
82 Collection<MepEntry> mepCollection = get(CfmMepService.class).getAllMeps(mdId, maId);
83 ArrayNode an = mapper().createArrayNode();
84 an.add(codec(MepEntry.class).encode(mepCollection, this));
85 return ok(mapper().createObjectNode().set("meps", an)).build();
86 } catch (CfmConfigException e) {
87 log.error("Get all Meps on {} failed because of exception",
88 mdName + "/" + maName, e);
89 return Response.serverError().entity("{ \"failure\":\"" + e.toString() + "\" }").build();
90 }
91
92 }
93
94 /**
95 * Get MEP by MD name, MA name and Mep Id.
96 *
97 * @param mdName The name of a Maintenance Domain
98 * @param maName The name of a Maintenance Association belonging to the MD
99 * @param mepId The Id of the MEP
100 * @return 200 OK with details of the MEP or 500 on error
101 */
102 @GET
103 @Path("{mep_id}")
104 @Produces(MediaType.APPLICATION_JSON)
105 @Consumes(MediaType.APPLICATION_JSON)
106 public Response getMep(@PathParam("md_name") String mdName,
107 @PathParam("ma_name") String maName,
108 @PathParam("mep_id") short mepId) {
109 log.debug("GET called for MEP {}", mdName + "/" + maName + "/" + mepId);
110 try {
111 MdId mdId = MdIdCharStr.asMdId(mdName);
112 MaIdShort maId = MaIdCharStr.asMaId(maName);
113 MepEntry mepEntry = get(CfmMepService.class)
114 .getMep(mdId, maId, MepId.valueOf(mepId));
115 if (mepEntry == null) {
116 return Response.serverError().entity("{ \"failure\":\"MEP " +
117 mdName + "/" + maName + "/" + mepId + " not found\" }").build();
118 }
119 ObjectNode node = mapper().createObjectNode();
120 node.set("mep", codec(MepEntry.class).encode(mepEntry, this));
121 return ok(node).build();
122 } catch (CfmConfigException e) {
123 log.error("Get Mep {} failed because of exception",
124 mdName + "/" + maName + "/" + mepId, e);
125 return Response.serverError().entity("{ \"failure\":\"" + e.toString() + "\" }").build();
126 }
127 }
128
129 /**
130 * Delete MEP by MD name, MA name and Mep Id.
131 *
132 * @param mdName The name of a Maintenance Domain
133 * @param maName The name of a Maintenance Association belonging to the MD
134 * @param mepIdShort The Id of the MEP
135 * @return 200 OK or 304 if not found, or 500 on error
136 */
137 @DELETE
138 @Path("{mep_id}")
139 @Consumes(MediaType.APPLICATION_JSON)
140 @Produces(MediaType.APPLICATION_JSON)
141 public Response deleteMep(@PathParam("md_name") String mdName,
142 @PathParam("ma_name") String maName,
143 @PathParam("mep_id") short mepIdShort) {
144 log.debug("DELETE called for MEP " + mdName + "/" + maName + "/" + mepIdShort);
145 try {
146 MdId mdId = MdIdCharStr.asMdId(mdName);
147 MaIdShort maId = MaIdCharStr.asMaId(maName);
148 boolean deleted = get(CfmMepService.class)
Sean Condon96b896d2017-12-11 12:44:29 -0800149 .deleteMep(mdId, maId, MepId.valueOf(mepIdShort), Optional.empty());
Sean Condon0e89bda2017-03-21 14:23:19 +0000150 if (!deleted) {
151 return Response.notModified(mdName + "/" + maName + "/" +
152 mepIdShort + " did not exist").build();
153 } else {
154 return ok("{ \"success\":\"deleted " + mdName + "/" + maName +
155 "/" + mepIdShort + "\" }").build();
156 }
157 } catch (CfmConfigException e) {
158 log.error("Delete Mep {} failed because of exception ",
159 mdName + "/" + maName + "/" + mepIdShort, e);
160 return Response.serverError().entity("{ \"failure\":\"" +
161 e.toString() + "\" }").build();
162 }
163 }
164
165 /**
166 * Create MEP with MD name, MA name and Mep Json.
167 *
Sean Condon081290d2017-11-02 13:15:08 +0000168 * @onos.rsModel MepCreate
Sean Condon0e89bda2017-03-21 14:23:19 +0000169 * @param mdName The name of a Maintenance Domain
170 * @param maName The name of a Maintenance Association belonging to the MD
171 * @param input A JSON formatted input stream specifying the Mep parameters
172 * @return 201 Created or 304 if already exists or 500 on error
173 */
174 @POST
175 @Consumes(MediaType.APPLICATION_JSON)
176 @Produces(MediaType.APPLICATION_JSON)
177 public Response createMep(@PathParam("md_name") String mdName,
178 @PathParam("ma_name") String maName, InputStream input) {
179 log.debug("POST called to Create Mep");
180 try {
181 MdId mdId = MdIdCharStr.asMdId(mdName);
182 MaIdShort maId = MaIdCharStr.asMaId(maName);
Sean Condon3a1efef2018-02-24 13:16:03 +0000183 MaintenanceAssociation ma =
184 get(CfmMdService.class).getMaintenanceAssociation(mdId, maId)
185 .orElseThrow(() -> new IllegalArgumentException(
186 "MA " + mdName + "/" + maName + " not Found"));
Sean Condon0e89bda2017-03-21 14:23:19 +0000187
188 ObjectMapper mapper = new ObjectMapper();
189 JsonNode cfg = mapper.readTree(input);
190 JsonCodec<Mep> mepCodec = codec(Mep.class);
191
192 Mep mep = ((MepCodec) mepCodec).decode((ObjectNode) cfg, this, mdName, maName);
193
Sean Condon96b896d2017-12-11 12:44:29 -0800194 Boolean didNotExist = get(CfmMepService.class).createMep(mdId, maId, mep);
195 if (!didNotExist) {
Sean Condon0e89bda2017-03-21 14:23:19 +0000196 return Response.notModified(mdName + "/" + ma.maId() + "/" + mep.mepId() +
197 " already exists").build();
198 }
199 return Response
Sean Condon3a1efef2018-02-24 13:16:03 +0000200 .created(new URI("md/" + mdName + "/ma/" + ma.maId() +
201 "/mep/" + mep.mepId()))
202 .entity("{ \"success\":\"mep " + mdName + "/" + ma.maId() +
203 "/" + mep.mepId() + " created\" }")
Sean Condon0e89bda2017-03-21 14:23:19 +0000204 .build();
205 } catch (Exception | CfmConfigException e) {
206 log.error("Create Mep on " + mdName + "/" + maName + " failed because of exception {}",
Sean Condon3a1efef2018-02-24 13:16:03 +0000207 e);
Sean Condon0e89bda2017-03-21 14:23:19 +0000208 return Response.serverError()
209 .entity("{ \"failure\":\"" + e.toString() + "\" }")
210 .build();
211 }
212 }
213
214 /**
215 * Transmit Loopback on MEP with MD name, MA name and Mep Id.
216 *
Sean Condon081290d2017-11-02 13:15:08 +0000217 * @onos.rsModel MepLbTransmit
Sean Condon0e89bda2017-03-21 14:23:19 +0000218 * @param mdName The name of a Maintenance Domain
219 * @param maName The name of a Maintenance Association belonging to the MD
220 * @param mepIdShort The id of a MEP belonging to the MA
221 * @param input A JSON formatted input stream specifying the Mep parameters
222 * @return 202 Received with success message or 500 on error
223 */
224 @PUT
225 @Path("{mep_id}/transmit-loopback")
226 @Consumes(MediaType.APPLICATION_JSON)
227 @Produces(MediaType.APPLICATION_JSON)
228 public Response transmitLoopback(
229 @PathParam("md_name") String mdName,
230 @PathParam("ma_name") String maName,
231 @PathParam("mep_id") short mepIdShort,
232 InputStream input) {
233 log.debug("PUT called to Transmit Loopback on Mep");
234
235 MdId mdId = MdIdCharStr.asMdId(mdName);
236 MaIdShort maId = MaIdCharStr.asMaId(maName);
Sean Condon3a1efef2018-02-24 13:16:03 +0000237 MaintenanceDomain md;
238 Optional<MaintenanceDomain> mdOpt = get(CfmMdService.class).getMaintenanceDomain(mdId);
239 if (mdOpt.isPresent()) {
240 md = mdOpt.get();
241 } else {
242 return Response.serverError()
243 .entity("{ \"failure\":\"" + mdName + " does not exist\" }")
244 .build();
245 }
246 MaintenanceAssociation ma;
247 Optional<MaintenanceAssociation> maOpt = get(CfmMdService.class)
248 .getMaintenanceAssociation(mdId, maId);
249 if (maOpt.isPresent()) {
250 ma = maOpt.get();
251 } else {
252 return Response.serverError()
253 .entity("{ \"failure\":\"" + maName + " does not exist\" }")
254 .build();
255 }
Sean Condon0e89bda2017-03-21 14:23:19 +0000256
257 MepId mepId = MepId.valueOf(mepIdShort);
258
259 try {
260 ObjectMapper mapper = new ObjectMapper();
261 JsonNode cfg = mapper.readTree(input);
262 JsonCodec<MepLbCreate> mepLbCreateCodec = codec(MepLbCreate.class);
263
264 MepLbCreate lbCreate = mepLbCreateCodec.decode((ObjectNode) cfg, this);
265 get(CfmMepService.class).transmitLoopback(md.mdId(), ma.maId(), mepId, lbCreate);
266 } catch (Exception | CfmConfigException e) {
267 log.error("Transmit Loopback on " + mdName + "/" + maName +
268 "/{} failed", String.valueOf(mepIdShort), e);
269 return Response.serverError()
270 .entity("{ \"failure\":\"" + e.toString() + "\" }")
271 .build();
272 }
273
274 return Response.accepted()
275 .entity("{ \"success\":\"Loopback on MEP " + mdName + "/" + ma.maId() + "/"
276 + mepId.id() + " started\" }").build();
277 }
278
279 /**
280 * Abort Loopback on MEP with MD name, MA name and Mep Id.
281 *
282 * @param mdName The name of a Maintenance Domain
283 * @param maName The name of a Maintenance Association belonging to the MD
284 * @param mepIdShort The id of a MEP belonging to the MA
285 * @return 202 Received with success message or 500 on error
286 */
287 @PUT
288 @Path("{mep_id}/abort-loopback")
289 @Consumes(MediaType.APPLICATION_JSON)
290 @Produces(MediaType.APPLICATION_JSON)
291 public Response abortLoopback(
292 @PathParam("md_name") String mdName,
293 @PathParam("ma_name") String maName,
294 @PathParam("mep_id") short mepIdShort) {
295 log.debug("PUT called to Abort Loopback on Mep");
296
297 MdId mdId = MdIdCharStr.asMdId(mdName);
298 MaIdShort maId = MaIdCharStr.asMaId(maName);
Sean Condon3a1efef2018-02-24 13:16:03 +0000299 MaintenanceDomain md;
300 Optional<MaintenanceDomain> mdOpt = get(CfmMdService.class).getMaintenanceDomain(mdId);
301 if (mdOpt.isPresent()) {
302 md = mdOpt.get();
303 } else {
304 return Response.serverError()
305 .entity("{ \"failure\":\"" + mdName + " does not exist\" }")
306 .build();
307 }
308 MaintenanceAssociation ma;
309 Optional<MaintenanceAssociation> maOpt = get(CfmMdService.class)
310 .getMaintenanceAssociation(mdId, maId);
311 if (maOpt.isPresent()) {
312 ma = maOpt.get();
313 } else {
314 return Response.serverError()
315 .entity("{ \"failure\":\"" + maName + " does not exist\" }")
316 .build();
317 }
Sean Condon0e89bda2017-03-21 14:23:19 +0000318
319 MepId mepId = MepId.valueOf(mepIdShort);
320
321 try {
322 get(CfmMepService.class).abortLoopback(md.mdId(), ma.maId(), mepId);
323 } catch (CfmConfigException e) {
324 log.error("Abort Loopback on " + mdName + "/" + maName +
325 "/{} failed", String.valueOf(mepIdShort), e);
326 return Response.serverError()
327 .entity("{ \"failure\":\"" + e.toString() + "\" }")
328 .build();
329 }
330
331 return Response.accepted()
332 .entity("{ \"success\":\"Loopback on MEP " + mdName + "/" + ma.maId() + "/"
333 + mepId.id() + " aborted\" }").build();
334 }
335
336 /**
337 * Transmit Linktrace on MEP with MD name, MA name and Mep Id.
338 *
Sean Condon081290d2017-11-02 13:15:08 +0000339 * @onos.rsModel MepLtTransmit
Sean Condon0e89bda2017-03-21 14:23:19 +0000340 * @param mdName The name of a Maintenance Domain
341 * @param maName The name of a Maintenance Association belonging to the MD
342 * @param mepIdShort The id of a MEP belonging to the MA
343 * @param input A JSON formatted input stream specifying the Linktrace parameters
344 * @return 202 Received with success message or 500 on error
345 */
346 @PUT
347 @Path("{mep_id}/transmit-linktrace")
348 @Consumes(MediaType.APPLICATION_JSON)
349 @Produces(MediaType.APPLICATION_JSON)
350 public Response transmitLinktrace(
351 @PathParam("md_name") String mdName,
352 @PathParam("ma_name") String maName,
353 @PathParam("mep_id") short mepIdShort,
354 InputStream input) {
355 log.debug("PUT called to Transmit Linktrace on Mep");
356
357 MdId mdId = MdIdCharStr.asMdId(mdName);
358 MaIdShort maId = MaIdCharStr.asMaId(maName);
Sean Condon3a1efef2018-02-24 13:16:03 +0000359 MaintenanceDomain md;
360 Optional<MaintenanceDomain> mdOpt = get(CfmMdService.class).getMaintenanceDomain(mdId);
361 if (mdOpt.isPresent()) {
362 md = mdOpt.get();
363 } else {
364 return Response.serverError()
365 .entity("{ \"failure\":\"" + mdName + " does not exist\" }")
366 .build();
367 }
368 MaintenanceAssociation ma;
369 Optional<MaintenanceAssociation> maOpt = get(CfmMdService.class)
370 .getMaintenanceAssociation(mdId, maId);
371 if (maOpt.isPresent()) {
372 ma = maOpt.get();
373 } else {
374 return Response.serverError()
375 .entity("{ \"failure\":\"" + maName + " does not exist\" }")
376 .build();
377 }
Sean Condon0e89bda2017-03-21 14:23:19 +0000378
379 MepId mepId = MepId.valueOf(mepIdShort);
380
381 try {
382 ObjectMapper mapper = new ObjectMapper();
383 JsonNode cfg = mapper.readTree(input);
384 JsonCodec<MepLtCreate> mepLtCreateCodec = codec(MepLtCreate.class);
385
386 MepLtCreate ltCreate = mepLtCreateCodec.decode((ObjectNode) cfg, this);
387 get(CfmMepService.class).transmitLinktrace(md.mdId(), ma.maId(), mepId, ltCreate);
388 } catch (Exception | CfmConfigException e) {
389 log.error("Transmit Linktrace on " + mdName + "/" + maName +
390 "/{} failed", String.valueOf(mepIdShort), e);
391 return Response.serverError()
392 .entity("{ \"failure\":\"" + e.toString() + "\" }")
393 .build();
394 }
395
396 return Response.accepted()
397 .entity("{ \"success\":\"Linktrace on MEP " + mdName + "/" + ma.maId() + "/"
398 + mepId.id() + " started\" }").build();
399 }
400}