diff options
author | valerijf <valerijf@yahoo-inc.com> | 2017-03-09 15:11:07 +0100 |
---|---|---|
committer | valerijf <valerijf@yahoo-inc.com> | 2017-03-09 15:11:07 +0100 |
commit | 5930e8bc49b4d6314d9cedc6223791f091739717 (patch) | |
tree | c5f23cf9a5e7ddcb21a3dfbccd52edf668606d60 /node-maintainer | |
parent | 86d966c3e11389b2f4190f7a549528efd6a8f11f (diff) |
Removed node-maintainer REST API
Diffstat (limited to 'node-maintainer')
5 files changed, 140 insertions, 329 deletions
diff --git a/node-maintainer/src/main/application/services.xml b/node-maintainer/src/main/application/services.xml deleted file mode 100644 index 09effc10ebd..00000000000 --- a/node-maintainer/src/main/application/services.xml +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!-- Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. --> -<services version="1.0"> - <jdisc version="1.0" jetty="true"> - <http> - <server id='server1' port='19094' /> - </http> - <handler id="com.yahoo.vespa.hosted.node.maintainer.restapi.v1.MaintainerApiHandler" bundle="node-maintainer"> - <binding>http://*/maintainer/*</binding> - </handler> - </jdisc> -</services> diff --git a/node-maintainer/src/main/java/com/yahoo/vespa/hosted/node/maintainer/Maintainer.java b/node-maintainer/src/main/java/com/yahoo/vespa/hosted/node/maintainer/Maintainer.java index 7a502476e0f..919643f40ee 100644 --- a/node-maintainer/src/main/java/com/yahoo/vespa/hosted/node/maintainer/Maintainer.java +++ b/node-maintainer/src/main/java/com/yahoo/vespa/hosted/node/maintainer/Maintainer.java @@ -1,32 +1,166 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.node.maintainer; -import com.yahoo.container.logging.AccessLog; import com.yahoo.slime.ArrayTraverser; import com.yahoo.slime.Inspector; import com.yahoo.slime.Type; +import com.yahoo.system.ProcessExecuter; import com.yahoo.vespa.config.SlimeUtils; -import com.yahoo.vespa.hosted.node.maintainer.restapi.v1.MaintainerApiHandler; +import org.apache.http.impl.client.HttpClientBuilder; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; /** * @author freva */ public class Maintainer { + private static final CoreCollector coreCollector = new CoreCollector(new ProcessExecuter()); + private static final CoredumpHandler coredumpHandler = new CoredumpHandler(HttpClientBuilder.create().build(), coreCollector); + public static void main(String[] args) { if (args.length != 1) { throw new RuntimeException("Expected only 1 argument - a JSON list of maintainer jobs to execute"); } - MaintainerApiHandler handler = new MaintainerApiHandler(Runnable::run, AccessLog.voidAccessLog()); Inspector object = SlimeUtils.jsonToSlime(args[0].getBytes()).get(); if (object.type() != Type.ARRAY) { throw new IllegalArgumentException("Expected a list maintainer jobs to execute"); } object.traverse((ArrayTraverser) (int i, Inspector item) -> { - String type = handler.getFieldOrFail(item, "type").asString(); - Inspector arguments = handler.getFieldOrFail(item, "arguments"); - handler.parseMaintenanceJob(type, arguments); + String type = getFieldOrFail(item, "type").asString(); + Inspector arguments = getFieldOrFail(item, "arguments"); + parseMaintenanceJob(type, arguments); }); } + + private static void parseMaintenanceJob(String type, Inspector arguments) { + if (arguments.type() != Type.OBJECT) { + throw new IllegalArgumentException("Expected a 'arguments' to be an object"); + } + + switch (type) { + case "delete-files": + parseDeleteFilesJob(arguments); + break; + + case "delete-directories": + parseDeleteDirectoriesJob(arguments); + break; + + case "recursive-delete": + parseRecursiveDelete(arguments); + break; + + case "move-files": + parseMoveFiles(arguments); + break; + + case "handle-core-dumps": + parseHandleCoreDumps(arguments); + break; + + default: + throw new IllegalArgumentException("Unknown job: " + type); + } + } + + private static void parseDeleteFilesJob(Inspector arguments) { + Path basePath = Paths.get(getFieldOrFail(arguments, "basePath").asString()); + Duration maxAge = Duration.ofSeconds(getFieldOrFail(arguments, "maxAgeSeconds").asLong()); + Optional<String> fileNameRegex = SlimeUtils.optionalString(getFieldOrFail(arguments, "fileNameRegex")); + boolean recursive = getFieldOrFail(arguments, "recursive").asBool(); + try { + FileHelper.deleteFiles(basePath, maxAge, fileNameRegex, recursive); + } catch (IOException e) { + throw new RuntimeException("Failed deleting files under " + basePath.toAbsolutePath() + + fileNameRegex.map(regex -> ", matching '" + regex + "'").orElse("") + + ", " + (recursive ? "" : "not ") + "recursively" + + " and older than " + maxAge, e); + } + } + + private static void parseDeleteDirectoriesJob(Inspector arguments) { + Path basePath = Paths.get(getFieldOrFail(arguments, "basePath").asString()); + Duration maxAge = Duration.ofSeconds(getFieldOrFail(arguments, "maxAgeSeconds").asLong()); + Optional<String> dirNameRegex = SlimeUtils.optionalString(getFieldOrFail(arguments, "dirNameRegex")); + try { + FileHelper.deleteDirectories(basePath, maxAge, dirNameRegex); + } catch (IOException e) { + throw new RuntimeException("Failed deleting directories under " + basePath.toAbsolutePath() + + dirNameRegex.map(regex -> ", matching '" + regex + "'").orElse("") + + " and older than " + maxAge, e); + } + } + + private static void parseRecursiveDelete(Inspector arguments) { + Path basePath = Paths.get(getFieldOrFail(arguments, "path").asString()); + try { + FileHelper.recursiveDelete(basePath); + } catch (IOException e) { + throw new RuntimeException("Failed deleting " + basePath.toAbsolutePath(), e); + } + } + + private static void parseMoveFiles(Inspector arguments) { + Path from = Paths.get(getFieldOrFail(arguments, "from").asString()); + Path to = Paths.get(getFieldOrFail(arguments, "to").asString()); + + try { + FileHelper.moveIfExists(from, to); + } catch (IOException e) { + throw new RuntimeException("Failed moving from " + from.toAbsolutePath() + ", to " + to.toAbsolutePath(), e); + } + } + + private static void parseHandleCoreDumps(Inspector arguments) { + Path coredumpsPath = Paths.get(getFieldOrFail(arguments, "coredumpsPath").asString()); + Path doneCoredumpsPath = Paths.get(getFieldOrFail(arguments, "doneCoredumpsPath").asString()); + Map<String, Object> attributesMap = parseMap(getFieldOrFail(arguments, "attributes")); + + try { + coredumpHandler.removeJavaCoredumps(coredumpsPath); + coredumpHandler.processAndReportCoredumps(coredumpsPath, doneCoredumpsPath, attributesMap); + } catch (IOException e) { + throw new RuntimeException("Failed processing coredumps at " + coredumpsPath.toAbsolutePath() + + ", moving fished dumps to " + doneCoredumpsPath.toAbsolutePath(), e); + } + } + + private static Map<String, Object> parseMap(Inspector object) { + Map<String, Object> map = new HashMap<>(); + getFieldOrFail(object, "attributes").traverse((String key, Inspector value) -> { + switch (value.type()) { + case BOOL: + map.put(key, value.asBool()); + break; + case LONG: + map.put(key, value.asLong()); + break; + case DOUBLE: + map.put(key, value.asDouble()); + break; + case STRING: + map.put(key, value.asString()); + break; + default: + throw new IllegalArgumentException("Invalid attribute for key '" + key + "', value " + value); + } + }); + return map; + } + + private static Inspector getFieldOrFail(Inspector object, String key) { + Inspector out = object.field(key); + if (out.type() == Type.NIX) { + throw new IllegalArgumentException("Key '" + key + "' was not found!"); + } + return out; + } } diff --git a/node-maintainer/src/main/java/com/yahoo/vespa/hosted/node/maintainer/restapi/v1/ErrorResponse.java b/node-maintainer/src/main/java/com/yahoo/vespa/hosted/node/maintainer/restapi/v1/ErrorResponse.java deleted file mode 100644 index 702ef1e43d9..00000000000 --- a/node-maintainer/src/main/java/com/yahoo/vespa/hosted/node/maintainer/restapi/v1/ErrorResponse.java +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.node.maintainer.restapi.v1; - -import com.yahoo.container.jdisc.HttpResponse; -import com.yahoo.slime.Cursor; -import com.yahoo.slime.JsonFormat; -import com.yahoo.slime.Slime; - -import java.io.IOException; -import java.io.OutputStream; - -import static com.yahoo.jdisc.Response.Status.BAD_REQUEST; -import static com.yahoo.jdisc.Response.Status.INTERNAL_SERVER_ERROR; -import static com.yahoo.jdisc.Response.Status.METHOD_NOT_ALLOWED; -import static com.yahoo.jdisc.Response.Status.NOT_FOUND; - -public class ErrorResponse extends HttpResponse { - - private final Slime slime = new Slime(); - - public enum errorCodes { - NOT_FOUND, - BAD_REQUEST, - METHOD_NOT_ALLOWED, - INTERNAL_SERVER_ERROR - } - - public ErrorResponse(int code, String errorType, String message) { - super(code); - Cursor root = slime.setObject(); - root.setString("error-code", errorType); - root.setString("message", message); - } - - public static ErrorResponse notFoundError(String message) { - return new ErrorResponse(NOT_FOUND, errorCodes.NOT_FOUND.name(), message); - } - - public static ErrorResponse internalServerError(String message) { - return new ErrorResponse(INTERNAL_SERVER_ERROR, errorCodes.INTERNAL_SERVER_ERROR.name(), message); - } - - public static ErrorResponse badRequest(String message) { - return new ErrorResponse(BAD_REQUEST, errorCodes.BAD_REQUEST.name(), message); - } - - public static ErrorResponse methodNotAllowed(String message) { - return new ErrorResponse(METHOD_NOT_ALLOWED, errorCodes.METHOD_NOT_ALLOWED.name(), message); - } - - @Override - public void render(OutputStream stream) throws IOException { - new JsonFormat(true).encode(stream, slime); - } - - @Override - public String getContentType() { return "application/json"; } - -} diff --git a/node-maintainer/src/main/java/com/yahoo/vespa/hosted/node/maintainer/restapi/v1/MaintainerApiHandler.java b/node-maintainer/src/main/java/com/yahoo/vespa/hosted/node/maintainer/restapi/v1/MaintainerApiHandler.java deleted file mode 100644 index 7aa8b09c746..00000000000 --- a/node-maintainer/src/main/java/com/yahoo/vespa/hosted/node/maintainer/restapi/v1/MaintainerApiHandler.java +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.node.maintainer.restapi.v1; - -import com.yahoo.container.jdisc.HttpRequest; -import com.yahoo.container.jdisc.HttpResponse; -import com.yahoo.container.jdisc.LoggingRequestHandler; -import com.yahoo.container.logging.AccessLog; -import com.yahoo.io.IOUtils; -import com.yahoo.slime.ArrayTraverser; -import com.yahoo.slime.Inspector; -import com.yahoo.slime.Slime; -import com.yahoo.slime.Type; -import com.yahoo.system.ProcessExecuter; -import com.yahoo.vespa.config.SlimeUtils; -import com.yahoo.vespa.hosted.node.maintainer.CoreCollector; -import com.yahoo.vespa.hosted.node.maintainer.CoredumpHandler; -import com.yahoo.vespa.hosted.node.maintainer.FileHelper; -import com.yahoo.yolean.Exceptions; -import org.apache.http.impl.client.HttpClientBuilder; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.Duration; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.Executor; -import java.util.logging.Level; - - -/** - * @author freva - */ -public class MaintainerApiHandler extends LoggingRequestHandler { - private static final CoreCollector coreCollector = new CoreCollector(new ProcessExecuter()); - private static final CoredumpHandler coredumpHandler = new CoredumpHandler(HttpClientBuilder.create().build(), coreCollector); - - public MaintainerApiHandler(Executor executor, AccessLog accessLog) { - super(executor, accessLog); - } - - @Override - public HttpResponse handle(HttpRequest request) { - try { - switch (request.getMethod()) { - case POST: return handlePOST(request); - default: return ErrorResponse.methodNotAllowed("Method '" + request.getMethod() + "' is not supported"); - } - } - catch (IllegalArgumentException e) { - return ErrorResponse.badRequest(Exceptions.toMessageString(e)); - } - catch (RuntimeException e) { - log.log(Level.WARNING, "Unexpected error handling '" + request.getUri() + "'", e); - return ErrorResponse.internalServerError(Exceptions.toMessageString(e)); - } - } - - private HttpResponse handlePOST(HttpRequest request) { - String requestPath = request.getUri().getPath(); - if (requestPath.equals("/maintainer/v1")) { - Inspector object = toSlime(request.getData()).get(); - if (object.type() != Type.ARRAY) { - throw new IllegalArgumentException("Expected a list maintainer jobs to execute"); - } - - object.traverse((ArrayTraverser) (int i, Inspector item) -> { - String type = getFieldOrFail(item, "type").asString(); - Inspector arguments = getFieldOrFail(item, "arguments"); - parseMaintenanceJob(type, arguments); - }); - return new MessageResponse("Successfully executed " + object.entries() + " commands"); - - } else if (requestPath.startsWith("/maintainer/v1/")) { - String type = requestPath.substring(requestPath.lastIndexOf('/') + 1); - Inspector arguments = toSlime(request.getData()).get(); - parseMaintenanceJob(type, arguments); - return new MessageResponse("Successfully executed " + type); - - } else { - return ErrorResponse.notFoundError("Nothing at path '" + requestPath + "'"); - } - } - - public void parseMaintenanceJob(String type, Inspector arguments) { - if (arguments.type() != Type.OBJECT) { - throw new IllegalArgumentException("Expected a 'arguments' to be an object"); - } - - switch (type) { - case "delete-files": - parseDeleteFilesJob(arguments); - break; - - case "delete-directories": - parseDeleteDirectoriesJob(arguments); - break; - - case "recursive-delete": - parseRecursiveDelete(arguments); - break; - - case "move-files": - parseMoveFiles(arguments); - break; - - case "handle-core-dumps": - parseHandleCoreDumps(arguments); - break; - - default: - throw new IllegalArgumentException("Unknown job: " + type); - } - } - - private void parseDeleteFilesJob(Inspector arguments) { - Path basePath = Paths.get(getFieldOrFail(arguments, "basePath").asString()); - Duration maxAge = Duration.ofSeconds(getFieldOrFail(arguments, "maxAgeSeconds").asLong()); - Optional<String> fileNameRegex = SlimeUtils.optionalString(getFieldOrFail(arguments, "fileNameRegex")); - boolean recursive = getFieldOrFail(arguments, "recursive").asBool(); - try { - FileHelper.deleteFiles(basePath, maxAge, fileNameRegex, recursive); - } catch (IOException e) { - throw new RuntimeException("Failed deleting files under " + basePath.toAbsolutePath() + - fileNameRegex.map(regex -> ", matching '" + regex + "'").orElse("") + - ", " + (recursive ? "" : "not ") + "recursively" + - " and older than " + maxAge, e); - } - } - - private void parseDeleteDirectoriesJob(Inspector arguments) { - Path basePath = Paths.get(getFieldOrFail(arguments, "basePath").asString()); - Duration maxAge = Duration.ofSeconds(getFieldOrFail(arguments, "maxAgeSeconds").asLong()); - Optional<String> dirNameRegex = SlimeUtils.optionalString(getFieldOrFail(arguments, "dirNameRegex")); - try { - FileHelper.deleteDirectories(basePath, maxAge, dirNameRegex); - } catch (IOException e) { - throw new RuntimeException("Failed deleting directories under " + basePath.toAbsolutePath() + - dirNameRegex.map(regex -> ", matching '" + regex + "'").orElse("") + - " and older than " + maxAge, e); - } - } - - private void parseRecursiveDelete(Inspector arguments) { - Path basePath = Paths.get(getFieldOrFail(arguments, "path").asString()); - try { - FileHelper.recursiveDelete(basePath); - } catch (IOException e) { - throw new RuntimeException("Failed deleting " + basePath.toAbsolutePath(), e); - } - } - - private void parseMoveFiles(Inspector arguments) { - Path from = Paths.get(getFieldOrFail(arguments, "from").asString()); - Path to = Paths.get(getFieldOrFail(arguments, "to").asString()); - - try { - FileHelper.moveIfExists(from, to); - } catch (IOException e) { - throw new RuntimeException("Failed moving from " + from.toAbsolutePath() + ", to " + to.toAbsolutePath(), e); - } - } - - private void parseHandleCoreDumps(Inspector arguments) { - Path coredumpsPath = Paths.get(getFieldOrFail(arguments, "coredumpsPath").asString()); - Path doneCoredumpsPath = Paths.get(getFieldOrFail(arguments, "doneCoredumpsPath").asString()); - Map<String, Object> attributesMap = parseMap(getFieldOrFail(arguments, "attributes")); - - try { - coredumpHandler.removeJavaCoredumps(coredumpsPath); - coredumpHandler.processAndReportCoredumps(coredumpsPath, doneCoredumpsPath, attributesMap); - } catch (IOException e) { - throw new RuntimeException("Failed processing coredumps at " + coredumpsPath.toAbsolutePath() + - ", moving fished dumps to " + doneCoredumpsPath.toAbsolutePath(), e); - } - } - - private Map<String, Object> parseMap(Inspector object) { - Map<String, Object> map = new HashMap<>(); - getFieldOrFail(object, "attributes").traverse((String key, Inspector value) -> { - switch (value.type()) { - case BOOL: - map.put(key, value.asBool()); - break; - case LONG: - map.put(key, value.asLong()); - break; - case DOUBLE: - map.put(key, value.asDouble()); - break; - case STRING: - map.put(key, value.asString()); - break; - default: - throw new IllegalArgumentException("Invalid attribute for key '" + key + "', value " + value); - } - }); - return map; - } - - private Slime toSlime(InputStream jsonStream) { - try { - byte[] jsonBytes = IOUtils.readBytes(jsonStream, 1000 * 1000); - return SlimeUtils.jsonToSlime(jsonBytes); - } catch (IOException e) { - throw new RuntimeException(); - } - } - - public Inspector getFieldOrFail(Inspector object, String key) { - Inspector out = object.field(key); - if (out.type() == Type.NIX) { - throw new IllegalArgumentException("Key '" + key + "' was not found!"); - } - return out; - } -} diff --git a/node-maintainer/src/main/java/com/yahoo/vespa/hosted/node/maintainer/restapi/v1/MessageResponse.java b/node-maintainer/src/main/java/com/yahoo/vespa/hosted/node/maintainer/restapi/v1/MessageResponse.java deleted file mode 100644 index 8fb82cd18c9..00000000000 --- a/node-maintainer/src/main/java/com/yahoo/vespa/hosted/node/maintainer/restapi/v1/MessageResponse.java +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.node.maintainer.restapi.v1; - -import com.yahoo.container.jdisc.HttpResponse; -import com.yahoo.slime.JsonFormat; -import com.yahoo.slime.Slime; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * A 200 ok response with a message in JSON - * - * @author bratseth - */ -public class MessageResponse extends HttpResponse { - - private final Slime slime = new Slime(); - - public MessageResponse(String message) { - super(200); - slime.setObject().setString("message", message); - } - - @Override - public void render(OutputStream stream) throws IOException { - new JsonFormat(true).encode(stream, slime); - } - - @Override - public String getContentType() { return "application/json"; } - -} |