@Override
    public void allocate(Allocation allocInfo) throws Exception {
      try {
        final VmInstanceLifecycleHelper helper = VmInstanceLifecycleHelpers.get();

        final PrepareNetworkResourcesType request = new PrepareNetworkResourcesType();
        request.setAvailabilityZone(allocInfo.getPartition().getName());
        request.setVpc(
            allocInfo.getSubnet() == null
                ? null
                : CloudMetadatas.toDisplayName().apply(allocInfo.getSubnet().getVpc()));
        request.setSubnet(CloudMetadatas.toDisplayName().apply(allocInfo.getSubnet()));
        request.setFeatures(Lists.<NetworkFeature>newArrayList(new DnsHostNamesFeature()));
        helper.prepareNetworkAllocation(allocInfo, request);
        final PrepareNetworkResourcesResultType result = Networking.getInstance().prepare(request);

        for (final ResourceToken token : allocInfo.getAllocationTokens()) {
          for (final NetworkResource networkResource : result.getResources()) {
            if (token.getInstanceId().equals(networkResource.getOwnerId())) {
              token
                  .getAttribute(NetworkResourceVmInstanceLifecycleHelper.NetworkResourcesKey)
                  .add(networkResource);
            }
          }
        }
      } catch (Exception e) {
        throw Objects.firstNonNull(Exceptions.findCause(e, NotEnoughResourcesException.class), e);
      }
    }
    @Override
    public boolean apply(Allocation allocInfo) throws MetadataException {
      Context ctx = allocInfo.getContext();
      NetworkGroups.lookup(
          ctx.getUserFullName().asAccountFullName(), NetworkGroups.defaultNetworkName());

      Set<String> networkNames = Sets.newHashSet(allocInfo.getRequest().getGroupSet());
      if (networkNames.isEmpty()) {
        networkNames.add(NetworkGroups.defaultNetworkName());
      }

      Map<String, NetworkGroup> networkRuleGroups = Maps.newHashMap();
      for (String groupName : networkNames) {
        NetworkGroup group =
            NetworkGroups.lookup(ctx.getUserFullName().asAccountFullName(), groupName);
        if (!ctx.hasAdministrativePrivileges()
            && !RestrictedTypes.filterPrivileged().apply(group)) {
          throw new IllegalMetadataAccessException(
              "Not authorized to use network group "
                  + groupName
                  + " for "
                  + ctx.getUser().getName());
        }
        networkRuleGroups.put(groupName, group);
      }
      Set<String> missingNets = Sets.difference(networkNames, networkRuleGroups.keySet());
      if (!missingNets.isEmpty()) {
        throw new NoSuchMetadataException("Failed to find security group info for: " + missingNets);
      } else {
        allocInfo.setNetworkRules(networkRuleGroups);
      }
      return true;
    }
 @SuppressWarnings("unchecked")
 @Override
 public void allocate(Allocation allocInfo) throws Exception {
   RestrictedTypes.allocateNamedUnitlessResources(
       allocInfo.getAllocationTokens().size(),
       allocInfo.getVmType().allocator(),
       (Predicate) Predicates.alwaysTrue());
 }
    @Override
    public boolean apply(Allocation allocInfo)
        throws MetadataException, AuthException, VerificationException {
      RunInstancesType msg = allocInfo.getRequest();
      String imageId = msg.getImageId();
      VmType vmType = allocInfo.getVmType();
      try {
        BootableSet bootSet = Emis.newBootableSet(imageId);
        allocInfo.setBootableSet(bootSet);

        // Add (1024L * 1024L * 10) to handle NTFS min requirements.
        if (!bootSet.isBlockStorage()) {
          if (Platform.windows.equals(bootSet.getMachine().getPlatform())
              && bootSet.getMachine().getImageSizeBytes()
                  > ((1024L * 1024L * 1024L * vmType.getDisk()) + (1024L * 1024L * 10))) {
            throw new ImageInstanceTypeVerificationException(
                "Unable to run instance "
                    + bootSet.getMachine().getDisplayName()
                    + " in which the size "
                    + bootSet.getMachine().getImageSizeBytes()
                    + " bytes of the instance is greater than the vmType "
                    + vmType.getDisplayName()
                    + " size "
                    + vmType.getDisk()
                    + " GB.");
          } else if (bootSet.getMachine().getImageSizeBytes()
              > ((1024L * 1024L * 1024L * vmType.getDisk()))) {
            throw new ImageInstanceTypeVerificationException(
                "Unable to run instance "
                    + bootSet.getMachine().getDisplayName()
                    + " in which the size "
                    + bootSet.getMachine().getImageSizeBytes()
                    + " bytes of the instance is greater than the vmType "
                    + vmType.getDisplayName()
                    + " size "
                    + vmType.getDisk()
                    + " GB.");
          }
        }
      } catch (VerificationException e) {
        throw e;
      } catch (MetadataException ex) {
        LOG.error(ex);
        throw ex;
      } catch (RuntimeException ex) {
        LOG.error(ex);
        throw new VerificationException(
            "Failed to verify references for request: "
                + msg.toSimpleString()
                + " because of: "
                + ex.getMessage(),
            ex);
      }
      return true;
    }
 @Override
 public boolean apply(Allocation allocInfo) throws MetadataException {
   Context ctx = allocInfo.getContext();
   User user = ctx.getUser();
   String instanceType = allocInfo.getRequest().getInstanceType();
   VmType vmType = VmTypes.lookup(instanceType);
   if (!ctx.hasAdministrativePrivileges() && !RestrictedTypes.filterPrivileged().apply(vmType)) {
     throw new IllegalMetadataAccessException(
         "Not authorized to allocate vm type " + instanceType + " for " + ctx.getUserFullName());
   }
   allocInfo.setVmType(vmType);
   return true;
 }
 @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 boolean apply(Allocation allocInfo) throws MetadataException {
   String instanceType = allocInfo.getRequest().getInstanceType();
   VmType vmType = VmTypes.lookup(instanceType);
   if (!RestrictedTypes.filterPrivileged().apply(vmType)) {
     throw new IllegalMetadataAccessException(
         "Not authorized to allocate vm type "
             + instanceType
             + " for "
             + allocInfo.getOwnerFullName());
   }
   allocInfo.setVmType(vmType);
   return true;
 }
 @Override
 public boolean apply(Allocation allocInfo) throws MetadataException {
   byte[] userData = allocInfo.getUserData();
   if (userData != null
       && userData.length > Integer.parseInt(VmInstances.USER_DATA_MAX_SIZE_KB) * 1024) {
     throw new InvalidMetadataException(
         "User data may not exceed " + VmInstances.USER_DATA_MAX_SIZE_KB + " KB");
   }
   return true;
 }
 @Override
 public boolean apply(Allocation allocInfo) throws MetadataException {
   RunInstancesType request = allocInfo.getRequest();
   String zoneName = request.getAvailabilityZone();
   if (Clusters.getInstance().listValues().isEmpty()) {
     LOG.debug("enabled values: " + Joiner.on("\n").join(Clusters.getInstance().listValues()));
     LOG.debug("disabled values: " + Joiner.on("\n").join(Clusters.getInstance().listValues()));
     throw new VerificationException(
         "Not enough resources: no cluster controller is currently available to run instances.");
   } else if (Partitions.exists(zoneName)) {
     Partition partition = Partitions.lookupByName(zoneName);
     allocInfo.setPartition(partition);
   } else if (Partition.DEFAULT_NAME.equals(zoneName)) {
     Partition partition = Partition.DEFAULT;
     allocInfo.setPartition(partition);
   } else {
     throw new VerificationException(
         "Not enough resources: no cluster controller is currently available to run instances.");
   }
   return true;
 }
