cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From edi...@apache.org
Subject [5/7] refactor kvm/vmware resource code
Date Fri, 10 May 2013 16:49:23 GMT
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);
         }


Mime
View raw message