hybrid_platforms_conductor 33.0.3 → 33.2.1
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/CHANGELOG.md +54 -0
- data/lib/hybrid_platforms_conductor/cmd_runner.rb +13 -11
- data/lib/hybrid_platforms_conductor/deployer.rb +1 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/local.rb +8 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/log/remote_fs.rb +3 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb +59 -37
- data/lib/hybrid_platforms_conductor/log.rb +3 -0
- data/lib/hybrid_platforms_conductor/topographer.rb +2 -1
- data/lib/hybrid_platforms_conductor/version.rb +1 -1
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/local/remote_actions_spec.rb +66 -0
- data/spec/hybrid_platforms_conductor_test/api/cmd_runner_spec.rb +6 -0
- data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/packaging_spec.rb +48 -2
- data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/services_deployment_spec.rb +92 -15
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f311db8004c9c9bce51821d58c9cee66e36b73565a70e990d5d56269a758ef07
|
|
4
|
+
data.tar.gz: 232be58c9d26f1821afea89a55421514c8f97becd2b316acf62c2e51c5e29b8c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d2c2fe3c9d0f5fccceb5a2a2b9759316730c536a5de99e63b5ecc32ef857b4f33a5aef5c4494c4b42f54a1b17a620af7a06526a953a095a8ac3e8fdc7d6fcd8e
|
|
7
|
+
data.tar.gz: 6d15f57eae1683425b64871b0234a33a6a98cf3300a3c481d98b88a525809c8ad277836a228565675b5bcd76bc23a130b5392431a045bbe18ec6cd032eeea27d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,57 @@
|
|
|
1
|
+
# [v33.2.1](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.2.0...v33.2.1) (2021-06-21 10:23:51)
|
|
2
|
+
|
|
3
|
+
## Global changes
|
|
4
|
+
### Patches
|
|
5
|
+
|
|
6
|
+
* [[Hotfix(platform_handler_serverless_chef)] Corrected dry-run mode not working](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/4800a0f4255c1999eed33651c1e66c445acd17bb)
|
|
7
|
+
|
|
8
|
+
## Changes for platform_handler_serverless_chef
|
|
9
|
+
### Patches
|
|
10
|
+
|
|
11
|
+
* [[Hotfix(platform_handler_serverless_chef)] Corrected dry-run mode not working](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/4800a0f4255c1999eed33651c1e66c445acd17bb)
|
|
12
|
+
|
|
13
|
+
# [v33.2.0](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.1.1...v33.2.0) (2021-06-18 23:22:21)
|
|
14
|
+
|
|
15
|
+
## Global changes
|
|
16
|
+
### Patches
|
|
17
|
+
|
|
18
|
+
* [[Feature(platform_handler_serverless_chef)] [#70] Install dependency gems from cookbook metadata before calling chef-client](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/6dfe7aa053db63489f3d0a236433304606051ecd)
|
|
19
|
+
|
|
20
|
+
## Changes for platform_handler_serverless_chef
|
|
21
|
+
### Features
|
|
22
|
+
|
|
23
|
+
* [[Feature(platform_handler_serverless_chef)] [#70] Install dependency gems from cookbook metadata before calling chef-client](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/6dfe7aa053db63489f3d0a236433304606051ecd)
|
|
24
|
+
|
|
25
|
+
# [v33.1.1](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.1.0...v33.1.1) (2021-06-18 13:19:39)
|
|
26
|
+
|
|
27
|
+
### Patches
|
|
28
|
+
|
|
29
|
+
* [[Fix] Corrected bugs on log remote_fs plugin not working in dry-run and topographer](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/90dcde919b6fc99b8f79fc642fef8b4150a5a9d6)
|
|
30
|
+
|
|
31
|
+
# [v33.1.0](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.0.4...v33.1.0) (2021-06-18 11:37:28)
|
|
32
|
+
|
|
33
|
+
## Global changes
|
|
34
|
+
### Patches
|
|
35
|
+
|
|
36
|
+
* [[Feature(connector_local)] [#68] Add sudo support when copying files using the local connector](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/7725beca4429de0e81bcac0c0ac4fe149e625da2)
|
|
37
|
+
|
|
38
|
+
## Changes for connector_local
|
|
39
|
+
### Features
|
|
40
|
+
|
|
41
|
+
* [[Feature(connector_local)] [#68] Add sudo support when copying files using the local connector](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/7725beca4429de0e81bcac0c0ac4fe149e625da2)
|
|
42
|
+
|
|
43
|
+
# [v33.0.4](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.0.3...v33.0.4) (2021-06-18 10:09:57)
|
|
44
|
+
|
|
45
|
+
## Global changes
|
|
46
|
+
### Patches
|
|
47
|
+
|
|
48
|
+
* [[Fix(cmd_runner)] [#69] Make sure commands are run in unbundled env](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/0795c1ffdcf1b355c9dc91423bb6b7d88918fcf7)
|
|
49
|
+
|
|
50
|
+
## Changes for cmd_runner
|
|
51
|
+
### Patches
|
|
52
|
+
|
|
53
|
+
* [[Fix(cmd_runner)] [#69] Make sure commands are run in unbundled env](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/0795c1ffdcf1b355c9dc91423bb6b7d88918fcf7)
|
|
54
|
+
|
|
1
55
|
# [v33.0.3](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.0.2...v33.0.3) (2021-06-17 12:42:32)
|
|
2
56
|
|
|
3
57
|
### Patches
|
|
@@ -130,18 +130,20 @@ module HybridPlatformsConductor
|
|
|
130
130
|
(log_to_stdout ? [@logger_stderr] : []) +
|
|
131
131
|
(file_output.nil? ? [] : [file_output])
|
|
132
132
|
) do
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
133
|
+
Bundler.with_unbundled_env do
|
|
134
|
+
cmd_result = TTY::Command.new(
|
|
135
|
+
printer: :null,
|
|
136
|
+
pty: true,
|
|
137
|
+
timeout: timeout,
|
|
138
|
+
uuid: false
|
|
139
|
+
).run!(cmd) do |stdout, stderr|
|
|
140
|
+
stdout_queue << stdout if stdout
|
|
141
|
+
stderr_queue << stderr if stderr
|
|
142
|
+
end
|
|
143
|
+
exit_status = cmd_result.exit_status
|
|
144
|
+
cmd_stdout = cmd_result.out
|
|
145
|
+
cmd_stderr = cmd_result.err
|
|
141
146
|
end
|
|
142
|
-
exit_status = cmd_result.exit_status
|
|
143
|
-
cmd_stdout = cmd_result.out
|
|
144
|
-
cmd_stderr = cmd_result.err
|
|
145
147
|
end
|
|
146
148
|
rescue TTY::Command::TimeoutExceeded
|
|
147
149
|
exit_status = :timeout
|
|
@@ -50,7 +50,9 @@ module HybridPlatformsConductor
|
|
|
50
50
|
# [API] - @stdout_io can be used to send stdout output
|
|
51
51
|
# [API] - @stderr_io can be used to send stderr output
|
|
52
52
|
def remote_interactive
|
|
53
|
-
|
|
53
|
+
Bundler.with_unbundled_env do
|
|
54
|
+
system "cd #{workspace_for(@node)} ; /bin/bash"
|
|
55
|
+
end
|
|
54
56
|
end
|
|
55
57
|
|
|
56
58
|
# rubocop:disable Lint/UnusedMethodArgument
|
|
@@ -73,7 +75,11 @@ module HybridPlatformsConductor
|
|
|
73
75
|
def remote_copy(from, to, sudo: false, owner: nil, group: nil)
|
|
74
76
|
# If the destination is a relative path, prepend the workspace dir to it.
|
|
75
77
|
to = "#{workspace_for(@node)}/#{to}" unless to.start_with?('/')
|
|
76
|
-
|
|
78
|
+
if sudo
|
|
79
|
+
run_cmd "#{@nodes_handler.sudo_on(@node)} cp -r \"#{from}\" \"#{to}\""
|
|
80
|
+
else
|
|
81
|
+
FileUtils.cp_r from, to unless @cmd_runner.dry_run
|
|
82
|
+
end
|
|
77
83
|
end
|
|
78
84
|
# rubocop:enable Lint/UnusedMethodArgument
|
|
79
85
|
|
|
@@ -121,7 +121,9 @@ module HybridPlatformsConductor
|
|
|
121
121
|
# ...
|
|
122
122
|
# ===== STDERR =====
|
|
123
123
|
# ...
|
|
124
|
-
if
|
|
124
|
+
if @cmd_runner.dry_run
|
|
125
|
+
{ error: 'No log to show in dry-run mode' }
|
|
126
|
+
elsif exit_status.is_a?(Symbol)
|
|
125
127
|
{ error: "Error: #{exit_status}\n#{stderr}" }
|
|
126
128
|
else
|
|
127
129
|
stdout_lines = stdout.split("\n")
|
|
@@ -74,18 +74,16 @@ module HybridPlatformsConductor
|
|
|
74
74
|
# [API] - @cmd_runner is accessible.
|
|
75
75
|
def setup
|
|
76
76
|
required_version = YAML.load_file("#{@repository_path}/chef_versions.yml")['workstation']
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
@cmd_runner.run_cmd "curl -L https://omnitruck.chef.io/install.sh | #{@cmd_runner.root? ? '' : 'sudo '}bash -s -- -P chef-workstation -v #{required_version}" unless existing_version == required_version
|
|
88
|
-
end
|
|
77
|
+
exit_status, stdout, _stderr = @cmd_runner.run_cmd '/opt/chef-workstation/bin/chef --version', expected_code: [0, :command_error]
|
|
78
|
+
existing_version =
|
|
79
|
+
if exit_status == :command_error
|
|
80
|
+
'not installed'
|
|
81
|
+
else
|
|
82
|
+
expected_match = stdout.match(/^Chef Workstation version: (.+)\.\d+$/)
|
|
83
|
+
expected_match.nil? ? 'unreadable' : expected_match[1]
|
|
84
|
+
end
|
|
85
|
+
log_debug "Current Chef version: #{existing_version}. Required version: #{required_version}"
|
|
86
|
+
@cmd_runner.run_cmd "curl -L https://omnitruck.chef.io/install.sh | #{@cmd_runner.root? ? '' : 'sudo '}bash -s -- -P chef-workstation -v #{required_version}" unless existing_version == required_version
|
|
89
87
|
end
|
|
90
88
|
|
|
91
89
|
# Get the list of known nodes.
|
|
@@ -160,29 +158,34 @@ module HybridPlatformsConductor
|
|
|
160
158
|
current_package_info = File.exist?(package_info_file) ? JSON.parse(File.read(package_info_file)).transform_keys(&:to_sym) : {}
|
|
161
159
|
next if current_package_info == package_info
|
|
162
160
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
policy_file = local_policy_file
|
|
175
|
-
end
|
|
176
|
-
lock_file = "#{File.dirname(policy_file)}/#{File.basename(policy_file, '.rb')}.lock.json"
|
|
177
|
-
# If the policy lock file does not exist, generate it
|
|
178
|
-
@cmd_runner.run_cmd "cd #{@repository_path} && /opt/chef-workstation/bin/chef install #{policy_file} --chef-license accept" unless File.exist?("#{@repository_path}/#{lock_file}")
|
|
179
|
-
extra_cp_data_bags = File.exist?("#{@repository_path}/data_bags") ? " && cp -ar data_bags/ #{package_dir}/" : ''
|
|
180
|
-
@cmd_runner.run_cmd "cd #{@repository_path} && \
|
|
181
|
-
#{@cmd_runner.root? ? '' : 'sudo '}rm -rf #{package_dir} && \
|
|
182
|
-
/opt/chef-workstation/bin/chef export #{policy_file} #{package_dir} --chef-license accept#{extra_cp_data_bags}"
|
|
161
|
+
policy_file = "policyfiles/#{service}.rb"
|
|
162
|
+
if local_environment
|
|
163
|
+
local_policy_file = "policyfiles/#{service}.local.rb"
|
|
164
|
+
# In local mode, we always regenerate the lock file as we may modify the run list
|
|
165
|
+
run_list = known_cookbook_paths.any? { |cookbook_path| File.exist?("#{@repository_path}/#{cookbook_path}/hpc_test/recipes/before_run.rb") } ? ['hpc_test::before_run'] : []
|
|
166
|
+
dsl_parser = DslParser.new
|
|
167
|
+
dsl_parser.parse("#{@repository_path}/#{policy_file}")
|
|
168
|
+
run_list.concat dsl_parser.calls.find { |call_info| call_info[:method] == :run_list }[:args].flatten
|
|
169
|
+
run_list << 'hpc_test::after_run' if known_cookbook_paths.any? { |cookbook_path| File.exist?("#{@repository_path}/#{cookbook_path}/hpc_test/recipes/after_run.rb") }
|
|
170
|
+
File.write("#{@repository_path}/#{local_policy_file}", File.read("#{@repository_path}/#{policy_file}") + "\nrun_list #{run_list.map { |recipe| "'#{recipe}'" }.join(', ')}\n")
|
|
171
|
+
policy_file = local_policy_file
|
|
183
172
|
end
|
|
173
|
+
lock_file = "#{File.dirname(policy_file)}/#{File.basename(policy_file, '.rb')}.lock.json"
|
|
174
|
+
# If the policy lock file does not exist, generate it
|
|
175
|
+
@cmd_runner.run_cmd "cd #{@repository_path} && /opt/chef-workstation/bin/chef install #{policy_file} --chef-license accept" unless File.exist?("#{@repository_path}/#{lock_file}")
|
|
176
|
+
extra_cp_data_bags = File.exist?("#{@repository_path}/data_bags") ? " && cp -ar data_bags/ #{package_dir}/" : ''
|
|
177
|
+
@cmd_runner.run_cmd "cd #{@repository_path} && \
|
|
178
|
+
#{@cmd_runner.root? ? '' : 'sudo '}rm -rf #{package_dir} && \
|
|
179
|
+
/opt/chef-workstation/bin/chef export #{policy_file} #{package_dir} --chef-license accept#{extra_cp_data_bags}"
|
|
184
180
|
next if @cmd_runner.dry_run
|
|
185
181
|
|
|
182
|
+
# Write the list of gems to be installed for this package
|
|
183
|
+
File.write(
|
|
184
|
+
"#{@repository_path}/#{package_dir}/gems.json",
|
|
185
|
+
Dir.glob("#{@repository_path}/#{package_dir}/cookbook_artifacts/*/metadata.json").map do |metadata|
|
|
186
|
+
JSON.parse(File.read(metadata))['gems']
|
|
187
|
+
end.flatten(1).to_json
|
|
188
|
+
)
|
|
186
189
|
# Create secrets file
|
|
187
190
|
secrets_file = "#{@repository_path}/#{package_dir}/data_bags/hpc_secrets/hpc_secrets.json"
|
|
188
191
|
FileUtils.mkdir_p(File.dirname(secrets_file))
|
|
@@ -224,10 +227,13 @@ module HybridPlatformsConductor
|
|
|
224
227
|
# * Array< Hash<Symbol,Object> >: List of actions to be done
|
|
225
228
|
def actions_to_deploy_on(node, service, use_why_run: true)
|
|
226
229
|
package_dir = "#{@repository_path}/dist/#{@local_env ? 'local' : 'prod'}/#{service}"
|
|
230
|
+
gems_to_install = []
|
|
227
231
|
# Generate the nodes attributes file
|
|
228
232
|
unless @cmd_runner.dry_run
|
|
229
233
|
FileUtils.mkdir_p "#{package_dir}/nodes"
|
|
230
234
|
File.write("#{package_dir}/nodes/#{node}.json", (known_nodes.include?(node) ? metadata_for(node) : {}).merge(@nodes_handler.metadata_of(node)).to_json)
|
|
235
|
+
# Get the gems to be installed
|
|
236
|
+
gems_to_install = JSON.parse(File.read("#{package_dir}/gems.json"))
|
|
231
237
|
end
|
|
232
238
|
client_options = [
|
|
233
239
|
'--local-mode',
|
|
@@ -237,7 +243,19 @@ module HybridPlatformsConductor
|
|
|
237
243
|
client_options << '--why-run' if use_why_run
|
|
238
244
|
if @nodes_handler.get_use_local_chef_of(node)
|
|
239
245
|
# Just run the chef-client directly from the packaged repository
|
|
240
|
-
|
|
246
|
+
sudo_prefix = @cmd_runner.root? ? '' : 'sudo '
|
|
247
|
+
[
|
|
248
|
+
{
|
|
249
|
+
bash: [
|
|
250
|
+
'set -e',
|
|
251
|
+
"cd #{package_dir}"
|
|
252
|
+
] +
|
|
253
|
+
gems_to_install.map { |(gem_name, gem_version)| "#{sudo_prefix}SSL_CERT_DIR=/etc/ssl/certs /opt/chef-workstation/bin/chef gem install #{gem_name} --version \"#{gem_version}\"" } +
|
|
254
|
+
[
|
|
255
|
+
"#{sudo_prefix}SSL_CERT_DIR=/etc/ssl/certs /opt/chef-workstation/bin/chef-client #{client_options.join(' ')}"
|
|
256
|
+
]
|
|
257
|
+
}
|
|
258
|
+
]
|
|
241
259
|
else
|
|
242
260
|
# Upload the package and run it from the node
|
|
243
261
|
package_name = File.basename(package_dir)
|
|
@@ -265,10 +283,14 @@ module HybridPlatformsConductor
|
|
|
265
283
|
scp: { package_dir => './hpc_deploy' },
|
|
266
284
|
remote_bash: [
|
|
267
285
|
'set -e',
|
|
268
|
-
"cd ./hpc_deploy/#{package_name}"
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
286
|
+
"cd ./hpc_deploy/#{package_name}"
|
|
287
|
+
] +
|
|
288
|
+
gems_to_install.map { |(gem_name, gem_version)| "#{sudo}SSL_CERT_DIR=/etc/ssl/certs /opt/chef/embedded/bin/gem install #{gem_name} --version \"#{gem_version}\"" } +
|
|
289
|
+
[
|
|
290
|
+
"#{sudo}SSL_CERT_DIR=/etc/ssl/certs /opt/chef/bin/chef-client #{client_options.join(' ')}",
|
|
291
|
+
'cd ..'
|
|
292
|
+
] +
|
|
293
|
+
(log_debug? ? [] : ["#{sudo}rm -rf ./hpc_deploy/#{package_name}"])
|
|
272
294
|
}
|
|
273
295
|
]
|
|
274
296
|
end
|
|
@@ -12,16 +12,19 @@ module HybridPlatformsConductor
|
|
|
12
12
|
# * *logger* (Logger): Logger to be used [default: Logger.new(STDOUT)]
|
|
13
13
|
# * *logger_stderr* (Logger): Logger to be used for stderr [default: Logger.new(STDERR)]
|
|
14
14
|
# * *config* (Config): Config to be used. [default: Config.new]
|
|
15
|
+
# * *cmd_runner* (CmdRunner): CmdRunner to be used [default: CmdRunner.new]
|
|
15
16
|
# * *nodes_handler* (NodesHandler): Nodes handler to be used. [default: NodesHandler.new]
|
|
16
17
|
# * *actions_executor* (ActionsExecutor): Actions executor to be used. [default: ActionsExecutor.new]
|
|
17
18
|
def initialize(
|
|
18
19
|
logger: Logger.new($stdout),
|
|
19
20
|
logger_stderr: Logger.new($stderr),
|
|
20
21
|
config: Config.new,
|
|
22
|
+
cmd_runner: CmdRunner.new,
|
|
21
23
|
nodes_handler: NodesHandler.new,
|
|
22
24
|
actions_executor: ActionsExecutor.new
|
|
23
25
|
)
|
|
24
26
|
super(logger: logger, logger_stderr: logger_stderr, config: config)
|
|
27
|
+
@cmd_runner = cmd_runner
|
|
25
28
|
@nodes_handler = nodes_handler
|
|
26
29
|
@actions_executor = actions_executor
|
|
27
30
|
end
|
|
@@ -304,7 +304,8 @@ module HybridPlatformsConductor
|
|
|
304
304
|
|
|
305
305
|
# Define clusters of ips with 24 bits ranges.
|
|
306
306
|
def define_clusters_ip_24
|
|
307
|
-
|
|
307
|
+
# Clone keys as we modify the hash in the loop
|
|
308
|
+
@nodes_graph.keys.clone.each do |node_name|
|
|
308
309
|
next unless @nodes_graph[node_name][:type] == :node && !@node_metadata[node_name][:private_ips].nil? && !@node_metadata[node_name][:private_ips].empty?
|
|
309
310
|
|
|
310
311
|
ip_24 = "#{@node_metadata[node_name][:private_ips].first.split('.')[0..2].join('.')}.0/24"
|
|
@@ -87,6 +87,43 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
|
87
87
|
end
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
+
it 'does not copy files remotely in dry-run mode' do
|
|
91
|
+
with_test_platform_for_remote_testing do
|
|
92
|
+
test_cmd_runner.dry_run = true
|
|
93
|
+
expect(FileUtils).not_to receive(:cp_r)
|
|
94
|
+
test_connector.remote_copy('/path/to/src.file', '/remote_path/to/dst.dir')
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it 'copies files remotely with sudo' do
|
|
99
|
+
with_test_platform_for_remote_testing(
|
|
100
|
+
expected_cmds: [
|
|
101
|
+
[
|
|
102
|
+
'sudo -u root cp -r "/path/to/src.file" "/remote_path/to/dst.dir"',
|
|
103
|
+
proc { [0, '', ''] }
|
|
104
|
+
]
|
|
105
|
+
]
|
|
106
|
+
) do
|
|
107
|
+
test_connector.remote_copy('/path/to/src.file', '/remote_path/to/dst.dir', sudo: true)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it 'copies files remotely with a different sudo' do
|
|
112
|
+
with_test_platform_for_remote_testing(
|
|
113
|
+
expected_cmds: [
|
|
114
|
+
[
|
|
115
|
+
'other_sudo --user root cp -r "/path/to/src.file" "/remote_path/to/dst.dir"',
|
|
116
|
+
proc { [0, '', ''] }
|
|
117
|
+
]
|
|
118
|
+
],
|
|
119
|
+
additional_config: <<~'EO_CONFIG'
|
|
120
|
+
sudo_for { |user| "other_sudo --user #{user}" }
|
|
121
|
+
EO_CONFIG
|
|
122
|
+
) do
|
|
123
|
+
test_connector.remote_copy('/path/to/src.file', '/remote_path/to/dst.dir', sudo: true)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
90
127
|
it 'copies files remotely with timeout' do
|
|
91
128
|
with_test_platform_for_remote_testing(
|
|
92
129
|
timeout: 5
|
|
@@ -103,6 +140,35 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
|
103
140
|
end
|
|
104
141
|
end
|
|
105
142
|
|
|
143
|
+
it 'copies relative files remotely with sudo' do
|
|
144
|
+
with_test_platform_for_remote_testing(
|
|
145
|
+
expected_cmds: [
|
|
146
|
+
[
|
|
147
|
+
'sudo -u root cp -r "/path/to/src.file" "/tmp/hpc_local_workspaces/node/to/dst.dir"',
|
|
148
|
+
proc { [0, '', ''] }
|
|
149
|
+
]
|
|
150
|
+
]
|
|
151
|
+
) do
|
|
152
|
+
test_connector.remote_copy('/path/to/src.file', 'to/dst.dir', sudo: true)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
it 'copies relative files remotely with a different sudo' do
|
|
157
|
+
with_test_platform_for_remote_testing(
|
|
158
|
+
expected_cmds: [
|
|
159
|
+
[
|
|
160
|
+
'other_sudo --user root cp -r "/path/to/src.file" "/tmp/hpc_local_workspaces/node/to/dst.dir"',
|
|
161
|
+
proc { [0, '', ''] }
|
|
162
|
+
]
|
|
163
|
+
],
|
|
164
|
+
additional_config: <<~'EO_CONFIG'
|
|
165
|
+
sudo_for { |user| "other_sudo --user #{user}" }
|
|
166
|
+
EO_CONFIG
|
|
167
|
+
) do
|
|
168
|
+
test_connector.remote_copy('/path/to/src.file', 'to/dst.dir', sudo: true)
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
106
172
|
end
|
|
107
173
|
|
|
108
174
|
end
|
|
@@ -45,6 +45,12 @@ describe HybridPlatformsConductor::CmdRunner do
|
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
it 'runs a command in an un-bundled environment' do
|
|
49
|
+
with_repository do
|
|
50
|
+
expect(test_cmd_runner.run_cmd('echo "${BUNDLE_GEMFILE}"')).to eq [0, "\n", '']
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
48
54
|
it 'fails when the command does not exit 0' do
|
|
49
55
|
with_repository do
|
|
50
56
|
expect { test_cmd_runner.run_cmd 'exit 1' }.to raise_error(HybridPlatformsConductor::CmdRunner::UnexpectedExitCodeError, 'Command \'exit 1\' returned error code 1 (expected 0).')
|
data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/packaging_spec.rb
CHANGED
|
@@ -12,6 +12,7 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
|
12
12
|
# * *export* (Boolean): Are we expecting the chef export stage? [default: true]
|
|
13
13
|
# * *data_bags* (Boolean): Do we expect data bags copy? [default: false]
|
|
14
14
|
# * *env* (String): Expected environment being packaged [default: 'prod']
|
|
15
|
+
# * *cookbook_metadata* (Hash<String, Hash>): JSON metadata to generate for packaged cookbooks [default: {}]
|
|
15
16
|
# * *block* (Proc): Code called with mock in place
|
|
16
17
|
def with_packaging_mocked(
|
|
17
18
|
repository,
|
|
@@ -21,6 +22,7 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
|
21
22
|
export: true,
|
|
22
23
|
data_bags: false,
|
|
23
24
|
env: 'prod',
|
|
25
|
+
cookbook_metadata: {},
|
|
24
26
|
&block
|
|
25
27
|
)
|
|
26
28
|
with_cmd_runner_mocked(
|
|
@@ -49,8 +51,14 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
|
49
51
|
[
|
|
50
52
|
%r{^cd #{Regexp.escape(repository)} &&\s+sudo rm -rf dist/#{Regexp.escape(env)}/#{Regexp.escape(policy)} &&\s+/opt/chef-workstation/bin/chef export #{Regexp.escape(policy_file)} dist/#{Regexp.escape(env)}/#{Regexp.escape(policy)} --chef-license accept#{data_bags ? " && cp -ar data_bags/ dist/#{Regexp.escape(env)}/#{Regexp.escape(policy)}/" : ''}$},
|
|
51
53
|
proc do
|
|
52
|
-
|
|
53
|
-
FileUtils.
|
|
54
|
+
package_dir = "#{repository}/dist/#{env}/#{policy}"
|
|
55
|
+
FileUtils.mkdir_p package_dir
|
|
56
|
+
FileUtils.cp_r("#{repository}/data_bags", "#{package_dir}/") if data_bags
|
|
57
|
+
cookbook_metadata.each do |cookbook, metadata|
|
|
58
|
+
metadata_file = "#{package_dir}/cookbook_artifacts/#{cookbook}/metadata.json"
|
|
59
|
+
FileUtils.mkdir_p File.dirname(metadata_file)
|
|
60
|
+
File.write(metadata_file, metadata.to_json)
|
|
61
|
+
end
|
|
54
62
|
[0, 'Chef export done', '']
|
|
55
63
|
end
|
|
56
64
|
]
|
|
@@ -80,6 +88,9 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
|
80
88
|
with_serverless_chef_platforms('1_node') do |platform, repository|
|
|
81
89
|
with_packaging_mocked(repository) do
|
|
82
90
|
platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
|
|
91
|
+
gems_file = "#{repository}/dist/prod/test_policy/gems.json"
|
|
92
|
+
expect(File.exist?(gems_file)).to eq true
|
|
93
|
+
expect(JSON.parse(File.read(gems_file))).to eq []
|
|
83
94
|
end
|
|
84
95
|
end
|
|
85
96
|
end
|
|
@@ -212,6 +223,41 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
|
212
223
|
|
|
213
224
|
end
|
|
214
225
|
|
|
226
|
+
context 'with a platform having several cookbooks' do
|
|
227
|
+
|
|
228
|
+
it 'generates the gems info to be installed' do
|
|
229
|
+
with_serverless_chef_platforms('several_cookbooks') do |platform, repository|
|
|
230
|
+
with_packaging_mocked(
|
|
231
|
+
repository,
|
|
232
|
+
policy: 'test_policy_1',
|
|
233
|
+
cookbook_metadata: {
|
|
234
|
+
'test_cookbook_1' => {
|
|
235
|
+
gems: [
|
|
236
|
+
['my_gem_1', '0.0.1'],
|
|
237
|
+
['my_gem_2', '0.0.2']
|
|
238
|
+
]
|
|
239
|
+
},
|
|
240
|
+
'dependency_cookbook' => {
|
|
241
|
+
gems: [
|
|
242
|
+
['my_gem_3', '~> 1.3']
|
|
243
|
+
]
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
) do
|
|
247
|
+
platform.package(services: { 'node1' => %w[test_policy_1] }, secrets: {}, local_environment: false)
|
|
248
|
+
gems_file = "#{repository}/dist/prod/test_policy_1/gems.json"
|
|
249
|
+
expect(File.exist?(gems_file)).to eq true
|
|
250
|
+
expect(JSON.parse(File.read(gems_file)).sort).to eq [
|
|
251
|
+
['my_gem_1', '0.0.1'],
|
|
252
|
+
['my_gem_2', '0.0.2'],
|
|
253
|
+
['my_gem_3', '~> 1.3']
|
|
254
|
+
].sort
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
end
|
|
260
|
+
|
|
215
261
|
context 'with a platform having data bags' do
|
|
216
262
|
|
|
217
263
|
it 'packages data bags' do
|
|
@@ -6,9 +6,18 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
|
6
6
|
#
|
|
7
7
|
# Parameters::
|
|
8
8
|
# * *repository* (String): The repository we package
|
|
9
|
+
# * *env* (String): The environment for which this repository is packaged [default: 'prod']
|
|
9
10
|
# * *service* (String): The service being packaged in this repository [default: 'test_policy']
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
# * *gems* (Array<String, String>): The [<name>, <version>] gems info to be installed as generated by the packaging [default: []]
|
|
12
|
+
def mock_package(
|
|
13
|
+
repository,
|
|
14
|
+
env: 'prod',
|
|
15
|
+
service: 'test_policy',
|
|
16
|
+
gems: []
|
|
17
|
+
)
|
|
18
|
+
package_dir = "#{repository}/dist/#{env}/#{service}"
|
|
19
|
+
FileUtils.mkdir_p package_dir
|
|
20
|
+
File.write("#{package_dir}/gems.json", gems.to_json)
|
|
12
21
|
end
|
|
13
22
|
|
|
14
23
|
# Get expected actions to deploy a service on a given node
|
|
@@ -20,6 +29,7 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
|
20
29
|
# * *env* (String): Environment expected to be packaged [default: 'prod']
|
|
21
30
|
# * *policy* (String): Expected policy to be packaged [default: 'test_policy']
|
|
22
31
|
# * *node* (String): Expected node to be deployed [default: 'node']
|
|
32
|
+
# * *gems_install_cmds* (Array<String>): Expected gem install commands [default: []]
|
|
23
33
|
# Result::
|
|
24
34
|
# * Array: Expected actions
|
|
25
35
|
def expected_actions_to_deploy_chef(
|
|
@@ -28,7 +38,8 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
|
28
38
|
sudo: 'sudo -u root ',
|
|
29
39
|
env: 'prod',
|
|
30
40
|
policy: 'test_policy',
|
|
31
|
-
node: 'node'
|
|
41
|
+
node: 'node',
|
|
42
|
+
gems_install_cmds: []
|
|
32
43
|
)
|
|
33
44
|
[
|
|
34
45
|
{
|
|
@@ -48,11 +59,14 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
|
48
59
|
scp: { "#{repository}/dist/#{env}/#{policy}" => './hpc_deploy' },
|
|
49
60
|
remote_bash: [
|
|
50
61
|
'set -e',
|
|
51
|
-
"cd ./hpc_deploy/#{policy}"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
62
|
+
"cd ./hpc_deploy/#{policy}"
|
|
63
|
+
] +
|
|
64
|
+
gems_install_cmds.map { |gem_install_cmd| "#{sudo}SSL_CERT_DIR=/etc/ssl/certs /opt/chef/embedded/bin/#{gem_install_cmd}" } +
|
|
65
|
+
[
|
|
66
|
+
"#{sudo}SSL_CERT_DIR=/etc/ssl/certs /opt/chef/bin/chef-client --local-mode --chef-license accept --json-attributes nodes/#{node}.json#{check_mode ? ' --why-run' : ''}",
|
|
67
|
+
'cd ..',
|
|
68
|
+
"#{sudo}rm -rf ./hpc_deploy/#{policy}"
|
|
69
|
+
]
|
|
56
70
|
}
|
|
57
71
|
]
|
|
58
72
|
end
|
|
@@ -109,6 +123,33 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
|
109
123
|
end
|
|
110
124
|
end
|
|
111
125
|
|
|
126
|
+
it 'returns actions to deploy on this node with gems to be installed' do
|
|
127
|
+
with_serverless_chef_platforms('1_node') do |platform, repository|
|
|
128
|
+
mock_package(
|
|
129
|
+
repository,
|
|
130
|
+
gems: [
|
|
131
|
+
['my_gem_1', '0.0.1'],
|
|
132
|
+
['my_gem_2', '0.0.2'],
|
|
133
|
+
['my_gem_3', '~> 1.3']
|
|
134
|
+
]
|
|
135
|
+
)
|
|
136
|
+
platform.prepare_for_deploy(
|
|
137
|
+
services: { 'node' => %w[test_policy] },
|
|
138
|
+
secrets: {},
|
|
139
|
+
local_environment: false,
|
|
140
|
+
why_run: false
|
|
141
|
+
)
|
|
142
|
+
expect(platform.actions_to_deploy_on('node', 'test_policy', use_why_run: false)).to eq expected_actions_to_deploy_chef(
|
|
143
|
+
repository,
|
|
144
|
+
gems_install_cmds: [
|
|
145
|
+
'gem install my_gem_1 --version "0.0.1"',
|
|
146
|
+
'gem install my_gem_2 --version "0.0.2"',
|
|
147
|
+
'gem install my_gem_3 --version "~> 1.3"'
|
|
148
|
+
]
|
|
149
|
+
)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
112
153
|
it 'returns actions to deploy on this node with node attributes setup from metadata' do
|
|
113
154
|
with_serverless_chef_platforms('1_node') do |platform, repository|
|
|
114
155
|
test_nodes_handler.override_metadata_of 'node', :new_metadata, 'new_value'
|
|
@@ -161,7 +202,7 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
|
161
202
|
|
|
162
203
|
it 'returns actions to deploy on this node using local mode' do
|
|
163
204
|
with_serverless_chef_platforms('1_node') do |platform, repository|
|
|
164
|
-
mock_package(repository)
|
|
205
|
+
mock_package(repository, env: 'local')
|
|
165
206
|
platform.prepare_for_deploy(
|
|
166
207
|
services: { 'node' => %w[test_policy] },
|
|
167
208
|
secrets: {},
|
|
@@ -174,7 +215,7 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
|
174
215
|
|
|
175
216
|
it 'returns actions to deploy on this node in why-run mode and local mode' do
|
|
176
217
|
with_serverless_chef_platforms('1_node') do |platform, repository|
|
|
177
|
-
mock_package(repository)
|
|
218
|
+
mock_package(repository, env: 'local')
|
|
178
219
|
platform.prepare_for_deploy(
|
|
179
220
|
services: { 'node' => %w[test_policy] },
|
|
180
221
|
secrets: {},
|
|
@@ -219,7 +260,7 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
|
219
260
|
|
|
220
261
|
it 'deploys services declared on 1 node on another node if asked' do
|
|
221
262
|
with_serverless_chef_platforms('several_nodes') do |platform, repository|
|
|
222
|
-
mock_package(repository)
|
|
263
|
+
mock_package(repository, service: 'test_policy_1')
|
|
223
264
|
platform.prepare_for_deploy(
|
|
224
265
|
services: { 'node2' => %w[test_policy_1] },
|
|
225
266
|
secrets: {},
|
|
@@ -230,9 +271,38 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
|
230
271
|
end
|
|
231
272
|
end
|
|
232
273
|
|
|
233
|
-
it 'deploys local
|
|
274
|
+
it 'deploys using the local chef workstation when use_local_chef is set' do
|
|
234
275
|
with_serverless_chef_platforms('several_nodes') do |platform, repository|
|
|
235
|
-
mock_package(repository)
|
|
276
|
+
mock_package(repository, service: 'test_policy_1')
|
|
277
|
+
platform.prepare_for_deploy(
|
|
278
|
+
services: { 'local' => %w[test_policy_1] },
|
|
279
|
+
secrets: {},
|
|
280
|
+
local_environment: false,
|
|
281
|
+
why_run: false
|
|
282
|
+
)
|
|
283
|
+
expect(platform.actions_to_deploy_on('local', 'test_policy_1', use_why_run: false)).to eq [
|
|
284
|
+
{
|
|
285
|
+
bash: [
|
|
286
|
+
'set -e',
|
|
287
|
+
"cd #{repository}/dist/prod/test_policy_1",
|
|
288
|
+
'sudo SSL_CERT_DIR=/etc/ssl/certs /opt/chef-workstation/bin/chef-client --local-mode --chef-license accept --json-attributes nodes/local.json'
|
|
289
|
+
]
|
|
290
|
+
}
|
|
291
|
+
]
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
it 'deploys using the local chef workstation with gems to be installed when use_local_chef is set' do
|
|
296
|
+
with_serverless_chef_platforms('several_nodes') do |platform, repository|
|
|
297
|
+
mock_package(
|
|
298
|
+
repository,
|
|
299
|
+
service: 'test_policy_1',
|
|
300
|
+
gems: [
|
|
301
|
+
['my_gem_1', '0.0.1'],
|
|
302
|
+
['my_gem_2', '0.0.2'],
|
|
303
|
+
['my_gem_3', '~> 1.3']
|
|
304
|
+
]
|
|
305
|
+
)
|
|
236
306
|
platform.prepare_for_deploy(
|
|
237
307
|
services: { 'local' => %w[test_policy_1] },
|
|
238
308
|
secrets: {},
|
|
@@ -241,7 +311,14 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
|
241
311
|
)
|
|
242
312
|
expect(platform.actions_to_deploy_on('local', 'test_policy_1', use_why_run: false)).to eq [
|
|
243
313
|
{
|
|
244
|
-
bash:
|
|
314
|
+
bash: [
|
|
315
|
+
'set -e',
|
|
316
|
+
"cd #{repository}/dist/prod/test_policy_1",
|
|
317
|
+
'sudo SSL_CERT_DIR=/etc/ssl/certs /opt/chef-workstation/bin/chef gem install my_gem_1 --version "0.0.1"',
|
|
318
|
+
'sudo SSL_CERT_DIR=/etc/ssl/certs /opt/chef-workstation/bin/chef gem install my_gem_2 --version "0.0.2"',
|
|
319
|
+
'sudo SSL_CERT_DIR=/etc/ssl/certs /opt/chef-workstation/bin/chef gem install my_gem_3 --version "~> 1.3"',
|
|
320
|
+
'sudo SSL_CERT_DIR=/etc/ssl/certs /opt/chef-workstation/bin/chef-client --local-mode --chef-license accept --json-attributes nodes/local.json'
|
|
321
|
+
]
|
|
245
322
|
}
|
|
246
323
|
]
|
|
247
324
|
end
|
|
@@ -254,7 +331,7 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
|
254
331
|
it 'deploys a service on a node belonging to another platform' do
|
|
255
332
|
with_serverless_chef_platforms({ 'p1' => '1_node', 'p2' => 'several_nodes' }) do |repositories|
|
|
256
333
|
platform_1, repository_1 = repositories.find { |platform, _repository| platform.name == 'p1' }
|
|
257
|
-
mock_package(repository_1)
|
|
334
|
+
mock_package(repository_1, service: 'test_policy_1')
|
|
258
335
|
platform_1.prepare_for_deploy(
|
|
259
336
|
services: { 'node2' => %w[test_policy_1] },
|
|
260
337
|
secrets: {},
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hybrid_platforms_conductor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 33.
|
|
4
|
+
version: 33.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Muriel Salvan
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-06-
|
|
11
|
+
date: 2021-06-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: range_operators
|