Class: DPL::Provider::Lambda

Inherits:
DPL::Provider show all
Defined in:
lib/dpl/provider/lambda.rb

Instance Attribute Summary

Attributes inherited from DPL::Provider

#context, #options

Instance Method Summary collapse

Methods inherited from DPL::Provider

apt_get, #check_app, #commit_msg, context, #create_key, #default_text_charset, #default_text_charset?, #deploy, deprecated, #detect_encoding?, #encoding_for, #error, experimental, #initialize, #log, new, npm_g, #option, pip, requires, #run, #setup_git_credentials, #setup_git_ssh, #sha, shell, #user_agent, #warn

Constructor Details

This class inherits a constructor from DPL::Provider

Instance Method Details

#check_authObject



160
161
162
# File 'lib/dpl/provider/lambda.rb', line 160

def check_auth
  log "Using Access Key: #{option(:access_key_id)[-4..-1].rjust(20, '*')}"
end

#cleanupObject



229
230
# File 'lib/dpl/provider/lambda.rb', line 229

def cleanup
end

#create_zip(dest_file_path, src_directory_path, files) ⇒ Object



146
147
148
149
150
151
152
153
154
# File 'lib/dpl/provider/lambda.rb', line 146

def create_zip(dest_file_path, src_directory_path, files)
  Zip::File.open(dest_file_path, Zip::File::CREATE) do |zipfile|
    files.each do |file|
      zipfile.add(file.sub(src_directory_path + File::SEPARATOR, ''), file)
    end
  end

  dest_file_path
end

#dead_letter_arnObject



176
177
178
# File 'lib/dpl/provider/lambda.rb', line 176

def dead_letter_arn
  options[:dead_letter_arn] ? { :target_arn => options[:dead_letter_arn]} : nil
end

#default_descriptionObject



200
201
202
# File 'lib/dpl/provider/lambda.rb', line 200

def default_description
  "Deploy build #{context.env['TRAVIS_BUILD_NUMBER']} to AWS Lambda via Travis CI"
end

#default_kms_key_arnObject



184
185
186
# File 'lib/dpl/provider/lambda.rb', line 184

def default_kms_key_arn
  nil
end

#default_memory_sizeObject



204
205
206
# File 'lib/dpl/provider/lambda.rb', line 204

def default_memory_size
  128
end

#default_module_nameObject



208
209
210
# File 'lib/dpl/provider/lambda.rb', line 208

def default_module_name
  'index'
end

#default_runtimeObject



192
193
194
# File 'lib/dpl/provider/lambda.rb', line 192

def default_runtime
  'nodejs'
end

#default_timeoutObject



196
197
198
# File 'lib/dpl/provider/lambda.rb', line 196

def default_timeout
  3 # seconds
end

#environment_variablesObject



172
173
174
# File 'lib/dpl/provider/lambda.rb', line 172

def environment_variables
  options[:environment_variables] ? { :variables => split_string_array_to_hash(options[:environment_variables]) } : nil
end

#function_tagsObject



188
189
190
# File 'lib/dpl/provider/lambda.rb', line 188

def function_tags
  options[:function_tags] ? split_string_array_to_hash(options[:function_tags]) : nil
end

#function_zipObject



112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/dpl/provider/lambda.rb', line 112

def function_zip
  target_zip_path = File.absolute_path(options[:zip] || Dir.pwd)
  dest_file_path = output_file_path

  if File.directory?(target_zip_path)
    zip_directory(dest_file_path, target_zip_path)
  elsif File.file?(target_zip_path)
    zip_file(dest_file_path, target_zip_path)
  else
    error('Invalid zip option. If set, must be path to directory, js file, or a zip file.')
  end

  File.new(dest_file_path)
end

#handlerObject



105
106
107
108
109
110
# File 'lib/dpl/provider/lambda.rb', line 105

def handler
  module_name = options[:module_name] || default_module_name
  handler_name = option(:handler_name)

  "#{module_name}.#{handler_name}"
end

#lambdaObject



11
12
13
# File 'lib/dpl/provider/lambda.rb', line 11

def lambda
  @lambda ||= ::Aws::Lambda::Client.new(lambda_options)
end

#lambda_optionsObject



15
16
17
18
19
20
# File 'lib/dpl/provider/lambda.rb', line 15

def lambda_options
  {
      region:      options[:region] || 'us-east-1',
      credentials: ::Aws::Credentials.new(option(:access_key_id), option(:secret_access_key))
  }
end

#needs_key?Boolean

Returns:

  • (Boolean)


156
157
158
# File 'lib/dpl/provider/lambda.rb', line 156

def needs_key?
  false
end

#output_file_pathObject



164
165
166
# File 'lib/dpl/provider/lambda.rb', line 164

def output_file_path
  @output_file_path ||= '/tmp/' + random_chars(8) + '-lambda.zip'
end

#publishObject



212
213
214
# File 'lib/dpl/provider/lambda.rb', line 212

def publish
  !!options[:publish]
end

#push_appObject



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
# File 'lib/dpl/provider/lambda.rb', line 22

