Introducción al API Java de Amazon Glacier

Introducción al API Java de Amazon Glacier

Amazon Glacier es un servicio de almacenamiento en el que podemos guardar cualquier tipo de archivo por tiempo indefinido. Entre sus características destacamos:

Ventajas

  • durabilidad, guardando los archivos por tiempo indefinido
  • coste, razonable comparando los servicios ofrecidos con otras opciones

Desventajas

  • tiempo de latencia: el acceso a sus ficheros no es inmediato, siendo su tiempo de acceso medio por operación de cuatro horas

Dadas estas características, a nosotros nos parece una buena opción para guardar de una manera segura archivos a los que no accederemos a menudo, siendo por ello ideal para el almacenamiento de copias de seguridad. Para ver un ejemplo práctico de uso, a continuación mostramos una solución para explotar el API Java que ofrece Amazon para la operación con su servicio, viendo cómo guardar, obtener y ver los ficheros nuestros archivos en Amazon Glacier.

Configuración del entorno

Para la preparación del entorno de desarrollo necesitaremos:

  1. Crear un proyecto Maven e introducir la dependencia:
    1
    2
    3
    
        com.amazonaws
            aws-java-sdk
            1.3.21
  2. Establecer las propiedades de acceso a nuestro servicio de Amazon Glacier. Podremos configurar un archivo de propiedades. Podría ser algo de estilo:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    aws.accessKeyId=NOC2EYUVO8B3Y2FO9CY3
    aws.secretKey=3i384BvySo8w4ycor82ny38o/Dydr98J5tyvc8yn
     
    glacierRegion=eu-west-1
    glacierEndPoint=https://glacier.eu-west-1.amazonaws.com/
     
    vaultName=
     
    sqsEndPoint=sqs.eu-west-1.amazonaws.com
    sqsQueueName=
     
    snsEndPoint=sns.eu-west-1.amazonaws.com
    snsTopicName=

Una vez configurado el entorno y el acceso con Amazon Glacier podremos comenzar a realizar las operaciones que describimos a continuación.

Guardado de archivos

Para guardar archivos en Glacier a través de Java podremos utilizar el siguiente código:

1
2
3
4
5
6
7
8
9
String vaultName = PropertiesManager.getVaultName();
SystemPropertiesCredentialsProvider credentials = new SystemPropertiesCredentialsProvider();
AmazonGlacierClient glacierClient = new AmazonGlacierClient(credentials);
glacierClient.setEndpoint(PropertiesManager.getGlacierEndPoint());
 
ArchiveTransferManager atm = new ArchiveTransferManager(glacierClient, credentials);
UploadResult result = atm.upload(vaultName, archiveToUpload, new File(archiveToUpload));
 
System.out.println("File uploaded! File ID: '" + result.getArchiveId() + "'. File name: '" + archiveToUpload+"'");

Recuperación de archivos

Para recuperar archivos guardados en Glacier a través de Java podremos usar el código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
String vaultName = PropertiesManager.getVaultName();
 
//there are several ways to import the credential. we choose this one, through SystemProperties
SystemPropertiesCredentialsProvider credentials = new SystemPropertiesCredentialsProvider();
 
//set up the glacier client
AmazonGlacierClient glacierClient = new AmazonGlacierClient(credentials);
glacierClient.setEndpoint(PropertiesManager.getGlacierEndPoint());
 
//we use the SQS client to enqueue the storage request
AmazonSQSClient sqsClient = new AmazonSQSClient(credentials);
sqsClient.setEndpoint(PropertiesManager.getSqsEndPoint());
 
//we use the SNS client to receive the notification of Amazon operation ending
AmazonSNSClient snsClient = new AmazonSNSClient(credentials);
snsClient.setEndpoint(PropertiesManager.getSnsEndPoint());
 
//download file
ArchiveTransferManager atm = new ArchiveTransferManager(glacierClient, sqsClient, snsClient);
atm.download(vaultName, archiveId, new File(downloadFilePath));

Listado de archivos (recuperación de inventario)

Aquí mostramos un ejemplo más completo de cómo recibir el inventario de nuestros archivos guardados en Amazon Glacier en formato JSON.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
public class DownloadInventoryWithSQSPolling {
 
    public static String vaultName;
    public static String snsTopicName;
    public static String sqsQueueName;
    public static String sqsQueueARN;
    public static String sqsQueueURL;
    public static String snsTopicARN;
    public static String snsSubscriptionARN;
    public static String fileName = "glacierInventory";
    public static long sleepTime = 600; 
    public static AmazonGlacierClient client;
    public static AmazonSQSClient sqsClient;
    public static AmazonSNSClient snsClient;
 
    public static void main(String[] args) {
        try {
            if (args.length!=1) {
                throw new Exception("Incorrect values. Filename expected");
            }
            fileName = args[0];
 
            SystemPropertiesCredentialsProvider credentials = new SystemPropertiesCredentialsProvider();
 
            client = new AmazonGlacierClient(credentials);
            client.setEndpoint(PropertiesManager.getGlacierEndPoint());
            sqsClient = new AmazonSQSClient(credentials);
            sqsClient.setEndpoint(PropertiesManager.getSqsEndPoint());
            sqsQueueName=PropertiesManager.getSqsQueueName();
            snsClient = new AmazonSNSClient(credentials);
            snsClient.setEndpoint(PropertiesManager.getSnsEndPoint());
            snsTopicName=PropertiesManager.getSnsTopicName();
            vaultName = PropertiesManager.getVaultName();
 
            setupSQS();
 
            setupSNS();
 
            String jobId = initiateJobRequest();
            System.out.println("Jobid = " + jobId);
 
            Boolean success = waitForJobToComplete(jobId, sqsQueueURL);
            if (!success) {
                throw new Exception("Job did not complete successfully.");
            }
 
            downloadJobOutput(jobId);
 
            cleanUp();
 
        } catch (Exception e) {
            System.err.println(e);
            e.printStackTrace();
            System.exit(-1);
        }   
    }
 
