/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package controllers.compute; import static com.emc.vipr.client.core.util.ResourceUtils.uri; import static com.emc.vipr.client.core.util.ResourceUtils.uris; import static controllers.Common.flashException; import static util.BourneUtil.getViprClient; import java.net.URI; import java.util.List; import java.util.Map; import java.util.Set; import models.HostTypes; import models.datatable.HostDataTable; import models.datatable.HostDataTable.HostInfo; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import play.data.binding.As; import play.data.validation.MaxSize; import play.data.validation.Min; import play.data.validation.MinSize; import play.data.validation.Required; import play.data.validation.Validation; import play.i18n.Messages; import play.mvc.With; import plugin.StorageOsPlugin; import util.ClusterUtils; import util.HostUtils; import util.MessagesUtils; import util.StringOption; import util.VCenterUtils; import util.datatable.DataTablesSupport; import util.validation.HostNameOrIpAddress; import com.emc.storageos.coordinator.client.model.Constants; import com.emc.storageos.coordinator.client.service.CoordinatorClient; import com.emc.storageos.model.host.ArrayAffinityHostParam; import com.emc.storageos.model.host.HostCreateParam; import com.emc.storageos.model.host.HostParam; import com.emc.storageos.model.host.HostRestRep; import com.emc.storageos.model.host.HostUpdateParam; import com.emc.storageos.model.host.InitiatorRestRep; import com.emc.storageos.model.host.IpInterfaceRestRep; import com.emc.storageos.model.host.cluster.ClusterRestRep; import com.emc.storageos.model.host.vcenter.VcenterDataCenterRestRep; import com.emc.storageos.model.host.vcenter.VcenterRestRep; import com.emc.storageos.model.project.ProjectRestRep; import com.emc.vipr.client.Task; import com.emc.vipr.client.core.util.ResourceUtils; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import controllers.Common; import controllers.deadbolt.Restrict; import controllers.deadbolt.Restrictions; import controllers.tenant.TenantSelector; import controllers.util.FlashException; import controllers.util.Models; import controllers.util.ViprResourceController; @With(Common.class) @Restrictions({ @Restrict("TENANT_ADMIN") }) public class Hosts extends ViprResourceController { protected static final String SAVED = "Hosts.saved"; protected static final String DELETED = "Hosts.deleted"; protected static final String UNKNOWN = "Hosts.unknown"; protected static final String MODEL_NAME = "Host"; protected static final String DETACH_STORAGE = "Hosts.detachStorage"; protected static final String DISCOVER_ARRAY_AFFINITY = "Hosts.arrayAffinityDiscoveryInitiated"; public static final String CONNECTION_FAILED_MSG = "host.validation.connection.failed"; public static void list() { TenantSelector.addRenderArgs(); renderArgs.put("dataTable", new HostDataTable()); CoordinatorClient coordinatorClient = StorageOsPlugin.getInstance().getCoordinatorClient(); String limit = coordinatorClient.getPropertyInfo().getProperty(Constants.RESOURCE_LIMIT_TENANT_HOSTS); renderArgs.put(Constants.RESOURCE_LIMIT_TENANT_HOSTS, limit); render(); } public static void listJson() { String tenantId = Models.currentAdminTenant(); List<HostRestRep> hosts = HostUtils.getHosts(tenantId); Map<URI, String> clusterMap = ResourceUtils.mapNames(getViprClient().clusters().listByTenant(uri(tenantId))); Set<URI> dataCenterIds = HostUtils.getDataCenterIds(hosts); Map<URI, VcenterDataCenterRestRep> vcenterDataCenters = HostUtils.getVcenterDataCenters(dataCenterIds); List<HostInfo> hostInfos = Lists.newArrayList(); for (HostRestRep host : hosts) { hostInfos.add(new HostInfo(host, clusterMap, vcenterDataCenters)); } renderJSON(DataTablesSupport.createJSON(hostInfos, params)); } public static void itemsJson(@As(",") String[] ids) { Map<URI, String> clusterMap = ResourceUtils.mapNames(getViprClient().clusters().listByTenant(uri(Models.currentAdminTenant()))); List<HostInfo> results = Lists.newArrayList(); if ((ids != null) && (ids.length > 0)) { for (String id : ids) { if (StringUtils.isBlank(id)) { continue; } HostRestRep host = HostUtils.getHost(uri(id)); if (host != null) { Set<URI> dataCenterIds = HostUtils.getDataCenterIds(Lists.newArrayList(host)); Map<URI, VcenterDataCenterRestRep> vcenterDataCenters = HostUtils.getVcenterDataCenters(dataCenterIds); results.add(new HostInfo(host, clusterMap, vcenterDataCenters)); } } } renderJSON(results); } public static void itemDetails(String id) { HostRestRep host = HostUtils.getHost(uri(id)); ClusterRestRep cluster = ClusterUtils.getCluster(ResourceUtils.id(host.getCluster())); VcenterDataCenterRestRep dataCenter = VCenterUtils.getDataCenter(ResourceUtils.id(host.getvCenterDataCenter())); VcenterRestRep vcenter = VCenterUtils.getVCenter(dataCenter); render(host, cluster, dataCenter, vcenter); } private static void addReferenceData() { renderArgs.put("types", StringOption.options(HostTypes.STANDARD_CREATION_TYPES, HostTypes.OPTION_PREFIX, false)); renderArgs.put("clusters", ClusterUtils.getClusterOptions(Models.currentTenant())); List<ProjectRestRep> projects = getViprClient().projects().getByTenant(ResourceUtils.uri(Models.currentTenant())); renderArgs.put("projects", projects); } public static void create() { addReferenceData(); HostForm host = new HostForm(); host.tenantId = Models.currentAdminTenant(); render("@edit", host); } @FlashException("list") public static void edit(String id) { HostRestRep dbHost = HostUtils.getHost(uri(id)); if (dbHost != null) { addReferenceData(); HostForm host = new HostForm(dbHost); List<InitiatorRestRep> initiators = HostUtils.getInitiators(dbHost.getId()); List<IpInterfaceRestRep> ipInterfaces = HostUtils.getIpInterfaces(dbHost.getId()); render(host, dbHost, initiators, ipInterfaces); } else { flash.error(MessagesUtils.get(UNKNOWN, id)); list(); } } private static void edit(HostForm host) { // Clear password/confirm before flashing params params.remove("host.password"); params.remove("host.passwordConfirm"); Common.handleError(); } public static void save(HostForm host) { host.validate("host"); if (Validation.hasErrors()) { edit(host); } try { Boolean validateConnectionParam = params.get("validateConnection", Boolean.class); boolean validateConnection = validateConnectionParam != null ? validateConnectionParam.booleanValue() : false; host.save(validateConnection); flash.success(MessagesUtils.get(SAVED, host.name)); list(); } catch (Exception e) { flashException(e); edit(host); } } @FlashException("list") public static void delete(@As(",") String[] ids, boolean detachStorage) { for (URI id : ResourceUtils.uris(ids)) { HostUtils.deactivate(id, detachStorage); } flash.success(MessagesUtils.get(DELETED)); list(); } @FlashException("list") public static void discoverArrayAffinity(@As(",") String[] ids) { ArrayAffinityHostParam param = new ArrayAffinityHostParam(uris(ids)); HostUtils.discoverHostArrayAffinity(param); flash.success(MessagesUtils.get(DISCOVER_ARRAY_AFFINITY)); list(); } public static void introspect(@As(",") String[] ids) { introspect(uris(ids)); } private static void introspect(List<URI> ids) { performSuccess(ids, new DiscoveryOperation(), DISCOVERY_STARTED); list(); } protected static class DiscoveryOperation implements ResourceIdOperation<Task<HostRestRep>> { @Override public Task<HostRestRep> performOperation(URI id) throws Exception { return HostUtils.discover(id); } } public static class HostForm { public String id; public String tenantId; @Required @MaxSize(128) @MinSize(2) public String name; @Required @HostNameOrIpAddress public String hostname; @Required @Min(1) public Integer port; @Required public String type; @MaxSize(1024) public String username; @MaxSize(1024) public String password; public String passwordConfirm; public boolean discoverable = true; public boolean useHttps; public HostForm() { } public HostForm(HostRestRep host) { this(); doReadFrom(host); } protected void doReadFrom(HostRestRep host) { this.id = host.getId().toString(); this.name = host.getName(); this.hostname = host.getHostName(); this.type = host.getType(); if (!isManualHost()) { this.username = host.getUsername(); if (host.getPortNumber() != null && host.getPortNumber() > -1) { this.port = host.getPortNumber(); } } this.discoverable = host.getDiscoverable() == null ? true : host.getDiscoverable(); this.useHttps = host.getUseSsl() == null ? true : host.getUseSsl(); } protected void doWriteTo(HostCreateParam hostCreateParam) { doWriteToHostParam(hostCreateParam); hostCreateParam.setType(this.type.toString()); hostCreateParam.setHostName(this.hostname); hostCreateParam.setCluster(ResourceUtils.NULL_URI); } protected void doWriteTo(HostUpdateParam hostUpdateParam) { doWriteToHostParam(hostUpdateParam); hostUpdateParam.setType(this.type.toString()); hostUpdateParam.setHostName(this.hostname); } protected void doWriteToHostParam(HostParam hostParam) { hostParam.setName(this.name); hostParam.setTenant(uri(tenantId)); if (isManualHost()) { hostParam.setUserName(Messages.get("Hosts.defaultUsername")); hostParam.setPassword(Messages.get("Hosts.defaultPassword")); hostParam.setUseSsl(false); hostParam.setDiscoverable(false); } else { if (StringUtils.isNotBlank(this.username)) { hostParam.setUserName(this.username); } if (StringUtils.isNotBlank(this.password)) { hostParam.setPassword(this.password); } hostParam.setPortNumber(this.port); hostParam.setUseSsl(this.useHttps); hostParam.setDiscoverable(this.discoverable); } } private boolean isManualHost() { return HostTypes.isOther(this.type) || HostTypes.isSUNVCS(this.type); } public void validate(String formName) { Validation.valid(formName, this); doValidation(formName); } protected void doValidation(String formName) { if (isManualHost()) { validateManualHost(formName); } else { validateStandardHost(formName); } } protected void validateStandardHost(String formName) { if (discoverable) { Validation.required(String.format("%s.username", formName), this.username); if (this.isNew()) { Validation.required(String.format("%s.password", formName), this.password); } boolean hasPassword = StringUtils.isNotBlank(password) || StringUtils.isNotBlank(passwordConfirm); boolean passwordMatches = StringUtils.equals(password, passwordConfirm); if (hasPassword && !passwordMatches) { Validation.addError(String.format("%s.passwordConfirm", formName), "error.password.doNotMatch"); } } } /** * Clears all other validation error, except for the specified fields. * * @param formName * the form name. * @param fieldsToKeep * the fields to keep. */ protected void clearOtherErrors(String formName, String... fieldsToKeep) { Set<play.data.validation.Error> errors = Sets.newHashSet(); for (String name : fieldsToKeep) { play.data.validation.Error error = Validation.error(String.format("%s.%s", formName, name)); if (error != null) { errors.add(error); } } Validation.clear(); for (play.data.validation.Error error : errors) { Validation.addError(error.getKey(), error.message()); } } protected void validateManualHost(String formName) { clearOtherErrors(formName, "name", "hostname"); } public void save(boolean validateConnection) { if (isNew()) { createHost(validateConnection); } else { updateHost(validateConnection); } } protected Task<HostRestRep> createHost(boolean validateConnection) { HostCreateParam hostCreateParam = new HostCreateParam(); doWriteTo(hostCreateParam); return HostUtils.createHost(hostCreateParam, validateConnection); } protected Task<HostRestRep> updateHost(boolean validateConnection) { HostUpdateParam hostUpdateParam = new HostUpdateParam(); doWriteTo(hostUpdateParam); return HostUtils.updateHost(uri(id), hostUpdateParam, validateConnection); } public boolean isNew() { return StringUtils.isBlank(id); } } }