cem_acpt 0.8.0 → 0.8.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 853cc9a89c0feaf798bb5efdfc0c8af47d2664121cddd3794b65a61d5dc80851
4
- data.tar.gz: 6d0d5c67e27918d7897ea567a4134249c8a81e23ea95e6a3850a65585ebdd3e0
3
+ metadata.gz: e7eb7faf465af2f2ea5ab7649db1cf7e05c55573b869966c7e99c49aff498bf7
4
+ data.tar.gz: d79aadcc053957630a339b49a5ea456c5d67cc0dab24b036184cfec3e6c67609
5
5
  SHA512:
6
- metadata.gz: 244c701ba966fa878c399efba4953db7be8f5977c906501f9d2da8410583ebf2c2c505c687dc03e8cd97b325f362b28472f68c089065cda21f83d01d16c15d22
7
- data.tar.gz: ae7ca222e4264ed32ed47df2745d76c8347c1b5eab94cd2f0278af581c7c7108fb006232c5bbb4d37b2455559c0826a5630498cd620d4fd85a8948b8a0856c22
6
+ metadata.gz: cee1f24c8c38d68b01078f56e41963a02f5c3c5e2df8a35907b86e19b20600fe5ba612d7382be02da41b0a38f662a09019f629cf4decae30f35dad14f878fd38
7
+ data.tar.gz: 968a449a29d6f487e802954ca9af7d1d64bd2dd85c7f95cbaf95cecf7357a261a113293e712b8be8b01a593564de885d25c80ab5b01632215b98e8bd43310012
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cem_acpt (0.8.0)
4
+ cem_acpt (0.8.2)
5
5
  async-http (>= 0.60, < 0.70)
6
6
  bcrypt_pbkdf (>= 1.0, < 2.0)
7
7
  deep_merge (>= 1.2, < 2.0)
@@ -4,6 +4,7 @@ require 'json'
4
4
  require 'open3'
5
5
  require 'stringio'
6
6
  require_relative '../../logging'
7
+ require_relative '../../utils/shell'
7
8
 
8
9
  module CemAcpt
9
10
  module Provision
@@ -81,34 +82,10 @@ module CemAcpt
81
82
  end
82
83
 
83
84
  def run_cmd(cmd, opts = {}, env = {}, suffix: '')
84
- logger.debug('CemAcpt::Provision::TerraformCmd') { "Running command with args: cmd = \"#{cmd}\", opts = \"#{opts}\", env = \"#{env}\", suffix = \"#{suffix}\"" }
85
- val, outerr = execute(format_cmd(cmd, opts, suffix), environment(env))
86
- raise "Error running command: #{cmd}\n#{outerr}" unless val.success?
87
-
88
- outerr
89
- end
90
-
91
- def execute(cmd, env)
92
- logger.debug('CemAcpt::Provision::TerraformCmd') { "Executing command: #{cmd}" }
93
- io_outerr = StringIO.new
94
- val = Open3.popen2e(env, cmd) do |stdin, outerr, wait_thr|
95
- stdin.close
96
- outerr.sync = true
97
- output_thread = Thread.new do
98
- while (line = outerr.readline_nonblock)
99
- logger << line
100
- io_outerr.write(line) unless line.chomp.empty?
101
- end
102
- rescue IO::WaitReadable
103
- retry
104
- rescue EOFError
105
- # Do nothing
106
- end
107
- wait_thr.join
108
- output_thread.exit
109
- wait_thr.value
110
- end
111
- [val, io_outerr.string]
85
+ cmd = format_cmd(cmd, opts, suffix)
86
+ env = environment(env)
87
+ logger.debug('CemAcpt::Provision::TerraformCmd') { "Running command \"#{cmd}\" with environment \"#{env}\"" }
88
+ CemAcpt::Utils::Shell.run_cmd(cmd, env, output: logger)
112
89
  end
113
90
 
114
91
  def chdir(opts = {})
@@ -123,14 +100,10 @@ module CemAcpt
123
100
  end
124
101
 
125
102
  def which_terraform
126
- exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
127
- ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
128
- exts.each do |ext|
129
- exe = File.join(path, "terraform#{ext}")
130
- return exe if File.executable?(exe) && !File.directory?(exe)
131
- end
132
- end
133
- raise 'terraform not found in PATH, make sure it is installed'
103
+ path = CemAcpt::Utils::Shell.which('terraform')
104
+ raise 'terraform not found in PATH, make sure it is installed' if path.nil?
105
+
106
+ path
134
107
  end
