Skip to content

Commit efc33cf

Browse files
committed
(gh-20) Add a task to check the version of the puppet binary
Provides a consistent way of verifying the installed version for acceptance testing. Version comparison is handled by Ruby's Gem::Version class. The agent's ruby is used to run the task. If Bolt knows the target has the puppet-agent, then the check.rb is run. If Bolt doesn't know whether puppet-agent is in place, the shell script is run, which will check for the puppet binary and either fail or kick off the check.rb if found.
1 parent 597a9df commit efc33cf

File tree

4 files changed

+295
-0
lines changed

4 files changed

+295
-0
lines changed

spec/tasks/check_spec.rb

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper'
4+
require_relative '../../tasks/check'
5+
6+
describe 'openvox_bootstrap::check' do
7+
before do
8+
allow(OpenvoxBootstrap::Check).to receive(:puppet_version).and_return('8.0.0')
9+
end
10+
11+
describe '.run' do
12+
let(:input) do
13+
{
14+
version: nil
15+
}
16+
end
17+
let(:expected_output) do
18+
{
19+
puppet_version: '8.0.0',
20+
valid: true
21+
}
22+
end
23+
24+
def validate_task_run(input:, expected: {}, code: 0)
25+
old_stdin = $stdin
26+
$stdin = StringIO.new(input.to_json)
27+
old_stdout = $stdout
28+
$stdout = StringIO.new
29+
30+
begin
31+
OpenvoxBootstrap::Check.run
32+
rescue SystemExit => e
33+
expect(e.status).to eq(code)
34+
end
35+
36+
output = JSON.parse($stdout.string, symbolize_names: true)
37+
expect(output).to eq(expected)
38+
ensure
39+
$stdin = old_stdin
40+
$stdout = old_stdout
41+
end
42+
43+
it 'raises for empty input' do
44+
expect do
45+
validate_task_run(input: nil)
46+
end.to raise_error(ArgumentError)
47+
end
48+
49+
it 'returns version without test if given no args' do
50+
validate_task_run(input: input, expected: expected_output)
51+
end
52+
53+
context 'testing valid version' do
54+
it 'returns successfully' do
55+
input[:version] = '8.0.0'
56+
57+
expected_output[:test] = 'eq'
58+
expected_output[:test_version] = '8.0.0'
59+
60+
validate_task_run(input: input, expected: expected_output)
61+
end
62+
end
63+
64+
context 'testing invalid version' do
65+
it 'returns non-zero' do
66+
input[:version] = '8.1.0'
67+
input[:test] = 'gt'
68+
69+
expected_output[:valid] = false
70+
expected_output[:test] = 'gt'
71+
expected_output[:test_version] = '8.1.0'
72+
73+
validate_task_run(input: input, expected: expected_output, code: 1)
74+
end
75+
end
76+
end
77+
78+
describe '#task' do
79+
let(:check) { OpenvoxBootstrap::Check.new }
80+
81+
context 'eq' do
82+
it 'returns true for equal versions' do
83+
expect(check.task(version: '8.0.0')).to(
84+
eq(
85+
{
86+
puppet_version: '8.0.0',
87+
valid: true,
88+
test: 'eq',
89+
test_version: '8.0.0'
90+
}
91+
)
92+
)
93+
end
94+
95+
it 'returns false for unequal versions' do
96+
expect(check.task(version: '8.0.1')).to(
97+
eq(
98+
{
99+
puppet_version: '8.0.0',
100+
valid: false,
101+
test: 'eq',
102+
test_version: '8.0.1'
103+
}
104+
)
105+
)
106+
end
107+
end
108+
109+
context 'ge' do
110+
it 'returns true for greater than versions' do
111+
expect(check.task(version: '7.0.0', test: 'ge')).to(
112+
eq(
113+
{
114+
puppet_version: '8.0.0',
115+
valid: true,
116+
test: 'ge',
117+
test_version: '7.0.0'
118+
}
119+
)
120+
)
121+
end
122+
123+
it 'returns true for equal versions' do
124+
expect(check.task(version: '8.0.0', test: 'ge')).to(include(valid: true))
125+
end
126+
127+
it 'returns false for less than versions' do
128+
expect(check.task(version: '9.0.0', test: 'ge')).to(
129+
eq(
130+
{
131+
puppet_version: '8.0.0',
132+
valid: false,
133+
test: 'ge',
134+
test_version: '9.0.0'
135+
}
136+
)
137+
)
138+
end
139+
end
140+
141+
context 'gt' do
142+
it 'is valid for greater than versions' do
143+
expect(check.task(version: '7.0.0', test: 'gt')).to(include(valid: true))
144+
end
145+
146+
it 'is invalid for equal versions or less than versions' do
147+
expect(check.task(version: '8.0.0', test: 'gt')).to(include(valid: false))
148+
expect(check.task(version: '8.0.1', test: 'gt')).to(include(valid: false))
149+
end
150+
end
151+
152+
context 'lt' do
153+
it 'is valid for less than versions' do
154+
expect(check.task(version: '8.0.1', test: 'lt')).to(include(valid: true))
155+
end
156+
157+
it 'is invalid for equal versions or greater than versions' do
158+
expect(check.task(version: '8.0.0', test: 'lt')).to(include(valid: false))
159+
expect(check.task(version: '7.0.0', test: 'lt')).to(include(valid: false))
160+
end
161+
end
162+
163+
context 'le' do
164+
it 'is valid for less than or equal versions' do
165+
expect(check.task(version: '9.0.0', test: 'le')).to(include(valid: true))
166+
expect(check.task(version: '8.0.0', test: 'le')).to(include(valid: true))
167+
end
168+
169+
it 'is invalid for greater than versions' do
170+
expect(check.task(version: '7.0.0', test: 'le')).to(include(valid: false))
171+
end
172+
end
173+
end
174+
end

