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