bolt 3.13.0 → 3.16.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bolt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Puppetfile +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +137 -104
- data/bolt-modules/boltlib/lib/puppet/functions/background.rb +2 -1
- data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +5 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +13 -0
- data/bolt-modules/boltlib/lib/puppet/functions/wait.rb +47 -7
- data/bolt-modules/out/lib/puppet/functions/out/message.rb +4 -2
- data/bolt-modules/out/lib/puppet/functions/out/verbose.rb +4 -2
- data/guides/{debugging.txt → debugging.yaml} +5 -6
- data/guides/{inventory.txt → inventory.yaml} +6 -7
- data/guides/{links.txt → links.yaml} +3 -4
- data/guides/{logging.txt → logging.yaml} +5 -6
- data/guides/{module.txt → module.yaml} +5 -6
- data/guides/{modulepath.txt → modulepath.yaml} +5 -6
- data/guides/{project.txt → project.yaml} +6 -7
- data/guides/{targets.txt → targets.yaml} +5 -6
- data/guides/{transports.txt → transports.yaml} +6 -7
- data/lib/bolt/analytics.rb +3 -20
- data/lib/bolt/application.rb +620 -0
- data/lib/bolt/bolt_option_parser.rb +17 -5
- data/lib/bolt/cli.rb +592 -772
- data/lib/bolt/config/transport/options.rb +12 -0
- data/lib/bolt/config/transport/ssh.rb +7 -0
- data/lib/bolt/executor.rb +12 -4
- data/lib/bolt/fiber_executor.rb +63 -14
- data/lib/bolt/module_installer/puppetfile.rb +24 -10
- data/lib/bolt/outputter/human.rb +199 -43
- data/lib/bolt/outputter/json.rb +66 -43
- data/lib/bolt/outputter/logger.rb +1 -1
- data/lib/bolt/pal.rb +67 -14
- data/lib/bolt/pal/yaml_plan/step.rb +2 -0
- data/lib/bolt/pal/yaml_plan/step/message.rb +0 -8
- data/lib/bolt/pal/yaml_plan/step/verbose.rb +31 -0
- data/lib/bolt/pal/yaml_plan/transpiler.rb +1 -1
- data/lib/bolt/plan_creator.rb +2 -20
- data/lib/bolt/plan_future.rb +23 -3
- data/lib/bolt/plan_result.rb +1 -1
- data/lib/bolt/plugin/task.rb +1 -1
- data/lib/bolt/project.rb +0 -7
- data/lib/bolt/result_set.rb +2 -1
- data/lib/bolt/transport/local/connection.rb +17 -1
- data/lib/bolt/transport/orch/connection.rb +13 -1
- data/lib/bolt/transport/ssh/exec_connection.rb +3 -1
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/file_cache.rb +12 -0
- data/lib/bolt_server/schemas/action-apply.json +32 -0
- data/lib/bolt_server/schemas/action-apply_prep.json +19 -0
- data/lib/bolt_server/schemas/partials/target-ssh.json +4 -0
- data/lib/bolt_server/schemas/partials/target-winrm.json +4 -0
- data/lib/bolt_server/transport_app.rb +180 -60
- data/lib/bolt_spec/plans/mock_executor.rb +16 -6
- metadata +23 -15
- data/guides/guide.txt +0 -17
- data/lib/bolt/secret.rb +0 -37
data/lib/bolt/plugin/task.rb
CHANGED
@@ -59,7 +59,7 @@ module Bolt
|
|
59
59
|
run_opts = {}
|
60
60
|
run_opts[:run_as] = opts['_run_as'] if opts['_run_as']
|
61
61
|
begin
|
62
|
-
task =
|
62
|
+
task = @context.get_validated_task(opts['task'], params)
|
63
63
|
rescue Bolt::Error => e
|
64
64
|
raise Bolt::Plugin::PluginError::ExecutionError.new(e.message, name, 'puppet_library')
|
65
65
|
end
|
data/lib/bolt/project.rb
CHANGED
@@ -209,12 +209,5 @@ module Bolt
|
|
209
209
|
Bolt::Logger.warn("missing_project_name", message)
|
210
210
|
end
|
211
211
|
end
|
212
|
-
|
213
|
-
def check_deprecated_file
|
214
|
-
if (@path + 'project.yaml').file?
|
215
|
-
msg = "Project configuration file 'project.yaml' is deprecated; use 'bolt-project.yaml' instead."
|
216
|
-
Bolt::Logger.warn("project_yaml", msg)
|
217
|
-
end
|
218
|
-
end
|
219
212
|
end
|
220
213
|
end
|
data/lib/bolt/result_set.rb
CHANGED
@@ -10,6 +10,8 @@ module Bolt
|
|
10
10
|
module Transport
|
11
11
|
class Local < Simple
|
12
12
|
class Connection
|
13
|
+
RUBY_ENV_VARS = %w[GEM_PATH GEM_HOME RUBYLIB RUBYLIB_PREFIX RUBYOPT RUBYPATH RUBYSHELL].freeze
|
14
|
+
|
13
15
|
attr_accessor :user, :logger, :target
|
14
16
|
|
15
17
|
def initialize(target)
|
@@ -68,7 +70,21 @@ module Bolt
|
|
68
70
|
end
|
69
71
|
end
|
70
72
|
|
71
|
-
|
73
|
+
# Only do this if bundled-ruby is set to false, not nil
|
74
|
+
ruby_env_vars = if target.transport_config['bundled-ruby'] == false
|
75
|
+
RUBY_ENV_VARS.each_with_object({}) do |e, acc|
|
76
|
+
acc[e] = ENV["BOLT_ORIG_#{e}"] if ENV["BOLT_ORIG_#{e}"]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
if target.transport_config['bundled-ruby'] == false &&
|
81
|
+
Gem.loaded_specs.keys.include?('bundler')
|
82
|
+
Bundler.with_unbundled_env do
|
83
|
+
Open3.popen3(ruby_env_vars || {}, *command)
|
84
|
+
end
|
85
|
+
else
|
86
|
+
Open3.popen3(ruby_env_vars || {}, *command)
|
87
|
+
end
|
72
88
|
end
|
73
89
|
|
74
90
|
# This is used by the Bash shell to decide whether to `cd` before
|
@@ -36,7 +36,8 @@ module Bolt
|
|
36
36
|
end
|
37
37
|
logger.debug("Creating orchestrator client for #{client_opts}")
|
38
38
|
@client = OrchestratorClient.new(client_opts, true)
|
39
|
-
@
|
39
|
+
@plan_context = plan_context
|
40
|
+
@plan_job = start_plan(@plan_context)
|
40
41
|
logger.debug("Started plan #{@plan_job}")
|
41
42
|
@environment = opts["task-environment"]
|
42
43
|
end
|
@@ -87,6 +88,17 @@ module Bolt
|
|
87
88
|
def run_task(targets, task, arguments, options)
|
88
89
|
body = build_request(targets, task, arguments, options[:description])
|
89
90
|
@client.run_task(body)
|
91
|
+
rescue OrchestratorClient::ApiError => e
|
92
|
+
if e.data['kind'] == 'puppetlabs.orchestrator/plan-already-finished'
|
93
|
+
@logger.debug("Retrying the task")
|
94
|
+
# Instead of recursing, just retry once
|
95
|
+
@plan_job = start_plan(@plan_context)
|
96
|
+
# Rebuild the request with the new plan job ID
|
97
|
+
body = build_request(targets, task, arguments, options[:description])
|
98
|
+
@client.run_task(body)
|
99
|
+
else
|
100
|
+
raise e
|
101
|
+
end
|
90
102
|
end
|
91
103
|
|
92
104
|
def query_inventory(targets)
|
@@ -47,7 +47,9 @@ module Bolt
|
|
47
47
|
cmd = []
|
48
48
|
# BatchMode is SSH's noninteractive option: if key authentication
|
49
49
|
# fails it will error out instead of falling back to password prompt
|
50
|
-
|
50
|
+
batch_mode = @target.transport_config['batch-mode'] ? 'yes' : 'no'
|
51
|
+
cmd += %W[-o BatchMode=#{batch_mode}]
|
52
|
+
|
51
53
|
cmd += %W[-o Port=#{@target.port}] if @target.port
|
52
54
|
|
53
55
|
if @target.transport_config.key?('host-key-check')
|
data/lib/bolt/version.rb
CHANGED
@@ -182,5 +182,17 @@ module BoltServer
|
|
182
182
|
end
|
183
183
|
end
|
184
184
|
end
|
185
|
+
|
186
|
+
def get_cached_project_file(versioned_project, file_name)
|
187
|
+
file_dir = create_cache_dir(versioned_project)
|
188
|
+
file_path = File.join(file_dir, file_name)
|
189
|
+
serial_execute { File.read(file_path) if File.exist?(file_path) }
|
190
|
+
end
|
191
|
+
|
192
|
+
def cache_project_file(versioned_project, file_name, data)
|
193
|
+
file_dir = create_cache_dir(versioned_project)
|
194
|
+
file_path = File.join(file_dir, file_name)
|
195
|
+
serial_execute { File.open(file_path, 'w') { |f| f.write(data) } }
|
196
|
+
end
|
185
197
|
end
|
186
198
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "http://json-schema.org/draft-04/schema#",
|
3
|
+
"title": "apply request",
|
4
|
+
"description": "POST <transport>/apply request schema",
|
5
|
+
"type": "object",
|
6
|
+
"properties": {
|
7
|
+
"versioned_project": {
|
8
|
+
"type": "string",
|
9
|
+
"description": "Project from which to load code"
|
10
|
+
},
|
11
|
+
"parameters": {
|
12
|
+
"type": "object",
|
13
|
+
"properties": {
|
14
|
+
"catalog": {
|
15
|
+
"type": "object",
|
16
|
+
"description": "Compiled catalog to apply"
|
17
|
+
},
|
18
|
+
"apply_options": {
|
19
|
+
"type": "object",
|
20
|
+
"description": "Options for application of a catalog"
|
21
|
+
}
|
22
|
+
}
|
23
|
+
},
|
24
|
+
"job_id": {
|
25
|
+
"type": "integer",
|
26
|
+
"description": "job-id associated with request"
|
27
|
+
},
|
28
|
+
"target": { "$ref": "partial:target-any" }
|
29
|
+
},
|
30
|
+
"required": ["target", "versioned_project", "parameters", "job_id"],
|
31
|
+
"additionalProperties": false
|
32
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "http://json-schema.org/draft-04/schema#",
|
3
|
+
"title": "apply_prep request",
|
4
|
+
"description": "POST <transport>/apply_prep request schema",
|
5
|
+
"type": "object",
|
6
|
+
"properties": {
|
7
|
+
"versioned_project": {
|
8
|
+
"type": "String",
|
9
|
+
"description": "Project from which to load code"
|
10
|
+
},
|
11
|
+
"target": { "$ref": "partial:target-any" },
|
12
|
+
"job_id": {
|
13
|
+
"type": "integer",
|
14
|
+
"description": "job-id associated with request"
|
15
|
+
}
|
16
|
+
},
|
17
|
+
"required": ["target", "versioned_project", "job_id"],
|
18
|
+
"additionalProperties": false
|
19
|
+
}
|
@@ -43,6 +43,8 @@ module BoltServer
|
|
43
43
|
transport-ssh
|
44
44
|
transport-winrm
|
45
45
|
connect-data
|
46
|
+
action-apply_prep
|
47
|
+
action-apply
|
46
48
|
].freeze
|
47
49
|
|
48
50
|
# PE_BOLTLIB_PATH is intended to function exactly like the BOLTLIB_PATH used
|
@@ -75,6 +77,12 @@ module BoltServer
|
|
75
77
|
# This is needed until the PAL is threadsafe.
|
76
78
|
@pal_mutex = Mutex.new
|
77
79
|
|
80
|
+
# Avoid redundant plugin tarbal construction
|
81
|
+
@plugin_mutex = Mutex.new
|
82
|
+
|
83
|
+
# Avoid redundant project_task metadata construction
|
84
|
+
@task_metadata_mutex = Mutex.new
|
85
|
+
|
78
86
|
@logger = Bolt::Logger.logger(self)
|
79
87
|
|
80
88
|
super(nil)
|
@@ -118,12 +126,7 @@ module BoltServer
|
|
118
126
|
end
|
119
127
|
end
|
120
128
|
|
121
|
-
def
|
122
|
-
validate_schema(@schemas["action-run_task"], body)
|
123
|
-
|
124
|
-
task_data = body['task']
|
125
|
-
task = Bolt::Task::PuppetServer.new(task_data['name'], task_data['metadata'], task_data['files'], @file_cache)
|
126
|
-
parameters = body['parameters'] || {}
|
129
|
+
def task_helper(target, task, parameters)
|
127
130
|
# Wrap parameters marked with '"sensitive": true' in the task metadata with a
|
128
131
|
# Sensitive wrapper type. This way it's not shown in logs.
|
129
132
|
if (param_spec = task.parameters)
|
@@ -142,6 +145,101 @@ module BoltServer
|
|
142
145
|
end
|
143
146
|
end
|
144
147
|
|
148
|
+
def run_task(target, body)
|
149
|
+
validate_schema(@schemas["action-run_task"], body)
|
150
|
+
|
151
|
+
task_data = body['task']
|
152
|
+
task = Bolt::Task::PuppetServer.new(task_data['name'], task_data['metadata'], task_data['files'], @file_cache)
|
153
|
+
task_helper(target, task, body['parameters'] || {})
|
154
|
+
end
|
155
|
+
|
156
|
+
def extract_install_task(target)
|
157
|
+
unless target.plugin_hooks['puppet_library']['task']
|
158
|
+
raise BoltServer::RequestError,
|
159
|
+
"Target must have 'task' plugin hook"
|
160
|
+
end
|
161
|
+
install_task = target.plugin_hooks['puppet_library']['task'].split('::', 2)
|
162
|
+
install_task << 'init' if install_task.count == 1
|
163
|
+
install_task
|
164
|
+
end
|
165
|
+
|
166
|
+
# This helper is responsible for computing or retrieving from the cache a plugin tarball. There are
|
167
|
+
# two supported plugin types 'fact_plugins', and 'all_plugins'. Note that this is cached based on
|
168
|
+
# versioned_project as there are no plugins in the "builtin content" directory
|
169
|
+
def plugin_tarball(versioned_project, tarball_type)
|
170
|
+
tarball_types = %w[fact_plugins all_plugins]
|
171
|
+
unless tarball_types.include?(tarball_type)
|
172
|
+
raise ArgumentError,
|
173
|
+
"tarball_type must be one of: #{tarball_types.join(', ')}"
|
174
|
+
end
|
175
|
+
# lock this so that in the case an apply/apply_prep with multiple targets hits this endpoint
|
176
|
+
# the tarball computation only happens once (all the other targets will just need to read the cached data)
|
177
|
+
@plugin_mutex.synchronize do
|
178
|
+
if (tarball = @file_cache.get_cached_project_file(versioned_project, tarball_type))
|
179
|
+
tarball
|
180
|
+
else
|
181
|
+
new_tarball = build_project_plugins_tarball(versioned_project) do |mod|
|
182
|
+
search_dirs = []
|
183
|
+
search_dirs << mod.plugins if mod.plugins?
|
184
|
+
search_dirs << mod.pluginfacts if mod.pluginfacts?
|
185
|
+
if tarball_type == 'all_plugins'
|
186
|
+
search_dirs << mod.files if mod.files?
|
187
|
+
type_files = "#{mod.path}/types"
|
188
|
+
search_dirs << type_files if File.exist?(type_files)
|
189
|
+
end
|
190
|
+
search_dirs
|
191
|
+
end
|
192
|
+
@file_cache.cache_project_file(versioned_project, tarball_type, new_tarball)
|
193
|
+
new_tarball
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# This helper is responsible for computing or retrieving task metadata for a project.
|
199
|
+
# It expects task name in segments and uses the combination of task name and versioned_project
|
200
|
+
# as a unique identifier for caching in addition to the job_id. The job id is added to protect against
|
201
|
+
# a case where the buildtin content is update (where the apply_helpers would be managed)
|
202
|
+
def project_task_metadata(versioned_project, task_name_segments, job_id)
|
203
|
+
cached_file_name = "#{task_name_segments.join('_')}_#{job_id}"
|
204
|
+
# lock this so that in the case an apply/apply_prep with multiple targets hits this endpoint the
|
205
|
+
# metadata computation will only be computed once, then the cache will be read.
|
206
|
+
@task_metadata_mutex.synchronize do
|
207
|
+
if (metadata = @file_cache.get_cached_project_file(versioned_project, cached_file_name))
|
208
|
+
JSON.parse(metadata)
|
209
|
+
else
|
210
|
+
new_metadata = in_bolt_project(versioned_project) do |context|
|
211
|
+
ps_parameters = {
|
212
|
+
'versioned_project' => versioned_project
|
213
|
+
}
|
214
|
+
pe_task_info(context[:pal], *task_name_segments, ps_parameters)
|
215
|
+
end
|
216
|
+
@file_cache.cache_project_file(versioned_project, cached_file_name, new_metadata.to_json)
|
217
|
+
new_metadata
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def apply_prep(target, body)
|
223
|
+
validate_schema(@schemas["action-apply_prep"], body)
|
224
|
+
plugins_tarball = plugin_tarball(body['versioned_project'], 'fact_plugins')
|
225
|
+
install_task_segments = extract_install_task(target.first)
|
226
|
+
task_data = project_task_metadata(body['versioned_project'], install_task_segments, body["job_id"])
|
227
|
+
task = Bolt::Task::PuppetServer.new(task_data['name'], task_data['metadata'], task_data['files'], @file_cache)
|
228
|
+
install_task_result = task_helper(target, task, target.first.plugin_hooks['puppet_library']['parameters'] || {})
|
229
|
+
return install_task_result unless install_task_result.ok
|
230
|
+
task_data = project_task_metadata(body['versioned_project'], %w[apply_helpers custom_facts], body["job_id"])
|
231
|
+
task = Bolt::Task::PuppetServer.new(task_data['name'], task_data['metadata'], task_data['files'], @file_cache)
|
232
|
+
task_helper(target, task, { 'plugins' => plugins_tarball })
|
233
|
+
end
|
234
|
+
|
235
|
+
def apply(target, body)
|
236
|
+
validate_schema(@schemas["action-apply"], body)
|
237
|
+
plugins_tarball = plugin_tarball(body['versioned_project'], 'all_plugins')
|
238
|
+
task_data = project_task_metadata(body['versioned_project'], %w[apply_helpers apply_catalog], body["job_id"])
|
239
|
+
task = Bolt::Task::PuppetServer.new(task_data['name'], task_data['metadata'], task_data['files'], @file_cache)
|
240
|
+
task_helper(target, task, body['parameters'].merge({ 'plugins' => plugins_tarball }))
|
241
|
+
end
|
242
|
+
|
145
243
|
def run_command(target, body)
|
146
244
|
validate_schema(@schemas["action-run_command"], body)
|
147
245
|
command = body['command']
|
@@ -389,6 +487,63 @@ module BoltServer
|
|
389
487
|
end
|
390
488
|
end
|
391
489
|
|
490
|
+
# The provided block takes a module object and returns the list
|
491
|
+
# of directories to search through. This is similar to
|
492
|
+
# Bolt::Applicator.build_plugin_tarball.
|
493
|
+
def build_project_plugins_tarball(versioned_project, &block)
|
494
|
+
start_time = Time.now
|
495
|
+
|
496
|
+
# Fetch the plugin files
|
497
|
+
plugin_files = in_bolt_project(versioned_project) do |context|
|
498
|
+
files = {}
|
499
|
+
|
500
|
+
# Bolt also sets plugin_modulepath to user modulepath so do it here too for
|
501
|
+
# consistency
|
502
|
+
plugin_modulepath = context[:pal].user_modulepath
|
503
|
+
Puppet.lookup(:current_environment).override_with(modulepath: plugin_modulepath).modules.each do |mod|
|
504
|
+
search_dirs = block.call(mod)
|
505
|
+
|
506
|
+
files[mod] ||= []
|
507
|
+
Find.find(*search_dirs).each do |file|
|
508
|
+
files[mod] << file if File.file?(file)
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
512
|
+
files
|
513
|
+
end
|
514
|
+
|
515
|
+
# Pack the plugin files
|
516
|
+
sio = StringIO.new
|
517
|
+
begin
|
518
|
+
output = Minitar::Output.new(Zlib::GzipWriter.new(sio))
|
519
|
+
|
520
|
+
plugin_files.each do |mod, files|
|
521
|
+
tar_dir = Pathname.new(mod.name)
|
522
|
+
mod_dir = Pathname.new(mod.path)
|
523
|
+
|
524
|
+
files.each do |file|
|
525
|
+
tar_path = tar_dir + Pathname.new(file).relative_path_from(mod_dir)
|
526
|
+
stat = File.stat(file)
|
527
|
+
content = File.binread(file)
|
528
|
+
output.tar.add_file_simple(
|
529
|
+
tar_path.to_s,
|
530
|
+
data: content,
|
531
|
+
size: content.size,
|
532
|
+
mode: stat.mode & 0o777,
|
533
|
+
mtime: stat.mtime
|
534
|
+
)
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
duration = Time.now - start_time
|
539
|
+
@logger.trace("Packed plugins in #{duration * 1000} ms")
|
540
|
+
ensure
|
541
|
+
output.close
|
542
|
+
end
|
543
|
+
|
544
|
+
Base64.encode64(sio.string)
|
545
|
+
end
|
546
|
+
|
392
547
|
get '/' do
|
393
548
|
200
|
394
549
|
end
|
@@ -419,6 +574,8 @@ module BoltServer
|
|
419
574
|
run_task
|
420
575
|
run_script
|
421
576
|
upload_file
|
577
|
+
apply
|
578
|
+
apply_prep
|
422
579
|
].freeze
|
423
580
|
|
424
581
|
def make_ssh_target(target_hash)
|
@@ -441,8 +598,9 @@ module BoltServer
|
|
441
598
|
'uri' => target_hash['hostname'],
|
442
599
|
'config' => {
|
443
600
|
'transport' => 'ssh',
|
444
|
-
'ssh' => opts
|
445
|
-
}
|
601
|
+
'ssh' => opts.slice(*Bolt::Config::Transport::SSH.options)
|
602
|
+
},
|
603
|
+
'plugin_hooks' => target_hash['plugin_hooks']
|
446
604
|
}
|
447
605
|
|
448
606
|
inventory = Bolt::Inventory.empty
|
@@ -479,8 +637,9 @@ module BoltServer
|
|
479
637
|
'uri' => target_hash['hostname'],
|
480
638
|
'config' => {
|
481
639
|
'transport' => 'winrm',
|
482
|
-
'winrm' => opts
|
483
|
-
}
|
640
|
+
'winrm' => opts.slice(*Bolt::Config::Transport::WinRM.options)
|
641
|
+
},
|
642
|
+
'plugin_hooks' => target_hash['plugin_hooks']
|
484
643
|
}
|
485
644
|
|
486
645
|
inventory = Bolt::Inventory.empty
|
@@ -699,60 +858,21 @@ module BoltServer
|
|
699
858
|
raise BoltServer::RequestError, "'versioned_project' is a required argument" if params['versioned_project'].nil?
|
700
859
|
content_type :json
|
701
860
|
|
702
|
-
|
703
|
-
start_time = Time.now
|
704
|
-
|
705
|
-
# Fetch the plugin files
|
706
|
-
plugin_files = in_bolt_project(params['versioned_project']) do |context|
|
707
|
-
files = {}
|
708
|
-
|
709
|
-
# Bolt also sets plugin_modulepath to user modulepath so do it here too for
|
710
|
-
# consistency
|
711
|
-
plugin_modulepath = context[:pal].user_modulepath
|
712
|
-
Puppet.lookup(:current_environment).override_with(modulepath: plugin_modulepath).modules.each do |mod|
|
713
|
-
search_dirs = []
|
714
|
-
search_dirs << mod.plugins if mod.plugins?
|
715
|
-
search_dirs << mod.pluginfacts if mod.pluginfacts?
|
716
|
-
|
717
|
-
files[mod] ||= []
|
718
|
-
Find.find(*search_dirs).each do |file|
|
719
|
-
files[mod] << file if File.file?(file)
|
720
|
-
end
|
721
|
-
end
|
722
|
-
|
723
|
-
files
|
724
|
-
end
|
861
|
+
plugins_tarball = plugin_tarball(params['versioned_project'], 'fact_plugins')
|
725
862
|
|
726
|
-
|
727
|
-
|
728
|
-
begin
|
729
|
-
output = Minitar::Output.new(Zlib::GzipWriter.new(sio))
|
730
|
-
|
731
|
-
plugin_files.each do |mod, files|
|
732
|
-
tar_dir = Pathname.new(mod.name)
|
733
|
-
mod_dir = Pathname.new(mod.path)
|
863
|
+
[200, plugins_tarball.to_json]
|
864
|
+
end
|
734
865
|
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
data: content,
|
742
|
-
size: content.size,
|
743
|
-
mode: stat.mode & 0o777,
|
744
|
-
mtime: stat.mtime
|
745
|
-
)
|
746
|
-
end
|
747
|
-
end
|
866
|
+
# Returns the base64 encoded tar archive of _all_ plugin code for a project
|
867
|
+
#
|
868
|
+
# @param versioned_project [String] the versioned_project to build the plugin tarball from
|
869
|
+
get '/project_plugin_tarball' do
|
870
|
+
raise BoltServer::RequestError, "'versioned_project' is a required argument" if params['versioned_project'].nil?
|
871
|
+
content_type :json
|
748
872
|
|
749
|
-
|
750
|
-
@logger.trace("Packed plugins in #{duration * 1000} ms")
|
751
|
-
ensure
|
752
|
-
output.close
|
753
|
-
end
|
873
|
+
plugins_tarball = plugin_tarball(params['versioned_project'], 'all_plugins')
|
754
874
|
|
755
|
-
[200,
|
875
|
+
[200, plugins_tarball.to_json]
|
756
876
|
end
|
757
877
|
|
758
878
|
error 404 do
|