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

Java tutorial

Introduction

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

Source

/**************************************************************************
 *   Copyright (c) 2013 - 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.AsmManagerMessages;
import com.dell.asm.asmcore.asmmanager.app.AsmManagerApp;
import com.dell.asm.asmcore.asmmanager.app.rest.DeviceInventoryService;
import com.dell.asm.asmcore.asmmanager.app.rest.ServiceTemplateService;
import com.dell.asm.asmcore.asmmanager.client.deviceinventory.DeviceState;
import com.dell.asm.asmcore.asmmanager.client.deviceinventory.ManagedState;
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.util.PuppetDbUtil;
import com.dell.asm.asmcore.asmmanager.client.util.PuppetEmcDevice;
import com.dell.asm.asmcore.asmmanager.client.util.PuppetEquallogicDevice;
import com.dell.asm.asmcore.asmmanager.client.util.ServiceTemplateClientUtil;
import com.dell.asm.asmcore.asmmanager.db.DeviceInventoryDAO;
import com.dell.asm.asmcore.asmmanager.db.entity.DeviceGroupEntity;
import com.dell.asm.asmcore.asmmanager.db.entity.DeviceInventoryEntity;
import com.dell.asm.asmcore.asmmanager.db.entity.FirmwareDeviceInventoryEntity;
import com.dell.asm.asmcore.asmmanager.db.entity.ServiceTemplateEntity;
import com.dell.asm.asmcore.asmmanager.db.entity.TemplateUserRefEntity;
import com.dell.asm.asmcore.asmmanager.exception.AsmManagerRuntimeException;
import com.dell.asm.asmcore.asmmanager.util.files.CopyFileVisitor;
import com.dell.asm.asmcore.asmmanager.util.files.DeleteDirectoryVisitor;
import com.dell.asm.asmcore.asmmanager.util.osrepository.OSRepositoryUtil;
import com.dell.asm.asmcore.asmmanager.util.razor.RazorRepo;
import com.dell.asm.asmcore.asmmanager.util.template.adjuster.AdjusterFactory;
import com.dell.asm.asmcore.user.model.User;
import com.dell.asm.common.model.CommandResponse;
import com.dell.asm.common.utilities.ExecuteSystemCommands;
import com.dell.asm.rest.common.exception.LocalizedWebApplicationException;
import com.dell.asm.rest.common.util.FilterParamParser;
import com.dell.pg.asm.identitypool.api.common.model.NetworkType;
import com.dell.pg.asm.identitypool.api.network.INetworkService;
import com.dell.pg.asm.identitypool.api.network.model.Network;
import com.dell.pg.orion.common.utilities.MarshalUtil;
import com.dell.pg.orion.security.encryption.EncryptionDAO;
import com.dell.pg.orion.security.encryption.IEncryptedString;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
import com.google.common.base.Joiner;
import java.io.Closeable;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import javax.ws.rs.core.Response;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.log4j.Logger;

public class ServiceTemplateUtil {

    private static final Logger LOGGER = Logger.getLogger(ServiceTemplateUtil.class);

    private static final String CURRENT_TEMPLATE_VERSION = AsmManagerUtil.getAsmVersion();
    private static final String SERVER_TYPE_BLADE = "blade";
    private static final ObjectMapper BACKEND_MAPPER = buildBackendObjectMapper();

    public static final String TEMPLATE_ATTACHMENT_DIR = "/opt/Dell/ASM/templates/";

    private EncryptionDAO encryptionDAO;
    private INetworkService networkService;
    private OSRepositoryUtil osRepositoryUtil;
    private DeviceInventoryDAO deviceInventoryDAO;

    private static ObjectMapper buildBackendObjectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        AnnotationIntrospector ai = new JaxbAnnotationIntrospector(mapper.getTypeFactory());
        mapper.setAnnotationIntrospector(ai);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return mapper;
    }

    public static String getCurrentTemplateVersion() {
        return CURRENT_TEMPLATE_VERSION;
    }

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

    public static void stripPasswords(ServiceTemplate template, String newValue) {
        for (ServiceTemplateComponent component : template.getComponents()) {
            for (ServiceTemplateCategory resource : component.getResources()) {
                for (ServiceTemplateSetting param : resource.getParameters()) {
                    if (ServiceTemplateSetting.ServiceTemplateSettingType.PASSWORD.equals(param.getType())) {
                        if (StringUtils.isNotEmpty(param.getValue())) {
                            param.setValue(newValue);
                        }
                    }
                }
            }
        }
    }

    public static List<ServiceTemplateCategory> findResources(ServiceTemplate template,
            ServiceTemplateComponent.ServiceTemplateComponentType componentType, String resourceId) {
        if (template == null) {
            throw new IllegalArgumentException("Template is required");
        }
        if (componentType == null) {
            throw new IllegalArgumentException("Component type is required");
        }
        if (resourceId == null) {
            throw new IllegalArgumentException("Resource id is required");
        }

        List<ServiceTemplateCategory> ret = new ArrayList<>();
        for (ServiceTemplateComponent component : template.getComponents()) {
            if (componentType.equals(component.getType())) {
                for (ServiceTemplateCategory resource : component.getResources()) {
                    if (resourceId.equals(resource.getId())) {
                        ret.add(resource);
                    }
                }
            }
        }
        return ret;
    }

    public static ServiceTemplateSetting findParameter(ServiceTemplateCategory resource, String parameterId) {
        if (resource == null) {
            throw new IllegalArgumentException("Resource is required");
        }
        if (parameterId == null) {
            throw new IllegalArgumentException("Parameter id is required");
        }
        for (ServiceTemplateSetting parameter : resource.getParameters()) {
            if (parameterId.equals(parameter.getId())) {
                return parameter;
            }
        }
        return null;
    }

    public static Map<String, String> resourceToMap(ServiceTemplateCategory resource) {
        Map<String, String> ret = new HashMap<>();
        for (ServiceTemplateSetting parameter : resource.getParameters()) {
            ret.put(parameter.getId(), parameter.getValue());
        }
        return ret;
    }

    public static String findParameterValue(ServiceTemplate template, String componentId, String resourceId,
            String parameterId) {
        for (ServiceTemplateComponent component : template.getComponents()) {
            if (StringUtils.equals(componentId, component.getId())) {
                for (ServiceTemplateCategory resource : component.getResources()) {
                    if (StringUtils.equals(resourceId, resource.getId())) {
                        for (ServiceTemplateSetting param : resource.getParameters()) {
                            if (StringUtils.equals(parameterId, param.getId())) {
                                return param.getValue();
                            }
                        }
                    }
                }
            }
        }
        return null;
    }

    public String setParameterValue(ServiceTemplate template, String componentId, String resourceId,
            String parameterId, String value) {
        for (ServiceTemplateComponent component : template.getComponents()) {
            if (StringUtils.equals(componentId, component.getId())) {
                for (ServiceTemplateCategory resource : component.getResources()) {
                    if (StringUtils.equals(resourceId, resource.getId())) {
                        for (ServiceTemplateSetting param : resource.getParameters()) {
                            if (StringUtils.equals(parameterId, param.getId())) {
                                param.setValue(value);
                            }
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     * Searches the specified {@code template} for password values. If non-null, those values
     * are replaced with encrypted string ids. When null the corresponding {@code origTemplate}
     * value is used.
     *
     * @param template The template whose password values should be encrypted.
     * @param origTemplate The template whose password values will be used in place of null
     *                     password values in @{code template}.
     */
    public void encryptPasswords(ServiceTemplate template, ServiceTemplate origTemplate) {
        for (ServiceTemplateComponent component : template.getComponents()) {
            for (ServiceTemplateCategory resource : component.getResources()) {
                for (ServiceTemplateSetting param : resource.getParameters()) {
                    if (ServiceTemplateSetting.ServiceTemplateSettingType.PASSWORD.equals(param.getType())) {
                        String plaintext = param.getValue();
                        if (!StringUtils.isEmpty(plaintext)
                                && !ServiceTemplateSettingIDs.SERVICE_TEMPLATE_PASSWORD_DEFAULT_TO_REMOVE
                                        .equals(plaintext)) {
                            // Replace the plaintext value with an encryption id
                            IEncryptedString encryptedString = getEncryptionDAO().encryptAndSave(plaintext);
                            param.setValue(encryptedString.getId());
                        } else if (origTemplate != null) {
                            // Use the original encryption id, if any
                            if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_PASSWORD_DEFAULT_TO_REMOVE
                                    .equals(plaintext) || (plaintext != null && plaintext.trim().isEmpty())) {
                                param.setValue("");
                            } else {
                                String encryptionId = findParameterValue(origTemplate, component.getId(),
                                        resource.getId(), param.getId());
                                String clonedFromId = component.getClonedFromId();
                                if (encryptionId == null && clonedFromId != null) {
                                    encryptionId = findParameterValue(origTemplate, clonedFromId, resource.getId(),
                                            param.getId());
                                    if (encryptionId != null) {
                                        // Duplicate the string so that the new component has it's own copy;
                                        // otherwise there may be problems when the encryption ids are deleted
                                        // when the service is torn down.
                                        IEncryptedString encryptedString = getEncryptionDAO()
                                                .findEncryptedStringById(encryptionId);
                                        if (encryptedString == null) {
                                            LOGGER.warn("No encrypted string found for " + encryptionId
                                                    + " from component " + clonedFromId + " resource "
                                                    + resource.getDisplayName() + " parameter "
                                                    + param.getDisplayName());
                                        } else {
                                            plaintext = encryptedString.getString();
                                            if (!ServiceTemplateSettingIDs.SERVICE_TEMPLATE_PASSWORD_DEFAULT_TO_REMOVE
                                                    .equals(plaintext)) {
                                                IEncryptedString copy = getEncryptionDAO()
                                                        .encryptAndSave(plaintext);
                                                encryptionId = copy.getId();
                                            }
                                        }
                                    }
                                }
                                if (encryptionId != null
                                        && encryptionId != ServiceTemplateSettingIDs.SERVICE_TEMPLATE_PASSWORD_DEFAULT_TO_REMOVE) {
                                    param.setValue(encryptionId);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    public void encryptPasswords(ServiceTemplate template) {
        encryptPasswords(template, null);
    }

    /**
     * Assuming the specified template has encrypted password values, decrypt them in place.
     *
     * @param template the template
     */
    public void decryptPasswords(ServiceTemplate template) {
        for (ServiceTemplateComponent component : template.getComponents()) {
            for (ServiceTemplateCategory resource : component.getResources()) {
                for (ServiceTemplateSetting param : resource.getParameters()) {
                    if (ServiceTemplateSetting.ServiceTemplateSettingType.PASSWORD.equals(param.getType())) {
                        String passwordId = param.getValue();
                        IEncryptedString encryptedString = getEncryptionDAO().findEncryptedStringById(passwordId);
                        if (encryptedString != null)
                            param.setValue(encryptedString.getString());
                    }
                }
            }
        }
    }

    public Set<String> getEncryptionIds(ServiceTemplateComponent component) {
        Set<String> ret = new HashSet<>();
        for (ServiceTemplateCategory resource : component.getResources()) {
            for (ServiceTemplateSetting param : resource.getParameters()) {
                if (ServiceTemplateSetting.ServiceTemplateSettingType.PASSWORD.equals(param.getType())) {
                    if (!StringUtils.isEmpty(param.getValue())) {
                        ret.add(param.getValue());
                    }
                }
            }
        }
        return ret;
    }

    public Set<String> getEncryptionIds(ServiceTemplate template) {
        Set<String> ret = new HashSet<>();
        for (ServiceTemplateComponent component : template.getComponents()) {
            ret.addAll(getEncryptionIds(component));
        }
        return ret;
    }

    /**
     * Assuming all non-null password values are encryption ids, replaces those encryption ids
     * with new values that decrypt to the same plaintext value. Useful when copying a template
     * where we want the new template to have the same passwords, but not point to the same
     * encryption record.
     *
     * @param template The template
     */
    public void duplicatePasswords(ServiceTemplate template) {
        for (ServiceTemplateComponent component : template.getComponents()) {
            for (ServiceTemplateCategory resource : component.getResources()) {
                for (ServiceTemplateSetting param : resource.getParameters()) {
                    if (ServiceTemplateSetting.ServiceTemplateSettingType.PASSWORD.equals(param.getType())
                            && !StringUtils.isEmpty(param.getValue())) {
                        IEncryptedString encryptedString = getEncryptionDAO()
                                .findEncryptedStringById(param.getValue());
                        if (encryptedString != null) {
                            String plaintext = encryptedString.getString();
                            IEncryptedString copy = getEncryptionDAO().encryptAndSave(plaintext);
                            param.setValue(copy.getId());
                        }
                    }
                }
            }
        }
    }

    public void deleteRemovedEncryptionIds(ServiceTemplate oldTemplate, ServiceTemplate newTemplate) {
        Set<String> encryptionIdsToDelete = getEncryptionIds(oldTemplate);
        encryptionIdsToDelete.removeAll(getEncryptionIds(newTemplate));
        for (String id : encryptionIdsToDelete) {
            IEncryptedString encryptedString = getEncryptionDAO().findEncryptedStringById(id);
            if (encryptedString != null)
                getEncryptionDAO().delete(encryptedString);
        }
    }

    public void deleteEncryptionIds(Set<String> encryptionIds) {
        for (String id : encryptionIds) {
            IEncryptedString encryptedString = getEncryptionDAO().findEncryptedStringById(id);
            if (encryptedString != null)
                getEncryptionDAO().delete(encryptedString);
        }
    }

    public void deleteEncryptionIds(ServiceTemplate template) {
        deleteEncryptionIds(getEncryptionIds(template));
    }

    /**
     * For each setting trim value from whitespaces.
     * @param template
     */
    public static void trimSpaces(ServiceTemplate template) {
        for (ServiceTemplateComponent component : template.getComponents()) {
            for (ServiceTemplateCategory resource : component.getResources()) {
                for (ServiceTemplateSetting param : resource.getParameters()) {
                    if (param.getValue() != null) {
                        param.setValue(param.getValue().trim());
                    }
                }
            }
        }
    }

    public static void addDefaultSelectOption(ServiceTemplateSetting setting) {
        ServiceTemplateClientUtil.addDefaultSelectOption(setting);
    }

    public static void addBooleanSelectOption(ServiceTemplateSetting setting) {
        addDefaultSelectOption(setting);

        setting.getOptions().add(new ServiceTemplateOption(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TRUE_NAME,
                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TRUE_VALUE, null, null));
        setting.getOptions().add(new ServiceTemplateOption(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_FALSE_NAME,
                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_FALSE_VALUE, null, null));
    }

    public static void addDeviceInventoryOptions(List<DeviceInventoryEntity> entities,
            ServiceTemplateSetting setting) {
        if (entities != null && setting != null) {
            for (DeviceInventoryEntity entity : entities) {
                setting.getOptions()
                        .add(new ServiceTemplateOption(entity.getServiceTag(), entity.getRefId(), null, null));
            }
        }
    }

    public static void addServerPoolOptions(List<DeviceGroupEntity> deviceGroups,
            ServiceTemplateSetting serverPool) {
        serverPool.getOptions()
                .add(new ServiceTemplateOption(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_POOL_GLOBAL_NAME,
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_POOL_GLOBAL_ID, null, null));
        Long userId = AsmManagerUtil.getUserId();
        if (deviceGroups != null && deviceGroups.size() > 0) {
            for (DeviceGroupEntity group : deviceGroups) {
                if (group.getGroupsUsers() != null && group.getGroupsUsers().size() > 0) {
                    if (group.getGroupsUsers().contains(userId)) {
                        if (group.getSeqId() != null) {
                            serverPool.getOptions().add(new ServiceTemplateOption(group.getName(),
                                    Long.toString(group.getSeqId()), null, null));
                        }
                    }
                }
            }
        }
        serverPool.setValue(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_POOL_GLOBAL_ID); // set it to the first pool which is the
    }

    /**
     * Find puppet device, return list of volumes.
     *
     * @param refId
     * @return
     */
    public List<ServiceTemplateOption> getCompellentVolumes(String refId) {
        List<ServiceTemplateOption> ret = new ArrayList<>();

        try {
            Map<String, String> data = PuppetModuleUtil.getPuppetDevice(refId);
            ObjectMapper mapper = new ObjectMapper();
            String objectStr = data.get("volume_data");
            if (objectStr != null && objectStr.length() > 0) {
                Map<String, List<Map<String, List<String>>>> parsedJson = null;
                try {
                    parsedJson = mapper.readValue(objectStr, Map.class);
                } catch (IOException e) {
                    LOGGER.error("Cannot get volume data for compellent device id=" + refId, e);
                    return ret;
                }
                List<Map<String, List<String>>> objectList = parsedJson.get("volume");
                if (objectList != null && objectList.size() > 0) {
                    //  Missing facts for type, statusinformation, volumetype, storagetype
                    for (Map<String, List<String>> volumeMap : objectList) {
                        String volumeName = volumeMap.get("Name").get(0);
                        ServiceTemplateOption opt = new ServiceTemplateOption(volumeName, volumeName,
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ASM_GUID, refId);
                        ret.add(opt);
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return ret;
    }

    /**
     * Find puppet device, return list of volumes.
     * @param refId
     * @return
     */
    public List<ServiceTemplateOption> getEqlVolumes(String refId) {
        List<ServiceTemplateOption> ret = new ArrayList<>();

        try {
            Map<String, String> data = PuppetModuleUtil.getPuppetDevice(refId);
            PuppetEquallogicDevice eqlDevice = PuppetDbUtil.convertToPuppetEquallogicDevice(data);
            if (eqlDevice == null)
                return ret;

            if (CollectionUtils.isNotEmpty(eqlDevice.getVolumesProperties())) {
                for (PuppetEquallogicDevice.VolumeProperties volumeProp : eqlDevice.getVolumesProperties()) {
                    if (PuppetEquallogicDevice.isVolumeInRecoveryBin(volumeProp)) {
                        LOGGER.warn("Skipped EQL volume since it is 0GB and offline: " + volumeProp.getName());
                    } else {
                        ServiceTemplateOption opt = new ServiceTemplateOption(volumeProp.getName(),
                                volumeProp.getName(), ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ASM_GUID, refId);
                        ret.add(opt);
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return ret;
    }

    /**
     * Find VNX puppet device, return list of volumes.
     * @param entity
     */
    public void getVNXDetails(DeviceInventoryEntity entity, List<ServiceTemplateOption> pools,
            List<ServiceTemplateOption> volums, Map<String, ServiceTemplateOption> typesOptMap) {

        if (pools == null || volums == null)
            return;

        try {
            PuppetEmcDevice vnx = PuppetModuleUtil.getPuppetEmcDevice(entity.getRefId());

            if (CollectionUtils.isNotEmpty(vnx.getPools())) {
                for (PuppetEmcDevice.Pool pool : vnx.getPools()) {
                    String poolNnameStr = pool.getName();
                    ServiceTemplateOption opt = new ServiceTemplateOption(poolNnameStr, poolNnameStr,
                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ASM_GUID, entity.getRefId());
                    pools.add(opt);

                    if (CollectionUtils.isNotEmpty(pool.getMlus())) {
                        for (PuppetEmcDevice.Pool.Mlu mlu : pool.getMlus()) {
                            String nameStr = mlu.getName();
                            opt = new ServiceTemplateOption(nameStr, nameStr,
                                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_VNX_POOL_ID, poolNnameStr);
                            volums.add(opt);
                        }
                    }
                }
            }

            if (vnx.getAddons() != null) {
                if (vnx.getAddons().isCompressionEnabled()) {
                    ServiceTemplateOption opt = typesOptMap
                            .get(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_VNX_TYPE_COMPRESSED);
                    addToDependencyValue(opt, entity.getRefId());
                }
                if (vnx.getAddons().isThinEnabled()) {
                    ServiceTemplateOption opt = typesOptMap
                            .get(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_VNX_TYPE_THIN);
                    addToDependencyValue(opt, entity.getRefId());
                }
                if (vnx.getAddons().isNonthinEnabled()) {
                    ServiceTemplateOption opt = typesOptMap
                            .get(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_VNX_TYPE_NONTHIN);
                    addToDependencyValue(opt, entity.getRefId());
                }
                if (vnx.getAddons().isSnapEnabled()) {
                    ServiceTemplateOption opt = typesOptMap
                            .get(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_VNX_TYPE_SNAP);
                    addToDependencyValue(opt, entity.getRefId());
                }
            }

        } catch (Exception e) {
            LOGGER.error("Cannot get VNX details for " + entity.getRefId(), e);
        }
    }

    public static void addToDependencyValue(ServiceTemplateOption opt, String value) {
        if (opt == null)
            return;

        if (StringUtils.isNotEmpty(opt.getDependencyValue())) {
            opt.setDependencyValue(opt.getDependencyValue() + "," + value);
        } else {
            opt.setDependencyValue(value);
        }
    }

    /**
     * Populate device list, networks and aggregates for Netapp entry.
     * @param deviceInventoryEntity
     * @param deviceDropdown
     * @param nfsSet
     * @param aggrSet
     */
    public void processNetappData(DeviceInventoryEntity deviceInventoryEntity,
            ServiceTemplateSetting deviceDropdown, ServiceTemplateSetting nfsSet, ServiceTemplateSetting aggrSet,
            List<ServiceTemplateOption> volumes) {
        String refId = deviceInventoryEntity.getRefId();

        ServiceTemplateOption selOptionDev = new ServiceTemplateOption();
        selOptionDev.setValue(refId);
        selOptionDev.setName(deviceInventoryEntity.getServiceTag());
        deviceDropdown.getOptions().add(selOptionDev);

        try {
            ObjectMapper mapper = new ObjectMapper();
            Map<String, String> deviceDetails = PuppetModuleUtil.getPuppetDevice(refId);

            String ips = deviceDetails.get("interface_ips");
            if (ips != null) {
                String[] ipsArr = ips.split(",");
                for (String ip : ipsArr) {
                    ServiceTemplateOption option = new ServiceTemplateOption(ip, ip,
                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ASM_GUID, refId);

                    // devices might have same options, UI needs the list with unique IDs
                    if (nfsSet.getOptions().contains(option)) {
                        ServiceTemplateOption optionOrigin = nfsSet.getOptions()
                                .get(nfsSet.getOptions().indexOf(option));
                        optionOrigin.setDependencyValue(optionOrigin.getDependencyValue().concat("," + refId));
                    } else {
                        nfsSet.getOptions().add(option);
                    }
                }
            }

            String aggrs = deviceDetails.get("aggregate_data");
            if (aggrs != null) {
                Map<String, String> parsedJson = null;
                parsedJson = mapper.readValue(aggrs, Map.class);
                for (String key : parsedJson.keySet()) {
                    String strVolumeData = parsedJson.get(key);
                    Map<String, String> volumeData = mapper.readValue(strVolumeData, Map.class);
                    String name = volumeData.get("Name");

                    ServiceTemplateOption option = new ServiceTemplateOption(name, name,
                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ASM_GUID, refId);

                    // devices might have same options, UI needs the list with unique IDs
                    if (aggrSet.getOptions().contains(option)) {
                        ServiceTemplateOption optionOrigin = aggrSet.getOptions()
                                .get(aggrSet.getOptions().indexOf(option));
                        optionOrigin.setDependencyValue(optionOrigin.getDependencyValue().concat("," + refId));
                    } else {
                        aggrSet.getOptions().add(option);
                    }

                }
            }

            String vols = deviceDetails.get("volume_data");
            if (vols != null) {
                Map<String, String> parsedJson = null;
                parsedJson = mapper.readValue(vols, Map.class);
                for (String key : parsedJson.keySet()) {
                    String strVolumeData = parsedJson.get(key);
                    Map<String, String> volumeData = mapper.readValue(strVolumeData, Map.class);
                    String name = volumeData.get("name");

                    ServiceTemplateOption option = new ServiceTemplateOption(name, name,
                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ASM_GUID, refId);

                    // devices might have same options, UI needs the list with unique IDs
                    if (volumes.contains(option)) {
                        ServiceTemplateOption optionOrigin = volumes.get(volumes.indexOf(option));
                        optionOrigin.setDependencyValue(optionOrigin.getDependencyValue().concat("," + refId));
                    } else {
                        volumes.add(option);
                    }

                }
            }

        } catch (Exception e) {
            LOGGER.error(e);
        }
    }

    /**
     * Helper to add a setting "Create new ..."
     *
     * @param component component to process
     * @param options list of options to select from
     * @param setId ID of target param  (i.e. volume, datacenter, cluster etc)
     * @param labelCreateNew label in drop down "Create new ..."
     * @param labelNew label in front of new input field "new xxx"
     */
    public static ServiceTemplateSetting processNewSetting(ServiceTemplateComponent component,
            Collection<ServiceTemplateOption> options, String setId, String labelCreateNew, String labelNew,
            boolean hideFromTemplate) {

        return ServiceTemplateClientUtil.processNewSetting(component, options, setId, labelCreateNew, labelNew,
                hideFromTemplate);
    }

    /**
     * For templates with drop down "select existing or create new" hide settings if user selects existing resource.
     * @param component
     * @param setId
     */
    public void setDependencyOnCreateNew(ServiceTemplateComponent component, String setId,
            List<String> exceptions) {
        for (ServiceTemplateSetting set : component.getResources().get(0).getParameters()) {
            if (exceptions != null && exceptions.contains(set.getId()))
                continue;

            if (!set.getId().equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ASM_GUID)
                    && !set.getId().equals(setId)) {
                if (set.getDependencyTarget() == null) {
                    set.setDependencyTarget(setId);
                    set.setDependencyValue(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_CREATE_NOW
                            + "," + ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_CREATE_DEPLOYMENT
                            + "," + ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_AUTOGENERATE);
                }
            }
        }
    }

    /**
     * Returns server network configuration of specified type.
     * @param component server component
     * @param types List of NetworkType
     * @return
     */
    public List<Network> getServerNetworkByType(ServiceTemplateComponent component, List<NetworkType> types) {
        List<Network> ret = new ArrayList<>();

        if (CollectionUtils.isEmpty(types))
            return ret;

        ServiceTemplateSetting networking = component
                .getTemplateSetting(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_NETWORK_CONFIG_ID);
        if (networking == null)
            return null;
        com.dell.asm.asmcore.asmmanager.client.networkconfiguration.NetworkConfiguration networkConfig = deserializeNetwork(
                networking.getValue());
        if (networkConfig == null) {
            // xml screwed up?
            LOGGER.error("Cannot parse network configuration from string: " + networking.getValue());
            return ret;
        }

        networkConfig.clearUnusedNetworkSettings();

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

        for (Interface interfaceObject : interfaces) {
            List<Partition> partitions = interfaceObject.getPartitions();
            for (Partition partition : partitions) {
                List<String> networkIds = partition.getNetworks();
                if (networkIds != null) {
                    for (String networkId : networkIds) {

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

                        if (networkObject == null) { // Means it's been deleted!
                            throw new LocalizedWebApplicationException(Response.Status.INTERNAL_SERVER_ERROR,
                                    AsmManagerMessages.networkDoesNotExist(networkId));
                        }

                        for (NetworkType type : types) {
                            if (networkObject.getType().equals(type)) {
                                ret.add(networkObject);
                            }
                        }
                    }
                }
                // for not partitioned just use the first one
                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;
                }
            }
        }

        return ret;
    }

    /**
     * Returns server network configuration of specified type.
     * @param component server component
     * @param type NetworkType
     * @return
     */
    public List<Network> getServerNetworkByType(ServiceTemplateComponent component, NetworkType type) {
        List<NetworkType> types = new ArrayList<>();
        types.add(type);
        return getServerNetworkByType(component, types);
    }

    public void encryptPasswordsInConfig(ServiceTemplate template) {
        if (template == null)
            return;

        for (ServiceTemplateComponent component : template.getComponents()) {
            for (ServiceTemplateCategory resource : component.getResources()) {
                for (ServiceTemplateSetting param : resource.getParameters()) {
                    if (param.getId().equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CHASSIS_CONFIG_USERS)) {
                        if (param.getValue() != null) {

                            List<Map<String, String>> users = (List) fromJSON(List.class, param.getValue());
                            if (users != null) {
                                for (Map<String, String> user : users) {
                                    for (String key : user.keySet()) {
                                        if (key.equals("password")) {
                                            IEncryptedString eS = getEncryptionDAO()
                                                    .findEncryptedStringById(user.get(key));
                                            if (eS == null) {
                                                eS = getEncryptionDAO().encryptAndSave(user.get(key));
                                                user.put(key, eS.getId());
                                            }
                                        }
                                    }
                                }
                                param.setValue(toJSON(users));
                            }
                        }
                    } else if (param.getId()
                            .equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CHASSIS_CONFIG_ALERT_DEST)) {
                        if (param.getValue() != null) {

                            List<Map<String, String>> traps = (List) fromJSON(List.class, param.getValue());
                            if (traps != null) {
                                for (Map<String, String> trap : traps) {
                                    for (String key : trap.keySet()) {
                                        if (key.equals("communityString")) {
                                            IEncryptedString eS = getEncryptionDAO()
                                                    .findEncryptedStringById(trap.get(key));
                                            if (eS == null) {
                                                eS = getEncryptionDAO().encryptAndSave(trap.get(key));
                                                trap.put(key, eS.getId());
                                            }
                                        }
                                    }
                                }
                                param.setValue(toJSON(traps));
                            }
                        }
                    }
                }
            }
        }
    }

    public void decryptPasswordsInConfig(ServiceTemplate template) {
        if (template == null)
            return;

        for (ServiceTemplateComponent component : template.getComponents()) {
            for (ServiceTemplateCategory resource : component.getResources()) {
                for (ServiceTemplateSetting param : resource.getParameters()) {
                    if (param.getId().equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CHASSIS_CONFIG_USERS)) {
                        if (param.getValue() != null) {

                            List<Map<String, String>> users = (List) fromJSON(List.class, param.getValue());
                            if (users != null) {
                                for (Map<String, String> user : users) {
                                    for (String key : user.keySet()) {
                                        if (key.equals("password")) {
                                            IEncryptedString eS = getEncryptionDAO()
                                                    .findEncryptedStringById(user.get(key));
                                            if (eS != null) {
                                                user.put(key, eS.getString());
                                                getEncryptionDAO().delete(eS);
                                            }
                                        }
                                    }
                                }
                                param.setValue(toJSON(users));
                            }
                        }
                    } else if (param.getId()
                            .equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CHASSIS_CONFIG_ALERT_DEST)) {
                        if (param.getValue() != null) {

                            List<Map<String, String>> traps = (List) fromJSON(List.class, param.getValue());
                            if (traps != null) {
                                for (Map<String, String> trap : traps) {
                                    for (String key : trap.keySet()) {
                                        if (key.equals("communityString")) {
                                            IEncryptedString eS = getEncryptionDAO()
                                                    .findEncryptedStringById(trap.get(key));
                                            if (eS != null) {
                                                trap.put(key, eS.getString());
                                                getEncryptionDAO().delete(eS);
                                            }
                                        }
                                    }
                                }
                                param.setValue(toJSON(traps));
                            }
                        }
                    }
                }
            }
        }
    }

    private Object fromJSON(Class claz, String source) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.readValue(source, claz);
        } catch (IOException e) {
            return null;
        }
    }

    private String toJSON(Object o) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.writeValueAsString(o);
        } catch (JsonProcessingException e) {
            return "";
        }
    }

    /**
     * Zip attachments and template content, encrypt zip file and return base64 encoded.
     * @param template
     * @param password
     * @return file name
     * @throws AsmManagerRuntimeException
     */
    public String exportTemplate(ServiceTemplate template, String password) throws AsmManagerRuntimeException {
        String stringTemplate = MarshalUtil.marshal(template);

        ensureTemplateAttachmentsFolderExists();

        // This is the tar file name.
        long currenttime = System.currentTimeMillis();

        String filename = "template.tmp";
        String foldername = "/tmp/template_" + currenttime;
        String zipFilename = foldername + ".zip";
        String[] command;
        CommandResponse cmdresponse = null;
        ExecuteSystemCommands cmdRunner = ExecuteSystemCommands.getInstance();

        Path tempFolder = Paths.get(foldername);
        Path zipFilePath = Paths.get(zipFilename);

        if (Files.exists(tempFolder)) {
            try {
                Files.delete(tempFolder);
            } catch (IOException e) {
                LOGGER.error(e);
                throw new AsmManagerRuntimeException("Cannot delete directory: " + tempFolder);
            }
        }

        try {
            Files.createDirectory(tempFolder);
        } catch (IOException e) {
            LOGGER.error(e);
            throw new AsmManagerRuntimeException("Cannot create directory: " + tempFolder);
        }

        writeToFile(foldername, filename, stringTemplate);

        // zip all attachments
        File attachPath = new File(TEMPLATE_ATTACHMENT_DIR + template.getId());
        if (attachPath.exists() && attachPath.isDirectory() && attachPath.list().length > 0) {
            try {
                command = new String[] { "/bin/bash", "-c",
                        "/bin/cp -r " + attachPath.getAbsolutePath() + "/* " + tempFolder };
                cmdresponse = cmdRunner.runCommandWithConsoleOutput(command);
            } catch (Exception e) {
                LOGGER.error(e);
                throw new AsmManagerRuntimeException("Cannot copy attachments to temp folder: " + tempFolder);
            }
            if (!cmdresponse.getReturnCode().equals("0")) {
                throw new AsmManagerRuntimeException("Copying of template attachments failed");
            }
        }

        command = new String[] { "/bin/bash", "-c", "/usr/bin/zip -j " + zipFilename + " " + tempFolder + "/*" };

        try {
            cmdresponse = cmdRunner.runCommandWithConsoleOutput(command);
        } catch (Exception e) {
            LOGGER.error("Command execution failed: " + command, e);
            throw new AsmManagerRuntimeException(e);
        } finally {
            try {
                FileUtils.deleteDirectory(new File(tempFolder.toString()));
            } catch (IOException e) {
                LOGGER.error("Cannot delete temp folder: " + tempFolder, e);
            }
        }
        if (!cmdresponse.getReturnCode().equals("0")) {
            throw new AsmManagerRuntimeException("Zipping of template attachments failed");
        }

        command = new String[] { "/bin/bash", "-c",
                "echo " + ExecuteSystemCommands.sanitizeShellArgument(password)
                        + " | gpg --batch -q --passphrase-fd 0 -c "
                        + ExecuteSystemCommands.sanitizeShellArgument(zipFilename) };
        try {
            cmdresponse = cmdRunner.callCommand(command);
        } catch (Exception e) {
            LOGGER.error("Command execution failed: " + command, e);
            throw new AsmManagerRuntimeException(e);
        } finally {
            try {
                Files.delete(zipFilePath);
            } catch (IOException e) {
                LOGGER.error("Cannot delete zip file: " + zipFilePath, e);
            }
        }

        LOGGER.debug("GPG return code: " + cmdresponse.getReturnCode() + " Return message: "
                + cmdresponse.getReturnMessage());
        if (!cmdresponse.getReturnCode().equals("0")) {
            throw new AsmManagerRuntimeException("Encryption of template failed");
        }

        return zipFilename + ".gpg";
    }

    private static void ensureTemplateAttachmentsFolderExists() {
        Path tempFolder = Paths.get(TEMPLATE_ATTACHMENT_DIR);

        if (!Files.exists(tempFolder)) {
            try {
                Files.createDirectory(tempFolder);
            } catch (IOException e) {
                LOGGER.error(e);
                throw new AsmManagerRuntimeException("Cannot create directory: " + tempFolder);
            }
        }

    }

    /**
     * Writes the script to a file.
     *
     * @param scriptPath script path
     * @param scriptFilename script filename
     * @param data script
     * @return script path and filename
     */
    public static String writeToFile(String scriptPath, String scriptFilename, Object data)
            throws AsmManagerRuntimeException {
        StringBuilder builder = new StringBuilder();
        builder.append(scriptPath).append(System.getProperty("file.separator")).append(scriptFilename);

        // Write the data in script file.
        File file = new File(builder.toString());

        FileOutputStream fos = null;
        DataOutputStream dos = null;
        try {
            fos = new FileOutputStream(file);
            dos = new DataOutputStream(fos);
            if (data instanceof String) {
                IOUtils.write((String) data, dos);
            } else if (data instanceof byte[]) {
                IOUtils.write((byte[]) data, dos);
            } else {
                throw new AsmManagerRuntimeException("Write file: Data must be string or byte[]");
            }

            ExecuteSystemCommands cmd = ExecuteSystemCommands.getInstance();
            // Change the permission of the script.
            cmd.callCommand(new String[] { "/bin/chmod", "0770", builder.toString() });
        } catch (Exception e) {
            throw new AsmManagerRuntimeException(e);
        } finally {
            try {
                closeStreamQuitely(fos);
                closeStreamQuitely(dos);
            } catch (Exception e) {
                LOGGER.warn("Unable to close the file stream.");
            }
        }

        return builder.toString();
    }

    /**
     * Decrypt, unzip and copy attachments to template folder.
     * @param encryptedTemplateFileData encrypted template file data
     * @param password
     * @return
     * @throws AsmManagerRuntimeException
     */
    public static ServiceTemplate importTemplate(byte[] encryptedTemplateFileData, String password)
            throws AsmManagerRuntimeException {

        ServiceTemplate svc = null;

        if (encryptedTemplateFileData != null && encryptedTemplateFileData.length > 0) {
            ensureTemplateAttachmentsFolderExists();

            // This is the tar file name.
            long currenttime = System.currentTimeMillis();

            String filename = "template_" + currenttime + ".gpg";
            String restoredFile = "template_" + currenttime + ".zip";
            String tempFolder = "/tmp/template_" + currenttime;

            writeToFile("/tmp", filename, encryptedTemplateFileData);

            CommandResponse cmdresponse = null;
            ExecuteSystemCommands cmdRunner = ExecuteSystemCommands.getInstance();

            String[] command = new String[] { "/bin/bash", "-c",
                    "echo " + ExecuteSystemCommands.sanitizeShellArgument(password)
                            + " | gpg --batch -q --utf8-strings --output "
                            + ExecuteSystemCommands.sanitizeShellArgument("/tmp/" + restoredFile)
                            + " --passphrase-fd 0 --decrypt "
                            + ExecuteSystemCommands.sanitizeShellArgument("/tmp/" + filename) };

            try {
                cmdresponse = cmdRunner.callCommand(command);
            } catch (Exception e) {
                LOGGER.error("GPG execution failed", e);
                throw new AsmManagerRuntimeException(e);
            } finally {
                File file = new File("/tmp/" + filename);
                file.delete();
            }

            LOGGER.debug("GPG return code: " + cmdresponse.getReturnCode() + " Return message: "
                    + cmdresponse.getReturnMessage());
            if (!cmdresponse.getReturnCode().equals("0")) {
                throw new AsmManagerRuntimeException("Decryption of template failed, invalid file or password");
            }

            String encFil = "/tmp/" + restoredFile;

            // unzip all attachments
            command = new String[] { "/usr/bin/unzip", encFil, "-d" + tempFolder };

            try {
                cmdresponse = cmdRunner.runCommandWithConsoleOutput(command);
            } catch (Exception e) {
                LOGGER.error("Command execution failed: " + command, e);
                throw new AsmManagerRuntimeException(e);
            }

            if (!cmdresponse.getReturnCode().equals("0")) {
                throw new AsmManagerRuntimeException("UnZipping of template attachments failed");
            }

            try {
                Files.delete(Paths.get(encFil));
            } catch (IOException e) {
                LOGGER.error("Cannot delete file " + encFil, e);
            }

            // read template content
            File file = new File(tempFolder + "/template.tmp");
            String content = null;
            InputStream is = null;
            try {
                is = new FileInputStream(file);
                content = IOUtils.toString(is);
            } catch (IOException e) {
                throw new AsmManagerRuntimeException(e);
            } finally {
                if (is != null)
                    IOUtils.closeQuietly(is);
            }
            file.delete();

            svc = MarshalUtil.unmarshal(ServiceTemplate.class, content);
            if (svc == null) {
                throw new AsmManagerRuntimeException("Template content is null. Bad import file.");
            }

            // copy
            Path attachPath = Paths.get(TEMPLATE_ATTACHMENT_DIR + svc.getId());
            if (Files.exists(attachPath)) {
                svc.setId(UUID.randomUUID().toString());
                attachPath = Paths.get(TEMPLATE_ATTACHMENT_DIR + svc.getId());
            }
            try {
                Files.createDirectory(attachPath);
            } catch (IOException e) {
                LOGGER.error(e);
                throw new AsmManagerRuntimeException("Cannot create directory: " + attachPath);
            }

            File tmpDir = new File(tempFolder);
            if (tmpDir.exists() && tmpDir.isDirectory()) {
                if (tmpDir.list().length > 0) {
                    try {
                        Files.walkFileTree(tmpDir.toPath(), new CopyFileVisitor(attachPath));
                    } catch (Exception e) {
                        LOGGER.error(e);
                        throw new AsmManagerRuntimeException(
                                "Cannot copy attachments to template folder: " + attachPath);
                    }
                }

                // cleanup
                try {
                    FileUtils.deleteDirectory(tmpDir);
                } catch (IOException e) {
                    LOGGER.error("Cannot delete temp folder: " + tempFolder, e);
                }
            }
        }

        return svc;
    }

    /**
     * Utility method to close the input/output stream
     *
     * @param cs
     */
    public static void closeStreamQuitely(Closeable cs) {
        try {
            if (cs != null) {
                cs.close();
            }
        } catch (Exception e) {
            LOGGER.info("Can't close Stream");
        }
    }

    public boolean hasNetworks(ServiceTemplateSetting setting) {
        if (setting.getValue() == null) {
            return false;
        }
        try {

            com.dell.asm.asmcore.asmmanager.client.networkconfiguration.NetworkConfiguration networkConfig = deserializeNetwork(
                    setting.getValue());
            if (networkConfig == null) {
                return false;
            }

            List<Interface> interfaces = networkConfig.getUsedInterfaces();
            for (Interface interfaceObject : interfaces) {
                List<Partition> partitions = interfaceObject.getPartitions();
                for (Partition partition : partitions) {
                    if (partition.getNetworks() != null && partition.getNetworks().size() > 0)
                        return true;
                }
            }

        } catch (Exception e) {
            LOGGER.error("Check for networks failed", e);
            return true;
        }
        return false;
    }

    public static void copyAttachments(String oldId, String id) throws AsmManagerRuntimeException, IOException {
        validateId(oldId);
        validateId(id);

        Path newAttachPath = Paths.get(TEMPLATE_ATTACHMENT_DIR + id);
        if (!Files.exists(newAttachPath)) {
            try {
                Files.createDirectory(newAttachPath);
            } catch (IOException e) {
                LOGGER.error(e);
                throw new AsmManagerRuntimeException("Cannot create directory: " + newAttachPath.toString());
            }
        }

        File oldDir = new File(TEMPLATE_ATTACHMENT_DIR + oldId);
        if (oldDir.isDirectory() && oldDir.list().length > 0) {
            try {
                Files.walkFileTree(oldDir.toPath(), new CopyFileVisitor(newAttachPath));
            } catch (Exception e) {
                LOGGER.error(e);
                throw new AsmManagerRuntimeException(
                        "Cannot copy attachments to template folder: " + newAttachPath.toString());
            }
        }
    }

    /**
     * Move template attachments from one location to another
     * @param oldId
     * @param id
     */
    public static void moveAttachments(String oldId, String id) throws AsmManagerRuntimeException, IOException {
        validateId(oldId);
        validateId(id);

        Path attachPath = Paths.get(TEMPLATE_ATTACHMENT_DIR + id);
        if (!Files.exists(attachPath)) {
            try {
                Files.createDirectory(attachPath);
            } catch (IOException e) {
                LOGGER.error(e);
                throw new AsmManagerRuntimeException("Cannot create directory: " + attachPath);
            }
        }

        File oldDir = new File(TEMPLATE_ATTACHMENT_DIR + oldId);
        if (oldDir.isDirectory() && oldDir.list().length > 0) {
            try {
                Files.walkFileTree(oldDir.toPath(), new CopyFileVisitor(attachPath));
            } catch (Exception e) {
                LOGGER.error(e);
                throw new AsmManagerRuntimeException("Cannot move attachments to template folder: " + attachPath);
            }
        }

        // cleanup
        try {
            FileUtils.deleteDirectory(oldDir);
        } catch (IOException e) {
            LOGGER.error("Cannot delete template folder: " + TEMPLATE_ATTACHMENT_DIR + oldId, e);
        }

    }

    public static void deleteAttachments(String id) {
        if (id != null) {
            validateId(id);

            ensureTemplateAttachmentsFolderExists();

            try {
                Path directory = Paths.get(TEMPLATE_ATTACHMENT_DIR + id);
                if (Files.exists(directory) && Files.isDirectory(directory)) {
                    Files.walkFileTree(directory, new DeleteDirectoryVisitor());
                }
            } catch (Exception e) {
                LOGGER.error("Exception occurred deleting directory during cleanup.", e);
            }
        }
    }

    /**
     * return the task associated with a repo
     * @param repoName
     */
    public String findTask(String repoName) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            WebClient client = WebClient.create(AsmManagerApp.razorApiUrl);
            client.accept("application/json");
            String json = client.path("collections/repos").get(String.class);
            String repoJson = client.replacePath("/collections/repos/" + repoName).get(String.class);
            Map<String, Object> repoData = (HashMap<String, Object>) mapper.readValue(repoJson, HashMap.class);
            String task = (String) ((LinkedHashMap) repoData.get("task")).get("name");
            return task;
        } catch (IOException e) {
            LOGGER.error(e);
            throw new AsmManagerRuntimeException("Could not find task attached to repo " + repoName);
        }

    }

    //Helper function that just makes it easier for us to know what task a repo is assigned to, without needing to make rest calls for each server component
    //Used for many of the checks, such as hasESX.
    public Map<String, String> mapReposToTasks() {
        List<RazorRepo> repos = getOsRepositoryUtil().getRazorOSImages(true);
        Map<String, String> repoMap = new HashMap<String, String>();
        for (RazorRepo r : repos) {
            repoMap.put(r.getName(), r.getTask());
        }
        return repoMap;
    }

    /**
     * Populates the OS image drop down, and returns back a map of the dependency target strings for each OS.
     * @param razorImages List of RazorRepo images
     * @param bareMetal True exclude esxi values
     * @return map of OS image task to OS image names
     */
    public static Map<String, String> processRazorImagesTargets(List<RazorRepo> razorImages, boolean bareMetal) {
        Map<String, String> imageTargets = new HashMap<>();
        if (razorImages != null && razorImages.size() > 0) {
            Map<String, List<String>> tempTargets = new HashMap<>();
            for (RazorRepo image : razorImages) {
                //This check may not be necessary to have, but shouldn't hurt anything. Just ensures no unsupported repo/tasks are attempted to be accessed in the map.
                switch (image.getTask()) {
                case ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_ESXI_VALUE:
                    //Fallthrough to add to tempTargets if baremetal is false
                    if (bareMetal) {
                        break;
                    }
                case ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_REDHAT6_VALUE:
                case ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_REDHAT7_VALUE:
                case ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_SUSE11_VALUE:
                case ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_SUSE12_VALUE:
                case ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_WINDOWS2012_VALUE:
                case ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_WINDOWS2008_VALUE:
                    List<String> names = tempTargets.get(image.getTask());
                    if (names == null) {
                        names = new ArrayList<>();
                        tempTargets.put(image.getTask(), names);
                    }
                    names.add(image.getName());
                    break;
                default:
                    break;
                }
            }
            //Populate the map with the comma-separated lists of the targets for easier use later.
            for (Map.Entry<String, List<String>> entry : tempTargets.entrySet()) {
                if (entry.getValue() != null && entry.getValue().size() > 0) {
                    String targets = Joiner.on(",").join(entry.getValue());
                    imageTargets.put(entry.getKey(), targets);
                }
            }
        }
        return imageTargets;
    }

    /**
     * Returns back a map of the dependency target strings for Linux-type OS's (excludes esxi).
     * @param razorImages List of RazorRepo images
     * @return map of OS image task to OS image names
     */
    public static Map<String, String> getLinuxRazorImageTargets(List<RazorRepo> razorImages) {
        Map<String, String> imageTargets = new HashMap<>();
        Map<String, ArrayList<String>> tempTargets = new HashMap<>();
        for (RazorRepo image : razorImages) {
            switch (image.getTask()) {
            case ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_REDHAT6_VALUE:
            case ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_REDHAT7_VALUE:
            case ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_SUSE11_VALUE:
            case ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_SUSE12_VALUE:
                ArrayList<String> names = tempTargets.get(image.getTask());
                if (names == null) {
                    names = new ArrayList<>();
                    tempTargets.put(image.getTask(), names);
                }
                names.add(image.getName());
                break;
            default:
                break;
            }
        }
        for (Map.Entry<String, ArrayList<String>> entry : tempTargets.entrySet()) {
            if (entry.getValue() != null && entry.getValue().size() > 0) {
                String targets = Joiner.on(",").join(entry.getValue());
                imageTargets.put(entry.getKey(), targets);
            }
        }
        return imageTargets;
    }

    public static void addOSImagesAsOptions(final List<RazorRepo> razorImages, final Map<String, String> repoNames,
            ServiceTemplateSetting setting) {
        if (setting != null) {
            for (RazorRepo image : razorImages) {
                String displayName = (repoNames.get(image.getName()) == null) ? image.getName()
                        : repoNames.get(image.getName());
                setting.getOptions().add(new ServiceTemplateOption(displayName, image.getName(), null, null));
            }
        }
    }

    //Called when getting a template, to ensure the os image dropdowns/dependencies are up to date.
    public void updateRazorTargets(ServiceTemplate svc) {
        List<RazorRepo> razorImages = getOsRepositoryUtil().getRazorOSImages(true);
        Map<String, String> imageTargets = processRazorImagesTargets(razorImages, false);
        String windowsValues = StringUtils.defaultIfBlank(
                Joiner.on(",").skipNulls().join(
                        imageTargets.get(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_WINDOWS2012_VALUE),
                        imageTargets.get(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_WINDOWS2008_VALUE)),
                null);
        String allLinuxValues = StringUtils.defaultIfBlank(Joiner.on(",").skipNulls().join(
                imageTargets.get(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_REDHAT6_VALUE),
                imageTargets.get(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_REDHAT7_VALUE),
                imageTargets.get(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_SUSE11_VALUE),
                imageTargets.get(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_SUSE12_VALUE)), null);

        String windows2012Values = imageTargets
                .get(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_WINDOWS2012_VALUE);
        String ntpValues = Joiner.on(",").skipNulls().join(allLinuxValues, windowsValues,
                imageTargets.get(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_ESXI_VALUE));

        for (ServiceTemplateComponent comp : svc.getComponents()) {
            if (ServiceTemplateComponent.ServiceTemplateComponentType.SERVER.equals(comp.getType())
                    || ServiceTemplateComponent.ServiceTemplateComponentType.VIRTUALMACHINE
                            .equals(comp.getType())) {
                if (windowsValues != null) {
                    setDependencyValue(comp, ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_VERSION_ID,
                            windowsValues);
                    setDependencyValue(comp, ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HV_PROD_KEY_ID,
                            windowsValues);
                    setDependencyValue(comp, ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HV_ADMIN_LOGIN_ID,
                            windowsValues);
                    setDependencyValue(comp,
                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_DOMAIN_PASSWORD_ID, windowsValues);
                    setDependencyValue(comp,
                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_DOMAIN_CONFIRM_PASSWORD_ID,
                            windowsValues);
                    setDependencyValue(comp, ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HV_DN_ID,
                            windowsValues);
                }
                if (allLinuxValues != null) {
                    setDependencyValue(comp, ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_LINUX_TIMEZONE_ID,
                            allLinuxValues);
                }
                if (windows2012Values != null) {
                    setDependencyValue(comp, ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HV_INSTALL,
                            windows2012Values);
                }
                if (ntpValues != null) {
                    setDependencyValue(comp, ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_LINUX_NTP_ID,
                            ntpValues);
                }
            }
        }
    }

    /**
     * method that just holds logic for updating certain values that may be hidden away from the user, but need to be passed through.
     * @param svcTemplate
     */
    public void setHiddenValues(ServiceTemplate svcTemplate) {
        //Update os_image_type to reflect the task associated with the repo selected.
        Map<String, String> tasks = mapReposToTasks();
        for (ServiceTemplateComponent component : svcTemplate.getComponents()) {
            if (ServiceTemplateComponent.ServiceTemplateComponentType.SERVER.equals(component.getType())
                    || ServiceTemplateComponent.ServiceTemplateComponentType.VIRTUALMACHINE
                            .equals(component.getType())) {

                // determine if esxi or hyperV and set internal flag
                component.isHypervisor(tasks);

                ServiceTemplateCategory templateResource = component
                        .getTemplateResource(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_RESOURCE);
                if (templateResource != null) {
                    ServiceTemplateSetting repo = templateResource
                            .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_IMAGE_ID);
                    ServiceTemplateSetting hypervInstall = templateResource
                            .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HV_INSTALL);
                    boolean hvValid = (hypervInstall != null)
                            && requiredDependenciesSatisfied(component, hypervInstall);

                    ServiceTemplateSetting imageType = templateResource
                            .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_TYPE_ID);
                    if (imageType != null) {
                        if (hvValid && "true".equals(hypervInstall.getValue()))
                            imageType.setValue(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_HYPERV_VALUE);
                        else {
                            if (repo != null) {
                                String task = tasks.get(repo.getValue());
                                imageType.setValue(task);
                            }
                        }
                    }
                }
            }
        }
    }

    public List<String> getAttemptedServers(ServiceTemplateComponent component) {
        List<String> servers = new ArrayList<>();
        ServiceTemplateSetting setting = component
                .getTemplateSetting(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_ATTEMPTED_SERVERS);
        if (setting != null) {
            ObjectMapper mapper = new ObjectMapper();
            try {
                if (StringUtils.isNotEmpty(setting.getValue()))
                    servers = mapper.readValue(setting.getValue(), List.class);
            } catch (IOException e) {
                LOGGER.error("Cannot parse SERVICE_TEMPLATE_SERVER_ATTEMPTED_SERVERS value: " + setting.getValue(),
                        e);
            }
        }

        return servers;
    }

    public List<String> addAttemptedServers(ServiceTemplateComponent component, String refId) {
        List<String> servers = new ArrayList<>();
        ServiceTemplateSetting setting = component
                .getTemplateSetting(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_ATTEMPTED_SERVERS);
        if (setting == null) {
            ServiceTemplateCategory category = component
                    .getTemplateResource(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_IDRAC_RESOURCE);
            if (category == null)
                category = component
                        .getTemplateResource(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_RESOURCE);
            setting = ServiceTemplateService.addDeploymentAttemptedSetting(category);
            if (setting == null) {
                throw new AsmManagerRuntimeException(
                        "No category SERVICE_TEMPLATE_SERVER_IDRAC_RESOURCE or SERVICE_TEMPLATE_SERVER_OS_RESOURCE in provided template component");
            }

        }
        ObjectMapper mapper = new ObjectMapper();
        try {
            if (StringUtils.isNotEmpty(setting.getValue()))
                servers = mapper.readValue(setting.getValue(), List.class);

            // ignore the same server - retry use case
            if (!servers.contains(refId))
                servers.add(refId);
            setting.setValue(mapper.writeValueAsString(servers));
        } catch (IOException e) {
            LOGGER.error("Cannot parse SERVICE_TEMPLATE_SERVER_ATTEMPTED_SERVERS value: " + setting.getValue(), e);
            throw new AsmManagerRuntimeException("failed to add to attempted servers");
        }
        return servers;
    }

    public static com.dell.asm.asmcore.asmmanager.client.networkconfiguration.NetworkConfiguration findNetworkConfiguration(
            ServiceTemplateComponent component) {
        ServiceTemplateCategory networkingResource = component
                .getTemplateResource(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_NETWORKING_COMP_ID);
        if (networkingResource != null) {
            ServiceTemplateSetting parameter = networkingResource
                    .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_NETWORK_CONFIG_ID);
            if (parameter != null) {
                return parameter.getNetworkConfiguration();
            }
        }
        return null;
    }

    private void setDependencyValue(ServiceTemplateComponent comp, String settingId, String value) {
        ServiceTemplateSetting setting = comp.getTemplateSetting(settingId);
        if (setting != null)
            setting.setDependencyValue(value);
    }

    public static boolean isConfirmPassword(String parameterId) {
        return ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_ADMIN_CONFIRM_PASSWORD_ID.equals(parameterId)
                || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VM_OS_DOMAIN_CONFIRM_PASSWORD_ID.equals(parameterId)
                || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_DOMAIN_CONFIRM_PASSWORD_ID
                        .equals(parameterId);
    }

    public void stripConfirmPasswordParameters(ServiceTemplate template) {
        for (ServiceTemplateComponent component : template.getComponents()) {
            for (ServiceTemplateCategory resource : component.getResources()) {
                Iterator<ServiceTemplateSetting> iterator = resource.getParameters().iterator();
                while (iterator.hasNext()) {
                    ServiceTemplateSetting param = iterator.next();
                    if (ServiceTemplateUtil.isConfirmPassword(param.getId())) {
                        iterator.remove();
                    }
                }
            }
        }
    }

    public static Pair<ServiceTemplateCategory, String> getServerSourceValue(ServiceTemplateComponent component,
            String serverSource) {
        // find SERVICE_TEMPLATE_SERVER_SOURCE; may be in either asm::idrac or asm::server
        for (ServiceTemplateCategory resource : component.getResources()) {
            ServiceTemplateSetting param = resource
                    .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_SOURCE);
            if (param != null && StringUtils.equals(serverSource, param.getValue())) {
                ServiceTemplateSetting valueParam = null;
                switch (serverSource) {
                case ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_SOURCE_POOL:
                    valueParam = resource.getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_POOL_ID);
                    break;
                case ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_SOURCE_MANUAL:
                    valueParam = resource
                            .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_MANUAL_SELECTION);
                    break;
                default:
                    LOGGER.warn("Unknown server source parameter " + serverSource + " for component " + component);
                    valueParam = null;
                    break;
                }

                if (valueParam == null || StringUtils.isBlank(valueParam.getValue())) {
                    return null;
                } else {
                    return Pair.of(resource, valueParam.getValue());
                }
            }
        }
        return null;
    }

    public static List<ServiceTemplateComponent> getServersFromSource(List<ServiceTemplateComponent> components,
            String serverSource) {
        List<ServiceTemplateComponent> ret = new ArrayList<>();
        for (ServiceTemplateComponent component : components) {
            if (ServiceTemplateComponent.ServiceTemplateComponentType.SERVER.equals(component.getType())) {
                Pair<ServiceTemplateCategory, String> pair = getServerSourceValue(component, serverSource);
                if (pair != null) {
                    ret.add(component);
                }
            }
        }
        return ret;
    }

    /**
     * Ensure all service template components have associations with components that have associations
     * with themselves
     *
     * @param svcTemplate
     */
    public static void ensureRelatedComponents(ServiceTemplate svcTemplate) {
        //build component map for easy access to all components on template
        Map<String, ServiceTemplateComponent> componentsMap = svcTemplate.fetchComponentsMap();

        // loop through map confirming all associated components have the same relationship
        for (Map.Entry<String, ServiceTemplateComponent> entry : componentsMap.entrySet()) {
            ServiceTemplateComponent currentComponent = entry.getValue();
            if (currentComponent != null && !currentComponent.getAssociatedComponents().isEmpty()) {
                Set<String> unmappedComponents = new HashSet<>();
                // loop through associated component entries and cofirm they have association with current component
                for (String associatedId : currentComponent.getAssociatedComponents().keySet()) {
                    ServiceTemplateComponent associatedComponent = componentsMap.get(associatedId);
                    if (associatedComponent != null) {
                        // if current component id not found in associated component's associated component keyset then add association
                        if (!associatedComponent.getAssociatedComponents().keySet()
                                .contains(currentComponent.getId())) {
                            LOGGER.warn("Adding missed associated component link " + currentComponent.getId()
                                    + " -> " + associatedComponent.getId());
                            associatedComponent.addAssociatedComponentName(currentComponent.getId(),
                                    currentComponent.getName());
                        }
                    } else {
                        unmappedComponents.add(associatedId);
                    }
                }
                if (!unmappedComponents.isEmpty()) {
                    for (String removeId : unmappedComponents) {
                        currentComponent.removeAssociatedComponent(removeId);
                    }
                }
            }
        }
    }

    public void setOtherDependencies(ServiceTemplateComponent compellent) {

        //here we set dependencies for fw version and for configure SAN support

        Double version = null;
        List<String> compRefIdList = new ArrayList<String>();
        List<ServiceTemplateCategory> compellentResources = compellent.getResources();
        DeviceInventoryDAO devInv = new DeviceInventoryDAO();
        boolean noCompellentInList = false;

        for (ServiceTemplateCategory resource : compellentResources) {
            List<ServiceTemplateSetting> params = resource.getParameters();
            for (ServiceTemplateSetting parameter : params) {
                if (parameter.getId().equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ASM_GUID)) {
                    List<ServiceTemplateOption> compList = parameter.getOptions();
                    if (compList.size() < 2) {
                        noCompellentInList = true;
                    } else {
                        for (ServiceTemplateOption comp : compList) {
                            if (!(comp.getName().equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SELECT))) {
                                Set<FirmwareDeviceInventoryEntity> compFwSet = devInv
                                        .getFirmwareDeviceInventoryByRefId(comp.getValue());
                                for (FirmwareDeviceInventoryEntity compFw : compFwSet) {
                                    version = new Double(compFw.getVersion().substring(0, 3));
                                    if (version != null
                                            && version >= ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_COMPELLENT_ESX6_TARGET_VERSION) {
                                        compRefIdList.add(comp.getValue());
                                    }
                                }
                            }
                        }
                    }
                }
                if (parameter.getId().equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_COMPELLENT_OS_ID)) {
                    List<ServiceTemplateOption> compList = parameter.getOptions();
                    for (ServiceTemplateOption comp : compList) {
                        if (comp.getName()
                                .equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_COMPELLENT_ESX6_NAME)
                                && !noCompellentInList) {
                            comp.setDependencyTarget(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ASM_GUID);
                            comp.setDependencyValue(compRefIdList.size() == 0 ? "--"
                                    : Joiner.on(",").skipNulls().join(compRefIdList));
                        }
                    }
                }
                if (parameter.getId().equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CONFIGURE_SAN)) {
                    parameter
                            .setDependencyTarget(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_COMPELLENT_PORTTYPE_ID);
                    parameter.setDependencyValue(
                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_COMPELLENT_PORTTYPE_FIBRE_CHANNEL);
                }
            }
        }
    }

    /**
     * For encoded JSON param s upgrade or convert parameter values to latest version.
     * @param parameter
     * @param templateVersion reserved for future usage
     */
    public static void upgradeParameter(ServiceTemplateSetting parameter, String templateVersion) {
        if (parameter.getId().equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_NETWORK_CONFIG_ID)) {
            com.dell.asm.asmcore.asmmanager.client.networkconfiguration.NetworkConfiguration configuration = null;
            if (StringUtils.isBlank(parameter.getValue())) {
                LOGGER.warn("upgradeParameter: Network configuration is blank, nothing to convert");
            } else {
                try {
                    configuration = deserializeNetwork(parameter.getValue());
                    upgradeNetworkConfiguration(configuration);
                    parameter.setValue(BACKEND_MAPPER.writeValueAsString(configuration));
                } catch (IOException e) {
                    LOGGER.error(
                            "upgradeParameter: Network configuration has invalid value: " + parameter.getValue(),
                            e);
                }
            }
        }
    }

    /**
     * Upgrade newtork config - move fabrics to interfaces, set servertype to null.
     * @param configuration
     */
    public static void upgradeNetworkConfiguration(
            com.dell.asm.asmcore.asmmanager.client.networkconfiguration.NetworkConfiguration configuration) {

        if (configuration != null) {
            List<Fabric> interfaces = new ArrayList<Fabric>();

            if (StringUtils.isNotBlank(configuration.getServertype())) {
                if (SERVER_TYPE_BLADE.equals(configuration.getServertype())) {
                    for (Fabric f : configuration.getFabrics()) {
                        if (f.isUsedforfc())
                            f.setFabrictype(Fabric.FC_TYPE);
                        else
                            f.setFabrictype(Fabric.ETHERNET_TYPE);
                        if (f.isEnabled())
                            interfaces.add(f);
                    }
                } else {
                    for (Fabric f : configuration.getInterfaces()) {
                        if (f.isUsedforfc())
                            f.setFabrictype(Fabric.FC_TYPE);
                        else
                            f.setFabrictype(Fabric.ETHERNET_TYPE);
                        if (f.isEnabled())
                            interfaces.add(f);
                    }
                }

                configuration.setServertype(null);
                configuration.getFabrics().clear();
                configuration.setInterfaces(interfaces);
            }
        }
    }

    /**
     * This method will remove any unused Networks that may have been set and left before saving the template.
     * @param serviceTemplate
     * @throws JsonProcessingException
     */
    public static void clearUnusedNetworks(ServiceTemplate serviceTemplate) throws JsonProcessingException {
        if (serviceTemplate.getComponents() != null) {
            for (ServiceTemplateComponent component : serviceTemplate.getComponents()) {
                if (component.getType() == ServiceTemplateComponentType.SERVER) {
                    for (ServiceTemplateCategory resource : component.getResources()) {
                        ServiceTemplateSetting networkingSetting = resource
                                .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_NETWORK_CONFIG_ID);
                        if (networkingSetting != null) {
                            com.dell.asm.asmcore.asmmanager.client.networkconfiguration.NetworkConfiguration networkConfig = deserializeNetwork(
                                    networkingSetting.getValue());
                            if (networkConfig != null) {
                                networkConfig.clearUnusedNetworkSettings();
                                String json = serializeNetwork(networkConfig);
                                networkingSetting.setValue(json);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * Currently uses ObjectMapper. Will NOT throw exception but return null if json is wrong.
     * It does NOT require adding "networkConfiguration:" to JSON as for MarshalUtil.fromJSON
     * @param value
     * @return
     */
    public static com.dell.asm.asmcore.asmmanager.client.networkconfiguration.NetworkConfiguration deserializeNetwork(
            String value) {
        try {
            return BACKEND_MAPPER.readValue(value,
                    com.dell.asm.asmcore.asmmanager.client.networkconfiguration.NetworkConfiguration.class);
            //String configString = "{ \"networkConfiguration\" : " + value + "}";
            //return MarshalUtil.fromJSON(com.dell.asm.asmcore.asmmanager.client.networkconfiguration.NetworkConfiguration.class, configString);
        } catch (IOException e) {
            LOGGER.error("Network configuration has invalid value: " + value);
        }
        return null;
    }

    /**
     * Serialize the object hierarchy and set it as the value for the network configuration setting
     * @param networkConfiguration
     * @return
     */
    public static String serializeNetwork(
            com.dell.asm.asmcore.asmmanager.client.networkconfiguration.NetworkConfiguration networkConfiguration) {
        String serializedNetwork = null;
        try {
            StringWriter sw = new StringWriter();
            BACKEND_MAPPER.writeValue(sw, networkConfiguration);
            serializedNetwork = sw.toString();
        } catch (IOException e) {
            LOGGER.error("Exception seen while marshaling network configuration. ", e);
        }
        return serializedNetwork;
    }

    /**
     * If dependency target is not null, verify dependency value satisfies template.
     * If target is null returns true (no dependency, setting is actual).
     * @param component
     * @param setting
     * @return
     */
    public static boolean checkDependency(ServiceTemplateComponent component, ServiceTemplateSetting setting) {
        if (StringUtils.isNotEmpty(setting.getDependencyTarget())) {
            ServiceTemplateSetting depTarget = component.getTemplateSetting(setting.getDependencyTarget());
            return (depTarget != null && StringUtils.contains(setting.getDependencyValue(), depTarget.getValue()));
        }
        return true;
    }

    /**
     * Update referenced template components with
     * @param refTmpl Referenced template
     * @param defaultTmpl Default template
     * @param componentType component type
     */
    public static void refineComponents(ServiceTemplate refTmpl, ServiceTemplate defaultTmpl,
            String componentType) {
        if (refTmpl == null)
            return;

        // two cases, if default template is null - we are editing existing template
        if (defaultTmpl == null) {
            defaultTmpl = refTmpl;
        }
        for (ServiceTemplateComponent refineComponent : defaultTmpl.getComponents()) {
            if (componentType == null || (refineComponent.getType() != null
                    && (componentType.equalsIgnoreCase(refineComponent.getType().getLabel())))) {
                AdjusterFactory.getRefiner(refineComponent.getType()).refine(refineComponent, refTmpl);
            }
        }
    }

    /**
     * Get the storage components associated with a cluster component.
     * Cluster must have associated server components.
     * @param component Cluster component
     * @param referencedTemplate Referenced Template
     * @return Set<ServiceTemplateComponent>
     */
    public static List<ServiceTemplateComponent> getAssociatedStorageComponentsFromCluster(
            ServiceTemplateComponent component, ServiceTemplate referencedTemplate) {
        Set<ServiceTemplateComponent> foundComponents = new HashSet<>();

        if (!ServiceTemplateComponentType.CLUSTER.equals(component.getType())) {
            return new ArrayList<>();
        }

        final Set<String> relClusterComps = component.getAssociatedComponents().keySet();

        if (CollectionUtils.isNotEmpty(relClusterComps)) {
            final Map<String, ServiceTemplateComponent> componentMap = referencedTemplate.fetchComponentsMap();
            for (String key : relClusterComps) {
                ServiceTemplateComponent relClusterComp = componentMap.get(key);
                if (relClusterComp != null
                        && ServiceTemplateComponentType.SERVER.equals(relClusterComp.getType())) {
                    Set<String> relServerComps = relClusterComp.getAssociatedComponents().keySet();
                    if (CollectionUtils.isNotEmpty(relServerComps)) {
                        for (String serverKey : relServerComps) {
                            ServiceTemplateComponent relServerComp = componentMap.get(serverKey);
                            if (relServerComp != null
                                    && ServiceTemplateComponentType.STORAGE.equals(relServerComp.getType())) {
                                foundComponents.add(relServerComp);
                            }
                        }
                    }
                }
            }
        }
        return new ArrayList<>(foundComponents);
    }

    /**
     * Get the cluster component associated with a storage component.
     * Cluster must have associated server components.
     * @param storageComponent Cluster component
     * @param componentMap Map<String, ServiceTemplateComponent>
     * @return Set<ServiceTemplateComponent>
     */
    public static ServiceTemplateComponent getAssociatedClusterComponentFromStorage(
            ServiceTemplateComponent storageComponent, Map<String, ServiceTemplateComponent> componentMap) {
        if (!ServiceTemplateComponentType.STORAGE.equals(storageComponent.getType())) {
            return null;
        }

        final Set<String> relServerCompKeys = storageComponent.getAssociatedComponents().keySet();

        if (CollectionUtils.isNotEmpty(relServerCompKeys)) {
            for (String key : relServerCompKeys) {
                ServiceTemplateComponent relServerComp = componentMap.get(key);
                if (relServerComp != null && ServiceTemplateComponentType.SERVER.equals(relServerComp.getType())) {
                    Set<String> relClusterCompKeys = relServerComp.getAssociatedComponents().keySet();
                    if (CollectionUtils.isNotEmpty(relClusterCompKeys)) {
                        for (String clusterKey : relClusterCompKeys) {
                            ServiceTemplateComponent relClusterComp = componentMap.get(clusterKey);
                            if (relClusterComp != null
                                    && ServiceTemplateComponentType.CLUSTER.equals(relClusterComp.getType())) {
                                return relClusterComp;
                            }
                        }
                    }
                }
            }
        }
        return null;
    }

    private static void validateId(String id) {
        if (id != null) {
            int fileSeparatorIndex = id.indexOf(File.separator);
            if (fileSeparatorIndex >= 0) {
                throw new IllegalArgumentException("Service Template Id can not include file paths");
            }
        }
    }

    /**
     * Returns list of directory entries.
     * @param templateId
     * @return
     */
    public static List<String> getAttachments(String templateId) {
        List<String> attachments = new ArrayList<String>();
        File templateDir = new File(TEMPLATE_ATTACHMENT_DIR + templateId);
        if (templateDir.exists()) {
            attachments = Arrays.asList(templateDir.list());
        }
        return attachments;
    }

    /**
     * Copy attachment to template directory
     * @param templateId
     * @param attachmentFile
     */
    public static void addOrReplaceAttachment(String templateId, File attachmentFile) {
        ensureTemplateAttachmentsFolderExists();

        Path tempFolder = Paths.get(TEMPLATE_ATTACHMENT_DIR + templateId);
        if (!Files.exists(tempFolder)) {
            try {
                Files.createDirectory(tempFolder);
            } catch (IOException e) {
                LOGGER.error("Cannot create attachment directory for template: " + templateId, e);
                throw new AsmManagerRuntimeException("Cannot create directory: " + tempFolder);
            }
        }

        Path existingAttachment = Paths
                .get(TEMPLATE_ATTACHMENT_DIR + templateId + File.separator + attachmentFile.getName());
        if (Files.exists(existingAttachment)) {
            FileUtils.deleteQuietly(existingAttachment.toFile());
        }

        try {
            FileUtils.copyFileToDirectory(attachmentFile, tempFolder.toFile());
        } catch (IOException e) {
            LOGGER.error("Cannot copy attachment " + attachmentFile.getName() + " to the directory for template: "
                    + templateId, e);
            throw new AsmManagerRuntimeException(
                    "Cannot copy template attachment " + attachmentFile.getName() + " to " + tempFolder);
        }
    }

    public static void addAssignedUsers(ServiceTemplate serviceTemplate,
            ServiceTemplateEntity serviceTemplateEntity) {
        if (serviceTemplate != null && serviceTemplateEntity != null) {
            if (serviceTemplate.getAssignedUsers() != null) {
                for (User user : serviceTemplate.getAssignedUsers()) {
                    TemplateUserRefEntity de = new TemplateUserRefEntity();
                    de.setUserId(user.getUserSeqId());
                    de.setTemplateId(serviceTemplate.getId());
                    de.setId(UUID.randomUUID().toString());
                    serviceTemplateEntity.getAssignedUserList().add(de);
                }
            }
        }
    }

    /**
     * Helper to add a setting "Create new ..." / "Autogenerate"
     * @param resource Resource to process
     * @param options list of options to select from
     */
    public static void processStorageVolumeName(ServiceTemplateCategory resource,
            List<ServiceTemplateOption> options) {

        // check if the storage resource was already upgraded
        ServiceTemplateSetting setTitle = resource
                .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID);
        if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_AUTOGENERATE.equals(setTitle.getValue())
                || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_EXISTING
                        .equals(setTitle.getValue())
                || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_CREATE_NOW
                        .equals(setTitle.getValue())
                || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_CREATE_DEPLOYMENT
                        .equals(setTitle.getValue())) {
            return;
        }

        for (int i = 0; i < resource.getParameters().size(); i++) {
            ServiceTemplateSetting set = resource.getParameters().get(i);
            if (set.getId().equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID)) {

                set.getOptions().clear();
                //addDefaultSelectOption(set);
                set.setType(ServiceTemplateSetting.ServiceTemplateSettingType.ENUMERATED);
                set.getOptions().add(new ServiceTemplateOption("Auto-generate storage volume name",
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_AUTOGENERATE, null, null));
                set.getOptions().add(new ServiceTemplateOption("Select an existing storage volume",
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_EXISTING, null, null));
                set.getOptions().add(new ServiceTemplateOption("Specify a new storage volume name now",
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_CREATE_NOW, null, null));
                set.getOptions()
                        .add(new ServiceTemplateOption("Specify storage volume name at time of deployment",
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_CREATE_DEPLOYMENT,
                                null, null));
                set.setValue(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_AUTOGENERATE);
                set.setRequiredAtDeployment(false);
                set.setOptionsSortable(false);

                ServiceTemplateSetting setNameExisting = new ServiceTemplateSetting();
                setNameExisting.setType(ServiceTemplateSetting.ServiceTemplateSettingType.STRING);
                setNameExisting.setId(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_EXISTING);
                setNameExisting.setDisplayName("Existing Volume Name");
                setNameExisting.setRequired(true);
                setNameExisting.setRequiredAtDeployment(false);
                setNameExisting.setHideFromTemplate(false);
                setNameExisting.setGroup(set.getGroup());
                setNameExisting.setDependencyTarget(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID);
                setNameExisting
                        .setDependencyValue(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_EXISTING);
                addDefaultSelectOption(setNameExisting);
                if (options != null) {
                    setNameExisting.getOptions().addAll(options);
                }
                resource.getParameters().add(i + 1, setNameExisting);

                ServiceTemplateSetting setNameTemplate = new ServiceTemplateSetting();
                setNameTemplate.setType(ServiceTemplateSetting.ServiceTemplateSettingType.STRING);
                setNameTemplate.setId(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_TEMPLATE);
                setNameTemplate.setDisplayName("Volume Name Template");
                setNameTemplate.setRequired(true);
                setNameTemplate.setRequiredAtDeployment(false);
                setNameTemplate.setHideFromTemplate(false);
                setNameTemplate.setGroup(set.getGroup());
                setNameTemplate.setValue("storage${num}");
                setNameTemplate.setDependencyTarget(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID);
                setNameTemplate.setDependencyValue(
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_AUTOGENERATE);
                setNameTemplate.setToolTip(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_AUTOGEN_VOLUME_TOOLTIP);
                resource.getParameters().add(i + 1, setNameTemplate);

                ServiceTemplateSetting setGenerated = new ServiceTemplateSetting();
                setGenerated.setType(ServiceTemplateSetting.ServiceTemplateSettingType.STRING);
                setGenerated.setId(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_GENERATED);
                setGenerated.setDisplayName("Generated Volume Name");
                setGenerated.setRequired(false);
                setGenerated.setRequiredAtDeployment(false);
                setGenerated.setHideFromTemplate(true);
                setGenerated.setGroup(set.getGroup());
                setGenerated.setDependencyTarget(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID);
                setGenerated.setDependencyValue(
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_AUTOGENERATE);
                resource.getParameters().add(i + 1, setGenerated);

                ServiceTemplateSetting setNew = new ServiceTemplateSetting();
                setNew.setType(ServiceTemplateSetting.ServiceTemplateSettingType.STRING);
                setNew.setId(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_NEW);
                setNew.setDisplayName("New Volume Name");
                setNew.setRequired(true);
                setNew.setRequiredAtDeployment(false);
                setNew.setHideFromTemplate(false);
                setNew.setGroup(set.getGroup());
                setNew.setDependencyTarget(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID);
                setNew.setDependencyValue(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_CREATE_NOW);
                resource.getParameters().add(i + 1, setNew);

                ServiceTemplateSetting setNewAtDeployment = new ServiceTemplateSetting();
                setNewAtDeployment.setType(ServiceTemplateSetting.ServiceTemplateSettingType.STRING);
                setNewAtDeployment.setId(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_NEW_AT_DEPLOYMENT);
                setNewAtDeployment.setDisplayName("New Volume Name");
                setNewAtDeployment.setRequired(true);
                setNewAtDeployment.setRequiredAtDeployment(true);
                setNewAtDeployment.setHideFromTemplate(true);
                setNewAtDeployment.setGroup(set.getGroup());
                setNewAtDeployment.setDependencyTarget(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID);
                setNewAtDeployment.setDependencyValue(
                        ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_CREATE_DEPLOYMENT);
                resource.getParameters().add(i + 1, setNewAtDeployment);

                break;
            }
        }
    }

    /**
     * For legacy storage components convert "title" setting to the settings correspoding to "existing" or "new" volume
     * @param resource
     */
    public static void convertOldStorageVolume(ServiceTemplateCategory resource) {
        ServiceTemplateSetting setTitle = resource
                .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID);
        if (setTitle != null) {
            if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CREATE_NEW_PREFIX.equals(setTitle.getValue())) {
                convertStorageTitleToNewVolume(resource);
            } else {
                convertStorageTitleToExistingVolume(resource);
            }
        }
    }

    /**
     * For legacy storage components convert "title" setting to the settings correspoding to "existing" volume
     * @param resource
     */
    public static void convertStorageTitleToExistingVolume(ServiceTemplateCategory resource) {
        ServiceTemplateSetting setTitle = resource
                .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID);
        if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_AUTOGENERATE.equals(setTitle.getValue())
                || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_EXISTING
                        .equals(setTitle.getValue())
                || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_CREATE_NOW
                        .equals(setTitle.getValue())
                || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_CREATE_DEPLOYMENT
                        .equals(setTitle.getValue())) {
            return;
        }

        String volume = setTitle.getValue();
        List<ServiceTemplateOption> options = new ArrayList<>();
        options.addAll(setTitle.getOptions());
        processStorageVolumeName(resource, options);
        setTitle.setValue(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_EXISTING);
        ServiceTemplateSetting setVolume = resource
                .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_EXISTING);
        setVolume.setValue(volume);

        LOGGER.debug("Storage volume upgraded, existing value = " + setVolume.getValue());
    }

    /**
     * For legacy storage components convert "title" setting to the settings correspoding to "new" volume
     * @param resource
     */
    public static void convertStorageTitleToNewVolume(ServiceTemplateCategory resource) {
        ServiceTemplateSetting setTitle = resource
                .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID);
        if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_AUTOGENERATE.equals(setTitle.getValue())
                || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_EXISTING
                        .equals(setTitle.getValue())
                || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_CREATE_NOW
                        .equals(setTitle.getValue())
                || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_CREATE_DEPLOYMENT
                        .equals(setTitle.getValue())) {
            return;
        }
        String volume = setTitle.getValue();
        // safety check - value must be set to $new%
        if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CREATE_NEW_PREFIX.equals(volume)) {
            ServiceTemplateSetting setNewTitle = resource
                    .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CREATE_NEW_PREFIX
                            + ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID);
            if (setNewTitle == null) {
                LOGGER.error("Invalid template: no setting "
                        + ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CREATE_NEW_PREFIX
                        + ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID);
                return;
            }

            List<ServiceTemplateOption> options = new ArrayList<>();
            options.addAll(setTitle.getOptions());

            processStorageVolumeName(resource, options);
            setTitle.setValue(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_CREATE_NOW);
            ServiceTemplateSetting setVolume = resource
                    .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_NEW);
            setVolume.setValue(setNewTitle.getValue());

            LOGGER.debug("Storage volume upgraded, new value = " + setNewTitle.getValue());
        }
    }

    /**
     * For given template resource get existing volume list.
     * @param category
     * @return HashSet of unique volumes
     */
    public static Set<String> getVolumeSet(ServiceTemplateCategory category) {
        ServiceTemplateSetting existingVolume = category
                .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_EXISTING);

        if (existingVolume == null) {
            return null;
        }
        Set<String> volumes = new HashSet<>();
        List<ServiceTemplateOption> storageTemplateOptions = existingVolume.getOptions();
        for (ServiceTemplateOption option : storageTemplateOptions) {
            if (StringUtils.isNotEmpty(option.getValue())) {
                volumes.add(option.getValue());
            }
        }
        return volumes;
    }

    /**
     * We need only "title" in deployment JSON. There are few auxilary parameters related to storage name that has to be
     * transformed into a single value, and removed afterwards
     * @param serviceTemplate
     * @return Map of storage component ID matching the storage volume. Needed for cluster processing.
     */
    public static Map<String, String> processStoragesForDeployment(ServiceTemplate serviceTemplate) {
        Map<String, String> storageMap = new HashMap<>();
        for (ServiceTemplateComponent component : serviceTemplate.getComponents()) {
            if (!ServiceTemplateComponent.ServiceTemplateComponentType.STORAGE.equals(component.getType()))
                continue;

            for (ServiceTemplateCategory resource : component.getResources()) {
                Iterator<ServiceTemplateSetting> it = resource.getParameters().iterator();
                while (it.hasNext()) {
                    ServiceTemplateSetting param = it.next();
                    if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID.equals(param.getId())) {

                        String volumeName = ServiceTemplateClientUtil.getVolumeNameForStorageComponent(resource);
                        if (volumeName == null) {
                            String err = "Cannot find volume name setting in the service template for component = "
                                    + component.getAsmGUID() + ", volume mode: " + param.getId();
                            LOGGER.error(err);
                            break;
                        }

                        param.setValue(volumeName);
                        param.getOptions().clear();
                        storageMap.put(component.getId(), volumeName);
                    }

                    if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_GENERATED.equals(param.getId())
                            || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_EXISTING.equals(param.getId())
                            || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_NEW.equals(param.getId())
                            || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_NEW_AT_DEPLOYMENT
                                    .equals(param.getId())
                            || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_TEMPLATE
                                    .equals(param.getId()))
                        it.remove();
                }
            }
        }
        return storageMap;
    }

    /**
     * For SDRS memebers in cluster settings we store storage comp IDs.
     * asm-deployer expects storage volumes - hence the conversion.
     * @param serviceTemplate
     * @param storageMap    Storage component ID -> storage volume
     */
    public static void processClustersForDeployment(ServiceTemplate serviceTemplate,
            Map<String, String> storageMap) {
        for (ServiceTemplateComponent cluster : serviceTemplate.getComponents()) {
            if (!ServiceTemplateComponent.ServiceTemplateComponentType.CLUSTER.equals(cluster.getType()))
                continue;

            ServiceTemplateSetting dsNames = cluster.getParameter(
                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ESX_CLUSTER_COMP_ID,
                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CLUSTER_CLUSTER_DS_POD_MEMBERS_ID);

            if (dsNames != null && StringUtils.isNotEmpty(dsNames.getValue())) {
                // value is a CSV list of storage component IDs
                String[] compIDs = dsNames.getValue().trim().split(",");
                StringBuilder volumes = new StringBuilder();
                for (String compID : compIDs) {
                    String volume = storageMap.get(compID);
                    if (StringUtils.isNotEmpty(volume)) {
                        if (volumes.length() > 0) {
                            volumes.append(",");
                        }
                        volumes.append(volume);
                    }
                }
                dsNames.setValue(volumes.toString());
            }
        }
    }

    public boolean requiredDependenciesSatisfied(final ServiceTemplateComponent component,
            final ServiceTemplateSetting parameter) {
        if (StringUtils.isBlank(parameter.getDependencyTarget())) {
            // there are no further dependencies
            return Boolean.TRUE;
        } else {
            final ServiceTemplateSetting dependencyTarget = component
                    .getTemplateSetting(parameter.getDependencyTarget());
            if (dependencyTarget != null) {
                final String dependencyValue = dependencyTarget.getValue();
                for (final String value : StringUtils.split(parameter.getDependencyValue(), ",")) {
                    if (StringUtils.equals(dependencyValue, value)) {
                        LOGGER.info("Found required dependency " + dependencyTarget.getId() + ": " + value);
                        // NOTE[fcarta] Its understood there is a possibility for circular dependencies. In the
                        // event an error like this should occur we are ok with a StackOverflowException being
                        // thrown. This would indicate a programmatic error in a default template. Currently users dont
                        // have the ability to modify default templates.
                        return requiredDependenciesSatisfied(component, dependencyTarget);
                    }
                }
            }
            // dependency not found
            return Boolean.FALSE;
        }
    }

    public List<DeviceInventoryEntity> getVCenterEntities(boolean includeBrownfieldVmMangers) {
        List<String> filter = new ArrayList<>();
        filter.add("eq,deviceType,vcenter");
        if (includeBrownfieldVmMangers) {
            filter.add("eq,state," + DeviceState.READY.getValue());
            filter.add(
                    "eq,managedState," + ManagedState.MANAGED.getValue() + "," + ManagedState.RESERVED.getValue());
        } else {
            filter.add("eq,state," + DeviceState.READY.getValue());
            filter.add("eq,managedState," + ManagedState.MANAGED.getValue());
        }
        FilterParamParser filterParser = new FilterParamParser(filter, DeviceInventoryService.validFilterColumns);
        List<FilterParamParser.FilterInfo> filterInfos = filterParser.parse();
        List<DeviceInventoryEntity> vCenterEntities = getDeviceInventoryDAO().getAllDeviceInventory(null,
                filterInfos, null);
        return vCenterEntities;
    }

    public List<DeviceInventoryEntity> getHypervEntities() {
        List<String> filter = new ArrayList<>();
        filter.add("eq,deviceType,scvmm");
        filter.add("eq,state," + DeviceState.READY.getValue());
        filter.add("eq,managedState," + ManagedState.MANAGED.getValue());
        FilterParamParser filterParser = new FilterParamParser(filter, DeviceInventoryService.validFilterColumns);
        List<FilterParamParser.FilterInfo> filterInfos = filterParser.parse();
        List<DeviceInventoryEntity> hypervEntities = getDeviceInventoryDAO().getAllDeviceInventory(null,
                filterInfos, null);
        return hypervEntities;
    }

    public Map<String, List<DeviceInventoryEntity>> getStorageDevicesMap() {
        Map<String, List<DeviceInventoryEntity>> storageDeviceMap = new HashMap<>();

        List<String> filter = new ArrayList<String>();
        filter.add("eq,deviceType,compellent,equallogic,netapp,emcvnx");
        filter.add("eq,state," + DeviceState.READY.getValue());
        filter.add("eq,managedState," + ManagedState.MANAGED.getValue());
        FilterParamParser filterParser = new FilterParamParser(filter, DeviceInventoryService.validFilterColumns);
        List<FilterParamParser.FilterInfo> filterInfos = filterParser.parse();

        List<DeviceInventoryEntity> storageEntities = getDeviceInventoryDAO().getAllDeviceInventory(null,
                filterInfos, null);
        if (storageEntities != null && storageEntities.size() > 0) {
            for (DeviceInventoryEntity device : storageEntities) {
                if (device.getDeviceType() != null) {
                    List<DeviceInventoryEntity> deviceList = storageDeviceMap.get(device.getDeviceType().name());
                    if (deviceList == null) {
                        deviceList = new ArrayList<>();
                        storageDeviceMap.put(device.getDeviceType().name(), deviceList);
                    }
                    deviceList.add(device);
                }
            }
        }
        return storageDeviceMap;
    }

    public EncryptionDAO getEncryptionDAO() {
        if (encryptionDAO == null) {
            encryptionDAO = EncryptionDAO.getInstance();
        }
        return encryptionDAO;
    }

    public void setEncryptionDAO(EncryptionDAO encryptionDAO) {
        this.encryptionDAO = encryptionDAO;
    }

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

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

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

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

    public DeviceInventoryDAO getDeviceInventoryDAO() {
        if (deviceInventoryDAO == null) {
            deviceInventoryDAO = new DeviceInventoryDAO();
        }
        return deviceInventoryDAO;
    }

    public void setDeviceInventoryDAO(DeviceInventoryDAO deviceInventoryDAO) {
        this.deviceInventoryDAO = deviceInventoryDAO;
    }
}