class CloudMagick::Builder

Constants

DEFAULT_REGION
DEFAULT_STAGE

Public Class Methods

new() click to toggle source
# File lib/cloud_magick/builder.rb, line 10
def initialize
  create_s3_bucket
  build_lambda
  build_api_gateway
  update_s3_bucket_redirection
  puts endpoint
end

Public Instance Methods

api_gateway_client() click to toggle source
# File lib/cloud_magick/builder.rb, line 283
def api_gateway_client
  @api_gateway_client ||= Aws::APIGateway::Client.new(
    region:            region,
    access_key_id:     ENV['ACCESS_KEY_ID'],
    secret_access_key: ENV['SECRET_ACCESS_KEY'],
  )
end
api_gateway_domain() click to toggle source
# File lib/cloud_magick/builder.rb, line 263
def api_gateway_domain
  "#{@api.id}.execute-api.ap-northeast-1.amazonaws.com"
end
app_name() click to toggle source
# File lib/cloud_magick/builder.rb, line 315
def app_name
  @app_name ||= ENV['APP_NAME']
end
aws_account_id() click to toggle source
# File lib/cloud_magick/builder.rb, line 267
def aws_account_id
  @aws_account_id ||= sts_client.get_caller_identity.account
end
bucket_name() click to toggle source
# File lib/cloud_magick/builder.rb, line 80
def bucket_name
  @bucket_name ||= app_name.gsub('_', '-')
end
build_api_gateway() click to toggle source
# File lib/cloud_magick/builder.rb, line 183
    def build_api_gateway
      @api = api_gateway_client.create_rest_api(
        name: app_name,
      )
      root_resource = api_gateway_client.get_resources({
        rest_api_id: @api.id,
        limit: 1,
      }).items.first
      parameter_resource = api_gateway_client.create_resource(
        rest_api_id: @api.id,
        parent_id: root_resource.id,
        path_part: '{parameter}',
      )
      filename_resource = api_gateway_client.create_resource(
        rest_api_id: @api.id,
        parent_id: parameter_resource.id,
        path_part: '{filename}',
      )
      api_gateway_client.put_method(
        rest_api_id: @api.id,
        resource_id: filename_resource.id,
        http_method: 'GET',
        authorization_type: 'NONE',
      )
      json_template = <<-EOS
{
  "bucket_name": "#{bucket_name}",
  "parameter": "$input.params('parameter')",
  "filename": "$input.params('filename')"
}
      EOS
      api_gateway_client.put_integration(
        rest_api_id: @api.id,
        resource_id: filename_resource.id,
        http_method: 'GET',
        type: 'AWS',
        integration_http_method: 'POST',
        uri: "arn:aws:apigateway:#{region}:lambda:path/2015-03-31/functions/arn:aws:lambda:#{region}:#{aws_account_id}:function:#{app_name}/invocations",
        request_templates: {
          'application/json' => json_template,
        },
        passthrough_behavior: 'WHEN_NO_TEMPLATES',
      )
      api_gateway_client.put_method_response(
        rest_api_id: @api.id,
        resource_id: filename_resource.id,
        http_method: 'GET',
        status_code: '302',
        response_parameters: {
          'method.response.header.Location' => true,
        },
      )
      api_gateway_client.put_integration_response(
        rest_api_id: @api.id,
        resource_id: filename_resource.id,
        http_method: 'GET',
        status_code: '302',
        response_parameters: {
          'method.response.header.Location' => 'integration.response.body.location',
        },
      )

      lambda_client.add_permission(
        function_name: app_name,
        statement_id: SecureRandom.uuid,
        action: 'lambda:InvokeFunction',
        principal: 'apigateway.amazonaws.com',
        source_arn: "arn:aws:execute-api:#{region}:#{aws_account_id}:#{@api.id}/*/GET/{parameter}/{filename}",
      )

      api_gateway_client.create_deployment(
        rest_api_id: @api.id,
        stage_name: stage,
      )
    end
build_lambda() click to toggle source
# File lib/cloud_magick/builder.rb, line 18
def build_lambda
  lambda_client.get_function(function_name: app_name)
rescue Aws::Lambda::Errors::ResourceNotFoundException
  role = build_lambda_role
  sleep 15 # FIXME
  lambda_client.create_function(
    function_name: app_name,
    runtime: 'nodejs4.3',
    role: role.arn,
    handler: 'index.handler',
    code: { zip_file: File.read(build_zip) },
    description: 'image resizing function',
    timeout: 30,
    memory_size: 1024,
    publish: true,
  )
