示例#1
0
 @Override
 public boolean apply(Allocation allocInfo) throws MetadataException {
   if (allocInfo.getRequest().getKeyName() == null
       || "".equals(allocInfo.getRequest().getKeyName())) {
     if (ImageMetadata.Platform.windows.equals(
         allocInfo.getBootSet().getMachine().getPlatform())) {
       throw new InvalidMetadataException(
           "You must specify a keypair when running a windows vm: "
               + allocInfo.getRequest().getImageId());
     } else {
       allocInfo.setSshKeyPair(KeyPairs.noKey());
       return true;
     }
   }
   Context ctx = allocInfo.getContext();
   RunInstancesType request = allocInfo.getRequest();
   String keyName = request.getKeyName();
   SshKeyPair key = KeyPairs.lookup(ctx.getUserFullName().asAccountFullName(), keyName);
   if (!ctx.hasAdministrativePrivileges() && !RestrictedTypes.filterPrivileged().apply(key)) {
     throw new IllegalMetadataAccessException(
         "Not authorized to use keypair " + keyName + " by " + ctx.getUser().getName());
   }
   allocInfo.setSshKeyPair(key);
   return true;
 }
    @Override
    public void allocate(Allocation allocInfo) throws Exception {
      Partition reqPartition = allocInfo.getPartition();
      String zoneName = reqPartition.getName();
      String vmTypeName = allocInfo.getVmType().getName();

      /* Validate min and max amount */
      final int minAmount = allocInfo.getMinCount();
      final int maxAmount = allocInfo.getMaxCount();
      if (minAmount > maxAmount)
        throw new RuntimeException(
            "Maximum instance count must not be smaller than minimum instance count");

      /* Retrieve our context and list of clusters associated with this zone */
      List<Cluster> authorizedClusters = this.doPrivilegedLookup(zoneName, vmTypeName);

      int remaining = maxAmount;
      int allocated = 0;
      int available;

      LOG.info(
          "Found authorized clusters: "
              + Iterables.transform(authorizedClusters, HasName.GET_NAME));

      /* Do we have any VM available throughout our clusters? */
      if ((available = checkAvailability(vmTypeName, authorizedClusters)) < minAmount) {
        throw new NotEnoughResourcesException(
            "Not enough resources ("
                + available
                + " in "
                + zoneName
                + " < "
                + minAmount
                + "): vm instances.");
      } else {
        for (Cluster cluster : authorizedClusters) {
          if (remaining <= 0) {
            break;
          } else {
            ResourceState state = cluster.getNodeState();
            Partition partition = cluster.getConfiguration().lookupPartition();

            /* Has a partition been set if the AZ was not specified? */
            if (allocInfo.getPartition().equals(Partition.DEFAULT)) {
              /*
               * Ok, do we have enough slots in this partition to support our request? We should have at least
               * the minimum. The list is sorted in order of resource availability from the cluster with the most
               * available to the cluster with the least amount available. This is why we don't check against the
               * maxAmount value since its a best effort at this point. If we select the partition here and we
               * can't fit maxAmount, based on the sorting order, the next partition will not fit maxAmount anyway.
               */
              int zoneAvailable = checkZoneAvailability(vmTypeName, partition, authorizedClusters);
              if (zoneAvailable < minAmount) continue;

              /* Lets use this partition */
              allocInfo.setPartition(partition);
            } else if (!allocInfo.getPartition().equals(partition)) {
              /* We should only pick clusters that are part of the selected AZ */
              continue;
            }

            if (allocInfo.getBootSet().getMachine() instanceof BlockStorageImageInfo) {
              try {
                Topology.lookup(Storage.class, partition);
              } catch (Exception ex) {
                allocInfo.abort();
                allocInfo.setPartition(reqPartition);
                throw new NotEnoughResourcesException(
                    "Not enough resources: Cannot run EBS instances in partition w/o a storage controller: "
                        + ex.getMessage(),
                    ex);
              }
            }

            try {
              int tryAmount =
                  (remaining > state.getAvailability(vmTypeName).getAvailable())
                      ? state.getAvailability(vmTypeName).getAvailable()
                      : remaining;

              List<ResourceToken> tokens =
                  this.requestResourceToken(allocInfo, tryAmount, maxAmount);
              remaining -= tokens.size();
              allocated += tokens.size();
            } catch (Exception t) {
              LOG.error(t);
              Logs.extreme().error(t, t);

              allocInfo.abort();
              allocInfo.setPartition(reqPartition);

              /* if we still have some allocation remaining AND no more resources are available */
              if (((available = checkZoneAvailability(vmTypeName, partition, authorizedClusters))
                      < remaining)
                  && (remaining > 0)) {
                throw new NotEnoughResourcesException(
                    "Not enough resources ("
                        + available
                        + " in "
                        + zoneName
                        + " < "
                        + minAmount
                        + "): vm instances.",
                    t);
              } else {
                throw new NotEnoughResourcesException(t.getMessage(), t);
              }
            }
          }
        }

        /* Were we able to meet our minimum requirements? */
        if ((allocated < minAmount) && (remaining > 0)) {
          allocInfo.abort();
          allocInfo.setPartition(reqPartition);

          if (reqPartition.equals(Partition.DEFAULT)) {
            throw new NotEnoughResourcesException(
                "Not enough resources available in all zone for " + minAmount + "): vm instances.");
          } else {
            available = checkZoneAvailability(vmTypeName, reqPartition, authorizedClusters);
            throw new NotEnoughResourcesException(
                "Not enough resources ("
                    + available
                    + " in "
                    + zoneName
                    + " < "
                    + minAmount
                    + "): vm instances.");
          }
        }
      }
    }
