glacieruploader icon indicating copy to clipboard operation
glacieruploader copied to clipboard

Add a flag to output data in JSON

Open megCanicalKb opened this issue 9 years ago • 8 comments

It would be nice to have a way to output the data in JSON to make it machine-parsable.

The use case here is to have a script that operates at a high-level while glacieruploader handles all of the operations/credentials.

Part of the changes that seems to be done include:

  • adding an option: "--json-output" and "-j"
  • redirecting the logging output to the error stream (to separate data and logs)
  • passing a new boolean to all commands: json_output
  • displaying in JSON when asked

megCanicalKb avatar Aug 23 '15 21:08 megCanicalKb

Good idea. I'm using more and more JSON output myself, so I can understand the usecase. Will see how easy it is to add JSON.

Thanks for the feedback!

MoriTanosuke avatar Aug 24 '15 04:08 MoriTanosuke

I added https://github.com/MoriTanosuke/glacieruploader/blob/master/src/main/java/de/kopis/glacier/printers/VaultPrinter.java pretty early, but it's hardcoded in a lot of places and probably not fit for the task.

At the moment the Commands do not output anything, just logging. Also there is no return value, so probably the exec method https://github.com/MoriTanosuke/glacieruploader/blob/master/src/main/java/de/kopis/glacier/commands/AbstractCommand.java#L74 needs to return an optional CommandResult to https://github.com/MoriTanosuke/glacieruploader/blob/master/src/main/java/de/kopis/glacier/GlacierUploader.java#L111 where I can then instantiate a new CommandPrinter with a JSON implementation. Will take a closer look in the evening.

MoriTanosuke avatar Aug 24 '15 04:08 MoriTanosuke

I've got a working prototype that works but i'm not a big fan of having to have the printer have a switch for raw/json.

I also had to make it output an array of JSON objects instead so I used a single instance of the printer and buffered the output until it's flushed. The auto-flush is ensure using the try-with-resource block which works nicely.

I'm thinking of keeping the printers but trying to have different classes and have something along the lines:

  • VaultPrinter (abstract)
  • VaultTextPrinter
  • VaultJSONPrinter
  • VaultPrinterFactory

It might be over-engineering the thing :-)

megCanicalKb avatar Aug 24 '15 06:08 megCanicalKb

I'll put theses changes up tomorrow night (PST time).

megCanicalKb avatar Aug 24 '15 06:08 megCanicalKb

Nice, that would be a great starting point. 👍 I'd expect a major refactoring for this in any case, so I'll start thinking about it as well.

MoriTanosuke avatar Aug 24 '15 07:08 MoriTanosuke

What comes to mind first is a modification on the interface for AbstractCommand like this:

public abstract Optional<CommandResult> exec(OptionSet options, GlacierUploaderOptionParser optionParser);

Then all commands can return a CommandResult with a definitive status and a custom message. Probably an exception as well. Could look like this:

package de.kopis.glacier.commands;

import com.amazonaws.AmazonClientException;

public class CommandResult {

    public enum CommandResultStatus {
        SUCCESS,
        FAILURE,
        UNKNOWN
    }

    private final String message;
    private final CommandResultStatus status;
    private Exception exception;

    public CommandResult(CommandResultStatus failure, String s, AmazonClientException exception) {
        this(failure, s);
        this.exception = exception;
    }

    public CommandResult(CommandResultStatus status, String message) {
        this.status = status;
        this.message = message;
    }

    public Exception getException() {
        return exception;
    }

    public String getMessage() {
        return message;
    }

    public CommandResultStatus getStatus() {
        return status;
    }
}

There should still be something like a XXX, maybe like this:

package de.kopis.glacier.printers;

import de.kopis.glacier.commands.CommandResult;

import java.io.PrintStream;

public class JsonCommandResultPrinter {
    public void print(PrintStream out, CommandResult result) {
        //TODO create JSON representation of CommandResult
    }
}

That way the GlacierUploader can still use different implementations, switchable by command line parameters at https://github.com/MoriTanosuke/glacieruploader/blob/master/src/main/java/de/kopis/glacier/GlacierUploader.java#L111

I'll give it a go and see how far I come.

@Megra Does this sound like what you had in mind in any case :question:

MoriTanosuke avatar Aug 24 '15 17:08 MoriTanosuke

Ok, I pushed my local branch. See https://github.com/MoriTanosuke/glacieruploader/tree/optional-command-responses for my changes so far and let me know what you think. I'll leave the branch open until this issue is solved.

MoriTanosuke avatar Aug 24 '15 17:08 MoriTanosuke

I pushed a small change to the branch and https://github.com/MoriTanosuke/glacieruploader/blob/optional-command-responses/src/main/java/de/kopis/glacier/GlacierUploader.java#L119 now takes the CommandResult and prints it to STDOUT.

This is what I got for an invalid command:

INFO  Using end point: https://glacier.eu-west-1.amazonaws.com
INFO  Creating vault myvaultname...
ERROR Couldn't create vault.
{status: 'FAILURE', message: 'Can not create vault: The security token included in the request is invalid. (Service: AmazonGlacier; Status Code: 403; Error Code: UnrecognizedClientException; Request ID: Uh0rH-Z7UTmUzmIv1YlJ3FR-MNZhUZy1yNC81yipzEza4sc)', requestId: 'Uh0rH-Z7UTmUzmIv1YlJ3FR-MNZhUZy1yNC81yipzEza4sc', exception: 'class com.amazonaws.AmazonServiceException'}

The first 3 lines are from my logging configuration. The last line prints the result as a JSON String. If there is a more information from the Amazon classes available, there would also be a field originalMessage with more information.

I also added the request ID in its own field in the JSON for easier access. Should be useful if a script has to remember or report those errors.

MoriTanosuke avatar Aug 27 '15 15:08 MoriTanosuke