public Map<String, LaunchConfiguration> describeLaunchConfigs(List<String> launchConfigNames) { if (launchConfigNames.isEmpty()) throw new Error("launchConfigNames must not be empty"); logger.info("describe launch configs, names={}", launchConfigNames); Map<String, LaunchConfiguration> results = Maps.newHashMap(); autoScaling.describeLaunchConfigurations(new DescribeLaunchConfigurationsRequest() .withLaunchConfigurationNames(launchConfigNames)) .getLaunchConfigurations() .forEach(config -> results.put(config.getLaunchConfigurationName(), config)); if (results.size() != launchConfigNames.size()) throw Exceptions.error("some launch config does not exist, foundNames={}", results.keySet()); return results; }
@Override public List<Machine> startMachines(int count) throws StartMachinesException { checkState(isConfigured(), "attempt to use unconfigured driver"); try { // We simply set the desired size of the scaling group without // waiting for the request to be fulfilled, simply because there is // no bulletproof method of knowing when this particular desired // size request has taken effect. Waiting for the group size to // reach the desired size is problematic, since the desired size may // be set to some other value while we are waiting. AutoScalingGroup group = this.client.getAutoScalingGroup(scalingGroupName()); LaunchConfiguration launchConfig = this.client.getLaunchConfiguration(group.getLaunchConfigurationName()); int newDesiredSize = group.getDesiredCapacity() + count; LOG.info("starting {} new instance(s) in scaling group '{}': " + "changing desired capacity from {} to {}", count, scalingGroupName(), group.getDesiredCapacity(), newDesiredSize); this.client.setDesiredSize(scalingGroupName(), newDesiredSize); return pseudoMachines(count, launchConfig); } catch (Exception e) { List<Machine> empty = Collections.emptyList(); throw new StartMachinesException(count, empty, e); } }
public AwsLaunchConfiguration transform(LaunchConfiguration configuration) { AwsLaunchConfiguration awsLaunchConfiguration = new AwsLaunchConfiguration(); awsLaunchConfiguration.setKeyName(configuration.getKeyName()); awsLaunchConfiguration.setImageId(configuration.getImageId()); awsLaunchConfiguration.setInstanceType(configuration.getInstanceType()); awsLaunchConfiguration.setAssociatePublicIpAddress(configuration.getAssociatePublicIpAddress()); awsLaunchConfiguration.setBlockDeviceMappings(configuration.getBlockDeviceMappings()); awsLaunchConfiguration.setCreatedTime(configuration.getCreatedTime()); awsLaunchConfiguration.setEbsOptimized(configuration.getEbsOptimized()); awsLaunchConfiguration.setIamInstanceProfile(configuration.getIamInstanceProfile()); awsLaunchConfiguration.setKernelId(configuration.getKernelId()); awsLaunchConfiguration.setLaunchConfigurationName(configuration.getLaunchConfigurationName()); awsLaunchConfiguration.setLaunchConfigurationARN(configuration.getLaunchConfigurationARN()); awsLaunchConfiguration.setSecurityGroups(configuration.getSecurityGroups()); awsLaunchConfiguration.setUserData(configuration.getUserData()); awsLaunchConfiguration.setRamdiskId(configuration.getRamdiskId()); awsLaunchConfiguration.setInstanceMonitoring(configuration.getInstanceMonitoring().getEnabled()); awsLaunchConfiguration.setSpotPrice(configuration.getSpotPrice()); awsLaunchConfiguration.setAssociatePublicIpAddress(configuration.getAssociatePublicIpAddress()); return awsLaunchConfiguration; }
public LaunchConfiguration createLaunchConfig(CreateLaunchConfigurationRequest request) throws Exception { return new Runner<LaunchConfiguration>() .retryInterval(Duration.ofSeconds(5)) .maxAttempts(3) .retryOn(e -> e instanceof AmazonServiceException) .run(() -> { logger.info("create launch config, request={}", request); autoScaling.createLaunchConfiguration(request); return describeLaunchConfig(request.getLaunchConfigurationName()); }); }
public void load() { String prefix = env.name + "-"; // find all AS group with prefix List<AutoScalingGroup> asGroups = AWS.as.listASGroups().stream() .filter(group -> group.getAutoScalingGroupName().startsWith(prefix)) .collect(Collectors.toList()); if (asGroups.isEmpty()) return; // load remote launch config in one request to maximize the speed List<String> launchConfigNames = asGroups.stream().map(AutoScalingGroup::getLaunchConfigurationName).collect(Collectors.toList()); Map<String, LaunchConfiguration> configs = AWS.as.describeLaunchConfigs(launchConfigNames); for (AutoScalingGroup remoteASGroup : asGroups) { String asGroupName = remoteASGroup.getAutoScalingGroupName(); String asGroupId = asGroupName.substring(prefix.length()); ASGroup asGroup = resources.find(ASGroup.class, asGroupId) .orElseGet(() -> resources.add(new ASGroup(asGroupId))); asGroup.remoteASGroup = remoteASGroup; asGroup.launchConfig.remoteLaunchConfig = configs.get(remoteASGroup.getLaunchConfigurationName()); asGroup.foundInRemote(); List<ScalingPolicy> remotePolicies = AWS.as.describeScalingPolicies(asGroupName); for (ScalingPolicy remotePolicy : remotePolicies) { String policyId = remotePolicy.getPolicyName(); AutoScalingPolicy policy = resources.find(AutoScalingPolicy.class, policyId) .orElseGet(() -> resources.add(new AutoScalingPolicy(policyId))); policy.remotePolicy = remotePolicy; policy.foundInRemote(); } } }
@Override public LaunchConfiguration call() { DescribeLaunchConfigurationsRequest request = new DescribeLaunchConfigurationsRequest() .withLaunchConfigurationNames(this.launchConfigurationName); DescribeLaunchConfigurationsResult result = getClient().getApi().describeLaunchConfigurations(request); List<LaunchConfiguration> launchConfigurations = result.getLaunchConfigurations(); if (launchConfigurations.isEmpty()) { throw new IllegalArgumentException(format("Launch Configuration '%s' doesn't exist in region '%s'.", this.launchConfigurationName, getClient().getRegion())); } return getOnlyElement(launchConfigurations); }
/** * Returns the machine instances in the Auto Scaling Group pool. * <p/> * For the case where {@code desiredCapacity} is greater than the number of * started instances, we produce a number of placeholder {@link Machine}s * (in {@code REQUESTED} state) for requested, but not yet acquired, * instances in an Auto Scaling Group. The number of produced placeholder * instances is the the difference between {@code desiredCapacity} and * {@code actualCapacity}. * <p/> * Rationale: the desired capacity of the AWS Auto Scaling Group may differ * from the actual number of instances in the group. If the desiredCapacity * of the Auto Scaling Group is greater than the actual number of instances * in the group, we should return placeholder Machines in {@code REQUESTED} * state for the missing instances. This prevents the {@link BaseCloudPool} * from regarding the scaling group too small and ordering new machines via * startMachines. * * @see com.elastisys.scale.cloudpool.commons.basepool.driver.CloudPoolDriver#listMachines() */ @Override public List<Machine> listMachines() throws CloudPoolDriverException { checkState(isConfigured(), "attempt to use unconfigured driver"); try { AutoScalingGroup group = this.client.getAutoScalingGroup(scalingGroupName()); int desiredCapacity = group.getDesiredCapacity(); // fetch actual scaling group members List<Instance> groupInstances = this.client.getAutoScalingGroupMembers(scalingGroupName()); List<Machine> acquiredMachines = groupInstances.stream().map(new InstanceToMachine()) .collect(Collectors.toList()); int actualCapacity = acquiredMachines.size(); // requested, but not yet allocated, machines int missingInstances = Math.max(desiredCapacity - actualCapacity, 0); LaunchConfiguration launchConfig = this.client.getLaunchConfiguration(group.getLaunchConfigurationName()); List<Machine> requestedInstances = pseudoMachines(missingInstances, launchConfig); List<Machine> pool = new ArrayList<>(); pool.addAll(acquiredMachines); pool.addAll(requestedInstances); return pool; } catch (Exception e) { throw new CloudPoolDriverException( format("failed to retrieve machines in cloud pool \"%s\", Auto Scaling Group \"%s\": %s", getPoolName(), scalingGroupName(), e.getMessage()), e); } }
public static AutoScalingGroup group(String name, LaunchConfiguration launchConfig, int desiredCapacity, Collection<com.amazonaws.services.ec2.model.Instance> ec2Instances) { AutoScalingGroup autoScalingGroup = new AutoScalingGroup().withAutoScalingGroupName(name) .withLaunchConfigurationName(launchConfig.getLaunchConfigurationName()) .withDesiredCapacity(desiredCapacity).withInstances(toAsInstances(ec2Instances)); return autoScalingGroup; }
/** * Creates a new {@link FakeAutoScalingClient} where the collection of Auto * Scaling Group members may differ from the total set of instances in the * cloud account. * * @param autoScalingGroupName * @param launchConfig * @param desiredCapacity * @param groupMmembers * @param nonGroupMembers */ public FakeAutoScalingClient(String autoScalingGroupName, LaunchConfiguration launchConfig, int desiredCapacity, List<Instance> groupMmembers, List<Instance> nonGroupMembers) { this.autoScalingGroupName = autoScalingGroupName; this.launchConfig = launchConfig; this.desiredCapacity = desiredCapacity; this.memberInstances = new ArrayList<>(groupMmembers); this.allInstances = new ArrayList<>(nonGroupMembers); this.allInstances.addAll(groupMmembers); this.idSequencer = this.allInstances.size(); }
/** * Sets up a fake {@link AutoScalingClient} with a fake pool containing both * instances that are members of the Auto Scaling Group and instances that * are not members. * * @param autoScalingGroupName * @param launchConfig * @param desiredCapacity * @param memberInstances * Auto Scaling Group members. * @param nonMemberInstances * EC2 instances that exist in the (fake) cloud but aren't * members of the Auto Scaling Group. */ private void setUpMockedAutoScalingGroup(String autoScalingGroupName, LaunchConfiguration launchConfig, int desiredCapacity, List<Instance> memberInstances, List<Instance> nonMemberInstances) { AutoScalingGroup autoScalingGroup = group(autoScalingGroupName, launchConfig, desiredCapacity, memberInstances); LOG.debug("setting up mocked group: {}", autoScalingGroup.getInstances().stream() .map(com.amazonaws.services.autoscaling.model.Instance::getInstanceId).collect(Collectors.toList())); // Lists.transform(autoScalingGroup.getInstances(), // AwsAutoScalingFunctions.toAutoScalingInstanceId())); when(this.mockAwsClient.getAutoScalingGroup(autoScalingGroupName)).thenReturn(autoScalingGroup); when(this.mockAwsClient.getLaunchConfiguration(launchConfig.getLaunchConfigurationName())) .thenReturn(launchConfig); when(this.mockAwsClient.getAutoScalingGroupMembers(autoScalingGroupName)).thenReturn(memberInstances); }
@RequestMapping(value = "/launchconfig", method = RequestMethod.GET) @ResponseBody public List<AwsLaunchConfiguration> listLaunchConfigurations(@RequestParam("accessKey") String accessKey, @RequestParam("secretKey") String secretKey) { List<AwsLaunchConfiguration> list = new ArrayList<>(); for (LaunchConfiguration item : awsec2Service .describeAmazonLaunchConfigurations(awsCredentialsFactory.createSimpleAWSCredentials(accessKey, secretKey))) { list.add(transformer.transform(item)); } return list; }
public List<AbstractResource<?>> toAsLaunchConfigurations(List<LaunchConfiguration> launchConfigurations, String accountId, Region region, DateTime dt) { List<AbstractResource<?>> resources = new ArrayList<>(); for (LaunchConfiguration launchConfiguration : launchConfigurations) { Ec2LaunchConfiguration ec2LaunchConfiguration = new Ec2LaunchConfiguration(); conf(ec2LaunchConfiguration, accountId, region, dt); ec2LaunchConfiguration.setResource(launchConfiguration); resources.add(ec2LaunchConfiguration); } log.debug("{} launch configurations found via api and converted to AsLaunchConfiguration", resources.size()); return resources; }
public LaunchConfiguration describeLaunchConfig(String launchConfigName) { logger.info("describe launch config, name={}", launchConfigName); return autoScaling.describeLaunchConfigurations(new DescribeLaunchConfigurationsRequest() .withLaunchConfigurationNames(launchConfigName)) .getLaunchConfigurations().get(0); }
@Override public LaunchConfiguration getLaunchConfiguration(String launchConfigurationName) throws AmazonClientException { checkArgument(isConfigured(), "can't use client before it's configured"); return new GetLaunchConfiguration(awsCredentials(), region(), clientConfig(), launchConfigurationName).call(); }
@Override public LaunchConfiguration getLaunchConfiguration(String launchConfigurationName) { checkArgument(launchConfigurationName.equals(this.launchConfig.getLaunchConfigurationName()), "unknown launch configuration '%s'", launchConfigurationName); return this.launchConfig; }
/** * Creates a number of "pseudo machine" in {@code REQUESTED} state as a * place-holder machines for a desired but not yet acquired Auto Scaling * Group members. * * @param missingInstances * Number of missing Auto Scaling Group instances. * @param launchConfig * The launch configuration of the Auto Scaling Group. * @return */ private List<Machine> pseudoMachines(int missingInstances, LaunchConfiguration launchConfig) { List<Machine> requestedInstances = new ArrayList<>(); for (int i = 0; i < missingInstances; i++) { String pseudoId = String.format("%s%d", REQUESTED_ID_PREFIX, i + 1); requestedInstances.add(pseudoMachine(pseudoId, launchConfig)); } return requestedInstances; }
/** * Creates a "pseudo machine" in {@code REQUESTED} state as a place-holder * machine for a desired but not yet acquired Auto Scaling Group member. * <p/> * We set the request time to <code>null</code>, since AWS AutoScaling does * not support reporting it and attempting to keep track of it manually is * rather awkward and brittle. * * @param pseudoId * The identifier to assign to the pseudo machine. * @param launchConfig * The launch configuration that describes how to launch an Auto * Scaling Group on-demand instance (or spot instance). * @return The pseudo machine. */ private Machine pseudoMachine(String pseudoId, LaunchConfiguration launchConfig) { // are spot instances or on-demand instances being launched for the Auto // Scaling Group String cloudProvider = launchConfig.getSpotPrice() != null ? CloudProviders.AWS_SPOT : CloudProviders.AWS_EC2; String instanceType = launchConfig.getInstanceType(); return Machine.builder().id(pseudoId).machineState(MachineState.REQUESTED).cloudProvider(cloudProvider) .region(cloudApiSettings().getRegion()).machineSize(instanceType).build(); }
/** * Retrieves a particular {@link LaunchConfiguration} (describing how to * launch on-demand or spot instances for an Auto Scaling Group). * * @param launchConfigurationName * The name of the Launch configuration. * @return * @throws AmazonClientException */ LaunchConfiguration getLaunchConfiguration(String launchConfigurationName) throws AmazonClientException;
/** * Creates a new {@link FakeAutoScalingClient} where the collection of Auto * Scaling Group members are all instances in the cloud account. * * @param autoScalingGroupName * @param launchConfig * @param desiredCapacity * @param groupMembers */ public FakeAutoScalingClient(String autoScalingGroupName, LaunchConfiguration launchConfig, int desiredCapacity, List<Instance> groupMembers) { this(autoScalingGroupName, launchConfig, desiredCapacity, groupMembers, new ArrayList<Instance>()); }
/** * Sets up a fake {@link AutoScalingClient} with a fake pool containing only * instances that are actual members of the Auto Scaling Group. * * @param autoScalingGroupName * @param launchConfig * @param desiredCapacity * @param memberInstances */ private void setUpMockedAutoScalingGroup(String autoScalingGroupName, LaunchConfiguration launchConfig, int desiredCapacity, List<Instance> memberInstances) { setUpMockedAutoScalingGroup(autoScalingGroupName, launchConfig, desiredCapacity, memberInstances, new ArrayList<Instance>()); }
List<LaunchConfiguration> describeAmazonLaunchConfigurations(AWSCredentials credentials);