cem_acpt 0.7.3 → 0.8.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/.rubocop.yml +3 -1
- data/Gemfile.lock +42 -14
- data/README.md +8 -0
- data/cem_acpt.gemspec +3 -1
- data/exe/cem_acpt_image +0 -0
- data/lib/cem_acpt/action_result.rb +85 -0
- data/lib/cem_acpt/cli.rb +42 -22
- data/lib/cem_acpt/config/base.rb +4 -2
- data/lib/cem_acpt/goss/api.rb +8 -2
- data/lib/cem_acpt/image_builder.rb +64 -72
- data/lib/cem_acpt/logging.rb +41 -30
- data/lib/cem_acpt/platform.rb +4 -5
- data/lib/cem_acpt/provision/terraform/linux.rb +2 -2
- data/lib/cem_acpt/provision/terraform/terraform_cmd.rb +181 -0
- data/lib/cem_acpt/provision/terraform/windows.rb +9 -0
- data/lib/cem_acpt/provision/terraform.rb +34 -47
- data/lib/cem_acpt/provision.rb +1 -1
- data/lib/cem_acpt/puppet_helpers.rb +1 -1
- data/lib/cem_acpt/test_data.rb +3 -3
- data/lib/cem_acpt/test_runner/log_formatter/error_formatter.rb +33 -0
- data/lib/cem_acpt/test_runner/log_formatter.rb +10 -1
- data/lib/cem_acpt/test_runner.rb +151 -52
- data/lib/cem_acpt/utils/ssh.rb +2 -2
- data/lib/cem_acpt/utils/terminal.rb +1 -5
- data/lib/cem_acpt/utils/winrm_runner.rb +160 -0
- data/lib/cem_acpt/utils.rb +41 -1
- data/lib/cem_acpt/version.rb +1 -1
- data/lib/cem_acpt.rb +51 -21
- data/lib/terraform/gcp/windows/main.tf +26 -0
- metadata +46 -8
@@ -0,0 +1,181 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'open3'
|
5
|
+
require 'stringio'
|
6
|
+
require_relative '../../logging'
|
7
|
+
|
8
|
+
module CemAcpt
|
9
|
+
module Provision
|
10
|
+
# Stand-in for ruby-terraform because ruby-terraform doesn't work with Ruby 3
|
11
|
+
class TerraformCmd
|
12
|
+
include CemAcpt::Logging
|
13
|
+
|
14
|
+
attr_accessor :working_dir
|
15
|
+
attr_reader :bin_path
|
16
|
+
|
17
|
+
def initialize(working_dir = nil, environment = {})
|
18
|
+
@working_dir = working_dir
|
19
|
+
@environment = environment
|
20
|
+
@bin_path = which_terraform
|
21
|
+
end
|
22
|
+
|
23
|
+
def inspect
|
24
|
+
to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
"#<#{self.class.name}:0x#{object_id.to_s(16)}>"
|
29
|
+
end
|
30
|
+
|
31
|
+
def environment=(env)
|
32
|
+
raise ArgumentError, 'environment must be a Hash' unless env.is_a?(Hash)
|
33
|
+
|
34
|
+
@environment = env
|
35
|
+
end
|
36
|
+
|
37
|
+
def environment(env = {})
|
38
|
+
raise ArgumentError, 'additional environment must be a Hash' unless env.is_a?(Hash)
|
39
|
+
|
40
|
+
if env.key?(:environment) && env[:environment].is_a?(Hash)
|
41
|
+
env = env[:environment]
|
42
|
+
end
|
43
|
+
@environment.merge(env)
|
44
|
+
end
|
45
|
+
|
46
|
+
def init(opts = {}, env = {})
|
47
|
+
run_cmd('init', opts, env)
|
48
|
+
end
|
49
|
+
|
50
|
+
def plan(opts = {}, env = {})
|
51
|
+
plan = extract_arg!(opts, :plan, required: true)
|
52
|
+
opts[:out] = plan
|
53
|
+
run_cmd('plan', opts, env)
|
54
|
+
end
|
55
|
+
|
56
|
+
def apply(opts = {}, env = {})
|
57
|
+
plan = extract_arg!(opts, :plan, required: true)
|
58
|
+
run_cmd('apply', opts, env, suffix: plan)
|
59
|
+
end
|
60
|
+
|
61
|
+
def destroy(opts = {}, env = {})
|
62
|
+
run_cmd('destroy', opts, env)
|
63
|
+
end
|
64
|
+
|
65
|
+
def show(opts = {}, env = {})
|
66
|
+
run_cmd('show', opts, env)
|
67
|
+
end
|
68
|
+
|
69
|
+
def output(opts = {}, env = {})
|
70
|
+
name = extract_arg!(opts, :name, required: true)
|
71
|
+
run_cmd('output', opts, env, suffix: name)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def extract_arg!(opts, key, required: false)
|
77
|
+
key = key.to_sym
|
78
|
+
raise ArgumentError, "option #{key} is required" if required && !opts.key?(key) && (opts[key].nil? || opts[key].empty?)
|
79
|
+
|
80
|
+
opts.delete(key)
|
81
|
+
end
|
82
|
+
|
83
|
+
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]
|
112
|
+
end
|
113
|
+
|
114
|
+
def chdir(opts = {})
|
115
|
+
[extract_arg!(opts, :chdir), working_dir, Dir.pwd].each do |d|
|
116
|
+
next if d.nil? || d.empty?
|
117
|
+
|
118
|
+
d = File.expand_path(d)
|
119
|
+
return "-chdir=#{d}" if File.directory?(d)
|
120
|
+
|
121
|
+
logger.warn('CemAcpt::Provision::TerraformCmd') { "Directory #{d} does not exist, using next..." }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
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'
|
134
|
+
end
|
135
|
+
|
136
|
+
def format_cmd(cmd, opts = {}, suffix = '')
|
137
|
+
formatted = [bin_path, chdir(opts), cmd]
|
138
|
+
opts_s = opts_string(opts)
|
139
|
+
formatted << opts_s unless opts_s.empty?
|
140
|
+
formatted << suffix unless suffix.empty?
|
141
|
+
formatted.join(' ')
|
142
|
+
end
|
143
|
+
|
144
|
+
def opts_string(opts = {})
|
145
|
+
formatted = opts.map do |k, v|
|
146
|
+
next if k.nil? || k.empty?
|
147
|
+
|
148
|
+
k = k.to_s
|
149
|
+
k.tr!('_', '-')
|
150
|
+
if k == 'vars'
|
151
|
+
v.map { |vk, vv| "-var '#{vk}=#{vv}'" }.join(' ')
|
152
|
+
elsif %w[input lock refresh].include?(k) # These are boolean flags with values
|
153
|
+
"-#{k}=#{v}"
|
154
|
+
elsif v.nil? || (v.respond_to?(:empty) && v.empty?) || v.is_a?(TrueClass)
|
155
|
+
"-#{k}"
|
156
|
+
else
|
157
|
+
case v
|
158
|
+
when Array, Hash
|
159
|
+
"-#{k}='#{v.to_json}'"
|
160
|
+
else
|
161
|
+
"-#{k}=#{v}"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
formatted.join(' ')
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# IO monkey patch for non-blocking readline
|
171
|
+
class ::IO
|
172
|
+
def readline_nonblock
|
173
|
+
rlnb = []
|
174
|
+
while (ch = read_nonblock(1))
|
175
|
+
rlnb << ch
|
176
|
+
break if ch == "\n"
|
177
|
+
end
|
178
|
+
rlnb.join
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -6,6 +6,7 @@ module CemAcpt
|
|
6
6
|
module Provision
|
7
7
|
# Class provides methods for gathering provision data for Windows nodes
|
8
8
|
class Windows < OsData
|
9
|
+
# A name that will match with how image names are on GCP
|
9
10
|
def self.valid_names
|
10
11
|
%w[windows]
|
11
12
|
end
|
@@ -17,6 +18,14 @@ module CemAcpt
|
|
17
18
|
def puppet_bin_path
|
18
19
|
'C:/Program Files/Puppet Labs/Puppet/bin/puppet.bat'
|
19
20
|
end
|
21
|
+
|
22
|
+
def destination_provision_directory
|
23
|
+
'C:/cem_acpt'
|
24
|
+
end
|
25
|
+
|
26
|
+
def provision_commands
|
27
|
+
['placeholder']
|
28
|
+
end
|
20
29
|
end
|
21
30
|
end
|
22
31
|
end
|
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
require 'fileutils'
|
4
4
|
require 'json'
|
5
|
-
require 'ruby-terraform'
|
6
5
|
require_relative '../logging'
|
7
6
|
require_relative 'terraform/linux'
|
8
7
|
require_relative 'terraform/windows'
|
8
|
+
require_relative 'terraform/terraform_cmd'
|
9
9
|
|
10
10
|
module CemAcpt
|
11
11
|
module Provision
|
@@ -27,13 +27,12 @@ module CemAcpt
|
|
27
27
|
@public_key = nil
|
28
28
|
end
|
29
29
|
|
30
|
+
# @return [Hash] A hash of instance names and IPs
|
30
31
|
def provision(reuse_working_dir: false)
|
31
|
-
logger.info('Terraform') { 'Provisioning nodes...' }
|
32
|
+
logger.info('CemAcpt::Provision::Terraform') { 'Provisioning nodes...' }
|
32
33
|
@working_dir = new_working_dir unless reuse_working_dir
|
33
34
|
validate_working_dir!
|
34
35
|
save_vars_to_file!(formatted_vars) # Easier to reuse nodes this way
|
35
|
-
|
36
|
-
terraform_configure_logging
|
37
36
|
terraform_init
|
38
37
|
terraform_plan(formatted_vars, DEFAULT_PLAN_NAME)
|
39
38
|
terraform_apply(DEFAULT_PLAN_NAME)
|
@@ -42,7 +41,7 @@ module CemAcpt
|
|
42
41
|
|
43
42
|
def destroy
|
44
43
|
terraform_destroy(formatted_vars)
|
45
|
-
logger.verbose('Terraform') { "Deleting old working directory #{working_dir}" }
|
44
|
+
logger.verbose('CemAcpt::Provision::Terraform') { "Deleting old working directory #{working_dir}" }
|
46
45
|
FileUtils.rm_rf(working_dir)
|
47
46
|
@working_dir = nil
|
48
47
|
@module_package_path = nil
|
@@ -57,25 +56,17 @@ module CemAcpt
|
|
57
56
|
private
|
58
57
|
|
59
58
|
def terraform
|
60
|
-
@terraform ||=
|
61
|
-
end
|
62
|
-
|
63
|
-
def terraform_configure_logging
|
64
|
-
terraform.configure do |c|
|
65
|
-
c.logger = logger
|
66
|
-
c.stdout = c.logger
|
67
|
-
c.stderr = c.logger
|
68
|
-
end
|
59
|
+
@terraform ||= CemAcpt::Provision::TerraformCmd.new(working_dir, environment)
|
69
60
|
end
|
70
61
|
|
71
62
|
def terraform_init
|
72
|
-
logger.
|
63
|
+
logger.info('CemAcpt::Provision::Terraform') { 'Initializing Terraform' }
|
73
64
|
terraform.init({ chdir: working_dir, input: false, no_color: true }, { environment: environment })
|
74
65
|
end
|
75
66
|
|
76
67
|
def terraform_plan(vars, plan_name = DEFAULT_PLAN_NAME)
|
77
|
-
logger.
|
78
|
-
logger.verbose('Terraform') { "Using vars:\n#{JSON.pretty_generate(vars)}" }
|
68
|
+
logger.info('CemAcpt::Provision::Terraform') { "Creating Terraform plan '#{plan_name}'" }
|
69
|
+
logger.verbose('CemAcpt::Provision::Terraform') { "Using vars:\n#{JSON.pretty_generate(vars)}" }
|
79
70
|
terraform.plan(
|
80
71
|
{
|
81
72
|
chdir: working_dir,
|
@@ -91,23 +82,24 @@ module CemAcpt
|
|
91
82
|
end
|
92
83
|
|
93
84
|
def terraform_apply(plan_name = DEFAULT_PLAN_NAME)
|
94
|
-
logger.
|
85
|
+
logger.info('CemAcpt::Provision::Terraform') { "Running Terraform apply with the plan #{plan_name}" }
|
95
86
|
terraform.apply({ chdir: working_dir, input: false, no_color: true, plan: plan_name }, { environment: environment })
|
96
87
|
end
|
97
88
|
|
98
89
|
def terraform_output(name, json: true)
|
99
|
-
logger.
|
90
|
+
logger.info('CemAcpt::Provision::Terraform') { "Getting Terraform output #{name}" }
|
100
91
|
terraform.output({ chdir: working_dir, no_color: true, json: json, name: name }, { environment: environment })
|
101
92
|
end
|
102
93
|
|
103
94
|
def terraform_destroy(vars)
|
104
|
-
logger.
|
95
|
+
logger.info('CemAcpt::Provision::Terraform') { 'Destroying Terraform resources...' }
|
96
|
+
logger.verbose('CemAcpt::Provision::Terraform') { "Using vars: #{vars}" }
|
105
97
|
terraform.destroy(
|
106
98
|
{
|
107
99
|
chdir: working_dir,
|
108
100
|
auto_approve: true,
|
109
101
|
input: false,
|
110
|
-
no_color:
|
102
|
+
no_color: nil,
|
111
103
|
vars: vars,
|
112
104
|
},
|
113
105
|
{
|
@@ -117,18 +109,18 @@ module CemAcpt
|
|
117
109
|
end
|
118
110
|
|
119
111
|
def terraform_show
|
120
|
-
logger.
|
112
|
+
logger.info('CemAcpt::Provision::Terraform') { 'Showing Terraform state' }
|
121
113
|
terraform.show({ chdir: working_dir, no_color: true }, { environment: environment })
|
122
114
|
end
|
123
115
|
|
124
116
|
def new_backend(test_name)
|
125
117
|
if CemAcpt::Provision::Linux.use_for?(test_name)
|
126
|
-
logger.info('Terraform') { 'Using Linux backend' }
|
127
|
-
logger.verbose('Terraform') { "Creating backend with provision_data:\n#{JSON.pretty_generate(@provision_data)}" }
|
118
|
+
logger.info('CemAcpt::Provision::Terraform') { 'Using Linux backend' }
|
119
|
+
logger.verbose('CemAcpt::Provision::Terraform') { "Creating backend with provision_data:\n#{JSON.pretty_generate(@provision_data)}" }
|
128
120
|
CemAcpt::Provision::Linux.new(@config, @provision_data)
|
129
121
|
elsif CemAcpt::Provision::Windows.use_for?(test_name)
|
130
|
-
logger.info('Terraform') { 'Using Windows backend' }
|
131
|
-
logger.verbose('Terraform') { "Creating backend with provision_data:\n#{JSON.pretty_generate(@provision_data)}" }
|
122
|
+
logger.info('CemAcpt::Provision::Terraform') { 'Using Windows backend' }
|
123
|
+
logger.verbose('CemAcpt::Provision::Terraform') { "Creating backend with provision_data:\n#{JSON.pretty_generate(@provision_data)}" }
|
132
124
|
CemAcpt::Provision::Windows.new(@config, @provision_data)
|
133
125
|
else
|
134
126
|
err_msg = [
|
@@ -136,9 +128,8 @@ module CemAcpt
|
|
136
128
|
"Known OSes are: #{CemAcpt::Provision::Linux.valid_names.join(', ')}",
|
137
129
|
"and #{CemAcpt::Provision::Windows.valid_names.join(', ')}.",
|
138
130
|
"Known versions are: #{CemAcpt::Provision::Linux.valid_versions.join(', ')}",
|
139
|
-
", and #{CemAcpt::Provision::Windows.valid_versions.join(', ')}."
|
131
|
+
", and #{CemAcpt::Provision::Windows.valid_versions.join(', ')}.",
|
140
132
|
].join(' ')
|
141
|
-
logger.error('Terraform') { err_msg }
|
142
133
|
raise ArgumentError, err_msg
|
143
134
|
end
|
144
135
|
end
|
@@ -146,57 +137,55 @@ module CemAcpt
|
|
146
137
|
def new_environment(config)
|
147
138
|
env = (config.get('terraform.environment') || {})
|
148
139
|
env['CLOUDSDK_PYTHON_SITEPACKAGES'] = '1' # This is needed for gcloud to use numpy
|
149
|
-
logger.verbose('Terraform') { "Using environment:\n#{JSON.pretty_generate(env)}" }
|
140
|
+
logger.verbose('CemAcpt::Provision::Terraform') { "Using environment:\n#{JSON.pretty_generate(env)}" }
|
150
141
|
env
|
151
142
|
end
|
152
143
|
|
153
144
|
def new_working_dir
|
154
|
-
logger.debug('Terraform') { 'Creating new working directory' }
|
145
|
+
logger.debug('CemAcpt::Provision::Terraform') { 'Creating new working directory' }
|
155
146
|
base_dir = File.join(@config.get('terraform.dir'), @config.get('platform.name'))
|
156
|
-
logger.verbose('Terraform') { "Base directory defined as #{base_dir}" }
|
147
|
+
logger.verbose('CemAcpt::Provision::Terraform') { "Base directory defined as #{base_dir}" }
|
157
148
|
@backend.base_provision_directory = base_dir
|
158
|
-
logger.verbose('Terraform') { 'Base directory set in backend' }
|
149
|
+
logger.verbose('CemAcpt::Provision::Terraform') { 'Base directory set in backend' }
|
159
150
|
work_dir = File.join(@config.get('terraform.dir'), "test_#{Time.now.to_i}")
|
160
|
-
logger.verbose('Terraform') { "Working directory defined as #{work_dir}" }
|
161
|
-
logger.verbose('Terraform') { "Copying backend provision directory #{@backend.provision_directory} to working directory" }
|
151
|
+
logger.verbose('CemAcpt::Provision::Terraform') { "Working directory defined as #{work_dir}" }
|
152
|
+
logger.verbose('CemAcpt::Provision::Terraform') { "Copying backend provision directory #{@backend.provision_directory} to working directory" }
|
162
153
|
FileUtils.cp_r(@backend.provision_directory, work_dir)
|
163
|
-
logger.verbose('Terraform') { "Copied provision directory #{@backend.provision_directory} to #{work_dir}" }
|
154
|
+
logger.verbose('CemAcpt::Provision::Terraform') { "Copied provision directory #{@backend.provision_directory} to #{work_dir}" }
|
164
155
|
FileUtils.cp(@provision_data[:module_package_path], work_dir)
|
165
156
|
@module_package_path = File.join(work_dir, File.basename(@provision_data[:module_package_path]))
|
166
|
-
logger.verbose('Terraform') { "Copied module package #{@provision_data[:module_package_path]} to #{work_dir}" }
|
157
|
+
logger.verbose('CemAcpt::Provision::Terraform') { "Copied module package #{@provision_data[:module_package_path]} to #{work_dir}" }
|
167
158
|
if File.exist?(@provision_data[:private_key])
|
168
159
|
FileUtils.cp(@provision_data[:private_key], work_dir)
|
169
160
|
@private_key = File.join(work_dir, File.basename(@provision_data[:private_key]))
|
170
|
-
logger.verbose('Terraform') { "Copied private key #{@provision_data[:private_key]} to #{work_dir}" }
|
161
|
+
logger.verbose('CemAcpt::Provision::Terraform') { "Copied private key #{@provision_data[:private_key]} to #{work_dir}" }
|
171
162
|
end
|
172
163
|
if File.exist?(@provision_data[:public_key])
|
173
164
|
FileUtils.cp(@provision_data[:public_key], work_dir)
|
174
165
|
@public_key = File.join(work_dir, File.basename(@provision_data[:public_key]))
|
175
|
-
logger.verbose('Terraform') { "Copied public key #{@provision_data[:public_key]} to #{work_dir}" }
|
166
|
+
logger.verbose('CemAcpt::Provision::Terraform') { "Copied public key #{@provision_data[:public_key]} to #{work_dir}" }
|
176
167
|
end
|
177
168
|
work_dir
|
178
169
|
rescue StandardError => e
|
179
|
-
logger.error('Terraform') { 'Error creating working directory' }
|
170
|
+
logger.error('CemAcpt::Provision::Terraform') { 'Error creating working directory' }
|
180
171
|
raise e
|
181
172
|
end
|
182
173
|
|
183
174
|
def validate_working_dir!
|
184
|
-
logger.debug('Terraform') { "Validating working directory #{working_dir}" }
|
185
|
-
logger.verbose('Terraform') { "Content of #{working_dir}:\n#{Dir.glob(File.join(working_dir, '*')).join("\n")}" }
|
175
|
+
logger.debug('CemAcpt::Provision::Terraform') { "Validating working directory #{working_dir}" }
|
176
|
+
logger.verbose('CemAcpt::Provision::Terraform') { "Content of #{working_dir}:\n#{Dir.glob(File.join(working_dir, '*')).join("\n")}" }
|
186
177
|
raise "Terraform working directory #{working_dir} does not exist" unless File.directory?(working_dir)
|
187
178
|
raise "Terraform working directory #{working_dir} does not contain a Terraform file" unless Dir.glob(File.join(working_dir, '*.tf')).any?
|
188
179
|
|
189
|
-
logger.info('Terraform') { "Using working directory: #{working_dir}" }
|
180
|
+
logger.info('CemAcpt::Provision::Terraform') { "Using working directory: #{working_dir}" }
|
190
181
|
rescue StandardError => e
|
191
|
-
logger.error('Terraform') { 'Error validating working directory' }
|
192
182
|
raise e
|
193
183
|
end
|
194
184
|
|
195
185
|
def save_vars_to_file!(vars)
|
196
|
-
logger.debug('Terraform') { "Saving vars to file #{File.join(working_dir, DEFAULT_VARS_FILE)}" }
|
186
|
+
logger.debug('CemAcpt::Provision::Terraform') { "Saving vars to file #{File.join(working_dir, DEFAULT_VARS_FILE)}" }
|
197
187
|
File.write(File.join(working_dir, DEFAULT_VARS_FILE), vars.to_json)
|
198
188
|
rescue StandardError => e
|
199
|
-
logger.error('Terraform') { 'Error saving vars to file' }
|
200
189
|
raise e
|
201
190
|
end
|
202
191
|
|
@@ -214,7 +203,6 @@ module CemAcpt
|
|
214
203
|
end
|
215
204
|
node_data.to_json
|
216
205
|
rescue StandardError => e
|
217
|
-
logger.error('Terraform') { 'Error creating node data' }
|
218
206
|
raise e
|
219
207
|
end
|
220
208
|
|
@@ -228,7 +216,6 @@ module CemAcpt
|
|
228
216
|
}
|
229
217
|
)
|
230
218
|
rescue StandardError => e
|
231
|
-
logger.error('Terraform') { 'Error creating formatted vars' }
|
232
219
|
raise e
|
233
220
|
end
|
234
221
|
end
|
data/lib/cem_acpt/provision.rb
CHANGED
@@ -10,7 +10,7 @@ module CemAcpt
|
|
10
10
|
def self.new_provisioner(config, provision_data)
|
11
11
|
case config.get('provisioner')
|
12
12
|
when 'terraform'
|
13
|
-
logger.debug('Provision') { 'Using Terraform provisioner' }
|
13
|
+
logger.debug('CemAcpt::Provision') { 'Using Terraform provisioner' }
|
14
14
|
CemAcpt::Provision::Terraform.new(config, provision_data)
|
15
15
|
else
|
16
16
|
raise ArgumentError, "Unknown provisioner #{config.get('provisioner')}"
|
@@ -30,7 +30,7 @@ module CemAcpt
|
|
30
30
|
_metadata = builder.metadata
|
31
31
|
|
32
32
|
# Builds the module package
|
33
|
-
logger.info("Building module package for #{builder.release_name}"
|
33
|
+
logger.info('CemAcpt::PuppetHelpers') { "Building module package for #{builder.release_name}" }
|
34
34
|
builder.build
|
35
35
|
end
|
36
36
|
end
|
data/lib/cem_acpt/test_data.rb
CHANGED
@@ -33,7 +33,7 @@ module CemAcpt
|
|
33
33
|
# Extracts, formats, and returns a test data hash.
|
34
34
|
# @return [Array<Hash>] an array of test data hashes
|
35
35
|
def acceptance_test_data
|
36
|
-
logger.info 'Gathering acceptance test data...'
|
36
|
+
logger.info('CemAcpt::TestData') { 'Gathering acceptance test data...' }
|
37
37
|
raise "No 'tests' entry found in config" unless @config.has?('tests')
|
38
38
|
|
39
39
|
@config.get('tests').each_with_object([]) do |test_name, a|
|
@@ -45,7 +45,7 @@ module CemAcpt
|
|
45
45
|
raise "Goss file not found for test #{test_name}" unless File.exist?(goss_file)
|
46
46
|
raise "Puppet manifest not found for test #{test_name}" unless File.exist?(puppet_manifest)
|
47
47
|
|
48
|
-
logger.debug("Complete test directory found for test #{test_name}: #{test_dir}"
|
48
|
+
logger.debug('CemAcpt::TestData') { "Complete test directory found for test #{test_name}: #{test_dir}" }
|
49
49
|
test_data = {
|
50
50
|
test_name: test_name,
|
51
51
|
test_dir: File.expand_path(test_dir),
|
@@ -71,7 +71,7 @@ module CemAcpt
|
|
71
71
|
@acceptance_tests = acpt_test_dir.children.select { |f| f.directory? && File.exist?(File.join(f, 'goss.yaml')) }.map(&:to_s)
|
72
72
|
raise 'No acceptance tests found' if @acceptance_tests.empty?
|
73
73
|
|
74
|
-
logger.info "Found #{@acceptance_tests.size} acceptance tests"
|
74
|
+
logger.info('CemAcpt') { "Found #{@acceptance_tests.size} acceptance tests" }
|
75
75
|
end
|
76
76
|
|
77
77
|
# Processes a for_each statement in the test data config.
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CemAcpt
|
4
|
+
module TestRunner
|
5
|
+
module LogFormatter
|
6
|
+
class ErrorFormatter
|
7
|
+
def inspect
|
8
|
+
to_s
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
"#<#{self.class.name}:0x#{object_id.to_s(16)}>"
|
13
|
+
end
|
14
|
+
|
15
|
+
def summary(response)
|
16
|
+
"Error: #{response.summary}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def results(response)
|
20
|
+
[response.summary, response.results.join("\n")]
|
21
|
+
end
|
22
|
+
|
23
|
+
def host_name(response)
|
24
|
+
"Error: #{response.error.class.name}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_name(response)
|
28
|
+
"Error: #{response.error.class.name}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,10 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'log_formatter/goss_action_response'
|
4
|
+
require_relative 'log_formatter/error_formatter'
|
4
5
|
|
5
6
|
module CemAcpt
|
6
7
|
module TestRunner
|
7
8
|
# Holds classes for formatting test runner results
|
8
|
-
module LogFormatter
|
9
|
+
module LogFormatter
|
10
|
+
def self.new_formatter(result, *args, **kwargs)
|
11
|
+
if result.error?
|
12
|
+
ErrorFormatter.new
|
13
|
+
else
|
14
|
+
GossActionResponse.new(*args)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
9
18
|
end
|
10
19
|
end
|