package io.fathom.cloud.compute.api.aws.ec2.actions; import io.fathom.cloud.CloudException; import io.fathom.cloud.compute.api.aws.ec2.AwsRequestContext; import io.fathom.cloud.compute.api.aws.ec2.model.Group; import io.fathom.cloud.compute.api.aws.ec2.model.Instance; import io.fathom.cloud.compute.api.aws.ec2.model.Instance.Monitoring; import io.fathom.cloud.compute.api.aws.ec2.model.Instance.Placement; import io.fathom.cloud.compute.api.aws.ec2.model.Instance.StateReason; import io.fathom.cloud.compute.api.aws.ec2.model.InstanceState; import io.fathom.cloud.compute.state.ComputeRepository; import io.fathom.cloud.protobuf.CloudModel; import io.fathom.cloud.protobuf.CloudModel.InstanceData; import io.fathom.cloud.protobuf.CloudModel.InstanceNetworkData; import io.fathom.cloud.protobuf.CloudModel.NetworkAddressData; import io.fathom.cloud.protobuf.CloudModel.ReservationData; import io.fathom.cloud.protobuf.CloudModel.SecurityGroupData; import io.fathom.cloud.server.model.Project; import io.fathom.cloud.server.model.User; import java.util.Date; import java.util.List; import javax.inject.Inject; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response.Status; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Lists; public abstract class AwsActionHandler { private static final Logger log = LoggerFactory.getLogger(AwsActionHandler.class); @Inject ComputeRepository instanceStateStore; private MultivaluedMap<String, String> formParameters; private AwsRequestContext context; public void init(AwsRequestContext context, MultivaluedMap<String, String> formParameters) { this.context = context; this.formParameters = formParameters; } public abstract Object go() throws CloudException; public int get(String key, int defaultValue) { String value = find(key); if (value == null) { return defaultValue; } return Integer.valueOf(value); } public String get(String key) { String value = find(key); if (value == null) { throw new WebApplicationException(Status.BAD_REQUEST); } return value; } public List<String> getList(String key) { List<String> value = findList(key); if (value == null) { throw new WebApplicationException(Status.BAD_REQUEST); } return value; } public List<String> findList(String key) { List<String> values = Lists.newArrayList(); int i = 1; while (true) { String value = find(key + "." + i); if (value == null) { break; } values.add(value); i++; } return values; } private String find(String key) { String value = formParameters.getFirst(key); return value; } public String getRequestId() { return context.getRequestId(); } protected User findUser() throws CloudException { throw new UnsupportedOperationException(); // CredentialInfo credential = getCredential(); // UserData user = authStore.getUsers().find(credential.getUserId()); // return user; } protected User getUser() throws CloudException { User user = findUser(); if (user == null) { throw new WebApplicationException(Status.UNAUTHORIZED); } return user; } protected Project findProject() throws CloudException { throw new UnsupportedOperationException(); // UserData user = getUser(); // if (user.getProjectIdsCount() == 0) { // return null; // } // // long projectId = user.getProjectIds(0); // // return authStore.getProjects().find(projectId); } protected Project getProject() throws CloudException { Project project = findProject(); if (project == null) { throw new IllegalStateException(); } return null; } // protected CredentialInfo getCredential() throws CloudException { // String accessKey = get("AWSAccessKeyId"); // // CredentialInfo credential = authStore.findCredential( // AuthStore.ACCESS_KEY_ID, accessKey); // // log.warn("TODO: Verify signature"); // // if (credential == null) { // throw new WebApplicationException(Status.FORBIDDEN); // } // // return credential; // } public static String toEc2ReservationId(long id) { String s = toHex8(id); return "r-" + s; } public static long decodeEc2Id(String id) { int dashIndex = id.indexOf('-'); if (dashIndex == -1) { throw new IllegalArgumentException(); } String hex = id.substring(dashIndex + 1); return Long.parseLong(hex, 16); } public static long decodeEc2Id(String prefix, String id) { if (!id.startsWith(prefix)) { throw new IllegalArgumentException(); } String hex = id.substring(prefix.length()); return Long.parseLong(hex, 16); } public static String toEc2InstanceId(long id) { String s = toHex8(id); return "i-" + s; } public static String toEc2ImageId(long id) { String s = toHex8(id); return "ami-" + s; } public static String toEc2SecurityGroupId(long id) { String s = toHex8(id); return "sg-" + s; } public static String toEc2Owner(long user) { return Long.toString(user); } private static String toHex8(long id) { String s = Long.toHexString(id); int length = s.length(); if (length > 8) { throw new IllegalStateException(); } if (s.length() != 8) { s = "00000000".substring(s.length()) + s; } return s; } protected Instance buildRunningInstanceXml(ReservationData reservationInfo, InstanceData instanceInfo) { Instance instance = new Instance(); instance.instanceId = toEc2InstanceId(instanceInfo.getId()); instance.imageId = toEc2ImageId(reservationInfo.getImageId()); instance.instanceState = buildInstanceState(instanceInfo); switch (instanceInfo.getInstanceState()) { case PENDING: instance.stateReason = new StateReason(); instance.stateReason.code = "pending"; instance.stateReason.message = "pending"; break; case RUNNING: break; case TERMINATED: break; default: throw new IllegalStateException(); } instance.instanceType = "m1.small"; Date launchTime = new Date(instanceInfo.getLaunchTime()); instance.launchTime = launchTime; instance.placement = new Placement(); instance.placement.availabilityZone = "main"; instance.placement.tenancy = "default"; instance.monitoring = new Monitoring(); instance.monitoring.state = "disabled"; instance.architecture = "x86_64"; instance.rootDeviceType = "instance-store"; instance.virtualizationType = "paravirtual"; instance.hypervisor = "xen"; instance.ebsOptimized = false; if (instanceInfo.hasNetwork()) { InstanceNetworkData network = instanceInfo.getNetwork(); NetworkAddressData bestPublic = null; NetworkAddressData bestPrivate = null; for (NetworkAddressData address : network.getAddressesList()) { if (address.getPublicAddress()) { if (bestPublic == null) { bestPublic = address; } else { log.warn("Selection between public addresses is primitive"); } } else { if (bestPrivate == null) { bestPrivate = address; } else { log.warn("Selection between private addresses is primitive"); } } } if (bestPublic != null) { instance.ipAddress = bestPublic.getIp(); } if (bestPrivate != null) { instance.privateIpAddress = bestPrivate.getIp(); } } return instance; } protected InstanceState buildInstanceState(InstanceData instanceInfo) { CloudModel.InstanceState state = instanceInfo.getInstanceState(); return buildInstanceState(state); } protected InstanceState buildInstanceState(CloudModel.InstanceState state) { InstanceState instanceState = new InstanceState(); switch (state) { case PENDING: instanceState.code = 0; instanceState.name = "pending"; break; case RUNNING: instanceState.code = 16; instanceState.name = "running"; break; case SHUTTING_DOWN: instanceState.code = 32; instanceState.name = "shutting-down"; break; case TERMINATED: instanceState.code = 48; instanceState.name = "terminated"; break; default: throw new IllegalStateException(); } return instanceState; } protected List<Group> buildGroupsXml(List<SecurityGroupData> groups) { List<Group> xml = Lists.newArrayList(); for (SecurityGroupData group : groups) { Group groupXml = new Group(); xml.add(groupXml); groupXml.groupId = toEc2SecurityGroupId(group.getId()); groupXml.groupName = group.getName(); } return xml; } protected List<SecurityGroupData> getSecurityGroups() { throw new UnsupportedOperationException(); // List<SecurityGroupData> groups = Lists.newArrayList(); // // { // SecurityGroupData.Builder g = SecurityGroupData.newBuilder(); // g.setId(1234); // g.setName("default"); // groups.add(g.build()); // } // return groups; } }