smart_proxy_openbolt 0.1.1 → 1.2.0

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.
@@ -1,9 +1,9 @@
1
- require 'net/http'
2
1
  require 'smart_proxy_openbolt/result'
3
- require 'thread'
4
2
 
5
3
  module Proxy::OpenBolt
6
4
  class Job
5
+ include ::Proxy::Log
6
+
7
7
  attr_accessor :id
8
8
  attr_reader :name, :parameters, :options, :status
9
9
 
@@ -35,11 +35,18 @@ module Proxy::OpenBolt
35
35
  result = execute
36
36
  update_status(result.status)
37
37
  store_result(result)
38
- rescue => e
39
- # This should never happen, but just in case we made a coding error,
40
- # expose something in the result.
38
+ rescue Exception => e # rubocop:disable Lint/RescueException
39
+ # Catch everything including non-StandardError exceptions (e.g.
40
+ # ScriptError) so the job always gets a terminal status.
41
41
  update_status(:exception)
42
- store_result({message: e.full_message, backtrace: e.backtrace})
42
+ logger.error("Job #{@id} failed (#{e.class}): #{e.message}")
43
+ logger.debug(e.backtrace.join("\n")) if e.backtrace
44
+ begin
45
+ store_result({ message: e.full_message, backtrace: e.backtrace })
46
+ rescue StandardError => store_error
47
+ logger.error("Job #{@id}: failed to store error result: #{store_error.message}")
48
+ logger.debug(store_error.backtrace.join("\n")) if store_error.backtrace
49
+ end
43
50
  end
44
51
  end
45
52
 
@@ -48,84 +55,13 @@ module Proxy::OpenBolt
48
55
  end
49
56
 
50
57
  def store_result(value)
51
- # On disk
52
- results_file = "#{Proxy::OpenBolt::Plugin.settings.log_dir}/#{@id}.json"
53
- File.open(results_file, 'w') { |f| f.write(value.to_json) }
54
-
55
- # Send to reports API
56
- #reports = get_reports(value)
57
-
58
- # TODO: Figure out how to authenticate with the /api/config_reports endpoint
59
- #reports.each do |report|
60
- # foreman = Proxy::SETTINGS.foreman_url
61
- # Send it
62
- # puts foreman
63
- #end
64
- end
65
-
66
- def log_item(text, level)
67
- {
68
- 'log': {
69
- 'sources': {
70
- 'source': 'OpenBolt'
71
- },
72
- 'messages': {
73
- 'message': text
74
- },
75
- 'level': level
76
- }
77
- }
58
+ File.write(Proxy::OpenBolt.result_file_path(@id), value.to_json)
78
59
  end
79
60
 
80
- def get_reports(value)
81
- command = value.command
82
- log = value.log
83
- items = value.value['items']
84
- return nil if items.nil?
85
- timestamp = Time.now.utc
86
-
87
- source = { 'sources': { 'source': 'OpenBolt' } }
88
- items.map do |item|
89
- target = item['target']
90
- status = item['status']
91
- data = item['value']
92
- message = item['message']
93
- logs = [log_item("Command: #{command}", 'info')]
94
- if data['_error']
95
- kind = data.dig('_error','kind')
96
- msg = data.dig('_error', 'msg')
97
- issue_code = data.dig('_error', 'issue_code')
98
- logs << log_item("Error kind: #{kind}", 'error')
99
- logs << log_item("Error mesage: #{msg}", 'error')
100
- logs << log_item("Error issue code: #{issue_code}", 'error')
101
- end
102
- logs << log_item("Result: #{data}", 'info')
103
- logs << log_item("Task run log: #{log}", 'info') if log
104
- logs << log_item("Message: #{message}", 'info') if message
105
- {
106
- 'config_report': {
107
- 'host': target,
108
- 'reported_at': timestamp,
109
- 'status': {
110
- "applied": status == 'success' ? 1 : 0,
111
- "failed": status == 'failure' ? 1 : 0,
112
- },
113
- 'logs': logs
114
- }
115
- }
116
- end
117
- items
118
- end
119
-
120
-
121
-
122
-
123
- # At the moment, always read back from the file so we don't store a bunch
124
- # of huge results in memory. Once we are database-backed, this is less
125
- # cumbersome and problematic.
61
+ # Read the result back from disk as a raw JSON string. We avoid parsing
62
+ # and re-serializing since the file is already valid JSON.
126
63
  def result
127
- results_file = "#{Proxy::OpenBolt::Plugin.settings.log_dir}/#{@id}.json"
128
- JSON.parse(File.read(results_file))
64
+ File.read(Proxy::OpenBolt.result_file_path(@id))
129
65
  end
130
66
  end
131
67
  end
@@ -0,0 +1,43 @@
1
+ module Proxy::OpenBolt
2
+ # Thread-safe, size-bounded cache that evicts the least recently used
3
+ # entry when full. Built on Ruby's insertion-ordered Hash.
4
+ # Implemented here rather than pulling in a gem to avoid adding
5
+ # packaging dependencies for something this straightforward.
6
+ class LruCache
7
+ def initialize(max_size)
8
+ raise ArgumentError, 'max_size must be at least 1' if max_size < 1
9
+ @max_size = max_size
10
+ @hash = {}
11
+ @mutex = Mutex.new
12
+ end
13
+
14
+ def get(key)
15
+ @mutex.synchronize do
16
+ return nil unless @hash.key?(key)
17
+ # Move to end (most recently used)
18
+ value = @hash.delete(key)
19
+ @hash[key] = value
20
+ end
21
+ end
22
+
23
+ def put(key, value)
24
+ @mutex.synchronize do
25
+ @hash.delete(key) if @hash.key?(key)
26
+ @hash[key] = value
27
+ @hash.shift if @hash.size > @max_size
28
+ end
29
+ end
30
+
31
+ def delete(key)
32
+ @mutex.synchronize { @hash.delete(key) }
33
+ end
34
+
35
+ def key?(key)
36
+ @mutex.synchronize { @hash.key?(key) }
37
+ end
38
+
39
+ def size
40
+ @mutex.synchronize { @hash.size }
41
+ end
42
+ end
43
+ end