Java tutorial
/* * * Copyright 2012 Netflix, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.netflix.simianarmy.client.aws; import com.amazonaws.AmazonServiceException; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.services.autoscaling.AmazonAutoScalingClient; import com.amazonaws.services.autoscaling.model.AutoScalingGroup; import com.amazonaws.services.autoscaling.model.AutoScalingInstanceDetails; import com.amazonaws.services.autoscaling.model.DeleteAutoScalingGroupRequest; import com.amazonaws.services.autoscaling.model.DeleteLaunchConfigurationRequest; import com.amazonaws.services.autoscaling.model.DescribeAutoScalingGroupsRequest; import com.amazonaws.services.autoscaling.model.DescribeAutoScalingGroupsResult; import com.amazonaws.services.autoscaling.model.DescribeAutoScalingInstancesRequest; import com.amazonaws.services.autoscaling.model.DescribeAutoScalingInstancesResult; import com.amazonaws.services.autoscaling.model.DescribeLaunchConfigurationsRequest; import com.amazonaws.services.autoscaling.model.DescribeLaunchConfigurationsResult; import com.amazonaws.services.autoscaling.model.LaunchConfiguration; import com.amazonaws.services.ec2.AmazonEC2; import com.amazonaws.services.ec2.AmazonEC2Client; import com.amazonaws.services.ec2.model.CreateSecurityGroupRequest; import com.amazonaws.services.ec2.model.CreateSecurityGroupResult; import com.amazonaws.services.ec2.model.CreateTagsRequest; import com.amazonaws.services.ec2.model.DeleteSnapshotRequest; import com.amazonaws.services.ec2.model.DeleteVolumeRequest; import com.amazonaws.services.ec2.model.DeregisterImageRequest; import com.amazonaws.services.ec2.model.DescribeImagesRequest; import com.amazonaws.services.ec2.model.DescribeImagesResult; import com.amazonaws.services.ec2.model.DescribeInstancesRequest; import com.amazonaws.services.ec2.model.DescribeInstancesResult; import com.amazonaws.services.ec2.model.DescribeSecurityGroupsRequest; import com.amazonaws.services.ec2.model.DescribeSecurityGroupsResult; import com.amazonaws.services.ec2.model.DescribeSnapshotsRequest; import com.amazonaws.services.ec2.model.DescribeSnapshotsResult; import com.amazonaws.services.ec2.model.DescribeVolumesRequest; import com.amazonaws.services.ec2.model.DescribeVolumesResult; import com.amazonaws.services.ec2.model.DetachVolumeRequest; import com.amazonaws.services.ec2.model.EbsInstanceBlockDevice; import com.amazonaws.services.ec2.model.Image; import com.amazonaws.services.ec2.model.Instance; import com.amazonaws.services.ec2.model.InstanceBlockDeviceMapping; import com.amazonaws.services.ec2.model.ModifyInstanceAttributeRequest; import com.amazonaws.services.ec2.model.Reservation; import com.amazonaws.services.ec2.model.SecurityGroup; import com.amazonaws.services.ec2.model.Snapshot; import com.amazonaws.services.ec2.model.Tag; import com.amazonaws.services.ec2.model.TerminateInstancesRequest; import com.amazonaws.services.ec2.model.Volume; import com.amazonaws.services.elasticloadbalancing.AmazonElasticLoadBalancingClient; import com.amazonaws.services.elasticloadbalancing.model.DescribeLoadBalancerAttributesRequest; import com.amazonaws.services.elasticloadbalancing.model.DescribeLoadBalancerAttributesResult; import com.amazonaws.services.elasticloadbalancing.model.DescribeLoadBalancersRequest; import com.amazonaws.services.elasticloadbalancing.model.DescribeLoadBalancersResult; import com.amazonaws.services.elasticloadbalancing.model.LoadBalancerAttributes; import com.amazonaws.services.elasticloadbalancing.model.LoadBalancerDescription; import com.amazonaws.services.simpledb.AmazonSimpleDB; import com.amazonaws.services.simpledb.AmazonSimpleDBClient; import com.google.common.base.Objects; import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; import com.google.inject.Module; import com.netflix.simianarmy.CloudClient; import com.netflix.simianarmy.NotFoundException; import org.apache.commons.lang.Validate; import org.jclouds.ContextBuilder; import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.Utils; import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadataBuilder; import org.jclouds.domain.LoginCredentials; import org.jclouds.ec2.EC2ApiMetadata; import org.jclouds.logging.slf4j.config.SLF4JLoggingModule; import org.jclouds.ssh.SshClient; import org.jclouds.ssh.jsch.config.JschSshClientModule; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; /** * The Class AWSClient. Simple Amazon EC2 and Amazon ASG client interface. */ public class AWSClient implements CloudClient { /** The Constant LOGGER. */ private static final Logger LOGGER = LoggerFactory.getLogger(AWSClient.class); /** The region. */ private final String region; private final AWSCredentialsProvider awsCredentialsProvider; private ComputeService jcloudsComputeService; /** * This constructor will let the AWS SDK obtain the credentials, which will * choose such in the following order: * * <ul> * <li>Environment Variables: {@code AWS_ACCESS_KEY_ID} and * {@code AWS_SECRET_KEY}</li> * <li>Java System Properties: {@code aws.accessKeyId} and * {@code aws.secretKey}</li> * <li>Instance Metadata Service, which provides the credentials associated * with the IAM role for the EC2 instance</li> * </ul> * * <p> * If credentials are provided explicitly, use * {@link com.netflix.simianarmy.basic.BasicSimianArmyContext#exportCredentials(String, String)} * which will set them as System properties used by each AWS SDK call. * </p> * * <p> * <b>Note:</b> Avoid storing credentials received dynamically via the * {@link com.amazonaws.auth.InstanceProfileCredentialsProvider} as these will be rotated and * their renewal is handled by its * {@link com.amazonaws.auth.InstanceProfileCredentialsProvider#getCredentials()} method. * </p> * * @param region * the region * @see com.amazonaws.auth.DefaultAWSCredentialsProviderChain * @see com.amazonaws.auth.InstanceProfileCredentialsProvider * @see com.netflix.simianarmy.basic.BasicSimianArmyContext#exportCredentials(String, String) */ public AWSClient(String region) { this.region = region; this.awsCredentialsProvider = null; } /** * The constructor allows you to provide your own AWS credentials provider. * @param region * the region * @param awsCredentialsProvider * the AWS credentials provider */ public AWSClient(String region, AWSCredentialsProvider awsCredentialsProvider) { this.region = region; this.awsCredentialsProvider = awsCredentialsProvider; } /** * The Region. * * @return the region the client is configured to communicate with */ public String region() { return region; } /** * Amazon EC2 client. Abstracted to aid testing. * * @return the Amazon EC2 client */ protected AmazonEC2 ec2Client() { AmazonEC2 client; if (awsCredentialsProvider == null) { client = new AmazonEC2Client(); } else { client = new AmazonEC2Client(awsCredentialsProvider); } client.setEndpoint("ec2." + region + ".amazonaws.com"); return client; } /** * Amazon ASG client. Abstracted to aid testing. * * @return the Amazon Auto Scaling client */ protected AmazonAutoScalingClient asgClient() { AmazonAutoScalingClient client; if (awsCredentialsProvider == null) { client = new AmazonAutoScalingClient(); } else { client = new AmazonAutoScalingClient(awsCredentialsProvider); } client.setEndpoint("autoscaling." + region + ".amazonaws.com"); return client; } /** * Amazon ELB client. Abstracted to aid testing. * * @return the Amazon ELB client */ protected AmazonElasticLoadBalancingClient elbClient() { AmazonElasticLoadBalancingClient client; if (awsCredentialsProvider == null) { client = new AmazonElasticLoadBalancingClient(); } else { client = new AmazonElasticLoadBalancingClient(awsCredentialsProvider); } client.setEndpoint("elasticloadbalancing." + region + ".amazonaws.com"); return client; } /** * Amazon SimpleDB client. * * @return the Amazon SimpleDB client */ public AmazonSimpleDB sdbClient() { AmazonSimpleDB client; if (awsCredentialsProvider == null) { client = new AmazonSimpleDBClient(); } else { client = new AmazonSimpleDBClient(awsCredentialsProvider); } // us-east-1 has special naming // http://docs.amazonwebservices.com/general/latest/gr/rande.html#sdb_region if (region == null || region.equals("us-east-1")) { client.setEndpoint("sdb.amazonaws.com"); } else { client.setEndpoint("sdb." + region + ".amazonaws.com"); } return client; } /** * Describe auto scaling groups. * * @return the list */ public List<AutoScalingGroup> describeAutoScalingGroups() { return describeAutoScalingGroups((String[]) null); } /** * Describe a set of specific auto scaling groups. * * @param names the ASG names * @return the auto scaling groups */ public List<AutoScalingGroup> describeAutoScalingGroups(String... names) { if (names == null || names.length == 0) { LOGGER.info(String.format("Getting all auto-scaling groups in region %s.", region)); } else { LOGGER.info( String.format("Getting auto-scaling groups for %d names in region %s.", names.length, region)); } List<AutoScalingGroup> asgs = new LinkedList<AutoScalingGroup>(); AmazonAutoScalingClient asgClient = asgClient(); DescribeAutoScalingGroupsRequest request = new DescribeAutoScalingGroupsRequest(); if (names != null) { request.setAutoScalingGroupNames(Arrays.asList(names)); } DescribeAutoScalingGroupsResult result = asgClient.describeAutoScalingGroups(request); asgs.addAll(result.getAutoScalingGroups()); while (result.getNextToken() != null) { request.setNextToken(result.getNextToken()); result = asgClient.describeAutoScalingGroups(request); asgs.addAll(result.getAutoScalingGroups()); } LOGGER.info(String.format("Got %d auto-scaling groups in region %s.", asgs.size(), region)); return asgs; } /** * Describe a set of specific ELBs. * * @param names the ELB names * @return the ELBs */ public List<LoadBalancerDescription> describeElasticLoadBalancers(String... names) { if (names == null || names.length == 0) { LOGGER.info(String.format("Getting all ELBs in region %s.", region)); } else { LOGGER.info(String.format("Getting ELBs for %d names in region %s.", names.length, region)); } AmazonElasticLoadBalancingClient elbClient = elbClient(); DescribeLoadBalancersRequest request = new DescribeLoadBalancersRequest().withLoadBalancerNames(names); DescribeLoadBalancersResult result = elbClient.describeLoadBalancers(request); List<LoadBalancerDescription> elbs = result.getLoadBalancerDescriptions(); LOGGER.info(String.format("Got %d ELBs in region %s.", elbs.size(), region)); return elbs; } /** * Describe a set of specific ELBs. * * @param names the ELB names * @return the ELBs */ public LoadBalancerAttributes describeElasticLoadBalancerAttributes(String name) { LOGGER.info(String.format("Getting attributes for ELB with name '%s' in region %s.", name, region)); AmazonElasticLoadBalancingClient elbClient = elbClient(); DescribeLoadBalancerAttributesRequest request = new DescribeLoadBalancerAttributesRequest() .withLoadBalancerName(name); DescribeLoadBalancerAttributesResult result = elbClient.describeLoadBalancerAttributes(request); LoadBalancerAttributes attrs = result.getLoadBalancerAttributes(); LOGGER.info(String.format("Got attributes for ELB with name '%s' in region %s.", name, region)); return attrs; } /** * Describe a set of specific auto-scaling instances. * * @param instanceIds the instance ids * @return the instances */ public List<AutoScalingInstanceDetails> describeAutoScalingInstances(String... instanceIds) { if (instanceIds == null || instanceIds.length == 0) { LOGGER.info(String.format("Getting all auto-scaling instances in region %s.", region)); } else { LOGGER.info(String.format("Getting auto-scaling instances for %d ids in region %s.", instanceIds.length, region)); } List<AutoScalingInstanceDetails> instances = new LinkedList<AutoScalingInstanceDetails>(); AmazonAutoScalingClient asgClient = asgClient(); DescribeAutoScalingInstancesRequest request = new DescribeAutoScalingInstancesRequest(); if (instanceIds != null) { request.setInstanceIds(Arrays.asList(instanceIds)); } DescribeAutoScalingInstancesResult result = asgClient.describeAutoScalingInstances(request); instances.addAll(result.getAutoScalingInstances()); while (result.getNextToken() != null) { request = request.withNextToken(result.getNextToken()); result = asgClient.describeAutoScalingInstances(request); instances.addAll(result.getAutoScalingInstances()); } LOGGER.info(String.format("Got %d auto-scaling instances.", instances.size())); return instances; } /** * Describe a set of specific instances. * * @param instanceIds the instance ids * @return the instances */ public List<Instance> describeInstances(String... instanceIds) { if (instanceIds == null || instanceIds.length == 0) { LOGGER.info(String.format("Getting all EC2 instances in region %s.", region)); } else { LOGGER.info( String.format("Getting EC2 instances for %d ids in region %s.", instanceIds.length, region)); } List<Instance> instances = new LinkedList<Instance>(); AmazonEC2 ec2Client = ec2Client(); DescribeInstancesRequest request = new DescribeInstancesRequest(); if (instanceIds != null) { request.withInstanceIds(Arrays.asList(instanceIds)); } DescribeInstancesResult result = ec2Client.describeInstances(request); for (Reservation reservation : result.getReservations()) { instances.addAll(reservation.getInstances()); } LOGGER.info(String.format("Got %d EC2 instances in region %s.", instances.size(), region)); return instances; } /** * Describe a set of specific launch configurations. * * @param names the launch configuration names * @return the launch configurations */ public List<LaunchConfiguration> describeLaunchConfigurations(String... names) { if (names == null || names.length == 0) { LOGGER.info(String.format("Getting all launch configurations in region %s.", region)); } else { LOGGER.info(String.format("Getting launch configurations for %d names in region %s.", names.length, region)); } List<LaunchConfiguration> lcs = new LinkedList<LaunchConfiguration>(); AmazonAutoScalingClient asgClient = asgClient(); DescribeLaunchConfigurationsRequest request = new DescribeLaunchConfigurationsRequest() .withLaunchConfigurationNames(names); DescribeLaunchConfigurationsResult result = asgClient.describeLaunchConfigurations(request); lcs.addAll(result.getLaunchConfigurations()); while (result.getNextToken() != null) { request.setNextToken(result.getNextToken()); result = asgClient.describeLaunchConfigurations(request); lcs.addAll(result.getLaunchConfigurations()); } LOGGER.info(String.format("Got %d launch configurations in region %s.", lcs.size(), region)); return lcs; } /** {@inheritDoc} */ @Override public void deleteAutoScalingGroup(String asgName) { Validate.notEmpty(asgName); LOGGER.info(String.format("Deleting auto-scaling group with name %s in region %s.", asgName, region)); AmazonAutoScalingClient asgClient = asgClient(); DeleteAutoScalingGroupRequest request = new DeleteAutoScalingGroupRequest() .withAutoScalingGroupName(asgName); asgClient.deleteAutoScalingGroup(request); } /** {@inheritDoc} */ @Override public void deleteLaunchConfiguration(String launchConfigName) { Validate.notEmpty(launchConfigName); LOGGER.info(String.format("Deleting launch configuration with name %s in region %s.", launchConfigName, region)); AmazonAutoScalingClient asgClient = asgClient(); DeleteLaunchConfigurationRequest request = new DeleteLaunchConfigurationRequest() .withLaunchConfigurationName(launchConfigName); asgClient.deleteLaunchConfiguration(request); } /** {@inheritDoc} */ @Override public void deleteImage(String imageId) { Validate.notEmpty(imageId); LOGGER.info(String.format("Deleting image %s in region %s.", imageId, region)); AmazonEC2 ec2Client = ec2Client(); DeregisterImageRequest request = new DeregisterImageRequest(imageId); ec2Client.deregisterImage(request); } /** {@inheritDoc} */ @Override public void deleteVolume(String volumeId) { Validate.notEmpty(volumeId); LOGGER.info(String.format("Deleting volume %s in region %s.", volumeId, region)); AmazonEC2 ec2Client = ec2Client(); DeleteVolumeRequest request = new DeleteVolumeRequest().withVolumeId(volumeId); ec2Client.deleteVolume(request); } /** {@inheritDoc} */ @Override public void deleteSnapshot(String snapshotId) { Validate.notEmpty(snapshotId); LOGGER.info(String.format("Deleting snapshot %s in region %s.", snapshotId, region)); AmazonEC2 ec2Client = ec2Client(); DeleteSnapshotRequest request = new DeleteSnapshotRequest().withSnapshotId(snapshotId); ec2Client.deleteSnapshot(request); } /** {@inheritDoc} */ @Override public void terminateInstance(String instanceId) { Validate.notEmpty(instanceId); LOGGER.info(String.format("Terminating instance %s in region %s.", instanceId, region)); try { ec2Client().terminateInstances(new TerminateInstancesRequest(Arrays.asList(instanceId))); } catch (AmazonServiceException e) { if (e.getErrorCode().equals("InvalidInstanceID.NotFound")) { throw new NotFoundException("AWS instance " + instanceId + " not found", e); } throw e; } } /** {@inheritDoc} */ public void setInstanceSecurityGroups(String instanceId, List<String> groupIds) { Validate.notEmpty(instanceId); LOGGER.info( String.format("Removing all security groups from instance %s in region %s.", instanceId, region)); try { ModifyInstanceAttributeRequest request = new ModifyInstanceAttributeRequest(); request.setInstanceId(instanceId); request.setGroups(groupIds); ec2Client().modifyInstanceAttribute(request); } catch (AmazonServiceException e) { if (e.getErrorCode().equals("InvalidInstanceID.NotFound")) { throw new NotFoundException("AWS instance " + instanceId + " not found", e); } throw e; } } /** * Describe a set of specific EBS volumes. * * @param volumeIds the volume ids * @return the volumes */ public List<Volume> describeVolumes(String... volumeIds) { if (volumeIds == null || volumeIds.length == 0) { LOGGER.info(String.format("Getting all EBS volumes in region %s.", region)); } else { LOGGER.info(String.format("Getting EBS volumes for %d ids in region %s.", volumeIds.length, region)); } AmazonEC2 ec2Client = ec2Client(); DescribeVolumesRequest request = new DescribeVolumesRequest(); if (volumeIds != null) { request.setVolumeIds(Arrays.asList(volumeIds)); } DescribeVolumesResult result = ec2Client.describeVolumes(request); List<Volume> volumes = result.getVolumes(); LOGGER.info(String.format("Got %d EBS volumes in region %s.", volumes.size(), region)); return volumes; } /** * Describe a set of specific EBS snapshots. * * @param snapshotIds the snapshot ids * @return the snapshots */ public List<Snapshot> describeSnapshots(String... snapshotIds) { if (snapshotIds == null || snapshotIds.length == 0) { LOGGER.info(String.format("Getting all EBS snapshots in region %s.", region)); } else { LOGGER.info( String.format("Getting EBS snapshotIds for %d ids in region %s.", snapshotIds.length, region)); } AmazonEC2 ec2Client = ec2Client(); DescribeSnapshotsRequest request = new DescribeSnapshotsRequest(); // Set the owner id to self to avoid getting snapshots from other accounts. request.withOwnerIds(Arrays.<String>asList("self")); if (snapshotIds != null) { request.setSnapshotIds(Arrays.asList(snapshotIds)); } DescribeSnapshotsResult result = ec2Client.describeSnapshots(request); List<Snapshot> snapshots = result.getSnapshots(); LOGGER.info(String.format("Got %d EBS snapshots in region %s.", snapshots.size(), region)); return snapshots; } @Override public void createTagsForResources(Map<String, String> keyValueMap, String... resourceIds) { Validate.notNull(keyValueMap); Validate.notEmpty(keyValueMap); Validate.notNull(resourceIds); Validate.notEmpty(resourceIds); AmazonEC2 ec2Client = ec2Client(); List<Tag> tags = new ArrayList<Tag>(); for (Map.Entry<String, String> entry : keyValueMap.entrySet()) { tags.add(new Tag(entry.getKey(), entry.getValue())); } CreateTagsRequest req = new CreateTagsRequest(Arrays.asList(resourceIds), tags); ec2Client.createTags(req); } /** * Describe a set of specific images. * * @param imageIds the image ids * @return the images */ public List<Image> describeImages(String... imageIds) { if (imageIds == null || imageIds.length == 0) { LOGGER.info(String.format("Getting all AMIs in region %s.", region)); } else { LOGGER.info(String.format("Getting AMIs for %d ids in region %s.", imageIds.length, region)); } AmazonEC2 ec2Client = ec2Client(); DescribeImagesRequest request = new DescribeImagesRequest(); if (imageIds != null) { request.setImageIds(Arrays.asList(imageIds)); } DescribeImagesResult result = ec2Client.describeImages(request); List<Image> images = result.getImages(); LOGGER.info(String.format("Got %d AMIs in region %s.", images.size(), region)); return images; } @Override public void detachVolume(String instanceId, String volumeId, boolean force) { Validate.notEmpty(instanceId); LOGGER.info(String.format("Detach volumes from instance %s in region %s.", instanceId, region)); try { DetachVolumeRequest detachVolumeRequest = new DetachVolumeRequest(); detachVolumeRequest.setForce(force); detachVolumeRequest.setInstanceId(instanceId); detachVolumeRequest.setVolumeId(volumeId); ec2Client().detachVolume(detachVolumeRequest); } catch (AmazonServiceException e) { if (e.getErrorCode().equals("InvalidInstanceID.NotFound")) { throw new NotFoundException("AWS instance " + instanceId + " not found", e); } throw e; } } @Override public List<String> listAttachedVolumes(String instanceId, boolean includeRoot) { Validate.notEmpty(instanceId); LOGGER.info(String.format("Listing volumes attached to instance %s in region %s.", instanceId, region)); try { List<String> volumeIds = new ArrayList<String>(); for (Instance instance : describeInstances(instanceId)) { String rootDeviceName = instance.getRootDeviceName(); for (InstanceBlockDeviceMapping ibdm : instance.getBlockDeviceMappings()) { EbsInstanceBlockDevice ebs = ibdm.getEbs(); if (ebs == null) { continue; } String volumeId = ebs.getVolumeId(); if (Strings.isNullOrEmpty(volumeId)) { continue; } if (!includeRoot && rootDeviceName != null && rootDeviceName.equals(ibdm.getDeviceName())) { continue; } volumeIds.add(volumeId); } } return volumeIds; } catch (AmazonServiceException e) { if (e.getErrorCode().equals("InvalidInstanceID.NotFound")) { throw new NotFoundException("AWS instance " + instanceId + " not found", e); } throw e; } } /** * Describe a set of security groups. * * @param groupNames the names of the groups to find * @return a list of matching groups */ public List<SecurityGroup> describeSecurityGroups(String... groupNames) { AmazonEC2 ec2Client = ec2Client(); DescribeSecurityGroupsRequest request = new DescribeSecurityGroupsRequest(); if (groupNames == null || groupNames.length == 0) { LOGGER.info(String.format("Getting all EC2 security groups in region %s.", region)); } else { LOGGER.info(String.format("Getting EC2 security groups for %d names in region %s.", groupNames.length, region)); request.withGroupNames(groupNames); } DescribeSecurityGroupsResult result; try { result = ec2Client.describeSecurityGroups(request); } catch (AmazonServiceException e) { if (e.getErrorCode().equals("InvalidGroup.NotFound")) { LOGGER.info("Got InvalidGroup.NotFound error for security groups; returning empty list"); return Collections.emptyList(); } throw e; } List<SecurityGroup> securityGroups = result.getSecurityGroups(); LOGGER.info(String.format("Got %d EC2 security groups in region %s.", securityGroups.size(), region)); return securityGroups; } /** {@inheritDoc} */ public String createSecurityGroup(String instanceId, String name, String description) { String vpcId = getVpcId(instanceId); AmazonEC2 ec2Client = ec2Client(); CreateSecurityGroupRequest request = new CreateSecurityGroupRequest(); request.setGroupName(name); request.setDescription(description); request.setVpcId(vpcId); LOGGER.info(String.format("Creating EC2 security group %s.", name)); CreateSecurityGroupResult result = ec2Client.createSecurityGroup(request); return result.getGroupId(); } /** * Convenience wrapper around describeInstances, for a single instance id. * * @param instanceId id of instance to find * @return the instance info, or null if instance not found */ public Instance describeInstance(String instanceId) { Instance instance = null; for (Instance i : describeInstances(instanceId)) { if (instance != null) { throw new IllegalStateException("Duplicate instance: " + instanceId); } instance = i; } return instance; } /** {@inheritDoc} */ @Override public synchronized ComputeService getJcloudsComputeService() { if (jcloudsComputeService == null) { String username = awsCredentialsProvider.getCredentials().getAWSAccessKeyId(); String password = awsCredentialsProvider.getCredentials().getAWSSecretKey(); ComputeServiceContext jcloudsContext = ContextBuilder.newBuilder("aws-ec2") .credentials(username, password) .modules(ImmutableSet.<Module>of(new SLF4JLoggingModule(), new JschSshClientModule())) .buildView(ComputeServiceContext.class); this.jcloudsComputeService = jcloudsContext.getComputeService(); } return jcloudsComputeService; } /** {@inheritDoc} */ @Override public String getJcloudsId(String instanceId) { return this.region + "/" + instanceId; } @Override public SshClient connectSsh(String instanceId, LoginCredentials credentials) { ComputeService computeService = getJcloudsComputeService(); String jcloudsId = getJcloudsId(instanceId); NodeMetadata node = getJcloudsNode(computeService, jcloudsId); node = NodeMetadataBuilder.fromNodeMetadata(node).credentials(credentials).build(); Utils utils = computeService.getContext().utils(); SshClient ssh = utils.sshForNode().apply(node); ssh.connect(); return ssh; } private NodeMetadata getJcloudsNode(ComputeService computeService, String jcloudsId) { // Work around a jclouds bug / documentation issue... // TODO: Figure out what's broken, and eliminate this function // This should work (?): // Set<NodeMetadata> nodes = computeService.listNodesByIds(Collections.singletonList(jcloudsId)); Set<NodeMetadata> nodes = Sets.newHashSet(); for (ComputeMetadata n : computeService.listNodes()) { if (jcloudsId.equals(n.getId())) { nodes.add((NodeMetadata) n); } } if (nodes.isEmpty()) { LOGGER.warn("Unable to find jclouds node: {}", jcloudsId); for (ComputeMetadata n : computeService.listNodes()) { LOGGER.info("Did find node: {}", n); } throw new IllegalStateException("Unable to find node using jclouds: " + jcloudsId); } NodeMetadata node = Iterables.getOnlyElement(nodes); return node; } /** {@inheritDoc} */ @Override public String findSecurityGroup(String instanceId, String groupName) { String vpcId = getVpcId(instanceId); SecurityGroup found = null; List<SecurityGroup> securityGroups = describeSecurityGroups(vpcId, groupName); for (SecurityGroup sg : securityGroups) { if (Objects.equal(vpcId, sg.getVpcId())) { if (found != null) { throw new IllegalStateException("Duplicate security groups found"); } found = sg; } } if (found == null) { return null; } return found.getGroupId(); } /** * Gets the VPC id for the given instance. * * @param instanceId * instance we're checking * @return vpc id, or null if not a vpc instance */ String getVpcId(String instanceId) { Instance awsInstance = describeInstance(instanceId); String vpcId = awsInstance.getVpcId(); if (Strings.isNullOrEmpty(vpcId)) { return null; } return vpcId; } /** {@inheritDoc} */ @Override public boolean canChangeInstanceSecurityGroups(String instanceId) { return null != getVpcId(instanceId); } }