+ public Map<String, List<ContainerFlowConfig>> getContainerFlows() {
+ Map<String, List<ContainerFlowConfig>> flowSpecConfig = new HashMap<String, List<ContainerFlowConfig>>();
+ for (Map.Entry<String, ContainerConfig> entry : containerConfigs.entrySet()) {
+ List<ContainerFlowConfig> set = entry.getValue().getContainerFlowConfigs();
+ flowSpecConfig.put(entry.getKey(), set);
+ }
+ return flowSpecConfig;
+ }
+
+ private void loadConfigurations() {
+ /*
+ * Read containers, container flows and finally containers' entries from file
+ * and program the database accordingly
+ */
+ if (containerConfigs.isEmpty()) {
+ loadContainerConfig();
+ }
+ }
+
+ private Status saveContainerConfig() {
+ return saveContainerConfigLocal();
+ }
+
+ public Status saveContainerConfigLocal() {
+ ObjectWriter objWriter = new ObjectWriter();
+
+ Status status = objWriter.write(new ConcurrentHashMap<String, ContainerConfig>(containerConfigs), containersFileName);
+ if (!status.isSuccess()) {
+ return new Status(StatusCode.INTERNALERROR, "Failed to save container configurations: "
+ + status.getDescription());
+ }
+ return new Status(StatusCode.SUCCESS);
+ }
+
+ private void removeComponentsStartUpfiles(String containerName) {
+ String startupLocation = String.format("./%s", GlobalConstants.STARTUPHOME.toString());
+ String containerPrint = String.format("_%s.", containerName.toLowerCase(Locale.ENGLISH));
+
+ File directory = new File(startupLocation);
+ String[] fileList = directory.list();
+
+ logger.trace("Deleteing startup configuration files for container {}", containerName);
+ if (fileList != null) {
+ for (String fileName : fileList) {
+ if (fileName.contains(containerPrint)) {
+ String fullPath = String.format("%s/%s", startupLocation, fileName);
+ File file = new File(fullPath);
+ boolean done = file.delete();
+ logger.trace("{} {}", (done ? "Deleted: " : "Failed to delete: "), fileName);
+ }
+ }
+ }
+ }
+
+ /**
+ * Create and initialize default all resource group and create association
+ * with default well known users and profiles, if not already learnt from
+ * another cluster node
+ */
+ private void createDefaultAuthorizationGroups() {
+ allResourcesGroupName = ContainerManager.allContainersGroup;
+
+ // Add the default container to the all containers group if needed
+ String defaultContainer = GlobalConstants.DEFAULT.toString();
+ Set<String> allContainers = (resourceGroups.containsKey(allResourcesGroupName)) ? resourceGroups
+ .get(allResourcesGroupName) : new HashSet<String>();
+ if (!allContainers.contains(defaultContainer)) {
+ // Add Default container
+ allContainers.add(defaultContainer);
+ // Update cluster
+ resourceGroups.put(allResourcesGroupName, allContainers);
+ }
+
+ // Add the controller well known roles, if not known already
+ if (!roles.containsKey(UserLevel.SYSTEMADMIN.toString())) {
+ roles.put(UserLevel.SYSTEMADMIN.toString(), AppRoleLevel.APPADMIN);
+ }
+ if (!roles.containsKey(UserLevel.NETWORKADMIN.toString())) {
+ roles.put(UserLevel.NETWORKADMIN.toString(), AppRoleLevel.APPADMIN);
+ }
+ if (!roles.containsKey(UserLevel.NETWORKOPERATOR.toString())) {
+ roles.put(UserLevel.NETWORKOPERATOR.toString(), AppRoleLevel.APPOPERATOR);
+ }
+
+ /*
+ * Create and add the all containers user groups and associate them to the
+ * default well known user roles, if not present already
+ */
+ if (!groupsAuthorizations.containsKey(UserLevel.NETWORKADMIN.toString())) {
+ Set<ResourceGroup> writeProfile = new HashSet<ResourceGroup>(1);
+ Set<ResourceGroup> readProfile = new HashSet<ResourceGroup>(1);
+ writeProfile.add(new ResourceGroup(allResourcesGroupName, Privilege.WRITE));
+ readProfile.add(new ResourceGroup(allResourcesGroupName, Privilege.READ));
+ groupsAuthorizations.put(UserLevel.SYSTEMADMIN.toString(), writeProfile);
+ groupsAuthorizations.put(UserLevel.NETWORKADMIN.toString(), writeProfile);
+ groupsAuthorizations.put(UserLevel.NETWORKOPERATOR.toString(), readProfile);
+ }
+ }
+
+ /**
+ * Until manual configuration is not available, automatically maintain the
+ * well known resource groups
+ *
+ * @param containerName
+ * @param delete
+ */
+ private void updateResourceGroups(String containerName, boolean delete) {
+ String containerProfile = System.getProperty("container.profile");
+ if (containerProfile == null) containerProfile = "Container";
+ // Container Roles and Container Resource Group
+ String groupName = containerProfile+"-" + containerName;
+ String containerAdminRole = containerProfile+"-" + containerName + "-Admin";
+ String containerOperatorRole = containerProfile+"-" + containerName + "-Operator";
+ Set<String> allContainerSet = resourceGroups.get(allResourcesGroupName);
+ if (delete) {
+ resourceGroups.remove(groupName);
+ groupsAuthorizations.remove(containerAdminRole);
+ groupsAuthorizations.remove(containerOperatorRole);
+ roles.remove(containerAdminRole);
+ roles.remove(containerOperatorRole);
+ // Update the all container group
+ allContainerSet.remove(containerName);
+ } else {
+ Set<String> resources = new HashSet<String>(1);
+ resources.add(containerName);
+ resourceGroups.put(groupName, resources);
+ Set<ResourceGroup> adminGroups = new HashSet<ResourceGroup>(1);
+ Set<ResourceGroup> operatorGroups = new HashSet<ResourceGroup>(1);
+ adminGroups.add(new ResourceGroup(groupName, Privilege.WRITE));
+ operatorGroups.add(new ResourceGroup(groupName, Privilege.READ));
+ groupsAuthorizations.put(containerAdminRole, adminGroups);
+ groupsAuthorizations.put(containerOperatorRole, operatorGroups);
+ roles.put(containerAdminRole, AppRoleLevel.APPADMIN);
+ roles.put(containerOperatorRole, AppRoleLevel.APPOPERATOR);
+ // Update the all containers resource group
+ allContainerSet.add(containerName);
+ }
+ // Update resource groups in cluster
+ resourceGroups.put(allResourcesGroupName, allContainerSet);
+ }
+
+ /**
+ * Notify ContainerAware listeners of the creation/deletion of the container
+ *
+ * @param containerName
+ * @param delete
+ * true is container was removed, false otherwise
+ */
+ private void notifyContainerAwareListeners(String containerName, boolean delete) {
+ // Back-end World: container name forced to lower case
+ String name = containerName.toLowerCase(Locale.ENGLISH);
+
+ synchronized (this.iContainerAware) {
+ for (IContainerAware i : this.iContainerAware) {
+ if (delete) {
+ i.containerDestroy(name);
+ } else {
+ i.containerCreate(name);
+ }
+ }
+ }
+ }
+
+ /**
+ * Notify the ContainerListener listeners in case the container mode has changed
+ * following a container configuration operation Note: this call must happen
+ * after the configuration db has been updated
+ *
+ * @param lastActionDelete
+ * true if the last container configuration operation was a container
+ * delete operation
+ */
+ private void notifyContainerModeChange(boolean lastActionDelete) {
+ if (lastActionDelete == false && containerConfigs.size() == 1) {
+ logger.info("First container Creation. Inform listeners");
+ synchronized (this.iContainerListener) {
+ for (IContainerListener i : this.iContainerListener) {
+ i.containerModeUpdated(UpdateType.ADDED);
+ }
+ }
+ } else if (lastActionDelete == true && containerConfigs.isEmpty()) {
+ logger.info("Last container Deletion. Inform listeners");
+ synchronized (this.iContainerListener) {
+ for (IContainerListener i : this.iContainerListener) {
+ i.containerModeUpdated(UpdateType.REMOVED);
+ }
+ }
+ }
+ }
+
+ private Status addRemoveContainerEntries(String containerName, List<String> nodeConnectorsString, boolean delete) {
+ // Construct action message
+ String action = String.format("Node conenctor(s) %s container %s: %s", delete ? "removal from" : "addition to",
+ containerName, nodeConnectorsString);
+
+ // Validity Check
+ if (nodeConnectorsString == null || nodeConnectorsString.isEmpty()) {
+ return new Status(StatusCode.BADREQUEST, "Node connector list is null or empty");
+ }
+
+ // Presence check
+ ContainerConfig entryConf = containerConfigs.get(containerName);
+ if (entryConf == null) {
+ String msg = String.format("Container not found: %s", containerName);
+ String error = String.format("Failed to apply %s: (%s)", action, msg);
+ logger.warn(error);
+ return new Status(StatusCode.NOTFOUND, msg);
+ }
+
+ // Validation check
+ Status status = ContainerConfig.validateNodeConnectors(nodeConnectorsString);
+ if (!status.isSuccess()) {
+ String error = String.format("Failed to apply %s: (%s)", action, status.getDescription());
+ logger.warn(error);
+ return status;
+ }
+
+ List<NodeConnector> nodeConnectors = ContainerConfig.nodeConnectorsFromString(nodeConnectorsString);
+
+ // Port sharing check
+ if (!delete) {
+ /*
+ * Check if the ports being added to this container already belong to
+ * other containers. If so check whether the the appropriate flow specs
+ * are configured on this container
+ */
+ status = validatePortSharing(containerName, nodeConnectors);
+ if (!status.isSuccess()) {
+ String error = String.format("Failed to apply %s: (%s)", action, status.getDescription());
+ logger.warn(error);
+ return status;
+ }
+ }
+
+ // Update Database
+ status = updateContainerEntryDatabase(containerName, nodeConnectors, delete);
+ if (!status.isSuccess()) {
+ String error = String.format("Failed to apply %s: (%s)", action, status.getDescription());
+ logger.warn(error);
+ return status;
+ }
+
+ // Update Configuration
+ status = (delete) ? entryConf.removeNodeConnectors(nodeConnectorsString) : entryConf
+ .addNodeConnectors(nodeConnectorsString);
+ if (!status.isSuccess()) {
+ String error = String.format("Failed to modify config for %s: (%s)", action, status.getDescription());
+ logger.warn(error);
+ // Revert backend changes
+ Status statusRevert = updateContainerEntryDatabase(containerName, nodeConnectors, !delete);
+ if (!statusRevert.isSuccess()) {
+ // Unlikely
+ logger.error("Failed to revert changes in database (CRITICAL)");
+ }
+ return status;
+ }
+
+ // Update cluster Configuration cache
+ containerConfigs.put(containerName, entryConf);
+
+ // Notify
+ UpdateType update = (delete) ? UpdateType.REMOVED : UpdateType.ADDED;
+ notifyContainerEntryChangeInternal(containerName, nodeConnectors, update);
+ // Trigger cluster notification
+ containerChangeEvents.put(containerName, new NodeConnectorsChangeEvent(nodeConnectors, update));
+
+ return status;
+ }
+
+ private void notifyContainerChangeInternal(ContainerConfig conf, UpdateType update) {
+ String containerName = conf.getContainerName();
+ logger.trace("Notifying listeners on {} for container {}", update, containerName);
+ // Back-end World: container name forced to lower case
+ String container = containerName.toLowerCase(Locale.ENGLISH);
+ boolean delete = (update == UpdateType.REMOVED);
+ // Check if a container mode change notification is needed
+ notifyContainerModeChange(delete);
+ // Notify listeners
+ notifyContainerAwareListeners(container, delete);
+ }
+
+ private void notifyContainerEntryChangeInternal(String containerName, List<NodeConnector> ncList, UpdateType update) {
+ logger.trace("Notifying listeners on {} for ports {} in container {}", update, ncList, containerName);
+ // Back-end World: container name forced to lower case
+ String container = containerName.toLowerCase(Locale.ENGLISH);
+ for (NodeConnector nodeConnector : ncList) {
+ // Now signal that the port has been added/removed
+ synchronized (this.iContainerListener) {
+ for (IContainerListener i : this.iContainerListener) {
+ i.nodeConnectorUpdated(container, nodeConnector, update);
+ }
+ }
+ }
+ }
+
+ private void notifyCFlowChangeInternal(String containerName, List<ContainerFlowConfig> confList, UpdateType update) {
+ logger.trace("Notifying listeners on {} for flow specs {} in container {}", update, confList, containerName);
+ // Back-end World: container name forced to lower case
+ String container = containerName.toLowerCase(Locale.ENGLISH);
+ synchronized (this.iContainerListener) {
+ for (ContainerFlowConfig conf : confList) {
+ for (Match match : conf.getMatches()) {
+ ContainerFlow cFlow = new ContainerFlow(match);
+ for (IContainerListener i : this.iContainerListener) {
+ i.containerFlowUpdated(container, cFlow, cFlow, update);
+ }
+ }
+ }
+ }
+ }
+
+ private Status addRemoveContainerFlow(String containerName, List<ContainerFlowConfig> cFlowConfList, boolean delete) {
+ // Construct action message
+ String action = String.format("Flow spec(s) %s container %s: %s", delete ? "removal from" : "addition to",
+ containerName, cFlowConfList);
+
+ // Presence check
+ ContainerConfig containerConfig = this.containerConfigs.get(containerName);
+ if (containerConfig == null) {
+ String msg = String.format("Container not found: %s", containerName);
+ String error = String.format("Failed to apply %s: (%s)", action, msg);
+ logger.warn(error);
+ return new Status(StatusCode.NOTFOUND, "Container not present");
+ }
+
+ // Validity check, check for overlaps on current container configuration
+ Status status = containerConfig.validateContainerFlowModify(cFlowConfList, delete);
+ if (!status.isSuccess()) {
+ String msg = status.getDescription();
+ String error = String.format("Failed to apply %s: (%s)", action, msg);
+ logger.warn(error);
+ return new Status(StatusCode.BADREQUEST, msg);
+ }
+
+ // Validate the operation in terms to the port sharing with other containers
+ for (ContainerFlowConfig conf : cFlowConfList) {
+ for (Match match : conf.getMatches()) {
+ ContainerFlow cFlow = new ContainerFlow(match);
+ status = validateContainerFlowAddRemoval(containerName, cFlow, delete);
+ if (!status.isSuccess()) {
+ String msg = "Validation failed: " + status.getDescription();
+ String error = String.format("Failed to apply %s: (%s)", action, msg);
+ logger.warn(error);
+ return new Status(StatusCode.BADREQUEST, msg);
+ }
+ }
+ }
+
+ // Update Database
+ status = updateContainerFlow(containerName, cFlowConfList, delete);
+ if (!status.isSuccess()) {
+ String error = String.format("Failed to apply %s: (%s)", action, status.getDescription());
+ logger.error(error);
+ return status;
+ }
+
+ // Update Configuration
+ status = (delete) ? containerConfig.removeContainerFlows(cFlowConfList) : containerConfig
+ .addContainerFlows(cFlowConfList);
+ if (!status.isSuccess()) {
+ String error = String.format("Failed to modify config for %s: (%s)", action, status.getDescription());
+ logger.error(error);
+ // Revert backend changes
+ Status statusRevert = updateContainerFlow(containerName, cFlowConfList, !delete);
+ if (!statusRevert.isSuccess()) {
+ // Unlikely
+ logger.error("Failed to revert changes in database (CRITICAL)");
+ }
+ return status;
+ }
+ // Update cluster cache
+ this.containerConfigs.put(containerName, containerConfig);
+
+ // Notify listeners
+ UpdateType update = (delete) ? UpdateType.REMOVED : UpdateType.ADDED;
+ notifyCFlowChangeInternal(containerName, cFlowConfList, update);
+ // Trigger cluster notification
+ containerChangeEvents.put(containerName, new ContainerFlowChangeEvent(cFlowConfList, update));
+
+ return status;
+ }
+
+ private Status addRemoveContainer(ContainerConfig containerConf, boolean delete) {
+ // Construct action message
+ String action = String.format("Container %s", delete ? "removal" : "creation");
+
+ // Valid configuration check
+ Status status = null;
+ String error = (containerConfigs == null) ? String.format("Invalid %s configuration: (null config object)", action)
+ : (!(status = containerConf.validate()).isSuccess()) ? String.format("Invalid %s configuration: (%s)",
+ action, status.getDescription()) : null;
+ if (error != null) {
+ logger.warn(error);
+ return new Status(StatusCode.BADREQUEST, error);
+ }
+
+ // Configuration presence check
+ String containerName = containerConf.getContainerName();
+ if (delete) {
+ if (!containerConfigs.containsKey(containerName)) {
+ String msg = String.format("%s Failed: (Container does not exist: %s)", action, containerName);
+ logger.warn(msg);
+ return new Status(StatusCode.NOTFOUND, msg);
+ }
+ } else {
+ if (containerConfigs.containsKey(containerName)) {
+ String msg = String.format("%s Failed: (Container already exist: %s)", action, containerName);
+ logger.warn(msg);
+ return new Status(StatusCode.CONFLICT, msg);
+ }
+ }
+
+ /*
+ * The proposed container configuration could be a complex one containing
+ * both ports and flow spec. If so, check if it has shared ports with
+ * other existing containers. If that is the case verify flow spec isolation
+ * is in place. No need to check on flow spec validation first. This
+ * would take care of both
+ */
+ if (!delete) {
+ status = validatePortSharing(containerConf);
+ if (!status.isSuccess()) {
+ error = String.format("%s Failed: (%s)", action, status.getDescription());
+ logger.error(error);
+ return status;
+ }
+ }
+
+ // Update Database
+ status = updateContainerDatabase(containerConf, delete);
+
+ // Abort and exit here if back-end database update failed
+ if (!status.isSuccess()) {
+ return status;
+ }
+
+ /*
+ * This is a quick fix until configuration service becomes the
+ * centralized configuration management place. Here container manager will
+ * remove the startup files for all the bundles that are present in the
+ * container being deleted. Do the cleanup here in Container manger as do not
+ * want to put this temporary code in Configuration manager yet which is
+ * ODL.
+ */
+ if (delete) {
+ // TODO: remove when Config Mgr takes over
+ removeComponentsStartUpfiles(containerName);
+ }
+
+ /*
+ * Update Configuration: This will trigger the notifications on cache
+ * update callback locally and on the other cluster nodes
+ */
+ if (delete) {
+ this.containerConfigs.remove(containerName);
+ } else {
+ this.containerConfigs.put(containerName, containerConf);
+ }
+
+ // Automatically create and populate user and resource groups
+ updateResourceGroups(containerName, delete);
+
+ // Notify listeners
+ UpdateType update = (delete) ? UpdateType.REMOVED : UpdateType.ADDED;
+ notifyContainerChangeInternal(containerConf, update);
+
+ // Trigger cluster notification
+ containerChangeEvents.put(containerName, new ContainerChangeEvent(containerConf, update));
+
+ if (update == UpdateType.ADDED) {
+ if (containerConf.hasFlowSpecs()) {
+ List<ContainerFlowConfig> specList = containerConf.getContainerFlowConfigs();
+ // Notify flow spec addition
+ notifyCFlowChangeInternal(containerName, specList, update);
+
+ // Trigger cluster notification
+ containerChangeEvents.put(containerName, new ContainerFlowChangeEvent(specList, update));
+ }
+
+ if (containerConf.hasNodeConnectors()) {
+ List<NodeConnector> ncList = containerConf.getPortList();
+ // Notify port(s) addition
+ notifyContainerEntryChangeInternal(containerName, ncList, update);
+ // Trigger cluster notification
+ containerChangeEvents.put(containerName, new NodeConnectorsChangeEvent(ncList, update));
+ }
+ }
+
+ return status;
+ }
+
+ @Override
+ public Status addContainer(ContainerConfig containerConf) {
+ return addRemoveContainer(containerConf, false);
+ }
+
+ @Override
+ public Status removeContainer(ContainerConfig containerConf) {
+ return addRemoveContainer(containerConf, true);
+ }
+
+ @Override
+ public Status removeContainer(String containerName) {
+ // Construct action message
+ String action = String.format("Container removal: %s", containerName);
+
+ ContainerConfig containerConf = containerConfigs.get(containerName);
+ if (containerConf == null) {
+ String msg = String.format("Container not found");
+ String error = String.format("Failed to apply %s: (%s)", action, msg);
+ logger.warn(error);
+ return new Status(StatusCode.NOTFOUND, msg);
+ }
+ return addRemoveContainer(containerConf, true);
+ }
+
+ @Override
+ public Status addContainerEntry(String containerName, List<String> nodeConnectors) {
+ return addRemoveContainerEntries(containerName, nodeConnectors, false);
+ }
+
+ @Override
+ public Status removeContainerEntry(String containerName, List<String> nodeConnectors) {
+ return addRemoveContainerEntries(containerName, nodeConnectors, true);
+ }
+
+ @Override
+ public Status addContainerFlows(String containerName, List<ContainerFlowConfig> fSpecConf) {
+ return addRemoveContainerFlow(containerName, fSpecConf, false);
+ }
+
+ @Override
+ public Status removeContainerFlows(String containerName, List<ContainerFlowConfig> fSpecConf) {
+ return addRemoveContainerFlow(containerName, fSpecConf, true);
+ }
+
+ @Override
+ public Status removeContainerFlows(String containerName, Set<String> names) {
+ // Construct action message
+ String action = String.format("Flow spec(s) removal from container %s: %s", containerName, names);
+
+ // Presence check
+ ContainerConfig sc = containerConfigs.get(containerName);
+ if (sc == null) {
+ String msg = String.format("Container not found: %s", containerName);
+ String error = String.format("Failed to apply %s: (%s)", action, msg);
+ logger.warn(error);
+ return new Status(StatusCode.NOTFOUND, msg);
+ }
+ List<ContainerFlowConfig> list = sc.getContainerFlowConfigs(names);
+ if (list.isEmpty() || list.size() != names.size()) {
+ String msg = String.format("Cannot find all the specified flow specs");
+ String error = String.format("Failed to apply %s: (%s)", action, msg);
+ logger.warn(error);
+ return new Status(StatusCode.BADREQUEST, msg);
+ }
+ return addRemoveContainerFlow(containerName, list, true);
+ }
+
+ @Override
+ public List<ContainerFlowConfig> getContainerFlows(String containerName) {
+ ContainerConfig sc = containerConfigs.get(containerName);
+ return (sc == null) ? new ArrayList<ContainerFlowConfig>(0) : sc.getContainerFlowConfigs();
+ }
+
+ @Override
+ public List<String> getContainerFlowNameList(String containerName) {
+ ContainerConfig sc = containerConfigs.get(containerName);
+ return (sc == null) ? new ArrayList<String>(0) : sc.getContainerFlowConfigsNames();
+ }
+
+ @Override
+ public Object readObject(ObjectInputStream ois) throws FileNotFoundException, IOException, ClassNotFoundException {
+ // Perform the class deserialization locally, from inside the package
+ // where the class is defined
+ return ois.readObject();
+ }
+
+ @SuppressWarnings("unchecked")
+ private void loadContainerConfig() {
+ ObjectReader objReader = new ObjectReader();
+ ConcurrentMap<String, ContainerConfig> configMap = (ConcurrentMap<String, ContainerConfig>) objReader.read(this,
+ containersFileName);
+
+ if (configMap == null) {
+ return;
+ }
+
+ for (Map.Entry<String, ContainerConfig> configEntry : configMap.entrySet()) {
+ addContainer(configEntry.getValue());
+ }
+ }
+
+ public void _psc(CommandInterpreter ci) {
+ for (Map.Entry<String, ContainerConfig> entry : containerConfigs.entrySet()) {
+ ContainerConfig sc = entry.getValue();
+ ci.println(String.format("%s: %s", sc.getContainerName(), sc.toString()));
+ }
+ ci.println("Total number of containers: " + containerConfigs.entrySet().size());
+ }
+
+ public void _pfc(CommandInterpreter ci) {
+ for (Map.Entry<String, ContainerConfig> entry : containerConfigs.entrySet()) {
+ ContainerConfig sc = entry.getValue();
+ ci.println(String.format("%s: %s", sc.getContainerName(), sc.getContainerFlowConfigs()));
+ }
+ }
+
+ public void _psd(CommandInterpreter ci) {
+ for (String containerName : containerData.keySet()) {
+ ContainerData sd = containerData.get(containerName);
+ for (Node sid : sd.getSwPorts().keySet()) {
+ Set<NodeConnector> s = sd.getSwPorts().get(sid);
+ ci.println("\t" + sid + " : " + s);
+ }
+
+ for (ContainerFlow s : sd.getContainerFlowSpecs()) {
+ ci.println("\t" + s.toString());
+ }
+ }
+ }
+
+ public void _psp(CommandInterpreter ci) {
+ for (NodeConnector sp : nodeConnectorToContainers.keySet()) {
+ ci.println(nodeConnectorToContainers.get(sp));
+ }
+ }
+
+ public void _psm(CommandInterpreter ci) {
+ for (Node sp : nodeToContainers.keySet()) {
+ ci.println(nodeToContainers.get(sp));
+ }
+ }
+
+ public void _addContainer(CommandInterpreter ci) {
+ String containerName = ci.nextArgument();
+ if (containerName == null) {
+ ci.print("Container Name not specified");
+ return;
+ }
+ String staticVlan = ci.nextArgument();
+ if (staticVlan == null) {
+ ci.print("Static Vlan not specified");
+ return;
+ }
+ ContainerConfig containerConfig = new ContainerConfig(containerName, staticVlan, null, null);
+ ci.println(this.addRemoveContainer(containerConfig, false));
+ }
+
+ public void _createContainer(CommandInterpreter ci) {
+ String containerName = ci.nextArgument();
+ if (containerName == null) {
+ ci.print("Container Name not specified");
+ return;
+ }
+ String staticVlan = ci.nextArgument();
+ if (staticVlan == null) {
+ ci.print("Static Vlan not specified");
+ return;
+ }
+ List<String> ports = new ArrayList<String>();
+ for (long l = 1L; l < 10L; l++) {
+ ports.add(NodeConnectorCreator.createOFNodeConnector((short) 1, NodeCreator.createOFNode(l)).toString());
+ }
+ List<ContainerFlowConfig> cFlowList = new ArrayList<ContainerFlowConfig>();
+ cFlowList.add(this.createSampleContainerFlowConfig("tcp", true));
+ ContainerConfig containerConfig = new ContainerConfig(containerName, staticVlan, ports, cFlowList);
+ ci.println(this.addRemoveContainer(containerConfig, false));
+ }
+
+ public void _removeContainer(CommandInterpreter ci) {
+ String containerName = ci.nextArgument();
+ if (containerName == null) {
+ ci.print("Container Name not specified");
+ return;
+ }
+ ContainerConfig containerConfig = new ContainerConfig(containerName, "", null, null);
+ ci.println(this.addRemoveContainer(containerConfig, true));
+ }
+
+ public void _addContainerEntry(CommandInterpreter ci) {
+ String containerName = ci.nextArgument();
+ if (containerName == null) {
+ ci.print("Container Name not specified");
+ return;
+ }
+ String nodeId = ci.nextArgument();
+ if (nodeId == null) {
+ ci.print("Node Id not specified");
+ return;
+ }
+ String portId = ci.nextArgument();
+ if (portId == null) {
+ ci.print("Port not specified");
+ return;
+ }
+ Node node = NodeCreator.createOFNode(Long.valueOf(nodeId));
+ Short port = Short.valueOf(portId);
+ NodeConnector nc = NodeConnectorCreator.createOFNodeConnector(port, node);
+ List<String> portList = new ArrayList<String>(1);
+ portList.add(nc.toString());
+ ci.println(this.addRemoveContainerEntries(containerName, portList, false));
+ }
+
+ public void _removeContainerEntry(CommandInterpreter ci) {
+ String containerName = ci.nextArgument();
+ if (containerName == null) {
+ ci.print("Container Name not specified");
+ return;
+ }
+ String nodeId = ci.nextArgument();
+ if (nodeId == null) {
+ ci.print("Node Id not specified");
+ return;
+ }
+ String portId = ci.nextArgument();
+ if (portId == null) {
+ ci.print("Port not specified");
+ return;
+ }
+ Node node = NodeCreator.createOFNode(Long.valueOf(nodeId));
+ Short port = Short.valueOf(portId);
+ NodeConnector nc = NodeConnectorCreator.createOFNodeConnector(port, node);
+ List<String> portList = new ArrayList<String>(1);
+ portList.add(nc.toString());
+ ci.println(this.addRemoveContainerEntries(containerName, portList, true));
+ }
+
+ private ContainerFlowConfig createSampleContainerFlowConfig(String cflowName, boolean boolUnidirectional) {
+ ContainerFlowConfig cfg = new ContainerFlowConfig(cflowName, "9.9.1.0/24", "19.9.1.2", "TCP", "1234", "25");
+ return cfg;
+ }
+
+ public void _addContainerFlow(CommandInterpreter ci) {
+ String containerName = ci.nextArgument();
+ if (containerName == null) {
+ ci.print("Container Name not specified");
+ return;
+ }
+ String cflowName = ci.nextArgument();
+ if (cflowName == null) {
+ ci.print("cflowName not specified");
+ return;
+ }
+ String unidirectional = ci.nextArgument();
+ boolean boolUnidirectional = Boolean.parseBoolean(unidirectional);
+ List<ContainerFlowConfig> list = new ArrayList<ContainerFlowConfig>();
+ list.add(createSampleContainerFlowConfig(cflowName, boolUnidirectional));
+ ci.println(this.addRemoveContainerFlow(containerName, list, false));
+ }
+
+ public void _removeContainerFlow(CommandInterpreter ci) {
+ String containerName = ci.nextArgument();
+ if (containerName == null) {
+ ci.print("Container Name not specified");
+ return;
+ }
+ String cflowName = ci.nextArgument();
+ if (cflowName == null) {
+ ci.print("cflowName not specified");
+ return;
+ }
+ Set<String> set = new HashSet<String>(1);
+ set.add(cflowName);
+ ci.println(this.removeContainerFlows(containerName, set));
+ }
+
+ @Override
+ public String getHelp() {
+ StringBuffer help = new StringBuffer();
+ help.append("---ContainerManager Testing---\n");
+ help.append("\tpsc - Print ContainerConfigs\n");
+ help.append("\tpfc - Print FlowSpecConfigs\n");
+ help.append("\tpsd - Print ContainerData\n");
+ help.append("\tpsp - Print nodeConnectorToContainers\n");
+ help.append("\tpsm - Print nodeToContainers\n");
+ help.append("\t addContainer <containerName> <staticVlan> \n");
+ help.append("\t removeContainer <containerName> \n");
+ help.append("\t addContainerEntry <containerName> <nodeId> <port> \n");
+ help.append("\t removeContainerEntry <containerName> <nodeId> <port> \n");
+ help.append("\t addContainerFlow <containerName> <cflowName> <unidirectional true/false>\n");
+ help.append("\t removeContainerFlow <containerName> <cflowName> \n");
+ return help.toString();
+ }
+
+ @Override
+ public boolean doesContainerExist(String containerName) {
+ // Test for default container
+ if (GlobalConstants.DEFAULT.toString().equalsIgnoreCase(containerName)) {
+ return true;
+ }
+ // Test for non-default one
+ return (getContainerByName(containerName) != null);
+ }
+
+ @Override
+ public ContainerData getContainerData(String containerName) {
+ return (getContainerByName(containerName));
+ }
+
+ @Override
+ public Status saveConfiguration() {
+ return saveContainerConfig();
+ }
+
+ public void _containermgrGetRoles(CommandInterpreter ci) {
+ ci.println("Configured roles for Container Mgr:");
+ List<String> list = this.getRoles();
+ for (String role : list) {
+ ci.println(role + "\t" + roles.get(role));
+ }
+ }
+
+ public void _containermgrGetAuthorizedGroups(CommandInterpreter ci) {
+ String roleName = ci.nextArgument();
+ if (roleName == null || roleName.trim().isEmpty()) {
+ ci.println("Invalid argument");
+ ci.println("mmGetAuthorizedGroups <role_name>");
+ return;
+ }
+ ci.println("Resource Groups associated to role " + roleName + ":");
+ List<ResourceGroup> list = this.getAuthorizedGroups(roleName);
+ for (ResourceGroup group : list) {
+ ci.println(group.toString());
+ }
+ }
+
+ public void _containermgrGetAuthorizedResources(CommandInterpreter ci) {
+ String roleName = ci.nextArgument();
+ if (roleName == null || roleName.trim().isEmpty()) {
+ ci.println("Invalid argument");
+ ci.println("mmGetAuthorizedResources <role_name>");
+ return;
+ }
+ ci.println("Resource associated to role " + roleName + ":");
+ List<Resource> list = this.getAuthorizedResources(roleName);
+ for (Resource resource : list) {
+ ci.println(resource.toString());
+ }
+ }
+
+ public void _containermgrGetResourcesForGroup(CommandInterpreter ci) {
+ String groupName = ci.nextArgument();
+ if (groupName == null || groupName.trim().isEmpty()) {
+ ci.println("Invalid argument");
+ ci.println("containermgrResourcesForGroup <group_name>");
+ return;
+ }
+ ci.println("Group " + groupName + " contains the following resources:");
+ List<Object> resources = this.getResources(groupName);
+ for (Object resource : resources) {
+ ci.println(resource.toString());
+ }
+ }
+
+ public void _containermgrGetUserLevel(CommandInterpreter ci) {
+ String userName = ci.nextArgument();
+ if (userName == null || userName.trim().isEmpty()) {
+ ci.println("Invalid argument");
+ ci.println("containermgrGetUserLevel <user_name>");
+ return;
+ }
+ ci.println("User " + userName + " has level: " + this.getUserLevel(userName));
+ }
+
+ public void _containermgrGetUserResources(CommandInterpreter ci) {
+ String userName = ci.nextArgument();
+ if (userName == null || userName.trim().isEmpty()) {
+ ci.println("Invalid argument");
+ ci.println("containermgrGetUserResources <user_name>");
+ return;
+ }
+ ci.println("User " + userName + " owns the following resources: ");
+ Set<Resource> resources = this.getAllResourcesforUser(userName);
+ for (Resource resource : resources) {
+ ci.println(resource.toString());
+ }
+ }
+
+ /*
+ * For scalability testing where as of now controller gui is unresponsive
+ * providing here an osgi hook to trigger the save config so that DT do not
+ * have to reaply the scalable configuration each time they restart the
+ * controller
+ */
+ // TODO: remove when no longer needed
+ public void _saveConfig(CommandInterpreter ci) {
+ Status status = new Status(StatusCode.NOSERVICE, "Configuration service not reachable");
+
+ IConfigurationService configService = (IConfigurationService) ServiceHelper.getGlobalInstance(
+ IConfigurationService.class, this);
+ if (configService != null) {
+ status = configService.saveConfigurations();
+ }
+ ci.println(status.toString());