|
8 | 8 | require 'timeout'
|
9 | 9 | require 'etc'
|
10 | 10 |
|
11 |
| -def main |
12 |
| - params = JSON.parse(STDIN.read) |
13 |
| - type = params['type'] |
14 |
| - targets = params['targets'] |
15 |
| - timeout = params['wait_until_connected_timeout'] |
16 |
| - token_file = params['token_file'] || File.join(Etc.getpwuid.dir, '.puppetlabs', 'token') |
| 11 | +class PEAdm |
| 12 | + class Task |
| 13 | + class PuppetInfraUpgrade |
| 14 | + def initialize(params) |
| 15 | + @type = params['type'] |
| 16 | + @targets = params['targets'] |
| 17 | + @timeout = params['wait_until_connected_timeout'] |
| 18 | + @token_file = params['token_file'] |
| 19 | + end |
17 | 20 |
|
18 |
| - exit 0 if targets.empty? |
| 21 | + def execute! |
| 22 | + exit 0 if @targets.empty? |
| 23 | + token_file = @token_file || File.join(Etc.getpwuid.dir, '.puppetlabs', 'token') |
19 | 24 |
|
20 |
| - cmd = ['/opt/puppetlabs/bin/puppet-infrastructure', '--render-as', 'json', 'upgrade'] |
21 |
| - cmd << '--token-file' << token_file unless params['token_file'].nil? |
22 |
| - cmd << type << targets.join(',') |
| 25 | + cmd = ['/opt/puppetlabs/bin/puppet-infrastructure', '--render-as', 'json', 'upgrade'] |
| 26 | + cmd << '--token-file' << token_file unless @token_file.nil? |
| 27 | + cmd << @type << @targets.join(',') |
23 | 28 |
|
24 |
| - wait_until_connected(nodes: targets, token_file: token_file, timeout: timeout) |
| 29 | + wait_until_connected(nodes: @targets, token_file: token_file, timeout: @timeout) |
25 | 30 |
|
26 |
| - stdouterr, status = Open3.capture2e(*cmd) |
27 |
| - puts stdouterr |
28 |
| - if status.success? |
29 |
| - exit 0 |
30 |
| - elsif status.exitstatus == 11 # Waiting for PuppetDB sync to complete, but otherwise successful |
31 |
| - exit 0 |
32 |
| - else |
33 |
| - exit status.exitstatus |
34 |
| - end |
35 |
| -end |
| 31 | + stdouterr, status = Open3.capture2e(*cmd) |
| 32 | + STDOUT.puts stdouterr |
36 | 33 |
|
37 |
| -def inventory_uri |
38 |
| - @inventory_uri ||= URI.parse('https://localhost:8143/orchestrator/v1/inventory') |
39 |
| -end |
| 34 | + # Exit code 11 indicates PuppetDB sync in progress, just not yet |
| 35 | + # finished. We consider that success. |
| 36 | + if [0, 11].include?(status.exitstatus) |
| 37 | + return |
| 38 | + else |
| 39 | + exit status.exitstatus |
| 40 | + end |
| 41 | + end |
40 | 42 |
|
41 |
| -def request_object(nodes:, token_file:) |
42 |
| - token = File.read(token_file) |
43 |
| - body = { |
44 |
| - 'nodes' => nodes, |
45 |
| - }.to_json |
| 43 | + def inventory_uri |
| 44 | + @inventory_uri ||= URI.parse('https://localhost:8143/orchestrator/v1/inventory') |
| 45 | + end |
46 | 46 |
|
47 |
| - request = Net::HTTP::Post.new(inventory_uri.request_uri) |
48 |
| - request['Content-Type'] = 'application/json' |
49 |
| - request['X-Authentication'] = token |
50 |
| - request.body = body |
| 47 | + def request_object(nodes:, token_file:) |
| 48 | + token = File.read(token_file) |
| 49 | + body = { |
| 50 | + 'nodes' => nodes, |
| 51 | + }.to_json |
51 | 52 |
|
52 |
| - request |
53 |
| -end |
| 53 | + request = Net::HTTP::Post.new(inventory_uri.request_uri) |
| 54 | + request['Content-Type'] = 'application/json' |
| 55 | + request['X-Authentication'] = token |
| 56 | + request.body = body |
54 | 57 |
|
55 |
| -def http_object |
56 |
| - http = Net::HTTP.new(inventory_uri.host, inventory_uri.port) |
57 |
| - http.use_ssl = true |
58 |
| - http.verify_mode = OpenSSL::SSL::VERIFY_NONE |
| 58 | + request |
| 59 | + end |
59 | 60 |
|
60 |
| - http |
61 |
| -end |
| 61 | + def http_object |
| 62 | + http = Net::HTTP.new(inventory_uri.host, inventory_uri.port) |
| 63 | + http.use_ssl = true |
| 64 | + http.verify_mode = OpenSSL::SSL::VERIFY_NONE |
| 65 | + |
| 66 | + http |
| 67 | + end |
62 | 68 |
|
63 |
| -def wait_until_connected(nodes:, token_file:, timeout: 120) |
64 |
| - http = http_object |
65 |
| - request = request_object(nodes: nodes, token_file: token_file) |
66 |
| - inventory = {} |
67 |
| - Timeout.timeout(timeout) do |
68 |
| - loop do |
69 |
| - response = http.request(request) |
70 |
| - raise unless response.is_a? Net::HTTPSuccess |
71 |
| - inventory = JSON.parse(response.body) |
72 |
| - break if inventory['items'].all? { |item| item['connected'] } |
73 |
| - sleep(1) |
| 69 | + def wait_until_connected(nodes:, token_file:, timeout: 120) |
| 70 | + http = http_object |
| 71 | + request = request_object(nodes: nodes, token_file: token_file) |
| 72 | + inventory = {} |
| 73 | + Timeout.timeout(timeout) do |
| 74 | + loop do |
| 75 | + response = http.request(request) |
| 76 | + unless response.is_a? Net::HTTPSuccess |
| 77 | + raise "Unexpected result from orchestrator: #{response.class}\n#{response}" |
| 78 | + end |
| 79 | + inventory = JSON.parse(response.body) |
| 80 | + break if inventory['items'].all? { |item| item['connected'] } |
| 81 | + sleep(1) |
| 82 | + end |
| 83 | + end |
| 84 | + rescue Timeout::Error |
| 85 | + raise 'Timed out waiting for nodes to be connected to orchestrator: ' + |
| 86 | + inventory['items'].reject { |item| item['connected'] } |
| 87 | + .map { |item| item['name'] } |
| 88 | + .to_s |
| 89 | + end |
74 | 90 | end
|
75 | 91 | end
|
76 |
| -rescue Timeout::Error |
77 |
| - raise 'Timed out waiting for nodes to be connected to orchestrator: ' + |
78 |
| - inventory['items'].reject { |item| item['connected'] } |
79 |
| - .map { |item| item['name'] } |
80 |
| - .to_s |
81 | 92 | end
|
82 | 93 |
|
83 |
| -main |
| 94 | +# Run the task unless an environment flag has been set, signaling not to. The |
| 95 | +# environment flag is used to disable auto-execution and enable Ruby unit |
| 96 | +# testing of this task. |
| 97 | +unless ENV['RSPEC_UNIT_TEST_MODE'] |
| 98 | + upgrade = PEAdm::Task::PuppetInfraUpgrade.new(JSON.parse(STDIN.read)) |
| 99 | + upgrade.execute! |
| 100 | +end |
0 commit comments