Class: Skylight::Util::NativeExtFetcher Private

Inherits:
Object
  • Object
show all
Includes:
FileUtils
Defined in:
lib/skylight/util/native_ext_fetcher.rb

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Defined Under Namespace

Classes: FetchError

Constant Summary collapse

BASE_URL =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

"https://s3.amazonaws.com/skylight-agent-packages/skylight-native"
MAX_REDIRECTS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

5
MAX_RETRIES =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

3

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source, target, version, checksum, arch, required, platform, log) ⇒ NativeExtFetcher

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of NativeExtFetcher.



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/skylight/util/native_ext_fetcher.rb', line 34

def initialize(source, target, version, checksum, arch, required, platform, log)
  raise "source required" unless source
  raise "target required" unless target
  raise "checksum required" unless checksum
  raise "arch required" unless arch

  @source = source
  @target = target
  @version = version
  @checksum = checksum
  @required = required
  @platform = platform
  @arch = arch
  @log = log
end

Class Method Details

.fetch(opts = {}) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/skylight/util/native_ext_fetcher.rb', line 20

def self.fetch(opts = {})
  fetcher = new(
    BASE_URL,
    opts[:target],
    opts[:version],
    opts[:checksum],
    opts[:arch],
    opts[:required],
    opts[:platform],
    opts[:logger] || Logger.new(STDOUT))

  fetcher.fetch
end

Instance Method Details

#basenameObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



172
173
174
# File 'lib/skylight/util/native_ext_fetcher.rb', line 172

def basename
  "skylight_#{@arch}.tar.gz"
end

#deconstruct_uri(uri) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



180
181
182
183
# File 'lib/skylight/util/native_ext_fetcher.rb', line 180

def deconstruct_uri(uri)
  uri = URI(uri)
  [ uri.host, uri.port, uri.scheme == 'https', uri.request_uri ]
end

#error(msg, e = nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



198
199
200
201
202
# File 'lib/skylight/util/native_ext_fetcher.rb', line 198

def error(msg, e=nil)
  msg = "[SKYLIGHT] #{msg}"
  msg << "\n#{e.backtrace.join("\n")}" if e
  @log.error msg
end

#fetchObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/skylight/util/native_ext_fetcher.rb', line 50

def fetch
  log "fetching native ext; curr-platform=#{@platform}; " \
    "requested-arch=#{@arch}; version=#{@version}"

  tar_gz = "#{@target}/#{basename}"

  unless sha2 = fetch_native_ext(source_uri, tar_gz, MAX_RETRIES, MAX_REDIRECTS)
    maybe_raise "could not fetch native extension"
    return
  end

  unless verify_checksum(sha2)
    maybe_raise "could not verify checksum"
    return
  end

  Dir.chdir File.dirname(tar_gz) do
    system "tar xzvf #{tar_gz}"
  end

  true
ensure
  rm_f tar_gz if tar_gz
end

#fetch_native_ext(uri, out, attempts, redirects) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/skylight/util/native_ext_fetcher.rb', line 75

def fetch_native_ext(uri, out, attempts, redirects)
  redirects.times do |i|
    # Ensure the location is available
    mkdir_p File.dirname(out)
    rm_f out

    remaining_attempts = attempts

    log "attempting to fetch from remote; uri=#{uri}"

    begin
      host, port, use_ssl, path = deconstruct_uri(uri)

      File.open out, 'w' do |f|
        res, extra = http_get(host, port, use_ssl, path, f)

        case res
        when :success
          log "successfully downloaded native ext; out=#{out}"
          return extra
        else
          log "fetching native ext; uri=#{uri}; redirected=#{res}"
          uri = res

          next
        end
      end
    rescue => e
      remaining_attempts -= 1

      error "failed to fetch native extension; uri=#{uri}; msg=#{e.message}; remaining-attempts=#{remaining_attempts}", e

      if remaining_attempts > 0
        sleep 2
        retry
      end

      return
    end
  end

  log "exceeded max redirects"
  return
end

#http_get(host, port, use_ssl, path, out) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/skylight/util/native_ext_fetcher.rb', line 120

def http_get(host, port, use_ssl, path, out)
  if http_proxy = ENV['HTTP_PROXY'] || ENV['http_proxy']
    log "connecting with proxy: #{http_proxy}"
    uri = URI.parse(http_proxy)
    p_host, p_port = uri.host, uri.port
    p_user, p_pass = uri.userinfo.split(/:/) if uri.userinfo
  end

  opts = {}
  opts[:use_ssl] = use_ssl

  if use_ssl
    opts[:ca_file] = SSL.ca_cert_file_or_default
  end

  Net::HTTP.start(host, port, p_host, p_port, p_user, p_pass, use_ssl: use_ssl) do |http|
    http.request_get path do |resp|
      case resp
      when Net::HTTPSuccess
        digest = Digest::SHA2.new

        resp.read_body do |chunk|
          digest << chunk
          out.write chunk
        end

        return [ :success, digest.hexdigest ]
      when Net::HTTPRedirection
        unless location = resp['location']
          raise "received redirect but no location"
        end

        return [ :redirect, location ]
      else
        raise "received HTTP status code #{resp.code}"
      end
    end
  end
end

#log(msg) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



193
194
195
196
# File 'lib/skylight/util/native_ext_fetcher.rb', line 193

def log(msg)
  msg = "[SKYLIGHT] #{msg}"
  @log.info msg
end

#maybe_raise(err) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



185
186
187
188
189
190
191
# File 'lib/skylight/util/native_ext_fetcher.rb', line 185

def maybe_raise(err)
  error err

  if @required
    raise err
  end
end

#source_uriObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



176
177
178
# File 'lib/skylight/util/native_ext_fetcher.rb', line 176

def source_uri
  "#{@source}/#{@version}/#{basename}"
end

#verify_checksum(actual) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



160
161
162
163
164
165
166
167
168
169
170
# File 'lib/skylight/util/native_ext_fetcher.rb', line 160

def verify_checksum(actual)
  unless @checksum == actual
    log "checksum mismatch; expected=#{@checksum}; actual=#{actual}"
    return false
  end

  true
rescue Exception => e
  error "failed to read skylight agent archive; e=#{e.message}"
  false
end