135
108
 
136
109
  def format_cmd(cmd, opts = {}, suffix = '')
@@ -25,6 +25,7 @@ module CemAcpt
25
25
  @module_package_path = nil
26
26
  @private_key = nil
27
27
  @public_key = nil
28
+ @applied = false
28
29
  end
29
30
 
30
31
  # @return [Hash] A hash of instance names and IPs
@@ -36,7 +37,18 @@ module CemAcpt
36
37
  terraform_init
37
38
  terraform_plan(formatted_vars, DEFAULT_PLAN_NAME)
38
39
  terraform_apply(DEFAULT_PLAN_NAME)
39
- JSON.parse(terraform_output('instance_name_ip', json: true))
40
+ @applied = true
41
+ end
42
+
43
+ def output
44
+ raise 'Terraform has not been applied yet' unless @applied
45
+
46
+ output = terraform_output('instance_name_ip', json: true)
47
+ logger.debug('CemAcpt::Provision::Terraform') { "Terraform output:\n#{output}" }
48
+ JSON.parse(output)
49
+ rescue JSON::ParserError => e
50
+ logger.error('CemAcpt::Provision::Terraform') { "Error parsing Terraform output: #{output}" }
51
+ raise e
40
52
  end
41
53
 
42
54
  def destroy
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'fileutils'
3
4
  require 'securerandom'
4
5
  require_relative 'action_result'
5
6
  require_relative 'goss'
@@ -8,7 +9,6 @@ require_relative 'platform'
8
9
  require_relative 'provision'
9
10
  require_relative 'test_data'
10
11
  require_relative 'utils'
11
- require_relative 'utils/winrm_runner'
12
12
  require_relative 'version'
13
13
  require_relative 'test_runner/log_formatter'
14
14
 
@@ -30,6 +30,7 @@ module CemAcpt
30
30
  @results = []
31
31
  @http_statuses = []
32
32
  @provisioned = false
33
+ @destroyed = false
33
34
  end
34
35
 
35
36
  def inspect
@@ -48,7 +49,6 @@ module CemAcpt
48
49
  Dir.chdir(module_dir)
49
50
  logger.start_ci_group("CemAcpt v#{CemAcpt::VERSION} run started at #{@start_time}")
50
51
  logger.info('CemAcpt::TestRunner') { "Using module directory: #{module_dir}..." }
51
- keep_terminal_alive
52
52
  @run_data[:private_key], @run_data[:public_key], @run_data[:known_hosts] = new_ephemeral_ssh_keys
53
53
  logger.info('CemAcpt::TestRunner') { 'Created ephemeral SSH key pair...' }
54
54
  @run_data[:module_package_path] = build_module_package
@@ -59,7 +59,8 @@ module CemAcpt
59
59
  @run_data[:nodes] = new_node_data
60
60
  logger.info('CemAcpt::TestRunner') { 'Created node data...' }
61
61
  logger.verbose('CemAcpt::TestRunner') { "Node data: #{@run_data[:nodes]}" }
62
- @instance_names_ips = provision_test_nodes
62
+ provision_test_nodes
63
+ @instance_names_ips = provisioner_output
63
64
  logger.info('CemAcpt::TestRunner') { "Instance names and IPs class: #{@instance_names_ips.class}" }
64
65
  @provisioned = true
65
66
  logger.info('CemAcpt::TestRunner') { 'Provisioned test nodes...' }
@@ -74,7 +75,7 @@ module CemAcpt
74
75
  # instance_names_ips. It contains the username, password, and ip of the
75
76
  # windows node, as well as the test name that will be run on that node.
76
77
  login_info = CemAcpt::Utils.get_windows_login_info(k, v)
77
- win_node = CemAcpt::Utils::WinRMRunner::WinNode.new(login_info, @run_data[:module_package_path].split('/').last)
78
+ win_node = CemAcpt::Utils::WinRMRunner::WinNode.new(login_info, @run_data[:win_remote_module_name])
78
79
  win_node.run
79
80
  end
80
81
  end
@@ -85,43 +86,37 @@ module CemAcpt
85
86
  logger.error('CemAcpt::TestRunner') { 'Run failed due to error...' }
86
87
  @results << ActionResult.new(e)
87
88
  ensure
89
+ logger.end_ci_group
88
90
  clean_up
