blob: 2f296452ddc72e740969618297e0b27ae9f35210 [file] [log] [blame]
Brian O'Connorcff03322015-02-03 15:28:59 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Brian O'Connorcff03322015-02-03 15:28:59 -08003 *
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 */
16package org.onosproject.net.intent;
17
Brian O'Connor9476fa12015-06-25 15:17:17 -040018import com.google.common.annotations.Beta;
Ray Milkey65cb59a2015-02-10 15:18:26 -080019import com.google.common.base.MoreObjects;
Brian O'Connorcff03322015-02-03 15:28:59 -080020import com.google.common.collect.ImmutableList;
Brian O'Connor5eb77c82015-03-02 18:09:39 -080021import org.onosproject.cluster.NodeId;
Brian O'Connorcff03322015-02-03 15:28:59 -080022import org.onosproject.store.Timestamp;
Jonathan Hart72175c22015-03-24 18:55:58 -070023import org.slf4j.Logger;
24import org.slf4j.LoggerFactory;
Brian O'Connorcff03322015-02-03 15:28:59 -080025
Brian O'Connorf0c5a052015-04-27 00:34:53 -070026import java.util.Collections;
Brian O'Connorcff03322015-02-03 15:28:59 -080027import java.util.List;
28import java.util.Objects;
29
Jonathan Hart0d18df32015-03-21 08:42:59 -070030import static com.google.common.base.Preconditions.checkNotNull;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070031import static org.onosproject.net.intent.IntentState.*;
Jonathan Hart0d18df32015-03-21 08:42:59 -070032
Brian O'Connorcff03322015-02-03 15:28:59 -080033/**
34 * A wrapper class that contains an intents, its state, and other metadata for
35 * internal use.
36 */
Brian O'Connor9476fa12015-06-25 15:17:17 -040037@Beta
Brian O'Connorcff03322015-02-03 15:28:59 -080038public class IntentData { //FIXME need to make this "immutable"
39 // manager should be able to mutate a local copy while processing
Jonathan Hart72175c22015-03-24 18:55:58 -070040
41 private static final Logger log = LoggerFactory.getLogger(IntentData.class);
42
Jonathan Hart0d18df32015-03-21 08:42:59 -070043 private final Intent intent;
Brian O'Connorcff03322015-02-03 15:28:59 -080044
Brian O'Connorf0c5a052015-04-27 00:34:53 -070045 private final IntentState request; //TODO perhaps we want a full fledged object for requests
Brian O'Connorcff03322015-02-03 15:28:59 -080046 private IntentState state;
Sho SHIMIZUcbcc02b2016-03-31 13:22:42 -070047 private final Timestamp version;
Brian O'Connor5eb77c82015-03-02 18:09:39 -080048 private NodeId origin;
Brian O'Connor6d8e3172015-04-30 15:43:57 -070049 private int errorCount;
Brian O'Connorcff03322015-02-03 15:28:59 -080050
51 private List<Intent> installables;
52
Jonathan Hart0d18df32015-03-21 08:42:59 -070053 /**
54 * Creates a new intent data object.
55 *
56 * @param intent intent this metadata references
57 * @param state intent state
58 * @param version version of the intent for this key
59 */
Brian O'Connorcff03322015-02-03 15:28:59 -080060 public IntentData(Intent intent, IntentState state, Timestamp version) {
Sho SHIMIZU70b88d82016-01-19 14:27:22 -080061 checkNotNull(intent);
62 checkNotNull(state);
63
Brian O'Connorcff03322015-02-03 15:28:59 -080064 this.intent = intent;
65 this.state = state;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070066 this.request = state;
Brian O'Connorcff03322015-02-03 15:28:59 -080067 this.version = version;
68 }
69
Jonathan Hart0d18df32015-03-21 08:42:59 -070070 /**
Sho SHIMIZU2f26fb22016-01-19 14:04:46 -080071 * Creates a new intent data object.
72 *
73 * @param intent intent this metadata references
74 * @param state intent state
75 * @param version version of the intent for this key
76 * @param origin ID of the node where the data was originally created
77 */
78 public IntentData(Intent intent, IntentState state, Timestamp version, NodeId origin) {
79 checkNotNull(intent);
80 checkNotNull(state);
81 checkNotNull(version);
82 checkNotNull(origin);
83
84 this.intent = intent;
85 this.state = state;
86 this.request = state;
87 this.version = version;
88 this.origin = origin;
89 }
90
91 /**
Brian O'Connorc590ebb2016-12-08 18:16:41 -080092 * Creates a new intent data object.
93 *
94 * @param intent intent this metadata references
95 * @param state intent state
96 * @param request intent request
97 * @param version version of the intent for this key
98 * @param origin ID of the node where the data was originally created
99 */
100 public IntentData(Intent intent, IntentState state, IntentState request, Timestamp version, NodeId origin) {
101 checkNotNull(intent);
102 checkNotNull(state);
103 checkNotNull(request);
104 checkNotNull(version);
105 checkNotNull(origin);
106
107 this.intent = intent;
108 this.state = state;
109 this.request = request;
110 this.version = version;
111 this.origin = origin;
112 }
113
114 /**
Jonathan Hart0d18df32015-03-21 08:42:59 -0700115 * Copy constructor.
116 *
117 * @param intentData intent data to copy
118 */
119 public IntentData(IntentData intentData) {
120 checkNotNull(intentData);
121
122 intent = intentData.intent;
123 state = intentData.state;
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700124 request = intentData.request;
Jonathan Hart0d18df32015-03-21 08:42:59 -0700125 version = intentData.version;
126 origin = intentData.origin;
127 installables = intentData.installables;
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700128 errorCount = intentData.errorCount;
Brian O'Connorcff03322015-02-03 15:28:59 -0800129 }
130
Sho SHIMIZU2f26fb22016-01-19 14:04:46 -0800131 /**
132 * Create a new instance based on the original instance with new installables.
133 *
134 * @param original original data
135 * @param installables new installable intents to set
136 */
137 public IntentData(IntentData original, List<Intent> installables) {
138 this(original);
139
Brian O'Connora78f0602016-09-22 10:56:08 -0700140 this.installables = checkNotNull(installables).isEmpty() ?
141 Collections.emptyList() : ImmutableList.copyOf(installables);
Sho SHIMIZU2f26fb22016-01-19 14:04:46 -0800142 }
143
Jonathan Hart0d18df32015-03-21 08:42:59 -0700144 // kryo constructor
145 protected IntentData() {
146 intent = null;
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700147 request = null;
Sho SHIMIZUcbcc02b2016-03-31 13:22:42 -0700148 version = null;
Jonathan Hart0d18df32015-03-21 08:42:59 -0700149 }
150
151 /**
152 * Returns the intent this metadata references.
153 *
154 * @return intent
155 */
Brian O'Connorcff03322015-02-03 15:28:59 -0800156 public Intent intent() {
157 return intent;
158 }
159
Jonathan Hart0d18df32015-03-21 08:42:59 -0700160 /**
161 * Returns the state of the intent.
162 *
163 * @return intent state
164 */
Brian O'Connorcff03322015-02-03 15:28:59 -0800165 public IntentState state() {
166 return state;
167 }
168
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700169 public IntentState request() {
170 return request;
171 }
172
Jonathan Hart0d18df32015-03-21 08:42:59 -0700173 /**
174 * Returns the intent key.
175 *
176 * @return intent key
177 */
Ray Milkey5b3717e2015-02-05 11:44:08 -0800178 public Key key() {
Brian O'Connorcff03322015-02-03 15:28:59 -0800179 return intent.key();
180 }
181
Jonathan Hart0d18df32015-03-21 08:42:59 -0700182 /**
183 * Returns the version of the intent for this key.
184 *
185 * @return intent version
186 */
Brian O'Connor2ba63fd2015-02-09 22:48:11 -0800187 public Timestamp version() {
188 return version;
189 }
190
Brian O'Connor5eb77c82015-03-02 18:09:39 -0800191 /**
Jonathan Hart0d18df32015-03-21 08:42:59 -0700192 * Returns the origin node that created this intent.
193 *
194 * @return origin node ID
195 */
Brian O'Connor5eb77c82015-03-02 18:09:39 -0800196 public NodeId origin() {
197 return origin;
198 }
199
Jonathan Hart0d18df32015-03-21 08:42:59 -0700200 /**
201 * Updates the state of the intent to the given new state.
202 *
203 * @param newState new state of the intent
204 */
Brian O'Connorcff03322015-02-03 15:28:59 -0800205 public void setState(IntentState newState) {
206 this.state = newState;
207 }
208
Brian O'Connor2ba63fd2015-02-09 22:48:11 -0800209 /**
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700210 * Increments the error count for this intent.
211 */
212 public void incrementErrorCount() {
213 errorCount++;
214 }
215
216 /**
217 * Sets the error count for this intent.
218 *
219 * @param newCount new count
220 */
221 public void setErrorCount(int newCount) {
222 errorCount = newCount;
223 }
224
225 /**
226 * Returns the number of times that this intent has encountered an error
227 * during installation or withdrawal.
228 *
229 * @return error count
230 */
231 public int errorCount() {
232 return errorCount;
233 }
234
235 /**
Jonathan Hart0d18df32015-03-21 08:42:59 -0700236 * Returns the installables associated with this intent.
237 *
238 * @return list of installable intents
239 */
Brian O'Connorcff03322015-02-03 15:28:59 -0800240 public List<Intent> installables() {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700241 return installables != null ? installables : Collections.emptyList();
Brian O'Connorcff03322015-02-03 15:28:59 -0800242 }
243
Jonathan Hart72175c22015-03-24 18:55:58 -0700244 /**
245 * Determines whether an intent data update is allowed. The update must
246 * either have a higher version than the current data, or the state
247 * transition between two updates of the same version must be sane.
248 *
249 * @param currentData existing intent data in the store
250 * @param newData new intent data update proposal
251 * @return true if we can apply the update, otherwise false
252 */
253 public static boolean isUpdateAcceptable(IntentData currentData, IntentData newData) {
254
255 if (currentData == null) {
256 return true;
Sho SHIMIZU2c05f912015-04-10 14:23:16 -0700257 } else if (currentData.version().isOlderThan(newData.version())) {
Jonathan Hart72175c22015-03-24 18:55:58 -0700258 return true;
Sho SHIMIZU2c05f912015-04-10 14:23:16 -0700259 } else if (currentData.version().isNewerThan(newData.version())) {
Yuta HIGUCHIf76f6d52017-05-15 18:02:09 -0700260 log.trace("{} update not acceptable: current is newer", newData.key());
Jonathan Hart72175c22015-03-24 18:55:58 -0700261 return false;
262 }
263
264 // current and new data versions are the same
265 IntentState currentState = currentData.state();
266 IntentState newState = newData.state();
267
268 switch (newState) {
269 case INSTALLING:
270 if (currentState == INSTALLING) {
Yuta HIGUCHIf76f6d52017-05-15 18:02:09 -0700271 log.trace("{} update not acceptable: no-op INSTALLING", newData.key());
Jonathan Hart72175c22015-03-24 18:55:58 -0700272 return false;
273 }
274 // FALLTHROUGH
275 case INSTALLED:
276 if (currentState == INSTALLED) {
277 return false;
278 } else if (currentState == WITHDRAWING || currentState == WITHDRAWN
279 || currentState == PURGE_REQ) {
280 log.warn("Invalid state transition from {} to {} for intent {}",
281 currentState, newState, newData.key());
282 return false;
283 }
284 return true;
285
286 case WITHDRAWING:
287 if (currentState == WITHDRAWING) {
Yuta HIGUCHIf76f6d52017-05-15 18:02:09 -0700288 log.trace("{} update not acceptable: no-op WITHDRAWING", newData.key());
Jonathan Hart72175c22015-03-24 18:55:58 -0700289 return false;
290 }
291 // FALLTHROUGH
292 case WITHDRAWN:
293 if (currentState == WITHDRAWN) {
Yuta HIGUCHIf76f6d52017-05-15 18:02:09 -0700294 log.trace("{} update not acceptable: no-op WITHDRAWN", newData.key());
Jonathan Hart72175c22015-03-24 18:55:58 -0700295 return false;
296 } else if (currentState == INSTALLING || currentState == INSTALLED
297 || currentState == PURGE_REQ) {
298 log.warn("Invalid state transition from {} to {} for intent {}",
299 currentState, newState, newData.key());
300 return false;
301 }
302 return true;
303
304 case FAILED:
305 if (currentState == FAILED) {
Yuta HIGUCHIf76f6d52017-05-15 18:02:09 -0700306 log.trace("{} update not acceptable: no-op FAILED", newData.key());
Jonathan Hart72175c22015-03-24 18:55:58 -0700307 return false;
308 }
309 return true;
310
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700311 case CORRUPT:
312 if (currentState == CORRUPT) {
Yuta HIGUCHIf76f6d52017-05-15 18:02:09 -0700313 log.trace("{} update not acceptable: no-op CORRUPT", newData.key());
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700314 return false;
315 }
316 return true;
317
Jonathan Hart72175c22015-03-24 18:55:58 -0700318 case PURGE_REQ:
Brian O'Connor597934f2015-07-16 11:44:03 -0700319 // TODO we should enforce that only WITHDRAWN intents can be purged
Jonathan Hart72175c22015-03-24 18:55:58 -0700320 return true;
321
322 case COMPILING:
323 case RECOMPILING:
324 case INSTALL_REQ:
325 case WITHDRAW_REQ:
326 default:
327 log.warn("Invalid state {} for intent {}", newState, newData.key());
328 return false;
329 }
330 }
331
Brian O'Connorcff03322015-02-03 15:28:59 -0800332 @Override
333 public int hashCode() {
334 return Objects.hash(intent, version);
335 }
336
337 @Override
338 public boolean equals(Object obj) {
339 if (this == obj) {
340 return true;
341 }
342 if (obj == null || getClass() != obj.getClass()) {
343 return false;
344 }
345 final IntentData other = (IntentData) obj;
346 return Objects.equals(this.intent, other.intent)
347 && Objects.equals(this.version, other.version);
348 }
Ray Milkey65cb59a2015-02-10 15:18:26 -0800349
Jonathan Hart0d18df32015-03-21 08:42:59 -0700350 @Override
Ray Milkey65cb59a2015-02-10 15:18:26 -0800351 public String toString() {
352 return MoreObjects.toStringHelper(getClass())
353 .add("key", key())
354 .add("state", state())
355 .add("version", version())
Ray Milkey9f74c082015-02-11 15:40:16 -0800356 .add("intent", intent())
Jonathan Hart0d18df32015-03-21 08:42:59 -0700357 .add("origin", origin())
Jonathan Hartd0ba2172015-02-11 13:54:33 -0800358 .add("installables", installables())
Ray Milkey65cb59a2015-02-10 15:18:26 -0800359 .toString();
360 }
361
Brian O'Connorcff03322015-02-03 15:28:59 -0800362}