mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
996 lines
40 KiB
Java
Executable File
996 lines
40 KiB
Java
Executable File
// Copyright 2012 Citrix Systems, Inc. Licensed under the
|
|
// Apache License, Version 2.0 (the "License"); you may not use this
|
|
// file except in compliance with the License. Citrix Systems, Inc.
|
|
// reserves all rights not expressly granted by 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.
|
|
//
|
|
// Automatically generated by addcopyright.py at 04/03/2012
|
|
package com.cloud.hypervisor.vmware;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.net.URI;
|
|
import java.net.URISyntaxException;
|
|
import java.net.URL;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Random;
|
|
import java.util.UUID;
|
|
import java.util.concurrent.Executors;
|
|
import java.util.concurrent.ScheduledExecutorService;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
import javax.ejb.Local;
|
|
import javax.naming.ConfigurationException;
|
|
|
|
import org.apache.log4j.Logger;
|
|
|
|
import com.cloud.agent.AgentManager;
|
|
import com.cloud.agent.Listener;
|
|
import com.cloud.agent.api.AgentControlAnswer;
|
|
import com.cloud.agent.api.AgentControlCommand;
|
|
import com.cloud.agent.api.Answer;
|
|
import com.cloud.agent.api.Command;
|
|
import com.cloud.agent.api.StartupCommand;
|
|
import com.cloud.agent.api.StartupRoutingCommand;
|
|
import com.cloud.cluster.CheckPointManager;
|
|
import com.cloud.cluster.ClusterManager;
|
|
import com.cloud.configuration.Config;
|
|
import com.cloud.configuration.dao.ConfigurationDao;
|
|
import com.cloud.dc.ClusterDetailsDao;
|
|
import com.cloud.dc.ClusterVO;
|
|
import com.cloud.dc.ClusterVSMMapVO;
|
|
import com.cloud.dc.dao.ClusterDao;
|
|
import com.cloud.dc.dao.ClusterVSMMapDao;
|
|
import com.cloud.exception.DiscoveredWithErrorException;
|
|
import com.cloud.host.HostVO;
|
|
import com.cloud.host.Status;
|
|
import com.cloud.host.dao.HostDao;
|
|
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
|
import com.cloud.hypervisor.vmware.manager.VmwareManager;
|
|
import com.cloud.hypervisor.vmware.manager.VmwareStorageManager;
|
|
import com.cloud.hypervisor.vmware.manager.VmwareStorageManagerImpl;
|
|
import com.cloud.hypervisor.vmware.manager.VmwareStorageMount;
|
|
import com.cloud.hypervisor.vmware.mo.DiskControllerType;
|
|
import com.cloud.hypervisor.vmware.mo.HostFirewallSystemMO;
|
|
import com.cloud.hypervisor.vmware.mo.HostMO;
|
|
import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
|
|
import com.cloud.hypervisor.vmware.mo.TaskMO;
|
|
import com.cloud.hypervisor.vmware.mo.VirtualEthernetCardType;
|
|
import com.cloud.hypervisor.vmware.mo.VmwareHostType;
|
|
import com.cloud.hypervisor.vmware.resource.SshHelper;
|
|
import com.cloud.hypervisor.vmware.util.VmwareContext;
|
|
import com.cloud.network.CiscoNexusVSMDeviceVO;
|
|
import com.cloud.network.NetworkManager;
|
|
import com.cloud.network.dao.CiscoNexusVSMDeviceDao;
|
|
import com.cloud.network.router.VirtualNetworkApplianceManager;
|
|
import com.cloud.org.Cluster.ClusterType;
|
|
import com.cloud.secstorage.CommandExecLogDao;
|
|
import com.cloud.serializer.GsonHelper;
|
|
import com.cloud.server.ConfigurationServer;
|
|
import com.cloud.storage.StorageLayer;
|
|
import com.cloud.storage.secondary.SecondaryStorageVmManager;
|
|
import com.cloud.utils.FileUtil;
|
|
import com.cloud.utils.NumbersUtil;
|
|
import com.cloud.utils.Pair;
|
|
import com.cloud.utils.component.ComponentLocator;
|
|
import com.cloud.utils.component.Inject;
|
|
import com.cloud.utils.component.Manager;
|
|
import com.cloud.utils.concurrency.NamedThreadFactory;
|
|
import com.cloud.utils.db.DB;
|
|
import com.cloud.utils.db.GlobalLock;
|
|
import com.cloud.utils.exception.CloudRuntimeException;
|
|
import com.cloud.utils.script.Script;
|
|
import com.cloud.vm.DomainRouterVO;
|
|
import com.google.gson.Gson;
|
|
import com.vmware.apputils.vim25.ServiceUtil;
|
|
import com.vmware.vim25.HostConnectSpec;
|
|
import com.vmware.vim25.HostPortGroupSpec;
|
|
import com.vmware.vim25.ManagedObjectReference;
|
|
|
|
@Local(value = {VmwareManager.class})
|
|
public class VmwareManagerImpl implements VmwareManager, VmwareStorageMount, Listener, Manager {
|
|
private static final Logger s_logger = Logger.getLogger(VmwareManagerImpl.class);
|
|
|
|
private static final int STARTUP_DELAY = 60000; // 60 seconds
|
|
private static final long DEFAULT_HOST_SCAN_INTERVAL = 600000; // every 10 minutes
|
|
|
|
private long _hostScanInterval = DEFAULT_HOST_SCAN_INTERVAL;
|
|
int _timeout;
|
|
|
|
private String _name;
|
|
private String _instance;
|
|
|
|
@Inject AgentManager _agentMgr;
|
|
@Inject
|
|
protected NetworkManager _netMgr;
|
|
@Inject HostDao _hostDao;
|
|
@Inject ClusterDao _clusterDao;
|
|
@Inject ClusterDetailsDao _clusterDetailsDao;
|
|
@Inject CommandExecLogDao _cmdExecLogDao;
|
|
@Inject ClusterManager _clusterMgr;
|
|
@Inject CheckPointManager _checkPointMgr;
|
|
@Inject VirtualNetworkApplianceManager _routerMgr;
|
|
@Inject SecondaryStorageVmManager _ssvmMgr;
|
|
@Inject CiscoNexusVSMDeviceDao _nexusDao;
|
|
@Inject ClusterVSMMapDao _vsmMapDao;
|
|
|
|
ConfigurationServer _configServer;
|
|
|
|
String _mountParent;
|
|
StorageLayer _storage;
|
|
|
|
String _privateNetworkVSwitchName;
|
|
String _publicNetworkVSwitchName;
|
|
String _guestNetworkVSwitchName;
|
|
boolean _nexusVSwitchActive;
|
|
String _serviceConsoleName;
|
|
String _managemetPortGroupName;
|
|
String _defaultSystemVmNicAdapterType = VirtualEthernetCardType.E1000.toString();
|
|
String _recycleHungWorker = "false";
|
|
int _additionalPortRangeStart;
|
|
int _additionalPortRangeSize;
|
|
int _maxHostsPerCluster;
|
|
int _routerExtraPublicNics = 2;
|
|
|
|
String _cpuOverprovisioningFactor = "1";
|
|
String _reserveCpu = "false";
|
|
|
|
String _memOverprovisioningFactor = "1";
|
|
String _reserveMem = "false";
|
|
|
|
String _rootDiskController = DiskControllerType.ide.toString();
|
|
|
|
Map<String, String> _storageMounts = new HashMap<String, String>();
|
|
|
|
Random _rand = new Random(System.currentTimeMillis());
|
|
Gson _gson;
|
|
|
|
VmwareStorageManager _storageMgr;
|
|
GlobalLock _exclusiveOpLock = GlobalLock.getInternLock("vmware.exclusive.op");
|
|
|
|
private final ScheduledExecutorService _hostScanScheduler = Executors.newScheduledThreadPool(
|
|
1, new NamedThreadFactory("Vmware-Host-Scan"));
|
|
|
|
public VmwareManagerImpl() {
|
|
_gson = GsonHelper.getGsonLogger();
|
|
_storageMgr = new VmwareStorageManagerImpl(this);
|
|
}
|
|
|
|
@Override
|
|
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
|
|
s_logger.info("Configure VmwareManagerImpl, manager name: " + name);
|
|
|
|
_name = name;
|
|
|
|
ComponentLocator locator = ComponentLocator.getCurrentLocator();
|
|
ConfigurationDao configDao = locator.getDao(ConfigurationDao.class);
|
|
if (configDao == null) {
|
|
throw new ConfigurationException("Unable to get the configuration dao.");
|
|
}
|
|
|
|
if(!configDao.isPremium()) {
|
|
s_logger.error("Vmware component can only run under premium distribution");
|
|
throw new ConfigurationException("Vmware component can only run under premium distribution");
|
|
}
|
|
|
|
_instance = configDao.getValue(Config.InstanceName.key());
|
|
if (_instance == null) {
|
|
_instance = "DEFAULT";
|
|
}
|
|
s_logger.info("VmwareManagerImpl config - instance.name: " + _instance);
|
|
|
|
_mountParent = configDao.getValue(Config.MountParent.key());
|
|
if (_mountParent == null) {
|
|
_mountParent = File.separator + "mnt";
|
|
}
|
|
|
|
if (_instance != null) {
|
|
_mountParent = _mountParent + File.separator + _instance;
|
|
}
|
|
s_logger.info("VmwareManagerImpl config - _mountParent: " + _mountParent);
|
|
|
|
String value = (String)params.get("scripts.timeout");
|
|
_timeout = NumbersUtil.parseInt(value, 1440) * 1000;
|
|
|
|
_storage = (StorageLayer)params.get(StorageLayer.InstanceConfigKey);
|
|
if (_storage == null) {
|
|
value = (String)params.get(StorageLayer.ClassConfigKey);
|
|
if (value == null) {
|
|
value = "com.cloud.storage.JavaStorageLayer";
|
|
}
|
|
|
|
try {
|
|
Class<?> clazz = Class.forName(value);
|
|
_storage = (StorageLayer)ComponentLocator.inject(clazz);
|
|
_storage.configure("StorageLayer", params);
|
|
} catch (ClassNotFoundException e) {
|
|
throw new ConfigurationException("Unable to find class " + value);
|
|
}
|
|
}
|
|
|
|
value = configDao.getValue(Config.VmwareUseNexusVSwitch.key());
|
|
if(value == null) {
|
|
_nexusVSwitchActive = false;
|
|
}
|
|
else
|
|
{
|
|
_nexusVSwitchActive = Boolean.parseBoolean(value);
|
|
}
|
|
|
|
_privateNetworkVSwitchName = configDao.getValue(Config.VmwarePrivateNetworkVSwitch.key());
|
|
|
|
if (_privateNetworkVSwitchName == null) {
|
|
_privateNetworkVSwitchName = "vSwitch0";
|
|
} else {
|
|
_privateNetworkVSwitchName = "privateEthernetPortProfile";
|
|
}
|
|
|
|
_publicNetworkVSwitchName = configDao.getValue(Config.VmwarePublicNetworkVSwitch.key());
|
|
|
|
if (_publicNetworkVSwitchName == null) {
|
|
_publicNetworkVSwitchName = "vSwitch0";
|
|
} else {
|
|
_publicNetworkVSwitchName = "publicEthernetPortProfile";
|
|
}
|
|
|
|
_guestNetworkVSwitchName = configDao.getValue(Config.VmwareGuestNetworkVSwitch.key());
|
|
|
|
if (_guestNetworkVSwitchName == null) {
|
|
_guestNetworkVSwitchName = "vSwitch0";
|
|
} else {
|
|
_guestNetworkVSwitchName = "guestEthernetPortProfile";
|
|
}
|
|
|
|
_serviceConsoleName = configDao.getValue(Config.VmwareServiceConsole.key());
|
|
if(_serviceConsoleName == null) {
|
|
_serviceConsoleName = "Service Console";
|
|
}
|
|
|
|
_managemetPortGroupName = configDao.getValue(Config.VmwareManagementPortGroup.key());
|
|
if(_managemetPortGroupName == null) {
|
|
_managemetPortGroupName = "Management Network";
|
|
}
|
|
|
|
_defaultSystemVmNicAdapterType = configDao.getValue(Config.VmwareSystemVmNicDeviceType.key());
|
|
if(_defaultSystemVmNicAdapterType == null)
|
|
_defaultSystemVmNicAdapterType = VirtualEthernetCardType.E1000.toString();
|
|
|
|
_additionalPortRangeStart = NumbersUtil.parseInt(configDao.getValue(Config.VmwareAdditionalVncPortRangeStart.key()), 59000);
|
|
if(_additionalPortRangeStart > 65535) {
|
|
s_logger.warn("Invalid port range start port (" + _additionalPortRangeStart + ") for additional VNC port allocation, reset it to default start port 59000");
|
|
_additionalPortRangeStart = 59000;
|
|
}
|
|
|
|
_additionalPortRangeSize = NumbersUtil.parseInt(configDao.getValue(Config.VmwareAdditionalVncPortRangeSize.key()), 1000);
|
|
if(_additionalPortRangeSize < 0 || _additionalPortRangeStart + _additionalPortRangeSize > 65535) {
|
|
s_logger.warn("Invalid port range size (" + _additionalPortRangeSize + " for range starts at " + _additionalPortRangeStart);
|
|
_additionalPortRangeSize = Math.min(1000, 65535 - _additionalPortRangeStart);
|
|
}
|
|
|
|
_routerExtraPublicNics = NumbersUtil.parseInt(configDao.getValue(Config.RouterExtraPublicNics.key()), 2);
|
|
|
|
_maxHostsPerCluster = NumbersUtil.parseInt(configDao.getValue(Config.VmwarePerClusterHostMax.key()), VmwareManager.MAX_HOSTS_PER_CLUSTER);
|
|
_cpuOverprovisioningFactor = configDao.getValue(Config.CPUOverprovisioningFactor.key());
|
|
if(_cpuOverprovisioningFactor == null || _cpuOverprovisioningFactor.isEmpty())
|
|
_cpuOverprovisioningFactor = "1";
|
|
|
|
_memOverprovisioningFactor = configDao.getValue(Config.MemOverprovisioningFactor.key());
|
|
if(_memOverprovisioningFactor == null || _memOverprovisioningFactor.isEmpty())
|
|
_memOverprovisioningFactor = "1";
|
|
|
|
_reserveCpu = configDao.getValue(Config.VmwareReserveCpu.key());
|
|
if(_reserveCpu == null || _reserveCpu.isEmpty())
|
|
_reserveCpu = "false";
|
|
_reserveMem = configDao.getValue(Config.VmwareReserveMem.key());
|
|
if(_reserveMem == null || _reserveMem.isEmpty())
|
|
_reserveMem = "false";
|
|
|
|
_recycleHungWorker = configDao.getValue(Config.VmwareRecycleHungWorker.key());
|
|
if(_recycleHungWorker == null || _recycleHungWorker.isEmpty())
|
|
_recycleHungWorker = "false";
|
|
|
|
_rootDiskController = configDao.getValue(Config.VmwareRootDiskControllerType.key());
|
|
if(_rootDiskController == null || _rootDiskController.isEmpty())
|
|
_rootDiskController = DiskControllerType.ide.toString();
|
|
|
|
s_logger.info("Additional VNC port allocation range is settled at " + _additionalPortRangeStart + " to " + (_additionalPortRangeStart + _additionalPortRangeSize));
|
|
|
|
value = configDao.getValue("vmware.host.scan.interval");
|
|
_hostScanInterval = NumbersUtil.parseLong(value, DEFAULT_HOST_SCAN_INTERVAL);
|
|
s_logger.info("VmwareManagerImpl config - vmware.host.scan.interval: " + _hostScanInterval);
|
|
|
|
((VmwareStorageManagerImpl)_storageMgr).configure(params);
|
|
|
|
if(_configServer == null)
|
|
_configServer = (ConfigurationServer)ComponentLocator.getComponent(ConfigurationServer.Name);
|
|
|
|
_agentMgr.registerForHostEvents(this, true, true, true);
|
|
|
|
s_logger.info("VmwareManagerImpl has been successfully configured");
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean start() {
|
|
_hostScanScheduler.scheduleAtFixedRate(getHostScanTask(),
|
|
STARTUP_DELAY, _hostScanInterval, TimeUnit.MILLISECONDS);
|
|
|
|
startupCleanup(_mountParent);
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean stop() {
|
|
_hostScanScheduler.shutdownNow();
|
|
try {
|
|
_hostScanScheduler.awaitTermination(3000, TimeUnit.MILLISECONDS);
|
|
} catch (InterruptedException e) {
|
|
}
|
|
|
|
shutdownCleanup();
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public String getName() {
|
|
return _name;
|
|
}
|
|
|
|
public boolean getNexusVSwitchGlobalParameter() {
|
|
return _nexusVSwitchActive;
|
|
}
|
|
|
|
@Override
|
|
public String composeWorkerName() {
|
|
return UUID.randomUUID().toString().replace("-", "");
|
|
}
|
|
|
|
@Override
|
|
public String getPrivateVSwitchName(long dcId, HypervisorType hypervisorType) {
|
|
return _netMgr.getDefaultManagementTrafficLabel(dcId, hypervisorType);
|
|
}
|
|
|
|
@Override
|
|
public String getPublicVSwitchName(long dcId, HypervisorType hypervisorType) {
|
|
return _netMgr.getDefaultPublicTrafficLabel(dcId, hypervisorType);
|
|
}
|
|
|
|
@Override
|
|
public String getGuestVSwitchName(long dcId, HypervisorType hypervisorType) {
|
|
return _netMgr.getDefaultGuestTrafficLabel(dcId, hypervisorType);
|
|
}
|
|
|
|
@Override
|
|
public List<ManagedObjectReference> addHostToPodCluster(VmwareContext serviceContext, long dcId, Long podId, Long clusterId,
|
|
String hostInventoryPath) throws Exception {
|
|
ManagedObjectReference mor = null;
|
|
if (serviceContext != null)
|
|
mor = serviceContext.getHostMorByPath(hostInventoryPath);
|
|
|
|
String privateTrafficLabel = null;
|
|
if (_nexusVSwitchActive) {
|
|
privateTrafficLabel = serviceContext.getStockObject("privateTrafficLabel");
|
|
if (privateTrafficLabel == null) {
|
|
privateTrafficLabel = _privateNetworkVSwitchName;
|
|
}
|
|
}
|
|
|
|
if(mor != null) {
|
|
List<ManagedObjectReference> returnedHostList = new ArrayList<ManagedObjectReference>();
|
|
|
|
if(mor.getType().equals("ComputeResource")) {
|
|
ManagedObjectReference[] hosts = (ManagedObjectReference[])serviceContext.getServiceUtil().getDynamicProperty(mor, "host");
|
|
assert(hosts != null);
|
|
|
|
// For ESX host, we need to enable host firewall to allow VNC access
|
|
HostMO hostMo = new HostMO(serviceContext, hosts[0]);
|
|
HostFirewallSystemMO firewallMo = hostMo.getHostFirewallSystemMO();
|
|
if(firewallMo != null) {
|
|
if(hostMo.getHostType() == VmwareHostType.ESX) {
|
|
firewallMo.enableRuleset("vncServer");
|
|
firewallMo.refreshFirewall();
|
|
}
|
|
}
|
|
|
|
// prepare at least one network on the vswitch to enable OVF importing
|
|
String managementPortGroupName = getManagementPortGroupByHost(hostMo);
|
|
assert(managementPortGroupName != null);
|
|
HostPortGroupSpec spec = hostMo.getPortGroupSpec(managementPortGroupName);
|
|
String vlanId = null;
|
|
if(spec.getVlanId() != 0) {
|
|
vlanId = String.valueOf(spec.getVlanId());
|
|
}
|
|
|
|
if(!_nexusVSwitchActive) {
|
|
HypervisorHostHelper.prepareNetwork(_privateNetworkVSwitchName, "cloud.private", hostMo, vlanId, null, null, 180000, false);
|
|
}
|
|
else {
|
|
s_logger.info("Preparing Network on " + privateTrafficLabel);
|
|
HypervisorHostHelper.prepareNetwork(privateTrafficLabel, "cloud.private", hostMo, vlanId, null, null, 180000);
|
|
}
|
|
returnedHostList.add(hosts[0]);
|
|
return returnedHostList;
|
|
} else if(mor.getType().equals("ClusterComputeResource")) {
|
|
ManagedObjectReference[] hosts = (ManagedObjectReference[])serviceContext.getServiceUtil().getDynamicProperty(mor, "host");
|
|
assert(hosts != null);
|
|
|
|
if(hosts.length > _maxHostsPerCluster) {
|
|
String msg = "vCenter cluster size is too big (current configured cluster size: " + _maxHostsPerCluster + ")";
|
|
s_logger.error(msg);
|
|
throw new DiscoveredWithErrorException(msg);
|
|
}
|
|
|
|
for(ManagedObjectReference morHost: hosts) {
|
|
// For ESX host, we need to enable host firewall to allow VNC access
|
|
HostMO hostMo = new HostMO(serviceContext, morHost);
|
|
HostFirewallSystemMO firewallMo = hostMo.getHostFirewallSystemMO();
|
|
if(firewallMo != null) {
|
|
if(hostMo.getHostType() == VmwareHostType.ESX) {
|
|
firewallMo.enableRuleset("vncServer");
|
|
firewallMo.refreshFirewall();
|
|
}
|
|
}
|
|
|
|
String managementPortGroupName = getManagementPortGroupByHost(hostMo);
|
|
assert(managementPortGroupName != null);
|
|
|
|
HostPortGroupSpec spec = hostMo.getPortGroupSpec(managementPortGroupName);
|
|
String vlanId = null;
|
|
if(spec.getVlanId() != 0) {
|
|
vlanId = String.valueOf(spec.getVlanId());
|
|
}
|
|
s_logger.info("Calling prepareNetwork : " + hostMo.getContext().toString());
|
|
// prepare at least one network on the vswitch to enable OVF importing
|
|
if(!_nexusVSwitchActive) {
|
|
HypervisorHostHelper.prepareNetwork(_privateNetworkVSwitchName, "cloud.private", hostMo, vlanId, null, null, 180000, false);
|
|
}
|
|
else {
|
|
s_logger.info("Preparing Network on " + privateTrafficLabel);
|
|
HypervisorHostHelper.prepareNetwork(privateTrafficLabel, "cloud.private", hostMo, vlanId, null, null, 180000);
|
|
}
|
|
returnedHostList.add(morHost);
|
|
}
|
|
return returnedHostList;
|
|
} else if(mor.getType().equals("HostSystem")) {
|
|
// For ESX host, we need to enable host firewall to allow VNC access
|
|
HostMO hostMo = new HostMO(serviceContext, mor);
|
|
HostFirewallSystemMO firewallMo = hostMo.getHostFirewallSystemMO();
|
|
if(firewallMo != null) {
|
|
if(hostMo.getHostType() == VmwareHostType.ESX) {
|
|
firewallMo.enableRuleset("vncServer");
|
|
firewallMo.refreshFirewall();
|
|
}
|
|
}
|
|
|
|
String managementPortGroupName = getManagementPortGroupByHost(hostMo);
|
|
assert(managementPortGroupName != null);
|
|
HostPortGroupSpec spec = hostMo.getPortGroupSpec(managementPortGroupName);
|
|
String vlanId = null;
|
|
if(spec.getVlanId() != 0) {
|
|
vlanId = String.valueOf(spec.getVlanId());
|
|
}
|
|
|
|
// prepare at least one network on the vswitch to enable OVF importing
|
|
if(!_nexusVSwitchActive) {
|
|
HypervisorHostHelper.prepareNetwork(_privateNetworkVSwitchName, "cloud.private", hostMo, vlanId, null, null, 180000, false);
|
|
}
|
|
else {
|
|
s_logger.info("Preparing Network on " + privateTrafficLabel);
|
|
HypervisorHostHelper.prepareNetwork(privateTrafficLabel, "cloud.private", hostMo, vlanId, null, null, 180000);
|
|
}
|
|
returnedHostList.add(mor);
|
|
return returnedHostList;
|
|
} else {
|
|
s_logger.error("Unsupport host type " + mor.getType() + ":" + mor.get_value() + " from inventory path: " + hostInventoryPath);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
s_logger.error("Unable to find host from inventory path: " + hostInventoryPath);
|
|
return null;
|
|
}
|
|
|
|
@Deprecated
|
|
private ManagedObjectReference addHostToVCenterCluster(VmwareContext serviceContext, ManagedObjectReference morCluster,
|
|
String host, String userName, String password) throws Exception {
|
|
|
|
ServiceUtil serviceUtil = serviceContext.getServiceUtil();
|
|
ManagedObjectReference morHost = serviceUtil.getDecendentMoRef(morCluster, "HostSystem", host);
|
|
if(morHost == null) {
|
|
HostConnectSpec hostSpec = new HostConnectSpec();
|
|
hostSpec.setUserName(userName);
|
|
hostSpec.setPassword(password);
|
|
hostSpec.setHostName(host);
|
|
hostSpec.setForce(true); // forcely take over the host
|
|
|
|
ManagedObjectReference morTask = serviceContext.getService().addHost_Task(morCluster, hostSpec, true, null, null);
|
|
String taskResult = serviceUtil.waitForTask(morTask);
|
|
if(!taskResult.equals("sucess")) {
|
|
s_logger.error("Unable to add host " + host + " to vSphere cluster due to " + TaskMO.getTaskFailureInfo(serviceContext, morTask));
|
|
throw new CloudRuntimeException("Unable to add host " + host + " to vSphere cluster due to " + taskResult);
|
|
}
|
|
serviceContext.waitForTaskProgressDone(morTask);
|
|
|
|
// init morHost after it has been created
|
|
morHost = serviceUtil.getDecendentMoRef(morCluster, "HostSystem", host);
|
|
if(morHost == null) {
|
|
throw new CloudRuntimeException("Successfully added host into vSphere but unable to find it later on?!. Please make sure you are either using IP address or full qualified domain name for host");
|
|
}
|
|
}
|
|
|
|
// For ESX host, we need to enable host firewall to allow VNC access
|
|
HostMO hostMo = new HostMO(serviceContext, morHost);
|
|
HostFirewallSystemMO firewallMo = hostMo.getHostFirewallSystemMO();
|
|
if(firewallMo != null) {
|
|
firewallMo.enableRuleset("vncServer");
|
|
firewallMo.refreshFirewall();
|
|
}
|
|
return morHost;
|
|
}
|
|
|
|
@Override
|
|
public String getSecondaryStorageStoreUrl(long dcId) {
|
|
List<HostVO> secStorageHosts = _ssvmMgr.listSecondaryStorageHostsInOneZone(dcId);
|
|
if(secStorageHosts.size() > 0)
|
|
return secStorageHosts.get(0).getStorageUrl();
|
|
|
|
return null;
|
|
}
|
|
|
|
public String getServiceConsolePortGroupName() {
|
|
return _serviceConsoleName;
|
|
}
|
|
|
|
public String getManagementPortGroupName() {
|
|
return _managemetPortGroupName;
|
|
}
|
|
|
|
@Override
|
|
public String getManagementPortGroupByHost(HostMO hostMo) throws Exception {
|
|
if(hostMo.getHostType() == VmwareHostType.ESXi)
|
|
return this._managemetPortGroupName;
|
|
return this._serviceConsoleName;
|
|
}
|
|
|
|
@Override
|
|
public void setupResourceStartupParams(Map<String, Object> params) {
|
|
params.put("private.network.vswitch.name", _privateNetworkVSwitchName);
|
|
params.put("public.network.vswitch.name", _publicNetworkVSwitchName);
|
|
params.put("guest.network.vswitch.name", _guestNetworkVSwitchName);
|
|
params.put("vmware.use.nexus.vswitch", _nexusVSwitchActive);
|
|
params.put("service.console.name", _serviceConsoleName);
|
|
params.put("management.portgroup.name", _managemetPortGroupName);
|
|
params.put("cpu.overprovisioning.factor", _cpuOverprovisioningFactor);
|
|
params.put("vmware.reserve.cpu", _reserveCpu);
|
|
params.put("mem.overprovisioning.factor", _memOverprovisioningFactor);
|
|
params.put("vmware.reserve.mem", _reserveMem);
|
|
params.put("vmware.root.disk.controller", _rootDiskController);
|
|
params.put("vmware.recycle.hung.wokervm", _recycleHungWorker);
|
|
}
|
|
|
|
@Override
|
|
public VmwareStorageManager getStorageManager() {
|
|
return _storageMgr;
|
|
}
|
|
|
|
|
|
@Override
|
|
public long pushCleanupCheckpoint(String hostGuid, String vmName) {
|
|
return _checkPointMgr.pushCheckPoint(new VmwareCleanupMaid(hostGuid, vmName));
|
|
}
|
|
|
|
@Override
|
|
public void popCleanupCheckpoint(long checkpoint) {
|
|
_checkPointMgr.popCheckPoint(checkpoint);
|
|
}
|
|
|
|
@Override
|
|
public void gcLeftOverVMs(VmwareContext context) {
|
|
VmwareCleanupMaid.gcLeftOverVMs(context);
|
|
}
|
|
|
|
@Override
|
|
public void prepareSecondaryStorageStore(String storageUrl) {
|
|
String mountPoint = getMountPoint(storageUrl);
|
|
|
|
GlobalLock lock = GlobalLock.getInternLock("prepare.systemvm");
|
|
try {
|
|
if(lock.lock(3600)) {
|
|
try {
|
|
File patchFolder = new File(mountPoint + "/systemvm");
|
|
if(!patchFolder.exists()) {
|
|
if(!patchFolder.mkdirs()) {
|
|
String msg = "Unable to create systemvm folder on secondary storage. location: " + patchFolder.toString();
|
|
s_logger.error(msg);
|
|
throw new CloudRuntimeException(msg);
|
|
}
|
|
}
|
|
|
|
File srcIso = getSystemVMPatchIsoFile();
|
|
File destIso = new File(mountPoint + "/systemvm/" + getSystemVMIsoFileNameOnDatastore());
|
|
if(!destIso.exists()) {
|
|
s_logger.info("Inject SSH key pairs before copying systemvm.iso into secondary storage");
|
|
_configServer.updateKeyPairs();
|
|
|
|
try {
|
|
FileUtil.copyfile(srcIso, destIso);
|
|
} catch(IOException e) {
|
|
s_logger.error("Unexpected exception ", e);
|
|
|
|
String msg = "Unable to copy systemvm ISO on secondary storage. src location: " + srcIso.toString() + ", dest location: " + destIso;
|
|
s_logger.error(msg);
|
|
throw new CloudRuntimeException(msg);
|
|
}
|
|
} else {
|
|
if(s_logger.isTraceEnabled())
|
|
s_logger.trace("SystemVM ISO file " + destIso.getPath() + " already exists");
|
|
}
|
|
} finally {
|
|
lock.unlock();
|
|
}
|
|
}
|
|
} finally {
|
|
lock.releaseRef();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String getSystemVMIsoFileNameOnDatastore() {
|
|
String version = ComponentLocator.class.getPackage().getImplementationVersion();
|
|
String fileName = "systemvm-" + version + ".iso";
|
|
return fileName.replace(':', '-');
|
|
}
|
|
|
|
@Override
|
|
public String getSystemVMDefaultNicAdapterType() {
|
|
return this._defaultSystemVmNicAdapterType;
|
|
}
|
|
|
|
private File getSystemVMPatchIsoFile() {
|
|
// locate systemvm.iso
|
|
URL url = ComponentLocator.class.getProtectionDomain().getCodeSource().getLocation();
|
|
File file = new File(url.getFile());
|
|
File isoFile = new File(file.getParent() + "/vms/systemvm.iso");
|
|
if (!isoFile.exists()) {
|
|
isoFile = new File("/usr/lib64/cloud/agent/" + "/vms/systemvm.iso");
|
|
if (!isoFile.exists()) {
|
|
isoFile = new File("/usr/lib/cloud/agent/" + "/vms/systemvm.iso");
|
|
}
|
|
}
|
|
return isoFile;
|
|
}
|
|
|
|
@Override
|
|
public File getSystemVMKeyFile() {
|
|
URL url = ComponentLocator.class.getProtectionDomain().getCodeSource().getLocation();
|
|
File file = new File(url.getFile());
|
|
|
|
File keyFile = new File(file.getParent(), "/scripts/vm/systemvm/id_rsa.cloud");
|
|
if (!keyFile.exists()) {
|
|
keyFile = new File("/usr/lib64/cloud/agent" + "/scripts/vm/systemvm/id_rsa.cloud");
|
|
if (!keyFile.exists()) {
|
|
keyFile = new File("/usr/lib/cloud/agent" + "/scripts/vm/systemvm/id_rsa.cloud");
|
|
}
|
|
}
|
|
return keyFile;
|
|
}
|
|
|
|
private Runnable getHostScanTask() {
|
|
return new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
// TODO scan vSphere for newly added hosts.
|
|
// we are going to both support adding host from CloudStack UI and
|
|
// adding host via vSphere server
|
|
//
|
|
// will implement host scanning later
|
|
}
|
|
};
|
|
}
|
|
|
|
@Override
|
|
public String getMountPoint(String storageUrl) {
|
|
String mountPoint = null;
|
|
synchronized(_storageMounts) {
|
|
mountPoint = _storageMounts.get(storageUrl);
|
|
if(mountPoint != null) {
|
|
return mountPoint;
|
|
}
|
|
|
|
URI uri;
|
|
try {
|
|
uri = new URI(storageUrl);
|
|
} catch (URISyntaxException e) {
|
|
s_logger.error("Invalid storage URL format ", e);
|
|
throw new CloudRuntimeException("Unable to create mount point due to invalid storage URL format " + storageUrl);
|
|
}
|
|
mountPoint = mount(uri.getHost() + ":" + uri.getPath(), _mountParent);
|
|
if(mountPoint == null) {
|
|
s_logger.error("Unable to create mount point for " + storageUrl);
|
|
return "/mnt/sec"; // throw new CloudRuntimeException("Unable to create mount point for " + storageUrl);
|
|
}
|
|
|
|
_storageMounts.put(storageUrl, mountPoint);
|
|
return mountPoint;
|
|
}
|
|
}
|
|
|
|
private String setupMountPoint(String parent) {
|
|
String mountPoint = null;
|
|
long mshostId = _clusterMgr.getManagementNodeId();
|
|
for (int i = 0; i < 10; i++) {
|
|
String mntPt = parent + File.separator + String.valueOf(mshostId) + "." + Integer.toHexString(_rand.nextInt(Integer.MAX_VALUE));
|
|
File file = new File(mntPt);
|
|
if (!file.exists()) {
|
|
if (_storage.mkdir(mntPt)) {
|
|
mountPoint = mntPt;
|
|
break;
|
|
}
|
|
}
|
|
s_logger.error("Unable to create mount: " + mntPt);
|
|
}
|
|
|
|
return mountPoint;
|
|
}
|
|
|
|
private void startupCleanup(String parent) {
|
|
s_logger.info("Cleanup mounted NFS mount points used in previous session");
|
|
|
|
long mshostId = _clusterMgr.getManagementNodeId();
|
|
|
|
// cleanup left-over NFS mounts from previous session
|
|
String[] mounts = _storage.listFiles(parent + File.separator + String.valueOf(mshostId) + ".*");
|
|
if(mounts != null && mounts.length > 0) {
|
|
for(String mountPoint : mounts) {
|
|
s_logger.info("umount NFS mount from previous session: " + mountPoint);
|
|
|
|
String result = null;
|
|
Script command = new Script(true, "umount", _timeout, s_logger);
|
|
command.add(mountPoint);
|
|
result = command.execute();
|
|
if (result != null) {
|
|
s_logger.warn("Unable to umount " + mountPoint + " due to " + result);
|
|
}
|
|
File file = new File(mountPoint);
|
|
if (file.exists()) {
|
|
file.delete();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void shutdownCleanup() {
|
|
s_logger.info("Cleanup mounted NFS mount points used in current session");
|
|
|
|
for(String mountPoint : _storageMounts.values()) {
|
|
s_logger.info("umount NFS mount: " + mountPoint);
|
|
|
|
String result = null;
|
|
Script command = new Script(true, "umount", _timeout, s_logger);
|
|
command.add(mountPoint);
|
|
result = command.execute();
|
|
if (result != null) {
|
|
s_logger.warn("Unable to umount " + mountPoint + " due to " + result);
|
|
}
|
|
File file = new File(mountPoint);
|
|
if (file.exists()) {
|
|
file.delete();
|
|
}
|
|
}
|
|
}
|
|
|
|
protected String mount(String path, String parent) {
|
|
String mountPoint = setupMountPoint(parent);
|
|
if (mountPoint == null) {
|
|
s_logger.warn("Unable to create a mount point");
|
|
return null;
|
|
}
|
|
|
|
Script script = null;
|
|
String result = null;
|
|
Script command = new Script(true, "mount", _timeout, s_logger);
|
|
command.add("-t", "nfs");
|
|
// command.add("-o", "soft,timeo=133,retrans=2147483647,tcp,acdirmax=0,acdirmin=0");
|
|
if ("Mac OS X".equalsIgnoreCase(System.getProperty("os.name"))) {
|
|
command.add("-o", "resvport");
|
|
}
|
|
command.add(path);
|
|
command.add(mountPoint);
|
|
result = command.execute();
|
|
if (result != null) {
|
|
s_logger.warn("Unable to mount " + path + " due to " + result);
|
|
File file = new File(mountPoint);
|
|
if (file.exists()) {
|
|
file.delete();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// Change permissions for the mountpoint
|
|
script = new Script(true, "chmod", _timeout, s_logger);
|
|
script.add("777", mountPoint);
|
|
result = script.execute();
|
|
if (result != null) {
|
|
s_logger.warn("Unable to set permissions for " + mountPoint + " due to " + result);
|
|
return null;
|
|
}
|
|
return mountPoint;
|
|
}
|
|
|
|
@DB
|
|
private void updateClusterNativeHAState(HostVO host, StartupCommand cmd) {
|
|
ClusterVO cluster = _clusterDao.findById(host.getClusterId());
|
|
if(cluster.getClusterType() == ClusterType.ExternalManaged) {
|
|
if(cmd instanceof StartupRoutingCommand) {
|
|
StartupRoutingCommand hostStartupCmd = (StartupRoutingCommand)cmd;
|
|
Map<String, String> details = hostStartupCmd.getHostDetails();
|
|
|
|
if(details.get("NativeHA") != null && details.get("NativeHA").equalsIgnoreCase("true")) {
|
|
_clusterDetailsDao.persist(host.getClusterId(), "NativeHA", "true");
|
|
} else {
|
|
_clusterDetailsDao.persist(host.getClusterId(), "NativeHA", "false");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override @DB
|
|
public boolean processAnswers(long agentId, long seq, Answer[] answers) {
|
|
if(answers != null) {
|
|
for(Answer answer : answers) {
|
|
String execIdStr = answer.getContextParam("execid");
|
|
if(execIdStr != null) {
|
|
long execId = 0;
|
|
try {
|
|
execId = Long.parseLong(execIdStr);
|
|
} catch(NumberFormatException e) {
|
|
assert(false);
|
|
}
|
|
|
|
_cmdExecLogDao.expunge(execId);
|
|
}
|
|
|
|
String checkPointIdStr = answer.getContextParam("checkpoint");
|
|
if(checkPointIdStr != null) {
|
|
_checkPointMgr.popCheckPoint(Long.parseLong(checkPointIdStr));
|
|
}
|
|
|
|
checkPointIdStr = answer.getContextParam("checkpoint2");
|
|
if(checkPointIdStr != null) {
|
|
_checkPointMgr.popCheckPoint(Long.parseLong(checkPointIdStr));
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean processCommands(long agentId, long seq, Command[] commands) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public AgentControlAnswer processControlCommand(long agentId, AgentControlCommand cmd) {
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public void processConnect(HostVO host, StartupCommand cmd, boolean forRebalance) {
|
|
if(cmd instanceof StartupCommand) {
|
|
if(host.getHypervisorType() == HypervisorType.VMware) {
|
|
updateClusterNativeHAState(host, cmd);
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected final int DEFAULT_DOMR_SSHPORT = 3922;
|
|
|
|
protected boolean shutdownRouterVM(DomainRouterVO router) {
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("Try to shutdown router VM " + router.getInstanceName() + " directly.");
|
|
}
|
|
|
|
Pair<Boolean, String> result;
|
|
try {
|
|
result = SshHelper.sshExecute(router.getPrivateIpAddress(), DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
|
|
"poweroff -f");
|
|
|
|
if (!result.first()) {
|
|
s_logger.debug("Unable to shutdown " + router.getInstanceName() + " directly");
|
|
return false;
|
|
}
|
|
} catch (Throwable e) {
|
|
s_logger.warn("Unable to shutdown router " + router.getInstanceName() + " directly.");
|
|
return false;
|
|
}
|
|
if (s_logger.isDebugEnabled()) {
|
|
s_logger.debug("Shutdown router " + router.getInstanceName() + " successful.");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean processDisconnect(long agentId, Status state) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean isRecurring() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public int getTimeout() {
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public boolean processTimeout(long agentId, long seq) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean beginExclusiveOperation(int timeOutSeconds) {
|
|
return _exclusiveOpLock.lock(timeOutSeconds);
|
|
}
|
|
|
|
@Override
|
|
public void endExclusiveOperation() {
|
|
_exclusiveOpLock.unlock();
|
|
}
|
|
|
|
@Override
|
|
public Pair<Integer, Integer> getAddiionalVncPortRange() {
|
|
return new Pair<Integer, Integer>(_additionalPortRangeStart, _additionalPortRangeSize);
|
|
}
|
|
|
|
@Override
|
|
public int getMaxHostsPerCluster() {
|
|
return this._maxHostsPerCluster;
|
|
}
|
|
|
|
@Override
|
|
public int getRouterExtraPublicNics() {
|
|
return this._routerExtraPublicNics;
|
|
}
|
|
|
|
@Override
|
|
public Map<String, String> getNexusVSMCredentialsByClusterId(Long clusterId) {
|
|
CiscoNexusVSMDeviceVO nexusVSM = null;
|
|
ClusterVSMMapVO vsmMapVO = null;
|
|
|
|
vsmMapVO = _vsmMapDao.findByClusterId(clusterId);
|
|
long vsmId = 0;
|
|
if (vsmMapVO != null) {
|
|
vsmId = vsmMapVO.getVsmId();
|
|
s_logger.info("vsmId is " + vsmId);
|
|
nexusVSM = _nexusDao.findById(vsmId);
|
|
s_logger.info("Fetching nexus vsm credentials from database.");
|
|
}
|
|
else {
|
|
s_logger.info("Found empty vsmMapVO.");
|
|
return null;
|
|
}
|
|
|
|
Map<String, String> nexusVSMCredentials = new HashMap<String, String>();
|
|
if (nexusVSM != null) {
|
|
nexusVSMCredentials.put("vsmip", nexusVSM.getipaddr());
|
|
nexusVSMCredentials.put("vsmusername", nexusVSM.getUserName());
|
|
nexusVSMCredentials.put("vsmpassword", nexusVSM.getPassword());
|
|
s_logger.info("Successfully fetched the credentials of Nexus VSM.");
|
|
}
|
|
return nexusVSMCredentials;
|
|
}
|
|
}
|