/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.computesystemcontroller.impl.adapter; import java.net.ConnectException; import java.net.NoRouteToHostException; import java.net.URI; import java.net.UnknownHostException; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.UUID; import javax.net.ssl.SSLException; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import com.emc.storageos.Controller; import com.emc.storageos.computesystemcontroller.ComputeSystemController; import com.emc.storageos.computesystemcontroller.ComputeSystemDialogProperties; import com.emc.storageos.computesystemcontroller.exceptions.ComputeSystemControllerException; import com.emc.storageos.computesystemcontroller.impl.ComputeSystemDiscoveryAdapter; import com.emc.storageos.computesystemcontroller.impl.ComputeSystemDiscoveryVersionValidator; import com.emc.storageos.computesystemcontroller.impl.ComputeSystemHelper; import com.emc.storageos.computesystemcontroller.impl.DiscoveryStatusUtils; import com.emc.storageos.coordinator.client.service.CoordinatorClient; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.ModelClient; import com.emc.storageos.db.client.model.Cluster; import com.emc.storageos.db.client.model.DataObject; import com.emc.storageos.db.client.model.DiscoveredDataObject.RegistrationStatus; import com.emc.storageos.db.client.model.Host; import com.emc.storageos.db.client.model.HostInterface; import com.emc.storageos.db.client.model.Initiator; import com.emc.storageos.db.client.model.IpInterface; 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.EndpointUtility; import com.emc.storageos.db.client.util.NullColumnValueGetter; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; public abstract class AbstractDiscoveryAdapter implements ComputeSystemDiscoveryAdapter { private Logger log; protected final static String CONTROLLER_SVC = "controllersvc"; protected final static String CONTROLLER_SVC_VER = "1"; @Autowired private ComputeSystemDiscoveryVersionValidator versionValidator; protected ModelClient modelClient; protected DbClient dbClient; protected CoordinatorClient coordinator; public ModelClient getModelClient() { return modelClient; } @Override public void setModelClient(ModelClient modelClient) { this.modelClient = modelClient; } public DbClient getDbClient() { return dbClient; } @Override public void setDbClient(DbClient dbClient) { this.dbClient = dbClient; } @Override public void setCoordinator(CoordinatorClient coordinator) { this.coordinator = coordinator; } @Override public ComputeSystemDiscoveryVersionValidator getVersionValidator() { return versionValidator; } protected <T extends DataObject> T findModelByLabel(List<T> models, String label) { for (T model : models) { if (StringUtils.equals(label, model.getLabel())) { return model; } } return null; } protected Host findHostByLabel(List<Host> models, String label) { for (Host model : models) { if (StringUtils.equals(label, model.getLabel())) { return model; } } return null; } protected IpInterface findInterfaceByIp(List<IpInterface> models, String ip) { for (IpInterface model : models) { if (StringUtils.equals(ip, model.getIpAddress())) { return model; } } return null; } /** * Gets a model object by ID. * * @param modelClass * the model class. * @param id * the ID of the model object. * @return the model. */ protected <T extends DataObject> T get(Class<T> modelClass, URI id) { return modelClient.of(modelClass).findById(id); } /** * Removes discovered IP interfaces from its host and ignores manually created IP interfaces * * @param ipInterfaces * list of IP interfaces */ protected void removeDiscoveredInterfaces(Iterable<IpInterface> ipInterfaces) { updateManuallyCreatedInterfaces(ipInterfaces); Iterable<IpInterface> discoveredInterfaces = Iterables.filter(ipInterfaces, new Predicate<IpInterface>() { @Override public boolean apply(IpInterface ipInterface) { return ipInterface.getIsManualCreation() != null && !ipInterface.getIsManualCreation(); } }); removeIpInterfaces(discoveredInterfaces); } /** * Updates IP interfaces by setting isManualCreation value to true if the value is null. * Handles the newly added isManualCreation field to IPInterface by assuming that null values * are true. During next discovery, any discovered interfaces will have isManualCreation * value set to false. * * @param ipInterfaces * list of IP interfaces */ protected void updateManuallyCreatedInterfaces(Iterable<IpInterface> ipInterfaces) { for (IpInterface ipInterface : ipInterfaces) { if (ipInterface.getIsManualCreation() == null) { ipInterface.setIsManualCreation(true); modelClient.save(ipInterface); } } } protected void removeIpInterfaces(Iterable<IpInterface> ipInterfaces) { for (IpInterface ipInterface : ipInterfaces) { ipInterface.setHost(NullColumnValueGetter.getNullURI()); ipInterface.setInactive(true); save(ipInterface); } } protected void addNewInitiatorsToExport(Host host, List<Initiator> newInitiators) { // update export if host is in use if (ComputeSystemHelper.isHostInUse(dbClient, host.getId())) { String taskId = UUID.randomUUID().toString(); ComputeSystemController controller = getController(ComputeSystemController.class, null); List<URI> uris = Lists.newArrayList(); for (Initiator initiator : newInitiators) { uris.add(initiator.getId()); } controller.addInitiatorsToExport(host.getId(), uris, taskId); } } protected void removeOldInitiatorFromExport(Host host, List<Initiator> oldInitiators) { // update export if host is in use if (!oldInitiators.isEmpty() && ComputeSystemHelper.isHostInUse(dbClient, host.getId())) { String taskId = UUID.randomUUID().toString(); ComputeSystemController controller = getController(ComputeSystemController.class, null); List<URI> uris = Lists.newArrayList(); for (Initiator initiator : oldInitiators) { uris.add(initiator.getId()); } controller.removeInitiatorsFromExport(host.getId(), uris, taskId); } } protected void addNewHostsToExport(URI clusterURI, List<Host> hosts, URI oldClusterURI) { // update export if host is in use if (ComputeSystemHelper.isClusterInExport(dbClient, clusterURI)) { String taskId = UUID.randomUUID().toString(); ComputeSystemController controller = getController(ComputeSystemController.class, null); List<URI> hostIds = Lists.newArrayList(); for (Host host : hosts) { hostIds.add(host.getId()); } controller.addHostsToExport(hostIds, clusterURI, taskId, oldClusterURI, false); } } protected void removeOldHostsFromExport(URI clusterURI, List<Host> hosts) { // update export if host is in use if (ComputeSystemHelper.isClusterInExport(dbClient, clusterURI)) { String taskId = UUID.randomUUID().toString(); ComputeSystemController controller = getController(ComputeSystemController.class, null); List<URI> hostIds = Lists.newArrayList(); for (Host host : hosts) { hostIds.add(host.getId()); } controller.removeHostsFromExport(hostIds, clusterURI, false, NullColumnValueGetter.getNullURI(), taskId); } } /** * Removes discovered initiators from its host and ignores manually created initiators * * @param initiators * list of initiators */ protected void removeDiscoveredInitiators(Iterable<Initiator> initiators) { Iterable<Initiator> discoveredInitiators = Iterables.filter(initiators, new Predicate<Initiator>() { @Override public boolean apply(Initiator initiator) { return !initiator.getIsManualCreation(); } }); removeInitiators(discoveredInitiators); } protected void removeInitiators(Iterable<Initiator> initiators) { for (Initiator initiator : initiators) { initiator.setHost(NullColumnValueGetter.getNullURI()); initiator.setHostName(""); initiator.setClusterName(""); save(initiator); } } protected Initiator findInitiatorByPort(List<Initiator> initiators, String port) { for (Initiator initiator : initiators) { if (StringUtils.equalsIgnoreCase(initiator.getInitiatorPort(), port)) { return initiator; } } // Search against the database for (Initiator initiator : modelClient.initiators().findByPort(port, true)) { if (StringUtils.equalsIgnoreCase(initiator.getInitiatorPort(), port)) { return initiator; } } return null; } protected Initiator getOrCreateInitiator(URI hostId, List<Initiator> initiators, String port) { Initiator initiator = findInitiatorByPort(initiators, port); if (initiator == null) { initiator = new Initiator(); initiator.setInitiatorPort(port); initiator.setLabel(EndpointUtility.changeCase(port)); } else { initiators.remove(initiator); } if (!NullColumnValueGetter.isNullURI(initiator.getHost()) && !initiator.getHost().equals(hostId)) { Host host = dbClient.queryObject(Host.class, hostId); Host initiatorHost = dbClient.queryObject(Host.class, initiator.getHost()); throw ComputeSystemControllerException.exceptions.illegalInitiator(host != null ? host.forDisplay() : hostId.toString(), initiator.getInitiatorPort(), initiatorHost != null ? initiatorHost.forDisplay() : initiator.getHost().toString()); } initiator.setIsManualCreation(false); return initiator; } /** * Finds a matching value in the list of models by label, or creates one if none is found. If a match is found in * the list, it will be removed from the list before returning. * * @param modelClass * the model class. * @param models * the list of models. * @param label * the label to match. * @return the matched value, or a new instance created with the specified label. */ protected <T extends DataObject> T getOrCreate(Class<T> modelClass, List<T> models, String label) { T model = findModelByLabel(models, label); if (model == null) { try { model = modelClass.newInstance(); } catch (InstantiationException e) { throw new IllegalArgumentException(e); } catch (IllegalAccessException e) { throw new IllegalArgumentException(e); } model.setLabel(label); info("Creating new instance of %s with label %s", modelClass.getSimpleName(), label); } else { models.remove(model); } return model; } /** * Finds a matching value in the list of IpInterfaces by ipAddress, or creates one if none is found. If a match is * found in * the list, it will be removed from the list before returning. * * @param models * the list of IpInterface models. * @param ip * the ip to match. * @return the matched value, or a new instance created with the specified ip. */ protected IpInterface getOrCreateInterfaceByIp(List<IpInterface> models, String ip) { IpInterface model = findInterfaceByIp(models, ip); if (model == null) { model = new IpInterface(); model.setIsManualCreation(false); model.setIpAddress(ip); model.setLabel(ip); } else { models.remove(model); } return model; } protected void save(DataObject model) { if (model.getCreationTime() == null) { debug("Creating %s: %s", model.getClass().getSimpleName(), toString(model)); } else { debug("Updating %s: %s", model.getClass().getSimpleName(), toString(model)); } modelClient.save(model); } protected void delete(DataObject model) { debug("Deactivating %s: %s", model.getClass().getSimpleName(), toString(model)); model.setInactive(true); modelClient.save(model); } protected <T extends DataObject> void delete(List<T> models) { for (T model : models) { delete(model); } } protected synchronized Logger getLog() { if (log == null) { log = LoggerFactory.getLogger(getClass()); } return log; } protected void error(String message, Object... args) { if (args != null && args.length > 0) { getLog().error(String.format(message, args)); } else { getLog().error(message); } } protected void warn(Throwable t, String message, Object... args) { if (args != null && args.length > 0) { getLog().warn(String.format(message, args), t); } else { getLog().warn(message, t); } } protected void warn(String message, Object... args) { if (args != null && args.length > 0) { getLog().warn(String.format(message, args)); } else { getLog().warn(message); } } protected void info(String message, Object... args) { if (getLog().isInfoEnabled()) { if (args != null && args.length > 0) { getLog().info(String.format(message, args)); } else { getLog().info(message); } } } protected void debug(String message, Object... args) { if (getLog().isDebugEnabled()) { if (args != null && args.length > 0) { getLog().debug(String.format(message, args)); } else { getLog().debug(message); } } } protected String toString(DataObject model) { if (model.getClass() == Host.class) { return toString((Host) model); } if (model.getClass() == IpInterface.class) { return toString((IpInterface) model); } if (model.getClass() == Initiator.class) { return toString((Initiator) model); } if (StringUtils.isNotBlank(model.getLabel())) { return model.getLabel(); } return model.toString(); } protected String toString(Host host) { return String.format("%s [%s]", host.getHostName(), host.getType()); } protected String toString(IpInterface ipInterface) { return String.format("%s [%s]", ipInterface.getIpAddress(), ipInterface.getProtocol()); } protected String toString(Initiator initiator) { if (StringUtils.isNotBlank(initiator.getInitiatorNode())) { return String.format("%s:%s [%s]", initiator.getInitiatorNode(), initiator.getInitiatorPort(), initiator.getProtocol()); } else { return String.format("%s [%s]", initiator.getInitiatorPort(), initiator.getProtocol()); } } @Override public String getErrorMessage(Throwable t) { Throwable rootCause = getRootCause(t); if (rootCause instanceof UnknownHostException) { return "Unknown host: " + rootCause.getMessage(); } else if (rootCause instanceof ConnectException) { return "Error connecting: " + rootCause.getMessage(); } else if (rootCause instanceof NoRouteToHostException) { return "No route to host: " + rootCause.getMessage(); } else if (rootCause instanceof SSLException) { return "SSL error: " + rootCause.getMessage(); } return getClosestErrorMessage(t); } protected String getClosestErrorMessage(Throwable originalThrowable) { String message = null; Throwable t = originalThrowable; while ((t != null) && (message == null)) { message = t.getMessage(); t = t.getCause() != t ? t.getCause() : null; } if (message == null) { message = originalThrowable.getClass().getName(); } return message; } protected Throwable getRootCause(Throwable t) { Throwable rootCause = t; while ((rootCause.getCause() != null) && (rootCause.getCause() != rootCause)) { rootCause = rootCause.getCause(); } return rootCause; } protected void setHostInterfaceRegistrationStatus(HostInterface hostInterface, Host host) { if (host.getRegistrationStatus().equals(RegistrationStatus.UNREGISTERED.toString())) { hostInterface.setRegistrationStatus(RegistrationStatus.UNREGISTERED.toString()); } else if (hostInterface.getId() == null) { hostInterface.setRegistrationStatus(RegistrationStatus.REGISTERED.toString()); } } /** * Looks up controller dependency for given hardware * * @param clazz * controller interface * @param hw * hardware name * @param <T> * @return */ protected <T extends Controller> T getController(Class<T> clazz, String hw) { return coordinator.locateService( clazz, CONTROLLER_SVC, CONTROLLER_SVC_VER, hw, clazz.getSimpleName()); } public void processHostChanges(HostStateChange changes) { processHostChanges(Collections.singletonList(changes), Collections.<URI> emptyList(), Collections.<URI> emptyList(), false); } public void processHostChanges(List<HostStateChange> changes, List<URI> deletedHosts, List<URI> deletedClusters, boolean isVCenter) { log.info("There are " + changes.size() + " changes"); // Iterate through all host state changes and create states for all of the affected export groups for (HostStateChange change : changes) { log.info("HostChange: " + change); Host host = dbClient.queryObject(Host.class, change.getHost().getId()); // For every host change (added/removed initiator, cluster change), get all exports that this host // currently belongs to List<Initiator> newInitiatorObjects = dbClient.queryObject(Initiator.class, change.getNewInitiators()); List<Initiator> oldInitiatorObjects = dbClient.queryObject(Initiator.class, change.getOldInitiators()); if (newInitiatorObjects.isEmpty() && !oldInitiatorObjects.isEmpty()) { List<URI> hostInitiators = ComputeSystemHelper.getChildrenUris(dbClient, host.getId(), Initiator.class, "host"); if (hostInitiators.size() == oldInitiatorObjects.size()) { log.info("No initiators were re-discovered for host " + host.getId() + " so we will not delete its initiators"); DiscoveryStatusUtils.markAsFailed(getModelClient(), host, "No initiators were discovered", null); continue; } } // check for changes as the following // 1) Detect vCenterDatacenter change // 2) If no datacenter change, detect cluster change // 3) If no datacenter or cluster change, make sure we have updated atleast the new datacenter for the host if (!NullColumnValueGetter.isNullURI(change.getOldDatacenter()) && !NullColumnValueGetter.isNullURI(change.getNewDatacenter()) && !change.getOldDatacenter().toString().equalsIgnoreCase(change.getNewDatacenter().toString())) { VcenterDataCenter oldDatacenter = dbClient.queryObject(VcenterDataCenter.class, change.getOldDatacenter()); VcenterDataCenter currentDatacenter = dbClient.queryObject(VcenterDataCenter.class, change.getNewDatacenter()); Cluster cluster = null; if (!NullColumnValueGetter.isNullURI(change.getNewCluster())) { cluster = dbClient.queryObject(Cluster.class, change.getNewCluster()); } URI oldClusterURI = change.getOldCluster(); Cluster oldCluster = null; if (!NullColumnValueGetter.isNullURI(oldClusterURI)) { oldCluster = dbClient.queryObject(Cluster.class, oldClusterURI); } if (!oldDatacenter.getVcenter().toString().equals(currentDatacenter.getVcenter().toString())) { Vcenter oldVcenter = dbClient.queryObject(Vcenter.class, oldDatacenter.getVcenter()); Vcenter currentVcenter = dbClient.queryObject(Vcenter.class, currentDatacenter.getVcenter()); EventUtils.createActionableEvent(dbClient, EventUtils.EventCode.HOST_VCENTER_CHANGE, host.getTenant(), ComputeSystemDialogProperties.getMessage("ComputeSystem.hostVcenterChangeLabel", oldVcenter.getLabel(), currentVcenter.getLabel()), ComputeSystemDialogProperties.getMessage("ComputeSystem.hostVcenterChangeDescription", host.getLabel(), oldCluster == null ? "N/A" : oldCluster.getLabel(), cluster == null ? " N/A " : cluster.getLabel()), ComputeSystemDialogProperties.getMessage("ComputeSystem.hostVcenterChangeWarning"), host, Lists.newArrayList(host.getId(), host.getCluster(), cluster == null ? NullColumnValueGetter.getNullURI() : cluster.getId()), EventUtils.hostVcenterChange, new Object[] { host.getId(), cluster != null ? cluster.getId() : NullColumnValueGetter.getNullURI(), currentDatacenter.getId(), isVCenter }, EventUtils.hostVcenterChangeDecline, new Object[] { host.getId(), cluster != null ? cluster.getId() : NullColumnValueGetter.getNullURI(), currentDatacenter.getId(), isVCenter }); } else { EventUtils.createActionableEvent(dbClient, EventUtils.EventCode.HOST_DATACENTER_CHANGE, host.getTenant(), ComputeSystemDialogProperties.getMessage("ComputeSystem.hostDatacenterChangeLabel", oldDatacenter.getLabel(), currentDatacenter.getLabel()), ComputeSystemDialogProperties.getMessage("ComputeSystem.hostDatacenterChangeDescription", host.getLabel(), oldCluster == null ? "N/A" : oldCluster.getLabel(), cluster == null ? " N/A " : cluster.getLabel()), ComputeSystemDialogProperties.getMessage("ComputeSystem.hostDatacenterChangeWarning"), host, Lists.newArrayList(host.getId(), host.getCluster(), cluster == null ? NullColumnValueGetter.getNullURI() : cluster.getId()), EventUtils.hostDatacenterChange, new Object[] { host.getId(), cluster != null ? cluster.getId() : NullColumnValueGetter.getNullURI(), currentDatacenter.getId(), isVCenter }, EventUtils.hostDatacenterChangeDecline, new Object[] { host.getId(), cluster != null ? cluster.getId() : NullColumnValueGetter.getNullURI(), currentDatacenter.getId(), isVCenter }); } } else if ((change.getOldCluster() == null && change.getNewCluster() != null) || (change.getOldCluster() != null && change.getNewCluster() == null) || (change.getOldCluster() != null && change.getNewCluster() != null && !change.getOldCluster().toString().equals(change.getNewCluster().toString()))) { Cluster cluster = null; if (!NullColumnValueGetter.isNullURI(change.getNewCluster())) { cluster = dbClient.queryObject(Cluster.class, change.getNewCluster()); } URI oldClusterURI = change.getOldCluster(); Cluster oldCluster = null; if (!NullColumnValueGetter.isNullURI(oldClusterURI)) { oldCluster = dbClient.queryObject(Cluster.class, oldClusterURI); } boolean oldClusterInUse = oldCluster == null ? false : ComputeSystemHelper.isClusterInExport(dbClient, oldCluster.getId()); boolean newClusterInUse = cluster == null ? false : ComputeSystemHelper.isClusterInExport(dbClient, cluster.getId()); if ((cluster != null || oldCluster != null) && (oldClusterInUse || newClusterInUse)) { String name = null; String description = null; if (cluster != null && oldCluster == null) { name = ComputeSystemDialogProperties.getMessage("ComputeSystem.hostClusterChangeAddedLabel", cluster.getLabel()); description = ComputeSystemDialogProperties.getMessage("ComputeSystem.hostClusterChangeAddedDescription", host.getLabel(), cluster.getLabel()); } else if (cluster == null && oldCluster != null) { name = ComputeSystemDialogProperties.getMessage("ComputeSystem.hostClusterChangeRemovedLabel", oldCluster.getLabel()); description = ComputeSystemDialogProperties.getMessage("ComputeSystem.hostClusterChangeRemovedDescription", host.getLabel(), oldCluster.getLabel()); } else { name = ComputeSystemDialogProperties.getMessage("ComputeSystem.hostClusterChangeMovedLabel", oldCluster.getLabel(), cluster.getLabel()); description = ComputeSystemDialogProperties.getMessage("ComputeSystem.hostClusterChangeMovedDescription", host.getLabel(), oldCluster.getLabel(), cluster.getLabel()); } EventUtils.createActionableEvent(dbClient, EventUtils.EventCode.HOST_CLUSTER_CHANGE, host.getTenant(), name, description, ComputeSystemDialogProperties.getMessage("ComputeSystem.hostClusterChangeWarning"), host, Lists.newArrayList(host.getId(), host.getCluster(), cluster == null ? NullColumnValueGetter.getNullURI() : cluster.getId()), EventUtils.hostClusterChange, new Object[] { host.getId(), cluster != null ? cluster.getId() : NullColumnValueGetter.getNullURI(), NullColumnValueGetter.isNullURI(change.getNewDatacenter()) ? NullColumnValueGetter.getNullURI() : change.getNewDatacenter(), isVCenter }, EventUtils.hostClusterChangeDecline, new Object[] { host.getId(), cluster != null ? cluster.getId() : NullColumnValueGetter.getNullURI(), NullColumnValueGetter.isNullURI(change.getNewDatacenter()) ? NullColumnValueGetter.getNullURI() : change.getNewDatacenter(), isVCenter }); } else { host.setCluster(cluster == null ? NullColumnValueGetter.getNullURI() : cluster.getId()); dbClient.updateObject(host); ComputeSystemHelper.updateHostAndInitiatorClusterReferences(dbClient, host.getCluster(), host.getId()); if (cluster != null) { ComputeSystemHelper.updateHostVcenterDatacenterReference(dbClient, host.getId(), cluster != null ? cluster.getVcenterDataCenter() : NullColumnValueGetter.getNullURI()); } } } else if (!NullColumnValueGetter.isNullURI(change.getNewDatacenter())) { VcenterDataCenter currentDatacenter = dbClient.queryObject(VcenterDataCenter.class, change.getNewDatacenter()); host.setTenant(currentDatacenter.getTenant()); host.setVcenterDataCenter(currentDatacenter.getId()); dbClient.updateObject(host); } if (ComputeSystemHelper.isHostInUse(dbClient, host.getId())) { for (Initiator oldInitiator : oldInitiatorObjects) { EventUtils.createActionableEvent(dbClient, EventUtils.EventCode.HOST_INITIATOR_DELETE, host.getTenant(), ComputeSystemDialogProperties.getMessage("ComputeSystem.removeInitiatorLabel", oldInitiator.getInitiatorPort()), ComputeSystemDialogProperties.getMessage("ComputeSystem.removeInitiatorDescription", oldInitiator.getInitiatorPort()), ComputeSystemDialogProperties.getMessage("ComputeSystem.removeInitiatorWarning"), host, Lists.newArrayList(host.getId(), oldInitiator.getId()), EventUtils.removeInitiator, new Object[] { oldInitiator.getId() }, EventUtils.removeInitiatorDecline, new Object[] { oldInitiator.getId() }); } for (Initiator newInitiator : newInitiatorObjects) { EventUtils.createActionableEvent(dbClient, EventUtils.EventCode.HOST_INITIATOR_ADD, host.getTenant(), ComputeSystemDialogProperties.getMessage("ComputeSystem.addInitiatorLabel", newInitiator.getInitiatorPort()), ComputeSystemDialogProperties.getMessage("ComputeSystem.addInitiatorDescription", newInitiator.getInitiatorPort()), ComputeSystemDialogProperties.getMessage("ComputeSystem.addInitiatorWarning"), host, Lists.newArrayList(host.getId(), newInitiator.getId()), EventUtils.addInitiator, new Object[] { newInitiator.getId() }, EventUtils.addInitiatorDecline, new Object[] { newInitiator.getId() }); } } else { for (Initiator oldInitiator : oldInitiatorObjects) { info("Deleting Initiator %s because it was not re-discovered and is not in use by any export groups", oldInitiator.getId()); dbClient.removeObject(oldInitiator); } } } log.info("Number of undiscovered hosts: " + deletedHosts.size()); Set<URI> incorrectDeletedHosts = Sets.newHashSet(); for (URI deletedHost : deletedHosts) { Host host = dbClient.queryObject(Host.class, deletedHost); URI clusterId = host.getCluster(); List<URI> clusterHosts = Lists.newArrayList(); if (!NullColumnValueGetter.isNullURI(clusterId)) { clusterHosts = ComputeSystemHelper.getChildrenUris(dbClient, clusterId, Host.class, "cluster"); } if (clusterHosts.contains(deletedHost) && deletedHosts.containsAll(clusterHosts)) { incorrectDeletedHosts.add(deletedHost); DiscoveryStatusUtils.markAsFailed(getModelClient(), host, "Error discovering host cluster", null); log.info("Host " + host.getId() + " is part of a cluster that was not re-discovered. Fail discovery and keep the host in our database"); } else { Vcenter vcenter = ComputeSystemHelper.getHostVcenter(dbClient, host); EventUtils.createActionableEvent(dbClient, EventUtils.EventCode.UNASSIGN_HOST_FROM_VCENTER, host.getTenant(), ComputeSystemDialogProperties.getMessage("ComputeSystem.hostVcenterUnassignLabel", vcenter == null ? "N/A" : vcenter.getLabel()), ComputeSystemDialogProperties.getMessage("ComputeSystem.hostVcenterUnassignDescription", host.getLabel(), vcenter == null ? "N/A" : vcenter.getLabel()), ComputeSystemDialogProperties.getMessage("ComputeSystem.hostVcenterUnassignWarning"), host, Lists.newArrayList(host.getId(), host.getCluster()), EventUtils.hostVcenterUnassign, new Object[] { deletedHost }, EventUtils.hostVcenterUnassignDecline, new Object[] { deletedHost }); } } // delete clusters that don't contain any hosts, don't have any exports, and don't have any pending events for (URI clusterId : deletedClusters) { List<URI> hostUris = ComputeSystemHelper.getChildrenUris(dbClient, clusterId, Host.class, "cluster"); if (hostUris.isEmpty() && !ComputeSystemHelper.isClusterInExport(dbClient, clusterId) && EventUtils.findAffectedResourcePendingEvents(dbClient, clusterId).isEmpty()) { Cluster cluster = dbClient.queryObject(Cluster.class, clusterId); info("Deactivating Cluster: " + clusterId); ComputeSystemHelper.doDeactivateCluster(dbClient, cluster); } else { info("Unable to delete cluster " + clusterId); } } } // TODO: move to AbstractHostDiscoveryAdapter once EsxHostDiscoveryAdatper is moved to extend it public void matchHostToComputeElements(Host host) { log.warn("Matching host to compute elements not supported for this host type."); } }