rookout 0.1.0 → 0.1.56

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rookout/atfork.rb +73 -0
  3. data/lib/rookout/augs/actions/action_run_processor.rb +4 -3
  4. data/lib/rookout/augs/aug.rb +33 -91
  5. data/lib/rookout/augs/aug_factory.rb +94 -27
  6. data/lib/rookout/augs/aug_rate_limiter.rb +50 -47
  7. data/lib/rookout/augs/augs_manager.rb +3 -1
  8. data/lib/rookout/augs/conditions/condition.rb +4 -2
  9. data/lib/rookout/augs/limits_manager.rb +32 -0
  10. data/lib/rookout/augs/locations/location.rb +75 -1
  11. data/lib/rookout/augs/locations/location_exception_handler.rb +22 -0
  12. data/lib/rookout/augs/locations/location_file_line.rb +21 -5
  13. data/lib/rookout/com_ws/agent_com_ws.rb +97 -58
  14. data/lib/rookout/com_ws/backoff.rb +5 -10
  15. data/lib/rookout/com_ws/command_handler.rb +1 -1
  16. data/lib/rookout/com_ws/envelope_wrapper.rb +68 -0
  17. data/lib/rookout/com_ws/git.rb +1 -1
  18. data/lib/rookout/com_ws/information.rb +95 -4
  19. data/lib/rookout/com_ws/output.rb +69 -21
  20. data/lib/rookout/com_ws/pinger.rb +41 -0
  21. data/lib/rookout/com_ws/websocket_client.rb +173 -0
  22. data/lib/rookout/commit.rb +3 -0
  23. data/lib/rookout/config.rb +94 -18
  24. data/lib/rookout/exceptions.rb +147 -12
  25. data/lib/rookout/interface.rb +95 -32
  26. data/lib/rookout/logger.rb +39 -10
  27. data/lib/rookout/processor/namespace_serializer.rb +2 -2
  28. data/lib/rookout/processor/namespace_serializer2.rb +331 -0
  29. data/lib/rookout/processor/namespaces/container_namespace.rb +5 -0
  30. data/lib/rookout/processor/namespaces/frame_namespace.rb +20 -17
  31. data/lib/rookout/processor/namespaces/namespace.rb +3 -2
  32. data/lib/rookout/processor/namespaces/noop_namespace.rb +4 -8
  33. data/lib/rookout/processor/namespaces/ruby_object_namespace.rb +39 -22
  34. data/lib/rookout/processor/namespaces/ruby_object_serializer.rb +15 -12
  35. data/lib/rookout/processor/namespaces/ruby_utils_namespace.rb +0 -4
  36. data/lib/rookout/processor/namespaces/stack_namespace.rb +6 -4
  37. data/lib/rookout/processor/namespaces/traceback_namespace.rb +13 -9
  38. data/lib/rookout/processor/operations/set_operation.rb +6 -1
  39. data/lib/rookout/processor/paths/arithmetic_path.rb +5 -3
  40. data/lib/rookout/processor/paths/canopy/actions.rb +5 -1
  41. data/lib/rookout/processor/paths/canopy/consts.rb +6 -4
  42. data/lib/rookout/processor/paths/canopy/maps.rb +286 -286
  43. data/lib/rookout/processor/paths/canopy/markers.rb +35 -4
  44. data/lib/rookout/processor/processor_factory.rb +0 -2
  45. data/lib/rookout/processor/rook_error.rb +6 -1
  46. data/lib/rookout/protobuf/controller_info_pb.rb +1 -0
  47. data/lib/rookout/protobuf/messages_pb.rb +54 -0
  48. data/lib/rookout/protobuf/variant2_pb.rb +42 -0
  49. data/lib/rookout/protobuf/variant_pb.rb +22 -0
  50. data/lib/rookout/rookout_singleton.rb +23 -5
  51. data/lib/rookout/sanitizer.rb +22 -0
  52. data/lib/rookout/services/position.rb +92 -75
  53. data/lib/rookout/services/tracer.rb +30 -16
  54. data/lib/rookout/start.rb +12 -0
  55. data/lib/rookout/trigger_services.rb +2 -2
  56. data/lib/rookout/user_warnings.rb +2 -0
  57. data/lib/rookout/utils.rb +34 -0
  58. data/lib/rookout/version.rb +1 -2
  59. data/lib/rookout.rb +4 -0
  60. metadata +77 -51
