bolt 0.16.1 → 0.16.2

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.

@@ -1,3 +1,3 @@
1
1
  module Bolt
2
- VERSION = '0.16.1'.freeze
2
+ VERSION = '0.16.2'.freeze
3
3
  end
@@ -5,7 +5,12 @@ Puppet::DataTypes.create_type('Target') do
5
5
  options => { type => Hash[String[1], Data], value => {} }
6
6
  },
7
7
  functions => {
8
+ host => Callable[[], String[1]],
8
9
  name => Callable[[], String[1]],
10
+ password => Callable[[], Optional[String[1]]],
11
+ port => Callable[[], Optional[Integer]],
12
+ protocol => Callable[[], Optional[String[1]]],
13
+ user => Callable[[], Optional[String[1]]],
9
14
  }
10
15
  PUPPET
11
16
 
@@ -5,7 +5,7 @@
5
5
 
6
6
  require 'bolt/error'
7
7
 
8
- Puppet::Functions.create_function(:fail_plan, Puppet::Functions::InternalFunction) do
8
+ Puppet::Functions.create_function(:fail_plan) do
9
9
  dispatch :from_args do
10
10
  param 'String[1]', :msg
11
11
  optional_param 'String[1]', :kind
@@ -8,15 +8,11 @@
8
8
  require 'bolt/error'
9
9
 
10
10
  Puppet::Functions.create_function(:file_upload, Puppet::Functions::InternalFunction) do
11
- local_types do
12
- type 'TargetOrTargets = Variant[String[1], Target, Array[TargetOrTargets]]'
13
- end
14
-
15
11
  dispatch :file_upload do
16
12
  scope_param
17
13
  param 'String[1]', :source
18
14
  param 'String[1]', :destination
19
- param 'TargetOrTargets', :targets
15
+ param 'Boltlib::TargetSpec', :targets
20
16
  optional_param 'Hash[String[1], Any]', :options
21
17
  return_type 'ResultSet'
22
18
  end
@@ -0,0 +1,41 @@
1
+ # Parses common ways of referring to targets and returns an array of Targets.
2
+ #
3
+ # Accepts input consisting of
4
+ # - a group
5
+ # - a target URI
6
+ # - an array of groups and/or target URIs
7
+ # - a string that consists of a comma-separated list of groups and/or target URIs
8
+ #
9
+ # Examples of the above would be
10
+ # - 'group1'
11
+ # - 'host1,group1,winrm://host2:54321'
12
+ # - ['host1', 'group1', 'winrm://host2:54321']
13
+ #
14
+ # Returns an array of unique Targets resolved from any target URIs and groups.
15
+
16
+ require 'bolt/error'
17
+
18
+ Puppet::Functions.create_function(:get_targets) do
19
+ dispatch :get_targets do
20
+ param 'Boltlib::TargetSpec', :names
21
+ return_type 'Array[Target]'
22
+ end
23
+
24
+ def get_targets(names)
25
+ unless Puppet[:tasks]
26
+ raise Puppet::ParseErrorWithIssue.from_issue_and_stack(
27
+ Puppet::Pops::Issues::TASK_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, operation: 'get_targets'
28
+ )
29
+ end
30
+
31
+ inventory = Puppet.lookup(:bolt_inventory) { nil }
32
+
33
+ unless inventory && Puppet.features.bolt?
34
+ raise Puppet::ParseErrorWithIssue.from_issue_and_stack(
35
+ Puppet::Pops::Issues::TASK_MISSING_BOLT, action: _('process targets through inventory')
36
+ )
37
+ end
38
+
39
+ inventory.get_targets(names)
40
+ end
41
+ end
@@ -8,13 +8,9 @@
8
8
  require 'bolt/error'
9
9
 
10
10
  Puppet::Functions.create_function(:run_command) do
11
- local_types do
12
- type 'TargetOrTargets = Variant[String[1], Target, Array[TargetOrTargets]]'
13
- end
14
-
15
11
  dispatch :run_command do
16
12
  param 'String[1]', :command
