@Override
  public Network design(
      NetworkOffering offering, DeploymentPlan plan, Network network, Account owner) {
    if (offering.getTrafficType() != TrafficType.Public
        || (offering.getGuestIpType() != null
            && offering.getGuestIpType() != GuestIpType.Virtual)) {
      s_logger.trace("We only take care of Public Virtual Network");
      return null;
    }

    if (offering.getTrafficType() == TrafficType.Public) {
      NetworkVO ntwk =
          new NetworkVO(
              offering.getTrafficType(),
              offering.getGuestIpType(),
              Mode.Static,
              BroadcastDomainType.Vlan,
              offering.getId(),
              plan.getDataCenterId());
      DataCenterVO dc = _dcDao.findById(plan.getDataCenterId());
      ntwk.setDns1(dc.getDns1());
      ntwk.setDns2(dc.getDns2());
      return ntwk;
    } else {
      return null;
    }
  }
  @Override
  public Network design(
      NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) {
    DataCenter dc = _dcDao.findById(plan.getDataCenterId());

    if (!canHandle(offering, dc)) {
      return null;
    }

    State state = State.Allocated;
    if (dc.getNetworkType() == NetworkType.Basic) {
      state = State.Setup;
    }

    NetworkVO config =
        new NetworkVO(
            offering.getTrafficType(),
            Mode.Dhcp,
            BroadcastDomainType.Vlan,
            offering.getId(),
            state,
            plan.getDataCenterId(),
            plan.getPhysicalNetworkId());

    if (userSpecified != null) {
      if ((userSpecified.getCidr() == null && userSpecified.getGateway() != null)
          || (userSpecified.getCidr() != null && userSpecified.getGateway() == null)) {
        throw new InvalidParameterValueException("cidr and gateway must be specified together.");
      }

      if (userSpecified.getCidr() != null) {
        config.setCidr(userSpecified.getCidr());
        config.setGateway(userSpecified.getGateway());
      }

      if (userSpecified.getBroadcastUri() != null) {
        config.setBroadcastUri(userSpecified.getBroadcastUri());
        config.setState(State.Setup);
      }

      if (userSpecified.getBroadcastDomainType() != null) {
        config.setBroadcastDomainType(userSpecified.getBroadcastDomainType());
      }
    }

    boolean isSecurityGroupEnabled =
        _networkMgr.areServicesSupportedByNetworkOffering(offering.getId(), Service.SecurityGroup);
    if (isSecurityGroupEnabled) {
      config.setName("SecurityGroupEnabledNetwork");
      config.setDisplayText("SecurityGroupEnabledNetwork");
    }

    return config;
  }
  @Override
  public Network design(
      final NetworkOffering offering,
      final DeploymentPlan plan,
      final Network userSpecified,
      final Account owner) {
    // Check of the isolation type of the related physical network is supported
    final PhysicalNetworkVO physnet = physicalNetworkDao.findById(plan.getPhysicalNetworkId());
    final DataCenter dc = _dcDao.findById(plan.getDataCenterId());
    if (!canHandle(offering, dc.getNetworkType(), physnet)) {
      s_logger.debug("Refusing to design this network");
      return null;
    }

    final List<NiciraNvpDeviceVO> devices = niciraNvpDao.listByPhysicalNetwork(physnet.getId());
    if (devices.isEmpty()) {
      s_logger.error("No NiciraNvp Controller on physical network " + physnet.getName());
      return null;
    }
    s_logger.debug(
        "Nicira Nvp " + devices.get(0).getUuid() + " found on physical network " + physnet.getId());

    s_logger.debug(
        "Physical isolation type is supported, asking GuestNetworkGuru to design this network");
    final NetworkVO networkObject = (NetworkVO) super.design(offering, plan, userSpecified, owner);
    if (networkObject == null) {
      return null;
    }
    networkObject.setBroadcastDomainType(BroadcastDomainType.Lswitch);

    return networkObject;
  }
  @Override
  public List<StoragePool> allocateToPool(
      DiskProfile dskCh,
      VirtualMachineProfile vmProfile,
      DeploymentPlan plan,
      ExcludeList avoid,
      int returnUpTo) {
    DataCenterVO dc = _dcDao.findById(plan.getDataCenterId());
    if (!dc.isLocalStorageEnabled()) {
      return null;
    }

    return super.allocateToPool(dskCh, vmProfile, plan, avoid, returnUpTo);
  }
  @Override
  public Network design(
      NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) {

    PhysicalNetworkVO physnet = _physicalNetworkDao.findById(plan.getPhysicalNetworkId());
    DataCenter dc = _dcDao.findById(plan.getDataCenterId());
    if (!canHandle(offering, dc.getNetworkType(), physnet)) {
      s_logger.debug("Refusing to design this network");
      return null;
    }
    NetworkVO config = (NetworkVO) super.design(offering, plan, userSpecified, owner);
    if (config == null) {
      return null;
    }

    config.setBroadcastDomainType(BroadcastDomainType.Vswitch);

    return config;
  }
  @Override
  public Network design(
      NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) {

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

    NetworkVO config = (NetworkVO) super.design(offering, plan, userSpecified, owner);
    if (config == null) {
      return null;
    } else if (_networkModel.networkIsConfiguredForExternalNetworking(
        plan.getDataCenterId(), config.getId())) {
      /* In order to revert userSpecified network setup */
      config.setState(State.Allocated);
    }

    return config;
  }
  @Override
  public Network design(
      NetworkOffering offering, DeploymentPlan plan, Network specifiedConfig, Account owner) {
    if (offering.getTrafficType() != TrafficType.Control) {
      return null;
    }

    NetworkVO config =
        new NetworkVO(
            offering.getTrafficType(),
            offering.getGuestIpType(),
            Mode.Static,
            BroadcastDomainType.LinkLocal,
            offering.getId(),
            plan.getDataCenterId());
    config.setCidr(_cidr);
    config.setGateway(_gateway);

    return config;
  }
  @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
  protected List<StoragePool> select(
      DiskProfile dskCh,
      VirtualMachineProfile vmProfile,
      DeploymentPlan plan,
      ExcludeList avoid,
      int returnUpTo) {

    List<StoragePool> suitablePools = new ArrayList<StoragePool>();

    s_logger.debug("LocalStoragePoolAllocator trying to find storage pool to fit the vm");

    if (!dskCh.useLocalStorage()) {
      return suitablePools;
    }

    // data disk and host identified from deploying vm (attach volume case)
    if (dskCh.getType() == Volume.Type.DATADISK && plan.getHostId() != null) {
      List<StoragePoolHostVO> hostPools = _poolHostDao.listByHostId(plan.getHostId());
      for (StoragePoolHostVO hostPool : hostPools) {
        StoragePoolVO pool = _storagePoolDao.findById(hostPool.getPoolId());
        if (pool != null && pool.isLocal()) {
          StoragePool pol = (StoragePool) this.dataStoreMgr.getPrimaryDataStore(pool.getId());
          if (filter(avoid, pol, dskCh, plan)) {
            s_logger.debug(
                "Found suitable local storage pool " + pool.getId() + ", adding to list");
            suitablePools.add(pol);
          } else {
            avoid.addPool(pool.getId());
          }
        }

        if (suitablePools.size() == returnUpTo) {
          break;
        }
      }
    } else {
      if (plan.getPodId() == null) {
        // zone wide primary storage deployment
        return null;
      }
      List<StoragePoolVO> availablePools =
          _storagePoolDao.findLocalStoragePoolsByTags(
              plan.getDataCenterId(), plan.getPodId(), plan.getClusterId(), dskCh.getTags());
      for (StoragePoolVO pool : availablePools) {
        if (suitablePools.size() == returnUpTo) {
          break;
        }
        StoragePool pol = (StoragePool) this.dataStoreMgr.getPrimaryDataStore(pool.getId());
        if (filter(avoid, pol, dskCh, plan)) {
          suitablePools.add(pol);
        } else {
          avoid.addPool(pool.getId());
        }
      }

      // add remaining pools in cluster, that did not match tags, to avoid
      // set
      List<StoragePoolVO> allPools =
          _storagePoolDao.findLocalStoragePoolsByTags(
              plan.getDataCenterId(), plan.getPodId(), plan.getClusterId(), null);
      allPools.removeAll(availablePools);
      for (StoragePoolVO pool : allPools) {
        avoid.addPool(pool.getId());
      }
    }

    if (s_logger.isDebugEnabled()) {
      s_logger.debug(
          "LocalStoragePoolAllocator returning "
              + suitablePools.size()
              + " suitable storage pools");
    }

    return suitablePools;
  }