@@ -1,10 +1,84 @@
1
1
  module Rookout
2
2
  module Augs
3
3
  module Locations
4
+ require_relative "../../processor/rook_error"
5
+
6
+ MAX_LOG_CACHE_SIZE = 10
7
+
4
8
  class Location
5
- def add_aug _trigger_services, _aug
9
+ def initialize output, aug
10
+ @output = output
11
+ @aug = aug
12
+ @log_cache = []
13
+ end
14
+
15
+ def add_aug _trigger_services
6
16
  raise NotImplementedError
7
17
  end
18
+
19
+ def id
20
+ @aug.id
21
+ end
22
+
23
+ def execute frame_binding, stack_trace, extracted
24
+ UserWarnings.with self do
25
+ begin
26
+ @aug.execute frame_binding, stack_trace, extracted, @output
27
+ rescue SystemExit
28
+ raise
29
+ rescue Exception => e
30
+ message = "Exception while processing Aug"
31
+ error = Processor::RookError.new e, message
32
+ notify_warning error
33
+ end
34
+ end
35
+ end
36
+
37
+ def notify_active
38
+ send_rule_status :Active
39
+ end
40
+
41
+ def notify_pending
42
+ send_rule_status :Pending
43
+ end
44
+
45
+ def notify_removed
46
+ send_rule_status :Deleted
47
+ end
48
+
49
+ def notify_error error
50
+ send_rule_status :Error, error
51
+ end
52
+
53
+ def notify_warning error
54
+ return if silence_log? error
55
+
56
+ Logger.instance.warning error.message, error.exception
57
+
58
+ # For easier testing
59
+ return if @output.nil?
60
+ @output.send_rule_status id, :Warning, error
61
+ end
62
+
63
+ private
64
+
65
+ def silence_log? error
66
+ return true if @log_cache.length >= MAX_LOG_CACHE_SIZE || @log_cache.include?(error.message)
67
+
68
+ @log_cache << error.message
69
+ false
70
+ end
71
+
72
+ def send_rule_status status, error = nil
73
+ return if @status == status
74
+
75
+ Logger.instance.info "Updating rule status for #{@id} to #{status}"
76
+ @status = status
77
+
78
+ # For easier testing
79
+ return if @output.nil?
80
+ @output.send_rule_status id, status, error
81
+ end
8
82
  end
9
83
  end
10
84
  end
@@ -0,0 +1,22 @@
1
+ module Rookout
2
+ module Augs
3
+ require_relative "../../logger"
4
+
5
+ require_relative "../../processor/rook_error"
6
+
7
+ module Locations
8
+ require_relative "location"
9
+
10
+ class LocationExceptionHandler < Location
11
+ NAME = "exception_handler".freeze
12
+
13
+ def initialize _arguments, output, aug
14
+ super output, aug
15
+ end
16
+
17
+ def add_aug _trigger_services
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,24 +1,40 @@
1
1
  module Rookout
2
2
  module Augs
3
+ require_relative "../../logger"
4
+
5
+ require_relative "../../processor/rook_error"
6
+
3
7
  module Locations
4
8
  require_relative "location"
5
9
 
6
10
  class LocationFileLine < Location
7
11
  NAME = "file_line".freeze
8
12
 
9
- def initialize arguments, _processor_factory
13
+ def initialize arguments, output, aug
14
+ super output, aug
10
15
  @filename = arguments["filename"]
11
16
  @lineno = arguments["lineno"]
12
17
 
18
+ # NOTE: Hashes are only used for suggestions, not for verification
13
19
  @file_hash = arguments["sha256"]
