diff --git a/bubble-server/src/main/java/bubble/cloud/compute/ec2/AmazonEC2Driver.java b/bubble-server/src/main/java/bubble/cloud/compute/ec2/AmazonEC2Driver.java index 533c32d2..5352db46 100644 --- a/bubble-server/src/main/java/bubble/cloud/compute/ec2/AmazonEC2Driver.java +++ b/bubble-server/src/main/java/bubble/cloud/compute/ec2/AmazonEC2Driver.java @@ -16,7 +16,6 @@ import com.amazonaws.services.ec2.AmazonEC2; import com.amazonaws.services.ec2.AmazonEC2ClientBuilder; import com.amazonaws.services.ec2.model.*; import lombok.Getter; -import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import org.cobbzilla.util.http.HttpRequestBean; import org.cobbzilla.util.http.HttpResponseBean; @@ -38,9 +37,9 @@ public class AmazonEC2Driver extends ComputeServiceDriverBase { public static final String TAG_CLOUD_UUID = "cloudUUID"; public static final String TAG_NODE_UUID = "nodeUUID"; - public static final String SUBNET_ID_PREFIX = "subnet_id_"; + public static final String KEY_NAME_PREFIX = "KeyName_"; public static final int MIN_COUNT = 1; - public static final int MAX_COUNT = 1; + public static final int MAX_COUNT = 5; @Getter(lazy = true) private final AWSCredentialsProvider ec2credentials = new BubbleAwsCredentialsProvider(cloud, getCredentials()); @@ -69,16 +68,22 @@ public class AmazonEC2Driver extends ComputeServiceDriverBase { } @Override public List listNodes() throws IOException { + final List nodes = new ArrayList<>(); - DescribeInstancesResult result = new DescribeInstancesResult(); + final AmazonEC2 ec2Client = getEc2Client(); + + DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest() + .withFilters( + new Filter("instance.group-id").withValues(config.getConfig("group")), + new Filter("tag:" + TAG_CLOUD_UUID).withValues(cloud.getUuid()), + new Filter("instance-state-name").withValues("running", "pending") + ); + + DescribeInstancesResult result = ec2Client.describeInstances(describeInstancesRequest); + if (result.getSdkHttpMetadata().getHttpStatusCode() == OK) { for (Reservation reservation : result.getReservations()) { for (Instance instance : reservation.getInstances()) { - if (instance.getState().equals("terminated") - || !instance.getTags().contains(new Tag().withKey(TAG_CLOUD_UUID).withValue(cloud.getUuid()))) { - log.debug("Skipping terminated node or node without cloud tag " + cloud.getUuid()); - continue; - } final String instanceId = instance.getInstanceId(); final String ip4 = instance.getPrivateIpAddress(); final String ip6 = instance.getPublicIpAddress(); @@ -92,21 +97,25 @@ public class AmazonEC2Driver extends ComputeServiceDriverBase { return nodes; } - @Override public BubbleNode start(@NonNull BubbleNode node) throws Exception { - final ComputeNodeSize size = config.getSize(node.getSize()); + @Override public BubbleNode start(BubbleNode node) throws Exception { + final ComputeNodeSize size = config.getSize(node.getSize()); final AmazonEC2 ec2Client = getEc2Client(); - DescribeSubnetsRequest describeSubnetsRequest = new DescribeSubnetsRequest(); + DescribeSubnetsRequest describeSubnetsRequest = new DescribeSubnetsRequest() + .withFilters(new Filter().withName("state").withValues("available")); String subnetId = ec2Client.describeSubnets(describeSubnetsRequest).getSubnets().stream() .filter(s -> s.getAvailableIpAddressCount() != 0) .findAny().orElseThrow(() -> new NoSuchElementException("Subnet not found")).getSubnetId(); + final String keyId = registerSshKey(node); + RunInstancesRequest runInstancesRequest = new RunInstancesRequest().withImageId(config.getConfig("imageId")) .withInstanceType(size.getInternalName()) .withMinCount(MIN_COUNT) .withMaxCount(MAX_COUNT) + .withKeyName(KEY_NAME_PREFIX+node.getUuid()) .withNetworkInterfaces(new InstanceNetworkInterfaceSpecification() .withAssociatePublicIpAddress(true) .withDeviceIndex(0) @@ -119,37 +128,46 @@ public class AmazonEC2Driver extends ComputeServiceDriverBase { return die("start: error running instance: " + runInstancesResult.getSdkHttpMetadata().getAllHttpHeaders()); - Instance instance = runInstancesResult.getReservation().getInstances().get(0); - final String instanceId = instance.getInstanceId(); - final String ip4 = instance.getPrivateIpAddress(); - final String ip6 = instance.getPublicIpAddress(); - final String keyId = registerSshKey(node); - - instance.setKeyName(keyId); - node.setIp4(ip4).setIp6(ip6).setTag(TAG_INSTANCE_ID, instanceId).setTag(TAG_SSH_KEY_ID, keyId); + final String instanceId = runInstancesResult.getReservation().getInstances().get(0).getInstanceId(); + node.setState(BubbleNodeState.booting); + node.setTag(TAG_INSTANCE_ID, instanceId).setTag(TAG_SSH_KEY_ID, keyId); nodeDAO.update(node); + // Describe instances to check run instance result and get IP addresses + DescribeInstancesResult result = ec2Client.describeInstances( + new DescribeInstancesRequest().withInstanceIds(instanceId)); + + if (result.getSdkHttpMetadata().getHttpStatusCode() == OK) { + for (Reservation reservation : result.getReservations()) { + for (Instance i : reservation.getInstances()) { + if (i.getInstanceId().equals(instanceId)) { + final String ip4 = i.getPrivateIpAddress(); + if (ip4 != null && ip4.length() > 0 && !ip4.equals("0.0.0.0")){ + node.setIp4(ip4); + nodeDAO.update(node); + } + final String ip6 = i.getPublicIpAddress(); + if (ip6 != null && ip6.length() > 0) { + node.setIp6(ip6); + nodeDAO.update(node); + } + break; + } + } + } + } + // Setting up the tags for the instance CreateTagsRequest createTagsRequest = new CreateTagsRequest() - .withResources(instance.getInstanceId()) + .withResources(instanceId) .withTags(new Tag(TAG_NODE_UUID, node.getUuid()), new Tag(TAG_CLOUD_UUID, cloud.getUuid())); - try { - ec2Client.createTags(createTagsRequest); - } catch (AmazonServiceException e) { - log.warn("start: error creating tags for instance: " + instanceId + e.getErrorMessage() + e.getErrorCode()); - } - - // Starting the Instance - StartInstancesRequest startInstancesRequest = new StartInstancesRequest().withInstanceIds(instanceId); - - ec2Client.startInstances(startInstancesRequest); return node; } - @Override public BubbleNode cleanupStart(@NonNull BubbleNode node) throws Exception { + @Override public BubbleNode cleanupStart(BubbleNode node) throws Exception { deleteEC2KeyPair(node); return node; } @@ -176,14 +194,14 @@ public class AmazonEC2Driver extends ComputeServiceDriverBase { return node; } - @Override public BubbleNode status(@NonNull BubbleNode node) throws Exception { + @Override public BubbleNode status(BubbleNode node) throws Exception { final List found = listNodes(); if (found.isEmpty()) { return node.setState(BubbleNodeState.stopped); } else { boolean isFound = false; for (BubbleNode foundNode : found) { - if (foundNode.getTag(TAG_INSTANCE_ID).equals(node.getTag(TAG_NODE_UUID))) { + if (foundNode.getTag(TAG_INSTANCE_ID).equals(node.getTag(TAG_INSTANCE_ID))) { node.setState(foundNode.getState()); isFound = true; break; @@ -194,10 +212,10 @@ public class AmazonEC2Driver extends ComputeServiceDriverBase { return node; } - private void deleteEC2KeyPair(@NonNull BubbleNode node) throws Exception { + private void deleteEC2KeyPair(BubbleNode node) throws Exception { if (node.hasTag(TAG_SSH_KEY_ID)) { DeleteKeyPairRequest request = new DeleteKeyPairRequest() - .withKeyName(node.getUuid()); + .withKeyName(KEY_NAME_PREFIX + node.getUuid()); // destroy key, check response final AmazonEC2 ec2Client = getEc2Client(); @@ -214,10 +232,13 @@ public class AmazonEC2Driver extends ComputeServiceDriverBase { node.setSshKey(newRsaKeyPair()); final AmazonEC2 ec2Client = getEc2Client(); - ImportKeyPairRequest importKeyPairRequest = new ImportKeyPairRequest(node.getUuid(), node.getSshKey().getSshPublicKey()); + ImportKeyPairRequest importKeyPairRequest = new ImportKeyPairRequest( + KEY_NAME_PREFIX + node.getUuid(), node.getSshKey().getSshPublicKey() + ); ImportKeyPairResult importKeyPairResult = ec2Client.importKeyPair(importKeyPairRequest); if (importKeyPairResult.getSdkHttpMetadata().getHttpStatusCode() != OK) { - return die("registerSshKey: error creating keyPair: " + importKeyPairResult.getSdkHttpMetadata().getAllHttpHeaders()); + return die("registerSshKey: error creating keyPair: " + + importKeyPairResult.getSdkHttpMetadata().getAllHttpHeaders()); } return importKeyPairResult.getKeyFingerprint(); } diff --git a/bubble-server/src/main/resources/models/defaults/cloudService.json b/bubble-server/src/main/resources/models/defaults/cloudService.json index 0c1905b7..eb5d7737 100644 --- a/bubble-server/src/main/resources/models/defaults/cloudService.json +++ b/bubble-server/src/main/resources/models/defaults/cloudService.json @@ -273,7 +273,7 @@ "driverConfig": { "regions": [{ "name": "US_WEST_2", "description": "US West (Oregon)", - "location": {"country": "US", "lat": "43.8041", "lon": "120.5542"} + "location": {"country": "US", "lat": "45.5272", "lon": "122.9361"} }], "sizes": [ {"name": "small", "type": "small", "internalName": "t2.micro", "vcpu": 1, "memoryMB": 1024, "ssdGB": 0}, diff --git a/bubble-server/src/test/resources/models/system/cloudService.json b/bubble-server/src/test/resources/models/system/cloudService.json index a34bd5b0..84683469 100644 --- a/bubble-server/src/test/resources/models/system/cloudService.json +++ b/bubble-server/src/test/resources/models/system/cloudService.json @@ -241,7 +241,7 @@ "driverConfig": { "regions": [{ "name": "US_WEST_2", "description": "US West (Oregon)", - "location": {"country": "US", "lat": "43.8041", "lon": "120.5542"} + "location": {"country": "US", "lat": "45.5272", "lon": "122.9361"} }], "sizes": [ {"name": "small", "type": "small", "internalName": "t2.micro", "vcpu": 1, "memoryMB": 1024, "ssdGB": 0},