com.dell.asm.asmcore.asmmanager.util.ServiceTemplateValidator.java Source code

Java tutorial

Introduction

Here is the source code for com.dell.asm.asmcore.asmmanager.util.ServiceTemplateValidator.java

Source

/**************************************************************************
 *   Copyright (c) 2015 Dell Inc. All rights reserved.                    *
 *                                                                        *
 * DELL INC. CONFIDENTIAL AND PROPRIETARY INFORMATION. This software may  *
 * only be supplied under the terms of a license agreement or             *
 * nondisclosure agreement with Dell Inc. and may not be copied or        *
 * disclosed except in accordance with the terms of such agreement.       *
 **************************************************************************/
package com.dell.asm.asmcore.asmmanager.util;

import com.dell.asm.asmcore.asmmanager.client.util.ServiceTemplateClientUtil;

import com.dell.pg.asm.identitypool.api.network.INetworkService;
import com.dell.pg.asm.identitypool.api.network.model.Network;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.dell.asm.asmcore.asmmanager.util.osrepository.OSRepositoryUtil;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.validator.GenericValidator;
import org.apache.log4j.Logger;
import org.apache.commons.lang3.StringEscapeUtils;

import com.dell.asm.asmcore.asmmanager.AsmManagerMessages;
import com.dell.asm.asmcore.asmmanager.client.networkconfiguration.Fabric;
import com.dell.asm.asmcore.asmmanager.client.networkconfiguration.Interface;
import com.dell.asm.asmcore.asmmanager.client.networkconfiguration.Partition;
import com.dell.asm.asmcore.asmmanager.client.servicetemplate.ServiceTemplate;
import com.dell.asm.asmcore.asmmanager.client.servicetemplate.ServiceTemplateCategory;
import com.dell.asm.asmcore.asmmanager.client.servicetemplate.ServiceTemplateComponent;
import com.dell.asm.asmcore.asmmanager.client.servicetemplate.ServiceTemplateComponent.ServiceTemplateComponentType;
import com.dell.asm.asmcore.asmmanager.client.servicetemplate.ServiceTemplateOption;
import com.dell.asm.asmcore.asmmanager.client.servicetemplate.ServiceTemplateSetting;
import com.dell.asm.asmcore.asmmanager.client.servicetemplate.ServiceTemplateSettingIDs;
import com.dell.asm.asmcore.asmmanager.client.servicetemplate.ServiceTemplateValid;
import com.dell.asm.asmcore.asmmanager.client.servicetemplate.TemplateRaidConfiguration;
import com.dell.asm.asmcore.asmmanager.client.servicetemplate.VirtualDiskConfiguration;
import com.dell.asm.asmcore.asmmanager.util.deployment.HostnameUtil;
import com.dell.asm.asmcore.asmmanager.util.deployment.NetworkingUtil;
import com.dell.asm.common.utilities.Validator;
import com.dell.asm.i18n2.AsmDetailedMessage;
import com.dell.asm.i18n2.AsmDetailedMessageList;
import com.dell.asm.i18n2.exception.AsmValidationException;
import com.dell.asm.server.client.policy.RaidLevel;
import com.dell.pg.asm.identitypool.api.common.model.NetworkType;
import com.dell.pg.orion.common.utilities.MarshalUtil;

public class ServiceTemplateValidator {

    private INetworkService networkService;
    private ServiceTemplateUtil serviceTemplateUtil;
    private OSRepositoryUtil osRepositoryUtil;

    private static final Logger LOGGER = Logger.getLogger(ServiceTemplateValidator.class);
    private static final String ERROR_DUPLICATE_NETWORKS = "networksDuplicate";
    private static final String ERROR_DUPLICATE_NETWORK_TYPE = "networkTypeDuplicate";
    private static final String ERROR_WORKLOAD_NETS_NOT_SAME = "workloadNetworksNotSame";

    /**
     * Default constructor. Don't init variables here - use getters/setters!
     */
    public ServiceTemplateValidator() {
    }

    /**
     * Validate all components.
     * @param svcTemplate Template to validate
     * @param options Options: deployment time, check for unique names, EM presence
     */
    public void validateTemplate(ServiceTemplate svcTemplate, ValidationOptions options) {
        validateTemplate(svcTemplate, options, null);
    }

    /**
     * Validate all components.
     * @param svcTemplate Template to validate
     * @param options Options: deployment time, check for unique names, EM presence
     * @param existingComponents existing components on scale up call. Used by storage volume validation
     */
    public void validateTemplate(ServiceTemplate svcTemplate, ValidationOptions options,
            List<String> existingComponents) {
        if (svcTemplate == null) {
            return;
        }
        // clear/reset template and component status to default - We assume innocent until proven guilty :)
        clearAllServiceTemplateValidations(svcTemplate);

        String tempXml = MarshalUtil.marshal(svcTemplate);
        ServiceTemplate templateToValidate = MarshalUtil.unmarshal(ServiceTemplate.class, tempXml);

        List<ServiceTemplateComponent> components = templateToValidate.getComponents();
        for (ServiceTemplateComponent component : components) {
            if (component.getComponentID() != null) {
                List<ServiceTemplateCategory> resources = component.getResources();
                for (ServiceTemplateCategory resource : resources) {
                    if (resource.getId() != null) {
                        List<ServiceTemplateSetting> parameters = resource.getParameters();
                        Iterator<ServiceTemplateSetting> iterator = parameters.iterator();
                        while (iterator.hasNext()) {
                            ServiceTemplateSetting next = iterator.next();
                            if (!getServiceTemplateUtil().requiredDependenciesSatisfied(component, next)) {
                                iterator.remove();
                            }
                        }
                    }
                }
            }
        }

        // only validate the next level if previous validation passes
        // we may want to change this eventually but leave as is for now since this is how previous validation worked
        // and then throwing web exceptions to exit the validation 
        // we are now deferring the exceptions to the caller but want validation to execute in the same manner as before
        validateTemplateFields(templateToValidate);

        //retrieve the repos to task map once for all validation
        final Map<String, String> repoToTaskMap = getServiceTemplateUtil().mapReposToTasks();

        if (templateToValidate.getTemplateValid().isValid()) {
            validateRequiredParameters(templateToValidate);
            validateStorageComponentFields(templateToValidate, options.isInventoryContainsEM(),
                    options.isCheckForUniqueness(), svcTemplate, existingComponents);
            validateStorageAuthorizationMatchesServer(templateToValidate);
            validatePasswords(templateToValidate);
            validateClusters(templateToValidate);
            validateServerComponents(templateToValidate, repoToTaskMap);
            validateComponentDependencies(templateToValidate, repoToTaskMap);
            validateVMs(templateToValidate, options.isDeployment());
        }
        copyAllServiceTemplateValidations(templateToValidate, svcTemplate);
    }

    public void validateTemplateFields(final ServiceTemplate svcTemplate) {
        final ServiceTemplateValid serviceTemplateValid = svcTemplate.getTemplateValid();

        // validate template name
        String templateName = svcTemplate.getTemplateName();
        if (GenericValidator.isBlankOrNull(templateName)) {
            serviceTemplateValid.addMessage(AsmManagerMessages.InvalidTemplateName(templateName));
        } else {
            // TODO[fcarta] find out if we need this doesnt look like it really does anything
            templateName = templateName.trim();
            Validator.isLocalisedTemplateNameValid(templateName);
        }
        if (!GenericValidator.isInRange(templateName.length(), Validator.NAME_MIN_SIZE, Validator.NAME_MAX_SIZE)) {
            serviceTemplateValid.addMessage(AsmManagerMessages.InvalidTemplateNameLength(templateName));
        }
        svcTemplate.setTemplateName(templateName.trim());

        // validate template description
        String description = svcTemplate.getTemplateDescription();
        try {
            Validator.validateDescription(description);
        } catch (AsmValidationException ex) {
            serviceTemplateValid.addMessage(ex.getEEMILocalizableMessage());
        }

        // if there are any validation error messages then template is invalid
        if (CollectionUtils.isNotEmpty(serviceTemplateValid.getMessages())) {
            serviceTemplateValid.setValid(Boolean.FALSE);
        }
    }

