/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.computesystemcontroller.impl; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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.constraint.NamedElementQueryResultList.NamedElement; import com.emc.storageos.db.client.constraint.URIQueryResultList; import com.emc.storageos.db.client.model.BlockObject; import com.emc.storageos.db.client.model.Cluster; import com.emc.storageos.db.client.model.DataObject; import com.emc.storageos.db.client.model.DiscoveredDataObject; import com.emc.storageos.db.client.model.DiscoveredDataObject.RegistrationStatus; import com.emc.storageos.db.client.model.ExportGroup; import com.emc.storageos.db.client.model.FileExport; import com.emc.storageos.db.client.model.FileShare; import com.emc.storageos.db.client.model.Host; import com.emc.storageos.db.client.model.Initiator; import com.emc.storageos.db.client.model.IpInterface; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.model.StringMap; import com.emc.storageos.db.client.model.Vcenter; import com.emc.storageos.db.client.model.VcenterDataCenter; import com.emc.storageos.db.client.model.util.EventUtils; import com.emc.storageos.db.client.util.CustomQueryUtility; import com.emc.storageos.db.client.util.DataObjectUtils; import com.emc.storageos.db.client.util.NullColumnValueGetter; import com.emc.storageos.model.NamedRelatedResourceRep; import com.emc.storageos.svcs.errorhandling.resources.APIException; import com.emc.storageos.util.ConnectivityUtil; import com.emc.storageos.util.ExportUtils; import com.emc.storageos.volumecontroller.placement.PlacementException; import com.google.common.base.Joiner; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.vmware.vim25.DatastoreSummary; import com.vmware.vim25.DatastoreSummaryMaintenanceModeState; import com.vmware.vim25.HostService; import com.vmware.vim25.mo.Datastore; import com.vmware.vim25.mo.HostSystem; import com.vmware.vim25.mo.VirtualMachine; public class ComputeSystemHelper { private static final Logger _log = LoggerFactory.getLogger(ComputeSystemHelper.class); /** * 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. * @param linkField the name of the field in the child class that stored the parent id * @return a list of children of tenant for the given class */ protected static <T extends DataObject> List<NamedElementQueryResultList.NamedElement> listChildren(DbClient dbClient, URI id, Class<T> clzz, String nameField, String linkField) { @SuppressWarnings("deprecation") List<URI> uris = dbClient.queryByConstraint( ContainmentConstraint.Factory.getContainedObjectsConstraint(id, clzz, linkField)); if (uris != null && !uris.isEmpty()) { Iterator<T> dataObjects = dbClient.queryIterativeObjectField(clzz, nameField, uris); List<NamedElementQueryResultList.NamedElement> elements = new ArrayList<NamedElementQueryResultList.NamedElement>(); while (dataObjects.hasNext()) { T dataObject = dataObjects.next(); Object name = DataObjectUtils.getPropertyValue(clzz, dataObject, nameField); elements.add(NamedElementQueryResultList.NamedElement.createElement( dataObject.getId(), name == null ? "" : name.toString())); } return elements; } else { return new ArrayList<NamedElementQueryResultList.NamedElement>(); } } /** * Utility function to recursively deactivate all the hosts interfaces * * @param host the host to deactivate */ public static void doDeactivateHost(DbClient dbClient, Host host) { List<IpInterface> hostInterfaces = queryIpInterfaces(dbClient, host.getId()); for (IpInterface hostInterface : hostInterfaces) { hostInterface.setRegistrationStatus(RegistrationStatus.UNREGISTERED.toString()); dbClient.markForDeletion(hostInterface); EventUtils.deleteResourceEvents(dbClient, hostInterface.getId()); } List<Initiator> initiators = queryInitiators(dbClient, host.getId()); for (Initiator initiator : initiators) { initiator.setRegistrationStatus(RegistrationStatus.UNREGISTERED.toString()); dbClient.markForDeletion(initiator); EventUtils.deleteResourceEvents(dbClient, initiator.getId()); } host.setRegistrationStatus(RegistrationStatus.UNREGISTERED.toString()); host.setProvisioningStatus(Host.ProvisioningJobStatus.COMPLETE.toString()); dbClient.persistObject(host); _log.info("marking host for deletion: {} {}", host.getLabel(), host.getId()); dbClient.markForDeletion(host); EventUtils.deleteResourceEvents(dbClient, host.getId()); } /** * Returns the Initiator of a host * * @param id the URN of a ViPR initiator * @return the Initiator of a host */ public static List<Initiator> queryInitiators(DbClient dbClient, URI id) { List<Initiator> initiators = new ArrayList<Initiator>(); URIQueryResultList initiatorUris = new URIQueryResultList(); dbClient.queryByConstraint( ContainmentConstraint.Factory.getContainedObjectsConstraint(id, Initiator.class, "host"), initiatorUris); if (initiatorUris.iterator().hasNext()) { for (URI initiatorUri : initiatorUris) { Initiator initiator = dbClient.queryObject(Initiator.class, initiatorUri); if (initiators != null && !initiator.getInactive()) { initiators.add(initiator); } } } return initiators; } /** * Utility function to recursively deactivate all the hosts / clusters from datacenter * * @param host the host to deactivate */ public static void doDeactivateVcenterDataCenter(DbClient dbClient, VcenterDataCenter dataCenter) { List<NamedElementQueryResultList.NamedElement> hostUris = listChildren(dbClient, dataCenter.getId(), Host.class, "label", "vcenterDataCenter"); Set<URI> doNotDeleteclusters = new HashSet<URI>(); for (NamedElementQueryResultList.NamedElement hostUri : hostUris) { Host host = dbClient.queryObject(Host.class, hostUri.getId()); if (host != null && !host.getInactive()) { if (NullColumnValueGetter.isNullURI(host.getComputeElement())) { doDeactivateHost(dbClient, host); } else { // do not delete hosts that have compute elements, simply break DC link host.setVcenterDataCenter(NullColumnValueGetter.getNullURI()); dbClient.persistObject(host); if (!NullColumnValueGetter.isNullURI(host.getCluster())) { doNotDeleteclusters.add(host.getCluster()); } } } } List<NamedElementQueryResultList.NamedElement> clustersUris = listChildren(dbClient, dataCenter.getId(), Cluster.class, "label", "vcenterDataCenter"); for (NamedElementQueryResultList.NamedElement clusterUri : clustersUris) { Cluster cluster = dbClient.queryObject(Cluster.class, clusterUri.getId()); if (cluster != null && !cluster.getInactive()) { if (doNotDeleteclusters.contains(cluster.getId())) { // do not delete clusters if hosts are not deleted, simply break DC link cluster.setVcenterDataCenter(NullColumnValueGetter.getNullURI()); cluster.setExternalId(NullColumnValueGetter.getNullStr()); dbClient.persistObject(cluster); } else { dbClient.markForDeletion(cluster); EventUtils.deleteResourceEvents(dbClient, cluster.getId()); } } } _log.info("marking DC for deletion: {} {}", dataCenter.getLabel(), dataCenter.getId()); dbClient.markForDeletion(dataCenter); EventUtils.deleteResourceEvents(dbClient, dataCenter.getId()); } /** * Utility function to dissociate a host and its initiator from its cluster * * @param host the host to dissociate */ public static void removeClusterFromHost(DbClient dbClient, Host host) { List<Initiator> initiators = ComputeSystemHelper.queryInitiators(dbClient, host.getId()); for (Initiator initiator : initiators) { initiator.setClusterName(""); dbClient.persistObject(initiator); } host.setCluster(NullColumnValueGetter.getNullURI()); dbClient.persistObject(host); } /** * Utility function to recursively deactivate cluster * Removes all references to the cluster from host. * * @param cluster the cluster to deactivate */ public static void doDeactivateCluster(DbClient dbClient, Cluster cluster) { List<NamedElementQueryResultList.NamedElement> hostUris = listChildren(dbClient, cluster.getId(), Host.class, "label", "cluster"); for (NamedElementQueryResultList.NamedElement hostUri : hostUris) { Host host = dbClient.queryObject(Host.class, hostUri.getId()); if (host != null && !host.getInactive()) { removeClusterFromHost(dbClient, host); } } _log.info("marking cluster for deletion: {} {}", cluster.getLabel(), cluster.getId()); dbClient.markForDeletion(cluster); EventUtils.deleteResourceEvents(dbClient, cluster.getId()); } /** * Returns the IP interface of a given host after it validates that the IP interface * exists, and belongs to the parent host. * * @param hostId the parent host URI * @param initiatorId the initiator URI * @param checkInactive when set to true, the function will also validates * that the initiator is active. * @return the host initiator */ public static List<IpInterface> queryIpInterfaces(DbClient dbClient, URI id) { List<IpInterface> ipInterfaces = new ArrayList<IpInterface>(); URIQueryResultList ipInterfaceUris = new URIQueryResultList(); dbClient.queryByConstraint( ContainmentConstraint.Factory.getContainedObjectsConstraint(id, IpInterface.class, "host"), ipInterfaceUris); if (ipInterfaceUris.iterator().hasNext()) { for (URI ipInterfaceUri : ipInterfaceUris) { IpInterface ipInterface = dbClient.queryObject(IpInterface.class, ipInterfaceUri); if (ipInterface != null && !ipInterface.getInactive()) { ipInterfaces.add(ipInterface); } } } return ipInterfaces; } /** * Checks if the host has initiators in use by export groups or ip interfaces in use * by file exports. * * @param hostId the host to be checked * @return true if the host has has initiators in use by export groups or ip interfaces in use * by file exports. */ public static boolean isHostInUse(DbClient dbClient, URI hostId) { List<Initiator> initiators = CustomQueryUtility.queryActiveResourcesByConstraint(dbClient, Initiator.class, ContainmentConstraint.Factory.getContainedObjectsConstraint(hostId, Initiator.class, "host")); for (Initiator initiator : initiators) { if (isInitiatorInUse(dbClient, initiator.getId().toString())) { return true; } } List<String> ipEndpoints = getIpInterfaceEndpoints(dbClient, hostId); if (isHostIpInterfacesInUse(dbClient, ipEndpoints, hostId)) { return true; } return !findExportsByHost(dbClient, hostId.toString()).isEmpty(); } /** * 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 * @see HostService#isHostInUse(URI) */ public static boolean isClusterInExport(DbClient dbClient, URI cluster) { List<ExportGroup> exportGroups = CustomQueryUtility.queryActiveResourcesByConstraint( dbClient, ExportGroup.class, AlternateIdConstraint.Factory.getConstraint( ExportGroup.class, "clusters", cluster.toString())); return !exportGroups.isEmpty(); } /** * Checks if an initiator in use by an export groups * * @param iniId the initiator URI * @return true if the initiator in use by export groups */ public static boolean isInitiatorInUse(DbClient dbClient, String iniId) { List<ExportGroup> exportGroups = CustomQueryUtility.queryActiveResourcesByConstraint( dbClient, ExportGroup.class, AlternateIdConstraint.Factory.getConstraint( ExportGroup.class, "initiators", iniId)); return !exportGroups.isEmpty(); } /** * Checks if an vcenter is in use by an export groups * * @param dbClient * @param vcenterURI the vcenter URI * @return true if the vcenter is in used by an export group. */ public static boolean isVcenterInUse(DbClient dbClient, URI vcenterURI) { List<NamedElementQueryResultList.NamedElement> datacenterUris = listChildren(dbClient, vcenterURI, VcenterDataCenter.class, "label", "vcenter"); for (NamedElementQueryResultList.NamedElement datacenterUri : datacenterUris) { if (isDataCenterInUse(dbClient, datacenterUri.getId())) { return true; } } return false; } /** * Checks if an datacenter is in use by an export groups * * @param dbClient * @param datacenterURI the datacenter URI * @return true if the datacenter is in used by an export group. */ public static boolean isDataCenterInUse(DbClient dbClient, URI datacenterURI) { VcenterDataCenter dataCenter = dbClient.queryObject(VcenterDataCenter.class, datacenterURI); if (dataCenter != null && !dataCenter.getInactive()) { List<NamedElementQueryResultList.NamedElement> hostUris = listChildren(dbClient, dataCenter.getId(), Host.class, "label", "vcenterDataCenter"); for (NamedElementQueryResultList.NamedElement hostUri : hostUris) { Host host = dbClient.queryObject(Host.class, hostUri.getId()); // ignore provisioned hosts if (host != null && !host.getInactive() && NullColumnValueGetter.isNullURI(host.getComputeElement()) && isHostInUse(dbClient, host.getId())) { return true; } } List<NamedElementQueryResultList.NamedElement> clustersUris = listChildren(dbClient, dataCenter.getId(), Cluster.class, "label", "vcenterDataCenter"); for (NamedElementQueryResultList.NamedElement clusterUri : clustersUris) { Cluster cluster = dbClient.queryObject(Cluster.class, clusterUri.getId()); if (cluster != null && !cluster.getInactive() && isClusterInExport(dbClient, clusterUri.getId())) { return true; } } } return false; } /** * A utility function that return a list of ip endpoints for a given host. Used * to mre efficiently check for host ip interfaces in use. * * @param hostId the host URI * @return list of ip endpoints for a given host */ public static List<String> getIpInterfaceEndpoints(DbClient dbClient, URI hostId) { List<IpInterface> ipInterfaces = CustomQueryUtility.queryActiveResourcesByConstraint(dbClient, IpInterface.class, ContainmentConstraint.Factory.getContainedObjectsConstraint(hostId, IpInterface.class, "host")); List<String> endpoints = new ArrayList<String>(); for (IpInterface ipInterface : ipInterfaces) { endpoints.add(ipInterface.getIpAddress()); } return endpoints; } /** * Checks if an ipInterface in use by a file export * * @param ipAddress the interface IP address * @return true if the ipInterface in use by a file export */ public static boolean isHostIpInterfacesInUse(DbClient dbClient, List<String> endpoints, URI hostId) { if (endpoints == null || endpoints.isEmpty()) { return false; } Host host = dbClient.queryObject(Host.class, hostId); List<FileShare> fileShares = null; if (!NullColumnValueGetter.isNullURI(host.getProject())) { fileShares = CustomQueryUtility.queryActiveResourcesByRelation( dbClient, host.getProject(), FileShare.class, "project"); } else if (!NullColumnValueGetter.isNullURI(host.getTenant())){ fileShares = CustomQueryUtility.queryActiveResourcesByRelation( dbClient, host.getTenant(), FileShare.class, "tenant"); } if (fileShares == null || fileShares.isEmpty()) { return false; } for (FileShare fileShare : fileShares) { if (fileShare != null && fileShare.getFsExports() != null) { for (FileExport fileExport : fileShare.getFsExports().values()) { if (fileExport != null && fileExport.getClients() != null) { for (String endpoint : endpoints) { if (fileExport.getClients().contains(endpoint)) { return true; } } } } } } return false; } public static List<ExportGroup> findExportsByHost(DbClient dbClient, String id) { List<ExportGroup> exportGroups = CustomQueryUtility.queryActiveResourcesByConstraint( dbClient, ExportGroup.class, AlternateIdConstraint.Factory.getConstraint( ExportGroup.class, "hosts", id)); return exportGroups; } public static List<ExportGroup> findExportsByInitiator(DbClient dbClient, String id) { List<ExportGroup> exportGroups = CustomQueryUtility.queryActiveResourcesByConstraint( dbClient, ExportGroup.class, AlternateIdConstraint.Factory.getConstraint( ExportGroup.class, "initiators", id)); return exportGroups; } public static List<FileShare> getFileSharesByHost(DbClient dbClient, URI hostId) { Host host = dbClient.queryObject(Host.class, hostId); if (!NullColumnValueGetter.isNullURI(host.getProject())) { return CustomQueryUtility.queryActiveResourcesByRelation( dbClient, host.getProject(), FileShare.class, "project"); } else if (!NullColumnValueGetter.isNullURI(host.getTenant())) { return CustomQueryUtility.queryActiveResourcesByRelation( dbClient, host.getTenant(), FileShare.class, "tenant"); } return new ArrayList<FileShare>(); } /** * Check if initiators have connectivity to a storage port. * * @param dbClient -- DbClient for database access * @param exportGroup -- ExportGroup * @param initiators -- List of Initiator objects * @return validInitiators that have connectivity to the StorageSystem */ public static List<Initiator> validatePortConnectivity(DbClient dbClient, ExportGroup exportGroup, List<Initiator> initiators) { Map<URI, Map<URI, Integer>> storageMap = getStorageToVolumeMap( dbClient, exportGroup, false); List<Initiator> validInitiators = Lists.newArrayList(); // we want to make sure the initiator can access each storage for (URI storage : storageMap.keySet()) { StorageSystem storageSystem = dbClient.queryObject( StorageSystem.class, storage); List<URI> varrays = new ArrayList<URI>(); varrays.add(exportGroup.getVirtualArray()); // If VPLEX, we need to add the potential HA varrays if (storageSystem.getSystemType().equals(DiscoveredDataObject.Type.vplex.name())) { List<URI> haVarrays = ExportUtils.getVarraysForStorageSystemVolumes(exportGroup, storage, dbClient); varrays.addAll(haVarrays); } for (Initiator initiator : initiators) { // check the initiator has connectivity if (hasConnectivityToSystem(storageSystem, varrays, initiator, dbClient)) { validInitiators.add(initiator); } } } return validInitiators; } /** * Checks if an initiator has connectivity to a storage system in a varray. * * @param dbClient * @param storageSystem the storage system where connectivity is needed * @param List<URI> varrays for possible connectivity * @param initiator the initiator * @param dbClient -- The dbClient that should be used * @return true if at least one port is found */ private static boolean hasConnectivityToSystem(StorageSystem storageSystem, List<URI> varrays, Initiator initiator, DbClient dbClient) { try { return ConnectivityUtil.isInitiatorConnectedToStorageSystem(initiator, storageSystem, varrays, dbClient); } catch (PlacementException ex) { _log.info(String.format("Initiator %s (%s) has no connectivity to StorageSystem %s (%s) in varray %s", initiator.getInitiatorPort(), initiator.getId(), storageSystem.getNativeGuid(), storageSystem.getId(), varrays)); return false; } catch (Exception ex) { throw APIException.badRequests.errorVerifyingInitiatorConnectivity( initiator.toString(), storageSystem.getNativeGuid(), ex.getMessage()); } } private static Map<URI, Map<URI, Integer>> getStorageToVolumeMap(DbClient dbClient, ExportGroup exportGroup, boolean protection) { Map<URI, Map<URI, Integer>> map = new HashMap<URI, Map<URI, Integer>>(); StringMap volumes = exportGroup.getVolumes(); if (volumes == null) { return map; } for (String uriString : volumes.keySet()) { URI blockURI = URI.create(uriString); BlockObject block = BlockObject.fetch(dbClient, blockURI); // If this is an RP-based Block Snapshot, use the protection controller instead of the underlying block controller URI storage = (block.getProtectionController() != null && protection && block.getId().toString().contains("BlockSnapshot")) ? block.getProtectionController() : block.getStorageController(); if (map.get(storage) == null) { map.put(storage, new HashMap<URI, Integer>()); } map.get(storage).put(blockURI, Integer.valueOf(volumes.get(uriString))); } return map; } protected static List<URI> toURIs(List<NamedElement> namedElements) { List<URI> out = Lists.newArrayList(); if (namedElements != null) { for (NamedElement namedElement : namedElements) { out.add(namedElement.getId()); } } return out; } /** * This function is to retrieve the uri of the static children of a given class. * * @param dbClient - Database client * @param id the URN of the parent * @param clzz the child class * @param linkField the name of the field in the child class that stored the parent id * @return a list of children of tenant for the given class */ public static <T extends DataObject> List<URI> getChildrenUris(DbClient dbClient, URI id, Class<T> clzz, String linkField) { List<URI> uris = dbClient.queryByConstraint( ContainmentConstraint.Factory.getContainedObjectsConstraint(id, clzz, linkField)); return uris; } /** * Update the cluster references for the host and its initiators * * @param dbClient dbclient * @param clusterURI the cluster that the host is being assigned to * @param hostURI the host id */ public static void updateHostAndInitiatorClusterReferences(DbClient dbClient, URI clusterURI, URI hostURI) { Host host = dbClient.queryObject(Host.class, hostURI); host.setCluster(clusterURI); dbClient.updateObject(host); updateInitiatorClusterName(dbClient, clusterURI, hostURI); } /** * Update the hosts vcenter datacenter reference * * @param dbClient dbclient * @param hostURI the host id to update * @param vCenterDataCenterId the id of the vcenter datacenter to set on the host */ public static void updateHostVcenterDatacenterReference(DbClient dbClient, URI hostURI, URI vCenterDataCenterId) { Host host = dbClient.queryObject(Host.class, hostURI); host.setVcenterDataCenter(vCenterDataCenterId); dbClient.updateObject(host); } /** * Update the cluster reference for all initiators that belong to hosts in the cluster * * @param dbClient dbclient * @param clusterURI the cluster id */ public static void updateInitiatorClusterName(DbClient dbClient, URI clusterURI) { if (!NullColumnValueGetter.isNullURI(clusterURI)) { List<URI> clusterHosts = ComputeSystemHelper.getChildrenUris(dbClient, clusterURI, Host.class, "cluster"); for (URI hostURI : clusterHosts) { updateInitiatorClusterName(dbClient, clusterURI, hostURI); } } } public static void updateInitiatorClusterName(DbClient dbClient, URI clusterURI, URI hostURI) { Cluster cluster = null; if (!NullColumnValueGetter.isNullURI(clusterURI)) { cluster = dbClient.queryObject(Cluster.class, clusterURI); } List<Initiator> initiators = ComputeSystemHelper.queryInitiators(dbClient, hostURI); for (Initiator initiator : initiators) { initiator.setClusterName(cluster != null ? cluster.getLabel() : "null"); } dbClient.updateObject(initiators); } public static void updateInitiatorHostName(DbClient dbClient, Host host) { List<Initiator> initiators = ComputeSystemHelper.queryInitiators(dbClient, host.getId()); for (Initiator initiator : initiators) { initiator.setHostName(host.getHostName()); } dbClient.updateObject(initiators); } /** * Updates the vCenterDataCenter and its Clusters and Hosts to the new tenantId. * * @param dbClient dbClient to make the DB queries. * @param dataCenter vCenterDataCenter to be updated. * @param tenantId new tenantId to be updated to the vCenterDataCenter. */ public static void updateVcenterDataCenterTenant(DbClient dbClient, VcenterDataCenter dataCenter, URI tenantId) { if (dataCenter == null || dataCenter.getInactive()) { return; } if(!NullColumnValueGetter.isNullURI(dataCenter.getTenant()) && isDataCenterInUse(dbClient, dataCenter.getId())) { //Since vCenterDataCenter contains some exports, //dont allow the update. Set<String> tenants = new HashSet<String>(); tenants.add(dataCenter.getTenant().toString()); throw APIException.badRequests.cannotRemoveTenant("vCenterDataCenter", dataCenter.getLabel(), tenants); } URI localTenantId = tenantId; if (localTenantId == null || localTenantId.equals(NullColumnValueGetter.getNullURI())) { localTenantId = NullColumnValueGetter.getNullURI(); } upateHostTenant(dbClient, dataCenter.getId(), localTenantId); updateClusterTenant(dbClient, dataCenter.getId(), localTenantId); dataCenter.setTenant(localTenantId); } /** * Updates the Cluster's tenant. * * @param dbClient DBClient for the database operations. * @param dataCenterId data center URI. * @param tenantId tenant id to be updated. */ private static void updateClusterTenant(DbClient dbClient, URI dataCenterId, URI tenantId) { List<NamedElement> clustersUris = listChildren(dbClient, dataCenterId, Cluster.class, "label", "vcenterDataCenter"); for (NamedElement clusterUri : clustersUris) { Cluster cluster = dbClient.queryObject(Cluster.class, clusterUri.getId()); if (cluster != null) { cluster.setTenant(tenantId); dbClient.persistObject(cluster); } } } /** * Updates the Host's tenant. * * @param dbClient DBClient for the database operations. * @param dataCenterId data center URI. * @param tenantId tenant id to be updated. */ private static void upateHostTenant(DbClient dbClient, URI dataCenterId, URI tenantId) { List<NamedElement> hostUris = listChildren(dbClient, dataCenterId, Host.class, "label", "vcenterDataCenter"); for (NamedElement hostUri : hostUris) { Host host = dbClient.queryObject(Host.class, hostUri.getId()); if (host != null) { host.setTenant(tenantId); dbClient.persistObject(host); } } } /** * Checks if an vCenter with respect to the tenant is in use by an export groups * * @param dbClient * @param vcenterURI the vcenter URI * @return true if the vcenter is in used by an export group. */ public static boolean isVcenterInUseForTheTenant(DbClient dbClient, URI vcenterURI, URI tenantId) { List<NamedElementQueryResultList.NamedElement> datacenterUris = listChildren(dbClient, vcenterURI, VcenterDataCenter.class, "label", "vcenter"); for (NamedElementQueryResultList.NamedElement datacenterUri : datacenterUris) { VcenterDataCenter vcenterDataCenter = dbClient.queryObject(VcenterDataCenter.class, datacenterUri.getId()); if (vcenterDataCenter != null && URIUtil.identical(tenantId, vcenterDataCenter.getTenant()) && isDataCenterInUse(dbClient, datacenterUri.getId())) { return true; } } return false; } /** * Verify that datastore can be unmounted from the given host * * @param datastore the datastore to check * @param host the host to check for any running VMs on the given datastore * * @throws Exception if an error occurs */ public static void verifyDatastore(Datastore datastore, HostSystem host) throws Exception { DatastoreSummary summary = datastore.getSummary(); if (summary == null) { throw new Exception("Summary unavailable for datastore " + datastore.getName()); } if (!summary.isAccessible()) { throw new Exception("Datastore " + datastore.getName() + " is not accessible"); } checkMaintenanceMode(datastore, summary); checkVirtualMachines(datastore, host); } /** * Check maintenance mode of a datastore and fail if datastore is entering maintenance mode * * @param datastore the datastore to check * @param summary the datastore summary * @throws Exception if datastore is entering maintenance mode */ public static void checkMaintenanceMode(Datastore datastore, DatastoreSummary summary) throws Exception { String mode = summary.getMaintenanceMode(); // If a datastore is already entering maintenance mode, fail if (DatastoreSummaryMaintenanceModeState.enteringMaintenance.name().equals(mode)) { throw new Exception("Datastore " + datastore.getName() + " is entering maintenance mode"); } } /** * Checks if Virtual Machines are running on the datastore and host, and fail if any are found * * @param datastore the datastore to check * @param host the host system to check * @throws Exception if datastore contains any virtual machines on the host */ public static void checkVirtualMachines(Datastore datastore, HostSystem host) throws Exception { VirtualMachine[] vms = datastore.getVms(); Set<String> names = Sets.newTreeSet(); if ((vms != null) && (vms.length > 0)) { for (VirtualMachine vm : vms) { if (isVirtualMachineRunningOnHost(host, vm)) { names.add(vm.getName()); } } } if (!names.isEmpty()) { throw new Exception( "Datastore " + datastore.getName() + " contains " + names.size() + " Virtual Machines running on host " + host.getName() + " and they are: " + Joiner.on(",").join(names)); } } /** * Returns true if the virtual machine is running on the host * * @param host the host to check * @param vm the virtual machine to check * @return true if the virtual machine is running on the host, otherwise false */ private static boolean isVirtualMachineRunningOnHost(HostSystem host, VirtualMachine vm) { return host != null && host.getConfig() != null && host.getConfig().getHost() != null && host.getConfig().getHost().getVal() != null && vm.getRuntime() != null && vm.getRuntime().getHost() != null && StringUtils.equalsIgnoreCase(host.getConfig().getHost().getVal(), vm.getRuntime().getHost().getVal()); } /** * Get the vcenter that the host belongs to or null if it doesn't belong to one * * @param dbClient the dbclient * @param host the host to check * @return vcenter that the host belongs to or null if it doesn't belong to one */ public static Vcenter getHostVcenter(DbClient dbClient, Host host) { if (host != null && !NullColumnValueGetter.isNullURI(host.getVcenterDataCenter())) { VcenterDataCenter datacenter = dbClient.queryObject(VcenterDataCenter.class, host.getVcenterDataCenter()); if (datacenter != null && !NullColumnValueGetter.isNullURI(datacenter.getVcenter())) { return dbClient.queryObject(Vcenter.class, datacenter.getVcenter()); } } return null; } }