You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ed...@apache.org on 2013/05/10 18:49:23 UTC
[5/7] refactor kvm/vmware resource code
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
new file mode 100644
index 0000000..c3fc0ec
--- /dev/null
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
@@ -0,0 +1,879 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.cloud.hypervisor.kvm.storage;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.text.DateFormat;
+import java.text.MessageFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.naming.ConfigurationException;
+
+import org.apache.cloudstack.storage.command.AttachAnswer;
+import org.apache.cloudstack.storage.command.AttachCommand;
+import org.apache.cloudstack.storage.command.CopyCmdAnswer;
+import org.apache.cloudstack.storage.command.CopyCommand;
+import org.apache.cloudstack.storage.command.CreateObjectAnswer;
+import org.apache.cloudstack.storage.command.CreateObjectCommand;
+import org.apache.cloudstack.storage.command.DeleteCommand;
+import org.apache.cloudstack.storage.command.DettachAnswer;
+import org.apache.cloudstack.storage.command.DettachCommand;
+import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
+import org.apache.cloudstack.storage.to.SnapshotObjectTO;
+import org.apache.cloudstack.storage.to.TemplateObjectTO;
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
+import org.apache.cloudstack.utils.qemu.QemuImg;
+import org.apache.cloudstack.utils.qemu.QemuImgException;
+import org.apache.cloudstack.utils.qemu.QemuImgFile;
+import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
+import org.apache.log4j.Logger;
+import org.libvirt.Connect;
+import org.libvirt.Domain;
+import org.libvirt.DomainInfo;
+import org.libvirt.DomainSnapshot;
+import org.libvirt.LibvirtException;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.AttachVolumeAnswer;
+import com.cloud.agent.api.BackupSnapshotAnswer;
+import com.cloud.agent.api.ManageSnapshotAnswer;
+import com.cloud.agent.api.ManageSnapshotCommand;
+import com.cloud.agent.api.storage.CreateAnswer;
+import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
+import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
+import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
+import com.cloud.agent.api.to.DiskTO;
+import com.cloud.agent.api.to.NfsTO;
+import com.cloud.agent.api.to.StorageFilerTO;
+import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.exception.InternalErrorException;
+import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
+import com.cloud.hypervisor.kvm.resource.LibvirtConnection;
+import com.cloud.hypervisor.kvm.resource.LibvirtDomainXMLParser;
+import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
+import com.cloud.storage.JavaStorageLayer;
+import com.cloud.storage.StorageLayer;
+import com.cloud.storage.Storage.ImageFormat;
+import com.cloud.storage.Storage.StoragePoolType;
+import com.cloud.storage.resource.StorageProcessor;
+import com.cloud.storage.template.Processor;
+import com.cloud.storage.template.QCOW2Processor;
+import com.cloud.storage.template.TemplateLocation;
+import com.cloud.storage.template.Processor.FormatInfo;
+import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.script.Script;
+import com.cloud.vm.DiskProfile;
+
+public class KVMStorageProcessor implements StorageProcessor {
+ private static final Logger s_logger = Logger.getLogger(KVMStorageProcessor.class);
+ private KVMStoragePoolManager storagePoolMgr;
+ private LibvirtComputingResource resource;
+ private StorageLayer storageLayer;
+ private String _createTmplPath;
+ private String _manageSnapshotPath;
+ private int _cmdsTimeout;
+ public KVMStorageProcessor(KVMStoragePoolManager storagePoolMgr, LibvirtComputingResource resource) {
+ this.storagePoolMgr = storagePoolMgr;
+ this.resource = resource;
+ }
+
+ protected String getDefaultStorageScriptsDir() {
+ return "scripts/storage/qcow2";
+ }
+
+ public boolean configure(String name, Map<String, Object> params)
+ throws ConfigurationException {
+ storageLayer = new JavaStorageLayer();
+ storageLayer.configure("StorageLayer", params);
+
+ String storageScriptsDir = (String) params.get("storage.scripts.dir");
+ if (storageScriptsDir == null) {
+ storageScriptsDir = getDefaultStorageScriptsDir();
+ }
+
+ _createTmplPath = Script
+ .findScript(storageScriptsDir, "createtmplt.sh");
+ if (_createTmplPath == null) {
+ throw new ConfigurationException(
+ "Unable to find the createtmplt.sh");
+ }
+
+ _manageSnapshotPath = Script.findScript(storageScriptsDir,
+ "managesnapshot.sh");
+ if (_manageSnapshotPath == null) {
+ throw new ConfigurationException(
+ "Unable to find the managesnapshot.sh");
+ }
+
+ String value = (String) params.get("cmds.timeout");
+ _cmdsTimeout = NumbersUtil.parseInt(value, 7200) * 1000;
+ return true;
+ }
+
+ @Override
+ public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) {
+ DataTO srcData = cmd.getSrcTO();
+ DataTO destData = cmd.getDestTO();
+ TemplateObjectTO template = (TemplateObjectTO)srcData;
+ DataStoreTO imageStore = template.getDataStore();
+ VolumeObjectTO volume = (VolumeObjectTO)destData;
+ PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volume.getDataStore();
+
+ if (!(imageStore instanceof NfsTO)) {
+ return new CopyCmdAnswer("unsupported protocol");
+ }
+
+ NfsTO nfsImageStore = (NfsTO)imageStore;
+ String tmplturl = nfsImageStore.getUrl() + File.separator + template.getPath();
+ int index = tmplturl.lastIndexOf("/");
+ String mountpoint = tmplturl.substring(0, index);
+ String tmpltname = null;
+ if (index < tmplturl.length() - 1) {
+ tmpltname = tmplturl.substring(index + 1);
+ }
+
+ KVMPhysicalDisk tmplVol = null;
+ KVMStoragePool secondaryPool = null;
+ try {
+ secondaryPool = storagePoolMgr.getStoragePoolByURI(mountpoint);
+
+ /* Get template vol */
+ if (tmpltname == null) {
+ secondaryPool.refresh();
+ List<KVMPhysicalDisk> disks = secondaryPool.listPhysicalDisks();
+ if (disks == null || disks.isEmpty()) {
+ return new PrimaryStorageDownloadAnswer(
+ "Failed to get volumes from pool: "
+ + secondaryPool.getUuid());
+ }
+ for (KVMPhysicalDisk disk : disks) {
+ if (disk.getName().endsWith("qcow2")) {
+ tmplVol = disk;
+ break;
+ }
+ }
+ if (tmplVol == null) {
+ return new PrimaryStorageDownloadAnswer(
+ "Failed to get template from pool: "
+ + secondaryPool.getUuid());
+ }
+ } else {
+ tmplVol = secondaryPool.getPhysicalDisk(tmpltname);
+ }
+
+ /* Copy volume to primary storage */
+ KVMStoragePool primaryPool = storagePoolMgr.getStoragePool(
+ primaryStore.getPoolType(),
+ primaryStore.getUuid());
+
+ KVMPhysicalDisk primaryVol = storagePoolMgr.copyPhysicalDisk(
+ tmplVol, UUID.randomUUID().toString(), primaryPool);
+
+ VolumeObjectTO newVol = new VolumeObjectTO();
+ newVol.setPath(primaryVol.getName());
+ newVol.setSize(primaryVol.getSize());
+ return new CopyCmdAnswer(newVol);
+ } catch (CloudRuntimeException e) {
+ return new CopyCmdAnswer(e.toString());
+ } finally {
+ if (secondaryPool != null) {
+ secondaryPool.delete();
+ }
+ }
+ }
+
+ // this is much like PrimaryStorageDownloadCommand, but keeping it separate
+ private KVMPhysicalDisk templateToPrimaryDownload(String templateUrl, KVMStoragePool primaryPool) {
+ int index = templateUrl.lastIndexOf("/");
+ String mountpoint = templateUrl.substring(0, index);
+ String templateName = null;
+ if (index < templateUrl.length() - 1) {
+ templateName = templateUrl.substring(index + 1);
+ }
+
+ KVMPhysicalDisk templateVol = null;
+ KVMStoragePool secondaryPool = null;
+ try {
+ secondaryPool = storagePoolMgr.getStoragePoolByURI(mountpoint);
+ /* Get template vol */
+ if (templateName == null) {
+ secondaryPool.refresh();
+ List<KVMPhysicalDisk> disks = secondaryPool.listPhysicalDisks();
+ if (disks == null || disks.isEmpty()) {
+ s_logger.error("Failed to get volumes from pool: " + secondaryPool.getUuid());
+ return null;
+ }
+ for (KVMPhysicalDisk disk : disks) {
+ if (disk.getName().endsWith("qcow2")) {
+ templateVol = disk;
+ break;
+ }
+ }
+ if (templateVol == null) {
+ s_logger.error("Failed to get template from pool: " + secondaryPool.getUuid());
+ return null;
+ }
+ } else {
+ templateVol = secondaryPool.getPhysicalDisk(templateName);
+ }
+
+ /* Copy volume to primary storage */
+
+ KVMPhysicalDisk primaryVol = storagePoolMgr.copyPhysicalDisk(templateVol, UUID.randomUUID().toString(), primaryPool);
+ return primaryVol;
+ } catch (CloudRuntimeException e) {
+ s_logger.error("Failed to download template to primary storage",e);
+ return null;
+ } finally {
+ if (secondaryPool != null) {
+ secondaryPool.delete();
+ }
+ }
+ }
+
+ @Override
+ public Answer cloneVolumeFromBaseTemplate(CopyCommand cmd) {
+ DataTO srcData = cmd.getSrcTO();
+ DataTO destData = cmd.getDestTO();
+ TemplateObjectTO template = (TemplateObjectTO)srcData;
+ DataStoreTO imageStore = template.getDataStore();
+ VolumeObjectTO volume = (VolumeObjectTO)destData;
+ PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volume.getDataStore();
+ KVMPhysicalDisk BaseVol = null;
+ KVMStoragePool primaryPool = null;
+ KVMPhysicalDisk vol = null;
+
+ try {
+ primaryPool = storagePoolMgr.getStoragePool(primaryStore.getPoolType(),
+ primaryStore.getUuid());
+
+ String templatePath = null;
+ if (imageStore instanceof NfsTO) {
+ NfsTO nfsImageStore = (NfsTO)imageStore;
+ templatePath = nfsImageStore.getUrl();
+ } else {
+ s_logger.debug("Failed to create volume: ");
+ return new CopyCmdAnswer("Unsupported protocol");
+ }
+
+ if(primaryPool.getType() == StoragePoolType.CLVM) {
+ vol = templateToPrimaryDownload(templatePath, primaryPool);
+ } else {
+ BaseVol = primaryPool.getPhysicalDisk(templatePath);
+ vol = storagePoolMgr.createDiskFromTemplate(BaseVol, UUID
+ .randomUUID().toString(), primaryPool);
+ }
+ if (vol == null) {
+ return new CopyCmdAnswer(
+ " Can't create storage volume on storage pool");
+ }
+
+ VolumeObjectTO newVol = new VolumeObjectTO();
+ newVol.setPath(vol.getName());
+ newVol.setSize(vol.getSize());
+
+ return new CopyCmdAnswer(newVol);
+ } catch (CloudRuntimeException e) {
+ s_logger.debug("Failed to create volume: " + e.toString());
+ return new CopyCmdAnswer(e.toString());
+ }
+ }
+
+ @Override
+ public Answer copyVolumeFromImageCacheToPrimary(CopyCommand cmd) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Answer copyVolumeFromPrimaryToSecondary(CopyCommand cmd) {
+ return null;
+ }
+
+ @Override
+ public Answer createTemplateFromVolume(CopyCommand cmd) {
+ DataTO srcData = cmd.getSrcTO();
+ DataTO destData = cmd.getDestTO();
+ int wait = cmd.getWait();
+ TemplateObjectTO template = (TemplateObjectTO)srcData;
+ DataStoreTO imageStore = template.getDataStore();
+ VolumeObjectTO volume = (VolumeObjectTO)destData;
+ PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volume.getDataStore();
+
+ if (!(imageStore instanceof NfsTO)) {
+ return new CopyCmdAnswer("unsupported protocol");
+ }
+ NfsTO nfsImageStore = (NfsTO)imageStore;
+
+ KVMStoragePool secondaryStorage = null;
+ KVMStoragePool primary = null;
+ try {
+ String templateFolder = template.getPath();
+
+ secondaryStorage = storagePoolMgr.getStoragePoolByURI(
+ nfsImageStore.getUrl());
+
+ try {
+ primary = storagePoolMgr.getStoragePool(
+ primaryStore.getPoolType(),
+ primaryStore.getUuid());
+ } catch (CloudRuntimeException e) {
+ if (e.getMessage().contains("not found")) {
+ primary = storagePoolMgr.createStoragePool(primaryStore.getUuid(),
+ primaryStore.getHost(), primaryStore.getPort(),
+ primaryStore.getPath(), null,
+ primaryStore.getPoolType());
+ } else {
+ return new CopyCmdAnswer(e.getMessage());
+ }
+ }
+
+ KVMPhysicalDisk disk = primary.getPhysicalDisk(volume.getPath());
+ String tmpltPath = secondaryStorage.getLocalPath() + File.separator
+ + templateFolder;
+ this.storageLayer.mkdirs(tmpltPath);
+ String templateName = UUID.randomUUID().toString();
+
+ if (primary.getType() != StoragePoolType.RBD) {
+ Script command = new Script(_createTmplPath, wait, s_logger);
+ command.add("-f", disk.getPath());
+ command.add("-t", tmpltPath);
+ command.add("-n", templateName + ".qcow2");
+
+ String result = command.execute();
+
+ if (result != null) {
+ s_logger.debug("failed to create template: " + result);
+ return new CopyCmdAnswer(result);
+ }
+ } else {
+ s_logger.debug("Converting RBD disk " + disk.getPath() + " into template " + templateName);
+
+ QemuImgFile srcFile = new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(primary.getSourceHost(),
+ primary.getSourcePort(),
+ primary.getAuthUserName(),
+ primary.getAuthSecret(),
+ disk.getPath()));
+ srcFile.setFormat(PhysicalDiskFormat.RAW);
+
+ QemuImgFile destFile = new QemuImgFile(tmpltPath + "/" + templateName + ".qcow2");
+ destFile.setFormat(PhysicalDiskFormat.QCOW2);
+
+ QemuImg q = new QemuImg();
+ try {
+ q.convert(srcFile, destFile);
+ } catch (QemuImgException e) {
+ s_logger.error("Failed to create new template while converting "
+ + srcFile.getFileName() + " to " + destFile.getFileName() + " the error was: " + e.getMessage());
+ }
+
+ File templateProp = new File(tmpltPath + "/template.properties");
+ if (!templateProp.exists()) {
+ templateProp.createNewFile();
+ }
+
+ String templateContent = "filename=" + templateName + ".qcow2" + System.getProperty("line.separator");
+
+ DateFormat dateFormat = new SimpleDateFormat("MM_dd_yyyy");
+ Date date = new Date();
+ templateContent += "snapshot.name=" + dateFormat.format(date) + System.getProperty("line.separator");
+
+ FileOutputStream templFo = new FileOutputStream(templateProp);
+ templFo.write(templateContent.getBytes());
+ templFo.flush();
+ templFo.close();
+ }
+
+ Map<String, Object> params = new HashMap<String, Object>();
+ params.put(StorageLayer.InstanceConfigKey, this.storageLayer);
+ Processor qcow2Processor = new QCOW2Processor();
+
+ qcow2Processor.configure("QCOW2 Processor", params);
+
+ FormatInfo info = qcow2Processor.process(tmpltPath, null,
+ templateName);
+
+ TemplateLocation loc = new TemplateLocation(this.storageLayer, tmpltPath);
+ loc.create(1, true, templateName);
+ loc.addFormat(info);
+ loc.save();
+
+ TemplateObjectTO newTemplate = new TemplateObjectTO();
+ newTemplate.setPath(templateFolder + templateName + ".qcow2");
+ return new CopyCmdAnswer(newTemplate);
+ } catch (Exception e) {
+ s_logger.debug("Failed to create template from volume: " + e.toString());
+ return new CopyCmdAnswer(e.toString());
+ } finally {
+ if (secondaryStorage != null) {
+ secondaryStorage.delete();
+ }
+ }
+ }
+
+ @Override
+ public Answer backupSnasphot(CopyCommand cmd) {
+ DataTO srcData = cmd.getSrcTO();
+ DataTO destData = cmd.getDestTO();
+ int wait = cmd.getWait();
+ SnapshotObjectTO snapshot = (SnapshotObjectTO)srcData;
+ PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)snapshot.getDataStore();
+ SnapshotObjectTO destSnapshot = (SnapshotObjectTO)destData;
+ DataStoreTO imageStore = destData.getDataStore();
+
+ if (!(imageStore instanceof NfsTO)) {
+ return new CopyCmdAnswer("unsupported protocol");
+ }
+ NfsTO nfsImageStore = (NfsTO)imageStore;
+
+ String secondaryStoragePoolUrl = nfsImageStore.getUrl();
+ //NOTE: snapshot name is encoded in snapshot path
+ int index = snapshot.getPath().lastIndexOf("/");
+
+ String snapshotName = snapshot.getPath().substring(index + 1);
+ String volumePath = snapshot.getVolume().getPath();
+ String snapshotDestPath = null;
+ String snapshotRelPath = null;
+ String vmName = snapshot.getVmName();
+ KVMStoragePool secondaryStoragePool = null;
+ try {
+ Connect conn = LibvirtConnection.getConnectionByVmName(vmName);
+
+ secondaryStoragePool = storagePoolMgr.getStoragePoolByURI(
+ secondaryStoragePoolUrl);
+
+ String ssPmountPath = secondaryStoragePool.getLocalPath();
+ snapshotRelPath = destSnapshot.getPath();
+
+ snapshotDestPath = ssPmountPath + File.separator + snapshotRelPath;
+ KVMStoragePool primaryPool = storagePoolMgr.getStoragePool(
+ primaryStore.getPoolType(),
+ primaryStore.getUuid());
+ KVMPhysicalDisk snapshotDisk = primaryPool.getPhysicalDisk(volumePath);
+ Script command = new Script(_manageSnapshotPath, _cmdsTimeout,
+ s_logger);
+ command.add("-b", snapshotDisk.getPath());
+ command.add("-n", snapshotName);
+ command.add("-p", snapshotDestPath);
+ command.add("-t", snapshotName);
+ String result = command.execute();
+ if (result != null) {
+ s_logger.debug("Failed to backup snaptshot: " + result);
+ return new CopyCmdAnswer(result);
+ }
+ /* Delete the snapshot on primary */
+
+ DomainInfo.DomainState state = null;
+ Domain vm = null;
+ if (vmName != null) {
+ try {
+ vm = this.resource.getDomain(conn, vmName);
+ state = vm.getInfo().state;
+ } catch (LibvirtException e) {
+ s_logger.trace("Ignoring libvirt error.", e);
+ }
+ }
+
+ KVMStoragePool primaryStorage = storagePoolMgr.getStoragePool(
+ primaryStore.getPoolType(),
+ primaryStore.getUuid());
+ if (state == DomainInfo.DomainState.VIR_DOMAIN_RUNNING
+ && !primaryStorage.isExternalSnapshot()) {
+ DomainSnapshot snap = vm.snapshotLookupByName(snapshotName);
+ snap.delete(0);
+
+ /*
+ * libvirt on RHEL6 doesn't handle resume event emitted from
+ * qemu
+ */
+ vm = this.resource.getDomain(conn, vmName);
+ state = vm.getInfo().state;
+ if (state == DomainInfo.DomainState.VIR_DOMAIN_PAUSED) {
+ vm.resume();
+ }
+ } else {
+ command = new Script(_manageSnapshotPath, _cmdsTimeout,
+ s_logger);
+ command.add("-d", snapshotDisk.getPath());
+ command.add("-n", snapshotName);
+ result = command.execute();
+ if (result != null) {
+ s_logger.debug("Failed to backup snapshot: " + result);
+ return new CopyCmdAnswer(
+ "Failed to backup snapshot: " + result);
+ }
+ }
+
+ SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
+ newSnapshot.setPath(snapshotRelPath
+ + File.separator + snapshotName);
+ return new CopyCmdAnswer(newSnapshot);
+ } catch (LibvirtException e) {
+ s_logger.debug("Failed to backup snapshot: " + e.toString());
+ return new CopyCmdAnswer(e.toString());
+ } catch (CloudRuntimeException e) {
+ s_logger.debug("Failed to backup snapshot: " + e.toString());
+ return new CopyCmdAnswer(e.toString());
+ } finally {
+ if (secondaryStoragePool != null) {
+ secondaryStoragePool.delete();
+ }
+ }
+ }
+
+ protected synchronized String attachOrDetachISO(Connect conn,
+ String vmName, String isoPath, boolean isAttach)
+ throws LibvirtException, URISyntaxException, InternalErrorException {
+ String isoXml = null;
+ if (isoPath != null && isAttach) {
+ int index = isoPath.lastIndexOf("/");
+ String path = isoPath.substring(0, index);
+ String name = isoPath.substring(index + 1);
+ KVMStoragePool secondaryPool = storagePoolMgr.getStoragePoolByURI(
+ path);
+ KVMPhysicalDisk isoVol = secondaryPool.getPhysicalDisk(name);
+ isoPath = isoVol.getPath();
+
+ DiskDef iso = new DiskDef();
+ iso.defISODisk(isoPath);
+ isoXml = iso.toString();
+ } else {
+ DiskDef iso = new DiskDef();
+ iso.defISODisk(null);
+ isoXml = iso.toString();
+ }
+
+ List<DiskDef> disks = this.resource.getDisks(conn, vmName);
+ String result = attachOrDetachDevice(conn, true, vmName, isoXml);
+ if (result == null && !isAttach) {
+ for (DiskDef disk : disks) {
+ if (disk.getDeviceType() == DiskDef.deviceType.CDROM) {
+ this.resource.cleanupDisk(conn, disk);
+ }
+ }
+
+ }
+ return result;
+ }
+ @Override
+ public Answer attachIso(AttachCommand cmd) {
+ DiskTO disk = cmd.getDisk();
+ TemplateObjectTO isoTO = (TemplateObjectTO)disk.getData();
+ DataStoreTO store = isoTO.getDataStore();
+ if (!(store instanceof NfsTO)) {
+ return new AttachAnswer("unsupported protocol");
+ }
+ NfsTO nfsStore = (NfsTO)store;
+ try {
+ Connect conn = LibvirtConnection.getConnectionByVmName(cmd.getVmName());
+ attachOrDetachISO(conn, cmd.getVmName(), nfsStore.getUrl() + File.separator + isoTO.getPath(),
+ true);
+ } catch (LibvirtException e) {
+ return new Answer(cmd, false, e.toString());
+ } catch (URISyntaxException e) {
+ return new Answer(cmd, false, e.toString());
+ } catch (InternalErrorException e) {
+ return new Answer(cmd, false, e.toString());
+ }
+
+ return new Answer(cmd);
+ }
+
+ protected synchronized String attachOrDetachDevice(Connect conn,
+ boolean attach, String vmName, String xml) throws LibvirtException,
+ InternalErrorException {
+ Domain dm = null;
+ try {
+ dm = conn.domainLookupByUUID(UUID.nameUUIDFromBytes((vmName
+ .getBytes())));
+
+ if (attach) {
+ s_logger.debug("Attaching device: " + xml);
+ dm.attachDevice(xml);
+ } else {
+ s_logger.debug("Detaching device: " + xml);
+ dm.detachDevice(xml);
+ }
+ } catch (LibvirtException e) {
+ if (attach) {
+ s_logger.warn("Failed to attach device to " + vmName + ": "
+ + e.getMessage());
+ } else {
+ s_logger.warn("Failed to detach device from " + vmName + ": "
+ + e.getMessage());
+ }
+ throw e;
+ } finally {
+ if (dm != null) {
+ try {
+ dm.free();
+ } catch (LibvirtException l) {
+ s_logger.trace("Ignoring libvirt error.", l);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ protected synchronized String attachOrDetachDisk(Connect conn,
+ boolean attach, String vmName, KVMPhysicalDisk attachingDisk,
+ int devId) throws LibvirtException, InternalErrorException {
+ List<DiskDef> disks = null;
+ Domain dm = null;
+ DiskDef diskdef = null;
+ try {
+ if (!attach) {
+ dm = conn.domainLookupByUUID(UUID.nameUUIDFromBytes(vmName
+ .getBytes()));
+ LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
+ String xml = dm.getXMLDesc(0);
+ parser.parseDomainXML(xml);
+ disks = parser.getDisks();
+
+ for (DiskDef disk : disks) {
+ String file = disk.getDiskPath();
+ if (file != null
+ && file.equalsIgnoreCase(attachingDisk.getPath())) {
+ diskdef = disk;
+ break;
+ }
+ }
+ if (diskdef == null) {
+ throw new InternalErrorException("disk: "
+ + attachingDisk.getPath()
+ + " is not attached before");
+ }
+ } else {
+ diskdef = new DiskDef();
+ if (attachingDisk.getFormat() == PhysicalDiskFormat.QCOW2) {
+ diskdef.defFileBasedDisk(attachingDisk.getPath(), devId,
+ DiskDef.diskBus.VIRTIO, DiskDef.diskFmtType.QCOW2);
+ } else if (attachingDisk.getFormat() == PhysicalDiskFormat.RAW) {
+ diskdef.defBlockBasedDisk(attachingDisk.getPath(), devId,
+ DiskDef.diskBus.VIRTIO);
+ }
+ }
+
+ String xml = diskdef.toString();
+ return attachOrDetachDevice(conn, attach, vmName, xml);
+ } finally {
+ if (dm != null) {
+ dm.free();
+ }
+ }
+ }
+
+ @Override
+ public Answer attachVolume(AttachCommand cmd) {
+ DiskTO disk = cmd.getDisk();
+ VolumeObjectTO vol = (VolumeObjectTO)disk.getData();
+ PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)vol.getDataStore();
+ String vmName = vol.getVmName();
+ try {
+ Connect conn = LibvirtConnection.getConnectionByVmName(vmName);
+ KVMStoragePool primary = storagePoolMgr.getStoragePool(
+ primaryStore.getPoolType(),
+ primaryStore.getUuid());
+
+ KVMPhysicalDisk phyDisk = primary.getPhysicalDisk(vol.getPath());
+ attachOrDetachDisk(conn, true, vmName, phyDisk,
+ disk.getDiskSeq().intValue());
+
+ return new AttachAnswer(disk);
+ } catch (LibvirtException e) {
+ s_logger.debug("Failed to attach volume: " + vol.getPath() + ", due to " + e.toString());
+ return new AttachAnswer(e.toString());
+ } catch (InternalErrorException e) {
+ s_logger.debug("Failed to attach volume: " + vol.getPath() + ", due to " + e.toString());
+ return new AttachAnswer(e.toString());
+ }
+
+
+ }
+
+ @Override
+ public Answer dettachIso(DettachCommand cmd) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Answer dettachVolume(DettachCommand cmd) {
+ DiskTO disk = cmd.getDisk();
+ VolumeObjectTO vol = (VolumeObjectTO)disk.getData();
+ PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)vol.getDataStore();
+ String vmName = vol.getVmName();
+ try {
+ Connect conn = LibvirtConnection.getConnectionByVmName(vmName);
+ KVMStoragePool primary = storagePoolMgr.getStoragePool(
+ primaryStore.getPoolType(),
+ primaryStore.getUuid());
+
+ KVMPhysicalDisk phyDisk = primary.getPhysicalDisk(vol.getPath());
+ attachOrDetachDisk(conn, false, vmName, phyDisk,
+ disk.getDiskSeq().intValue());
+
+ return new DettachAnswer(disk);
+ } catch (LibvirtException e) {
+ s_logger.debug("Failed to attach volume: " + vol.getPath() + ", due to " + e.toString());
+ return new DettachAnswer(e.toString());
+ } catch (InternalErrorException e) {
+ s_logger.debug("Failed to attach volume: " + vol.getPath() + ", due to " + e.toString());
+ return new DettachAnswer(e.toString());
+ }
+ }
+
+ @Override
+ public Answer createVolume(CreateObjectCommand cmd) {
+ VolumeObjectTO volume = (VolumeObjectTO)cmd.getData();
+ PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volume.getDataStore();
+
+ KVMStoragePool primaryPool = null;
+ KVMPhysicalDisk vol = null;
+ long disksize;
+ try {
+ primaryPool = storagePoolMgr.getStoragePool(primaryStore.getPoolType(),
+ primaryStore.getUuid());
+ disksize = volume.getSize();
+
+ vol = primaryPool.createPhysicalDisk(UUID.randomUUID()
+ .toString(), disksize);
+
+ VolumeObjectTO newVol = new VolumeObjectTO();
+ newVol.setPath(vol.getName());
+
+ return new CreateObjectAnswer(newVol);
+ } catch (Exception e) {
+ s_logger.debug("Failed to create volume: " + e.toString());
+ return new CreateObjectAnswer(e.toString());
+ }
+ }
+
+ protected static MessageFormat SnapshotXML = new MessageFormat(
+ " <domainsnapshot>" + " <name>{0}</name>" + " <domain>"
+ + " <uuid>{1}</uuid>" + " </domain>"
+ + " </domainsnapshot>");
+
+ @Override
+ public Answer createSnapshot(CreateObjectCommand cmd) {
+ VolumeObjectTO volume = (VolumeObjectTO)cmd.getData();
+ PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volume.getDataStore();
+ String snapshotName = UUID.randomUUID().toString();
+ String vmName = volume.getVmName();
+ try {
+ Connect conn = LibvirtConnection.getConnectionByVmName(vmName);
+ DomainInfo.DomainState state = null;
+ Domain vm = null;
+ if (vmName != null) {
+ try {
+ vm = this.resource.getDomain(conn, vmName);
+ state = vm.getInfo().state;
+ } catch (LibvirtException e) {
+ s_logger.trace("Ignoring libvirt error.", e);
+ }
+ }
+
+ KVMStoragePool primaryPool = storagePoolMgr.getStoragePool(
+ primaryStore.getPoolType(),
+ primaryStore.getUuid());
+
+ if (primaryPool.getType() == StoragePoolType.RBD) {
+ s_logger.debug("Snapshots are not supported on RBD volumes");
+ return new CreateObjectAnswer(
+ "Snapshots are not supported on RBD volumes");
+ }
+
+ KVMPhysicalDisk disk = primaryPool.getPhysicalDisk(volume.getPath());
+ if (state == DomainInfo.DomainState.VIR_DOMAIN_RUNNING
+ && !primaryPool.isExternalSnapshot()) {
+ String vmUuid = vm.getUUIDString();
+ Object[] args = new Object[] { snapshotName, vmUuid };
+ String snapshot = SnapshotXML.format(args);
+ s_logger.debug(snapshot);
+
+ vm.snapshotCreateXML(snapshot);
+ /*
+ * libvirt on RHEL6 doesn't handle resume event emitted from
+ * qemu
+ */
+ vm = this.resource.getDomain(conn, vmName);
+ state = vm.getInfo().state;
+ if (state == DomainInfo.DomainState.VIR_DOMAIN_PAUSED) {
+ vm.resume();
+ }
+ } else {
+
+ /* VM is not running, create a snapshot by ourself */
+ final Script command = new Script(_manageSnapshotPath,
+ this._cmdsTimeout, s_logger);
+ command.add("-c", disk.getPath());
+ command.add("-n", snapshotName);
+ String result = command.execute();
+ if (result != null) {
+ s_logger.debug("Failed to manage snapshot: " + result);
+ return new CreateObjectAnswer(
+ "Failed to manage snapshot: " + result);
+ }
+ }
+
+ SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
+ //NOTE: sort of hack, we'd better just put snapshtoName
+ newSnapshot.setPath(disk.getPath() + File.separator + snapshotName);
+ return new CreateObjectAnswer(newSnapshot);
+ } catch (LibvirtException e) {
+ s_logger.debug("Failed to manage snapshot: " + e.toString());
+ return new CreateObjectAnswer(
+ "Failed to manage snapshot: " + e.toString());
+ }
+ }
+
+ @Override
+ public Answer deleteVolume(DeleteCommand cmd) {
+ VolumeObjectTO vol = (VolumeObjectTO)cmd.getData();
+ PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)vol.getDataStore();
+ try {
+ KVMStoragePool pool = storagePoolMgr.getStoragePool(
+ primaryStore.getPoolType(),
+ primaryStore.getUuid());
+ try {
+ pool.getPhysicalDisk(vol.getPath());
+ } catch(Exception e) {
+ s_logger.debug("can't find volume: " + vol.getPath() + ", return true");
+ return new Answer(null);
+ }
+ pool.deletePhysicalDisk(vol.getPath());
+ return new Answer(null);
+ } catch (CloudRuntimeException e) {
+ s_logger.debug("Failed to delete volume: " + e.toString());
+ return new Answer(null, false, e.toString());
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageResource.java
new file mode 100644
index 0000000..52e142e
--- /dev/null
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageResource.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.cloud.hypervisor.kvm.storage;
+
+import org.apache.cloudstack.storage.command.AttachCommand;
+import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreCmd;
+import org.apache.cloudstack.storage.command.CopyCommand;
+import org.apache.cloudstack.storage.command.CreateObjectCommand;
+import org.apache.cloudstack.storage.command.CreatePrimaryDataStoreCmd;
+import org.apache.cloudstack.storage.command.DeleteCommand;
+import org.apache.cloudstack.storage.command.DettachCommand;
+import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
+
+public class KVMStorageResource {
+ private LibvirtComputingResource resource;
+ public KVMStorageResource(LibvirtComputingResource resource) {
+ this.resource = resource;
+ }
+
+ public Answer handleStorageCommands(StorageSubSystemCommand command) {
+ if (command instanceof CopyCommand) {
+ return this.execute((CopyCommand)command);
+ } else if (command instanceof AttachPrimaryDataStoreCmd) {
+ return this.execute((AttachPrimaryDataStoreCmd)command);
+ } else if (command instanceof CreatePrimaryDataStoreCmd) {
+ return execute((CreatePrimaryDataStoreCmd) command);
+ } else if (command instanceof CreateObjectCommand) {
+ return execute((CreateObjectCommand) command);
+ } else if (command instanceof DeleteCommand) {
+ return execute((DeleteCommand)command);
+ } else if (command instanceof AttachCommand) {
+ return execute((AttachCommand)command);
+ } else if (command instanceof DettachCommand) {
+ return execute((DettachCommand)command);
+ }
+ return new Answer((Command)command, false, "not implemented yet");
+ }
+
+ protected Answer execute(CopyCommand cmd) {
+ return new Answer((Command)cmd, false, "not implemented yet");
+ }
+
+ protected Answer execute(AttachPrimaryDataStoreCmd cmd) {
+ return new Answer((Command)cmd, false, "not implemented yet");
+ }
+
+ protected Answer execute(CreatePrimaryDataStoreCmd cmd) {
+ return new Answer((Command)cmd, false, "not implemented yet");
+ }
+
+ protected Answer execute(CreateObjectCommand cmd) {
+ return new Answer((Command)cmd, false, "not implemented yet");
+ }
+
+ protected Answer execute(DeleteCommand cmd) {
+ return new Answer((Command)cmd, false, "not implemented yet");
+ }
+
+ protected Answer execute(AttachCommand cmd) {
+ return new Answer((Command)cmd, false, "not implemented yet");
+ }
+
+ protected Answer execute(DettachCommand cmd) {
+ return new Answer((Command)cmd, false, "not implemented yet");
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
index 0f85f4e..f91786f 100755
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
@@ -39,6 +39,11 @@ import java.util.UUID;
import javax.naming.ConfigurationException;
+import org.apache.cloudstack.storage.command.DeleteCommand;
+import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
+import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
+import org.apache.cloudstack.storage.to.TemplateObjectTO;
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
import org.apache.log4j.Logger;
import org.apache.log4j.NDC;
@@ -162,8 +167,11 @@ import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
import com.cloud.agent.api.storage.ResizeVolumeAnswer;
import com.cloud.agent.api.storage.ResizeVolumeCommand;
+import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DiskTO;
import com.cloud.agent.api.to.FirewallRuleTO;
import com.cloud.agent.api.to.IpAddressTO;
+import com.cloud.agent.api.to.NfsTO;
import com.cloud.agent.api.to.NicTO;
import com.cloud.agent.api.to.PortForwardingRuleTO;
import com.cloud.agent.api.to.StaticNatRuleTO;
@@ -177,6 +185,7 @@ import com.cloud.host.Host.Type;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.hypervisor.vmware.manager.VmwareHostService;
import com.cloud.hypervisor.vmware.manager.VmwareManager;
+import com.cloud.hypervisor.vmware.manager.VmwareStorageMount;
import com.cloud.hypervisor.vmware.mo.ClusterMO;
import com.cloud.hypervisor.vmware.mo.CustomFieldConstants;
import com.cloud.hypervisor.vmware.mo.CustomFieldsManagerMO;
@@ -210,8 +219,12 @@ import com.cloud.storage.Storage;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.Volume;
import com.cloud.storage.resource.StoragePoolResource;
+import com.cloud.storage.resource.StorageSubsystemCommandHandler;
+import com.cloud.storage.resource.StorageSubsystemCommandHandlerBase;
+import com.cloud.storage.resource.VmwareStorageProcessor;
import com.cloud.storage.template.TemplateProp;
import com.cloud.utils.DateUtil;
+import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.StringUtils;
import com.cloud.utils.db.DB;
@@ -313,6 +326,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
protected Gson _gson;
protected volatile long _cmdSequence = 1;
+
+ protected StorageSubsystemCommandHandler storageHandler;
protected static HashMap<VirtualMachinePowerState, State> s_statesTable;
static {
@@ -321,6 +336,10 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
s_statesTable.put(VirtualMachinePowerState.POWERED_OFF, State.Stopped);
s_statesTable.put(VirtualMachinePowerState.SUSPENDED, State.Stopped);
}
+
+ public Gson getGson() {
+ return this._gson;
+ }
public VmwareResource() {
_gson = GsonHelper.getGsonLogger();
@@ -472,6 +491,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
answer = execute((CheckS2SVpnConnectionsCommand) cmd);
} else if (clz == ResizeVolumeCommand.class) {
return execute((ResizeVolumeCommand) cmd);
+ } else if (clz == StorageSubSystemCommand.class) {
+ return this.storageHandler.handleStorageCommands((StorageSubSystemCommand)cmd);
} else {
answer = Answer.createUnsupportedCommandAnswer(cmd);
}
@@ -2026,14 +2047,21 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
return new CheckSshAnswer(cmd);
}
- private VolumeTO[] validateDisks(VolumeTO[] disks) {
- List<VolumeTO> validatedDisks = new ArrayList<VolumeTO>();
+ private DiskTO[] validateDisks(DiskTO[] disks) {
+ List<DiskTO> validatedDisks = new ArrayList<DiskTO>();
- for (VolumeTO vol : disks) {
- if (vol.getPoolUuid() != null && !vol.getPoolUuid().isEmpty()) {
- validatedDisks.add(vol);
- } else if (vol.getPoolType() == StoragePoolType.ISO && (vol.getPath() != null && !vol.getPath().isEmpty())) {
- validatedDisks.add(vol);
+ for (DiskTO vol : disks) {
+ if (vol.getType() != Volume.Type.ISO) {
+ VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData();
+ PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volumeTO.getDataStore();
+ if (primaryStore.getUuid() != null && !primaryStore.getUuid().isEmpty()) {
+ validatedDisks.add(vol);
+ }
+ } else if (vol.getType() == Volume.Type.ISO) {
+ TemplateObjectTO templateTO = (TemplateObjectTO)vol.getData();
+ if (templateTO.getPath() != null && !templateTO.getPath().isEmpty()) {
+ validatedDisks.add(vol);
+ }
} else {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Drop invalid disk option, volumeTO: " + _gson.toJson(vol));
@@ -2041,7 +2069,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
}
}
- return validatedDisks.toArray(new VolumeTO[0]);
+ return validatedDisks.toArray(new DiskTO[0]);
}
protected StartAnswer execute(StartCommand cmd) {
@@ -2068,7 +2096,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
s_logger.debug("VM " + vmName + " will be started with NIC device type: " + nicDeviceType);
VmwareHypervisorHost hyperHost = getHyperHost(context);
- VolumeTO[] disks = validateDisks(vmSpec.getDisks());
+ DiskTO[] disks = validateDisks(vmSpec.getDisks());
assert (disks.length > 0);
NicTO[] nics = vmSpec.getNics();
@@ -2105,9 +2133,10 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
} else {
int ramMb = (int) (vmSpec.getMinRam() / (1024 * 1024));
Pair<ManagedObjectReference, DatastoreMO> rootDiskDataStoreDetails = null;
- for (VolumeTO vol : disks) {
+ for (DiskTO vol : disks) {
if (vol.getType() == Volume.Type.ROOT) {
- rootDiskDataStoreDetails = dataStoresDetails.get(vol.getPoolUuid());
+ PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)vol.getData().getDataStore();
+ rootDiskDataStoreDetails = dataStoresDetails.get(primaryStore.getUuid());
}
}
@@ -2126,12 +2155,12 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
}
int totalChangeDevices = disks.length + nics.length;
- VolumeTO volIso = null;
+ DiskTO volIso = null;
if (vmSpec.getType() != VirtualMachine.Type.User) {
// system VM needs a patch ISO
totalChangeDevices++;
} else {
- for (VolumeTO vol : disks) {
+ for (DiskTO vol : disks) {
if (vol.getType() == Volume.Type.ISO) {
volIso = vol;
break;
@@ -2188,23 +2217,35 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
i++;
} else {
// we will always plugin a CDROM device
- if (volIso != null && volIso.getPath() != null && !volIso.getPath().isEmpty()) {
- Pair<String, ManagedObjectReference> isoDatastoreInfo = getIsoDatastoreInfo(hyperHost, volIso.getPath());
- assert (isoDatastoreInfo != null);
- assert (isoDatastoreInfo.second() != null);
-
- deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
- Pair<VirtualDevice, Boolean> isoInfo = VmwareHelper.prepareIsoDevice(vmMo, isoDatastoreInfo.first(), isoDatastoreInfo.second(), true, true, i, i + 1);
- deviceConfigSpecArray[i].setDevice(isoInfo.first());
- if (isoInfo.second()) {
- if(s_logger.isDebugEnabled())
- s_logger.debug("Prepare ISO volume at new device " + _gson.toJson(isoInfo.first()));
- deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD);
- } else {
- if(s_logger.isDebugEnabled())
- s_logger.debug("Prepare ISO volume at existing device " + _gson.toJson(isoInfo.first()));
- deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT);
- }
+
+ if (volIso != null) {
+ TemplateObjectTO iso = (TemplateObjectTO)volIso.getData();
+
+ if (iso.getPath() != null && !iso.getPath().isEmpty()) {
+ DataStoreTO imageStore = iso.getDataStore();
+ if (!(imageStore instanceof NfsTO)) {
+ s_logger.debug("unsupported protocol");
+ throw new Exception("unsupported protocol");
+ }
+ NfsTO nfsImageStore = (NfsTO)imageStore;
+ String isoPath = nfsImageStore.getUrl() + File.separator + iso.getPath();
+ Pair<String, ManagedObjectReference> isoDatastoreInfo = getIsoDatastoreInfo(hyperHost, isoPath);
+ assert (isoDatastoreInfo != null);
+ assert (isoDatastoreInfo.second() != null);
+
+ deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
+ Pair<VirtualDevice, Boolean> isoInfo = VmwareHelper.prepareIsoDevice(vmMo, isoDatastoreInfo.first(), isoDatastoreInfo.second(), true, true, i, i + 1);
+ deviceConfigSpecArray[i].setDevice(isoInfo.first());
+ if (isoInfo.second()) {
+ if(s_logger.isDebugEnabled())
+ s_logger.debug("Prepare ISO volume at new device " + _gson.toJson(isoInfo.first()));
+ deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD);
+ } else {
+ if(s_logger.isDebugEnabled())
+ s_logger.debug("Prepare ISO volume at existing device " + _gson.toJson(isoInfo.first()));
+ deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT);
+ }
+ }
} else {
deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
Pair<VirtualDevice, Boolean> isoInfo = VmwareHelper.prepareIsoDevice(vmMo, null, null, true, true, i, i + 1);
@@ -2224,7 +2265,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
i++;
}
- for (VolumeTO vol : sortVolumesByDeviceId(disks)) {
+ for (DiskTO vol : sortVolumesByDeviceId(disks)) {
deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
if (vol.getType() == Volume.Type.ISO) {
@@ -2247,11 +2288,13 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
}
if (vol.getType() != Volume.Type.ISO) {
- Pair<ManagedObjectReference, DatastoreMO> volumeDsDetails = dataStoresDetails.get(vol.getPoolUuid());
+ VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData();
+ PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volumeTO.getDataStore();
+ Pair<ManagedObjectReference, DatastoreMO> volumeDsDetails = dataStoresDetails.get(primaryStore.getUuid());
assert (volumeDsDetails != null);
VirtualDevice device;
- datastoreDiskPath = String.format("[%s] %s.vmdk", volumeDsDetails.second().getName(), vol.getPath());
- String chainInfo = vol.getChainInfo();
+ datastoreDiskPath = String.format("[%s] %s.vmdk", volumeDsDetails.second().getName(), volumeTO.getPath());
+ String chainInfo = volumeTO.getChainInfo();
if (chainInfo != null && !chainInfo.isEmpty()) {
String[] diskChain = _gson.fromJson(chainInfo, String[].class);
@@ -2424,19 +2467,19 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
return listForSort.toArray(new NicTO[0]);
}
- private VolumeTO[] sortVolumesByDeviceId(VolumeTO[] volumes) {
+ private DiskTO[] sortVolumesByDeviceId(DiskTO[] volumes) {
- List<VolumeTO> listForSort = new ArrayList<VolumeTO>();
- for (VolumeTO vol : volumes) {
+ List<DiskTO> listForSort = new ArrayList<DiskTO>();
+ for (DiskTO vol : volumes) {
listForSort.add(vol);
}
- Collections.sort(listForSort, new Comparator<VolumeTO>() {
+ Collections.sort(listForSort, new Comparator<DiskTO>() {
@Override
- public int compare(VolumeTO arg0, VolumeTO arg1) {
- if (arg0.getDeviceId() < arg1.getDeviceId()) {
+ public int compare(DiskTO arg0, DiskTO arg1) {
+ if (arg0.getDiskSeq() < arg1.getDiskSeq()) {
return -1;
- } else if (arg0.getDeviceId() == arg1.getDeviceId()) {
+ } else if (arg0.getDiskSeq() == arg1.getDiskSeq()) {
return 0;
}
@@ -2444,16 +2487,18 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
}
});
- return listForSort.toArray(new VolumeTO[0]);
+ return listForSort.toArray(new DiskTO[0]);
}
- private HashMap<String, Pair<ManagedObjectReference, DatastoreMO>> inferDatastoreDetailsFromDiskInfo(VmwareHypervisorHost hyperHost, VmwareContext context, VolumeTO[] disks) throws Exception {
+ private HashMap<String, Pair<ManagedObjectReference, DatastoreMO>> inferDatastoreDetailsFromDiskInfo(VmwareHypervisorHost hyperHost, VmwareContext context, DiskTO[] disks) throws Exception {
HashMap<String ,Pair<ManagedObjectReference, DatastoreMO>> poolMors = new HashMap<String, Pair<ManagedObjectReference, DatastoreMO>>();
assert (hyperHost != null) && (context != null);
- for (VolumeTO vol : disks) {
+ for (DiskTO vol : disks) {
if (vol.getType() != Volume.Type.ISO) {
- String poolUuid = vol.getPoolUuid();
+ VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData();
+ PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volumeTO.getDataStore();
+ String poolUuid = primaryStore.getUuid();
if(poolMors.get(poolUuid) == null) {
ManagedObjectReference morDataStore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, poolUuid);
if (morDataStore == null) {
@@ -2461,7 +2506,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
s_logger.error(msg);
throw new Exception(msg);
}
- poolMors.put(vol.getPoolUuid(), new Pair<ManagedObjectReference, DatastoreMO> (morDataStore, new DatastoreMO(context, morDataStore)));
+ poolMors.put(poolUuid, new Pair<ManagedObjectReference, DatastoreMO> (morDataStore, new DatastoreMO(context, morDataStore)));
}
}
}
@@ -3306,7 +3351,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
}
}
- private synchronized ManagedObjectReference prepareSecondaryDatastoreOnHost(String storeUrl) throws Exception {
+ public synchronized ManagedObjectReference prepareSecondaryDatastoreOnHost(String storeUrl) throws Exception {
String storeName = getSecondaryDatastoreUUID(storeUrl);
URI uri = new URI(storeUrl);
@@ -3670,8 +3715,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
}
}
- @Override
- public Answer execute(DestroyCommand cmd) {
+
+ public Answer execute(DeleteCommand cmd) {
if (s_logger.isInfoEnabled()) {
s_logger.info("Executing resource DestroyCommand: " + _gson.toJson(cmd));
}
@@ -3691,11 +3736,12 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
try {
VmwareContext context = getServiceContext();
VmwareHypervisorHost hyperHost = getHyperHost(context);
- VolumeTO vol = cmd.getVolume();
+ VolumeObjectTO vol = (VolumeObjectTO)cmd.getData();
+ PrimaryDataStoreTO store = (PrimaryDataStoreTO)vol.getDataStore();
- ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, vol.getPoolUuid());
+ ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, store.getUuid());
if (morDs == null) {
- String msg = "Unable to find datastore based on volume mount point " + cmd.getVolume().getMountPoint();
+ String msg = "Unable to find datastore based on volume mount point " + store.getPath();
s_logger.error(msg);
throw new Exception(msg);
}
@@ -3706,8 +3752,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
ClusterMO clusterMo = new ClusterMO(context, morCluster);
- if (cmd.getVolume().getType() == Volume.Type.ROOT) {
- String vmName = cmd.getVmName();
+ if (vol.getVolumeType() == Volume.Type.ROOT) {
+ String vmName = vol.getVmName();
if (vmName != null) {
VirtualMachineMO vmMo = clusterMo.findVmOnHyperHost(vmName);
if (vmMo != null) {
@@ -3734,20 +3780,20 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
}
if (s_logger.isInfoEnabled())
- s_logger.info("Destroy volume by original name: " + cmd.getVolume().getPath() + ".vmdk");
- dsMo.deleteFile(cmd.getVolume().getPath() + ".vmdk", morDc, true);
+ s_logger.info("Destroy volume by original name: " + vol.getPath() + ".vmdk");
+ dsMo.deleteFile(vol.getPath() + ".vmdk", morDc, true);
// root volume may be created via linked-clone, delete the delta disk as well
if (_fullCloneFlag) {
if (s_logger.isInfoEnabled()) {
- s_logger.info("Destroy volume by derived name: " + cmd.getVolume().getPath() + "-flat.vmdk");
+ s_logger.info("Destroy volume by derived name: " + vol.getPath() + "-flat.vmdk");
}
- dsMo.deleteFile(cmd.getVolume().getPath() + "-flat.vmdk", morDc, true);
+ dsMo.deleteFile(vol.getPath() + "-flat.vmdk", morDc, true);
} else {
if (s_logger.isInfoEnabled()) {
- s_logger.info("Destroy volume by derived name: " + cmd.getVolume().getPath() + "-delta.vmdk");
+ s_logger.info("Destroy volume by derived name: " + vol.getPath() + "-delta.vmdk");
}
- dsMo.deleteFile(cmd.getVolume().getPath() + "-delta.vmdk", morDc, true);
+ dsMo.deleteFile(vol.getPath() + "-delta.vmdk", morDc, true);
}
return new Answer(cmd, true, "Success");
}
@@ -3757,17 +3803,17 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
}
} else {
// evitTemplate will be converted into DestroyCommand, test if we are running in this case
- VirtualMachineMO vmMo = clusterMo.findVmOnHyperHost(cmd.getVolume().getPath());
+ VirtualMachineMO vmMo = clusterMo.findVmOnHyperHost(vol.getPath());
if (vmMo != null) {
if (s_logger.isInfoEnabled())
- s_logger.info("Destroy template volume " + cmd.getVolume().getPath());
+ s_logger.info("Destroy template volume " + vol.getPath());
vmMo.destroy();
return new Answer(cmd, true, "Success");
}
}
- String chainInfo = cmd.getVolume().getChainInfo();
+ String chainInfo = vol.getChainInfo();
if (chainInfo != null && !chainInfo.isEmpty()) {
s_logger.info("Destroy volume by chain info: " + chainInfo);
String[] diskChain = _gson.fromJson(chainInfo, String[].class);
@@ -3783,23 +3829,23 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
if (s_logger.isInfoEnabled()) {
s_logger.info("Empty disk chain info, fall back to try to delete by original backing file name");
}
- dsMo.deleteFile(cmd.getVolume().getPath() + ".vmdk", morDc, true);
+ dsMo.deleteFile(vol.getPath() + ".vmdk", morDc, true);
if (s_logger.isInfoEnabled()) {
- s_logger.info("Destroy volume by derived name: " + cmd.getVolume().getPath() + "-flat.vmdk");
+ s_logger.info("Destroy volume by derived name: " + vol.getPath() + "-flat.vmdk");
}
- dsMo.deleteFile(cmd.getVolume().getPath() + "-flat.vmdk", morDc, true);
+ dsMo.deleteFile(vol.getPath() + "-flat.vmdk", morDc, true);
}
} else {
if (s_logger.isInfoEnabled()) {
- s_logger.info("Destroy volume by original name: " + cmd.getVolume().getPath() + ".vmdk");
+ s_logger.info("Destroy volume by original name: " + vol.getPath() + ".vmdk");
}
- dsMo.deleteFile(cmd.getVolume().getPath() + ".vmdk", morDc, true);
+ dsMo.deleteFile(vol.getPath() + ".vmdk", morDc, true);
if (s_logger.isInfoEnabled()) {
- s_logger.info("Destroy volume by derived name: " + cmd.getVolume().getPath() + "-flat.vmdk");
+ s_logger.info("Destroy volume by derived name: " + vol.getPath() + "-flat.vmdk");
}
- dsMo.deleteFile(cmd.getVolume().getPath() + "-flat.vmdk", morDc, true);
+ dsMo.deleteFile(vol.getPath() + "-flat.vmdk", morDc, true);
}
return new Answer(cmd, true, "Success");
@@ -3815,7 +3861,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
}
}
- private void cleanupNetwork(HostMO hostMo, NetworkDetails netDetails) {
+ public void cleanupNetwork(HostMO hostMo, NetworkDetails netDetails) {
// we will no longer cleanup VLAN networks in order to support native VMware HA
/*
* assert(netDetails.getName() != null); try { synchronized(this) { NetworkMO networkMo = new
@@ -4857,7 +4903,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
return s_statesTable.get(powerState);
}
- private static State getVmState(VirtualMachineMO vmMo) throws Exception {
+ public static State getVmState(VirtualMachineMO vmMo) throws Exception {
VirtualMachineRuntimeInfo runtimeInfo = vmMo.getRuntimeInfo();
return convertState(runtimeInfo.getPowerState());
}
@@ -4991,6 +5037,13 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
} else {
_fullCloneFlag = false;
}
+ value = (String)params.get("scripts.timeout");
+ int timeout = NumbersUtil.parseInt(value, 1440) * 1000;
+ VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
+ VmwareStorageProcessor storageProcessor = new VmwareStorageProcessor((VmwareHostService)this, this._fullCloneFlag, (VmwareStorageMount)mgr,
+ timeout, this, this._shutdown_waitMs
+ );
+ storageHandler = new StorageSubsystemCommandHandlerBase(storageProcessor);
return true;
}
@@ -5010,15 +5063,15 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
return true;
}
- private VmwareContext getServiceContext() {
+ public VmwareContext getServiceContext() {
return getServiceContext(null);
}
- private void invalidateServiceContext() {
+ public void invalidateServiceContext() {
invalidateServiceContext(null);
}
- private VmwareHypervisorHost getHyperHost(VmwareContext context) {
+ public VmwareHypervisorHost getHyperHost(VmwareContext context) {
return getHyperHost(context, null);
}
@@ -5115,4 +5168,10 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
// TODO Auto-generated method stub
}
+
+ @Override
+ public Answer execute(DestroyCommand cmd) {
+ // TODO Auto-generated method stub
+ return null;
+ }
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java
index 566e750..645b6d3 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java
@@ -18,6 +18,7 @@ package com.cloud.storage.resource;
import java.util.List;
+import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
import org.apache.log4j.Logger;
import com.cloud.agent.api.Answer;
@@ -29,6 +30,7 @@ import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
import com.cloud.agent.api.storage.CopyVolumeCommand;
import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
import com.cloud.hypervisor.vmware.manager.VmwareHostService;
+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;
@@ -51,6 +53,7 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe
private final VmwareStorageManager _storageMgr;
private final Gson _gson;
+ private StorageSubsystemCommandHandler storageSubsystemHandler;
/*
private Map<String, HostMO> _activeHosts = new HashMap<String, HostMO>();
@@ -60,6 +63,11 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe
_resource = resource;
_storageMgr = new VmwareStorageManagerImpl(this);
_gson = GsonHelper.getGsonLogger();
+
+ VmwareStorageProcessor storageProcessor = new VmwareStorageProcessor((VmwareHostService)this, true, (VmwareStorageMount)this,
+ null, null, null
+ );
+ storageSubsystemHandler = new StorageSubsystemCommandHandlerBase(storageProcessor);
}
@Override
@@ -77,6 +85,8 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe
answer = execute((CopyVolumeCommand)cmd);
} else if(cmd instanceof CreateVolumeFromSnapshotCommand) {
answer = execute((CreateVolumeFromSnapshotCommand)cmd);
+ } else if (cmd instanceof StorageSubSystemCommand) {
+ answer = storageSubsystemHandler.handleStorageCommands((StorageSubSystemCommand)cmd);
} else {
answer = _resource.defaultAction(cmd);
}