89
91
  process_test_results
90
92
  Dir.chdir(@old_dir) if @old_dir
91
93
  @results
92
94
  end
93
95
 
94
- def clean_up(trap_context = false)
95
- logger.end_ci_group
96
- kill_keep_terminal_alive unless trap_context
97
- cleanup_bucket # Clean up bucket if we're testing the cem_windows module
98
-
99
- return no_destroy if config.get('no_destroy_nodes')
96
+ def clean_up(_trap_context = false)
97
+ logger.start_ci_group("CemAcpt v#{CemAcpt::VERSION} run finished at #{Time.now}")
98
+ logger.debug('CemAcpt::TestRunner') { "Starting clean up, provisioned: #{@provisioned}, destroyed: #{@destroyed}" }
100
99
 
101
- clean_ephemeral_ssh_keys
102
- destroy_test_nodes if @provisioned && !@destroyed
100
+ if config.get('no_destroy_nodes')
101
+ logger.warn('CemAcpt::TestRunner') { 'Not destroying test nodes because no-destroy-nodes is set...' }
102
+ @provisioner&.show
103
+ logger.info('CemAcpt') { "Test SSH Keys:\n Private Key: #{@run_data[:private_key]}\n Public Key:#{@run_data[:public_key]}" }
104
+ else
105
+ cleanup_bucket # Clean up bucket if we're testing the cem_windows module
106
+ clean_ephemeral_ssh_keys
107
+ destroy_test_nodes
108
+ end
103
109
  rescue StandardError => e
104
110
  logger.verbose('CemAcpt::TestRunner') { "Error cleaning up: #{e}" }
105
111
  logger.verbose('CemAcpt::TestRunner') { e.backtrace.join("\n") }
112
+ ensure
113
+ logger.end_ci_group
106
114
  end
107
115
 
108
116
  private
109
117
 
110
118
  attr_reader :config
111
119
 
112
- # @return [Thread] The thread that keeps the terminal alive
113
- def keep_terminal_alive
114
- return unless config.ci?
115
-
116
- @keep_terminal_alive ||= CemAcpt::Utils::Terminal.keep_terminal_alive
117
- end
118
-
119
- def kill_keep_terminal_alive
120
- return if @trap_context
121
-
122
- keep_terminal_alive&.kill
123
- end
124
-
125
120
  # @return [String] The path to the module package
126
121
  def build_module_package
127
122
  if config.get('tests').first.include? 'windows'
@@ -162,24 +157,41 @@ module CemAcpt
162
157
  @provisioner.provision
163
158
  end
164
159
 
165
- def destroy_test_nodes
166
- return no_destroy if config.get('no_destroy_nodes')
160
+ def provisioner_output
161
+ logger.info('CemAcpt::TestRunner') { 'Getting provisioner output...' }
162
+ @attempts = 0
163
+ @max_attempts = 3
164
+ output = nil
165
+ while @attempts < @max_attempts
166
+ @attempts += 1
167
+ output = @provisioner.output
168
+ break unless (output.nil? || output.empty?) && @attempts < @max_attempts # Don't sleep if this is last attempt
169
+
170
+ logger.info('CemAcpt::TestRunner') { "Provisioner output is nil or empty, retrying (#{@attempts}/#{@max_attempts})" }
171
+ sleep 3
172
+ end
173
+ raise 'Provisioner output is nil or empty' if output.nil? || output.empty?
167
174
 
168
- logger.info('CemAcpt::TestRunner') { 'Destroying test nodes...' }
169
- logger.start_ci_group("CemAcpt v#{CemAcpt::VERSION} run finished at #{Time.now}")
170
- @provisioner&.destroy
171
- @destroyed = true
172
- ensure
173
- logger.end_ci_group
175
+ output
176
+ end
177
+
178
+ def destroy_test_nodes
179
+ logger.info('CemAcpt::TestRunner') { 'Destroying test nodes if necessary...' }
180
+ if !@provisioned
181
+ logger.warn('CemAcpt::TestRunner') { 'Test nodes not provisioned, nothing to destroy...' }
182
+ elsif @destroyed
183
+ logger.warn('CemAcpt::TestRunner') { 'Test nodes already destroyed, not destroying...' }
184
+ else
185
+ logger.info('CemAcpt::TestRunner') { 'Test nodes are provisioned and not destroyed, destroying...' }
186
+ @provisioner&.destroy
187
+ @destroyed = true
188
+ end
174
189
  end
