blob: ac4e525d1ef77190c06f946575cd21ae614255b7 [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
Ray Milkey86ee5e82018-04-02 15:33:07 -070059import static org.onlab.util.Tools.readTreeFromStream;
60
Sean Condon0e89bda2017-03-21 14:23:19 +000061/**
62 * Layer 2 CFM Maintenance Association Endpoint (MEP) web resource.
63 */
64@Path("md/{md_name}/ma/{ma_name}/mep")
65public class MepWebResource extends AbstractWebResource {
66 private final Logger log = LoggerFactory.getLogger(getClass());
67
68 /**
69 * Get all MEPs by MD name, MA name.
70 *
71 * @param mdName The name of a Maintenance Domain
72 * @param maName The name of a Maintenance Association belonging to the MD
73 * @return 200 OK with a list of MEPS or 500 on error
74 */
75 @GET
76 @Produces(MediaType.APPLICATION_JSON)
77 @Consumes(MediaType.APPLICATION_JSON)
78 public Response getAllMepsForMa(@PathParam("md_name") String mdName,
79 @PathParam("ma_name") String maName) {
80 log.debug("GET all Meps called for MA {}", mdName + "/" + maName);
81 try {
82 MdId mdId = MdIdCharStr.asMdId(mdName);
83 MaIdShort maId = MaIdCharStr.asMaId(maName);
84 Collection<MepEntry> mepCollection = get(CfmMepService.class).getAllMeps(mdId, maId);
85 ArrayNode an = mapper().createArrayNode();
86 an.add(codec(MepEntry.class).encode(mepCollection, this));
87 return ok(mapper().createObjectNode().set("meps", an)).build();
88 } catch (CfmConfigException e) {
89 log.error("Get all Meps on {} failed because of exception",
90 mdName + "/" + maName, e);
91 return Response.serverError().entity("{ \"failure\":\"" + e.toString() + "\" }").build();
92 }
93
94 }
95
96 /**
97 * Get MEP by MD name, MA name and Mep Id.
98 *
99 * @param mdName The name of a Maintenance Domain
100 * @param maName The name of a Maintenance Association belonging to the MD
101 * @param mepId The Id of the MEP
102 * @return 200 OK with details of the MEP or 500 on error
103 */
104 @GET
105 @Path("{mep_id}")
106 @Produces(MediaType.APPLICATION_JSON)
107 @Consumes(MediaType.APPLICATION_JSON)
108 public Response getMep(@PathParam("md_name") String mdName,
109 @PathParam("ma_name") String maName,
110 @PathParam("mep_id") short mepId) {
111 log.debug("GET called for MEP {}", mdName + "/" + maName + "/" + mepId);
112 try {
113 MdId mdId = MdIdCharStr.asMdId(mdName);
114 MaIdShort maId = MaIdCharStr.asMaId(maName);
115 MepEntry mepEntry = get(CfmMepService.class)
116 .getMep(mdId, maId, MepId.valueOf(mepId));
117 if (mepEntry == null) {
118 return Response.serverError().entity("{ \"failure\":\"MEP " +
119 mdName + "/" + maName + "/" + mepId + " not found\" }").build();
120 }
121 ObjectNode node = mapper().createObjectNode();
122 node.set("mep", codec(MepEntry.class).encode(mepEntry, this));
123 return ok(node).build();
124 } catch (CfmConfigException e) {
125 log.error("Get Mep {} failed because of exception",
126 mdName + "/" + maName + "/" + mepId, e);
127 return Response.serverError().entity("{ \"failure\":\"" + e.toString() + "\" }").build();
128 }
129 }
130
131 /**
132 * Delete MEP by MD name, MA name and Mep Id.
133 *
134 * @param mdName The name of a Maintenance Domain
135 * @param maName The name of a Maintenance Association belonging to the MD
136 * @param mepIdShort The Id of the MEP
137 * @return 200 OK or 304 if not found, or 500 on error
138 */
139 @DELETE
140 @Path("{mep_id}")
141 @Consumes(MediaType.APPLICATION_JSON)
142 @Produces(MediaType.APPLICATION_JSON)
143 public Response deleteMep(@PathParam("md_name") String mdName,
144 @PathParam("ma_name") String maName,
145 @PathParam("mep_id") short mepIdShort) {
146 log.debug("DELETE called for MEP " + mdName + "/" + maName + "/" + mepIdShort);
147 try {
148 MdId mdId = MdIdCharStr.asMdId(mdName);
149 MaIdShort maId = MaIdCharStr.asMaId(maName);
150 boolean deleted = get(CfmMepService.class)
Sean Condon96b896d2017-12-11 12:44:29 -0800151 .deleteMep(mdId, maId, MepId.valueOf(mepIdShort), Optional.empty());
Sean Condon0e89bda2017-03-21 14:23:19 +0000152 if (!deleted) {
153 return Response.notModified(mdName + "/" + maName + "/" +
154 mepIdShort + " did not exist").build();
155 } else {
156 return ok("{ \"success\":\"deleted " + mdName + "/" + maName +
157 "/" + mepIdShort + "\" }").build();
158 }
159 } catch (CfmConfigException e) {
160 log.error("Delete Mep {} failed because of exception ",
161 mdName + "/" + maName + "/" + mepIdShort, e);
162 return Response.serverError().entity("{ \"failure\":\"" +
163 e.toString() + "\" }").build();
164 }
165 }
166
167 /**
168 * Create MEP with MD name, MA name and Mep Json.
169 *
Sean Condon081290d2017-11-02 13:15:08 +0000170 * @onos.rsModel MepCreate
Sean Condon0e89bda2017-03-21 14:23:19 +0000171 * @param mdName The name of a Maintenance Domain
172 * @param maName The name of a Maintenance Association belonging to the MD
173 * @param input A JSON formatted input stream specifying the Mep parameters
174 * @return 201 Created or 304 if already exists or 500 on error
175 */
176 @POST
177 @Consumes(MediaType.APPLICATION_JSON)
178 @Produces(MediaType.APPLICATION_JSON)
179 public Response createMep(@PathParam("md_name") String mdName,
180 @PathParam("ma_name") String maName, InputStream input) {
181 log.debug("POST called to Create Mep");
182 try {
183 MdId mdId = MdIdCharStr.asMdId(mdName);
184 MaIdShort maId = MaIdCharStr.asMaId(maName);
Sean Condon3a1efef2018-02-24 13:16:03 +0000185 MaintenanceAssociation ma =
186 get(CfmMdService.class).getMaintenanceAssociation(mdId, maId)
187 .orElseThrow(() -> new IllegalArgumentException(
188 "MA " + mdName + "/" + maName + " not Found"));
Sean Condon0e89bda2017-03-21 14:23:19 +0000189
190 ObjectMapper mapper = new ObjectMapper();
Ray Milkey86ee5e82018-04-02 15:33:07 -0700191 JsonNode cfg = readTreeFromStream(mapper(), input);
Sean Condon0e89bda2017-03-21 14:23:19 +0000192 JsonCodec<Mep> mepCodec = codec(Mep.class);
193
194 Mep mep = ((MepCodec) mepCodec).decode((ObjectNode) cfg, this, mdName, maName);
195
Sean Condon96b896d2017-12-11 12:44:29 -0800196 Boolean didNotExist = get(CfmMepService.class).createMep(mdId, maId, mep);
197 if (!didNotExist) {
Sean Condon0e89bda2017-03-21 14:23:19 +0000198 return Response.notModified(mdName + "/" + ma.maId() + "/" + mep.mepId() +
199 " already exists").build();
200 }
201 return Response
Sean Condon3a1efef2018-02-24 13:16:03 +0000202 .created(new URI("md/" + mdName + "/ma/" + ma.maId() +
203 "/mep/" + mep.mepId()))
204 .entity("{ \"success\":\"mep " + mdName + "/" + ma.maId() +
205 "/" + mep.mepId() + " created\" }")
Sean Condon0e89bda2017-03-21 14:23:19 +0000206 .build();
207 } catch (Exception | CfmConfigException e) {
208 log.error("Create Mep on " + mdName + "/" + maName + " failed because of exception {}",
Sean Condon3a1efef2018-02-24 13:16:03 +0000209 e);
Sean Condon0e89bda2017-03-21 14:23:19 +0000210 return Response.serverError()
211 .entity("{ \"failure\":\"" + e.toString() + "\" }")
212 .build();
213 }
214 }
215
216 /**
217 * Transmit Loopback on MEP with MD name, MA name and Mep Id.
218 *
Sean Condon081290d2017-11-02 13:15:08 +0000219 * @onos.rsModel MepLbTransmit
Sean Condon0e89bda2017-03-21 14:23:19 +0000220 * @param mdName The name of a Maintenance Domain
221 * @param maName The name of a Maintenance Association belonging to the MD
222 * @param mepIdShort The id of a MEP belonging to the MA
223 * @param input A JSON formatted input stream specifying the Mep parameters
224 * @return 202 Received with success message or 500 on error
225 */
226 @PUT
227 @Path("{mep_id}/transmit-loopback")
228 @Consumes(MediaType.APPLICATION_JSON)
229 @Produces(MediaType.APPLICATION_JSON)
230 public Response transmitLoopback(
231 @PathParam("md_name") String mdName,
232 @PathParam("ma_name") String maName,
233 @PathParam("mep_id") short mepIdShort,
234 InputStream input) {
235 log.debug("PUT called to Transmit Loopback on Mep");
236
237 MdId mdId = MdIdCharStr.asMdId(mdName);
238 MaIdShort maId = MaIdCharStr.asMaId(maName);
Sean Condon3a1efef2018-02-24 13:16:03 +0000239 MaintenanceDomain md;
240 Optional<MaintenanceDomain> mdOpt = get(CfmMdService.class).getMaintenanceDomain(mdId);
241 if (mdOpt.isPresent()) {
242 md = mdOpt.get();
243 } else {
244 return Response.serverError()
245 .entity("{ \"failure\":\"" + mdName + " does not exist\" }")
246 .build();
247 }
248 MaintenanceAssociation ma;
249 Optional<MaintenanceAssociation> maOpt = get(CfmMdService.class)
250 .getMaintenanceAssociation(mdId, maId);
251 if (maOpt.isPresent()) {
252 ma = maOpt.get();
253 } else {
254 return Response.serverError()
255 .entity("{ \"failure\":\"" + maName + " does not exist\" }")
256 .build();
257 }
Sean Condon0e89bda2017-03-21 14:23:19 +0000258
259 MepId mepId = MepId.valueOf(mepIdShort);
260
261 try {
262 ObjectMapper mapper = new ObjectMapper();
Ray Milkey86ee5e82018-04-02 15:33:07 -0700263 JsonNode cfg = readTreeFromStream(mapper(), input);
Sean Condon0e89bda2017-03-21 14:23:19 +0000264 JsonCodec<MepLbCreate> mepLbCreateCodec = codec(MepLbCreate.class);
265
266 MepLbCreate lbCreate = mepLbCreateCodec.decode((ObjectNode) cfg, this);
267 get(CfmMepService.class).transmitLoopback(md.mdId(), ma.maId(), mepId, lbCreate);
268 } catch (Exception | CfmConfigException e) {
269 log.error("Transmit Loopback on " + mdName + "/" + maName +
270 "/{} failed", String.valueOf(mepIdShort), e);
271 return Response.serverError()
272 .entity("{ \"failure\":\"" + e.toString() + "\" }")
273 .build();
274 }
275
276 return Response.accepted()
277 .entity("{ \"success\":\"Loopback on MEP " + mdName + "/" + ma.maId() + "/"
278 + mepId.id() + " started\" }").build();
279 }
280
281 /**
282 * Abort Loopback on MEP with MD name, MA name and Mep Id.
283 *
284 * @param mdName The name of a Maintenance Domain
285 * @param maName The name of a Maintenance Association belonging to the MD
286 * @param mepIdShort The id of a MEP belonging to the MA
287 * @return 202 Received with success message or 500 on error
288 */
289 @PUT
290 @Path("{mep_id}/abort-loopback")
291 @Consumes(MediaType.APPLICATION_JSON)
292 @Produces(MediaType.APPLICATION_JSON)
293 public Response abortLoopback(
294 @PathParam("md_name") String mdName,
295 @PathParam("ma_name") String maName,
296 @PathParam("mep_id") short mepIdShort) {
297 log.debug("PUT called to Abort Loopback on Mep");
298
299 MdId mdId = MdIdCharStr.asMdId(mdName);
300 MaIdShort maId = MaIdCharStr.asMaId(maName);
Sean Condon3a1efef2018-02-24 13:16:03 +0000301 MaintenanceDomain md;
302 Optional<MaintenanceDomain> mdOpt = get(CfmMdService.class).getMaintenanceDomain(mdId);
303 if (mdOpt.isPresent()) {
304 md = mdOpt.get();
305 } else {
306 return Response.serverError()
307 .entity("{ \"failure\":\"" + mdName + " does not exist\" }")
308 .build();
309 }
310 MaintenanceAssociation ma;
311 Optional<MaintenanceAssociation> maOpt = get(CfmMdService.class)
312 .getMaintenanceAssociation(mdId, maId);
313 if (maOpt.isPresent()) {
314 ma = maOpt.get();
315 } else {
316 return Response.serverError()
317 .entity("{ \"failure\":\"" + maName + " does not exist\" }")
318 .build();
319 }
Sean Condon0e89bda2017-03-21 14:23:19 +0000320
321 MepId mepId = MepId.valueOf(mepIdShort);
322
323 try {
324 get(CfmMepService.class).abortLoopback(md.mdId(), ma.maId(), mepId);
325 } catch (CfmConfigException e) {
326 log.error("Abort Loopback on " + mdName + "/" + maName +
327 "/{} failed", String.valueOf(mepIdShort), e);
328 return Response.serverError()
329 .entity("{ \"failure\":\"" + e.toString() + "\" }")
330 .build();
331 }
332
333 return Response.accepted()
334 .entity("{ \"success\":\"Loopback on MEP " + mdName + "/" + ma.maId() + "/"
335 + mepId.id() + " aborted\" }").build();
336 }
337
338 /**
339 * Transmit Linktrace on MEP with MD name, MA name and Mep Id.
340 *
Sean Condon081290d2017-11-02 13:15:08 +0000341 * @onos.rsModel MepLtTransmit
Sean Condon0e89bda2017-03-21 14:23:19 +0000342 * @param mdName The name of a Maintenance Domain
343 * @param maName The name of a Maintenance Association belonging to the MD
344 * @param mepIdShort The id of a MEP belonging to the MA
345 * @param input A JSON formatted input stream specifying the Linktrace parameters
346 * @return 202 Received with success message or 500 on error
347 */
348 @PUT
349 @Path("{mep_id}/transmit-linktrace")
350 @Consumes(MediaType.APPLICATION_JSON)
351 @Produces(MediaType.APPLICATION_JSON)
352 public Response transmitLinktrace(
353 @PathParam("md_name") String mdName,
354 @PathParam("ma_name") String maName,
355 @PathParam("mep_id") short mepIdShort,
356 InputStream input) {
357 log.debug("PUT called to Transmit Linktrace on Mep");
358
359 MdId mdId = MdIdCharStr.asMdId(mdName);
360 MaIdShort maId = MaIdCharStr.asMaId(maName);
Sean Condon3a1efef2018-02-24 13:16:03 +0000361 MaintenanceDomain md;
362 Optional<MaintenanceDomain> mdOpt = get(CfmMdService.class).getMaintenanceDomain(mdId);
363 if (mdOpt.isPresent()) {
364 md = mdOpt.get();
365 } else {
366 return Response.serverError()
367 .entity("{ \"failure\":\"" + mdName + " does not exist\" }")
368 .build();
369 }
370 MaintenanceAssociation ma;
371 Optional<MaintenanceAssociation> maOpt = get(CfmMdService.class)
372 .getMaintenanceAssociation(mdId, maId);
373 if (maOpt.isPresent()) {
374 ma = maOpt.get();
375 } else {
376 return Response.serverError()
377 .entity("{ \"failure\":\"" + maName + " does not exist\" }")
378 .build();
379 }
Sean Condon0e89bda2017-03-21 14:23:19 +0000380
381 MepId mepId = MepId.valueOf(mepIdShort);
382
383 try {
384 ObjectMapper mapper = new ObjectMapper();
Ray Milkey86ee5e82018-04-02 15:33:07 -0700385 JsonNode cfg = readTreeFromStream(mapper, input);
Sean Condon0e89bda2017-03-21 14:23:19 +0000386 JsonCodec<MepLtCreate> mepLtCreateCodec = codec(MepLtCreate.class);
387
388 MepLtCreate ltCreate = mepLtCreateCodec.decode((ObjectNode) cfg, this);
389 get(CfmMepService.class).transmitLinktrace(md.mdId(), ma.maId(), mepId, ltCreate);
390 } catch (Exception | CfmConfigException e) {
391 log.error("Transmit Linktrace on " + mdName + "/" + maName +
392 "/{} failed", String.valueOf(mepIdShort), e);
393 return Response.serverError()
394 .entity("{ \"failure\":\"" + e.toString() + "\" }")
395 .build();
396 }
397
398 return Response.accepted()
399 .entity("{ \"success\":\"Linktrace on MEP " + mdName + "/" + ma.maId() + "/"
400 + mepId.id() + " started\" }").build();
401 }
402}