blob: c54c5bce863445c6e787b15affc9090e7f0ff7af [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
Ray Milkey65cb59a2015-02-10 15:18:26 -080018import com.google.common.base.MoreObjects;
Brian O'Connorcff03322015-02-03 15:28:59 -080019import com.google.common.collect.ImmutableList;
Brian O'Connor5eb77c82015-03-02 18:09:39 -080020import org.onosproject.cluster.NodeId;
Brian O'Connorcff03322015-02-03 15:28:59 -080021import org.onosproject.store.Timestamp;
Jonathan Hart72175c22015-03-24 18:55:58 -070022import org.slf4j.Logger;
23import org.slf4j.LoggerFactory;
Brian O'Connorcff03322015-02-03 15:28:59 -080024
Brian O'Connorf0c5a052015-04-27 00:34:53 -070025import java.util.Collections;
Brian O'Connorcff03322015-02-03 15:28:59 -080026import java.util.List;
27import java.util.Objects;
28
Jonathan Hart0d18df32015-03-21 08:42:59 -070029import static com.google.common.base.Preconditions.checkNotNull;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070030import static org.onosproject.net.intent.IntentState.*;
Jonathan Hart0d18df32015-03-21 08:42:59 -070031
Brian O'Connorcff03322015-02-03 15:28:59 -080032/**
33 * A wrapper class that contains an intents, its state, and other metadata for
34 * internal use.
35 */
36public class IntentData { //FIXME need to make this "immutable"
37 // manager should be able to mutate a local copy while processing
Jonathan Hart72175c22015-03-24 18:55:58 -070038
39 private static final Logger log = LoggerFactory.getLogger(IntentData.class);
40
Jonathan Hart0d18df32015-03-21 08:42:59 -070041 private final Intent intent;
Brian O'Connorcff03322015-02-03 15:28:59 -080042
Brian O'Connorf0c5a052015-04-27 00:34:53 -070043 private final IntentState request; //TODO perhaps we want a full fledged object for requests
Brian O'Connorcff03322015-02-03 15:28:59 -080044 private IntentState state;
45 private Timestamp version;
Brian O'Connor5eb77c82015-03-02 18:09:39 -080046 private NodeId origin;
Brian O'Connor6d8e3172015-04-30 15:43:57 -070047 private int errorCount;
Brian O'Connorcff03322015-02-03 15:28:59 -080048
49 private List<Intent> installables;
50
Jonathan Hart0d18df32015-03-21 08:42:59 -070051 /**
52 * Creates a new intent data object.
53 *
54 * @param intent intent this metadata references
55 * @param state intent state
56 * @param version version of the intent for this key
57 */
Brian O'Connorcff03322015-02-03 15:28:59 -080058 public IntentData(Intent intent, IntentState state, Timestamp version) {
59 this.intent = intent;
60 this.state = state;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070061 this.request = state;
Brian O'Connorcff03322015-02-03 15:28:59 -080062 this.version = version;
63 }
64
Jonathan Hart0d18df32015-03-21 08:42:59 -070065 /**
66 * Copy constructor.
67 *
68 * @param intentData intent data to copy
69 */
70 public IntentData(IntentData intentData) {
71 checkNotNull(intentData);
72
73 intent = intentData.intent;
74 state = intentData.state;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070075 request = intentData.request;
Jonathan Hart0d18df32015-03-21 08:42:59 -070076 version = intentData.version;
77 origin = intentData.origin;
78 installables = intentData.installables;
Brian O'Connor6d8e3172015-04-30 15:43:57 -070079 errorCount = intentData.errorCount;
Brian O'Connorcff03322015-02-03 15:28:59 -080080 }
81
Jonathan Hart0d18df32015-03-21 08:42:59 -070082 // kryo constructor
83 protected IntentData() {
84 intent = null;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070085 request = null;
Jonathan Hart0d18df32015-03-21 08:42:59 -070086 }
87
88 /**
89 * Returns the intent this metadata references.
90 *
91 * @return intent
92 */
Brian O'Connorcff03322015-02-03 15:28:59 -080093 public Intent intent() {
94 return intent;
95 }
96
Jonathan Hart0d18df32015-03-21 08:42:59 -070097 /**
98 * Returns the state of the intent.
99 *
100 * @return intent state
101 */
Brian O'Connorcff03322015-02-03 15:28:59 -0800102 public IntentState state() {
103 return state;
104 }
105
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700106 public IntentState request() {
107 return request;
108 }
109
Jonathan Hart0d18df32015-03-21 08:42:59 -0700110 /**
111 * Returns the intent key.
112 *
113 * @return intent key
114 */
Ray Milkey5b3717e2015-02-05 11:44:08 -0800115 public Key key() {
Brian O'Connorcff03322015-02-03 15:28:59 -0800116 return intent.key();
117 }
118
Jonathan Hart0d18df32015-03-21 08:42:59 -0700119 /**
120 * Returns the version of the intent for this key.
121 *
122 * @return intent version
123 */
Brian O'Connor2ba63fd2015-02-09 22:48:11 -0800124 public Timestamp version() {
125 return version;
126 }
127
Brian O'Connor5eb77c82015-03-02 18:09:39 -0800128 /**
Jonathan Hart0d18df32015-03-21 08:42:59 -0700129 * Sets the origin, which is the node that created the intent.
Brian O'Connor5eb77c82015-03-02 18:09:39 -0800130 *
131 * @param origin origin instance
132 */
133 public void setOrigin(NodeId origin) {
134 this.origin = origin;
135 }
136
Jonathan Hart0d18df32015-03-21 08:42:59 -0700137 /**
138 * Returns the origin node that created this intent.
139 *
140 * @return origin node ID
141 */
Brian O'Connor5eb77c82015-03-02 18:09:39 -0800142 public NodeId origin() {
143 return origin;
144 }
145
Jonathan Hart0d18df32015-03-21 08:42:59 -0700146 /**
147 * Updates the state of the intent to the given new state.
148 *
149 * @param newState new state of the intent
150 */
Brian O'Connorcff03322015-02-03 15:28:59 -0800151 public void setState(IntentState newState) {
152 this.state = newState;
153 }
154
Brian O'Connor2ba63fd2015-02-09 22:48:11 -0800155 /**
156 * Sets the version for this intent data.
157 * <p>
158 * The store should call this method only once when the IntentData is
159 * first passed into the pending map. Ideally, an IntentData is timestamped
160 * on the same thread that the called used to submit the intents.
161 * </p>
162 *
163 * @param version the version/timestamp for this intent data
164 */
165 public void setVersion(Timestamp version) {
166 this.version = version;
167 }
168
Jonathan Hart0d18df32015-03-21 08:42:59 -0700169 /**
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700170 * Increments the error count for this intent.
171 */
172 public void incrementErrorCount() {
173 errorCount++;
174 }
175
176 /**
177 * Sets the error count for this intent.
178 *
179 * @param newCount new count
180 */
181 public void setErrorCount(int newCount) {
182 errorCount = newCount;
183 }
184
185 /**
186 * Returns the number of times that this intent has encountered an error
187 * during installation or withdrawal.
188 *
189 * @return error count
190 */
191 public int errorCount() {
192 return errorCount;
193 }
194
195 /**
Jonathan Hart0d18df32015-03-21 08:42:59 -0700196 * Sets the intent installables to the given list of intents.
197 *
198 * @param installables list of installables for this intent
199 */
Brian O'Connorcff03322015-02-03 15:28:59 -0800200 public void setInstallables(List<Intent> installables) {
201 this.installables = ImmutableList.copyOf(installables);
202 }
203
Jonathan Hart0d18df32015-03-21 08:42:59 -0700204 /**
205 * Returns the installables associated with this intent.
206 *
207 * @return list of installable intents
208 */
Brian O'Connorcff03322015-02-03 15:28:59 -0800209 public List<Intent> installables() {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700210 return installables != null ? installables : Collections.emptyList();
Brian O'Connorcff03322015-02-03 15:28:59 -0800211 }
212
Jonathan Hart72175c22015-03-24 18:55:58 -0700213 /**
214 * Determines whether an intent data update is allowed. The update must
215 * either have a higher version than the current data, or the state
216 * transition between two updates of the same version must be sane.
217 *
218 * @param currentData existing intent data in the store
219 * @param newData new intent data update proposal
220 * @return true if we can apply the update, otherwise false
221 */
222 public static boolean isUpdateAcceptable(IntentData currentData, IntentData newData) {
223
224 if (currentData == null) {
225 return true;
Sho SHIMIZU2c05f912015-04-10 14:23:16 -0700226 } else if (currentData.version().isOlderThan(newData.version())) {
Jonathan Hart72175c22015-03-24 18:55:58 -0700227 return true;
Sho SHIMIZU2c05f912015-04-10 14:23:16 -0700228 } else if (currentData.version().isNewerThan(newData.version())) {
Jonathan Hart72175c22015-03-24 18:55:58 -0700229 return false;
230 }
231
232 // current and new data versions are the same
233 IntentState currentState = currentData.state();
234 IntentState newState = newData.state();
235
236 switch (newState) {
237 case INSTALLING:
238 if (currentState == INSTALLING) {
239 return false;
240 }
241 // FALLTHROUGH
242 case INSTALLED:
243 if (currentState == INSTALLED) {
244 return false;
245 } else if (currentState == WITHDRAWING || currentState == WITHDRAWN
246 || currentState == PURGE_REQ) {
247 log.warn("Invalid state transition from {} to {} for intent {}",
248 currentState, newState, newData.key());
249 return false;
250 }
251 return true;
252
253 case WITHDRAWING:
254 if (currentState == WITHDRAWING) {
255 return false;
256 }
257 // FALLTHROUGH
258 case WITHDRAWN:
259 if (currentState == WITHDRAWN) {
260 return false;
261 } else if (currentState == INSTALLING || currentState == INSTALLED
262 || currentState == PURGE_REQ) {
263 log.warn("Invalid state transition from {} to {} for intent {}",
264 currentState, newState, newData.key());
265 return false;
266 }
267 return true;
268
269 case FAILED:
270 if (currentState == FAILED) {
271 return false;
272 }
273 return true;
274
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700275 case CORRUPT:
276 if (currentState == CORRUPT) {
277 return false;
278 }
279 return true;
280
Jonathan Hart72175c22015-03-24 18:55:58 -0700281 case PURGE_REQ:
282 return true;
283
284 case COMPILING:
285 case RECOMPILING:
286 case INSTALL_REQ:
287 case WITHDRAW_REQ:
288 default:
289 log.warn("Invalid state {} for intent {}", newState, newData.key());
290 return false;
291 }
292 }
293
Brian O'Connorcff03322015-02-03 15:28:59 -0800294 @Override
295 public int hashCode() {
296 return Objects.hash(intent, version);
297 }
298
299 @Override
300 public boolean equals(Object obj) {
301 if (this == obj) {
302 return true;
303 }
304 if (obj == null || getClass() != obj.getClass()) {
305 return false;
306 }
307 final IntentData other = (IntentData) obj;
308 return Objects.equals(this.intent, other.intent)
309 && Objects.equals(this.version, other.version);
310 }
Ray Milkey65cb59a2015-02-10 15:18:26 -0800311
Jonathan Hart0d18df32015-03-21 08:42:59 -0700312 @Override
Ray Milkey65cb59a2015-02-10 15:18:26 -0800313 public String toString() {
314 return MoreObjects.toStringHelper(getClass())
315 .add("key", key())
316 .add("state", state())
317 .add("version", version())
Ray Milkey9f74c082015-02-11 15:40:16 -0800318 .add("intent", intent())
Jonathan Hart0d18df32015-03-21 08:42:59 -0700319 .add("origin", origin())
Jonathan Hartd0ba2172015-02-11 13:54:33 -0800320 .add("installables", installables())
Ray Milkey65cb59a2015-02-10 15:18:26 -0800321 .toString();
322 }
323
Brian O'Connorcff03322015-02-03 15:28:59 -0800324}