private boolean canHandle(Network config) {
    DataCenter zone = _configMgr.getZone(config.getDataCenterId());
    if ((zone.getNetworkType() == NetworkType.Advanced
            && config.getGuestType() != Network.GuestType.Isolated)
        || (zone.getNetworkType() == NetworkType.Basic
            && config.getGuestType() != Network.GuestType.Shared)) {
      s_logger.trace("Not handling network type = " + config.getGuestType());
      return false;
    }

    return _networkManager.networkIsConfiguredForExternalNetworking(zone.getId(), config.getId());
  }
  @Override
  public boolean shutdown(Network network, ReservationContext context, boolean cleanup)
      throws ResourceUnavailableException, ConcurrentOperationException {
    DataCenter zone = _configMgr.getZone(network.getDataCenterId());

    // don't have to implement network is Basic zone
    if (zone.getNetworkType() == NetworkType.Basic) {
      s_logger.debug("Not handling network shutdown in zone of type " + NetworkType.Basic);
      return false;
    }

    if (!canHandle(network)) {
      return false;
    }
    try {
      return _externalNetworkManager.manageGuestNetworkWithExternalFirewall(false, network);
    } catch (InsufficientCapacityException capacityException) {
      // TODO: handle out of capacity exception
      return false;
    }
  }
