package com.hubspot.blazar.resources; import javax.inject.Inject; import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; import javax.ws.rs.NotFoundException; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response.Status; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Optional; import com.hubspot.blazar.base.LogChunk; import com.hubspot.blazar.base.ModuleBuild; import com.hubspot.blazar.base.ModuleBuild.State; import com.hubspot.blazar.data.service.ModuleBuildService; import com.hubspot.blazar.exception.LogNotFoundException; import com.hubspot.blazar.externalservice.BuildClusterService; import com.hubspot.horizon.AsyncHttpClient; @Path("/modules/builds") @Produces(MediaType.APPLICATION_JSON) public class ModuleBuildResource { private static final Logger LOG = LoggerFactory.getLogger(ModuleBuildResource.class); private static final String BUILD_LOG_NAME = "service.log"; private final BuildClusterService buildClusterService; private final ModuleBuildService moduleBuildService; private final AsyncHttpClient asyncHttpClient; @Inject public ModuleBuildResource(BuildClusterService buildClusterService, ModuleBuildService moduleBuildService, AsyncHttpClient asyncHttpClient) { this.buildClusterService = buildClusterService; this.moduleBuildService = moduleBuildService; this.asyncHttpClient = asyncHttpClient; } @GET @Path("/{id}") public Optional<ModuleBuild> get(@PathParam("id") long moduleBuildId) { return moduleBuildService.get(moduleBuildId); } @PUT @Path("/{id}/start") public ModuleBuild start(@PathParam("id") long moduleBuildId, @QueryParam("taskId") Optional<String> taskId) { if (!taskId.isPresent()) { throw new IllegalArgumentException("Task ID is required"); } return moduleBuildService.setStateToLaunching(moduleBuildId, taskId.get()); } @PUT @Path("/{id}/success") public ModuleBuild completeSuccess(@PathParam("id") long moduleBuildId) { return moduleBuildService.setStateToSucceded(moduleBuildId); } @PUT @Path("/{id}/failure") public ModuleBuild completeFailure(@PathParam("id") long moduleBuildId) { return moduleBuildService.setStateToFailed(moduleBuildId); } @GET @Path("/{id}/log") public LogChunk getLog(@PathParam("id") long moduleBuildId, @QueryParam("offset") @DefaultValue("0") long offset, @QueryParam("length") @DefaultValue("65536") long length) throws Exception { try { ModuleBuild moduleBuild = getBuildWithError(moduleBuildId); return buildClusterService.getBuildContainerLog(moduleBuild, offset, length); } catch (LogNotFoundException e) { throw new NotFoundException(e.getMessage(), e); } catch (NotFoundException e) { throw e; } catch (Exception e) { throw new WebApplicationException(String.format("An error occurred while retrieving the log for module build %d. The error is: %s", moduleBuildId, e.getMessage()), Status.INTERNAL_SERVER_ERROR); } } @GET @Path("/{id}/log/size") public Object getLogSize(@PathParam("id") long moduleBuildId) { try { ModuleBuild moduleBuild = getBuildWithError(moduleBuildId); long logFileSize = buildClusterService.getBuildContainerLogSize(moduleBuild); return new Object() { public long getSize() { return logFileSize; } }; } catch (LogNotFoundException e) { throw new NotFoundException(e.getMessage(), e); } catch (NotFoundException e) { throw e; } catch (Exception e) { throw new WebApplicationException(String.format("An error occurred while retrieving the log size for module build %d. The error is: %s", moduleBuildId, e.getMessage()), Status.INTERNAL_SERVER_ERROR); } } @GET @Path("{id}/log/download-url") public Object getLogDownloadUrl(@PathParam("id") long moduleBuildId) { try { ModuleBuild moduleBuild = getBuildWithError(moduleBuildId); String buildLogUrl = buildClusterService.getBuildContainerLogUrl(moduleBuild); return new Object() { public String getDownloadUrl() { return buildLogUrl; } }; } catch (LogNotFoundException e) { throw new NotFoundException(e.getMessage(), e); } catch (NotFoundException e) { throw e; } catch (Exception e) { throw new WebApplicationException(String.format("An error occurred while retrieving the log url for module build %d. The error is: %s", moduleBuildId, e.getMessage()), Status.INTERNAL_SERVER_ERROR); } } private ModuleBuild getBuildWithError(long moduleBuildId) { Optional<ModuleBuild> maybeBuild = get(moduleBuildId); if (maybeBuild.isPresent()) { return maybeBuild.get(); } else { throw new NotFoundException("No module build found with id: " + moduleBuildId); } } private ModuleBuild getBuildWithExpectedState(long moduleBuildId, State expected) { ModuleBuild build = getBuildWithError(moduleBuildId); if (build.getState() == expected) { return build; } else { throw new IllegalStateException(String.format("Build is in state %s, expected %s", build.getState(), expected)); } } }