| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| package com.cloud.resource; |
| |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.net.URLDecoder; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import javax.ejb.Local; |
| import javax.inject.Inject; |
| import javax.naming.ConfigurationException; |
| |
| import org.apache.cloudstack.api.ApiConstants; |
| import org.apache.cloudstack.api.command.admin.cluster.AddClusterCmd; |
| import org.apache.cloudstack.api.command.admin.cluster.DeleteClusterCmd; |
| import org.apache.cloudstack.api.command.admin.host.AddHostCmd; |
| import org.apache.cloudstack.api.command.admin.host.AddSecondaryStorageCmd; |
| import org.apache.cloudstack.api.command.admin.host.CancelMaintenanceCmd; |
| import org.apache.cloudstack.api.command.admin.host.PrepareForMaintenanceCmd; |
| import org.apache.cloudstack.api.command.admin.host.ReconnectHostCmd; |
| import org.apache.cloudstack.api.command.admin.host.UpdateHostCmd; |
| import org.apache.cloudstack.api.command.admin.host.UpdateHostPasswordCmd; |
| import org.apache.cloudstack.api.command.admin.storage.AddS3Cmd; |
| import org.apache.cloudstack.api.command.admin.storage.ListS3sCmd; |
| import org.apache.cloudstack.api.command.admin.swift.AddSwiftCmd; |
| import org.apache.cloudstack.api.command.admin.swift.ListSwiftsCmd; |
| import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; |
| import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; |
| import org.apache.log4j.Logger; |
| import org.springframework.stereotype.Component; |
| |
| import com.cloud.agent.AgentManager; |
| import com.cloud.agent.AgentManager.TapAgentsAction; |
| import com.cloud.agent.api.Answer; |
| import com.cloud.agent.api.GetHostStatsAnswer; |
| import com.cloud.agent.api.GetHostStatsCommand; |
| import com.cloud.agent.api.MaintainAnswer; |
| import com.cloud.agent.api.MaintainCommand; |
| import com.cloud.agent.api.StartupCommand; |
| import com.cloud.agent.api.StartupRoutingCommand; |
| import com.cloud.agent.api.UnsupportedAnswer; |
| import com.cloud.agent.api.UpdateHostPasswordCommand; |
| import com.cloud.agent.manager.AgentAttache; |
| import com.cloud.agent.manager.ClusteredAgentManagerImpl; |
| import com.cloud.agent.manager.allocator.PodAllocator; |
| import com.cloud.agent.transport.Request; |
| import com.cloud.api.ApiDBUtils; |
| import com.cloud.capacity.Capacity; |
| import com.cloud.capacity.CapacityVO; |
| import com.cloud.capacity.dao.CapacityDao; |
| import com.cloud.cluster.ClusterManager; |
| import com.cloud.cluster.ManagementServerNode; |
| import com.cloud.configuration.Config; |
| import com.cloud.configuration.ConfigurationManager; |
| import com.cloud.configuration.dao.ConfigurationDao; |
| import com.cloud.dc.ClusterDetailsDao; |
| import com.cloud.dc.ClusterDetailsVO; |
| import com.cloud.dc.ClusterVO; |
| import com.cloud.dc.DataCenterIpAddressVO; |
| import com.cloud.dc.DataCenterVO; |
| import com.cloud.dc.HostPodVO; |
| import com.cloud.dc.PodCluster; |
| import com.cloud.dc.dao.ClusterDao; |
| import com.cloud.dc.dao.ClusterVSMMapDao; |
| import com.cloud.dc.dao.DataCenterDao; |
| import com.cloud.dc.dao.DataCenterIpAddressDao; |
| import com.cloud.dc.dao.HostPodDao; |
| import com.cloud.deploy.PlannerHostReservationVO; |
| import com.cloud.deploy.dao.PlannerHostReservationDao; |
| import com.cloud.event.ActionEvent; |
| import com.cloud.event.EventTypes; |
| import com.cloud.exception.AgentUnavailableException; |
| import com.cloud.exception.DiscoveryException; |
| import com.cloud.exception.InvalidParameterValueException; |
| import com.cloud.exception.PermissionDeniedException; |
| import com.cloud.exception.ResourceInUseException; |
| import com.cloud.ha.HighAvailabilityManager; |
| import com.cloud.ha.HighAvailabilityManager.WorkType; |
| import com.cloud.host.DetailVO; |
| import com.cloud.host.Host; |
| import com.cloud.host.Host.Type; |
| import com.cloud.host.HostStats; |
| import com.cloud.host.HostVO; |
| import com.cloud.host.Status; |
| import com.cloud.host.Status.Event; |
| import com.cloud.host.dao.HostDao; |
| import com.cloud.host.dao.HostDetailsDao; |
| import com.cloud.host.dao.HostTagsDao; |
| import com.cloud.hypervisor.Hypervisor; |
| import com.cloud.hypervisor.Hypervisor.HypervisorType; |
| import com.cloud.hypervisor.kvm.discoverer.KvmDummyResourceBase; |
| import com.cloud.network.dao.IPAddressDao; |
| import com.cloud.network.dao.IPAddressVO; |
| import com.cloud.org.Cluster; |
| import com.cloud.org.Grouping; |
| import com.cloud.org.Grouping.AllocationState; |
| import com.cloud.org.Managed; |
| import com.cloud.service.ServiceOfferingVO; |
| import com.cloud.storage.GuestOSCategoryVO; |
| import com.cloud.storage.S3; |
| import com.cloud.storage.S3VO; |
| import com.cloud.storage.StorageManager; |
| import com.cloud.storage.StoragePool; |
| import com.cloud.storage.StoragePoolHostVO; |
| import com.cloud.storage.StoragePoolStatus; |
| import com.cloud.storage.StorageService; |
| import com.cloud.storage.Swift; |
| import com.cloud.storage.SwiftVO; |
| import com.cloud.storage.VMTemplateVO; |
| import com.cloud.storage.dao.GuestOSCategoryDao; |
| import com.cloud.storage.dao.StoragePoolHostDao; |
| import com.cloud.storage.dao.VMTemplateDao; |
| import com.cloud.storage.s3.S3Manager; |
| import com.cloud.storage.secondary.SecondaryStorageVmManager; |
| import com.cloud.storage.swift.SwiftManager; |
| import com.cloud.template.VirtualMachineTemplate; |
| import com.cloud.user.Account; |
| import com.cloud.user.AccountManager; |
| import com.cloud.user.User; |
| import com.cloud.user.UserContext; |
| import com.cloud.utils.Pair; |
| import com.cloud.utils.StringUtils; |
| import com.cloud.utils.UriUtils; |
| import com.cloud.utils.component.Manager; |
| import com.cloud.utils.component.ManagerBase; |
| import com.cloud.utils.db.DB; |
| import com.cloud.utils.db.GlobalLock; |
| import com.cloud.utils.db.SearchBuilder; |
| import com.cloud.utils.db.SearchCriteria; |
| import com.cloud.utils.db.SearchCriteria.Op; |
| import com.cloud.utils.db.SearchCriteria2; |
| import com.cloud.utils.db.SearchCriteriaService; |
| import com.cloud.utils.db.Transaction; |
| import com.cloud.utils.exception.CloudRuntimeException; |
| import com.cloud.utils.fsm.NoTransitionException; |
| import com.cloud.utils.net.Ip; |
| import com.cloud.utils.net.NetUtils; |
| import com.cloud.utils.ssh.SSHCmdHelper; |
| import com.cloud.utils.ssh.sshException; |
| import com.cloud.vm.VMInstanceVO; |
| import com.cloud.vm.VirtualMachine.State; |
| import com.cloud.vm.VirtualMachineManager; |
| import com.cloud.vm.dao.VMInstanceDao; |
| |
| @Component |
| @Local({ ResourceManager.class, ResourceService.class }) |
| public class ResourceManagerImpl extends ManagerBase implements ResourceManager, ResourceService, |
| Manager { |
| private static final Logger s_logger = Logger |
| .getLogger(ResourceManagerImpl.class); |
| |
| @Inject |
| AccountManager _accountMgr; |
| @Inject |
| AgentManager _agentMgr; |
| @Inject |
| StorageManager _storageMgr; |
| @Inject |
| protected SecondaryStorageVmManager _secondaryStorageMgr; |
| |
| @Inject |
| protected DataCenterDao _dcDao; |
| @Inject |
| protected HostPodDao _podDao; |
| @Inject |
| protected ClusterDetailsDao _clusterDetailsDao; |
| @Inject |
| protected ClusterDao _clusterDao; |
| @Inject |
| protected CapacityDao _capacityDao; |
| @Inject |
| protected HostDao _hostDao; |
| @Inject |
| protected SwiftManager _swiftMgr; |
| @Inject |
| protected S3Manager _s3Mgr; |
| @Inject |
| protected HostDetailsDao _hostDetailsDao; |
| @Inject |
| protected ConfigurationDao _configDao; |
| @Inject |
| protected HostTagsDao _hostTagsDao; |
| @Inject |
| protected GuestOSCategoryDao _guestOSCategoryDao; |
| @Inject |
| protected PrimaryDataStoreDao _storagePoolDao; |
| @Inject |
| protected DataCenterIpAddressDao _privateIPAddressDao; |
| @Inject |
| protected IPAddressDao _publicIPAddressDao; |
| @Inject |
| protected VirtualMachineManager _vmMgr; |
| @Inject |
| protected VMInstanceDao _vmDao; |
| @Inject |
| protected HighAvailabilityManager _haMgr; |
| @Inject |
| protected StorageService _storageSvr; |
| @Inject |
| PlannerHostReservationDao _plannerHostReserveDao; |
| |
| protected List<? extends Discoverer> _discoverers; |
| public List<? extends Discoverer> getDiscoverers() { |
| return _discoverers; |
| } |
| public void setDiscoverers(List<? extends Discoverer> _discoverers) { |
| this._discoverers = _discoverers; |
| } |
| |
| @Inject |
| protected ClusterManager _clusterMgr; |
| @Inject |
| protected StoragePoolHostDao _storagePoolHostDao; |
| |
| protected List<PodAllocator> _podAllocators; |
| public List<PodAllocator> getPodAllocators() { |
| return _podAllocators; |
| } |
| public void setPodAllocators(List<PodAllocator> _podAllocators) { |
| this._podAllocators = _podAllocators; |
| } |
| |
| @Inject |
| protected VMTemplateDao _templateDao; |
| @Inject |
| protected ConfigurationManager _configMgr; |
| @Inject |
| protected ClusterVSMMapDao _clusterVSMMapDao; |
| |
| protected long _nodeId = ManagementServerNode.getManagementServerId(); |
| |
| protected HashMap<String, ResourceStateAdapter> _resourceStateAdapters = new HashMap<String, ResourceStateAdapter>(); |
| |
| protected HashMap<Integer, List<ResourceListener>> _lifeCycleListeners = new HashMap<Integer, List<ResourceListener>>(); |
| private HypervisorType _defaultSystemVMHypervisor; |
| |
| private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 30; // seconds |
| |
| private void insertListener(Integer event, ResourceListener listener) { |
| List<ResourceListener> lst = _lifeCycleListeners.get(event); |
| if (lst == null) { |
| lst = new ArrayList<ResourceListener>(); |
| _lifeCycleListeners.put(event, lst); |
| } |
| |
| if (lst.contains(listener)) { |
| throw new CloudRuntimeException("Duplicate resource lisener:" |
| + listener.getClass().getSimpleName()); |
| } |
| |
| lst.add(listener); |
| } |
| |
| @Override |
| public void registerResourceEvent(Integer event, ResourceListener listener) { |
| synchronized (_lifeCycleListeners) { |
| if ((event & ResourceListener.EVENT_DISCOVER_BEFORE) != 0) { |
| insertListener(ResourceListener.EVENT_DISCOVER_BEFORE, listener); |
| } |
| if ((event & ResourceListener.EVENT_DISCOVER_AFTER) != 0) { |
| insertListener(ResourceListener.EVENT_DISCOVER_AFTER, listener); |
| } |
| if ((event & ResourceListener.EVENT_DELETE_HOST_BEFORE) != 0) { |
| insertListener(ResourceListener.EVENT_DELETE_HOST_BEFORE, |
| listener); |
| } |
| if ((event & ResourceListener.EVENT_DELETE_HOST_AFTER) != 0) { |
| insertListener(ResourceListener.EVENT_DELETE_HOST_AFTER, |
| listener); |
| } |
| if ((event & ResourceListener.EVENT_CANCEL_MAINTENANCE_BEFORE) != 0) { |
| insertListener( |
| ResourceListener.EVENT_CANCEL_MAINTENANCE_BEFORE, |
| listener); |
| } |
| if ((event & ResourceListener.EVENT_CANCEL_MAINTENANCE_AFTER) != 0) { |
| insertListener(ResourceListener.EVENT_CANCEL_MAINTENANCE_AFTER, |
| listener); |
| } |
| if ((event & ResourceListener.EVENT_PREPARE_MAINTENANCE_BEFORE) != 0) { |
| insertListener( |
| ResourceListener.EVENT_PREPARE_MAINTENANCE_BEFORE, |
| listener); |
| } |
| if ((event & ResourceListener.EVENT_PREPARE_MAINTENANCE_AFTER) != 0) { |
| insertListener( |
| ResourceListener.EVENT_PREPARE_MAINTENANCE_AFTER, |
| listener); |
| } |
| } |
| } |
| |
| @Override |
| public void unregisterResourceEvent(ResourceListener listener) { |
| synchronized (_lifeCycleListeners) { |
| Iterator it = _lifeCycleListeners.entrySet().iterator(); |
| while (it.hasNext()) { |
| Map.Entry<Integer, List<ResourceListener>> items = (Map.Entry<Integer, List<ResourceListener>>) it |
| .next(); |
| List<ResourceListener> lst = items.getValue(); |
| lst.remove(listener); |
| } |
| } |
| } |
| |
| protected void processResourceEvent(Integer event, Object... params) { |
| List<ResourceListener> lst = _lifeCycleListeners.get(event); |
| if (lst == null || lst.size() == 0) { |
| return; |
| } |
| |
| String eventName; |
| for (ResourceListener l : lst) { |
| if (event == ResourceListener.EVENT_DISCOVER_BEFORE) { |
| l.processDiscoverEventBefore((Long) params[0], |
| (Long) params[1], (Long) params[2], (URI) params[3], |
| (String) params[4], (String) params[5], |
| (List<String>) params[6]); |
| eventName = "EVENT_DISCOVER_BEFORE"; |
| } else if (event == ResourceListener.EVENT_DISCOVER_AFTER) { |
| l.processDiscoverEventAfter((Map<? extends ServerResource, Map<String, String>>) params[0]); |
| eventName = "EVENT_DISCOVER_AFTER"; |
| } else if (event == ResourceListener.EVENT_DELETE_HOST_BEFORE) { |
| l.processDeleteHostEventBefore((HostVO) params[0]); |
| eventName = "EVENT_DELETE_HOST_BEFORE"; |
| } else if (event == ResourceListener.EVENT_DELETE_HOST_AFTER) { |
| l.processDeletHostEventAfter((HostVO) params[0]); |
| eventName = "EVENT_DELETE_HOST_AFTER"; |
| } else if (event == ResourceListener.EVENT_CANCEL_MAINTENANCE_BEFORE) { |
| l.processCancelMaintenaceEventBefore((Long) params[0]); |
| eventName = "EVENT_CANCEL_MAINTENANCE_BEFORE"; |
| } else if (event == ResourceListener.EVENT_CANCEL_MAINTENANCE_AFTER) { |
| l.processCancelMaintenaceEventAfter((Long) params[0]); |
| eventName = "EVENT_CANCEL_MAINTENANCE_AFTER"; |
| } else if (event == ResourceListener.EVENT_PREPARE_MAINTENANCE_BEFORE) { |
| l.processPrepareMaintenaceEventBefore((Long) params[0]); |
| eventName = "EVENT_PREPARE_MAINTENANCE_BEFORE"; |
| } else if (event == ResourceListener.EVENT_PREPARE_MAINTENANCE_AFTER) { |
| l.processPrepareMaintenaceEventAfter((Long) params[0]); |
| eventName = "EVENT_PREPARE_MAINTENANCE_AFTER"; |
| } else { |
| throw new CloudRuntimeException("Unknown resource event:" |
| + event); |
| } |
| s_logger.debug("Sent resource event " + eventName + " to listener " |
| + l.getClass().getSimpleName()); |
| } |
| |
| } |
| |
| @DB |
| @Override |
| public List<? extends Cluster> discoverCluster(AddClusterCmd cmd) |
| throws IllegalArgumentException, DiscoveryException, |
| ResourceInUseException { |
| long dcId = cmd.getZoneId(); |
| long podId = cmd.getPodId(); |
| String clusterName = cmd.getClusterName(); |
| String url = cmd.getUrl(); |
| String username = cmd.getUsername(); |
| String password = cmd.getPassword(); |
| |
| if (url != null) { |
| url = URLDecoder.decode(url); |
| } |
| |
| URI uri = null; |
| |
| // Check if the zone exists in the system |
| DataCenterVO zone = _dcDao.findById(dcId); |
| if (zone == null) { |
| InvalidParameterValueException ex = new InvalidParameterValueException( |
| "Can't find zone by the id specified"); |
| ex.addProxyObject(zone, dcId, "dcId"); |
| throw ex; |
| } |
| |
| Account account = UserContext.current().getCaller(); |
| if (Grouping.AllocationState.Disabled == zone.getAllocationState() |
| && !_accountMgr.isRootAdmin(account.getType())) { |
| PermissionDeniedException ex = new PermissionDeniedException( |
| "Cannot perform this operation, Zone with specified id is currently disabled"); |
| ex.addProxyObject(zone, dcId, "dcId"); |
| throw ex; |
| } |
| |
| HostPodVO pod = _podDao.findById(podId); |
| if (pod == null) { |
| throw new InvalidParameterValueException( |
| "Can't find pod with specified podId " + podId); |
| } |
| |
| // Check if the pod exists in the system |
| if (_podDao.findById(podId) == null) { |
| throw new InvalidParameterValueException("Can't find pod by id " |
| + podId); |
| } |
| // check if pod belongs to the zone |
| if (!Long.valueOf(pod.getDataCenterId()).equals(dcId)) { |
| InvalidParameterValueException ex = new InvalidParameterValueException( |
| "Pod with specified id doesn't belong to the zone " + dcId); |
| ex.addProxyObject(pod, podId, "podId"); |
| ex.addProxyObject(zone, dcId, "dcId"); |
| throw ex; |
| } |
| |
| // Verify cluster information and create a new cluster if needed |
| if (clusterName == null || clusterName.isEmpty()) { |
| throw new InvalidParameterValueException( |
| "Please specify cluster name"); |
| } |
| |
| if (cmd.getHypervisor() == null || cmd.getHypervisor().isEmpty()) { |
| throw new InvalidParameterValueException( |
| "Please specify a hypervisor"); |
| } |
| |
| Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType |
| .getType(cmd.getHypervisor()); |
| if (hypervisorType == null) { |
| s_logger.error("Unable to resolve " + cmd.getHypervisor() |
| + " to a valid supported hypervisor type"); |
| throw new InvalidParameterValueException("Unable to resolve " |
| + cmd.getHypervisor() + " to a supported "); |
| } |
| |
| Cluster.ClusterType clusterType = null; |
| if (cmd.getClusterType() != null && !cmd.getClusterType().isEmpty()) { |
| clusterType = Cluster.ClusterType.valueOf(cmd.getClusterType()); |
| } |
| if (clusterType == null) { |
| clusterType = Cluster.ClusterType.CloudManaged; |
| } |
| |
| Grouping.AllocationState allocationState = null; |
| if (cmd.getAllocationState() != null |
| && !cmd.getAllocationState().isEmpty()) { |
| try { |
| allocationState = Grouping.AllocationState.valueOf(cmd |
| .getAllocationState()); |
| } catch (IllegalArgumentException ex) { |
| throw new InvalidParameterValueException( |
| "Unable to resolve Allocation State '" |
| + cmd.getAllocationState() |
| + "' to a supported state"); |
| } |
| } |
| if (allocationState == null) { |
| allocationState = Grouping.AllocationState.Enabled; |
| } |
| |
| Discoverer discoverer = getMatchingDiscover(hypervisorType); |
| if (discoverer == null) { |
| |
| throw new InvalidParameterValueException( |
| "Could not find corresponding resource manager for " |
| + cmd.getHypervisor()); |
| } |
| |
| if (hypervisorType == HypervisorType.VMware) { |
| Map<String, String> allParams = cmd.getFullUrlParams(); |
| discoverer.putParam(allParams); |
| } |
| |
| List<ClusterVO> result = new ArrayList<ClusterVO>(); |
| |
| long clusterId = 0; |
| ClusterVO cluster = new ClusterVO(dcId, podId, clusterName); |
| cluster.setHypervisorType(cmd.getHypervisor()); |
| |
| cluster.setClusterType(clusterType); |
| cluster.setAllocationState(allocationState); |
| try { |
| cluster = _clusterDao.persist(cluster); |
| } catch (Exception e) { |
| // no longer tolerate exception during the cluster creation phase |
| CloudRuntimeException ex = new CloudRuntimeException( |
| "Unable to create cluster " + clusterName |
| + " in pod and data center with specified ids", e); |
| // Get the pod VO object's table name. |
| ex.addProxyObject(pod, podId, "podId"); |
| ex.addProxyObject(zone, dcId, "dcId"); |
| throw ex; |
| } |
| clusterId = cluster.getId(); |
| result.add(cluster); |
| |
| ClusterDetailsVO cluster_detail_cpu = new ClusterDetailsVO(clusterId, "cpuOvercommitRatio", Float.toString(cmd.getCpuOvercommitRatio())); |
| ClusterDetailsVO cluster_detail_ram = new ClusterDetailsVO(clusterId, "memoryOvercommitRatio", Float.toString(cmd.getMemoryOvercommitRatio())); |
| _clusterDetailsDao.persist(cluster_detail_cpu); |
| _clusterDetailsDao.persist(cluster_detail_ram); |
| |
| if (clusterType == Cluster.ClusterType.CloudManaged) { |
| return result; |
| } |
| |
| // save cluster details for later cluster/host cross-checking |
| Map<String, String> details = new HashMap<String, String>(); |
| details.put("url", url); |
| details.put("username", username); |
| details.put("password", password); |
| _clusterDetailsDao.persist(cluster.getId(), details); |
| |
| _clusterDetailsDao.persist(cluster_detail_cpu); |
| _clusterDetailsDao.persist(cluster_detail_ram); |
| //create a new entry only if the overcommit ratios are greater than 1. |
| if(cmd.getCpuOvercommitRatio().compareTo(1f) > 0) { |
| cluster_detail_cpu = new ClusterDetailsVO(clusterId, "cpuOvercommitRatio", Float.toString(cmd.getCpuOvercommitRatio())); |
| _clusterDetailsDao.persist(cluster_detail_cpu); |
| } |
| |
| |
| if(cmd.getMemoryOvercommitRatio().compareTo(1f) > 0) { |
| cluster_detail_ram = new ClusterDetailsVO(clusterId, "memoryOvercommitRatio", Float.toString(cmd.getMemoryOvercommitRatio())); |
| _clusterDetailsDao.persist(cluster_detail_ram); |
| } |
| |
| |
| boolean success = false; |
| try { |
| try { |
| uri = new URI(UriUtils.encodeURIComponent(url)); |
| if (uri.getScheme() == null) { |
| throw new InvalidParameterValueException( |
| "uri.scheme is null " + url |
| + ", add http:// as a prefix"); |
| } else if (uri.getScheme().equalsIgnoreCase("http")) { |
| if (uri.getHost() == null |
| || uri.getHost().equalsIgnoreCase("") |
| || uri.getPath() == null |
| || uri.getPath().equalsIgnoreCase("")) { |
| throw new InvalidParameterValueException( |
| "Your host and/or path is wrong. Make sure it's of the format http://hostname/path"); |
| } |
| } |
| } catch (URISyntaxException e) { |
| throw new InvalidParameterValueException(url |
| + " is not a valid uri"); |
| } |
| |
| List<HostVO> hosts = new ArrayList<HostVO>(); |
| Map<? extends ServerResource, Map<String, String>> resources = null; |
| resources = discoverer.find(dcId, podId, clusterId, uri, username, |
| password, null); |
| |
| if (resources != null) { |
| for (Map.Entry<? extends ServerResource, Map<String, String>> entry : resources |
| .entrySet()) { |
| ServerResource resource = entry.getKey(); |
| |
| // For Hyper-V, we are here means agent have already started |
| // and connected to management server |
| if (hypervisorType == Hypervisor.HypervisorType.Hyperv) { |
| break; |
| } |
| |
| HostVO host = (HostVO) createHostAndAgent(resource, |
| entry.getValue(), true, null, false); |
| if (host != null) { |
| hosts.add(host); |
| } |
| discoverer.postDiscovery(hosts, _nodeId); |
| } |
| s_logger.info("External cluster has been successfully discovered by " |
| + discoverer.getName()); |
| success = true; |
| return result; |
| } |
| |
| s_logger.warn("Unable to find the server resources at " + url); |
| throw new DiscoveryException("Unable to add the external cluster"); |
| } finally { |
| if (!success) { |
| _clusterDetailsDao.deleteDetails(clusterId); |
| _clusterDao.remove(clusterId); |
| } |
| } |
| } |
| |
| @Override |
| public Discoverer getMatchingDiscover( |
| Hypervisor.HypervisorType hypervisorType) { |
| for (Discoverer discoverer : _discoverers) { |
| if (discoverer.getHypervisorType() == hypervisorType) |
| return discoverer; |
| } |
| return null; |
| } |
| |
| @Override |
| public List<? extends Host> discoverHosts(AddHostCmd cmd) |
| throws IllegalArgumentException, DiscoveryException, |
| InvalidParameterValueException { |
| Long dcId = cmd.getZoneId(); |
| Long podId = cmd.getPodId(); |
| Long clusterId = cmd.getClusterId(); |
| String clusterName = cmd.getClusterName(); |
| String url = cmd.getUrl(); |
| String username = cmd.getUsername(); |
| String password = cmd.getPassword(); |
| List<String> hostTags = cmd.getHostTags(); |
| |
| dcId = _accountMgr.checkAccessAndSpecifyAuthority(UserContext.current() |
| .getCaller(), dcId); |
| |
| // this is for standalone option |
| if (clusterName == null && clusterId == null) { |
| clusterName = "Standalone-" + url; |
| } |
| |
| if (clusterId != null) { |
| ClusterVO cluster = _clusterDao.findById(clusterId); |
| if (cluster == null) { |
| InvalidParameterValueException ex = new InvalidParameterValueException( |
| "can not find cluster for specified clusterId"); |
| ex.addProxyObject(cluster, clusterId, "clusterId"); |
| throw ex; |
| } else { |
| if (cluster.getGuid() == null) { |
| List<HostVO> hosts = listAllHostsInCluster(clusterId); |
| if (!hosts.isEmpty()) { |
| CloudRuntimeException ex = new CloudRuntimeException( |
| "Guid is not updated for cluster with specified cluster id; need to wait for hosts in this cluster to come up"); |
| ex.addProxyObject(cluster, clusterId, "clusterId"); |
| throw ex; |
| } |
| } |
| } |
| } |
| |
| return discoverHostsFull(dcId, podId, clusterId, clusterName, url, username, password, cmd.getHypervisor(), hostTags, cmd.getFullUrlParams(), true); |
| } |
| |
| @Override |
| public List<? extends Host> discoverHosts(AddSecondaryStorageCmd cmd) |
| throws IllegalArgumentException, DiscoveryException, |
| InvalidParameterValueException { |
| Long dcId = cmd.getZoneId(); |
| String url = cmd.getUrl(); |
| return discoverHostsFull(dcId, null, null, null, url, null, null, "SecondaryStorage", null, null, false); |
| } |
| |
| @Override |
| public Swift discoverSwift(AddSwiftCmd cmd) throws DiscoveryException { |
| return _swiftMgr.addSwift(cmd); |
| } |
| |
| @Override |
| public Pair<List<? extends Swift>, Integer> listSwifts(ListSwiftsCmd cmd) { |
| Pair<List<SwiftVO>, Integer> swifts = _swiftMgr.listSwifts(cmd); |
| return new Pair<List<? extends Swift>, Integer>(swifts.first(), swifts.second()); |
| } |
| |
| @Override |
| public S3 discoverS3(final AddS3Cmd cmd) throws DiscoveryException { |
| return this._s3Mgr.addS3(cmd); |
| } |
| |
| @Override |
| public List<S3VO> listS3s(final ListS3sCmd cmd) { |
| return this._s3Mgr.listS3s(cmd); |
| } |
| |
| private List<HostVO> discoverHostsFull(Long dcId, Long podId, Long clusterId, String clusterName, String url, String username, String password, String hypervisorType, List<String> hostTags, |
| Map<String, String> params, boolean deferAgentCreation) throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException { |
| URI uri = null; |
| |
| // Check if the zone exists in the system |
| DataCenterVO zone = _dcDao.findById(dcId); |
| if (zone == null) { |
| throw new InvalidParameterValueException("Can't find zone by id " |
| + dcId); |
| } |
| |
| Account account = UserContext.current().getCaller(); |
| if (Grouping.AllocationState.Disabled == zone.getAllocationState() |
| && !_accountMgr.isRootAdmin(account.getType())) { |
| PermissionDeniedException ex = new PermissionDeniedException( |
| "Cannot perform this operation, Zone with specified id is currently disabled"); |
| ex.addProxyObject(zone, dcId, "dcId"); |
| throw ex; |
| } |
| |
| // Check if the pod exists in the system |
| if (podId != null) { |
| HostPodVO pod = _podDao.findById(podId); |
| if (pod == null) { |
| throw new InvalidParameterValueException( |
| "Can't find pod by id " + podId); |
| } |
| // check if pod belongs to the zone |
| if (!Long.valueOf(pod.getDataCenterId()).equals(dcId)) { |
| InvalidParameterValueException ex = new InvalidParameterValueException( |
| "Pod with specified podId" |
| + podId |
| + " doesn't belong to the zone with specified zoneId" |
| + dcId); |
| ex.addProxyObject(pod, podId, "podId"); |
| ex.addProxyObject(zone, dcId, "dcId"); |
| throw ex; |
| } |
| } |
| |
| // Verify cluster information and create a new cluster if needed |
| if (clusterName != null && clusterId != null) { |
| throw new InvalidParameterValueException( |
| "Can't specify cluster by both id and name"); |
| } |
| |
| if (hypervisorType == null || hypervisorType.isEmpty()) { |
| throw new InvalidParameterValueException( |
| "Need to specify Hypervisor Type"); |
| } |
| |
| if ((clusterName != null || clusterId != null) && podId == null) { |
| throw new InvalidParameterValueException( |
| "Can't specify cluster without specifying the pod"); |
| } |
| |
| if (clusterId != null) { |
| if (_clusterDao.findById(clusterId) == null) { |
| throw new InvalidParameterValueException( |
| "Can't find cluster by id " + clusterId); |
| } |
| |
| if (hypervisorType.equalsIgnoreCase(HypervisorType.VMware |
| .toString())) { |
| // VMware only allows adding host to an existing cluster, as we |
| // already have a lot of information |
| // in cluster object, to simplify user input, we will construct |
| // neccessary information here |
| Map<String, String> clusterDetails = this._clusterDetailsDao |
| .findDetails(clusterId); |
| username = clusterDetails.get("username"); |
| assert (username != null); |
| |
| password = clusterDetails.get("password"); |
| assert (password != null); |
| |
| try { |
| uri = new URI(UriUtils.encodeURIComponent(url)); |
| |
| url = clusterDetails.get("url") + "/" + uri.getHost(); |
| } catch (URISyntaxException e) { |
| throw new InvalidParameterValueException(url |
| + " is not a valid uri"); |
| } |
| } |
| } |
| |
| if (clusterName != null) { |
| HostPodVO pod = _podDao.findById(podId); |
| if (pod == null) { |
| throw new InvalidParameterValueException( |
| "Can't find pod by id " + podId); |
| } |
| ClusterVO cluster = new ClusterVO(dcId, podId, clusterName); |
| cluster.setHypervisorType(hypervisorType); |
| try { |
| cluster = _clusterDao.persist(cluster); |
| } catch (Exception e) { |
| cluster = _clusterDao.findBy(clusterName, podId); |
| if (cluster == null) { |
| CloudRuntimeException ex = new CloudRuntimeException( |
| "Unable to create cluster " |
| + clusterName |
| + " in pod with specified podId and data center with specified dcID", |
| e); |
| ex.addProxyObject(pod, podId, "podId"); |
| ex.addProxyObject(zone, dcId, "dcId"); |
| throw ex; |
| } |
| } |
| clusterId = cluster.getId(); |
| if (_clusterDetailsDao.findDetail(clusterId,"cpuOvercommitRatio") == null) { |
| ClusterDetailsVO cluster_cpu_detail = new ClusterDetailsVO(clusterId,"cpuOvercommitRatio","1"); |
| ClusterDetailsVO cluster_memory_detail = new ClusterDetailsVO(clusterId,"memoryOvercommitRatio","1"); |
| _clusterDetailsDao.persist(cluster_cpu_detail); |
| _clusterDetailsDao.persist(cluster_memory_detail); |
| } |
| |
| } |
| |
| try { |
| uri = new URI(UriUtils.encodeURIComponent(url)); |
| if (uri.getScheme() == null) { |
| throw new InvalidParameterValueException("uri.scheme is null " |
| + url + ", add nfs:// as a prefix"); |
| } else if (uri.getScheme().equalsIgnoreCase("nfs")) { |
| if (uri.getHost() == null || uri.getHost().equalsIgnoreCase("") |
| || uri.getPath() == null |
| || uri.getPath().equalsIgnoreCase("")) { |
| throw new InvalidParameterValueException( |
| "Your host and/or path is wrong. Make sure it's of the format nfs://hostname/path"); |
| } |
| } |
| } catch (URISyntaxException e) { |
| throw new InvalidParameterValueException(url |
| + " is not a valid uri"); |
| } |
| |
| List<HostVO> hosts = new ArrayList<HostVO>(); |
| s_logger.info("Trying to add a new host at " + url + " in data center " |
| + dcId); |
| boolean isHypervisorTypeSupported = false; |
| for (Discoverer discoverer : _discoverers) { |
| if (params != null) { |
| discoverer.putParam(params); |
| } |
| |
| if (!discoverer.matchHypervisor(hypervisorType)) { |
| continue; |
| } |
| isHypervisorTypeSupported = true; |
| Map<? extends ServerResource, Map<String, String>> resources = null; |
| |
| processResourceEvent(ResourceListener.EVENT_DISCOVER_BEFORE, dcId, |
| podId, clusterId, uri, username, password, hostTags); |
| try { |
| resources = discoverer.find(dcId, podId, clusterId, uri, |
| username, password, hostTags); |
| } catch (DiscoveryException e) { |
| throw e; |
| } catch (Exception e) { |
| s_logger.info("Exception in host discovery process with discoverer: " |
| + discoverer.getName() |
| + ", skip to another discoverer if there is any"); |
| } |
| processResourceEvent(ResourceListener.EVENT_DISCOVER_AFTER, |
| resources); |
| |
| if (resources != null) { |
| for (Map.Entry<? extends ServerResource, Map<String, String>> entry : resources |
| .entrySet()) { |
| ServerResource resource = entry.getKey(); |
| /* |
| * For KVM, if we go to here, that means kvm agent is |
| * already connected to mgt svr. |
| */ |
| if (resource instanceof KvmDummyResourceBase) { |
| Map<String, String> details = entry.getValue(); |
| String guid = details.get("guid"); |
| List<HostVO> kvmHosts = listAllUpAndEnabledHosts( |
| Host.Type.Routing, clusterId, podId, dcId); |
| for (HostVO host : kvmHosts) { |
| if (host.getGuid().equalsIgnoreCase(guid)) { |
| if (hostTags != null) { |
| if (s_logger.isTraceEnabled()) { |
| s_logger.trace("Adding Host Tags for KVM host, tags: :" |
| + hostTags); |
| } |
| _hostTagsDao |
| .persist(host.getId(), hostTags); |
| } |
| hosts.add(host); |
| return hosts; |
| } |
| } |
| return null; |
| } |
| |
| HostVO host = null; |
| if (deferAgentCreation) { |
| host = (HostVO)createHostAndAgentDeferred(resource, entry.getValue(), true, hostTags, false); |
| } else { |
| host = (HostVO)createHostAndAgent(resource, entry.getValue(), true, hostTags, false); |
| } |
| if (host != null) { |
| hosts.add(host); |
| } |
| discoverer.postDiscovery(hosts, _nodeId); |
| |
| } |
| s_logger.info("server resources successfully discovered by " |
| + discoverer.getName()); |
| return hosts; |
| } |
| } |
| if (!isHypervisorTypeSupported) { |
| String msg = "Do not support HypervisorType " + hypervisorType |
| + " for " + url; |
| s_logger.warn(msg); |
| throw new DiscoveryException(msg); |
| } |
| s_logger.warn("Unable to find the server resources at " + url); |
| throw new DiscoveryException("Unable to add the host"); |
| } |
| |
| @Override |
| public Host getHost(long hostId) { |
| return _hostDao.findById(hostId); |
| } |
| |
| @DB |
| protected boolean doDeleteHost(long hostId, boolean isForced, |
| boolean isForceDeleteStorage) { |
| User caller = _accountMgr.getActiveUser(UserContext.current() |
| .getCallerUserId()); |
| // Verify that host exists |
| HostVO host = _hostDao.findById(hostId); |
| if (host == null) { |
| throw new InvalidParameterValueException("Host with id " + hostId |
| + " doesn't exist"); |
| } |
| _accountMgr.checkAccessAndSpecifyAuthority(UserContext.current() |
| .getCaller(), host.getDataCenterId()); |
| |
| /* |
| * TODO: check current agent status and updateAgentStatus to removed. If |
| * it was already removed, that means someone is deleting host |
| * concurrently, return. And consider the situation of CloudStack |
| * shutdown during delete. A global lock? |
| */ |
| AgentAttache attache = _agentMgr.findAttache(hostId); |
| // Get storage pool host mappings here because they can be removed as a |
| // part of handleDisconnect later |
| // TODO: find out the bad boy, what's a buggy logic! |
| List<StoragePoolHostVO> pools = _storagePoolHostDao |
| .listByHostIdIncludingRemoved(hostId); |
| |
| ResourceStateAdapter.DeleteHostAnswer answer = (ResourceStateAdapter.DeleteHostAnswer) dispatchToStateAdapters( |
| ResourceStateAdapter.Event.DELETE_HOST, false, host, |
| new Boolean(isForced), new Boolean(isForceDeleteStorage)); |
| |
| if (answer == null) { |
| throw new CloudRuntimeException( |
| "No resource adapter respond to DELETE_HOST event for " |
| + host.getName() + " id = " + hostId |
| + ", hypervisorType is " + host.getHypervisorType() |
| + ", host type is " + host.getType()); |
| } |
| |
| if (answer.getIsException()) { |
| return false; |
| } |
| |
| if (!answer.getIsContinue()) { |
| return true; |
| } |
| |
| Transaction txn = Transaction.currentTxn(); |
| txn.start(); |
| |
| _dcDao.releasePrivateIpAddress(host.getPrivateIpAddress(), |
| host.getDataCenterId(), null); |
| _agentMgr.disconnectWithoutInvestigation(hostId, Status.Event.Remove); |
| |
| // delete host details |
| _hostDetailsDao.deleteDetails(hostId); |
| |
| host.setGuid(null); |
| Long clusterId = host.getClusterId(); |
| host.setClusterId(null); |
| _hostDao.update(host.getId(), host); |
| |
| _hostDao.remove(hostId); |
| if (clusterId != null) { |
| List<HostVO> hosts = listAllHostsInCluster(clusterId); |
| if (hosts.size() == 0) { |
| ClusterVO cluster = _clusterDao.findById(clusterId); |
| cluster.setGuid(null); |
| _clusterDao.update(clusterId, cluster); |
| } |
| } |
| |
| try { |
| resourceStateTransitTo(host, ResourceState.Event.DeleteHost, |
| _nodeId); |
| } catch (NoTransitionException e) { |
| s_logger.debug("Cannot transmit host " + host.getId() |
| + "to Enabled state", e); |
| } |
| |
| // Delete the associated entries in host ref table |
| _storagePoolHostDao.deletePrimaryRecordsForHost(hostId); |
| |
| // For pool ids you got, delete local storage host entries in pool table |
| // where |
| for (StoragePoolHostVO pool : pools) { |
| Long poolId = pool.getPoolId(); |
| StoragePoolVO storagePool = _storagePoolDao.findById(poolId); |
| if (storagePool.isLocal() && isForceDeleteStorage) { |
| storagePool.setUuid(null); |
| storagePool.setClusterId(null); |
| _storagePoolDao.update(poolId, storagePool); |
| _storagePoolDao.remove(poolId); |
| s_logger.debug("Local storage id=" + poolId |
| + " is removed as a part of host removal id=" + hostId); |
| } |
| } |
| |
| // delete the op_host_capacity entry |
| Object[] capacityTypes = { Capacity.CAPACITY_TYPE_CPU, |
| Capacity.CAPACITY_TYPE_MEMORY }; |
| SearchCriteria<CapacityVO> hostCapacitySC = _capacityDao |
| .createSearchCriteria(); |
| hostCapacitySC.addAnd("hostOrPoolId", SearchCriteria.Op.EQ, hostId); |
| hostCapacitySC.addAnd("capacityType", SearchCriteria.Op.IN, |
| capacityTypes); |
| _capacityDao.remove(hostCapacitySC); |
| txn.commit(); |
| return true; |
| } |
| |
| @Override |
| public boolean deleteHost(long hostId, boolean isForced, |
| boolean isForceDeleteStorage) { |
| try { |
| Boolean result = _clusterMgr.propagateResourceEvent(hostId, |
| ResourceState.Event.DeleteHost); |
| if (result != null) { |
| return result; |
| } |
| } catch (AgentUnavailableException e) { |
| return false; |
| } |
| |
| return doDeleteHost(hostId, isForced, isForceDeleteStorage); |
| } |
| |
| @Override |
| @DB |
| public boolean deleteCluster(DeleteClusterCmd cmd) { |
| Transaction txn = Transaction.currentTxn(); |
| try { |
| txn.start(); |
| ClusterVO cluster = _clusterDao.lockRow(cmd.getId(), true); |
| if (cluster == null) { |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Cluster: " + cmd.getId() |
| + " does not even exist. Delete call is ignored."); |
| } |
| txn.rollback(); |
| throw new CloudRuntimeException("Cluster: " + cmd.getId() |
| + " does not exist"); |
| } |
| |
| Hypervisor.HypervisorType hypervisorType = cluster |
| .getHypervisorType(); |
| |
| List<HostVO> hosts = listAllHostsInCluster(cmd.getId()); |
| if (hosts.size() > 0) { |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Cluster: " + cmd.getId() |
| + " still has hosts, can't remove"); |
| } |
| txn.rollback(); |
| throw new CloudRuntimeException("Cluster: " + cmd.getId() |
| + " cannot be removed. Cluster still has hosts"); |
| } |
| |
| // don't allow to remove the cluster if it has non-removed storage |
| // pools |
| List<StoragePoolVO> storagePools = _storagePoolDao |
| .listPoolsByCluster(cmd.getId()); |
| if (storagePools.size() > 0) { |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Cluster: " + cmd.getId() |
| + " still has storage pools, can't remove"); |
| } |
| txn.rollback(); |
| throw new CloudRuntimeException("Cluster: " + cmd.getId() |
| + " cannot be removed. Cluster still has storage pools"); |
| } |
| |
| if (_clusterDao.remove(cmd.getId())) { |
| _capacityDao.removeBy(null, null, null, cluster.getId(), null); |
| // If this cluster is of type vmware, and if the nexus vswitch |
| // global parameter setting is turned |
| // on, remove the row in cluster_vsm_map for this cluster id. |
| if (hypervisorType == HypervisorType.VMware |
| && Boolean.parseBoolean(_configDao |
| .getValue(Config.VmwareUseNexusVSwitch |
| .toString()))) { |
| _clusterVSMMapDao.removeByClusterId(cmd.getId()); |
| } |
| } |
| |
| txn.commit(); |
| return true; |
| } catch (CloudRuntimeException e) { |
| throw e; |
| } catch (Throwable t) { |
| s_logger.error("Unable to delete cluster: " + cmd.getId(), t); |
| txn.rollback(); |
| return false; |
| } |
| } |
| |
| @Override |
| @DB |
| public Cluster updateCluster(Cluster clusterToUpdate, String clusterType, |
| String hypervisor, String allocationState, String managedstate,Float memoryovercommitratio, Float cpuovercommitratio) { |
| |
| ClusterVO cluster = (ClusterVO) clusterToUpdate; |
| // Verify cluster information and update the cluster if needed |
| boolean doUpdate = false; |
| |
| if (hypervisor != null && !hypervisor.isEmpty()) { |
| Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType |
| .getType(hypervisor); |
| if (hypervisorType == null) { |
| s_logger.error("Unable to resolve " + hypervisor |
| + " to a valid supported hypervisor type"); |
| throw new InvalidParameterValueException("Unable to resolve " |
| + hypervisor + " to a supported type"); |
| } else { |
| cluster.setHypervisorType(hypervisor); |
| doUpdate = true; |
| } |
| } |
| |
| Cluster.ClusterType newClusterType = null; |
| if (clusterType != null && !clusterType.isEmpty()) { |
| try { |
| newClusterType = Cluster.ClusterType.valueOf(clusterType); |
| } catch (IllegalArgumentException ex) { |
| throw new InvalidParameterValueException("Unable to resolve " |
| + clusterType + " to a supported type"); |
| } |
| if (newClusterType == null) { |
| s_logger.error("Unable to resolve " + clusterType |
| + " to a valid supported cluster type"); |
| throw new InvalidParameterValueException("Unable to resolve " |
| + clusterType + " to a supported type"); |
| } else { |
| cluster.setClusterType(newClusterType); |
| doUpdate = true; |
| } |
| } |
| |
| Grouping.AllocationState newAllocationState = null; |
| if (allocationState != null && !allocationState.isEmpty()) { |
| try { |
| newAllocationState = Grouping.AllocationState |
| .valueOf(allocationState); |
| } catch (IllegalArgumentException ex) { |
| throw new InvalidParameterValueException( |
| "Unable to resolve Allocation State '" |
| + allocationState + "' to a supported state"); |
| } |
| if (newAllocationState == null) { |
| s_logger.error("Unable to resolve " + allocationState |
| + " to a valid supported allocation State"); |
| throw new InvalidParameterValueException("Unable to resolve " |
| + allocationState + " to a supported state"); |
| } else { |
| _capacityDao.updateCapacityState(null, null, cluster.getId(), |
| null, allocationState); |
| cluster.setAllocationState(newAllocationState); |
| doUpdate = true; |
| } |
| } |
| |
| Managed.ManagedState newManagedState = null; |
| Managed.ManagedState oldManagedState = cluster.getManagedState(); |
| if (managedstate != null && !managedstate.isEmpty()) { |
| try { |
| newManagedState = Managed.ManagedState.valueOf(managedstate); |
| } catch (IllegalArgumentException ex) { |
| throw new InvalidParameterValueException( |
| "Unable to resolve Managed State '" + managedstate |
| + "' to a supported state"); |
| } |
| if (newManagedState == null) { |
| s_logger.error("Unable to resolve Managed State '" |
| + managedstate + "' to a supported state"); |
| throw new InvalidParameterValueException( |
| "Unable to resolve Managed State '" + managedstate |
| + "' to a supported state"); |
| } else { |
| doUpdate = true; |
| } |
| } |
| |
| if (memoryovercommitratio != null) { |
| ClusterDetailsVO memory_detail = _clusterDetailsDao.findDetail(cluster.getId(),"memoryOvercommitRatio"); |
| memory_detail.setValue(Float.toString(memoryovercommitratio)); |
| _clusterDetailsDao.update(memory_detail.getId(),memory_detail); |
| } |
| |
| if (cpuovercommitratio != null) { |
| ClusterDetailsVO cpu_detail = _clusterDetailsDao.findDetail(cluster.getId(),"cpuOvercommitRatio"); |
| cpu_detail.setValue(Float.toString(cpuovercommitratio)); |
| _clusterDetailsDao.update(cpu_detail.getId(),cpu_detail); |
| } |
| |
| |
| if (doUpdate) { |
| Transaction txn = Transaction.currentTxn(); |
| try { |
| txn.start(); |
| _clusterDao.update(cluster.getId(), cluster); |
| txn.commit(); |
| } catch (Exception e) { |
| s_logger.error( |
| "Unable to update cluster due to " + e.getMessage(), e); |
| throw new CloudRuntimeException( |
| "Failed to update cluster. Please contact Cloud Support."); |
| } |
| } |
| |
| if (newManagedState != null && !newManagedState.equals(oldManagedState)) { |
| Transaction txn = Transaction.currentTxn(); |
| if (newManagedState.equals(Managed.ManagedState.Unmanaged)) { |
| boolean success = false; |
| try { |
| txn.start(); |
| cluster.setManagedState(Managed.ManagedState.PrepareUnmanaged); |
| _clusterDao.update(cluster.getId(), cluster); |
| txn.commit(); |
| List<HostVO> hosts = listAllUpAndEnabledHosts( |
| Host.Type.Routing, cluster.getId(), |
| cluster.getPodId(), cluster.getDataCenterId()); |
| for (HostVO host : hosts) { |
| if (host.getType().equals(Host.Type.Routing) |
| && !host.getStatus().equals(Status.Down) |
| && !host.getStatus() |
| .equals(Status.Disconnected) |
| && !host.getStatus().equals(Status.Up) |
| && !host.getStatus().equals(Status.Alert)) { |
| String msg = "host " + host.getPrivateIpAddress() |
| + " should not be in " |
| + host.getStatus().toString() + " status"; |
| throw new CloudRuntimeException( |
| "PrepareUnmanaged Failed due to " + msg); |
| } |
| } |
| |
| for (HostVO host : hosts) { |
| if (host.getStatus().equals(Status.Up)) { |
| umanageHost(host.getId()); |
| } |
| } |
| int retry = 40; |
| boolean lsuccess = true; |
| for (int i = 0; i < retry; i++) { |
| lsuccess = true; |
| try { |
| Thread.sleep(5 * 1000); |
| } catch (Exception e) { |
| } |
| hosts = listAllUpAndEnabledHosts(Host.Type.Routing, |
| cluster.getId(), cluster.getPodId(), |
| cluster.getDataCenterId()); |
| for (HostVO host : hosts) { |
| if (!host.getStatus().equals(Status.Down) |
| && !host.getStatus().equals( |
| Status.Disconnected) |
| && !host.getStatus().equals(Status.Alert)) { |
| lsuccess = false; |
| break; |
| } |
| } |
| if (lsuccess == true) { |
| success = true; |
| break; |
| } |
| } |
| if (success == false) { |
| throw new CloudRuntimeException( |
| "PrepareUnmanaged Failed due to some hosts are still in UP status after 5 Minutes, please try later "); |
| } |
| } finally { |
| txn.start(); |
| cluster.setManagedState(success ? Managed.ManagedState.Unmanaged |
| : Managed.ManagedState.PrepareUnmanagedError); |
| _clusterDao.update(cluster.getId(), cluster); |
| txn.commit(); |
| } |
| } else if (newManagedState.equals(Managed.ManagedState.Managed)) { |
| txn.start(); |
| cluster.setManagedState(Managed.ManagedState.Managed); |
| _clusterDao.update(cluster.getId(), cluster); |
| txn.commit(); |
| } |
| |
| } |
| |
| return cluster; |
| } |
| |
| @Override |
| public Host cancelMaintenance(CancelMaintenanceCmd cmd) { |
| Long hostId = cmd.getId(); |
| |
| // verify input parameters |
| HostVO host = _hostDao.findById(hostId); |
| if (host == null || host.getRemoved() != null) { |
| throw new InvalidParameterValueException("Host with id " |
| + hostId.toString() + " doesn't exist"); |
| } |
| |
| processResourceEvent(ResourceListener.EVENT_CANCEL_MAINTENANCE_BEFORE, |
| hostId); |
| boolean success = cancelMaintenance(hostId); |
| processResourceEvent(ResourceListener.EVENT_CANCEL_MAINTENANCE_AFTER, |
| hostId); |
| if (!success) { |
| throw new CloudRuntimeException( |
| "Internal error cancelling maintenance."); |
| } |
| return host; |
| } |
| |
| @Override |
| public Host reconnectHost(ReconnectHostCmd cmd) { |
| Long hostId = cmd.getId(); |
| |
| HostVO host = _hostDao.findById(hostId); |
| if (host == null) { |
| throw new InvalidParameterValueException("Host with id " |
| + hostId.toString() + " doesn't exist"); |
| } |
| |
| return (_agentMgr.reconnect(hostId) ? host : null); |
| } |
| |
| @Override |
| public boolean resourceStateTransitTo(Host host, ResourceState.Event event, |
| long msId) throws NoTransitionException { |
| ResourceState currentState = host.getResourceState(); |
| ResourceState nextState = currentState.getNextState(event); |
| if (nextState == null) { |
| throw new NoTransitionException( |
| "No next resource state found for current state =" |
| + currentState + " event =" + event); |
| } |
| |
| // TO DO - Make it more granular and have better conversion into |
| // capacity type |
| |
| if (host.getType() == Type.Routing && host.getClusterId() != null) { |
| AllocationState capacityState = _configMgr |
| .findClusterAllocationState(ApiDBUtils.findClusterById(host |
| .getClusterId())); |
| if (capacityState == AllocationState.Enabled |
| && nextState != ResourceState.Enabled) { |
| capacityState = AllocationState.Disabled; |
| } |
| _capacityDao.updateCapacityState(null, null, null, host.getId(), |
| capacityState.toString()); |
| } |
| return _hostDao.updateResourceState(currentState, event, nextState, |
| host); |
| } |
| |
| private boolean doMaintain(final long hostId) { |
| HostVO host = _hostDao.findById(hostId); |
| MaintainAnswer answer = (MaintainAnswer) _agentMgr.easySend(hostId, |
| new MaintainCommand()); |
| if (answer == null || !answer.getResult()) { |
| s_logger.warn("Unable to send MaintainCommand to host: " + hostId); |
| } |
| |
| try { |
| resourceStateTransitTo(host, |
| ResourceState.Event.AdminAskMaintenace, _nodeId); |
| } catch (NoTransitionException e) { |
| String err = "Cannot transimit resource state of host " |
| + host.getId() + " to " + ResourceState.Maintenance; |
| s_logger.debug(err, e); |
| throw new CloudRuntimeException(err + e.getMessage()); |
| } |
| |
| _agentMgr.pullAgentToMaintenance(hostId); |
| |
| /* TODO: move below to listener */ |
| if (host.getType() == Host.Type.Routing) { |
| |
| final List<VMInstanceVO> vms = _vmDao.listByHostId(hostId); |
| if (vms.size() == 0) { |
| return true; |
| } |
| |
| List<HostVO> hosts = listAllUpAndEnabledHosts(Host.Type.Routing, |
| host.getClusterId(), host.getPodId(), |
| host.getDataCenterId()); |
| for (final VMInstanceVO vm : vms) { |
| if (hosts == null || hosts.isEmpty() || !answer.getMigrate()) { |
| // for the last host in this cluster, stop all the VMs |
| _haMgr.scheduleStop(vm, hostId, WorkType.ForceStop); |
| } else { |
| _haMgr.scheduleMigration(vm); |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public boolean maintain(final long hostId) throws AgentUnavailableException { |
| Boolean result = _clusterMgr.propagateResourceEvent(hostId, |
| ResourceState.Event.AdminAskMaintenace); |
| if (result != null) { |
| return result; |
| } |
| |
| return doMaintain(hostId); |
| } |
| |
| @Override |
| public Host maintain(PrepareForMaintenanceCmd cmd) { |
| Long hostId = cmd.getId(); |
| HostVO host = _hostDao.findById(hostId); |
| |
| if (host == null) { |
| s_logger.debug("Unable to find host " + hostId); |
| throw new InvalidParameterValueException( |
| "Unable to find host with ID: " + hostId |
| + ". Please specify a valid host ID."); |
| } |
| |
| if (_hostDao.countBy(host.getClusterId(), |
| ResourceState.PrepareForMaintenance, |
| ResourceState.ErrorInMaintenance) > 0) { |
| throw new InvalidParameterValueException( |
| "There are other servers in PrepareForMaintenance OR ErrorInMaintenance STATUS in cluster " |
| + host.getClusterId()); |
| } |
| |
| if (_storageMgr.isLocalStorageActiveOnHost(host.getId())) { |
| throw new InvalidParameterValueException( |
| "There are active VMs using the host's local storage pool. Please stop all VMs on this host that use local storage."); |
| } |
| |
| try { |
| processResourceEvent( |
| ResourceListener.EVENT_PREPARE_MAINTENANCE_BEFORE, hostId); |
| if (maintain(hostId)) { |
| processResourceEvent( |
| ResourceListener.EVENT_PREPARE_MAINTENANCE_AFTER, |
| hostId); |
| return _hostDao.findById(hostId); |
| } else { |
| throw new CloudRuntimeException( |
| "Unable to prepare for maintenance host " + hostId); |
| } |
| } catch (AgentUnavailableException e) { |
| throw new CloudRuntimeException( |
| "Unable to prepare for maintenance host " + hostId); |
| } |
| } |
| |
| @Override |
| public Host updateHost(UpdateHostCmd cmd) throws NoTransitionException { |
| Long hostId = cmd.getId(); |
| Long guestOSCategoryId = cmd.getOsCategoryId(); |
| |
| // Verify that the host exists |
| HostVO host = _hostDao.findById(hostId); |
| if (host == null) { |
| throw new InvalidParameterValueException("Host with id " + hostId |
| + " doesn't exist"); |
| } |
| |
| if (cmd.getAllocationState() != null) { |
| ResourceState.Event resourceEvent = ResourceState.Event.toEvent(cmd |
| .getAllocationState()); |
| if (resourceEvent != ResourceState.Event.Enable |
| && resourceEvent != ResourceState.Event.Disable) { |
| throw new CloudRuntimeException("Invalid allocation state:" |
| + cmd.getAllocationState() |
| + ", only Enable/Disable are allowed"); |
| } |
| |
| resourceStateTransitTo(host, resourceEvent, _nodeId); |
| } |
| |
| if (guestOSCategoryId != null) { |
| // Verify that the guest OS Category exists |
| if (guestOSCategoryId > 0) { |
| if (_guestOSCategoryDao.findById(guestOSCategoryId) == null) { |
| throw new InvalidParameterValueException( |
| "Please specify a valid guest OS category."); |
| } |
| } |
| |
| GuestOSCategoryVO guestOSCategory = _guestOSCategoryDao |
| .findById(guestOSCategoryId); |
| Map<String, String> hostDetails = _hostDetailsDao |
| .findDetails(hostId); |
| |
| if (guestOSCategory != null |
| && !GuestOSCategoryVO.CATEGORY_NONE |
| .equalsIgnoreCase(guestOSCategory.getName())) { |
| // Save a new entry for guest.os.category.id |
| hostDetails.put("guest.os.category.id", |
| String.valueOf(guestOSCategory.getId())); |
| } else { |
| // Delete any existing entry for guest.os.category.id |
| hostDetails.remove("guest.os.category.id"); |
| } |
| _hostDetailsDao.persist(hostId, hostDetails); |
| } |
| |
| List<String> hostTags = cmd.getHostTags(); |
| if (hostTags != null) { |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Updating Host Tags to :" + hostTags); |
| } |
| _hostTagsDao.persist(hostId, hostTags); |
| } |
| |
| String url = cmd.getUrl(); |
| if (url != null) { |
| _storageMgr.updateSecondaryStorage(cmd.getId(), cmd.getUrl()); |
| } |
| |
| HostVO updatedHost = _hostDao.findById(hostId); |
| return updatedHost; |
| } |
| |
| @Override |
| public Cluster getCluster(Long clusterId) { |
| return _clusterDao.findById(clusterId); |
| } |
| |
| @Override |
| public boolean configure(String name, Map<String, Object> params) |
| throws ConfigurationException { |
| _defaultSystemVMHypervisor = HypervisorType.getType(_configDao |
| .getValue(Config.SystemVMDefaultHypervisor.toString())); |
| return true; |
| } |
| |
| @Override |
| public List<HypervisorType> getSupportedHypervisorTypes(long zoneId, |
| boolean forVirtualRouter, Long podId) { |
| List<HypervisorType> hypervisorTypes = new ArrayList<HypervisorType>(); |
| |
| List<ClusterVO> clustersForZone = new ArrayList<ClusterVO>(); |
| if (podId != null) { |
| clustersForZone = _clusterDao.listByPodId(podId); |
| } else { |
| clustersForZone = _clusterDao.listByZoneId(zoneId); |
| } |
| |
| for (ClusterVO cluster : clustersForZone) { |
| HypervisorType hType = cluster.getHypervisorType(); |
| if (!forVirtualRouter |
| || (forVirtualRouter && hType != HypervisorType.BareMetal && hType != HypervisorType.Ovm)) { |
| hypervisorTypes.add(hType); |
| } |
| } |
| |
| return hypervisorTypes; |
| } |
| |
| @Override |
| public HypervisorType getDefaultHypervisor(long zoneId) { |
| HypervisorType defaultHyper = HypervisorType.None; |
| if (_defaultSystemVMHypervisor != HypervisorType.None) { |
| defaultHyper = _defaultSystemVMHypervisor; |
| } |
| |
| DataCenterVO dc = _dcDao.findById(zoneId); |
| if (dc == null) { |
| return HypervisorType.None; |
| } |
| _dcDao.loadDetails(dc); |
| String defaultHypervisorInZone = dc |
| .getDetail("defaultSystemVMHypervisorType"); |
| if (defaultHypervisorInZone != null) { |
| defaultHyper = HypervisorType.getType(defaultHypervisorInZone); |
| } |
| |
| List<VMTemplateVO> systemTemplates = _templateDao |
| .listAllSystemVMTemplates(); |
| boolean isValid = false; |
| for (VMTemplateVO template : systemTemplates) { |
| if (template.getHypervisorType() == defaultHyper) { |
| isValid = true; |
| break; |
| } |
| } |
| |
| if (isValid) { |
| List<ClusterVO> clusters = _clusterDao.listByDcHyType(zoneId, |
| defaultHyper.toString()); |
| if (clusters.size() <= 0) { |
| isValid = false; |
| } |
| } |
| |
| if (isValid) { |
| return defaultHyper; |
| } else { |
| return HypervisorType.None; |
| } |
| } |
| |
| @Override |
| public HypervisorType getAvailableHypervisor(long zoneId) { |
| HypervisorType defaultHype = getDefaultHypervisor(zoneId); |
| if (defaultHype == HypervisorType.None) { |
| List<HypervisorType> supportedHypes = getSupportedHypervisorTypes( |
| zoneId, false, null); |
| if (supportedHypes.size() > 0) { |
| defaultHype = supportedHypes.get(0); |
| } |
| } |
| |
| if (defaultHype == HypervisorType.None) { |
| defaultHype = HypervisorType.Any; |
| } |
| return defaultHype; |
| } |
| |
| @Override |
| public void registerResourceStateAdapter(String name, |
| ResourceStateAdapter adapter) { |
| if (_resourceStateAdapters.get(name) != null) { |
| throw new CloudRuntimeException(name + " has registered"); |
| } |
| |
| synchronized (_resourceStateAdapters) { |
| _resourceStateAdapters.put(name, adapter); |
| } |
| } |
| |
| @Override |
| public void unregisterResourceStateAdapter(String name) { |
| synchronized (_resourceStateAdapters) { |
| _resourceStateAdapters.remove(name); |
| } |
| } |
| |
| private Object dispatchToStateAdapters(ResourceStateAdapter.Event event, |
| boolean singleTaker, Object... args) { |
| synchronized (_resourceStateAdapters) { |
| Iterator<Map.Entry<String, ResourceStateAdapter>> it = _resourceStateAdapters.entrySet().iterator(); |
| Object result = null; |
| while (it.hasNext()) { |
| Map.Entry<String, ResourceStateAdapter> item = it |
| .next(); |
| ResourceStateAdapter adapter = item.getValue(); |
| |
| String msg = new String("Dispatching resource state event " |
| + event + " to " + item.getKey()); |
| s_logger.debug(msg); |
| |
| if (event == ResourceStateAdapter.Event.CREATE_HOST_VO_FOR_CONNECTED) { |
| result = adapter.createHostVOForConnectedAgent( |
| (HostVO) args[0], (StartupCommand[]) args[1]); |
| if (result != null && singleTaker) { |
| break; |
| } |
| } else if (event == ResourceStateAdapter.Event.CREATE_HOST_VO_FOR_DIRECT_CONNECT) { |
| result = adapter.createHostVOForDirectConnectAgent( |
| (HostVO) args[0], (StartupCommand[]) args[1], |
| (ServerResource) args[2], |
| (Map<String, String>) args[3], |
| (List<String>) args[4]); |
| if (result != null && singleTaker) { |
| break; |
| } |
| } else if (event == ResourceStateAdapter.Event.DELETE_HOST) { |
| try { |
| result = adapter.deleteHost((HostVO) args[0], |
| (Boolean) args[1], (Boolean) args[2]); |
| if (result != null) { |
| break; |
| } |
| } catch (UnableDeleteHostException e) { |
| s_logger.debug("Adapter " + adapter.getName() |
| + " says unable to delete host", e); |
| result = new ResourceStateAdapter.DeleteHostAnswer( |
| false, true); |
| } |
| } else { |
| throw new CloudRuntimeException( |
| "Unknown resource state event:" + event); |
| } |
| } |
| |
| return result; |
| } |
| } |
| |
| @Override |
| public void checkCIDR(HostPodVO pod, DataCenterVO dc, |
| String serverPrivateIP, String serverPrivateNetmask) |
| throws IllegalArgumentException { |
| if (serverPrivateIP == null) { |
| return; |
| } |
| // Get the CIDR address and CIDR size |
| String cidrAddress = pod.getCidrAddress(); |
| long cidrSize = pod.getCidrSize(); |
| |
| // If the server's private IP address is not in the same subnet as the |
| // pod's CIDR, return false |
| String cidrSubnet = NetUtils.getCidrSubNet(cidrAddress, cidrSize); |
| String serverSubnet = NetUtils.getSubNet(serverPrivateIP, |
| serverPrivateNetmask); |
| if (!cidrSubnet.equals(serverSubnet)) { |
| s_logger.warn("The private ip address of the server (" |
| + serverPrivateIP |
| + ") is not compatible with the CIDR of pod: " |
| + pod.getName() + " and zone: " + dc.getName()); |
| throw new IllegalArgumentException( |
| "The private ip address of the server (" + serverPrivateIP |
| + ") is not compatible with the CIDR of pod: " |
| + pod.getName() + " and zone: " + dc.getName()); |
| } |
| |
| // If the server's private netmask is less inclusive than the pod's CIDR |
| // netmask, return false |
| String cidrNetmask = NetUtils |
| .getCidrSubNet("255.255.255.255", cidrSize); |
| long cidrNetmaskNumeric = NetUtils.ip2Long(cidrNetmask); |
| long serverNetmaskNumeric = NetUtils.ip2Long(serverPrivateNetmask); |
| if (serverNetmaskNumeric > cidrNetmaskNumeric) { |
| throw new IllegalArgumentException( |
| "The private ip address of the server (" + serverPrivateIP |
| + ") is not compatible with the CIDR of pod: " |
| + pod.getName() + " and zone: " + dc.getName()); |
| } |
| |
| } |
| |
| private boolean checkCIDR(HostPodVO pod, String serverPrivateIP, |
| String serverPrivateNetmask) { |
| if (serverPrivateIP == null) { |
| return true; |
| } |
| // Get the CIDR address and CIDR size |
| String cidrAddress = pod.getCidrAddress(); |
| long cidrSize = pod.getCidrSize(); |
| |
| // If the server's private IP address is not in the same subnet as the |
| // pod's CIDR, return false |
| String cidrSubnet = NetUtils.getCidrSubNet(cidrAddress, cidrSize); |
| String serverSubnet = NetUtils.getSubNet(serverPrivateIP, |
| serverPrivateNetmask); |
| if (!cidrSubnet.equals(serverSubnet)) { |
| return false; |
| } |
| |
| // If the server's private netmask is less inclusive than the pod's CIDR |
| // netmask, return false |
| String cidrNetmask = NetUtils |
| .getCidrSubNet("255.255.255.255", cidrSize); |
| long cidrNetmaskNumeric = NetUtils.ip2Long(cidrNetmask); |
| long serverNetmaskNumeric = NetUtils.ip2Long(serverPrivateNetmask); |
| if (serverNetmaskNumeric > cidrNetmaskNumeric) { |
| return false; |
| } |
| return true; |
| } |
| |
| protected HostVO createHostVO(StartupCommand[] cmds, |
| ServerResource resource, Map<String, String> details, |
| List<String> hostTags, ResourceStateAdapter.Event stateEvent) { |
| StartupCommand startup = cmds[0]; |
| HostVO host = findHostByGuid(startup.getGuid()); |
| boolean isNew = false; |
| if (host == null) { |
| host = findHostByGuid(startup.getGuidWithoutResource()); |
| } |
| if (host == null) { |
| host = new HostVO(startup.getGuid()); |
| isNew = true; |
| } |
| |
| String dataCenter = startup.getDataCenter(); |
| String pod = startup.getPod(); |
| String cluster = startup.getCluster(); |
| |
| if (pod != null && dataCenter != null |
| && pod.equalsIgnoreCase("default") |
| && dataCenter.equalsIgnoreCase("default")) { |
| List<HostPodVO> pods = _podDao.listAllIncludingRemoved(); |
| for (HostPodVO hpv : pods) { |
| if (checkCIDR(hpv, startup.getPrivateIpAddress(), |
| startup.getPrivateNetmask())) { |
| pod = hpv.getName(); |
| dataCenter = _dcDao.findById(hpv.getDataCenterId()) |
| .getName(); |
| break; |
| } |
| } |
| } |
| |
| long dcId = -1; |
| DataCenterVO dc = _dcDao.findByName(dataCenter); |
| if (dc == null) { |
| try { |
| dcId = Long.parseLong(dataCenter); |
| dc = _dcDao.findById(dcId); |
| } catch (final NumberFormatException e) { |
| } |
| } |
| if (dc == null) { |
| throw new IllegalArgumentException("Host " |
| + startup.getPrivateIpAddress() |
| + " sent incorrect data center: " + dataCenter); |
| } |
| dcId = dc.getId(); |
| |
| HostPodVO p = _podDao.findByName(pod, dcId); |
| if (p == null) { |
| try { |
| final long podId = Long.parseLong(pod); |
| p = _podDao.findById(podId); |
| } catch (final NumberFormatException e) { |
| } |
| } |
| /* |
| * ResourceStateAdapter is responsible for throwing Exception if Pod is |
| * null and non-null is required. for example, XcpServerDiscoever. |
| * Others, like PxeServer, ExternalFireware don't require Pod |
| */ |
| Long podId = (p == null ? null : p.getId()); |
| |
| Long clusterId = null; |
| if (cluster != null) { |
| try { |
| clusterId = Long.valueOf(cluster); |
| } catch (NumberFormatException e) { |
| ClusterVO c = _clusterDao.findBy(cluster, podId); |
| if (c == null) { |
| c = new ClusterVO(dcId, podId, cluster); |
| c = _clusterDao.persist(c); |
| } |
| clusterId = c.getId(); |
| } |
| } |
| |
| host.setDataCenterId(dc.getId()); |
| host.setPodId(podId); |
| host.setClusterId(clusterId); |
| host.setPrivateIpAddress(startup.getPrivateIpAddress()); |
| host.setPrivateNetmask(startup.getPrivateNetmask()); |
| host.setPrivateMacAddress(startup.getPrivateMacAddress()); |
| host.setPublicIpAddress(startup.getPublicIpAddress()); |
| host.setPublicMacAddress(startup.getPublicMacAddress()); |
| host.setPublicNetmask(startup.getPublicNetmask()); |
| host.setStorageIpAddress(startup.getStorageIpAddress()); |
| host.setStorageMacAddress(startup.getStorageMacAddress()); |
| host.setStorageNetmask(startup.getStorageNetmask()); |
| host.setVersion(startup.getVersion()); |
| host.setName(startup.getName()); |
| host.setManagementServerId(_nodeId); |
| host.setStorageUrl(startup.getIqn()); |
| host.setLastPinged(System.currentTimeMillis() >> 10); |
| host.setHostTags(hostTags); |
| host.setDetails(details); |
| if (startup.getStorageIpAddressDeux() != null) { |
| host.setStorageIpAddressDeux(startup.getStorageIpAddressDeux()); |
| host.setStorageMacAddressDeux(startup.getStorageMacAddressDeux()); |
| host.setStorageNetmaskDeux(startup.getStorageNetmaskDeux()); |
| } |
| if (resource != null) { |
| /* null when agent is connected agent */ |
| host.setResource(resource.getClass().getName()); |
| } |
| |
| host = (HostVO) dispatchToStateAdapters(stateEvent, true, host, cmds, |
| resource, details, hostTags); |
| if (host == null) { |
| throw new CloudRuntimeException( |
| "No resource state adapter response"); |
| } |
| |
| if (isNew) { |
| host = _hostDao.persist(host); |
| } else { |
| _hostDao.update(host.getId(), host); |
| } |
| |
| try { |
| resourceStateTransitTo(host, ResourceState.Event.InternalCreated, |
| _nodeId); |
| /* Agent goes to Connecting status */ |
| _agentMgr.agentStatusTransitTo(host, Status.Event.AgentConnected, |
| _nodeId); |
| } catch (Exception e) { |
| s_logger.debug("Cannot transmit host " + host.getId() |
| + " to Creating state", e); |
| _agentMgr.agentStatusTransitTo(host, Status.Event.Error, _nodeId); |
| try { |
| resourceStateTransitTo(host, ResourceState.Event.Error, _nodeId); |
| } catch (NoTransitionException e1) { |
| s_logger.debug("Cannot transmit host " + host.getId() |
| + "to Error state", e); |
| } |
| } |
| |
| return host; |
| } |
| |
| private boolean isFirstHostInCluster(HostVO host) |
| { |
| boolean isFirstHost = true; |
| if (host.getClusterId() != null) { |
| SearchBuilder<HostVO> sb = _hostDao.createSearchBuilder(); |
| sb.and("removed", sb.entity().getRemoved(), SearchCriteria.Op.NULL); |
| sb.and("cluster", sb.entity().getClusterId(), SearchCriteria.Op.EQ); |
| sb.done(); |
| SearchCriteria<HostVO> sc = sb.create(); |
| sc.setParameters("cluster", host.getClusterId()); |
| |
| List<HostVO> hosts = _hostDao.search(sc, null); |
| if (hosts != null && hosts.size() > 1) { |
| isFirstHost = false; |
| } |
| } |
| return isFirstHost; |
| } |
| |
| private void markHostAsDisconnected(HostVO host, StartupCommand[] cmds) { |
| if (host == null) { // in case host is null due to some errors, try reloading the host from db |
| if (cmds != null) { |
| StartupCommand firstCmd = cmds[0]; |
| host = findHostByGuid(firstCmd.getGuid()); |
| if (host == null) { |
| host = findHostByGuid(firstCmd.getGuidWithoutResource()); |
| } |
| } |
| } |
| |
| if (host != null) { |
| // Change agent status to Alert, so that host is considered for reconnection next time |
| _agentMgr.agentStatusTransitTo(host, Status.Event.AgentDisconnected, _nodeId); |
| } |
| } |
| |
| private Host createHostAndAgent(ServerResource resource, Map<String, String> details, boolean old, List<String> hostTags, |
| boolean forRebalance) { |
| HostVO host = null; |
| AgentAttache attache = null; |
| StartupCommand[] cmds = null; |
| boolean hostExists = false; |
| |
| try { |
| cmds = resource.initialize(); |
| if (cmds == null) { |
| s_logger.info("Unable to fully initialize the agent because no StartupCommands are returned"); |
| return null; |
| } |
| |
| /* Generate a random version in a dev setup situation */ |
| if (this.getClass().getPackage().getImplementationVersion() == null) { |
| for (StartupCommand cmd : cmds) { |
| if (cmd.getVersion() == null) { |
| cmd.setVersion(Long.toString(System.currentTimeMillis())); |
| } |
| } |
| } |
| |
| if (s_logger.isDebugEnabled()) { |
| new Request(-1l, -1l, cmds, true, false).logD( |
| "Startup request from directly connected host: ", true); |
| } |
| |
| if (old) { |
| StartupCommand firstCmd = cmds[0]; |
| host = findHostByGuid(firstCmd.getGuid()); |
| if (host == null) { |
| host = findHostByGuid(firstCmd.getGuidWithoutResource()); |
| } |
| if (host != null && host.getRemoved() == null) { // host already added, no need to add again |
| s_logger.debug("Found the host " + host.getId() + " by guid: " + firstCmd.getGuid() + ", old host reconnected as new"); |
| hostExists = true; // ensures that host status is left unchanged in case of adding same one again |
| return null; |
| } |
| } |
| |
| host = createHostVO( |
| cmds, |
| resource, |
| details, |
| hostTags, |
| ResourceStateAdapter.Event.CREATE_HOST_VO_FOR_DIRECT_CONNECT); |
| if (host != null) { |
| attache = _agentMgr.handleDirectConnectAgent(host, cmds, |
| resource, forRebalance); |
| /* reload myself from database */ |
| host = _hostDao.findById(host.getId()); |
| } |
| } catch (Exception e) { |
| s_logger.warn("Unable to connect due to ", e); |
| } finally { |
| if (hostExists) { |
| if (cmds != null) { |
| resource.disconnected(); |
| } |
| } else { |
| if (attache == null) { |
| if (cmds != null) { |
| resource.disconnected(); |
| } |
| markHostAsDisconnected(host, cmds); |
| } |
| } |
| } |
| |
| return host; |
| } |
| |
| private Host createHostAndAgentDeferred(ServerResource resource, Map<String, String> details, boolean old, List<String> hostTags, |
| boolean forRebalance) { |
| HostVO host = null; |
| AgentAttache attache = null; |
| StartupCommand[] cmds = null; |
| boolean hostExists = false; |
| boolean deferAgentCreation = true; |
| |
| try { |
| cmds = resource.initialize(); |
| if (cmds == null) { |
| s_logger.info("Unable to fully initialize the agent because no StartupCommands are returned"); |
| return null; |
| } |
| |
| /* Generate a random version in a dev setup situation */ |
| if ( this.getClass().getPackage().getImplementationVersion() == null ) { |
| for ( StartupCommand cmd : cmds ) { |
| if ( cmd.getVersion() == null ) { |
| cmd.setVersion(Long.toString(System.currentTimeMillis())); |
| } |
| } |
| } |
| |
| if (s_logger.isDebugEnabled()) { |
| new Request(-1l, -1l, cmds, true, false).logD("Startup request from directly connected host: ", true); |
| } |
| |
| if (old) { |
| StartupCommand firstCmd = cmds[0]; |
| host = findHostByGuid(firstCmd.getGuid()); |
| if (host == null) { |
| host = findHostByGuid(firstCmd.getGuidWithoutResource()); |
| } |
| if (host != null && host.getRemoved() == null) { // host already added, no need to add again |
| s_logger.debug("Found the host " + host.getId() + " by guid: " + firstCmd.getGuid() + ", old host reconnected as new"); |
| hostExists = true; // ensures that host status is left unchanged in case of adding same one again |
| return null; |
| } |
| } |
| |
| host = null; |
| GlobalLock addHostLock = GlobalLock.getInternLock("AddHostLock"); |
| try { |
| if (addHostLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION)) { // to safely determine first host in cluster in multi-MS scenario |
| try { |
| host = createHostVO(cmds, resource, details, hostTags, ResourceStateAdapter.Event.CREATE_HOST_VO_FOR_DIRECT_CONNECT); |
| if (host != null) { |
| deferAgentCreation = !isFirstHostInCluster(host); // if first host in cluster no need to defer agent creation |
| } |
| } finally { |
| addHostLock.unlock(); |
| } |
| } |
| } finally { |
| addHostLock.releaseRef(); |
| } |
| |
| if (host != null) { |
| if (!deferAgentCreation) { // if first host in cluster then create agent otherwise defer it to scan task |
| attache = _agentMgr.handleDirectConnectAgent(host, cmds, resource, forRebalance); |
| host = _hostDao.findById(host.getId()); // reload |
| } else { |
| host = _hostDao.findById(host.getId()); // reload |
| // force host status to 'Alert' so that it is loaded for connection during next scan task |
| _agentMgr.agentStatusTransitTo(host, Status.Event.AgentDisconnected, _nodeId); |
| |
| host = _hostDao.findById(host.getId()); // reload |
| host.setLastPinged(0); // so that scan task can pick it up |
| _hostDao.update(host.getId(), host); |
| |
| // schedule a scan task immediately |
| if (_agentMgr instanceof ClusteredAgentManagerImpl) { |
| ClusteredAgentManagerImpl clusteredAgentMgr = (ClusteredAgentManagerImpl)_agentMgr; |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Scheduling a host scan task"); |
| } |
| // schedule host scan task on current MS |
| clusteredAgentMgr.scheduleHostScanTask(); |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Notifying all peer MS to schedule host scan task"); |
| } |
| // notify peers to schedule a host scan task as well |
| clusteredAgentMgr.notifyNodesInClusterToScheduleHostScanTask(); |
| } |
| } |
| } |
| } catch (Exception e) { |
| s_logger.warn("Unable to connect due to ", e); |
| } finally { |
| if (hostExists) { |
| if (cmds != null) { |
| resource.disconnected(); |
| } |
| } else { |
| if (!deferAgentCreation && attache == null) { |
| if (cmds != null) { |
| resource.disconnected(); |
| } |
| markHostAsDisconnected(host, cmds); |
| } |
| } |
| } |
| |
| return host; |
| } |
| |
| @Override |
| public Host createHostAndAgent(Long hostId, ServerResource resource, |
| Map<String, String> details, boolean old, List<String> hostTags, |
| boolean forRebalance) { |
| _agentMgr.tapLoadingAgents(hostId, TapAgentsAction.Add); |
| Host host = createHostAndAgent(resource, details, old, hostTags, |
| forRebalance); |
| _agentMgr.tapLoadingAgents(hostId, TapAgentsAction.Del); |
| return host; |
| } |
| |
| @Override |
| public Host addHost(long zoneId, ServerResource resource, Type hostType, |
| Map<String, String> hostDetails) { |
| // Check if the zone exists in the system |
| if (_dcDao.findById(zoneId) == null) { |
| throw new InvalidParameterValueException("Can't find zone with id " |
| + zoneId); |
| } |
| |
| Map<String, String> details = hostDetails; |
| String guid = details.get("guid"); |
| List<HostVO> currentHosts = this |
| .listAllUpAndEnabledHostsInOneZoneByType(hostType, zoneId); |
| for (HostVO currentHost : currentHosts) { |
| if (currentHost.getGuid().equals(guid)) { |
| return currentHost; |
| } |
| } |
| |
| return createHostAndAgent(resource, hostDetails, true, null, false); |
| } |
| |
| @Override |
| public HostVO createHostVOForConnectedAgent(StartupCommand[] cmds) { |
| return createHostVO(cmds, null, null, null, |
| ResourceStateAdapter.Event.CREATE_HOST_VO_FOR_CONNECTED); |
| } |
| |
| private void checkIPConflicts(HostPodVO pod, DataCenterVO dc, |
| String serverPrivateIP, String serverPrivateNetmask, |
| String serverPublicIP, String serverPublicNetmask) { |
| // If the server's private IP is the same as is public IP, this host has |
| // a host-only private network. Don't check for conflicts with the |
| // private IP address table. |
| if (serverPrivateIP != serverPublicIP) { |
| if (!_privateIPAddressDao.mark(dc.getId(), pod.getId(), |
| serverPrivateIP)) { |
| // If the server's private IP address is already in the |
| // database, return false |
| List<DataCenterIpAddressVO> existingPrivateIPs = _privateIPAddressDao |
| .listByPodIdDcIdIpAddress(pod.getId(), dc.getId(), |
| serverPrivateIP); |
| |
| assert existingPrivateIPs.size() <= 1 : " How can we get more than one ip address with " |
| + serverPrivateIP; |
| if (existingPrivateIPs.size() > 1) { |
| throw new IllegalArgumentException( |
| "The private ip address of the server (" |
| + serverPrivateIP |
| + ") is already in use in pod: " |
| + pod.getName() + " and zone: " |
| + dc.getName()); |
| } |
| if (existingPrivateIPs.size() == 1) { |
| DataCenterIpAddressVO vo = existingPrivateIPs.get(0); |
| if (vo.getInstanceId() != null) { |
| throw new IllegalArgumentException( |
| "The private ip address of the server (" |
| + serverPrivateIP |
| + ") is already in use in pod: " |
| + pod.getName() + " and zone: " |
| + dc.getName()); |
| } |
| } |
| } |
| } |
| |
| if (serverPublicIP != null |
| && !_publicIPAddressDao |
| .mark(dc.getId(), new Ip(serverPublicIP))) { |
| // If the server's public IP address is already in the database, |
| // return false |
| List<IPAddressVO> existingPublicIPs = _publicIPAddressDao |
| .listByDcIdIpAddress(dc.getId(), serverPublicIP); |
| if (existingPublicIPs.size() > 0) { |
| throw new IllegalArgumentException( |
| "The public ip address of the server (" |
| + serverPublicIP |
| + ") is already in use in zone: " |
| + dc.getName()); |
| } |
| } |
| } |
| |
| @Override |
| public HostVO fillRoutingHostVO(HostVO host, StartupRoutingCommand ssCmd, |
| HypervisorType hyType, Map<String, String> details, |
| List<String> hostTags) { |
| if (host.getPodId() == null) { |
| s_logger.error("Host " + ssCmd.getPrivateIpAddress() |
| + " sent incorrect pod, pod id is null"); |
| throw new IllegalArgumentException("Host " |
| + ssCmd.getPrivateIpAddress() |
| + " sent incorrect pod, pod id is null"); |
| } |
| |
| ClusterVO clusterVO = _clusterDao.findById(host.getClusterId()); |
| if (clusterVO.getHypervisorType() != hyType) { |
| throw new IllegalArgumentException( |
| "Can't add host whose hypervisor type is: " + hyType |
| + " into cluster: " + clusterVO.getId() |
| + " whose hypervisor type is: " |
| + clusterVO.getHypervisorType()); |
| } |
| |
| final Map<String, String> hostDetails = ssCmd.getHostDetails(); |
| if (hostDetails != null) { |
| if (details != null) { |
| details.putAll(hostDetails); |
| } else { |
| details = hostDetails; |
| } |
| } |
| |
| HostPodVO pod = _podDao.findById(host.getPodId()); |
| DataCenterVO dc = _dcDao.findById(host.getDataCenterId()); |
| checkIPConflicts(pod, dc, ssCmd.getPrivateIpAddress(), |
| ssCmd.getPublicIpAddress(), ssCmd.getPublicIpAddress(), |
| ssCmd.getPublicNetmask()); |
| host.setType(com.cloud.host.Host.Type.Routing); |
| host.setDetails(details); |
| host.setCaps(ssCmd.getCapabilities()); |
| host.setCpus(ssCmd.getCpus()); |
| host.setTotalMemory(ssCmd.getMemory()); |
| host.setSpeed(ssCmd.getSpeed()); |
| host.setHypervisorType(hyType); |
| host.setHypervisorVersion(ssCmd.getHypervisorVersion()); |
| return host; |
| } |
| |
| @Override |
| public void deleteRoutingHost(HostVO host, boolean isForced, |
| boolean forceDestroyStorage) throws UnableDeleteHostException { |
| if (host.getType() != Host.Type.Routing) { |
| throw new CloudRuntimeException( |
| "Non-Routing host gets in deleteRoutingHost, id is " |
| + host.getId()); |
| } |
| |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Deleting Host: " + host.getId() + " Guid:" |
| + host.getGuid()); |
| } |
| |
| User caller = _accountMgr.getActiveUser(UserContext.current() |
| .getCallerUserId()); |
| |
| if (forceDestroyStorage) { |
| // put local storage into mainenance mode, will set all the VMs on |
| // this local storage into stopped state |
| StoragePoolVO storagePool = _storageMgr.findLocalStorageOnHost(host |
| .getId()); |
| if (storagePool != null) { |
| if (storagePool.getStatus() == StoragePoolStatus.Up |
| || storagePool.getStatus() == StoragePoolStatus.ErrorInMaintenance) { |
| try { |
| StoragePool pool = _storageSvr |
| .preparePrimaryStorageForMaintenance(storagePool |
| .getId()); |
| if (pool == null) { |
| s_logger.debug("Failed to set primary storage into maintenance mode"); |
| |
| throw new UnableDeleteHostException( |
| "Failed to set primary storage into maintenance mode"); |
| } |
| } catch (Exception e) { |
| s_logger.debug("Failed to set primary storage into maintenance mode, due to: " |
| + e.toString()); |
| throw new UnableDeleteHostException( |
| "Failed to set primary storage into maintenance mode, due to: " |
| + e.toString()); |
| } |
| } |
| |
| List<VMInstanceVO> vmsOnLocalStorage = _storageMgr |
| .listByStoragePool(storagePool.getId()); |
| for (VMInstanceVO vm : vmsOnLocalStorage) { |
| try { |
| if (!_vmMgr.destroy(vm, caller, |
| _accountMgr.getAccount(vm.getAccountId()))) { |
| String errorMsg = "There was an error Destory the vm: " |
| + vm |
| + " as a part of hostDelete id=" |
| + host.getId(); |
| s_logger.warn(errorMsg); |
| throw new UnableDeleteHostException(errorMsg); |
| } |
| } catch (Exception e) { |
| String errorMsg = "There was an error Destory the vm: " |
| + vm + " as a part of hostDelete id=" |
| + host.getId(); |
| s_logger.debug(errorMsg, e); |
| throw new UnableDeleteHostException(errorMsg + "," |
| + e.getMessage()); |
| } |
| } |
| } |
| } else { |
| // Check if there are vms running/starting/stopping on this host |
| List<VMInstanceVO> vms = _vmDao.listByHostId(host.getId()); |
| if (!vms.isEmpty()) { |
| if (isForced) { |
| // Stop HA disabled vms and HA enabled vms in Stopping state |
| // Restart HA enabled vms |
| for (VMInstanceVO vm : vms) { |
| if (!vm.isHaEnabled() |
| || vm.getState() == State.Stopping) { |
| s_logger.debug("Stopping vm: " + vm |
| + " as a part of deleteHost id=" |
| + host.getId()); |
| try { |
| if (!_vmMgr.advanceStop(vm, true, caller, |
| _accountMgr.getAccount(vm |
| .getAccountId()))) { |
| String errorMsg = "There was an error stopping the vm: " |
| + vm |
| + " as a part of hostDelete id=" |
| + host.getId(); |
| s_logger.warn(errorMsg); |
| throw new UnableDeleteHostException( |
| errorMsg); |
| } |
| } catch (Exception e) { |
| String errorMsg = "There was an error stopping the vm: " |
| + vm |
| + " as a part of hostDelete id=" |
| + host.getId(); |
| s_logger.debug(errorMsg, e); |
| throw new UnableDeleteHostException(errorMsg |
| + "," + e.getMessage()); |
| } |
| } else if (vm.isHaEnabled() |
| && (vm.getState() == State.Running || vm |
| .getState() == State.Starting)) { |
| s_logger.debug("Scheduling restart for vm: " + vm |
| + " " + vm.getState() + " on the host id=" |
| + host.getId()); |
| _haMgr.scheduleRestart(vm, false); |
| } |
| } |
| } else { |
| throw new UnableDeleteHostException( |
| "Unable to delete the host as there are vms in " |
| + vms.get(0).getState() |
| + " state using this host and isForced=false specified"); |
| } |
| } |
| } |
| } |
| |
| private boolean doCancelMaintenance(long hostId) { |
| HostVO host; |
| host = _hostDao.findById(hostId); |
| if (host == null || host.getRemoved() != null) { |
| s_logger.warn("Unable to find host " + hostId); |
| return true; |
| } |
| |
| /* |
| * TODO: think twice about returning true or throwing out exception, I |
| * really prefer to exception that always exposes bugs |
| */ |
| if (host.getResourceState() != ResourceState.PrepareForMaintenance |
| && host.getResourceState() != ResourceState.Maintenance |
| && host.getResourceState() != ResourceState.ErrorInMaintenance) { |
| throw new CloudRuntimeException( |
| "Cannot perform cancelMaintenance when resource state is " |
| + host.getResourceState() + ", hostId = " + hostId); |
| } |
| |
| /* TODO: move to listener */ |
| _haMgr.cancelScheduledMigrations(host); |
| List<VMInstanceVO> vms = _haMgr.findTakenMigrationWork(); |
| for (VMInstanceVO vm : vms) { |
| if (vm.getHostId() != null && vm.getHostId() == hostId) { |
| s_logger.info("Unable to cancel migration because the vm is being migrated: " |
| + vm); |
| return false; |
| } |
| } |
| |
| try { |
| resourceStateTransitTo(host, |
| ResourceState.Event.AdminCancelMaintenance, _nodeId); |
| _agentMgr.pullAgentOutMaintenance(hostId); |
| |
| // for kvm, need to log into kvm host, restart cloudstack-agent |
| if (host.getHypervisorType() == HypervisorType.KVM) { |
| _hostDao.loadDetails(host); |
| String password = host.getDetail("password"); |
| String username = host.getDetail("username"); |
| if (password == null || username == null) { |
| s_logger.debug("Can't find password/username"); |
| return false; |
| } |
| com.trilead.ssh2.Connection connection = SSHCmdHelper |
| .acquireAuthorizedConnection( |
| host.getPrivateIpAddress(), 22, username, |
| password); |
| if (connection == null) { |
| s_logger.debug("Failed to connect to host: " |
| + host.getPrivateIpAddress()); |
| return false; |
| } |
| |
| try { |
| SSHCmdHelper.sshExecuteCmdOneShot(connection, |
| "service cloudstack-agent restart"); |
| } catch (sshException e) { |
| return false; |
| } |
| } |
| |
| return true; |
| } catch (NoTransitionException e) { |
| s_logger.debug("Cannot transmit host " + host.getId() |
| + "to Enabled state", e); |
| return false; |
| } |
| } |
| |
| private boolean cancelMaintenance(long hostId) { |
| try { |
| Boolean result = _clusterMgr.propagateResourceEvent(hostId, |
| ResourceState.Event.AdminCancelMaintenance); |
| |
| if (result != null) { |
| return result; |
| } |
| } catch (AgentUnavailableException e) { |
| return false; |
| } |
| |
| return doCancelMaintenance(hostId); |
| } |
| |
| @Override |
| public boolean executeUserRequest(long hostId, ResourceState.Event event) |
| throws AgentUnavailableException { |
| if (event == ResourceState.Event.AdminAskMaintenace) { |
| return doMaintain(hostId); |
| } else if (event == ResourceState.Event.AdminCancelMaintenance) { |
| return doCancelMaintenance(hostId); |
| } else if (event == ResourceState.Event.DeleteHost) { |
| /* TODO: Ask alex why we assume the last two parameters are false */ |
| return doDeleteHost(hostId, false, false); |
| } else if (event == ResourceState.Event.Unmanaged) { |
| return doUmanageHost(hostId); |
| } else if (event == ResourceState.Event.UpdatePassword) { |
| return doUpdateHostPassword(hostId); |
| } else { |
| throw new CloudRuntimeException( |
| "Received an resource event we are not handling now, " |
| + event); |
| } |
| } |
| |
| private boolean doUmanageHost(long hostId) { |
| HostVO host = _hostDao.findById(hostId); |
| if (host == null) { |
| s_logger.debug("Cannot find host " + hostId |
| + ", assuming it has been deleted, skip umanage"); |
| return true; |
| } |
| |
| if (host.getHypervisorType() == HypervisorType.KVM) { |
| MaintainAnswer answer = (MaintainAnswer) _agentMgr.easySend(hostId, |
| new MaintainCommand()); |
| } |
| |
| _agentMgr.disconnectWithoutInvestigation(hostId, |
| Event.ShutdownRequested); |
| return true; |
| } |
| |
| @Override |
| public boolean umanageHost(long hostId) { |
| try { |
| Boolean result = _clusterMgr.propagateResourceEvent(hostId, |
| ResourceState.Event.Unmanaged); |
| |
| if (result != null) { |
| return result; |
| } |
| } catch (AgentUnavailableException e) { |
| return false; |
| } |
| |
| return doUmanageHost(hostId); |
| } |
| |
| private boolean doUpdateHostPassword(long hostId) { |
| AgentAttache attache = _agentMgr.findAttache(hostId); |
| if (attache == null) { |
| return false; |
| } |
| |
| DetailVO nv = _hostDetailsDao.findDetail(hostId, ApiConstants.USERNAME); |
| String username = nv.getValue(); |
| nv = _hostDetailsDao.findDetail(hostId, ApiConstants.PASSWORD); |
| String password = nv.getValue(); |
| UpdateHostPasswordCommand cmd = new UpdateHostPasswordCommand(username, |
| password); |
| attache.updatePassword(cmd); |
| return true; |
| } |
| |
| @Override |
| public boolean updateHostPassword(UpdateHostPasswordCmd cmd) { |
| if (cmd.getClusterId() == null) { |
| // update agent attache password |
| try { |
| Boolean result = _clusterMgr.propagateResourceEvent( |
| cmd.getHostId(), ResourceState.Event.UpdatePassword); |
| if (result != null) { |
| return result; |
| } |
| } catch (AgentUnavailableException e) { |
| } |
| |
| return doUpdateHostPassword(cmd.getHostId()); |
| } else { |
| // get agents for the cluster |
| List<HostVO> hosts = this.listAllHostsInCluster(cmd.getClusterId()); |
| for (HostVO h : hosts) { |
| try { |
| /* |
| * FIXME: this is a buggy logic, check with alex. Shouldn't |
| * return if propagation return non null |
| */ |
| Boolean result = _clusterMgr.propagateResourceEvent( |
| h.getId(), ResourceState.Event.UpdatePassword); |
| if (result != null) { |
| return result; |
| } |
| |
| doUpdateHostPassword(h.getId()); |
| } catch (AgentUnavailableException e) { |
| } |
| } |
| |
| return true; |
| } |
| } |
| |
| @Override |
| public boolean maintenanceFailed(long hostId) { |
| HostVO host = _hostDao.findById(hostId); |
| if (host == null) { |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Cant not find host " + hostId); |
| } |
| return false; |
| } else { |
| try { |
| return resourceStateTransitTo(host, |
| ResourceState.Event.UnableToMigrate, _nodeId); |
| } catch (NoTransitionException e) { |
| s_logger.debug( |
| "No next resource state for host " + host.getId() |
| + " while current state is " |
| + host.getResourceState() + " with event " |
| + ResourceState.Event.UnableToMigrate, e); |
| return false; |
| } |
| } |
| } |
| |
| @Override |
| public List<HostVO> findDirectlyConnectedHosts() { |
| /* The resource column is not null for direct connected resource */ |
| SearchCriteriaService<HostVO, HostVO> sc = SearchCriteria2 |
| .create(HostVO.class); |
| sc.addAnd(sc.getEntity().getResource(), Op.NNULL); |
| sc.addAnd(sc.getEntity().getResourceState(), Op.NIN, |
| ResourceState.Disabled); |
| return sc.list(); |
| } |
| |
| @Override |
| public List<HostVO> listAllUpAndEnabledHosts(Type type, Long clusterId, |
| Long podId, long dcId) { |
| SearchCriteriaService<HostVO, HostVO> sc = SearchCriteria2 |
| .create(HostVO.class); |
| if (type != null) { |
| sc.addAnd(sc.getEntity().getType(), Op.EQ, type); |
| } |
| if (clusterId != null) { |
| sc.addAnd(sc.getEntity().getClusterId(), Op.EQ, clusterId); |
| } |
| if (podId != null) { |
| sc.addAnd(sc.getEntity().getPodId(), Op.EQ, podId); |
| } |
| sc.addAnd(sc.getEntity().getDataCenterId(), Op.EQ, dcId); |
| sc.addAnd(sc.getEntity().getStatus(), Op.EQ, Status.Up); |
| sc.addAnd(sc.getEntity().getResourceState(), Op.EQ, |
| ResourceState.Enabled); |
| return sc.list(); |
| } |
| |
| @Override |
| public List<HostVO> listAllUpAndEnabledNonHAHosts(Type type, |
| Long clusterId, Long podId, long dcId) { |
| String haTag = _haMgr.getHaTag(); |
| return _hostDao.listAllUpAndEnabledNonHAHosts(type, clusterId, podId, |
| dcId, haTag); |
| } |
| |
| @Override |
| public List<HostVO> findHostByGuid(long dcId, String guid) { |
| SearchCriteriaService<HostVO, HostVO> sc = SearchCriteria2 |
| .create(HostVO.class); |
| sc.addAnd(sc.getEntity().getDataCenterId(), Op.EQ, dcId); |
| sc.addAnd(sc.getEntity().getGuid(), Op.EQ, guid); |
| return sc.list(); |
| } |
| |
| @Override |
| public List<HostVO> listAllHostsInCluster(long clusterId) { |
| SearchCriteriaService<HostVO, HostVO> sc = SearchCriteria2 |
| .create(HostVO.class); |
| sc.addAnd(sc.getEntity().getClusterId(), Op.EQ, clusterId); |
| return sc.list(); |
| } |
| |
| @Override |
| public List<HostVO> listHostsInClusterByStatus(long clusterId, Status status) { |
| SearchCriteriaService<HostVO, HostVO> sc = SearchCriteria2 |
| .create(HostVO.class); |
| sc.addAnd(sc.getEntity().getClusterId(), Op.EQ, clusterId); |
| sc.addAnd(sc.getEntity().getStatus(), Op.EQ, status); |
| return sc.list(); |
| } |
| |
| @Override |
| public List<HostVO> listAllUpAndEnabledHostsInOneZoneByType(Type type, |
| long dcId) { |
| SearchCriteriaService<HostVO, HostVO> sc = SearchCriteria2 |
| .create(HostVO.class); |
| sc.addAnd(sc.getEntity().getType(), Op.EQ, type); |
| sc.addAnd(sc.getEntity().getDataCenterId(), Op.EQ, dcId); |
| sc.addAnd(sc.getEntity().getStatus(), Op.EQ, Status.Up); |
| sc.addAnd(sc.getEntity().getResourceState(), Op.EQ, |
| ResourceState.Enabled); |
| return sc.list(); |
| } |
| |
| @Override |
| public List<HostVO> listAllNotInMaintenanceHostsInOneZone(Type type, |
| Long dcId) { |
| SearchCriteriaService<HostVO, HostVO> sc = SearchCriteria2 |
| .create(HostVO.class); |
| if (dcId != null) { |
| sc.addAnd(sc.getEntity().getDataCenterId(), Op.EQ, dcId); |
| } |
| sc.addAnd(sc.getEntity().getType(), Op.EQ, type); |
| sc.addAnd(sc.getEntity().getResourceState(), Op.NIN, |
| ResourceState.Maintenance, ResourceState.ErrorInMaintenance, |
| ResourceState.PrepareForMaintenance, ResourceState.Error); |
| return sc.list(); |
| } |
| |
| @Override |
| public List<HostVO> listAllHostsInOneZoneByType(Type type, long dcId) { |
| SearchCriteriaService<HostVO, HostVO> sc = SearchCriteria2 |
| .create(HostVO.class); |
| sc.addAnd(sc.getEntity().getType(), Op.EQ, type); |
| sc.addAnd(sc.getEntity().getDataCenterId(), Op.EQ, dcId); |
| return sc.list(); |
| } |
| |
| @Override |
| public List<HostVO> listAllHostsInAllZonesByType(Type type) { |
| SearchCriteriaService<HostVO, HostVO> sc = SearchCriteria2 |
| .create(HostVO.class); |
| sc.addAnd(sc.getEntity().getType(), Op.EQ, type); |
| return sc.list(); |
| } |
| |
| @Override |
| public List<HypervisorType> listAvailHypervisorInZone(Long hostId, |
| Long zoneId) { |
| SearchCriteriaService<HostVO, HostVO> sc = SearchCriteria2 |
| .create(HostVO.class); |
| if (zoneId != null) { |
| sc.addAnd(sc.getEntity().getDataCenterId(), Op.EQ, zoneId); |
| } |
| if (hostId != null) { |
| sc.addAnd(sc.getEntity().getId(), Op.EQ, hostId); |
| } |
| sc.addAnd(sc.getEntity().getType(), Op.EQ, Host.Type.Routing); |
| List<HostVO> hosts = sc.list(); |
| |
| List<HypervisorType> hypers = new ArrayList<HypervisorType>(5); |
| for (HostVO host : hosts) { |
| hypers.add(host.getHypervisorType()); |
| } |
| return hypers; |
| } |
| |
| @Override |
| public HostVO findHostByGuid(String guid) { |
| SearchCriteriaService<HostVO, HostVO> sc = SearchCriteria2 |
| .create(HostVO.class); |
| sc.addAnd(sc.getEntity().getGuid(), Op.EQ, guid); |
| return sc.find(); |
| } |
| |
| @Override |
| public HostVO findHostByName(String name) { |
| SearchCriteriaService<HostVO, HostVO> sc = SearchCriteria2 |
| .create(HostVO.class); |
| sc.addAnd(sc.getEntity().getName(), Op.EQ, name); |
| return sc.find(); |
| } |
| |
| @Override |
| public List<HostVO> listHostsByNameLike(String name) { |
| SearchCriteriaService<HostVO, HostVO> sc = SearchCriteria2 |
| .create(HostVO.class); |
| sc.addAnd(sc.getEntity().getName(), Op.LIKE, "%" + name + "%"); |
| return sc.list(); |
| } |
| |
| @Override |
| public Pair<HostPodVO, Long> findPod(VirtualMachineTemplate template, |
| ServiceOfferingVO offering, DataCenterVO dc, long accountId, |
| Set<Long> avoids) { |
| for (PodAllocator allocator : _podAllocators) { |
| final Pair<HostPodVO, Long> pod = allocator.allocateTo(template, |
| offering, dc, accountId, avoids); |
| if (pod != null) { |
| return pod; |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public HostStats getHostStatistics(long hostId) { |
| Answer answer = _agentMgr.easySend(hostId, new GetHostStatsCommand( |
| _hostDao.findById(hostId).getGuid(), _hostDao.findById(hostId) |
| .getName(), hostId)); |
| |
| if (answer != null && (answer instanceof UnsupportedAnswer)) { |
| return null; |
| } |
| |
| if (answer == null || !answer.getResult()) { |
| String msg = "Unable to obtain host " + hostId + " statistics. "; |
| s_logger.warn(msg); |
| return null; |
| } else { |
| |
| // now construct the result object |
| if (answer instanceof GetHostStatsAnswer) { |
| return ((GetHostStatsAnswer) answer).getHostStats(); |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public Long getGuestOSCategoryId(long hostId) { |
| HostVO host = _hostDao.findById(hostId); |
| if (host == null) { |
| return null; |
| } else { |
| _hostDao.loadDetails(host); |
| DetailVO detail = _hostDetailsDao.findDetail(hostId, |
| "guest.os.category.id"); |
| if (detail == null) { |
| return null; |
| } else { |
| return Long.parseLong(detail.getValue()); |
| } |
| } |
| } |
| |
| @Override |
| public String getHostTags(long hostId) { |
| List<String> hostTags = _hostTagsDao.gethostTags(hostId); |
| if (hostTags == null) { |
| return null; |
| } else { |
| return StringUtils.listToCsvTags(hostTags); |
| } |
| } |
| |
| @Override |
| public List<PodCluster> listByDataCenter(long dcId) { |
| List<HostPodVO> pods = _podDao.listByDataCenterId(dcId); |
| ArrayList<PodCluster> pcs = new ArrayList<PodCluster>(); |
| for (HostPodVO pod : pods) { |
| List<ClusterVO> clusters = _clusterDao.listByPodId(pod.getId()); |
| if (clusters.size() == 0) { |
| pcs.add(new PodCluster(pod, null)); |
| } else { |
| for (ClusterVO cluster : clusters) { |
| pcs.add(new PodCluster(pod, cluster)); |
| } |
| } |
| } |
| return pcs; |
| } |
| |
| @Override |
| public List<HostVO> listAllUpAndEnabledHostsInOneZoneByHypervisor( |
| HypervisorType type, long dcId) { |
| SearchCriteriaService<HostVO, HostVO> sc = SearchCriteria2 |
| .create(HostVO.class); |
| sc.addAnd(sc.getEntity().getHypervisorType(), Op.EQ, type); |
| sc.addAnd(sc.getEntity().getDataCenterId(), Op.EQ, dcId); |
| sc.addAnd(sc.getEntity().getStatus(), Op.EQ, Status.Up); |
| sc.addAnd(sc.getEntity().getResourceState(), Op.EQ, |
| ResourceState.Enabled); |
| return sc.list(); |
| } |
| |
| @Override |
| @DB |
| @ActionEvent(eventType = EventTypes.EVENT_HOST_RESERVATION_RELEASE, eventDescription = "releasing host reservation", async = true) |
| public boolean releaseHostReservation(Long hostId) { |
| Transaction txn = Transaction.currentTxn(); |
| try { |
| txn.start(); |
| PlannerHostReservationVO reservationEntry = _plannerHostReserveDao.findByHostId(hostId); |
| if (reservationEntry != null) { |
| long id = reservationEntry.getId(); |
| PlannerHostReservationVO hostReservation = _plannerHostReserveDao.lockRow(id, true); |
| if (hostReservation == null) { |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Host reservation for host: " + hostId + " does not even exist. Release reservartion call is ignored."); |
| } |
| txn.rollback(); |
| return false; |
| } |
| hostReservation.setResourceUsage(null); |
| _plannerHostReserveDao.persist(hostReservation); |
| txn.commit(); |
| return true; |
| } |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Host reservation for host: " + hostId |
| + " does not even exist. Release reservartion call is ignored."); |
| } |
| return false; |
| } catch (CloudRuntimeException e) { |
| throw e; |
| } catch (Throwable t) { |
| s_logger.error("Unable to release host reservation for host: " + hostId, t); |
| txn.rollback(); |
| return false; |
| } |
| } |
| } |