@Override
  public boolean prepare(
      VirtualMachineProfile profile,
      NicProfile nic,
      Network network,
      DeployDestination dest,
      ReservationContext context) {
    try {
      if (DataCenter.NetworkType.Basic.equals(dest.getDataCenter().getNetworkType())) {
        if (!preparePxeInBasicZone(profile, nic, dest, context)) {
          return false;
        }
      } else {
        if (!preparePxeInAdvancedZone(profile, nic, network, dest, context)) {
          return false;
        }
      }

      IpmISetBootDevCommand bootCmd = new IpmISetBootDevCommand(BootDev.pxe);
      Answer aws = _agentMgr.send(dest.getHost().getId(), bootCmd);
      if (!aws.getResult()) {
        s_logger.warn(
            "Unable to set host: "
                + dest.getHost().getId()
                + " to PXE boot because "
                + aws.getDetails());
      }

      return aws.getResult();
    } catch (Exception e) {
      s_logger.warn("Cannot prepare PXE server", e);
      return false;
    }
  }
  @Override
  public boolean prepareCreateTemplate(Long pxeServerId, UserVm vm, String templateUrl) {
    List<NicVO> nics = _nicDao.listByVmId(vm.getId());
    if (nics.size() != 1) {
      throw new CloudRuntimeException("Wrong nic number " + nics.size() + " of vm " + vm.getId());
    }

    /* use last host id when VM stopped */
    Long hostId = (vm.getHostId() == null ? vm.getLastHostId() : vm.getHostId());
    HostVO host = _hostDao.findById(hostId);
    DataCenterVO dc = _dcDao.findById(host.getDataCenterId());
    NicVO nic = nics.get(0);
    String mask = nic.getNetmask();
    String mac = nic.getMacAddress();
    String ip = nic.getIp4Address();
    String gateway = nic.getGateway();
    String dns = dc.getDns1();
    if (dns == null) {
      dns = dc.getDns2();
    }

    try {
      prepareCreateTemplateCommand cmd =
          new prepareCreateTemplateCommand(ip, mac, mask, gateway, dns, templateUrl);
      Answer ans = _agentMgr.send(pxeServerId, cmd);
      return ans.getResult();
    } catch (Exception e) {
      s_logger.debug("Prepare for creating baremetal template failed", e);
      return false;
    }
  }
  private boolean configureSourceNat(
      long vlanId, String guestCidr, PublicIp sourceNatIp, long hostId) {
    boolean add = (sourceNatIp.getState() == IpAddress.State.Releasing ? false : true);
    IpAddressTO ip =
        new IpAddressTO(
            sourceNatIp.getAccountId(),
            sourceNatIp.getAddress().addr(),
            add,
            false,
            sourceNatIp.isSourceNat(),
            sourceNatIp.getVlanTag(),
            sourceNatIp.getGateway(),
            sourceNatIp.getNetmask(),
            sourceNatIp.getMacAddress(),
            null,
            sourceNatIp.isOneToOneNat());
    boolean addSourceNat = false;
    if (sourceNatIp.isSourceNat()) {
      addSourceNat = add;
    }

    SetSourceNatCommand cmd = new SetSourceNatCommand(ip, addSourceNat);
    cmd.setContextParam(NetworkElementCommand.GUEST_VLAN_TAG, Long.toString(vlanId));
    cmd.setContextParam(NetworkElementCommand.GUEST_NETWORK_CIDR, guestCidr);
    Answer answer = _agentMgr.easySend(hostId, cmd);
    return answer.getResult();
  }
  private boolean sendCommandsToRouter(final DomainRouterVO elbVm, Commands cmds)
      throws AgentUnavailableException {
    Answer[] answers = null;
    try {
      answers = _agentMgr.send(elbVm.getHostId(), cmds);
    } catch (OperationTimedoutException e) {
      s_logger.warn("ELB: Timed Out", e);
      throw new AgentUnavailableException(
          "Unable to send commands to virtual elbVm ", elbVm.getHostId(), e);
    }

    if (answers == null) {
      return false;
    }

    if (answers.length != cmds.size()) {
      return false;
    }

    // FIXME: Have to return state for individual command in the future
    if (answers.length > 0) {
      Answer ans = answers[0];
      return ans.getResult();
    }
    return true;
  }
  protected Status testIpAddress(Long hostId, String testHostIp) {
    try {
      Answer pingTestAnswer = _agentMgr.send(hostId, new PingTestCommand(testHostIp));
      if (pingTestAnswer == null) {
        if (s_logger.isDebugEnabled()) {
          s_logger.debug("host (" + testHostIp + ") returns null answer");
        }
        return null;
      }

      if (pingTestAnswer.getResult()) {
        if (s_logger.isDebugEnabled()) {
          s_logger.debug(
              "host (" + testHostIp + ") has been successfully pinged, returning that host is up");
        }
        // computing host is available, but could not reach agent, return false
        return Status.Up;
      } else {
        if (s_logger.isDebugEnabled()) {
          s_logger.debug(
              "host (" + testHostIp + ") cannot be pinged, returning null ('I don't know')");
        }
        return null;
      }
    } catch (AgentUnavailableException e) {
      return null;
    } catch (OperationTimedoutException e) {
      return null;
    }
  }
  private void handleDestroyTunnelAnswer(Answer ans, long from, long to, long account) {
    String toStr = (to == 0 ? "all peers" : Long.toString(to));

    if (ans.getResult()) {
      OvsTunnelAccountVO lock = _tunnelAccountDao.acquireInLockTable(Long.valueOf(1));
      if (lock == null) {
        s_logger.warn(
            String.format(
                "failed to lock ovs_tunnel_account, remove record of tunnel(from=%1$s, to=%2$s account=%3$s) failed",
                from, to, account));
        return;
      }

      if (to == 0) {
        _tunnelAccountDao.removeByFromAccount(from, account);
      } else {
        _tunnelAccountDao.removeByFromToAccount(from, to, account);
      }
      _tunnelAccountDao.releaseFromLockTable(lock.getId());

      s_logger.debug(
          String.format(
              "Destroy tunnel(account:%1$s, from:%2$s, to:%3$s) successful", account, from, toStr));
    } else {
      s_logger.debug(
          String.format(
              "Destroy tunnel(account:%1$s, from:%2$s, to:%3$s) failed", account, from, toStr));
    }
  }
  /**
   * @return For Commands with handler OnError.Continue, one command succeeding is successful. If
   *     not, all commands must succeed to be successful.
   */
  public boolean isSuccessful() {
    if (_answers == null) {
      return false;
    }
    if (_handler == OnError.Continue) {
      return true;
    }
    for (Answer answer : _answers) {
      if (_handler == OnError.Continue && answer.getResult()) {
        return true;
      } else if (_handler != OnError.Continue && !answer.getResult()) {
        return false;
      }
    }

    return _handler != OnError.Continue;
  }
  @Override
  public boolean generateVMSetupCommand(Long ssAHostId) {
    HostVO ssAHost = _hostDao.findById(ssAHostId);
    if (ssAHost.getType() != Host.Type.SecondaryStorageVM) {
      return false;
    }
    SecondaryStorageVmVO secStorageVm = _secStorageVmDao.findByInstanceName(ssAHost.getName());
    if (secStorageVm == null) {
      s_logger.warn("secondary storage VM " + ssAHost.getName() + " doesn't exist");
      return false;
    }

    SecStorageVMSetupCommand setupCmd = new SecStorageVMSetupCommand();
    if (_allowedInternalSites != null) {
      List<String> allowedCidrs = new ArrayList<String>();
      String[] cidrs = _allowedInternalSites.split(",");
      for (String cidr : cidrs) {
        if (NetUtils.isValidCIDR(cidr) || NetUtils.isValidIp(cidr)) {
          allowedCidrs.add(cidr);
        }
      }
      List<? extends Nic> nics =
          _networkMgr.getNicsForTraffic(secStorageVm.getId(), TrafficType.Management);
      Nic privateNic = nics.get(0);
      String privateCidr =
          NetUtils.ipAndNetMaskToCidr(privateNic.getIp4Address(), privateNic.getNetmask());
      String publicCidr =
          NetUtils.ipAndNetMaskToCidr(
              secStorageVm.getPublicIpAddress(), secStorageVm.getPublicNetmask());
      if (NetUtils.isNetworkAWithinNetworkB(privateCidr, publicCidr)
          || NetUtils.isNetworkAWithinNetworkB(publicCidr, privateCidr)) {
        s_logger.info(
            "private and public interface overlaps, add a default route through private interface. privateCidr: "
                + privateCidr
                + ", publicCidr: "
                + publicCidr);
        allowedCidrs.add(NetUtils.ALL_CIDRS);
      }
      setupCmd.setAllowedInternalSites(allowedCidrs.toArray(new String[allowedCidrs.size()]));
    }
    String copyPasswd = _configDao.getValue("secstorage.copy.password");
    setupCmd.setCopyPassword(copyPasswd);
    setupCmd.setCopyUserName(TemplateConstants.DEFAULT_HTTP_AUTH_USER);
    Answer answer = _agentMgr.easySend(ssAHostId, setupCmd);
    if (answer != null && answer.getResult()) {
      if (s_logger.isDebugEnabled()) {
        s_logger.debug("Successfully programmed http auth into " + secStorageVm.getHostName());
      }
      return true;
    } else {
      if (s_logger.isDebugEnabled()) {
        s_logger.debug(
            "failed to program http auth into secondary storage vm : "
                + secStorageVm.getHostName());
      }
      return false;
    }
  }
  protected Long stopVM(final HaWorkVO work) {
    final VirtualMachineGuru<VMInstanceVO> mgr = findManager(work.getType());
    final VMInstanceVO vm = mgr.get(work.getInstanceId());
    s_logger.info("Stopping " + vm.toString());
    try {
      if (work.getWorkType() == WorkType.Stop) {
        if (vm.getHostId() != null) {
          if (mgr.stop(vm, 0)) {
            s_logger.info("Successfully stopped " + vm.toString());
            return null;
          }
        } else {
          if (s_logger.isDebugEnabled()) {
            s_logger.debug(vm.toString() + " has already been stopped");
          }
          return null;
        }
      } else if (work.getWorkType() == WorkType.CheckStop) {
        if ((vm.getState() != State.Stopping)
            || vm.getHostId() == null
            || vm.getHostId().longValue() != work.getHostId()) {
          if (s_logger.isDebugEnabled()) {
            s_logger.debug(
                vm.toString()
                    + " is different now.  Scheduled Host: "
                    + work.getHostId()
                    + " Current Host: "
                    + (vm.getHostId() != null ? vm.getHostId() : "none")
                    + " State: "
                    + vm.getState());
          }
          return null;
        } else {
          Command cmd = mgr.cleanup(vm, null);
          Answer ans = _agentMgr.send(work.getHostId(), cmd);
          if (ans.getResult()) {
            mgr.completeStopCommand(vm);
            s_logger.info("Successfully stopped " + vm.toString());
            return null;
          }
          s_logger.debug(
              "Stop for " + vm.toString() + " was unsuccessful. Detail: " + ans.getDetails());
        }
      } else {
        assert false
            : "Who decided there's other steps but didn't modify the guy who does the work?";
      }
    } catch (final AgentUnavailableException e) {
      s_logger.debug("Agnet is not available" + e.getMessage());
    } catch (OperationTimedoutException e) {
      s_logger.debug("operation timed out: " + e.getMessage());
    }

    work.setTimesTried(work.getTimesTried() + 1);
    return (System.currentTimeMillis() >> 10) + _stopRetryInterval;
  }
 public Void deleteCallback(
     AsyncCallbackDispatcher<SamplePrimaryDataStoreDriverImpl, Answer> callback,
     AsyncRpcContext<CommandResult> context) {
   CommandResult result = new CommandResult();
   Answer answer = callback.getResult();
   if (!answer.getResult()) {
     result.setResult(answer.getDetails());
   }
   context.getParentCallback().complete(result);
   return null;
 }
  @Override
  public boolean processAnswers(long agentId, long seq, Answer[] answers) {
    List<Long> affectedVms = new ArrayList<Long>();
    int commandNum = 0;
    for (Answer ans : answers) {
      if (ans instanceof SecurityGroupRuleAnswer) {
        SecurityGroupRuleAnswer ruleAnswer = (SecurityGroupRuleAnswer) ans;
        if (ans.getResult()) {
          s_logger.debug(
              "Successfully programmed rule " + ruleAnswer.toString() + " into host " + agentId);
          _workDao.updateStep(ruleAnswer.getVmId(), ruleAnswer.getLogSequenceNumber(), Step.Done);
          recordSuccess(ruleAnswer.getVmId());
        } else {
          _workDao.updateStep(ruleAnswer.getVmId(), ruleAnswer.getLogSequenceNumber(), Step.Error);
          ;
          s_logger.debug(
              "Failed to program rule "
                  + ruleAnswer.toString()
                  + " into host "
                  + agentId
                  + " due to "
                  + ruleAnswer.getDetails()
                  + " and updated  jobs");
          if (ruleAnswer.getReason() == FailureReason.CANNOT_BRIDGE_FIREWALL) {
            s_logger.debug(
                "Not retrying security group rules for vm "
                    + ruleAnswer.getVmId()
                    + " on failure since host "
                    + agentId
                    + " cannot do bridge firewalling");
          } else if (ruleAnswer.getReason() == FailureReason.PROGRAMMING_FAILED) {
            if (checkShouldRetryOnFailure(ruleAnswer.getVmId())) {
              s_logger.debug(
                  "Retrying security group rules on failure for vm " + ruleAnswer.getVmId());
              affectedVms.add(ruleAnswer.getVmId());
            } else {
              s_logger.debug(
                  "Not retrying security group rules for vm "
                      + ruleAnswer.getVmId()
                      + " on failure: too many retries");
            }
          }
        }
        commandNum++;
        if (_workTracker != null) _workTracker.processAnswers(agentId, seq, answers);
      }
    }

    if (affectedVms.size() > 0) {
      _securityGroupManager.scheduleRulesetUpdateToHosts(affectedVms, false, new Long(10 * 1000l));
    }

    return true;
  }
 private boolean configureNexusVsmForAsa(
     long vlanId,
     String gateway,
     String vsmUsername,
     String vsmPassword,
     String vsmIp,
     String asaInPortProfile,
     long hostId) {
   ConfigureNexusVsmForAsaCommand cmd =
       new ConfigureNexusVsmForAsaCommand(
           vlanId, gateway, vsmUsername, vsmPassword, vsmIp, asaInPortProfile);
   Answer answer = _agentMgr.easySend(hostId, cmd);
   return answer.getResult();
 }
  private Map<Long, TemplateInfo> listVolume(HostVO ssHost) {
    ListVolumeCommand cmd = new ListVolumeCommand(ssHost.getStorageUrl());
    Answer answer = _agentMgr.sendToSecStorage(ssHost, cmd);
    if (answer != null && answer.getResult()) {
      ListVolumeAnswer tanswer = (ListVolumeAnswer) answer;
      return tanswer.getTemplateInfo();
    } else {
      if (s_logger.isDebugEnabled()) {
        s_logger.debug("Can not list volumes for secondary storage host " + ssHost.getId());
      }
    }

    return null;
  }
  @DB
  @Override
  public boolean deleteDataStore(DataStore store) {
    List<StoragePoolHostVO> hostPoolRecords = _storagePoolHostDao.listByPoolId(store.getId());
    StoragePool pool = (StoragePool) store;
    boolean deleteFlag = false;
    // find the hypervisor where the storage is attached to.
    HypervisorType hType = null;
    if (hostPoolRecords.size() > 0) {
      hType = getHypervisorType(hostPoolRecords.get(0).getHostId());
    }

    // Remove the SR associated with the Xenserver
    for (StoragePoolHostVO host : hostPoolRecords) {
      DeleteStoragePoolCommand deleteCmd = new DeleteStoragePoolCommand(pool);
      final Answer answer = agentMgr.easySend(host.getHostId(), deleteCmd);

      if (answer != null && answer.getResult()) {
        deleteFlag = true;
        // if host is KVM hypervisor then send deleteStoragepoolcmd to all the kvm hosts.
        if (HypervisorType.KVM != hType) {
          break;
        }
      } else {
        if (answer != null) {
          s_logger.debug("Failed to delete storage pool: " + answer.getResult());
        }
      }
    }

    if (!deleteFlag) {
      throw new CloudRuntimeException("Failed to delete storage pool on host");
    }

    return dataStoreHelper.deletePrimaryDataStore(store);
  }
 private Map<String, TemplateInfo> listTemplate(SwiftVO swift) {
   if (swift == null) {
     return null;
   }
   ListTemplateCommand cmd = new ListTemplateCommand(swift.toSwiftTO());
   Answer answer = _agentMgr.sendToSSVM(null, cmd);
   if (answer != null && answer.getResult()) {
     ListTemplateAnswer tanswer = (ListTemplateAnswer) answer;
     return tanswer.getTemplateInfo();
   } else {
     if (s_logger.isDebugEnabled()) {
       s_logger.debug("can not list template for swift " + swift);
     }
   }
   return null;
 }
  protected boolean setupVpcGuestNetwork(
      final Network network,
      final VirtualRouter router,
      final boolean add,
      final NicProfile guestNic)
      throws ConcurrentOperationException, ResourceUnavailableException {

    boolean result = true;
    if (router.getState() == State.Running) {
      final SetupGuestNetworkCommand setupCmd =
          _commandSetupHelper.createSetupGuestNetworkCommand(
              (DomainRouterVO) router, add, guestNic);

      final Commands cmds = new Commands(Command.OnError.Stop);
      cmds.addCommand("setupguestnetwork", setupCmd);
      _nwHelper.sendCommandsToRouter(router, cmds);

      final Answer setupAnswer = cmds.getAnswer("setupguestnetwork");
      final String setup = add ? "set" : "destroy";
      if (!(setupAnswer != null && setupAnswer.getResult())) {
        s_logger.warn("Unable to " + setup + " guest network on router " + router);
        result = false;
      }
      return result;
    } else if (router.getState() == State.Stopped || router.getState() == State.Stopping) {
      s_logger.debug(
          "Router "
              + router.getInstanceName()
              + " is in "
              + router.getState()
              + ", so not sending setup guest network command to the backend");
      return true;
    } else {
      s_logger.warn(
          "Unable to setup guest network on virtual router "
              + router
              + " is not in the right state "
              + router.getState());
      throw new ResourceUnavailableException(
          "Unable to setup guest network on the backend,"
              + " virtual router "
              + router
              + " is not in the right state",
          DataCenter.class,
          router.getDataCenterId());
    }
  }
 @Override
 public void deleteAsync(
     DataStore dataStore, DataObject data, AsyncCompletionCallback<CommandResult> callback) {
   CommandResult result = new CommandResult();
   try {
     DeleteCommand cmd = new DeleteCommand(data.getTO());
     EndPoint ep = _epSelector.select(data);
     Answer answer = ep.sendMessage(cmd);
     if (answer != null && !answer.getResult()) {
       result.setResult(answer.getDetails());
     }
   } catch (Exception ex) {
     s_logger.debug("Unable to destoy " + data.getType().toString() + ": " + data.getId(), ex);
     result.setResult(ex.toString());
   }
   callback.complete(result);
 }
 private boolean createLogicalEdgeFirewall(
     long vlanId,
     String gateway,
     String gatewayNetmask,
     String publicIp,
     String publicNetmask,
     List<String> publicGateways,
     long hostId) {
   CreateLogicalEdgeFirewallCommand cmd =
       new CreateLogicalEdgeFirewallCommand(
           vlanId, publicIp, gateway, publicNetmask, gatewayNetmask);
   for (String publicGateway : publicGateways) {
     cmd.getPublicGateways().add(publicGateway);
   }
   Answer answer = _agentMgr.easySend(hostId, cmd);
   return answer.getResult();
 }
  private boolean preparePxeInBasicZone(
      VirtualMachineProfile profile,
      NicProfile nic,
      DeployDestination dest,
      ReservationContext context)
      throws AgentUnavailableException, OperationTimedoutException {
    NetworkVO nwVO = _nwDao.findById(nic.getNetworkId());
    QueryBuilder<BaremetalPxeVO> sc = QueryBuilder.create(BaremetalPxeVO.class);
    sc.and(sc.entity().getDeviceType(), Op.EQ, BaremetalPxeType.KICK_START.toString());
    sc.and(sc.entity().getPhysicalNetworkId(), Op.EQ, nwVO.getPhysicalNetworkId());
    BaremetalPxeVO pxeVo = sc.find();
    if (pxeVo == null) {
      throw new CloudRuntimeException(
          "No kickstart PXE server found in pod: "
              + dest.getPod().getId()
              + ", you need to add it before starting VM");
    }
    VMTemplateVO template = _tmpDao.findById(profile.getTemplateId());
    List<String> tuple = parseKickstartUrl(profile);

    String ks = tuple.get(0);
    String kernel = tuple.get(1);
    String initrd = tuple.get(2);

    PrepareKickstartPxeServerCommand cmd = new PrepareKickstartPxeServerCommand();
    cmd.setKsFile(ks);
    cmd.setInitrd(initrd);
    cmd.setKernel(kernel);
    cmd.setMac(nic.getMacAddress());
    cmd.setTemplateUuid(template.getUuid());
    Answer aws = _agentMgr.send(pxeVo.getHostId(), cmd);
    if (!aws.getResult()) {
      s_logger.warn(
          "Unable to set host: "
              + dest.getHost().getId()
              + " to PXE boot because "
              + aws.getDetails());
      return false;
    }

    return true;
  }
  private Boolean testUserVM(VirtualMachine vm, Nic nic, VirtualRouter router) {
    String privateIp = nic.getIp4Address();
    String routerPrivateIp = router.getPrivateIpAddress();

    List<Long> otherHosts = new ArrayList<Long>();
    if (vm.getHypervisorType() == HypervisorType.XenServer
        || vm.getHypervisorType() == HypervisorType.KVM) {
      otherHosts.add(router.getHostId());
    } else {
      otherHosts = findHostByPod(router.getPodIdToDeployIn(), null);
    }
    for (Long hostId : otherHosts) {
      try {
        Answer pingTestAnswer =
            _agentMgr.easySend(hostId, new PingTestCommand(routerPrivateIp, privateIp));
        if (pingTestAnswer != null && pingTestAnswer.getResult()) {
          if (s_logger.isDebugEnabled()) {
            s_logger.debug(
                "user vm's "
                    + vm.getHostName()
                    + " ip address "
                    + privateIp
                    + "  has been successfully pinged from the Virtual Router "
                    + router.getHostName()
                    + ", returning that vm is alive");
          }
          return Boolean.TRUE;
        }
      } catch (Exception e) {
        if (s_logger.isDebugEnabled()) {
          s_logger.debug("Couldn't reach due to", e);
        }
        continue;
      }
    }
    if (s_logger.isDebugEnabled()) {
      s_logger.debug(vm + " could not be pinged, returning that it is unknown");
    }
    return null;
  }
  @Override
  public boolean rebootSecStorageVm(long secStorageVmId) {
    final SecondaryStorageVmVO secStorageVm = _secStorageVmDao.findById(secStorageVmId);

    if (secStorageVm == null || secStorageVm.getState() == State.Destroyed) {
      return false;
    }

    if (secStorageVm.getState() == State.Running && secStorageVm.getHostId() != null) {
      final RebootCommand cmd = new RebootCommand(secStorageVm.getInstanceName());
      final Answer answer = _agentMgr.easySend(secStorageVm.getHostId(), cmd);

      if (answer != null && answer.getResult()) {
        if (s_logger.isDebugEnabled()) {
          s_logger.debug("Successfully reboot secondary storage vm " + secStorageVm.getHostName());
        }

        SubscriptionMgr.getInstance()
            .notifySubscribers(
                ALERT_SUBJECT,
                this,
                new SecStorageVmAlertEventArgs(
                    SecStorageVmAlertEventArgs.SSVM_REBOOTED,
                    secStorageVm.getDataCenterIdToDeployIn(),
                    secStorageVm.getId(),
                    secStorageVm,
                    null));

        return true;
      } else {
        String msg = "Rebooting Secondary Storage VM failed - " + secStorageVm.getHostName();
        if (s_logger.isDebugEnabled()) {
          s_logger.debug(msg);
        }
        return false;
      }
    } else {
      return startSecStorageVm(secStorageVmId) != null;
    }
  }
  private Map<String, TemplateProp> listTemplate(DataStore ssStore) {
    ListTemplateCommand cmd = new ListTemplateCommand(ssStore.getTO());
    EndPoint ep = _epSelector.select(ssStore);
    Answer answer = null;
    if (ep == null) {
      String errMsg = "No remote endpoint to send command, check if host or ssvm is down?";
      s_logger.error(errMsg);
      answer = new Answer(cmd, false, errMsg);
    } else {
      answer = ep.sendMessage(cmd);
    }
    if (answer != null && answer.getResult()) {
      ListTemplateAnswer tanswer = (ListTemplateAnswer) answer;
      return tanswer.getTemplateInfo();
    } else {
      if (s_logger.isDebugEnabled()) {
        s_logger.debug("can not list template for secondary storage host " + ssStore.getId());
      }
    }

    return null;
  }
  @Override
  public boolean sendCommandsToRouter(final VirtualRouter router, final Commands cmds)
      throws AgentUnavailableException, ResourceUnavailableException {
    if (!checkRouterVersion(router)) {
      s_logger.debug(
          "Router requires upgrade. Unable to send command to router:"
              + router.getId()
              + ", router template version : "
              + router.getTemplateVersion()
              + ", minimal required version : "
              + NetworkOrchestrationService.MinVRVersion.valueIn(router.getDataCenterId()));
      throw new ResourceUnavailableException(
          "Unable to send command. Router requires upgrade", VirtualRouter.class, router.getId());
    }
    Answer[] answers = null;
    try {
      answers = _agentMgr.send(router.getHostId(), cmds);
    } catch (final OperationTimedoutException e) {
      s_logger.warn("Timed Out", e);
      throw new AgentUnavailableException(
          "Unable to send commands to virtual router ", router.getHostId(), e);
    }

    if (answers == null || answers.length != cmds.size()) {
      return false;
    }

    // FIXME: Have to return state for individual command in the future
    boolean result = true;
    for (final Answer answer : answers) {
      if (!answer.getResult()) {
        result = false;
        break;
      }
    }
    return result;
  }
  protected Long destroyVM(HaWorkVO work) {
    final VirtualMachineGuru<VMInstanceVO> mgr = findManager(work.getType());
    final VMInstanceVO vm = mgr.get(work.getInstanceId());
    s_logger.info("Destroying " + vm.toString());
    try {
      if (vm.getState() != State.Destroyed) {
        s_logger.info("VM is no longer in Destroyed state " + vm.toString());
        return null;
      }

      if (vm.getHostId() != null) {
        Command cmd = mgr.cleanup(vm, null);
        Answer ans = _agentMgr.send(work.getHostId(), cmd);
        if (ans.getResult()) {
          mgr.completeStopCommand(vm);
          if (mgr.destroy(vm)) {
            s_logger.info("Successfully stopped " + vm.toString());
            return null;
          }
        }
        s_logger.debug(
            "Stop for " + vm.toString() + " was unsuccessful. Detail: " + ans.getDetails());
      } else {
        if (s_logger.isDebugEnabled()) {
          s_logger.debug(vm.toString() + " has already been stopped");
        }
        return null;
      }
    } catch (final AgentUnavailableException e) {
      s_logger.debug("Agnet is not available" + e.getMessage());
    } catch (OperationTimedoutException e) {
      s_logger.debug("operation timed out: " + e.getMessage());
    }

    work.setTimesTried(work.getTimesTried() + 1);
    return (System.currentTimeMillis() >> 10) + _stopRetryInterval;
  }
 protected boolean createStoragePool(long hostId, StoragePool pool) {
   s_logger.debug("creating pool " + pool.getName() + " on  host " + hostId);
   if (pool.getPoolType() != StoragePoolType.NetworkFilesystem
       && pool.getPoolType() != StoragePoolType.Filesystem
       && pool.getPoolType() != StoragePoolType.IscsiLUN
       && pool.getPoolType() != StoragePoolType.Iscsi
       && pool.getPoolType() != StoragePoolType.VMFS
       && pool.getPoolType() != StoragePoolType.SharedMountPoint
       && pool.getPoolType() != StoragePoolType.PreSetup
       && pool.getPoolType() != StoragePoolType.OCFS2
       && pool.getPoolType() != StoragePoolType.RBD
       && pool.getPoolType() != StoragePoolType.CLVM) {
     s_logger.warn(" Doesn't support storage pool type " + pool.getPoolType());
     return false;
   }
   CreateStoragePoolCommand cmd = new CreateStoragePoolCommand(true, pool);
   final Answer answer = agentMgr.easySend(hostId, cmd);
   if (answer != null && answer.getResult()) {
     return true;
   } else {
     primaryDataStoreDao.expunge(pool.getId());
     String msg = "";
     if (answer != null) {
       msg =
           "Can not create storage pool through host " + hostId + " due to " + answer.getDetails();
       s_logger.warn(msg);
     } else {
       msg =
           "Can not create storage pool through host "
               + hostId
               + " due to CreateStoragePoolCommand returns null";
       s_logger.warn(msg);
     }
     throw new CloudRuntimeException(msg);
   }
 }
  public void processAnswer(VMOperationListener listener, long agentId, long seq, Answer answer) {

    UserVmVO vm = listener.getVm();
    VMOperationParam param = listener.getParam();
    AsyncJobManager asyncMgr = getAsyncJobMgr();
    ManagementServer managementServer = asyncMgr.getExecutorContext().getManagementServer();
    String params =
        "id="
            + vm.getId()
            + "\nvmName="
            + vm.getName()
            + "\nsoId="
            + vm.getServiceOfferingId()
            + "\ntId="
            + vm.getTemplateId()
            + "\ndcId="
            + vm.getDataCenterId();
    if (s_logger.isDebugEnabled())
      s_logger.debug(
          "Execute asynchronize stop VM command: received answer, " + vm.getHostId() + "-" + seq);

    boolean stopped = false;
    if (answer != null && answer.getResult()) stopped = true;

    boolean jobStatusUpdated = false;
    try {
      if (stopped) {
        // completeStopCommand will log the event, if we log it here we will end up with duplicated
        // stop event
        asyncMgr
            .getExecutorContext()
            .getVmMgr()
            .completeStopCommand(
                param.getUserId(), vm, Event.OperationSucceeded, param.getEventId());
        asyncMgr.completeAsyncJob(
            getJob().getId(),
            AsyncJobResult.STATUS_SUCCEEDED,
            0,
            VMExecutorHelper.composeResultObject(
                asyncMgr.getExecutorContext().getManagementServer(), vm, null));
        jobStatusUpdated = true;
      } else {
        asyncMgr
            .getExecutorContext()
            .getItMgr()
            .stateTransitTo(vm, Event.OperationFailed, vm.getHostId());
        asyncMgr.completeAsyncJob(
            getJob().getId(),
            AsyncJobResult.STATUS_FAILED,
            BaseCmd.INTERNAL_ERROR,
            "Agent failed to stop VM");
        jobStatusUpdated = true;

        EventUtils.saveEvent(
            param.getUserId(),
            param.getAccountId(),
            EventVO.LEVEL_ERROR,
            EventTypes.EVENT_VM_STOP,
            "Failed to stop VM instance : " + vm.getName(),
            params,
            param.getEventId());
      }
    } catch (Exception e) {
      s_logger.error("Unexpected exception " + e.getMessage(), e);
      if (!jobStatusUpdated) {
        if (stopped) {
          asyncMgr.completeAsyncJob(
              getJob().getId(),
              AsyncJobResult.STATUS_SUCCEEDED,
              0,
              VMExecutorHelper.composeResultObject(
                  asyncMgr.getExecutorContext().getManagementServer(), vm, null));
        } else {
          asyncMgr.completeAsyncJob(
              getJob().getId(),
              AsyncJobResult.STATUS_FAILED,
              BaseCmd.INTERNAL_ERROR,
              "Agent failed to stop VM");
          EventUtils.saveEvent(
              param.getUserId(),
              param.getAccountId(),
              EventVO.LEVEL_ERROR,
              EventTypes.EVENT_VM_STOP,
              "Failed to stop VM instance : " + vm.getName(),
              params,
              param.getEventId());
        }
      }
    } finally {
      asyncMgr.releaseSyncSource(this);
    }
  }
  @Override
  @DB
  public boolean delete(TemplateProfile profile) {
    boolean success = true;

    VMTemplateVO template = profile.getTemplate();
    Long zoneId = profile.getZoneId();
    Long templateId = template.getId();

    String zoneName;
    List<HostVO> secondaryStorageHosts;
    if (!template.isCrossZones() && zoneId != null) {
      DataCenterVO zone = _dcDao.findById(zoneId);
      zoneName = zone.getName();
      secondaryStorageHosts = _ssvmMgr.listSecondaryStorageHostsInOneZone(zoneId);
    } else {
      zoneName = "(all zones)";
      secondaryStorageHosts = _ssvmMgr.listSecondaryStorageHostsInAllZones();
    }

    s_logger.debug(
        "Attempting to mark template host refs for template: "
            + template.getName()
            + " as destroyed in zone: "
            + zoneName);

    // Make sure the template is downloaded to all the necessary secondary storage hosts
    for (HostVO secondaryStorageHost : secondaryStorageHosts) {
      long hostId = secondaryStorageHost.getId();
      List<VMTemplateHostVO> templateHostVOs = _tmpltHostDao.listByHostTemplate(hostId, templateId);
      for (VMTemplateHostVO templateHostVO : templateHostVOs) {
        if (templateHostVO.getDownloadState() == Status.DOWNLOAD_IN_PROGRESS) {
          String errorMsg = "Please specify a template that is not currently being downloaded.";
          s_logger.debug(
              "Template: "
                  + template.getName()
                  + " is currently being downloaded to secondary storage host: "
                  + secondaryStorageHost.getName()
                  + "; cant' delete it.");
          throw new CloudRuntimeException(errorMsg);
        }
      }
    }

    Account account = _accountDao.findByIdIncludingRemoved(template.getAccountId());
    String eventType = "";

    if (template.getFormat().equals(ImageFormat.ISO)) {
      eventType = EventTypes.EVENT_ISO_DELETE;
    } else {
      eventType = EventTypes.EVENT_TEMPLATE_DELETE;
    }

    // Iterate through all necessary secondary storage hosts and mark the template on each host as
    // destroyed
    for (HostVO secondaryStorageHost : secondaryStorageHosts) {
      long hostId = secondaryStorageHost.getId();
      long sZoneId = secondaryStorageHost.getDataCenterId();
      List<VMTemplateHostVO> templateHostVOs = _tmpltHostDao.listByHostTemplate(hostId, templateId);
      for (VMTemplateHostVO templateHostVO : templateHostVOs) {
        VMTemplateHostVO lock = _tmpltHostDao.acquireInLockTable(templateHostVO.getId());
        try {
          if (lock == null) {
            s_logger.debug(
                "Failed to acquire lock when deleting templateHostVO with ID: "
                    + templateHostVO.getId());
            success = false;
            break;
          }
          UsageEventVO usageEvent =
              new UsageEventVO(eventType, account.getId(), sZoneId, templateId, null);
          _usageEventDao.persist(usageEvent);
          templateHostVO.setDestroyed(true);
          _tmpltHostDao.update(templateHostVO.getId(), templateHostVO);
          String installPath = templateHostVO.getInstallPath();
          if (installPath != null) {
            Answer answer =
                _agentMgr.sendToSecStorage(
                    secondaryStorageHost,
                    new DeleteTemplateCommand(secondaryStorageHost.getStorageUrl(), installPath));

            if (answer == null || !answer.getResult()) {
              s_logger.debug(
                  "Failed to delete "
                      + templateHostVO
                      + " due to "
                      + ((answer == null) ? "answer is null" : answer.getDetails()));
            } else {
              _tmpltHostDao.remove(templateHostVO.getId());
              s_logger.debug("Deleted template at: " + installPath);
            }
          } else {
            _tmpltHostDao.remove(templateHostVO.getId());
          }
          VMTemplateZoneVO templateZone = _tmpltZoneDao.findByZoneTemplate(sZoneId, templateId);

          if (templateZone != null) {
            _tmpltZoneDao.remove(templateZone.getId());
          }
        } finally {
          if (lock != null) {
            _tmpltHostDao.releaseFromLockTable(lock.getId());
          }
        }
      }

      if (!success) {
        break;
      }
    }

    s_logger.debug(
        "Successfully marked template host refs for template: "
            + template.getName()
            + " as destroyed in zone: "
            + zoneName);

    // If there are no more non-destroyed template host entries for this template, delete it
    if (success && (_tmpltHostDao.listByTemplateId(templateId).size() == 0)) {
      long accountId = template.getAccountId();

      VMTemplateVO lock = _tmpltDao.acquireInLockTable(templateId);

      try {
        if (lock == null) {
          s_logger.debug("Failed to acquire lock when deleting template with ID: " + templateId);
          success = false;
        } else if (_tmpltDao.remove(templateId)) {
          // Decrement the number of templates
          _resourceLimitMgr.decrementResourceCount(accountId, ResourceType.template);
        }

      } finally {
        if (lock != null) {
          _tmpltDao.releaseFromLockTable(lock.getId());
        }
      }

      s_logger.debug(
          "Removed template: "
              + template.getName()
              + " because all of its template host refs were marked as destroyed.");
    }

    return success;
  }
    @Override
    public void run() {
      try {
        SearchCriteria<HostVO> sc = _hostDao.createSearchCriteria();
        sc.addAnd("status", SearchCriteria.Op.EQ, Status.Up.toString());
        sc.addAnd("type", SearchCriteria.Op.EQ, Host.Type.Storage.toString());

        ConcurrentHashMap<Long, StorageStats> storageStats =
            new ConcurrentHashMap<Long, StorageStats>();
        List<HostVO> hosts = _hostDao.search(sc, null);
        for (HostVO host : hosts) {
          GetStorageStatsCommand command = new GetStorageStatsCommand(host.getGuid());
          Answer answer = _agentMgr.easySend(host.getId(), command);
          if (answer != null && answer.getResult()) {
            storageStats.put(host.getId(), (StorageStats) answer);
          }
        }

        sc = _hostDao.createSearchCriteria();
        sc.addAnd("status", SearchCriteria.Op.EQ, Status.Up.toString());
        sc.addAnd("type", SearchCriteria.Op.EQ, Host.Type.SecondaryStorage.toString());

        hosts = _hostDao.search(sc, null);
        for (HostVO host : hosts) {
          GetStorageStatsCommand command = new GetStorageStatsCommand(host.getGuid());
          Answer answer = _agentMgr.easySend(host.getId(), command);
          if (answer != null && answer.getResult()) {
            storageStats.put(host.getId(), (StorageStats) answer);
          }
        }
        _storageStats = storageStats;

        ConcurrentHashMap<Long, StorageStats> storagePoolStats =
            new ConcurrentHashMap<Long, StorageStats>();

        List<StoragePoolVO> storagePools = _storagePoolDao.listAll();
        for (StoragePoolVO pool : storagePools) {
          GetStorageStatsCommand command =
              new GetStorageStatsCommand(pool.getUuid(), pool.getPoolType(), pool.getPath());
          Answer answer = _storageManager.sendToPool(pool, command);
          if (answer != null && answer.getResult()) {
            storagePoolStats.put(pool.getId(), (StorageStats) answer);
          }
        }
        _storagePoolStats = storagePoolStats;

        // a list to store the new capacity entries that will be committed once everything is
        // calculated
        List<CapacityVO> newCapacities = new ArrayList<CapacityVO>();

        // Updating the storage entries and creating new ones if they dont exist.
        Transaction txn = Transaction.open(Transaction.CLOUD_DB);
        try {
          if (s_logger.isTraceEnabled()) {
            s_logger.trace("recalculating system storage capacity");
          }
          txn.start();
          for (Long hostId : storageStats.keySet()) {
            StorageStats stats = storageStats.get(hostId);
            short capacityType = -1;
            HostVO host = _hostDao.findById(hostId);
            host.setTotalSize(stats.getCapacityBytes());
            _hostDao.update(host.getId(), host);

            SearchCriteria<CapacityVO> capacitySC = _capacityDao.createSearchCriteria();
            capacitySC.addAnd("hostOrPoolId", SearchCriteria.Op.EQ, hostId);
            capacitySC.addAnd("dataCenterId", SearchCriteria.Op.EQ, host.getDataCenterId());

            if (Host.Type.SecondaryStorage.equals(host.getType())) {
              capacityType = CapacityVO.CAPACITY_TYPE_SECONDARY_STORAGE;
            } else if (Host.Type.Storage.equals(host.getType())) {
              capacityType = CapacityVO.CAPACITY_TYPE_STORAGE;
            }
            if (-1 != capacityType) {
              capacitySC.addAnd("capacityType", SearchCriteria.Op.EQ, capacityType);
              List<CapacityVO> capacities = _capacityDao.search(capacitySC, null);
              if (capacities.size() == 0) { // Create a new one
                CapacityVO capacity =
                    new CapacityVO(
                        host.getId(),
                        host.getDataCenterId(),
                        host.getPodId(),
                        stats.getByteUsed(),
                        stats.getCapacityBytes(),
                        capacityType);
                _capacityDao.persist(capacity);
              } else { // Update if it already exists.
                CapacityVO capacity = capacities.get(0);
                capacity.setUsedCapacity(stats.getByteUsed());
                capacity.setTotalCapacity(stats.getCapacityBytes());
                _capacityDao.update(capacity.getId(), capacity);
              }
            }
          } // End of for
          txn.commit();
        } catch (Exception ex) {
          txn.rollback();
          s_logger.error("Unable to start transaction for storage capacity update");
        } finally {
          txn.close();
        }

        for (Long poolId : storagePoolStats.keySet()) {
          StorageStats stats = storagePoolStats.get(poolId);
          StoragePoolVO pool = _storagePoolDao.findById(poolId);

          if (pool == null) {
            continue;
          }

          pool.setCapacityBytes(stats.getCapacityBytes());
          long available = stats.getCapacityBytes() - stats.getByteUsed();
          if (available < 0) {
            available = 0;
          }
          pool.setAvailableBytes(available);
          _storagePoolDao.update(pool.getId(), pool);

          _storageManager.createCapacityEntry(pool, 0L);
        }
      } catch (Throwable t) {
        s_logger.error("Error trying to retrieve storage stats", t);
      }
    }
  // Returns server component used by server manager to operate the plugin.
  // Server component is a ServerResource. If a connected agent is used, the
  // ServerResource is
  // ignored in favour of another created in response to
  @Override
  public final Map<? extends ServerResource, Map<String, String>> find(
      final long dcId,
      final Long podId,
      final Long clusterId,
      final URI uri,
      final String username,
      final String password,
      final List<String> hostTags)
      throws DiscoveryException {

    if (s_logger.isInfoEnabled()) {
      s_logger.info(
          "Discover host. dc(zone): "
              + dcId
              + ", pod: "
              + podId
              + ", cluster: "
              + clusterId
              + ", uri host: "
              + uri.getHost());
    }

    // Assertions
    if (podId == null) {
      if (s_logger.isInfoEnabled()) {
        s_logger.info("No pod is assigned, skipping the discovery in" + " Hyperv discoverer");
      }
      return null;
    }
    ClusterVO cluster = _clusterDao.findById(clusterId); // ClusterVO exists
    // in the
    // database
    if (cluster == null) {
      if (s_logger.isInfoEnabled()) {
        s_logger.info("No cluster in database for cluster id " + clusterId);
      }
      return null;
    }
    if (cluster.getHypervisorType() != HypervisorType.Hyperv) {
      if (s_logger.isInfoEnabled()) {
        s_logger.info("Cluster " + clusterId + "is not for Hyperv hypervisors");
      }
      return null;
    }
    if (!uri.getScheme().equals("http")) {
      String msg =
          "urlString is not http so we're not taking care of" + " the discovery for this: " + uri;
      s_logger.debug(msg);
      return null;
    }

    try {
      String hostname = uri.getHost();
      InetAddress ia = InetAddress.getByName(hostname);
      String agentIp = ia.getHostAddress();
      String uuidSeed = agentIp;
      String guidWithTail = calcServerResourceGuid(uuidSeed) + "-HypervResource";

      if (_resourceMgr.findHostByGuid(guidWithTail) != null) {
        s_logger.debug(
            "Skipping " + agentIp + " because " + guidWithTail + " is already in the database.");
        return null;
      }

      s_logger.info(
          "Creating"
              + HypervDirectConnectResource.class.getName()
              + " HypervDummyResourceBase for zone/pod/cluster "
              + dcId
              + "/"
              + podId
              + "/"
              + clusterId);

      // Some Hypervisors organise themselves in pools.
      // The startup command tells us what pool they are using.
      // In the meantime, we have to place a GUID corresponding to the
      // pool in the database
      // This GUID may change.
      if (cluster.getGuid() == null) {
        cluster.setGuid(
            UUID.nameUUIDFromBytes(String.valueOf(clusterId).getBytes(Charset.forName("UTF-8")))
                .toString());
        _clusterDao.update(clusterId, cluster);
      }

      // Settings required by all server resources managing a hypervisor
      Map<String, Object> params = new HashMap<String, Object>();
      params.put("zone", Long.toString(dcId));
      params.put("pod", Long.toString(podId));
      params.put("cluster", Long.toString(clusterId));
      params.put("guid", guidWithTail);
      params.put("ipaddress", agentIp);

      // Hyper-V specific settings
      Map<String, String> details = new HashMap<String, String>();
      details.put("url", uri.getHost());
      details.put("username", username);
      details.put("password", password);
      details.put("cluster.guid", cluster.getGuid());

      params.putAll(details);

      HypervDirectConnectResource resource = new HypervDirectConnectResource();
      resource.configure(agentIp, params);

      // Assert
      // TODO: test by using bogus URL and bogus virtual path in URL
      ReadyCommand ping = new ReadyCommand();
      Answer pingAns = resource.executeRequest(ping);
      if (pingAns == null || !pingAns.getResult()) {
        String errMsg = "Agent not running, or no route to agent on at " + uri;
        s_logger.debug(errMsg);
        throw new DiscoveryException(errMsg);
      }

      Map<HypervDirectConnectResource, Map<String, String>> resources =
          new HashMap<HypervDirectConnectResource, Map<String, String>>();
      resources.put(resource, details);

      // TODO: does the resource have to create a connection?
      return resources;
    } catch (ConfigurationException e) {
      _alertMgr.sendAlert(
          AlertManager.AlertType.ALERT_TYPE_HOST,
          dcId,
          podId,
          "Unable to add " + uri.getHost(),
          "Error is " + e.getMessage());
      s_logger.warn("Unable to instantiate " + uri.getHost(), e);
    } catch (UnknownHostException e) {
      _alertMgr.sendAlert(
          AlertManager.AlertType.ALERT_TYPE_HOST,
          dcId,
          podId,
          "Unable to add " + uri.getHost(),
          "Error is " + e.getMessage());

      s_logger.warn("Unable to instantiate " + uri.getHost(), e);
    } catch (Exception e) {
      String msg = " can't setup agent, due to " + e.toString() + " - " + e.getMessage();
      s_logger.warn(msg);
    }
    return null;
  }
  @Override
  public boolean startRemoteAccessVpn(final RemoteAccessVpn vpn, final VirtualRouter router)
      throws ResourceUnavailableException {
    if (router.getState() != State.Running) {
      s_logger.warn(
          "Unable to apply remote access VPN configuration, virtual router is not in the right state "
              + router.getState());
      throw new ResourceUnavailableException(
          "Unable to apply remote access VPN configuration,"
              + " virtual router is not in the right state",
          DataCenter.class,
          router.getDataCenterId());
    }

    final Commands cmds = new Commands(Command.OnError.Stop);
    _commandSetupHelper.createApplyVpnCommands(true, vpn, router, cmds);

    try {
      _agentMgr.send(router.getHostId(), cmds);
    } catch (final OperationTimedoutException e) {
      s_logger.debug("Failed to start remote access VPN: ", e);
      throw new AgentUnavailableException(
          "Unable to send commands to virtual router ", router.getHostId(), e);
    }
    Answer answer = cmds.getAnswer("users");
    if (!answer.getResult()) {
      s_logger.error(
          "Unable to start vpn: unable add users to vpn in zone "
              + router.getDataCenterId()
              + " for account "
              + vpn.getAccountId()
              + " on domR: "
              + router.getInstanceName()
              + " due to "
              + answer.getDetails());
      throw new ResourceUnavailableException(
          "Unable to start vpn: Unable to add users to vpn in zone "
              + router.getDataCenterId()
              + " for account "
              + vpn.getAccountId()
              + " on domR: "
              + router.getInstanceName()
              + " due to "
              + answer.getDetails(),
          DataCenter.class,
          router.getDataCenterId());
    }
    answer = cmds.getAnswer("startVpn");
    if (!answer.getResult()) {
      s_logger.error(
          "Unable to start vpn in zone "
              + router.getDataCenterId()
              + " for account "
              + vpn.getAccountId()
              + " on domR: "
              + router.getInstanceName()
              + " due to "
              + answer.getDetails());
      throw new ResourceUnavailableException(
          "Unable to start vpn in zone "
              + router.getDataCenterId()
              + " for account "
              + vpn.getAccountId()
              + " on domR: "
              + router.getInstanceName()
              + " due to "
              + answer.getDetails(),
          DataCenter.class,
          router.getDataCenterId());
    }

    return true;
  }