@Override
  public AsyncCallFuture<TemplateApiResult> copyTemplate(
      TemplateInfo srcTemplate, DataStore destStore) {
    // generate a URL from source template ssvm to download to destination data store
    String url = generateCopyUrl(srcTemplate);
    if (url == null) {
      s_logger.warn(
          "Unable to start/resume copy of template "
              + srcTemplate.getUniqueName()
              + " to "
              + destStore.getName()
              + ", no secondary storage vm in running state in source zone");
      throw new CloudRuntimeException("No secondary VM in running state in source template zone ");
    }

    TemplateObject tmplForCopy =
        (TemplateObject) _templateFactory.getTemplate(srcTemplate, destStore);
    if (s_logger.isDebugEnabled()) {
      s_logger.debug("Setting source template url to " + url);
    }
    tmplForCopy.setUrl(url);

    if (s_logger.isDebugEnabled()) {
      s_logger.debug("Mark template_store_ref entry as Creating");
    }
    AsyncCallFuture<TemplateApiResult> future = new AsyncCallFuture<TemplateApiResult>();
    DataObject templateOnStore = destStore.create(tmplForCopy);
    templateOnStore.processEvent(Event.CreateOnlyRequested);

    if (s_logger.isDebugEnabled()) {
      s_logger.debug("Invoke datastore driver createAsync to create template on destination store");
    }
    try {
      TemplateOpContext<TemplateApiResult> context =
          new TemplateOpContext<TemplateApiResult>(null, (TemplateObject) templateOnStore, future);
      AsyncCallbackDispatcher<TemplateServiceImpl, CreateCmdResult> caller =
          AsyncCallbackDispatcher.create(this);
      caller
          .setCallback(caller.getTarget().copyTemplateCrossZoneCallBack(null, null))
          .setContext(context);
      destStore.getDriver().createAsync(destStore, templateOnStore, caller);
    } catch (CloudRuntimeException ex) {
      // clean up already persisted template_store_ref entry in case of createTemplateCallback is
      // never called
      TemplateDataStoreVO templateStoreVO =
          _vmTemplateStoreDao.findByStoreTemplate(destStore.getId(), srcTemplate.getId());
      if (templateStoreVO != null) {
        TemplateInfo tmplObj = _templateFactory.getTemplate(srcTemplate, destStore);
        tmplObj.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed);
      }
      TemplateApiResult res = new TemplateApiResult((TemplateObject) templateOnStore);
      res.setResult(ex.getMessage());
      future.complete(res);
    }
    return future;
  }
  private AsyncCallFuture<TemplateApiResult> copyAsync(
      DataObject source, TemplateInfo template, DataStore store) {
    AsyncCallFuture<TemplateApiResult> future = new AsyncCallFuture<TemplateApiResult>();
    DataObject templateOnStore = store.create(template);
    templateOnStore.processEvent(Event.CreateOnlyRequested);

    TemplateOpContext<TemplateApiResult> context =
        new TemplateOpContext<TemplateApiResult>(null, (TemplateObject) templateOnStore, future);
    AsyncCallbackDispatcher<TemplateServiceImpl, CopyCommandResult> caller =
        AsyncCallbackDispatcher.create(this);
    caller.setCallback(caller.getTarget().copyTemplateCallBack(null, null)).setContext(context);
    _motionSrv.copyAsync(source, templateOnStore, caller);
    return future;
  }
  @Test(priority = -1)
  public void setUp() {
    ComponentContext.initComponentsLifeCycle();

    host = hostDao.findByGuid(this.getHostGuid());
    if (host != null) {
      dcId = host.getDataCenterId();
      clusterId = host.getClusterId();
      podId = host.getPodId();
      imageStore = this.imageStoreDao.findByName(imageStoreName);
    } else {
      // create data center
      DataCenterVO dc =
          new DataCenterVO(
              UUID.randomUUID().toString(),
              "test",
              "8.8.8.8",
              null,
              "10.0.0.1",
              null,
              "10.0.0.1/24",
              null,
              null,
              NetworkType.Basic,
              null,
              null,
              true,
              true,
              null,
              null);
      dc = dcDao.persist(dc);
      dcId = dc.getId();
      // create pod

      HostPodVO pod =
          new HostPodVO(
              UUID.randomUUID().toString(),
              dc.getId(),
              this.getHostGateway(),
              this.getHostCidr(),
              8,
              "test");
      pod = podDao.persist(pod);
      podId = pod.getId();
      // create xen cluster
      ClusterVO cluster = new ClusterVO(dc.getId(), pod.getId(), "devcloud cluster");
      cluster.setHypervisorType(HypervisorType.VMware.toString());
      cluster.setClusterType(ClusterType.ExternalManaged);
      cluster.setManagedState(ManagedState.Managed);
      cluster = clusterDao.persist(cluster);
      clusterId = cluster.getId();

      // setup vcenter
      ClusterDetailsVO clusterDetailVO = new ClusterDetailsVO(cluster.getId(), "url", null);
      this.clusterDetailsDao.persist(clusterDetailVO);
      clusterDetailVO = new ClusterDetailsVO(cluster.getId(), "username", null);
      this.clusterDetailsDao.persist(clusterDetailVO);
      clusterDetailVO = new ClusterDetailsVO(cluster.getId(), "password", null);
      this.clusterDetailsDao.persist(clusterDetailVO);
      // create xen host

      host = new HostVO(this.getHostGuid());
      host.setName("devcloud vmware host");
      host.setType(Host.Type.Routing);
      host.setPrivateIpAddress(this.getHostIp());
      host.setDataCenterId(dc.getId());
      host.setVersion("6.0.1");
      host.setAvailable(true);
      host.setSetup(true);
      host.setPodId(podId);
      host.setLastPinged(0);
      host.setResourceState(ResourceState.Enabled);
      host.setHypervisorType(HypervisorType.VMware);
      host.setClusterId(cluster.getId());

      host = hostDao.persist(host);

      imageStore = new ImageStoreVO();
      imageStore.setName(imageStoreName);
      imageStore.setDataCenterId(dcId);
      imageStore.setProviderName("CloudStack ImageStore Provider");
      imageStore.setRole(DataStoreRole.Image);
      imageStore.setUrl(this.getSecondaryStorage());
      imageStore.setUuid(UUID.randomUUID().toString());
      imageStore.setProtocol("nfs");
      imageStore = imageStoreDao.persist(imageStore);
    }

    image = new VMTemplateVO();
    image.setTemplateType(TemplateType.USER);
    image.setUrl(this.getTemplateUrl());
    image.setUniqueName(UUID.randomUUID().toString());
    image.setName(UUID.randomUUID().toString());
    image.setPublicTemplate(true);
    image.setFeatured(true);
    image.setRequiresHvm(true);
    image.setBits(64);
    image.setFormat(Storage.ImageFormat.VHD);
    image.setEnablePassword(true);
    image.setEnableSshKey(true);
    image.setGuestOSId(1);
    image.setBootable(true);
    image.setPrepopulate(true);
    image.setCrossZones(true);
    image.setExtractable(true);

    image = imageDataDao.persist(image);

    /*
     * TemplateDataStoreVO templateStore = new TemplateDataStoreVO();
     *
     * templateStore.setDataStoreId(imageStore.getId());
     * templateStore.setDownloadPercent(100);
     * templateStore.setDownloadState(Status.DOWNLOADED);
     * templateStore.setDownloadUrl(imageStore.getUrl());
     * templateStore.setInstallPath(this.getImageInstallPath());
     * templateStore.setTemplateId(image.getId());
     * templateStoreDao.persist(templateStore);
     */

    DataStore store = this.dataStoreMgr.getDataStore(imageStore.getId(), DataStoreRole.Image);
    TemplateInfo template = templateFactory.getTemplate(image.getId(), DataStoreRole.Image);
    DataObject templateOnStore = store.create(template);
    TemplateObjectTO to = new TemplateObjectTO();
    to.setPath(this.getImageInstallPath());
    CopyCmdAnswer answer = new CopyCmdAnswer(to);
    templateOnStore.processEvent(Event.CreateOnlyRequested);
    templateOnStore.processEvent(Event.OperationSuccessed, answer);
  }
  @Override
  public AsyncCallFuture<TemplateApiResult> copyTemplate(
      TemplateInfo srcTemplate, DataStore destStore) {
    // for vmware template, we need to check if ova packing is needed, since template created from
    // snapshot does not have .ova file
    // we invoke createEntityExtractURL to trigger ova packing. Ideally, we can directly use
    // extractURL to pass to following createTemplate.
    // Need to understand what is the background to use two different urls for copy and extract.
    if (srcTemplate.getFormat() == ImageFormat.OVA) {
      ImageStoreEntity tmpltStore = (ImageStoreEntity) srcTemplate.getDataStore();
      tmpltStore.createEntityExtractUrl(
          srcTemplate.getInstallPath(), srcTemplate.getFormat(), srcTemplate);
    }
    // generate a URL from source template ssvm to download to destination data store
    String url = generateCopyUrl(srcTemplate);
    if (url == null) {
      s_logger.warn(
          "Unable to start/resume copy of template "
              + srcTemplate.getUniqueName()
              + " to "
              + destStore.getName()
              + ", no secondary storage vm in running state in source zone");
      throw new CloudRuntimeException("No secondary VM in running state in source template zone ");
    }

    TemplateObject tmplForCopy =
        (TemplateObject) _templateFactory.getTemplate(srcTemplate, destStore);
    if (s_logger.isDebugEnabled()) {
      s_logger.debug("Setting source template url to " + url);
    }
    tmplForCopy.setUrl(url);

    if (s_logger.isDebugEnabled()) {
      s_logger.debug("Mark template_store_ref entry as Creating");
    }
    AsyncCallFuture<TemplateApiResult> future = new AsyncCallFuture<TemplateApiResult>();
    DataObject templateOnStore = destStore.create(tmplForCopy);
    templateOnStore.processEvent(Event.CreateOnlyRequested);

    if (s_logger.isDebugEnabled()) {
      s_logger.debug("Invoke datastore driver createAsync to create template on destination store");
    }
    try {
      TemplateOpContext<TemplateApiResult> context =
          new TemplateOpContext<TemplateApiResult>(null, (TemplateObject) templateOnStore, future);
      AsyncCallbackDispatcher<TemplateServiceImpl, CreateCmdResult> caller =
          AsyncCallbackDispatcher.create(this);
      caller
          .setCallback(caller.getTarget().copyTemplateCrossZoneCallBack(null, null))
          .setContext(context);
      destStore.getDriver().createAsync(destStore, templateOnStore, caller);
    } catch (CloudRuntimeException ex) {
      // clean up already persisted template_store_ref entry in case of createTemplateCallback is
      // never called
      TemplateDataStoreVO templateStoreVO =
          _vmTemplateStoreDao.findByStoreTemplate(destStore.getId(), srcTemplate.getId());
      if (templateStoreVO != null) {
        TemplateInfo tmplObj = _templateFactory.getTemplate(srcTemplate, destStore);
        tmplObj.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed);
      }
      TemplateApiResult res = new TemplateApiResult((TemplateObject) templateOnStore);
      res.setResult(ex.getMessage());
      future.complete(res);
    }
    return future;
  }