    /**
     * Validates the storage components within a ServiceTemplate.
     * 
     * @param svcTemplate the service template to be validated, with non-required options removed
     * @param inventoryContainsEM
     * @param checkForUniqueVolume true if volume names are to be checked for uniqueness, or false if that
     *      validation is to be skipped.
     * @param originalTemplate the service template to be validated, as it is stored in DB
     * @param existingComponents Skip volume validation for these components
     */
    public void validateStorageComponentFields(ServiceTemplate svcTemplate, boolean inventoryContainsEM,
            boolean checkForUniqueVolume, ServiceTemplate originalTemplate, List<String> existingComponents) {
        List<String> chapUserNames = new ArrayList<>();
        Boolean isChapValidationExecuted;
        isChapValidationExecuted = false;

        Map<String, Set<String>> uniqueStorageNames = getStorageVolumeMap(originalTemplate);

        List<String> volNames = new ArrayList<>();

        for (ServiceTemplateComponent component : safeList(svcTemplate.getComponents())) {
            boolean validateComponentVolume = existingComponents == null
                    || !existingComponents.contains(component.getId());

            if (component.getType() == ServiceTemplateComponentType.STORAGE) {
                final ServiceTemplateValid componentValid = component.getComponentValid();
                final ServiceTemplateSetting titleSet = svcTemplate.getTemplateSetting(component,
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID);

                if (titleSet == null || StringUtils.isEmpty(titleSet.getValue())) {
                    // bug in UI or controller
                    componentValid.addMessage(AsmManagerMessages.internalError());
                }

                boolean isChapEverUsed = false;
                for (ServiceTemplateCategory category : safeList(component.getResources())) {
                    boolean useChap = false;

                    if (validateComponentVolume && checkForUniqueVolume && uniqueStorageNames != null
                            && !uniqueStorageNames.isEmpty()) {
                        String storageName = ServiceTemplateClientUtil.getVolumeNameForStorageComponent(category);
                        Set<String> existingStorageVolumes = new HashSet<>();
                        ServiceTemplateSetting targetSetting = svcTemplate.getTemplateSetting(component,
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ASM_GUID);
                        if (targetSetting != null) {
                            String targetName = targetSetting.getValue();
                            if (targetName != null) {
                                existingStorageVolumes = uniqueStorageNames.get(targetName);
                            }
                        }
                        // Verify the storagename is unique
                        if (ServiceTemplateClientUtil.isNewStorageVolume(category, false)) {
                            if (StringUtils.isNotEmpty(storageName)) {
                                if (!existingStorageVolumes.add(storageName)) {
                                    duplicateVolNamesError(componentValid, storageName);
                                }
                            }
                        } else if (ServiceTemplateClientUtil.isExistingVolume(category)) {
                            // for existing volumes check those still exists
                            if (!existingStorageVolumes.contains(storageName)) {
                                LOGGER.error("Volume name do not exists: " + storageName);
                                componentValid.addMessage(AsmManagerMessages.nonexistentVolumeName(storageName));
                                break;
                            }
                        }
                    }

                    for (ServiceTemplateSetting setting : safeList(category.getParameters())) {

                        if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID.equalsIgnoreCase(setting.getId())) {
                            String volumeNameInTemplate = ServiceTemplateClientUtil
                                    .getVolumeNameForStorageComponent(category);
                            // if name should be generated, emulate it now
                            if (StringUtils.isEmpty(volumeNameInTemplate)
                                    && ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_AUTOGENERATE
                                            .equals(setting.getValue())) {
                                volumeNameInTemplate = HostnameUtil.generateNameFromNumTemplate(category
                                        .getParameter(
                                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_TEMPLATE)
                                        .getValue(), new HashSet<String>());
                            }
                            // skip dup test for autogen storage volume
                            if (StringUtils.isNotEmpty(volumeNameInTemplate)
                                    && ServiceTemplateClientUtil.isNewStorageVolume(setting, false)) {
                                volNames.add(volumeNameInTemplate);
                                Set<String> volNameSet = new HashSet<>(volNames);
                                if (volNames.size() != 0 && (volNameSet.size() != volNames.size())) {
                                    duplicateVolNamesError(componentValid, volumeNameInTemplate);
                                }
                            }

                            if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_EQL_COMP_ID
                                    .equals(category.getId())) {
                                // volume name may be empty only if it is publish time and option is
                                // "create at deployment". We ignore it. We check all other cases.
                                if (StringUtils.isNotEmpty(volumeNameInTemplate)
                                        && ServiceTemplateClientUtil.isNewStorageVolume(setting, true)
                                        && !isEqlVolNameValid(volumeNameInTemplate)) {
                                    LOGGER.error("Invalid volume name " + volumeNameInTemplate);
                                    componentValid.addMessage(AsmManagerMessages.invalidEqlVolName(
                                            StringEscapeUtils.escapeHtml4(volumeNameInTemplate)));
                                    break;
                                }
                            }

                            if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_COMPELLENT_COMP_ID
                                    .equals(category.getId())) {
                                List<ServiceTemplateSetting> params = category.getParameters();
                                for (ServiceTemplateSetting param : params) {
                                    if (param.getId().equalsIgnoreCase(
                                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_COMPELLENT_PORTTYPE_ID)
                                            && ServiceTemplateSettingIDs.SERVICE_TEMPLATE_COMPELLENT_PORTTYPE_ISCSI
                                                    .equalsIgnoreCase(param.getValue())
                                            && !inventoryContainsEM) {
                                        LOGGER.error("No EM in inventory while CMPL exists in Template");
                                        componentValid.addMessage(AsmManagerMessages.noEmInInventory());
                                        break;
                                    }

                                    Map<String, ServiceTemplateComponent> map = svcTemplate.fetchComponentsMap();
                                    if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_COMPELLENT_BOOT_VOLUME_ID
                                            .equalsIgnoreCase(param.getId())) {
                                        for (String key : component.getAssociatedComponents().keySet()) {
                                            if (map.get(key) != null && map.get(key)
                                                    .getType() == ServiceTemplateComponentType.SERVER) {
                                                for (ServiceTemplateCategory serverCategory : safeList(
                                                        svcTemplate.findComponentById(key).getResources())) {
                                                    for (ServiceTemplateSetting serverParam : safeList(
                                                            serverCategory.getParameters())) {
                                                        if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_ID
                                                                .equals(serverParam.getId())) {
                                                            if (StringUtils.equals(param.getValue(), "true")
                                                                    && !(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_ISCSI
                                                                            .equals(serverParam.getValue())
                                                                            || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_FC
                                                                                    .equals(serverParam
                                                                                            .getValue()))) {
                                                                LOGGER.error(
                                                                        "For a storage with Boot Volume option checked - the Target Boot Device of associated server component should be either Boot from SAN (FC) or Boot from SAN (iSCSI)");
                                                                componentValid.addMessage(
                                                                        AsmManagerMessages.bootVolumeChecked());
                                                            } else if (StringUtils.equals(param.getValue(), "false")
                                                                    && (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_ISCSI
                                                                            .equals(serverParam.getValue())
                                                                            || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_FC
                                                                                    .equals(serverParam
                                                                                            .getValue()))) {
                                                                LOGGER.error(
                                                                        "For a storage with Boot Volume option not checked - the Target Boot Device of associated server component can not be Boot from SAN (FC) or Boot from SAN (iSCSI)");
                                                                componentValid.addMessage(
                                                                        AsmManagerMessages.bootVolumeNotChecked());
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_COMPELLENT_PORTTYPE_ID
                                            .equalsIgnoreCase(param.getId())
                                            && ServiceTemplateSettingIDs.SERVICE_TEMPLATE_COMPELLENT_PORTTYPE_FIBRE_CHANNEL
                                                    .equalsIgnoreCase(param.getValue())) {
                                        if (!isFcStorageWithFcServer(component, svcTemplate)
                                                && component.getAssociatedComponents().size() > 0) {
                                            LOGGER.error(
                                                    "Server component attached with FC Storage component must have FC interface...");
                                            componentValid.addMessage(AsmManagerMessages.fcStorageWithServer());
                                            break;
                                        }
                                    }
                                }
                            }
                            if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_VNX_VOLUME_ID
                                    .equals(category.getId())) {
                                if (!isFcStorageWithFcServer(component, svcTemplate)
                                        && component.getAssociatedComponents().size() > 0) {
                                    LOGGER.error(
                                            "Server component attached with FC Storage component must have FC interface...");
                                    componentValid.addMessage(AsmManagerMessages.fcStorageWithServer());
                                    break;
                                }
                            }
                        } else if (setting.getId().equalsIgnoreCase("size")
                                && ServiceTemplateClientUtil.isNewStorageVolume(titleSet, true)) {
                            if (category.getId().contains("compellent")) {
                                if (!Validator.isCompellentVolumeSizeValid(setting.getValue())) {
                                    LOGGER.error("Invalid volume size " + setting.getValue());
                                    componentValid.addMessage(
                                            AsmManagerMessages.invalidVolumeSizeCmpl(setting.getValue()));
                                }
                            } else if (category.getId().contains("equallogic")
                                    || category.getId().contains("netapp")
                                    || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_VNX_VOLUME_ID
                                            .equals(category.getId())) {
                                if (!Validator.isEquallogicVolumeSizeValid(setting.getValue())) {
                                    LOGGER.error("Invalid volume size " + setting.getValue());
                                    componentValid.addMessage(
                                            AsmManagerMessages.invalidVolumeSizeEql(setting.getValue()));
                                }
                            }
                        } else if (setting.getId().equalsIgnoreCase("snapreserve")
                                || setting.getId().equalsIgnoreCase("thinminreserve")
                                || setting.getId().equalsIgnoreCase("thingrowthwarn")
                                || setting.getId().equalsIgnoreCase("thingrowthmax")
                                || setting.getId().equalsIgnoreCase("thinwarnsoftthres")
                                || setting.getId().equalsIgnoreCase("thinwarnhardthres")) {
                            if (!Validator.isValidPercentage(setting.getValue())) {
                                LOGGER.error("Invalid percentage value" + setting.getValue());
                                componentValid
                                        .addMessage(AsmManagerMessages.invalidPercentageFormat(setting.getValue()));
                            }
                        } else if (setting.getId().equalsIgnoreCase(
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_AUTH_TYPE_ID)) {
                            if (setting.getValue()
                                    .equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_AUTH_TYPE_CHAP_ID)) {
                                useChap = true;
                                isChapEverUsed = true;
                            }
                        } else if (useChap && setting.getId().equalsIgnoreCase("chap_user_name")) {
                            chapUserNames.add(setting.getValue());
                            if (!Validator.isValidCHAPUsername(setting.getValue())) {
                                LOGGER.error("Invalid chap username" + setting.getValue());
                                componentValid
                                        .addMessage(AsmManagerMessages.invalidCHAPUserName(setting.getValue()));
                            }
                            Set<String> chapUserNameSet = new HashSet<>(chapUserNames);
                            if (chapUserNameSet.size() > 1 && !isChapValidationExecuted) {
                                isChapValidationExecuted = true;
                                chapUserNameError(componentValid);
                            }
                        } else if (useChap && setting.getId().equalsIgnoreCase("passwd")) {
                            if (!Validator.isValidCHAPPassword(setting.getValue())) {
                                LOGGER.error("Invalid chap password" + setting.getValue());
                                componentValid.addMessage(AsmManagerMessages.invalidCHAPPassword());
                            }
                        } else if (setting.getId().equalsIgnoreCase("volumefolder")
                                || setting.getId().equalsIgnoreCase("serverfolder")) {
                            if (!Validator.isValidFolderName(setting.getValue())) {
                                LOGGER.error("Invalid folder name" + setting.getValue());
                                componentValid.addMessage(AsmManagerMessages.invalidFolderName(setting.getValue()));
                            }
                        } else if (setting.getId().equalsIgnoreCase("wwn")) {
                            if (!Validator.isValidServerWWN(setting.getValue())) {
                                LOGGER.error("Invalid server wwn" + setting.getValue());
                                componentValid.addMessage(AsmManagerMessages.invalidServerWWN(setting.getValue()));
                            }
                        } else if (setting.getId().equalsIgnoreCase("iqnOrIP")
                                && StringUtils.isNotEmpty(setting.getValue())) {
                            String[] vals;
                            if (setting.getValue().indexOf(',') > 0) {
                                vals = setting.getValue().split(",");
                            } else {
                                vals = new String[1];
                                vals[0] = setting.getValue();
                            }
                            for (String s : vals) {
                                if (!Validator.isValidIPAddressWildcard(s) && !Validator.isValidIQN(s)) {
                                    LOGGER.error("Invalid server iqnOrIP: " + s);
                                    componentValid.addMessage(AsmManagerMessages.invalidServerIPorIQN(s));
                                }
                            }
                        } else if (setting.getId()
                                .equalsIgnoreCase(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_NFS_NETWORK_ID)
                                && StringUtils.isNotEmpty(setting.getValue())) {
                            if (!Validator.isValidIPAddress(setting.getValue())) {
                                LOGGER.error("Invalid NFS/CIFS IP: " + setting.getValue());
                                componentValid.addMessage(AsmManagerMessages.invalidIPforNFS(setting.getValue()));
                            }
                        } else if ((setting.getId().equalsIgnoreCase("volume_notes")
                                || setting.getId().equalsIgnoreCase("server_notes"))
                                && StringUtils.isNotEmpty(setting.getValue())) {
                            if (!Validator.isLocalisedDisplayNameValid(setting.getValue())) {
                                LOGGER.error("Invalid notes " + setting.getValue());
                                componentValid.addMessage(AsmManagerMessages.invalidNotes(setting.getValue()));
                            }
                        }
                    }
                }

                // Validate ICQN/IP vs Chap Settings for related Servers
                final Set<String> relCompsKeys = component.getAssociatedComponents().keySet();
                if (relCompsKeys.size() > 0) {
                    // map to keep count of the number of times a server is added to the same cluster
                    // used to make sure a server is not added to the same cluster more than once
                    for (String key : relCompsKeys) {
                        final ServiceTemplateComponent relComp = svcTemplate.findComponentById(key);
                        // Loop through the related components and check for any servers that are added twice
                        if (relComp != null && relComp.getType() == ServiceTemplateComponentType.SERVER) {
                            for (ServiceTemplateCategory category : safeList(relComp.getResources())) {
                                for (ServiceTemplateSetting setting : safeList(category.getParameters())) {
                                    if ((setting.getId().equalsIgnoreCase(
                                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_ID)
                                            && setting.getValue().equals(
                                                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_ISCSI))
                                            && isChapEverUsed) {
                                        LOGGER.warn(
                                                "Invalid use of CHAP on Target Boot Device - Boot from SAN (ISCSI).");
                                        componentValid
                                                .addMessage(AsmManagerMessages.invalidAuthenticationForStorage());
                                    }
                                }
                            }
                        }
                    }
                }

                // if there are any validation error messages then template is invalid
                if (CollectionUtils.isNotEmpty(componentValid.getMessages())) {
                    componentValid.setValid(Boolean.FALSE);
                    svcTemplate.getTemplateValid().setValid(Boolean.FALSE);
                }
            }
        }
    }

    /**
      * Create a map of ASMGUID to volumes for each storage in template
      * @param template
      * @return
      */
    private Map<String, Set<String>> getStorageVolumeMap(ServiceTemplate template) {
        Map<String, Set<String>> uniqueStorageNames = new HashMap<>();
        for (ServiceTemplateComponent component : safeList(template.getComponents())) {
            if (component.getType() == ServiceTemplateComponentType.STORAGE) {
                for (ServiceTemplateCategory category : safeList(component.getResources())) {
                    ServiceTemplateSetting targetSetting = template.getTemplateSetting(component,
                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ASM_GUID);
                    if (targetSetting != null) {
                        String targetName = targetSetting.getValue();
                        Set<String> storageNames = getServiceTemplateUtil().getVolumeSet(category);
                        if (storageNames != null) {
                            uniqueStorageNames.put(targetName, storageNames);
                        }
                    }
                }
            }
        }
        return uniqueStorageNames;
    }

    boolean isFcStorageWithFcServer(ServiceTemplateComponent component, ServiceTemplate svcTemplate) {
        Map<String, ServiceTemplateComponent> map = svcTemplate.fetchComponentsMap();
        for (String key : component.getAssociatedComponents().keySet()) {
            if (map.get(key) != null && map.get(key).getType() == ServiceTemplateComponentType.SERVER) {
                com.dell.asm.asmcore.asmmanager.client.networkconfiguration.NetworkConfiguration network_config = getServiceTemplateUtil()
                        .deserializeNetwork(svcTemplate.findComponentById(key).getParameterValue(
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_NETWORKING_COMP_ID,
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_NETWORK_CONFIG_ID));
                if (network_config != null) {
                    for (Fabric each_interface : network_config.getInterfaces()) {
                        if (Fabric.FC_TYPE.equalsIgnoreCase(each_interface.getFabrictype())) {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }

    boolean isEqlVolNameValid(String volumeNameInTemplate) {
        if (!Validator.isValidEqlVolumeName(volumeNameInTemplate)
                || !Validator.isValidEqlVolumeNameSize(volumeNameInTemplate)) {
            return Boolean.FALSE;
        } else {
            return Boolean.TRUE;
        }
    }

    private static void chapUserNameError(ServiceTemplateValid componentValid) {
        LOGGER.error("Chap usernames are not same");
        componentValid.addMessage(AsmManagerMessages.sameChapUsernames());
    }

    private static void duplicateVolNamesError(ServiceTemplateValid componentValid, String volumeNameInTemplate) {
        LOGGER.error("Volume name, " + volumeNameInTemplate + ", already exists");
        componentValid.addMessage(AsmManagerMessages.storageVolumeNameAlreadyExists(volumeNameInTemplate));
    }

    public void validateClusters(final ServiceTemplate svcTemplate) {
        // map to keep count of the number of times a particular server is added to any/all clusters
        // used to ensure a server is not added to multiple clusters
        final Map<String, Integer> clusterCount = new HashMap<String, Integer>();
        final Map<ServiceTemplateComponent, Integer> intraClusterServerCount = new HashMap<ServiceTemplateComponent, Integer>();
        for (ServiceTemplateComponent component : safeList(svcTemplate.getComponents())) {
            if (component.getType() == ServiceTemplateComponentType.CLUSTER) {
                final ServiceTemplateValid componentValid = component.getComponentValid();
                // ensure same cluster is not added more than once
                final String clusterKey = generateClusterKey(svcTemplate, component);
                if (!clusterCount.containsKey(clusterKey)) {
                    clusterCount.put(clusterKey, Integer.valueOf(0));
                }
                Integer clusterOccurrence = clusterCount.get(clusterKey);
                clusterCount.put(clusterKey, ++clusterOccurrence);
                if (clusterOccurrence > 1) {
                    componentValid.addMessage(AsmManagerMessages.clusterDuplicate(component.getName()));
                    componentValid.setValid(Boolean.FALSE);
                    svcTemplate.getTemplateValid().setValid(Boolean.FALSE);
                    continue;
                }

                ServiceTemplateSetting failureToleranceMethodSetting = null;
                ServiceTemplateSetting numberFailuresSet = null;

                for (ServiceTemplateCategory resource : safeList(component.getResources())) {
                    for (ServiceTemplateSetting parameter : safeList(resource.getParameters())) {
                        if (parameter.getId().toLowerCase().equalsIgnoreCase(
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CREATE_NEW_PREFIX + "name")
                                && parameter.getValue().toLowerCase().contains(" ")
                                && resource.getId().equalsIgnoreCase(
                                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SCVMM_CLUSTER_COMP_ID)) {
                            componentValid.addMessage(AsmManagerMessages.hyperVClusterNamesWithSpaces());
                            componentValid.setValid(Boolean.FALSE);
                            svcTemplate.getTemplateValid().setValid(Boolean.FALSE);
                        } else if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CLUSTER_FAILURE_ID
                                .equals(parameter.getId()) && !parameter.isHideFromTemplate()) {
                            failureToleranceMethodSetting = parameter;
                        } else if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CLUSTER_FAILURES_NUM_ID
                                .equals(parameter.getId()) && !parameter.isHideFromTemplate()) {
                            numberFailuresSet = parameter;
                        }
                    }
                }

                int numFailuresToTolerate = -1;

                if (failureToleranceMethodSetting != null
                        && !ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SELECT
                                .equals(failureToleranceMethodSetting.getValue())
                        && numberFailuresSet != null && numberFailuresSet.getValue() != null
                        && !ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SELECT
                                .equals(numberFailuresSet.getValue())) {
                    try {
                        numFailuresToTolerate = Integer.parseInt(numberFailuresSet.getValue());
                    } catch (NumberFormatException nfe) {
                        LOGGER.error("Invalid value for "
                                + ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CLUSTER_FAILURES_NUM_ID + " : "
                                + numberFailuresSet.getValue());
                        componentValid.addMessage(AsmManagerMessages.internalError());
                        componentValid.setValid(Boolean.FALSE);
                        svcTemplate.getTemplateValid().setValid(Boolean.FALSE);
                    }
                }

                List<ServiceTemplateComponent> storageComponents = getServiceTemplateUtil()
                        .getAssociatedStorageComponentsFromCluster(component, svcTemplate);
                String podValue = component.getParameterValue(
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ESX_CLUSTER_COMP_ID,
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CLUSTER_CLUSTER_DSC_ID);
                for (ServiceTemplateComponent dsComponent : storageComponents) {
                    ServiceTemplateCategory resource = dsComponent.getResources().get(0);
                    String storageName = ServiceTemplateClientUtil.getVolumeNameForStorageComponent(resource);
                    if (storageName != null && !storageName.isEmpty() && podValue != null
                            && podValue.equalsIgnoreCase(storageName)) {
                        LOGGER.error("Duplicate Storage Cluster Name And Volume Name");
                        componentValid.addMessage(AsmManagerMessages.duplicatePodAndVolName(storageName));
                        break;
                    }
                }

                final Set<String> relCompsKeys = component.getAssociatedComponents().keySet();
                if (relCompsKeys.size() > 0) {
                    // map to keep count of the number of times a server is added to the same cluster
                    // used to make sure a server is not added to the same cluster more than once
                    final Map<ServiceTemplateComponent, Integer> interClusterServerCount = new HashMap<ServiceTemplateComponent, Integer>();
                    for (String key : relCompsKeys) {
                        final ServiceTemplateComponent relComp = svcTemplate.findComponentById(key);
                        // Loop through the related components and check for any servers that are added twice
                        if (relComp != null && relComp.getType() == ServiceTemplateComponentType.SERVER
                                && relComp.isTeardown() == false) {
                            // check the number of occurrences of server in current cluster is not more than one
                            if (!interClusterServerCount.containsKey(relComp)) {
                                interClusterServerCount.put(relComp, Integer.valueOf(0));
                            }
                            Integer serverOccurrencesInSameCluster = interClusterServerCount.get(relComp);
                            interClusterServerCount.put(relComp, ++serverOccurrencesInSameCluster);
                            if (serverOccurrencesInSameCluster > 1) {
                                componentValid.addMessage(AsmManagerMessages.serverIsInMoreThan1Cluster());
                                componentValid.setValid(Boolean.FALSE);
                                svcTemplate.getTemplateValid().setValid(Boolean.FALSE);
                                continue;
                            }

                            // check occurrences of server between clusters is not more than one
                            if (!intraClusterServerCount.containsKey(relComp)) {
                                intraClusterServerCount.put(relComp, Integer.valueOf(0));
                            }
                            Integer serverOccurrencesBetweenClusters = intraClusterServerCount.get(relComp);
                            intraClusterServerCount.put(relComp, ++serverOccurrencesBetweenClusters);
                            if (serverOccurrencesBetweenClusters > 1) {
                                componentValid.addMessage(AsmManagerMessages.serverIsInMoreThan1Cluster());
                                componentValid.setValid(Boolean.FALSE);
                                svcTemplate.getTemplateValid().setValid(Boolean.FALSE);
                            }

                        }
                    }
                }

                int requiredNumberOfHosts = 0;
                String vsanParamValue = component.getParameterValue(
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ESX_CLUSTER_COMP_ID,
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CLUSTER_CLUSTER_VSAN_ID);
                if (vsanParamValue != null && vsanParamValue.equalsIgnoreCase("true")
                        && failureToleranceMethodSetting == null && numberFailuresSet == null) {
                    requiredNumberOfHosts = 3;
                }

                if (failureToleranceMethodSetting != null && numFailuresToTolerate >= 0) {

                    if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CLUSTER_FAILURE_RAID1_ID
                            .equals(failureToleranceMethodSetting.getValue())) {
                        switch (numFailuresToTolerate) {
                        case 0:
                        case 1:
                            requiredNumberOfHosts = 3;
                            break;
                        case 2:
                            requiredNumberOfHosts = 5;
                            break;
                        case 3:
                            requiredNumberOfHosts = 7;
                        }

                    } else if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CLUSTER_FAILURE_RAID5_ID
                            .equals(failureToleranceMethodSetting.getValue())) {
                        switch (numFailuresToTolerate) {
                        case 1:
                            requiredNumberOfHosts = 4;
                            break;
                        case 2:
                            requiredNumberOfHosts = 6;
                        }
                    }

                }

                if (intraClusterServerCount.size() < requiredNumberOfHosts) {
                    componentValid.addMessage(AsmManagerMessages.insufficientNumberOfHostsPerCluster(
                            intraClusterServerCount.size(), requiredNumberOfHosts));
                    componentValid.setValid(Boolean.FALSE);
                    svcTemplate.getTemplateValid().setValid(Boolean.FALSE);
                }

                // vsan port names
                ServiceTemplateSetting vdsSet = component.getParameter(
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ESX_CLUSTER_COMP_ID,
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CLUSTER_CLUSTER_VDS_ID);
                if (vdsSet != null && !vdsSet.isHideFromTemplate()
                        && ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CLUSTER_CLUSTER_VDS_DST_ID
                                .equals(vdsSet.getValue())) {
                    ServiceTemplateCategory vdsCategory = component.getTemplateResource(
                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ESX_CLUSTER_COMP_VDS_ID);
                    if (vdsCategory != null) {
                        List<String> vdsNames = new ArrayList<>();
                        List<String> pgNames = new ArrayList<>();
                        for (ServiceTemplateSetting setting : vdsCategory.getParameters()) {
                            if (setting.getId()
                                    .startsWith(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CLUSTER_VDS_NAME_ID)) {
                                String vdsName = null;
                                if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CREATE_NEW_PREFIX
                                        .equals(setting.getValue())) {
                                    ServiceTemplateSetting newSetting = vdsCategory.getParameter(
                                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CREATE_NEW_PREFIX
                                                    + setting.getId());
                                    if (newSetting != null && StringUtils.isNotEmpty(newSetting.getValue())) {
                                        vdsName = newSetting.getValue();
                                    }
                                } else {
                                    vdsName = setting.getValue();
                                }

                                if (StringUtils.isNotEmpty(vdsName)) {
                                    if (vdsNames.contains(vdsName)) {
                                        componentValid.addMessage(AsmManagerMessages.duplicateVDSName(vdsName));
                                    } else {
                                        vdsNames.add(vdsName);
                                    }
                                }
                            } else if (setting.getId()
                                    .startsWith(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CLUSTER_VDS_PG_ID)) {
                                String pgName = null;
                                if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CREATE_NEW_PREFIX
                                        .equals(setting.getValue())) {
                                    ServiceTemplateSetting newSetting = vdsCategory.getParameter(
                                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CREATE_NEW_PREFIX
                                                    + setting.getId());
                                    if (newSetting != null && StringUtils.isNotEmpty(newSetting.getValue())) {
                                        pgName = newSetting.getValue();
                                    }
                                } else {
                                    pgName = setting.getValue();
                                }

                                if (StringUtils.isNotEmpty(pgName)) {
                                    if (pgNames.contains(pgName)) {
                                        componentValid
                                                .addMessage(AsmManagerMessages.duplicatePortGroupName(pgName));
                                    } else {
                                        pgNames.add(pgName);
                                    }
                                }
                            }
                        }
                    }
                }

                // if there are any validation error messages then template is invalid
                if (CollectionUtils.isNotEmpty(componentValid.getMessages())) {
                    componentValid.setValid(Boolean.FALSE);
                    svcTemplate.getTemplateValid().setValid(Boolean.FALSE);
                }
            }
        }
    }

    private static String generateClusterKey(final ServiceTemplate svcTemplate,
            final ServiceTemplateComponent clusterComponent) {
        if (clusterComponent != null && clusterComponent.getType() == ServiceTemplateComponentType.CLUSTER) {
            String asmGuid = getSafeTemplateSettingValue(svcTemplate, clusterComponent,
                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ASM_GUID);
            String clusterName = asmGuid + "_";
            if (clusterComponent.getComponentID()
                    .equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SCVMM_CLUSTER_COMPONENT_ID)) {
                final String newClusterId = getSafeTemplateSettingValue(svcTemplate, clusterComponent,
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CREATE_NEW_PREFIX
                                + ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SCVMM_CLUSTER_CLUSTER_ID);
                final String clusterId = getSafeTemplateSettingValue(svcTemplate, clusterComponent,
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SCVMM_CLUSTER_CLUSTER_ID);
                clusterName += StringUtils.isNotBlank(newClusterId) ? newClusterId : clusterId;
            } else if (clusterComponent.getComponentID()
                    .equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ESX_CLUSTER_COMPONENT_ID)) {
                final String newClusterId = getSafeTemplateSettingValue(svcTemplate, clusterComponent,
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CREATE_NEW_PREFIX
                                + ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CLUSTER_CLUSTER_ID);
                final String clusterId = getSafeTemplateSettingValue(svcTemplate, clusterComponent,
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CLUSTER_CLUSTER_ID);
                clusterName += StringUtils.isNotBlank(newClusterId) ? newClusterId : clusterId;
            }
            return clusterName;
        } else {
            LOGGER.error(String.format("Component: %s is not of cluster type.", clusterComponent));
            throw new IllegalArgumentException(
                    String.format("Component: %s is not of cluster type.", clusterComponent));
        }
    }

    private static String getSafeTemplateSettingValue(final ServiceTemplate svcTemplate,
            final ServiceTemplateComponent component, final String templateSettingId) {
        final ServiceTemplateSetting templateSetting = svcTemplate.getTemplateSetting(component, templateSettingId);
        return (templateSetting != null) ? templateSetting.getValue() : StringUtils.EMPTY;
    }

    public void validateServerComponents(ServiceTemplate svcTemplate, final Map<String, String> repoToTaskMap) {
        for (ServiceTemplateComponent component : safeList(svcTemplate.getComponents())) {
            boolean installHyperVChecked = false, domainSettingsMissing = false, domainSettingsFilled = false,
                    rhelImage = false, windows2008 = false, isHypervChapValidationExecuted = false;

            if (component.getType() == ServiceTemplateComponentType.SERVER) {
                final ServiceTemplateValid componentValid = component.getComponentValid();
                ServiceTemplateSetting templateImageType = component
                        .getTemplateSetting(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_TYPE_ID);
                if (templateImageType != null && StringUtils.isNotEmpty(templateImageType.getValue())) {
                    if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_REDHAT6_VALUE
                            .equals(templateImageType.getValue())
                            || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_REDHAT7_VALUE
                                    .equals(templateImageType.getValue())) {
                        rhelImage = true;
                    } else if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_WINDOWS2008_VALUE
                            .equals(templateImageType.getValue())) {
                        windows2008 = true;
                    }
                }
                for (ServiceTemplateCategory category : safeList(component.getResources())) {
                    for (ServiceTemplateSetting setting : safeList(category.getParameters())) {
                        if (!rhelImage && setting.getId()
                                .equalsIgnoreCase(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_RAID_ID)) {
                            if (StringUtils.isNotEmpty(setting.getValue())
                                    && setting.getValue().toLowerCase().contains(
                                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_ADVANCED_NON_RAID_ID)) {
                                LOGGER.error("non-RAID configuration not allowed for non-RHEL images: "
                                        + setting.getValue());
                                componentValid.addMessage(AsmManagerMessages.invalidNonRaidConfiguration());
                            }
                        }
                        if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_WINDOWS2008_VALUE
                                .equalsIgnoreCase(setting.getValue())
                                || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_WINDOWS2012_VALUE
                                        .equalsIgnoreCase(setting.getValue())) {
                            Map<String, ServiceTemplateComponent> map = svcTemplate.fetchComponentsMap();
                            for (String key : component.getAssociatedComponents().keySet()) {
                                if (map.get(key) != null
                                        && map.get(key).getType() == ServiceTemplateComponentType.CLUSTER) {
                                    ServiceTemplateCategory cat = svcTemplate.getTemplateResource(map.get(key),
                                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SCVMM_CLUSTER_COMP_ID);
                                    if (cat == null) {
                                        componentValid
                                                .addMessage(AsmManagerMessages.windowsServerWithVMWareCluster());
                                    }
                                }
                            }
                        }
                        if (setting.getId().equalsIgnoreCase(
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HOSTNAME_ID)) {
                            if (StringUtils.isNotEmpty(setting.getValue())
                                    && !HostnameUtil.isValidHostName(setting.getValue(), component)) {
                                ServiceTemplateSetting imageType = component.getTemplateSetting(
                                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_TYPE_ID);
                                if (imageType != null && imageType.getValue()
                                        .equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_ESXI_VALUE)) {
                                    LOGGER.error("Invalid hostname for ESX: " + setting.getValue());
                                    componentValid
                                            .addMessage(AsmManagerMessages.invalidEsxHostname(setting.getValue()));
                                } else {
                                    LOGGER.error("Invalid hostname: " + setting.getValue());
                                    componentValid
                                            .addMessage(AsmManagerMessages.invalidHostname(setting.getValue()));
                                }
                            }
                        } else if (setting.getId().equalsIgnoreCase(
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_VIRTUALIZATION_ID)
                                && ((component.hasHyperV() || component.hasESX(repoToTaskMap))
                                        && !(setting.getValue().equals("Enabled")))) {
                            LOGGER.error(
                                    "BIOS VT must be set for ES or HyperV for server : " + component.getAsmGUID());
                            componentValid.addMessage(AsmManagerMessages.mustSetBIOSForHypervisor());
                        } else if (setting.getId().equalsIgnoreCase(
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_EXECUTE_DISABLE_ID)) {
                            // must be checked for ESX and HyperV
                            if ((component.hasHyperV() || component.hasESX(repoToTaskMap))
                                    && !(setting.getValue().equals("Enabled"))) {
                                LOGGER.error("BIOS Execute Disable must be set for ES or HyperV for server : "
                                        + component.getAsmGUID());
                                componentValid.addMessage(AsmManagerMessages.execDisableCheck());
                            }
                        } else if (setting.getId()
                                .equalsIgnoreCase(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_IMAGE_ID)) {
                            if (!svcTemplate.isDraft()) {
                                if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_COMPID_ALL
                                        .equals(component.getComponentID())
                                        && component.hasDiskBoot()
                                        && (setting.getValue() == null
                                                || setting.getValue().equals(
                                                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SELECT_ID)
                                                || setting.getValue().equals(""))) {
                                    LOGGER.error("Missed OS image for server : " + component.getAsmGUID());
                                    componentValid.addMessage(AsmManagerMessages.serverMustHaveOsImage());
                                }

                                // Validate the external image is actually present
                                if (!getOsRepositoryUtil().isOSRepositoryValid(setting.getValue())) {
                                    LOGGER.error("OS Repository in Error state : " + component.getAsmGUID());
                                    componentValid
                                            .addMessage(AsmManagerMessages.osRepositoryInvalid(setting.getValue()));
                                }
                            }
                        } else if (setting.getId().equalsIgnoreCase(
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HOSTNAME_TEMPLATE_ID)) {
                            if (StringUtils.isNotEmpty(setting.getValue())
                                    && !HostnameUtil.isValidHostNameTemplate(setting.getValue(), component)) {
                                ServiceTemplateSetting imageType = component.getTemplateSetting(
                                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_TYPE_ID);
                                if (imageType != null && imageType.getValue()
                                        .equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_ESXI_VALUE)) {
                                    LOGGER.error("Invalid hostname template for ESX: " + setting.getValue());
                                    componentValid.addMessage(
                                            AsmManagerMessages.invalidEsxHostnameTemplate(setting.getValue()));
                                } else {
                                    LOGGER.error("Invalid hostname template: " + setting.getValue());
                                    componentValid.addMessage(
                                            AsmManagerMessages.invalidHostnameTemplate(setting.getValue()));
                                }
                            }
                        } else if (setting.getId()
                                .equalsIgnoreCase(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_RAID_ID)) {
                            if (StringUtils.isNotEmpty(setting.getValue()) && !validateRAID(setting.getValue())) {
                                LOGGER.error("Invalid RAID configuration: " + setting.getValue());
                                componentValid.addMessage(AsmManagerMessages.invalidRaidConfiguration());
                            }
                        } else if (setting.getId().equalsIgnoreCase(
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_LINUX_NTP_ID)) {
                            // NTP server is required for HyperV
                            if (component.hasHyperV() && StringUtils.isEmpty(setting.getValue())) {
                                LOGGER.error("NTP not set for HyperV for server : " + component.getAsmGUID());
                                componentValid.addMessage(AsmManagerMessages.mustSetNtpForHypervisor());
                            }
                        } else if (setting.getId().equalsIgnoreCase(
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_ID)) {

                            if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_COMPID_ALL
                                    .equals(component.getComponentID())
                                    && (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_SD
                                            .equals(setting.getValue())
                                            || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_SD_RAID_VSAN
                                                    .equals(setting.getValue())
                                            || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_SD_RAID
                                                    .equals(setting.getValue()))
                                    && !component.hasESX(repoToTaskMap)) {
                                LOGGER.error("OS Image must be ESX for SD boot types, server : "
                                        + component.getAsmGUID());
                                componentValid.addMessage(AsmManagerMessages.mustHaveESXForSD());
                            }
                            if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_COMPID_ALL
                                    .equals(component.getComponentID())
                                    && (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_SD
                                            .equals(setting.getValue())
                                            || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_SD_RAID
                                                    .equals(setting.getValue())
                                            || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_SD_RAID_VSAN
                                                    .equals(setting.getValue())
                                            || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_AHCI_VSAN
                                                    .equals(setting.getValue())
                                            || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_HD
                                                    .equals(setting.getValue()))) {

                                List<Network> networks = getServiceTemplateUtil().getServerNetworkByType(component,
                                        NetworkType.PXE);
                                if (networks.size() == 0) { // Then a PXE Network does NOT exist!
                                    LOGGER.error(
                                            "Server uses a SD Card or a Local Hard Drive but does not have a PXE Network configured.");
                                    componentValid
                                            .addMessage(AsmManagerMessages.serverMissingPxeNetworkForBootDevice());
                                }
                            }
                        } else if (setting.getId().equalsIgnoreCase(
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_NETWORK_DEFAULT_GATEWAY_ID)) {
                            if (StringUtils.isNotEmpty(setting.getValue())
                                    && !ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_DHCP_NETWORK_ID
                                            .equals(setting.getValue())) {
                                List<NetworkType> types = new ArrayList<>();
                                types.add(NetworkType.PUBLIC_LAN);
                                types.add(NetworkType.PRIVATE_LAN);
                                List<Network> networks = getServiceTemplateUtil().getServerNetworkByType(component,
                                        types);
                                boolean found = false;
                                for (Network network : networks) {
                                    if (setting.getValue().equals(network.getId())) {
                                        found = true;
                                        break;
                                    }
                                }

                                if (!found) {
                                    LOGGER.error(
                                            "Selected default gateway network is not included in the network configuration.");
                                    componentValid.addMessage(AsmManagerMessages.invalidDefaultGatewayNetwork());
                                }
                            }
                        } else if (setting.getId().equalsIgnoreCase(ServiceTemplateSettingIDs.LOCAL_STORAGE_ID)
                                && !setting.isHideFromTemplate() && "true".equals(setting.getValue())) {

                            List<Network> netwVSAN = serviceTemplateUtil.getServerNetworkByType(component,
                                    NetworkType.VSAN);
                            // normally we would use HashSet<NetworkConfiguration> for duplicate check
                            // but hashCode of NetworkConfiguration has issues (recursive inclusion in iPAddressRanges) and will yeld
                            // different result for same object. I don't want to fix it at this point as it potentially affects large amount of code.
                            // all we need here to ensure unique vlan ID for VSAN networks

                            HashSet<String> duplicateNetworkCheck = new HashSet<>();
                            for (Network ncfg : netwVSAN) {
                                duplicateNetworkCheck.add(String.valueOf(ncfg.getVlanId()));
                            }
                            if (duplicateNetworkCheck.size() != 1) {
                                LOGGER.error("Number of VSAN networks != 1: " + duplicateNetworkCheck.size());
                                componentValid.addMessage(AsmManagerMessages.incorrectNumberOfVSANNetworks());
                            }
                        }
                        if (setting.getId().equalsIgnoreCase(
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_ID)
                                && (!setting.getValue().equalsIgnoreCase(
                                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_NONE)
                                        && !setting.getValue().equalsIgnoreCase(
                                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_NONE_WITH_RAID))) {
                            List<ServiceTemplateCategory> compList = component.getResources();
                            for (ServiceTemplateCategory comp : compList) {
                                if (comp.getId()
                                        .equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_BIOS_RESOURCE)) {
                                    List<ServiceTemplateSetting> paramList = comp.getParameters();
                                    for (ServiceTemplateSetting param : paramList) {
                                        if ((param.getId().equals("BootMode")
                                                && !param.getValue().equalsIgnoreCase("bios"))) {
                                            LOGGER.error(
                                                    "If Target boot device is not None or None with RAID, BootMode must be  BIOS");
                                            componentValid.addMessage(AsmManagerMessages.bootModeCheck());
                                        }
                                    }
                                }
                            }
                        }
                        if ((setting.getId().equalsIgnoreCase(
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_ID)
                                && setting.getValue().equals(
                                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_SD))) {
                            List<ServiceTemplateCategory> compList = component.getResources();
                            for (ServiceTemplateCategory comp : compList) {
                                if (comp.getId()
                                        .equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_BIOS_RESOURCE)) {
                                    List<ServiceTemplateSetting> paramList = comp.getParameters();
                                    for (ServiceTemplateSetting param : paramList) {
                                        if ((param.getId().equals("IntegratedRaid")
                                                && param.getValue().equals("Enabled"))
                                                || (param.getId().equals("InternalSdCard")
                                                        && !param.getValue().equals("On"))) {
                                            LOGGER.error(
                                                    "If - Target boot device = SD, IntegratedRaid must not be enabled and IntegratedSd must be On");
                                            componentValid.addMessage(AsmManagerMessages.integratedRaidCheck());
                                        }
                                    }
                                }
                            }
                        }
                        if ((setting.getId().equalsIgnoreCase(
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_ID)
                                && setting.getValue().equals(
                                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_HD))) {
                            List<ServiceTemplateCategory> compList = component.getResources();
                            for (ServiceTemplateCategory comp : compList) {
                                if (comp.getId()
                                        .equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_BIOS_RESOURCE)) {
                                    List<ServiceTemplateSetting> paramList = comp.getParameters();
                                    for (ServiceTemplateSetting param : paramList) {
                                        if ((param.getId().equals("InternalSdCard")
                                                && param.getValue().equals("On"))
                                                || (param.getId().equals("InternalSdCardRedundancy")
                                                        && !param.getValue().equals("n/a"))
                                                || (param.getId().equals("InternalSdCardPrimaryCard")
                                                        && !param.getValue().equals("n/a"))) {
                                            LOGGER.error(
                                                    "If - Target boot device = HD, IntegratedSd must be Off, InternalSdCardRedundancy and InternalSdCardPrimaryCard must be NA");
                                            componentValid.addMessage(AsmManagerMessages.integratedSdCheck());
                                        }
                                    }
                                }
                            }
                        }
                        if ((setting.getId()
                                .equalsIgnoreCase(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HV_INSTALL)
                                && setting.getValue().equals("true"))) {
                            installHyperVChecked = true;
                        }
                        if (setting.getId()
                                .equalsIgnoreCase(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HV_DN_ID)
                                || setting.getId().equalsIgnoreCase(
                                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HV_ADMIN_LOGIN_ID)
                                || setting.getId().equalsIgnoreCase(
                                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HV_FQDN_ID)
                                || setting.getId().equalsIgnoreCase(
                                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_DOMAIN_PASSWORD_ID)
                                || setting.getId().equalsIgnoreCase(
                                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_DOMAIN_CONFIRM_PASSWORD_ID)) {
                            if (StringUtils.isEmpty(setting.getValue())) {
                                domainSettingsMissing = true;
                            } else {
                                // at least one domain field is not empty
                                domainSettingsFilled = true;
                            }
                        }
                        if (!windows2008
                                && ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HV_DN_ID
                                        .equalsIgnoreCase(setting.getId())
                                && !StringUtils.isBlank(setting.getValue()) && !setting.isHideFromTemplate()) {
                            String domain_login = component.getParameterValue(
                                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_RESOURCE,
                                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HV_ADMIN_LOGIN_ID);
                            String domain_pw = component.getParameterValue(
                                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_RESOURCE,
                                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_DOMAIN_PASSWORD_ID);
                            if (StringUtils.isBlank(domain_login) || StringUtils.isBlank(domain_pw)) {
                                LOGGER.error(
                                        "If domain name is specified for a server component domain admin and domain admin password are required");
                                componentValid.addMessage(AsmManagerMessages.winDomainFieldsCheck());
                            }
                        }
                    }
                }
                if (windows2008 && domainSettingsFilled) {
                    LOGGER.error("Windows 2008 used with Domain settings");
                    componentValid.addMessage(AsmManagerMessages.windows2008WithDomainSettings());
                }
                if (installHyperVChecked && domainSettingsMissing) {
                    LOGGER.error(
                            "Install HyperV checked while DomainName or Username or Password or Conf Password is empty");
                    componentValid.addMessage(AsmManagerMessages.hyperVDomainSettingsMissing());
                }
                if (installHyperVChecked && !isHypervChapValidationExecuted) {
                    if (isHyperVWithChapStorage(svcTemplate, component, isHypervChapValidationExecuted)) {
                        LOGGER.error("For Install HyperV case Equallogic volumes can not have CHAP authentication");
                        componentValid.addMessage(AsmManagerMessages.hypervEqlChapValidation());
                    }
                }
                this.validateServerWithEqualLogicStorageIsNotUsingStaticIscsiNetwork(svcTemplate, component);
                this.validateServerComponentsWithStorageHaveTwoPartitionsWithIsciNetworks(svcTemplate, component);

                if (CollectionUtils.isNotEmpty(componentValid.getMessages())) {
                    componentValid.setValid(Boolean.FALSE);
                    svcTemplate.getTemplateValid().setValid(Boolean.FALSE);
                }
            }
        }
    }

    public boolean isHyperVWithChapStorage(ServiceTemplate svcTemplate, ServiceTemplateComponent component,
            boolean isHypervChapValidationExecuted) {
        Map<String, ServiceTemplateComponent> map = svcTemplate.fetchComponentsMap();
        boolean validationFailed = false;
        for (String key : component.getAssociatedComponents().keySet()) {
            if (map.get(key) != null && map.get(key).getType() == ServiceTemplateComponentType.STORAGE) {
                for (ServiceTemplateCategory category : safeList(
                        svcTemplate.findComponentById(key).getResources())) {
                    if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_EQL_COMP_ID.equals(category.getId())) {
                        for (ServiceTemplateSetting setting : safeList(category.getParameters())) {
                            if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_AUTH_TYPE_ID
                                    .equals(setting.getId())) {
                                if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_AUTH_TYPE_CHAP_ID
                                        .equals(setting.getValue()) && !isHypervChapValidationExecuted) {
                                    isHypervChapValidationExecuted = true;
                                    validationFailed = true;
                                }
                            }
                        }
                    }
                }
            }
        }
        return validationFailed;
    }

    public void validateComponentDependencies(ServiceTemplate svcTemplate,
            final Map<String, String> repoToTaskMap) {
        boolean clusterPresent = templateContainsComponentOfType(svcTemplate,
                ServiceTemplateComponent.ServiceTemplateComponentType.CLUSTER);
        boolean vmPresent = templateContainsComponentOfType(svcTemplate,
                ServiceTemplateComponent.ServiceTemplateComponentType.VIRTUALMACHINE);
        boolean applicationPresent = templateContainsComponentOfType(svcTemplate,
                ServiceTemplateComponent.ServiceTemplateComponentType.SERVICE);
        boolean serverPresent = templateContainsComponentOfType(svcTemplate, ServiceTemplateComponentType.SERVER);
        boolean storagePresent = templateContainsComponentOfType(svcTemplate, ServiceTemplateComponentType.STORAGE);

        final ServiceTemplateValid serviceTemplateValid = svcTemplate.getTemplateValid();
        if (applicationPresent && !serverPresent && !vmPresent) {
            LOGGER.warn("Template has an application, but no virtual machine or server.");
            serviceTemplateValid.addMessage(AsmManagerMessages.templateHasApplicationWithoutVM());
        }
        if (vmPresent && !clusterPresent) {
            LOGGER.warn("Template has a virtual machine, but no cluster.");
            serviceTemplateValid.addMessage(AsmManagerMessages.templateHasVMWithoutCluster());
        }
        if (CollectionUtils.isNotEmpty(serviceTemplateValid.getMessages())) {
            serviceTemplateValid.setValid(Boolean.FALSE);
            return; // if the template is invalid dont proceed with checking the components 
        }

        if (serverPresent) {
            if (!svcTemplate.isDraft()) {
                for (ServiceTemplateComponent component : safeList(svcTemplate.getComponents())) {
                    if (component.getType() == ServiceTemplateComponentType.SERVER) {
                        validateNetworks(component, repoToTaskMap);
                        if (!component.getComponentValid().isValid()) {
                            svcTemplate.getTemplateValid().setValid(Boolean.FALSE);
                            continue; // network validation failed
                        }

                        final ServiceTemplateValid componentValid = component.getComponentValid();
                        List<Network> netwStorageISCSI = getServiceTemplateUtil().getServerNetworkByType(component,
                                NetworkType.STORAGE_ISCSI_SAN);
                        List<Network> netwStorageFC = getServiceTemplateUtil().getServerNetworkByType(component,
                                NetworkType.STORAGE_FCOE_SAN);
                        List<Network> netwHypMgmt = getServiceTemplateUtil().getServerNetworkByType(component,
                                NetworkType.HYPERVISOR_MANAGEMENT);
                        List<Network> netwHypMgr = getServiceTemplateUtil().getServerNetworkByType(component,
                                NetworkType.HYPERVISOR_MIGRATION);
                        List<Network> netwPXE = getServiceTemplateUtil().getServerNetworkByType(component,
                                NetworkType.PXE);
                        List<Network> netwFile = getServiceTemplateUtil().getServerNetworkByType(component,
                                NetworkType.FILESHARE);
                        final Set<String> relCompsKeys = component.getAssociatedComponents().keySet();

                        if (component.hasHyperV()) {
                            // must have 2 storages of EQL type, with at lest 512m size volume
                            int numStorageComp = 0;
                            if (relCompsKeys.size() > 0) {
                                for (String key : relCompsKeys) {
                                    ServiceTemplateComponent relComp = svcTemplate.findComponentById(key);
                                    if (relComp != null
                                            && relComp.getType() == ServiceTemplateComponentType.STORAGE) {
                                        ServiceTemplateSetting volume = svcTemplate.getTemplateSetting(relComp,
                                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID);
                                        numStorageComp++;
                                        ServiceTemplateSetting storageSize = svcTemplate.getTemplateSetting(relComp,
                                                "size");
                                        // check only for new volumes
                                        if (ServiceTemplateClientUtil.isNewStorageVolume(volume, true)
                                                && (storageSize == null
                                                        || getStorageSizeMB(storageSize.getValue()) < 512)) {
                                            componentValid.addMessage(AsmManagerMessages.storageSizeLess512());
                                        }
                                    } else if (relComp != null
                                            && relComp.getType() == ServiceTemplateComponentType.CLUSTER) {
                                        ServiceTemplateCategory cat = svcTemplate.getTemplateResource(relComp,
                                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SCVMM_CLUSTER_COMP_ID);
                                        if (cat == null) {
                                            componentValid.addMessage(AsmManagerMessages.clusterMustBeHyperV());
                                        }
                                    }
                                }
                                if (storagePresent && numStorageComp < 2) {
                                    componentValid.addMessage(AsmManagerMessages.storageMustHave2EQL());
                                }
                            }

                        } else if (component.hasESX(repoToTaskMap)) {
                            ServiceTemplateSetting stgMEM = svcTemplate.getTemplateSetting(component,
                                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_EQL_MEM_ID);

                            // Throw a validation error if EqlLogic MEM is enbaled with a DHCP storage network.
                            if (storagePresent && stgMEM != null && stgMEM.getValue() != null
                                    && stgMEM.getValue().equals("true")) {
                                if (!(netwStorageISCSI.size() > 0 && netwStorageISCSI.get(0).isStatic()
                                        || netwStorageFC.size() > 0 && netwStorageFC.get(0).isStatic())) {
                                    componentValid.addMessage(AsmManagerMessages.memMustHaveStatic());
                                }

                                // if there is a related compellent storage, porttype must be FibreChannel
                                if (relCompsKeys.size() > 0) {
                                    for (String key : relCompsKeys) {
                                        ServiceTemplateComponent relComp = svcTemplate.findComponentById(key);
                                        if (relComp != null
                                                && relComp.getType() == ServiceTemplateComponentType.STORAGE) {
                                            ServiceTemplateCategory eqlStorage = svcTemplate.getTemplateResource(
                                                    relComp,
                                                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_EQL_COMP_ID);
                                            if (eqlStorage == null) {
                                                componentValid.addMessage(
                                                        AsmManagerMessages.eqlMemUsedWithWrongStorage());
                                            }
                                        }
                                    }
                                }
                            }

                            if (clusterPresent) {
                                // Check for 2 conditions
                                // 1. Throw an error if a server is related to more than one cluster
                                // 2. Throw an error if HA is enable with less than 2 storage components

                                int numStorageComp = 0;
                                int numClusterComp = 0;
                                boolean isHA = false;
                                boolean hasEQL = false;
                                boolean isVSAN = false;

                                if (relCompsKeys.size() > 0) {
                                    for (String key : relCompsKeys) {
                                        ServiceTemplateComponent relComp = svcTemplate.findComponentById(key);
                                        if (relComp != null) {
                                            if (relComp.getType() == ServiceTemplateComponentType.STORAGE) {
                                                numStorageComp++;
                                            }
                                            if (relComp.getType() == ServiceTemplateComponentType.CLUSTER) {
                                                ServiceTemplateSetting stgHA = svcTemplate.getTemplateSetting(
                                                        relComp,
                                                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CLUSTER_CLUSTER_HA_ID);
                                                if (stgHA != null && stgHA.getValue() != null
                                                        && stgHA.getValue().equals("true")) {
                                                    isHA = true;
                                                }
                                                numClusterComp++;
                                                if (numClusterComp > 1) {
                                                    componentValid.addMessage(
                                                            AsmManagerMessages.serverIsInMoreThan1Cluster());
                                                }

                                                // check for VDS cluster
                                                if (netwHypMgmt.size() < 2) {
                                                    ServiceTemplateSetting vdsSet = relComp.getParameter(
                                                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ESX_CLUSTER_COMP_ID,
                                                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CLUSTER_CLUSTER_VDS_ID);
                                                    if (vdsSet != null
                                                            && ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CLUSTER_CLUSTER_VDS_DST_ID
                                                                    .equals(vdsSet.getValue()))
                                                        componentValid.addMessage(
                                                                AsmManagerMessages.serverMustHave2HVMNetworks());
                                                }
                                            }
                                            if (storagePresent && svcTemplate.getTemplateResource(relComp,
                                                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_EQL_COMP_ID) != null) {
                                                hasEQL = true;
                                            }
                                        } else {
                                            // we don't have default related components any more. If we are here, something must be wrong with
                                            // template processing. Keep it for debugging
                                            LOGGER.error("Cannot find related component by key: " + key
                                                    + ", service template: " + MarshalUtil.marshal(svcTemplate));
                                        }
                                    }
                                }

                                if (checkForMinStorageComponents(component, isHA, storagePresent, numStorageComp)) {
                                    componentValid.addMessage(AsmManagerMessages.haMustHave2StorComponents());
                                }

                                // We need a minimum of 2 iscsi networks selected for an end to end esx deployment with a cluster
                                if (hasEQL && netwStorageISCSI.size() != 2) {
                                    componentValid.addMessage(AsmManagerMessages.serverMustHave2ISCSI());
                                }
                            } else if (storagePresent) {
                                // ESX, storage and no cluster
                                componentValid.addMessage(AsmManagerMessages.esxTemplateMustHaveCluster());
                            }
                        }
                        if (storagePresent && component.hasDiskBoot()) {
                            boolean hasNetApp = false;
                            boolean hasCompellent = false;
                            boolean hasEQL = false;
                            if (relCompsKeys.size() > 0) {
                                for (String key : relCompsKeys) {
                                    ServiceTemplateComponent relComp = svcTemplate.findComponentById(key);
                                    if (relComp != null
                                            && relComp.getType() == ServiceTemplateComponentType.STORAGE) {
                                        if (svcTemplate.getTemplateResource(relComp,
                                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_NETAPP_COMP_ID) != null) {
                                            hasNetApp = true;
                                        }
                                        if (svcTemplate.getTemplateResource(relComp,
                                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_COMPELLENT_COMP_ID) != null) {
                                            hasCompellent = true;
                                        }
                                        if (svcTemplate.getTemplateResource(relComp,
                                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_EQL_COMP_ID) != null) {
                                            hasEQL = true;
                                        }
                                    }
                                }
                            }
                            // SAN (iSCSI) network is required in the case if the template include the EQL storage as datastore
                            if (netwStorageISCSI.size() == 0 && hasEQL) {
                                componentValid.addMessage(AsmManagerMessages.serverMustHaveStorageNetwork());
                            }
                            // ISCSI and CMPL = error
                            /*if (netwStorageISCSI.size() >0 && hasCompellent) {
                            componentValid.addMessage(AsmManagerMessages.storageCompellentAndISCSI());
                            }*/
                            // In the case for NetApp, make sure required networks are selected. - Hypervisor Mgmt, Hypervisor Migration, PXE must be partition 1, and Fileshare network.
                            if (hasNetApp && (netwHypMgmt.size() == 0 || netwHypMgr.size() == 0
                                    || netwPXE.size() == 0 || netwFile.size() == 0)) {
                                componentValid
                                        .addMessage(AsmManagerMessages.serverWithNetappMustHaveRequiredNetwork());
                            }
                        }

                        if (CollectionUtils.isNotEmpty(componentValid.getMessages())) {
                            componentValid.setValid(Boolean.FALSE);
                            svcTemplate.getTemplateValid().setValid(Boolean.FALSE);
                        }
                        // end of server type
                    } else if (component.getType() == ServiceTemplateComponentType.CLUSTER) {
                        final ServiceTemplateValid componentValid = component.getComponentValid();
                        // hyperV cluster must be coupled with hyperv server
                        if (component.hasHyperV()) {
                            final Set<String> relCompsKeys = component.getAssociatedComponents().keySet();
                            int numStorageComp = 0;
                            if (relCompsKeys.size() > 0) {
                                for (String key : relCompsKeys) {
                                    ServiceTemplateComponent relComp = svcTemplate.findComponentById(key);
                                    if (relComp != null
                                            && relComp.getType() == ServiceTemplateComponentType.SERVER) {
                                        if (!relComp.hasHyperV())
                                            componentValid.addMessage(AsmManagerMessages.serverMustBeHyperV());
                                    }
                                }
                            }
                        }
                        if (CollectionUtils.isNotEmpty(componentValid.getMessages())) {
                            componentValid.setValid(Boolean.FALSE);
                            svcTemplate.getTemplateValid().setValid(Boolean.FALSE);
                        }
                    } // end of cluster type
                } // end of component loop
            } else { // Means we are in draft mode
                for (ServiceTemplateComponent component : safeList(svcTemplate.getComponents())) {
                    if (component.getType() == ServiceTemplateComponentType.SERVER) {
                        validateNetworks(component, repoToTaskMap);
                    }
                }
            }
        }
    }

    boolean checkForMinStorageComponents(ServiceTemplateComponent component, boolean isHA, boolean storagePresent,
            int numStorageComp) {
        String vsan_param = component.getParameterValue(
                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_RESOURCE,
                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_RESOURCE_VSAN);
        boolean isVSAN = false;
        if (vsan_param != null && vsan_param.equals("true")) {
            isVSAN = true;
        }
        if (isHA && storagePresent && numStorageComp < 2 && !isVSAN) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Validate server network configuration
     * @param component
     */
    public void validateNetworks(ServiceTemplateComponent component, final Map<String, String> repoToTaskMap) {
        // for use with partition mask
        int M_PXE = 0x0000001;
        int M_HMGMT = 0x0000010;
        int M_HMGRN = 0x0000100;
        int M_HCLST = 0x0001000;
        int M_ISCSI = 0x0010000;
        int M_FILE = 0x0100000;
        int M_OTHER = 0x1000000;

        ServiceTemplateSetting networking = component
                .getTemplateSetting(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_NETWORK_CONFIG_ID);
        if (networking == null) {
            // some server components may not include networking configuration
            return;
        }

        // Skip network validation of hardware only configuration
        if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_COMPID_HW.equals(component.getComponentID())) {
            return;
        }

        com.dell.asm.asmcore.asmmanager.client.networkconfiguration.NetworkConfiguration networkConfig = getServiceTemplateUtil()
                .deserializeNetwork(networking.getValue());

        if (networkConfig == null) {
            LOGGER.warn("No networking configuration on server component: " + component.getAsmGUID());
            return;
        }
        boolean isSanBoot = component.hasSanBoot();
        boolean isNoneBoot = component.hasNoneBoot();
        boolean hasESX = component.hasESX(repoToTaskMap);
        boolean hasHyperV = component.hasHyperV();
        boolean hasBareMetalOS = component.hasBareMetal(repoToTaskMap);
        boolean isISCSIBoot = component.hasSanISCSIBoot();

        List<String> vMotionNetworks = new ArrayList<String>();
        List<String> pxeNetworks = new ArrayList<String>();
        List<String> hypManangementNetworks = new ArrayList<String>();
        List<String> vsanNetworks = new ArrayList<String>();
        List<String> fipsNetworks = new ArrayList<String>();

        boolean hasPXE = false;
        boolean hasStaticPXE = false;
        boolean hasPXEOnPartNot1 = false;
        boolean hasHypervisorMgmt = false;
        boolean hasHMOnPart1 = false;
        boolean hasHypervisorMigration = false;
        boolean hasHypervisorCluster = false;
        boolean hasISCSI = false;

        boolean hasHypervisorMgmtStatic = false;
        boolean hasHypervisorMigrationStatic = false;
        boolean hasHypervisorClusterStatic = false;
        boolean hasISCSIStatic = false;
        boolean hasInvalidPartitionNetwork = false;

        boolean hasOtherStatic = false;

        boolean componentInvalidForEsx = false;
        String errorCase = null;

        List<Interface> interfaces = networkConfig.getUsedInterfaces();

        HashSet<String> partitionNetworkTypes = new HashSet<String>();
        List<List<String>> workloadNetworksCheck = new ArrayList<List<String>>();
        List<String> bareMetalOsNetworkCheck = new ArrayList<String>();

        boolean iscsiOnPort1 = false;
        boolean foundSingleISCSIOnPort1 = false;

        boolean isBootDeviceFc = false;
        boolean fcNetworkPresent = false;

        final ServiceTemplateValid componentValid = component.getComponentValid();

        for (ServiceTemplateCategory category : safeList(component.getResources())) {
            for (ServiceTemplateSetting setting : safeList(category.getParameters())) {
                if ((setting.getId()
                        .equalsIgnoreCase(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_ID)
                        && setting.getValue()
                                .equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_FC))) {
                    isBootDeviceFc = true;
                }
                if (((setting.getId()
                        .equalsIgnoreCase(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_NETWORK_CONFIG_ID)
                        && setting.getValue().toLowerCase().contains("\"usedforfc\":true")))
                        || ((setting.getId().equalsIgnoreCase(
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_NETWORK_CONFIG_ID)
                                && setting.getValue().toLowerCase().contains("\"fabrictype\":\"fc\"")))) {
                    fcNetworkPresent = true;
                }
            }
        }

        if (isBootDeviceFc && !fcNetworkPresent) {
            LOGGER.error("fcNetworksError");
            componentValid.addMessage(AsmManagerMessages.fcNwtworksValidation());
            componentValid.setValid(Boolean.FALSE);
        }

        for (Interface interfaceObject : interfaces) {

            if (interfaceObject.isPartitioned() && hasHyperV) {
                // stop vaidation here and return
                componentValid.addMessage(AsmManagerMessages.serverWithHyperVPartitioned());
                componentValid.setValid(Boolean.FALSE);
                return;
            }

            List<Partition> partitions = interfaceObject.getPartitions();

            for (Partition partition : partitions) {

                partitionNetworkTypes.clear();
                bareMetalOsNetworkCheck.clear();

                List<String> networkIds = partition.getNetworks();
                Integer curMask = 0;

                if (networkIds != null) {
                    for (String networkId : networkIds) {

                        Network networkObject = getNetworkService().getNetwork(networkId);

                        // In general networkObject should never be null, but ran into cases with
                        // invalid default templates where it was.
                        String networkType = networkObject == null ? "" : networkObject.getType().value();

                        boolean isStatic = networkObject != null && networkObject.isStatic();
                        if (networkType.equals(NetworkType.STORAGE_ISCSI_SAN.value())) {
                            hasISCSI = true;
                            curMask |= M_ISCSI;
                            hasISCSIStatic = isStatic;

                            if (isSanBoot && !isStatic) {
                                // iSCSI must be static fo SAN boot iSCSI
                                componentValid.addMessage(AsmManagerMessages.iscsiMustHaveStatic());
                            }
                        } else if (networkType.equals(NetworkType.PXE.value())) {
                            hasPXE = true;
                            curMask |= M_PXE;
                            if (networkObject.isStatic()) {
                                hasStaticPXE = true;
                            }
                            if (!partition.getName().equals("1"))
                                hasPXEOnPartNot1 = true;

                        } else if (networkType.equals(NetworkType.HYPERVISOR_MANAGEMENT.value())) {
                            hasHypervisorMgmt = true;
                            curMask |= M_HMGMT;
                            if (partition.getName().equals("1"))
                                hasHMOnPart1 = true;

                            hasHypervisorMgmtStatic = isStatic;

                        } else if (networkType.equals(NetworkType.HYPERVISOR_CLUSTER_PRIVATE.value())) {
                            hasHypervisorCluster = true;
                            hasHypervisorClusterStatic = isStatic;
                            curMask |= M_HCLST;
                        } else if (networkType.equals(NetworkType.HYPERVISOR_MIGRATION.value())) {
                            hasHypervisorMigration = true;
                            hasHypervisorMigrationStatic = isStatic;
                            curMask |= M_HMGRN;
                        } else if (networkType.equals(NetworkType.FILESHARE.value())) {
                            curMask |= M_FILE;
                        } else {
                            curMask |= M_OTHER;

                            if (isStatic) {
                                hasOtherStatic = true;
                            }
                        }

                        if (hasESX) {
                            if (networkType.equals(NetworkType.HYPERVISOR_MIGRATION.value())) {
                                vMotionNetworks.add(networkId);
                            }

                            if (networkType.equals(NetworkType.PXE.value())) {
                                pxeNetworks.add(networkId);
                            }

                            if (networkType.equals(NetworkType.VSAN.value())) {
                                vsanNetworks.add(networkId);
                            }

                            if (networkType.equals(NetworkType.FIP_SNOOPING.value())) {
                                fipsNetworks.add(networkId);
                            }

                            if (networkType.equals(NetworkType.HYPERVISOR_MANAGEMENT.value())) {
                                hypManangementNetworks.add(networkId);
                            }

                            if (networkType.equals(NetworkType.PRIVATE_LAN.value())
                                    || networkType.equals(NetworkType.PUBLIC_LAN.value())) {
                                List<String> netTemp = new ArrayList<String>();
                                for (String netId : networkIds) {
                                    if (NetworkType.PRIVATE_LAN
                                            .equals(getNetworkService().getNetwork(netId).getType())
                                            || NetworkType.PUBLIC_LAN
                                                    .equals(getNetworkService().getNetwork(netId).getType())) {
                                        netTemp.add(netId);
                                    }
                                }
                                workloadNetworksCheck.add(netTemp);
                            }
                            partitionNetworkTypes.add(networkType);
                        }

                        if (hasBareMetalOS) {
                            if (!hasInvalidPartitionNetwork) {
                                // partition index, number, etc. is always 0; use the name to identify the partition index
                                if (component.hasLinuxOS() && !partition.getName().equals("1")) {
                                    hasInvalidPartitionNetwork = true;
                                    componentValid.addMessage(
                                            AsmManagerMessages.invalidPartitionForNetwork(component.getName()));
                                }
                            }
                            bareMetalOsNetworkCheck.add(networkType);
                        }
                    }
                }

                if (hasBareMetalOS && bareMetalOsNetworkCheck.size() != 0) {
                    boolean validNets = true;
                    for (String netType : bareMetalOsNetworkCheck) {
                        if (!netType.equals(NetworkType.PXE.value())
                                && !netType.equals(NetworkType.PRIVATE_LAN.value())
                                && !netType.equals(NetworkType.PUBLIC_LAN.value())
                                && !netType.equals(NetworkType.STORAGE_FCOE_SAN.value())
                                && !netType.equals(NetworkType.FIP_SNOOPING.value())
                                && !netType.equals(NetworkType.FILESHARE.value())
                                && !netType.equals(NetworkType.STORAGE_ISCSI_SAN.value())) {
                            validNets = false;
                            LOGGER.error("incorrectNetworksOnBareMetalOs");
                            componentValid
                                    .addMessage(AsmManagerMessages.incorrectNetworkConfForBareMetalAndLinux2());
                            break;
                        }
                    }
                    if (!validNets)
                        break;
                }

                if (hasESX) {
                    if (partitionNetworkTypes.contains(NetworkType.FIP_SNOOPING.value())
                            && !(partitionNetworkTypes.contains(NetworkType.FIP_SNOOPING.value())
                                    && partitionNetworkTypes.contains(NetworkType.STORAGE_FCOE_SAN.value()))) {
                        componentInvalidForEsx = true;
                        errorCase = ERROR_DUPLICATE_NETWORK_TYPE;
                        LOGGER.error(
                                "networkTypeDuplicateOnSamePartition - FIP Snooping FCOE Networks Partitions Error");
                    }
                }

                // checks per port
                // Bare metal OS
                if (hasBareMetalOS) {
                    if (interfaceObject.getName().equals("Port 1")) {

                        //  In the case of boot from iSCSI, iSCSI network must be selected for one of the NIC port1. And no other network can be seleced on the same port.
                        if (isISCSIBoot && hasISCSI) {
                            iscsiOnPort1 = true;
                        }

                        if (isISCSIBoot && hasISCSI && curMask == M_ISCSI) {
                            foundSingleISCSIOnPort1 = true;
                        }
                    }
                }

                // ignore all but first partitions
                if (!interfaceObject.isPartitioned())
                    break;
                // Different nic types have different number of partitions but data may include more that should be ignored
                if (partition.getName().equals(Integer.toString(interfaceObject.getMaxPartitions()))) {
                    break;
                }

            }
        }

        if (hasBareMetalOS) {
            //  In the case of boot from iSCSI, iSCSI network must be selected for one of the NIC port1. And no other network can be seleced on the same port.
            if (isISCSIBoot && !iscsiOnPort1) {
                componentValid.addMessage(AsmManagerMessages.iscsiMustBeOnPort1());
            }
            if (isISCSIBoot && hasISCSI && !foundSingleISCSIOnPort1) {
                componentValid.addMessage(AsmManagerMessages.iscsiMustBeTheOnlyNetwork());
            }
        }

        // For any cases that requires ASM to deploy OS, need to make sure PXE network is selected.
        // this is required for full server component
        if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_COMPID_ALL.equals(component.getComponentID())) {
            if (!isSanBoot && !isNoneBoot && !hasPXE) {
                componentValid.addMessage(AsmManagerMessages.serverMustHavePXE());
            } else {
                // Installing Hyper-V or Windows using a static OS Installation network is not currently supported
                if (hasStaticPXE) {
                    ServiceTemplateSetting osVersion = component.getParameter(
                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_RESOURCE,
                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_VERSION_ID);
                }

                if (hasBareMetalOS) {
                    if (hasPXE && hasPXEOnPartNot1)
                        componentValid.addMessage(AsmManagerMessages.wrongPartition(NetworkType.PXE.value(), 1));
                }

                // In the case for Hyper-v, make sure required networks are selected.
                // Hypervisor Mgmt, Hypervisor Migration, Hypervisor Cluster private, PXE, iSCSI
                // no partitions
                if (hasHyperV) {
                    if (!hasPXE)
                        componentValid.addMessage(
                                AsmManagerMessages.serverMissedNetwork("Hyper-V", NetworkType.PXE.value()));
                    else if (hasPXE && hasPXEOnPartNot1)
                        componentValid.addMessage(AsmManagerMessages.wrongPartition(NetworkType.PXE.value(), 1));
                    else if (!hasHypervisorMgmt)
                        componentValid.addMessage(AsmManagerMessages.serverMissedNetwork("Hyper-V",
                                NetworkType.HYPERVISOR_MANAGEMENT.value()));
                    else if (hasHypervisorMgmt && !hasHMOnPart1)
                        componentValid.addMessage(
                                AsmManagerMessages.wrongPartition(NetworkType.HYPERVISOR_MANAGEMENT.value(), 1));
                    else if (!hasHypervisorMigration)
                        componentValid.addMessage(AsmManagerMessages.serverMissedNetwork("Hyper-V",
                                NetworkType.HYPERVISOR_MIGRATION.value()));
                    else if (!hasHypervisorCluster)
                        componentValid.addMessage(AsmManagerMessages.serverMissedNetwork("Hyper-V",
                                NetworkType.HYPERVISOR_CLUSTER_PRIVATE.value()));

                    if (hasISCSI && !hasISCSIStatic) {
                        componentValid.addMessage(
                                AsmManagerMessages.hypervRequiresStatic(NetworkType.STORAGE_ISCSI_SAN.value()));
                    } else if (!hasHypervisorMgmtStatic) {
                        componentValid.addMessage(
                                AsmManagerMessages.hypervRequiresStatic(NetworkType.HYPERVISOR_MANAGEMENT.value()));
                    } else if (!hasHypervisorMigrationStatic) {
                        componentValid.addMessage(
                                AsmManagerMessages.hypervRequiresStatic(NetworkType.HYPERVISOR_MIGRATION.value()));
                    } else if (!hasHypervisorClusterStatic) {
                        componentValid.addMessage(AsmManagerMessages
                                .hypervRequiresStatic(NetworkType.HYPERVISOR_CLUSTER_PRIVATE.value()));
                    }
                }

                // In the case for ESXi, make sure required networks are selected.
                // Hypervisor Mgmt, Hypervisor Migration, Hypervisor Cluster private, PXE must be partition 1
                if (hasESX) {

                    HashSet<String> duplicateNetworkCheck;

                    if (!hasPXE)
                        componentValid
                                .addMessage(AsmManagerMessages.serverMissedNetwork("ESX", NetworkType.PXE.value()));
                    else if (hasPXE && hasPXEOnPartNot1)
                        componentValid.addMessage(AsmManagerMessages.wrongPartition(NetworkType.PXE.value(), 1));
                    else if (!hasHypervisorMgmt)
                        componentValid.addMessage(AsmManagerMessages.serverMissedNetwork("ESX",
                                NetworkType.HYPERVISOR_MANAGEMENT.value()));

                    if (workloadNetworksCheck.size() > 1) {
                        for (List<String> partitionNetworks : workloadNetworksCheck) {
                            if (!(partitionNetworks.containsAll(workloadNetworksCheck.get(1))
                                    && workloadNetworksCheck.get(1).containsAll(partitionNetworks))) {
                                componentInvalidForEsx = true;
                                errorCase = ERROR_WORKLOAD_NETS_NOT_SAME;
                                LOGGER.error(ERROR_WORKLOAD_NETS_NOT_SAME);
                            }
                        }
                    }

                    duplicateNetworkCheck = new HashSet<>(pxeNetworks);
                    if (duplicateNetworkCheck.size() > 1) {
                        componentInvalidForEsx = true;
                        errorCase = ERROR_DUPLICATE_NETWORKS;
                        LOGGER.error("duplicateNetworkCheck - PXE");
                    }

                    duplicateNetworkCheck = new HashSet<>(vMotionNetworks);
                    if (duplicateNetworkCheck.size() > 1) {
                        componentInvalidForEsx = true;
                        errorCase = ERROR_DUPLICATE_NETWORKS;
                        LOGGER.error("duplicateNetworkCheck - vMotionNetworks");
                    }

                    duplicateNetworkCheck = new HashSet<>(hypManangementNetworks);
                    if (duplicateNetworkCheck.size() > 1) {
                        componentInvalidForEsx = true;
                        errorCase = ERROR_DUPLICATE_NETWORKS;
                        LOGGER.error("duplicateNetworkCheck - hypManangementNetworks");
                    }

                    duplicateNetworkCheck = new HashSet<>(fipsNetworks);
                    if (duplicateNetworkCheck.size() > 1) {
                        componentInvalidForEsx = true;
                        errorCase = ERROR_DUPLICATE_NETWORKS;
                        LOGGER.error("duplicateNetworkCheck - fipsNetworks");
                    }

                    if (componentInvalidForEsx) {
                        if (ERROR_DUPLICATE_NETWORKS.equals(errorCase))
                            componentValid.addMessage(AsmManagerMessages.networksDuplicate());

                        if (ERROR_DUPLICATE_NETWORK_TYPE.equals(errorCase))
                            componentValid.addMessage(AsmManagerMessages.networkTypeDuplicate());

                        if (ERROR_WORKLOAD_NETS_NOT_SAME.equals(errorCase))
                            componentValid.addMessage(AsmManagerMessages.workloadNetworksNotSame());
                    }
                }
            }
        }

        if (CollectionUtils.isNotEmpty(componentValid.getMessages())) {
            componentValid.setValid(Boolean.FALSE);
        }
    }

    public void validateVMs(ServiceTemplate svcTemplate, boolean isDeployment) {
        final List<String> names = new ArrayList<>();
        for (ServiceTemplateComponent component : safeList(svcTemplate.getComponents())) {
            if (component.getType() == ServiceTemplateComponentType.VIRTUALMACHINE) {
                final ServiceTemplateValid componentValid = component.getComponentValid();
                ServiceTemplateSetting nameSet = svcTemplate.getTemplateSetting(component,
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VM_NAME);
                if (nameSet != null) {
                    if (names.contains(nameSet.getValue())) {
                        if (isDeployment) {
                            LOGGER.error("Duplicate name for VM: " + nameSet.getValue());
                            componentValid.addMessage(AsmManagerMessages.duplicateVMName(nameSet.getValue()));
                        }
                    } else {
                        names.add(nameSet.getValue());
                    }
                }

                ServiceTemplateSetting setting = svcTemplate.getTemplateSetting(component,
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HOSTNAME_ID);
                if (setting == null) {
                    setting = svcTemplate.getTemplateSetting(component,
                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VM_NAME);
                }
                if (setting != null && StringUtils.isNotEmpty(setting.getValue())
                        && !HostnameUtil.isValidHostName(setting.getValue(), component)) {
                    LOGGER.error("Invalid hostname: " + setting.getValue());
                    componentValid.addMessage(AsmManagerMessages.invalidHostname(setting.getValue()));
                }

                setting = svcTemplate.getTemplateSetting(component,
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HOSTNAME_TEMPLATE_ID);
                if ((setting != null) && StringUtils.isNotEmpty(setting.getValue())
                        && !HostnameUtil.isValidHostNameTemplateForVMs(setting.getValue(), component)) {
                    LOGGER.error("Invalid hostname template: " + setting.getValue());
                    componentValid.addMessage(AsmManagerMessages.invalidHostnameTemplateForVMs());
                }

                setting = svcTemplate.getTemplateSetting(component,
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VM_NAME_TEMPLATE_ID);
                if ((setting != null) && StringUtils.isNotEmpty(setting.getValue())
                        && !HostnameUtil.isValidHostNameTemplateForVMs(setting.getValue(), component)) {
                    LOGGER.error("Invalid hostname template: " + setting.getValue());
                    componentValid.addMessage(AsmManagerMessages.invalidHostnameTemplateForVMs());
                }

                ServiceTemplateSetting setNetwork = svcTemplate.getTemplateSetting(component,
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VM_NETWORK_ID);
                if (setNetwork == null || StringUtils.isEmpty(setNetwork.getValue())) {
                    LOGGER.error("VM must have workload network");
                    componentValid.addMessage(AsmManagerMessages.vmMustHaveNetwork(component.getName()));
                }

                int numClusters = countAssociatedClusters(svcTemplate, component);
                if (numClusters != 1) {
                    componentValid.addMessage(AsmManagerMessages.invalidNumberOfClustersForVM());
                }
                // ensure the VM type is valid against the Cluster type
                validateAssociatedClusterType(svcTemplate, component, componentValid);

                if (CollectionUtils.isNotEmpty(componentValid.getMessages())) {
                    componentValid.setValid(Boolean.FALSE);
                    svcTemplate.getTemplateValid().setValid(Boolean.FALSE);
                }
            }
        }
    }

    private void validateAssociatedClusterType(ServiceTemplate svcTemplate, ServiceTemplateComponent component,
            final ServiceTemplateValid componentValid) {
        Set<String> related = component.getAssociatedComponents().keySet();
        ServiceTemplateComponent cluster = null;
        if (related != null && related.size() > 0) {
            // Match required is no longer completely valid due to VMs having Applications
            // A cluster may not actually exist for the VM, but an Application may there
            boolean matchRequired = false;
            if (related.size() > 1) {
                matchRequired = true;
            }
            for (ServiceTemplateComponent c : safeList(svcTemplate.getComponents())) {
                if (c.getType() == ServiceTemplateComponentType.CLUSTER) {
                    if (matchRequired && !related.contains(c.getId())) {
                        continue;
                    } else {
                        cluster = c;
                        break;
                    }
                }
            }
            if (cluster != null // Cluster may not be there if it's been removed
                    && (component
                            .getTemplateResource(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VM_RESOURCE) != null
                            && cluster.getTemplateResource(
                                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SCVMM_CLUSTER_COMP_ID) != null)
                    || (component
                            .getTemplateResource(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_HV_VM_RESOURCE) != null
                            && cluster.getTemplateResource(
                                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ESX_CLUSTER_COMP_ID) != null)) {
                LOGGER.warn("VM type and the cluster type do not match!");
                componentValid.addMessage(AsmManagerMessages.invalidVMAssociation());
            }
        }
    }

    private int countAssociatedClusters(ServiceTemplate svcTemplate, ServiceTemplateComponent component) {
        int count = 0;
        Set<String> related = component.getAssociatedComponents().keySet();
        if (related != null && related.size() > 0) {
            for (ServiceTemplateComponent c : safeList(svcTemplate.getComponents())) {
                if (c.getType() == ServiceTemplateComponentType.CLUSTER && related.contains(c.getId())) {
                    ++count;
                }
            }
        }
        return count;
    }

    public void validateRequiredParameters(final ServiceTemplate svcTemplate) {
        // Loop through all the parameters since we dont have a good way to look them up right now
        // if they are marked required ensure a value is set otherwise log message and set template to invalid
        for (final ServiceTemplateComponent component : svcTemplate.getComponents()) {
            final ServiceTemplateValid componentValid = component.getComponentValid();
            for (final ServiceTemplateCategory resource : component.getResources()) {
                for (final ServiceTemplateSetting parameter : resource.getParameters()) {
                    if (isVisibleRequiredParameter(parameter)
                            && getServiceTemplateUtil().requiredDependenciesSatisfied(component, parameter)
                            && StringUtils.isBlank(parameter.getValue())) {
                        LOGGER.error("Component id: " + component.getId() + " resource id: " + resource.getId()
                                + " is missing a required parameter value for " + parameter.getDisplayName());
                        componentValid.addMessage(AsmManagerMessages.missingTemplateRequired(component.getName(),
                                parameter.getDisplayName()));
                    }
                }
            }
            if (CollectionUtils.isNotEmpty(componentValid.getMessages())) {
                componentValid.setValid(Boolean.FALSE);
                svcTemplate.getTemplateValid().setValid(Boolean.FALSE);
            }
        }
    }

    private static boolean isVisibleRequiredParameter(final ServiceTemplateSetting parameter) {
        if (parameter != null) {
            return !parameter.isHideFromTemplate() && parameter.isRequired();
        }
        return Boolean.FALSE;
    }

    public void validatePasswords(ServiceTemplate svcTemplate) {
        for (ServiceTemplateComponent component : safeList(svcTemplate.getComponents())) {
            if (component.getType() == ServiceTemplateComponent.ServiceTemplateComponentType.SERVER || component
                    .getType() == ServiceTemplateComponent.ServiceTemplateComponentType.VIRTUALMACHINE) {
                final ServiceTemplateValid componentValid = component.getComponentValid();
                ServiceTemplateSetting targetBoot = svcTemplate.getTemplateSetting(component,
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_ID);
                for (ServiceTemplateCategory category : component.getResources()) {
                    if (category.getId()
                            .equalsIgnoreCase(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_RESOURCE)) {
                        ServiceTemplateSetting osPass = svcTemplate.getTemplateSetting(component,
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_ADMIN_PASSWORD_ID);
                        ServiceTemplateSetting osPassConfirm = svcTemplate.getTemplateSetting(component,
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_ADMIN_CONFIRM_PASSWORD_ID);
                        ServiceTemplateSetting osDomainPass = svcTemplate.getTemplateSetting(component,
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_DOMAIN_PASSWORD_ID);
                        ServiceTemplateSetting osDomainPassConfirm = svcTemplate.getTemplateSetting(component,
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_DOMAIN_CONFIRM_PASSWORD_ID);

                        //ignore password check for San Boot types
                        if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_COMPID_ALL
                                .equals(component.getComponentID())
                                && targetBoot != null
                                && (targetBoot.getValue().equals(
                                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_SD)
                                        || targetBoot.getValue().equals(
                                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_SD_RAID)
                                        || targetBoot.getValue().equals(
                                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_SD_RAID_VSAN)
                                        || targetBoot.getValue().equals(
                                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_HD)
                                        || targetBoot.getValue().equals(
                                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_AHCI_VSAN))
                                || targetBoot == null) {
                            if (osPass != null && StringUtils.isEmpty(osPass.getValue())) {
                                componentValid
                                        .addMessage(AsmManagerMessages.PasswordNullEmpty(osPass.getDisplayName()));
                                continue;
                            } else if (osPassConfirm != null && StringUtils.isEmpty(osPassConfirm.getValue())) {
                                componentValid.addMessage(
                                        AsmManagerMessages.PasswordNullEmpty(osPassConfirm.getDisplayName()));
                                continue;
                            }

                            if (!confirmPasswords(osPass, osPassConfirm)) {
                                LOGGER.warn("Passwords don't match.");
                                componentValid.addMessage(AsmManagerMessages.passwordMismatch());
                            }
                        }

                        if (!confirmPasswords(osDomainPass, osDomainPassConfirm)) {
                            LOGGER.warn("Passwords don't match.");
                            componentValid.addMessage(AsmManagerMessages.passwordMismatch());
                        }
                    }
                }

                if (CollectionUtils.isNotEmpty(componentValid.getMessages())) {
                    componentValid.setValid(Boolean.FALSE);
                    svcTemplate.getTemplateValid().setValid(Boolean.FALSE);
                }
            }
        }
    }

    /**
     * Makes sure number of physical disks conforms to RAID level requirements.
     * @param value
     * @return
     */
    public boolean validateRAID(String value) {
        if (StringUtils.isNotEmpty(value)) {
            String configString = "{ \"templateRaidConfiguration\" : " + value + "}";
            TemplateRaidConfiguration configuration = MarshalUtil.fromJSON(TemplateRaidConfiguration.class,
                    configString);
            if (configuration.getRaidtype() == TemplateRaidConfiguration.RaidTypeUI.advanced) {
                for (VirtualDiskConfiguration tvd : configuration.getVirtualdisks()) {
                    int disksRequired = RaidLevel.fromUIValue(tvd.getRaidlevel().name()).getMinDisksRequired();
                    if (disksRequired > tvd.getNumberofdisks()) {
                        return Boolean.FALSE;
                    }
                }
            }
        }

        return Boolean.TRUE;
    }

    /******************************************************************************************************************
     * VALIDATOR helper methods
     ******************************************************************************************************************/

    /**
     * Clear all the validation toggles and messages for the given service template and its associated components
     * @param svcTemplate
     */
    public void clearAllServiceTemplateValidations(final ServiceTemplate svcTemplate) {
        svcTemplate.setTemplateValid(ServiceTemplateValid.getDefaultInstance());
        for (ServiceTemplateComponent component : svcTemplate.getComponents()) {
            component.setComponentValid(ServiceTemplateValid.getDefaultInstance());
        }
    }

    /**
     * Sometimes we need to copy over the validation from temp templates that are used just for validation. This 
     * is usually done when the temp templates are copies with decrypted passwords.
     * @param srcTemplate
     */
    public void copyAllServiceTemplateValidations(final ServiceTemplate srcTemplate,
            final ServiceTemplate destTemplate) {
        destTemplate.setTemplateValid(srcTemplate.getTemplateValid());
        for (final ServiceTemplateComponent srcComponent : safeList(srcTemplate.getComponents())) {
            final ServiceTemplateComponent destComponent = destTemplate.findComponentById(srcComponent.getId());
            destComponent.setComponentValid(srcComponent.getComponentValid());
        }
    }

    public AsmDetailedMessageList getAllServiceTemplateValidationMessages(final ServiceTemplate svcTemplate) {
        final List<AsmDetailedMessage> validationMessages = new ArrayList<AsmDetailedMessage>();
        validationMessages.addAll(svcTemplate.getTemplateValid().getMessages());
        for (final ServiceTemplateComponent component : safeList(svcTemplate.getComponents())) {
            validationMessages.addAll(component.getComponentValid().getMessages());
        }
        return new AsmDetailedMessageList(validationMessages);
    }

    /**
     * Parse string like "512m" and return numeric value
     * @param value
     * @return
     */
    private static int getStorageSizeMB(String value) {
        if (StringUtils.isEmpty(value)) {
            return 0;
        }

        String sValue = value.trim();
        int ret = 0;
        try {
            if (sValue.endsWith("MB")) {
                ret = Integer.parseInt(sValue.split("MB")[0]);
            } else if (sValue.endsWith("GB")) {
                ret = Integer.parseInt(sValue.substring(0, sValue.indexOf("GB"))) * 1024;
            } else if (sValue.endsWith("TB")) {
                ret = Integer.parseInt(sValue.substring(0, sValue.indexOf("TB"))) * 1024 * 1024;
            }
        } catch (NumberFormatException nfe) {
            LOGGER.error("Invalid value for storage size: " + sValue, nfe);
            return 0;
        }

        return ret;
    }

    private static boolean templateContainsComponentOfType(ServiceTemplate svcTemplate,
            ServiceTemplateComponentType targetComponentType) {
        List<ServiceTemplateComponent> components = svcTemplate.getComponents();
        for (ServiceTemplateComponent component : components) {
            if (component.getType() == targetComponentType) {
                return true;
            }
        }
        return false;
    }

    private static boolean confirmPasswords(ServiceTemplateSetting pass, ServiceTemplateSetting confirmPass) {
        if (pass == null || confirmPass == null || pass.getValue() == null || confirmPass.getValue() == null) {
            return true;
        }

        return StringUtils.equals(pass.getValue(), confirmPass.getValue());
    }

    @SuppressWarnings("unchecked")
    public <T> List<T> safeList(final List<T> list) {
        return CollectionUtils.isEmpty(list) ? Collections.EMPTY_LIST : list;
    }

    /**
     *  Identifies groups of Storages that all relate to the same Server and then validates that the group of Storages
     *  are all using the same Authentication (either all using IQN/IP or all using CHAP).
     */
    private void validateStorageAuthorizationMatchesServer(ServiceTemplate serviceTemplate) {
        for (ServiceTemplateComponent component : serviceTemplate.getComponents()) {
            // If it's Storage we need to see if it's related to a Server and make sure Authorization is same as other Storages
            if (component.getType() == ServiceTemplateComponentType.SERVER) {
                ArrayList<ServiceTemplateComponent> relatedStorageComponents = ServiceTemplateValidator
                        .getRelatedStoragesForComponentServer(component, serviceTemplate);
                this.validateStorageAuthorizationMatches(serviceTemplate, relatedStorageComponents);
            }
        }
    }

    // Method assumes component passed in is of type Server 
    private static ArrayList<ServiceTemplateComponent> getRelatedStoragesForComponentServer(
            ServiceTemplateComponent storageComponent, ServiceTemplate serviceTemplate) {
        ArrayList<ServiceTemplateComponent> relatedStorages = new ArrayList<ServiceTemplateComponent>();
        Set<String> associatedComponentKeys = storageComponent.getAssociatedComponents().keySet();
        if (associatedComponentKeys.size() > 0) {
            for (ServiceTemplateComponent component : serviceTemplate.getComponents()) {
                if (component.getType() == ServiceTemplateComponentType.STORAGE
                        && associatedComponentKeys.contains(component.getId())) {
                    relatedStorages.add(component);
                }
            }
        }
        return relatedStorages;
    }

    /**
     * Validates whether the Storages for a single Server all use the same Authentication.  All Storage components 
     * attached to a Service must either use IQN/IP authentication or CHAP authentication.  Storge components attached
     * to a Server cannot use both IQN/IP and CHAP.
     * 
     * If the Storages are not using the same Authentication, then the component where the first discrepancy is found
     * will be marked as invalid.  Note, only ONE Storage component will be marked as invalid, not all of them.
     * 
     * @param serviceTemplate the ServiceTemplate that is being validated.
     * @param relatedStorageComponents Storages that are all related to the same Server.
     */
    private void validateStorageAuthorizationMatches(ServiceTemplate serviceTemplate,
            ArrayList<ServiceTemplateComponent> relatedStorageComponents) {

        // Will assume all of the items in the related/original list are the same, and thus only check the first one.
        if (relatedStorageComponents.size() > 0) {
            ServiceTemplateComponent originalStorageComponent = relatedStorageComponents.get(0);

            // Check to see what the new Storage component uses for Authentication
            boolean storageUsesChap = false;
            boolean storageUsesIqn = false;
            for (ServiceTemplateComponent component : relatedStorageComponents) {
                for (ServiceTemplateCategory category : safeList(component.getResources())) {
                    for (ServiceTemplateSetting setting : safeList(category.getParameters())) {
                        if (setting.getId().equalsIgnoreCase(
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_AUTH_TYPE_ID)) {
                            if (setting.getValue()
                                    .equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_AUTH_TYPE_CHAP_ID)) {
                                storageUsesChap = true;
                            } else if (setting.getValue().equals(
                                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_AUTH_TYPE_IQNIP_ID)) {
                                storageUsesIqn = true;
                            }

                            if (storageUsesChap && storageUsesIqn) {
                                LOGGER.error(
                                        "Newly added Storage is configured to use IQN but the related Server's Storage component(s) is not configured to use CHAP!");

                                final ServiceTemplateValid componentValid = component.getComponentValid();
                                componentValid
                                        .addMessage(AsmManagerMessages.invalidMixedAuthenticationForStorage());
                                componentValid.setValid(Boolean.FALSE);
                                serviceTemplate.getTemplateValid().setValid(Boolean.FALSE);
                            }
                        }
                    }
                }
            }
        }
    }

    // If a Server has an EqualLogic Related Component that uses IQN/IP Authentication, 
    // then the Servers Network cannot be a DHCP iSCSI
    // Assumes the component passed in is of type Server.
    private void validateServerWithEqualLogicStorageIsNotUsingStaticIscsiNetwork(ServiceTemplate serviceTemplate,
            ServiceTemplateComponent serverComponent) {

        for (String serverRelCompId : serverComponent.getAssociatedComponents().keySet()) {
            for (ServiceTemplateComponent serverRelatedComponent : serviceTemplate.getComponents()) {
                if (serverRelatedComponent.getId().equals(serverRelCompId)
                        && serverRelatedComponent.getType() == ServiceTemplateComponentType.STORAGE
                        && serviceTemplate.getTemplateResource(serverRelatedComponent,
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_EQL_COMP_ID) != null
                        && this.doesStorageComponentUseIqnAuthentication(serverRelatedComponent)) {
                    List<Network> networks = getServiceTemplateUtil().getServerNetworkByType(serverComponent,
                            NetworkType.STORAGE_ISCSI_SAN);
                    boolean areIsciNetworksAllStatic = NetworkingUtil.areAllNetworksConfiguredToBeStatic(networks);
                    if (!areIsciNetworksAllStatic) {
                        LOGGER.error(
                                "Cannot use a DHCP iSCSI network on a Server component that is attached to an EqualLogic Storage component that uses IQN/IP authentication. IQN/IP requires a static IP in order to set up the authentication rules properly.");

                        final ServiceTemplateValid componentValid = serverComponent.getComponentValid();
                        componentValid.addMessage(AsmManagerMessages
                                .invalidIscsiNetworkConfigurationForServerWithEqualLogicStorageUsingIqnIp());
                        componentValid.setValid(Boolean.FALSE);
                        serviceTemplate.getTemplateValid().setValid(Boolean.FALSE);
                    }
                }
            }
        }
    }

    // Returns a boolean indicating if the Storage component uses IQN Authentication
    private boolean doesStorageComponentUseIqnAuthentication(ServiceTemplateComponent storageComponent) {
        boolean usesIqn = false;
        for (ServiceTemplateCategory category : safeList(storageComponent.getResources())) {
            for (ServiceTemplateSetting setting : safeList(category.getParameters())) {
                if (setting.getId()
                        .equalsIgnoreCase(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_AUTH_TYPE_ID)
                        && setting.getValue()
                                .equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_AUTH_TYPE_IQNIP_ID)) {
                    usesIqn = true;
                }
            }
        }
        return usesIqn;
    }

    // Checks to see if a Server with an EqualLogic Storage has at least 2 iscsi Networks assigned
    private void validateServerComponentsWithStorageHaveTwoPartitionsWithIsciNetworks(
            ServiceTemplate serviceTemplate, ServiceTemplateComponent serverComponent) {

        boolean isBootFromSanTemplate = false;

        for (ServiceTemplateComponent serverComponent1 : serviceTemplate.getComponents()) {
            for (ServiceTemplateCategory resource : serverComponent1.getResources()) {
                if (resource.getId().equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_IDRAC_RESOURCE)) {
                    for (ServiceTemplateSetting param : resource.getParameters()) {
                        if (param.getId()
                                .equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_ID)
                                && param.getValue().equals(
                                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_TARGET_BOOTDEVICE_ISCSI)) {
                            isBootFromSanTemplate = true;
                        }
                    }
                }
            }
        }

        for (String serverRelCompId : serverComponent.getAssociatedComponents().keySet()) {
            for (ServiceTemplateComponent serverRelatedComponent : serviceTemplate.getComponents()) {

                if (serverRelatedComponent.getId().equals(serverRelCompId)
                        && serverRelatedComponent.getType() == ServiceTemplateComponentType.STORAGE
                        && (serviceTemplate.getTemplateResource(serverRelatedComponent,
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_EQL_COMP_ID) != null
                                || (serviceTemplate.getTemplateResource(serverRelatedComponent,
                                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_COMPELLENT_COMP_ID) != null
                                        && ServiceTemplateSettingIDs.SERVICE_TEMPLATE_COMPELLENT_PORTTYPE_ISCSI
                                                .equals(serviceTemplate.getTemplateSetting(serverRelatedComponent,
                                                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_COMPELLENT_PORTTYPE_ID)
                                                        .getValue())))) {
                    List<Network> networks = getServiceTemplateUtil().getServerNetworkByType(serverComponent,
                            NetworkType.STORAGE_ISCSI_SAN);
                    boolean areThereTwoOrMoreNetworks = networks.size() >= 2;
                    boolean atleastOneIscsiNetwork = networks.size() >= 1;
                    if (!areThereTwoOrMoreNetworks && !isBootFromSanTemplate) {
                        LOGGER.error(
                                "Storage must have at least 2 iSCSI Networks configured on 2 separate partitions! Only "
                                        + networks.size() + " are configured!");

                        final ServiceTemplateValid componentValid = serverComponent.getComponentValid();
                        componentValid.addMessage(
                                AsmManagerMessages.insufficientNumberOfIsciNetworksForStorageComponent());
                        componentValid.setValid(Boolean.FALSE);
                        serviceTemplate.getTemplateValid().setValid(Boolean.FALSE);
                    }
                    if (!atleastOneIscsiNetwork && isBootFromSanTemplate) {
                        LOGGER.error(
                                "Storage must have at least 1 iSCSI Network configured for Boot From SAN template");

                        final ServiceTemplateValid componentValid = serverComponent.getComponentValid();
                        componentValid.addMessage(AsmManagerMessages
                                .insufficientNumberOfIsciNetworksForStorageComponentBootFromSanTemplate());
                        componentValid.setValid(Boolean.FALSE);
                        serviceTemplate.getTemplateValid().setValid(Boolean.FALSE);
                    }
                }
            }
        }
    }

    // Gets the unique names for the given storage template
    private static Set<String> getStorageNameList(ServiceTemplateSetting storageTitleSetting) {
        if (storageTitleSetting == null)
            return null;

        HashSet<String> names = new HashSet<String>();

        List<ServiceTemplateOption> storageTemplateOptions = storageTitleSetting.getOptions();
        for (ServiceTemplateOption option : storageTemplateOptions) {
            names.add(option.getValue());
        }

        return names;
    }

    /**
     * Options for validation.
     */
    public static class ValidationOptions {
        private boolean isDeployment;

        public boolean isCheckForUniqueness() {
            return checkForUniqueness;
        }

        public void setCheckForUniqueness(boolean checkForUniqueness) {
            this.checkForUniqueness = checkForUniqueness;
        }

        private boolean checkForUniqueness;
        private boolean inventoryContainsEM;

        public boolean isDeployment() {
            return isDeployment;
        }

        public void setDeployment(boolean deployment) {
            isDeployment = deployment;
        }

        public boolean isInventoryContainsEM() {
            return inventoryContainsEM;
        }

        public void setInventoryContainsEM(boolean inventoryContainsEM) {
            this.inventoryContainsEM = inventoryContainsEM;
        }

        /**
         * Constructor for options.
         * @param isDeployment  Deployment time
         * @param checkForUniqueness   Check volumes for uniqueness - new deployment or scale down
         * @param inventoryContainsEM   ASM inventory has Element Manager
         */
        public ValidationOptions(boolean isDeployment, boolean checkForUniqueness, boolean inventoryContainsEM) {
            this.isDeployment = isDeployment;
            this.checkForUniqueness = checkForUniqueness;
            this.inventoryContainsEM = inventoryContainsEM;
        }
    }

    public INetworkService getNetworkService() {
        if (networkService == null) {
            networkService = ProxyUtil.getNetworkProxy();
        }
        return networkService;
    }

    public void setNetworkService(INetworkService networkService) {
        this.networkService = networkService;
    }

    public ServiceTemplateUtil getServiceTemplateUtil() {
        if (serviceTemplateUtil == null) {
            serviceTemplateUtil = new ServiceTemplateUtil();
        }
        return serviceTemplateUtil;
    }

    public void setServiceTemplateUtil(ServiceTemplateUtil serviceTemplateUtil) {
        this.serviceTemplateUtil = serviceTemplateUtil;
    }

    public OSRepositoryUtil getOsRepositoryUtil() {
        if (osRepositoryUtil == null) {
            osRepositoryUtil = new OSRepositoryUtil();
        }
        return osRepositoryUtil;
    }

    public void setOsRepositoryUtil(OSRepositoryUtil osRepositoryUtil) {
        this.osRepositoryUtil = osRepositoryUtil;
    }

}