def push_app

  # The original LambdaPreview client supported create/update in one call
  # To keep compatibility we try to fetch the function and then decide
  # whether to update the code or create a new function

  function_name = options[:name] || option(:function_name)
  
  begin
    response = lambda.get_function({function_name: function_name})

    log "Function #{function_name} already exists, updating."

    # Options defined at
    #   https://docs.aws.amazon.com/sdkforruby/api/Aws/Lambda/Client.html#update_function_configuration-instance_method
    response = lambda.update_function_configuration({
                 function_name:        function_name,
                 description:          options[:description]    || default_description,
                 timeout:              options[:timeout]        || default_timeout,
                 memory_size:          options[:memory_size]    || default_memory_size,
                 role:                 option(:role),
                 handler:              handler,
                 runtime:              options[:runtime]        || default_runtime,
                 vpc_config:           vpc_config,
                 environment:          environment_variables,
                 dead_letter_config:   dead_letter_arn,
                 kms_key_arn:          options[:kms_key_arn] || default_kms_key_arn,
                 tracing_config:       tracing_mode
               })

    log "Updated configuration of function: #{response.function_name}."

    if function_tags
      log "Add tags to function #{response.function_name}."
      response = lambda.tag_resource({
              resource: response.function_arn,
              tags: function_tags
            })
    end

    # Options defined at
    #   https://docs.aws.amazon.com/sdkforruby/api/Aws/Lambda/Client.html#update_function_code-instance_method
    response = lambda.update_function_code({
                                             function_name:  options[:name] || option(:function_name),
                                             zip_file:       function_zip,
                                             publish:        publish
                                         })

    log "Updated code of function: #{response.function_name}."
  rescue ::Aws::Lambda::Errors::ResourceNotFoundException
    log "Function #{function_name} does not exist, creating."
    # Options defined at
    #   https://docs.aws.amazon.com/lambda/latest/dg/API_CreateFunction.html
    response = lambda.create_function({
                function_name:        options[:name]           || option(:function_name),
                description:          options[:description]    || default_description,
                timeout:              options[:timeout]        || default_timeout,
                memory_size:          options[:memory_size]    || default_memory_size,
                role:                 option(:role),
                handler:              handler,
                code: {
                 zip_file:           function_zip,
                },
                runtime:              options[:runtime]        || default_runtime,
                publish:              publish,
                vpc_config:           vpc_config,
                environment:          environment_variables,
                dead_letter_config:   dead_letter_arn,
                kms_key_arn:          options[:kms_key_arn] || default_kms_key_arn,
                tracing_config:       tracing_mode,
                tags:                 function_tags
              })

    log "Created lambda: #{response.function_name}."
  end
rescue ::Aws::Lambda::Errors::ServiceException => exception
  error(exception.message)
rescue ::Aws::Lambda::Errors::InvalidParameterValueException => exception
  error(exception.message)
rescue ::Aws::Lambda::Errors::ResourceNotFoundException => exception
  error(exception.message)
end

#random_chars(count = 8) ⇒ Object



225
226
227
# File 'lib/dpl/provider/lambda.rb', line 225

def random_chars(count=8)
  (36**(count-1) + rand(36**count - 36**(count-1))).to_s(36)
end

#split_string_array_to_hash(arr, delimiter = "=") ⇒ Object



216
217
218
219
220
221
222
223
# File 'lib/dpl/provider/lambda.rb', line 216

def split_string_array_to_hash(arr, delimiter="=")
  variables = {}
  Array(arr).map do |val|
    keyval = val.split(delimiter)
    variables[keyval[0]] = keyval[1]
  end
  variables
end

#tracing_modeObject



180
181
182
# File 'lib/dpl/provider/lambda.rb', line 180

def tracing_mode
  options[:tracing_mode] ? { :mode => options[:tracing_mode]} : nil
end

#uncleanupObject



232
233
# File 'lib/dpl/provider/lambda.rb', line 232

def uncleanup
end

#vpc_configObject



168
169
170
# File 'lib/dpl/provider/lambda.rb', line 168

def vpc_config
  options[:subnet_ids] && options[:security_group_ids] ? { :subnet_ids => Array(options[:subnet_ids]), :security_group_ids => Array(options[:security_group_ids]) } : nil
end

#zip_directory(dest_file_path, target_directory_path) ⇒ Object



141
142
143
144
# File 'lib/dpl/provider/lambda.rb', line 141

def zip_directory(dest_file_path, target_directory_path)
  files = Dir[File.join(target_directory_path, '**', '**')]
  create_zip(dest_file_path, target_directory_path, files)
end

#zip_file(dest_file_path, target_file_path) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/dpl/provider/lambda.rb', line 127

def zip_file(dest_file_path, target_file_path)
  if File.extname(target_file_path) == '.zip'
    # Just copy it to the destination right away, since it is already a zip.
    FileUtils.cp(target_file_path, dest_file_path)
    dest_file_path
  else
    # Zip up the file.
    src_directory_path = File.dirname(target_file_path)
    files = [ target_file_path ]

    create_zip(dest_file_path, src_directory_path, files)
  end
end