blob: e24e14e0fcaa903f89292362ad2166a63df96502 [file] [log] [blame]
Brian O'Connorcff03322015-02-03 15:28:59 -08001/*
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 */
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;
47 private 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) {
61 this.intent = intent;
62 this.state = state;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070063 this.request = state;
Brian O'Connorcff03322015-02-03 15:28:59 -080064 this.version = version;
65 }
66
Jonathan Hart0d18df32015-03-21 08:42:59 -070067 /**
68 * Copy constructor.
69 *
70 * @param intentData intent data to copy
71 */
72 public IntentData(IntentData intentData) {
73 checkNotNull(intentData);
74
75 intent = intentData.intent;
76 state = intentData.state;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070077 request = intentData.request;
Jonathan Hart0d18df32015-03-21 08:42:59 -070078 version = intentData.version;
79 origin = intentData.origin;
80 installables = intentData.installables;
Brian O'Connor6d8e3172015-04-30 15:43:57 -070081 errorCount = intentData.errorCount;
Brian O'Connorcff03322015-02-03 15:28:59 -080082 }
83
Jonathan Hart0d18df32015-03-21 08:42:59 -070084 // kryo constructor
85 protected IntentData() {
86 intent = null;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070087 request = null;
Jonathan Hart0d18df32015-03-21 08:42:59 -070088 }
89
90 /**
91 * Returns the intent this metadata references.
92 *
93 * @return intent
94 */
Brian O'Connorcff03322015-02-03 15:28:59 -080095 public Intent intent() {
96 return intent;
97 }
98
Jonathan Hart0d18df32015-03-21 08:42:59 -070099 /**
100 * Returns the state of the intent.
101 *
102 * @return intent state
103 */
Brian O'Connorcff03322015-02-03 15:28:59 -0800104 public IntentState state() {
105 return state;
106 }
107
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700108 public IntentState request() {
109 return request;
110 }
111
Jonathan Hart0d18df32015-03-21 08:42:59 -0700112 /**
113 * Returns the intent key.
114 *
115 * @return intent key
116 */
Ray Milkey5b3717e2015-02-05 11:44:08 -0800117 public Key key() {
Brian O'Connorcff03322015-02-03 15:28:59 -0800118 return intent.key();
119 }
120
Jonathan Hart0d18df32015-03-21 08:42:59 -0700121 /**
122 * Returns the version of the intent for this key.
123 *
124 * @return intent version
125 */
Brian O'Connor2ba63fd2015-02-09 22:48:11 -0800126 public Timestamp version() {
127 return version;
128 }
129
Brian O'Connor5eb77c82015-03-02 18:09:39 -0800130 /**
Jonathan Hart0d18df32015-03-21 08:42:59 -0700131 * Sets the origin, which is the node that created the intent.
Brian O'Connor5eb77c82015-03-02 18:09:39 -0800132 *
133 * @param origin origin instance
134 */
135 public void setOrigin(NodeId origin) {
136 this.origin = origin;
137 }
138
Jonathan Hart0d18df32015-03-21 08:42:59 -0700139 /**
140 * Returns the origin node that created this intent.
141 *
142 * @return origin node ID
143 */
Brian O'Connor5eb77c82015-03-02 18:09:39 -0800144 public NodeId origin() {
145 return origin;
146 }
147
Jonathan Hart0d18df32015-03-21 08:42:59 -0700148 /**
149 * Updates the state of the intent to the given new state.
150 *
151 * @param newState new state of the intent
152 */
Brian O'Connorcff03322015-02-03 15:28:59 -0800153 public void setState(IntentState newState) {
154 this.state = newState;
155 }
156
Brian O'Connor2ba63fd2015-02-09 22:48:11 -0800157 /**
158 * Sets the version for this intent data.
159 * <p>
160 * The store should call this method only once when the IntentData is
161 * first passed into the pending map. Ideally, an IntentData is timestamped
162 * on the same thread that the called used to submit the intents.
163 * </p>
164 *
165 * @param version the version/timestamp for this intent data
166 */
167 public void setVersion(Timestamp version) {
168 this.version = version;
169 }
170
Jonathan Hart0d18df32015-03-21 08:42:59 -0700171 /**
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700172 * Increments the error count for this intent.
173 */
174 public void incrementErrorCount() {
175 errorCount++;
176 }
177
178 /**
179 * Sets the error count for this intent.
180 *
181 * @param newCount new count
182 */
183 public void setErrorCount(int newCount) {
184 errorCount = newCount;
185 }
186
187 /**
188 * Returns the number of times that this intent has encountered an error
189 * during installation or withdrawal.
190 *
191 * @return error count
192 */
193 public int errorCount() {
194 return errorCount;
195 }
196
197 /**
Jonathan Hart0d18df32015-03-21 08:42:59 -0700198 * Sets the intent installables to the given list of intents.
199 *
200 * @param installables list of installables for this intent
201 */
Brian O'Connorcff03322015-02-03 15:28:59 -0800202 public void setInstallables(List<Intent> installables) {
203 this.installables = ImmutableList.copyOf(installables);
204 }
205
Jonathan Hart0d18df32015-03-21 08:42:59 -0700206 /**
207 * Returns the installables associated with this intent.
208 *
209 * @return list of installable intents
210 */
Brian O'Connorcff03322015-02-03 15:28:59 -0800211 public List<Intent> installables() {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700212 return installables != null ? installables : Collections.emptyList();
Brian O'Connorcff03322015-02-03 15:28:59 -0800213 }
214
Jonathan Hart72175c22015-03-24 18:55:58 -0700215 /**
216 * Determines whether an intent data update is allowed. The update must
217 * either have a higher version than the current data, or the state
218 * transition between two updates of the same version must be sane.
219 *
220 * @param currentData existing intent data in the store
221 * @param newData new intent data update proposal
222 * @return true if we can apply the update, otherwise false
223 */
224 public static boolean isUpdateAcceptable(IntentData currentData, IntentData newData) {
225
226 if (currentData == null) {
227 return true;
Sho SHIMIZU2c05f912015-04-10 14:23:16 -0700228 } else if (currentData.version().isOlderThan(newData.version())) {
Jonathan Hart72175c22015-03-24 18:55:58 -0700229 return true;
Sho SHIMIZU2c05f912015-04-10 14:23:16 -0700230 } else if (currentData.version().isNewerThan(newData.version())) {
Jonathan Hart72175c22015-03-24 18:55:58 -0700231 return false;
232 }
233
234 // current and new data versions are the same
235 IntentState currentState = currentData.state();
236 IntentState newState = newData.state();
237
238 switch (newState) {
239 case INSTALLING:
240 if (currentState == INSTALLING) {
241 return false;
242 }
243 // FALLTHROUGH
244 case INSTALLED:
245 if (currentState == INSTALLED) {
246 return false;
247 } else if (currentState == WITHDRAWING || currentState == WITHDRAWN
248 || currentState == PURGE_REQ) {
249 log.warn("Invalid state transition from {} to {} for intent {}",
250 currentState, newState, newData.key());
251 return false;
252 }
253 return true;
254
255 case WITHDRAWING:
256 if (currentState == WITHDRAWING) {
257 return false;
258 }
259 // FALLTHROUGH
260 case WITHDRAWN:
261 if (currentState == WITHDRAWN) {
262 return false;
263 } else if (currentState == INSTALLING || currentState == INSTALLED
264 || currentState == PURGE_REQ) {
265 log.warn("Invalid state transition from {} to {} for intent {}",
266 currentState, newState, newData.key());
267 return false;
268 }
269 return true;
270
271 case FAILED:
272 if (currentState == FAILED) {
273 return false;
274 }
275 return true;
276
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700277 case CORRUPT:
278 if (currentState == CORRUPT) {
279 return false;
280 }
281 return true;
282
Jonathan Hart72175c22015-03-24 18:55:58 -0700283 case PURGE_REQ:
Brian O'Connor597934f2015-07-16 11:44:03 -0700284 // TODO we should enforce that only WITHDRAWN intents can be purged
Jonathan Hart72175c22015-03-24 18:55:58 -0700285 return true;
286
287 case COMPILING:
288 case RECOMPILING:
289 case INSTALL_REQ:
290 case WITHDRAW_REQ:
291 default:
292 log.warn("Invalid state {} for intent {}", newState, newData.key());
293 return false;
294 }
295 }
296
Brian O'Connorcff03322015-02-03 15:28:59 -0800297 @Override
298 public int hashCode() {
299 return Objects.hash(intent, version);
300 }
301
302 @Override
303 public boolean equals(Object obj) {
304 if (this == obj) {
305 return true;
306 }
307 if (obj == null || getClass() != obj.getClass()) {
308 return false;
309 }
310 final IntentData other = (IntentData) obj;
311 return Objects.equals(this.intent, other.intent)
312 && Objects.equals(this.version, other.version);
313 }
Ray Milkey65cb59a2015-02-10 15:18:26 -0800314
Jonathan Hart0d18df32015-03-21 08:42:59 -0700315 @Override
Ray Milkey65cb59a2015-02-10 15:18:26 -0800316 public String toString() {
317 return MoreObjects.toStringHelper(getClass())
318 .add("key", key())
319 .add("state", state())
320 .add("version", version())
Ray Milkey9f74c082015-02-11 15:40:16 -0800321 .add("intent", intent())
Jonathan Hart0d18df32015-03-21 08:42:59 -0700322 .add("origin", origin())
Jonathan Hartd0ba2172015-02-11 13:54:33 -0800323 .add("installables", installables())
Ray Milkey65cb59a2015-02-10 15:18:26 -0800324 .toString();
325 }
326
Brian O'Connorcff03322015-02-03 15:28:59 -0800327}