17
- param 'TargetOrTargets', :targets
13
+ param 'Boltlib::TargetSpec', :targets
18
14
  optional_param 'Hash[String[1], Any]', :options
19
15
  return_type 'ResultSet'
20
16
  end
@@ -35,7 +31,7 @@ Puppet::Functions.create_function(:run_command) do
35
31
  )
36
32
  end
37
33
 
38
- # Ensure that that given targets are all Target instances
34
+ # Ensure that given targets are all Target instances
39
35
  targets = inventory.get_targets(targets)
40
36
 
41
37
  if targets.empty?
@@ -61,7 +61,10 @@ Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction
61
61
 
62
62
  return result
63
63
  end
64
+
64
65
  # Could not find plan
65
- raise ArgumentError, "Function #{self.class.name}(): Unknown plan: '#{plan_name}'"
66
+ raise Puppet::ParseErrorWithIssue.from_issue_and_stack(
67
+ Puppet::Pops::Issues.issue(:UNKNOWN_PLAN) { Bolt::Error.unknown_plan(plan_name) }
68
+ )
66
69
  end
67
70
  end
@@ -6,14 +6,10 @@
6
6
  # * The returned value contains information about the result per target.
7
7
  #
8
8
  Puppet::Functions.create_function(:run_script, Puppet::Functions::InternalFunction) do
9
- local_types do
10
- type 'TargetOrTargets = Variant[String[1], Target, Array[TargetOrTargets]]'
11
- end
12
-
13
9
  dispatch :run_script do
14
10
  scope_param
15
11
  param 'String[1]', :script
16
- param 'TargetOrTargets', :targets
12
+ param 'Boltlib::TargetSpec', :targets
17
13
  optional_param 'Hash[String[1], Any]', :options
18
14
  return_type 'ResultSet'
19
15
  end
@@ -46,7 +42,7 @@ Puppet::Functions.create_function(:run_script, Puppet::Functions::InternalFuncti
46
42
  )
47
43
  end
48
44
 
49
- # Ensure that that given targets are all Target instances)
45
+ # Ensure that given targets are all Target instances)
50
46
  targets = inventory.get_targets(targets)
51
47
 
52
48
  #
@@ -8,13 +8,9 @@
8
8
  require 'bolt/error'
9
9
 
10
10
  Puppet::Functions.create_function(:run_task) do
11
- local_types do
12
- type 'TargetOrTargets = Variant[String[1], Target, Array[TargetOrTargets]]'
13
- end
14
-
15
11
  dispatch :run_task do
16
12
  param 'String[1]', :task_name
17
- param 'TargetOrTargets', :targets
13
+ param 'Boltlib::TargetSpec', :targets
18
14
  optional_param 'Hash[String[1], Any]', :task_args
19
15
  return_type 'ResultSet'
20
16
  end
@@ -22,7 +18,7 @@ Puppet::Functions.create_function(:run_task) do
22
18
  # this is used from 'bolt task run'
23
19
  dispatch :run_task_raw do
24
20
  param 'String[1]', :task_name
25
- param 'TargetOrTargets', :targets
21
+ param 'Boltlib::TargetSpec', :targets
26
22
  optional_param 'Hash[String[1], Any]', :task_args
27
23
  # return_type 'ResultSet'
28
24
  block_param
@@ -48,9 +44,7 @@ Puppet::Functions.create_function(:run_task) do
48
44
  # TODO: use the compiler injection once PUP-8237 lands
49
45
  task_signature = Puppet::Pal::ScriptCompiler.new(closure_scope.compiler).task_signature(task_name)
50
46
  if task_signature.nil?
51
- raise Puppet::ParseErrorWithIssue.from_issue_and_stack(
52
- Puppet::Pops::Issues::UNKNOWN_TASK, type_name: task_name
53
- )
47
+ raise with_stack(:UNKNOWN_TASK, Bolt::Error.unknown_task(task_name))
54
48
  end
55
49
 
56
50
  executor = Puppet.lookup(:bolt_executor) { nil }
