/*******************************************************************************
* Copyright (c) 2012-2015 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.runner;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.rest.Service;
import org.eclipse.che.api.core.rest.annotations.Description;
import org.eclipse.che.api.core.rest.annotations.GenerateLink;
import org.eclipse.che.api.core.rest.shared.dto.Link;
import org.eclipse.che.api.runner.dto.ApplicationProcessDescriptor;
import org.eclipse.che.api.runner.dto.RunnerDescriptor;
import org.eclipse.che.api.runner.dto.RunnerServer;
import org.eclipse.che.api.runner.dto.RunnerServerLocation;
import org.eclipse.che.api.runner.dto.RunnerServerRegistration;
import org.eclipse.che.api.runner.internal.Constants;
import org.eclipse.che.dto.server.DtoFactory;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
import com.wordnik.swagger.annotations.ApiResponse;
import com.wordnik.swagger.annotations.ApiResponses;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.security.RolesAllowed;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
/**
* RESTful API for administration.
*
* @author andrew00x
*/
@Api(value = "/admin/runner",
description = "Runner manager (admin)")
@Path("/admin/runner")
@Description("Runner administration REST API")
@RolesAllowed("system/admin")
public class RunnerAdminService extends Service {
private static final Logger LOG = LoggerFactory.getLogger(RunnerAdminService.class);
@Inject
private RunQueue runner;
@ApiOperation(value = "Register a new runner",
notes = "Register a new runner service",
response = RunnerServerRegistration.class,
position = 1)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 403, message = "User not authorized to call this method"),
@ApiResponse(code = 500, message = "Internal Server Error")})
@GenerateLink(rel = Constants.LINK_REL_REGISTER_RUNNER_SERVER)
@POST
@Path("/server/register")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response registerRunnerServer(@ApiParam(value = "JSON with runner location and options")
RunnerServerRegistration registration) throws Exception {
runner.registerRunnerServer(registration);
return Response.status(Response.Status.OK).build();
}
@ApiOperation(value = "Unregister runner",
notes = "Unregister runner service",
response = RunnerServerLocation.class,
position = 2)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 403, message = "User not authorized to call this method"),
@ApiResponse(code = 500, message = "Internal Server Error")})
@GenerateLink(rel = Constants.LINK_REL_UNREGISTER_RUNNER_SERVER)
@POST
@Path("/server/unregister")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response unregisterRunnerServer(@ApiParam(value = "Location of a runner to unregister", required = true)
RunnerServerLocation location) throws Exception {
runner.unregisterRunnerServer(location);
return Response.status(Response.Status.OK).build();
}
private static final String[] SERVER_LINK_RELS = new String[]{Constants.LINK_REL_AVAILABLE_RUNNERS,
Constants.LINK_REL_SERVER_STATE,
Constants.LINK_REL_RUNNER_STATE};
@ApiOperation(value = "Get all registered runners",
notes = "Get all registered runners",
response = RunnerServer.class,
responseContainer = "List",
position = 3)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 403, message = "User not authorized to call this method"),
@ApiResponse(code = 500, message = "Internal Server Error")})
@GenerateLink(rel = Constants.LINK_REL_REGISTERED_RUNNER_SERVER)
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/server")
public List<RunnerServer> getRegisteredServers() {
final List<RemoteRunnerServer> runnerServers = runner.getRegisterRunnerServers();
final List<RunnerServer> result = new LinkedList<>();
final DtoFactory dtoFactory = DtoFactory.getInstance();
for (RemoteRunnerServer runnerServer : runnerServers) {
final RunnerServer runnerServerDTO = dtoFactory.createDto(RunnerServer.class);
runnerServerDTO.withUrl(runnerServer.getBaseUrl());
try {
runnerServerDTO.withDedicated(runnerServer.isDedicated())
.withWorkspace(runnerServer.getAssignedWorkspace())
.withProject(runnerServer.getAssignedProject());
final List<Link> adminLinks = new LinkedList<>();
for (String linkRel : SERVER_LINK_RELS) {
final Link link = runnerServer.getLink(linkRel);
if (link != null) {
if (Constants.LINK_REL_RUNNER_STATE.equals(linkRel)) {
for (RunnerDescriptor runner : runnerServer.getRunnerDescriptors()) {
final String href = link.getHref();
final String hrefWithRunner = href + ((href.indexOf('?') > 0 ? '&' : '?') + "runner=" + runner.getName());
final Link linkCopy = dtoFactory.clone(link);
linkCopy.getParameters().clear();
linkCopy.setHref(hrefWithRunner);
adminLinks.add(linkCopy);
}
} else {
adminLinks.add(link);
}
}
}
runnerServerDTO.withDescription(runnerServer.getServiceDescriptor().getDescription())
.withServerState(runnerServer.getServerState())
.withLinks(adminLinks);
} catch (IOException | ServerException e) {
LOG.error(e.getMessage(), e);
}
result.add(runnerServerDTO);
}
return result;
}
@ApiOperation(value = "Check runner queue",
notes = "Check runner queue. JSON with queue state and details is returned",
response = ApplicationProcessDescriptor.class,
responseContainer = "List",
position = 4)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 403, message = "User not authorized to call this method"),
@ApiResponse(code = 500, message = "Internal Server Error")})
@GenerateLink(rel = Constants.LINK_REL_RUNNER_TASKS)
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/queue")
public List<ApplicationProcessDescriptor> getTasks() throws Exception {
final List<ApplicationProcessDescriptor> result = new LinkedList<>();
for (RunQueueTask queueTask : runner.getTasks()) {
final ApplicationProcessDescriptor descriptor = queueTask.getDescriptor();
final RemoteRunnerProcess remoteProcess = queueTask.getRemoteProcess();
if (remoteProcess != null) {
descriptor.setServerUrl(remoteProcess.getServerUrl());
}
result.add(descriptor);
}
return result;
}
}