rookout 0.1.0 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|