chloride 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of chloride might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.rubocop.yml +12 -0
- data/lib/chloride/action/detect_platform.rb +235 -0
- data/lib/chloride/event/message.rb +2 -2
- data/lib/chloride/executor.rb +67 -0
- data/lib/chloride/host.rb +1 -1
- data/lib/chloride/step.rb +53 -0
- data/lib/chloride/step/noop.rb +24 -0
- data/lib/chloride/version.rb +1 -1
- metadata +5 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4745a7cd2b20421818ebf6baf24deed96fca4f72
|
4
|
+
data.tar.gz: caf69fb1a91510985ac7cef32ec93304086ba7b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39ca494f094616cbb357d7416e5751aaaa8452b6518187005fd81ac82264dcf74cf02918ae8a62c9a038cc58c9adbbcef8efd992b0ce2d1c42e4c735bbcaa3d5
|
7
|
+
data.tar.gz: ee6bc7998b0534ebd52f888e488d26c1d666d6bea4fa852a571581c4494008224bfef08870c027847b58016fe2c393ced62a5737e20f6b210901c472a2c15e05
|
data/.rubocop.yml
CHANGED
@@ -50,13 +50,18 @@ Lint/Void:
|
|
50
50
|
|
51
51
|
# Offense count: 6
|
52
52
|
Metrics/AbcSize:
|
53
|
+
Enabled: false
|
53
54
|
Max: 70
|
54
55
|
|
55
56
|
# Offense count: 4
|
56
57
|
# Configuration parameters: CountComments.
|
57
58
|
Metrics/BlockLength:
|
59
|
+
Enabled: false
|
58
60
|
Max: 45
|
59
61
|
|
62
|
+
Metrics/BlockNesting:
|
63
|
+
Max: 4
|
64
|
+
|
60
65
|
# Offense count: 1
|
61
66
|
# Configuration parameters: CountComments.
|
62
67
|
Metrics/ClassLength:
|
@@ -64,6 +69,7 @@ Metrics/ClassLength:
|
|
64
69
|
|
65
70
|
# Offense count: 2
|
66
71
|
Metrics/CyclomaticComplexity:
|
72
|
+
Enabled: false
|
67
73
|
Max: 20
|
68
74
|
|
69
75
|
# Offense count: 90
|
@@ -75,10 +81,12 @@ Metrics/LineLength:
|
|
75
81
|
# Offense count: 10
|
76
82
|
# Configuration parameters: CountComments.
|
77
83
|
Metrics/MethodLength:
|
84
|
+
Enabled: false
|
78
85
|
Max: 89
|
79
86
|
|
80
87
|
# Offense count: 2
|
81
88
|
Metrics/PerceivedComplexity:
|
89
|
+
Enabled: false
|
82
90
|
Max: 23
|
83
91
|
|
84
92
|
# Offense count: 10
|
@@ -119,6 +127,7 @@ Style/BracesAroundHashParameters:
|
|
119
127
|
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
120
128
|
# SupportedStyles: nested, compact
|
121
129
|
Style/ClassAndModuleChildren:
|
130
|
+
Enabled: false
|
122
131
|
Exclude:
|
123
132
|
- 'lib/chloride/action/execute.rb'
|
124
133
|
- 'lib/chloride/action/file_copy.rb'
|
@@ -154,7 +163,10 @@ Style/Documentation:
|
|
154
163
|
- 'lib/chloride/errors.rb'
|
155
164
|
- 'lib/chloride/event.rb'
|
156
165
|
- 'lib/chloride/event/message.rb'
|
166
|
+
- 'lib/chloride/executor.rb'
|
157
167
|
- 'lib/chloride/host.rb'
|
168
|
+
- 'lib/chloride/step.rb'
|
169
|
+
- 'lib/chloride/step/noop.rb'
|
158
170
|
|
159
171
|
# Cop supports --auto-correct.
|
160
172
|
Style/EmptyLines:
|
@@ -0,0 +1,235 @@
|
|
1
|
+
require 'chloride/errors'
|
2
|
+
require 'chloride/action'
|
3
|
+
|
4
|
+
# Executes a shell command on the hosts provided. Will block until completion.
|
5
|
+
class Chloride::Action::DetectPlatform < Chloride::Action
|
6
|
+
attr_reader :results, :hosts
|
7
|
+
|
8
|
+
# TODO: Document args
|
9
|
+
def initialize(args)
|
10
|
+
super
|
11
|
+
|
12
|
+
@hosts = args[:hosts] || [args[:host]]
|
13
|
+
end
|
14
|
+
|
15
|
+
# TODO: Document block format
|
16
|
+
def go(&stream_block)
|
17
|
+
@status = :running
|
18
|
+
@results = Hash.new { |h, k| h[k] = {} }
|
19
|
+
@hosts.each do |host|
|
20
|
+
# First try identifying using lsb_release. This takes care of Ubuntu (lsb-release is part of ubuntu-minimal).
|
21
|
+
lsb = exec_and_log(host, 'lsb_release -icr', true, @results[host.hostname], &stream_block)
|
22
|
+
|
23
|
+
if (lsb[:exit_status]).zero?
|
24
|
+
lsb_data = {}
|
25
|
+
lsb[:stdout].each_line do |l|
|
26
|
+
k, v = l.split(':')
|
27
|
+
lsb_data[k.strip] = v.strip if k && v
|
28
|
+
end
|
29
|
+
|
30
|
+
distribution = lsb_data['Distributor ID'].downcase.gsub(/\s+/, '')
|
31
|
+
distribution = case distribution
|
32
|
+
when /redhatenterpriseserver|redhatenterpriseclient|redhatenterpriseas|redhatenterprisees|enterpriseenterpriseserver|redhatenterpriseworkstation|redhatenterprisecomputenode|oracleserver/
|
33
|
+
:rhel
|
34
|
+
when /enterprise.*/
|
35
|
+
:centos
|
36
|
+
when /scientific|scientifics|scientificsl/
|
37
|
+
:rhel
|
38
|
+
when /amazonami/
|
39
|
+
:amazon
|
40
|
+
when /suselinux/
|
41
|
+
:sles
|
42
|
+
else
|
43
|
+
distribution.to_sym
|
44
|
+
end
|
45
|
+
|
46
|
+
release = lsb_data['Release'].gsub(/\s+/, '')
|
47
|
+
release = case distribution
|
48
|
+
when :centos, :rhel
|
49
|
+
release.split('.')[0]
|
50
|
+
when :debian
|
51
|
+
if release == 'testing'
|
52
|
+
'7'
|
53
|
+
else
|
54
|
+
release.split('.')[0]
|
55
|
+
end
|
56
|
+
else
|
57
|
+
release
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Check for Redhat
|
62
|
+
if !distribution && !release
|
63
|
+
redhat_release = exec_and_log(host, 'cat /etc/redhat-release', true, @results[host.hostname], &stream_block)
|
64
|
+
|
65
|
+
if (redhat_release[:exit_status]).zero?
|
66
|
+
stdout = redhat_release[:stdout]
|
67
|
+
|
68
|
+
distribution = case stdout
|
69
|
+
when /red hat enterprise/im
|
70
|
+
:rhel
|
71
|
+
when /centos/im
|
72
|
+
:centos
|
73
|
+
when /scientific/im
|
74
|
+
:rhel
|
75
|
+
end
|
76
|
+
|
77
|
+
release = /.* release ([[:digit:]]).*/.match(stdout)[1]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Check for Cumulus
|
82
|
+
if !distribution && !release
|
83
|
+
os_release = exec_and_log(host, 'cat /etc/os-release', true, @results[host.hostname], &stream_block)
|
84
|
+
|
85
|
+
if (os_release[:exit_status]).zero?
|
86
|
+
stdout = os_release[:stdout]
|
87
|
+
|
88
|
+
distribution = :cumulus if /Cumulus Linux/m =~ stdout
|
89
|
+
release = /VERSION_ID=(\d+\.\d)/.match(stdout)[1] if distribution
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Check for EOS
|
94
|
+
if !distribution && !release
|
95
|
+
eos_release = exec_and_log(host, 'cat /etc/Eos-release', true, @results[host.hostname], &stream_block)
|
96
|
+
|
97
|
+
if (eos_release[:exit_status]).zero?
|
98
|
+
stdout = eos_release[:stdout]
|
99
|
+
|
100
|
+
distribution = :eos if /Arista Networks EOS/m =~ stdout
|
101
|
+
|
102
|
+
release = /^Arista Networks EOS v*(.*)\..*$/.match(stdout)[1]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Check for Debian
|
107
|
+
if !distribution && !release
|
108
|
+
debian_version = exec_and_log(host, 'cat /etc/debian_version', true, @results[host.hostname], &stream_block)
|
109
|
+
|
110
|
+
if (debian_version[:exit_status]).zero?
|
111
|
+
stdout = debian_version[:stdout]
|
112
|
+
distribution = :debian
|
113
|
+
|
114
|
+
release = case stdout
|
115
|
+
when /^[[:digit:]]/
|
116
|
+
stdout.split('.')[0]
|
117
|
+
when /^wheezy/.match(stdout)
|
118
|
+
'7'
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Check for SuSE
|
124
|
+
if !distribution && !release
|
125
|
+
suse_release = exec_and_log(host, 'cat /etc/SuSE-release', true, @results[host.hostname], &stream_block)
|
126
|
+
|
127
|
+
if (suse_release[:exit_status]).zero?
|
128
|
+
stdout = suse_release[:stdout]
|
129
|
+
|
130
|
+
if /Enterprise Server/ =~ stdout
|
131
|
+
distribution = :sles
|
132
|
+
release = /^VERSION = (\d*)/m.match(stdout)[1]
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Check for Amazon 6, or fail
|
138
|
+
if !distribution && !release
|
139
|
+
system_release = exec_and_log(host, 'cat /etc/system-release', true, @results[host.hostname], &stream_block)
|
140
|
+
|
141
|
+
if (system_release[:exit_status]).zero?
|
142
|
+
stdout = system_release[:stdout]
|
143
|
+
|
144
|
+
if /amazon linux/im =~ stdout
|
145
|
+
distribution = :amazon
|
146
|
+
# How is this safe to assume?
|
147
|
+
release = '6'
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Check for Solaris
|
153
|
+
if !distribution && !release
|
154
|
+
uname = exec_and_log(host, 'uname -s', true, @results[host.hostname], &stream_block)
|
155
|
+
|
156
|
+
if (uname[:exit_status]).zero?
|
157
|
+
distribution = case uname.results[hostname][:stdout].strip
|
158
|
+
when 'SunOS'
|
159
|
+
unamer = exec_and_log(host, 'uname -r', true, @results[host.hostname], &stream_block)
|
160
|
+
|
161
|
+
if (unamer[:exit_status]).zero?
|
162
|
+
release = unamer.results[hostname][:stdout].split('.')[0]
|
163
|
+
end
|
164
|
+
|
165
|
+
:solaris
|
166
|
+
when 'AIX'
|
167
|
+
oslevel = exec_and_log(host, 'oslevel', true, @results[host.hostname], &stream_block)
|
168
|
+
yield oslevel
|
169
|
+
|
170
|
+
if (oslevel[:exit_status]).zero?
|
171
|
+
release = oslevel.results[hostname][:stdout].split('.')[0..1].join('.')
|
172
|
+
end
|
173
|
+
|
174
|
+
:aix
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# Architecture
|
180
|
+
unamem = exec_and_log(host, 'uname -m', true, @results[host.hostname], &stream_block)
|
181
|
+
|
182
|
+
if (unamem[:exit_status]).zero?
|
183
|
+
architecture = unamem[:stdout].strip
|
184
|
+
|
185
|
+
architecture = case architecture
|
186
|
+
when 'i686'
|
187
|
+
'i386'
|
188
|
+
when 'ppc'
|
189
|
+
'powerpc'
|
190
|
+
when 'x86_64'
|
191
|
+
[:ubuntu, :debian].include?(distribution) ? 'amd64' : 'x86_64'
|
192
|
+
else
|
193
|
+
architecture
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
host.data[:os] = {}
|
198
|
+
# Tag
|
199
|
+
@results[host.hostname][:distribution] = host.data[:os][:distribution] = distribution
|
200
|
+
@results[host.hostname][:release] = host.data[:os][:release] = release
|
201
|
+
@results[host.hostname][:architecture] = host.data[:os][:architecture] = architecture
|
202
|
+
|
203
|
+
tag_distribution = distribution || 'unknown'
|
204
|
+
tag_release = release || 'unknown'
|
205
|
+
tag_architecture = architecture || 'unknown'
|
206
|
+
|
207
|
+
@results[host.hostname][:tag] = host.data[:os][:tag] = case distribution
|
208
|
+
when :rhel, :centos, :amazon
|
209
|
+
"el-#{tag_release}-#{tag_architecture}"
|
210
|
+
else
|
211
|
+
"#{tag_distribution}-#{tag_release}-#{tag_architecture}"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
@results
|
216
|
+
end
|
217
|
+
|
218
|
+
def success?
|
219
|
+
@results.all? do |_host, result|
|
220
|
+
!(result[:distribution].nil? || result[:release].nil? || result[:architecture].nil?)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def error_message(hostname)
|
225
|
+
@results[hostname][:stderr].strip if @results.key?(hostname) && @results[hostname].key?(:stderr)
|
226
|
+
end
|
227
|
+
|
228
|
+
def name
|
229
|
+
:detect_platform
|
230
|
+
end
|
231
|
+
|
232
|
+
def description
|
233
|
+
"Detect OS on #{@hosts.join(', ')}"
|
234
|
+
end
|
235
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'cgi'
|
2
2
|
|
3
3
|
module Chloride
|
4
4
|
class Event
|
@@ -15,7 +15,7 @@ module Chloride
|
|
15
15
|
{
|
16
16
|
severity: @severity,
|
17
17
|
hostname: @hostname,
|
18
|
-
message:
|
18
|
+
message: CGI.escape_html(remove_ansi(@message))
|
19
19
|
}.to_json(*args)
|
20
20
|
end
|
21
21
|
|
@@ -0,0 +1,67 @@
|
|
1
|
+
class Chloride::Executor
|
2
|
+
def initialize(logger, &stream_block)
|
3
|
+
@logger = logger
|
4
|
+
@stream_block = stream_block
|
5
|
+
end
|
6
|
+
|
7
|
+
def publish(event, action_id = nil)
|
8
|
+
event.action_id = action_id if action_id
|
9
|
+
@stream_block.call(event) if @stream_block
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute(steps)
|
13
|
+
# Perform the plan given
|
14
|
+
skip_remaining_steps = false
|
15
|
+
|
16
|
+
steps.each do |step|
|
17
|
+
# TODO: Check for step.pre
|
18
|
+
if skip_remaining_steps
|
19
|
+
publish Chloride::Event.new(:step_skip, step.name)
|
20
|
+
next
|
21
|
+
end
|
22
|
+
|
23
|
+
publish Chloride::Event.new(:step_start, step.name)
|
24
|
+
|
25
|
+
begin
|
26
|
+
step.perform_step do |action|
|
27
|
+
action_id = SecureRandom.uuid
|
28
|
+
publish(Chloride::Event.new(:action_start, action.name), action_id)
|
29
|
+
|
30
|
+
action.go do |event|
|
31
|
+
publish(event, action_id)
|
32
|
+
end
|
33
|
+
|
34
|
+
if action.success?
|
35
|
+
publish(Chloride::Event.new(:action_success, action.name), action_id)
|
36
|
+
else
|
37
|
+
publish(Chloride::Event.new(:action_fail, action.name), action_id)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
41
|
+
# Treat *any* error like a step failure and proceed accordingly
|
42
|
+
@logger.error [e, *e.backtrace].join("\n")
|
43
|
+
step.error(step.infra.installer_hostname, "An error occured while performing #{step.name}: #{e.message}")
|
44
|
+
end
|
45
|
+
|
46
|
+
type = case step.status
|
47
|
+
when :error
|
48
|
+
skip_remaining_steps = step.fail_stop?
|
49
|
+
:step_error
|
50
|
+
when :warn
|
51
|
+
:step_warn
|
52
|
+
else
|
53
|
+
:step_success
|
54
|
+
end
|
55
|
+
|
56
|
+
Chloride::Event.new(type, step.name).tap do |event|
|
57
|
+
step.messages.each { |m| event.add_message(m) }
|
58
|
+
publish event
|
59
|
+
end
|
60
|
+
|
61
|
+
# Clear the messages so that revalidation doesn't log them again
|
62
|
+
step.reset
|
63
|
+
|
64
|
+
# TODO: Check for step.post
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/chloride/host.rb
CHANGED
@@ -7,7 +7,7 @@ require 'timeout'
|
|
7
7
|
require 'json'
|
8
8
|
|
9
9
|
class Chloride::Host
|
10
|
-
attr_reader :data, :remote_conn, :
|
10
|
+
attr_reader :data, :remote_conn, :hostname, :username, :ssh_key_file, :ssh_key_passphrase, :localhost
|
11
11
|
attr_accessor :data
|
12
12
|
|
13
13
|
def initialize(hostname, config = {})
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class Chloride::Step
|
2
|
+
attr_reader :actions, :hosts, :messages, :status
|
3
|
+
|
4
|
+
def initialize(data = {}, pre = nil, post = nil)
|
5
|
+
@pre = pre
|
6
|
+
@post = post
|
7
|
+
@data = data
|
8
|
+
@hosts = Set.new
|
9
|
+
|
10
|
+
@actions = []
|
11
|
+
@messages = []
|
12
|
+
|
13
|
+
@status = :success
|
14
|
+
@uuid = SecureRandom.uuid
|
15
|
+
end
|
16
|
+
|
17
|
+
def perform_step(_execute_block)
|
18
|
+
raise NotImplementedError, "Don't know how to perform this kind of step"
|
19
|
+
end
|
20
|
+
|
21
|
+
def name
|
22
|
+
raise NotImplementedError, 'Step name required'
|
23
|
+
end
|
24
|
+
|
25
|
+
def description
|
26
|
+
raise NotImplementedError, 'Step description required'
|
27
|
+
end
|
28
|
+
|
29
|
+
def fail_stop?
|
30
|
+
false
|
31
|
+
end
|
32
|
+
|
33
|
+
def reset
|
34
|
+
@status = :success
|
35
|
+
@messages.clear
|
36
|
+
end
|
37
|
+
|
38
|
+
def error(hostname, message)
|
39
|
+
@messages << Chloride::Event::Message.new(:error, hostname, message)
|
40
|
+
@status = :error
|
41
|
+
end
|
42
|
+
|
43
|
+
def warning(hostname, message)
|
44
|
+
@messages << Chloride::Event::Message.new(:warn, hostname, message)
|
45
|
+
@status = :warn unless @status == :error
|
46
|
+
end
|
47
|
+
|
48
|
+
def info(hostname, message)
|
49
|
+
@messages << Chloride::Event::Message.new(:info, hostname, message)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
require 'chloride/event'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'chloride/step'
|
2
|
+
|
3
|
+
class Chloride::Step::Noop < Chloride::Step
|
4
|
+
def initialize(data = {}, pre = nil, post = nil)
|
5
|
+
super(data, pre, post)
|
6
|
+
@name = data[:name]
|
7
|
+
@performed = false
|
8
|
+
end
|
9
|
+
|
10
|
+
def perform_step(_execute_block)
|
11
|
+
@performed = true
|
12
|
+
# noop
|
13
|
+
end
|
14
|
+
|
15
|
+
def performed?
|
16
|
+
@performed
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :name
|
20
|
+
|
21
|
+
def description
|
22
|
+
'Do basically nothing'
|
23
|
+
end
|
24
|
+
end
|
data/lib/chloride/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chloride
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brandon High
|
@@ -161,6 +161,7 @@ files:
|
|
161
161
|
- chloride.gemspec
|
162
162
|
- lib/chloride.rb
|
163
163
|
- lib/chloride/action.rb
|
164
|
+
- lib/chloride/action/detect_platform.rb
|
164
165
|
- lib/chloride/action/execute.rb
|
165
166
|
- lib/chloride/action/file_copy.rb
|
166
167
|
- lib/chloride/action/mkdir.rb
|
@@ -169,7 +170,10 @@ files:
|
|
169
170
|
- lib/chloride/errors.rb
|
170
171
|
- lib/chloride/event.rb
|
171
172
|
- lib/chloride/event/message.rb
|
173
|
+
- lib/chloride/executor.rb
|
172
174
|
- lib/chloride/host.rb
|
175
|
+
- lib/chloride/step.rb
|
176
|
+
- lib/chloride/step/noop.rb
|
173
177
|
- lib/chloride/version.rb
|
174
178
|
homepage: https://github.com/puppetlabs/chloride
|
175
179
|
licenses:
|