bolt 2.44.0 → 3.0.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/functions/apply_prep.rb +25 -0
- data/bolt-modules/boltlib/lib/puppet/functions/wait_until_available.rb +7 -3
- data/lib/bolt/bolt_option_parser.rb +3 -120
- data/lib/bolt/cli.rb +30 -112
- data/lib/bolt/config.rb +35 -214
- data/lib/bolt/config/options.rb +13 -122
- data/lib/bolt/config/transport/local.rb +1 -0
- data/lib/bolt/config/transport/options.rb +1 -1
- data/lib/bolt/logger.rb +1 -1
- data/lib/bolt/outputter/human.rb +1 -1
- data/lib/bolt/outputter/json.rb +16 -16
- data/lib/bolt/pal.rb +1 -1
- data/lib/bolt/pal/yaml_plan/evaluator.rb +7 -19
- data/lib/bolt/pal/yaml_plan/step.rb +3 -24
- data/lib/bolt/pal/yaml_plan/step/upload.rb +2 -2
- data/lib/bolt/plugin/module.rb +0 -23
- data/lib/bolt/plugin/puppet_connect_data.rb +45 -3
- data/lib/bolt/project.rb +16 -56
- data/lib/bolt/project_manager.rb +4 -3
- data/lib/bolt/project_manager/module_migrator.rb +6 -5
- data/lib/bolt/shell/powershell.rb +1 -2
- data/lib/bolt/shell/powershell/snippets.rb +9 -149
- data/lib/bolt/transport/local.rb +1 -9
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/transport_app.rb +1 -1
- data/modules/aggregate/plans/count.pp +21 -0
- data/modules/aggregate/plans/targets.pp +21 -0
- data/modules/puppet_connect/plans/test_input_data.pp +31 -0
- data/modules/puppetdb_fact/plans/init.pp +10 -0
- metadata +3 -3
- data/modules/aggregate/plans/nodes.pp +0 -36
data/lib/bolt/project_manager.rb
CHANGED
@@ -166,10 +166,11 @@ module Bolt
|
|
166
166
|
# Migrates the project-level configuration file to the latest version.
|
167
167
|
#
|
168
168
|
private def migrate_config
|
169
|
-
migrator
|
169
|
+
migrator = ConfigMigrator.new(@outputter)
|
170
|
+
configfile = @config.project.path + 'bolt.yaml'
|
170
171
|
|
171
172
|
migrator.migrate(
|
172
|
-
|
173
|
+
configfile,
|
173
174
|
@config.project.project_file,
|
174
175
|
@config.inventoryfile || @config.project.inventory_file,
|
175
176
|
@config.project.backup_dir
|
@@ -194,7 +195,7 @@ module Bolt
|
|
194
195
|
|
195
196
|
migrator.migrate(
|
196
197
|
@config.project,
|
197
|
-
@config.modulepath
|
198
|
+
@config.modulepath[0...-1]
|
198
199
|
)
|
199
200
|
end
|
200
201
|
end
|
@@ -6,19 +6,20 @@ module Bolt
|
|
6
6
|
class ProjectManager
|
7
7
|
class ModuleMigrator < Migrator
|
8
8
|
def migrate(project, configured_modulepath)
|
9
|
-
return true
|
9
|
+
return true if project.managed_moduledir.exist?
|
10
10
|
|
11
11
|
@outputter.print_message "Migrating project modules\n\n"
|
12
12
|
|
13
13
|
config = project.project_file
|
14
14
|
puppetfile = project.puppetfile
|
15
15
|
managed_moduledir = project.managed_moduledir
|
16
|
-
|
16
|
+
new_modulepath = [(project.path + 'modules').to_s]
|
17
|
+
old_modulepath = [(project.path + 'modules').to_s,
|
17
18
|
(project.path + 'site-modules').to_s,
|
18
19
|
(project.path + 'site').to_s]
|
19
20
|
|
20
21
|
# Notify user to manually migrate modules if using non-default modulepath
|
21
|
-
if configured_modulepath !=
|
22
|
+
if configured_modulepath != new_modulepath && configured_modulepath != old_modulepath
|
22
23
|
@outputter.print_action_step(
|
23
24
|
"Project has a non-default configured modulepath, unable to automatically "\
|
24
25
|
"migrate project modules. To migrate project modules manually, see "\
|
@@ -27,10 +28,10 @@ module Bolt
|
|
27
28
|
true
|
28
29
|
# Migrate modules from Puppetfile
|
29
30
|
elsif File.exist?(puppetfile)
|
30
|
-
migrate_modules_from_puppetfile(config, puppetfile, managed_moduledir,
|
31
|
+
migrate_modules_from_puppetfile(config, puppetfile, managed_moduledir, old_modulepath)
|
31
32
|
# Migrate modules to updated modulepath
|
32
33
|
else
|
33
|
-
consolidate_modules(
|
34
|
+
consolidate_modules(old_modulepath)
|
34
35
|
update_project_config([], config)
|
35
36
|
end
|
36
37
|
end
|
@@ -23,8 +23,7 @@ module Bolt
|
|
23
23
|
# This lets us know how many targets have Powershell 2, and lets the
|
24
24
|
# user know how many targets they have with PS2
|
25
25
|
msg = "Detected PowerShell 2 on one or more targets.\nPowerShell 2 "\
|
26
|
-
"is
|
27
|
-
"bolt-debug.log or run with '--log-level debug' to see the full "\
|
26
|
+
"is unsupported. See bolt-debug.log or run with '--log-level debug' to see the full "\
|
28
27
|
"list of targets with PowerShell 2."
|
29
28
|
|
30
29
|
Bolt::Logger.deprecate_once("powershell_2", msg)
|
@@ -70,12 +70,17 @@ module Bolt
|
|
70
70
|
def ps_task(path, arguments)
|
71
71
|
<<~PS
|
72
72
|
$private:tempArgs = Get-ContentAsJson (
|
73
|
-
|
73
|
+
[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{Base64.encode64(JSON.dump(arguments))}'))
|
74
74
|
)
|
75
75
|
$allowedArgs = (Get-Command "#{path}").Parameters.Keys
|
76
76
|
$private:taskArgs = @{}
|
77
77
|
$private:tempArgs.Keys | ? { $allowedArgs -contains $_ } | % { $private:taskArgs[$_] = $private:tempArgs[$_] }
|
78
|
-
try {
|
78
|
+
try {
|
79
|
+
& "#{path}" @taskArgs
|
80
|
+
} catch {
|
81
|
+
$Host.UI.WriteErrorLine("[$($_.FullyQualifiedErrorId)] Exception $($_.InvocationInfo.PositionMessage).`n$($_.Exception.Message)");
|
82
|
+
exit 1;
|
83
|
+
}
|
79
84
|
PS
|
80
85
|
end
|
81
86
|
|
@@ -102,151 +107,11 @@ module Bolt
|
|
102
107
|
"${boltBaseDir}\\hiera\\lib;" +
|
103
108
|
$ENV:RUBYLIB
|
104
109
|
|
105
|
-
Add-Type -AssemblyName System.ServiceModel.Web, System.Runtime.Serialization
|
106
|
-
$utf8 = [System.Text.Encoding]::UTF8
|
107
|
-
|
108
|
-
function Write-Stream {
|
109
|
-
PARAM(
|
110
|
-
[Parameter(Position=0)] $stream,
|
111
|
-
[Parameter(ValueFromPipeline=$true)] $string
|
112
|
-
)
|
113
|
-
PROCESS {
|
114
|
-
$bytes = $utf8.GetBytes($string)
|
115
|
-
$stream.Write( $bytes, 0, $bytes.Length )
|
116
|
-
}
|
117
|
-
}
|
118
|
-
|
119
|
-
function Convert-JsonToXml {
|
120
|
-
PARAM([Parameter(ValueFromPipeline=$true)] [string[]] $json)
|
121
|
-
BEGIN {
|
122
|
-
$mStream = New-Object System.IO.MemoryStream
|
123
|
-
}
|
124
|
-
PROCESS {
|
125
|
-
$json | Write-Stream -Stream $mStream
|
126
|
-
}
|
127
|
-
END {
|
128
|
-
$mStream.Position = 0
|
129
|
-
try {
|
130
|
-
$jsonReader = [System.Runtime.Serialization.Json.JsonReaderWriterFactory]::CreateJsonReader($mStream,[System.Xml.XmlDictionaryReaderQuotas]::Max)
|
131
|
-
$xml = New-Object Xml.XmlDocument
|
132
|
-
$xml.Load($jsonReader)
|
133
|
-
$xml
|
134
|
-
} finally {
|
135
|
-
$jsonReader.Close()
|
136
|
-
$mStream.Dispose()
|
137
|
-
}
|
138
|
-
}
|
139
|
-
}
|
140
|
-
|
141
|
-
Function ConvertFrom-Xml {
|
142
|
-
[CmdletBinding(DefaultParameterSetName="AutoType")]
|
143
|
-
PARAM(
|
144
|
-
[Parameter(ValueFromPipeline=$true,Mandatory=$true,Position=1)] [Xml.XmlNode] $xml,
|
145
|
-
[Parameter(Mandatory=$true,ParameterSetName="ManualType")] [Type] $Type,
|
146
|
-
[Switch] $ForceType
|
147
|
-
)
|
148
|
-
PROCESS{
|
149
|
-
if (Get-Member -InputObject $xml -Name root) {
|
150
|
-
return $xml.root.Objects | ConvertFrom-Xml
|
151
|
-
} elseif (Get-Member -InputObject $xml -Name Objects) {
|
152
|
-
return $xml.Objects | ConvertFrom-Xml
|
153
|
-
}
|
154
|
-
$propbag = @{}
|
155
|
-
foreach ($name in Get-Member -InputObject $xml -MemberType Properties | Where-Object{$_.Name -notmatch "^(__.*|type)$"} | Select-Object -ExpandProperty name) {
|
156
|
-
Write-Debug "$Name Type: $($xml.$Name.type)" -Debug:$false
|
157
|
-
$propbag."$Name" = Convert-Properties $xml."$name"
|
158
|
-
}
|
159
|
-
if (!$Type -and $xml.HasAttribute("__type")) { $Type = $xml.__Type }
|
160
|
-
if ($ForceType -and $Type) {
|
161
|
-
try {
|
162
|
-
$output = New-Object $Type -Property $propbag
|
163
|
-
} catch {
|
164
|
-
$output = New-Object PSObject -Property $propbag
|
165
|
-
$output.PsTypeNames.Insert(0, $xml.__type)
|
166
|
-
}
|
167
|
-
} elseif ($propbag.Count -ne 0) {
|
168
|
-
$output = New-Object PSObject -Property $propbag
|
169
|
-
if ($Type) {
|
170
|
-
$output.PsTypeNames.Insert(0, $Type)
|
171
|
-
}
|
172
|
-
}
|
173
|
-
return $output
|
174
|
-
}
|
175
|
-
}
|
176
|
-
|
177
|
-
Function Convert-Properties {
|
178
|
-
PARAM($InputObject)
|
179
|
-
switch ($InputObject.type) {
|
180
|
-
"object" {
|
181
|
-
return (ConvertFrom-Xml -Xml $InputObject)
|
182
|
-
}
|
183
|
-
"string" {
|
184
|
-
$MightBeADate = $InputObject.get_InnerText() -as [DateTime]
|
185
|
-
## Strings that are actually dates (*grumble* JSON is crap)
|
186
|
-
if ($MightBeADate -and $propbag."$Name" -eq $MightBeADate.ToString("G")) {
|
187
|
-
return $MightBeADate
|
188
|
-
} else {
|
189
|
-
return $InputObject.get_InnerText()
|
190
|
-
}
|
191
|
-
}
|
192
|
-
"number" {
|
193
|
-
$number = $InputObject.get_InnerText()
|
194
|
-
if ($number -eq ($number -as [int])) {
|
195
|
-
return $number -as [int]
|
196
|
-
} elseif ($number -eq ($number -as [double])) {
|
197
|
-
return $number -as [double]
|
198
|
-
} else {
|
199
|
-
return $number -as [decimal]
|
200
|
-
}
|
201
|
-
}
|
202
|
-
"boolean" {
|
203
|
-
return [bool]::parse($InputObject.get_InnerText())
|
204
|
-
}
|
205
|
-
"null" {
|
206
|
-
return $null
|
207
|
-
}
|
208
|
-
"array" {
|
209
|
-
[object[]]$Items = $(foreach( $item in $InputObject.GetEnumerator() ) {
|
210
|
-
Convert-Properties $item
|
211
|
-
})
|
212
|
-
return $Items
|
213
|
-
}
|
214
|
-
default {
|
215
|
-
return $InputObject
|
216
|
-
}
|
217
|
-
}
|
218
|
-
}
|
219
|
-
|
220
|
-
Function ConvertFrom-Json2 {
|
221
|
-
[CmdletBinding()]
|
222
|
-
PARAM(
|
223
|
-
[Parameter(ValueFromPipeline=$true,Mandatory=$true,Position=1)] [string] $InputObject,
|
224
|
-
[Parameter(Mandatory=$true)] [Type] $Type,
|
225
|
-
[Switch] $ForceType
|
226
|
-
)
|
227
|
-
PROCESS {
|
228
|
-
$null = $PSBoundParameters.Remove("InputObject")
|
229
|
-
[Xml.XmlElement]$xml = (Convert-JsonToXml $InputObject).Root
|
230
|
-
if ($xml) {
|
231
|
-
if ($xml.Objects) {
|
232
|
-
$xml.Objects.Item.GetEnumerator() | ConvertFrom-Xml @PSBoundParameters
|
233
|
-
} elseif ($xml.Item -and $xml.Item -isnot [System.Management.Automation.PSParameterizedProperty]) {
|
234
|
-
$xml.Item | ConvertFrom-Xml @PSBoundParameters
|
235
|
-
} else {
|
236
|
-
$xml | ConvertFrom-Xml @PSBoundParameters
|
237
|
-
}
|
238
|
-
} else {
|
239
|
-
Write-Error "Failed to parse JSON with JsonReader" -Debug:$false
|
240
|
-
}
|
241
|
-
}
|
242
|
-
}
|
243
|
-
|
244
110
|
function ConvertFrom-PSCustomObject
|
245
111
|
{
|
246
112
|
PARAM([Parameter(ValueFromPipeline = $true)] $InputObject)
|
247
113
|
PROCESS {
|
248
114
|
if ($null -eq $InputObject) { return $null }
|
249
|
-
|
250
115
|
if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string]) {
|
251
116
|
$collection = @(
|
252
117
|
foreach ($object in $InputObject) { ConvertFrom-PSCustomObject $object }
|
@@ -273,13 +138,8 @@ module Bolt
|
|
273
138
|
[Parameter(Mandatory = $true)] $Text,
|
274
139
|
[Parameter(Mandatory = $false)] [Text.Encoding] $Encoding = [Text.Encoding]::UTF8
|
275
140
|
)
|
276
|
-
|
277
|
-
|
278
|
-
if ($PSVersionTable.PSVersion -lt [Version]'3.0') {
|
279
|
-
$Text | ConvertFrom-Json2 -Type PSObject | ConvertFrom-PSCustomObject
|
280
|
-
} else {
|
281
|
-
$Text | ConvertFrom-Json | ConvertFrom-PSCustomObject
|
282
|
-
}
|
141
|
+
|
142
|
+
$Text | ConvertFrom-Json | ConvertFrom-PSCustomObject
|
283
143
|
}
|
284
144
|
PS
|
285
145
|
end
|
data/lib/bolt/transport/local.rb
CHANGED
@@ -11,18 +11,10 @@ module Bolt
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def with_connection(target)
|
14
|
-
if target.transport_config['bundled-ruby']
|
14
|
+
if target.transport_config['bundled-ruby']
|
15
15
|
target.set_local_defaults
|
16
16
|
end
|
17
17
|
|
18
|
-
if target.name != 'localhost' &&
|
19
|
-
!target.transport_config.key?('bundled-ruby')
|
20
|
-
msg = "The local transport will default to using Bolt's Ruby interpreter and "\
|
21
|
-
"setting the 'puppet-agent' feature in Bolt 3.0. Enable or disable these "\
|
22
|
-
"defaults by setting 'bundled-ruby' in the local transport config."
|
23
|
-
Bolt::Logger.warn_once("local_default_config", msg)
|
24
|
-
end
|
25
|
-
|
26
18
|
yield Connection.new(target)
|
27
19
|
end
|
28
20
|
end
|
data/lib/bolt/version.rb
CHANGED
@@ -352,7 +352,7 @@ module BoltServer
|
|
352
352
|
end
|
353
353
|
|
354
354
|
def allowed_helper(metadata, allowlist)
|
355
|
-
allowed = allowlist.nil? || allowlist.include?(metadata['name'])
|
355
|
+
allowed = allowlist.nil? || allowlist.include?(metadata['name'])
|
356
356
|
metadata.merge({ 'allowed' => allowed })
|
357
357
|
end
|
358
358
|
|
@@ -1,3 +1,24 @@
|
|
1
|
+
# @summary
|
2
|
+
# Run a task, command, or script on targets and aggregate the results as
|
3
|
+
# a count of targets for each value of a key.
|
4
|
+
#
|
5
|
+
# This plan accepts an action and a list of targets. The action can be the name
|
6
|
+
# of a task, a script, or a command to run. It will run the action on the
|
7
|
+
# targets and aggregate the key/value pairs in each Result into a hash, mapping
|
8
|
+
# the keys to a hash of each distinct value and how many targets returned that
|
9
|
+
# value for the key.
|
10
|
+
#
|
11
|
+
# @param command
|
12
|
+
# The command to run. Mutually exclusive with script and task.
|
13
|
+
# @param script
|
14
|
+
# The path to the script to run. Mutually exclusive with command and task.
|
15
|
+
# @param task
|
16
|
+
# The name of the task to run. Mutually exclusive with command and script.
|
17
|
+
# @param targets
|
18
|
+
# The list of targets to run the action on.
|
19
|
+
# @param params
|
20
|
+
# A hash of parameters and options to pass to the `run_*` function
|
21
|
+
# associated with the action (e.g. run_task).
|
1
22
|
plan aggregate::count(
|
2
23
|
Optional[String[0]] $task = undef,
|
3
24
|
Optional[String[0]] $command = undef,
|
@@ -1,3 +1,24 @@
|
|
1
|
+
# @summary
|
2
|
+
# Run a task, command, or script on targets and aggregate the results as
|
3
|
+
# the list of targets for each value of a key in the results.
|
4
|
+
#
|
5
|
+
# This plan accepts an action and a list of targets. The action can be the name
|
6
|
+
# of a task, a script, or a command to run. It will run the action on the
|
7
|
+
# targets and aggregate the key/value pairs in each Result into a hash, mapping
|
8
|
+
# the keys to a hash of each distinct value and a list of targets returning that
|
9
|
+
# value.
|
10
|
+
#
|
11
|
+
# @param command
|
12
|
+
# The command to run. Mutually exclusive with script and task.
|
13
|
+
# @param script
|
14
|
+
# The path to the script to run. Mutually exclusive with command and task.
|
15
|
+
# @param task
|
16
|
+
# The name of the task to run. Mutually exclusive with command and script.
|
17
|
+
# @param targets
|
18
|
+
# The list of targets to run the action on.
|
19
|
+
# @param params
|
20
|
+
# A hash of parameters and options to pass to the `run_*` function
|
21
|
+
# associated with the action (e.g. run_task).
|
1
22
|
plan aggregate::targets(
|
2
23
|
Optional[String[0]] $task = undef,
|
3
24
|
Optional[String[0]] $command = undef,
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# @summary
|
2
|
+
# Tests that the provided Puppet Connect input data is complete, meaning that all consuming inventory targets are connectable.
|
3
|
+
#
|
4
|
+
# This plan should only be used as part of the copy-pastable "test input data"
|
5
|
+
# workflow specified in the Puppet Connect docs.
|
6
|
+
#
|
7
|
+
# @param targets
|
8
|
+
# The set of targets to test. Usually this should be 'all', the default.
|
9
|
+
#
|
10
|
+
# @return ResultSet the result of invoking the 'is connectable?' query on all
|
11
|
+
# the targets. Note that this query currently consists of running the 'echo'
|
12
|
+
# command.
|
13
|
+
#
|
14
|
+
plan puppet_connect::test_input_data(TargetSpec $targets = 'all') {
|
15
|
+
$targs = get_targets($targets)
|
16
|
+
$targs.each |$target| {
|
17
|
+
if $target.transport != 'ssh' and $target.transport != 'winrm' {
|
18
|
+
fail_plan("Inventory contains target ${target} with unsupported transport, must be ssh or winrm")
|
19
|
+
}
|
20
|
+
if $target.transport == 'ssh' {
|
21
|
+
# Disable SSH autoloading to prevent false positive results
|
22
|
+
# (input data is wrong but target is still connectable due
|
23
|
+
# to autoloaded config)
|
24
|
+
set_config($target, ['ssh', 'load-config'], false)
|
25
|
+
}
|
26
|
+
}
|
27
|
+
# The SSH/WinRM transports will report an 'unknown host' error for targets where
|
28
|
+
# 'host' is unknown so run_command's implementation will take care of raising that
|
29
|
+
# error for us.
|
30
|
+
return run_command('echo Connected', $targs)
|
31
|
+
}
|
@@ -1,3 +1,13 @@
|
|
1
|
+
# @summary
|
2
|
+
# Collect facts for the specified targets from PuppetDB and store them
|
3
|
+
# on the Targets.
|
4
|
+
#
|
5
|
+
# This plan accepts a list of targets to collect facts for from the configured
|
6
|
+
# PuppetDB connection. After collecting facts, they are stored on each target's
|
7
|
+
# Target object. The updated facts can then be accessed using `$target.facts`.
|
8
|
+
#
|
9
|
+
# @param targets
|
10
|
+
# The targets to collect facts for.
|
1
11
|
plan puppetdb_fact(TargetSpec $targets) {
|
2
12
|
$targs = get_targets($targets)
|
3
13
|
$certnames = $targs.map |$target| { $target.host }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bolt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppet
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -609,12 +609,12 @@ files:
|
|
609
609
|
- modules/aggregate/lib/puppet/functions/aggregate/nodes.rb
|
610
610
|
- modules/aggregate/lib/puppet/functions/aggregate/targets.rb
|
611
611
|
- modules/aggregate/plans/count.pp
|
612
|
-
- modules/aggregate/plans/nodes.pp
|
613
612
|
- modules/aggregate/plans/targets.pp
|
614
613
|
- modules/canary/lib/puppet/functions/canary/merge.rb
|
615
614
|
- modules/canary/lib/puppet/functions/canary/random_split.rb
|
616
615
|
- modules/canary/lib/puppet/functions/canary/skip.rb
|
617
616
|
- modules/canary/plans/init.pp
|
617
|
+
- modules/puppet_connect/plans/test_input_data.pp
|
618
618
|
- modules/puppetdb_fact/plans/init.pp
|
619
619
|
homepage: https://github.com/puppetlabs/bolt
|
620
620
|
licenses:
|
@@ -1,36 +0,0 @@
|
|
1
|
-
plan aggregate::nodes(
|
2
|
-
Optional[String[0]] $task = undef,
|
3
|
-
Optional[String[0]] $command = undef,
|
4
|
-
Optional[String[0]] $script = undef,
|
5
|
-
TargetSpec $nodes,
|
6
|
-
Hash[String, Data] $params = {}
|
7
|
-
) {
|
8
|
-
|
9
|
-
# Validation
|
10
|
-
$type_count = [$task, $command, $script].reduce(0) |$acc, $v| {
|
11
|
-
if ($v) {
|
12
|
-
$acc + 1
|
13
|
-
} else {
|
14
|
-
$acc
|
15
|
-
}
|
16
|
-
}
|
17
|
-
|
18
|
-
if ($type_count == 0) {
|
19
|
-
fail_plan("Must specify a command, script, or task to run", 'aggregate/invalid-params')
|
20
|
-
}
|
21
|
-
|
22
|
-
if ($type_count > 1) {
|
23
|
-
fail_plan("Must specify only one command, script, or task to run", 'aggregate/invalid-params')
|
24
|
-
}
|
25
|
-
|
26
|
-
$res = if ($task) {
|
27
|
-
run_task($task, $nodes, $params)
|
28
|
-
} elsif ($command) {
|
29
|
-
run_command($command, $nodes, $params)
|
30
|
-
} elsif ($script) {
|
31
|
-
run_script($script, $nodes, $params)
|
32
|
-
}
|
33
|
-
|
34
|
-
return aggregate::nodes($res)
|
35
|
-
}
|
36
|
-
|