bolt 2.22.0 → 2.26.0
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/datatypes/result.rb +2 -1
- data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +1 -1
- data/bolt-modules/ctrl/lib/puppet/functions/ctrl/do_until.rb +12 -6
- data/bolt-modules/dir/lib/puppet/functions/dir/children.rb +1 -1
- data/bolt-modules/out/lib/puppet/functions/out/message.rb +1 -1
- data/exe/bolt +1 -0
- data/guides/inventory.txt +19 -0
- data/guides/project.txt +22 -0
- data/lib/bolt/analytics.rb +8 -8
- data/lib/bolt/applicator.rb +6 -6
- data/lib/bolt/bolt_option_parser.rb +47 -24
- data/lib/bolt/catalog.rb +4 -2
- data/lib/bolt/cli.rb +97 -78
- data/lib/bolt/config.rb +46 -24
- data/lib/bolt/config/options.rb +9 -6
- data/lib/bolt/executor.rb +10 -8
- data/lib/bolt/inventory.rb +8 -1
- data/lib/bolt/inventory/group.rb +4 -4
- data/lib/bolt/inventory/inventory.rb +1 -1
- data/lib/bolt/inventory/target.rb +1 -1
- data/lib/bolt/logger.rb +12 -6
- data/lib/bolt/outputter.rb +56 -0
- data/lib/bolt/outputter/human.rb +10 -9
- data/lib/bolt/outputter/json.rb +11 -4
- data/lib/bolt/outputter/logger.rb +3 -3
- data/lib/bolt/outputter/rainbow.rb +15 -0
- data/lib/bolt/pal.rb +9 -19
- data/lib/bolt/pal/yaml_plan/evaluator.rb +2 -2
- data/lib/bolt/pal/yaml_plan/transpiler.rb +11 -3
- data/lib/bolt/plugin/prompt.rb +3 -3
- data/lib/bolt/plugin/puppetdb.rb +1 -1
- data/lib/bolt/project.rb +32 -19
- data/lib/bolt/project_migrate.rb +138 -0
- data/lib/bolt/puppetdb/client.rb +1 -1
- data/lib/bolt/puppetdb/config.rb +1 -1
- data/lib/bolt/r10k_log_proxy.rb +1 -1
- data/lib/bolt/rerun.rb +1 -1
- data/lib/bolt/result.rb +8 -0
- data/lib/bolt/shell.rb +1 -1
- data/lib/bolt/shell/bash.rb +7 -7
- data/lib/bolt/task.rb +1 -1
- data/lib/bolt/transport/base.rb +1 -1
- data/lib/bolt/transport/docker/connection.rb +10 -10
- data/lib/bolt/transport/local/connection.rb +3 -3
- data/lib/bolt/transport/orch.rb +3 -3
- data/lib/bolt/transport/ssh.rb +1 -1
- data/lib/bolt/transport/ssh/connection.rb +6 -6
- data/lib/bolt/transport/ssh/exec_connection.rb +5 -5
- data/lib/bolt/transport/winrm.rb +1 -1
- data/lib/bolt/transport/winrm/connection.rb +9 -9
- data/lib/bolt/util.rb +2 -2
- data/lib/bolt/util/puppet_log_level.rb +4 -3
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/base_config.rb +1 -1
- data/lib/bolt_server/file_cache.rb +1 -1
- data/lib/bolt_server/pe/pal.rb +1 -1
- data/lib/bolt_server/transport_app.rb +76 -0
- data/lib/bolt_spec/plans.rb +1 -1
- data/lib/bolt_spec/plans/action_stubs.rb +1 -1
- data/lib/bolt_spec/run.rb +3 -0
- data/libexec/apply_catalog.rb +2 -2
- data/libexec/bolt_catalog +1 -1
- data/libexec/custom_facts.rb +1 -1
- data/libexec/query_resources.rb +1 -1
- metadata +9 -12
data/lib/bolt/task.rb
CHANGED
data/lib/bolt/transport/base.rb
CHANGED
@@ -10,9 +10,9 @@ module Bolt
|
|
10
10
|
def initialize(target)
|
11
11
|
raise Bolt::ValidationError, "Target #{target.safe_name} does not have a host" unless target.host
|
12
12
|
@target = target
|
13
|
-
@logger =
|
13
|
+
@logger = Bolt::Logger.logger(target.safe_name)
|
14
14
|
@docker_host = @target.options['service-url']
|
15
|
-
@logger.
|
15
|
+
@logger.trace("Initializing docker connection to #{@target.safe_name}")
|
16
16
|
end
|
17
17
|
|
18
18
|
def connect
|
@@ -25,7 +25,7 @@ module Bolt
|
|
25
25
|
output = execute_local_docker_json_command('inspect', [output[index]["ID"]])
|
26
26
|
# Store the container information for later
|
27
27
|
@container_info = output[0]
|
28
|
-
@logger.
|
28
|
+
@logger.trace { "Opened session" }
|
29
29
|
true
|
30
30
|
rescue StandardError => e
|
31
31
|
raise Bolt::Node::ConnectError.new(
|
@@ -57,16 +57,16 @@ module Bolt
|
|
57
57
|
command_options << container_id
|
58
58
|
command_options.concat(command)
|
59
59
|
|
60
|
-
@logger.
|
60
|
+
@logger.trace { "Executing: exec #{command_options}" }
|
61
61
|
|
62
62
|
stdout_str, stderr_str, status = execute_local_docker_command('exec', command_options, options[:stdin])
|
63
63
|
|
64
64
|
# The actual result is the exitstatus not the process object
|
65
65
|
status = status.nil? ? -32768 : status.exitstatus
|
66
66
|
if status == 0
|
67
|
-
@logger.
|
67
|
+
@logger.trace { "Command returned successfully" }
|
68
68
|
else
|
69
|
-
@logger.
|
69
|
+
@logger.trace { "Command failed with exit code #{status}" }
|
70
70
|
end
|
71
71
|
stdout_str.force_encoding(Encoding::UTF_8)
|
72
72
|
stderr_str.force_encoding(Encoding::UTF_8)
|
@@ -75,12 +75,12 @@ module Bolt
|
|
75
75
|
stderr_str.gsub!("\r\n", "\n")
|
76
76
|
[stdout_str, stderr_str, status]
|
77
77
|
rescue StandardError
|
78
|
-
@logger.
|
78
|
+
@logger.trace { "Command aborted" }
|
79
79
|
raise
|
80
80
|
end
|
81
81
|
|
82
82
|
def write_remote_file(source, destination)
|
83
|
-
@logger.
|
83
|
+
@logger.trace { "Uploading #{source} to #{destination}" }
|
84
84
|
_, stdout_str, status = execute_local_docker_command('cp', [source, "#{container_id}:#{destination}"])
|
85
85
|
unless status.exitstatus.zero?
|
86
86
|
raise "Error writing file to container #{@container_id}: #{stdout_str}"
|
@@ -90,7 +90,7 @@ module Bolt
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def write_remote_directory(source, destination)
|
93
|
-
@logger.
|
93
|
+
@logger.trace { "Uploading #{source} to #{destination}" }
|
94
94
|
_, stdout_str, status = execute_local_docker_command('cp', [source, "#{container_id}:#{destination}"])
|
95
95
|
unless status.exitstatus.zero?
|
96
96
|
raise "Error writing directory to container #{@container_id}: #{stdout_str}"
|
@@ -100,7 +100,7 @@ module Bolt
|
|
100
100
|
end
|
101
101
|
|
102
102
|
def download_remote_content(source, destination)
|
103
|
-
@logger.
|
103
|
+
@logger.trace { "Downloading #{source} to #{destination}" }
|
104
104
|
# Create the destination directory, otherwise copying a source directory with Docker will
|
105
105
|
# copy the *contents* of the directory.
|
106
106
|
# https://docs.docker.com/engine/reference/commandline/cp/
|
@@ -16,7 +16,7 @@ module Bolt
|
|
16
16
|
@target = target
|
17
17
|
# The familiar problem: Etc.getlogin is broken on osx
|
18
18
|
@user = ENV['USER'] || Etc.getlogin
|
19
|
-
@logger =
|
19
|
+
@logger = Bolt::Logger.logger(self)
|
20
20
|
end
|
21
21
|
|
22
22
|
def shell
|
@@ -28,7 +28,7 @@ module Bolt
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def upload_file(source, dest)
|
31
|
-
@logger.
|
31
|
+
@logger.trace { "Uploading #{source} to #{dest}" }
|
32
32
|
if source.is_a?(StringIO)
|
33
33
|
Tempfile.create(File.basename(dest)) do |f|
|
34
34
|
f.write(source.read)
|
@@ -46,7 +46,7 @@ module Bolt
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def download_file(source, dest, _download)
|
49
|
-
@logger.
|
49
|
+
@logger.trace { "Downloading #{source} to #{dest}" }
|
50
50
|
# Create the destination directory for the target, or the
|
51
51
|
# copied file will have the target's name
|
52
52
|
FileUtils.mkdir_p(dest)
|
data/lib/bolt/transport/orch.rb
CHANGED
@@ -38,7 +38,7 @@ module Bolt
|
|
38
38
|
@connections.each_value do |conn|
|
39
39
|
conn.finish_plan(result)
|
40
40
|
rescue StandardError => e
|
41
|
-
@logger.
|
41
|
+
@logger.trace("Failed to finish plan on #{conn.key}: #{e.message}")
|
42
42
|
end
|
43
43
|
end
|
44
44
|
end
|
@@ -133,7 +133,7 @@ module Bolt
|
|
133
133
|
next unless File.file?(file)
|
134
134
|
|
135
135
|
tar_path = Pathname.new(file).relative_path_from(Pathname.new(directory))
|
136
|
-
@logger.
|
136
|
+
@logger.trace("Packing #{file} to #{tar_path}")
|
137
137
|
stat = File.stat(file)
|
138
138
|
content = File.binread(file)
|
139
139
|
output.tar.add_file_simple(
|
@@ -146,7 +146,7 @@ module Bolt
|
|
146
146
|
end
|
147
147
|
|
148
148
|
duration = Time.now - start_time
|
149
|
-
@logger.
|
149
|
+
@logger.trace("Packed upload in #{duration * 1000} ms")
|
150
150
|
|
151
151
|
output.close
|
152
152
|
io.string
|
data/lib/bolt/transport/ssh.rb
CHANGED
@@ -17,7 +17,7 @@ module Bolt
|
|
17
17
|
rescue LoadError
|
18
18
|
logger.debug("Authentication method 'gssapi-with-mic' (Kerberos) is not available.")
|
19
19
|
end
|
20
|
-
@transport_logger =
|
20
|
+
@transport_logger = Bolt::Logger.logger(Net::SSH)
|
21
21
|
@transport_logger.level = :warn
|
22
22
|
end
|
23
23
|
|
@@ -26,9 +26,9 @@ module Bolt
|
|
26
26
|
@user = @target.user || ssh_config[:user] || Etc.getlogin
|
27
27
|
@strict_host_key_checking = ssh_config[:strict_host_key_checking]
|
28
28
|
|
29
|
-
@logger =
|
29
|
+
@logger = Bolt::Logger.logger(@target.safe_name)
|
30
30
|
@transport_logger = transport_logger
|
31
|
-
@logger.
|
31
|
+
@logger.trace("Initializing ssh connection to #{@target.safe_name}")
|
32
32
|
|
33
33
|
if target.options['private-key']&.instance_of?(String)
|
34
34
|
begin
|
@@ -131,7 +131,7 @@ module Bolt
|
|
131
131
|
|
132
132
|
@session = Net::SSH.start(target.host, @user, options)
|
133
133
|
validate_ssh_version
|
134
|
-
@logger.
|
134
|
+
@logger.trace { "Opened session" }
|
135
135
|
rescue Net::SSH::AuthenticationFailed => e
|
136
136
|
raise Bolt::Node::ConnectError.new(
|
137
137
|
e.message,
|
@@ -161,7 +161,7 @@ module Bolt
|
|
161
161
|
rescue Timeout::Error
|
162
162
|
@session.shutdown!
|
163
163
|
end
|
164
|
-
@logger.
|
164
|
+
@logger.trace { "Closed session" }
|
165
165
|
end
|
166
166
|
end
|
167
167
|
|
@@ -237,7 +237,7 @@ module Bolt
|
|
237
237
|
|
238
238
|
def upload_file(source, destination)
|
239
239
|
# Do not log wrapper script content
|
240
|
-
@logger.
|
240
|
+
@logger.trace { "Uploading #{source} to #{destination}" } unless source.is_a?(StringIO)
|
241
241
|
@session.scp.upload!(source, destination, recursive: true)
|
242
242
|
rescue StandardError => e
|
243
243
|
raise Bolt::Node::FileError.new(e.message, 'WRITE_ERROR')
|
@@ -245,7 +245,7 @@ module Bolt
|
|
245
245
|
|
246
246
|
def download_file(source, destination, _download)
|
247
247
|
# Do not log wrapper script content
|
248
|
-
@logger.
|
248
|
+
@logger.trace { "Downloading #{source} to #{destination}" }
|
249
249
|
@session.scp.download!(source, destination, recursive: true)
|
250
250
|
rescue StandardError => e
|
251
251
|
raise Bolt::Node::FileError.new(e.message, 'WRITE_ERROR')
|
@@ -14,7 +14,7 @@ module Bolt
|
|
14
14
|
@target = target
|
15
15
|
ssh_config = Net::SSH::Config.for(target.host)
|
16
16
|
@user = @target.user || ssh_config[:user] || Etc.getlogin
|
17
|
-
@logger =
|
17
|
+
@logger = Bolt::Logger.logger(self)
|
18
18
|
end
|
19
19
|
|
20
20
|
# This is used to verify we can connect to targets with `connected?`
|
@@ -66,7 +66,7 @@ module Bolt
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def upload_file(source, dest)
|
69
|
-
@logger.
|
69
|
+
@logger.trace { "Uploading #{source} to #{dest}" } unless source.is_a?(StringIO)
|
70
70
|
|
71
71
|
cp_conf = @target.transport_config['copy-command'] || ["scp", "-r"]
|
72
72
|
cp_cmd = Array(cp_conf)
|
@@ -87,7 +87,7 @@ module Bolt
|
|
87
87
|
end
|
88
88
|
|
89
89
|
if stat.success?
|
90
|
-
@logger.
|
90
|
+
@logger.trace "Successfully uploaded #{source} to #{dest}"
|
91
91
|
else
|
92
92
|
message = "Could not copy file to #{dest}: #{err}"
|
93
93
|
raise Bolt::Node::FileError.new(message, 'COPY_ERROR')
|
@@ -95,7 +95,7 @@ module Bolt
|
|
95
95
|
end
|
96
96
|
|
97
97
|
def download_file(source, dest, _download)
|
98
|
-
@logger.
|
98
|
+
@logger.trace { "Downloading #{userhost}:#{source} to #{dest}" }
|
99
99
|
|
100
100
|
FileUtils.mkdir_p(dest)
|
101
101
|
|
@@ -108,7 +108,7 @@ module Bolt
|
|
108
108
|
_, err, stat = Open3.capture3(*cp_cmd)
|
109
109
|
|
110
110
|
if stat.success?
|
111
|
-
@logger.
|
111
|
+
@logger.trace "Successfully downloaded #{userhost}:#{source} to #{dest}"
|
112
112
|
else
|
113
113
|
message = "Could not copy file to #{dest}: #{err}"
|
114
114
|
raise Bolt::Node::FileError.new(message, 'COPY_ERROR')
|
data/lib/bolt/transport/winrm.rb
CHANGED
@@ -18,8 +18,8 @@ module Bolt
|
|
18
18
|
@user = @target.user
|
19
19
|
# Build set of extensions from extensions config as well as interpreters
|
20
20
|
|
21
|
-
@logger =
|
22
|
-
logger.
|
21
|
+
@logger = Bolt::Logger.logger(@target.safe_name)
|
22
|
+
logger.trace("Initializing winrm connection to #{@target.safe_name}")
|
23
23
|
@transport_logger = transport_logger
|
24
24
|
end
|
25
25
|
|
@@ -55,7 +55,7 @@ module Bolt
|
|
55
55
|
|
56
56
|
@session = @connection.shell(:powershell)
|
57
57
|
@session.run('$PSVersionTable.PSVersion')
|
58
|
-
@logger.
|
58
|
+
@logger.trace { "Opened session" }
|
59
59
|
end
|
60
60
|
rescue Timeout::Error
|
61
61
|
# If we're using the default port with SSL, a timeout probably means the
|
@@ -97,11 +97,11 @@ module Bolt
|
|
97
97
|
def disconnect
|
98
98
|
@session&.close
|
99
99
|
@client&.disconnect!
|
100
|
-
@logger.
|
100
|
+
@logger.trace { "Closed session" }
|
101
101
|
end
|
102
102
|
|
103
103
|
def execute(command)
|
104
|
-
@logger.
|
104
|
+
@logger.trace { "Executing command: #{command}" }
|
105
105
|
|
106
106
|
inp = StringIO.new
|
107
107
|
# This transport doesn't accept stdin, so close the stream to ensure
|
@@ -134,12 +134,12 @@ module Bolt
|
|
134
134
|
"with 'ulimit -n 1024'. See https://puppet.com/docs/bolt/latest/bolt_known_issues.html for details."
|
135
135
|
raise Bolt::Error.new(msg, 'bolt/too-many-files')
|
136
136
|
rescue StandardError
|
137
|
-
@logger.
|
137
|
+
@logger.trace { "Command aborted" }
|
138
138
|
raise
|
139
139
|
end
|
140
140
|
|
141
141
|
def upload_file(source, destination)
|
142
|
-
@logger.
|
142
|
+
@logger.trace { "Uploading #{source} to #{destination}" }
|
143
143
|
if target.options['file-protocol'] == 'smb'
|
144
144
|
upload_file_smb(source, destination)
|
145
145
|
else
|
@@ -185,7 +185,7 @@ module Bolt
|
|
185
185
|
end
|
186
186
|
|
187
187
|
def download_file(source, destination, download)
|
188
|
-
@logger.
|
188
|
+
@logger.trace { "Downloading #{source} to #{destination}" }
|
189
189
|
if target.options['file-protocol'] == 'smb'
|
190
190
|
download_file_smb(source, destination)
|
191
191
|
else
|
@@ -257,7 +257,7 @@ module Bolt
|
|
257
257
|
status = @client.login
|
258
258
|
case status
|
259
259
|
when WindowsError::NTStatus::STATUS_SUCCESS
|
260
|
-
@logger.
|
260
|
+
@logger.trace { "Connected to #{@client.dns_host_name}" }
|
261
261
|
when WindowsError::NTStatus::STATUS_LOGON_FAILURE
|
262
262
|
raise Bolt::Node::ConnectError.new(
|
263
263
|
"SMB authentication failed for #{target.safe_name}",
|
data/lib/bolt/util.rb
CHANGED
@@ -6,14 +6,14 @@ module Bolt
|
|
6
6
|
def read_yaml_hash(path, file_name)
|
7
7
|
require 'yaml'
|
8
8
|
|
9
|
-
logger =
|
9
|
+
logger = Bolt::Logger.logger(self)
|
10
10
|
path = File.expand_path(path)
|
11
11
|
content = File.open(path, "r:UTF-8") { |f| YAML.safe_load(f.read) } || {}
|
12
12
|
unless content.is_a?(Hash)
|
13
13
|
msg = "Invalid content for #{file_name} file: #{path} should be a Hash or empty, not #{content.class}"
|
14
14
|
raise Bolt::FileError.new(msg, path)
|
15
15
|
end
|
16
|
-
logger.
|
16
|
+
logger.trace("Loaded #{file_name} from #{path}")
|
17
17
|
content
|
18
18
|
rescue Errno::ENOENT
|
19
19
|
raise Bolt::FileError.new("Could not read #{file_name} file: #{path}", path)
|
@@ -4,9 +4,10 @@ module Bolt
|
|
4
4
|
module Util
|
5
5
|
module PuppetLogLevel
|
6
6
|
MAPPING = {
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
# Demote Puppet's logs by one level, since Puppet is an implementation detail of Bolt
|
8
|
+
debug: :trace,
|
9
|
+
info: :debug,
|
10
|
+
notice: :info,
|
10
11
|
warning: :warn,
|
11
12
|
err: :error,
|
12
13
|
# The following are used by Puppet functions of the same name, and are all treated as
|
data/lib/bolt/version.rb
CHANGED
data/lib/bolt_server/pe/pal.rb
CHANGED
@@ -58,7 +58,7 @@ module BoltServer
|
|
58
58
|
# Bolt::PAL::MODULES_PATH which would be more complex if we tried to use @modulepath since
|
59
59
|
# we need to append our modulepaths and exclude modules shiped in bolt gem code
|
60
60
|
modulepath_dirs = environment.modulepath
|
61
|
-
@
|
61
|
+
@user_modulepath = modulepath_dirs
|
62
62
|
@modulepath = [PE_BOLTLIB_PATH, Bolt::PAL::BOLTLIB_PATH, *modulepath_dirs]
|
63
63
|
end
|
64
64
|
end
|
@@ -221,6 +221,56 @@ module BoltServer
|
|
221
221
|
plan_info
|
222
222
|
end
|
223
223
|
|
224
|
+
def build_puppetserver_uri(file_identifier, module_name, environment)
|
225
|
+
segments = file_identifier.split('/', 3)
|
226
|
+
if segments.size == 1
|
227
|
+
{
|
228
|
+
'path' => "/puppet/v3/file_content/tasks/#{module_name}/#{file_identifier}",
|
229
|
+
'params' => {
|
230
|
+
'environment' => environment
|
231
|
+
}
|
232
|
+
}
|
233
|
+
else
|
234
|
+
module_segment, mount_segment, name_segment = *segments
|
235
|
+
{
|
236
|
+
'path' => case mount_segment
|
237
|
+
when 'files'
|
238
|
+
"/puppet/v3/file_content/modules/#{module_segment}/#{name_segment}"
|
239
|
+
when 'tasks'
|
240
|
+
"/puppet/v3/file_content/tasks/#{module_segment}/#{name_segment}"
|
241
|
+
when 'lib'
|
242
|
+
"/puppet/v3/file_content/plugins/#{name_segment}"
|
243
|
+
end,
|
244
|
+
'params' => {
|
245
|
+
'environment' => environment
|
246
|
+
}
|
247
|
+
}
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def pe_task_info(pal, module_name, task_name, environment)
|
252
|
+
# Handle case where task name is simply module name with special `init` task
|
253
|
+
task_name = if task_name == 'init' || task_name.nil?
|
254
|
+
module_name
|
255
|
+
else
|
256
|
+
"#{module_name}::#{task_name}"
|
257
|
+
end
|
258
|
+
task = pal.get_task(task_name)
|
259
|
+
files = task.files.map do |file_hash|
|
260
|
+
{
|
261
|
+
'filename' => file_hash['name'],
|
262
|
+
'sha256' => Digest::SHA256.hexdigest(File.read(file_hash['path'])),
|
263
|
+
'size_bytes' => File.size(file_hash['path']),
|
264
|
+
'uri' => build_puppetserver_uri(file_hash['name'], module_name, environment)
|
265
|
+
}
|
266
|
+
end
|
267
|
+
{
|
268
|
+
'metadata' => task.metadata,
|
269
|
+
'name' => task.name,
|
270
|
+
'files' => files
|
271
|
+
}
|
272
|
+
end
|
273
|
+
|
224
274
|
get '/' do
|
225
275
|
200
|
226
276
|
end
|
@@ -351,6 +401,16 @@ module BoltServer
|
|
351
401
|
end
|
352
402
|
end
|
353
403
|
|
404
|
+
# Fetches the metadata for a single task
|
405
|
+
#
|
406
|
+
# @param environment [String] the environment to fetch the task from
|
407
|
+
get '/tasks/:module_name/:task_name' do
|
408
|
+
in_pe_pal_env(params['environment']) do |pal|
|
409
|
+
task_info = pe_task_info(pal, params[:module_name], params[:task_name], params['environment'])
|
410
|
+
[200, task_info.to_json]
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
354
414
|
# Fetches the list of plans for an environment, optionally fetching all metadata for each plan
|
355
415
|
#
|
356
416
|
# @param environment [String] the environment to fetch the list of plans from
|
@@ -375,6 +435,22 @@ module BoltServer
|
|
375
435
|
end
|
376
436
|
end
|
377
437
|
|
438
|
+
# Fetches the list of tasks for an environment
|
439
|
+
#
|
440
|
+
# @param environment [String] the environment to fetch the list of tasks from
|
441
|
+
get '/tasks' do
|
442
|
+
in_pe_pal_env(params['environment']) do |pal|
|
443
|
+
tasks = pal.list_tasks
|
444
|
+
tasks_response = tasks.map { |task_name, _description| { 'name' => task_name } }.to_json
|
445
|
+
|
446
|
+
# We structure this array of tasks to be an array of hashes so that it matches the structure
|
447
|
+
# returned by the puppetserver API that serves data like this. Structuring the output this way
|
448
|
+
# makes switching between puppetserver and bolt-server easier, which makes changes to switch
|
449
|
+
# to bolt-server smaller/simpler.
|
450
|
+
[200, tasks_response]
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
378
454
|
error 404 do
|
379
455
|
err = Bolt::Error.new("Could not find route #{request.path}",
|
380
456
|
'boltserver/not-found')
|