tasks/check.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"description": "Check whether a Puppet(tm) implementation is installed. Optionally checks the version.",
3+
"parameters": {
4+
"version": {
5+
"description": "The version of the implementation to check. To check if version meets a minimum, set test to 'ge' and version to x, x.y or x.y.z",
6+
"type": "Optional[String]"
7+
},
8+
"test": {
9+
"description": "Version comparison operator.",
10+
"type": "Enum['eq', 'lt', 'le', 'gt', 'ge']",
11+
"default": "eq"
12+
}
13+
},
14+
"implementations": [
15+
{
16+
"name": "check.rb",
17+
"input_method": "stdin",
18+
"requirements": ["puppet-agent"]
19+
},
20+
{
21+
"name": "check_linux.sh",
22+
"input_method": "environment",
23+
"requirements": ["shell"],
24+
"files": [
25+
"openvox_bootstrap/tasks/check.rb"
26+
]
27+
}
28+
]
29+
}

tasks/check.rb

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#! /opt/puppetlabs/puppet/bin/ruby
2+
# frozen_string_literal: true
3+
4+
require 'json'
5+
6+
module OpenvoxBootstrap
7+
class Check
8+
# Get the Puppet version from the installed Puppet library.
9+
#
10+
# "require 'puppet/version'" can be fooled by the Ruby environment
11+
# if the gem is installed. For example:
12+
#
13+
# bolt task run openvox_bootstrap::check --targets localhost
14+
#
15+
# will be executed using the bolt package's Ruby environment,
16+
# which includes a puppet gem that will mostly likely be out of
17+
# sync with the installed Puppet version.
18+
def self.puppet_version
19+
require '/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/version'
20+
Puppet.version
21+
end
22+
23+
# Run the task and print the result as JSON.
24+
def self.run
25+
params = JSON.parse($stdin.read)
26+
raise(ArgumentError, <<~ERR) unless params.is_a?(Hash)
27+
Expected a Hash, got #{params.class}: #{params.inspect}
28+
ERR
29+
30+
params.transform_keys!(&:to_sym)
31+
# Clean out empty params so that task defaults are used.
32+
params.delete_if { |_, v| v.nil? || v == '' }
33+
34+
result = Check.new.task(**params)
35+
puts JSON.pretty_generate(result)
36+
result[:valid] ? exit(0) : exit(1)
37+
end
38+
39+
def task(version: nil, test: 'eq', **_kwargs)
40+
puppet_version = Gem::Version.new(OpenvoxBootstrap::Check.puppet_version)
41+
result = {
42+
puppet_version: puppet_version.to_s,
43+
}
44+
result[:valid] = if version.nil? || version.empty?
45+
true
46+
else
47+
test_version = Gem::Version.new(version)
48+
result[:test] = test
49+
result[:test_version] = version
50+
case test
51+
when 'eq'
52+
puppet_version == test_version
53+
when 'lt'
54+
puppet_version < test_version
55+
when 'le'
56+
puppet_version <= test_version
57+
when 'gt'
58+
puppet_version > test_version
59+
when 'ge'
60+
puppet_version >= test_version
61+
else
62+
raise ArgumentError, "Unknown test: '#{test}'"
63+
end
64+
end
65+
66+
result
67+
end
68+
end
69+
end
70+
71+
OpenvoxBootstrap::Check.run if __FILE__ == $PROGRAM_NAME

tasks/check_linux.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#! /usr/bin/env bash
2+
3+
set -e
4+
5+
declare PT__installdir
6+
declare PT_version
7+
declare PT_test
8+
9+
bindir='/opt/puppetlabs/puppet/bin'
10+
11+
if ! [ -f "${bindir}/puppet" ]; then
12+
echo "Error: No puppet binary found at '${bindir}/puppet'. Is the package installed?"
13+
exit 1
14+
fi
15+
16+
"${bindir}/ruby" "${PT__installdir}/openvox_bootstrap/tasks/check.rb" <<JSON
17+
{
18+
"version": "${PT_version}",
19+
"test": "${PT_test}"
20+
}
21+
JSON

0 commit comments

Comments
 (0)