Thomas Vachuska

Adding STC scenario for testing host intent-based connectivity.

Change-Id: I7375a9fdb121a6a288df5d54a23cfbd9d54258f3
...@@ -33,6 +33,7 @@ import java.util.Objects; ...@@ -33,6 +33,7 @@ import java.util.Objects;
33 import java.util.concurrent.CountDownLatch; 33 import java.util.concurrent.CountDownLatch;
34 import java.util.concurrent.TimeUnit; 34 import java.util.concurrent.TimeUnit;
35 35
36 +import static com.google.common.base.Strings.isNullOrEmpty;
36 import static org.onosproject.net.intent.IntentState.FAILED; 37 import static org.onosproject.net.intent.IntentState.FAILED;
37 import static org.onosproject.net.intent.IntentState.WITHDRAWN; 38 import static org.onosproject.net.intent.IntentState.WITHDRAWN;
38 39
...@@ -40,17 +41,17 @@ import static org.onosproject.net.intent.IntentState.WITHDRAWN; ...@@ -40,17 +41,17 @@ import static org.onosproject.net.intent.IntentState.WITHDRAWN;
40 * Removes an intent. 41 * Removes an intent.
41 */ 42 */
42 @Command(scope = "onos", name = "remove-intent", 43 @Command(scope = "onos", name = "remove-intent",
43 - description = "Removes the specified intent") 44 + description = "Removes the specified intent")
44 public class IntentRemoveCommand extends AbstractShellCommand { 45 public class IntentRemoveCommand extends AbstractShellCommand {
45 46
46 @Argument(index = 0, name = "app", 47 @Argument(index = 0, name = "app",
47 - description = "Application ID", 48 + description = "Application ID",
48 - required = true, multiValued = false) 49 + required = false, multiValued = false)
49 String applicationIdString = null; 50 String applicationIdString = null;
50 51
51 @Argument(index = 1, name = "key", 52 @Argument(index = 1, name = "key",
52 - description = "Intent Key", 53 + description = "Intent Key",
53 - required = true, multiValued = false) 54 + required = false, multiValued = false)
54 String keyString = null; 55 String keyString = null;
55 56
56 @Option(name = "-p", aliases = "--purge", 57 @Option(name = "-p", aliases = "--purge",
...@@ -69,7 +70,7 @@ public class IntentRemoveCommand extends AbstractShellCommand { ...@@ -69,7 +70,7 @@ public class IntentRemoveCommand extends AbstractShellCommand {
69 CoreService coreService = get(CoreService.class); 70 CoreService coreService = get(CoreService.class);
70 71
71 ApplicationId appId = appId(); 72 ApplicationId appId = appId();
72 - if (applicationIdString != null) { 73 + if (!isNullOrEmpty(applicationIdString)) {
73 appId = coreService.getAppId(applicationIdString); 74 appId = coreService.getAppId(applicationIdString);
74 if (appId == null) { 75 if (appId == null) {
75 print("Cannot find application Id %s", applicationIdString); 76 print("Cannot find application Id %s", applicationIdString);
...@@ -77,73 +78,87 @@ public class IntentRemoveCommand extends AbstractShellCommand { ...@@ -77,73 +78,87 @@ public class IntentRemoveCommand extends AbstractShellCommand {
77 } 78 }
78 } 79 }
79 80
80 - final Key key; 81 + if (isNullOrEmpty(keyString)) {
81 - if (keyString.startsWith("0x")) { 82 + for (Intent intent : intentService.getIntents()) {
82 - // The intent uses a LongKey 83 + if (intent.appId().equals(appId)) {
83 - keyString = keyString.replaceFirst("0x", ""); 84 + removeIntent(intentService, intent);
84 - key = Key.of(new BigInteger(keyString, 16).longValue(), appId); 85 + }
85 - } else { 86 + }
86 - // The intent uses a StringKey
87 - key = Key.of(keyString, appId);
88 - }
89 87
90 - Intent intent = intentService.getIntent(key); 88 + } else {
91 - if (intent != null) { 89 + final Key key;
92 - IntentListener listener = null; 90 + if (keyString.startsWith("0x")) {
93 - final CountDownLatch withdrawLatch, purgeLatch; 91 + // The intent uses a LongKey
94 - if (purgeAfterRemove || sync) { 92 + keyString = keyString.replaceFirst("0x", "");
95 - // set up latch and listener to track uninstall progress 93 + key = Key.of(new BigInteger(keyString, 16).longValue(), appId);
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 { 94 } else {
111 - purgeLatch = null; 95 + // The intent uses a StringKey
112 - withdrawLatch = null; 96 + key = Key.of(keyString, appId);
113 } 97 }
114 98
115 - // request the withdraw 99 + Intent intent = intentService.getIntent(key);
116 - intentService.withdraw(intent); 100 + if (intent != null) {
101 + removeIntent(intentService, intent);
102 + }
103 + }
104 + }
117 105
118 - if (purgeAfterRemove || sync) { 106 + private void removeIntent(IntentService intentService, Intent intent) {
119 - try { // wait for withdraw event 107 + IntentListener listener = null;
120 - withdrawLatch.await(5, TimeUnit.SECONDS); 108 + Key key = intent.key();
121 - } catch (InterruptedException e) { 109 + final CountDownLatch withdrawLatch, purgeLatch;
122 - print("Timed out waiting for intent {} withdraw", key); 110 + if (purgeAfterRemove || sync) {
123 - } 111 + // set up latch and listener to track uninstall progress
124 - // double check the state 112 + withdrawLatch = new CountDownLatch(1);
125 - IntentState state = intentService.getIntentState(key); 113 + purgeLatch = purgeAfterRemove ? new CountDownLatch(1) : null;
126 - if (purgeAfterRemove && (state == WITHDRAWN || state == FAILED)) { 114 + listener = (IntentEvent event) -> {
127 - intentService.purge(intent); 115 + if (Objects.equals(event.subject().key(), key)) {
116 + if (event.type() == IntentEvent.Type.WITHDRAWN ||
117 + event.type() == IntentEvent.Type.FAILED) {
118 + withdrawLatch.countDown();
119 + } else if (purgeAfterRemove &&
120 + event.type() == IntentEvent.Type.PURGED) {
121 + purgeLatch.countDown();
122 + }
128 } 123 }
129 - if (sync) { // wait for purge event 124 + };
125 + intentService.addListener(listener);
126 + } else {
127 + purgeLatch = null;
128 + withdrawLatch = null;
129 + }
130 +
131 + // request the withdraw
132 + intentService.withdraw(intent);
133 +
134 + if (purgeAfterRemove || sync) {
135 + try { // wait for withdraw event
136 + withdrawLatch.await(5, TimeUnit.SECONDS);
137 + } catch (InterruptedException e) {
138 + print("Timed out waiting for intent {} withdraw", key);
139 + }
140 + // double check the state
141 + IntentState state = intentService.getIntentState(key);
142 + if (purgeAfterRemove && (state == WITHDRAWN || state == FAILED)) {
143 + intentService.purge(intent);
144 + }
145 + if (sync) { // wait for purge event
130 /* TODO 146 /* TODO
131 Technically, the event comes before map.remove() is called. 147 Technically, the event comes before map.remove() is called.
132 If we depend on sync and purge working together, we will 148 If we depend on sync and purge working together, we will
133 need to address this. 149 need to address this.
134 */ 150 */
135 - try { 151 + try {
136 - purgeLatch.await(5, TimeUnit.SECONDS); 152 + purgeLatch.await(5, TimeUnit.SECONDS);
137 - } catch (InterruptedException e) { 153 + } catch (InterruptedException e) {
138 - print("Timed out waiting for intent {} purge", key); 154 + print("Timed out waiting for intent {} purge", key);
139 - }
140 } 155 }
141 } 156 }
157 + }
142 158
143 - if (listener != null) { 159 + if (listener != null) {
144 - // clean up the listener 160 + // clean up the listener
145 - intentService.removeListener(listener); 161 + intentService.removeListener(listener);
146 - }
147 } 162 }
148 } 163 }
149 } 164 }
......
1 +<!--
2 + ~ Copyright 2015 Open Networking Laboratory
3 + ~
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 +<scenario name="net-host-intent" description="Network host intent connectivity test">
17 + <!-- TODO: parametrize this via recipes -->
18 + <group name="Host-Intent-Connectivity">
19 + <step name="Uninstall-Reactive-Forwarding"
20 + exec="onos ${OC1} app deactivate org.onosproject.fwd org.onosproject.ifwd"/>
21 +
22 + <step name="Find-Host-1" requires="^"
23 + exec="onos-mininet sendAndExpect h1 ping -c1 h4 --expect ."/>
24 + <step name="Find-Host-2" requires="^"
25 + exec="onos-mininet sendAndExpect h4 ping -c1 h1 --expect ."/>
26 +
27 + <step name="Create-Intent" requires="^"
28 + exec="onos ${OCI} add-host-intent 00:00:00:00:00:01/-1 00:00:00:00:00:04/-1"/>
29 +
30 + <import file="${ONOS_SCENARIOS}/net-link-down-up.xml" namespace="Host-Intent"/>
31 + <dependency name="Host-Intent.Net-Link-Down-Up" requires="Create-Intent"/>
32 +
33 + <step name="Remove-Intent" requires="Host-Intent.Net-Link-Down-Up"
34 + exec="onos ${OCI} remove-intent --purge"/>
35 + </group>
36 +</scenario>
...\ No newline at end of file ...\ No newline at end of file
...@@ -13,9 +13,9 @@ ...@@ -13,9 +13,9 @@
13 ~ See the License for the specific language governing permissions and 13 ~ See the License for the specific language governing permissions and
14 ~ limitations under the License. 14 ~ limitations under the License.
15 --> 15 -->
16 -<scenario name="net-link-up-down" description="Network link up-down test"> 16 +<scenario name="net-link-down-up" description="Network link up-down test">
17 <!-- TODO: parametrize this via recipes --> 17 <!-- TODO: parametrize this via recipes -->
18 - <group name="Net-Link-Up-Down"> 18 + <group name="Net-Link-Down-Up">
19 <step name="Ping-1" 19 <step name="Ping-1"
20 exec="onos-mininet sendAndExpect h1 ping -c1 h4 --expect \ 0% packet loss"/> 20 exec="onos-mininet sendAndExpect h1 ping -c1 h4 --expect \ 0% packet loss"/>
21 <step name="Link-1-Down" requires="Ping-1" 21 <step name="Link-1-Down" requires="Ping-1"
......
...@@ -17,13 +17,16 @@ ...@@ -17,13 +17,16 @@
17 <group name="Net-Smoke"> 17 <group name="Net-Smoke">
18 <import file="${ONOS_SCENARIOS}/net-setup.xml"/> 18 <import file="${ONOS_SCENARIOS}/net-setup.xml"/>
19 19
20 - <import file="${ONOS_SCENARIOS}/net-pingall.xml"/> 20 + <import file="${ONOS_SCENARIOS}/net-pingall.xml" namespace="Reactive-Forwarding"/>
21 - <dependency name="Net-Pingall" requires="Net-Setup"/> 21 + <dependency name="Reactive-Forwarding.Net-Pingall" requires="Net-Setup"/>
22 22
23 - <import file="${ONOS_SCENARIOS}/net-link-up-down.xml"/> 23 + <import file="${ONOS_SCENARIOS}/net-link-down-up.xml" namespace="Reactive-Forwarding"/>
24 - <dependency name="Net-Link-Up-Down" requires="~Net-Pingall"/> 24 + <dependency name="Reactive-Forwarding.Net-Link-Down-Up" requires="~Reactive-Forwarding.Net-Pingall"/>
25 +
26 + <import file="${ONOS_SCENARIOS}/net-host-intent.xml"/>
27 + <dependency name="Host-Intent-Connectivity" requires="~Reactive-Forwarding.Net-Link-Down-Up"/>
25 28
26 <import file="${ONOS_SCENARIOS}/net-teardown.xml"/> 29 <import file="${ONOS_SCENARIOS}/net-teardown.xml"/>
27 - <dependency name="Net-Teardown" requires="~Net-Link-Up-Down"/> 30 + <dependency name="Net-Teardown" requires="~Host-Intent-Connectivity"/>
28 </group> 31 </group>
29 </scenario> 32 </scenario>
...\ No newline at end of file ...\ No newline at end of file
......