175
190
 
176
191
  def no_destroy
177
- logger.warn('CemAcpt::TestRunner') { 'Not destroying test nodes...' }
178
- logger.start_ci_group("CemAcpt v#{CemAcpt::VERSION} run finished at #{Time.now}")
192
+ logger.warn('CemAcpt::TestRunner') { 'Not destroying test nodes because no-destroy-nodes is set...' }
179
193
  @provisioner&.show
180
194
  logger.info('CemAcpt') { "Test SSH Keys:\n Private Key: #{@run_data[:private_key]}\n Public Key:#{@run_data[:public_key]}" }
181
- ensure
182
- logger.end_ci_group
183
195
  end
184
196
 
185
197
  def run_tests(hosts, only_actions, except_actions)
@@ -248,38 +260,25 @@ module CemAcpt
248
260
  # This should only be done once per cem_acpt run. It's important to update the module_package_path
249
261
  # in the run_data to reflect the new module path if we do end up changing the module name
250
262
  def upload_module_to_bucket
251
- curr_module_path = @run_data[:module_package_path].split('/')[0..-2].join('/')
252
- curr_module_name = @run_data[:module_package_path].split('/')[-1]
253
-
254
- logger.debug('CemAcpt') { 'Checking if there duplicate cem_windows module in the bucket already...' }
255
- # Checking if the module already exists in the bucket. Gcloud will return an empty string if the module
256
- # doesn't exist in the bucket.
257
- attempts = 0
258
- until `gcloud storage ls gs://win_cem_acpt/#{curr_module_name}`.empty? do
259
- raise "Failed to rename duplicate module in GCloud" if attempts >= 3
260
-
261
- logger.debug('CemAcpt') { 'Duplicate cem_windows module found. Renaming cem_windows module...' }
262
- # Rename the cem_windows module
263
- curr_module_name = SecureRandom.uuid << curr_module_name
264
- `mv #{@run_data[:module_package_path]} #{curr_module_path}/#{curr_module_name}`
265
- # update the module_package_path in the run_data
266
- @run_data[:module_package_path] = File.join(curr_module_path, curr_module_name)
267
- attempts += 1
268
- end
263
+ @run_data[:win_remote_module_name] = SecureRandom.uuid << File.split(@run_data[:module_package_path]).last
264
+ @run_data[:win_remote_module_path] = File.join('gs://win_cem_acpt', @run_data[:win_remote_module_name])
269
265
  # Upload the module from the local host to the bucket
270
- logger.info('CemAcpt') { 'Transporting cem_windows module...' }
271
- gcloud_cmd = `gcloud storage cp #{@run_data[:module_package_path]} gs://win_cem_acpt`
272
- logger.debug('CemAcpt') { "Uploaded cem_windows module to bucket: #{gcloud_cmd}" }
266
+ logger.info('CemAcpt') { "Uploading #{@run_data[:module_pakage_path]} to #{@run_data[:win_remote_module_path]}..." }
267
+ CemAcpt::Utils::Shell.run_cmd("gcloud storage cp #{@run_data[:module_package_path]} #{@run_data[:win_remote_module_path]}")
268
+ logger.debug('CemAcpt') { 'Successfully uploaded module' }
273
269
  end
274
270
 
275
271
  # We have to clean up our gcp bucket after we're done testing. This will limit the duplicated
276
272
  # modules existing in the bucket.
277
273
  def cleanup_bucket
278
- # Cleanup the module from the bucket
279
- cleanup_cmd = `gcloud storage rm gs://win_cem_acpt/#{@run_data[:module_package_path].split('/')[-1]}`
280
- logger.debug('CemAcpt') { "Removed module from bucket: #{cleanup_cmd}" }
281
- rescue StandardError
282
- logger.info('CemAcpt') { 'No module to clean up in the bucket. You might not be running test for cem_windows' }
274
+ if @run_data[:win_remote_module_path]
275
+ logger.info('CemAcpt::TestRunner') { "Cleaning up bucket #{@run_data[:win_remote_module_path]}..." }
276
+ # Cleanup the module from the bucket
277
+ cleanup_cmd = CemAcpt::Utils::Shell.run_cmd("gcloud storage rm #{@run_data[:win_remote_module_path]}", raise_on_error: false)
278
+ logger.debug('CemAcpt::TestRunner') { "Removed module from bucket: #{cleanup_cmd}" } unless cleanup_cmd.nil? || cleanup_cmd.empty?
279
+ else
280
+ logger.info('CemAcpt::TestRunner') { 'No module to clean up in bucket...' }
281
+ end
283
282
  end