14
20
  @line_crc = arguments["line_crc32_2"]
15
- @line_unique = arguments["line_unique"] != 0
21
+ @line_unique = arguments["line_unique"] || false
16
22
  end
17
23
 
18
- attr_reader :filename, :lineno, :file_hash, :line_crc, :line_unique
24
+ attr_reader :filename
25
+ attr_reader :lineno
26
+ attr_reader :file_hash
27
+ attr_reader :line_crc
28
+ attr_reader :line_unique
19
29
 
20
- def add_aug trigger_services, aug
21
- trigger_services.get_service("position").add_aug self, aug
30
+ def add_aug trigger_services
31
+ trigger_services.get_service("position").add_aug self
32
+ rescue SystemExit
33
+ raise
34
+ rescue Exception => e
35
+ message = "Exception when adding aug"
36
+ Logger.instance.error message, e
37
+ notify_error Processor::RookError.new e, message
22
38
  end
23
39
  end
24
40
  end
@@ -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,21 +8,30 @@ 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
24
25
 
25
- def initialize output, agent_host, agent_port, proxy, token, labels
26
- agent_host_with_protocl = agent_host.include?("://") ? agent_host : "ws://#{agent_host}"
27
- @uri = "#{agent_host_with_protocl}:#{agent_port}/v1"
26
+ attr_reader :pending_messages
27
+
28
+ def initialize output, agent_host, agent_port, proxy, token, labels, print_on_connect
29
+ if agent_host.nil? || agent_host.empty?
30
+ @uri = ""
31
+ else
32
+ agent_host_with_protocl = agent_host.include?("://") ? agent_host : "ws://#{agent_host}"
33
+ @uri = "#{agent_host_with_protocl}:#{agent_port}/v1"
34
+ end
28
35
  if proxy.nil? || proxy.empty?
29
36
  @proxy = nil
30
37
  else
@@ -38,37 +45,55 @@ module Rookout
38
45
  @info = Information.new labels
39
46
  reset_id
40
47
 
41
- @thread = nil
48
+ @main_thread = nil
49
+ @outgoing_thread = nil
42
50
  @pending_messages = Queue.new
51
+ @pending_messages_length = 0
43
52
 
44
53
  @running = false
45
54
  @ready_event = Concurrent::Event.new
46
55
  once("Com::Rookout::InitialAugsCommand") { @ready_event.set }
47
- end
48
56
 
49
- def add message
50
- buffer = wrap_in_envelope message
51
- if buffer.length > Config.agent_com_max_message_limit
52
- exc = Exceptions::RookMessageSizeExceeded.new buffer.length, Coonfig.agent_com_max_message_limit
53
- warning = RookError.new exc, message
54
- UserWarnings.notify_warning warning
57
+ @print_on_initial_connection = print_on_connect
58
+ end
55
59
 
56
- Logger.instance.warn "Dropping message, size was #{buffer.length} which is over the message size limit"
57
- return
60
+ def add envelope_wrapper
61
+ msg_size = envelope_wrapper.calculate_size
62
+ if @pending_messages_length + msg_size > Config.agent_com_max_queue_messages_length ||
63
+ queue_full?
64
+ raise Exceptions::RookOutputQueueFull
58
65
  end
59
66
 
60
- @pending_messages.push buffer if @pending_messages.length < Config.agent_com_max_queued_messages
67
+ @pending_messages.push envelope_wrapper
68
+ @pending_messages_length += msg_size
69
+ end
70
+
71
+ def queue_full?
72
+ @pending_messages.length >= Config.agent_com_max_queued_messages
61
73
  end
62
74
 
63
75
  def connect
64
76
  @running = true
65
77
 
66
- @thread = Thread.new { connection_thread }
67
- @thread.name = "rookout-connection-thread"
78
+ @main_thread = Thread.new { connection_thread }
79
+ @main_thread.name = "rookout-connection-thread"
80
+ end
81
+
82
+ def stop
83
+ @running = false
84
+
85
+ # Ask outgoing thread to exit (if running)
86
+ @pending_messages << ExitMessage.new(@outgoing_thread)
87
+
88
+ @main_thread.join
68
89
  end