@@ -63,12 +57,12 @@ Puppet::Functions.create_function(:run_task) do
63
57
 
64
58
  use_args = task_args.reject { |k, _| k.start_with?('_') }
65
59
 
66
- task_signature.runnable_with?(use_args) do |mismatch|
67
- raise Puppet::ParseError, mismatch
68
- end || (raise Puppet::ParseError, 'Task parameters did not match')
60
+ task_signature.runnable_with?(use_args) do |mismatch_message|
61
+ raise with_stack(:TYPE_MISMATCH, mismatch_message)
62
+ end || (raise with_stack(:TYPE_MISMATCH, 'Task parameters do not match'))
69
63
 
70
64
  unless Puppet::Pops::Types::TypeFactory.data.instance?(use_args)
71
- raise Puppet::ParseError, 'Task parameters is not of type Data'
65
+ raise with_stack(:TYPE_NOT_DATA, 'Task parameters is not of type Data')
72
66
  end
73
67
 
74
68
  task = task_signature.task
@@ -77,18 +71,22 @@ Puppet::Functions.create_function(:run_task) do
77
71
  if task.supports_noop
78
72
  use_args['_noop'] = true
79
73
  else
80
- raise Puppet::ParseError, 'Task does not support noop'
74
+ raise with_stack(:TASK_NO_NOOP, 'Task does not support noop')
81
75
  end
82
76
  end
83
77
 
84
- # Ensure that that given targets are all Target instances
78
+ # Ensure that given targets are all Target instances
85
79
  targets = inventory.get_targets(targets)
86
80
  if targets.empty?
87
81
  Bolt::ResultSet.new([])
88
82
  else
89
- # TODO: pass entire task to executor
90
83
  options = task_args.select { |k, _| k == '_run_as' }
91
- executor.run_task(targets, task.executable, task.input_method, use_args, options, &block)
84
+ executor.run_task(targets, task, use_args, options, &block)
92
85
  end
93
86
  end
87
+
88
+ def with_stack(kind, msg)
89
+ issue = Puppet::Pops::Issues.issue(kind) { msg }
90
+ Puppet::ParseErrorWithIssue.from_issue_and_stack(issue)
91
+ end
94
92
  end
@@ -0,0 +1,7 @@
1
+ # A TargetSpec represents any String, Target or combination thereof that can be
2
+ # passed to get_targets() to return an Array[Target]. Generally, users
3
+ # shouldn't need to worry about the distinction between TargetSpec and
4
+ # Target/Array[Target], since the run_* functions will all handle them both
5
+ # automatically. But for use cases that need to deal with the exact list of
6
+ # Targets that will be used, get_targets() will return that.
7
+ type Boltlib::TargetSpec = Variant[String[1], Target, Array[Boltlib::TargetSpec]]
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: 0.16.1
4
+ version: 0.16.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-02-09 00:00:00.000000000 Z
11
+ date: 2018-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -341,12 +341,8 @@ files:
341
341
  - lib/bolt/inventory.rb
342
342
  - lib/bolt/inventory/group.rb
343
343
  - lib/bolt/logger.rb
344
- - lib/bolt/node.rb
345
344
  - lib/bolt/node/errors.rb
346
- - lib/bolt/node/orch.rb
347
345
  - lib/bolt/node/output.rb
348
- - lib/bolt/node/ssh.rb
349
- - lib/bolt/node/winrm.rb
350
346
  - lib/bolt/notifier.rb
351
347
  - lib/bolt/outputter.rb
352
348
  - lib/bolt/outputter/human.rb
@@ -355,6 +351,12 @@ files:
355
351
  - lib/bolt/result.rb
356
352
  - lib/bolt/result_set.rb
357
353
  - lib/bolt/target.rb
354
+ - lib/bolt/transport/base.rb
355
+ - lib/bolt/transport/orch.rb
356
+ - lib/bolt/transport/ssh.rb
357
+ - lib/bolt/transport/ssh/connection.rb
358
+ - lib/bolt/transport/winrm.rb
359
+ - lib/bolt/transport/winrm/connection.rb
358
360
  - lib/bolt/util.rb
