blob: b22ea08cb123371e40ac6176aeaf96bc96760423 [file] [log] [blame]
Ray Milkey2b217142014-12-15 09:24:24 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Ray Milkey2b217142014-12-15 09:24:24 -08003 *
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 */
Jonathan Hart9bb32ab2015-05-05 18:17:31 -070016package org.onosproject.rest.resources;
Ray Milkey2b217142014-12-15 09:24:24 -080017
Jian Lic2a542b2016-05-10 11:48:19 -070018import com.fasterxml.jackson.databind.node.ObjectNode;
Ayaka Koshibec06c89b2015-02-10 19:25:41 -080019import org.onosproject.core.ApplicationId;
20import org.onosproject.core.CoreService;
Chiara Contolia8f69ff2016-07-28 01:06:07 +090021import org.onosproject.net.intent.SinglePointToMultiPointIntent;
22import org.onosproject.net.intent.PointToPointIntent;
Ray Milkeyc95bb9d2015-01-06 10:28:24 -080023import org.onosproject.net.intent.HostToHostIntent;
Ray Milkey2b217142014-12-15 09:24:24 -080024import org.onosproject.net.intent.Intent;
Chiara Contolia8f69ff2016-07-28 01:06:07 +090025import org.onosproject.net.intent.IntentState;
Ray Milkey67c22722015-03-09 15:48:57 -070026import org.onosproject.net.intent.IntentEvent;
27import org.onosproject.net.intent.IntentListener;
Ray Milkey2b217142014-12-15 09:24:24 -080028import org.onosproject.net.intent.IntentService;
Ray Milkeyf9af43c2015-02-09 16:45:48 -080029import org.onosproject.net.intent.Key;
Jonathan Hart9bb32ab2015-05-05 18:17:31 -070030import org.onosproject.rest.AbstractWebResource;
Ray Milkey67c22722015-03-09 15:48:57 -070031import org.slf4j.Logger;
Ray Milkey2b217142014-12-15 09:24:24 -080032
Jian Lic2a542b2016-05-10 11:48:19 -070033import 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.PathParam;
39import javax.ws.rs.Produces;
40import javax.ws.rs.core.Context;
41import javax.ws.rs.core.MediaType;
42import javax.ws.rs.core.Response;
43import javax.ws.rs.core.UriBuilder;
44import javax.ws.rs.core.UriInfo;
45import java.io.IOException;
46import java.io.InputStream;
47import java.util.Objects;
48import java.util.concurrent.CountDownLatch;
49import java.util.concurrent.TimeUnit;
Ray Milkey2b217142014-12-15 09:24:24 -080050
Thomas Vachuskaf8cac482015-04-08 19:40:12 -070051import static org.onlab.util.Tools.nullIsNotFound;
Ray Milkey67c22722015-03-09 15:48:57 -070052import static org.onosproject.net.intent.IntentState.FAILED;
53import static org.onosproject.net.intent.IntentState.WITHDRAWN;
54import static org.slf4j.LoggerFactory.getLogger;
55
Ray Milkey2b217142014-12-15 09:24:24 -080056/**
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -070057 * Query, submit and withdraw network intents.
Ray Milkey2b217142014-12-15 09:24:24 -080058 */
Ray Milkey2b217142014-12-15 09:24:24 -080059@Path("intents")
60public class IntentsWebResource extends AbstractWebResource {
Ray Milkey303e6712015-07-17 14:06:21 -070061 @Context
Jian Licc730a62016-05-10 16:36:16 -070062 private UriInfo uriInfo;
Ray Milkey303e6712015-07-17 14:06:21 -070063
Ray Milkey67c22722015-03-09 15:48:57 -070064 private static final Logger log = getLogger(IntentsWebResource.class);
65 private static final int WITHDRAW_EVENT_TIMEOUT_SECONDS = 5;
66
Jian Licc730a62016-05-10 16:36:16 -070067 private static final String INTENT_NOT_FOUND = "Intent is not found";
Ray Milkey2b217142014-12-15 09:24:24 -080068
69 /**
Jian Licc730a62016-05-10 16:36:16 -070070 * Gets all intents.
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -070071 * Returns array containing all the intents in the system.
Jian Licc730a62016-05-10 16:36:16 -070072 *
73 * @return 200 OK with array of all the intents in the system
Andrea Campanella10c4adc2015-12-03 15:27:54 -080074 * @onos.rsModel Intents
Ray Milkey2b217142014-12-15 09:24:24 -080075 */
76 @GET
77 @Produces(MediaType.APPLICATION_JSON)
78 public Response getIntents() {
79 final Iterable<Intent> intents = get(IntentService.class).getIntents();
80 final ObjectNode root = encodeArray(Intent.class, "intents", intents);
Ray Milkey3f025692015-01-26 11:15:41 -080081 return ok(root).build();
Ray Milkey2b217142014-12-15 09:24:24 -080082 }
83
84 /**
Jian Licc730a62016-05-10 16:36:16 -070085 * Gets intent by application and key.
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -070086 * Returns details of the specified intent.
Jian Licc730a62016-05-10 16:36:16 -070087 *
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -070088 * @param appId application identifier
89 * @param key intent key
Jian Licc730a62016-05-10 16:36:16 -070090 * @return 200 OK with intent data
91 * @onos.rsModel Intents
Ray Milkey2b217142014-12-15 09:24:24 -080092 */
93 @GET
94 @Produces(MediaType.APPLICATION_JSON)
Ayaka Koshibec06c89b2015-02-10 19:25:41 -080095 @Path("{appId}/{key}")
Ray Milkeyf7cb4012015-07-20 13:01:07 -070096 public Response getIntentById(@PathParam("appId") String appId,
Ayaka Koshibec06c89b2015-02-10 19:25:41 -080097 @PathParam("key") String key) {
98 final ApplicationId app = get(CoreService.class).getAppId(appId);
99
100 Intent intent = get(IntentService.class).getIntent(Key.of(key, app));
101 if (intent == null) {
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700102 long numericalKey = Long.decode(key);
103 intent = get(IntentService.class).getIntent(Key.of(numericalKey, app));
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800104 }
105 nullIsNotFound(intent, INTENT_NOT_FOUND);
106
Ray Milkeyc95bb9d2015-01-06 10:28:24 -0800107 final ObjectNode root;
108 if (intent instanceof HostToHostIntent) {
109 root = codec(HostToHostIntent.class).encode((HostToHostIntent) intent, this);
110 } else if (intent instanceof PointToPointIntent) {
111 root = codec(PointToPointIntent.class).encode((PointToPointIntent) intent, this);
Chiara Contolia8f69ff2016-07-28 01:06:07 +0900112 } else if (intent instanceof SinglePointToMultiPointIntent) {
113 root = codec(SinglePointToMultiPointIntent.class).encode((SinglePointToMultiPointIntent) intent, this);
Ray Milkeyc95bb9d2015-01-06 10:28:24 -0800114 } else {
115 root = codec(Intent.class).encode(intent, this);
116 }
Ray Milkey3f025692015-01-26 11:15:41 -0800117 return ok(root).build();
Ray Milkey2b217142014-12-15 09:24:24 -0800118 }
Ray Milkey67c22722015-03-09 15:48:57 -0700119
Jian Licc730a62016-05-10 16:36:16 -0700120 /**
121 * Internal listener for tracking the intent deletion events.
122 */
123 private class DeleteListener implements IntentListener {
Ray Milkey67c22722015-03-09 15:48:57 -0700124 final Key key;
125 final CountDownLatch latch;
126
Jian Licc730a62016-05-10 16:36:16 -0700127 /**
128 * Default constructor.
129 *
130 * @param key key
131 * @param latch count down latch
132 */
Ray Milkey67c22722015-03-09 15:48:57 -0700133 DeleteListener(Key key, CountDownLatch latch) {
134 this.key = key;
135 this.latch = latch;
136 }
137
138 @Override
139 public void event(IntentEvent event) {
140 if (Objects.equals(event.subject().key(), key) &&
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700141 (event.type() == IntentEvent.Type.WITHDRAWN ||
142 event.type() == IntentEvent.Type.FAILED)) {
Ray Milkey67c22722015-03-09 15:48:57 -0700143 latch.countDown();
144 }
145 }
146 }
147
148 /**
Jian Licc730a62016-05-10 16:36:16 -0700149 * Submits a new intent.
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700150 * Creates and submits intent from the JSON request.
Jian Licc730a62016-05-10 16:36:16 -0700151 *
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700152 * @param stream input JSON
153 * @return status of the request - CREATED if the JSON is correct,
154 * BAD_REQUEST if the JSON is invalid
Jian Licc730a62016-05-10 16:36:16 -0700155 * @onos.rsModel IntentHost
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700156 */
157 @POST
158 @Consumes(MediaType.APPLICATION_JSON)
159 @Produces(MediaType.APPLICATION_JSON)
160 public Response createIntent(InputStream stream) {
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700161 try {
162 IntentService service = get(IntentService.class);
163 ObjectNode root = (ObjectNode) mapper().readTree(stream);
164 Intent intent = codec(Intent.class).decode(root, this);
165 service.submit(intent);
Ray Milkey303e6712015-07-17 14:06:21 -0700166 UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
167 .path("intents")
Ray Milkey8d076402015-08-31 15:43:18 -0700168 .path(intent.appId().name())
Ray Milkey303e6712015-07-17 14:06:21 -0700169 .path(Long.toString(intent.id().fingerprint()));
170 return Response
171 .created(locationBuilder.build())
172 .build();
173 } catch (IOException ioe) {
174 throw new IllegalArgumentException(ioe);
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700175 }
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700176 }
177
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700178 /**
Jian Licc730a62016-05-10 16:36:16 -0700179 * Withdraws intent.
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700180 * Withdraws the specified intent from the system.
181 *
182 * @param appId application identifier
183 * @param key intent key
Jian Lic2a542b2016-05-10 11:48:19 -0700184 * @return 204 NO CONTENT
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700185 */
186 @DELETE
187 @Path("{appId}/{key}")
Jian Lic2a542b2016-05-10 11:48:19 -0700188 public Response deleteIntentById(@PathParam("appId") String appId,
Jian Licc730a62016-05-10 16:36:16 -0700189 @PathParam("key") String key) {
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700190 final ApplicationId app = get(CoreService.class).getAppId(appId);
191
192 Intent intent = get(IntentService.class).getIntent(Key.of(key, app));
193 IntentService service = get(IntentService.class);
194
195 if (intent == null) {
196 intent = service
197 .getIntent(Key.of(Long.decode(key), app));
198 }
199 if (intent == null) {
200 // No such intent. REST standards recommend a positive status code
201 // in this case.
Jian Lic2a542b2016-05-10 11:48:19 -0700202 return Response.noContent().build();
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700203 }
204
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700205 Key k = intent.key();
206
207 // set up latch and listener to track uninstall progress
208 CountDownLatch latch = new CountDownLatch(1);
209
210 IntentListener listener = new DeleteListener(k, latch);
211 service.addListener(listener);
212
213 try {
214 // request the withdraw
215 service.withdraw(intent);
216
217 try {
218 latch.await(WITHDRAW_EVENT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
219 } catch (InterruptedException e) {
220 log.info("REST Delete operation timed out waiting for intent {}", k);
221 }
222 // double check the state
223 IntentState state = service.getIntentState(k);
224 if (state == WITHDRAWN || state == FAILED) {
225 service.purge(intent);
226 }
227
228 } finally {
229 // clean up the listener
230 service.removeListener(listener);
231 }
Jian Lic2a542b2016-05-10 11:48:19 -0700232 return Response.noContent().build();
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700233 }
Ray Milkey2b217142014-12-15 09:24:24 -0800234}