Ejemplo n.º 3
0
  @DB
  @Override
  public void updateCapacityForHost(HostVO host) {
    // prepare the service offerings
    List<ServiceOfferingVO> offerings = _offeringsDao.listAllIncludingRemoved();
    Map<Long, ServiceOfferingVO> offeringsMap = new HashMap<Long, ServiceOfferingVO>();
    for (ServiceOfferingVO offering : offerings) {
      offeringsMap.put(offering.getId(), offering);
    }

    long usedCpu = 0;
    long usedMemory = 0;
    long reservedMemory = 0;
    long reservedCpu = 0;

    List<VMInstanceVO> vms = _vmDao.listUpByHostId(host.getId());
    if (s_logger.isDebugEnabled()) {
      s_logger.debug("Found " + vms.size() + " VMs on host " + host.getId());
    }

    for (VMInstanceVO vm : vms) {
      ServiceOffering so = offeringsMap.get(vm.getServiceOfferingId());
      usedMemory += so.getRamSize() * 1024L * 1024L;
      usedCpu += so.getCpu() * so.getSpeed();
    }

    List<VMInstanceVO> vmsByLastHostId = _vmDao.listByLastHostId(host.getId());
    if (s_logger.isDebugEnabled()) {
      s_logger.debug(
          "Found " + vmsByLastHostId.size() + " VM, not running on host " + host.getId());
    }
    for (VMInstanceVO vm : vmsByLastHostId) {
      long secondsSinceLastUpdate =
          (DateUtil.currentGMTTime().getTime() - vm.getUpdateTime().getTime()) / 1000;
      if (secondsSinceLastUpdate < _vmCapacityReleaseInterval) {
        ServiceOffering so = offeringsMap.get(vm.getServiceOfferingId());
        reservedMemory += so.getRamSize() * 1024L * 1024L;
        reservedCpu += so.getCpu() * so.getSpeed();
      }
    }

    CapacityVO cpuCap = _capacityDao.findByHostIdType(host.getId(), CapacityVO.CAPACITY_TYPE_CPU);
    CapacityVO memCap =
        _capacityDao.findByHostIdType(host.getId(), CapacityVO.CAPACITY_TYPE_MEMORY);

    if (cpuCap != null && memCap != null) {
      if (cpuCap.getUsedCapacity() == usedCpu && cpuCap.getReservedCapacity() == reservedCpu) {
        s_logger.debug(
            "No need to calibrate cpu capacity, host:"
                + host.getId()
                + " usedCpu: "
                + cpuCap.getUsedCapacity()
                + " reservedCpu: "
                + cpuCap.getReservedCapacity());
      } else if (cpuCap.getReservedCapacity() != reservedCpu) {
        s_logger.debug(
            "Calibrate reserved cpu for host: "
                + host.getId()
                + " old reservedCpu:"
                + cpuCap.getReservedCapacity()
                + " new reservedCpu:"
                + reservedCpu);
        cpuCap.setReservedCapacity(reservedCpu);
      } else if (cpuCap.getUsedCapacity() != usedCpu) {
        s_logger.debug(
            "Calibrate used cpu for host: "
                + host.getId()
                + " old usedCpu:"
                + cpuCap.getUsedCapacity()
                + " new usedCpu:"
                + usedCpu);
        cpuCap.setUsedCapacity(usedCpu);
      }

      if (memCap.getUsedCapacity() == usedMemory
          && memCap.getReservedCapacity() == reservedMemory) {
        s_logger.debug(
            "No need to calibrate memory capacity, host:"
                + host.getId()
                + " usedMem: "
                + memCap.getUsedCapacity()
                + " reservedMem: "
                + memCap.getReservedCapacity());
      } else if (memCap.getReservedCapacity() != reservedMemory) {
        s_logger.debug(
            "Calibrate reserved memory for host: "
                + host.getId()
                + " old reservedMem:"
                + memCap.getReservedCapacity()
                + " new reservedMem:"
                + reservedMemory);
        memCap.setReservedCapacity(reservedMemory);
      } else if (memCap.getUsedCapacity() != usedMemory) {
        /*
         * Didn't calibrate for used memory, because VMs can be in state(starting/migrating) that I don't know on which host they are
         * allocated
         */
        s_logger.debug(
            "Calibrate used memory for host: "
                + host.getId()
                + " old usedMem: "
                + memCap.getUsedCapacity()
                + " new usedMem: "
                + usedMemory);
        memCap.setUsedCapacity(usedMemory);
      }

      try {
        _capacityDao.update(cpuCap.getId(), cpuCap);
        _capacityDao.update(memCap.getId(), memCap);
      } catch (Exception e) {
        s_logger.error(
            "Caught exception while updating cpu/memory capacity for the host " + host.getId(), e);
      }
    } else {
      Transaction txn = Transaction.currentTxn();
      CapacityState capacityState =
          _configMgr.findClusterAllocationState(ApiDBUtils.findClusterById(host.getClusterId()))
                  == AllocationState.Disabled
              ? CapacityState.Disabled
              : CapacityState.Enabled;
      txn.start();
      CapacityVO capacity =
          new CapacityVO(
              host.getId(),
              host.getDataCenterId(),
              host.getPodId(),
              host.getClusterId(),
              usedMemory,
              host.getTotalMemory(),
              CapacityVO.CAPACITY_TYPE_MEMORY);
      capacity.setReservedCapacity(reservedMemory);
      capacity.setCapacityState(capacityState);
      _capacityDao.persist(capacity);

      capacity =
          new CapacityVO(
              host.getId(),
              host.getDataCenterId(),
              host.getPodId(),
              host.getClusterId(),
              usedCpu,
              (long) (host.getCpus().longValue() * host.getSpeed().longValue()),
              CapacityVO.CAPACITY_TYPE_CPU);
      capacity.setReservedCapacity(reservedCpu);
      capacity.setCapacityState(capacityState);
      _capacityDao.persist(capacity);
      txn.commit();
    }
  }
  @Override
  public boolean implement(
      Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context)
      throws ConcurrentOperationException, ResourceUnavailableException,
          InsufficientCapacityException {
    DataCenter zone = _configMgr.getZone(network.getDataCenterId());

    if (zone.getNetworkType() == NetworkType.Basic) {
      s_logger.debug("Not handling network implement in zone of type " + NetworkType.Basic);
      return false;
    }

    if (!canHandle(network)) {
      return false;
    }

    List<CiscoVnmcControllerVO> devices =
        _ciscoVnmcDao.listByPhysicalNetwork(network.getPhysicalNetworkId());
    if (devices.isEmpty()) {
      s_logger.error("No Cisco Vnmc device on network " + network.getName());
      return false;
    }

    List<CiscoAsa1000vDeviceVO> asaList =
        _ciscoAsa1000vDao.listByPhysicalNetwork(network.getPhysicalNetworkId());
    if (asaList.isEmpty()) {
      s_logger.debug("No Cisco ASA 1000v device on network " + network.getName());
      return false;
    }

    NetworkAsa1000vMapVO asaForNetwork = _networkAsa1000vMapDao.findByNetworkId(network.getId());
    if (asaForNetwork != null) {
      s_logger.debug("Cisco ASA 1000v device already associated with network " + network.getName());
      return true;
    }

    if (!_networkModel.isProviderSupportServiceInNetwork(
        network.getId(), Service.SourceNat, Provider.CiscoVnmc)) {
      s_logger.error(
          "SourceNat service is not provided by Cisco Vnmc device on network " + network.getName());
      return false;
    }

    Transaction txn = Transaction.currentTxn();
    boolean status = false;
    try {
      txn.start();

      // ensure that there is an ASA 1000v assigned to this network
      CiscoAsa1000vDevice assignedAsa = assignAsa1000vToNetwork(network);
      if (assignedAsa == null) {
        s_logger.error("Unable to assign ASA 1000v device to network " + network.getName());
        return false;
      }

      ClusterVO asaCluster = _clusterDao.findById(assignedAsa.getClusterId());
      ClusterVSMMapVO clusterVsmMap = _clusterVsmMapDao.findByClusterId(assignedAsa.getClusterId());
      if (clusterVsmMap == null) {
        s_logger.error(
            "Vmware cluster "
                + asaCluster.getName()
                + " has no Cisco Nexus VSM device associated with it");
        return false;
      }

      CiscoNexusVSMDeviceVO vsmDevice = _vsmDeviceDao.findById(clusterVsmMap.getVsmId());
      if (vsmDevice == null) {
        s_logger.error(
            "Unable to load details of Cisco Nexus VSM device associated with cluster "
                + asaCluster.getName());
        return false;
      }

      CiscoVnmcControllerVO ciscoVnmcDevice = devices.get(0);
      HostVO ciscoVnmcHost = _hostDao.findById(ciscoVnmcDevice.getHostId());
      _hostDao.loadDetails(ciscoVnmcHost);
      Account owner = context.getAccount();
      PublicIp sourceNatIp = _ipAddrMgr.assignSourceNatIpAddressToGuestNetwork(owner, network);
      String vlan = network.getBroadcastUri().getHost();
      long vlanId = Long.parseLong(vlan);

      List<VlanVO> vlanVOList =
          _vlanDao.listVlansByPhysicalNetworkId(network.getPhysicalNetworkId());
      List<String> publicGateways = new ArrayList<String>();
      for (VlanVO vlanVO : vlanVOList) {
        publicGateways.add(vlanVO.getVlanGateway());
      }

      // due to VNMC limitation of not allowing source NAT ip as the outside ip of firewall,
      // an additional public ip needs to acquired for assigning as firewall outside ip.
      // In case there are already additional ip addresses available (network restart) use one
      // of them such that it is not the source NAT ip
      IpAddress outsideIp = null;
      List<IPAddressVO> publicIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), null);
      for (IPAddressVO ip : publicIps) {
        if (!ip.isSourceNat()) {
          outsideIp = ip;
          break;
        }
      }
      if (outsideIp == null) { // none available, acquire one
        try {
          Account caller = CallContext.current().getCallingAccount();
          long callerUserId = CallContext.current().getCallingUserId();
          outsideIp = _ipAddrMgr.allocateIp(owner, false, caller, callerUserId, zone);
        } catch (ResourceAllocationException e) {
          s_logger.error("Unable to allocate additional public Ip address. Exception details " + e);
          return false;
        }

        try {
          outsideIp =
              _ipAddrMgr.associateIPToGuestNetwork(outsideIp.getId(), network.getId(), true);
        } catch (ResourceAllocationException e) {
          s_logger.error(
              "Unable to assign allocated additional public Ip "
                  + outsideIp.getAddress().addr()
                  + " to network with vlan "
                  + vlanId
                  + ". Exception details "
                  + e);
          return false;
        }
      }

      // create logical edge firewall in VNMC
      String gatewayNetmask = NetUtils.getCidrNetmask(network.getCidr());
      // due to ASA limitation of allowing single subnet to be assigned to firewall interfaces,
      // all public ip addresses must be from same subnet, this essentially means single public
      // subnet in zone
      if (!createLogicalEdgeFirewall(
          vlanId,
          network.getGateway(),
          gatewayNetmask,
          outsideIp.getAddress().addr(),
          sourceNatIp.getNetmask(),
          publicGateways,
          ciscoVnmcHost.getId())) {
        s_logger.error(
            "Failed to create logical edge firewall in Cisco VNMC device for network "
                + network.getName());
        return false;
      }

      // create stuff in VSM for ASA device
      if (!configureNexusVsmForAsa(
          vlanId,
          network.getGateway(),
          vsmDevice.getUserName(),
          vsmDevice.getPassword(),
          vsmDevice.getipaddr(),
          assignedAsa.getInPortProfile(),
          ciscoVnmcHost.getId())) {
        s_logger.error(
            "Failed to configure Cisco Nexus VSM "
                + vsmDevice.getipaddr()
                + " for ASA device for network "
                + network.getName());
        return false;
      }

      // configure source NAT
      if (!configureSourceNat(vlanId, network.getCidr(), sourceNatIp, ciscoVnmcHost.getId())) {
        s_logger.error(
            "Failed to configure source NAT in Cisco VNMC device for network " + network.getName());
        return false;
      }

      // associate Asa 1000v instance with logical edge firewall
      if (!associateAsaWithLogicalEdgeFirewall(
          vlanId, assignedAsa.getManagementIp(), ciscoVnmcHost.getId())) {
        s_logger.error(
            "Failed to associate Cisco ASA 1000v ("
                + assignedAsa.getManagementIp()
                + ") with logical edge firewall in VNMC for network "
                + network.getName());
        return false;
      }

      status = true;
      txn.commit();
    } finally {
      if (!status) {
        txn.rollback();
        // FIXME: also undo changes in VNMC, VSM if anything failed
      }
    }

    return true;
  }