private List<String> parseKickstartUrl(VirtualMachineProfile profile) {
    String tpl = profile.getTemplate().getUrl();
    assert tpl != null : "How can a null template get here!!!";
    String[] tpls = tpl.split(";");
    CloudRuntimeException err =
        new CloudRuntimeException(
            String.format(
                "template url[%s] is not correctly encoded. it must be in format of ks=http_link_to_kickstartfile;kernel=nfs_path_to_pxe_kernel;initrd=nfs_path_to_pxe_initrd",
                tpl));
    if (tpls.length != 3) {
      throw err;
    }

    String ks = null;
    String kernel = null;
    String initrd = null;

    for (String t : tpls) {
      String[] kv = t.split("=");
      if (kv.length != 2) {
        throw err;
      }
      if (kv[0].equals("ks")) {
        ks = kv[1];
      } else if (kv[0].equals("kernel")) {
        kernel = kv[1];
      } else if (kv[0].equals("initrd")) {
        initrd = kv[1];
      } else {
        throw err;
      }
    }

    return Arrays.asList(ks, kernel, initrd);
  }
  @Override
  public VirtualMachineTO implement(VirtualMachineProfile vm) {
    VirtualMachineTO to = toVirtualMachineTO(vm);

    VMInstanceVO vo = _vmDao.findById(vm.getId());
    if (vo.getLastHostId() == null) {
      to.setBootArgs(BaremetalManager.DO_PXE);
    }

    Map<String, String> details = new HashMap<String, String>();
    details.put("template", vm.getTemplate().getUrl());
    to.setDetails(details);

    // Determine the VM's OS description
    GuestOSVO guestOS = _guestOsDao.findById(vm.getVirtualMachine().getGuestOSId());
    to.setOs(guestOS.getDisplayName());

    return to;
  }
  private boolean preparePxeInAdvancedZone(
      VirtualMachineProfile profile,
      NicProfile nic,
      Network network,
      DeployDestination dest,
      ReservationContext context)
      throws Exception {
    DomainRouterVO vr = getVirtualRouter(network);
    List<NicVO> nics = _nicDao.listByVmId(vr.getId());
    NicVO mgmtNic = null;
    for (NicVO nicvo : nics) {
      if (ControlNetworkGuru.class.getSimpleName().equals(nicvo.getReserver())) {
        mgmtNic = nicvo;
        break;
      }
    }

    if (mgmtNic == null) {
      throw new CloudRuntimeException(
          String.format("cannot find management nic on virtual router[id:%s]", vr.getId()));
    }

    String internalServerIp = _configDao.getValue(Config.BaremetalInternalStorageServer.key());
    if (internalServerIp == null) {
      throw new CloudRuntimeException(
          String.format(
              "please specify 'baremetal.internal.storage.server.ip', which is the http server/nfs server storing kickstart files and ISO files, in global setting"));
    }

    List<String> tuple = parseKickstartUrl(profile);
    String cmd =
        String.format(
            "/usr/bin/prepare_pxe.sh %s %s %s %s %s %s",
            tuple.get(1),
            tuple.get(2),
            profile.getTemplate().getUuid(),
            String.format("01-%s", nic.getMacAddress().replaceAll(":", "-")).toLowerCase(),
            tuple.get(0),
            nic.getMacAddress().toLowerCase());
    s_logger.debug(
        String.format(
            "prepare pxe on virtual router[ip:%s], cmd: %s", mgmtNic.getIp4Address(), cmd));
    Pair<Boolean, String> ret =
        SshHelper.sshExecute(
            mgmtNic.getIp4Address(), 3922, "root", getSystemVMKeyFile(), null, cmd);
    if (!ret.first()) {
      throw new CloudRuntimeException(
          String.format(
              "failed preparing PXE in virtual router[id:%s], because %s",
              vr.getId(), ret.second()));
    }

    // String internalServerIp = "10.223.110.231";
    cmd =
        String.format(
            "/usr/bin/baremetal_snat.sh %s %s %s",
            mgmtNic.getIp4Address(), internalServerIp, mgmtNic.getGateway());
    s_logger.debug(
        String.format(
            "prepare SNAT on virtual router[ip:%s], cmd: %s", mgmtNic.getIp4Address(), cmd));
    ret =
        SshHelper.sshExecute(
            mgmtNic.getIp4Address(), 3922, "root", getSystemVMKeyFile(), null, cmd);
    if (!ret.first()) {
      throw new CloudRuntimeException(
          String.format(
              "failed preparing PXE in virtual router[id:%s], because %s",
              vr.getId(), ret.second()));
    }

    return true;
  }
  @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;
    }
  }