blob: 3199bcc5e33a7ddcf0702d34da3f273b5f87a254 [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
61 UriInfo uriInfo;
62
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
Ray Milkey2b217142014-12-15 09:24:24 -080066 public static final String INTENT_NOT_FOUND = "Intent is not found";
67
68 /**
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -070069 * Get all intents.
70 * Returns array containing all the intents in the system.
Andrea Campanella10c4adc2015-12-03 15:27:54 -080071 * @onos.rsModel Intents
Ray Milkey2b217142014-12-15 09:24:24 -080072 * @return array of all the intents in the system
73 */
74 @GET
75 @Produces(MediaType.APPLICATION_JSON)
76 public Response getIntents() {
77 final Iterable<Intent> intents = get(IntentService.class).getIntents();
78 final ObjectNode root = encodeArray(Intent.class, "intents", intents);
Ray Milkey3f025692015-01-26 11:15:41 -080079 return ok(root).build();
Ray Milkey2b217142014-12-15 09:24:24 -080080 }
81
82 /**
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -070083 * Get intent by application and key.
84 * Returns details of the specified intent.
Andrea Campanella10c4adc2015-12-03 15:27:54 -080085 * @onos.rsModel Intents
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -070086 * @param appId application identifier
87 * @param key intent key
Ray Milkey2b217142014-12-15 09:24:24 -080088 * @return intent data
89 */
90 @GET
91 @Produces(MediaType.APPLICATION_JSON)
Ayaka Koshibec06c89b2015-02-10 19:25:41 -080092 @Path("{appId}/{key}")
Ray Milkeyf7cb4012015-07-20 13:01:07 -070093 public Response getIntentById(@PathParam("appId") String appId,
Ayaka Koshibec06c89b2015-02-10 19:25:41 -080094 @PathParam("key") String key) {
95 final ApplicationId app = get(CoreService.class).getAppId(appId);
96
97 Intent intent = get(IntentService.class).getIntent(Key.of(key, app));
98 if (intent == null) {
Ray Milkeyf7cb4012015-07-20 13:01:07 -070099 long numericalKey = Long.decode(key);
100 intent = get(IntentService.class).getIntent(Key.of(numericalKey, app));
Ayaka Koshibec06c89b2015-02-10 19:25:41 -0800101 }
102 nullIsNotFound(intent, INTENT_NOT_FOUND);
103
Ray Milkeyc95bb9d2015-01-06 10:28:24 -0800104 final ObjectNode root;
105 if (intent instanceof HostToHostIntent) {
106 root = codec(HostToHostIntent.class).encode((HostToHostIntent) intent, this);
107 } else if (intent instanceof PointToPointIntent) {
108 root = codec(PointToPointIntent.class).encode((PointToPointIntent) intent, this);
109 } else {
110 root = codec(Intent.class).encode(intent, this);
111 }
Ray Milkey3f025692015-01-26 11:15:41 -0800112 return ok(root).build();
Ray Milkey2b217142014-12-15 09:24:24 -0800113 }
Ray Milkey67c22722015-03-09 15:48:57 -0700114
115 class DeleteListener implements IntentListener {
116 final Key key;
117 final CountDownLatch latch;
118
119 DeleteListener(Key key, CountDownLatch latch) {
120 this.key = key;
121 this.latch = latch;
122 }
123
124 @Override
125 public void event(IntentEvent event) {
126 if (Objects.equals(event.subject().key(), key) &&
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700127 (event.type() == IntentEvent.Type.WITHDRAWN ||
128 event.type() == IntentEvent.Type.FAILED)) {
Ray Milkey67c22722015-03-09 15:48:57 -0700129 latch.countDown();
130 }
131 }
132 }
133
134 /**
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700135 * Submit a new intent.
136 * Creates and submits intent from the JSON request.
Andrea Campanella10c4adc2015-12-03 15:27:54 -0800137 * @onos.rsModel IntentHost
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700138 * @param stream input JSON
139 * @return status of the request - CREATED if the JSON is correct,
140 * BAD_REQUEST if the JSON is invalid
141 */
142 @POST
143 @Consumes(MediaType.APPLICATION_JSON)
144 @Produces(MediaType.APPLICATION_JSON)
145 public Response createIntent(InputStream stream) {
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700146 try {
147 IntentService service = get(IntentService.class);
148 ObjectNode root = (ObjectNode) mapper().readTree(stream);
149 Intent intent = codec(Intent.class).decode(root, this);
150 service.submit(intent);
Ray Milkey303e6712015-07-17 14:06:21 -0700151 UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
152 .path("intents")
Ray Milkey8d076402015-08-31 15:43:18 -0700153 .path(intent.appId().name())
Ray Milkey303e6712015-07-17 14:06:21 -0700154 .path(Long.toString(intent.id().fingerprint()));
155 return Response
156 .created(locationBuilder.build())
157 .build();
158 } catch (IOException ioe) {
159 throw new IllegalArgumentException(ioe);
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700160 }
Ray Milkeyb82c42b2015-06-30 09:42:20 -0700161 }
162
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700163 /**
164 * Withdraw intent.
165 * Withdraws the specified intent from the system.
166 *
167 * @param appId application identifier
168 * @param key intent key
Jian Lic2a542b2016-05-10 11:48:19 -0700169 * @return 204 NO CONTENT
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700170 */
171 @DELETE
172 @Path("{appId}/{key}")
Jian Lic2a542b2016-05-10 11:48:19 -0700173 public Response deleteIntentById(@PathParam("appId") String appId,
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700174 @PathParam("key") String key) {
175 final ApplicationId app = get(CoreService.class).getAppId(appId);
176
177 Intent intent = get(IntentService.class).getIntent(Key.of(key, app));
178 IntentService service = get(IntentService.class);
179
180 if (intent == null) {
181 intent = service
182 .getIntent(Key.of(Long.decode(key), app));
183 }
184 if (intent == null) {
185 // No such intent. REST standards recommend a positive status code
186 // in this case.
Jian Lic2a542b2016-05-10 11:48:19 -0700187 return Response.noContent().build();
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700188 }
189
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700190 Key k = intent.key();
191
192 // set up latch and listener to track uninstall progress
193 CountDownLatch latch = new CountDownLatch(1);
194
195 IntentListener listener = new DeleteListener(k, latch);
196 service.addListener(listener);
197
198 try {
199 // request the withdraw
200 service.withdraw(intent);
201
202 try {
203 latch.await(WITHDRAW_EVENT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
204 } catch (InterruptedException e) {
205 log.info("REST Delete operation timed out waiting for intent {}", k);
206 }
207 // double check the state
208 IntentState state = service.getIntentState(k);
209 if (state == WITHDRAWN || state == FAILED) {
210 service.purge(intent);
211 }
212
213 } finally {
214 // clean up the listener
215 service.removeListener(listener);
216 }
Jian Lic2a542b2016-05-10 11:48:19 -0700217 return Response.noContent().build();
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700218 }
219
Ray Milkey2b217142014-12-15 09:24:24 -0800220}