blob: ea2c67c0b12435340abdaaee0bc7bfeab8a8ce25 [file] [log] [blame]
Thomas Vachuska7d693f52014-10-21 19:17:57 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present 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.IntentState;
suibin zhangbaa163f2015-08-06 09:22:24 -070026import org.onosproject.net.intent.IntentService;
27import org.onosproject.net.intent.IntentListener;
28import org.onosproject.net.intent.IntentEvent;
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;
suibin zhangbaa163f2015-08-06 09:22:24 -070032import java.util.EnumSet;
Brian O'Connor8016f342015-02-24 17:00:39 -080033import java.util.Objects;
34import java.util.concurrent.CountDownLatch;
35import java.util.concurrent.TimeUnit;
36
Thomas Vachuska33937c42015-07-15 17:40:32 -070037import static com.google.common.base.Strings.isNullOrEmpty;
Brian O'Connor8016f342015-02-24 17:00:39 -080038import static org.onosproject.net.intent.IntentState.FAILED;
39import static org.onosproject.net.intent.IntentState.WITHDRAWN;
Thomas Vachuska4926c1b2014-10-21 00:44:10 -070040
Brian O'Connora4cab072014-10-03 18:46:39 -070041/**
Ray Milkey02479862015-02-17 17:02:19 -080042 * Removes an intent.
Brian O'Connora4cab072014-10-03 18:46:39 -070043 */
tom6db1f0a2014-10-07 09:12:29 -070044@Command(scope = "onos", name = "remove-intent",
Thomas Vachuska33937c42015-07-15 17:40:32 -070045 description = "Removes the specified intent")
tom6db1f0a2014-10-07 09:12:29 -070046public class IntentRemoveCommand extends AbstractShellCommand {
Brian O'Connora4cab072014-10-03 18:46:39 -070047
Ray Milkey02479862015-02-17 17:02:19 -080048 @Argument(index = 0, name = "app",
Thomas Vachuska33937c42015-07-15 17:40:32 -070049 description = "Application ID",
50 required = false, multiValued = false)
Ray Milkey02479862015-02-17 17:02:19 -080051 String applicationIdString = null;
52
Brian O'Connor422b8752015-06-04 16:16:49 -070053 @Argument(index = 1, name = "key",
Thomas Vachuska33937c42015-07-15 17:40:32 -070054 description = "Intent Key",
55 required = false, multiValued = false)
Brian O'Connor422b8752015-06-04 16:16:49 -070056 String keyString = null;
Brian O'Connora4cab072014-10-03 18:46:39 -070057
Brian O'Connor8016f342015-02-24 17:00:39 -080058 @Option(name = "-p", aliases = "--purge",
59 description = "Purge the intent from the store after removal",
60 required = false, multiValued = false)
61 private boolean purgeAfterRemove = false;
62
63 @Option(name = "-s", aliases = "--sync",
64 description = "Waits for the removal before returning",
65 required = false, multiValued = false)
66 private boolean sync = false;
67
suibin zhangbaa163f2015-08-06 09:22:24 -070068 private static final EnumSet<IntentState> CAN_PURGE = EnumSet.of(WITHDRAWN, FAILED);
69
Brian O'Connora4cab072014-10-03 18:46:39 -070070 @Override
71 protected void execute() {
Ray Milkey02479862015-02-17 17:02:19 -080072 IntentService intentService = get(IntentService.class);
73 CoreService coreService = get(CoreService.class);
74
suibin zhang5e897b72015-08-06 10:02:18 -070075 if (purgeAfterRemove || sync) {
76 print("Using \"sync\" to remove/purge intents - this may take a while...");
77 print("Check \"summary\" to see remove/purge progress.");
suibin zhangbaa163f2015-08-06 09:22:24 -070078 }
79
Ray Milkey02479862015-02-17 17:02:19 -080080 ApplicationId appId = appId();
Thomas Vachuska33937c42015-07-15 17:40:32 -070081 if (!isNullOrEmpty(applicationIdString)) {
Ray Milkey02479862015-02-17 17:02:19 -080082 appId = coreService.getAppId(applicationIdString);
83 if (appId == null) {
84 print("Cannot find application Id %s", applicationIdString);
85 return;
86 }
87 }
Brian O'Connora4cab072014-10-03 18:46:39 -070088
Thomas Vachuska33937c42015-07-15 17:40:32 -070089 if (isNullOrEmpty(keyString)) {
90 for (Intent intent : intentService.getIntents()) {
91 if (intent.appId().equals(appId)) {
92 removeIntent(intentService, intent);
93 }
Ray Milkey8c6d00e2015-03-13 14:14:34 -070094 }
Brian O'Connor8016f342015-02-24 17:00:39 -080095
Thomas Vachuska33937c42015-07-15 17:40:32 -070096 } else {
97 final Key key;
98 if (keyString.startsWith("0x")) {
99 // The intent uses a LongKey
100 keyString = keyString.replaceFirst("0x", "");
101 key = Key.of(new BigInteger(keyString, 16).longValue(), appId);
102 } else {
103 // The intent uses a StringKey
104 key = Key.of(keyString, appId);
105 }
Brian O'Connor8016f342015-02-24 17:00:39 -0800106
Thomas Vachuska33937c42015-07-15 17:40:32 -0700107 Intent intent = intentService.getIntent(key);
108 if (intent != null) {
109 removeIntent(intentService, intent);
110 }
111 }
112 }
113
114 private void removeIntent(IntentService intentService, Intent intent) {
115 IntentListener listener = null;
116 Key key = intent.key();
117 final CountDownLatch withdrawLatch, purgeLatch;
118 if (purgeAfterRemove || sync) {
119 // set up latch and listener to track uninstall progress
120 withdrawLatch = new CountDownLatch(1);
121 purgeLatch = purgeAfterRemove ? new CountDownLatch(1) : null;
122 listener = (IntentEvent event) -> {
123 if (Objects.equals(event.subject().key(), key)) {
124 if (event.type() == IntentEvent.Type.WITHDRAWN ||
125 event.type() == IntentEvent.Type.FAILED) {
126 withdrawLatch.countDown();
127 } else if (purgeAfterRemove &&
128 event.type() == IntentEvent.Type.PURGED) {
129 purgeLatch.countDown();
130 }
Brian O'Connor8016f342015-02-24 17:00:39 -0800131 }
Thomas Vachuska33937c42015-07-15 17:40:32 -0700132 };
133 intentService.addListener(listener);
134 } else {
135 purgeLatch = null;
136 withdrawLatch = null;
137 }
138
139 // request the withdraw
140 intentService.withdraw(intent);
141
142 if (purgeAfterRemove || sync) {
143 try { // wait for withdraw event
144 withdrawLatch.await(5, TimeUnit.SECONDS);
145 } catch (InterruptedException e) {
146 print("Timed out waiting for intent {} withdraw", key);
147 }
suibin zhangbaa163f2015-08-06 09:22:24 -0700148 if (purgeAfterRemove && CAN_PURGE.contains(intentService.getIntentState(key))) {
Thomas Vachuska33937c42015-07-15 17:40:32 -0700149 intentService.purge(intent);
suibin zhangbaa163f2015-08-06 09:22:24 -0700150 if (sync) { // wait for purge event
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700151 /* TODO
152 Technically, the event comes before map.remove() is called.
153 If we depend on sync and purge working together, we will
154 need to address this.
155 */
suibin zhangbaa163f2015-08-06 09:22:24 -0700156 try {
157 purgeLatch.await(5, TimeUnit.SECONDS);
158 } catch (InterruptedException e) {
159 print("Timed out waiting for intent {} purge", key);
160 }
Brian O'Connor8016f342015-02-24 17:00:39 -0800161 }
162 }
Thomas Vachuska33937c42015-07-15 17:40:32 -0700163 }
Brian O'Connor8016f342015-02-24 17:00:39 -0800164
Thomas Vachuska33937c42015-07-15 17:40:32 -0700165 if (listener != null) {
166 // clean up the listener
167 intentService.removeListener(listener);
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700168 }
Brian O'Connora4cab072014-10-03 18:46:39 -0700169 }
170}