blob: f0ce167b43e03a42a4a6ddd27d27534b80267b07 [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
51 @Argument(index = 1, name = "id",
52 description = "Intent ID",
Brian O'Connora4cab072014-10-03 18:46:39 -070053 required = true, multiValued = false)
54 String id = null;
55
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;
Thomas Vachuska4926c1b2014-10-21 00:44:10 -070081 if (id.startsWith("0x")) {
Brian O'Connora4cab072014-10-03 18:46:39 -070082 id = id.replaceFirst("0x", "");
Pingping Lin08c30662015-06-04 15:32:15 -070083 key = Key.of(new BigInteger(id, 16).longValue(), appId);
84 } else {
85 // This line is to use the intent key to delete an intent
86 key = Key.of(id, appId);
Brian O'Connora4cab072014-10-03 18:46:39 -070087 }
Brian O'Connora4cab072014-10-03 18:46:39 -070088
Ray Milkey02479862015-02-17 17:02:19 -080089 Intent intent = intentService.getIntent(key);
Brian O'Connora4cab072014-10-03 18:46:39 -070090 if (intent != null) {
Ray Milkey8c6d00e2015-03-13 14:14:34 -070091 IntentListener listener = null;
92 final CountDownLatch withdrawLatch, purgeLatch;
93 if (purgeAfterRemove || sync) {
94 // set up latch and listener to track uninstall progress
95 withdrawLatch = new CountDownLatch(1);
96 purgeLatch = purgeAfterRemove ? new CountDownLatch(1) : null;
97 listener = (IntentEvent event) -> {
98 if (Objects.equals(event.subject().key(), key)) {
99 if (event.type() == IntentEvent.Type.WITHDRAWN ||
100 event.type() == IntentEvent.Type.FAILED) {
101 withdrawLatch.countDown();
102 } else if (purgeAfterRemove &&
103 event.type() == IntentEvent.Type.PURGED) {
104 purgeLatch.countDown();
105 }
106 }
107 };
108 intentService.addListener(listener);
109 } else {
110 purgeLatch = null;
111 withdrawLatch = null;
112 }
Brian O'Connor8016f342015-02-24 17:00:39 -0800113
114 // request the withdraw
Ray Milkey02479862015-02-17 17:02:19 -0800115 intentService.withdraw(intent);
Brian O'Connor8016f342015-02-24 17:00:39 -0800116
117 if (purgeAfterRemove || sync) {
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700118 try { // wait for withdraw event
119 withdrawLatch.await(5, TimeUnit.SECONDS);
Brian O'Connor8016f342015-02-24 17:00:39 -0800120 } catch (InterruptedException e) {
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700121 print("Timed out waiting for intent {} withdraw", key);
Brian O'Connor8016f342015-02-24 17:00:39 -0800122 }
123 // double check the state
124 IntentState state = intentService.getIntentState(key);
125 if (purgeAfterRemove && (state == WITHDRAWN || state == FAILED)) {
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700126 intentService.purge(intent);
127 }
128 if (sync) { // wait for purge event
129 /* TODO
130 Technically, the event comes before map.remove() is called.
131 If we depend on sync and purge working together, we will
132 need to address this.
133 */
134 try {
135 purgeLatch.await(5, TimeUnit.SECONDS);
136 } catch (InterruptedException e) {
137 print("Timed out waiting for intent {} purge", key);
138 }
Brian O'Connor8016f342015-02-24 17:00:39 -0800139 }
140 }
Brian O'Connor8016f342015-02-24 17:00:39 -0800141
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700142 if (listener != null) {
143 // clean up the listener
144 intentService.removeListener(listener);
145 }
146 }
Brian O'Connora4cab072014-10-03 18:46:39 -0700147 }
148}