    private static void setupSQS() {
        CreateQueueRequest request = new CreateQueueRequest()
            .withQueueName(sqsQueueName);
        CreateQueueResult result = sqsClient.createQueue(request);  
        sqsQueueURL = result.getQueueUrl();
 
        GetQueueAttributesRequest qRequest = new GetQueueAttributesRequest()
            .withQueueUrl(sqsQueueURL)
            .withAttributeNames("QueueArn");
 
        GetQueueAttributesResult qResult = sqsClient.getQueueAttributes(qRequest);
        sqsQueueARN = qResult.getAttributes().get("QueueArn");
 
        Policy sqsPolicy = 
            new Policy().withStatements(
                    new Statement(Effect.Allow)
                    .withPrincipals(Principal.AllUsers)
                    .withActions(SQSActions.SendMessage)
                    .withResources(new Resource(sqsQueueARN)));
        Map<String, String> queueAttributes = new HashMap<String, String>();
        queueAttributes.put("Policy", sqsPolicy.toJson());
        sqsClient.setQueueAttributes(new SetQueueAttributesRequest(sqsQueueURL, queueAttributes)); 
 
    }
    private static void setupSNS() {
        CreateTopicRequest request = new CreateTopicRequest()
            .withName(snsTopicName);
        CreateTopicResult result = snsClient.createTopic(request);
        snsTopicARN = result.getTopicArn();
 
        SubscribeRequest request2 = new SubscribeRequest()
            .withTopicArn(snsTopicARN)
            .withEndpoint(sqsQueueARN)
            .withProtocol("sqs");
        SubscribeResult result2 = snsClient.subscribe(request2);
 
        snsSubscriptionARN = result2.getSubscriptionArn();
    }
    private static String initiateJobRequest() {
 
        JobParameters jobParameters = new JobParameters()
            .withType("inventory-retrieval")
            .withSNSTopic(snsTopicARN);
 
        InitiateJobRequest request = new InitiateJobRequest()
            .withVaultName(vaultName)
            .withJobParameters(jobParameters);
 
        InitiateJobResult response = client.initiateJob(request);
 
        return response.getJobId();
    }
 
    private static Boolean waitForJobToComplete(String jobId, String sqsQueueUrl) throws InterruptedException, JsonParseException, IOException {
 
        Boolean messageFound = false;
        Boolean jobSuccessful = false;
        ObjectMapper mapper = new ObjectMapper();
        JsonFactory factory = mapper.getFactory();
 
        while (!messageFound) {
            List msgs = sqsClient.receiveMessage(
               new ReceiveMessageRequest(sqsQueueUrl).withMaxNumberOfMessages(10)).getMessages();
 
            if (msgs.size() > 0) {
                for (Message m : msgs) {
                    JsonParser jpMessage = factory.createJsonParser(m.getBody());
                    JsonNode jobMessageNode = mapper.readTree(jpMessage);
                    String jobMessage = jobMessageNode.get("Message").textValue();
 
                    JsonParser jpDesc = factory.createJsonParser(jobMessage);
                    JsonNode jobDescNode = mapper.readTree(jpDesc);
                    String retrievedJobId = jobDescNode.get("JobId").textValue();
                    String statusCode = jobDescNode.get("StatusCode").textValue();
                    if (retrievedJobId.equals(jobId)) {
                        messageFound = true;
                        if (statusCode.equals("Succeeded")) {
                            jobSuccessful = true;
                        }
                    }
                }
 
            } else {
              Thread.sleep(sleepTime * 1000); 
            }
          }
        return (messageFound && jobSuccessful);
    }
 
    private static void downloadJobOutput(String jobId) throws IOException {
 
        GetJobOutputRequest getJobOutputRequest = new GetJobOutputRequest()
            .withVaultName(vaultName)
            .withJobId(jobId);
        GetJobOutputResult getJobOutputResult = client.getJobOutput(getJobOutputRequest);
 
        FileWriter fstream = new FileWriter(fileName);
        BufferedWriter out = new BufferedWriter(fstream);
        BufferedReader in = new BufferedReader(new InputStreamReader(getJobOutputResult.getBody()));            
        String inputLine;
        try {
            while ((inputLine = in.readLine()) != null) {
                out.write(inputLine);
            }
        }catch(IOException e) {
            throw new AmazonClientException("Unable to save archive", e);
        }finally{
            try {in.close();}  catch (Exception e) {}
            try {out.close();}  catch (Exception e) {}             
        }
        System.out.println("Retrieved inventory to " + fileName);
    }
 
    private static void cleanUp() {
        snsClient.unsubscribe(new UnsubscribeRequest(snsSubscriptionARN));
        snsClient.deleteTopic(new DeleteTopicRequest(snsTopicARN));
        sqsClient.deleteQueue(new DeleteQueueRequest(sqsQueueURL));
    }
}

Más recursos

Aquí sólo mostramos sencillos ejemplos a modo introductorio, pero el API permite de realizar más operaciones, como subida de ficheros en varias partes. Por ello, para profundizar, os recomendamos:

  • Tutorial de Amazon en inglés
  • Consultar la documentación oficial de Amazon Glacier
  • Integrar esta solución para el almacenamiento de copias de seguridad con el tutorial de copias de seguridad en linux que ya tratamos.
Publicado en septiembre 2, 2015

,

,

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

« »