Example #10
0
 @Override
 public boolean apply(Allocation allocInfo) throws MetadataException {
   if (allocInfo.getRequest().getKeyName() == null
       || "".equals(allocInfo.getRequest().getKeyName())) {
     allocInfo.setSshKeyPair(KeyPairs.noKey());
     return true;
   }
   UserFullName ownerFullName = allocInfo.getOwnerFullName();
   RunInstancesType request = allocInfo.getRequest();
   String keyName = request.getKeyName();
   SshKeyPair key = KeyPairs.lookup(ownerFullName.asAccountFullName(), keyName);
   if (!RestrictedTypes.filterPrivileged().apply(key)) {
     throw new IllegalMetadataAccessException(
         "Not authorized to use keypair " + keyName + " by " + ownerFullName.getUserName());
   }
   allocInfo.setSshKeyPair(key);
   return true;
 }
 @Override
 public void fail(Allocation allocInfo, Throwable t) {
   allocInfo.abort();
 }
    @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.");
          }
        }
      }
    }
    private List<ResourceToken> requestResourceToken(
        final Allocation allocInfo, final int tryAmount, final int maxAmount) throws Exception {
      ServiceConfiguration config =
          Topology.lookup(ClusterController.class, allocInfo.getPartition());
      Cluster cluster = Clusters.lookup(config);
      /**
       * TODO:GRZE: this is the call path which needs to trigger gating.
       * It shouldn't be handled directly here, but instead be handled in {@link ResourceState#requestResourceAllocation().
       *
       */
      if (cluster.getGateLock().readLock().tryLock(60, TimeUnit.SECONDS)) {
        try {
          final ResourceState state = cluster.getNodeState();
          /**
           * NOTE: If the defined instance type has an ordering conflict w/ some other type then it
           * isn't safe to service TWO requests which use differing types during the same resource
           * refresh duty cycle. This determines whether or not an asynchronous allocation is safe
           * to do for the request instance type or whether a synchronous resource availability
           * refresh is needed.
           */
          boolean unorderedType = VmTypes.isUnorderedType(allocInfo.getVmType());
          boolean forceResourceRefresh = state.hasUnorderedTokens() || unorderedType;
          /**
           * GRZE: if the vm type is not "nicely" ordered then we force a refresh of the actual
           * cluster state. Note: we already hold the cluster gating lock here so this update will
           * be mutual exclusive wrt both resource allocations and cluster state updates.
           */
          if (forceResourceRefresh) {
            cluster.refreshResources();
          }
          final List<ResourceToken> tokens =
              state.requestResourceAllocation(allocInfo, tryAmount, maxAmount);
          final Iterator<ResourceToken> tokenIterator = tokens.iterator();
          try {
            final Supplier<ResourceToken> allocator =
                new Supplier<ResourceToken>() {
                  @Override
                  public ResourceToken get() {
                    final ResourceToken ret = tokenIterator.next();
                    allocInfo.getAllocationTokens().add(ret);
                    return ret;
                  }
                };

            RestrictedTypes.allocateUnitlessResources(tokens.size(), allocator);
          } finally {
            // release any tokens that were not allocated
            Iterators.all(
                tokenIterator,
                new Predicate<ResourceToken>() {
                  @Override
                  public boolean apply(final ResourceToken resourceToken) {
                    state.releaseToken(resourceToken);
                    return true;
                  }
                });
          }
          return allocInfo.getAllocationTokens();
        } finally {
          cluster.getGateLock().readLock().unlock();
        }
      } else {
        throw new ServiceStateException(
            "Failed to allocate resources in the zone "
                + cluster.getPartition()
                + ", it is currently locked for maintenance.");
      }
    }
