package io.fathom.cloud.compute.metadata; import io.fathom.cloud.CloudException; import io.fathom.cloud.compute.services.ComputeServices; import io.fathom.cloud.protobuf.CloudModel.InstanceData; import io.fathom.cloud.protobuf.CloudModel.InstanceState; import io.fathom.cloud.protobuf.CloudModel.KeyPairData; import io.fathom.cloud.protobuf.CloudModel.MetadataData; import io.fathom.cloud.protobuf.CloudModel.MetadataEntryData; import io.fathom.cloud.protobuf.CloudModel.NetworkAddressData; import io.fathom.cloud.server.resources.FathomCloudResourceBase; import io.fathom.cloud.services.AuthService; import java.net.Inet6Address; import java.net.InetAddress; import java.util.List; import javax.inject.Inject; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response.Status; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Joiner; import com.google.common.collect.Lists; import com.google.common.net.InetAddresses; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.google.inject.persist.Transactional; @Path("/openstack/metadata") @Transactional public class MetadataResource extends FathomCloudResourceBase { private static final Logger log = LoggerFactory.getLogger(MetadataResource.class); @Inject ComputeServices computeServices; @Inject AuthService authServices; private InstanceData getInstance() throws CloudException { String remoteAddr = httpRequest.getRemoteAddr(); InetAddress remoteAddress = InetAddresses.forString(remoteAddr); InstanceData instance = computeServices.findInstanceByAddress(remoteAddress); if (instance == null) { throw new WebApplicationException(Status.FORBIDDEN); } return instance; } @Path("openstack/{version}/meta_data.json") @GET @Produces({ JSON }) public JsonElement getOpenstackMetadata() throws CloudException { InstanceData instance = getInstance(); String identityUri = "http://[fd00::c10d]:8080/openstack/identity/"; // String identityUri = authServices.getIdentityUri(baseUrl); // String uuid = UUID.randomUUID().toString(); JsonObject o = new JsonObject(); o.addProperty("uuid", instance.getId()); o.addProperty("identity_uri", identityUri); JsonObject meta = new JsonObject(); MetadataData metadata = instance.getMetadata(); for (MetadataEntryData entry : metadata.getEntryList()) { meta.addProperty(entry.getKey(), entry.getValue()); } o.add("meta", meta); return o; } @Path("openstack/{version}/secret/{key}") @GET public byte[] getSecret(@PathParam("key") String key) throws CloudException { InstanceData instance = getInstance(); byte[] secretData = computeServices.getSecret(instance.getProjectId(), instance.getId(), key); if (secretData == null) { throw new WebApplicationException(Status.NOT_FOUND); } return secretData; } @Path("openstack/{version}/user_data") @GET @Produces({ JSON }) public JsonElement getOpenstackUserData() { throw new UnsupportedOperationException(); } @Path("openstack/{version}/peers") @GET @Produces({ JSON }) public JsonArray getOpenstackPeers() throws CloudException { InstanceData instance = getInstance(); JsonArray ret = new JsonArray(); for (InstanceData peer : computeServices.getPeers(instance)) { // TODO: Should we skip ourselves?? if (peer.getId() == instance.getId()) { continue; } // TODO: Return a typed object InstanceState state = peer.getInstanceState(); if (state != null) { switch (state) { case TERMINATED: case STOPPED: case STOPPING: continue; } } JsonObject o = new JsonObject(); JsonArray addresses = new JsonArray(); for (NetworkAddressData address : peer.getNetwork().getAddressesList()) { if (!address.getPublicAddress()) { continue; } InetAddress inetAddress = InetAddresses.forString(address.getIp()); if (inetAddress instanceof Inet6Address) { addresses.add(new JsonPrimitive(InetAddresses.toAddrString(inetAddress))); } } o.add("addresses", addresses); ret.add(o); } return ret; } @GET public String getEc2Versions() { List<String> versions = Lists.newArrayList(); versions.add("1.0"); versions.add("2007-01-19"); versions.add("2007-03-01"); versions.add("2007-08-29"); versions.add("2007-10-10"); versions.add("2007-12-15"); versions.add("2008-02-01"); versions.add("2008-09-01"); versions.add("2009-04-04"); versions.add("2011-01-01"); versions.add("2011-05-01"); versions.add("2012-01-12"); return Joiner.on("\n").join(versions); } @Path("{version}") @GET public String getEc2Sections() { List<String> sections = Lists.newArrayList(); sections.add("dynamic"); sections.add("meta-data"); return Joiner.on("\n").join(sections); } @Path("{version}/meta-data") @GET public String getEc2MetadataKeys() { List<String> keys = Lists.newArrayList(); keys.add("ami-id"); keys.add("ami-launch-index"); keys.add("ami-manifest-path"); keys.add("block-device-mapping/"); keys.add("hostname"); keys.add("instance-action"); keys.add("instance-id"); keys.add("instance-type"); keys.add("kernel-id"); keys.add("local-hostname"); keys.add("local-ipv4"); keys.add("mac"); keys.add("metrics/"); keys.add("network/"); keys.add("placement/"); keys.add("product-codes"); keys.add("profile"); keys.add("public-hostname"); keys.add("public-ipv4"); keys.add("public-keys/"); keys.add("reservation-id"); return Joiner.on("\n").join(keys); } @Path("{version}/meta-data/{key}") @GET public String getEc2MetadataValue(@PathParam("key") String key) throws CloudException { InstanceData instance = getInstance(); if (key.equals("public-keys")) { if (instance.hasKeyPair()) { KeyPairData keyPair = instance.getKeyPair(); String name = keyPair.getKey(); String s = "0=" + name; return s; } } log.warn("Unsupported ec2 metadata key: {}", key); throw new WebApplicationException(Status.NOT_FOUND); } @Path("{version}/meta-data/{key}/{index}/{subkey}") @GET public String getEc2MetadataArrayValue(@PathParam("key") String key, @PathParam("index") int index, @PathParam("subkey") String subkey) throws CloudException { InstanceData instance = getInstance(); if (key.equals("public-keys")) { if (subkey.equals("openssh-key")) { if (index == 0 && instance.hasKeyPair()) { KeyPairData keyPair = instance.getKeyPair(); String s = keyPair.getPublicKey(); return s; } } } log.warn("Unsupported ec2 metadata key: {}", key); throw new WebApplicationException(Status.NOT_FOUND); } }