359
361
  - lib/bolt/version.rb
360
362
  - modules/boltlib/lib/puppet/datatypes/result.rb
@@ -362,10 +364,12 @@ files:
362
364
  - modules/boltlib/lib/puppet/datatypes/target.rb
363
365
  - modules/boltlib/lib/puppet/functions/fail_plan.rb
364
366
  - modules/boltlib/lib/puppet/functions/file_upload.rb
367
+ - modules/boltlib/lib/puppet/functions/get_targets.rb
365
368
  - modules/boltlib/lib/puppet/functions/run_command.rb
366
369
  - modules/boltlib/lib/puppet/functions/run_plan.rb
367
370
  - modules/boltlib/lib/puppet/functions/run_script.rb
368
371
  - modules/boltlib/lib/puppet/functions/run_task.rb
372
+ - modules/boltlib/types/targetspec.pp
369
373
  - vendored/facter/lib/facter.rb
370
374
  - vendored/facter/lib/facter/Cfkey.rb
371
375
  - vendored/facter/lib/facter/application.rb
@@ -1,76 +0,0 @@
1
- require 'bolt/result'
2
- require 'bolt/config'
3
- require 'bolt/target'
4
- require 'logging'
5
-
6
- module Bolt
7
- class Node
8
- STDIN_METHODS = %w[both stdin].freeze
9
- ENVIRONMENT_METHODS = %w[both environment].freeze
10
-
11
- def self.from_target(target)
12
- klass = case target.protocol
13
- when 'winrm'
14
- Bolt::WinRM
15
- when 'pcp'
16
- Bolt::Orch
17
- else
18
- Bolt::SSH
19
- end
20
- klass.new(target)
21
- end
22
-
23
- def self.initialize_transport(_logger); end
24
-
25
- attr_reader :logger, :user, :password, :connect_timeout, :target, :run_as
26
-
27
- def initialize(target)
28
- @target = target
29
-
30
- transport_conf = target.options
31
- @user = @target.user
32
- @password = @target.password
33
- @key = transport_conf[:key]
34
- @cacert = transport_conf[:cacert]
35
- @tty = transport_conf[:tty]
36
- @host_key_check = transport_conf[:host_key_check]
37
- @ssl = transport_conf[:ssl]
38
- @connect_timeout = transport_conf[:connect_timeout]
39
- @sudo_password = transport_conf[:sudo_password]
40
- @run_as = transport_conf[:run_as]
41
- @conf_run_as = transport_conf[:run_as]
42
- @tmpdir = transport_conf[:tmpdir]
43
- @service_url = transport_conf[:service_url]
44
- @token_file = transport_conf[:token_file]
45
- @orch_task_environment = transport_conf[:orch_task_environment]
46
- @extensions = transport_conf[:extensions]
47
-
48
- @logger = Logging.logger[@target.host]
49
- end
50
-
51
- def uri
52
- @target.uri
53
- end
54
-
55
- def upload(_source, _destination, _options = nil)
56
- raise NotImplementedError, 'transports must implement upload(source, destination, options = nil)'
57
- end
58
-
59
- def run_command(_command, _options = nil)
60
- raise NotImplementedError, 'transports must implement run_command(command, options = nil)'
61
- end
62
-
63
- def run_script(_script, _arguments, _options = nil)
64
- raise NotImplementedError, 'transports must implement run_script(script, arguments, options = nil)'
65
- end
66
-
67
- def run_task(_task, _input_method, _arguments, _options = nil)
68
- raise NotImplementedError, 'transports must implement run_task(task, input_method, arguments, options = nil)'
69
- end
70
- end
71
- end
72
-
73
- require 'bolt/node/errors'
74
- require 'bolt/node/ssh'
75
- require 'bolt/node/winrm'
76
- require 'bolt/node/orch'
@@ -1,126 +0,0 @@
1
- require 'base64'
2
- require 'json'
3
- require 'orchestrator_client'
4
-
5
- module Bolt
6
- class Orch < Node
7
- CONF_FILE = File.expand_path('~/.puppetlabs/client-tools/orchestrator.conf')
8
- BOLT_MOCK_FILE = 'bolt/tasks/init'.freeze
9
-
10
- def connect; end
11
-
12
- def disconnect; end
13
-
14
- def protocol
15
- 'pcp'
16
- end
17
-
18
- def make_client
19
- opts = {}
20
- opts["service-url"] = @service_url if @service_url
21
- opts["token-file"] = @token_file if @token_file
22
- opts["cacert"] = @cacert if @cacert
23
- OrchestratorClient.new(opts, true)
24
- end
25
-
26
- def client
27
- @client ||= make_client
28
- end
29
-
30
- # This avoids a refactor to pass more task data around
31
- def task_name_from_path(path)
32
- path = File.absolute_path(path)
33
- parts = path.split(File::Separator)
34
- if parts.length < 3 || parts[-2] != 'tasks'
35
- raise ArgumentError, "Task path was not inside a module."
36
- end
37
- mod = parts[-3]
38
- name = File.basename(path).split('.')[0]
39
- if name == 'init'
40
- mod
41
- else
42
- "#{mod}::#{name}"
43
- end
44
- end
45
-
46
- def run_task(task, _input_method, arguments, _options = nil)
47
- body = { task: task_name_from_path(task),
48
- environment: @orch_task_environment,
49
- noop: arguments['_noop'],
50
- params: arguments.reject { |k, _| k == '_noop' },
51
- scope: {
52
- nodes: [@target.host]
53
- } }
54
- # Should we handle errors here or let them propagate?
55
- results = client.run_task(body)
56
- node_result = results[0]
57
- state = node_result['state']
58
- result = node_result['result']
59
-
60
- # If it's finished or already has a proper error simply pass it to the
61
- # the result otherwise make sure an error is generated
62
- if state == 'finished' || result['_error']
63
- Bolt::Result.new(@target, value: result)
64
- elsif state == 'skipped'
65
- Bolt::Result.new(
66
- @target,
67
- value: { '_error' => {
68
- 'kind' => 'puppetlabs.tasks/skipped-node',
69
- 'msg' => "Node #{@target.host} was skipped",
70
- 'details' => {}
71
- } }
72
- )
73
- else
74
- # Make a generic error with a unkown exit_code
75
- Bolt::Result.for_task(@target, result.to_json, '', 'unknown')
76
- end
77
- end
78
-
79
- # run_task generates a result that makes sense for a generic task which
80
- # needs to be unwrapped to extract stdout/stderr/exitcode.
81
- #
82
- def unwrap_bolt_result(result)
83
- if result.error_hash
84
- # something went wrong return the failure
85
- return result
86
- end
87
-
88
- Bolt::Result.for_command(@target, result.value['stdout'], result.value['stderr'], result.value['exit_code'])
89
- end
90
-
91
- def run_command(command, _options = nil)
92
- result = run_task(BOLT_MOCK_FILE,
93
- 'stdin',
94
- action: 'command',
95
- command: command,
96
- options: {})
97
- unwrap_bolt_result(result)
98
- end
99
-
100
- def upload(source, destination)
101
- content = File.open(source, &:read)
102
- content = Base64.encode64(content)
103
- mode = File.stat(source).mode
104
- params = {
105
- action: 'upload',
106
- path: destination,
107
- content: content,
108
- mode: mode
109
- }
110
- result = run_task(BOLT_MOCK_FILE, 'stdin', params)
111
- result = Bolt::Result.for_upload(@target, source, destination) unless result.error_hash
112
- result
113
- end
114
-
115
- def run_script(script, arguments, _options = nil)
116
- content = File.open(script, &:read)
117
- content = Base64.encode64(content)
118
- params = {
119
- action: 'script',
120
- content: content,
121
- arguments: arguments
122
- }
123
- unwrap_bolt_result(run_task(BOLT_MOCK_FILE, 'stdin', params))
124
- end
125
- end
126
- end