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
[5/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/manager/VmwareStorageManagerImpl.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
new file mode 100644
index 0000000..b525e13
--- /dev/null
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
@@ -0,0 +1,880 @@
+// 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.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.rmi.RemoteException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.BackupSnapshotAnswer;
+import com.cloud.agent.api.BackupSnapshotCommand;
+import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
+import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
+import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer;
+import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
+import com.cloud.agent.api.storage.CopyVolumeAnswer;
+import com.cloud.agent.api.storage.CopyVolumeCommand;
+import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
+import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
+import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
+import com.cloud.agent.api.to.StorageFilerTO;
+import com.cloud.hypervisor.vmware.mo.CustomFieldConstants;
+import com.cloud.hypervisor.vmware.mo.DatacenterMO;
+import com.cloud.hypervisor.vmware.mo.DatastoreMO;
+import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
+import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
+import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
+import com.cloud.hypervisor.vmware.util.VmwareContext;
+import com.cloud.hypervisor.vmware.util.VmwareHelper;
+import com.cloud.storage.JavaStorageLayer;
+import com.cloud.storage.Storage.ImageFormat;
+import com.cloud.storage.StorageLayer;
+import com.cloud.storage.template.VmdkProcessor;
+import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.Pair;
+import com.cloud.utils.StringUtils;
+import com.cloud.utils.Ternary;
+import com.cloud.utils.script.Script;
+import com.vmware.vim25.ManagedObjectReference;
+import com.vmware.vim25.VirtualDeviceConfigSpec;
+import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
+import com.vmware.vim25.VirtualDisk;
+import com.vmware.vim25.VirtualLsiLogicController;
+import com.vmware.vim25.VirtualMachineConfigSpec;
+import com.vmware.vim25.VirtualMachineFileInfo;
+import com.vmware.vim25.VirtualMachineGuestOsIdentifier;
+import com.vmware.vim25.VirtualSCSISharing;
+
+public class VmwareStorageManagerImpl implements VmwareStorageManager {
+ private static final Logger s_logger = Logger.getLogger(VmwareStorageManagerImpl.class);
+
+ private final VmwareStorageMount _mountService;
+ private final StorageLayer _storage = new JavaStorageLayer();
+
+ private int _timeout;
+
+ public VmwareStorageManagerImpl(VmwareStorageMount mountService) {
+ assert(mountService != null);
+ _mountService = mountService;
+ }
+
+ public void configure(Map<String, Object> params) {
+ s_logger.info("Configure VmwareStorageManagerImpl");
+
+ String value = (String)params.get("scripts.timeout");
+ _timeout = NumbersUtil.parseInt(value, 1440) * 1000;
+ }
+
+ @Override
+ public Answer execute(VmwareHostService hostService, PrimaryStorageDownloadCommand cmd) {
+ String secondaryStorageUrl = cmd.getSecondaryStorageUrl();
+ assert (secondaryStorageUrl != null);
+
+ String templateUrl = cmd.getUrl();
+
+ String templateName = null;
+ String mountPoint = null;
+ if (templateUrl.endsWith(".ova")) {
+ int index = templateUrl.lastIndexOf("/");
+ mountPoint = templateUrl.substring(0, index);
+ mountPoint = mountPoint.substring(secondaryStorageUrl.length() + 1);
+ if (!mountPoint.endsWith("/")) {
+ mountPoint = mountPoint + "/";
+ }
+
+ templateName = templateUrl.substring(index + 1).replace("." + ImageFormat.OVA.getFileExtension(), "");
+
+ if (templateName == null || templateName.isEmpty()) {
+ templateName = cmd.getName();
+ }
+ } else {
+ mountPoint = templateUrl.substring(secondaryStorageUrl.length() + 1);
+ if (!mountPoint.endsWith("/")) {
+ mountPoint = mountPoint + "/";
+ }
+ templateName = cmd.getName();
+ }
+
+ VmwareContext context = hostService.getServiceContext(cmd);
+ try {
+ VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+
+ String templateUuidName = UUID.nameUUIDFromBytes((templateName + "@" + cmd.getPoolUuid() + "-" + hyperHost.getMor().get_value()).getBytes()).toString();
+ // truncate template name to 32 chars to ensure they work well with vSphere API's.
+ templateUuidName = templateUuidName.replace("-", "");
+
+ DatacenterMO dcMo = new DatacenterMO(context, hyperHost.getHyperHostDatacenter());
+ VirtualMachineMO templateMo = VmwareHelper.pickOneVmOnRunningHost(dcMo.findVmByNameAndLabel(templateUuidName), true);
+
+ if (templateMo == null) {
+ if(s_logger.isInfoEnabled())
+ s_logger.info("Template " + templateName + " is not setup yet, setup template from secondary storage with uuid name: " + templateUuidName);
+ ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, cmd.getPoolUuid());
+ assert (morDs != null);
+ DatastoreMO primaryStorageDatastoreMo = new DatastoreMO(context, morDs);
+
+ copyTemplateFromSecondaryToPrimary(hyperHost,
+ primaryStorageDatastoreMo, secondaryStorageUrl,
+ mountPoint, templateName, templateUuidName);
+ } else {
+ s_logger.info("Template " + templateName + " has already been setup, skip the template setup process in primary storage");
+ }
+
+ return new PrimaryStorageDownloadAnswer(templateUuidName, 0);
+ } catch (Throwable e) {
+ if (e instanceof RemoteException) {
+ hostService.invalidateServiceContext(context);
+ }
+
+ String msg = "Unable to execute PrimaryStorageDownloadCommand due to exception";
+ s_logger.error(msg, e);
+ return new PrimaryStorageDownloadAnswer(msg);
+ }
+ }
+
+ @Override
+ public Answer execute(VmwareHostService hostService, BackupSnapshotCommand cmd) {
+ Long accountId = cmd.getAccountId();
+ Long volumeId = cmd.getVolumeId();
+ String secondaryStorageUrl = cmd.getSecondaryStorageUrl();
+ String snapshotUuid = cmd.getSnapshotUuid(); // not null: Precondition.
+ String prevSnapshotUuid = cmd.getPrevSnapshotUuid();
+ String prevBackupUuid = cmd.getPrevBackupUuid();
+ VirtualMachineMO workerVm=null;
+ String workerVMName = null;
+ String volumePath = cmd.getVolumePath();
+ ManagedObjectReference morDs = null;
+ DatastoreMO dsMo=null;
+
+ // By default assume failure
+ String details = null;
+ boolean success = false;
+ String snapshotBackupUuid = null;
+
+ VmwareContext context = hostService.getServiceContext(cmd);
+ VirtualMachineMO vmMo = null;
+ try {
+ VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+ morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, cmd.getPool().getUuid());
+
+ try {
+ vmMo = hyperHost.findVmOnHyperHost(cmd.getVmName());
+ if (vmMo == null) {
+ if(s_logger.isDebugEnabled())
+ s_logger.debug("Unable to find owner VM for BackupSnapshotCommand on host " + hyperHost.getHyperHostName() + ", will try within datacenter");
+
+ vmMo = hyperHost.findVmOnPeerHyperHost(cmd.getVmName());
+ if(vmMo == null) {
+ dsMo = new DatastoreMO(hyperHost.getContext(), morDs);
+
+ workerVMName = hostService.getWorkerName(context, cmd, 0);
+
+ // attach a volume to dummay wrapper VM for taking snapshot and exporting the VM for backup
+ if (!hyperHost.createBlankVm(workerVMName, 1, 512, 0, false, 4, 0, VirtualMachineGuestOsIdentifier._otherGuest.toString(), morDs, false)) {
+ String msg = "Unable to create worker VM to execute BackupSnapshotCommand";
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+ vmMo = hyperHost.findVmOnHyperHost(workerVMName);
+ if (vmMo == null) {
+ throw new Exception("Failed to find the newly create or relocated VM. vmName: " + workerVMName);
+ }
+ workerVm = vmMo;
+
+ // attach volume to worker VM
+ String datastoreVolumePath = String.format("[%s] %s.vmdk", dsMo.getName(), volumePath);
+ vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs);
+ }
+ }
+
+ if (!vmMo.createSnapshot(snapshotUuid, "Snapshot taken for " + cmd.getSnapshotName(), false, false)) {
+ throw new Exception("Failed to take snapshot " + cmd.getSnapshotName() + " on vm: " + cmd.getVmName());
+ }
+
+ snapshotBackupUuid = backupSnapshotToSecondaryStorage(vmMo, accountId, volumeId, cmd.getVolumePath(), snapshotUuid, secondaryStorageUrl, prevSnapshotUuid, prevBackupUuid,
+ hostService.getWorkerName(context, cmd, 1));
+
+ success = (snapshotBackupUuid != null);
+ if (success) {
+ details = "Successfully backedUp the snapshotUuid: " + snapshotUuid + " to secondary storage.";
+ }
+
+ } finally {
+ if(vmMo != null)
+ vmMo.removeAllSnapshots();
+
+ try {
+ if (workerVm != null) {
+ // detach volume and destroy worker vm
+ workerVm.detachAllDisks();
+ workerVm.destroy();
+ }
+ } catch (Throwable e) {
+ s_logger.warn("Failed to destroy worker VM: " + workerVMName);
+ }
+ }
+ } catch (Throwable e) {
+ if (e instanceof RemoteException) {
+ hostService.invalidateServiceContext(context);
+ }
+
+ s_logger.error("Unexpecpted exception ", e);
+
+ details = "BackupSnapshotCommand exception: " + StringUtils.getExceptionStackInfo(e);
+ return new BackupSnapshotAnswer(cmd, false, details, snapshotBackupUuid, true);
+ }
+
+ return new BackupSnapshotAnswer(cmd, success, details, snapshotBackupUuid, true);
+ }
+
+ @Override
+ public Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromVolumeCommand cmd) {
+ String secondaryStoragePoolURL = cmd.getSecondaryStorageUrl();
+ String volumePath = cmd.getVolumePath();
+ Long accountId = cmd.getAccountId();
+ Long templateId = cmd.getTemplateId();
+ String details = null;
+
+ VmwareContext context = hostService.getServiceContext(cmd);
+ try {
+ VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+
+ VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(cmd.getVmName());
+ if (vmMo == null) {
+ if(s_logger.isDebugEnabled())
+ s_logger.debug("Unable to find the owner VM for CreatePrivateTemplateFromVolumeCommand on host " + hyperHost.getHyperHostName() + ", try within datacenter");
+ vmMo = hyperHost.findVmOnPeerHyperHost(cmd.getVmName());
+
+ if(vmMo == null) {
+ String msg = "Unable to find the owner VM for volume operation. vm: " + cmd.getVmName();
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+ }
+
+ Ternary<String, Long, Long> result = createTemplateFromVolume(vmMo,
+ accountId, templateId, cmd.getUniqueName(),
+ secondaryStoragePoolURL, volumePath,
+ hostService.getWorkerName(context, cmd, 0));
+
+ return new CreatePrivateTemplateAnswer(cmd, true, null,
+ result.first(), result.third(), result.second(),
+ cmd.getUniqueName(), ImageFormat.OVA);
+
+ } catch (Throwable e) {
+ if (e instanceof RemoteException) {
+ hostService.invalidateServiceContext(context);
+ }
+
+ s_logger.error("Unexpecpted exception ", e);
+
+ details = "CreatePrivateTemplateFromVolumeCommand exception: " + StringUtils.getExceptionStackInfo(e);
+ return new CreatePrivateTemplateAnswer(cmd, false, details);
+ }
+ }
+
+ @Override
+ public Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromSnapshotCommand cmd) {
+ Long accountId = cmd.getAccountId();
+ Long volumeId = cmd.getVolumeId();
+ String secondaryStorageUrl = cmd.getSecondaryStorageUrl();
+ String backedUpSnapshotUuid = cmd.getSnapshotUuid();
+ Long newTemplateId = cmd.getNewTemplateId();
+ String details;
+ String uniqeName = UUID.randomUUID().toString();
+
+ VmwareContext context = hostService.getServiceContext(cmd);
+ try {
+ Ternary<String, Long, Long> result = createTemplateFromSnapshot(accountId,
+ newTemplateId, uniqeName,
+ secondaryStorageUrl, volumeId,
+ backedUpSnapshotUuid);
+
+ return new CreatePrivateTemplateAnswer(cmd, true, null,
+ result.first(), result.third(), result.second(),
+ uniqeName, ImageFormat.OVA);
+ } catch (Throwable e) {
+ if (e instanceof RemoteException) {
+ hostService.invalidateServiceContext(context);
+ }
+
+ s_logger.error("Unexpecpted exception ", e);
+
+ details = "CreatePrivateTemplateFromSnapshotCommand exception: " + StringUtils.getExceptionStackInfo(e);
+ return new CreatePrivateTemplateAnswer(cmd, false, details);
+ }
+ }
+
+ @Override
+ public Answer execute(VmwareHostService hostService, CopyVolumeCommand cmd) {
+ Long volumeId = cmd.getVolumeId();
+ String volumePath = cmd.getVolumePath();
+ String secondaryStorageURL = cmd.getSecondaryStorageURL();
+ String vmName = cmd.getVmName();
+
+ VmwareContext context = hostService.getServiceContext(cmd);
+ try {
+ VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+
+ Pair<String, String> result;
+ if (cmd.toSecondaryStorage()) {
+ result = copyVolumeToSecStorage(hostService,
+ hyperHost, cmd, vmName, volumeId, cmd.getPool().getUuid(), volumePath,
+ secondaryStorageURL,
+ hostService.getWorkerName(context, cmd, 0));
+ } else {
+ StorageFilerTO poolTO = cmd.getPool();
+
+ ManagedObjectReference morDatastore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, poolTO.getUuid());
+ if (morDatastore == null) {
+ morDatastore = hyperHost.mountDatastore(
+ false,
+ poolTO.getHost(), 0, poolTO.getPath(),
+ poolTO.getUuid().replace("-", ""));
+
+ if (morDatastore == null) {
+ throw new Exception("Unable to mount storage pool on host. storeUrl: " + poolTO.getHost() + ":/" + poolTO.getPath());
+ }
+ }
+
+ result = copyVolumeFromSecStorage(
+ hyperHost, volumeId,
+ new DatastoreMO(context, morDatastore),
+ secondaryStorageURL, volumePath);
+ }
+ return new CopyVolumeAnswer(cmd, true, null, result.first(), result.second());
+ } catch (Throwable e) {
+ if (e instanceof RemoteException) {
+ hostService.invalidateServiceContext(context);
+ }
+
+ String msg = "Unable to execute CopyVolumeCommand due to exception";
+ s_logger.error(msg, e);
+ return new CopyVolumeAnswer(cmd, false, "CopyVolumeCommand failed due to exception: " + StringUtils.getExceptionStackInfo(e), null, null);
+ }
+ }
+
+ @Override
+ public Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCommand cmd) {
+
+ String primaryStorageNameLabel = cmd.getPrimaryStoragePoolNameLabel();
+ Long accountId = cmd.getAccountId();
+ Long volumeId = cmd.getVolumeId();
+ String secondaryStorageUrl = cmd.getSecondaryStorageUrl();
+ String backedUpSnapshotUuid = cmd.getSnapshotUuid();
+
+ String details = null;
+ boolean success = false;
+ String newVolumeName = UUID.randomUUID().toString().replaceAll("-", "");
+
+ VmwareContext context = hostService.getServiceContext(cmd);
+ try {
+ VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+
+ ManagedObjectReference morPrimaryDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, primaryStorageNameLabel);
+ if (morPrimaryDs == null) {
+ String msg = "Unable to find datastore: " + primaryStorageNameLabel;
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+
+ DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs);
+ details = createVolumeFromSnapshot(hyperHost, primaryDsMo,
+ newVolumeName, accountId, volumeId, secondaryStorageUrl, backedUpSnapshotUuid);
+ if (details == null) {
+ success = true;
+ }
+ } catch (Throwable e) {
+ if (e instanceof RemoteException) {
+ hostService.invalidateServiceContext(context);
+ }
+
+ s_logger.error("Unexpecpted exception ", e);
+ details = "CreateVolumeFromSnapshotCommand exception: " + StringUtils.getExceptionStackInfo(e);
+ }
+
+ return new CreateVolumeFromSnapshotAnswer(cmd, success, details, newVolumeName);
+ }
+
+ // templateName: name in secondary storage
+ // templateUuid: will be used at hypervisor layer
+ private void copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, DatastoreMO datastoreMo, String secondaryStorageUrl,
+ String templatePathAtSecondaryStorage, String templateName, String templateUuid) throws Exception {
+
+ s_logger.info("Executing copyTemplateFromSecondaryToPrimary. secondaryStorage: "
+ + secondaryStorageUrl + ", templatePathAtSecondaryStorage: " + templatePathAtSecondaryStorage
+ + ", templateName: " + templateName);
+
+ String secondaryMountPoint = _mountService.getMountPoint(secondaryStorageUrl);
+ s_logger.info("Secondary storage mount point: " + secondaryMountPoint);
+
+ String srcOVAFileName = secondaryMountPoint + "/" + templatePathAtSecondaryStorage +
+ templateName + "." + ImageFormat.OVA.getFileExtension();
+
+ String srcFileName = getOVFFilePath(srcOVAFileName);
+ if(srcFileName == null) {
+ Script command = new Script("tar", 0, s_logger);
+ command.add("--no-same-owner");
+ command.add("-xf", srcOVAFileName);
+ command.setWorkDir(secondaryMountPoint + "/" + templatePathAtSecondaryStorage);
+ s_logger.info("Executing command: " + command.toString());
+ String result = command.execute();
+ if(result != null) {
+ String msg = "Unable to unpack snapshot OVA file at: " + srcOVAFileName;
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+ }
+
+ srcFileName = getOVFFilePath(srcOVAFileName);
+ if(srcFileName == null) {
+ String msg = "Unable to locate OVF file in template package directory: " + srcOVAFileName;
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+
+ String vmName = templateUuid;
+ hyperHost.importVmFromOVF(srcFileName, vmName, datastoreMo, "thin");
+
+ VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmName);
+ if(vmMo == null) {
+ String msg = "Failed to import OVA template. secondaryStorage: "
+ + secondaryStorageUrl + ", templatePathAtSecondaryStorage: " + templatePathAtSecondaryStorage
+ + ", templateName: " + templateName + ", templateUuid: " + templateUuid;
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+
+ if(vmMo.createSnapshot("cloud.template.base", "Base snapshot", false, false)) {
+ vmMo.setCustomFieldValue(CustomFieldConstants.CLOUD_UUID, templateUuid);
+ vmMo.markAsTemplate();
+ } else {
+ vmMo.destroy();
+ String msg = "Unable to create base snapshot for template, templateName: " + templateName + ", templateUuid: " + templateUuid;
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+ }
+
+ private Ternary<String, Long, Long> createTemplateFromVolume(VirtualMachineMO vmMo, long accountId, long templateId, String templateUniqueName,
+ String secStorageUrl, String volumePath, String workerVmName) throws Exception {
+
+ String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl);
+ String installPath = getTemplateRelativeDirInSecStorage(accountId, templateId);
+ String installFullPath = secondaryMountPoint + "/" + installPath;
+ synchronized(installPath.intern()) {
+ Script command = new Script(false, "mkdir", _timeout, s_logger);
+ command.add("-p");
+ command.add(installFullPath);
+
+ String result = command.execute();
+ if(result != null) {
+ String msg = "unable to prepare template directory: "
+ + installPath + ", storage: " + secStorageUrl + ", error msg: " + result;
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+ }
+
+ VirtualMachineMO clonedVm = null;
+ try {
+ Pair<VirtualDisk, String> volumeDeviceInfo = vmMo.getDiskDevice(volumePath, false);
+ if(volumeDeviceInfo == null) {
+ String msg = "Unable to find related disk device for volume. volume path: " + volumePath;
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+
+ if(!vmMo.createSnapshot(templateUniqueName, "Temporary snapshot for template creation", false, false)) {
+ String msg = "Unable to take snapshot for creating template from volume. volume path: " + volumePath;
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+
+ // 4 MB is the minimum requirement for VM memory in VMware
+ vmMo.cloneFromCurrentSnapshot(workerVmName, 0, 4, volumeDeviceInfo.second(),
+ VmwareHelper.getDiskDeviceDatastore(volumeDeviceInfo.first()));
+ clonedVm = vmMo.getRunningHost().findVmOnHyperHost(workerVmName);
+ if(clonedVm == null) {
+ String msg = "Unable to create dummy VM to export volume. volume path: " + volumePath;
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+
+ clonedVm.exportVm(secondaryMountPoint + "/" + installPath, templateUniqueName, true, false);
+
+ long physicalSize = new File(installFullPath + "/" + templateUniqueName + ".ova").length();
+ VmdkProcessor processor = new VmdkProcessor();
+ Map<String, Object> params = new HashMap<String, Object>();
+ params.put(StorageLayer.InstanceConfigKey, _storage);
+ processor.configure("VMDK Processor", params);
+ long virtualSize = processor.getTemplateVirtualSize(installFullPath, templateUniqueName);
+
+ postCreatePrivateTemplate(installFullPath, templateId, templateUniqueName, physicalSize, virtualSize);
+ return new Ternary<String, Long, Long>(installPath + "/" + templateUniqueName + ".ova", physicalSize, virtualSize);
+
+ } finally {
+ if(clonedVm != null) {
+ clonedVm.detachAllDisks();
+ clonedVm.destroy();
+ }
+
+ vmMo.removeSnapshot(templateUniqueName, false);
+ }
+ }
+
+ private Ternary<String, Long, Long> createTemplateFromSnapshot(long accountId, long templateId, String templateUniqueName,
+ String secStorageUrl, long volumeId, String backedUpSnapshotUuid) throws Exception {
+
+ String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl);
+ String installPath = getTemplateRelativeDirInSecStorage(accountId, templateId);
+ String installFullPath = secondaryMountPoint + "/" + installPath;
+ String installFullName = installFullPath + "/" + templateUniqueName + ".ova";
+ String snapshotFullName = secondaryMountPoint + "/" + getSnapshotRelativeDirInSecStorage(accountId, volumeId)
+ + "/" + backedUpSnapshotUuid + ".ova";
+ String result;
+ Script command;
+
+ synchronized(installPath.intern()) {
+ command = new Script(false, "mkdir", _timeout, s_logger);
+ command.add("-p");
+ command.add(installFullPath);
+
+ result = command.execute();
+ if(result != null) {
+ String msg = "unable to prepare template directory: "
+ + installPath + ", storage: " + secStorageUrl + ", error msg: " + result;
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+ }
+
+ try {
+ command = new Script(false, "cp", _timeout, s_logger);
+ command.add(snapshotFullName);
+ command.add(installFullName);
+ result = command.execute();
+ if(result != null) {
+ String msg = "unable to copy snapshot " + snapshotFullName + " to " + installFullPath;
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+
+ // untar OVA file at template directory
+ command = new Script("tar", 0, s_logger);
+ command.add("--no-same-owner");
+ command.add("-xf", installFullName);
+ command.setWorkDir(installFullPath);
+ s_logger.info("Executing command: " + command.toString());
+ result = command.execute();
+ if(result != null) {
+ String msg = "unable to untar snapshot " + snapshotFullName + " to "
+ + installFullPath;
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+
+ long physicalSize = new File(installFullPath + "/" + templateUniqueName + ".ova").length();
+ VmdkProcessor processor = new VmdkProcessor();
+ Map<String, Object> params = new HashMap<String, Object>();
+ params.put(StorageLayer.InstanceConfigKey, _storage);
+ processor.configure("VMDK Processor", params);
+ long virtualSize = processor.getTemplateVirtualSize(installFullPath, templateUniqueName);
+
+ postCreatePrivateTemplate(installFullPath, templateId, templateUniqueName, physicalSize, virtualSize);
+ return new Ternary<String, Long, Long>(installPath + "/" + templateUniqueName + ".ova", physicalSize, virtualSize);
+
+ } catch(Exception e) {
+ // TODO, clean up left over files
+ throw e;
+ }
+ }
+
+ private void postCreatePrivateTemplate(String installFullPath, long templateId,
+ String templateName, long size, long virtualSize) throws Exception {
+
+ // TODO a bit ugly here
+ BufferedWriter out = null;
+ try {
+ out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(installFullPath + "/template.properties")));
+ out.write("filename=" + templateName + ".ova");
+ out.newLine();
+ out.write("description=");
+ out.newLine();
+ out.write("checksum=");
+ out.newLine();
+ out.write("hvm=false");
+ out.newLine();
+ out.write("size=" + size);
+ out.newLine();
+ out.write("ova=true");
+ out.newLine();
+ out.write("id=" + templateId);
+ out.newLine();
+ out.write("public=false");
+ out.newLine();
+ out.write("ova.filename=" + templateName + ".ova");
+ out.newLine();
+ out.write("uniquename=" + templateName);
+ out.newLine();
+ out.write("ova.virtualsize=" + virtualSize);
+ out.newLine();
+ out.write("virtualsize=" + virtualSize);
+ out.newLine();
+ out.write("ova.size=" + size);
+ out.newLine();
+ } finally {
+ if(out != null)
+ out.close();
+ }
+ }
+
+ private String createVolumeFromSnapshot(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName,
+ long accountId, long volumeId, String secStorageUrl, String snapshotBackupUuid) throws Exception {
+
+ restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName,
+ secStorageUrl, getSnapshotRelativeDirInSecStorage(accountId, volumeId), snapshotBackupUuid);
+ return null;
+ }
+
+ private void restoreVolumeFromSecStorage(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName,
+ String secStorageUrl, String secStorageDir, String backupName) throws Exception {
+
+ String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl);
+ String srcOVAFileName = secondaryMountPoint + "/" + secStorageDir + "/"
+ + backupName + "." + ImageFormat.OVA.getFileExtension();
+
+ String srcFileName = getOVFFilePath(srcOVAFileName);
+ if(srcFileName == null) {
+ Script command = new Script("tar", 0, s_logger);
+ command.add("--no-same-owner");
+ command.add("-xf", srcOVAFileName);
+ command.setWorkDir(secondaryMountPoint + "/" + secStorageDir);
+ s_logger.info("Executing command: " + command.toString());
+ String result = command.execute();
+ if(result != null) {
+ String msg = "Unable to unpack snapshot OVA file at: " + srcOVAFileName;
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+ }
+
+ srcFileName = getOVFFilePath(srcOVAFileName);
+ if(srcFileName == null) {
+ String msg = "Unable to locate OVF file in template package directory: " + srcOVAFileName;
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+
+ VirtualMachineMO clonedVm = null;
+ try {
+ hyperHost.importVmFromOVF(srcFileName, newVolumeName, primaryDsMo, "thin");
+ clonedVm = hyperHost.findVmOnHyperHost(newVolumeName);
+ if(clonedVm == null)
+ throw new Exception("Unable to create container VM for volume creation");
+
+ clonedVm.moveAllVmDiskFiles(primaryDsMo, "", false);
+ clonedVm.detachAllDisks();
+ } finally {
+ if(clonedVm != null) {
+ clonedVm.detachAllDisks();
+ clonedVm.destroy();
+ }
+ }
+ }
+
+ private String backupSnapshotToSecondaryStorage(VirtualMachineMO vmMo, long accountId, long volumeId,
+ String volumePath, String snapshotUuid, String secStorageUrl,
+ String prevSnapshotUuid, String prevBackupUuid, String workerVmName) throws Exception {
+
+ String backupUuid = UUID.randomUUID().toString();
+ exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl,
+ getSnapshotRelativeDirInSecStorage(accountId, volumeId), backupUuid, workerVmName);
+ return backupUuid;
+ }
+
+ private void exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volumePath,
+ String secStorageUrl, String secStorageDir, String exportName,
+ String workerVmName) throws Exception {
+
+ String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl);
+ String exportPath = secondaryMountPoint + "/" + secStorageDir;
+
+ synchronized(exportPath.intern()) {
+ if(!new File(exportPath).exists()) {
+ Script command = new Script(false, "mkdir", _timeout, s_logger);
+ command.add("-p");
+ command.add(exportPath);
+ if(command.execute() != null)
+ throw new Exception("unable to prepare snapshot backup directory");
+ }
+ }
+
+ VirtualMachineMO clonedVm = null;
+ try {
+
+ Pair<VirtualDisk, String> volumeDeviceInfo = vmMo.getDiskDevice(volumePath, false);
+ if(volumeDeviceInfo == null) {
+ String msg = "Unable to find related disk device for volume. volume path: " + volumePath;
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+
+ // 4 MB is the minimum requirement for VM memory in VMware
+ vmMo.cloneFromCurrentSnapshot(workerVmName, 0, 4, volumeDeviceInfo.second(),
+ VmwareHelper.getDiskDeviceDatastore(volumeDeviceInfo.first()));
+ clonedVm = vmMo.getRunningHost().findVmOnHyperHost(workerVmName);
+ if(clonedVm == null) {
+ String msg = "Unable to create dummy VM to export volume. volume path: " + volumePath;
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+
+ clonedVm.exportVm(exportPath, exportName, true, true);
+ } finally {
+ if(clonedVm != null) {
+ clonedVm.detachAllDisks();
+ clonedVm.destroy();
+ }
+ }
+ }
+
+ private String deleteSnapshotOnSecondaryStorge(long accountId, long volumeId, String secStorageUrl, String backupUuid) throws Exception {
+
+ String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl);
+ String snapshotMountRoot = secondaryMountPoint + "/" + getSnapshotRelativeDirInSecStorage(accountId, volumeId);
+ File file = new File(snapshotMountRoot + "/" + backupUuid + ".ova");
+ if(file.exists()) {
+ if(file.delete())
+ return null;
+
+ } else {
+ return "Backup file does not exist. backupUuid: " + backupUuid;
+ }
+
+ return "Failed to delete snapshot backup file, backupUuid: " + backupUuid;
+ }
+
+ private Pair<String, String> copyVolumeToSecStorage(VmwareHostService hostService, VmwareHypervisorHost hyperHost, CopyVolumeCommand cmd,
+ String vmName, long volumeId, String poolId, String volumePath,
+ String secStorageUrl, String workerVmName) throws Exception {
+
+ String volumeFolder = String.valueOf(volumeId) + "/";
+ VirtualMachineMO workerVm=null;
+ VirtualMachineMO vmMo=null;
+ String exportName = UUID.randomUUID().toString();
+
+ try {
+ ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, poolId);
+
+ if (morDs == null) {
+ String msg = "Unable to find volumes's storage pool for copy volume operation";
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+
+ vmMo = hyperHost.findVmOnHyperHost(vmName);
+ if (vmMo == null) {
+ // create a dummy worker vm for attaching the volume
+ DatastoreMO dsMo = new DatastoreMO(hyperHost.getContext(), morDs);
+ //restrict VM name to 32 chars, (else snapshot descriptor file name will be truncated to 32 chars of vm name)
+ VirtualMachineConfigSpec vmConfig = new VirtualMachineConfigSpec();
+ vmConfig.setName(workerVmName);
+ vmConfig.setMemoryMB((long) 4);
+ vmConfig.setNumCPUs(1);
+ vmConfig.setGuestId(VirtualMachineGuestOsIdentifier._otherGuest.toString());
+ VirtualMachineFileInfo fileInfo = new VirtualMachineFileInfo();
+ fileInfo.setVmPathName(String.format("[%s]", dsMo.getName()));
+ vmConfig.setFiles(fileInfo);
+
+ // Scsi controller
+ VirtualLsiLogicController scsiController = new VirtualLsiLogicController();
+ scsiController.setSharedBus(VirtualSCSISharing.noSharing);
+ scsiController.setBusNumber(0);
+ scsiController.setKey(1);
+ VirtualDeviceConfigSpec scsiControllerSpec = new VirtualDeviceConfigSpec();
+ scsiControllerSpec.setDevice(scsiController);
+ scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.add);
+ vmConfig.setDeviceChange(new VirtualDeviceConfigSpec[] { scsiControllerSpec });
+
+ hyperHost.createVm(vmConfig);
+ workerVm = hyperHost.findVmOnHyperHost(workerVmName);
+ if (workerVm == null) {
+ String msg = "Unable to create worker VM to execute CopyVolumeCommand";
+ s_logger.error(msg);
+ throw new Exception(msg);
+ }
+
+ //attach volume to worker VM
+ String datastoreVolumePath = String.format("[%s] %s.vmdk", dsMo.getName(), volumePath);
+ workerVm.attachDisk(new String[] { datastoreVolumePath }, morDs);
+ vmMo = workerVm;
+ }
+
+ vmMo.createSnapshot(exportName, "Temporary snapshot for copy-volume command", false, false);
+
+ exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, "volumes/" + volumeFolder, exportName,
+ hostService.getWorkerName(hyperHost.getContext(), cmd, 1));
+ return new Pair<String, String>(volumeFolder, exportName);
+
+ } finally {
+ vmMo.removeSnapshot(exportName, false);
+ if (workerVm != null) {
+ //detach volume and destroy worker vm
+ workerVm.detachAllDisks();
+ workerVm.destroy();
+ }
+ }
+ }
+
+ private Pair<String, String> copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, long volumeId,
+ DatastoreMO dsMo, String secStorageUrl, String exportName) throws Exception {
+
+ String volumeFolder = String.valueOf(volumeId) + "/";
+ String newVolume = UUID.randomUUID().toString().replaceAll("-", "");
+ restoreVolumeFromSecStorage(hyperHost, dsMo, newVolume, secStorageUrl, "volumes/" + volumeFolder, exportName);
+
+ return new Pair<String, String>(volumeFolder, newVolume);
+ }
+
+ private String getOVFFilePath(String srcOVAFileName) {
+ File file = new File(srcOVAFileName);
+ assert(_storage != null);
+ String[] files = _storage.listFiles(file.getParent());
+ if(files != null) {
+ for(String fileName : files) {
+ if(fileName.toLowerCase().endsWith(".ovf")) {
+ File ovfFile = new File(fileName);
+ return file.getParent() + File.separator + ovfFile.getName();
+ }
+ }
+ }
+ return null;
+ }
+
+ private static String getTemplateRelativeDirInSecStorage(long accountId, long templateId) {
+ return "template/tmpl/" + accountId + "/" + templateId;
+ }
+
+ private static String getSnapshotRelativeDirInSecStorage(long accountId, long volumeId) {
+ return "snapshots/" + accountId + "/" + volumeId;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8197f1f0/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java
new file mode 100644
index 0000000..9f4de50
--- /dev/null
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java
@@ -0,0 +1,17 @@
+// 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;
+
+public interface VmwareStorageMount {
+ String getMountPoint(String storageUrl);
+}
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8197f1f0/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java
new file mode 100755
index 0000000..f82afb8
--- /dev/null
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java
@@ -0,0 +1,60 @@
+// 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.resource;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.hypervisor.vmware.manager.VmwareManager;
+import com.cloud.hypervisor.vmware.util.VmwareContext;
+import com.cloud.utils.StringUtils;
+import com.cloud.utils.component.ComponentLocator;
+import com.vmware.apputils.version.ExtendedAppUtil;
+
+public class VmwareContextFactory {
+
+ private static final Logger s_logger = Logger.getLogger(VmwareContextFactory.class);
+
+ private static volatile int s_seq = 1;
+ private static VmwareManager s_vmwareMgr;
+
+ static {
+ // skip certificate check
+ System.setProperty("axis.socketSecureFactory", "org.apache.axis.components.net.SunFakeTrustSocketFactory");
+
+ ComponentLocator locator = ComponentLocator.getLocator("management-server");
+ s_vmwareMgr = locator.getManager(VmwareManager.class);
+ }
+
+ public static VmwareContext create(String vCenterAddress, String vCenterUserName, String vCenterPassword) throws Exception {
+ assert(vCenterAddress != null);
+ assert(vCenterUserName != null);
+ assert(vCenterPassword != null);
+
+ String serviceUrl = "https://" + vCenterAddress + "/sdk/vimService";
+ String[] params = new String[] {"--url", serviceUrl, "--username", vCenterUserName, "--password", vCenterPassword };
+
+ if(s_logger.isDebugEnabled())
+ s_logger.debug("initialize VmwareContext. url: " + serviceUrl + ", username: " + vCenterUserName + ", password: " + StringUtils.getMaskedPasswordForDisplay(vCenterPassword));
+
+ ExtendedAppUtil appUtil = ExtendedAppUtil.initialize(vCenterAddress + "-" + s_seq++, params);
+
+ appUtil.connect();
+ VmwareContext context = new VmwareContext(appUtil, vCenterAddress);
+ context.registerStockObject(VmwareManager.CONTEXT_STOCK_NAME, s_vmwareMgr);
+
+ context.registerStockObject("serviceconsole", s_vmwareMgr.getServiceConsolePortGroupName());
+ context.registerStockObject("manageportgroup", s_vmwareMgr.getManagementPortGroupName());
+
+ return context;
+ }
+}