skylight 3.1.5 → 4.0.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -9
- data/bin/skylight +1 -1
- data/ext/extconf.rb +74 -76
- data/ext/libskylight.yml +7 -6
- data/lib/skylight.rb +15 -13
- data/lib/skylight/api.rb +40 -37
- data/lib/skylight/cli.rb +55 -60
- data/lib/skylight/cli/doctor.rb +13 -14
- data/lib/skylight/cli/helpers.rb +20 -22
- data/lib/skylight/cli/merger.rb +119 -116
- data/lib/skylight/config.rb +110 -96
- data/lib/skylight/errors.rb +8 -10
- data/lib/skylight/helpers.rb +35 -37
- data/lib/skylight/native.rb +13 -13
- data/lib/skylight/native_ext_fetcher.rb +30 -37
- data/lib/skylight/probes/sinatra_add_middleware.rb +2 -2
- data/lib/skylight/railtie.rb +32 -8
- data/lib/skylight/sinatra.rb +1 -1
- data/lib/skylight/trace.rb +4 -5
- data/lib/skylight/util/component.rb +76 -11
- data/lib/skylight/util/deploy.rb +10 -21
- data/lib/skylight/util/hostname.rb +4 -4
- data/lib/skylight/util/http.rb +134 -136
- data/lib/skylight/util/ssl.rb +6 -6
- data/lib/skylight/version.rb +1 -1
- metadata +51 -50
data/lib/skylight/util/deploy.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "json"
|
2
|
+
require "skylight/core/util/logging"
|
3
3
|
|
4
4
|
module Skylight
|
5
5
|
module Util
|
6
|
-
|
7
6
|
module Deploy
|
8
|
-
|
9
7
|
def self.build(config)
|
10
8
|
DEPLOY_TYPES.each do |type|
|
11
9
|
deploy = type.new(config)
|
@@ -15,7 +13,6 @@ module Skylight
|
|
15
13
|
end
|
16
14
|
|
17
15
|
class EmptyDeploy
|
18
|
-
|
19
16
|
attr_reader :config
|
20
17
|
attr_reader :timestamp
|
21
18
|
|
@@ -41,11 +38,10 @@ module Skylight
|
|
41
38
|
timestamp: timestamp,
|
42
39
|
deploy_id: id.to_s[0..100] # Keep this sane
|
43
40
|
}
|
44
|
-
hash[:git_sha] = git_sha
|
41
|
+
hash[:git_sha] = git_sha[0..40] if git_sha # A valid SHA will never exceed 40
|
45
42
|
hash[:description] = description[0..255] if description # Avoid massive descriptions
|
46
43
|
hash
|
47
44
|
end
|
48
|
-
|
49
45
|
end
|
50
46
|
|
51
47
|
class DefaultDeploy < EmptyDeploy
|
@@ -69,26 +65,24 @@ module Skylight
|
|
69
65
|
def description
|
70
66
|
config.get(:'deploy.description')
|
71
67
|
end
|
72
|
-
|
73
68
|
end
|
74
69
|
|
75
70
|
class HerokuDeploy < EmptyDeploy
|
76
|
-
|
77
71
|
def initialize(*)
|
78
72
|
super
|
79
73
|
@info = get_info
|
80
74
|
end
|
81
75
|
|
82
76
|
def id
|
83
|
-
@info ? @info[
|
77
|
+
@info ? @info["id"] : nil
|
84
78
|
end
|
85
79
|
|
86
80
|
def git_sha
|
87
|
-
@info ? @info[
|
81
|
+
@info ? @info["commit"] : nil
|
88
82
|
end
|
89
83
|
|
90
84
|
def description
|
91
|
-
@info ? @info[
|
85
|
+
@info ? @info["description"] : nil
|
92
86
|
end
|
93
87
|
|
94
88
|
private
|
@@ -97,16 +91,14 @@ module Skylight
|
|
97
91
|
info_path = config[:'heroku.dyno_info_path']
|
98
92
|
|
99
93
|
if File.exist?(info_path)
|
100
|
-
if info = JSON.parse(File.read(info_path))
|
101
|
-
info[
|
94
|
+
if (info = JSON.parse(File.read(info_path)))
|
95
|
+
info["release"]
|
102
96
|
end
|
103
97
|
end
|
104
98
|
end
|
105
|
-
|
106
99
|
end
|
107
100
|
|
108
101
|
class GitDeploy < EmptyDeploy
|
109
|
-
|
110
102
|
attr_reader :git_sha, :description
|
111
103
|
|
112
104
|
def initialize(*)
|
@@ -119,15 +111,12 @@ module Skylight
|
|
119
111
|
def get_info
|
120
112
|
Dir.chdir(config.root) do
|
121
113
|
info = `git log -1 --pretty="%H %s" 2>&1`
|
122
|
-
info.split(" ", 2).map(&:strip) if
|
114
|
+
info.split(" ", 2).map(&:strip) if $CHILD_STATUS.success?
|
123
115
|
end
|
124
116
|
end
|
125
|
-
|
126
117
|
end
|
127
118
|
|
128
|
-
DEPLOY_TYPES = [DefaultDeploy, HerokuDeploy, GitDeploy]
|
129
|
-
|
119
|
+
DEPLOY_TYPES = [DefaultDeploy, HerokuDeploy, GitDeploy].freeze
|
130
120
|
end
|
131
|
-
|
132
121
|
end
|
133
122
|
end
|
@@ -1,13 +1,13 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "socket"
|
2
|
+
require "securerandom"
|
3
3
|
|
4
4
|
module Skylight
|
5
5
|
module Util
|
6
6
|
module Hostname
|
7
7
|
def self.default_hostname
|
8
|
-
if hostname = Socket.gethostname
|
8
|
+
if (hostname = Socket.gethostname)
|
9
9
|
hostname.strip!
|
10
|
-
hostname = nil if hostname ==
|
10
|
+
hostname = nil if hostname == ""
|
11
11
|
end
|
12
12
|
|
13
13
|
hostname || "gen-#{SecureRandom.uuid}"
|
data/lib/skylight/util/http.rb
CHANGED
@@ -1,42 +1,38 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
1
|
+
require "uri"
|
2
|
+
require "json"
|
3
|
+
require "openssl"
|
4
|
+
require "net/http"
|
5
|
+
require "net/https"
|
6
|
+
require "skylight/core/util/gzip"
|
7
|
+
require "skylight/util/ssl"
|
8
8
|
|
9
9
|
module Skylight
|
10
10
|
module Util
|
11
11
|
class HTTP
|
12
|
-
CONTENT_ENCODING =
|
13
|
-
CONTENT_LENGTH =
|
14
|
-
CONTENT_TYPE =
|
15
|
-
ACCEPT =
|
16
|
-
X_VERSION_HDR =
|
17
|
-
APPLICATION_JSON =
|
18
|
-
AUTHORIZATION =
|
19
|
-
DEFLATE =
|
20
|
-
GZIP =
|
12
|
+
CONTENT_ENCODING = "content-encoding".freeze
|
13
|
+
CONTENT_LENGTH = "content-length".freeze
|
14
|
+
CONTENT_TYPE = "content-type".freeze
|
15
|
+
ACCEPT = "Accept".freeze
|
16
|
+
X_VERSION_HDR = "x-skylight-agent-version".freeze
|
17
|
+
APPLICATION_JSON = "application/json".freeze
|
18
|
+
AUTHORIZATION = "authorization".freeze
|
19
|
+
DEFLATE = "deflate".freeze
|
20
|
+
GZIP = "gzip".freeze
|
21
21
|
|
22
22
|
include Core::Util::Logging
|
23
23
|
|
24
24
|
attr_accessor :authentication
|
25
25
|
attr_reader :host, :port, :config
|
26
26
|
|
27
|
-
READ_EXCEPTIONS = [Timeout::Error, EOFError]
|
28
|
-
# This doesn't exist on Ruby 1.9.3
|
29
|
-
READ_EXCEPTIONS << Net::ReadTimeout if defined?(Net::ReadTimeout)
|
30
|
-
READ_EXCEPTIONS.freeze
|
27
|
+
READ_EXCEPTIONS = [Timeout::Error, EOFError, Net::ReadTimeout].freeze
|
31
28
|
|
32
29
|
class StartError < StandardError
|
33
30
|
attr_reader :original
|
34
31
|
|
35
|
-
def initialize(
|
36
|
-
@original =
|
37
|
-
super
|
32
|
+
def initialize(error)
|
33
|
+
@original = error
|
34
|
+
super error.inspect
|
38
35
|
end
|
39
|
-
|
40
36
|
end
|
41
37
|
|
42
38
|
class ReadResponseError < StandardError; end
|
@@ -44,27 +40,28 @@ module Skylight
|
|
44
40
|
def initialize(config, service = :auth, opts = {})
|
45
41
|
@config = config
|
46
42
|
|
47
|
-
unless url = config["#{service}_url"]
|
43
|
+
unless (url = config["#{service}_url"])
|
48
44
|
raise ArgumentError, "no URL specified for #{service}"
|
49
45
|
end
|
50
46
|
|
51
47
|
url = URI.parse(url)
|
52
48
|
|
53
|
-
@ssl = url.scheme ==
|
49
|
+
@ssl = url.scheme == "https"
|
54
50
|
@host = url.host
|
55
51
|
@port = url.port
|
56
52
|
|
57
|
-
if proxy_url = config[:proxy_url]
|
53
|
+
if (proxy_url = config[:proxy_url])
|
58
54
|
proxy_url = URI.parse(proxy_url)
|
59
|
-
@proxy_addr
|
60
|
-
@
|
55
|
+
@proxy_addr = proxy_url.host
|
56
|
+
@proxy_port = proxy_url.port
|
57
|
+
@proxy_user, @proxy_pass = (proxy_url.userinfo || "").split(/:/)
|
61
58
|
end
|
62
59
|
|
63
60
|
@open_timeout = get_timeout(:connect, config, service, opts)
|
64
61
|
@read_timeout = get_timeout(:read, config, service, opts)
|
65
62
|
|
66
63
|
@deflate = config["#{service}_http_deflate"]
|
67
|
-
@authentication = config[:
|
64
|
+
@authentication = config[:authentication]
|
68
65
|
end
|
69
66
|
|
70
67
|
def get(endpoint, hdrs = {})
|
@@ -82,146 +79,147 @@ module Skylight
|
|
82
79
|
execute(request, body)
|
83
80
|
end
|
84
81
|
|
85
|
-
|
82
|
+
private
|
86
83
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
84
|
+
def get_timeout(type, config, service, opts)
|
85
|
+
config.duration_ms("#{service}_http_#{type}_timeout") ||
|
86
|
+
opts[:timeout] || 15
|
87
|
+
end
|
91
88
|
|
92
|
-
|
93
|
-
|
89
|
+
def build_request(type, endpoint, hdrs, length = nil)
|
90
|
+
headers = {}
|
94
91
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
92
|
+
headers[CONTENT_LENGTH] = length.to_s if length
|
93
|
+
headers[AUTHORIZATION] = authentication if authentication
|
94
|
+
headers[ACCEPT] = APPLICATION_JSON
|
95
|
+
headers[X_VERSION_HDR] = VERSION
|
96
|
+
headers[CONTENT_ENCODING] = GZIP if length && @deflate
|
97
|
+
|
98
|
+
hdrs.each do |k, v|
|
99
|
+
headers[k] = v
|
100
|
+
end
|
100
101
|
|
101
|
-
|
102
|
-
headers[k] = v
|
102
|
+
type.new(endpoint, headers)
|
103
103
|
end
|
104
104
|
|
105
|
-
|
106
|
-
|
105
|
+
def do_request(http, req)
|
106
|
+
begin
|
107
|
+
client = http.start
|
108
|
+
rescue => e
|
109
|
+
# TODO: Retry here
|
110
|
+
raise StartError, e
|
111
|
+
end
|
107
112
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
raise StartError, e
|
114
|
-
end
|
113
|
+
begin
|
114
|
+
res = client.request(req)
|
115
|
+
rescue *READ_EXCEPTIONS => e
|
116
|
+
raise ReadResponseError, e.inspect
|
117
|
+
end
|
115
118
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
raise ReadResponseError, e.inspect
|
119
|
+
yield res
|
120
|
+
ensure
|
121
|
+
client.finish if client
|
120
122
|
end
|
121
123
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
124
|
+
def execute(req, body = nil)
|
125
|
+
t do
|
126
|
+
fmt "executing HTTP request; host=%s; port=%s; path=%s, body=%s",
|
127
|
+
@host, @port, req.path, body && body.bytesize
|
128
|
+
end
|
126
129
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
+
if body
|
131
|
+
body = Gzip.compress(body) if @deflate
|
132
|
+
req.body = body
|
133
|
+
end
|
130
134
|
|
131
|
-
|
132
|
-
|
133
|
-
req.body = body
|
134
|
-
end
|
135
|
+
http = Net::HTTP.new(@host, @port,
|
136
|
+
@proxy_addr, @proxy_port, @proxy_user, @proxy_pass)
|
135
137
|
|
136
|
-
|
137
|
-
|
138
|
+
http.open_timeout = @open_timeout
|
139
|
+
http.read_timeout = @read_timeout
|
138
140
|
|
139
|
-
|
140
|
-
|
141
|
+
if @ssl
|
142
|
+
http.use_ssl = true
|
141
143
|
|
142
|
-
|
143
|
-
|
144
|
+
unless SSL.ca_cert_file?
|
145
|
+
http.ca_file = SSL.ca_cert_file_or_default
|
146
|
+
end
|
144
147
|
|
145
|
-
|
146
|
-
http.ca_file = SSL.ca_cert_file_or_default
|
148
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
147
149
|
end
|
148
150
|
|
149
|
-
http
|
150
|
-
|
151
|
+
do_request(http, req) do |res|
|
152
|
+
unless res.code =~ /2\d\d/
|
153
|
+
debug "server responded with #{res.code}"
|
154
|
+
t { fmt "body=%s", res.body }
|
155
|
+
end
|
151
156
|
|
152
|
-
|
153
|
-
unless res.code =~ /2\d\d/
|
154
|
-
debug "server responded with #{res.code}"
|
155
|
-
t { fmt "body=%s", res.body }
|
157
|
+
Response.new(res.code.to_i, res, res.body)
|
156
158
|
end
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
@body = body
|
159
|
+
rescue Exception => e
|
160
|
+
error "http %s %s failed; error=%s; msg=%s", req.method, req.path, e.class, e.message
|
161
|
+
t { e.backtrace.join("\n") }
|
162
|
+
ErrorResponse.new(req, e)
|
163
|
+
end
|
164
|
+
|
165
|
+
class Response
|
166
|
+
attr_reader :status, :headers, :body, :exception
|
167
|
+
|
168
|
+
def initialize(status, headers, body)
|
169
|
+
@status = status
|
170
|
+
@headers = headers
|
171
|
+
|
172
|
+
if (headers[CONTENT_TYPE] || "").include?(APPLICATION_JSON)
|
173
|
+
begin
|
174
|
+
@body = JSON.parse(body)
|
175
|
+
rescue JSON::ParserError
|
176
|
+
@body = body # not really JSON I guess
|
177
|
+
end
|
178
|
+
else
|
179
|
+
@body = body
|
178
180
|
end
|
179
|
-
else
|
180
|
-
@body = body
|
181
181
|
end
|
182
|
-
end
|
183
182
|
|
184
|
-
|
185
|
-
|
186
|
-
|
183
|
+
def success?
|
184
|
+
status >= 200 && status < 300
|
185
|
+
end
|
187
186
|
|
188
|
-
|
189
|
-
|
190
|
-
|
187
|
+
def to_s
|
188
|
+
body.to_s
|
189
|
+
end
|
191
190
|
|
192
|
-
|
193
|
-
|
191
|
+
def get(key)
|
192
|
+
return nil unless body.is_a?(Hash)
|
194
193
|
|
195
|
-
|
196
|
-
|
197
|
-
|
194
|
+
res = body
|
195
|
+
key.split(".").each do |part|
|
196
|
+
return unless (res = res[part])
|
197
|
+
end
|
198
|
+
res
|
198
199
|
end
|
199
|
-
res
|
200
|
-
end
|
201
200
|
|
202
|
-
|
203
|
-
|
204
|
-
|
201
|
+
def respond_to_missing?(name, include_all = false)
|
202
|
+
super || body.respond_to?(name, include_all)
|
203
|
+
end
|
205
204
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
205
|
+
def method_missing(name, *args, &blk)
|
206
|
+
if respond_to_missing?(name)
|
207
|
+
body.send(name, *args, &blk)
|
208
|
+
else
|
209
|
+
super
|
210
|
+
end
|
211
211
|
end
|
212
212
|
end
|
213
|
-
end
|
214
213
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
214
|
+
ErrorResponse = Struct.new(:request, :exception) do
|
215
|
+
def status
|
216
|
+
nil
|
217
|
+
end
|
219
218
|
|
220
|
-
|
221
|
-
|
219
|
+
def success?
|
220
|
+
false
|
221
|
+
end
|
222
222
|
end
|
223
|
-
end
|
224
|
-
|
225
223
|
end
|
226
224
|
end
|
227
225
|
end
|