3 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
5 * This program and the accompanying materials are made available under the
6 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7 * and is available at http://www.eclipse.org/legal/epl-v10.html
10 package org.opendaylight.controller.containermanager;
12 import java.io.Serializable;
13 import java.util.ArrayList;
14 import java.util.HashSet;
15 import java.util.List;
18 import javax.xml.bind.annotation.XmlAccessType;
19 import javax.xml.bind.annotation.XmlAccessorType;
20 import javax.xml.bind.annotation.XmlElement;
21 import javax.xml.bind.annotation.XmlRootElement;
23 import org.opendaylight.controller.sal.core.ContainerFlow;
24 import org.opendaylight.controller.sal.core.NodeConnector;
25 import org.opendaylight.controller.sal.match.Match;
26 import org.opendaylight.controller.sal.utils.GlobalConstants;
27 import org.opendaylight.controller.sal.utils.Status;
28 import org.opendaylight.controller.sal.utils.StatusCode;
31 * Container Configuration Java Object for Container Manager Represents a container
32 * configuration information for Container Manager.
34 * Objects of this class are also serialized to and deserialized from binary
35 * files through java serialization API when saving to/reading from Container
36 * Manager startup configuration file.
38 @XmlRootElement(name = "container-config")
39 @XmlAccessorType(XmlAccessType.NONE)
40 public class ContainerConfig implements Serializable {
41 private static final long serialVersionUID = 2L;
42 private static final String regexName = "^\\w+$";
45 private String container;
48 private String staticVlan;
50 @XmlElement(name = "nodeConnectors")
51 private List<String> ports;
53 @XmlElement(name = "flowSpecs")
54 private List<ContainerFlowConfig> containerFlows;
56 public String getContainer() {
60 public void setContainer(String container) {
61 this.container = container;
64 public String getStaticVlan() {
68 public void setStaticVlan(String staticVlan) {
69 this.staticVlan = staticVlan;
72 public List<ContainerFlowConfig> getContainerFlows() {
73 return containerFlows;
76 public void setContainerFlows(List<ContainerFlowConfig> containerFlows) {
77 this.containerFlows = containerFlows;
80 public static long getSerialversionuid() {
81 return serialVersionUID;
84 public static String getRegexname() {
88 public void setPorts(List<String> ports) {
93 * Default constructor needed by Gson.
95 * @return a Default ContainerConfig
97 public ContainerConfig() {
98 this.container = null;
99 this.staticVlan = null;
100 this.ports = new ArrayList<String>(0);
101 this.containerFlows = new ArrayList<ContainerFlowConfig>(0);
105 * Constructor for the ContainerConfig.
108 * Name of the container in this configuration
110 * vlan assigned to this container
112 * the name of the node assigned to the container from this
115 * the list of NodeConnectors on the Node belonging to the container
116 * @return the constructed object
118 public ContainerConfig(String container, String vlan, List<String> portList, List<ContainerFlowConfig> containerFlows) {
119 this.container = container;
120 this.staticVlan = vlan;
121 this.ports = (portList == null) ? new ArrayList<String>(0) : new ArrayList<String>(portList);
122 this.containerFlows = (containerFlows == null) ? new ArrayList<ContainerFlowConfig>(0)
123 : new ArrayList<ContainerFlowConfig>(containerFlows);
126 public ContainerConfig(ContainerConfig config) {
127 this.container = config.container;
128 this.staticVlan = config.staticVlan;
129 this.ports = (config.ports == null) ? new ArrayList<String>(0) : new ArrayList<String>(config.ports);
130 this.containerFlows = (config.containerFlows == null) ? new ArrayList<ContainerFlowConfig>(0)
131 : new ArrayList<ContainerFlowConfig>(config.containerFlows);
135 * Returns the container name.
137 * @return the container name
139 public String getContainerName() {
144 * Returns the Vlan tag.
146 * @return the Vlan Tag configured for this container configuration
148 public String getVlanTag() {
153 * Returns the configured ports.
155 * @return the string with the list of ports associated to the container on this
158 public List<String> getPorts() {
159 return new ArrayList<String>(ports);
163 * Returns the list of container flows configured for this container
167 public List<ContainerFlowConfig> getContainerFlowConfigs() {
168 return (containerFlows == null || containerFlows.isEmpty()) ? new ArrayList<ContainerFlowConfig>(0)
169 : new ArrayList<ContainerFlowConfig>(containerFlows);
173 * Matches container name against passed parameter.
176 * name of the container to be matched
177 * @return true if the passed argument correspond with the container name in the
180 public boolean matchName(String name) {
181 return this.container.equals(name);
185 * Parse the port list in several NodeConnector descriptor.
187 * @return the list of NodeConnector corresponding to the ports configured
188 * on this configuration
190 public List<NodeConnector> getPortList() {
191 List<NodeConnector> portList = new ArrayList<NodeConnector>();
192 if (ports != null && !ports.isEmpty()) {
193 for (String portString : ports) {
194 portList.add(NodeConnector.fromString(portString));
201 * Checks if this is a valid container configuration
203 * @return true, if is valid container configuration, false otherwise
205 public Status validate() {
206 Status status = validateName();
207 if (status.isSuccess()) {
208 status = validateStaticVlan();
209 if (status.isSuccess()) {
210 status = validatePorts();
211 if (status.isSuccess()) {
212 status = validateContainerFlows();
220 * Checks for valid name.
222 * @return true, if successful
224 private Status validateName() {
225 // No Container configuration allowed to container default
226 return ((container != null) && container.matches(regexName) && !container.equalsIgnoreCase(GlobalConstants.DEFAULT.toString())) ?
227 new Status(StatusCode.SUCCESS) : new Status(StatusCode.BADREQUEST, "Invalid container name");
231 * Checks for valid ports.
233 * @return true, if successful
235 private Status validatePorts() {
236 return validateNodeConnectors(this.ports);
239 public static Status validateNodeConnectors(List<String> connectorList) {
240 if (connectorList != null && !connectorList.isEmpty()) {
241 for (String ncString : connectorList) {
242 if (NodeConnector.fromString(ncString) == null) {
243 return new Status(StatusCode.BADREQUEST, "Invalid node connector: " + ncString);
248 return new Status(StatusCode.SUCCESS);
251 public static List<NodeConnector> nodeConnectorsFromString(List<String> nodeConnectorStrings) {
252 List<NodeConnector> list = new ArrayList<NodeConnector>(nodeConnectorStrings.size());
253 for (String str : nodeConnectorStrings) {
254 list.add(NodeConnector.fromString(str));
260 * Checks for valid static vlan.
262 * @return true, if successful
264 private Status validateStaticVlan() {
265 if (staticVlan != null && !staticVlan.trim().isEmpty()) {
268 vl = Short.valueOf(staticVlan);
269 } catch (NumberFormatException e) {
270 return new Status(StatusCode.BADREQUEST, "Static Vlan Value must be between 1 and 4095");
272 if ((vl < 1) || (vl > 4095)) {
273 return new Status(StatusCode.BADREQUEST, "Static Vlan Value must be between 1 and 4095");
276 return new Status(StatusCode.SUCCESS);
279 private Status validateContainerFlows() {
280 if (containerFlows != null && !containerFlows.isEmpty()) {
281 for (ContainerFlowConfig conf : containerFlows) {
282 Status status = conf.validate();
283 if (!status.isSuccess()) {
284 return new Status(StatusCode.BADREQUEST, "Invalid Flow Spec: " + status.getDescription());
288 return new Status(StatusCode.SUCCESS);
292 * Returns Vlan value in short
294 * @return the Vlan tag
296 public short getStaticVlanValue() {
297 if ((staticVlan == null) || (staticVlan.trim().isEmpty())) {
301 return Short.valueOf(staticVlan);
302 } catch (NumberFormatException e) {
307 public Status addNodeConnectors(List<String> ncList) {
309 Status status = ContainerConfig.validateNodeConnectors(ncList);
310 if (!status.isSuccess()) {
315 ports.addAll(ncList);
316 return new Status(StatusCode.SUCCESS);
319 public Status removeNodeConnectors(List<String> ncList) {
321 Status status = ContainerConfig.validateNodeConnectors(ncList);
322 if (!status.isSuccess()) {
326 if (ports.isEmpty()) {
327 return new Status(StatusCode.BADREQUEST, "The following node connectors are not part of this container: "
330 List<String> extra = new ArrayList<String>(ncList);
331 extra.removeAll(ports);
332 if (!extra.isEmpty()) {
333 return new Status(StatusCode.CONFLICT, "The following node connectors are not part of this container: " + extra);
336 ports.removeAll(ncList);
337 return new Status(StatusCode.SUCCESS);
340 public Status validateContainerFlowModify(List<ContainerFlowConfig> cFlowConfigs, boolean delete) {
342 if (cFlowConfigs == null || cFlowConfigs.isEmpty()) {
343 return new Status(StatusCode.BADREQUEST, "Invalid Flow Spec configuration(s): null or empty list");
346 for (ContainerFlowConfig cFlowConf : cFlowConfigs) {
347 Status status = cFlowConf.validate();
348 if (!status.isSuccess()) {
349 return new Status(StatusCode.BADREQUEST, String.format("Invalid Flow Spec configuration (%s): %s",
350 cFlowConf.getName(), status.getDescription()));
353 // Name conflict check
354 List<String> existingNames = this.getContainerFlowConfigsNames();
355 List<String> proposedNames = this.getContainerFlowConfigsNames(cFlowConfigs);
357 // Check for duplicates in the request
358 if (proposedNames.size() < cFlowConfigs.size()) {
359 return new Status(StatusCode.BADREQUEST,
360 "Invalid Flow Spec configuration(s): duplicate name configs present");
363 // Check for overflow
366 if (proposedNames.size() > existingNames.size()) {
367 return new Status(StatusCode.BADREQUEST,
368 "Invalid request: requested to remove more flow spec configs than available ones");
371 for (ContainerFlowConfig config : cFlowConfigs) {
372 if (!this.containerFlows.contains(config)) {
373 return new Status(StatusCode.BADREQUEST, String.format(
374 "Invalid request: requested to remove nonexistent flow spec config: %s",
379 // Check for conflicting names with existing cFlows
380 List<String> conflicting = new ArrayList<String>(existingNames);
381 conflicting.retainAll(proposedNames);
382 if (!conflicting.isEmpty()) {
383 return new Status(StatusCode.CONFLICT,
384 "Invalid Flow Spec configuration: flow spec name(s) conflict with existing flow specs: "
385 + conflicting.toString());
389 * Check for conflicting flow spec match (we only check for strict
390 * equality). Remove this in case (*) is reintroduced
392 if (this.containerFlows != null && !this.containerFlows.isEmpty()) {
393 Set<Match> existingMatches = new HashSet<Match>();
394 for (ContainerFlowConfig existing : this.containerFlows) {
395 existingMatches.addAll(existing.getMatches());
397 for (ContainerFlowConfig proposed : cFlowConfigs) {
398 if (existingMatches.removeAll(proposed.getMatches())) {
399 return new Status(StatusCode.CONFLICT, String.format(
400 "Invalid Flow Spec configuration: %s conflicts with existing flow spec",
401 proposed.getName()));
408 return new Status(StatusCode.SUCCESS);
411 public ContainerFlowConfig getContainerFlowConfig(String name) {
412 if (this.containerFlows != null && !this.containerFlows.isEmpty()) {
413 for (ContainerFlowConfig conf : this.containerFlows) {
414 if (conf.getName().equals(name)) {
415 return new ContainerFlowConfig(conf);
422 public List<String> getContainerFlowConfigsNames() {
423 return getContainerFlowConfigsNames(this.containerFlows);
427 * Returns the list of unique names for the passed list of
428 * ContainerFlowConfig objects. the list will not contain duplicates even
429 * though the passed object list has ContainerFlowConfig objects with same
433 * the list of ContainerFlowConfig objects
434 * @return the list of correspondent unique container flow names. The return
435 * list may differ from the passed list in size, if the latter
436 * contains duplicates
438 private List<String> getContainerFlowConfigsNames(List<ContainerFlowConfig> confList) {
439 // Use set to check for duplicates later
440 Set<String> namesSet = new HashSet<String>();
441 if (confList != null) {
442 for (ContainerFlowConfig conf : confList) {
443 namesSet.add(conf.getName());
446 return new ArrayList<String>(namesSet);
450 * Add the proposed list of container flow configurations to this container
451 * configuration. A validation check on the operation is first run.
453 * @param containerFlowConfigs
454 * the proposed list of container flow configuration objects to
455 * add to this container configuration object
456 * @return the result of this request as Status object
458 public Status addContainerFlows(List<ContainerFlowConfig> containerFlowConfigs) {
459 Status status = this.validateContainerFlowModify(containerFlowConfigs, false);
460 if (!status.isSuccess()) {
463 if (this.containerFlows.addAll(containerFlowConfigs) == false) {
464 return new Status(StatusCode.INTERNALERROR, "Unable to update the flow spec configuration(s)");
466 return new Status(StatusCode.SUCCESS);
469 public Status removeContainerFlows(List<ContainerFlowConfig> containerFlowConfigs) {
470 Status status = this.validateContainerFlowModify(containerFlowConfigs, true);
471 if (!status.isSuccess()) {
474 if (this.containerFlows.removeAll(containerFlowConfigs) == false) {
475 return new Status(StatusCode.INTERNALERROR, "Unable to update the flow spec configuration(s)");
477 return new Status(StatusCode.SUCCESS);
480 public Status removeContainerFlows(Set<String> names) {
482 if (names == null || names.isEmpty()) {
483 return new Status(StatusCode.BADREQUEST, "Invalid flow spec names list");
486 List<String> present = this.getContainerFlowConfigsNames();
487 if (!present.containsAll(names)) {
488 List<String> notPresent = new ArrayList<String>(names);
489 notPresent.retainAll(present);
490 return new Status(StatusCode.BADREQUEST, "Following flow spec(s) are not present: " + notPresent);
493 List<ContainerFlowConfig> toDelete = new ArrayList<ContainerFlowConfig>(names.size());
494 for (ContainerFlowConfig config : this.containerFlows) {
495 if (names.contains(config.getName())) {
496 toDelete.add(config);
499 if (this.containerFlows.removeAll(toDelete) == false) {
500 return new Status(StatusCode.INTERNALERROR, "Unable to remove the flow spec configuration(s)");
502 return new Status(StatusCode.SUCCESS);
505 public List<ContainerFlowConfig> getContainerFlowConfigs(Set<String> names) {
506 List<ContainerFlowConfig> list = new ArrayList<ContainerFlowConfig>(names.size());
507 for (String name : names) {
508 ContainerFlowConfig conf = this.getContainerFlowConfig(name);
510 list.add(new ContainerFlowConfig(conf));
517 public int hashCode() {
518 final int prime = 31;
520 result = prime * result + ((containerFlows == null) ? 0 : containerFlows.hashCode());
521 result = prime * result + ((ports == null) ? 0 : ports.hashCode());
522 result = prime * result + ((container == null) ? 0 : container.hashCode());
523 result = prime * result + ((staticVlan == null) ? 0 : staticVlan.hashCode());
528 public boolean equals(Object obj) {
535 if (getClass() != obj.getClass()) {
538 ContainerConfig other = (ContainerConfig) obj;
539 if (containerFlows == null) {
540 if (other.containerFlows != null) {
543 } else if (!containerFlows.equals(other.containerFlows)) {
547 if (other.ports != null) {
550 } else if (!ports.equals(other.ports)) {
553 if (container == null) {
554 if (other.container != null) {
557 } else if (!container.equals(other.container)) {
560 if (staticVlan == null) {
561 if (other.staticVlan != null) {
564 } else if (!staticVlan.equals(other.staticVlan)) {
574 * @see java.lang.Object#toString()
577 public String toString() {
578 String vlString = "";
579 if (staticVlan != null) {
580 vlString = staticVlan;
582 return "container=" + container + ((vlString.equals("") ? "" : " static Vlan=" + vlString)) + " ports=" + ports + " flowspecs=" + containerFlows;
586 * Returns whether this Container configuration object has any ports specified
588 * @return true if any port is specified, false otherwise
590 public boolean hasNodeConnectors() {
591 return (ports != null && !ports.isEmpty());
595 * Returns whether this Container configuration object has any flow specs specified
597 * @return true if any flow spec is specified, false otherwise
599 public boolean hasFlowSpecs() {
600 return (containerFlows != null && !containerFlows.isEmpty());
603 public List<ContainerFlow> getContainerFlowSpecs() {
604 List<ContainerFlow> list = new ArrayList<ContainerFlow>();
605 if (containerFlows != null && !containerFlows.isEmpty()) {
606 for (ContainerFlowConfig flowSpec : containerFlows) {
607 for (Match match : flowSpec.getMatches()) {
608 list.add(new ContainerFlow(match));