blob: 20a6165d402a20f0f49e5d1eddc488c5b14c7e6c [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;
Brian O'Connorabafb502014-12-02 22:26:20 -080060import org.onosproject.net.intent.IntentService;
alshabibfd23d312014-11-11 18:14:47 -080061import org.slf4j.Logger;
62
alshabib486349d2014-11-25 18:09:25 -050063import java.util.Collection;
64import java.util.Collections;
alshabibfd23d312014-11-11 18:14:47 -080065import java.util.HashSet;
alshabib486349d2014-11-25 18:09:25 -050066import java.util.Iterator;
67import java.util.LinkedList;
alshabibfd23d312014-11-11 18:14:47 -080068import java.util.List;
alshabib486349d2014-11-25 18:09:25 -050069import java.util.Objects;
70import java.util.Optional;
71import java.util.Random;
alshabibfd23d312014-11-11 18:14:47 -080072import java.util.Set;
alshabib3a0e9f52015-02-08 14:51:16 -080073import java.util.concurrent.Callable;
alshabib486349d2014-11-25 18:09:25 -050074import java.util.concurrent.CountDownLatch;
alshabib3a0e9f52015-02-08 14:51:16 -080075import java.util.concurrent.ExecutionException;
alshabibfd23d312014-11-11 18:14:47 -080076import java.util.concurrent.ExecutorService;
77import java.util.concurrent.Executors;
alshabib3a0e9f52015-02-08 14:51:16 -080078import java.util.concurrent.Future;
alshabib486349d2014-11-25 18:09:25 -050079import java.util.concurrent.TimeUnit;
alshabib3a0e9f52015-02-08 14:51:16 -080080import java.util.concurrent.TimeoutException;
alshabibfd23d312014-11-11 18:14:47 -080081
82import static org.slf4j.LoggerFactory.getLogger;
83
84/**
85 * Application to set up demos.
86 */
87@Component(immediate = true)
88@Service
89public class DemoInstaller implements DemoAPI {
90
91 private final Logger log = getLogger(getClass());
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected CoreService coreService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected IntentService intentService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected HostService hostService;
101
alshabib486349d2014-11-25 18:09:25 -0500102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected MastershipService mastershipService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected IntentBatchService intentBatchService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected ClusterService clusterService;
110
alshabib3a0e9f52015-02-08 14:51:16 -0800111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected DeviceService deviceService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected FlowRuleService flowService;
116
alshabibfd23d312014-11-11 18:14:47 -0800117 private ExecutorService worker;
118
alshabib3a0e9f52015-02-08 14:51:16 -0800119 private ExecutorService installWorker;
alshabib486349d2014-11-25 18:09:25 -0500120
alshabibfd23d312014-11-11 18:14:47 -0800121 private ApplicationId appId;
122
123 private final Set<Intent> existingIntents = new HashSet<>();
alshabib486349d2014-11-25 18:09:25 -0500124 private RandomInstaller randomInstaller;
alshabibfd23d312014-11-11 18:14:47 -0800125
alshabib3a0e9f52015-02-08 14:51:16 -0800126 private ObjectMapper mapper = new ObjectMapper();
127
alshabibfd23d312014-11-11 18:14:47 -0800128
129
130 @Activate
131 public void activate() {
alshabib486349d2014-11-25 18:09:25 -0500132 String nodeId = clusterService.getLocalNode().ip().toString();
Brian O'Connorabafb502014-12-02 22:26:20 -0800133 appId = coreService.registerApplication("org.onosproject.demo.installer."
alshabib486349d2014-11-25 18:09:25 -0500134 + nodeId);
alshabibfd23d312014-11-11 18:14:47 -0800135 worker = Executors.newFixedThreadPool(1,
136 new ThreadFactoryBuilder()
137 .setNameFormat("demo-app-worker")
138 .build());
139 log.info("Started with Application ID {}", appId.id());
140 }
141
142 @Deactivate
143 public void deactivate() {
alshabib486349d2014-11-25 18:09:25 -0500144 shutdownAndAwaitTermination(worker);
alshabib3a0e9f52015-02-08 14:51:16 -0800145 if (installWorker != null && !installWorker.isShutdown()) {
146 shutdownAndAwaitTermination(installWorker);
alshabib486349d2014-11-25 18:09:25 -0500147 }
alshabibfd23d312014-11-11 18:14:47 -0800148 log.info("Stopped");
149 }
150
151 @Override
alshabib3a0e9f52015-02-08 14:51:16 -0800152 public JsonNode flowTest(Optional<JsonNode> params) {
153 int flowsPerDevice = 1000;
154 int neighbours = 0;
155 if (params.isPresent()) {
156 flowsPerDevice = params.get().get("flowsPerDevice").asInt();
157 neighbours = params.get().get("neighbours").asInt();
158 }
159
160 Future<JsonNode> future = worker.submit(new FlowTest(flowsPerDevice, neighbours));
161
162 try {
163 return future.get(10, TimeUnit.SECONDS);
164 } catch (InterruptedException | ExecutionException | TimeoutException e) {
165 ObjectNode node = mapper.createObjectNode();
166 node.put("Error", e.getMessage());
167 return node;
168 }
169 }
170
171 @Override
alshabib486349d2014-11-25 18:09:25 -0500172 public void setup(InstallType type, Optional<JsonNode> runParams) {
alshabibfd23d312014-11-11 18:14:47 -0800173 switch (type) {
174 case MESH:
175 log.debug("Installing mesh intents");
176 worker.execute(new MeshInstaller());
177 break;
178 case RANDOM:
alshabib486349d2014-11-25 18:09:25 -0500179 //check that we do not have a random installer running
alshabib3a0e9f52015-02-08 14:51:16 -0800180 if (installWorker == null || installWorker.isShutdown()) {
181 installWorker = Executors.newFixedThreadPool(1,
alshabib486349d2014-11-25 18:09:25 -0500182 new ThreadFactoryBuilder()
183 .setNameFormat("random-worker")
184 .build());
185 log.debug("Installing random sequence of intents");
186 randomInstaller = new RandomInstaller(runParams);
alshabib3a0e9f52015-02-08 14:51:16 -0800187 installWorker.execute(randomInstaller);
alshabib486349d2014-11-25 18:09:25 -0500188 } else {
189 log.warn("Random installer is already running");
190 }
191 break;
alshabibfd23d312014-11-11 18:14:47 -0800192 default:
193 throw new IllegalArgumentException("What is it you want exactly?");
194 }
195 }
196
197 @Override
198 public void tearDown() {
199 worker.submit(new UnInstaller());
200 }
201
202
alshabib486349d2014-11-25 18:09:25 -0500203 /**
204 * Simply installs a mesh of intents from all the hosts existing in the network.
205 */
alshabibfd23d312014-11-11 18:14:47 -0800206 private class MeshInstaller implements Runnable {
207
208 @Override
209 public void run() {
210 TrafficSelector selector = DefaultTrafficSelector.builder().build();
211 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
alshabib19678cc2014-11-12 11:06:08 -0800212 List<Constraint> constraint = Lists.newArrayList();
alshabibfd23d312014-11-11 18:14:47 -0800213 List<Host> hosts = Lists.newArrayList(hostService.getHosts());
214 while (!hosts.isEmpty()) {
215 Host src = hosts.remove(0);
216 for (Host dst : hosts) {
217 HostToHostIntent intent = new HostToHostIntent(appId, src.id(), dst.id(),
218 selector, treatment,
alshabib19678cc2014-11-12 11:06:08 -0800219 constraint);
alshabibfd23d312014-11-11 18:14:47 -0800220 existingIntents.add(intent);
221 intentService.submit(intent);
222 }
223 }
224 }
225 }
226
alshabib486349d2014-11-25 18:09:25 -0500227 /**
228 * Randomly installs and withdraws intents.
229 */
230 private class RandomInstaller implements Runnable {
alshabibfd23d312014-11-11 18:14:47 -0800231
alshabib486349d2014-11-25 18:09:25 -0500232 private final boolean isLocal;
233 private final Set<Host> hosts;
234
235 private final Random random = new Random(System.currentTimeMillis());
236
237 private Set<HostPair> uninstalledOrWithdrawn;
238 private Set<HostPair> installed;
239
240 private CountDownLatch latch;
241
242 //used to wait on a batch to be processed.
243 private static final int ITERATIONMAX = 50000000;
244
245
246 public RandomInstaller(Optional<JsonNode> runParams) {
247 /*
248 Check if we have params and honour them. Otherwise
249 set defaults to processing only local stuff and
250 all local hosts.
251 */
252 if (runParams.isPresent()) {
253 JsonNode node = runParams.get();
254 isLocal = node.get("local").asBoolean();
255 hosts = node.get("hosts") == null ? Sets.newHashSet(hostService.getHosts()) :
256 constructHostIds(node.get("hosts").elements());
257 } else {
258 isLocal = true;
259 hosts = Sets.newHashSet(hostService.getHosts());
260 }
261
262 //construct list of intents.
263 installed = Sets.newHashSet();
264 if (isLocal) {
265 uninstalledOrWithdrawn = buildPairs(pruneHostsByMasterShip());
266 } else {
267 uninstalledOrWithdrawn = buildPairs(hosts);
268 }
269
270 }
271
272 private Set<Host> constructHostIds(Iterator<JsonNode> elements) {
273 Set<Host> hostIds = Sets.newHashSet();
274 JsonNode n;
275 while (elements.hasNext()) {
276 n = elements.next();
277 hostIds.add(hostService.getHost(HostId.hostId(n.textValue())));
278 }
279 return hostIds;
280 }
281
282 @Override
283 public void run() {
alshabib3a0e9f52015-02-08 14:51:16 -0800284 if (!installWorker.isShutdown()) {
alshabib486349d2014-11-25 18:09:25 -0500285 randomize();
286 latch = new CountDownLatch(1);
287 try {
288 trackIntents();
289 } catch (InterruptedException e) {
290 shutdown();
291 }
292 }
293
294 }
295
296
297 /**
298 * Check whether the previously submitted batch is in progress
299 * and if yes submit the next one. If things hang, wait for at
300 * most 5 seconds and bail.
301 * @throws InterruptedException if the thread go interupted
302 */
303 private void trackIntents() throws InterruptedException {
304 int count = 0;
305 while (!latch.await(100, TimeUnit.NANOSECONDS)) {
306 if (intentBatchService.getPendingOperations().isEmpty()) {
307 latch.countDown();
308 }
309 count++;
310 if (count > ITERATIONMAX) {
Brian O'Connor86f6f7f2014-12-01 17:02:45 -0800311 log.warn("A batch is stuck processing. " +
312 "pending : {}",
alshabib486349d2014-11-25 18:09:25 -0500313 intentBatchService.getPendingOperations());
alshabib3a0e9f52015-02-08 14:51:16 -0800314 shutdownAndAwaitTermination(installWorker);
alshabib486349d2014-11-25 18:09:25 -0500315 }
316 }
Brian O'Connor03406a42015-02-03 17:28:57 -0800317 //if everything is good proceed.
alshabib3a0e9f52015-02-08 14:51:16 -0800318 if (!installWorker.isShutdown()) {
319 installWorker.execute(this);
alshabib486349d2014-11-25 18:09:25 -0500320 }
321
322 }
323
324 public void shutdown() {
325 log.warn("Shutting down random installer!");
326 cleanUp();
327 }
328
329
330 /**
331 * Shuffle the uninstalled and installed list (separately) and select
332 * a random number of them and install or uninstall them respectively.
333 */
334 private void randomize() {
335 List<HostPair> hostList = new LinkedList<>(uninstalledOrWithdrawn);
336 Collections.shuffle(hostList);
337 List<HostPair> toInstall = hostList.subList(0,
338 random.nextInt(hostList.size() - 1));
339 List<HostPair> toRemove;
340 if (!installed.isEmpty()) {
341 hostList = new LinkedList<>(installed);
342 Collections.shuffle(hostList);
343 toRemove = hostList.subList(0,
344 random.nextInt(hostList.size() - 1));
345 uninstallIntents(toRemove);
346 }
347 installIntents(toInstall);
348
349 }
350
351 private void installIntents(List<HostPair> toInstall) {
alshabib486349d2014-11-25 18:09:25 -0500352 for (HostPair pair : toInstall) {
353 installed.add(pair);
354 uninstalledOrWithdrawn.remove(pair);
Brian O'Connor03406a42015-02-03 17:28:57 -0800355 intentService.submit(pair.h2hIntent());
alshabib486349d2014-11-25 18:09:25 -0500356 }
alshabib486349d2014-11-25 18:09:25 -0500357 }
358
359 private void uninstallIntents(Collection<HostPair> toRemove) {
alshabib486349d2014-11-25 18:09:25 -0500360 for (HostPair pair : toRemove) {
361 installed.remove(pair);
362 uninstalledOrWithdrawn.add(pair);
Brian O'Connor03406a42015-02-03 17:28:57 -0800363 intentService.withdraw(pair.h2hIntent());
alshabib486349d2014-11-25 18:09:25 -0500364 }
alshabib486349d2014-11-25 18:09:25 -0500365 }
366
367 /**
368 * Take everything and remove it all.
369 */
370 private void cleanUp() {
371 List<HostPair> allPairs = Lists.newArrayList(installed);
372 allPairs.addAll(uninstalledOrWithdrawn);
alshabib486349d2014-11-25 18:09:25 -0500373 for (HostPair pair : allPairs) {
Brian O'Connor03406a42015-02-03 17:28:57 -0800374 intentService.withdraw(pair.h2hIntent());
alshabib486349d2014-11-25 18:09:25 -0500375 }
alshabib486349d2014-11-25 18:09:25 -0500376 }
377
378
379 private Set<HostPair> buildPairs(Set<Host> hosts) {
380 Set<HostPair> pairs = Sets.newHashSet();
381 Iterator<Host> it = Sets.newHashSet(hosts).iterator();
382 while (it.hasNext()) {
383 Host src = it.next();
384 it.remove();
385 for (Host dst : hosts) {
386 pairs.add(new HostPair(src, dst));
387 }
388 }
389 return pairs;
390 }
391
392 private Set<Host> pruneHostsByMasterShip() {
393 return FluentIterable.from(hosts)
394 .filter(hasLocalMaster())
395 .toSet();
396
397 }
398
399 private Predicate<? super Host> hasLocalMaster() {
400 return new Predicate<Host>() {
401 @Override
402 public boolean apply(Host host) {
403 return mastershipService.getLocalRole(
404 host.location().deviceId()).equals(MastershipRole.MASTER);
405 }
406 };
407 }
408
409
410 /**
411 * Simple class representing a pair of hosts and precomputes the associated
412 * h2h intent.
413 */
414 private class HostPair {
415
416 private final Host src;
417 private final Host dst;
418
419 private final TrafficSelector selector = DefaultTrafficSelector.builder().build();
420 private final TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
421 private final List<Constraint> constraint = Lists.newArrayList();
422 private final HostToHostIntent intent;
423
424 public HostPair(Host src, Host dst) {
425 this.src = src;
426 this.dst = dst;
427 this.intent = new HostToHostIntent(appId, src.id(), dst.id(),
428 selector, treatment, constraint);
429 }
430
431 public HostToHostIntent h2hIntent() {
432 return intent;
433 }
434
435 @Override
436 public boolean equals(Object o) {
437 if (this == o) {
438 return true;
439 }
440 if (o == null || getClass() != o.getClass()) {
441 return false;
442 }
443
444 HostPair hostPair = (HostPair) o;
445
446 return Objects.equals(src, hostPair.src) &&
447 Objects.equals(dst, hostPair.dst);
448
449 }
450
451 @Override
452 public int hashCode() {
453 return Objects.hash(src, dst);
454 }
455
456
457 }
458
459 }
460
461 /**
462 * Remove anything that is running and clear it all out.
463 */
alshabibfd23d312014-11-11 18:14:47 -0800464 private class UnInstaller implements Runnable {
465 @Override
466 public void run() {
alshabib486349d2014-11-25 18:09:25 -0500467 if (!existingIntents.isEmpty()) {
468 clearExistingIntents();
469 }
470
alshabib3a0e9f52015-02-08 14:51:16 -0800471 if (installWorker != null && !installWorker.isShutdown()) {
472 shutdownAndAwaitTermination(installWorker);
alshabib486349d2014-11-25 18:09:25 -0500473 randomInstaller.shutdown();
474 }
475 }
476
477 private void clearExistingIntents() {
alshabibfd23d312014-11-11 18:14:47 -0800478 for (Intent i : existingIntents) {
479 intentService.withdraw(i);
480 }
alshabib486349d2014-11-25 18:09:25 -0500481 existingIntents.clear();
alshabibfd23d312014-11-11 18:14:47 -0800482 }
483 }
alshabib486349d2014-11-25 18:09:25 -0500484
485 /**
486 * Shutdown a pool cleanly if possible.
487 *
488 * @param pool an executorService
489 */
490 private void shutdownAndAwaitTermination(ExecutorService pool) {
491 pool.shutdown(); // Disable new tasks from being submitted
492 try {
493 // Wait a while for existing tasks to terminate
494 if (!pool.awaitTermination(10, TimeUnit.SECONDS)) {
495 pool.shutdownNow(); // Cancel currently executing tasks
496 // Wait a while for tasks to respond to being cancelled
497 if (!pool.awaitTermination(10, TimeUnit.SECONDS)) {
498 log.error("Pool did not terminate");
499 }
500 }
501 } catch (Exception ie) {
502 // (Re-)Cancel if current thread also interrupted
503 pool.shutdownNow();
504 // Preserve interrupt status
505 Thread.currentThread().interrupt();
506 }
507 }
508
alshabib3a0e9f52015-02-08 14:51:16 -0800509 private class FlowTest implements Callable<JsonNode> {
510 private final int flowPerDevice;
511 private final int neighbours;
512 private FlowRuleOperations.Builder adds;
513 private FlowRuleOperations.Builder removes;
514
515 public FlowTest(int flowsPerDevice, int neighbours) {
516 this.flowPerDevice = flowsPerDevice;
517 this.neighbours = neighbours;
518 prepareInstallation();
519 }
520
521 private void prepareInstallation() {
522 Set<ControllerNode> instances = Sets.newHashSet(clusterService.getNodes());
523 instances.remove(clusterService.getLocalNode());
524 Set<NodeId> acceptableNodes = Sets.newHashSet();
525 if (neighbours >= instances.size()) {
526 instances.forEach(instance -> acceptableNodes.add(instance.id()));
527 } else {
528 Iterator<ControllerNode> nodes = instances.iterator();
529 for (int i = neighbours; i > 0; i--) {
530 acceptableNodes.add(nodes.next().id());
531 }
532 }
533 acceptableNodes.add(clusterService.getLocalNode().id());
534
535 Set<Device> devices = Sets.newHashSet();
536 for (Device dev : deviceService.getDevices()) {
537 if (acceptableNodes.contains(
538 mastershipService.getMasterFor(dev.id()))) {
539 devices.add(dev);
540 }
541 }
542
543 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
544 .setOutput(PortNumber.portNumber(RandomUtils.nextInt())).build();
545 TrafficSelector.Builder sbuilder;
546 FlowRuleOperations.Builder rules = FlowRuleOperations.builder();
547 FlowRuleOperations.Builder remove = FlowRuleOperations.builder();
548
549 for (Device d : devices) {
550 for (int i = 0; i < this.flowPerDevice; i++) {
551 sbuilder = DefaultTrafficSelector.builder();
552
553 sbuilder.matchEthSrc(MacAddress.valueOf(RandomUtils.nextInt() * i))
554 .matchEthDst(MacAddress.valueOf((Integer.MAX_VALUE - i) * RandomUtils.nextInt()));
555
556
557 int randomPriority = RandomUtils.nextInt();
558 DefaultFlowRule f = new DefaultFlowRule(d.id(), sbuilder.build(), treatment,
559 randomPriority, appId, 10, false);
560 rules.add(f);
561 remove.remove(f);
562
563 }
564 }
565
566 this.adds = rules;
567 this.removes = remove;
568 }
569
570 @Override
571 public JsonNode call() throws Exception {
572 ObjectNode node = mapper.createObjectNode();
573 CountDownLatch latch = new CountDownLatch(1);
574 flowService.apply(adds.build(new FlowRuleOperationsContext() {
575
576 private final Stopwatch timer = Stopwatch.createStarted();
577
578 @Override
579 public void onSuccess(FlowRuleOperations ops) {
580
581 long elapsed = timer.elapsed(TimeUnit.MILLISECONDS);
582 node.put("elapsed", elapsed);
583
584
585 latch.countDown();
586 }
587 }));
588
589 latch.await(10, TimeUnit.SECONDS);
590 flowService.apply(removes.build());
591 return node;
592 }
593 }
alshabibfd23d312014-11-11 18:14:47 -0800594}
595
596