| /** |
| * Copyright (C) 2011 Cloud.com, Inc. All rights reserved. |
| */ |
| |
| package com.cloud.hypervisor.vmware;
|
|
|
| import java.net.URI;
|
| import java.net.URLDecoder;
|
| import java.util.HashMap;
|
| import java.util.List;
|
| import java.util.Map;
|
| import java.util.UUID;
|
|
|
| import javax.ejb.Local;
|
| import javax.naming.ConfigurationException;
|
|
|
| import org.apache.log4j.Logger;
|
|
|
| import com.cloud.agent.api.StartupCommand; |
| import com.cloud.agent.api.StartupRoutingCommand; |
| import com.cloud.alert.AlertManager;
|
| import com.cloud.configuration.dao.ConfigurationDao;
|
| import com.cloud.dc.ClusterDetailsDao;
|
| import com.cloud.dc.ClusterVO;
|
| import com.cloud.dc.dao.ClusterDao;
|
| import com.cloud.exception.DiscoveredWithErrorException; |
| import com.cloud.exception.DiscoveryException;
|
| import com.cloud.host.HostVO;
|
| import com.cloud.host.dao.HostDao; |
| import com.cloud.hypervisor.Hypervisor;
|
| import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
| import com.cloud.hypervisor.vmware.manager.VmwareManager;
|
| import com.cloud.hypervisor.vmware.mo.ClusterMO;
|
| import com.cloud.hypervisor.vmware.mo.HostMO;
|
| import com.cloud.hypervisor.vmware.resource.VmwareContextFactory;
|
| import com.cloud.hypervisor.vmware.resource.VmwareResource;
|
| import com.cloud.hypervisor.vmware.util.VmwareContext;
|
| import com.cloud.resource.Discoverer;
|
| import com.cloud.resource.DiscovererBase;
|
| import com.cloud.resource.ResourceManager; |
| import com.cloud.resource.ResourceStateAdapter; |
| import com.cloud.resource.ServerResource;
|
| import com.cloud.resource.UnableDeleteHostException; |
| import com.cloud.resource.ResourceStateAdapter.DeleteHostAnswer; |
| import com.cloud.storage.Storage.ImageFormat;
|
| import com.cloud.storage.Storage.TemplateType;
|
| import com.cloud.storage.VMTemplateVO;
|
| import com.cloud.storage.dao.VMTemplateDao;
|
| import com.cloud.user.Account;
|
| import com.cloud.utils.UriUtils;
|
| import com.cloud.utils.component.ComponentLocator;
|
| import com.cloud.utils.component.Inject;
|
| import com.vmware.vim25.ClusterDasConfigInfo;
|
| import com.vmware.vim25.ManagedObjectReference;
|
|
|
| @Local(value=Discoverer.class)
|
| public class VmwareServerDiscoverer extends DiscovererBase implements Discoverer, ResourceStateAdapter {
|
| private static final Logger s_logger = Logger.getLogger(VmwareServerDiscoverer.class);
|
|
|
| @Inject ClusterDao _clusterDao;
|
| @Inject VmwareManager _vmwareMgr;
|
| @Inject AlertManager _alertMgr;
|
| @Inject VMTemplateDao _tmpltDao;
|
| @Inject ClusterDetailsDao _clusterDetailsDao; |
| @Inject HostDao _hostDao;
|
| @Inject ResourceManager _resourceMgr; |
|
|
| @Override
|
| public Map<? extends ServerResource, Map<String, String>> find(long dcId, Long podId, Long clusterId, URI url,
|
| String username, String password, List<String> hostTags) throws DiscoveryException {
|
|
|
| if(s_logger.isInfoEnabled())
|
| s_logger.info("Discover host. dc: " + dcId + ", pod: " + podId + ", cluster: " + clusterId + ", uri host: " + url.getHost());
|
|
|
| if(podId == null) {
|
| if(s_logger.isInfoEnabled())
|
| s_logger.info("No pod is assigned, assuming that it is not for vmware and skip it to next discoverer");
|
| return null;
|
| }
|
|
|
| ClusterVO cluster = _clusterDao.findById(clusterId);
|
| if(cluster == null || cluster.getHypervisorType() != HypervisorType.VMware) {
|
| if(s_logger.isInfoEnabled())
|
| s_logger.info("invalid cluster id or cluster is not for VMware hypervisors");
|
| return null;
|
| } |
| |
| List<HostVO> hosts = _resourceMgr.listAllHostsInCluster(clusterId); |
| if(hosts.size() >= _vmwareMgr.getMaxHostsPerCluster()) { |
| String msg = "VMware cluster " + cluster.getName() + " is too big to add new host now. (current configured cluster size: " + _vmwareMgr.getMaxHostsPerCluster() + ")"; |
| s_logger.error(msg); |
| throw new DiscoveredWithErrorException(msg); |
| } |
|
|
| VmwareContext context = null;
|
| try {
|
| context = VmwareContextFactory.create(url.getHost(), username, password);
|
| List<ManagedObjectReference> morHosts = _vmwareMgr.addHostToPodCluster(context, dcId, podId, clusterId,
|
| URLDecoder.decode(url.getPath()));
|
| if(morHosts == null) {
|
| s_logger.error("Unable to find host or cluster based on url: " + URLDecoder.decode(url.getPath()));
|
| return null;
|
| }
|
|
|
| ManagedObjectReference morCluster = null;
|
| Map<String, String> clusterDetails = _clusterDetailsDao.findDetails(clusterId);
|
| if(clusterDetails.get("url") != null) {
|
| URI uriFromCluster = new URI(UriUtils.encodeURIComponent(clusterDetails.get("url")));
|
| morCluster = context.getHostMorByPath(URLDecoder.decode(uriFromCluster.getPath()));
|
|
|
| if(morCluster == null || !morCluster.getType().equalsIgnoreCase("ClusterComputeResource")) {
|
| s_logger.warn("Cluster url does not point to a valid vSphere cluster, url: " + clusterDetails.get("url"));
|
| return null;
|
| } else {
|
| ClusterMO clusterMo = new ClusterMO(context, morCluster);
|
| ClusterDasConfigInfo dasConfig = clusterMo.getDasConfig();
|
| if(dasConfig != null && dasConfig.getEnabled() != null && dasConfig.getEnabled().booleanValue()) {
|
| clusterDetails.put("NativeHA", "true");
|
| _clusterDetailsDao.persist(clusterId, clusterDetails);
|
| }
|
| }
|
| }
|
|
|
| if(!validateDiscoveredHosts(context, morCluster, morHosts)) {
|
| if(morCluster == null)
|
| s_logger.warn("The discovered host is not standalone host, can not be added to a standalone cluster");
|
| else
|
| s_logger.warn("The discovered host does not belong to the cluster");
|
| return null;
|
| }
|
|
|
| Map<VmwareResource, Map<String, String>> resources = new HashMap<VmwareResource, Map<String, String>>();
|
| for(ManagedObjectReference morHost : morHosts) {
|
| Map<String, String> details = new HashMap<String, String>();
|
| Map<String, Object> params = new HashMap<String, Object>();
|
|
|
| HostMO hostMo = new HostMO(context, morHost);
|
| details.put("url", hostMo.getHostName());
|
| details.put("username", username);
|
| details.put("password", password);
|
| String guid = morHost.getType() + ":" + morHost.get_value() + "@"+ url.getHost();
|
| details.put("guid", guid);
|
|
|
| params.put("url", hostMo.getHostName());
|
| params.put("username", username);
|
| params.put("password", password);
|
| params.put("zone", Long.toString(dcId));
|
| params.put("pod", Long.toString(podId));
|
| params.put("cluster", Long.toString(clusterId));
|
| params.put("guid", guid);
|
|
|
| VmwareResource resource = new VmwareResource();
|
| try {
|
| resource.configure("VMware", params);
|
| } catch (ConfigurationException e) {
|
| _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, podId, "Unable to add " + url.getHost(), "Error is " + e.getMessage());
|
| s_logger.warn("Unable to instantiate " + url.getHost(), e);
|
| }
|
| resource.start();
|
|
|
| resources.put(resource, details);
|
| }
|
|
|
| // place a place holder guid derived from cluster ID
|
| cluster.setGuid(UUID.nameUUIDFromBytes(String.valueOf(clusterId).getBytes()).toString());
|
| _clusterDao.update(clusterId, cluster);
|
|
|
| return resources;
|
| } catch (DiscoveredWithErrorException e) { |
| throw e; |
| } catch (Exception e) {
|
| s_logger.warn("Unable to connect to Vmware vSphere server. service address: " + url.getHost());
|
| return null;
|
| } finally {
|
| if(context != null)
|
| context.close();
|
| }
|
| }
|
|
|
| private boolean validateDiscoveredHosts(VmwareContext context, ManagedObjectReference morCluster, List<ManagedObjectReference> morHosts) throws Exception {
|
| if(morCluster == null) {
|
| for(ManagedObjectReference morHost : morHosts) {
|
| ManagedObjectReference morParent = (ManagedObjectReference)context.getServiceUtil().getDynamicProperty(morHost, "parent");
|
| if(morParent.getType().equalsIgnoreCase("ClusterComputeResource"))
|
| return false;
|
| }
|
| } else {
|
| for(ManagedObjectReference morHost : morHosts) {
|
| ManagedObjectReference morParent = (ManagedObjectReference)context.getServiceUtil().getDynamicProperty(morHost, "parent");
|
| if(!morParent.getType().equalsIgnoreCase("ClusterComputeResource"))
|
| return false;
|
|
|
| if(!morParent.get_value().equals(morCluster.get_value()))
|
| return false;
|
| }
|
| }
|
|
|
| return true;
|
| }
|
|
|
| @Override
|
| public void postDiscovery(List<HostVO> hosts, long msId) {
|
| // do nothing
|
| }
|
|
|
| @Override
|
| public boolean matchHypervisor(String hypervisor) {
|
| if(hypervisor == null)
|
| return true;
|
|
|
| return Hypervisor.HypervisorType.VMware.toString().equalsIgnoreCase(hypervisor);
|
| }
|
|
|
| @Override
|
| public Hypervisor.HypervisorType getHypervisorType() {
|
| return Hypervisor.HypervisorType.VMware;
|
| }
|
|
|
| @Override
|
| public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
|
| if(s_logger.isInfoEnabled())
|
| s_logger.info("Configure VmwareServerDiscoverer, discover name: " + name);
|
|
|
| super.configure(name, params);
|
|
|
| ComponentLocator locator = ComponentLocator.getCurrentLocator();
|
| ConfigurationDao configDao = locator.getDao(ConfigurationDao.class);
|
| if (configDao == null) {
|
| throw new ConfigurationException("Unable to get the configuration dao.");
|
| }
|
|
|
| createVmwareToolsIso();
|
|
|
| if(s_logger.isInfoEnabled()) {
|
| s_logger.info("VmwareServerDiscoverer has been successfully configured"); |
| } |
| _resourceMgr.registerResourceStateAdapter(this.getClass().getSimpleName(), this);
|
| return true;
|
| }
|
|
|
| private void createVmwareToolsIso() {
|
| String isoName = "vmware-tools.iso";
|
| VMTemplateVO tmplt = _tmpltDao.findByTemplateName(isoName);
|
| Long id;
|
| if (tmplt == null) {
|
| id = _tmpltDao.getNextInSequence(Long.class, "id");
|
| VMTemplateVO template = new VMTemplateVO(id, isoName, isoName, ImageFormat.ISO, true, true,
|
| TemplateType.PERHOST, null, null, true, 64,
|
| Account.ACCOUNT_ID_SYSTEM, null, "VMware Tools Installer ISO", false, 1, false, HypervisorType.VMware);
|
| _tmpltDao.persist(template);
|
| } else {
|
| id = tmplt.getId();
|
| tmplt.setTemplateType(TemplateType.PERHOST);
|
| tmplt.setUrl(null);
|
| _tmpltDao.update(id, tmplt);
|
| }
|
| } |
| |
| @Override |
| public HostVO createHostVOForConnectedAgent(HostVO host, StartupCommand[] cmd) { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| @Override |
| public HostVO createHostVOForDirectConnectAgent(HostVO host, StartupCommand[] startup, ServerResource resource, Map<String, String> details, |
| List<String> hostTags) { |
| StartupCommand firstCmd = startup[0]; |
| if (!(firstCmd instanceof StartupRoutingCommand)) { |
| return null; |
| } |
| |
| StartupRoutingCommand ssCmd = ((StartupRoutingCommand) firstCmd); |
| if (ssCmd.getHypervisorType() != HypervisorType.VMware) { |
| return null; |
| } |
| |
| return _resourceMgr.fillRoutingHostVO(host, ssCmd, HypervisorType.VMware, details, hostTags); |
| } |
| |
| @Override |
| public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) throws UnableDeleteHostException { |
| if (host.getType() != com.cloud.host.Host.Type.Routing || host.getHypervisorType() != HypervisorType.VMware) { |
| return null; |
| } |
| |
| _resourceMgr.deleteRoutingHost(host, isForced, isForceDeleteStorage); |
| return new DeleteHostAnswer(true); |
| } |
| |
| @Override |
| public boolean stop() { |
| _resourceMgr.unregisterResourceStateAdapter(this.getClass().getSimpleName()); |
| return super.stop(); |
| }
|
| }
|
|
|