Class: CloudFormationTool::CloudFormation::LambdaCode

Inherits:
Object
  • Object
show all
Includes:
Storable
Defined in:
lib/cloud_formation_tool/cloud_formation/lambda_code.rb

Constant Summary

Constants included from CloudFormationTool

VERSION

Instance Method Summary collapse

Methods included from Storable

#cached_object, #make_filename, #upload

Methods included from CloudFormationTool

#aws_config, #awsas, #awscf, #awscreds, #awsec2, #awss3, #cf_bucket_name, #find_profile, #profile, #region, #s3_bucket_name

Constructor Details

#initialize(code, tpl) ⇒ LambdaCode

Returns a new instance of LambdaCode.



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
# File 'lib/cloud_formation_tool/cloud_formation/lambda_code.rb', line 10

def initialize(code, tpl)
  @data = code
  @data['Url'] = @data.delete 'URL' if @data.key? 'URL' # normalize to CF convention if seeing old key
  if @data.key? 'Url'
    log "Trying Lambda code from #{@data['Url']}"
    @data['Url'] = url = tpl.resolveVal(@data['Url'])
    return unless url.is_a? String
    log "Downloading Lambda code from #{url}"
    if already_in_cache(url)
      log "Reusing remote cached object instead of downloading"
    else
      res = fetch_from_url(url)
      @s3_url = URI(upload(make_filename(url.split('.').last), res.body, mime_type: res['content-type'], gzip: false))
      log "uploaded Lambda function to #{@s3_url}"
    end
  elsif @data.key? 'Path'
    @data['Path'] = path = tpl.resolveVal(@data['Path'])
    return unless path.is_a? String
    log "Reading Lambda code from #{path}"
    path = if path.start_with? "/" then path else "#{tpl.basedir}/#{path}" end
    if File.directory?(path)
      @s3_url = URI(upload(make_filename('zip'), zip_path(path), mime_type: 'application/zip', gzip: false))
      log "uploaded Lambda function to #{@s3_url}"
    else # Convert files to ZipFile
      @data.delete 'Path'
      @data['ZipFile'] = File.read(path)
    end
  end
end

Instance Method Details

#already_in_cache(uri_str) ⇒ Object



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
# File 'lib/cloud_formation_tool/cloud_formation/lambda_code.rb', line 51

def already_in_cache(uri_str)
  limit = 10
  url = URI(uri_str)
  until url.nil?
    begin
      raise ArgumentError, 'too many HTTP redirects' if limit == 0
      Net::HTTP.start(url.host, url.port, use_ssl: true) do |http|
        request = Net::HTTP::Get.new(url)
        http.request(request) do |response|
          # handle redirects like Github likes to do
          case response
            when Net::HTTPSuccess then
              url = nil
              http.finish if check_cached(response['ETag'])
            when Net::HTTPRedirection then
              location = response['location']
              log "Cache check redirected to #{location}"
              limit = limit - 1
              response.body
              url = URI(location)
            else
              log "arg err"
              raise ArgumentError, "Error getting response: #{response}"
          end
        end
      end
    rescue IOError => e
      retry unless url.nil?
    end
  end
  !@s3_url.nil?
end

#check_cached(etag) ⇒ Object



84
85
86
87
88
89
90
91
92
93
# File 'lib/cloud_formation_tool/cloud_formation/lambda_code.rb', line 84

def check_cached(etag)
  etag.gsub!(/"/,'') unless etag.nil?
  o = cached_object(etag)
  if o.nil?
    false
  else
    @s3_url = URI(o.public_url)
    true
  end
end

#fetch_from_url(uri_str) ⇒ Object



95
96
97
98
99
100
# File 'lib/cloud_formation_tool/cloud_formation/lambda_code.rb', line 95

def fetch_from_url(uri_str)
  $__fetch_cache ||= Hash.new do |h, url|
    h[url] = fetch_from_url_real(url)
  end
  $__fetch_cache[uri_str]
end

#fetch_from_url_real(uri_str, limit = 10) ⇒ Object

Raises:

  • (ArgumentError)


102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/cloud_formation_tool/cloud_formation/lambda_code.rb', line 102

def fetch_from_url_real(uri_str, limit = 10)
  raise ArgumentError, 'too many HTTP redirects' if limit == 0
  response = Net::HTTP.get_response(URI(uri_str))
  case response
  when Net::HTTPSuccess then
    response
  when Net::HTTPRedirection then
    location = response['location']
    log "redirected to #{location}"
    fetch_from_url_real(location, limit - 1)
  else
    raise CloudFormationTool::Errors::AppError, "Error downloading #{url}: #{response.value}"
  end
end

#rdir(path, prefix = '', &block) ⇒ Object



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/cloud_formation_tool/cloud_formation/lambda_code.rb', line 128

def rdir path, prefix = '', &block
  ents = []
  (Dir.entries(path) - %w(. ..)).collect do |ent|
    diskpath = File.join(path,ent)
    localpath = prefix.length>0 ? File.join(prefix,ent) : ent
    if block_given?
      if File.directory? diskpath
        rdir diskpath, localpath, &block
      else
        yield localpath
      end
    end
    if File.directory? diskpath
      rdir diskpath, localpath
    else
      ent
    end
  end.flatten
end

#to_cloudformationObject



117
118
119
120
121
122
123
124
125
126
# File 'lib/cloud_formation_tool/cloud_formation/lambda_code.rb', line 117

def to_cloudformation
  if @s3_url.nil?
    @data
  else
    {
      'S3Bucket' => @s3_url.hostname.split('.').first,
      'S3Key' => @s3_url.path[1..-1]
    }
  end
end

#zip_path(path) ⇒ Object



40
41
42
43
44
45
46
47
48
49
# File 'lib/cloud_formation_tool/cloud_formation/lambda_code.rb', line 40

def zip_path(path)
  Zip::OutputStream.write_buffer do |zf|
    rdir path do |ent|
      #log "Deflating #{ent}"
      filepath = File.join(path,ent)
      zf.put_next_entry ::Zip::Entry.new(nil, ent, nil, nil, nil, nil, nil, nil, ::Zip::DOSTime.at(File.mtime(filepath).to_i))
      zf.write File.read(filepath) 
    end
  end.string
end