hybrid_platforms_conductor 33.1.1 → 33.2.4
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 +61 -0
- data/lib/hybrid_platforms_conductor/cmd_runner.rb +1 -1
- data/lib/hybrid_platforms_conductor/config.rb +0 -35
- data/lib/hybrid_platforms_conductor/core_extensions/bundler/without_bundled_env.rb +54 -0
- data/lib/hybrid_platforms_conductor/deployer.rb +33 -0
- data/lib/hybrid_platforms_conductor/executable.rb +2 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb +32 -6
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox/reserve_proxmox_container +1 -0
- data/lib/hybrid_platforms_conductor/version.rb +1 -1
- data/spec/hybrid_platforms_conductor_test/api/cmd_runner_spec.rb +15 -1
- data/spec/hybrid_platforms_conductor_test/api/config_spec.rb +0 -34
- data/spec/hybrid_platforms_conductor_test/api/deployer/config_dsl_spec.rb +34 -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 +93 -16
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bd578efdc520f51dc9752ace39626e73dbdda736fd4376ee5e9ce55ed34a0a4d
|
|
4
|
+
data.tar.gz: c44c935905b7a62a4a0f3ea037b0f1e4ed8fa07bdad4802e38143fe1a448bfd1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f0070cf6736acaa5b9a1e36279bab3b9f6530c26ea341feec4fb4775d022e1c67e2694df832a3ab340b765e10bf510969febe82e4b34fa564e9aab82eea71314
|
|
7
|
+
data.tar.gz: d5cc0229b32b7f75d1c7604e304e6986b0b7ab121676dfd62121d954c48e3ba93f827dabfbb8320c9f945339c334263ff9404c8c60e1be5a0b03e4b390cc044f
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,64 @@
|
|
|
1
|
+
# [v33.2.4](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.2.3...v33.2.4) (2021-06-23 15:14:20)
|
|
2
|
+
|
|
3
|
+
## Global changes
|
|
4
|
+
### Patches
|
|
5
|
+
|
|
6
|
+
* [[Hotfix(platform_handler_serverless_chef)] Forward environment in sudo commands](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/fd3b58875665c29dd071b5af2055eab0c45c0974)
|
|
7
|
+
* [[Hotfix] Fixed unbundled environment not cleaned + Moved deployer config DSL in deployer.rb](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/2bce6dbc31d98b27f196ed646eb9aa669b0f9a86)
|
|
8
|
+
|
|
9
|
+
## Changes for platform_handler_serverless_chef
|
|
10
|
+
### Patches
|
|
11
|
+
|
|
12
|
+
* [[Hotfix(platform_handler_serverless_chef)] Forward environment in sudo commands](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/fd3b58875665c29dd071b5af2055eab0c45c0974)
|
|
13
|
+
|
|
14
|
+
# [v33.2.3](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.2.2...v33.2.3) (2021-06-23 13:45:56)
|
|
15
|
+
|
|
16
|
+
## Global changes
|
|
17
|
+
### Patches
|
|
18
|
+
|
|
19
|
+
* [[Hotfix(provisioner_proxmox)] Add missing require in synchronization script](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/7a6c71595789c9180e1d95323fc5cf5051f2e2cd)
|
|
20
|
+
|
|
21
|
+
## Changes for provisioner_proxmox
|
|
22
|
+
### Patches
|
|
23
|
+
|
|
24
|
+
* [[Hotfix(provisioner_proxmox)] Add missing require in synchronization script](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/7a6c71595789c9180e1d95323fc5cf5051f2e2cd)
|
|
25
|
+
|
|
26
|
+
# [v33.2.2](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.2.1...v33.2.2) (2021-06-21 12:41:35)
|
|
27
|
+
|
|
28
|
+
## Global changes
|
|
29
|
+
### Patches
|
|
30
|
+
|
|
31
|
+
* [[Hotfix(cmd_runner)] Retain dynamically set environment while executing commands](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/d709d5d2871e43196cc1f5f9eaf5b2155b34ed4e)
|
|
32
|
+
|
|
33
|
+
## Changes for cmd_runner
|
|
34
|
+
### Patches
|
|
35
|
+
|
|
36
|
+
* [[Hotfix(cmd_runner)] Retain dynamically set environment while executing commands](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/d709d5d2871e43196cc1f5f9eaf5b2155b34ed4e)
|
|
37
|
+
|
|
38
|
+
# [v33.2.1](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.2.0...v33.2.1) (2021-06-21 10:23:51)
|
|
39
|
+
|
|
40
|
+
## Global changes
|
|
41
|
+
### Patches
|
|
42
|
+
|
|
43
|
+
* [[Hotfix(platform_handler_serverless_chef)] Corrected dry-run mode not working](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/4800a0f4255c1999eed33651c1e66c445acd17bb)
|
|
44
|
+
|
|
45
|
+
## Changes for platform_handler_serverless_chef
|
|
46
|
+
### Patches
|
|
47
|
+
|
|
48
|
+
* [[Hotfix(platform_handler_serverless_chef)] Corrected dry-run mode not working](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/4800a0f4255c1999eed33651c1e66c445acd17bb)
|
|
49
|
+
|
|
50
|
+
# [v33.2.0](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.1.1...v33.2.0) (2021-06-18 23:22:21)
|
|
51
|
+
|
|
52
|
+
## Global changes
|
|
53
|
+
### Patches
|
|
54
|
+
|
|
55
|
+
* [[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)
|
|
56
|
+
|
|
57
|
+
## Changes for platform_handler_serverless_chef
|
|
58
|
+
### Features
|
|
59
|
+
|
|
60
|
+
* [[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)
|
|
61
|
+
|
|
1
62
|
# [v33.1.1](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.1.0...v33.1.1) (2021-06-18 13:19:39)
|
|
2
63
|
|
|
3
64
|
### Patches
|
|
@@ -130,7 +130,7 @@ module HybridPlatformsConductor
|
|
|
130
130
|
(log_to_stdout ? [@logger_stderr] : []) +
|
|
131
131
|
(file_output.nil? ? [] : [file_output])
|
|
132
132
|
) do
|
|
133
|
-
Bundler.
|
|
133
|
+
Bundler.without_bundled_env do
|
|
134
134
|
cmd_result = TTY::Command.new(
|
|
135
135
|
printer: :null,
|
|
136
136
|
pty: true,
|
|
@@ -47,12 +47,6 @@ module HybridPlatformsConductor
|
|
|
47
47
|
# Array<Hash,Symbol,Object>
|
|
48
48
|
attr_reader :expected_failures
|
|
49
49
|
|
|
50
|
-
# List of retriable errors. Each info has the following properties:
|
|
51
|
-
# * *nodes_selectors_stack* (Array<Object>): Stack of nodes selectors impacted by those errors
|
|
52
|
-
# * *errors_on_stdout* (Array<String or Regexp>): List of errors match (as exact string match or using a regexp) to check against stdout
|
|
53
|
-
# * *errors_on_stderr* (Array<String or Regexp>): List of errors match (as exact string match or using a regexp) to check against stderr
|
|
54
|
-
attr_reader :retriable_errors
|
|
55
|
-
|
|
56
50
|
# List of deployment schedules. Each info has the following properties:
|
|
57
51
|
# * *nodes_selectors_stack* (Array<Object>): Stack of nodes selectors impacted by this rule
|
|
58
52
|
# * *schedule* (IceCube::Schedule): The deployment schedule
|
|
@@ -81,11 +75,6 @@ module HybridPlatformsConductor
|
|
|
81
75
|
# * *reason* (String): Reason for this expected failure
|
|
82
76
|
# Array<Hash,Symbol,Object>
|
|
83
77
|
@expected_failures = []
|
|
84
|
-
# List of retriable errors. Each info has the following properties:
|
|
85
|
-
# * *nodes_selectors_stack* (Array<Object>): Stack of nodes selectors impacted by those errors
|
|
86
|
-
# * *errors_on_stdout* (Array<String or Regexp>): List of errors match (as exact string match or using a regexp) to check against stdout
|
|
87
|
-
# * *errors_on_stderr* (Array<String or Regexp>): List of errors match (as exact string match or using a regexp) to check against stderr
|
|
88
|
-
@retriable_errors = []
|
|
89
78
|
# List of deployment schedules. Each info has the following properties:
|
|
90
79
|
# * *nodes_selectors_stack* (Array<Object>): Stack of nodes selectors impacted by this rule
|
|
91
80
|
# * *schedule* (IceCube::Schedule): The deployment schedule
|
|
@@ -162,30 +151,6 @@ module HybridPlatformsConductor
|
|
|
162
151
|
end
|
|
163
152
|
expose :expect_tests_to_fail
|
|
164
153
|
|
|
165
|
-
# Mark some errors on stdout to be retriable during a deploy
|
|
166
|
-
#
|
|
167
|
-
# Parameters::
|
|
168
|
-
# * *errors* (String, Regexp or Array<String or Regexp>): Single (or list of) errors matching pattern (either as exact string match or using a regexp).
|
|
169
|
-
def retry_deploy_for_errors_on_stdout(errors)
|
|
170
|
-
@retriable_errors << {
|
|
171
|
-
errors_on_stdout: errors.is_a?(Array) ? errors : [errors],
|
|
172
|
-
nodes_selectors_stack: current_nodes_selectors_stack
|
|
173
|
-
}
|
|
174
|
-
end
|
|
175
|
-
expose :retry_deploy_for_errors_on_stdout
|
|
176
|
-
|
|
177
|
-
# Mark some errors on stderr to be retriable during a deploy
|
|
178
|
-
#
|
|
179
|
-
# Parameters::
|
|
180
|
-
# * *errors* (String, Regexp or Array<String or Regexp>): Single (or list of) errors matching pattern (either as exact string match or using a regexp).
|
|
181
|
-
def retry_deploy_for_errors_on_stderr(errors)
|
|
182
|
-
@retriable_errors << {
|
|
183
|
-
errors_on_stderr: errors.is_a?(Array) ? errors : [errors],
|
|
184
|
-
nodes_selectors_stack: current_nodes_selectors_stack
|
|
185
|
-
}
|
|
186
|
-
end
|
|
187
|
-
expose :retry_deploy_for_errors_on_stderr
|
|
188
|
-
|
|
189
154
|
# Set a deployment schedule
|
|
190
155
|
#
|
|
191
156
|
# Parameters::
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Add a way to clean the current env from Bundler variables
|
|
2
|
+
module Bundler
|
|
3
|
+
|
|
4
|
+
class << self
|
|
5
|
+
|
|
6
|
+
# Run block with all bundler-related variables removed from the current environment
|
|
7
|
+
def without_bundled_env(&block)
|
|
8
|
+
with_env(current_unbundled_env, &block)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# @return [Hash] Environment with all bundler-related variables removed
|
|
12
|
+
def current_unbundled_env
|
|
13
|
+
env = ENV.clone.to_hash
|
|
14
|
+
%w[
|
|
15
|
+
PATH
|
|
16
|
+
RUBYLIB
|
|
17
|
+
RUBYOPT
|
|
18
|
+
].each do |env_name|
|
|
19
|
+
if original_env.key?(env_name)
|
|
20
|
+
env[env_name] = original_env[env_name]
|
|
21
|
+
else
|
|
22
|
+
env.delete(env_name)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
env['MANPATH'] = env['BUNDLER_ORIG_MANPATH'] if env.key?('BUNDLER_ORIG_MANPATH')
|
|
27
|
+
|
|
28
|
+
env.delete_if do |k, _|
|
|
29
|
+
%w[
|
|
30
|
+
GEM_
|
|
31
|
+
BUNDLE_
|
|
32
|
+
BUNDLER_
|
|
33
|
+
].any? { |prefix| k.start_with?(prefix) }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
if env.key?('RUBYOPT')
|
|
37
|
+
rubyopt = env['RUBYOPT'].split
|
|
38
|
+
rubyopt.delete("-r#{File.expand_path('bundler/setup', __dir__)}")
|
|
39
|
+
rubyopt.delete('-rbundler/setup')
|
|
40
|
+
env['RUBYOPT'] = rubyopt.join(' ')
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
if env.key?('RUBYLIB')
|
|
44
|
+
rubylib = env['RUBYLIB'].split(File::PATH_SEPARATOR)
|
|
45
|
+
rubylib.delete(File.expand_path(__dir__))
|
|
46
|
+
env['RUBYLIB'] = rubylib.join(File::PATH_SEPARATOR)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
env
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
@@ -18,6 +18,12 @@ module HybridPlatformsConductor
|
|
|
18
18
|
# Extend the Config DSL
|
|
19
19
|
module ConfigDSLExtension
|
|
20
20
|
|
|
21
|
+
# List of retriable errors. Each info has the following properties:
|
|
22
|
+
# * *nodes_selectors_stack* (Array<Object>): Stack of nodes selectors impacted by those errors
|
|
23
|
+
# * *errors_on_stdout* (Array<String or Regexp>): List of errors match (as exact string match or using a regexp) to check against stdout
|
|
24
|
+
# * *errors_on_stderr* (Array<String or Regexp>): List of errors match (as exact string match or using a regexp) to check against stderr
|
|
25
|
+
attr_reader :retriable_errors
|
|
26
|
+
|
|
21
27
|
# List of log plugins. Each info has the following properties:
|
|
22
28
|
# * *nodes_selectors_stack* (Array<Object>): Stack of nodes selectors impacted by this rule.
|
|
23
29
|
# * *log_plugins* (Array<Symbol>): List of log plugins to be used to store deployment logs.
|
|
@@ -36,6 +42,11 @@ module HybridPlatformsConductor
|
|
|
36
42
|
# Mixin initializer
|
|
37
43
|
def init_deployer_config
|
|
38
44
|
@packaging_timeout_secs = 60
|
|
45
|
+
# List of retriable errors. Each info has the following properties:
|
|
46
|
+
# * *nodes_selectors_stack* (Array<Object>): Stack of nodes selectors impacted by those errors
|
|
47
|
+
# * *errors_on_stdout* (Array<String or Regexp>): List of errors match (as exact string match or using a regexp) to check against stdout
|
|
48
|
+
# * *errors_on_stderr* (Array<String or Regexp>): List of errors match (as exact string match or using a regexp) to check against stderr
|
|
49
|
+
@retriable_errors = []
|
|
39
50
|
@deployment_logs = []
|
|
40
51
|
@secrets_readers = []
|
|
41
52
|
end
|
|
@@ -48,6 +59,28 @@ module HybridPlatformsConductor
|
|
|
48
59
|
@packaging_timeout_secs = packaging_timeout_secs
|
|
49
60
|
end
|
|
50
61
|
|
|
62
|
+
# Mark some errors on stdout to be retriable during a deploy
|
|
63
|
+
#
|
|
64
|
+
# Parameters::
|
|
65
|
+
# * *errors* (String, Regexp or Array<String or Regexp>): Single (or list of) errors matching pattern (either as exact string match or using a regexp).
|
|
66
|
+
def retry_deploy_for_errors_on_stdout(errors)
|
|
67
|
+
@retriable_errors << {
|
|
68
|
+
errors_on_stdout: errors.is_a?(Array) ? errors : [errors],
|
|
69
|
+
nodes_selectors_stack: current_nodes_selectors_stack
|
|
70
|
+
}
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Mark some errors on stderr to be retriable during a deploy
|
|
74
|
+
#
|
|
75
|
+
# Parameters::
|
|
76
|
+
# * *errors* (String, Regexp or Array<String or Regexp>): Single (or list of) errors matching pattern (either as exact string match or using a regexp).
|
|
77
|
+
def retry_deploy_for_errors_on_stderr(errors)
|
|
78
|
+
@retriable_errors << {
|
|
79
|
+
errors_on_stderr: errors.is_a?(Array) ? errors : [errors],
|
|
80
|
+
nodes_selectors_stack: current_nodes_selectors_stack
|
|
81
|
+
}
|
|
82
|
+
end
|
|
83
|
+
|
|
51
84
|
# Set the deployment log plugins to be used
|
|
52
85
|
#
|
|
53
86
|
# Parameters::
|
|
@@ -179,6 +179,13 @@ module HybridPlatformsConductor
|
|
|
179
179
|
/opt/chef-workstation/bin/chef export #{policy_file} #{package_dir} --chef-license accept#{extra_cp_data_bags}"
|
|
180
180
|
next if @cmd_runner.dry_run
|
|
181
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
|
+
)
|
|
182
189
|
# Create secrets file
|
|
183
190
|
secrets_file = "#{@repository_path}/#{package_dir}/data_bags/hpc_secrets/hpc_secrets.json"
|
|
184
191
|
FileUtils.mkdir_p(File.dirname(secrets_file))
|
|
@@ -220,10 +227,13 @@ module HybridPlatformsConductor
|
|
|
220
227
|
# * Array< Hash<Symbol,Object> >: List of actions to be done
|
|
221
228
|
def actions_to_deploy_on(node, service, use_why_run: true)
|
|
222
229
|
package_dir = "#{@repository_path}/dist/#{@local_env ? 'local' : 'prod'}/#{service}"
|
|
230
|
+
gems_to_install = []
|
|
223
231
|
# Generate the nodes attributes file
|
|
224
232
|
unless @cmd_runner.dry_run
|
|
225
233
|
FileUtils.mkdir_p "#{package_dir}/nodes"
|
|
226
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"))
|
|
227
237
|
end
|
|
228
238
|
client_options = [
|
|
229
239
|
'--local-mode',
|
|
@@ -233,7 +243,19 @@ module HybridPlatformsConductor
|
|
|
233
243
|
client_options << '--why-run' if use_why_run
|
|
234
244
|
if @nodes_handler.get_use_local_chef_of(node)
|
|
235
245
|
# Just run the chef-client directly from the packaged repository
|
|
236
|
-
|
|
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
|
+
]
|
|
237
259
|
else
|
|
238
260
|
# Upload the package and run it from the node
|
|
239
261
|
package_name = File.basename(package_dir)
|
|
@@ -241,7 +263,7 @@ module HybridPlatformsConductor
|
|
|
241
263
|
raise "Missing file #{chef_versions_file} specifying the Chef Infra Client version to be deployed" unless File.exist?(chef_versions_file)
|
|
242
264
|
|
|
243
265
|
required_chef_client_version = YAML.load_file(chef_versions_file)['client']
|
|
244
|
-
sudo = (@actions_executor.connector(:ssh).ssh_user == 'root' ? '' : "#{@nodes_handler.sudo_on(node)} ")
|
|
266
|
+
sudo = (@actions_executor.connector(:ssh).ssh_user == 'root' ? '' : "#{@nodes_handler.sudo_on(node)} -E ")
|
|
245
267
|
[
|
|
246
268
|
{
|
|
247
269
|
# Install dependencies
|
|
@@ -261,10 +283,14 @@ module HybridPlatformsConductor
|
|
|
261
283
|
scp: { package_dir => './hpc_deploy' },
|
|
262
284
|
remote_bash: [
|
|
263
285
|
'set -e',
|
|
264
|
-
"cd ./hpc_deploy/#{package_name}"
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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}"])
|
|
268
294
|
}
|
|
269
295
|
]
|
|
270
296
|
end
|
|
@@ -47,7 +47,21 @@ describe HybridPlatformsConductor::CmdRunner do
|
|
|
47
47
|
|
|
48
48
|
it 'runs a command in an un-bundled environment' do
|
|
49
49
|
with_repository do
|
|
50
|
-
|
|
50
|
+
%w[
|
|
51
|
+
BUNDLE_GEMFILE
|
|
52
|
+
GEM_HOME
|
|
53
|
+
RUBYOPT
|
|
54
|
+
].each do |var_to_check|
|
|
55
|
+
expect(test_cmd_runner.run_cmd("echo \"${#{var_to_check}}\"")).to eq [0, "\n", '']
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'keeps dynamically set environment' do
|
|
61
|
+
with_repository do
|
|
62
|
+
value = ('a'..'z').to_a.sample(8).join
|
|
63
|
+
ENV['hpc_test_new_variable'] = value
|
|
64
|
+
expect(test_cmd_runner.run_cmd('echo "${hpc_test_new_variable}"')).to eq [0, "#{value}\n", '']
|
|
51
65
|
end
|
|
52
66
|
end
|
|
53
67
|
|
|
@@ -155,40 +155,6 @@ describe HybridPlatformsConductor::Config do
|
|
|
155
155
|
end
|
|
156
156
|
end
|
|
157
157
|
|
|
158
|
-
it 'returns the retriable errors correctly' do
|
|
159
|
-
with_platforms '
|
|
160
|
-
retry_deploy_for_errors_on_stdout \'Retry stdout global\'
|
|
161
|
-
retry_deploy_for_errors_on_stderr [
|
|
162
|
-
\'Retry stderr global\',
|
|
163
|
-
/.+Retry stderr regexp global/
|
|
164
|
-
]
|
|
165
|
-
for_nodes(%w[node1 node2 node3]) do
|
|
166
|
-
retry_deploy_for_errors_on_stdout \'Retry stdout nodes\'
|
|
167
|
-
retry_deploy_for_errors_on_stderr \'Retry stderr nodes\'
|
|
168
|
-
end
|
|
169
|
-
' do
|
|
170
|
-
sort_proc = proc { |retriable_error_info| ((retriable_error_info[:errors_on_stdout] || []) + (retriable_error_info[:errors_on_stderr] || [])).first.to_s }
|
|
171
|
-
expect(test_config.retriable_errors.sort_by(&sort_proc)).to eq [
|
|
172
|
-
{
|
|
173
|
-
nodes_selectors_stack: [],
|
|
174
|
-
errors_on_stdout: ['Retry stdout global']
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
nodes_selectors_stack: [],
|
|
178
|
-
errors_on_stderr: ['Retry stderr global', /.+Retry stderr regexp global/]
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
nodes_selectors_stack: [%w[node1 node2 node3]],
|
|
182
|
-
errors_on_stdout: ['Retry stdout nodes']
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
nodes_selectors_stack: [%w[node1 node2 node3]],
|
|
186
|
-
errors_on_stderr: ['Retry stderr nodes']
|
|
187
|
-
}
|
|
188
|
-
].sort_by(&sort_proc)
|
|
189
|
-
end
|
|
190
|
-
end
|
|
191
|
-
|
|
192
158
|
it 'returns the deployment schedules correctly' do
|
|
193
159
|
with_platforms '
|
|
194
160
|
deployment_schedule(IceCube::Schedule.new(Time.parse(\'2020-05-01 11:22:33 UTC\')))
|
|
@@ -8,6 +8,40 @@ describe HybridPlatformsConductor::Deployer do
|
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
it 'returns the retriable errors correctly' do
|
|
12
|
+
with_platforms '
|
|
13
|
+
retry_deploy_for_errors_on_stdout \'Retry stdout global\'
|
|
14
|
+
retry_deploy_for_errors_on_stderr [
|
|
15
|
+
\'Retry stderr global\',
|
|
16
|
+
/.+Retry stderr regexp global/
|
|
17
|
+
]
|
|
18
|
+
for_nodes(%w[node1 node2 node3]) do
|
|
19
|
+
retry_deploy_for_errors_on_stdout \'Retry stdout nodes\'
|
|
20
|
+
retry_deploy_for_errors_on_stderr \'Retry stderr nodes\'
|
|
21
|
+
end
|
|
22
|
+
' do
|
|
23
|
+
sort_proc = proc { |retriable_error_info| ((retriable_error_info[:errors_on_stdout] || []) + (retriable_error_info[:errors_on_stderr] || [])).first.to_s }
|
|
24
|
+
expect(test_config.retriable_errors.sort_by(&sort_proc)).to eq [
|
|
25
|
+
{
|
|
26
|
+
nodes_selectors_stack: [],
|
|
27
|
+
errors_on_stdout: ['Retry stdout global']
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
nodes_selectors_stack: [],
|
|
31
|
+
errors_on_stderr: ['Retry stderr global', /.+Retry stderr regexp global/]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
nodes_selectors_stack: [%w[node1 node2 node3]],
|
|
35
|
+
errors_on_stdout: ['Retry stdout nodes']
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
nodes_selectors_stack: [%w[node1 node2 node3]],
|
|
39
|
+
errors_on_stderr: ['Retry stderr nodes']
|
|
40
|
+
}
|
|
41
|
+
].sort_by(&sort_proc)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
11
45
|
it 'declares log plugins to be used' do
|
|
12
46
|
with_platforms(
|
|
13
47
|
<<~EO_CONFIG
|
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,15 +29,17 @@ 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(
|
|
26
36
|
repository,
|
|
27
37
|
check_mode: false,
|
|
28
|
-
sudo: 'sudo -u root ',
|
|
38
|
+
sudo: 'sudo -u root -E ',
|
|
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.4
|
|
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-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: range_operators
|
|
@@ -695,6 +695,7 @@ files:
|
|
|
695
695
|
- lib/hybrid_platforms_conductor/config.rb
|
|
696
696
|
- lib/hybrid_platforms_conductor/confluence.rb
|
|
697
697
|
- lib/hybrid_platforms_conductor/connector.rb
|
|
698
|
+
- lib/hybrid_platforms_conductor/core_extensions/bundler/without_bundled_env.rb
|
|
698
699
|
- lib/hybrid_platforms_conductor/core_extensions/cleanroom/fix_kwargs.rb
|
|
699
700
|
- lib/hybrid_platforms_conductor/core_extensions/symbol/zero.rb
|
|
700
701
|
- lib/hybrid_platforms_conductor/credentials.rb
|