package io.fathom.cloud.compute.services; import io.fathom.cloud.Clock; import io.fathom.cloud.CloudException; import io.fathom.cloud.compute.scheduler.InstanceScheduler; import io.fathom.cloud.compute.scheduler.SchedulerHost; import io.fathom.cloud.compute.state.ComputeRepository; import io.fathom.cloud.protobuf.CloudModel.InstanceData; import io.fathom.cloud.server.model.Project; import io.fathom.cloud.state.NumberedItemCollection; import java.io.IOException; import java.util.Date; 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.fathomdb.TimeSpan; import com.google.common.base.Strings; import com.google.inject.persist.Transactional; @Singleton @Transactional public class Instances { private static final Logger log = LoggerFactory.getLogger(Instances.class); @Inject ComputeRepository repository; @Inject InstanceScheduler scheduler; public void purgeDeletedInstances(TimeSpan age) throws CloudException { for (long projectId : repository.listInstanceProjects()) { try { purgeDeletedInstances(projectId, age); } catch (Exception e) { log.error("Error while purging instances for project: " + projectId, e); } } } public void purgeDeletedInstances(long projectId, TimeSpan age) throws CloudException { for (InstanceData instance : repository.getInstances(projectId).list()) { boolean delete = false; switch (instance.getInstanceState()) { case TERMINATED: { Date deletedAt = Clock.toDate(instance.getTerminatedAt()); if (age.hasTimedOut(deletedAt)) { delete = true; } break; } default: continue; } if (delete) { log.info("Purging instance: {}", instance.getId()); try { purgeInstance(instance); } catch (Exception e) { log.error("Error while purging instance: " + instance.getId(), e); } } } } private void purgeInstance(InstanceData instance) throws IOException, CloudException { SchedulerHost host = scheduler.findHost(instance.getHostId()); if (host == null) { throw new IllegalStateException("No host for instance"); } String hostCookie = instance.getHostCookie(); if (Strings.isNullOrEmpty(hostCookie)) { throw new IllegalStateException("No container for instance"); } UUID containerId = UUID.fromString(hostCookie); host.purgeInstance(containerId); // TODO: Should we delete entirely? Maybe after a certain amount of // time? Maybe as part of an accounting sweep? } public InstanceData updateInstance(Project project, long id, String name) throws CloudException { NumberedItemCollection<InstanceData> store = repository.getInstances(project.getId()); InstanceData instance = store.find(id); if (instance == null) { throw new WebApplicationException(Status.NOT_FOUND); } InstanceData.Builder b = InstanceData.newBuilder(instance); b.setName(name); return store.update(b); } }