@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 void reserve(
      NicProfile nic,
      Network config,
      VirtualMachineProfile<? extends VirtualMachine> vm,
      DeployDestination dest,
      ReservationContext context)
      throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException {
    assert nic.getTrafficType() == TrafficType.Control;

    if (dest.getHost().getHypervisorType() == HypervisorType.VmWare
        && vm.getType() == VirtualMachine.Type.DomainRouter) {
      super.reserve(nic, config, vm, dest, context);

      String mac = _networkMgr.getNextAvailableMacAddressInNetwork(config.getId());
      nic.setMacAddress(mac);
      return;
    }

    String ip =
        _dcDao.allocateLinkLocalIpAddress(
            dest.getDataCenter().getId(),
            dest.getPod().getId(),
            nic.getId(),
            context.getReservationId());
    nic.setIp4Address(ip);
    nic.setMacAddress(NetUtils.long2Mac(NetUtils.ip2Long(ip) | (14l << 40)));
    nic.setNetmask("255.255.0.0");
    nic.setFormat(AddressFormat.Ip4);
    nic.setGateway(NetUtils.getLinkLocalGateway());
  }
  @Override
  @DB
  public boolean prepare(
      Network network,
      NicProfile nic,
      VirtualMachineProfile<? extends VirtualMachine> vm,
      DeployDestination dest,
      ReservationContext context)
      throws ConcurrentOperationException, ResourceUnavailableException,
          InsufficientCapacityException {
    Host host = dest.getHost();
    if (host == null || host.getHypervisorType() != HypervisorType.BareMetal) {
      return true;
    }

    Transaction txn = Transaction.currentTxn();
    txn.start();
    nic.setMacAddress(host.getPrivateMacAddress());
    NicVO vo = _nicDao.findById(nic.getId());
    assert vo != null : "Where ths nic " + nic.getId() + " going???";
    vo.setMacAddress(nic.getMacAddress());
    _nicDao.update(vo.getId(), vo);
    txn.commit();
    s_logger.debug(
        "Bare Metal changes mac address of nic " + nic.getId() + " to " + nic.getMacAddress());

    return _dhcpMgr.addVirtualMachineIntoNetwork(network, nic, vm, dest, context);
  }
  @Override
  public boolean prepareMigration(
      final NicProfile nic,
      final Network network,
      final VirtualMachineProfile vm,
      final DeployDestination dest,
      final ReservationContext context) {
    if (!canHandle(network, Service.Connectivity)) {
      return false;
    }

    if (nic.getBroadcastType() != Networks.BroadcastDomainType.Vswitch) {
      return false;
    }

    if (nic.getTrafficType() != Networks.TrafficType.Guest) {
      return false;
    }

    if (vm.getType() != VirtualMachine.Type.User
        && vm.getType() != VirtualMachine.Type.DomainRouter) {
      return false;
    }

    // prepare the tunnel network on the host, in order for VM to get launched
    _ovsTunnelMgr.checkAndPrepareHostForTunnelNetwork(network, dest.getHost());

    return true;
  }
  @Override
  public boolean finalizeDeployment(
      Commands cmds,
      VirtualMachineProfile<SecondaryStorageVmVO> profile,
      DeployDestination dest,
      ReservationContext context) {

    finalizeCommandsOnStart(cmds, profile);

    SecondaryStorageVmVO secVm = profile.getVirtualMachine();
    DataCenter dc = dest.getDataCenter();
    List<NicProfile> nics = profile.getNics();
    for (NicProfile nic : nics) {
      if ((nic.getTrafficType() == TrafficType.Public
              && dc.getNetworkType() == NetworkType.Advanced)
          || (nic.getTrafficType() == TrafficType.Guest
              && (dc.getNetworkType() == NetworkType.Basic || dc.isSecurityGroupEnabled()))) {
        secVm.setPublicIpAddress(nic.getIp4Address());
        secVm.setPublicNetmask(nic.getNetmask());
        secVm.setPublicMacAddress(nic.getMacAddress());
      } else if (nic.getTrafficType() == TrafficType.Management) {
        secVm.setPrivateIpAddress(nic.getIp4Address());
        secVm.setPrivateMacAddress(nic.getMacAddress());
      }
    }
    _secStorageVmDao.update(secVm.getId(), secVm);
    return true;
  }
  @Override
  public Network implement(
      Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context)
      throws InsufficientVirtualNetworkCapcityException {
    assert (network.getState() == State.Implementing) : "Why are we implementing " + network;

    long dcId = dest.getDataCenter().getId();
    NetworkType nwType = dest.getDataCenter().getNetworkType();
    // get physical network id
    Long physicalNetworkId = network.getPhysicalNetworkId();
    // physical network id can be null in Guest Network in Basic zone, so
    // locate the physical network
    if (physicalNetworkId == null) {
      physicalNetworkId =
          _networkModel.findPhysicalNetworkId(dcId, offering.getTags(), offering.getTrafficType());
    }
    PhysicalNetworkVO physnet = _physicalNetworkDao.findById(physicalNetworkId);

    if (!canHandle(offering, nwType, physnet)) {
      s_logger.debug("Refusing to design this network");
      return null;
    }
    NetworkVO implemented = (NetworkVO) super.implement(network, offering, dest, context);

    if (network.getGateway() != null) {
      implemented.setGateway(network.getGateway());
    }

    if (network.getCidr() != null) {
      implemented.setCidr(network.getCidr());
    }
    String name = network.getName();
    if (name == null || name.isEmpty()) {
      name = ((NetworkVO) network).getUuid();
    }

    // do we need to create switch right now?

    implemented.setBroadcastDomainType(BroadcastDomainType.Vswitch);

    return implemented;
  }
  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;
  }
  // we use context.reservationId for dedup of guru & element operations.
  public boolean createNicEnv(
      Network network, NicProfile nic, DeployDestination dest, ReservationContext context) {
    String tenantNetworkUuid = _sspUuidDao.findUuidByNetwork(network);
    if (tenantNetworkUuid == null) {
      s_logger.debug("Skipping #createNicEnv() for nic on " + network.toString());
      return true;
    }

    String reservationId = context.getReservationId();
    List<SspUuidVO> tenantPortUuidVos = _sspUuidDao.listUUidVoByNicProfile(nic);
    for (SspUuidVO tenantPortUuidVo : tenantPortUuidVos) {
      if (reservationId.equals(tenantPortUuidVo.getReservationId())) {
        s_logger.info("Skipping because reservation found " + reservationId);
        return true;
      }
    }

    String tenantPortUuid = null;
    for (SspClient client :
        fetchSspClients(network.getPhysicalNetworkId(), network.getDataCenterId(), true)) {
      SspClient.TenantPort sspPort = client.createTenantPort(tenantNetworkUuid);
      if (sspPort != null) {
        tenantPortUuid = sspPort.uuid;
        nic.setReservationId(reservationId);

        SspUuidVO uuid = new SspUuidVO();
        uuid.setUuid(tenantPortUuid);
        uuid.setObjClass(SspUuidVO.objClassNicProfile);
        uuid.setObjId(nic.getId());
        uuid.setReservationId(reservationId);
        _sspUuidDao.persist(uuid);
        break;
      }
    }
    if (tenantPortUuid == null) {
      s_logger.debug("#createNicEnv() failed for nic on " + network.toString());
      return false;
    }

    for (SspClient client :
        fetchSspClients(network.getPhysicalNetworkId(), network.getDataCenterId(), true)) {
      SspClient.TenantPort sspPort =
          client.updateTenantVifBinding(tenantPortUuid, dest.getHost().getPrivateIpAddress());
      if (sspPort != null) {
        if (sspPort.vlanId != null) {
          nic.setBroadcastType(BroadcastDomainType.Vlan);
          nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(String.valueOf(sspPort.vlanId)));
        }
        return true;
      }
    }
    s_logger.error("Updating vif failed " + nic.toString());
    return false;
  }
 @Override
 public void reserve(
     NicProfile nic,
     Network network,
     VirtualMachineProfile<? extends VirtualMachine> vm,
     DeployDestination dest,
     ReservationContext context)
     throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException,
         ConcurrentOperationException {
   if (nic.getIp4Address() == null) {
     getIp(nic, dest.getDataCenter(), vm, network);
   }
 }
  protected List<HypervisorType> getHypervisors(
      final RouterDeploymentDefinition routerDeploymentDefinition)
      throws InsufficientServerCapacityException {
    final DeployDestination dest = routerDeploymentDefinition.getDest();
    List<HypervisorType> hypervisors = new ArrayList<HypervisorType>();
    if (dest.getCluster() != null) {
      if (dest.getCluster().getHypervisorType() == HypervisorType.Ovm) {
        hypervisors.add(getClusterToStartDomainRouterForOvm(dest.getCluster().getPodId()));
      } else {
        hypervisors.add(dest.getCluster().getHypervisorType());
      }
    } else {
      final HypervisorType defaults =
          _resourceMgr.getDefaultHypervisor(dest.getDataCenter().getId());
      if (defaults != HypervisorType.None) {
        hypervisors.add(defaults);
      } else {
        // if there is no default hypervisor, get it from the cluster
        hypervisors =
            _resourceMgr.getSupportedHypervisorTypes(
                dest.getDataCenter().getId(),
                true,
                routerDeploymentDefinition.getPlan().getPodId());
      }
    }

    filterSupportedHypervisors(hypervisors);

    if (hypervisors.isEmpty()) {
      if (routerDeploymentDefinition.getPodId() != null) {
        throw new InsufficientServerCapacityException(
            "Unable to create virtual router, there are no clusters in the pod."
                + getNoHypervisorsErrMsgDetails(),
            Pod.class,
            routerDeploymentDefinition.getPodId());
      }
      throw new InsufficientServerCapacityException(
          "Unable to create virtual router, there are no clusters in the zone."
              + getNoHypervisorsErrMsgDetails(),
          DataCenter.class,
          dest.getDataCenter().getId());
    }
    return hypervisors;
  }
  @Override
  public String reserveVirtualMachine(
      VMEntityVO vmEntityVO, String plannerToUse, DeploymentPlan planToDeploy, ExcludeList exclude)
      throws InsufficientCapacityException, ResourceUnavailableException {

    // call planner and get the deployDestination.
    // load vm instance and offerings and call virtualMachineManagerImpl
    // FIXME: profile should work on VirtualMachineEntity
    VMInstanceVO vm = _vmDao.findByUuid(vmEntityVO.getUuid());
    VirtualMachineProfileImpl<VMInstanceVO> vmProfile =
        new VirtualMachineProfileImpl<VMInstanceVO>(vm);
    DataCenterDeployment plan =
        new DataCenterDeployment(
            vm.getDataCenterId(), vm.getPodIdToDeployIn(), null, null, null, null);
    if (planToDeploy != null && planToDeploy.getDataCenterId() != 0) {
      plan =
          new DataCenterDeployment(
              planToDeploy.getDataCenterId(),
              planToDeploy.getPodId(),
              planToDeploy.getClusterId(),
              planToDeploy.getHostId(),
              planToDeploy.getPoolId(),
              planToDeploy.getPhysicalNetworkId());
    }

    List<VolumeVO> vols = _volsDao.findReadyRootVolumesByInstance(vm.getId());
    if (!vols.isEmpty()) {
      VolumeVO vol = vols.get(0);
      StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId());
      if (!pool.isInMaintenance()) {
        long rootVolDcId = pool.getDataCenterId();
        Long rootVolPodId = pool.getPodId();
        Long rootVolClusterId = pool.getClusterId();
        if (planToDeploy != null && planToDeploy.getDataCenterId() != 0) {
          Long clusterIdSpecified = planToDeploy.getClusterId();
          if (clusterIdSpecified != null && rootVolClusterId != null) {
            if (rootVolClusterId.longValue() != clusterIdSpecified.longValue()) {
              // cannot satisfy the plan passed in to the
              // planner
              throw new ResourceUnavailableException(
                  "Root volume is ready in different cluster, Deployment plan provided cannot be satisfied, unable to create a deployment for "
                      + vm,
                  Cluster.class,
                  clusterIdSpecified);
            }
          }
          plan =
              new DataCenterDeployment(
                  planToDeploy.getDataCenterId(),
                  planToDeploy.getPodId(),
                  planToDeploy.getClusterId(),
                  planToDeploy.getHostId(),
                  vol.getPoolId(),
                  null,
                  null);
        } else {
          plan =
              new DataCenterDeployment(
                  rootVolDcId, rootVolPodId, rootVolClusterId, null, vol.getPoolId(), null, null);
        }
      }
    }

    DeploymentPlanner planner = ComponentContext.getComponent(plannerToUse);
    DeployDestination dest = null;

    if (planner.canHandle(vmProfile, plan, exclude)) {
      dest = planner.plan(vmProfile, plan, exclude);
    }

    if (dest != null) {
      // save destination with VMEntityVO
      VMReservationVO vmReservation =
          new VMReservationVO(
              vm.getId(),
              dest.getDataCenter().getId(),
              dest.getPod().getId(),
              dest.getCluster().getId(),
              dest.getHost().getId());
      Map<Long, Long> volumeReservationMap = new HashMap<Long, Long>();
      for (Volume vo : dest.getStorageForDisks().keySet()) {
        volumeReservationMap.put(vo.getId(), dest.getStorageForDisks().get(vo).getId());
      }
      vmReservation.setVolumeReservation(volumeReservationMap);

      vmEntityVO.setVmReservation(vmReservation);
      _vmEntityDao.persist(vmEntityVO);

      return vmReservation.getUuid();
    } else {
      throw new InsufficientServerCapacityException(
          "Unable to create a deployment for " + vmProfile,
          DataCenter.class,
          plan.getDataCenterId());
    }
  }
  @Override
  public Network implement(
      Network config, NetworkOffering offering, DeployDestination dest, ReservationContext context)
      throws InsufficientVirtualNetworkCapcityException {
    assert (config.getState() == State.Implementing) : "Why are we implementing " + config;

    if (Boolean.parseBoolean(_configDao.getValue(Config.OvsTunnelNetwork.key()))) {
      return null;
    }

    if (!_networkModel.networkIsConfiguredForExternalNetworking(
        config.getDataCenterId(), config.getId())) {
      return super.implement(config, offering, dest, context);
    }

    DataCenter zone = dest.getDataCenter();
    NetworkVO implemented =
        new NetworkVO(
            config.getTrafficType(),
            config.getMode(),
            config.getBroadcastDomainType(),
            config.getNetworkOfferingId(),
            State.Allocated,
            config.getDataCenterId(),
            config.getPhysicalNetworkId());

    // Get a vlan tag
    int vlanTag;
    if (config.getBroadcastUri() == null) {
      String vnet =
          _dcDao.allocateVnet(
              zone.getId(),
              config.getPhysicalNetworkId(),
              config.getAccountId(),
              context.getReservationId());

      try {
        vlanTag = Integer.parseInt(vnet);
      } catch (NumberFormatException e) {
        throw new CloudRuntimeException(
            "Obtained an invalid guest vlan tag. Exception: " + e.getMessage());
      }

      implemented.setBroadcastUri(BroadcastDomainType.Vlan.toUri(vlanTag));
      ActionEventUtils.onCompletedActionEvent(
          UserContext.current().getCallerUserId(),
          config.getAccountId(),
          EventVO.LEVEL_INFO,
          EventTypes.EVENT_ZONE_VLAN_ASSIGN,
          "Assigned Zone Vlan: " + vnet + " Network Id: " + config.getId(),
          0);
    } else {
      vlanTag = Integer.parseInt(config.getBroadcastUri().getHost());
      implemented.setBroadcastUri(config.getBroadcastUri());
    }

    // Determine the new gateway and CIDR
    String[] oldCidr = config.getCidr().split("/");
    String oldCidrAddress = oldCidr[0];
    int cidrSize = Integer.parseInt(oldCidr[1]);
    long newCidrAddress = (NetUtils.ip2Long(oldCidrAddress));
    // if the implementing network is for vpc, no need to generate newcidr, use the cidr that came
    // from super cidr
    if (config.getVpcId() != null) {
      implemented.setGateway(config.getGateway());
      implemented.setCidr(config.getCidr());
      implemented.setState(State.Implemented);
    } else {
      // Determine the offset from the lowest vlan tag
      int offset = getVlanOffset(config.getPhysicalNetworkId(), vlanTag);
      cidrSize = getGloballyConfiguredCidrSize();
      // If the offset has more bits than there is room for, return null
      long bitsInOffset = 32 - Integer.numberOfLeadingZeros(offset);
      if (bitsInOffset > (cidrSize - 8)) {
        throw new CloudRuntimeException(
            "The offset "
                + offset
                + " needs "
                + bitsInOffset
                + " bits, but only have "
                + (cidrSize - 8)
                + " bits to work with.");
      }
      newCidrAddress =
          (NetUtils.ip2Long(oldCidrAddress) & 0xff000000) | (offset << (32 - cidrSize));
      implemented.setGateway(NetUtils.long2Ip(newCidrAddress + 1));
      implemented.setCidr(NetUtils.long2Ip(newCidrAddress) + "/" + cidrSize);
      implemented.setState(State.Implemented);
    }

    // Mask the Ipv4 address of all nics that use this network with the new guest VLAN offset
    List<NicVO> nicsInNetwork = _nicDao.listByNetworkId(config.getId());
    for (NicVO nic : nicsInNetwork) {
      if (nic.getIp4Address() != null) {
        long ipMask = getIpMask(nic.getIp4Address(), cidrSize);
        nic.setIp4Address(NetUtils.long2Ip(newCidrAddress | ipMask));
        _nicDao.persist(nic);
      }
    }

    // Mask the destination address of all port forwarding rules in this network with the new guest
    // VLAN offset
    List<PortForwardingRuleVO> pfRulesInNetwork = _pfRulesDao.listByNetwork(config.getId());
    for (PortForwardingRuleVO pfRule : pfRulesInNetwork) {
      if (pfRule.getDestinationIpAddress() != null) {
        long ipMask = getIpMask(pfRule.getDestinationIpAddress().addr(), cidrSize);
        String maskedDestinationIpAddress = NetUtils.long2Ip(newCidrAddress | ipMask);
        pfRule.setDestinationIpAddress(new Ip(maskedDestinationIpAddress));
        _pfRulesDao.update(pfRule.getId(), pfRule);
      }
    }

    return implemented;
  }
  @Override
  public Network implement(
      final Network network,
      final NetworkOffering offering,
      final DeployDestination dest,
      final ReservationContext context)
      throws InsufficientVirtualNetworkCapacityException {
    assert network.getState() == State.Implementing : "Why are we implementing " + network;

    final long dcId = dest.getDataCenter().getId();

    Long physicalNetworkId = network.getPhysicalNetworkId();

    // physical network id can be null in Guest Network in Basic zone, so locate the physical
    // network
    if (physicalNetworkId == null) {
      physicalNetworkId =
          networkModel.findPhysicalNetworkId(dcId, offering.getTags(), offering.getTrafficType());
    }

    final NetworkVO implemented =
        new NetworkVO(
            network.getTrafficType(),
            network.getMode(),
            network.getBroadcastDomainType(),
            network.getNetworkOfferingId(),
            State.Allocated,
            network.getDataCenterId(),
            physicalNetworkId,
            offering.getRedundantRouter());

    if (network.getGateway() != null) {
      implemented.setGateway(network.getGateway());
    }

    if (network.getCidr() != null) {
      implemented.setCidr(network.getCidr());
    }

    // Name is either the given name or the uuid
    String name = network.getName();
    if (name == null || name.isEmpty()) {
      name = ((NetworkVO) network).getUuid();
    }
    if (name.length() > MAX_NAME_LENGTH) {
      name = name.substring(0, MAX_NAME_LENGTH - 1);
    }

    final List<NiciraNvpDeviceVO> devices = niciraNvpDao.listByPhysicalNetwork(physicalNetworkId);
    if (devices.isEmpty()) {
      s_logger.error("No NiciraNvp Controller on physical network " + physicalNetworkId);
      return null;
    }
    final NiciraNvpDeviceVO niciraNvpDevice = devices.get(0);
    final HostVO niciraNvpHost = hostDao.findById(niciraNvpDevice.getHostId());
    hostDao.loadDetails(niciraNvpHost);
    final String transportzoneuuid = niciraNvpHost.getDetail("transportzoneuuid");
    final String transportzoneisotype = niciraNvpHost.getDetail("transportzoneisotype");

    final CreateLogicalSwitchCommand cmd =
        new CreateLogicalSwitchCommand(
            transportzoneuuid,
            transportzoneisotype,
            name,
            context.getDomain().getName() + "-" + context.getAccount().getAccountName());
    final CreateLogicalSwitchAnswer answer =
        (CreateLogicalSwitchAnswer) agentMgr.easySend(niciraNvpHost.getId(), cmd);

    if (answer == null || !answer.getResult()) {
      s_logger.error("CreateLogicalSwitchCommand failed");
      return null;
    }

    try {
      implemented.setBroadcastUri(new URI("lswitch", answer.getLogicalSwitchUuid(), null));
      implemented.setBroadcastDomainType(BroadcastDomainType.Lswitch);
      s_logger.info(
          "Implemented OK, network linked to  = " + implemented.getBroadcastUri().toString());
    } catch (final URISyntaxException e) {
      s_logger.error(
          "Unable to store logical switch id in broadcast uri, uuid = " + implemented.getUuid(), e);
      return null;
    }

    return implemented;
  }
  @Override
  public boolean finalizeVirtualMachineProfile(
      VirtualMachineProfile<DomainRouterVO> profile,
      DeployDestination dest,
      ReservationContext context) {
    DomainRouterVO elbVm = profile.getVirtualMachine();

    List<NicProfile> elbNics = profile.getNics();
    Long guestNtwkId = null;
    for (NicProfile routerNic : elbNics) {
      if (routerNic.getTrafficType() == TrafficType.Guest) {
        guestNtwkId = routerNic.getNetworkId();
        break;
      }
    }

    NetworkVO guestNetwork = _networkDao.findById(guestNtwkId);

    DataCenter dc = dest.getDataCenter();

    StringBuilder buf = profile.getBootArgsBuilder();
    buf.append(" template=domP type=" + _systemVmType);
    buf.append(" name=").append(profile.getHostName());
    NicProfile controlNic = null;
    String defaultDns1 = null;
    String defaultDns2 = null;

    for (NicProfile nic : profile.getNics()) {
      int deviceId = nic.getDeviceId();
      buf.append(" eth").append(deviceId).append("ip=").append(nic.getIp4Address());
      buf.append(" eth").append(deviceId).append("mask=").append(nic.getNetmask());
      if (nic.isDefaultNic()) {
        buf.append(" gateway=").append(nic.getGateway());
        defaultDns1 = nic.getDns1();
        defaultDns2 = nic.getDns2();
      }
      if (nic.getTrafficType() == TrafficType.Management) {
        buf.append(" localgw=").append(dest.getPod().getGateway());
      } else if (nic.getTrafficType() == TrafficType.Control) {
        //  control command is sent over management network in VMware
        if (dest.getHost().getHypervisorType() == HypervisorType.VMware) {
          if (s_logger.isInfoEnabled()) {
            s_logger.info(
                "Check if we need to add management server explicit route to ELB vm. pod cidr: "
                    + dest.getPod().getCidrAddress()
                    + "/"
                    + dest.getPod().getCidrSize()
                    + ", pod gateway: "
                    + dest.getPod().getGateway()
                    + ", management host: "
                    + _mgmtHost);
          }

          if (s_logger.isDebugEnabled()) {
            s_logger.debug("Added management server explicit route to ELB vm.");
          }
          // always add management explicit route, for basic networking setup
          buf.append(" mgmtcidr=").append(_mgmtCidr);
          buf.append(" localgw=").append(dest.getPod().getGateway());

          if (dc.getNetworkType() == NetworkType.Basic) {
            // ask elb vm to setup SSH on guest network
            buf.append(" sshonguest=true");
          }
        }

        controlNic = nic;
      }
    }
    String domain = guestNetwork.getNetworkDomain();
    if (domain != null) {
      buf.append(" domain=" + domain);
    }

    buf.append(" dns1=").append(defaultDns1);
    if (defaultDns2 != null) {
      buf.append(" dns2=").append(defaultDns2);
    }

    if (s_logger.isDebugEnabled()) {
      s_logger.debug("Boot Args for " + profile + ": " + buf.toString());
    }

    if (controlNic == null) {
      throw new CloudRuntimeException("Didn't start a control port");
    }

    return true;
  }
  public DomainRouterVO deployELBVm(
      Network guestNetwork, DeployDestination dest, Account owner, Map<Param, Object> params)
      throws ConcurrentOperationException, ResourceUnavailableException,
          InsufficientCapacityException {
    long dcId = dest.getDataCenter().getId();

    // lock guest network
    Long guestNetworkId = guestNetwork.getId();
    guestNetwork = _networkDao.acquireInLockTable(guestNetworkId);

    if (guestNetwork == null) {
      throw new ConcurrentOperationException("Unable to acquire network lock: " + guestNetworkId);
    }

    try {

      if (_networkModel.isNetworkSystem(guestNetwork)
          || guestNetwork.getGuestType() == Network.GuestType.Shared) {
        owner = _accountService.getSystemAccount();
      }

      if (s_logger.isDebugEnabled()) {
        s_logger.debug(
            "Starting a ELB vm for network configurations: " + guestNetwork + " in " + dest);
      }
      assert guestNetwork.getState() == Network.State.Implemented
              || guestNetwork.getState() == Network.State.Setup
              || guestNetwork.getState() == Network.State.Implementing
          : "Network is not yet fully implemented: " + guestNetwork;

      DataCenterDeployment plan = null;
      DomainRouterVO elbVm = null;

      plan = new DataCenterDeployment(dcId, dest.getPod().getId(), null, null, null, null);

      if (elbVm == null) {
        long id = _routerDao.getNextInSequence(Long.class, "id");
        if (s_logger.isDebugEnabled()) {
          s_logger.debug("Creating the ELB vm " + id);
        }

        List<? extends NetworkOffering> offerings =
            _networkModel.getSystemAccountNetworkOfferings(NetworkOffering.SystemControlNetwork);
        NetworkOffering controlOffering = offerings.get(0);
        NetworkVO controlConfig =
            _networkMgr.setupNetwork(_systemAcct, controlOffering, plan, null, null, false).get(0);

        List<Pair<NetworkVO, NicProfile>> networks = new ArrayList<Pair<NetworkVO, NicProfile>>(2);
        NicProfile guestNic = new NicProfile();
        guestNic.setDefaultNic(true);
        networks.add(new Pair<NetworkVO, NicProfile>(controlConfig, null));
        networks.add(new Pair<NetworkVO, NicProfile>((NetworkVO) guestNetwork, guestNic));

        VMTemplateVO template = _templateDao.findSystemVMTemplate(dcId);

        String typeString = "ElasticLoadBalancerVm";
        Long physicalNetworkId = _networkModel.getPhysicalNetworkId(guestNetwork);
        PhysicalNetworkServiceProvider provider =
            _physicalProviderDao.findByServiceProvider(physicalNetworkId, typeString);
        if (provider == null) {
          throw new CloudRuntimeException(
              "Cannot find service provider "
                  + typeString
                  + " in physical network "
                  + physicalNetworkId);
        }
        VirtualRouterProvider vrProvider =
            _vrProviderDao.findByNspIdAndType(
                provider.getId(), VirtualRouterProviderType.ElasticLoadBalancerVm);
        if (vrProvider == null) {
          throw new CloudRuntimeException(
              "Cannot find virtual router provider "
                  + typeString
                  + " as service provider "
                  + provider.getId());
        }

        elbVm =
            new DomainRouterVO(
                id,
                _elasticLbVmOffering.getId(),
                vrProvider.getId(),
                VirtualMachineName.getSystemVmName(id, _instance, _elbVmNamePrefix),
                template.getId(),
                template.getHypervisorType(),
                template.getGuestOSId(),
                owner.getDomainId(),
                owner.getId(),
                false,
                0,
                false,
                RedundantState.UNKNOWN,
                _elasticLbVmOffering.getOfferHA(),
                false,
                VirtualMachine.Type.ElasticLoadBalancerVm,
                null);
        elbVm.setRole(Role.LB);
        elbVm = _itMgr.allocate(elbVm, template, _elasticLbVmOffering, networks, plan, null, owner);
        // TODO: create usage stats
      }

      State state = elbVm.getState();
      if (state != State.Running) {
        elbVm =
            this.start(
                elbVm, _accountService.getSystemUser(), _accountService.getSystemAccount(), params);
      }

      return elbVm;
    } finally {
      _networkDao.releaseFromLockTable(guestNetworkId);
    }
  }
  @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;
    }
  }
  @DB
  protected void CheckAndCreateTunnel(VirtualMachine instance, DeployDestination dest) {
    if (!_isEnabled) {
      return;
    }

    if (instance.getType() != VirtualMachine.Type.User
        && instance.getType() != VirtualMachine.Type.DomainRouter) {
      return;
    }

    long hostId = dest.getHost().getId();
    long accountId = instance.getAccountId();
    List<UserVmVO> vms = _userVmDao.listByAccountId(accountId);
    List<DomainRouterVO> routers =
        _routerDao.findBy(accountId, instance.getDataCenterIdToDeployIn());
    List<VMInstanceVO> ins = new ArrayList<VMInstanceVO>();
    if (vms != null) {
      ins.addAll(vms);
    }
    if (routers.size() != 0) {
      ins.addAll(routers);
    }
    List<Pair<Long, Integer>> toHosts = new ArrayList<Pair<Long, Integer>>();
    List<Pair<Long, Integer>> fromHosts = new ArrayList<Pair<Long, Integer>>();
    int key;

    for (VMInstanceVO v : ins) {
      Long rh = v.getHostId();
      if (rh == null || rh.longValue() == hostId) {
        continue;
      }

      OvsTunnelAccountVO ta =
          _tunnelAccountDao.getByFromToAccount(hostId, rh.longValue(), accountId);
      if (ta == null) {
        key = getGreKey(hostId, rh.longValue(), accountId);
        if (key == -1) {
          s_logger.warn(
              String.format(
                  "Cannot get GRE key for from=%1$s to=%2$s accountId=%3$s, tunnel create failed",
                  hostId, rh.longValue(), accountId));
          continue;
        }

        Pair<Long, Integer> p = new Pair<Long, Integer>(rh, Integer.valueOf(key));
        if (!toHosts.contains(p)) {
          toHosts.add(p);
        }
      }

      ta = _tunnelAccountDao.getByFromToAccount(rh.longValue(), hostId, accountId);
      if (ta == null) {
        key = getGreKey(rh.longValue(), hostId, accountId);
        if (key == -1) {
          s_logger.warn(
              String.format(
                  "Cannot get GRE key for from=%1$s to=%2$s accountId=%3$s, tunnel create failed",
                  rh.longValue(), hostId, accountId));
          continue;
        }

        Pair<Long, Integer> p = new Pair<Long, Integer>(rh, Integer.valueOf(key));
        if (!fromHosts.contains(p)) {
          fromHosts.add(p);
        }
      }
    }

    try {
      String myIp = dest.getHost().getPrivateIpAddress();
      for (Pair<Long, Integer> i : toHosts) {
        HostVO rHost = _hostDao.findById(i.first());
        Commands cmds =
            new Commands(
                new OvsCreateTunnelCommand(
                    rHost.getPrivateIpAddress(),
                    i.second().toString(),
                    Long.valueOf(hostId),
                    i.first(),
                    accountId,
                    myIp));
        s_logger.debug("Ask host " + hostId + " to create gre tunnel to " + i.first());
        Answer[] answers = _agentMgr.send(hostId, cmds);
        handleCreateTunnelAnswer(answers);
      }

      for (Pair<Long, Integer> i : fromHosts) {
        HostVO rHost = _hostDao.findById(i.first());
        Commands cmd2s =
            new Commands(
                new OvsCreateTunnelCommand(
                    myIp,
                    i.second().toString(),
                    i.first(),
                    Long.valueOf(hostId),
                    accountId,
                    rHost.getPrivateIpAddress()));
        s_logger.debug("Ask host " + i.first() + " to create gre tunnel to " + hostId);
        Answer[] answers = _agentMgr.send(i.first(), cmd2s);
        handleCreateTunnelAnswer(answers);
      }
    } catch (Exception e) {
      s_logger.debug("Ovs Tunnel network created tunnel failed", e);
    }
  }
  @Override
  public boolean finalizeVirtualMachineProfile(
      VirtualMachineProfile<SecondaryStorageVmVO> profile,
      DeployDestination dest,
      ReservationContext context) {

    SecondaryStorageVmVO vm = profile.getVirtualMachine();
    Map<String, String> details = _vmDetailsDao.findDetails(vm.getId());
    vm.setDetails(details);

    HostVO secHost = _hostDao.findSecondaryStorageHost(dest.getDataCenter().getId());
    assert (secHost != null);

    StringBuilder buf = profile.getBootArgsBuilder();
    buf.append(" template=domP type=secstorage");
    buf.append(" host=").append(_mgmt_host);
    buf.append(" port=").append(_mgmt_port);
    buf.append(" name=").append(profile.getVirtualMachine().getHostName());

    buf.append(" zone=").append(dest.getDataCenter().getId());
    buf.append(" pod=").append(dest.getPod().getId());

    buf.append(" guid=").append(profile.getVirtualMachine().getHostName());

    if (_configDao.isPremium()) {
      if (profile.getHypervisorType() == HypervisorType.Hyperv) {
        buf.append(" resource=com.cloud.storage.resource.CifsSecondaryStorageResource");
      } else {
        buf.append(" resource=com.cloud.storage.resource.PremiumSecondaryStorageResource");
      }
    } else {
      buf.append(" resource=com.cloud.storage.resource.NfsSecondaryStorageResource");
    }
    buf.append(" instance=SecStorage");
    buf.append(" sslcopy=").append(Boolean.toString(_useSSlCopy));
    buf.append(" role=").append(profile.getVirtualMachine().getRole().toString());

    boolean externalDhcp = false;
    String externalDhcpStr =
        _configDao.getValue("direct.attach.network.externalIpAllocator.enabled");
    if (externalDhcpStr != null && externalDhcpStr.equalsIgnoreCase("true")) {
      externalDhcp = true;
    }

    for (NicProfile nic : profile.getNics()) {
      int deviceId = nic.getDeviceId();
      if (nic.getIp4Address() == null) {
        buf.append(" eth").append(deviceId).append("mask=").append("0.0.0.0");
        buf.append(" eth").append(deviceId).append("ip=").append("0.0.0.0");
      } else {
        buf.append(" eth").append(deviceId).append("ip=").append(nic.getIp4Address());
        buf.append(" eth").append(deviceId).append("mask=").append(nic.getNetmask());
      }

      buf.append(" eth").append(deviceId).append("mask=").append(nic.getNetmask());
      if (nic.isDefaultNic()) {
        buf.append(" gateway=").append(nic.getGateway());
      }
      if (nic.getTrafficType() == TrafficType.Management) {
        String mgmt_cidr = _configDao.getValue(Config.ManagementNetwork.key());
        if (NetUtils.isValidCIDR(mgmt_cidr)) {
          buf.append(" mgmtcidr=").append(mgmt_cidr);
        }
        buf.append(" localgw=").append(dest.getPod().getGateway());
        buf.append(" private.network.device=").append("eth").append(deviceId);
      } else if (nic.getTrafficType() == TrafficType.Public) {
        buf.append(" public.network.device=").append("eth").append(deviceId);
      }
    }

    /* External DHCP mode */
    if (externalDhcp) {
      buf.append(" bootproto=dhcp");
    }

    DataCenterVO dc = _dcDao.findById(profile.getVirtualMachine().getDataCenterIdToDeployIn());
    buf.append(" internaldns1=").append(dc.getInternalDns1());
    if (dc.getInternalDns2() != null) {
      buf.append(" internaldns2=").append(dc.getInternalDns2());
    }
    buf.append(" dns1=").append(dc.getDns1());
    if (dc.getDns2() != null) {
      buf.append(" dns2=").append(dc.getDns2());
    }

    String bootArgs = buf.toString();
    if (s_logger.isDebugEnabled()) {
      s_logger.debug("Boot Args for " + profile + ": " + bootArgs);
    }

    return true;
  }