content: // 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.ovm3.resources;
  
  import java.net.URI;
  import java.net.URISyntaxException;
  import java.util.UUID;
  
  import org.apache.cloudstack.agent.directdownload.DirectDownloadCommand;
  import org.apache.cloudstack.storage.command.AttachAnswer;
  import org.apache.cloudstack.storage.command.AttachCommand;
  import org.apache.cloudstack.storage.command.CheckDataStoreStoragePolicyComplianceCommand;
  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.DettachCommand;
  import org.apache.cloudstack.storage.command.ForgetObjectCmd;
  import org.apache.cloudstack.storage.command.IntroduceObjectCmd;
  import org.apache.cloudstack.storage.command.ResignatureAnswer;
  import org.apache.cloudstack.storage.command.ResignatureCommand;
  import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand;
  import org.apache.cloudstack.storage.command.SnapshotAndCopyAnswer;
  import org.apache.cloudstack.storage.command.SyncVolumePathCommand;
  import org.apache.cloudstack.storage.to.SnapshotObjectTO;
  import org.apache.cloudstack.storage.to.TemplateObjectTO;
  import org.apache.cloudstack.storage.to.VolumeObjectTO;
  import org.apache.logging.log4j.Logger;
  import org.apache.logging.log4j.LogManager;
  
  import com.cloud.agent.api.Answer;
  import com.cloud.agent.api.Command;
  import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
  import com.cloud.agent.api.storage.CopyVolumeAnswer;
  import com.cloud.agent.api.storage.CopyVolumeCommand;
  import com.cloud.agent.api.storage.CreateAnswer;
  import com.cloud.agent.api.storage.CreateCommand;
  import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
  import com.cloud.agent.api.storage.DestroyCommand;
  import com.cloud.agent.api.to.DataObjectType;
  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.hypervisor.ovm3.objects.CloudstackPlugin;
  import com.cloud.hypervisor.ovm3.objects.Connection;
  import com.cloud.hypervisor.ovm3.objects.Linux;
  import com.cloud.hypervisor.ovm3.objects.Ovm3ResourceException;
  import com.cloud.hypervisor.ovm3.objects.OvmObject;
  import com.cloud.hypervisor.ovm3.objects.StoragePlugin;
  import com.cloud.hypervisor.ovm3.objects.StoragePlugin.FileProperties;
  import com.cloud.hypervisor.ovm3.objects.Xen;
  import com.cloud.hypervisor.ovm3.resources.helpers.Ovm3Configuration;
  import com.cloud.hypervisor.ovm3.resources.helpers.Ovm3StoragePool;
  import com.cloud.storage.Storage.ImageFormat;
  import com.cloud.storage.Volume;
  import com.cloud.storage.resource.StorageProcessor;
  import com.cloud.vm.DiskProfile;
  
  /**
   * Storage related bits
   */
  public class Ovm3StorageProcessor implements StorageProcessor {
      protected Logger logger = LogManager.getLogger(getClass());
      private Connection c;
      private OvmObject ovmObject = new OvmObject();
      private Ovm3StoragePool pool;
      private Ovm3Configuration config;
  
      public Ovm3StorageProcessor(Connection conn, Ovm3Configuration ovm3config,
              Ovm3StoragePool ovm3pool) {
          c = conn;
          config = ovm3config;
          pool = ovm3pool;
      }
  
      public final Answer execute(final CopyCommand cmd) {
          logger.debug("execute: "+ cmd.getClass());
          DataTO srcData = cmd.getSrcTO();
          DataStoreTO srcStore = srcData.getDataStore();
          DataTO destData = cmd.getDestTO();
          DataStoreTO destStore = destData.getDataStore();
          String msg = "Not implemented yet";
          try {
              /* target and source are NFS and TEMPLATE */
              if ((srcStore instanceof NfsTO)
                      && (srcData.getObjectType() == DataObjectType.TEMPLATE)
                      && (destData.getObjectType() == DataObjectType.TEMPLATE)) {
                  return copyTemplateToPrimaryStorage(cmd);
                  /* we assume the cache for templates is local */
              } else if ((srcData.getObjectType() == DataObjectType.TEMPLATE)
                      && (destData.getObjectType() == DataObjectType.VOLUME)) {
                  if (srcStore.getUrl().equals(destStore.getUrl())) {
                      return cloneVolumeFromBaseTemplate(cmd);
                  } else {
                      msg = "Primary to Primary doesn't match";
                      logger.debug(msg);
                  }
              } else if ((srcData.getObjectType() == DataObjectType.SNAPSHOT)
                      && (destData.getObjectType() == DataObjectType.SNAPSHOT)) {
                  return backupSnapshot(cmd);
              } else if ((srcData.getObjectType() == DataObjectType.SNAPSHOT)
                      && (destData.getObjectType() == DataObjectType.TEMPLATE)) {
                  return createTemplateFromSnapshot(cmd);
              } else if ((srcData.getObjectType() == DataObjectType.SNAPSHOT)
                      && (destData.getObjectType() == DataObjectType.VOLUME)) {
                  return createVolumeFromSnapshot(cmd);
              } else {
                  msg = "Unable to do stuff for " + srcStore.getClass() + ":"
                          + srcData.getObjectType() + " to "
                          + destStore.getClass() + ":" + destData.getObjectType();
                  logger.debug(msg);
              }
          } catch (Exception e) {
              msg = "Catch Exception " + e.getClass().getName()
                      + " for template due to " + e.toString();
              logger.warn(msg, e);
              return new CopyCmdAnswer(msg);
          }
          logger.warn(msg + " " + cmd.getClass());
          return new CopyCmdAnswer(msg);
      }
  
      public Answer execute(DeleteCommand cmd) {
          DataTO data = cmd.getData();
          String msg;
          logger.debug("Deleting object: " + data.getObjectType());
          if (data.getObjectType() == DataObjectType.VOLUME) {
              return deleteVolume(cmd);
          } else if (data.getObjectType() == DataObjectType.SNAPSHOT) {
              return deleteSnapshot(cmd);
          } else if (data.getObjectType() == DataObjectType.TEMPLATE) {
              msg = "Template deletion is not implemented yet.";
              logger.info(msg);
          } else {
              msg = data.getObjectType() + " deletion is not implemented yet.";
              logger.info(msg);
          }
          return new Answer(cmd, false, msg);
      }
  
      public CreateAnswer execute(CreateCommand cmd) {
          logger.debug("execute: "+ cmd.getClass());
          StorageFilerTO primaryStorage = cmd.getPool();
          DiskProfile disk = cmd.getDiskCharacteristics();
          /* disk should have a uuid */
          // should also be replaced with getVirtualDiskPath ?
          String fileName = UUID.randomUUID().toString() + ".raw";
          String dst = primaryStorage.getPath() + "/"
                  + primaryStorage.getUuid() + "/" + fileName;
          try {
              StoragePlugin store = new StoragePlugin(c);
              if (cmd.getTemplateUrl() != null) {
                  logger.debug("CreateCommand " + cmd.getTemplateUrl() + " "
                          + dst);
                  Linux host = new Linux(c);
                  host.copyFile(cmd.getTemplateUrl(), dst);
              } else {
                  /* this is a dup with the createVolume ? */
                  logger.debug("CreateCommand " + dst);
                  store.storagePluginCreate(primaryStorage.getUuid(),
                          primaryStorage.getHost(), dst, disk.getSize(), false);
              }
              FileProperties fp = store.storagePluginGetFileInfo(
                      primaryStorage.getUuid(), primaryStorage.getHost(), dst);
              VolumeTO volume = new VolumeTO(cmd.getVolumeId(), disk.getType(),
                      primaryStorage.getType(), primaryStorage.getUuid(),
                      primaryStorage.getPath(), fileName, fp.getName(),
                      fp.getSize(), null);
              return new CreateAnswer(cmd, volume);
          } catch (Exception e) {
              logger.debug("CreateCommand failed", e);
              return new CreateAnswer(cmd, e.getMessage());
          }
      }
  
      /**
       * src is Nfs and Template from secondary storage to primary
       */
      @Override
      public CopyCmdAnswer copyTemplateToPrimaryStorage(CopyCommand cmd) {
          logger.debug("execute copyTemplateToPrimaryStorage: "+ cmd.getClass());
          DataTO srcData = cmd.getSrcTO();
          DataStoreTO srcStore = srcData.getDataStore();
          DataTO destData = cmd.getDestTO();
          NfsTO srcImageStore = (NfsTO) srcStore;
          TemplateObjectTO destTemplate = (TemplateObjectTO) destData;
          try {
              String secPoolUuid = pool.setupSecondaryStorage(srcImageStore.getUrl());
              String primaryPoolUuid = destData.getDataStore().getUuid();
              String destPath = config.getAgentOvmRepoPath() + "/"
                      + ovmObject.deDash(primaryPoolUuid) + "/"
                      + config.getTemplateDir();
              String sourcePath = config.getAgentSecStoragePath()
                      + "/" + secPoolUuid;
              Linux host = new Linux(c);
              String destUuid = destTemplate.getUuid();
              /*
               * Would love to add dynamic formats (tolower), to also support
               * VHD and QCOW2, although Ovm3.2 does not have tapdisk2 anymore
               * so we can forget about that.
               */
              /* TODO: add checksumming */
              String srcFile = sourcePath + "/"
                      + srcData.getPath();
              if (srcData.getPath().endsWith("/")) {
                  srcFile = sourcePath + "/" + srcData.getPath()
                          + "/" + destUuid + ".raw";
              }
              String destFile = destPath + "/" + destUuid + ".raw";
              logger.debug("CopyFrom: " + srcData.getObjectType() + ","
                      + srcFile + " to " + destData.getObjectType() + ","
                      + destFile);
              host.copyFile(srcFile, destFile);
              TemplateObjectTO newVol = new TemplateObjectTO();
              newVol.setUuid(destUuid);
              // was destfile
              newVol.setPath(destUuid);
              newVol.setFormat(ImageFormat.RAW);
              return new CopyCmdAnswer(newVol);
          } catch (Ovm3ResourceException e) {
              String msg = "Error while copying template to primary storage: " + e.getMessage();
              logger.info(msg);
              return new CopyCmdAnswer(msg);
          }
      }
      /**
       * Only copies in case of dest is NfsTO, xenserver also unmounts secstorage
       */
      @Override
      public Answer copyVolumeFromPrimaryToSecondary(CopyCommand cmd) {
          logger.debug("execute copyVolumeFromPrimaryToSecondary: "+ cmd.getClass());
          return new Answer(cmd);
      }
      /**
       * dest is VolumeObject, src is a template
       */
      @Override
      public CopyCmdAnswer cloneVolumeFromBaseTemplate(CopyCommand cmd) {
          logger.debug("execute cloneVolumeFromBaseTemplate: "+ cmd.getClass());
          try {
              // src
              DataTO srcData = cmd.getSrcTO();
              TemplateObjectTO src = (TemplateObjectTO) srcData;
              String srcFile = getVirtualDiskPath(src.getUuid(), src.getDataStore().getUuid());
              srcFile = srcFile.replace(config.getVirtualDiskDir(), config.getTemplateDir());
  
              DataTO destData = cmd.getDestTO();
              VolumeObjectTO dest = (VolumeObjectTO) destData;
              String destFile = getVirtualDiskPath(dest.getUuid(), dest.getDataStore().getUuid());
              Linux host = new Linux(c);
              logger.debug("CopyFrom: " + srcData.getObjectType() + ","
                      + srcFile + " to " + destData.getObjectType() + ","
                      + destFile);
              host.copyFile(srcFile, destFile);
              VolumeObjectTO newVol = new VolumeObjectTO();
              newVol.setUuid(dest.getUuid());
              // was destfile
              newVol.setPath(dest.getUuid());
              newVol.setFormat(ImageFormat.RAW);
              return new CopyCmdAnswer(newVol);
          } catch (Ovm3ResourceException e) {
              String msg = "Error cloneVolumeFromBaseTemplate: " + e.getMessage();
              logger.info(msg);
              return new CopyCmdAnswer(msg);
          }
      }
      /**
       * createprivatetemplate, also needs template.properties
       */
      @Override
      public Answer createTemplateFromVolume(CopyCommand cmd) {
          logger.debug("execute createTemplateFromVolume: "+ cmd.getClass());
          return new Answer(cmd);
      }
      /**
       * Volume to Volume from NfsTO
       */
      @Override
      public Answer copyVolumeFromImageCacheToPrimary(CopyCommand cmd) {
          logger.debug("execute copyVolumeFromImageCacheToPrimary: "+ cmd.getClass());
          return new Answer(cmd);
      }
      /**
       * Copies from secondary to secondary
       */
      @Override
      public Answer createTemplateFromSnapshot(CopyCommand cmd) {
          logger.debug("execute createTemplateFromSnapshot: "+ cmd.getClass());
          try {
              // src.getPath contains the uuid of the snapshot.
              DataTO srcData = cmd.getSrcTO();
              SnapshotObjectTO srcSnap = (SnapshotObjectTO) srcData;
              String secPoolUuid = pool.setupSecondaryStorage(srcData.getDataStore().getUrl());
              String srcFile = config.getAgentSecStoragePath()
                      + "/" + secPoolUuid + "/"
                      + srcSnap.getPath();
              // dest
              DataTO destData = cmd.getDestTO();
              TemplateObjectTO destTemplate = (TemplateObjectTO) destData;
              String secPoolUuidTemplate = pool.setupSecondaryStorage(destData.getDataStore().getUrl());
              String destDir = config.getAgentSecStoragePath()
                      + "/" + secPoolUuidTemplate + "/"
                      + destTemplate.getPath();
              String destFile = destDir + "/"
                      + destTemplate.getUuid() + ".raw";
              CloudstackPlugin csp = new CloudstackPlugin(c);
              csp.ovsMkdirs(destDir);
  
              Linux host = new Linux(c);
              host.copyFile(srcFile, destFile);
              TemplateObjectTO newVol = new TemplateObjectTO();
              newVol.setUuid(destTemplate.getUuid());
              newVol.setPath(destTemplate.getUuid());
              newVol.setFormat(ImageFormat.RAW);
              return new CopyCmdAnswer(newVol);
          } catch (Ovm3ResourceException e) {
              String msg = "Error backupSnapshot: " + e.getMessage();
              logger.info(msg);
              return new CopyCmdAnswer(msg);
          }
      }
  
      /**
       * use the cache, or the normal nfs, also delete the leftovers for us
       * also contains object store storage in xenserver.
       */
      @Override
      public CopyCmdAnswer backupSnapshot(CopyCommand cmd) {
          logger.debug("execute backupSnapshot: "+ cmd.getClass());
          try {
              DataTO srcData = cmd.getSrcTO();
              DataTO destData = cmd.getDestTO();
              SnapshotObjectTO src = (SnapshotObjectTO) srcData;
              SnapshotObjectTO dest = (SnapshotObjectTO) destData;
  
              // src.getPath contains the uuid of the snapshot.
              String srcFile = getVirtualDiskPath(src.getPath(), src.getDataStore().getUuid());
  
              // destination
              String storeUrl = dest.getDataStore().getUrl();
              String secPoolUuid = pool.setupSecondaryStorage(storeUrl);
              String destDir = config.getAgentSecStoragePath()
                      + "/" + secPoolUuid + "/"
                      + dest.getPath();
              String destFile =  destDir + "/" + src.getPath();
              destFile = destFile.concat(".raw");
              // copy
              Linux host = new Linux(c);
              CloudstackPlugin csp = new CloudstackPlugin(c);
              csp.ovsMkdirs(destDir);
              logger.debug("CopyFrom: " + srcData.getObjectType() + ","
                      + srcFile + " to " + destData.getObjectType() + ","
                      + destFile);
              host.copyFile(srcFile, destFile);
              StoragePlugin sp = new StoragePlugin(c);
              sp.storagePluginDestroy(secPoolUuid, srcFile);
  
              SnapshotObjectTO newSnap = new SnapshotObjectTO();
              // newSnap.setPath(destFile);
              // damnit frickin crap, no reference whatsoever... could use parent ?
              newSnap.setPath(dest.getPath() + "/" + src.getPath() + ".raw");
              newSnap.setParentSnapshotPath(null);
              return new CopyCmdAnswer(newSnap);
          } catch (Ovm3ResourceException e) {
              String msg = "Error backupSnapshot: " + e.getMessage();
              logger.info(msg);
              return new CopyCmdAnswer(msg);
          }
      }
  
      public Answer execute(CreateObjectCommand cmd) {
          logger.debug("execute: "+ cmd.getClass());
          DataTO data = cmd.getData();
          if (data.getObjectType() == DataObjectType.VOLUME) {
              return createVolume(cmd);
          } else if (data.getObjectType() == DataObjectType.SNAPSHOT) {
              return createSnapshot(cmd);
          } else if (data.getObjectType() == DataObjectType.TEMPLATE) {
              logger.debug("Template object creation not supported.");
          }
          return new CreateObjectAnswer(data.getObjectType()
                  + " object creation not supported");
      }
      /**
       * Attach an iso
       */
      @Override
      public AttachAnswer attachIso(AttachCommand cmd) {
          logger.debug("execute attachIso: "+ cmd.getClass());
          String vmName = cmd.getVmName();
          DiskTO disk = cmd.getDisk();
          return attachDetach(cmd, vmName, disk, true);
      }
      /**
       * Detach an iso
       */
      @Override
      public AttachAnswer dettachIso(DettachCommand cmd) {
          logger.debug("execute dettachIso: "+ cmd.getClass());
          String vmName = cmd.getVmName();
          DiskTO disk = cmd.getDisk();
          return attachDetach(cmd, vmName, disk, false);
      }
  
      /**
       * Iso specific path return.
       * @param disk
       * @return
       * @throws Ovm3ResourceException
       */
      private String getIsoPath(DiskTO disk) throws Ovm3ResourceException {
          TemplateObjectTO isoTO = (TemplateObjectTO) disk.getData();
          DataStoreTO store = isoTO.getDataStore();
          NfsTO nfsStore = (NfsTO) store;
          String secPoolUuid = pool.setupSecondaryStorage(nfsStore.getUrl());
          return config.getAgentSecStoragePath() + "/"
                  + secPoolUuid + "/" + isoTO.getPath();
      }
  
      /**
       * Returns the disk path
       * @param diskUuid
       * @return
       * @throws Ovm3ResourceException
       */
      public String getVirtualDiskPath(String diskUuid, String storeUuid) throws Ovm3ResourceException {
          String d = config.getAgentOvmRepoPath() +
                  "/" +
                  ovmObject.deDash(storeUuid) +
                  "/" +
                  config.getVirtualDiskDir() +
                  "/" +
                  diskUuid;
          if (!d.endsWith(".raw")) {
              d = d.concat(".raw");
          }
          return d;
      }
      public String getVirtualDiskPath(DiskTO disk, String storeUuid) throws Ovm3ResourceException {
          return getVirtualDiskPath(disk.getPath(), storeUuid);
      }
  
      /**
       * Generic disk attach/detach.
       * @param cmd
       * @param vmName
       * @param disk
       * @param isAttach
       * @return
       */
      private AttachAnswer attachDetach(Command cmd, String vmName, DiskTO disk,
              boolean isAttach) {
          Xen xen = new Xen(c);
          String doThis = (isAttach) ? "Attach" : "Dettach";
          logger.debug(doThis + " volume type " + disk.getType() + "  " + vmName);
          String msg = "";
          String path = "";
          try {
              Xen.Vm vm = xen.getVmConfig(vmName);
              /* check running */
              if (vm == null) {
                  msg = doThis + " can't find VM " + vmName;
                  logger.debug(msg);
                  return new AttachAnswer(msg);
              }
              if (disk.getType() == Volume.Type.ISO) {
                  path = getIsoPath(disk);
              } else if (disk.getType() == Volume.Type.DATADISK) {
                  path = getVirtualDiskPath(disk, vm.getPrimaryPoolUuid());
              }
              if ("".equals(path)) {
                  msg = doThis + " can't do anything with an empty path.";
                  logger.debug(msg);
                  return new AttachAnswer(msg);
              }
              if (isAttach) {
                  if (disk.getType() == Volume.Type.ISO) {
                      vm.addIso(path);
                  } else {
                      vm.addDataDisk(path);
                  }
              } else {
                  if (!vm.removeDisk(path)) {
                      msg = doThis + " failed for " + vmName + disk.getType()
                              + "  was not attached " + path;
                      logger.debug(msg);
                      return new AttachAnswer(msg);
                  }
              }
              xen.configureVm(ovmObject.deDash(vm.getPrimaryPoolUuid()),
                      vm.getVmUuid());
              return new AttachAnswer(disk);
          } catch (Ovm3ResourceException e) {
              msg = doThis + " failed for " + vmName + " " + e.getMessage();
              logger.warn(msg, e);
              return new AttachAnswer(msg);
          }
      }
      /**
       * Attach a volume
       */
      @Override
      public AttachAnswer attachVolume(AttachCommand cmd) {
          logger.debug("execute attachVolume: "+ cmd.getClass());
          String vmName = cmd.getVmName();
          DiskTO disk = cmd.getDisk();
          return attachDetach(cmd, vmName, disk, true);
      }
      /**
       * Detach a volume
       */
      @Override
      public AttachAnswer dettachVolume(DettachCommand cmd) {
          logger.debug("execute dettachVolume: "+ cmd.getClass());
          String vmName = cmd.getVmName();
          DiskTO disk = cmd.getDisk();
          return attachDetach(cmd, vmName, disk, false);
      }
  
      /**
       * Creates a volume, just a normal empty volume.
       */
      @Override
      public Answer createVolume(CreateObjectCommand cmd) {
          logger.debug("execute createVolume: "+ cmd.getClass());
          DataTO data = cmd.getData();
          VolumeObjectTO volume = (VolumeObjectTO) data;
          try {
              /*
               * public Boolean storagePluginCreate(String uuid, String ssuuid,
               * String host, String file, Integer size)
               */
              String poolUuid = data.getDataStore().getUuid();
              String storeUrl = data.getDataStore().getUrl();
              URI uri = new URI(storeUrl);
              String host = uri.getHost();
              String file = getVirtualDiskPath(volume.getUuid(), poolUuid);
              Long size = volume.getSize();
              StoragePlugin sp = new StoragePlugin(c);
              FileProperties fp = sp.storagePluginCreate(poolUuid, host, file,
                      size, false);
              if (!fp.getName().equals(file)) {
                  return new CreateObjectAnswer("Filename mismatch: "
                          + fp.getName() + " != " + file);
              }
              VolumeObjectTO newVol = new VolumeObjectTO();
              newVol.setName(volume.getName());
              newVol.setSize(fp.getSize());
              newVol.setPath(volume.getUuid());
              return new CreateObjectAnswer(newVol);
          } catch (Ovm3ResourceException | URISyntaxException e) {
              logger.info("Volume creation failed: " + e.toString(), e);
              return new CreateObjectAnswer(e.toString());
          }
      }
  
      /**
       * Creates a snapshot from a volume, but only if the VM is stopped.
       * This due qemu not being able to snap raw volumes.
       *
       * if stopped yes, if running ... no, unless we have ocfs2 when
       * using raw partitions (file:) if using tap:aio we cloud...
       * The "ancient" way:
       * We do however follow the "two stage" approach, of "snap"
       * on primary first, with the create object... and then
       * backup the snapshot with the copycmd....
       * (should transfer to createSnapshot, backupSnapshot)
       */
      @Override
      public Answer createSnapshot(CreateObjectCommand cmd) {
          logger.debug("execute createSnapshot: "+ cmd.getClass());
          DataTO data = cmd.getData();
          Xen xen = new Xen(c);
          SnapshotObjectTO snap = (SnapshotObjectTO) data;
          VolumeObjectTO vol = snap.getVolume();
          try {
              Xen.Vm vm = xen.getVmConfig(snap.getVmName());
              if (vm != null) {
                  return new CreateObjectAnswer(
                          "Snapshot object creation not supported for running VMs."
                                  + snap.getVmName());
              }
              Linux host = new Linux(c);
              String uuid = host.newUuid();
              /* for root volumes this works... */
              String src = vol.getPath() + "/" + vol.getUuid()
                      + ".raw";
              String dest = vol.getPath() + "/" + uuid + ".raw";
              /* seems that sometimes the path is already contains a file
               * in case, we just replace it.... (Seems to happen if not ROOT)
               */
              if (vol.getPath().contains(vol.getUuid())) {
                  src = getVirtualDiskPath(vol.getUuid(),data.getDataStore().getUuid());
                  dest = src.replace(vol.getUuid(), uuid);
              }
              logger.debug("Snapshot " + src + " to " + dest);
              host.copyFile(src, dest);
              SnapshotObjectTO nsnap = new SnapshotObjectTO();
              // nsnap.setPath(dest);
              // move to something that looks the same as xenserver.
              nsnap.setPath(uuid);
              return new CreateObjectAnswer(nsnap);
          } catch (Ovm3ResourceException e) {
              return new CreateObjectAnswer(
                      "Snapshot object creation failed. " + e.getMessage());
          }
      }
  
      @Override
      public Answer deleteVolume(DeleteCommand cmd) {
          logger.debug("execute deleteVolume: "+ cmd.getClass());
          DataTO data = cmd.getData();
          VolumeObjectTO volume = (VolumeObjectTO) data;
          try {
              String poolUuid = data.getDataStore().getUuid();
              String uuid = volume.getUuid();
              String path = getVirtualDiskPath(uuid, poolUuid);
              StoragePlugin sp = new StoragePlugin(c);
              sp.storagePluginDestroy(poolUuid, path);
              logger.debug("Volume deletion success: " + path);
          } catch (Ovm3ResourceException e) {
              logger.info("Volume deletion failed: " + e.toString(), e);
              return new CreateObjectAnswer(e.toString());
          }
          return new Answer(cmd);
      }
  
      /*
       * CopyVolumeCommand gets the storage_pool should use that for
       * bumper bowling.
       */
      public CopyVolumeAnswer execute(CopyVolumeCommand cmd) {
          logger.debug("execute: "+ cmd.getClass());
          String volumePath = cmd.getVolumePath();
          /* is a repository */
          String secondaryStorageURL = cmd.getSecondaryStorageURL();
          int wait = cmd.getWait();
          if (wait == 0) {
              wait = 7200;
          }
  
          try {
              Linux host = new Linux(c);
  
              /* to secondary storage */
              if (cmd.toSecondaryStorage()) {
                  logger.debug("Copy to  secondary storage " + volumePath
                          + " to " + secondaryStorageURL);
                  host.copyFile(volumePath, secondaryStorageURL);
                  /* from secondary storage */
              } else {
                  logger.debug("Copy from secondary storage "
                          + secondaryStorageURL + " to " + volumePath);
                  host.copyFile(secondaryStorageURL, volumePath);
              }
              /* check the truth of this */
              return new CopyVolumeAnswer(cmd, true, null, null, null);
          } catch (Ovm3ResourceException e) {
              logger.debug("Copy volume failed", e);
              return new CopyVolumeAnswer(cmd, false, e.getMessage(), null, null);
          }
      }
  
      /* Destroy a volume (image) */
      public Answer execute(DestroyCommand cmd) {
          logger.debug("execute: "+ cmd.getClass());
          VolumeTO vol = cmd.getVolume();
          String vmName = cmd.getVmName();
          try {
              StoragePlugin store = new StoragePlugin(c);
              store.storagePluginDestroy(vol.getPoolUuid(), vol.getPath());
              return new Answer(cmd, true, "Success");
          } catch (Ovm3ResourceException e) {
              logger.debug("Destroy volume " + vol.getName() + " failed for "
                      + vmName + " ", e);
              return new Answer(cmd, false, e.getMessage());
          }
      }
  
      /* check if a VM is running should be added */
      public CreatePrivateTemplateAnswer execute(
              final CreatePrivateTemplateFromVolumeCommand cmd) {
          logger.debug("execute: "+ cmd.getClass());
          String volumePath = cmd.getVolumePath();
          Long accountId = cmd.getAccountId();
          Long templateId = cmd.getTemplateId();
          int wait = cmd.getWait();
          if (wait == 0) {
              /* Defaut timeout 2 hours */
              wait = 7200;
          }
  
          try {
              /* missing uuid */
              String installPath = config.getAgentOvmRepoPath() + "/"
                      + config.getTemplateDir() + "/"
                      + accountId + "/" + templateId;
              Linux host = new Linux(c);
              host.copyFile(volumePath, installPath);
              return new CreatePrivateTemplateAnswer(cmd, true, installPath);
          } catch (Exception e) {
              logger.debug("Create template failed", e);
              return new CreatePrivateTemplateAnswer(cmd, false, e.getMessage());
          }
      }
  
      /**
       * SnapshotObjectTO secondary to VolumeObjectTO primary in xenserver,
       */
      @Override
      public Answer createVolumeFromSnapshot(CopyCommand cmd) {
          logger.debug("execute createVolumeFromSnapshot: "+ cmd.getClass());
          try {
              DataTO srcData = cmd.getSrcTO();
              DataStoreTO srcStore = srcData.getDataStore();
              NfsTO srcImageStore = (NfsTO) srcStore;
  
              // source, should contain snap dir/filename
              SnapshotObjectTO srcSnap = (SnapshotObjectTO) srcData;
              String secPoolUuid = pool.setupSecondaryStorage(srcImageStore.getUrl());
              String srcFile = config.getAgentSecStoragePath()
                      + "/" + secPoolUuid + "/"
                      + srcSnap.getPath();
  
              // dest
              DataTO destData = cmd.getDestTO();
              VolumeObjectTO destVol = (VolumeObjectTO) destData;
              String primaryPoolUuid = destData.getDataStore().getUuid();
              String destFile = getVirtualDiskPath(destVol.getUuid(), ovmObject.deDash(primaryPoolUuid));
  
              Linux host = new Linux(c);
              host.copyFile(srcFile, destFile);
  
              VolumeObjectTO newVol = new VolumeObjectTO();
              newVol.setUuid(destVol.getUuid());
              // newVol.setPath(destFile);
              newVol.setPath(destVol.getUuid());
              newVol.setFormat(ImageFormat.RAW);
              return new CopyCmdAnswer(newVol);
              /* we assume the cache for templates is local */
          } catch (Ovm3ResourceException e) {
              logger.debug("Failed to createVolumeFromSnapshot: ", e);
              return new CopyCmdAnswer(e.toString());
          }
      }
  
      /**
       * Is not used in normal operation, the SSVM takes care of this.
       */
      @Override
      public Answer deleteSnapshot(DeleteCommand cmd) {
          logger.debug("execute deleteSnapshot: "+ cmd.getClass());
          DataTO data = cmd.getData();
          SnapshotObjectTO snap = (SnapshotObjectTO) data;
          String storeUrl = data.getDataStore().getUrl();
          String snapUuid = snap.getPath();
          try {
              // snapshots/accountid/volumeid
              String secPoolUuid = pool.setupSecondaryStorage(storeUrl);
              String filePath = config.getAgentSecStoragePath()
                      + "/" + secPoolUuid + "/"
                      + snapUuid + ".raw";
              StoragePlugin sp = new StoragePlugin(c);
              sp.storagePluginDestroy(secPoolUuid, filePath);
              logger.debug("Snapshot deletion success: " + filePath);
              return new Answer(cmd, true, "Deleted Snapshot " + filePath);
          } catch (Ovm3ResourceException e) {
              logger.info("Snapshot deletion failed: " + e.toString(), e);
              return new CreateObjectAnswer(e.toString());
          }
      }
      /**
       * SR scan in xenserver
       */
      @Override
      public Answer introduceObject(IntroduceObjectCmd cmd) {
          logger.debug("execute introduceObject: "+ cmd.getClass());
          return new Answer(cmd, false, "not implemented yet");
      }
      /**
       * used as unmount for VDIs in xenserver
       */
      @Override
      public Answer forgetObject(ForgetObjectCmd cmd) {
          logger.debug("execute forgetObject: "+ cmd.getClass());
          return new Answer(cmd, false, "not implemented yet");
      }
  
      /**
       * make sure both mounts are there, snapshot source image
       * copy snap to dest image, remove source snap and unmount
       * iSCSI?
       */
      @Override
      public SnapshotAndCopyAnswer snapshotAndCopy(SnapshotAndCopyCommand cmd) {
          logger.info("'SnapshotAndCopyAnswer snapshotAndCopy(SnapshotAndCopyCommand)' not currently used for Ovm3StorageProcessor");
  
          return new SnapshotAndCopyAnswer("Not implemented");
      }
  
      @Override
      public ResignatureAnswer resignature(final ResignatureCommand cmd) {
          logger.info("'ResignatureAnswer resignature(ResignatureCommand)' not currently used for Ovm3StorageProcessor");
  
          return new ResignatureAnswer("Not implemented");
      }
  
      @Override
      public Answer handleDownloadTemplateToPrimaryStorage(DirectDownloadCommand cmd) {
          return null;
      }
  
      @Override
      public Answer checkDataStoreStoragePolicyCompliance(CheckDataStoreStoragePolicyComplianceCommand cmd) {
          logger.info("'CheckDataStoreStoragePolicyComplianceCommand' not applicable used for Ovm3StorageProcessor");
          return new Answer(cmd,false,"Not applicable used for Ovm3StorageProcessor");
      }
  
      @Override
      public Answer syncVolumePath(SyncVolumePathCommand cmd) {
          logger.info("SyncVolumePathCommand not currently applicable for Ovm3StorageProcessor");
          return new Answer(cmd, false, "Not currently applicable for Ovm3StorageProcessor");
      }
  
      @Override
      public Answer copyVolumeFromPrimaryToPrimary(CopyCommand cmd) {
          return null;
      }
  
      /**
       * Attach disks
       * @param cmd
       * @return
       */
      public Answer execute(AttachCommand cmd) {
          logger.debug("execute: "+ cmd.getClass());
          String vmName = cmd.getVmName();
          DiskTO disk = cmd.getDisk();
          return attachDetach(cmd, vmName, disk, true);
      }
  
      /**
       * Detach disks, calls a middle man which calls attachDetach for volumes.
       * @param cmd
       * @return
       */
      public Answer execute(DettachCommand cmd) {
          logger.debug("execute: "+ cmd.getClass());
          String vmName = cmd.getVmName();
          DiskTO disk = cmd.getDisk();
          return attachDetach(cmd, vmName, disk, false);
      }
  }
  