blob: 854697bb444d813163f03209dc8dfa332fca8ae1 [file] [log] [blame]
Andreas Pantelopouloscd339592018-02-23 14:18:00 -08001/*
2 * Copyright 2015-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 */
16package org.onosproject.segmentrouting.web;
17
Andreas Pantelopoulosff691b72018-03-12 16:30:20 -070018import com.fasterxml.jackson.databind.JsonNode;
Andreas Pantelopouloscd339592018-02-23 14:18:00 -080019import com.fasterxml.jackson.databind.ObjectMapper;
Andreas Pantelopoulosff691b72018-03-12 16:30:20 -070020import com.fasterxml.jackson.databind.node.ArrayNode;
Andreas Pantelopouloscd339592018-02-23 14:18:00 -080021import com.fasterxml.jackson.databind.node.ObjectNode;
Laszlo Pappc5e85bb2018-04-04 16:17:52 +010022import org.apache.commons.lang3.tuple.Pair;
Andreas Pantelopoulosff691b72018-03-12 16:30:20 -070023import org.onlab.util.ItemNotFoundException;
Andreas Pantelopouloscd339592018-02-23 14:18:00 -080024import org.onosproject.rest.AbstractWebResource;
25import org.onosproject.segmentrouting.SegmentRoutingService;
26import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelDescription;
27import org.onosproject.segmentrouting.pwaas.L2TunnelPolicy;
28import org.onosproject.segmentrouting.pwaas.L2Tunnel;
29import org.onosproject.segmentrouting.pwaas.L2TunnelHandler;
30import org.slf4j.Logger;
31import org.slf4j.LoggerFactory;
32
33import javax.ws.rs.Consumes;
34import javax.ws.rs.DELETE;
35import javax.ws.rs.GET;
36import javax.ws.rs.POST;
37import javax.ws.rs.Path;
38import javax.ws.rs.Produces;
39import javax.ws.rs.core.MediaType;
40import javax.ws.rs.core.Response;
41import java.io.IOException;
42import java.io.InputStream;
Andreas Pantelopoulosff691b72018-03-12 16:30:20 -070043import java.util.ArrayList;
Andreas Pantelopouloscd339592018-02-23 14:18:00 -080044import java.util.List;
45import java.util.stream.Collectors;
46
Andreas Pantelopoulosff691b72018-03-12 16:30:20 -070047import static org.onlab.util.Tools.nullIsIllegal;
Ray Milkey86ee5e82018-04-02 15:33:07 -070048import static org.onlab.util.Tools.readTreeFromStream;
Andreas Pantelopoulosff691b72018-03-12 16:30:20 -070049
Andreas Pantelopouloscd339592018-02-23 14:18:00 -080050/**
51 * Query, create and remove pseudowires.
52 */
53@Path("pseudowire")
54public class PseudowireWebResource extends AbstractWebResource {
55
56 private static final PseudowireCodec PSEUDOWIRE_CODEC = new PseudowireCodec();
Andreas Pantelopoulosff691b72018-03-12 16:30:20 -070057 public static final String PWS = "pseudowires";
58 private static final String PWS_KEY_ERROR = "Pseudowires key must be present.";
Andreas Pantelopouloscd339592018-02-23 14:18:00 -080059
60 private static Logger log = LoggerFactory
61 .getLogger(PseudowireWebResource.class);
62
63 /**
64 * Get all pseudowires.
65 * Returns an array of pseudowires.
66 *
67 * @return status of OK
68 */
69 @GET
70 @Produces(MediaType.APPLICATION_JSON)
71 public Response getPseudowire() {
72 SegmentRoutingService srService = get(SegmentRoutingService.class);
73
74 log.debug("Fetching pseudowires form rest api!");
75
76 List<L2TunnelPolicy> policies = srService.getL2Policies();
77 List<L2Tunnel> tunnels = srService.getL2Tunnels();
78 List<DefaultL2TunnelDescription> pseudowires = tunnels.stream()
79 .map(l2Tunnel -> {
80 L2TunnelPolicy policy = null;
81 for (L2TunnelPolicy l2Policy : policies) {
82 if (l2Policy.tunnelId() == l2Tunnel.tunnelId()) {
83 policy = l2Policy;
84 break;
85 }
86 }
87
88 // return a copy
89 return new DefaultL2TunnelDescription(l2Tunnel, policy);
90 })
91 .collect(Collectors.toList());
92
93 ObjectNode result = new ObjectMapper().createObjectNode();
94 result.set("pseudowires", new PseudowireCodec().encode(pseudowires, this));
95
96 return ok(result.toString()).build();
97 }
98
99 /**
100 * Create a new pseudowire.
101 *
102 * @param input JSON stream for pseudowire to create
103 * @return Response with appropriate status
104 * @throws IOException Throws IO exception.
105 * @onos.rsModel PseudowireCreate
106 */
107 @POST
108 @Consumes(MediaType.APPLICATION_JSON)
109 public Response createPseudowire(InputStream input) throws IOException {
110
111 ObjectMapper mapper = new ObjectMapper();
Ray Milkey86ee5e82018-04-02 15:33:07 -0700112 ObjectNode pseudowireJson = readTreeFromStream(mapper, input);
Andreas Pantelopouloscd339592018-02-23 14:18:00 -0800113 SegmentRoutingService srService = get(SegmentRoutingService.class);
114
115 DefaultL2TunnelDescription pseudowire = PSEUDOWIRE_CODEC.decode(pseudowireJson, this);
116 if (pseudowire == null) {
117 return Response.serverError().status(Response.Status.BAD_REQUEST).build();
118 }
119
Andreas Pantelopoulosffe69742018-03-20 13:58:49 -0700120 long tunId = pseudowire.l2Tunnel().tunnelId();
121 log.debug("Creating pseudowire {} from rest api!", tunId);
Andreas Pantelopouloscd339592018-02-23 14:18:00 -0800122
123 L2TunnelHandler.Result res = srService.addPseudowire(pseudowire);
124 switch (res) {
Andreas Pantelopoulosffe69742018-03-20 13:58:49 -0700125 case WRONG_PARAMETERS:
126 case CONFIGURATION_ERROR:
127 case PATH_NOT_FOUND:
128 case INTERNAL_ERROR:
129 log.error("Pseudowire {} could not be added : {}", tunId, res.getSpecificError());
Andreas Pantelopouloscd339592018-02-23 14:18:00 -0800130 return Response.serverError().status(Response.Status.INTERNAL_SERVER_ERROR).build();
Andreas Pantelopouloscd339592018-02-23 14:18:00 -0800131 case SUCCESS:
Andreas Pantelopoulosffe69742018-03-20 13:58:49 -0700132 log.info("Pseudowire {} succesfully deployed!", pseudowire.l2Tunnel().tunnelId());
Andreas Pantelopoulosff691b72018-03-12 16:30:20 -0700133 return Response.ok().build();
134 default:
135 return Response.ok().build();
136 }
137 }
138
139 /**
140 * Create a bulk of pseudowires.
141 *
142 * @param input JSON stream for pseudowires to create
143 * @return Response with appropriate status
144 * @throws IOException Throws IO exception.
145 * @onos.rsModel PseudowireCreateBulk
146 */
147 @POST
148 @Path("/bulk")
149 @Consumes(MediaType.APPLICATION_JSON)
150 public Response createPseudowiresBulk(InputStream input) throws IOException {
151
152 ObjectMapper mapper = new ObjectMapper();
Ray Milkey86ee5e82018-04-02 15:33:07 -0700153 ObjectNode pseudowireJson = readTreeFromStream(mapper, input);
Andreas Pantelopoulosff691b72018-03-12 16:30:20 -0700154 SegmentRoutingService srService = get(SegmentRoutingService.class);
155 List<DefaultL2TunnelDescription> pseudowires;
156
157 try {
158 ArrayNode pseudowiresArray = nullIsIllegal((ArrayNode) pseudowireJson.get(PWS), PWS_KEY_ERROR);
159 pseudowires = PSEUDOWIRE_CODEC.decode(pseudowiresArray, this);
160 } catch (ItemNotFoundException e) {
161 return Response.serverError().status(Response.Status.BAD_REQUEST).build();
162 }
163
164 log.debug("Creating pseudowires {} from rest api!", pseudowires);
Andreas Pantelopoulosffe69742018-03-20 13:58:49 -0700165 List<Pair<DefaultL2TunnelDescription, String>> failed = new ArrayList<>();
Andreas Pantelopoulosff691b72018-03-12 16:30:20 -0700166
Andreas Pantelopoulosffe69742018-03-20 13:58:49 -0700167 for (DefaultL2TunnelDescription pw : pseudowires) {
168 L2TunnelHandler.Result res = srService.addPseudowire(pw);
169 if (!(res == L2TunnelHandler.Result.SUCCESS)) {
170 log.trace("Could not create pseudowire {} : {}", pw.l2Tunnel().tunnelId(), res.getSpecificError());
Laszlo Pappc5e85bb2018-04-04 16:17:52 +0100171 failed.add(Pair.of(pw, res.getSpecificError()));
Andreas Pantelopoulosffe69742018-03-20 13:58:49 -0700172 }
173 }
Andreas Pantelopoulosff691b72018-03-12 16:30:20 -0700174
Andreas Pantelopoulosffe69742018-03-20 13:58:49 -0700175 if (failed.size() == 0) {
176 // all pseudowires were instantiated
177 return Response.ok().build();
178 } else {
179 PseudowireCodec pwCodec = new PseudowireCodec();
180 // some failed, need to report them to user
181 ObjectNode result = pwCodec.encodeFailedPseudowires(failed, this);
182 return Response.serverError().entity(result).build();
Andreas Pantelopouloscd339592018-02-23 14:18:00 -0800183 }
184 }
185
186 /**
187 * Delete a pseudowire.
188 *
189 * @param input JSON stream for pseudowire to delete
190 * @return Response with appropriate status
191 * @throws IOException Throws IO exception.
192 * @onos.rsModel PseudowireDelete
193 */
194 @DELETE
195 @Consumes(MediaType.APPLICATION_JSON)
196 public Response removePseudowire(InputStream input) throws IOException {
197
198 ObjectMapper mapper = new ObjectMapper();
Ray Milkey86ee5e82018-04-02 15:33:07 -0700199 ObjectNode pseudowireJson = readTreeFromStream(mapper, input);
Andreas Pantelopouloscd339592018-02-23 14:18:00 -0800200 SegmentRoutingService srService = get(SegmentRoutingService.class);
201
202 Integer pseudowireId = PSEUDOWIRE_CODEC.decodeId(pseudowireJson);
203 if (pseudowireId == null) {
204 return Response.serverError().status(Response.Status.BAD_REQUEST).build();
205 }
206
Andreas Pantelopoulosff691b72018-03-12 16:30:20 -0700207 log.debug("Deleting pseudowire {} from rest api!", pseudowireId);
Andreas Pantelopouloscd339592018-02-23 14:18:00 -0800208
209 L2TunnelHandler.Result res = srService.removePseudowire(pseudowireId);
210 switch (res) {
Andreas Pantelopoulosffe69742018-03-20 13:58:49 -0700211 case WRONG_PARAMETERS:
212 case INTERNAL_ERROR:
213 log.error("Pseudowire {} could not be removed : {}",
214 pseudowireId, res.getSpecificError());
Andreas Pantelopouloscd339592018-02-23 14:18:00 -0800215 return Response.noContent().build();
216 case SUCCESS:
Andreas Pantelopoulosff691b72018-03-12 16:30:20 -0700217 log.debug("Pseudowire {} was removed succesfully!", pseudowireId);
Andreas Pantelopouloscd339592018-02-23 14:18:00 -0800218 return Response.noContent().build();
219 default:
220 return Response.noContent().build();
221 }
222 }
Andreas Pantelopoulosff691b72018-03-12 16:30:20 -0700223
224 /**
225 * Delete a bulk of pseudowires.
226 *
227 * @param input JSON stream for pseudowires to delete
228 * @return Response with appropriate status
229 * @throws IOException Throws IO exception.
230 * @onos.rsModel PseudowireDeleteBulk
231 */
232 @DELETE
233 @Path("/bulk")
234 @Consumes(MediaType.APPLICATION_JSON)
235 public Response removePseudowiresBulk(InputStream input) throws IOException {
236
237 ObjectMapper mapper = new ObjectMapper();
Ray Milkey86ee5e82018-04-02 15:33:07 -0700238 ObjectNode pseudowireJson = readTreeFromStream(mapper, input);
Andreas Pantelopoulosff691b72018-03-12 16:30:20 -0700239 SegmentRoutingService srService = get(SegmentRoutingService.class);
240
241 List<Integer> ids = new ArrayList<>();
242
243 // try to parse all ids, if key is not present, or if an id is not an int
244 // throw an exception and stop process
245 try {
246 for (JsonNode node : pseudowireJson.withArray(PWS)) {
247 Integer idToDelete = PseudowireCodec.decodeId((ObjectNode) node);
248 if (idToDelete == null) {
249 log.error("Error when parsing pseudowire for deletion in REST API.");
250 throw new IllegalArgumentException("Id of pseudowire should be an integer!");
251 }
252 ids.add(idToDelete);
253 }
254 } catch (IllegalArgumentException e) {
255 log.error("Pseudowire ID should be an integer.");
256 return Response.serverError().status(Response.Status.BAD_REQUEST).build();
257 } catch (UnsupportedOperationException e) {
258 log.error("Pseudowires for deletion should be an array of pseudowire ids.");
259 return Response.serverError().status(Response.Status.BAD_REQUEST).build();
260 }
261
262 for (Integer pseudowireId : ids) {
263 L2TunnelHandler.Result res = srService.removePseudowire(pseudowireId);
264 switch (res) {
Andreas Pantelopoulosffe69742018-03-20 13:58:49 -0700265 case WRONG_PARAMETERS:
266 case INTERNAL_ERROR:
267 log.error("Pseudowire {} could not be removed, internal error : {}",
268 pseudowireId, res.getSpecificError());
Ray Milkeyb994f8d2018-03-14 09:55:13 -0700269 break;
Andreas Pantelopoulosff691b72018-03-12 16:30:20 -0700270 case SUCCESS:
271 log.debug("Pseudowire {} was removed succesfully!", pseudowireId);
Ray Milkeyb994f8d2018-03-14 09:55:13 -0700272 break;
Andreas Pantelopoulosff691b72018-03-12 16:30:20 -0700273 default:
274 }
275 }
276
277 return Response.noContent().build();
278 }
Andreas Pantelopouloscd339592018-02-23 14:18:00 -0800279}