rookout 0.1.0 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rookout/augs/actions/action_run_processor.rb +3 -3
- data/lib/rookout/augs/aug.rb +24 -90
- data/lib/rookout/augs/aug_factory.rb +24 -14
- data/lib/rookout/augs/aug_rate_limiter.rb +3 -3
- data/lib/rookout/augs/augs_manager.rb +3 -1
- data/lib/rookout/augs/conditions/condition.rb +4 -2
- data/lib/rookout/augs/locations/location.rb +75 -1
- data/lib/rookout/augs/locations/location_exception_handler.rb +22 -0
- data/lib/rookout/augs/locations/location_file_line.rb +16 -4
- data/lib/rookout/com_ws/agent_com_ws.rb +28 -33
- data/lib/rookout/com_ws/information.rb +1 -1
- data/lib/rookout/com_ws/output.rb +4 -10
- data/lib/rookout/com_ws/pinger.rb +36 -0
- data/lib/rookout/com_ws/websocket_client.rb +143 -0
- data/lib/rookout/commit.rb +3 -0
- data/lib/rookout/config.rb +1 -0
- data/lib/rookout/exceptions.rb +40 -0
- data/lib/rookout/interface.rb +41 -24
- data/lib/rookout/logger.rb +16 -2
- data/lib/rookout/processor/namespace_serializer.rb +1 -1
- data/lib/rookout/processor/namespaces/frame_namespace.rb +1 -0
- data/lib/rookout/processor/namespaces/namespace.rb +2 -2
- data/lib/rookout/processor/namespaces/noop_namespace.rb +1 -1
- data/lib/rookout/processor/namespaces/ruby_object_serializer.rb +4 -3
- data/lib/rookout/processor/operations/set_operation.rb +4 -1
- data/lib/rookout/processor/paths/arithmetic_path.rb +1 -1
- data/lib/rookout/processor/paths/canopy/markers.rb +5 -2
- data/lib/rookout/rookout_singleton.rb +4 -3
- data/lib/rookout/services/position.rb +73 -73
- data/lib/rookout/services/tracer.rb +8 -5
- data/lib/rookout/trigger_services.rb +2 -2
- data/lib/rookout/user_warnings.rb +2 -0
- data/lib/rookout/utils.rb +9 -0
- data/lib/rookout/version.rb +1 -2
- metadata +37 -32
@@ -1,7 +1,5 @@
|
|
1
1
|
module Rookout
|
2
2
|
module ComWs
|
3
|
-
require "securerandom"
|
4
|
-
require "kontena-websocket-client"
|
5
3
|
require "event_emitter"
|
6
4
|
require "google/protobuf/well_known_types"
|
7
5
|
require "concurrent"
|
@@ -10,14 +8,17 @@ module Rookout
|
|
10
8
|
require_relative "../logger"
|
11
9
|
require_relative "../user_warnings"
|
12
10
|
require_relative "../exceptions"
|
11
|
+
require_relative "../utils"
|
13
12
|
|
14
13
|
require_relative "../processor/rook_error"
|
15
14
|
|
16
15
|
require_relative "../protobuf/messages_pb"
|
17
16
|
require_relative "../protobuf/envelope_pb"
|
18
17
|
|
18
|
+
require_relative "websocket_client"
|
19
19
|
require_relative "backoff"
|
20
20
|
require_relative "information"
|
21
|
+
require_relative "pinger"
|
21
22
|
|
22
23
|
class AgentComWs
|
23
24
|
include EventEmitter
|
@@ -68,7 +69,11 @@ module Rookout
|
|
68
69
|
end
|
69
70
|
|
70
71
|
def wait_for_ready
|
71
|
-
@ready_event.wait Config.agent_com_timeout
|
72
|
+
is_finished = @ready_event.wait Config.agent_com_timeout
|
73
|
+
# We didn't finish - will keep trying in the background
|
74
|
+
raise Exceptions::RookCommunicationException unless is_finished
|
75
|
+
|
76
|
+
# We finished - raise if we failed
|
72
77
|
raise @connection_error if @connection_error
|
73
78
|
end
|
74
79
|
|
@@ -86,17 +91,15 @@ module Rookout
|
|
86
91
|
while @running
|
87
92
|
begin
|
88
93
|
backoff.before_connection_attempt
|
89
|
-
|
90
|
-
register client
|
94
|
+
client = open_new_connection
|
91
95
|
|
92
|
-
|
93
|
-
|
94
|
-
|
96
|
+
Logger.instance.debug "WebSocket connected successfully"
|
97
|
+
@token_valid = true
|
98
|
+
backoff.after_connect
|
95
99
|
|
96
|
-
|
97
|
-
end
|
100
|
+
connection_pump client
|
98
101
|
rescue Exception => e
|
99
|
-
if !@token_valid && e.
|
102
|
+
if !@token_valid && e.message.include?("403")
|
100
103
|
@connection_error = Exceptions::RookInvalidToken.new @token
|
101
104
|
@ready_event.set
|
102
105
|
end
|
@@ -109,26 +112,15 @@ module Rookout
|
|
109
112
|
end
|
110
113
|
end
|
111
114
|
|
112
|
-
def
|
113
|
-
|
114
|
-
|
115
|
-
}
|
116
|
-
|
117
|
-
headers["X-Rookout-Token"] = @token unless @token.nil?
|
118
|
-
|
119
|
-
# NOTE: WE DONT HAVE PROXY SUPPORT (YET) - THIS WILL PROBABLY REQUIRE FORKING KONTENA
|
120
|
-
{ headers: headers,
|
121
|
-
connect_timeout: Config.agent_com_timeout,
|
122
|
-
open_timeout: Config.agent_com_timeout,
|
123
|
-
ping_interval: Config.agent_com_ping_interval,
|
124
|
-
ping_timeout: Config.agent_com_ping_timeout }
|
125
|
-
end
|
115
|
+
def open_new_connection
|
116
|
+
client = WebsocketClient.new @uri, @proxy, @token
|
117
|
+
client.connect
|
126
118
|
|
127
|
-
def register client
|
128
119
|
Logger.instance.info "Registering agent with id #{@agent_id}"
|
129
|
-
|
130
120
|
msg = Com::Rookout::NewAgentMessage.new agent_info: @info.pack
|
131
|
-
client.
|
121
|
+
client.send_frame wrap_in_envelope(msg)
|
122
|
+
|
123
|
+
client
|
132
124
|
end
|
133
125
|
|
134
126
|
ACCEPTED_MESSAGE_TYPES = [
|
@@ -140,11 +132,11 @@ module Rookout
|
|
140
132
|
].freeze
|
141
133
|
|
142
134
|
def connection_pump client
|
143
|
-
on_outgoing_exit = proc { client.
|
135
|
+
on_outgoing_exit = proc { client.close }
|
144
136
|
send_thread = Thread.new { outgoing client, on_outgoing_exit }
|
145
137
|
send_thread.name = "rookout-outgoing-thread"
|
146
138
|
|
147
|
-
|
139
|
+
message_handler = proc do |raw_message|
|
148
140
|
envelope = Com::Rookout::Envelope.decode raw_message.pack("c*")
|
149
141
|
|
150
142
|
ACCEPTED_MESSAGE_TYPES.each do |klass|
|
@@ -153,6 +145,8 @@ module Rookout
|
|
153
145
|
end
|
154
146
|
end
|
155
147
|
|
148
|
+
client.connection_pump message_handler
|
149
|
+
|
156
150
|
Logger.instance.debug "Incoming loop - socket disconnected"
|
157
151
|
|
158
152
|
@pending_messages.push ExitMessage.new(send_thread)
|
@@ -160,7 +154,7 @@ module Rookout
|
|
160
154
|
end
|
161
155
|
|
162
156
|
def outgoing client, on_exit
|
163
|
-
|
157
|
+
Pinger.new(client, Config.agent_com_ping_interval, Config.agent_com_ping_timeout).repeat do
|
164
158
|
begin
|
165
159
|
msg = @pending_messages.pop true
|
166
160
|
rescue ThreadError
|
@@ -174,7 +168,7 @@ module Rookout
|
|
174
168
|
msg.event.set
|
175
169
|
else
|
176
170
|
begin
|
177
|
-
client.
|
171
|
+
client.send_frame msg
|
178
172
|
rescue RuntimeError
|
179
173
|
@queue << msg
|
180
174
|
break
|
@@ -184,6 +178,7 @@ module Rookout
|
|
184
178
|
rescue Exception => e
|
185
179
|
Logger.instance.exception "Outgoing thread failed", e
|
186
180
|
ensure
|
181
|
+
Logger.instance.debug "Outgoing thread exiting"
|
187
182
|
on_exit.call
|
188
183
|
end
|
189
184
|
|
@@ -196,7 +191,7 @@ module Rookout
|
|
196
191
|
end
|
197
192
|
|
198
193
|
def reset_id
|
199
|
-
@agent_id =
|
194
|
+
@agent_id = Utils.uuid
|
200
195
|
@output.agent_id = @agent_id
|
201
196
|
@info.agent_id = @agent_id
|
202
197
|
end
|
@@ -57,19 +57,13 @@ module Rookout
|
|
57
57
|
return if @closing || !@agent_com
|
58
58
|
|
59
59
|
@rule_status_update_bucket.if_available do
|
60
|
-
|
60
|
+
status = Com::Rookout::RuleStatusMessage.new agent_id: @agent_id,
|
61
|
+
rule_id: rule_id,
|
62
|
+
active: active
|
61
63
|
if error
|
62
|
-
|
63
|
-
type: error.type
|
64
|
-
protobuf_error.parameters.copy_from error.parameters
|
65
|
-
protobuf_error.exc.copy_from error.exc
|
66
|
-
protobuf_error.traceback.copy_from error.traceback
|
64
|
+
status.error = error.dumps
|
67
65
|
end
|
68
66
|
|
69
|
-
status = Com::Rookout::RuleStatusMessage.new agent_id: @agent_id,
|
70
|
-
rule_id: rule_id,
|
71
|
-
active: active,
|
72
|
-
error: protobuf_error
|
73
67
|
@agent_com.add status
|
74
68
|
end
|
75
69
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Rookout
|
2
|
+
module ComWs
|
3
|
+
require_relative "../logger"
|
4
|
+
|
5
|
+
class Pinger
|
6
|
+
def initialize connection, interval, timeout
|
7
|
+
@interval = interval
|
8
|
+
@timeout = timeout
|
9
|
+
@connection = connection
|
10
|
+
|
11
|
+
@last_pong = Time.now
|
12
|
+
@last_ping = Time.now
|
13
|
+
end
|
14
|
+
|
15
|
+
def repeat
|
16
|
+
loop do
|
17
|
+
if Time.now - @last_ping > @interval
|
18
|
+
Logger.instance.debug "Sending Ping"
|
19
|
+
@last_ping = Time.now
|
20
|
+
@connection.ping Time.now.to_s do
|
21
|
+
Logger.instance.debug "Got Ping reply"
|
22
|
+
@last_pong = Time.now
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
if Time.now - @last_pong > @timeout
|
27
|
+
Logger.instance.debug "Ping timeout"
|
28
|
+
break
|
29
|
+
end
|
30
|
+
|
31
|
+
yield
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module Rookout
|
2
|
+
module ComWs
|
3
|
+
require "openssl"
|
4
|
+
require "websocket/driver"
|
5
|
+
|
6
|
+
require_relative "../config"
|
7
|
+
require_relative "../logger"
|
8
|
+
require_relative "../exceptions"
|
9
|
+
|
10
|
+
class WebsocketClient
|
11
|
+
def initialize url, proxy, token
|
12
|
+
@token = token
|
13
|
+
@connection = WebsocketConnection.new url, proxy
|
14
|
+
@driver = nil
|
15
|
+
@error = nil
|
16
|
+
@last_ping = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def connect
|
20
|
+
# TODO: add proxy support
|
21
|
+
@connection.connect
|
22
|
+
@driver = WebSocket::Driver.client @connection
|
23
|
+
|
24
|
+
headers.each do |key, value|
|
25
|
+
@driver.set_header key, value
|
26
|
+
end
|
27
|
+
|
28
|
+
@driver.on :error do |error|
|
29
|
+
@error = error
|
30
|
+
end
|
31
|
+
|
32
|
+
# Connect to the remote server
|
33
|
+
@driver.start
|
34
|
+
# TODO: ADD CONNECT TIMEOUT
|
35
|
+
while @driver.state == :connecting
|
36
|
+
recv_data = @connection.read_char
|
37
|
+
@driver.parse recv_data
|
38
|
+
end
|
39
|
+
|
40
|
+
raise Exceptions::RookWebsocketException, @error if @driver.state != :open
|
41
|
+
end
|
42
|
+
|
43
|
+
def connection_pump message_handler
|
44
|
+
@driver.on :message do |e|
|
45
|
+
message_handler.call e.data
|
46
|
+
end
|
47
|
+
|
48
|
+
until @driver.state == :closed
|
49
|
+
recv_data = @connection.read_char
|
50
|
+
@driver.parse recv_data
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def send_frame msg
|
55
|
+
@driver.binary msg
|
56
|
+
end
|
57
|
+
|
58
|
+
def ping message, &callback
|
59
|
+
@driver.ping message, &callback
|
60
|
+
end
|
61
|
+
|
62
|
+
def close
|
63
|
+
return if @driver.nil?
|
64
|
+
|
65
|
+
@driver.close
|
66
|
+
@connection.close
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def headers
|
72
|
+
result = {
|
73
|
+
"User-Agent" => "RookoutAgent/#{Config.rookout_version}+#{Config.rookout_commit}"
|
74
|
+
}
|
75
|
+
|
76
|
+
result["X-Rookout-Token"] = @token unless @token.nil?
|
77
|
+
|
78
|
+
result
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class WebsocketConnection
|
83
|
+
def initialize url, proxy
|
84
|
+
@url = url
|
85
|
+
@proxy = proxy
|
86
|
+
|
87
|
+
@uri = URI.parse @url
|
88
|
+
@secure = %w[https wss].include? @uri.scheme
|
89
|
+
|
90
|
+
@socket = nil
|
91
|
+
end
|
92
|
+
|
93
|
+
def connect
|
94
|
+
if @secure
|
95
|
+
@socket = ssl_connect
|
96
|
+
else
|
97
|
+
@socket = tcp_connect
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
attr_reader :url
|
102
|
+
|
103
|
+
def read_char
|
104
|
+
@socket.getc
|
105
|
+
end
|
106
|
+
|
107
|
+
def write buffer
|
108
|
+
@socket << buffer
|
109
|
+
end
|
110
|
+
|
111
|
+
def close
|
112
|
+
return if @socket.nil?
|
113
|
+
|
114
|
+
@socket.close
|
115
|
+
@socket = nil
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def tcp_connect
|
121
|
+
TCPSocket.new @uri.host,
|
122
|
+
@uri.port || (@secure ? 443 : 80)
|
123
|
+
end
|
124
|
+
|
125
|
+
def ssl_connect
|
126
|
+
tcp_socket = tcp_connect
|
127
|
+
|
128
|
+
ctx = ::OpenSSL::SSL::SSLContext.new
|
129
|
+
ctx.min_version = ::OpenSSL::SSL::TLS1_2_VERSION
|
130
|
+
cert_store = ::OpenSSL::X509::Store.new
|
131
|
+
cert_store.set_default_paths
|
132
|
+
ctx.cert_store = cert_store
|
133
|
+
|
134
|
+
ssl_socket = ::OpenSSL::SSL::SSLSocket.new tcp_socket, ctx
|
135
|
+
ssl_socket.hostname = @uri.host
|
136
|
+
ssl_socket.sync_close = true
|
137
|
+
ssl_socket.connect
|
138
|
+
|
139
|
+
ssl_socket
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
data/lib/rookout/config.rb
CHANGED
data/lib/rookout/exceptions.rb
CHANGED
@@ -136,5 +136,45 @@ module Rookout
|
|
136
136
|
super "No Rookout token was supplied. Make sure to pass the Rookout Token when starting the rook"
|
137
137
|
end
|
138
138
|
end
|
139
|
+
|
140
|
+
class RookInvalidOptions < ToolException
|
141
|
+
def initialize description
|
142
|
+
super description
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class RookCrcMismatchException < ToolException
|
147
|
+
def initialize filepath, expected, calculated
|
148
|
+
super "Line CRC32s do not match! path: #{filepath}, expected: #{expected}, calculated:#{calculated}",
|
149
|
+
{
|
150
|
+
"filepath" => filepath,
|
151
|
+
"expected" => expected,
|
152
|
+
"calculated" => calculated
|
153
|
+
}
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
class RookLineMoved < ToolException
|
158
|
+
def initialize filepath, old_line_no, new_line_no
|
159
|
+
super "Line has moved! path: #{filepath}, original line no: #{old_line_no}, new line no: #{new_line_no}",
|
160
|
+
{
|
161
|
+
"filepath" => filepath,
|
162
|
+
"old_line_no" => old_line_no,
|
163
|
+
"new_line_no" => new_line_no
|
164
|
+
}
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
class RookCommunicationException < ToolException
|
169
|
+
def initialize
|
170
|
+
super "Failed to connect to the controller - will continue attempting in the background"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
class RookWebsocketException < ToolException
|
175
|
+
def initialize error
|
176
|
+
super "Error from Websocket #{error}", { "error" => error }
|
177
|
+
end
|
178
|
+
end
|
139
179
|
end
|
140
180
|
end
|
data/lib/rookout/interface.rb
CHANGED
@@ -5,6 +5,7 @@ module Rookout
|
|
5
5
|
|
6
6
|
require_relative "config"
|
7
7
|
require_relative "exceptions"
|
8
|
+
include Exceptions
|
8
9
|
|
9
10
|
def initialize
|
10
11
|
@rook = nil
|
@@ -19,24 +20,21 @@ module Rookout
|
|
19
20
|
require_relative "rookout_singleton"
|
20
21
|
|
21
22
|
configure_logging options
|
22
|
-
labels = options[:labels] || parse_labels(ENV["ROOKOUT_LABELS"])
|
23
|
-
validate_labels labels
|
24
|
-
|
25
23
|
configure_git options
|
26
24
|
|
27
|
-
|
28
|
-
|
29
|
-
async_start = true? ENV["ROOKOUT_ASYNC_START"]
|
30
|
-
fork = evaluate_flag options[:fork], "ROOKOUT_ENABLE_FORK"
|
31
|
-
|
32
|
-
print_config com, labels: labels, async_start: async_start, fork: fork if Config.debug
|
25
|
+
start_options = configure_start_options options
|
26
|
+
print_config start_options
|
33
27
|
|
34
28
|
rook = RookoutSingleton.instance
|
35
|
-
rook.connect
|
36
|
-
|
37
|
-
|
29
|
+
rook.connect(**start_options)
|
30
|
+
rescue RookMissingToken, RookInvalidToken, RookInvalidOptions, RookVersionNotSupported => e
|
31
|
+
raise if throw_errors
|
32
|
+
STDERR.puts "[Rookout] Failed to start Rookout: #{e.message}"
|
33
|
+
rescue RookCommunicationException => e
|
34
|
+
raise if throw_errors
|
35
|
+
STDERR.puts "[Rookout] " + e.message
|
38
36
|
rescue Exception => e
|
39
|
-
puts e.full_message if Config.debug
|
37
|
+
STDERR.puts e.full_message if Config.debug
|
40
38
|
raise if throw_errors
|
41
39
|
end
|
42
40
|
end
|
@@ -59,7 +57,7 @@ module Rookout
|
|
59
57
|
def configure_logging options
|
60
58
|
if Config.debug
|
61
59
|
log_to_stderr = true
|
62
|
-
log_level =
|
60
|
+
log_level = :DEBUG
|
63
61
|
else
|
64
62
|
log_to_stderr = evaluate_flag options[:log_to_stderr], "ROOKOUT_LOG_TO_STDERR"
|
65
63
|
log_level = options[:log_level] || ENV["ROOKOUT_LOG_FILE"]
|
@@ -77,16 +75,22 @@ module Rookout
|
|
77
75
|
Config.user_git_commit = options[:git_commit] if options[:git_commit]
|
78
76
|
end
|
79
77
|
|
80
|
-
def
|
78
|
+
def configure_start_options options
|
81
79
|
host = evaluate_config options[:host], "ROOKOUT_CONTROLLER_HOST", "wss://control.rookout.com"
|
82
80
|
port = evaluate_config options[:port], "ROOKOUT_CONTROLLER_PORT", 443
|
83
81
|
proxy = evaluate_config options[:proxy], "ROOKOUT_PROXY"
|
84
82
|
token = evaluate_config options[:token], "ROOKOUT_TOKEN"
|
85
83
|
|
86
|
-
raise
|
84
|
+
raise RookMissingToken if token.nil? && host == "wss://control.rookout.com"
|
87
85
|
verify_token token if token
|
88
86
|
|
89
|
-
|
87
|
+
labels = stringify_labels(options[:labels]) || parse_labels(ENV["ROOKOUT_LABELS"])
|
88
|
+
validate_labels labels
|
89
|
+
|
90
|
+
async_start = true? ENV["ROOKOUT_ASYNC_START"]
|
91
|
+
fork = evaluate_flag options[:fork], "ROOKOUT_ENABLE_FORK"
|
92
|
+
|
93
|
+
{ host: host, port: port, proxy: proxy, token: token, labels: labels, async_start: async_start, fork: fork }
|
90
94
|
end
|
91
95
|
|
92
96
|
def evaluate_flag argument, env_var_name
|
@@ -104,6 +108,18 @@ module Rookout
|
|
104
108
|
default
|
105
109
|
end
|
106
110
|
|
111
|
+
def stringify_labels labels
|
112
|
+
return nil unless labels
|
113
|
+
|
114
|
+
stringified_labels = {}
|
115
|
+
|
116
|
+
labels.each do |label_name, label_value|
|
117
|
+
stringified_labels[label_name.to_s] = label_value.to_s
|
118
|
+
end
|
119
|
+
|
120
|
+
stringified_labels
|
121
|
+
end
|
122
|
+
|
107
123
|
def parse_labels raw_labels
|
108
124
|
labels = {}
|
109
125
|
return labels if raw_labels.nil?
|
@@ -120,21 +136,22 @@ module Rookout
|
|
120
136
|
def validate_labels labels
|
121
137
|
labels.each do |label_name, _|
|
122
138
|
if label_name.start_with? "$"
|
123
|
-
raise
|
139
|
+
raise RookInvalidLabel, label_name
|
124
140
|
end
|
125
141
|
end
|
126
142
|
end
|
127
143
|
|
128
144
|
def verify_token token
|
129
|
-
raise
|
130
|
-
raise
|
131
|
-
raise
|
145
|
+
raise RookInvalidOptions, "Rookout token should be a String" unless token.is_a? String
|
146
|
+
raise RookInvalidOptions, "Rookout token should be 64 characters" unless token.length == 64
|
147
|
+
raise RookInvalidOptions, "Rookout token must consist of only hexadecimal characters" unless
|
132
148
|
token.match(/^[0-9a-zA-Z]{0,64}$/)
|
133
149
|
end
|
134
150
|
|
135
|
-
def print_config
|
136
|
-
|
137
|
-
|
151
|
+
def print_config options
|
152
|
+
return unless Config.debug
|
153
|
+
|
154
|
+
puts "[Rookout] Start Options: #{options}"
|
138
155
|
end
|
139
156
|
end
|
140
157
|
end
|