package io.fathom.cloud.compute.services;
import io.fathom.cloud.CloudException;
import io.fathom.cloud.blobs.BlobData;
import io.fathom.cloud.blobs.TempFile;
import io.fathom.cloud.compute.api.os.model.actions.CreateImageRequest;
import io.fathom.cloud.compute.scheduler.InstanceScheduler;
import io.fathom.cloud.compute.scheduler.SchedulerHost;
import io.fathom.cloud.compute.scheduler.SchedulerHost.SchedulerHostNetwork;
import io.fathom.cloud.compute.state.ComputeRepository;
import io.fathom.cloud.protobuf.CloudModel.InstanceData;
import io.fathom.cloud.protobuf.CloudModel.NetworkAddressData;
import io.fathom.cloud.protobuf.CloudModel.ReservationData;
import io.fathom.cloud.server.auth.Auth;
import io.fathom.cloud.server.auth.Auth.Domain;
import io.fathom.cloud.server.model.Project;
import io.fathom.cloud.services.ImageService;
import java.io.IOException;
import java.net.InetAddress;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response.Status;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.net.InetAddresses;
import com.google.inject.persist.Transactional;
@Transactional
@Singleton
public class ComputeServices {
private static final Logger log = LoggerFactory.getLogger(ComputeServices.class);
@Inject
ComputeRepository computeRepository;
@Inject
InstanceScheduler scheduler;
@Inject
ImageService imageService;
public List<InstanceData> listInstances(Auth auth, Project project) throws CloudException {
List<InstanceData> instances = Lists.newArrayList();
if (project == null) {
Domain domainAdmin = auth.findDomainWithAdminRole();
if (domainAdmin == null) {
throw new WebApplicationException(Status.FORBIDDEN);
}
for (long projectId : computeRepository.listInstanceProjects()) {
if (auth.checkProject(projectId)) {
listInstances(instances, projectId);
}
}
} else {
if (!auth.checkProject(project.getId())) {
throw new WebApplicationException(Status.NOT_FOUND);
}
listInstances(instances, project.getId());
}
return instances;
}
// private Auth getAuth() {
// Auth auth = authProvider.get();
// if (auth == null) {
// throw new WebApplicationException(Status.UNAUTHORIZED);
// }
// return auth;
// }
void listInstances(List<InstanceData> dest, long projectId) throws CloudException {
for (InstanceData instance : computeRepository.getInstances(projectId).list()) {
switch (instance.getInstanceState()) {
case TERMINATED:
continue;
default:
break;
}
dest.add(instance);
}
}
public InstanceData findInstance(long projectId, long instanceId) throws CloudException {
return computeRepository.getInstances(projectId).find(instanceId);
}
public byte[] getSecret(long projectId, long instanceId, String key) throws CloudException {
InstanceData instance = findInstance(projectId, instanceId);
if (instance == null) {
return null;
}
SchedulerHost host = scheduler.findHost(instance.getHostId());
if (host == null) {
return null;
}
String hostCookie = instance.getHostCookie();
UUID containerId = UUID.fromString(hostCookie);
byte[] secretData;
try {
secretData = host.getSecret(containerId, key);
} catch (IOException e) {
throw new CloudException("Error reading secret", e);
}
return secretData;
}
public InstanceData findInstanceByAddress(InetAddress address) throws CloudException {
SchedulerHostNetwork network = scheduler.findHostByAddress(address);
if (network == null) {
return null;
}
String ip = InetAddresses.toAddrString(address);
NetworkAddressData addressInfo = computeRepository.getHostIps(network.getHost().getId(), network.getKey())
.find(ip);
if (addressInfo == null) {
return null;
}
long projectId = addressInfo.getProjectId();
long instanceId = addressInfo.getInstanceId();
if (projectId == 0 || instanceId == 0) {
return null;
}
InstanceData instance = computeRepository.getInstances(projectId).find(instanceId);
if (instance == null) {
return null;
}
return instance;
// if (addressInfo.get)
// VirtualIpData vip =
// computeRepository.getAllocatedVips(pool.getId()).find(address);
// if (vip == null) {
// continue;
// }
//
// if (vip.getProjectId() != project.getId()) {
// continue;
// }
//
// return new VirtualIp(pool, vip);
// }
// }
// }
// }
}
/**
* Returns instances in same project; we are experimenting with exposing
* this through the metadata service
*/
public List<InstanceData> getPeers(InstanceData instance) throws CloudException {
return computeRepository.getInstances(instance.getProjectId()).list();
}
/**
* Creates a disk image from a container
*/
public ImageService.Image createImage(Project project, InstanceData instance, CreateImageRequest request)
throws IOException, CloudException {
// TODO: The spec (?) says this call is async.
// We would probably do better to spend the effort to make it really
// fast instead (BtrFS?)
SchedulerHost host = scheduler.findHost(instance.getHostId());
if (host == null) {
throw new IllegalStateException();
}
String hostCookie = instance.getHostCookie();
log.warn("createImage is inefficient - we should support side-load");
Map<String, String> metadata = Maps.newHashMap();
if (request.metadata != null) {
metadata.putAll(request.metadata);
}
if (request.name != null) {
metadata.put(ImageService.METADATA_KEY_NAME, request.name);
}
metadata.put(ImageService.METADATA_KEY_CONTAINER_FORMAT, "tar");
metadata.put(ImageService.METADATA_KEY_DISK_FORMAT, "raw");
UUID containerId = UUID.fromString(hostCookie);
try (TempFile snapshot = host.createImage(containerId)) {
ImageService.Image image = imageService.createImage(instance.getProjectId(), metadata);
BlobData blobData = BlobData.build(snapshot.getFile());
image = imageService.uploadData(image, blobData);
return image;
}
}
public ReservationData createReservation(Auth auth, Project project, ReservationData.Builder b)
throws CloudException {
return computeRepository.getReservations(project).create(b);
}
public InstanceData createInstance(Auth auth, Project project, InstanceData.Builder b) throws CloudException {
return computeRepository.getInstances(project.getId()).create(b);
}
}