blob: 10ac5a38d52e00d37f022f576fab160d73609dbc [file] [log] [blame]
alshabibfd23d312014-11-11 18:14:47 -08001/*
2 * Copyright 2014 Open Networking Laboratory
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 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.demo;
alshabibfd23d312014-11-11 18:14:47 -080017
alshabib486349d2014-11-25 18:09:25 -050018import com.fasterxml.jackson.databind.JsonNode;
alshabib3a0e9f52015-02-08 14:51:16 -080019import com.fasterxml.jackson.databind.ObjectMapper;
20import com.fasterxml.jackson.databind.node.ObjectNode;
alshabib486349d2014-11-25 18:09:25 -050021import com.google.common.base.Predicate;
alshabib3a0e9f52015-02-08 14:51:16 -080022import com.google.common.base.Stopwatch;
alshabib486349d2014-11-25 18:09:25 -050023import com.google.common.collect.FluentIterable;
alshabibfd23d312014-11-11 18:14:47 -080024import com.google.common.collect.Lists;
alshabib486349d2014-11-25 18:09:25 -050025import com.google.common.collect.Sets;
alshabibfd23d312014-11-11 18:14:47 -080026import com.google.common.util.concurrent.ThreadFactoryBuilder;
alshabib3a0e9f52015-02-08 14:51:16 -080027import org.apache.commons.lang.math.RandomUtils;
alshabibfd23d312014-11-11 18:14:47 -080028import org.apache.felix.scr.annotations.Activate;
29import org.apache.felix.scr.annotations.Component;
30import org.apache.felix.scr.annotations.Deactivate;
31import org.apache.felix.scr.annotations.Reference;
32import org.apache.felix.scr.annotations.ReferenceCardinality;
33import org.apache.felix.scr.annotations.Service;
alshabib3a0e9f52015-02-08 14:51:16 -080034import org.onlab.packet.MacAddress;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.cluster.ClusterService;
alshabib3a0e9f52015-02-08 14:51:16 -080036import org.onosproject.cluster.ControllerNode;
37import org.onosproject.cluster.NodeId;
Brian O'Connorabafb502014-12-02 22:26:20 -080038import org.onosproject.core.ApplicationId;
39import org.onosproject.core.CoreService;
40import org.onosproject.mastership.MastershipService;
alshabib3a0e9f52015-02-08 14:51:16 -080041import org.onosproject.net.Device;
Brian O'Connorabafb502014-12-02 22:26:20 -080042import org.onosproject.net.Host;
43import org.onosproject.net.HostId;
44import org.onosproject.net.MastershipRole;
alshabib3a0e9f52015-02-08 14:51:16 -080045import org.onosproject.net.PortNumber;
46import org.onosproject.net.device.DeviceService;
47import org.onosproject.net.flow.DefaultFlowRule;
Brian O'Connorabafb502014-12-02 22:26:20 -080048import org.onosproject.net.flow.DefaultTrafficSelector;
49import org.onosproject.net.flow.DefaultTrafficTreatment;
alshabib3a0e9f52015-02-08 14:51:16 -080050import org.onosproject.net.flow.FlowRuleOperations;
51import org.onosproject.net.flow.FlowRuleOperationsContext;
52import org.onosproject.net.flow.FlowRuleService;
Brian O'Connorabafb502014-12-02 22:26:20 -080053import org.onosproject.net.flow.TrafficSelector;
54import org.onosproject.net.flow.TrafficTreatment;
55import org.onosproject.net.host.HostService;
56import org.onosproject.net.intent.Constraint;
57import org.onosproject.net.intent.HostToHostIntent;
58import org.onosproject.net.intent.Intent;
59import org.onosproject.net.intent.IntentBatchService;
60import org.onosproject.net.intent.IntentOperations;
61import org.onosproject.net.intent.IntentService;
alshabibfd23d312014-11-11 18:14:47 -080062import org.slf4j.Logger;
63
alshabib486349d2014-11-25 18:09:25 -050064import java.util.Collection;
65import java.util.Collections;
alshabibfd23d312014-11-11 18:14:47 -080066import java.util.HashSet;
alshabib486349d2014-11-25 18:09:25 -050067import java.util.Iterator;
68import java.util.LinkedList;
alshabibfd23d312014-11-11 18:14:47 -080069import java.util.List;
alshabib486349d2014-11-25 18:09:25 -050070import java.util.Objects;
71import java.util.Optional;
72import java.util.Random;
alshabibfd23d312014-11-11 18:14:47 -080073import java.util.Set;
alshabib3a0e9f52015-02-08 14:51:16 -080074import java.util.concurrent.Callable;
alshabib486349d2014-11-25 18:09:25 -050075import java.util.concurrent.CountDownLatch;
alshabib3a0e9f52015-02-08 14:51:16 -080076import java.util.concurrent.ExecutionException;
alshabibfd23d312014-11-11 18:14:47 -080077import java.util.concurrent.ExecutorService;
78import java.util.concurrent.Executors;
alshabib3a0e9f52015-02-08 14:51:16 -080079import java.util.concurrent.Future;
alshabib486349d2014-11-25 18:09:25 -050080import java.util.concurrent.TimeUnit;
alshabib3a0e9f52015-02-08 14:51:16 -080081import java.util.concurrent.TimeoutException;
alshabibfd23d312014-11-11 18:14:47 -080082
83import static org.slf4j.LoggerFactory.getLogger;
84
85/**
86 * Application to set up demos.
87 */
88@Component(immediate = true)
89@Service
90public class DemoInstaller implements DemoAPI {
91
92 private final Logger log = getLogger(getClass());
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected CoreService coreService;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected IntentService intentService;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected HostService hostService;
102
alshabib486349d2014-11-25 18:09:25 -0500103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected MastershipService mastershipService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected IntentBatchService intentBatchService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected ClusterService clusterService;
111
alshabib3a0e9f52015-02-08 14:51:16 -0800112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected DeviceService deviceService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected FlowRuleService flowService;
117
alshabibfd23d312014-11-11 18:14:47 -0800118 private ExecutorService worker;
119
alshabib3a0e9f52015-02-08 14:51:16 -0800120 private ExecutorService installWorker;
alshabib486349d2014-11-25 18:09:25 -0500121
alshabibfd23d312014-11-11 18:14:47 -0800122 private ApplicationId appId;
123
124 private final Set<Intent> existingIntents = new HashSet<>();
alshabib486349d2014-11-25 18:09:25 -0500125 private RandomInstaller randomInstaller;
alshabibfd23d312014-11-11 18:14:47 -0800126
alshabib3a0e9f52015-02-08 14:51:16 -0800127 private ObjectMapper mapper = new ObjectMapper();
128
alshabibfd23d312014-11-11 18:14:47 -0800129
130
131 @Activate
132 public void activate() {
alshabib486349d2014-11-25 18:09:25 -0500133 String nodeId = clusterService.getLocalNode().ip().toString();
Brian O'Connorabafb502014-12-02 22:26:20 -0800134 appId = coreService.registerApplication("org.onosproject.demo.installer."
alshabib486349d2014-11-25 18:09:25 -0500135 + nodeId);
alshabibfd23d312014-11-11 18:14:47 -0800136 worker = Executors.newFixedThreadPool(1,
137 new ThreadFactoryBuilder()
138 .setNameFormat("demo-app-worker")
139 .build());
140 log.info("Started with Application ID {}", appId.id());
141 }
142
143 @Deactivate
144 public void deactivate() {
alshabib486349d2014-11-25 18:09:25 -0500145 shutdownAndAwaitTermination(worker);
alshabib3a0e9f52015-02-08 14:51:16 -0800146 if (installWorker != null && !installWorker.isShutdown()) {
147 shutdownAndAwaitTermination(installWorker);
alshabib486349d2014-11-25 18:09:25 -0500148 }
alshabibfd23d312014-11-11 18:14:47 -0800149 log.info("Stopped");
150 }
151
152 @Override
alshabib3a0e9f52015-02-08 14:51:16 -0800153 public JsonNode flowTest(Optional<JsonNode> params) {
154 int flowsPerDevice = 1000;
155 int neighbours = 0;
156 if (params.isPresent()) {
157 flowsPerDevice = params.get().get("flowsPerDevice").asInt();
158 neighbours = params.get().get("neighbours").asInt();
159 }
160
161 Future<JsonNode> future = worker.submit(new FlowTest(flowsPerDevice, neighbours));
162
163 try {
164 return future.get(10, TimeUnit.SECONDS);
165 } catch (InterruptedException | ExecutionException | TimeoutException e) {
166 ObjectNode node = mapper.createObjectNode();
167 node.put("Error", e.getMessage());
168 return node;
169 }
170 }
171
172 @Override
alshabib486349d2014-11-25 18:09:25 -0500173 public void setup(InstallType type, Optional<JsonNode> runParams) {
alshabibfd23d312014-11-11 18:14:47 -0800174 switch (type) {
175 case MESH:
176 log.debug("Installing mesh intents");
177 worker.execute(new MeshInstaller());
178 break;
179 case RANDOM:
alshabib486349d2014-11-25 18:09:25 -0500180 //check that we do not have a random installer running
alshabib3a0e9f52015-02-08 14:51:16 -0800181 if (installWorker == null || installWorker.isShutdown()) {
182 installWorker = Executors.newFixedThreadPool(1,
alshabib486349d2014-11-25 18:09:25 -0500183 new ThreadFactoryBuilder()
184 .setNameFormat("random-worker")
185 .build());
186 log.debug("Installing random sequence of intents");
187 randomInstaller = new RandomInstaller(runParams);
alshabib3a0e9f52015-02-08 14:51:16 -0800188 installWorker.execute(randomInstaller);
alshabib486349d2014-11-25 18:09:25 -0500189 } else {
190 log.warn("Random installer is already running");
191 }
192 break;
alshabibfd23d312014-11-11 18:14:47 -0800193 default:
194 throw new IllegalArgumentException("What is it you want exactly?");
195 }
196 }
197
198 @Override
199 public void tearDown() {
200 worker.submit(new UnInstaller());
201 }
202
203
alshabib486349d2014-11-25 18:09:25 -0500204 /**
205 * Simply installs a mesh of intents from all the hosts existing in the network.
206 */
alshabibfd23d312014-11-11 18:14:47 -0800207 private class MeshInstaller implements Runnable {
208
209 @Override
210 public void run() {
211 TrafficSelector selector = DefaultTrafficSelector.builder().build();
212 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
alshabib19678cc2014-11-12 11:06:08 -0800213 List<Constraint> constraint = Lists.newArrayList();
alshabibfd23d312014-11-11 18:14:47 -0800214 List<Host> hosts = Lists.newArrayList(hostService.getHosts());
215 while (!hosts.isEmpty()) {
216 Host src = hosts.remove(0);
217 for (Host dst : hosts) {
218 HostToHostIntent intent = new HostToHostIntent(appId, src.id(), dst.id(),
219 selector, treatment,
alshabib19678cc2014-11-12 11:06:08 -0800220 constraint);
alshabibfd23d312014-11-11 18:14:47 -0800221 existingIntents.add(intent);
222 intentService.submit(intent);
223 }
224 }
225 }
226 }
227
alshabib486349d2014-11-25 18:09:25 -0500228 /**
229 * Randomly installs and withdraws intents.
230 */
231 private class RandomInstaller implements Runnable {
alshabibfd23d312014-11-11 18:14:47 -0800232
alshabib486349d2014-11-25 18:09:25 -0500233 private final boolean isLocal;
234 private final Set<Host> hosts;
235
236 private final Random random = new Random(System.currentTimeMillis());
237
238 private Set<HostPair> uninstalledOrWithdrawn;
239 private Set<HostPair> installed;
240
241 private CountDownLatch latch;
242
243 //used to wait on a batch to be processed.
244 private static final int ITERATIONMAX = 50000000;
245
246
247 public RandomInstaller(Optional<JsonNode> runParams) {
248 /*
249 Check if we have params and honour them. Otherwise
250 set defaults to processing only local stuff and
251 all local hosts.
252 */
253 if (runParams.isPresent()) {
254 JsonNode node = runParams.get();
255 isLocal = node.get("local").asBoolean();
256 hosts = node.get("hosts") == null ? Sets.newHashSet(hostService.getHosts()) :
257 constructHostIds(node.get("hosts").elements());
258 } else {
259 isLocal = true;
260 hosts = Sets.newHashSet(hostService.getHosts());
261 }
262
263 //construct list of intents.
264 installed = Sets.newHashSet();
265 if (isLocal) {
266 uninstalledOrWithdrawn = buildPairs(pruneHostsByMasterShip());
267 } else {
268 uninstalledOrWithdrawn = buildPairs(hosts);
269 }
270
271 }
272
273 private Set<Host> constructHostIds(Iterator<JsonNode> elements) {
274 Set<Host> hostIds = Sets.newHashSet();
275 JsonNode n;
276 while (elements.hasNext()) {
277 n = elements.next();
278 hostIds.add(hostService.getHost(HostId.hostId(n.textValue())));
279 }
280 return hostIds;
281 }
282
283 @Override
284 public void run() {
alshabib3a0e9f52015-02-08 14:51:16 -0800285 if (!installWorker.isShutdown()) {
alshabib486349d2014-11-25 18:09:25 -0500286 randomize();
287 latch = new CountDownLatch(1);
288 try {
289 trackIntents();
290 } catch (InterruptedException e) {
291 shutdown();
292 }
293 }
294
295 }
296
297
298 /**
299 * Check whether the previously submitted batch is in progress
300 * and if yes submit the next one. If things hang, wait for at
301 * most 5 seconds and bail.
302 * @throws InterruptedException if the thread go interupted
303 */
304 private void trackIntents() throws InterruptedException {
305 int count = 0;
306 while (!latch.await(100, TimeUnit.NANOSECONDS)) {
307 if (intentBatchService.getPendingOperations().isEmpty()) {
308 latch.countDown();
309 }
310 count++;
311 if (count > ITERATIONMAX) {
Brian O'Connor86f6f7f2014-12-01 17:02:45 -0800312 log.warn("A batch is stuck processing. " +
313 "pending : {}",
alshabib486349d2014-11-25 18:09:25 -0500314 intentBatchService.getPendingOperations());
alshabib3a0e9f52015-02-08 14:51:16 -0800315 shutdownAndAwaitTermination(installWorker);
alshabib486349d2014-11-25 18:09:25 -0500316 }
317 }
318 //if everyting is good proceed.
alshabib3a0e9f52015-02-08 14:51:16 -0800319 if (!installWorker.isShutdown()) {
320 installWorker.execute(this);
alshabib486349d2014-11-25 18:09:25 -0500321 }
322
323 }
324
325 public void shutdown() {
326 log.warn("Shutting down random installer!");
327 cleanUp();
328 }
329
330
331 /**
332 * Shuffle the uninstalled and installed list (separately) and select
333 * a random number of them and install or uninstall them respectively.
334 */
335 private void randomize() {
336 List<HostPair> hostList = new LinkedList<>(uninstalledOrWithdrawn);
337 Collections.shuffle(hostList);
338 List<HostPair> toInstall = hostList.subList(0,
339 random.nextInt(hostList.size() - 1));
340 List<HostPair> toRemove;
341 if (!installed.isEmpty()) {
342 hostList = new LinkedList<>(installed);
343 Collections.shuffle(hostList);
344 toRemove = hostList.subList(0,
345 random.nextInt(hostList.size() - 1));
346 uninstallIntents(toRemove);
347 }
348 installIntents(toInstall);
349
350 }
351
352 private void installIntents(List<HostPair> toInstall) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800353 IntentOperations.Builder builder = IntentOperations.builder(appId);
alshabib486349d2014-11-25 18:09:25 -0500354 for (HostPair pair : toInstall) {
355 installed.add(pair);
356 uninstalledOrWithdrawn.remove(pair);
357 builder.addSubmitOperation(pair.h2hIntent());
358 }
359 intentBatchService.addIntentOperations(builder.build());
360 }
361
362 private void uninstallIntents(Collection<HostPair> toRemove) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800363 IntentOperations.Builder builder = IntentOperations.builder(appId);
alshabib486349d2014-11-25 18:09:25 -0500364 for (HostPair pair : toRemove) {
365 installed.remove(pair);
366 uninstalledOrWithdrawn.add(pair);
367 builder.addWithdrawOperation(pair.h2hIntent().id());
368 }
369 intentBatchService.addIntentOperations(builder.build());
370 }
371
372 /**
373 * Take everything and remove it all.
374 */
375 private void cleanUp() {
376 List<HostPair> allPairs = Lists.newArrayList(installed);
377 allPairs.addAll(uninstalledOrWithdrawn);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800378 IntentOperations.Builder builder = IntentOperations.builder(appId);
alshabib486349d2014-11-25 18:09:25 -0500379 for (HostPair pair : allPairs) {
380 builder.addWithdrawOperation(pair.h2hIntent().id());
381 }
382 intentBatchService.addIntentOperations(builder.build());
383 }
384
385
386 private Set<HostPair> buildPairs(Set<Host> hosts) {
387 Set<HostPair> pairs = Sets.newHashSet();
388 Iterator<Host> it = Sets.newHashSet(hosts).iterator();
389 while (it.hasNext()) {
390 Host src = it.next();
391 it.remove();
392 for (Host dst : hosts) {
393 pairs.add(new HostPair(src, dst));
394 }
395 }
396 return pairs;
397 }
398
399 private Set<Host> pruneHostsByMasterShip() {
400 return FluentIterable.from(hosts)
401 .filter(hasLocalMaster())
402 .toSet();
403
404 }
405
406 private Predicate<? super Host> hasLocalMaster() {
407 return new Predicate<Host>() {
408 @Override
409 public boolean apply(Host host) {
410 return mastershipService.getLocalRole(
411 host.location().deviceId()).equals(MastershipRole.MASTER);
412 }
413 };
414 }
415
416
417 /**
418 * Simple class representing a pair of hosts and precomputes the associated
419 * h2h intent.
420 */
421 private class HostPair {
422
423 private final Host src;
424 private final Host dst;
425
426 private final TrafficSelector selector = DefaultTrafficSelector.builder().build();
427 private final TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
428 private final List<Constraint> constraint = Lists.newArrayList();
429 private final HostToHostIntent intent;
430
431 public HostPair(Host src, Host dst) {
432 this.src = src;
433 this.dst = dst;
434 this.intent = new HostToHostIntent(appId, src.id(), dst.id(),
435 selector, treatment, constraint);
436 }
437
438 public HostToHostIntent h2hIntent() {
439 return intent;
440 }
441
442 @Override
443 public boolean equals(Object o) {
444 if (this == o) {
445 return true;
446 }
447 if (o == null || getClass() != o.getClass()) {
448 return false;
449 }
450
451 HostPair hostPair = (HostPair) o;
452
453 return Objects.equals(src, hostPair.src) &&
454 Objects.equals(dst, hostPair.dst);
455
456 }
457
458 @Override
459 public int hashCode() {
460 return Objects.hash(src, dst);
461 }
462
463
464 }
465
466 }
467
468 /**
469 * Remove anything that is running and clear it all out.
470 */
alshabibfd23d312014-11-11 18:14:47 -0800471 private class UnInstaller implements Runnable {
472 @Override
473 public void run() {
alshabib486349d2014-11-25 18:09:25 -0500474 if (!existingIntents.isEmpty()) {
475 clearExistingIntents();
476 }
477
alshabib3a0e9f52015-02-08 14:51:16 -0800478 if (installWorker != null && !installWorker.isShutdown()) {
479 shutdownAndAwaitTermination(installWorker);
alshabib486349d2014-11-25 18:09:25 -0500480 randomInstaller.shutdown();
481 }
482 }
483
484 private void clearExistingIntents() {
alshabibfd23d312014-11-11 18:14:47 -0800485 for (Intent i : existingIntents) {
486 intentService.withdraw(i);
487 }
alshabib486349d2014-11-25 18:09:25 -0500488 existingIntents.clear();
alshabibfd23d312014-11-11 18:14:47 -0800489 }
490 }
alshabib486349d2014-11-25 18:09:25 -0500491
492 /**
493 * Shutdown a pool cleanly if possible.
494 *
495 * @param pool an executorService
496 */
497 private void shutdownAndAwaitTermination(ExecutorService pool) {
498 pool.shutdown(); // Disable new tasks from being submitted
499 try {
500 // Wait a while for existing tasks to terminate
501 if (!pool.awaitTermination(10, TimeUnit.SECONDS)) {
502 pool.shutdownNow(); // Cancel currently executing tasks
503 // Wait a while for tasks to respond to being cancelled
504 if (!pool.awaitTermination(10, TimeUnit.SECONDS)) {
505 log.error("Pool did not terminate");
506 }
507 }
508 } catch (Exception ie) {
509 // (Re-)Cancel if current thread also interrupted
510 pool.shutdownNow();
511 // Preserve interrupt status
512 Thread.currentThread().interrupt();
513 }
514 }
515
alshabib3a0e9f52015-02-08 14:51:16 -0800516 private class FlowTest implements Callable<JsonNode> {
517 private final int flowPerDevice;
518 private final int neighbours;
519 private FlowRuleOperations.Builder adds;
520 private FlowRuleOperations.Builder removes;
521
522 public FlowTest(int flowsPerDevice, int neighbours) {
523 this.flowPerDevice = flowsPerDevice;
524 this.neighbours = neighbours;
525 prepareInstallation();
526 }
527
528 private void prepareInstallation() {
529 Set<ControllerNode> instances = Sets.newHashSet(clusterService.getNodes());
530 instances.remove(clusterService.getLocalNode());
531 Set<NodeId> acceptableNodes = Sets.newHashSet();
532 if (neighbours >= instances.size()) {
533 instances.forEach(instance -> acceptableNodes.add(instance.id()));
534 } else {
535 Iterator<ControllerNode> nodes = instances.iterator();
536 for (int i = neighbours; i > 0; i--) {
537 acceptableNodes.add(nodes.next().id());
538 }
539 }
540 acceptableNodes.add(clusterService.getLocalNode().id());
541
542 Set<Device> devices = Sets.newHashSet();
543 for (Device dev : deviceService.getDevices()) {
544 if (acceptableNodes.contains(
545 mastershipService.getMasterFor(dev.id()))) {
546 devices.add(dev);
547 }
548 }
549
550 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
551 .setOutput(PortNumber.portNumber(RandomUtils.nextInt())).build();
552 TrafficSelector.Builder sbuilder;
553 FlowRuleOperations.Builder rules = FlowRuleOperations.builder();
554 FlowRuleOperations.Builder remove = FlowRuleOperations.builder();
555
556 for (Device d : devices) {
557 for (int i = 0; i < this.flowPerDevice; i++) {
558 sbuilder = DefaultTrafficSelector.builder();
559
560 sbuilder.matchEthSrc(MacAddress.valueOf(RandomUtils.nextInt() * i))
561 .matchEthDst(MacAddress.valueOf((Integer.MAX_VALUE - i) * RandomUtils.nextInt()));
562
563
564 int randomPriority = RandomUtils.nextInt();
565 DefaultFlowRule f = new DefaultFlowRule(d.id(), sbuilder.build(), treatment,
566 randomPriority, appId, 10, false);
567 rules.add(f);
568 remove.remove(f);
569
570 }
571 }
572
573 this.adds = rules;
574 this.removes = remove;
575 }
576
577 @Override
578 public JsonNode call() throws Exception {
579 ObjectNode node = mapper.createObjectNode();
580 CountDownLatch latch = new CountDownLatch(1);
581 flowService.apply(adds.build(new FlowRuleOperationsContext() {
582
583 private final Stopwatch timer = Stopwatch.createStarted();
584
585 @Override
586 public void onSuccess(FlowRuleOperations ops) {
587
588 long elapsed = timer.elapsed(TimeUnit.MILLISECONDS);
589 node.put("elapsed", elapsed);
590
591
592 latch.countDown();
593 }
594 }));
595
596 latch.await(10, TimeUnit.SECONDS);
597 flowService.apply(removes.build());
598 return node;
599 }
600 }
alshabibfd23d312014-11-11 18:14:47 -0800601}
602
603