Example #14
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;
    }
Example #15
0
    @Override
    public boolean apply(final Allocation allocInfo) throws MetadataException {
      final UserFullName ownerFullName = allocInfo.getOwnerFullName();
      final String instanceProfileArn = allocInfo.getRequest().getIamInstanceProfileArn();
      final String instanceProfileName = allocInfo.getRequest().getIamInstanceProfileName();
      if (!Strings.isNullOrEmpty(instanceProfileArn)
          || !Strings.isNullOrEmpty(instanceProfileName)) {

        final String profileAccount;
        final String profileName;
        if (!Strings.isNullOrEmpty(instanceProfileArn))
          try {
            final Ern name = Ern.parse(instanceProfileArn);
            if (!(name instanceof EuareResourceName)) {
              throw new InvalidInstanceProfileMetadataException(
                  "Invalid IAM instance profile ARN: " + instanceProfileArn);
            }
            profileAccount = name.getAccount();
            profileName = ((EuareResourceName) name).getName();

          } catch (JSONException e) {
            throw new InvalidInstanceProfileMetadataException(
                "Invalid IAM instance profile ARN: " + instanceProfileArn, e);
          }
        else {
          profileAccount = ownerFullName.getAccountNumber();
          profileName = instanceProfileName;
        }

        final InstanceProfile profile;
        try {
          profile = Accounts.lookupInstanceProfileByName(profileAccount, profileName);
        } catch (AuthException e) {
          throw new InvalidInstanceProfileMetadataException(
              "Invalid IAM instance profile: " + profileAccount + "/" + profileName, e);
        }

        if (!Strings.isNullOrEmpty(instanceProfileName)
            && !instanceProfileName.equals(profile.getName())) {
          throw new InvalidInstanceProfileMetadataException(
              String.format(
                  "Invalid IAM instance profile name '%s' for ARN: %s",
                  profileName, instanceProfileArn));
        }

        try {
          final AuthContextSupplier user = allocInfo.getAuthContext();
          if (!Permissions.isAuthorized(
              PolicySpec.VENDOR_IAM,
              PolicySpec.IAM_RESOURCE_INSTANCE_PROFILE,
              Accounts.getInstanceProfileFullName(profile),
              AccountFullName.getInstance(profile.getAccountNumber()),
              PolicySpec.IAM_LISTINSTANCEPROFILES,
              user)) {
            throw new IllegalMetadataAccessException(
                String.format(
                    "Not authorized to access instance profile with ARN %s for %s",
                    profile.getInstanceProfileArn(), ownerFullName));
          }

          final Role role = profile.getRole();
          if (role != null
              && !Permissions.isAuthorized(
                  PolicySpec.VENDOR_IAM,
                  PolicySpec.IAM_RESOURCE_ROLE,
                  Accounts.getRoleFullName(role),
                  AccountFullName.getInstance(role.getAccountNumber()),
                  PolicySpec.IAM_PASSROLE,
                  user)) {
            throw new IllegalMetadataAccessException(
                String.format(
                    "Not authorized to pass role with ARN %s for %s",
                    role.getRoleArn(), ownerFullName));
          }

          if (role != null) {
            allocInfo.setInstanceProfileArn(profile.getInstanceProfileArn());
            allocInfo.setIamInstanceProfileId(profile.getInstanceProfileId());
            allocInfo.setIamRoleArn(role.getRoleArn());
          } else {
            throw new InvalidInstanceProfileMetadataException(
                "Role not found for IAM instance profile ARN: " + profile.getInstanceProfileArn());
          }
        } catch (AuthException e) {
          throw new MetadataException("IAM instance profile error", e);
        }
      }
      return true;
    }