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.
- checksums.yaml +4 -4
- data/README.md +297 -11
- data/lib/smart_proxy_openbolt/api.rb +20 -41
- data/lib/smart_proxy_openbolt/config/choria-client.conf +25 -0
- data/lib/smart_proxy_openbolt/error.rb +17 -27
- data/lib/smart_proxy_openbolt/executor.rb +32 -26
- data/lib/smart_proxy_openbolt/job.rb +17 -81
- data/lib/smart_proxy_openbolt/lru_cache.rb +43 -0
- data/lib/smart_proxy_openbolt/main.rb +293 -106
- data/lib/smart_proxy_openbolt/plugin.rb +7 -9
- data/lib/smart_proxy_openbolt/result.rb +20 -23
- data/lib/smart_proxy_openbolt/task_job.rb +36 -41
- data/lib/smart_proxy_openbolt/version.rb +1 -1
- data/settings.d/openbolt.yml +1 -0
- metadata +6 -3
|
@@ -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
|
-
#
|
|
40
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
81
|
-
|
|
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
|
-
|
|
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
|