blob: 6fc545159d481270f506d103cafe86916bca05f5 [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;
Ray Milkeyc95bb9d2015-01-06 10:28:24 -080021import org.onosproject.net.intent.HostToHostIntent;
Ray Milkey2b217142014-12-15 09:24:24 -080022import org.onosproject.net.intent.Intent;
Ray Milkey67c22722015-03-09 15:48:57 -070023import org.onosproject.net.intent.IntentEvent;
24import org.onosproject.net.intent.IntentListener;
Ray Milkey2b217142014-12-15 09:24:24 -080025import org.onosproject.net.intent.IntentService;
Ray Milkey67c22722015-03-09 15:48:57 -070026import org.onosproject.net.intent.IntentState;
Ray Milkeyf9af43c2015-02-09 16:45:48 -080027import org.onosproject.net.intent.Key;
Ray Milkeyc95bb9d2015-01-06 10:28:24 -080028import org.onosproject.net.intent.PointToPointIntent;
Jonathan Hart9bb32ab2015-05-05 18:17:31 -070029import org.onosproject.rest.AbstractWebResource;
Ray Milkey67c22722015-03-09 15:48:57 -070030import org.slf4j.Logger;
Ray Milkey2b217142014-12-15 09:24:24 -080031
Jian Lic2a542b2016-05-10 11:48:19 -070032import javax.ws.rs.Consumes;
33import javax.ws.rs.DELETE;
34import javax.ws.rs.GET;
35import javax.ws.rs.POST;
36import javax.ws.rs.Path;
37import javax.ws.rs.PathParam;
38import javax.ws.rs.Produces;
39import javax.ws.rs.core.Context;
40import javax.ws.rs.core.MediaType;
41import javax.ws.rs.core.Response;
42import javax.ws.rs.core.UriBuilder;
43import javax.ws.rs.core.UriInfo;
44import java.io.IOException;
45import java.io.InputStream;
46import java.util.Objects;
47import java.util.concurrent.CountDownLatch;
48import java.util.concurrent.TimeUnit;
Ray Milkey2b217142014-12-15 09:24:24 -080049
Thomas Vachuskaf8cac482015-04-08 19:40:12 -070050import static org.onlab.util.Tools.nullIsNotFound;
Ray Milkey67c22722015-03-09 15:48:57 -070051import static org.onosproject.net.intent.IntentState.FAILED;
52import static org.onosproject.net.intent.IntentState.WITHDRAWN;
53import static org.slf4j.LoggerFactory.getLogger;
54
Ray Milkey2b217142014-12-15 09:24:24 -080055/**
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -070056 * Query, submit and withdraw network intents.
Ray Milkey2b217142014-12-15 09:24:24 -080057 */
Ray Milkey2b217142014-12-15 09:24:24 -080058@Path("intents")
59public class IntentsWebResource extends AbstractWebResource {
Ray Milkey303e6712015-07-17 14:06:21 -070060 @Context
Jian Licc730a62016-05-10 16:36:16 -070061 private UriInfo uriInfo;
Ray Milkey303e6712015-07-17 14:06:21 -070062
Ray Milkey67c22722015-03-09 15:48:57 -070063 private static final Logger log = getLogger(IntentsWebResource.class);
64 private static final int WITHDRAW_EVENT_TIMEOUT_SECONDS = 5;
65
Jian Licc730a62016-05-10 16:36:16 -070066 private static final String INTENT_NOT_FOUND = "Intent is not found";
Ray Milkey2b217142014-12-15 09:24:24 -080067
68 /**
Jian Licc730a62016-05-10 16:36:16 -070069 * Gets all intents.
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -070070 * Returns array containing all the intents in the system.
Jian Licc730a62016-05-10 16:36:16 -070071 *
72 * @return 200 OK with array of all the intents in the system
Andrea Campanella10c4adc2015-12-03 15:27:54 -080073 * @onos.rsModel Intents
Ray Milkey2b217142014-12-15 09:24:24 -080074 */
75 @GET
76 @Produces(MediaType.APPLICATION_JSON)
77 public Response getIntents() {
78 final Iterable<Intent> intents = get(IntentService.class).getIntents();
79 final ObjectNode root = encodeArray(Intent.class, "intents", intents);
Ray Milkey3f025692015-01-26 11:15:41 -080080 return ok(root).build();
Ray Milkey2b217142014-12-15 09:24:24 -080081 }
82
83 /**
Jian Licc730a62016-05-10 16:36:16 -070084 * Gets intent by application and key.
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -070085 * Returns details of the specified intent.
Jian Licc730a62016-05-10 16:36:16 -070086 *
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -070087 * @param appId application identifier
88 * @param key intent key
Jian Licc730a62016-05-10 16:36:16 -070089 * @return 200 OK with intent data
90 * @onos.rsModel Intents
Ray Milkey2b217142014-12-15 09:24:24 -080091 */
92 @GET
93 @Produces(MediaType.APPLICATION_JSON)
Ayaka Koshibec06c89b2015-02-10 19:25:41 -080094 @Path("{appId}/{key}")
Ray Milkeyf7cb4012015-07-20 13:01:07 -070095 public Response getIntentById(@PathParam("appId") String appId,
Ayaka Koshibec06c89b2015-02-10 19:25:41 -080096 @PathParam("key") String key) {
97 final ApplicationId app = get(CoreService.class).getAppId(appId);
98
99 Intent intent = get(IntentService.class).getIntent(Key.of(key, app));
100 if (intent == null) {
Ray Milkeyf7cb4012015-07-20 13:01:07 -0700101 long numericalKey = Long.decode(key);
102 intent = get(IntentService.class).getIntent(Key.of(numericalKey, app));
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800103 }
104 nullIsNotFound(intent, INTENT_NOT_FOUND);
105
Ray Milkeyc95bb9d2015-01-06 10:28:24 -0800106 final ObjectNode root;
107 if (intent instanceof HostToHostIntent) {
108 root = codec(HostToHostIntent.class).encode((HostToHostIntent) intent, this);
109 } else if (intent instanceof PointToPointIntent) {
110 root = codec(PointToPointIntent.class).encode((PointToPointIntent) intent, this);
111 } else {
112 root = codec(Intent.class).encode(intent, this);
113 }
Ray Milkey3f025692015-01-26 11:15:41 -0800114 return ok(root).build();
Ray Milkey2b217142014-12-15 09:24:24 -0800115 }
Ray Milkey67c22722015-03-09 15:48:57 -0700116
Jian Licc730a62016-05-10 16:36:16 -0700117 /**
118 * Internal listener for tracking the intent deletion events.
119 */
120 private class DeleteListener implements IntentListener {
Ray Milkey67c22722015-03-09 15:48:57 -0700121 final Key key;
122 final CountDownLatch latch;
123
Jian Licc730a62016-05-10 16:36:16 -0700124 /**
125 * Default constructor.
126 *
127 * @param key key
128 * @param latch count down latch
129 */
Ray Milkey67c22722015-03-09 15:48:57 -0700130 DeleteListener(Key key, CountDownLatch latch) {
131 this.key = key;
132 this.latch = latch;
133 }
134
135 @Override
136 public void event(IntentEvent event) {
137 if (Objects.equals(event.subject().key(), key) &&
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700138 (event.type() == IntentEvent.Type.WITHDRAWN ||
139 event.type() == IntentEvent.Type.FAILED)) {
Ray Milkey67c22722015-03-09 15:48:57 -0700140 latch.countDown();
141 }
142 }
143 }
144
145 /**
Jian Licc730a62016-05-10 16:36:16 -0700146 * Submits a new intent.
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700147 * Creates and submits intent from the JSON request.
Jian Licc730a62016-05-10 16:36:16 -0700148 *
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700149 * @param stream input JSON
150 * @return status of the request - CREATED if the JSON is correct,
151 * BAD_REQUEST if the JSON is invalid
Jian Licc730a62016-05-10 16:36:16 -0700152 * @onos.rsModel IntentHost
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700153 */
154 @POST
155 @Consumes(MediaType.APPLICATION_JSON)
156 @Produces(MediaType.APPLICATION_JSON)
157 public Response createIntent(InputStream stream) {
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700158 try {
159 IntentService service = get(IntentService.class);
160 ObjectNode root = (ObjectNode) mapper().readTree(stream);
161 Intent intent = codec(Intent.class).decode(root, this);
162 service.submit(intent);
Ray Milkey303e6712015-07-17 14:06:21 -0700163 UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
164 .path("intents")
Ray Milkey8d076402015-08-31 15:43:18 -0700165 .path(intent.appId().name())
Ray Milkey303e6712015-07-17 14:06:21 -0700166 .path(Long.toString(intent.id().fingerprint()));
167 return Response
168 .created(locationBuilder.build())
169 .build();
170 } catch (IOException ioe) {
171 throw new IllegalArgumentException(ioe);
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700172 }
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700173 }
174
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700175 /**
Jian Licc730a62016-05-10 16:36:16 -0700176 * Withdraws intent.
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700177 * Withdraws the specified intent from the system.
178 *
179 * @param appId application identifier
180 * @param key intent key
Jian Lic2a542b2016-05-10 11:48:19 -0700181 * @return 204 NO CONTENT
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700182 */
183 @DELETE
184 @Path("{appId}/{key}")
Jian Lic2a542b2016-05-10 11:48:19 -0700185 public Response deleteIntentById(@PathParam("appId") String appId,
Jian Licc730a62016-05-10 16:36:16 -0700186 @PathParam("key") String key) {
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700187 final ApplicationId app = get(CoreService.class).getAppId(appId);
188
189 Intent intent = get(IntentService.class).getIntent(Key.of(key, app));
190 IntentService service = get(IntentService.class);
191
192 if (intent == null) {
193 intent = service
194 .getIntent(Key.of(Long.decode(key), app));
195 }
196 if (intent == null) {
197 // No such intent. REST standards recommend a positive status code
198 // in this case.
Jian Lic2a542b2016-05-10 11:48:19 -0700199 return Response.noContent().build();
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700200 }
201
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700202 Key k = intent.key();
203
204 // set up latch and listener to track uninstall progress
205 CountDownLatch latch = new CountDownLatch(1);
206
207 IntentListener listener = new DeleteListener(k, latch);
208 service.addListener(listener);
209
210 try {
211 // request the withdraw
212 service.withdraw(intent);
213
214 try {
215 latch.await(WITHDRAW_EVENT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
216 } catch (InterruptedException e) {
217 log.info("REST Delete operation timed out waiting for intent {}", k);
218 }
219 // double check the state
220 IntentState state = service.getIntentState(k);
221 if (state == WITHDRAWN || state == FAILED) {
222 service.purge(intent);
223 }
224
225 } finally {
226 // clean up the listener
227 service.removeListener(listener);
228 }
Jian Lic2a542b2016-05-10 11:48:19 -0700229 return Response.noContent().build();
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700230 }
Ray Milkey2b217142014-12-15 09:24:24 -0800231}