284
283
  end
285
284
  end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+ require 'stringio'
5
+
6
+ module CemAcpt
7
+ # Error class for shell commands
8
+ class ShellCommandError < StandardError; end
9
+
10
+ module Utils
11
+ # Generic utilities for running local shell commands
12
+ module Shell
13
+ # Runs a command in a subshell and returns the Process::Status
14
+ # and the string output of the command.
15
+ # @param cmd [String] The command to run
16
+ # @param env [Hash] A hash of environment variables to set
17
+ # @param output [IO] An IO object that implements #:<< to write the output of the
18
+ # command to in real time. Typically this is a Logger object. Defaults to $stdout.
19
+ # If the object responds to #:debug, the command will be logged at the debug level.
20
+ # @param raise_on_fail [Boolean] Whether to raise an error if the command fails
21
+ # @return [String] The string output of the command
22
+ def self.run_cmd(cmd, env = {}, output: $stdout, raise_on_fail: true)
23
+ io_outerr = StringIO.new
24
+ if output.respond_to?(:debug)
25
+ output.debug('CemAcpt::Utils::Shell') { "Running command:\n\t#{cmd}\nWith environment:\n\t#{env}" }
26
+ else
27
+ output << "Running command:\n\t#{cmd}\nWith environment:\n\t#{env}\n"
28
+ end
29
+ val = Open3.popen2e(env, cmd) do |stdin, outerr, wait_thr|
30
+ stdin.close
31
+ outerr.sync = true
32
+ output_thread = Thread.new do
33
+ while (line = outerr.gets("\n"))
34
+ output << line if output
35
+ io_outerr.write(line) unless line.chomp.empty?
36
+ end
37
+ end
38
+ wait_thr.join
39
+ output_thread.exit
40
+ wait_thr.value
41
+ end
42
+ io_string = io_outerr.string
43
+ raise CemAcpt::ShellCommandError, "Error running command: #{cmd}\n#{io_string}" if raise_on_fail && !val.success?
44
+
45
+ io_string
46
+ end
47
+
48
+ # Mimics the behavior of the `which` command.
49
+ # @param cmd [String] The command to find
50
+ # @return [String] The path to the command
51
+ # @return [nil] If the command is not found
52
+ def self.which(cmd)
53
+ return cmd if File.executable?(cmd) && !File.directory?(cmd)
54
+
55
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
56
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
57
+ exts.each do |ext|
58
+ exe = File.join(path, "#{cmd}#{ext}")
59
+ return exe if File.executable?(exe) && !File.directory?(exe)
60
+ end
61
+ end
62
+ nil
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'open3'
3
+ require_relative 'shell'
4
4
  require_relative '../logging'
5
5
 
6
6
  module CemAcpt
@@ -32,9 +32,7 @@ module CemAcpt
32
32
  delete(key_name) # Delete existing keys with same name
33
33
  cmd = new_keygen_cmd(key_name, **options)
34
34
  logger.debug('CemAcpt::Utils::SSH::Keygen') { "Creating SSH key with command: #{cmd}" }
35
- _stdout, stderr, status = Open3.capture3(cmd)
36
- raise "Failed to create SSH key! #{stderr}" unless status.success?
37
-
35
+ CemAcpt::Utils::Shell.run_cmd(cmd, output: logger)
38
36
  key_paths(key_name)
39
37
  end
40
38
 
@@ -53,20 +51,11 @@ module CemAcpt
53
51
 
54
52
  private
55
53
 
56
- FIND_BIN_PATH_COMMANDS = [
57
- "#{ENV['SHELL']} -c 'command -v ssh-keygen'",
58
- "#{ENV['SHELL']} -c 'which ssh-keygen'",
59
- ].freeze
60
-
61
- def find_bin_path(find_cmd = FIND_BIN_PATH_COMMANDS.first)
62
- bin_path, stderr, status = Open3.capture3(find_cmd)
63
- raise "Cannot find ssh-keygen with command #{find_cmd}: #{stderr}" unless status.success?
64
-
65
- bin_path.chomp
66
- rescue StandardError => e
67
- return find_bin_path(FIND_BIN_PATH_COMMANDS.last) unless FIND_BIN_PATH_COMMANDS.last == find_cmd
54
+ def find_bin_path
55
+ bin_path = CemAcpt::Utils::Shell.which('ssh-keygen')
56
+ raise 'Cannot find command ssh-keygen in PATH, make sure it is installed' if bin_path.nil?
68
57
 
