Class: SfnLambda::Control
- Inherits:
-
Object
- Object
- SfnLambda::Control
- Includes:
- Singleton
- Defined in:
- lib/sfn-lambda/control.rb
Constant Summary collapse
- DEFAULTS =
{ :INLINE_MAX_SIZE => 4096, :INLINE_RESTRICTED => ['java8'].freeze, :BUILD_REQUIRED => { 'java8' => { :build_command => 'mvn package', :output_directory => './target', :asset_extension => '.jar' }.freeze }.freeze }.freeze
Instance Attribute Summary collapse
-
#callback ⇒ Object
Returns the value of attribute callback.
-
#functions ⇒ Object
readonly
Returns the value of attribute functions.
Instance Method Summary collapse
-
#[](key) ⇒ Object
Get configuration value for control via sfn configuration and fall back to defined defaults if not set.
-
#apply_build!(info) ⇒ TrueClass, FalseClass
Build the lambda asset if building is a requirement.
- #bucket ⇒ Miasma::Models::Storage::Bucket
-
#can_inline?(info) ⇒ TrueClass, FalseClass
Determine if function can be defined inline within template.
-
#discover_functions! ⇒ NilClass
Discover all defined lambda functions available in directories provided via configuration.
-
#format_content(info) ⇒ Smash
Format lambda function content to use within template.
-
#generate_key_name(info) ⇒ String
Generate key name based on state.
-
#get(name, runtime = nil) ⇒ Hash
Get path to lambda function.
-
#initialize ⇒ self
constructor
Create a new control instance.
-
#lambda_directories ⇒ Array<String>
Paths to lambda storage directories.
-
#versioning_enabled? ⇒ TrueClass, FalseClass
Bucket has versioning enabled.
Constructor Details
#initialize ⇒ self
Create a new control instance
32 33 34 |
# File 'lib/sfn-lambda/control.rb', line 32 def initialize @functions = Smash.new end |
Instance Attribute Details
#callback ⇒ Object
Returns the value of attribute callback.
27 28 29 |
# File 'lib/sfn-lambda/control.rb', line 27 def callback @callback end |
#functions ⇒ Object (readonly)
Returns the value of attribute functions.
26 27 28 |
# File 'lib/sfn-lambda/control.rb', line 26 def functions @functions end |
Instance Method Details
#[](key) ⇒ Object
Get configuration value for control via sfn configuration and fall back to defined defaults if not set
197 198 199 |
# File 'lib/sfn-lambda/control.rb', line 197 def [](key) callback.config.fetch(:lambda, :config, key.to_s.downcase, DEFAULTS[key.to_s.upcase.to_sym]) end |
#apply_build!(info) ⇒ TrueClass, FalseClass
Build the lambda asset if building is a requirement
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/sfn-lambda/control.rb', line 112 def apply_build!(info) if(build_info = self[:build_required][info[:runtime]]) Open3.popen3(build_info[:build_command], :chdir => info[:path]) do |stdin, stdout, stderr, wait_thread| exit_status = wait_thread.value unless(exit_status.success?) callback.ui.error "Failed to build lambda assets for storage from path: #{info[:path]}" callback.ui.debug "Build command used which generated failure: `#{build_info[:build_command]}`" callback.ui.debug "STDOUT: #{stdout.read}" callback.ui.debug "STDERR: #{stderr.read}" raise "Failed to build lambda asset for storage! (path: `#{info[:path]}`)" end end file = Dir.glob(File.join(info[:path], build_info[:output_directory], "*.#{build_config[:asset_extension]}")).first if(file) info[:path] = file true else debug "Glob pattern used for build asset detection: `#{File.join(info[:path], build_info[:output_directory], "*.#{build_config[:asset_extension]}")}`" raise "Failed to locate generated build asset for storage! (path: `#{info[:path]}`)" end else false end end |
#bucket ⇒ Miasma::Models::Storage::Bucket
138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/sfn-lambda/control.rb', line 138 def bucket storage_bucket = callback.config.fetch(:lambda, :upload, :bucket, callback.config[:nesting_bucket]) if(storage_bucket) s3 = api.connection.api_for(:storage) l_bucket = s3.buckets.get(storage_bucket) end unless(l_bucket) raise "Failed to locate configured bucket for lambda storage (#{storage_bucket})" else l_bucket end end |
#can_inline?(info) ⇒ TrueClass, FalseClass
Determine if function can be defined inline within template
189 190 191 |
# File 'lib/sfn-lambda/control.rb', line 189 def can_inline?(info) !self[:inline_restricted].include?(info[:runtime]) && File.size(info[:path]) <= self[:inline_max_size] end |
#discover_functions! ⇒ NilClass
Discover all defined lambda functions available in directories provided via configuration
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/sfn-lambda/control.rb', line 205 def discover_functions! core_paths = lambda_directories core_paths.each do |path| Dir.new(path).each do |dir_item| next if dir_item.start_with?('.') next unless File.directory?(File.join(path, dir_item)) if(self[:build_required].keys.include?(dir_item)) Dir.new(File.join(path, dir_item)).each do |item| next if item.start_with?('.') full_item = File.join(path, dir_item, item) next unless File.directory?(full_item) functions.set(dir_item, item, full_item) end else items = Dir.glob(File.join(path, dir_item, '**', '**', '*')) items.each do |full_item| next unless File.file?(full_item) item = full_item.sub(File.join(path, dir_item, ''), '').gsub(File::SEPARATOR, '') item = item.sub(/#{Regexp.escape(File.extname(item))}$/, '') functions.set(dir_item, item, full_item) end end end end nil end |
#format_content(info) ⇒ Smash
Format lambda function content to use within template. Will provide raw source when function can be inlined within the template. If inline is not available, it will store within S3
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/sfn-lambda/control.rb', line 84 def format_content(info) if(can_inline?(info)) Smash.new(:raw => File.read(info[:path])) else apply_build!(info) key_name = generate_key_name(info) io = File.open(info[:path], 'rb') file = bucket.files.build file.name = key_name file.body = io file.save io.close if(versioning_enabled?) result = s3.request( :path => s3.file_path(file), :endpoint => s3.bucket_endpoint(file.bucket), :method => :head ) version = result[:headers][:x_amz_version_id] end Smash(:bucket => storage_bucket, :key => key_name, :version => version) end end |
#generate_key_name(info) ⇒ String
Generate key name based on state
171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/sfn-lambda/control.rb', line 171 def generate_key_name(info) if(versioning_enabled?) "sfn.lambda/#{info[:runtime]}/#{File.basename(info[:path])}" else checksum = Digest::SHA256.new File.open(info[:path], 'rb') do |file| while(content = file.read(2048)) checksum << content end end "sfn.lambda/#{info[:runtime]}/#{File.basename(info[:path])}-#{checksum.base64digest}" end end |
#get(name, runtime = nil) ⇒ Hash
Get path to lambda function
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/sfn-lambda/control.rb', line 55 def get(name, runtime=nil) unless(runtime) runtime = functions.keys.find_all do |r_name| functions[r_name].keys.include?(name.to_s) end if(runtime.empty?) raise "Failed to locate requested lambda function `#{name}`" elsif(runtime.size > 1) raise "Multiple lambda function matches for `#{name}`. (In runtimes: `#{runtime.sort.join('`, `')}`)" end runtime = runtime.first end result = functions.get(runtime, name) if(result.nil?) raise "Failed to locate requested lambda function `#{name}`" else Smash.new(:path => result, :runtime => runtime, :name => name) end end |
#lambda_directories ⇒ Array<String>
Returns paths to lambda storage directories.
37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/sfn-lambda/control.rb', line 37 def lambda_directories paths = [callback.config.fetch(:lambda, :directory, 'lambda')].flatten.compact.uniq.map do |path| File.(path) end invalids = paths.find_all do |path| !File.directory?(path) end unless(invalids.empty?) raise "Invalid lambda directory paths provided: #{invalids.join(', ')}" end paths end |
#versioning_enabled? ⇒ TrueClass, FalseClass
Returns bucket has versioning enabled.
152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/sfn-lambda/control.rb', line 152 def versioning_enabled? unless(@versioned.nil?) s3 = api.connection.api_for(:storage) result = s3.request( :path => '/', :params => { :versioning => true }, :endpoint => s3.bucket_endpoint(bucket) ) @versioned = result.get(:body, 'VersioningConfiguration', 'Status') == 'Enabled' end @versioned end |