69
90
 
70
91
  def wait_for_ready
71
- @ready_event.wait Config.agent_com_timeout
92
+ is_finished = @ready_event.wait Config.agent_com_timeout
93
+ # We didn't finish - will keep trying in the background
94
+ raise Exceptions::RookCommunicationException unless is_finished
95
+
96
+ # We finished - raise if we failed
72
97
  raise @connection_error if @connection_error
73
98
  end
74
99
 
@@ -85,50 +110,49 @@ module Rookout
85
110
 
86
111
  while @running
87
112
  begin
88
- backoff.before_connection_attempt
89
- Kontena::Websocket::Client.connect(@uri, **create_options) do |client|
90
- register client
113
+ client = open_new_connection
91
114
 
92
- Logger.instance.debug "WebSocket connected successfully"
93
- @token_valid = true
94
- backoff.after_connect
95
-
96
- connection_pump client
115
+ if @print_on_initial_connection
116
+ @print_on_initial_connection = false
117
+ Utils.quiet_puts "[Rookout] Successfully connected to controller."
118
+ Logger.instance.debug "[Rookout] Agent ID is #{@agent_id}"
97
119
  end
120
+ Logger.instance.debug "WebSocket connected successfully"
121
+ Logger.instance.info "Finished initialization"
122
+
123
+ @token_valid = true
124
+ backoff.after_connect
125
+
126
+ connection_pump client
98
127
  rescue Exception => e
99
- if !@token_valid && e.is_a?(Kontena::Websocket::ProtocolError) && e.message.include?("403")
128
+ if !@token_valid && e.message.include?("403")
100
129
  @connection_error = Exceptions::RookInvalidToken.new @token
101
130
  @ready_event.set
102
131
  end
103
132
 
104
- Logger.instance.info "Connection failed; reason = #{e.message}"
133
+ if e.message.include? "400"
134
+ @connection_error = Exceptions::RookWebSocketError.new 400
135
+ @ready_event.set
136
+ end
137
+
138
+ Logger.instance.warning "Connection failed; reason = #{e.message}"
105
139
  end
106
140
 
107
141
  backoff.after_disconnect
108
142
  Logger.instance.debug "Reconnecting"
109
143
  end
144
+ rescue Exception => e
145
+ Logger.instance.error "Unexpected error in connection_thread", e
110
146
  end
111
147
 
