/*************************************************************************** * Copyright (c) 2012-2015 VMware, Inc. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ***************************************************************************/ package com.vmware.bdd.apitypes; import java.io.Serializable; import java.util.List; import java.util.Map; import java.util.TreeMap; import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; import com.vmware.bdd.apitypes.Datastore.DatastoreType; import com.vmware.bdd.exception.ClusterConfigException; import com.vmware.bdd.utils.AuAssert; import com.vmware.bdd.utils.CommonUtil; import com.vmware.bdd.utils.Constants; /** * Cluster creation spec */ public class NodeGroupAdd implements Serializable { // @Expose // private String name; @Expose @SerializedName("groups") private NodeGroupCreate[] nodeGroups; // This means whether this object already contains the cluster definition. // If not, will load the default spec file. private Boolean specFile = false; public NodeGroupAdd() { } public NodeGroupAdd(NodeGroupAdd cluster) { // this.name = cluster.name; this.nodeGroups = cluster.nodeGroups; } // // @RestRequired // public String getName() { // return name; // } // // public void setName(String name) { // this.name = name; // } public NodeGroupCreate[] getNodeGroups() { return nodeGroups; } public void setNodeGroups(NodeGroupCreate[] nodeGroups) { this.nodeGroups = nodeGroups; } public Boolean isSpecFile() { return specFile; } public void setSpecFile(Boolean specFile) { this.specFile = specFile; } public boolean validateNodeGroupPlacementPolicies( List<String> failedMsgList, List<String> warningMsgList) { boolean valid = true; Map<String, NodeGroupCreate> allGroups = new TreeMap<String, NodeGroupCreate>(); if (getNodeGroups() == null) { return valid; } for (NodeGroupCreate nodeGroupCreate : getNodeGroups()) { allGroups.put(nodeGroupCreate.getName(), nodeGroupCreate); } return valid; } public int totalInstances() { int num = 0; for (int i = 0; i < nodeGroups.length; i++) { num += nodeGroups[i].getInstanceNum(); } return num; } public NodeGroupCreate getNodeGroup(String name) { AuAssert.check(name != null); for (NodeGroupCreate nodeGroup : this.nodeGroups) { if (nodeGroup.getName().equals(name)) { return nodeGroup; } } return null; } /** * Validate nodeGroupCreates member formats and values in the ClusterCreate. */ public void validateNodeGroupAdd(List<String> failedMsgList, List<String> warningMsgList) { // Find NodeGroupCreate array from current ClusterCreate instance. NodeGroupCreate[] nodeGroupCreates = getNodeGroups(); AuAssert.check(nodeGroupCreates != null && nodeGroupCreates.length > 0); validateNodeGroupNames(); // check placement policies validateNodeGroupPlacementPolicies(failedMsgList, warningMsgList); // check supported storage type: LOCAL/SHARED/TEMPFS For tempfs // relationship: if a compute node has // strict association with a data node, its disk type can be set to // "TEMPFS". Otherwise, it is not // allowed to use tempfs as the disk type. validateStorageType(failedMsgList); // check node group's swapRatio validateSwapRatio(nodeGroupCreates, failedMsgList); for (NodeGroupCreate nodeGroupCreate : nodeGroupCreates) { // check node group's instanceNum checkInstanceNum(nodeGroupCreate, failedMsgList); // check CPU number and memory capacity checkCPUAndMemory(nodeGroupCreate, failedMsgList, warningMsgList); } if (!warningMsgList.isEmpty() && !warningMsgList.get(0).startsWith("Warning: ")) { warningMsgList.set(0, "Warning: " + warningMsgList.get(0)); } } private void checkCPUAndMemory(NodeGroupCreate nodeGroup, List<String> failedMsgList, List<String> warningMsgList) { Integer cpuNum = nodeGroup.getCpuNum(); Integer memCap = nodeGroup.getMemCapacityMB(); if (cpuNum != null && cpuNum <= 0) { failedMsgList.add(new StringBuilder().append(nodeGroup.getName()) .append(".").append("cpuNum=").append(cpuNum).append(".") .toString()); } if (memCap != null) { if (memCap <= 0) { failedMsgList.add(new StringBuilder().append(nodeGroup.getName()) .append(".").append("memCapacityMB=").append(memCap) .append(".").toString()); } else { // make VM memory value devisible by 4 // makeVmMemoryDivisibleBy4(nodeGroup, warningMsgList); } } } private boolean checkInstanceNum(NodeGroupCreate nodeGroup, List<String> failedMsgList) { boolean validated = true; if (nodeGroup.getInstanceNum() < 0) { validated = false; collectInstanceNumInvalidateMsg(nodeGroup, failedMsgList); } return validated; } private void collectInstanceNumInvalidateMsg(NodeGroupCreate nodeGroup, List<String> failedMsgList) { failedMsgList.add(new StringBuilder().append(nodeGroup.getName()) .append(".").append("instanceNum=") .append(nodeGroup.getInstanceNum()).append(".").toString()); } public void validateNodeGroupNames() { if (nodeGroups != null && nodeGroups.length > 0) { StringBuffer invalidNodeGroupNames = new StringBuffer(); for (NodeGroupCreate nodeGroup : nodeGroups) { if (CommonUtil.isBlank(nodeGroup.getName()) || !CommonUtil.validateNodeGroupName(nodeGroup.getName())) { invalidNodeGroupNames.append("'").append(nodeGroup.getName()) .append("'").append(","); } } if (invalidNodeGroupNames.length() > 0) { invalidNodeGroupNames.delete(invalidNodeGroupNames.length() - 1, invalidNodeGroupNames.length()); throw ClusterConfigException .NODE_GROUP_NAME_IS_INVALID(invalidNodeGroupNames.toString()); } } else { throw ClusterConfigException.NODE_GROUP_NOT_EXISTING(); } } public void validateStorageType(List<String> failedMsgList) { for (NodeGroupCreate nodeGroupCreate : getNodeGroups()) { StorageRead storageDef = nodeGroupCreate.getStorage(); if (storageDef != null) { String storageType = storageDef.getType(); if (storageType != null) { storageType = storageType.toUpperCase(); // only support storage type of TEMPFS/LOCAL/SHARED if (!storageType.equals(DatastoreType.TEMPFS.toString()) && !storageType.equals(DatastoreType.LOCAL.toString()) && !storageType.equals(DatastoreType.SHARED.toString())) { failedMsgList.add("Invalid storage type " + storageType + ". " + Constants.STORAGE_TYPE_ALLOWED); } else if (storageType.equals(DatastoreType.TEMPFS.toString())) {// tempfs disk type failedMsgList.add(Constants.TEMPFS_NOT_ALLOWED); } } } } } private void validateSwapRatio(NodeGroupCreate[] nodeGroups, List<String> failedMsgList) { boolean validated = true; StringBuilder invalidNodeGroupNames = new StringBuilder(); for (NodeGroupCreate nodeGroup : nodeGroups) { if (nodeGroup.getSwapRatio() < 0) { validated = false; invalidNodeGroupNames.append(nodeGroup.getName()).append(","); } } if (!validated) { StringBuilder errorMsgBuff = new StringBuilder(); invalidNodeGroupNames.delete(invalidNodeGroupNames.length() - 1, invalidNodeGroupNames.length()); failedMsgList .add(errorMsgBuff .append("The 'swapRatio' must be greater than or equal to 0 in group ") .append(invalidNodeGroupNames.toString()).append(".") .toString()); } } }