@Override
 public BaremetalPxeResponse getApiResponse(BaremetalPxeVO vo) {
   BaremetalPxePingResponse response = new BaremetalPxePingResponse();
   response.setId(String.valueOf(vo.getId()));
   response.setPhysicalNetworkId(String.valueOf(vo.getPhysicalNetworkId()));
   response.setPodId(String.valueOf(vo.getPodId()));
   Map<String, String> details = _hostDetailsDao.findDetails(vo.getHostId());
   response.setPingStorageServerIp(
       details.get(BaremetalPxeService.PXE_PARAM_PING_STORAGE_SERVER_IP));
   response.setPingDir(details.get(BaremetalPxeService.PXE_PARAM_PING_ROOT_DIR));
   response.setTftpDir(details.get(BaremetalPxeService.PXE_PARAM_TFTP_DIR));
   return response;
 }
 @Override
 public BaremetalPxeResponse getApiResponse(BaremetalPxeVO vo) {
   BaremetalPxeResponse response = new BaremetalPxeResponse();
   response.setId(vo.getUuid());
   HostVO host = _hostDao.findById(vo.getHostId());
   response.setUrl(host.getPrivateIpAddress());
   PhysicalNetworkServiceProviderVO providerVO =
       _physicalNetworkServiceProviderDao.findById(vo.getNetworkServiceProviderId());
   response.setPhysicalNetworkId(providerVO.getUuid());
   PhysicalNetworkVO nwVO = _physicalNetworkDao.findById(vo.getPhysicalNetworkId());
   response.setPhysicalNetworkId(nwVO.getUuid());
   response.setObjectName("baremetalpxeserver");
   return response;
 }
  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;
  }
  @Override
  @DB
  public BaremetalPxeVO addPxeServer(AddBaremetalPxeCmd cmd) {
    AddBaremetalKickStartPxeCmd kcmd = (AddBaremetalKickStartPxeCmd) cmd;
    PhysicalNetworkVO pNetwork = null;
    long zoneId;

    if (cmd.getPhysicalNetworkId() == null
        || cmd.getUrl() == null
        || cmd.getUsername() == null
        || cmd.getPassword() == null) {
      throw new IllegalArgumentException(
          "At least one of the required parameters(physical network id, url, username, password) is null");
    }

    pNetwork = _physicalNetworkDao.findById(cmd.getPhysicalNetworkId());
    if (pNetwork == null) {
      throw new IllegalArgumentException(
          "Could not find phyical network with ID: " + cmd.getPhysicalNetworkId());
    }
    zoneId = pNetwork.getDataCenterId();

    PhysicalNetworkServiceProviderVO ntwkSvcProvider =
        _physicalNetworkServiceProviderDao.findByServiceProvider(
            pNetwork.getId(), BaremetalPxeManager.BAREMETAL_PXE_SERVICE_PROVIDER.getName());
    if (ntwkSvcProvider == null) {
      throw new CloudRuntimeException(
          "Network Service Provider: "
              + BaremetalPxeManager.BAREMETAL_PXE_SERVICE_PROVIDER.getName()
              + " is not enabled in the physical network: "
              + cmd.getPhysicalNetworkId()
              + "to add this device");
    } else if (ntwkSvcProvider.getState() == PhysicalNetworkServiceProvider.State.Shutdown) {
      throw new CloudRuntimeException(
          "Network Service Provider: "
              + ntwkSvcProvider.getProviderName()
              + " is in shutdown state in the physical network: "
              + cmd.getPhysicalNetworkId()
              + "to add this device");
    }

    List<HostVO> pxes = _resourceMgr.listAllHostsInOneZoneByType(Host.Type.BaremetalPxe, zoneId);
    if (!pxes.isEmpty()) {
      throw new IllegalArgumentException("Already had a PXE server zone: " + zoneId);
    }

    String tftpDir = kcmd.getTftpDir();
    if (tftpDir == null) {
      throw new IllegalArgumentException("No TFTP directory specified");
    }

    URI uri;
    try {
      uri = new URI(cmd.getUrl());
    } catch (Exception e) {
      s_logger.debug(e);
      throw new IllegalArgumentException(e.getMessage());
    }
    String ipAddress = uri.getHost();
    if (ipAddress == null) {
      ipAddress = cmd.getUrl();
    }

    String guid =
        getPxeServerGuid(Long.toString(zoneId), BaremetalPxeType.KICK_START.toString(), ipAddress);

    ServerResource resource = null;
    Map params = new HashMap<String, String>();
    params.put(BaremetalPxeService.PXE_PARAM_ZONE, Long.toString(zoneId));
    params.put(BaremetalPxeService.PXE_PARAM_IP, ipAddress);
    params.put(BaremetalPxeService.PXE_PARAM_USERNAME, cmd.getUsername());
    params.put(BaremetalPxeService.PXE_PARAM_PASSWORD, cmd.getPassword());
    params.put(BaremetalPxeService.PXE_PARAM_TFTP_DIR, tftpDir);
    params.put(BaremetalPxeService.PXE_PARAM_GUID, guid);
    resource = new BaremetalKickStartPxeResource();
    try {
      resource.configure("KickStart PXE resource", params);
    } catch (Exception e) {
      throw new CloudRuntimeException(e.getMessage(), e);
    }

    Host pxeServer = _resourceMgr.addHost(zoneId, resource, Host.Type.BaremetalPxe, params);
    if (pxeServer == null) {
      throw new CloudRuntimeException("Cannot add PXE server as a host");
    }

    BaremetalPxeVO vo = new BaremetalPxeVO();
    vo.setHostId(pxeServer.getId());
    vo.setNetworkServiceProviderId(ntwkSvcProvider.getId());
    vo.setPhysicalNetworkId(kcmd.getPhysicalNetworkId());
    vo.setDeviceType(BaremetalPxeType.KICK_START.toString());
    _pxeDao.persist(vo);
    return vo;
  }
  @Override
  public boolean addUserData(NicProfile nic, VirtualMachineProfile profile) {
    UserVmVO vm = _vmDao.findById(profile.getVirtualMachine().getId());
    _vmDao.loadDetails(vm);

    String serviceOffering =
        _serviceOfferingDao
            .findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId())
            .getDisplayText();
    String zoneName = _dcDao.findById(vm.getDataCenterId()).getName();
    NicVO nvo = _nicDao.findById(nic.getId());
    VmDataCommand cmd =
        new VmDataCommand(
            nvo.getIPv4Address(), vm.getInstanceName(), _ntwkModel.getExecuteInSeqNtwkElmtCmd());
    // if you add new metadata files, also edit
    // systemvm/patches/debian/config/var/www/html/latest/.htaccess
    cmd.addVmData("userdata", "user-data", vm.getUserData());
    cmd.addVmData("metadata", "service-offering", StringUtils.unicodeEscape(serviceOffering));
    cmd.addVmData("metadata", "availability-zone", StringUtils.unicodeEscape(zoneName));
    cmd.addVmData("metadata", "local-ipv4", nic.getIPv4Address());
    cmd.addVmData("metadata", "local-hostname", StringUtils.unicodeEscape(vm.getInstanceName()));
    cmd.addVmData("metadata", "public-ipv4", nic.getIPv4Address());
    cmd.addVmData("metadata", "public-hostname", StringUtils.unicodeEscape(vm.getInstanceName()));
    cmd.addVmData("metadata", "instance-id", String.valueOf(vm.getId()));
    cmd.addVmData("metadata", "vm-id", String.valueOf(vm.getInstanceName()));
    cmd.addVmData("metadata", "public-keys", null);
    String cloudIdentifier = _configDao.getValue("cloud.identifier");
    if (cloudIdentifier == null) {
      cloudIdentifier = "";
    } else {
      cloudIdentifier = "CloudStack-{" + cloudIdentifier + "}";
    }
    cmd.addVmData("metadata", "cloud-identifier", cloudIdentifier);

    List<PhysicalNetworkVO> phys = _phynwDao.listByZone(vm.getDataCenterId());
    if (phys.isEmpty()) {
      throw new CloudRuntimeException(
          String.format("Cannot find physical network in zone %s", vm.getDataCenterId()));
    }
    if (phys.size() > 1) {
      throw new CloudRuntimeException(
          String.format(
              "Baremetal only supports one physical network in zone, but zone %s has %s physical networks",
              vm.getDataCenterId(), phys.size()));
    }
    PhysicalNetworkVO phy = phys.get(0);

    QueryBuilder<BaremetalPxeVO> sc = QueryBuilder.create(BaremetalPxeVO.class);
    // TODO: handle both kickstart and PING
    // sc.addAnd(sc.getEntity().getPodId(), Op.EQ, vm.getPodIdToDeployIn());
    sc.and(sc.entity().getPhysicalNetworkId(), Op.EQ, phy.getId());
    BaremetalPxeVO pxeVo = sc.find();
    if (pxeVo == null) {
      throw new CloudRuntimeException(
          "No PXE server found in pod: "
              + vm.getPodIdToDeployIn()
              + ", you need to add it before starting VM");
    }

    try {
      Answer ans = _agentMgr.send(pxeVo.getHostId(), cmd);
      if (!ans.getResult()) {
        s_logger.debug(
            String.format(
                "Add userdata to vm:%s failed because %s", vm.getInstanceName(), ans.getDetails()));
        return false;
      } else {
        return true;
      }
    } catch (Exception e) {
      s_logger.debug(String.format("Add userdata to vm:%s failed", vm.getInstanceName()), e);
      return false;
    }
  }
 @Override
 public BaremetalPxeResponse getApiResponse(BaremetalPxeVO vo) {
   return getServiceByType(vo.getDeviceType()).getApiResponse(vo);
 }
  @Override
  public boolean prepare(
      VirtualMachineProfile<UserVmVO> profile,
      NicProfile pxeNic,
      DeployDestination dest,
      ReservationContext context) {
    SearchCriteriaService<BaremetalPxeVO, BaremetalPxeVO> sc =
        SearchCriteria2.create(BaremetalPxeVO.class);
    sc.addAnd(sc.getEntity().getDeviceType(), Op.EQ, BaremetalPxeType.PING.toString());
    sc.addAnd(sc.getEntity().getPodId(), Op.EQ, dest.getPod().getId());
    BaremetalPxeVO pxeVo = sc.find();
    if (pxeVo == null) {
      throw new CloudRuntimeException(
          "No PING PXE server found in pod: "
              + dest.getPod().getId()
              + ", you need to add it before starting VM");
    }
    long pxeServerId = pxeVo.getHostId();

    String mac = pxeNic.getMacAddress();
    String ip = pxeNic.getIp4Address();
    String gateway = pxeNic.getGateway();
    String mask = pxeNic.getNetmask();
    String dns = pxeNic.getDns1();
    if (dns == null) {
      dns = pxeNic.getDns2();
    }

    try {
      String tpl = profile.getTemplate().getUrl();
      assert tpl != null : "How can a null template get here!!!";
      PreparePxeServerCommand cmd =
          new PreparePxeServerCommand(
              ip,
              mac,
              mask,
              gateway,
              dns,
              tpl,
              profile.getVirtualMachine().getInstanceName(),
              dest.getHost().getName());
      PreparePxeServerAnswer ans = (PreparePxeServerAnswer) _agentMgr.send(pxeServerId, cmd);
      if (!ans.getResult()) {
        s_logger.warn(
            "Unable tot program PXE server: " + pxeVo.getId() + " because " + ans.getDetails());
        return false;
      }

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

      return anw.getResult();
    } catch (Exception e) {
      s_logger.warn("Cannot prepare PXE server", e);
      return false;
    }
  }
  @Override
  @DB
  public BaremetalPxeVO addPxeServer(AddBaremetalPxeCmd cmd) {
    AddBaremetalPxePingServerCmd pcmd = (AddBaremetalPxePingServerCmd) cmd;

    PhysicalNetworkVO pNetwork = null;
    long zoneId;

    if (cmd.getPhysicalNetworkId() == null
        || cmd.getUrl() == null
        || cmd.getUsername() == null
        || cmd.getPassword() == null) {
      throw new IllegalArgumentException(
          "At least one of the required parameters(physical network id, url, username, password) is null");
    }

    pNetwork = _physicalNetworkDao.findById(cmd.getPhysicalNetworkId());
    if (pNetwork == null) {
      throw new IllegalArgumentException(
          "Could not find phyical network with ID: " + cmd.getPhysicalNetworkId());
    }
    zoneId = pNetwork.getDataCenterId();

    PhysicalNetworkServiceProviderVO ntwkSvcProvider =
        _physicalNetworkServiceProviderDao.findByServiceProvider(
            pNetwork.getId(), BaremetalPxeManager.BAREMETAL_PXE_SERVICE_PROVIDER.getName());
    if (ntwkSvcProvider == null) {
      throw new CloudRuntimeException(
          "Network Service Provider: "
              + BaremetalPxeManager.BAREMETAL_PXE_SERVICE_PROVIDER.getName()
              + " is not enabled in the physical network: "
              + cmd.getPhysicalNetworkId()
              + "to add this device");
    } else if (ntwkSvcProvider.getState() == PhysicalNetworkServiceProvider.State.Shutdown) {
      throw new CloudRuntimeException(
          "Network Service Provider: "
              + ntwkSvcProvider.getProviderName()
              + " is in shutdown state in the physical network: "
              + cmd.getPhysicalNetworkId()
              + "to add this device");
    }

    HostPodVO pod = _podDao.findById(cmd.getPodId());
    if (pod == null) {
      throw new IllegalArgumentException("Could not find pod with ID: " + cmd.getPodId());
    }

    List<HostVO> pxes =
        _resourceMgr.listAllUpAndEnabledHosts(Host.Type.BaremetalPxe, null, cmd.getPodId(), zoneId);
    if (pxes.size() != 0) {
      throw new IllegalArgumentException(
          "Already had a PXE server in Pod: " + cmd.getPodId() + " zone: " + zoneId);
    }

    String storageServerIp = pcmd.getPingStorageServerIp();
    if (storageServerIp == null) {
      throw new IllegalArgumentException("No IP for storage server specified");
    }
    String pingDir = pcmd.getPingDir();
    if (pingDir == null) {
      throw new IllegalArgumentException("No direcotry for storage server specified");
    }
    String tftpDir = pcmd.getTftpDir();
    if (tftpDir == null) {
      throw new IllegalArgumentException("No TFTP directory specified");
    }

    String cifsUsername = pcmd.getPingStorageServerUserName();
    if (cifsUsername == null || cifsUsername.equalsIgnoreCase("")) {
      cifsUsername = "******";
    }
    String cifsPassword = pcmd.getPingStorageServerPassword();
    if (cifsPassword == null || cifsPassword.equalsIgnoreCase("")) {
      cifsPassword = "******";
    }

    URI uri;
    try {
      uri = new URI(cmd.getUrl());
    } catch (Exception e) {
      s_logger.debug(e);
      throw new IllegalArgumentException(e.getMessage());
    }
    String ipAddress = uri.getHost();

    String guid =
        getPxeServerGuid(
            Long.toString(zoneId) + "-" + pod.getId(), BaremetalPxeType.PING.toString(), ipAddress);

    ServerResource resource = null;
    Map params = new HashMap<String, String>();
    params.put(BaremetalPxeService.PXE_PARAM_ZONE, Long.toString(zoneId));
    params.put(BaremetalPxeService.PXE_PARAM_POD, String.valueOf(pod.getId()));
    params.put(BaremetalPxeService.PXE_PARAM_IP, ipAddress);
    params.put(BaremetalPxeService.PXE_PARAM_USERNAME, cmd.getUsername());
    params.put(BaremetalPxeService.PXE_PARAM_PASSWORD, cmd.getPassword());
    params.put(BaremetalPxeService.PXE_PARAM_PING_STORAGE_SERVER_IP, storageServerIp);
    params.put(BaremetalPxeService.PXE_PARAM_PING_ROOT_DIR, pingDir);
    params.put(BaremetalPxeService.PXE_PARAM_TFTP_DIR, tftpDir);
    params.put(BaremetalPxeService.PXE_PARAM_PING_STORAGE_SERVER_USERNAME, cifsUsername);
    params.put(BaremetalPxeService.PXE_PARAM_PING_STORAGE_SERVER_PASSWORD, cifsPassword);
    params.put(BaremetalPxeService.PXE_PARAM_GUID, guid);

    resource = new BaremetalPingPxeResource();
    try {
      resource.configure("PING PXE resource", params);
    } catch (Exception e) {
      s_logger.debug(e);
      throw new CloudRuntimeException(e.getMessage());
    }

    Host pxeServer = _resourceMgr.addHost(zoneId, resource, Host.Type.BaremetalPxe, params);
    if (pxeServer == null) {
      throw new CloudRuntimeException("Cannot add PXE server as a host");
    }

    BaremetalPxeVO vo = new BaremetalPxeVO();
    Transaction txn = Transaction.currentTxn();
    vo.setHostId(pxeServer.getId());
    vo.setNetworkServiceProviderId(ntwkSvcProvider.getId());
    vo.setPodId(pod.getId());
    vo.setPhysicalNetworkId(pcmd.getPhysicalNetworkId());
    vo.setDeviceType(BaremetalPxeType.PING.toString());
    txn.start();
    _pxeDao.persist(vo);
    txn.commit();
    return vo;
  }