end
build_lambda_role() click to toggle source
# File lib/cloud_magick/builder.rb, line 107
    def build_lambda_role
      iam_client.get_role(role_name: "lambda-#{app_name}").role
    rescue Aws::IAM::Errors::NoSuchEntity
      role_policy_document = <<-EOS
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
      EOS
      role = iam_client.create_role(
        role_name: "lambda-#{app_name}",
        assume_role_policy_document: role_policy_document,
      ).role
      policy_document = <<-EOS
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
          "s3:PutObject",
          "s3:GetAccelerateConfiguration",
          "s3:GetBucketAcl",
          "s3:GetBucketCORS",
          "s3:GetBucketLocation",
          "s3:GetBucketLogging",
          "s3:GetBucketNotification",
          "s3:GetBucketPolicy",
          "s3:GetBucketRequestPayment",
          "s3:GetBucketTagging",
          "s3:GetBucketVersioning",
          "s3:GetBucketWebsite",
          "s3:GetLifecycleConfiguration",
          "s3:GetObject",
          "s3:GetObjectAcl",
          "s3:GetObjectTorrent",
          "s3:GetObjectVersion",
          "s3:GetObjectVersionAcl",
          "s3:GetObjectVersionTorrent",
          "s3:GetReplicationConfiguration",
          "s3:ListAllMyBuckets",
          "s3:ListBucket",
          "s3:ListBucketMultipartUploads",
          "s3:ListBucketVersions",
          "s3:ListMultipartUploadParts"
      ],
      "Resource": "arn:aws:s3:::#{bucket_name}/*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    }
  ]
}
      EOS
      iam_client.put_role_policy(
        role_name: role.role_name,
        policy_name: "lambda-#{app_name}-policy",
        policy_document: policy_document,
      )
      role
    end
build_zip() click to toggle source
# File lib/cloud_magick/builder.rb, line 36
def build_zip
  folder = File.join(__dir__, '..', '..', 'templates')
  input_filenames = ['index.js']

  tmp_dir = File.join(__dir__, '..', '..', 'tmp')
  Dir.mkdir(tmp_dir) unless Dir.exist?(tmp_dir)
  filepath = File.join(tmp_dir, 'lambda.zip')
  File.delete(filepath) if File.exist?(filepath)
  Zip::File.open(filepath, Zip::File::CREATE) do |zipfile|
    input_filenames.each do |filename|
      zipfile.add(filename, File.join(folder, filename))
    end
  end
  filepath
end
create_s3_bucket() click to toggle source
# File lib/cloud_magick/builder.rb, line 52
    def create_s3_bucket
      s3_client.create_bucket(
        bucket: bucket_name,
        create_bucket_configuration: {
          location_constraint: region,
        },
      )
      bucket_policy = <<-EOS
{
  "Version": "2012-10-17",
  "Id": "allow access processed data",
  "Statement": [
    {
      "Sid": "allow access all",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::#{bucket_name}/*"
    }
  ]
}
      EOS
      s3_client.put_bucket_policy(
        bucket: bucket_name,
        policy: bucket_policy,
      )
    end
endpoint() click to toggle source
# File lib/cloud_magick/builder.rb, line 259
def endpoint
  "http://#{bucket_name}.s3-website-#{region}.amazonaws.com/"
end
iam_client() click to toggle source
# File lib/cloud_magick/builder.rb, line 299
def iam_client
  @iam_client ||= Aws::IAM::Client.new(
    region:            region,
    access_key_id:     ENV['ACCESS_KEY_ID'],
    secret_access_key: ENV['SECRET_ACCESS_KEY'],
  )
end
lambda_client() click to toggle source
# File lib/cloud_magick/builder.rb, line 275
def lambda_client
  @lambda_client ||= Aws::Lambda::Client.new(
    region:            region,
    access_key_id:     ENV['ACCESS_KEY_ID'],
    secret_access_key: ENV['SECRET_ACCESS_KEY'],
  )
end
region() click to toggle source
# File lib/cloud_magick/builder.rb, line 271
def region
  @region ||= DEFAULT_REGION
end
s3_client() click to toggle source
# File lib/cloud_magick/builder.rb, line 307
def s3_client
  @s3_client ||= Aws::S3::Client.new(
    region:            region,
    access_key_id:     ENV['ACCESS_KEY_ID'],
    secret_access_key: ENV['SECRET_ACCESS_KEY'],
  )
end
stage() click to toggle source
# File lib/cloud_magick/builder.rb, line 319
def stage
  @stage ||= DEFAULT_STAGE
end
sts_client() click to toggle source
# File lib/cloud_magick/builder.rb, line 291
def sts_client
  @sts_client ||= Aws::STS::Client.new(
    region:            region,
    access_key_id:     ENV['ACCESS_KEY_ID'],
    secret_access_key: ENV['SECRET_ACCESS_KEY'],
  )
end
update_s3_bucket_redirection() click to toggle source
# File lib/cloud_magick/builder.rb, line 84
def update_s3_bucket_redirection
  s3_client.put_bucket_website(
    bucket: bucket_name,
    website_configuration: {
      index_document: {
        suffix: 'index.html',
      },
      routing_rules: [
        {
          condition: {
            http_error_code_returned_equals: '404',
          },
          redirect: {
            host_name: api_gateway_domain,
            http_redirect_code: '302',
            replace_key_prefix_with: "#{stage}/",
          },
        },
      ],
    },
  )
end