You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by mu...@apache.org on 2012/06/27 04:45:55 UTC
[4/9] moving out VMWAre and Nexus VSM support code into
plugins/hypervisors/vmware
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8197f1f0/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java
new file mode 100755
index 0000000..af53dad
--- /dev/null
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java
@@ -0,0 +1,364 @@
+// 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.net.URI;
+import java.net.URLDecoder;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.StartupCommand;
+import com.cloud.agent.api.StartupRoutingCommand;
+import com.cloud.alert.AlertManager;
+import com.cloud.configuration.dao.ConfigurationDao;
+import com.cloud.dc.ClusterDetailsDao;
+import com.cloud.dc.ClusterVO;
+import com.cloud.dc.DataCenter.NetworkType;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.dao.ClusterDao;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.exception.DiscoveredWithErrorException;
+import com.cloud.exception.DiscoveryException;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
+import com.cloud.hypervisor.Hypervisor;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.hypervisor.vmware.manager.VmwareManager;
+import com.cloud.hypervisor.vmware.mo.ClusterMO;
+import com.cloud.hypervisor.vmware.mo.HostMO;
+import com.cloud.hypervisor.vmware.resource.VmwareContextFactory;
+import com.cloud.hypervisor.vmware.resource.VmwareResource;
+import com.cloud.hypervisor.vmware.util.VmwareContext;
+import com.cloud.network.NetworkManager;
+import com.cloud.network.dao.CiscoNexusVSMDeviceDao;
+import com.cloud.resource.Discoverer;
+import com.cloud.resource.DiscovererBase;
+import com.cloud.resource.ResourceManager;
+import com.cloud.resource.ResourceStateAdapter;
+import com.cloud.resource.ServerResource;
+import com.cloud.resource.UnableDeleteHostException;
+import com.cloud.storage.Storage.ImageFormat;
+import com.cloud.storage.Storage.TemplateType;
+import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.dao.VMTemplateDao;
+import com.cloud.user.Account;
+import com.cloud.utils.UriUtils;
+import com.cloud.utils.component.ComponentLocator;
+import com.cloud.utils.component.Inject;
+import com.vmware.vim25.ClusterDasConfigInfo;
+import com.vmware.vim25.ManagedObjectReference;
+
+@Local(value=Discoverer.class)
+public class VmwareServerDiscoverer extends DiscovererBase implements Discoverer, ResourceStateAdapter {
+ private static final Logger s_logger = Logger.getLogger(VmwareServerDiscoverer.class);
+
+ @Inject ClusterDao _clusterDao;
+ @Inject VmwareManager _vmwareMgr;
+ @Inject AlertManager _alertMgr;
+ @Inject VMTemplateDao _tmpltDao;
+ @Inject ClusterDetailsDao _clusterDetailsDao;
+ @Inject HostDao _hostDao;
+ @Inject
+ DataCenterDao _dcDao;
+ @Inject ResourceManager _resourceMgr;
+ @Inject CiscoNexusVSMDeviceDao _nexusDao;
+ @Inject
+ NetworkManager _netmgr;
+
+ @Override
+ public Map<? extends ServerResource, Map<String, String>> find(long dcId, Long podId, Long clusterId, URI url,
+ String username, String password, List<String> hostTags) throws DiscoveryException {
+
+ if(s_logger.isInfoEnabled())
+ s_logger.info("Discover host. dc: " + dcId + ", pod: " + podId + ", cluster: " + clusterId + ", uri host: " + url.getHost());
+
+ if(podId == null) {
+ if(s_logger.isInfoEnabled())
+ s_logger.info("No pod is assigned, assuming that it is not for vmware and skip it to next discoverer");
+ return null;
+ }
+
+ ClusterVO cluster = _clusterDao.findById(clusterId);
+ if(cluster == null || cluster.getHypervisorType() != HypervisorType.VMware) {
+ if(s_logger.isInfoEnabled())
+ s_logger.info("invalid cluster id or cluster is not for VMware hypervisors");
+ return null;
+ }
+
+ List<HostVO> hosts = _resourceMgr.listAllHostsInCluster(clusterId);
+ if(hosts.size() >= _vmwareMgr.getMaxHostsPerCluster()) {
+ String msg = "VMware cluster " + cluster.getName() + " is too big to add new host now. (current configured cluster size: " + _vmwareMgr.getMaxHostsPerCluster() + ")";
+ s_logger.error(msg);
+ throw new DiscoveredWithErrorException(msg);
+ }
+
+ String privateTrafficLabel = null;
+ String publicTrafficLabel = null;
+ String guestTrafficLabel = null;
+ Map<String, String> vsmCredentials = null;
+
+ privateTrafficLabel = _netmgr.getDefaultManagementTrafficLabel(dcId, HypervisorType.VMware);
+ if (privateTrafficLabel != null) {
+ s_logger.info("Detected private network label : " + privateTrafficLabel);
+ }
+
+ if (_vmwareMgr.getNexusVSwitchGlobalParameter()) {
+ DataCenterVO zone = _dcDao.findById(dcId);
+ NetworkType zoneType = zone.getNetworkType();
+ if (zoneType != NetworkType.Basic) {
+ publicTrafficLabel = _netmgr.getDefaultPublicTrafficLabel(dcId, HypervisorType.VMware);
+ if (publicTrafficLabel != null) {
+ s_logger.info("Detected public network label : " + publicTrafficLabel);
+ }
+ }
+ // Get physical network label
+ guestTrafficLabel = _netmgr.getDefaultGuestTrafficLabel(dcId, HypervisorType.VMware);
+ if (guestTrafficLabel != null) {
+ s_logger.info("Detected guest network label : " + guestTrafficLabel);
+ }
+ vsmCredentials = _vmwareMgr.getNexusVSMCredentialsByClusterId(clusterId);
+ }
+
+ VmwareContext context = null;
+ try {
+ context = VmwareContextFactory.create(url.getHost(), username, password);
+ if (privateTrafficLabel != null)
+ context.registerStockObject("privateTrafficLabel", privateTrafficLabel);
+
+ if (_vmwareMgr.getNexusVSwitchGlobalParameter()) {
+ if (vsmCredentials != null) {
+ s_logger.info("Stocking credentials of Nexus VSM");
+ context.registerStockObject("vsmcredentials", vsmCredentials);
+ }
+ }
+ List<ManagedObjectReference> morHosts = _vmwareMgr.addHostToPodCluster(context, dcId, podId, clusterId,
+ URLDecoder.decode(url.getPath()));
+ if (morHosts == null)
+ s_logger.info("Found 0 hosts.");
+ if (privateTrafficLabel != null)
+ context.uregisterStockObject("privateTrafficLabel");
+
+ if(morHosts == null) {
+ s_logger.error("Unable to find host or cluster based on url: " + URLDecoder.decode(url.getPath()));
+ return null;
+ }
+
+ ManagedObjectReference morCluster = null;
+ Map<String, String> clusterDetails = _clusterDetailsDao.findDetails(clusterId);
+ if(clusterDetails.get("url") != null) {
+ URI uriFromCluster = new URI(UriUtils.encodeURIComponent(clusterDetails.get("url")));
+ morCluster = context.getHostMorByPath(URLDecoder.decode(uriFromCluster.getPath()));
+
+ if(morCluster == null || !morCluster.getType().equalsIgnoreCase("ClusterComputeResource")) {
+ s_logger.warn("Cluster url does not point to a valid vSphere cluster, url: " + clusterDetails.get("url"));
+ return null;
+ } else {
+ ClusterMO clusterMo = new ClusterMO(context, morCluster);
+ ClusterDasConfigInfo dasConfig = clusterMo.getDasConfig();
+ if(dasConfig != null && dasConfig.getEnabled() != null && dasConfig.getEnabled().booleanValue()) {
+ clusterDetails.put("NativeHA", "true");
+ _clusterDetailsDao.persist(clusterId, clusterDetails);
+ }
+ }
+ }
+
+ if(!validateDiscoveredHosts(context, morCluster, morHosts)) {
+ if(morCluster == null)
+ s_logger.warn("The discovered host is not standalone host, can not be added to a standalone cluster");
+ else
+ s_logger.warn("The discovered host does not belong to the cluster");
+ return null;
+ }
+
+ Map<VmwareResource, Map<String, String>> resources = new HashMap<VmwareResource, Map<String, String>>();
+ for(ManagedObjectReference morHost : morHosts) {
+ Map<String, String> details = new HashMap<String, String>();
+ Map<String, Object> params = new HashMap<String, Object>();
+
+ HostMO hostMo = new HostMO(context, morHost);
+ details.put("url", hostMo.getHostName());
+ details.put("username", username);
+ details.put("password", password);
+ String guid = morHost.getType() + ":" + morHost.get_value() + "@"+ url.getHost();
+ details.put("guid", guid);
+
+ params.put("url", hostMo.getHostName());
+ params.put("username", username);
+ params.put("password", password);
+ params.put("zone", Long.toString(dcId));
+ params.put("pod", Long.toString(podId));
+ params.put("cluster", Long.toString(clusterId));
+ params.put("guid", guid);
+ if (privateTrafficLabel != null) {
+ params.put("private.network.vswitch.name", privateTrafficLabel);
+ }
+ if (publicTrafficLabel != null) {
+ params.put("public.network.vswitch.name", publicTrafficLabel);
+ }
+ if (guestTrafficLabel != null) {
+ params.put("guest.network.vswitch.name", guestTrafficLabel);
+ }
+
+ VmwareResource resource = new VmwareResource();
+ try {
+ resource.configure("VMware", params);
+ } catch (ConfigurationException e) {
+ _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, podId, "Unable to add " + url.getHost(), "Error is " + e.getMessage());
+ s_logger.warn("Unable to instantiate " + url.getHost(), e);
+ }
+ resource.start();
+
+ resources.put(resource, details);
+ }
+
+ // place a place holder guid derived from cluster ID
+ cluster.setGuid(UUID.nameUUIDFromBytes(String.valueOf(clusterId).getBytes()).toString());
+ _clusterDao.update(clusterId, cluster);
+
+ return resources;
+ } catch (DiscoveredWithErrorException e) {
+ throw e;
+ } catch (Exception e) {
+ s_logger.warn("Unable to connect to Vmware vSphere server. service address: " + url.getHost());
+ return null;
+ } finally {
+ if(context != null)
+ context.close();
+ }
+ }
+
+ private boolean validateDiscoveredHosts(VmwareContext context, ManagedObjectReference morCluster, List<ManagedObjectReference> morHosts) throws Exception {
+ if(morCluster == null) {
+ for(ManagedObjectReference morHost : morHosts) {
+ ManagedObjectReference morParent = (ManagedObjectReference)context.getServiceUtil().getDynamicProperty(morHost, "parent");
+ if(morParent.getType().equalsIgnoreCase("ClusterComputeResource"))
+ return false;
+ }
+ } else {
+ for(ManagedObjectReference morHost : morHosts) {
+ ManagedObjectReference morParent = (ManagedObjectReference)context.getServiceUtil().getDynamicProperty(morHost, "parent");
+ if(!morParent.getType().equalsIgnoreCase("ClusterComputeResource"))
+ return false;
+
+ if(!morParent.get_value().equals(morCluster.get_value()))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public void postDiscovery(List<HostVO> hosts, long msId) {
+ // do nothing
+ }
+
+ @Override
+ public boolean matchHypervisor(String hypervisor) {
+ if(hypervisor == null)
+ return true;
+
+ return Hypervisor.HypervisorType.VMware.toString().equalsIgnoreCase(hypervisor);
+ }
+
+ @Override
+ public Hypervisor.HypervisorType getHypervisorType() {
+ return Hypervisor.HypervisorType.VMware;
+ }
+
+ @Override
+ public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+ if(s_logger.isInfoEnabled())
+ s_logger.info("Configure VmwareServerDiscoverer, discover name: " + name);
+
+ super.configure(name, params);
+
+ ComponentLocator locator = ComponentLocator.getCurrentLocator();
+ ConfigurationDao configDao = locator.getDao(ConfigurationDao.class);
+ if (configDao == null) {
+ throw new ConfigurationException("Unable to get the configuration dao.");
+ }
+
+ createVmwareToolsIso();
+
+ if(s_logger.isInfoEnabled()) {
+ s_logger.info("VmwareServerDiscoverer has been successfully configured");
+ }
+ _resourceMgr.registerResourceStateAdapter(this.getClass().getSimpleName(), this);
+ return true;
+ }
+
+ private void createVmwareToolsIso() {
+ String isoName = "vmware-tools.iso";
+ VMTemplateVO tmplt = _tmpltDao.findByTemplateName(isoName);
+ Long id;
+ if (tmplt == null) {
+ id = _tmpltDao.getNextInSequence(Long.class, "id");
+ VMTemplateVO template = new VMTemplateVO(id, isoName, isoName, ImageFormat.ISO, true, true,
+ TemplateType.PERHOST, null, null, true, 64,
+ Account.ACCOUNT_ID_SYSTEM, null, "VMware Tools Installer ISO", false, 1, false, HypervisorType.VMware);
+ _tmpltDao.persist(template);
+ } else {
+ id = tmplt.getId();
+ tmplt.setTemplateType(TemplateType.PERHOST);
+ tmplt.setUrl(null);
+ _tmpltDao.update(id, tmplt);
+ }
+ }
+
+ @Override
+ public HostVO createHostVOForConnectedAgent(HostVO host, StartupCommand[] cmd) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public HostVO createHostVOForDirectConnectAgent(HostVO host, StartupCommand[] startup, ServerResource resource, Map<String, String> details,
+ List<String> hostTags) {
+ StartupCommand firstCmd = startup[0];
+ if (!(firstCmd instanceof StartupRoutingCommand)) {
+ return null;
+ }
+
+ StartupRoutingCommand ssCmd = ((StartupRoutingCommand) firstCmd);
+ if (ssCmd.getHypervisorType() != HypervisorType.VMware) {
+ return null;
+ }
+
+ return _resourceMgr.fillRoutingHostVO(host, ssCmd, HypervisorType.VMware, details, hostTags);
+ }
+
+ @Override
+ public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) throws UnableDeleteHostException {
+ if (host.getType() != com.cloud.host.Host.Type.Routing || host.getHypervisorType() != HypervisorType.VMware) {
+ return null;
+ }
+
+ _resourceMgr.deleteRoutingHost(host, isForced, isForceDeleteStorage);
+ return new DeleteHostAnswer(true);
+ }
+
+ @Override
+ public boolean stop() {
+ _resourceMgr.unregisterResourceStateAdapter(this.getClass().getSimpleName());
+ return super.stop();
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8197f1f0/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java
new file mode 100644
index 0000000..5822af8
--- /dev/null
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java
@@ -0,0 +1,25 @@
+// 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.manager;
+
+import com.cloud.agent.api.Command;
+import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
+import com.cloud.hypervisor.vmware.util.VmwareContext;
+
+public interface VmwareHostService {
+ VmwareContext getServiceContext(Command cmd);
+ void invalidateServiceContext(VmwareContext context);
+ VmwareHypervisorHost getHyperHost(VmwareContext context, Command cmd);
+
+ String getWorkerName(VmwareContext context, Command cmd, int workerSequence);
+}
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8197f1f0/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java
new file mode 100755
index 0000000..7d85a96
--- /dev/null
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java
@@ -0,0 +1,73 @@
+// 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.manager;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.hypervisor.vmware.mo.HostMO;
+import com.cloud.hypervisor.vmware.util.VmwareContext;
+import com.cloud.utils.Pair;
+import com.vmware.vim25.ManagedObjectReference;
+
+public interface VmwareManager {
+ public final String CONTEXT_STOCK_NAME = "vmwareMgr";
+
+ // this limitation comes from the fact that we are using linked clone on shared VMFS storage,
+ // we need to limit the size of vCenter cluster, http://en.wikipedia.org/wiki/VMware_VMFS
+ public final int MAX_HOSTS_PER_CLUSTER = 8;
+
+ String composeWorkerName();
+
+ String getSystemVMIsoFileNameOnDatastore();
+ String getSystemVMDefaultNicAdapterType();
+
+ void prepareSecondaryStorageStore(String strStorageUrl);
+
+ void setupResourceStartupParams(Map<String, Object> params);
+ List<ManagedObjectReference> addHostToPodCluster(VmwareContext serviceContext, long dcId, Long podId, Long clusterId,
+ String hostInventoryPath) throws Exception;
+
+ String getManagementPortGroupByHost(HostMO hostMo) throws Exception;
+ String getServiceConsolePortGroupName();
+ String getManagementPortGroupName();
+
+ String getSecondaryStorageStoreUrl(long dcId);
+
+ File getSystemVMKeyFile();
+
+ VmwareStorageManager getStorageManager();
+ long pushCleanupCheckpoint(String hostGuid, String vmName);
+ void popCleanupCheckpoint(long checkpiont);
+ void gcLeftOverVMs(VmwareContext context);
+
+ Pair<Integer, Integer> getAddiionalVncPortRange();
+
+ int getMaxHostsPerCluster();
+ int getRouterExtraPublicNics();
+
+ boolean beginExclusiveOperation(int timeOutSeconds);
+ void endExclusiveOperation();
+
+ boolean getNexusVSwitchGlobalParameter();
+
+ Map<String, String> getNexusVSMCredentialsByClusterId(Long clusterId);
+
+ String getPrivateVSwitchName(long dcId, HypervisorType hypervisorType);
+
+ String getPublicVSwitchName(long dcId, HypervisorType hypervisorType);
+
+ String getGuestVSwitchName(long dcId, HypervisorType hypervisorType);
+}
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8197f1f0/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java
new file mode 100755
index 0000000..debb6fe
--- /dev/null
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java
@@ -0,0 +1,992 @@
+// 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.manager;
+
+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.VmwareCleanupMaid;
+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.utils.ssh.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;
+ 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 vlanId = null;
+ if(privateTrafficLabel != null) {
+ String[] tokens = privateTrafficLabel.split(",");
+ if(tokens.length == 2)
+ vlanId = tokens[1];
+ }
+
+ 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 vlanId = null;
+ if(privateTrafficLabel != null) {
+ String[] tokens = privateTrafficLabel.split(",");
+ if(tokens.length == 2)
+ vlanId = tokens[1];
+ }
+
+
+ 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 vlanId = null;
+ if(privateTrafficLabel != null) {
+ String[] tokens = privateTrafficLabel.split(",");
+ if(tokens.length == 2)
+ vlanId = tokens[1];
+ }
+
+ // 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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8197f1f0/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java
new file mode 100644
index 0000000..b237291
--- /dev/null
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java
@@ -0,0 +1,30 @@
+// 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.manager;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.BackupSnapshotCommand;
+import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
+import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
+import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
+import com.cloud.agent.api.storage.CopyVolumeCommand;
+import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
+
+public interface VmwareStorageManager {
+ Answer execute(VmwareHostService hostService, PrimaryStorageDownloadCommand cmd);
+ Answer execute(VmwareHostService hostService, BackupSnapshotCommand cmd);
+ Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromVolumeCommand cmd);
+ Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromSnapshotCommand cmd);
+ Answer execute(VmwareHostService hostService, CopyVolumeCommand cmd);
+ Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCommand cmd);
+}