blob: dceed7b83feb90d99338ac8bf00d32c52fb25d5c [file] [log] [blame]
Thomas Vachuska7d693f52014-10-21 19:17:57 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 Open Networking Laboratory
Thomas Vachuska7d693f52014-10-21 19:17:57 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska7d693f52014-10-21 19:17:57 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska7d693f52014-10-21 19:17:57 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.cli.net;
Brian O'Connora4cab072014-10-03 18:46:39 -070017
18import org.apache.karaf.shell.commands.Argument;
19import org.apache.karaf.shell.commands.Command;
Brian O'Connor8016f342015-02-24 17:00:39 -080020import org.apache.karaf.shell.commands.Option;
Brian O'Connorabafb502014-12-02 22:26:20 -080021import org.onosproject.cli.AbstractShellCommand;
Ray Milkey02479862015-02-17 17:02:19 -080022import org.onosproject.core.ApplicationId;
23import org.onosproject.core.CoreService;
Brian O'Connorabafb502014-12-02 22:26:20 -080024import org.onosproject.net.intent.Intent;
Brian O'Connor8016f342015-02-24 17:00:39 -080025import org.onosproject.net.intent.IntentEvent;
26import org.onosproject.net.intent.IntentListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080027import org.onosproject.net.intent.IntentService;
Brian O'Connor8016f342015-02-24 17:00:39 -080028import org.onosproject.net.intent.IntentState;
Ray Milkeyf9af43c2015-02-09 16:45:48 -080029import org.onosproject.net.intent.Key;
Brian O'Connora4cab072014-10-03 18:46:39 -070030
Thomas Vachuska4926c1b2014-10-21 00:44:10 -070031import java.math.BigInteger;
Brian O'Connor8016f342015-02-24 17:00:39 -080032import java.util.Objects;
33import java.util.concurrent.CountDownLatch;
34import java.util.concurrent.TimeUnit;
35
36import static org.onosproject.net.intent.IntentState.FAILED;
37import static org.onosproject.net.intent.IntentState.WITHDRAWN;
Thomas Vachuska4926c1b2014-10-21 00:44:10 -070038
Brian O'Connora4cab072014-10-03 18:46:39 -070039/**
Ray Milkey02479862015-02-17 17:02:19 -080040 * Removes an intent.
Brian O'Connora4cab072014-10-03 18:46:39 -070041 */
tom6db1f0a2014-10-07 09:12:29 -070042@Command(scope = "onos", name = "remove-intent",
43 description = "Removes the specified intent")
44public class IntentRemoveCommand extends AbstractShellCommand {
Brian O'Connora4cab072014-10-03 18:46:39 -070045
Ray Milkey02479862015-02-17 17:02:19 -080046 @Argument(index = 0, name = "app",
47 description = "Application ID",
48 required = true, multiValued = false)
49 String applicationIdString = null;
50
Brian O'Connor422b8752015-06-04 16:16:49 -070051 @Argument(index = 1, name = "key",
52 description = "Intent Key",
Brian O'Connora4cab072014-10-03 18:46:39 -070053 required = true, multiValued = false)
Brian O'Connor422b8752015-06-04 16:16:49 -070054 String keyString = null;
Brian O'Connora4cab072014-10-03 18:46:39 -070055
Brian O'Connor8016f342015-02-24 17:00:39 -080056 @Option(name = "-p", aliases = "--purge",
57 description = "Purge the intent from the store after removal",
58 required = false, multiValued = false)
59 private boolean purgeAfterRemove = false;
60
61 @Option(name = "-s", aliases = "--sync",
62 description = "Waits for the removal before returning",
63 required = false, multiValued = false)
64 private boolean sync = false;
65
Brian O'Connora4cab072014-10-03 18:46:39 -070066 @Override
67 protected void execute() {
Ray Milkey02479862015-02-17 17:02:19 -080068 IntentService intentService = get(IntentService.class);
69 CoreService coreService = get(CoreService.class);
70
71 ApplicationId appId = appId();
72 if (applicationIdString != null) {
73 appId = coreService.getAppId(applicationIdString);
74 if (appId == null) {
75 print("Cannot find application Id %s", applicationIdString);
76 return;
77 }
78 }
Brian O'Connora4cab072014-10-03 18:46:39 -070079
Pingping Lin08c30662015-06-04 15:32:15 -070080 final Key key;
Brian O'Connor422b8752015-06-04 16:16:49 -070081 if (keyString.startsWith("0x")) {
82 // The intent uses a LongKey
83 keyString = keyString.replaceFirst("0x", "");
84 key = Key.of(new BigInteger(keyString, 16).longValue(), appId);
Pingping Lin08c30662015-06-04 15:32:15 -070085 } else {
Brian O'Connor422b8752015-06-04 16:16:49 -070086 // The intent uses a StringKey
87 key = Key.of(keyString, appId);
Brian O'Connora4cab072014-10-03 18:46:39 -070088 }
Brian O'Connora4cab072014-10-03 18:46:39 -070089
Ray Milkey02479862015-02-17 17:02:19 -080090 Intent intent = intentService.getIntent(key);
Brian O'Connora4cab072014-10-03 18:46:39 -070091 if (intent != null) {
Ray Milkey8c6d00e2015-03-13 14:14:34 -070092 IntentListener listener = null;
93 final CountDownLatch withdrawLatch, purgeLatch;
94 if (purgeAfterRemove || sync) {
95 // set up latch and listener to track uninstall progress
96 withdrawLatch = new CountDownLatch(1);
97 purgeLatch = purgeAfterRemove ? new CountDownLatch(1) : null;
98 listener = (IntentEvent event) -> {
99 if (Objects.equals(event.subject().key(), key)) {
100 if (event.type() == IntentEvent.Type.WITHDRAWN ||
101 event.type() == IntentEvent.Type.FAILED) {
102 withdrawLatch.countDown();
103 } else if (purgeAfterRemove &&
104 event.type() == IntentEvent.Type.PURGED) {
105 purgeLatch.countDown();
106 }
107 }
108 };
109 intentService.addListener(listener);
110 } else {
111 purgeLatch = null;
112 withdrawLatch = null;
113 }
Brian O'Connor8016f342015-02-24 17:00:39 -0800114
115 // request the withdraw
Ray Milkey02479862015-02-17 17:02:19 -0800116 intentService.withdraw(intent);
Brian O'Connor8016f342015-02-24 17:00:39 -0800117
118 if (purgeAfterRemove || sync) {
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700119 try { // wait for withdraw event
120 withdrawLatch.await(5, TimeUnit.SECONDS);
Brian O'Connor8016f342015-02-24 17:00:39 -0800121 } catch (InterruptedException e) {
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700122 print("Timed out waiting for intent {} withdraw", key);
Brian O'Connor8016f342015-02-24 17:00:39 -0800123 }
124 // double check the state
125 IntentState state = intentService.getIntentState(key);
126 if (purgeAfterRemove && (state == WITHDRAWN || state == FAILED)) {
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700127 intentService.purge(intent);
128 }
129 if (sync) { // wait for purge event
130 /* TODO
131 Technically, the event comes before map.remove() is called.
132 If we depend on sync and purge working together, we will
133 need to address this.
134 */
135 try {
136 purgeLatch.await(5, TimeUnit.SECONDS);
137 } catch (InterruptedException e) {
138 print("Timed out waiting for intent {} purge", key);
139 }
Brian O'Connor8016f342015-02-24 17:00:39 -0800140 }
141 }
Brian O'Connor8016f342015-02-24 17:00:39 -0800142
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700143 if (listener != null) {
144 // clean up the listener
145 intentService.removeListener(listener);
146 }
147 }
Brian O'Connora4cab072014-10-03 18:46:39 -0700148 }
149}