/*
* Copyright (c) 2013 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.api.service.impl.resource;
import static com.emc.storageos.api.mapper.DbObjectMapper.map;
import static com.emc.storageos.api.mapper.DbObjectMapper.toRelatedResource;
import static com.emc.storageos.api.mapper.HostMapper.map;
import static com.emc.storageos.api.mapper.TaskMapper.toTask;
import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.emc.storageos.api.mapper.functions.MapCluster;
import com.emc.storageos.api.service.authorization.PermissionsHelper;
import com.emc.storageos.api.service.impl.resource.utils.VolumeIngestionUtil;
import com.emc.storageos.api.service.impl.response.BulkList;
import com.emc.storageos.api.service.impl.response.ResRepFilter;
import com.emc.storageos.computesystemcontroller.ComputeSystemController;
import com.emc.storageos.computesystemcontroller.impl.ComputeSystemHelper;
import com.emc.storageos.computesystemcontroller.impl.adapter.VcenterDiscoveryAdapter;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.URIUtil;
import com.emc.storageos.db.client.constraint.AlternateIdConstraint;
import com.emc.storageos.db.client.constraint.ContainmentConstraint;
import com.emc.storageos.db.client.constraint.NamedElementQueryResultList;
import com.emc.storageos.db.client.model.Cluster;
import com.emc.storageos.db.client.model.DataObject;
import com.emc.storageos.db.client.model.ExportGroup;
import com.emc.storageos.db.client.model.Host;
import com.emc.storageos.db.client.model.Operation;
import com.emc.storageos.db.client.model.Project;
import com.emc.storageos.db.client.model.Task;
import com.emc.storageos.db.client.model.TenantOrg;
import com.emc.storageos.db.client.model.Vcenter;
import com.emc.storageos.db.client.model.VcenterDataCenter;
import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedExportMask;
import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedVolume;
import com.emc.storageos.db.client.model.util.TaskUtils;
import com.emc.storageos.db.client.util.CustomQueryUtility;
import com.emc.storageos.db.client.util.NullColumnValueGetter;
import com.emc.storageos.db.exceptions.DatabaseException;
import com.emc.storageos.model.BulkIdParam;
import com.emc.storageos.model.NamedRelatedResourceRep;
import com.emc.storageos.model.RelatedResourceRep;
import com.emc.storageos.model.ResourceOperationTypeEnum;
import com.emc.storageos.model.ResourceTypeEnum;
import com.emc.storageos.model.TaskResourceRep;
import com.emc.storageos.model.block.UnManagedExportMaskList;
import com.emc.storageos.model.block.UnManagedVolumeList;
import com.emc.storageos.model.host.HostList;
import com.emc.storageos.model.host.cluster.ClusterBulkRep;
import com.emc.storageos.model.host.cluster.ClusterParam;
import com.emc.storageos.model.host.cluster.ClusterRestRep;
import com.emc.storageos.model.host.cluster.ClusterUpdateParam;
import com.emc.storageos.security.authentication.StorageOSUser;
import com.emc.storageos.security.authorization.ACL;
import com.emc.storageos.security.authorization.CheckPermission;
import com.emc.storageos.security.authorization.DefaultPermissions;
import com.emc.storageos.security.authorization.Role;
import com.emc.storageos.services.OperationTypeEnum;
import com.emc.storageos.svcs.errorhandling.resources.APIException;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import com.iwave.ext.vmware.VCenterAPI;
import com.vmware.vim25.mo.ClusterComputeResource;
import com.vmware.vim25.mo.HostSystem;
/**
* A service that provides APIs for viewing, updating and deleting clusters.
*
*/
@DefaultPermissions(readRoles = { Role.TENANT_ADMIN, Role.SYSTEM_MONITOR, Role.SYSTEM_ADMIN },
writeRoles = { Role.TENANT_ADMIN },
readAcls = { ACL.ANY })
@Path("/compute/clusters")
public class ClusterService extends TaskResourceService {
// Logger
protected final static Logger _log = LoggerFactory.getLogger(ClusterService.class);
private static final String EVENT_SERVICE_TYPE = "cluster";
@Override
public String getServiceType() {
return EVENT_SERVICE_TYPE;
}
@Autowired
private HostService _hostService;
/**
* Updates one or more of the cluster attributes.
*
* @param id the URN of a ViPR cluster
* @param updateParam the parameter that has the attributes to be
* updated.
* @prereq none
* @brief Update cluster attributes
* @return the representation of the updated cluster.
*/
@PUT
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.TENANT_ADMIN })
@Path("/{id}")
public ClusterRestRep updateCluster(@PathParam("id") URI id,
ClusterUpdateParam updateParam,
@DefaultValue("true") @QueryParam("update-exports") boolean updateExports) {
// update the cluster
Cluster cluster = queryObject(Cluster.class, id, true);
validateClusterData(updateParam, cluster.getTenant(), cluster, _dbClient);
populateCluster(updateParam, cluster);
_dbClient.persistObject(cluster);
if (!Strings.isNullOrEmpty(updateParam.findName())) {
ComputeSystemHelper.updateInitiatorClusterName(_dbClient, cluster.getId());
}
auditOp(OperationTypeEnum.UPDATE_CLUSTER, true, null,
cluster.auditParameters());
return map(queryObject(Cluster.class, id, false));
}
/**
* Validates the input parameter for create and update cluster.
*
* @param param the input parameter
* @param cluster the cluster to be updated. This should be null for create validation.
* @param tid the parent tenant Id
* @param dbClient and instance of {@link DbClient}
*/
protected void validateClusterData(ClusterParam param, URI tenanUri,
Cluster cluster, DbClient dbClient) {
// validate the project is present and active
if (!NullColumnValueGetter.isNullURI(param.getProject())) {
Project project = queryObject(Project.class, param.getProject(), true);
if (!project.getTenantOrg().getURI().equals(tenanUri)) {
throw APIException.badRequests.resourcedoesNotBelongToClusterTenantOrg("project");
}
}
// make sure the cluster is unique for the tenant
if (cluster == null || (param.findName() != null && !cluster.getLabel().equals(param.findName()))) {
checkDuplicateChildName(tenanUri, Cluster.class, "label",
"tenant", param.findName(), dbClient);
}
// when the cluster is in a vcenter data center, validate the data center
if (!NullColumnValueGetter.isNullURI(param.getVcenterDataCenter())) {
VcenterDataCenter dataCenter = queryObject(VcenterDataCenter.class, param.getVcenterDataCenter(),
true);
if (!dataCenter.getTenant().equals(tenanUri)) {
throw APIException.badRequests.resourcedoesNotBelongToClusterTenantOrg("data center");
}
}
// if the cluster project is being modified, check for active exports
if (cluster != null && !areEqual(cluster.getProject(), param.getProject())) {
if (isClusterInUse(cluster)) {
throw APIException.badRequests.clusterProjectChangeNotAllowed(cluster.getLabel());
}
}
}
/**
* Checks if the cluster has one or more of its hosts in use
*
* @param cluster the cluster to be checked
* @return true if one or more of the cluster hosts is in use
* @see HostService#isHostInUse(URI)
*/
private boolean isClusterInUse(Cluster cluster) {
List<Host> hosts =
CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, Host.class,
ContainmentConstraint.Factory.getContainedObjectsConstraint(cluster.getId(), Host.class, "cluster"));
for (Host host : hosts) {
if (ComputeSystemHelper.isHostInUse(_dbClient, host.getId())) {
return true;
}
}
return false;
}
/**
* Updates export groups that are referenced by the given cluster by removing the cluster
* reference and initiators belonging to hosts in this cluster. Volumes are left intact.
*
* @param id the URN of a ViPR Cluster
* @brief Detach storage from Cluster
* @return OK if detaching completed successfully
* @throws DatabaseException when a DB error occurs
*/
@POST
@Path("/{id}/detach-storage")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.TENANT_ADMIN })
public TaskResourceRep detachStorage(@PathParam("id") URI id) throws DatabaseException {
Cluster cluster = queryObject(Cluster.class, id, true);
String taskId = UUID.randomUUID().toString();
Operation op = _dbClient.createTaskOpStatus(Cluster.class, id, taskId,
ResourceOperationTypeEnum.DETACH_VCENTER_DATACENTER_STORAGE);
ComputeSystemController controller = getController(ComputeSystemController.class, null);
controller.detachClusterStorage(cluster.getId(), false, true, taskId);
return toTask(cluster, taskId, op);
}
/**
* Checks if the cluster has any export
*
* @param cluster the cluster to be checked
* @return true if one or more of the cluster hosts is in use
*/
private boolean isClusterInExport(Cluster cluster) {
List<ExportGroup> exportGroups = CustomQueryUtility.queryActiveResourcesByConstraint(
_dbClient, ExportGroup.class,
AlternateIdConstraint.Factory.getConstraint(
ExportGroup.class, "clusters", cluster.getId().toString()));
return !exportGroups.isEmpty();
}
/**
* Shows the information for one cluster.
*
* @param id the URN of a ViPR cluster
* @prereq none
* @brief Show cluster
* @return All the non-null attributes of the cluster.
* @throws DatabaseException when a DB error occurs.
*/
@GET
@Path("/{id}")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public ClusterRestRep getCluster(@PathParam("id") URI id) throws DatabaseException {
Cluster cluster = queryObject(Cluster.class, id, false);
// check the user permissions
verifyAuthorizedInTenantOrg(cluster.getTenant(), getUserFromContext());
return map(cluster);
}
/**
* List the hosts of a cluster.
*
* @param id the URN of a ViPR cluster
* @prereq none
* @brief List cluster hosts
* @return The list of hosts of the cluster.
* @throws DatabaseException when a DB error occurs.
*/
@GET
@Path("/{id}/hosts")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public HostList getClusterHosts(@PathParam("id") URI id) throws DatabaseException {
Cluster cluster = queryObject(Cluster.class, id, true);
// check the user permissions
verifyAuthorizedInTenantOrg(cluster.getTenant(), getUserFromContext());
HostList list = new HostList();
list.setHosts(map(ResourceTypeEnum.HOST, listChildren(id, Host.class, "label", "cluster")));
return list;
}
/**
* Deactivates the cluster and removes reference from its hosts. By passing in true for detachStorage,
* any associated storage with the cluster can be detached.
*
* @param id the URN of a ViPR cluster to be deactivated
* @prereq The cluster hosts must not have block or file exports if it is to be deleted without detaching storage
* @brief Delete cluster.
* @return OK if deactivation completed successfully
* @throws DatabaseException when a DB error occurs
*/
@POST
@Path("/{id}/deactivate")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.TENANT_ADMIN })
public TaskResourceRep deactivateCluster(@PathParam("id") URI id,
@DefaultValue("false") @QueryParam("detach-storage") boolean detachStorage,
@DefaultValue("true") @QueryParam("check-vms") boolean checkVms) throws DatabaseException {
Cluster cluster = queryObject(Cluster.class, id, true);
if (ComputeSystemHelper.isClusterInExport(_dbClient, cluster.getId()) && !detachStorage) {
throw APIException.badRequests.resourceHasActiveReferences(Cluster.class.getSimpleName(), id);
} else if (resourceHasPendingTasks(id)) {
throw APIException.badRequests
.resourceCannotBeDeleted("Cluster has another operation in progress. " + cluster.getLabel());
} else {
List<URI> clusterHosts = ComputeSystemHelper.getChildrenUris(_dbClient, id, Host.class, "cluster");
List<Host> hosts = _dbClient.queryObject(Host.class, clusterHosts);
if (null != hosts && !hosts.isEmpty()) {
for (Host host : hosts) {
if (null != host && resourceHasPendingTasks(host.getId())) {
// throw exception and do not proceed with
// cluster delete...
throw APIException.badRequests.resourceCannotBeDeleted(
"Cluster has host - "+ host.getLabel() +" with another operation in progress. " + cluster.getLabel());
}
}
}
validateVcenterClusterHosts(cluster);
String taskId = UUID.randomUUID().toString();
Operation op = _dbClient.createTaskOpStatus(Cluster.class, id, taskId,
ResourceOperationTypeEnum.DELETE_CLUSTER);
ComputeSystemController controller = getController(ComputeSystemController.class, null);
// VBDU [DONE]: COP-28449, Cross verify checkVMs is always passed as TRUE. We can explicitly make this true
// always in the code.
controller.detachClusterStorage(id, true, true, taskId);
auditOp(OperationTypeEnum.DELETE_CLUSTER, true, op.getStatus(),
cluster.auditParameters());
return toTask(cluster, taskId, op);
}
}
/**
* Updates the shared export groups of the give cluster [Deprecated]
*
* @param id the URN of a ViPR cluster
*
* @return the representation of the updated cluster.
*/
@POST
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.TENANT_ADMIN })
@Path("/{id}/update-shared-exports")
@Deprecated
public TaskResourceRep updateClusterSharedExports(@PathParam("id") URI id) {
// This call is immediately deprecated. It only served the UI, so nobody externally should be using it.
// In case someone is, they should move over to update hosts like the UI has.
throw APIException.badRequests.deprecatedRestCall("POST /compute/clusters/{cluster-id}/update-shared-exports",
"PUT /compute/hosts/{host-id}");
}
/**
* List data for the specified clusters.
*
* @param param
* POST data containing the id list.
* @prereq none
* @brief List data of specified clusters
* @return list of representations.
*
* @throws DatabaseException
* When an error occurs querying the database.
*/
@POST
@Path("/bulk")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Override
public ClusterBulkRep getBulkResources(BulkIdParam param) {
return (ClusterBulkRep) super.getBulkResources(param);
}
/**
* Creates an instance of host cluster for the provided parameter
*
* @param tenant the tenant organization to which the cluster belongs
* @param param the parameter that contains the cluster properties and attributes.
* @return an instance of {@link Host}
*/
protected Cluster createNewCluster(TenantOrg tenant, ClusterParam param) {
Cluster cluster = new Cluster();
cluster.setId(URIUtil.createId(Cluster.class));
cluster.setTenant(tenant.getId());
populateCluster(param, cluster);
return cluster;
}
private void populateCluster(ClusterParam param, Cluster cluster) {
String clusterName = param.findName();
if (!Strings.isNullOrEmpty(clusterName)) {
cluster.setLabel(clusterName);
}
if (param.getVcenterDataCenter() != null) {
cluster.setVcenterDataCenter(NullColumnValueGetter.isNullURI(param.getVcenterDataCenter()) ?
NullColumnValueGetter.getNullURI() : param.getVcenterDataCenter());
}
if (param.getAutoExportEnabled() != null) {
cluster.setAutoExportEnabled(param.getAutoExportEnabled());
}
// Commented out because cluster project is not currently used
// if (param.project != null) {
// cluster.setProject(NullColumnValueGetter.isNullURI(param.project) ?
// NullColumnValueGetter.getNullURI() : param.project);
// }
}
@Override
protected DataObject queryResource(URI id) {
return queryObject(Cluster.class, id, false);
}
@Override
protected URI getTenantOwner(URI id) {
Cluster cluster = queryObject(Cluster.class, id, false);
return cluster.getTenant();
}
@Override
protected ResourceTypeEnum getResourceType() {
return ResourceTypeEnum.CLUSTER;
}
@SuppressWarnings("unchecked")
@Override
public Class<Cluster> getResourceClass() {
return Cluster.class;
}
@Override
public ClusterBulkRep queryBulkResourceReps(List<URI> ids) {
Iterator<Cluster> _dbIterator =
_dbClient.queryIterativeObjects(getResourceClass(), ids);
return new ClusterBulkRep(BulkList.wrapping(_dbIterator, MapCluster.getInstance()));
}
@Override
public ClusterBulkRep queryFilteredBulkResourceReps(List<URI> ids) {
Iterator<Cluster> _dbIterator =
_dbClient.queryIterativeObjects(getResourceClass(), ids);
BulkList.ResourceFilter filter = new BulkList.ClusterFilter(getUserFromContext(), _permissionsHelper);
return new ClusterBulkRep(BulkList.wrapping(_dbIterator, MapCluster.getInstance(), filter));
}
@Override
protected boolean isZoneLevelResource() {
return false;
}
@Override
protected boolean isSysAdminReadableResource() {
return true;
}
public static class ClusterResRepFilter<E extends RelatedResourceRep>
extends ResRepFilter<E> {
public ClusterResRepFilter(StorageOSUser user,
PermissionsHelper permissionsHelper) {
super(user, permissionsHelper);
}
@Override
public boolean isAccessible(E resrep) {
boolean ret = false;
URI id = resrep.getId();
Cluster obj = _permissionsHelper.getObjectById(id, Cluster.class);
if (obj == null) {
return false;
}
if (obj.getTenant().toString().equals(_user.getTenantId())) {
return true;
}
ret = isTenantAccessible(obj.getTenant());
return ret;
}
}
/**
* Get object specific permissions filter
*/
@Override
public ResRepFilter<? extends RelatedResourceRep> getPermissionFilter(StorageOSUser user,
PermissionsHelper permissionsHelper)
{
return new ClusterResRepFilter(user, permissionsHelper);
}
/**
* Gets the UnManagedVolumes exposed to a Cluster.
*
* @param id the URI of a ViPR Cluster
* @return a list of UnManagedVolumes exposed to this host
* @throws DatabaseException when a database error occurs
*/
@GET
@Path("/{id}/unmanaged-volumes")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public UnManagedVolumeList getUnmanagedVolumes(@PathParam("id") URI id) throws DatabaseException {
Cluster cluster = queryObject(Cluster.class, id, false);
// check the user permissions
verifyAuthorizedInTenantOrg(cluster.getTenant(), getUserFromContext());
// get the unmanaged volumes
List<UnManagedVolume> unmanagedVolumes = VolumeIngestionUtil.findUnManagedVolumesForCluster(id, _dbClient);
UnManagedVolumeList list = new UnManagedVolumeList();
for (UnManagedVolume volume : unmanagedVolumes) {
list.getUnManagedVolumes()
.add(toRelatedResource(ResourceTypeEnum.UNMANAGED_VOLUMES, volume.getId()));
}
return list;
}
/**
* Gets the UnManagedExportMasks found for a Cluster.
*
* @param id the URI of a ViPR Cluster
* @return a list of UnManagedExportMasks found for the Cluster
* @throws DatabaseException when a database error occurs
*/
@GET
@Path("/{id}/unmanaged-export-masks")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public UnManagedExportMaskList getUnmanagedExportMasks(@PathParam("id") URI id) throws DatabaseException {
Cluster cluster = queryObject(Cluster.class, id, false);
// check the user permissions
verifyAuthorizedInTenantOrg(cluster.getTenant(), getUserFromContext());
// get the unmanaged export masks
List<UnManagedExportMask> uems = VolumeIngestionUtil.findUnManagedExportMasksForCluster(id, _dbClient);
UnManagedExportMaskList list = new UnManagedExportMaskList();
for (UnManagedExportMask uem : uems) {
list.getUnManagedExportMasks()
.add(toRelatedResource(ResourceTypeEnum.UNMANAGED_EXPORT_MASKS, uem.getId()));
}
return list;
}
/**
* Verify if the given resource has pending/running tasks associated.
* @param id URI of resource to check for task
*
* @return true if resource has tasks running/pending else false.
*/
private boolean resourceHasPendingTasks(URI id) {
boolean hasPendingTasks = false;
List<Task> taskList = TaskUtils.findResourceTasks(_dbClient, id);
for (Task task : taskList) {
if (!task.getInactive() && task.isPending()) {
hasPendingTasks = true;
break;
}
}
return hasPendingTasks;
}
/**
* List the vblock hosts of a cluster.
*
* @param id the URN of a ViPR cluster
*
* @return The list of vblock hosts in the cluster.
* @throws DatabaseException when a DB error occurs.
*/
@GET
@Path("/{id}/vblock-hosts")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public HostList getClusterVblockHosts(@PathParam("id") URI id) throws DatabaseException {
Cluster cluster = queryObject(Cluster.class, id, true);
// check the user permissions
verifyAuthorizedInTenantOrg(cluster.getTenant(), getUserFromContext());
HostList list = new HostList();
list.setHosts(map(ResourceTypeEnum.HOST, getVblockHostsFromCluster(id)));
return list;
}
/**
* This function is to retrieve the children of a given class.
*
* @param id the URN of parent
* @param clzz the child class
* @param nameField the name of the field of the child class that will be displayed as
* name in {@link NamedRelatedResourceRep}. Note this field should be a required
* field because, objects for which this field is null will not be returned by
* this function.
*
* @return a list of children of tenant for the given class
*/
private <T extends DataObject> List<NamedElementQueryResultList.NamedElement> getVblockHostsFromCluster(URI id) {
List<Host> hosts = CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, Host.class,
ContainmentConstraint.Factory.getContainedObjectsConstraint(id, Host.class, "cluster"));
if (hosts != null && !hosts.isEmpty()) {
List<NamedElementQueryResultList.NamedElement> elements = new ArrayList<NamedElementQueryResultList.NamedElement>(
hosts.size());
for (Host host : hosts) {
if (!NullColumnValueGetter.isNullURI(host.getComputeElement()) || !NullColumnValueGetter.isNullURI(host.getServiceProfile())) {
elements.add(NamedElementQueryResultList.NamedElement.createElement(
host.getId(), host.getLabel() == null ? "" : host.getLabel()));
}
}
return elements;
} else {
return new ArrayList<NamedElementQueryResultList.NamedElement>();
}
}
/**
* Validate that the hosts in the cluster in our database matches the vCenter environment
*
* @param cluster the cluster to check
*/
public void validateVcenterClusterHosts(Cluster cluster) {
if (null == cluster) {
_log.error("Validation cluster is not set, not performing vCenter cluster validation");
return;
}
// We can only proceed if this cluster belongs to a datacenter
if (NullColumnValueGetter.isNullURI(cluster.getVcenterDataCenter())) {
_log.info("Cluster is not synced to vcenter");
return;
}
// Get a list of the cluster's hosts that are in our database.
List<URI> clusterHosts = ComputeSystemHelper.getChildrenUris(_dbClient, cluster.getId(), Host.class, "cluster");
VcenterDataCenter vcenterDataCenter = _dbClient.queryObject(VcenterDataCenter.class,
cluster.getVcenterDataCenter());
// If the datacenter is not in our database, we must fail the validation.
if (vcenterDataCenter == null) {
throw APIException.badRequests.vCenterDataCenterNotFound(cluster.getVcenterDataCenter());
}
// If the datacenter has a null vCenter reference, we must fail the validation.
if (NullColumnValueGetter.isNullURI(vcenterDataCenter.getVcenter())) {
throw APIException.badRequests.vCenterDataCenterHasNullVcenter(vcenterDataCenter.forDisplay());
}
Vcenter vcenter = _dbClient.queryObject(Vcenter.class,
vcenterDataCenter.getVcenter());
// If the vCenter is not in our database, we must fail the validation.
if (vcenter == null) {
throw APIException.badRequests.vCenterNotFound(vcenterDataCenter.getVcenter());
}
List<Host> dbHosts = _dbClient.queryObject(Host.class, clusterHosts);
VCenterAPI api = VcenterDiscoveryAdapter.createVCenterAPI(vcenter);
try {
// Query the vCenter to get a reference to the cluster so that we can compare the hosts between the actual
// environment and our database representation of the cluster.
ClusterComputeResource vcenterCluster = api.findCluster(vcenterDataCenter.getLabel(), cluster.getLabel());
// If we can't find the cluster on the vCenter environment, we can not proceed with validation.
// The cluster may not have been pushed to vCenter yet.
if (vcenterCluster == null) {
_log.info("Unable to find cluster %s in datacenter %s in vCenter environment %s", cluster.getLabel(),
vcenterDataCenter.getLabel(), vcenter.getLabel());
return;
}
// Gather a set of all the host UUIDs in this vCenter cluster.
Set<String> vCenterHostUuids = Sets.newHashSet();
for (HostSystem hostSystem : vcenterCluster.getHosts()) {
if (hostSystem != null && hostSystem.getHardware() != null && hostSystem.getHardware().systemInfo != null) {
vCenterHostUuids.add(hostSystem.getHardware().systemInfo.uuid);
}
}
// Gather a set of all the host UUIDs in our database.
Set<String> dbHostUuids = Sets.newHashSet();
for (Host host : dbHosts) {
dbHostUuids.add(host.getUuid());
}
// If there are hosts in vCenter that are not in our database, fail the validation
if (!dbHostUuids.containsAll(vCenterHostUuids)) {
throw APIException.badRequests.clusterHostMismatch(cluster.forDisplay());
}
} finally {
if (api != null) {
api.logout();
}
}
}
}