Thomas Vachuska

Adding synchronous behaviour to the calendar REST API to wait until intent is in…

… parked state. Needs testing.

Change-Id: I218bcc7f6a1cadbf4325d5e4976a720752d26192
...@@ -16,14 +16,24 @@ ...@@ -16,14 +16,24 @@
16 package org.onlab.onos.calendar; 16 package org.onlab.onos.calendar;
17 17
18 import java.net.URI; 18 import java.net.URI;
19 +import java.util.concurrent.CountDownLatch;
20 +import java.util.concurrent.TimeUnit;
21 +
19 import org.onlab.onos.net.ConnectPoint; 22 import org.onlab.onos.net.ConnectPoint;
20 import org.onlab.onos.net.DeviceId; 23 import org.onlab.onos.net.DeviceId;
24 +import org.onlab.onos.net.intent.Intent;
25 +import org.onlab.onos.net.intent.IntentEvent;
26 +import org.onlab.onos.net.intent.IntentId;
27 +import org.onlab.onos.net.intent.IntentListener;
21 import org.onlab.onos.net.intent.IntentService; 28 import org.onlab.onos.net.intent.IntentService;
29 +import org.onlab.onos.net.intent.IntentState;
22 import org.onlab.rest.BaseResource; 30 import org.onlab.rest.BaseResource;
31 +
23 import javax.ws.rs.POST; 32 import javax.ws.rs.POST;
24 import javax.ws.rs.DELETE; 33 import javax.ws.rs.DELETE;
25 import javax.ws.rs.PathParam; 34 import javax.ws.rs.PathParam;
26 import javax.ws.rs.core.Response; 35 import javax.ws.rs.core.Response;
36 +
27 import org.onlab.onos.core.ApplicationId; 37 import org.onlab.onos.core.ApplicationId;
28 import org.onlab.onos.core.CoreService; 38 import org.onlab.onos.core.CoreService;
29 import org.onlab.onos.net.flow.DefaultTrafficSelector; 39 import org.onlab.onos.net.flow.DefaultTrafficSelector;
...@@ -31,10 +41,15 @@ import org.onlab.onos.net.flow.TrafficSelector; ...@@ -31,10 +41,15 @@ import org.onlab.onos.net.flow.TrafficSelector;
31 import org.onlab.onos.net.flow.TrafficTreatment; 41 import org.onlab.onos.net.flow.TrafficTreatment;
32 import org.onlab.onos.net.intent.PointToPointIntent; 42 import org.onlab.onos.net.intent.PointToPointIntent;
33 import org.onlab.packet.Ethernet; 43 import org.onlab.packet.Ethernet;
44 +
34 import static org.onlab.onos.net.PortNumber.portNumber; 45 import static org.onlab.onos.net.PortNumber.portNumber;
35 import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder; 46 import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder;
36 47
48 +import static org.onlab.onos.net.intent.IntentState.FAILED;
49 +import static org.onlab.onos.net.intent.IntentState.INSTALLED;
50 +import static org.onlab.onos.net.intent.IntentState.WITHDRAWN;
37 import static org.slf4j.LoggerFactory.getLogger; 51 import static org.slf4j.LoggerFactory.getLogger;
52 +
38 import org.slf4j.Logger; 53 import org.slf4j.Logger;
39 54
40 /** 55 /**
...@@ -44,6 +59,7 @@ import org.slf4j.Logger; ...@@ -44,6 +59,7 @@ import org.slf4j.Logger;
44 public class BandwidthCalendarResource extends BaseResource { 59 public class BandwidthCalendarResource extends BaseResource {
45 60
46 private static final Logger log = getLogger(BandwidthCalendarResource.class); 61 private static final Logger log = getLogger(BandwidthCalendarResource.class);
62 + private static final long TIMEOUT = 5; // seconds
47 63
48 @javax.ws.rs.Path("/{src}/{dst}/{srcPort}/{dstPort}/{bandwidth}") 64 @javax.ws.rs.Path("/{src}/{dst}/{srcPort}/{dstPort}/{bandwidth}")
49 @POST 65 @POST
...@@ -68,24 +84,38 @@ public class BandwidthCalendarResource extends BaseResource { ...@@ -68,24 +84,38 @@ public class BandwidthCalendarResource extends BaseResource {
68 PointToPointIntent intentP2P = 84 PointToPointIntent intentP2P =
69 new PointToPointIntent(appId(), selector, treatment, 85 new PointToPointIntent(appId(), selector, treatment,
70 srcPoint, dstPoint); 86 srcPoint, dstPoint);
71 - service.submit(intentP2P);
72 - log.info("Submitted Calendar App intent: src = " + src + "dest = " + dst
73 - + "srcPort = " + srcPort + "destPort" + dstPort + "intentID = " + intentP2P.id().toString());
74 - String reply = intentP2P.id().toString() + "\n";
75 87
88 + CountDownLatch latch = new CountDownLatch(1);
89 + InternalIntentListener listener = new InternalIntentListener(intentP2P, service, latch);
90 + service.addListener(listener);
91 + service.submit(intentP2P);
92 + try {
93 + if (latch.await(TIMEOUT, TimeUnit.SECONDS)) {
94 + log.info("Submitted Calendar App intent: src = {}; dst = {}; " +
95 + "srcPort = {}; dstPort = {}; intentID = {}",
96 + src, dst, srcPort, dstPort, intentP2P.id());
97 + String reply = intentP2P.id() + " " + listener.getState() + "\n";
76 return Response.ok(reply).build(); 98 return Response.ok(reply).build();
77 } 99 }
100 + } catch (InterruptedException e) {
101 + log.warn("Interrupted while waiting for intent {} status", intentP2P.id());
102 + }
103 + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
104 + }
78 105
79 @javax.ws.rs.Path("/cancellation/{intentId}") 106 @javax.ws.rs.Path("/cancellation/{intentId}")
80 @DELETE 107 @DELETE
81 public Response withdrawIntent(@PathParam("intentId") String intentId) { 108 public Response withdrawIntent(@PathParam("intentId") String intentId) {
82 - 109 + log.info("Receiving Teardown request for {}", intentId);
83 - log.info("Receiving Teardown request..."); 110 + IntentService service = get(IntentService.class);
84 - log.info("Withdraw intentId = {} ", intentId); 111 + Intent intent = service.getIntent(IntentId.valueOf(Long.parseLong(intentId)));
85 - 112 + if (intent != null) {
113 + service.withdraw(intent);
86 String reply = "ok\n"; 114 String reply = "ok\n";
87 return Response.ok(reply).build(); 115 return Response.ok(reply).build();
88 } 116 }
117 + return Response.status(Response.Status.NOT_FOUND).build();
118 + }
89 119
90 @javax.ws.rs.Path("/modification/{intentId}/{bandwidth}") 120 @javax.ws.rs.Path("/modification/{intentId}/{bandwidth}")
91 @POST 121 @POST
...@@ -115,4 +145,34 @@ public class BandwidthCalendarResource extends BaseResource { ...@@ -115,4 +145,34 @@ public class BandwidthCalendarResource extends BaseResource {
115 protected ApplicationId appId() { 145 protected ApplicationId appId() {
116 return get(CoreService.class).registerApplication("org.onlab.onos.calendar"); 146 return get(CoreService.class).registerApplication("org.onlab.onos.calendar");
117 } 147 }
148 +
149 + // Auxiliary listener to wait until the given intent reaches the installed or failed states.
150 + private final class InternalIntentListener implements IntentListener {
151 + private final Intent intent;
152 + private final IntentService service;
153 + private final CountDownLatch latch;
154 + private IntentState state;
155 +
156 + private InternalIntentListener(Intent intent, IntentService service,
157 + CountDownLatch latch) {
158 + this.intent = intent;
159 + this.service = service;
160 + this.latch = latch;
161 + }
162 +
163 + @Override
164 + public void event(IntentEvent event) {
165 + if (event.subject().equals(intent)) {
166 + state = service.getIntentState(intent.id());
167 + if (state == INSTALLED || state == FAILED || state == WITHDRAWN) {
168 + latch.countDown();
169 + }
170 + service.removeListener(this);
171 + }
172 + }
173 +
174 + public IntentState getState() {
175 + return state;
176 + }
177 + }
118 } 178 }
......