示例#3
0
    @Override
    public boolean apply(Allocation allocInfo) throws MetadataException {

      BootableImageInfo imageInfo = allocInfo.getBootSet().getMachine();
      final ArrayList<BlockDeviceMappingItemType> instanceMappings =
          allocInfo.getRequest().getBlockDeviceMapping() != null
              ? allocInfo.getRequest().getBlockDeviceMapping()
              : new ArrayList<BlockDeviceMappingItemType>();
      List<DeviceMapping> imageMappings =
          new ArrayList<DeviceMapping>(((ImageInfo) imageInfo).getDeviceMappings());

      // Figure out the final set of mappings for this instance and add it to the request before
      // verifying the mappings.

      //    for ( DeviceMapping imageMapping : imageMappings ) {
      //  	if( !Iterables.any( instanceMappings, Images.findBlockDeviceMappingItempType(
      // imageMapping.getDeviceName() ) ) ) {
      //  	  instanceMappings.add(Images.DeviceMappingDetails.INSTANCE.apply(imageMapping));
      //  	}
      //    }

      // Is this an overkill?? Should I rather go with the above logic. Damn complexity seems
      // same...
      // probably m * n where m is the number of image mappings and n is the number of instance
      // mappings
      instanceMappings.addAll(
          Lists.transform(
              Lists.newArrayList(
                  Iterables.filter(
                      imageMappings,
                      new Predicate<DeviceMapping>() {
                        @Override
                        public boolean apply(DeviceMapping arg0) {
                          return !Iterables.any(
                              instanceMappings,
                              Images.findBlockDeviceMappingItempType(arg0.getDeviceName()));
                        }
                      })),
              Images.DeviceMappingDetails.INSTANCE));

      if (imageInfo instanceof BlockStorageImageInfo) { // bfebs image

        if (!instanceMappings.isEmpty()) {

          // Verify all block device mappings. Dont fuss if both snapshot id and volume size are
          // left blank
          Images.isDeviceMappingListValid(instanceMappings, Boolean.TRUE, Boolean.TRUE);

          BlockStorageImageInfo bfebsImage = (BlockStorageImageInfo) imageInfo;
          Integer imageSizeGB = (int) (bfebsImage.getImageSizeBytes() / BYTES_PER_GB);
          Integer userRequestedSizeGB = null;

          // Find the root block device mapping in the run instance request. Validate it
          BlockDeviceMappingItemType rootBlockDevice =
              Iterables.find(
                  instanceMappings,
                  Images.findEbsRootOptionalSnapshot(bfebsImage.getRootDeviceName()),
                  null);
          if (rootBlockDevice != null) {
            // Ensure that root device is not mapped to a different snapshot, logical device or
            // suppressed.
            // Verify that the root device size is not smaller than the image size
            if (StringUtils.isNotBlank(rootBlockDevice.getEbs().getSnapshotId())
                && !StringUtils.equals(
                    rootBlockDevice.getEbs().getSnapshotId(), bfebsImage.getSnapshotId())) {
              throw new InvalidMetadataException(
                  "Snapshot ID cannot be modified for the root device. "
                      + "Source snapshot from the image registration will be used for creating the root device");
            } else if (StringUtils.isNotBlank(rootBlockDevice.getVirtualName())) {
              throw new InvalidMetadataException(
                  "Logical type cannot be modified for the root device. "
                      + "Source snapshot from the image registration will be used for creating the root device");
            } else if (rootBlockDevice.getNoDevice() != null && rootBlockDevice.getNoDevice()) {
              throw new InvalidMetadataException(
                  "Root device cannot be suppressed. "
                      + "Source snapshot from the image registration will be used for creating the root device");
            } else if ((userRequestedSizeGB = rootBlockDevice.getEbs().getVolumeSize()) != null
                && userRequestedSizeGB < imageSizeGB) {
              throw new InvalidMetadataException(
                  "Root device volume cannot be smaller than the image size");
            }

            // Gather all the information for the root device mapping and populate it in the run
            // instance request
            if (rootBlockDevice.getEbs().getSnapshotId() == null) {
              rootBlockDevice.getEbs().setSnapshotId(bfebsImage.getSnapshotId());
            }
            if (rootBlockDevice.getEbs().getVolumeSize() == null) {
              rootBlockDevice.getEbs().setVolumeSize(imageSizeGB);
            }
            if (rootBlockDevice.getEbs().getDeleteOnTermination() == null) {
              rootBlockDevice.getEbs().setDeleteOnTermination(bfebsImage.getDeleteOnTerminate());
            }
          } else {
            // This should never happen. Root device mapping will always exist in the block storage
            // image and or run instance request
            throw new InvalidMetadataException("Root block device mapping not found\n");
          }
        }
      } else { // Instance store image
        // Verify all block device mappings. EBS mappings must be considered invalid since AWS
        // doesn't support it
        Images.isDeviceMappingListValid(instanceMappings, Boolean.TRUE, Boolean.FALSE);
      }

      // Set the final list of block device mappings in the run instance request (necessary if the
      // instance mappings were null). Checked with grze that its okay
      allocInfo.getRequest().setBlockDeviceMapping(instanceMappings);
      return true;
    }