112
- def create_options
113
- headers = {
114
- "User-Agent" => "RookoutAgent/#{Config.rookout_version}+#{Config.rookout_commit}"
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
126
-
127
- def register client
128
- Logger.instance.info "Registering agent with id #{@agent_id}"
148
+ def open_new_connection
149
+ client = WebsocketClient.new @uri, @proxy, @token
150
+ client.connect
129
151
 
130
152
  msg = Com::Rookout::NewAgentMessage.new agent_info: @info.pack
131
- client.send wrap_in_envelope(msg)
153
+ client.send_frame wrap_in_envelope(msg)
154
+
155
+ client
132
156
  end
133
157
 
134
158
  ACCEPTED_MESSAGE_TYPES = [
@@ -140,11 +164,18 @@ module Rookout
140
164
  ].freeze
141
165
 
142
166
  def connection_pump client
143
- on_outgoing_exit = proc { client.disconnect }
144
- send_thread = Thread.new { outgoing client, on_outgoing_exit }
145
- send_thread.name = "rookout-outgoing-thread"
167
+ on_outgoing_exit = proc {
168
+ begin
169
+ client.close
170
+ rescue Exception => e
171
+ Logger.instance.error "Unexpected error exiting outgoing thread", e
172
+ end
173
+ }
174
+
175
+ @outgoing_thread = Thread.new { outgoing client, on_outgoing_exit }
176
+ @outgoing_thread.name = "rookout-outgoing-thread"
146
177
 
147
- client.read do |raw_message|
178
+ message_handler = proc do |raw_message|
148
179
  envelope = Com::Rookout::Envelope.decode raw_message.pack("c*")
149
180
 
150
181
  ACCEPTED_MESSAGE_TYPES.each do |klass|
@@ -153,28 +184,35 @@ module Rookout
153
184
  end
154
185
  end
155
186
 
187
+ client.connection_pump message_handler
188
+
156
189
  Logger.instance.debug "Incoming loop - socket disconnected"
157
190
 
158
191
  @pending_messages.push ExitMessage.new(send_thread)
159
- send_thread.join
192
+ @outgoing_thread.join
193
+ @outgoing_thread = nil
160
194
  end
161
195
 
162
196
  def outgoing client, on_exit
163
- loop do
197
+ Pinger.new(client, Config.agent_com_ping_interval, Config.agent_com_ping_timeout).repeat do
164
198
  begin
165
- msg = @pending_messages.pop true
199
+ envelope_wrapper = @pending_messages.pop true
166
200
  rescue ThreadError
167
201
  sleep 0.25
168
202
  next
169
203
  end
170
204
 
171
- if msg.is_a? ExitMessage
205
+ msg = envelope_wrapper.envelope
206
+ @pending_messages_length -= envelope_wrapper.calculate_size
207
+
208
+ case msg
209
+ when ExitMessage
172
210
  break if msg.thread == Thread.current
173
- elsif msg.is_a? FlushMessage
211
+ when FlushMessage
174
212
  msg.event.set
175
213
  else
176
214
  begin
177
- client.send msg
215
+ client.send_frame msg
178
216
  rescue RuntimeError
179
217
  @queue << msg
180
218
  break
@@ -184,6 +222,7 @@ module Rookout
184
222
  rescue Exception => e
185
223
  Logger.instance.exception "Outgoing thread failed", e
186
224
  ensure
225
+ Logger.instance.debug "Outgoing thread exiting"
187
226
  on_exit.call
188
227
  end
189
228
 
@@ -196,7 +235,7 @@ module Rookout
196
235
  end
197
236
 
198
237
  def reset_id
199
- @agent_id = SecureRandom.uuid
238
+ @agent_id = Utils.uuid
200
239
  @output.agent_id = @agent_id
201
240
  @info.agent_id = @agent_id
202
241
  end
@@ -4,25 +4,20 @@ module Rookout
4
4
 
5
5
  class Backoff
6
6
  def initialize
7
- @connected = false
8
- @last_successful_connection = Time.mktime 1970
9
- reset_backoff
10
- end
11
-
12
- def before_connection_attempt
13
- return unless Time.new > @last_successful_connection + Config.backoff_reset_time
7
+ @connect_time = nil
14
8
  reset_backoff
15
9
  end
16
10
 
17
11
  def after_disconnect
18
- @connected = false
12
+ reset_backoff if @connect_time && Time.new > @connect_time + Config.backoff_reset_time
13
+ @connect_time = nil
14
+
19
15
  sleep @next_backoff
20
16
  @next_backoff = [@next_backoff * 2, Config.backoff_max_time].min
21
17
  end
22
18
 
23
19
  def after_connect
24
- @connected = true
25
- @last_successful_connection = Time.now
20
+ @connect_time = Time.now
26
21
  end
27
22
 
28
23
  private
@@ -5,10 +5,10 @@ module Rookout
5
5
  class CommandHandler
6
6
  def initialize agent_com, augs_manager
7
7
  agent_com.on "Com::Rookout::InitialAugsCommand" do |initial_augs|
8
+ Config.update_config initial_augs.sdk_configuration
8
9
  augs = initial_augs.augs.map { |aug_json| JSON.parse aug_json }
9
10
  augs_manager.initialize_augs augs
10
11
  end
11
-
12
12
  agent_com.on "Com::Rookout::AddAugCommand" do |command|
13
13
  augs_manager.add_aug JSON.parse(command.aug_json)
14
14
  end
@@ -0,0 +1,68 @@
1
+ require_relative "../protobuf/envelope_pb"
2
+ require_relative "../processor/namespace_serializer2"
3
+
4
+
5
+ class EnvelopeWrapperBase
6
+ def wrap_in_envelope message
7
+ any_message = Google::Protobuf::Any.pack message
8
+ timestamp = Google::Protobuf::Timestamp.new
9
+ timestamp.from_time Time.new
10
+ envelope = Com::Rookout::Envelope.new msg: any_message, timestamp: timestamp
11
+ Com::Rookout::Envelope.encode envelope
12
+ end
13
+
14
+ def envelope
15
+ raise NotImplementedError
16
+ end
17
+
18
+ def calculate_size
19
+ raise NotImplementedError
20
+ end
21
+ end
22
+
23
+ class Variant2EnvelopeWrapper < EnvelopeWrapperBase
24
+ def initialize agent_id, aug_id, report_id, arguments
25
+ super()
26
+
27
+ @aug_report_message = Com::Rookout::AugReportMessage.new agent_id: agent_id,
28
+ aug_id: aug_id,
29
+ report_id: report_id
30
+ @serializer = Rookout::Processor::NamespaceSerializer2.new
31
+ @aug_report_message.arguments2 = @serializer.dump arguments, true
32
+
33
+ @estimated_length = @serializer.estimated_pending_bytes
34
+ @envelope = nil
35
+ end
36
+
37
+ def envelope
38
+ if @envelope.nil?
39
+ @serializer.string_cache.each do |key, value|
40
+ @aug_report_message.strings_cache[key.encode "UTF-8", invalid: :replace, undef: :replace, replace: "?"] = value
41
+ end
42
+ @envelope = wrap_in_envelope @aug_report_message
43
+
44
+ @serializer = nil
45
+ @aug_report_message = nil
46
+ end
47
+ @envelope
48
+ end
49
+
50
+ def calculate_size
51
+ @estimated_length
52
+ end
53
+ end
54
+
55
+ class EnvelopeWrapper < EnvelopeWrapperBase
56
+ def initialize message
57
+ super()
58
+ @envelope = wrap_in_envelope message
59
+ end
60
+
61
+ def envelope
62
+ @envelope
63
+ end
64
+
65
+ def calculate_size
66
+ @envelope.length
67
+ end
68
+ end
@@ -42,7 +42,7 @@ module Rookout
42
42
  link_contents = File.read link_path
43
43
 
44
44
  if link_contents.start_with? "ref:"
45
- next_link = (link_contents.split " ")[1].strip
45
+ next_link = link_contents.split[1].strip
46
46
  follow_sym_links root, next_link
47
47
  else
48
48
  link_contents.strip
@@ -11,10 +11,17 @@ module Rookout
11
11
  require_relative "git"
12
12
  include Git
13
13
 
14
- def initialize labels
14
+ def initialize labels, k8s_file_path = "/var/run/secrets/kubernetes.io/serviceaccount/namespace"
15
15
  @agent_id = nil
16
16
  @labels = labels.clone
17
- @labels["rookout_debug"] = "on"
17
+ @labels["rookout_debug"] = "on" if Config.debug
18
+
19
+ k8_namespace = create_cluster_namespace k8s_file_path
20
+ unless k8_namespace == "" || @labels.key?("k8s_namespace")
21
+ @labels["k8s_namespace"] = k8_namespace
22
+ end
23
+
24
+ collect_serverless_labels
18
25
 
19
26
  @ip_addr = local_ip
20
27
 
@@ -50,6 +57,7 @@ module Rookout
50
57
  end
51
58
 
52
59
  attr_accessor :agent_id
60
+ attr_accessor :labels
53
61
 
54
62
  private
55
63
 
@@ -65,10 +73,52 @@ module Rookout
65
73
  end
66
74
  # rubocop:enable Style/ParallelAssignment
67
75
 
76
+ def create_cluster_namespace k8s_file_path
77
+ return_value = ""
78
+
79
+ # No Kubernetes is valid
80
+ if File.file? k8s_file_path
81
+ # Read the file contents and return it as result
82
+ return_value = File.read k8s_file_path
83
+ end
84
+
85
+ return_value
86
+ end
87
+
88
+ def parse_raw_git_sources
89
+ git_sources_raw = ENV["ROOKOUT_SOURCES"]
90
+ if git_sources_raw.nil?
91
+ return nil
92
+ end
93
+
94
+ git_sources = git_sources_raw.split ";"
95
+ user_git_sources = {}
96
+ git_sources.each do |url|
97
+ url_parts = url.split "#"
98
+ if url_parts.length != 2
99
+ next
100
+ end
101
+
102
+ remote_url = url_parts[0]
103
+ commit = url_parts[1]
104
+ user_git_sources[remote_url] = commit
105
+ end
106
+
107
+ user_git_sources
108
+ end
109
+
68
110
  def create_scm_information
69
- user_git_origin = Config.user_git_origin || ENV["ROOKOUT_ORIGIN"]
111
+ user_git_origin = Config.user_git_origin || ENV["ROOKOUT_REMOTE_ORIGIN"]
70
112
  user_git_commit = Config.user_git_commit || ENV["ROOKOUT_COMMIT"]
71
113
 
114
+ user_git_sources = Config.user_git_sources || parse_raw_git_sources
115
+
116
+ if !user_git_sources.nil? && !user_git_sources.empty?
117
+ user_git_sources = user_git_sources.map do |remote_url, commit|
118
+ Com::Rookout::SCMInformation::SourceInfo.new remoteOriginUrl: remote_url, commit: commit
119
+ end
120
+ end
121
+
72
122
  if user_git_origin.nil? && user_git_commit.nil?
73
123
  search_path = File.dirname File.absolute_path($PROGRAM_NAME)
74
124
  git_root = find_root search_path
@@ -78,7 +128,48 @@ module Rookout
78
128
  end
79
129
  end
80
130
 
81
- Com::Rookout::SCMInformation.new origin: user_git_origin, commit: user_git_commit
131
+ Com::Rookout::SCMInformation.new origin: user_git_origin, commit: user_git_commit, sources: user_git_sources
132
+ end
133
+
134
+ def aws_lambda?
135
+ !ENV["AWS_LAMBDA_FUNCTION_NAME"].nil?
136
+ end
137
+
138
+ def google_cloud_function?
139
+ !ENV["FUNCTION_TARGET"].nil? && !ENV["FUNCTION_SIGNATURE_TYPE"].nil?
140
+ end
141
+
142
+ def cloud_run_or_fire_base?
143
+ !ENV["K_SERVICE"].nil? &&
144
+ !ENV["K_REVISION"].nil? &&
145
+ !ENV["K_CONFIGURATION"].nil? &&
146
+ !ENV["PORT"].nil?
147
+ end
148
+
149
+ def azure_function?
150
+ !ENV["FUNCTIONS_WORKER_RUNTIME"].nil? && !ENV["WEBSITE_SITE_NAME"].nil?
151
+ end
152
+
153
+ def collect_serverless_labels
154
+ if aws_lambda?
155
+ @labels["function_name"] = ENV["AWS_LAMBDA_FUNCTION_NAME"]
156
+ @labels["aws_region"] = ENV["AWS_REGION"]
157
+
158
+ elsif google_cloud_function? || cloud_run_or_fire_base?
159
+ function_name = ENV["FUNCTION_NAME"]
160
+ if function_name.nil?
161
+ function_name = ENV["K_SERVICE"]
162
+ end
163
+ @labels["function_name"] = function_name
164
+
165
+ elsif azure_function?
166
+ @labels["function_name"] = ENV["WEBSITE_SITE_NAME"]
167
+ @labels["azure_region"] = ENV["REGION_NAME"]
168
+ end
169
+
170
+ return unless @labels.key? "function_name"
171
+
172
+ @labels["rookout_serverless"] = "true"
82
173
  end
83
174
  end
84
175
  end