Простая программа на Scala, работающая с Amazon S3

12 марта 2015

Несмотря на существование большого количества распределенных файловых систем (Riak CS, MongoDB GridFS, Cassandra File System, и прочих) многие продолжают отдавать свое предпочтение сервису Amazon S3. Что не удивительно, учитывая его гибкость, разумную стоимость, отсутствие необходимости самому что-либо администрировать и наличие могучего SDK. В этой заметке будет показано, как работать с Amazon S3 при помощи этого SDK на языке программирования Scala.

Прежде, чем перейти непосредственно к программированию, создадим небольшое тестовое окружение через консоль AWS. Находим в ней сервис S3, открываем, жмем «Create Bucket». От вас потребуется выбрать регион, в котором будет размещаться бакет, а также ввести имя бакета. Имена бакетов в S3 глобальны, поэтому не удивляйтесь, если имя «test-bucket» уже будет занято другим пользователем :) Также в скором времени нам понадобится идентификатор выбранного региона. Откройте бакет, нажмите Properties (справа), найдите раздел Static Website Histing, а в нем — endpoint:

Amazon S3 Endpoint

Название региона является частью endpoint и на скриншоте подчеркнуто красным. У меня регион называется «us-west-1», у вас он может быть таким же или чем-то похожим, в зависимости от региона, выбранного при создании бакета. Или, то же самое можно узнать еще проще, посмотрев внимательно на URL в строке браузера:

https://console.aws.amazon.com/s3/home?region=us-west-1

Для работы с S3 из Scala нам понадобится пользователь, обладающий соответствующими правами. В консоли AWS находим сервис IAM, создаем одного нового пользователя. После того, как пользователь будет создан, вы увидите примерно такую картину:

Новый пользователь, созданный через IAM

Сохраните где-нибудь Access Key ID и Secret Access Key, они нам скоро понадобятся.

В свойствах пользователя найдите раздел Managed Policies и нажмите Attach Policy. В списке находим полиси с именем AmazonS3FullAccess, ставим напротив него галку, жмем Attach Policy. Итак, у нас есть бакет в S3 и пользователь с полным доступом к сервису S3. Теперь можно и попрогать:

package me.eax.s3_example

import com.amazonaws._
import com.amazonaws.auth._
import com.amazonaws.services.s3._
import com.amazonaws.services.s3.model._
import java.io._

object AmazonS3Example extends App {
  val accessKey = "AKIAJNSEFYYHD43JLEKQ"
  val secretKey = "8c0NOloloTrololoOloloTrololoOloloTrololo"
  val bucketName = "eaxme-test"
  // вот где понадобилось имя региона:
  val urlPrefix = "https://s3-us-west-1.amazonaws.com"

  val credentials = new BasicAWSCredentials(accessKey, secretKey)
  val client = new AmazonS3Client(credentials)

  def uploadToS3(fileName: String, uploadPath: String): String = {
    client.putObject(bucketName, uploadPath, new File(fileName))

    val acl = client.getObjectAcl(bucketName, uploadPath)
    acl.grantPermission(GroupGrantee.AllUsers, Permission.Read)
    client.setObjectAcl(bucketName, uploadPath, acl)

    s"$urlPrefix/$bucketName/$uploadPath"
  }

  def fileIsUploadedToS3(uploadPath: String): Boolean = {
    try {
      client.getObjectMetadata(bucketName, uploadPath)
      true
    } catch {
      case e: AmazonServiceException if e.getStatusCode == 404 =>
        false
    }
  }
 
  def downloadFromS3(uploadPath: String, downloadPath: String) {
    if(!fileIsUploadedToS3(uploadPath)) {
      throw new RuntimeException(s"File $uploadPath is not uploaded!")
    }
    client.getObject(new GetObjectRequest(bucketName, uploadPath),
                     new File(downloadPath))
  }

  if(args.length < 2) {
    println("Usage: prog.jar file.dat s3/upload/path.dat " +
            "local/download/path.dat")
  } else {
    val Array(fileName, uploadPath, downloadPath, _*) = args
    println(s"Uploading $fileName...")

    val url = uploadToS3(fileName, uploadPath)
    println(s"Uploaded: $url")

    downloadFromS3(uploadPath, downloadPath)
    println(s"Downloaded: $downloadPath")
  }
}

Эта программа закачивает заданный файл в S3, а затем скачивает его обратно. Как видите, все довольно просто — заводится клиент, у клиента есть методы getObject и putObject. По умолчанию файлы, залитые в S3, недоступны извне по прямой ссылке. Поэтому в данном примере мы явно проставляем права доступа к файлу с помощью метода setObjectAcl. Вывод программы:

Uploading /home/eax/temp/doge.jpg...
Uploaded: https://s3-us-west-1.amazonaws.com/eaxme-test/xx/yy/doge.jpg
Downloaded: /tmp/downloaded-doge.jpg

Можно проверить, что файл доступен по прямой ссылке для скачивания, что согласно консоли AWS он действительно находится в бакете с правильными правами, а также что скаченный файл ничем не отличается от закаченного. Вот, собственно, и все, никакой особой магии в работе с Amazon S3 нет. Сожалею, если разочаровал :)

Ссылки по теме:

А для каких целей вы используете Amazon S3? И не доводилось ли вам работать с другими распределенными файловыми системами?

Дополнение: Использование Elastic Load Balancer и Auto Scaling Groups

Метки: , , .


Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.