blob: 8f073e6a22b9c44b59c50b2c6df9ee25f6a257a9 [file] [log] [blame]
Brian Stanke11f6d532016-07-05 16:17:59 -04001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Brian Stanke11f6d532016-07-05 16:17:59 -04003 *
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 */
16
17package org.onosproject.cli.net.vnet;
18
19import org.apache.karaf.shell.commands.Argument;
20import org.apache.karaf.shell.commands.Command;
21import org.apache.karaf.shell.commands.Option;
22import org.onosproject.cli.AbstractShellCommand;
23import org.onosproject.core.ApplicationId;
24import org.onosproject.core.CoreService;
25import org.onosproject.incubator.net.virtual.NetworkId;
26import org.onosproject.incubator.net.virtual.VirtualNetworkService;
27import org.onosproject.net.intent.Intent;
28import org.onosproject.net.intent.IntentEvent;
29import org.onosproject.net.intent.IntentListener;
30import org.onosproject.net.intent.IntentService;
31import org.onosproject.net.intent.IntentState;
32import org.onosproject.net.intent.Key;
33
34import java.math.BigInteger;
35import java.util.EnumSet;
36import java.util.Objects;
37import java.util.concurrent.CountDownLatch;
38import java.util.concurrent.TimeUnit;
39
40import static com.google.common.base.Strings.isNullOrEmpty;
41import static org.onosproject.net.intent.IntentState.FAILED;
42import static org.onosproject.net.intent.IntentState.WITHDRAWN;
43
44/**
45 * Removes a virtual network intent.
46 */
47@Command(scope = "onos", name = "remove-vnet-intent",
48 description = "Removes the virtual network intent")
49public class VirtualNetworkIntentRemoveCommand extends AbstractShellCommand {
50
51 @Argument(index = 0, name = "networkId", description = "Network ID",
52 required = true, multiValued = false)
53 Long networkId = null;
54
55 @Argument(index = 1, name = "app",
56 description = "Application ID",
57 required = false, multiValued = false)
58 String applicationIdString = null;
59
60 @Argument(index = 2, name = "key",
61 description = "Intent Key",
62 required = false, multiValued = false)
63 String keyString = null;
64
65 @Option(name = "-p", aliases = "--purge",
66 description = "Purge the intent from the store after removal",
67 required = false, multiValued = false)
68 private boolean purgeAfterRemove = false;
69
70 @Option(name = "-s", aliases = "--sync",
71 description = "Waits for the removal before returning",
72 required = false, multiValued = false)
73 private boolean sync = false;
74
75 private static final EnumSet<IntentState> CAN_PURGE = EnumSet.of(WITHDRAWN, FAILED);
76
77 @Override
78 protected void execute() {
79 VirtualNetworkService service = get(VirtualNetworkService.class);
80 IntentService intentService = service.get(NetworkId.networkId(networkId), IntentService.class);
81 CoreService coreService = get(CoreService.class);
82
83 if (purgeAfterRemove || sync) {
84 print("Using \"sync\" to remove/purge intents - this may take a while...");
85 print("Check \"summary\" to see remove/purge progress.");
86 }
87
88 ApplicationId appId = appId();
89 if (!isNullOrEmpty(applicationIdString)) {
90 appId = coreService.getAppId(applicationIdString);
91 if (appId == null) {
92 print("Cannot find application Id %s", applicationIdString);
93 return;
94 }
95 }
96
97 if (isNullOrEmpty(keyString)) {
98 for (Intent intent : intentService.getIntents()) {
99 if (intent.appId().equals(appId)) {
100 removeIntent(intentService, intent);
101 }
102 }
103
104 } else {
105 final Key key;
106 if (keyString.startsWith("0x")) {
107 // The intent uses a LongKey
108 keyString = keyString.replaceFirst("0x", "");
109 key = Key.of(new BigInteger(keyString, 16).longValue(), appId);
110 } else {
111 // The intent uses a StringKey
112 key = Key.of(keyString, appId);
113 }
114
115 Intent intent = intentService.getIntent(key);
116 if (intent != null) {
117 removeIntent(intentService, intent);
118 } else {
119 print("Intent not found!");
120 }
121 }
122 }
123
124 /**
125 * Removes the intent using the specified intentService.
126 *
127 * @param intentService intent service
128 * @param intent intent
129 */
130 private void removeIntent(IntentService intentService, Intent intent) {
131 IntentListener listener = null;
132 Key key = intent.key();
133 final CountDownLatch withdrawLatch, purgeLatch;
134 if (purgeAfterRemove || sync) {
135 // set up latch and listener to track uninstall progress
136 withdrawLatch = new CountDownLatch(1);
137 purgeLatch = purgeAfterRemove ? new CountDownLatch(1) : null;
138 listener = (IntentEvent event) -> {
139 if (Objects.equals(event.subject().key(), key)) {
140 if (event.type() == IntentEvent.Type.WITHDRAWN ||
141 event.type() == IntentEvent.Type.FAILED) {
142 withdrawLatch.countDown();
143 } else if (purgeAfterRemove &&
144 event.type() == IntentEvent.Type.PURGED) {
145 purgeLatch.countDown();
146 }
147 }
148 };
149 intentService.addListener(listener);
150 } else {
151 purgeLatch = null;
152 withdrawLatch = null;
153 }
154
155 // request the withdraw
156 intentService.withdraw(intent);
157
158 if (purgeAfterRemove || sync) {
159 try { // wait for withdraw event
160 withdrawLatch.await(5, TimeUnit.SECONDS);
161 } catch (InterruptedException e) {
162 print("Timed out waiting for intent {} withdraw", key);
163 }
164 if (purgeAfterRemove && CAN_PURGE.contains(intentService.getIntentState(key))) {
165 intentService.purge(intent);
166 if (sync) { // wait for purge event
167 /* TODO
168 Technically, the event comes before map.remove() is called.
169 If we depend on sync and purge working together, we will
170 need to address this.
171 */
172 try {
173 purgeLatch.await(5, TimeUnit.SECONDS);
174 } catch (InterruptedException e) {
175 print("Timed out waiting for intent {} purge", key);
176 }
177 }
178 }
179 }
180
181 if (listener != null) {
182 // clean up the listener
183 intentService.removeListener(listener);
184 }
185 }
186}