69
- raise e
58
+ bin_path
70
59
  end
71
60
 
72
61
  def new_keygen_cmd(key_name, **options)
@@ -100,12 +89,10 @@ module CemAcpt
100
89
  end
101
90
 
102
91
  def self.ssh_keygen
103
- bin_path = `#{ENV['SHELL']} -c 'command -v ssh-keygen'`.chomp
104
- raise 'Cannot find ssh-keygen! Install it and verify PATH' unless bin_path
92
+ bin_path = CemAcpt::Utils::Shell.which('ssh-keygen')
93
+ raise 'Cannot find command ssh-keygen in PATH, make sure it is installed' if bin_path.nil?
105
94
 
106
95
  bin_path
107
- rescue StandardError => e
108
- raise "Cannot find ssh-keygen! Install it and verify PATH. Orignal error: #{e}"
109
96
  end
110
97
 
111
98
  def self.default_keydir
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'utils/puppet'
4
+ require_relative 'utils/shell'
4
5
  require_relative 'utils/ssh'
5
6
  require_relative 'utils/terminal'
7
+ require_relative 'utils/winrm_runner'
6
8
  require_relative 'logging'
7
9
 
8
10
  module CemAcpt
@@ -19,17 +21,33 @@ module CemAcpt
19
21
  FileUtils.rm_f(package_file)
20
22
  `cd #{module_dir} && touch puppetlabs-cem_windows.tar.gz && tar -czf puppetlabs-cem_windows.tar.gz --exclude=puppetlabs-cem_windows.tar.gz *`
21
23
  logger.info('CemAcpt') { "Windows module packaged at #{package_file}" }
22
- return package_file
24
+ package_file
23
25
  end
24
26
 
25
27
  def reset_password_readiness_polling(instance_name)
26
- result = %x(echo Y | gcloud compute reset-windows-password #{instance_name} --zone=us-west1-b)
27
- while result.empty?
28
+ attempts = 0
29
+ last_error = nil
30
+ result = nil
31
+ begin
32
+ result = CemAcpt::Utils::Shell.run_cmd("echo Y | gcloud compute reset-windows-password #{instance_name} --zone=us-west1-b")
33
+ rescue StandardError => e
34
+ logger.debug('CemAcpt::Utils') { "Error polling for password readiness: #{e}" }
35
+ last_error = e
36
+ end
37
+ while result.nil? || result.empty?
38
+ raise "Instance not ready for password reset. Last error: #{last_error}" if attempts >= 60 # 10 minutes
39
+
28
40
  logger.info('CemAcpt') { "Waiting for instance #{instance_name} to be ready for password reset..." }
29
41
  sleep 10
30
- result = %x(echo Y | gcloud compute reset-windows-password #{instance_name} --zone=us-west1-b)
42
+ begin
43
+ result = CemAcpt::Utils::Shell.run_cmd("echo Y | gcloud compute reset-windows-password #{instance_name} --zone=us-west1-b")
44
+ rescue StandardError => e
45
+ logger.debug('CemAcpt::Utils') { "Error polling for password readiness: #{e}" }
46
+ last_error = e
47
+ end
48
+ attempts += 1
31
49
  end
32
- return result
50
+ result
33
51
  end
34
52
 
35
53
  def get_windows_login_info(instance_name, hash_of_instance)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CemAcpt
4
- VERSION = '0.8.0'
4
+ VERSION = '0.8.2'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cem_acpt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - puppetlabs
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-08-30 00:00:00.000000000 Z
11
+ date: 2023-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async-http
@@ -237,6 +237,7 @@ files:
237
237
  - lib/cem_acpt/test_runner/log_formatter/goss_action_response.rb
238
238
  - lib/cem_acpt/utils.rb
239
239
  - lib/cem_acpt/utils/puppet.rb
240
+ - lib/cem_acpt/utils/shell.rb
240
241
  - lib/cem_acpt/utils/ssh.rb
241
242
  - lib/cem_acpt/utils/terminal.rb
242
243
  - lib/cem_acpt/utils/winrm_runner.rb