bolt 1.5.0 → 1.6.0
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.
Potentially problematic release.
This version of bolt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +1 -1
- data/lib/bolt/config.rb +14 -10
- data/lib/bolt/executor.rb +10 -4
- data/lib/bolt/inventory.rb +11 -10
- data/lib/bolt/node/errors.rb +8 -1
- data/lib/bolt/target.rb +25 -2
- data/lib/bolt/task.rb +13 -2
- data/lib/bolt/task/remote.rb +25 -0
- data/lib/bolt/transport/base.rb +22 -6
- data/lib/bolt/transport/docker.rb +6 -0
- data/lib/bolt/transport/local.rb +64 -20
- data/lib/bolt/transport/powershell.rb +330 -0
- data/lib/bolt/transport/remote.rb +53 -0
- data/lib/bolt/transport/ssh.rb +1 -2
- data/lib/bolt/transport/winrm.rb +16 -89
- data/lib/bolt/transport/winrm/connection.rb +5 -216
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/file_cache.rb +1 -1
- metadata +19 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 557353adda3a863e4f748933cb24860616848d1696d9f0914be23474616f43ca
         | 
| 4 | 
            +
              data.tar.gz: 91dc4d72ba25e2e827c5bf170574bedef50c744a4e31ac48684699ff59cdf753
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 6a4c8b39f2c353498168cf89a5e70f7b4699e6332e2826efd24a905d94ca7b52ec76a6db98e94f83fe5f7fce4b6c7f58cbc51b56e79b3fce3acf0f014f2669f8
         | 
| 7 | 
            +
              data.tar.gz: 6bf22f4aaef6a2741b64d77b900c9a85fd3c3588feb4a071d582415afbc5ecc479048ba7aea9912131c383d5ec2e3966682f5ea8a3cade87722a927d12275c7e
         | 
| @@ -99,7 +99,7 @@ Puppet::Functions.create_function(:run_task) do | |
| 99 99 | 
             
                options['_description'] = description if description
         | 
| 100 100 |  | 
| 101 101 | 
             
                # Don't bother loading the local task definition if all targets use the 'pcp' transport.
         | 
| 102 | 
            -
                if !targets.empty? && targets.all? { |t| t. | 
| 102 | 
            +
                if !targets.empty? && targets.all? { |t| t.transport == 'pcp' }
         | 
| 103 103 | 
             
                  # create a fake task
         | 
| 104 104 | 
             
                  task = Bolt::Task.new(name: task_name, files: [{ 'name' => '', 'path' => '' }])
         | 
| 105 105 | 
             
                else
         | 
    
        data/lib/bolt/config.rb
    CHANGED
    
    | @@ -10,6 +10,7 @@ require 'bolt/transport/winrm' | |
| 10 10 | 
             
            require 'bolt/transport/orch'
         | 
| 11 11 | 
             
            require 'bolt/transport/local'
         | 
| 12 12 | 
             
            require 'bolt/transport/docker'
         | 
| 13 | 
            +
            require 'bolt/transport/remote'
         | 
| 13 14 |  | 
| 14 15 | 
             
            module Bolt
         | 
| 15 16 | 
             
              TRANSPORTS = {
         | 
| @@ -17,7 +18,8 @@ module Bolt | |
| 17 18 | 
             
                winrm: Bolt::Transport::WinRM,
         | 
| 18 19 | 
             
                pcp: Bolt::Transport::Orch,
         | 
| 19 20 | 
             
                local: Bolt::Transport::Local,
         | 
| 20 | 
            -
                docker: Bolt::Transport::Docker
         | 
| 21 | 
            +
                docker: Bolt::Transport::Docker,
         | 
| 22 | 
            +
                remote: Bolt::Transport::Remote
         | 
| 21 23 | 
             
              }.freeze
         | 
| 22 24 |  | 
| 23 25 | 
             
              class UnknownTransportError < Bolt::Error
         | 
| @@ -36,16 +38,15 @@ module Bolt | |
| 36 38 | 
             
                                       private-key tty tmpdir user connect-timeout
         | 
| 37 39 | 
             
                                       cacert token-file service-url].freeze
         | 
| 38 40 |  | 
| 39 | 
            -
                 | 
| 40 | 
            -
                  'connect-timeout' => 10,
         | 
| 41 | 
            -
                  'tty' => false
         | 
| 42 | 
            -
                }.freeze
         | 
| 43 | 
            -
             | 
| 41 | 
            +
                # TODO: move these to the transport themselves
         | 
| 44 42 | 
             
                TRANSPORT_SPECIFIC_DEFAULTS = {
         | 
| 45 43 | 
             
                  ssh: {
         | 
| 46 | 
            -
                    ' | 
| 44 | 
            +
                    'connect-timeout' => 10,
         | 
| 45 | 
            +
                    'host-key-check' => true,
         | 
| 46 | 
            +
                    'tty' => false
         | 
| 47 47 | 
             
                  },
         | 
| 48 48 | 
             
                  winrm: {
         | 
| 49 | 
            +
                    'connect-timeout' => 10,
         | 
| 49 50 | 
             
                    'ssl' => true,
         | 
| 50 51 | 
             
                    'ssl-verify' => true
         | 
| 51 52 | 
             
                  },
         | 
| @@ -53,7 +54,10 @@ module Bolt | |
| 53 54 | 
             
                    'task-environment' => 'production'
         | 
| 54 55 | 
             
                  },
         | 
| 55 56 | 
             
                  local: {},
         | 
| 56 | 
            -
                  docker: {}
         | 
| 57 | 
            +
                  docker: {},
         | 
| 58 | 
            +
                  remote: {
         | 
| 59 | 
            +
                    'run-on' => 'localhost'
         | 
| 60 | 
            +
                  }
         | 
| 57 61 | 
             
                }.freeze
         | 
| 58 62 |  | 
| 59 63 | 
             
                def self.default
         | 
| @@ -88,7 +92,7 @@ module Bolt | |
| 88 92 |  | 
| 89 93 | 
             
                  @transports = {}
         | 
| 90 94 | 
             
                  TRANSPORTS.each_key do |transport|
         | 
| 91 | 
            -
                    @transports[transport] =  | 
| 95 | 
            +
                    @transports[transport] = TRANSPORT_SPECIFIC_DEFAULTS[transport].dup
         | 
| 92 96 | 
             
                  end
         | 
| 93 97 |  | 
| 94 98 | 
             
                  update_from_file(config_data)
         | 
| @@ -158,7 +162,7 @@ module Bolt | |
| 158 162 |  | 
| 159 163 | 
             
                  TRANSPORTS.each do |key, impl|
         | 
| 160 164 | 
             
                    if data[key.to_s]
         | 
| 161 | 
            -
                      selected = data[key.to_s] | 
| 165 | 
            +
                      selected = impl.filter_options(data[key.to_s])
         | 
| 162 166 | 
             
                      @transports[key].merge!(selected)
         | 
| 163 167 | 
             
                    end
         | 
| 164 168 | 
             
                  end
         | 
    
        data/lib/bolt/executor.rb
    CHANGED
    
    | @@ -32,9 +32,15 @@ module Bolt | |
| 32 32 | 
             
                  @load_config = load_config
         | 
| 33 33 |  | 
| 34 34 | 
             
                  @transports = Bolt::TRANSPORTS.each_with_object({}) do |(key, val), coll|
         | 
| 35 | 
            -
                    coll[key.to_s] =  | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 35 | 
            +
                    coll[key.to_s] = if key == :remote
         | 
| 36 | 
            +
                                       Concurrent::Delay.new do
         | 
| 37 | 
            +
                                         val.new(self)
         | 
| 38 | 
            +
                                       end
         | 
| 39 | 
            +
                                     else
         | 
| 40 | 
            +
                                       Concurrent::Delay.new do
         | 
| 41 | 
            +
                                         val.new
         | 
| 42 | 
            +
                                       end
         | 
| 43 | 
            +
                                     end
         | 
| 38 44 | 
             
                  end
         | 
| 39 45 | 
             
                  @reported_transports = Set.new
         | 
| 40 46 |  | 
| @@ -64,7 +70,7 @@ module Bolt | |
| 64 70 | 
             
                # defined by the transport. Yields each batch, along with the corresponding
         | 
| 65 71 | 
             
                # transport, to the block in turn and returns an array of result promises.
         | 
| 66 72 | 
             
                def queue_execute(targets)
         | 
| 67 | 
            -
                  targets.group_by(&: | 
| 73 | 
            +
                  targets.group_by(&:transport).flat_map do |protocol, protocol_targets|
         | 
| 68 74 | 
             
                    transport = transport(protocol)
         | 
| 69 75 | 
             
                    report_transport(transport, protocol_targets.count)
         | 
| 70 76 | 
             
                    transport.batches(protocol_targets).flat_map do |batch|
         | 
    
        data/lib/bolt/inventory.rb
    CHANGED
    
    | @@ -167,19 +167,17 @@ module Bolt | |
| 167 167 | 
             
                # Should this reconfigure configured targets?
         | 
| 168 168 | 
             
                def update_target(target)
         | 
| 169 169 | 
             
                  data = @groups.data_for(target.name)
         | 
| 170 | 
            -
             | 
| 171 | 
            -
                  unless data
         | 
| 172 | 
            -
                    data = {}
         | 
| 173 | 
            -
                    unless Bolt::Util.windows?
         | 
| 174 | 
            -
                      data['config'] = { 'transport' => 'local' } if target.name == 'localhost'
         | 
| 175 | 
            -
                    end
         | 
| 176 | 
            -
                  end
         | 
| 170 | 
            +
                  data ||= {}
         | 
| 177 171 |  | 
| 178 172 | 
             
                  unless data['config']
         | 
| 179 173 | 
             
                    @logger.debug("Did not find config for #{target.name} in inventory")
         | 
| 180 174 | 
             
                    data['config'] = {}
         | 
| 181 175 | 
             
                  end
         | 
| 182 176 |  | 
| 177 | 
            +
                  unless data['config']['transport']
         | 
| 178 | 
            +
                    data['config']['transport'] = 'local' if target.name == 'localhost'
         | 
| 179 | 
            +
                  end
         | 
| 180 | 
            +
             | 
| 183 181 | 
             
                  # These should only get set from the inventory if they have not yet
         | 
| 184 182 | 
             
                  # been instantiated
         | 
| 185 183 | 
             
                  set_vars_from_hash(target.name, data['vars']) unless @target_vars[target.name]
         | 
| @@ -191,11 +189,13 @@ module Bolt | |
| 191 189 | 
             
                  conf.update_from_inventory(data['config'])
         | 
| 192 190 | 
             
                  conf.validate
         | 
| 193 191 |  | 
| 194 | 
            -
                   | 
| 195 | 
            -
             | 
| 192 | 
            +
                  target.update_conf(conf.transport_conf)
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                  unless target.transport.nil? || Bolt::TRANSPORTS.include?(target.transport.to_sym)
         | 
| 195 | 
            +
                    raise Bolt::UnknownTransportError.new(target.transport, target.uri)
         | 
| 196 196 | 
             
                  end
         | 
| 197 197 |  | 
| 198 | 
            -
                  target | 
| 198 | 
            +
                  target
         | 
| 199 199 | 
             
                end
         | 
| 200 200 | 
             
                private :update_target
         | 
| 201 201 |  | 
| @@ -226,6 +226,7 @@ module Bolt | |
| 226 226 |  | 
| 227 227 | 
             
                def expand_targets(targets)
         | 
| 228 228 | 
             
                  if targets.is_a? Bolt::Target
         | 
| 229 | 
            +
                    targets.inventory = self
         | 
| 229 230 | 
             
                    targets
         | 
| 230 231 | 
             
                  elsif targets.is_a? Array
         | 
| 231 232 | 
             
                    targets.map { |tish| expand_targets(tish) }
         | 
    
        data/lib/bolt/node/errors.rb
    CHANGED
    
    | @@ -7,7 +7,8 @@ module Bolt | |
| 7 7 | 
             
                class BaseError < Bolt::Error
         | 
| 8 8 | 
             
                  attr_reader :issue_code
         | 
| 9 9 |  | 
| 10 | 
            -
                   | 
| 10 | 
            +
                  # TODO: can we just drop issue code here?
         | 
| 11 | 
            +
                  def initialize(message, issue_code = nil)
         | 
| 11 12 | 
             
                    super(message, kind, nil, issue_code)
         | 
| 12 13 | 
             
                  end
         | 
| 13 14 |  | 
| @@ -34,6 +35,12 @@ module Bolt | |
| 34 35 | 
             
                  end
         | 
| 35 36 | 
             
                end
         | 
| 36 37 |  | 
| 38 | 
            +
                class RemoteError < BaseError
         | 
| 39 | 
            +
                  def kind
         | 
| 40 | 
            +
                    'puppetlabs.tasks/remote-task-error'
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 37 44 | 
             
                class EnvironmentVarError < BaseError
         | 
| 38 45 | 
             
                  def initialize(var, val)
         | 
| 39 46 | 
             
                    message = "Could not set environment variable '#{var}' to '#{val}'"
         | 
    
        data/lib/bolt/target.rb
    CHANGED
    
    | @@ -6,7 +6,9 @@ require 'bolt/error' | |
| 6 6 | 
             
            module Bolt
         | 
| 7 7 | 
             
              class Target
         | 
| 8 8 | 
             
                attr_reader :uri, :options
         | 
| 9 | 
            -
                 | 
| 9 | 
            +
                # CODEREVIEW: this feels wrong. The altertative is threading inventory through the
         | 
| 10 | 
            +
                # executor to the RemoteTransport
         | 
| 11 | 
            +
                attr_accessor :inventory
         | 
| 10 12 |  | 
| 11 13 | 
             
                PRINT_OPTS ||= %w[host user port protocol].freeze
         | 
| 12 14 |  | 
| @@ -41,7 +43,7 @@ module Bolt | |
| 41 43 | 
             
                def update_conf(conf)
         | 
| 42 44 | 
             
                  @protocol = conf[:transport]
         | 
| 43 45 |  | 
| 44 | 
            -
                  t_conf = conf[:transports][ | 
| 46 | 
            +
                  t_conf = conf[:transports][transport.to_sym] || {}
         | 
| 45 47 | 
             
                  # Override url methods
         | 
| 46 48 | 
             
                  @user = t_conf['user']
         | 
| 47 49 | 
             
                  @password = t_conf['password']
         | 
| @@ -85,6 +87,18 @@ module Bolt | |
| 85 87 | 
             
                  "Target('#{@uri}', #{opts})"
         | 
| 86 88 | 
             
                end
         | 
| 87 89 |  | 
| 90 | 
            +
                def to_h
         | 
| 91 | 
            +
                  options.merge(
         | 
| 92 | 
            +
                    'name' => name,
         | 
| 93 | 
            +
                    'uri' => uri,
         | 
| 94 | 
            +
                    'protocol' => protocol,
         | 
| 95 | 
            +
                    'user' => user,
         | 
| 96 | 
            +
                    'password' => password,
         | 
| 97 | 
            +
                    'host' => host,
         | 
| 98 | 
            +
                    'port' => port
         | 
| 99 | 
            +
                  )
         | 
| 100 | 
            +
                end
         | 
| 101 | 
            +
             | 
| 88 102 | 
             
                def host
         | 
| 89 103 | 
             
                  @uri_obj.hostname
         | 
| 90 104 | 
             
                end
         | 
| @@ -95,10 +109,19 @@ module Bolt | |
| 95 109 | 
             
                  uri
         | 
| 96 110 | 
             
                end
         | 
| 97 111 |  | 
| 112 | 
            +
                def remote?
         | 
| 113 | 
            +
                  @uri_obj.scheme == 'remote' || @protocol == 'remote'
         | 
| 114 | 
            +
                end
         | 
| 115 | 
            +
             | 
| 98 116 | 
             
                def port
         | 
| 99 117 | 
             
                  @uri_obj.port || @port
         | 
| 100 118 | 
             
                end
         | 
| 101 119 |  | 
| 120 | 
            +
                # transport is separate from protocol for remote targets.
         | 
| 121 | 
            +
                def transport
         | 
| 122 | 
            +
                  remote? ? 'remote' : protocol
         | 
| 123 | 
            +
                end
         | 
| 124 | 
            +
             | 
| 102 125 | 
             
                def protocol
         | 
| 103 126 | 
             
                  @uri_obj.scheme || @protocol
         | 
| 104 127 | 
             
                end
         | 
    
        data/lib/bolt/task.rb
    CHANGED
    
    | @@ -1,6 +1,13 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            module Bolt
         | 
| 4 | 
            +
              class NoImplementationError < Bolt::Error
         | 
| 5 | 
            +
                def initialize(target, task)
         | 
| 6 | 
            +
                  msg = "No suitable implementation of #{task.name} for #{target.name}"
         | 
| 7 | 
            +
                  super(msg, 'bolt/no-implementation')
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 4 11 | 
             
              # Represents a Task.
         | 
| 5 12 | 
             
              # @file and @files are mutually exclusive.
         | 
| 6 13 | 
             
              # @name [String] name of the task
         | 
| @@ -51,13 +58,17 @@ module Bolt | |
| 51 58 | 
             
                  file_map[file_name]['path']
         | 
| 52 59 | 
             
                end
         | 
| 53 60 |  | 
| 61 | 
            +
                def implementations
         | 
| 62 | 
            +
                  metadata['implementations']
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 54 65 | 
             
                # Returns a hash of implementation name, path to executable, input method (if defined),
         | 
| 55 66 | 
             
                # and any additional files (name and path)
         | 
| 56 67 | 
             
                def select_implementation(target, additional_features = [])
         | 
| 57 | 
            -
                  impl = if (impls =  | 
| 68 | 
            +
                  impl = if (impls = implementations)
         | 
| 58 69 | 
             
                           available_features = target.features + additional_features
         | 
| 59 70 | 
             
                           impl = impls.find { |imp| Set.new(imp['requirements']).subset?(available_features) }
         | 
| 60 | 
            -
                           raise  | 
| 71 | 
            +
                           raise NoImplementationError.new(target, self) unless impl
         | 
| 61 72 | 
             
                           impl = impl.dup
         | 
| 62 73 | 
             
                           impl['path'] = file_path(impl['name'])
         | 
| 63 74 | 
             
                           impl.delete('requirements')
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'bolt/task'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Bolt
         | 
| 6 | 
            +
              class Task
         | 
| 7 | 
            +
                class Remote < Task
         | 
| 8 | 
            +
                  def self.from_task(task)
         | 
| 9 | 
            +
                    new(task.name, task.file, task.files, task.metadata)
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  def implementations
         | 
| 13 | 
            +
                    metadata['implementations']&.select { |i| i['remote'] || metadata['remote'] }
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def select_implementation(target, *args)
         | 
| 17 | 
            +
                    unless implementations || metadata['remote']
         | 
| 18 | 
            +
                      raise NoImplementationError.new(target, self)
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    super(target, *args)
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
    
        data/lib/bolt/transport/base.rb
    CHANGED
    
    | @@ -44,7 +44,12 @@ module Bolt | |
| 44 44 |  | 
| 45 45 | 
             
                  # Returns options this transport supports
         | 
| 46 46 | 
             
                  def self.options
         | 
| 47 | 
            -
                    raise NotImplementedError, | 
| 47 | 
            +
                    raise NotImplementedError,
         | 
| 48 | 
            +
                          "self.options() or self.filter_options(unfiltered) must be implemented by the transport class"
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  def self.filter_options(unfiltered)
         | 
| 52 | 
            +
                    unfiltered.select { |k| options.include?(k) }
         | 
| 48 53 | 
             
                  end
         | 
| 49 54 |  | 
| 50 55 | 
             
                  def self.validate(_options)
         | 
| @@ -72,13 +77,24 @@ module Bolt | |
| 72 77 | 
             
                    []
         | 
| 73 78 | 
             
                  end
         | 
| 74 79 |  | 
| 75 | 
            -
                  def  | 
| 80 | 
            +
                  def default_input_method(_executable)
         | 
| 81 | 
            +
                    'both'
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                  def select_implementation(target, task)
         | 
| 85 | 
            +
                    impl = task.select_implementation(target, provided_features)
         | 
| 86 | 
            +
                    impl['input_method'] ||= default_input_method(impl['path'])
         | 
| 87 | 
            +
                    impl
         | 
| 88 | 
            +
                  end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                  def reject_transport_options(target, options)
         | 
| 76 91 | 
             
                    if target.options['run-as']
         | 
| 77 92 | 
             
                      options.reject { |k, _v| k == '_run_as' }
         | 
| 78 93 | 
             
                    else
         | 
| 79 94 | 
             
                      options
         | 
| 80 95 | 
             
                    end
         | 
| 81 96 | 
             
                  end
         | 
| 97 | 
            +
                  private :reject_transport_options
         | 
| 82 98 |  | 
| 83 99 | 
             
                  # Transform a parameter map to an environment variable map, with parameter names prefixed
         | 
| 84 100 | 
             
                  # with 'PT_' and values transformed to JSON unless they're strings.
         | 
| @@ -111,7 +127,7 @@ module Bolt | |
| 111 127 | 
             
                    target = targets.first
         | 
| 112 128 | 
             
                    with_events(target, callback) do
         | 
| 113 129 | 
             
                      @logger.debug { "Running task run '#{task}' on #{target.uri}" }
         | 
| 114 | 
            -
                      run_task(target, task, arguments,  | 
| 130 | 
            +
                      run_task(target, task, arguments, reject_transport_options(target, options))
         | 
| 115 131 | 
             
                    end
         | 
| 116 132 | 
             
                  end
         | 
| 117 133 |  | 
| @@ -125,7 +141,7 @@ module Bolt | |
| 125 141 | 
             
                    target = targets.first
         | 
| 126 142 | 
             
                    with_events(target, callback) do
         | 
| 127 143 | 
             
                      @logger.debug("Running command '#{command}' on #{target.uri}")
         | 
| 128 | 
            -
                      run_command(target, command,  | 
| 144 | 
            +
                      run_command(target, command, reject_transport_options(target, options))
         | 
| 129 145 | 
             
                    end
         | 
| 130 146 | 
             
                  end
         | 
| 131 147 |  | 
| @@ -139,7 +155,7 @@ module Bolt | |
| 139 155 | 
             
                    target = targets.first
         | 
| 140 156 | 
             
                    with_events(target, callback) do
         | 
| 141 157 | 
             
                      @logger.debug { "Running script '#{script}' on #{target.uri}" }
         | 
| 142 | 
            -
                      run_script(target, script, arguments,  | 
| 158 | 
            +
                      run_script(target, script, arguments, reject_transport_options(target, options))
         | 
| 143 159 | 
             
                    end
         | 
| 144 160 | 
             
                  end
         | 
| 145 161 |  | 
| @@ -153,7 +169,7 @@ module Bolt | |
| 153 169 | 
             
                    target = targets.first
         | 
| 154 170 | 
             
                    with_events(target, callback) do
         | 
| 155 171 | 
             
                      @logger.debug { "Uploading: '#{source}' to #{destination} on #{target.uri}" }
         | 
| 156 | 
            -
                      upload(target, source, destination,  | 
| 172 | 
            +
                      upload(target, source, destination, reject_transport_options(target, options))
         | 
| 157 173 | 
             
                    end
         | 
| 158 174 | 
             
                  end
         | 
| 159 175 |  | 
    
        data/lib/bolt/transport/local.rb
    CHANGED
    
    | @@ -4,6 +4,7 @@ require 'json' | |
| 4 4 | 
             
            require 'fileutils'
         | 
| 5 5 | 
             
            require 'tmpdir'
         | 
| 6 6 | 
             
            require 'bolt/transport/base'
         | 
| 7 | 
            +
            require 'bolt/transport/powershell'
         | 
| 7 8 | 
             
            require 'bolt/util'
         | 
| 8 9 |  | 
| 9 10 | 
             
            module Bolt
         | 
| @@ -14,19 +15,23 @@ module Bolt | |
| 14 15 | 
             
                  end
         | 
| 15 16 |  | 
| 16 17 | 
             
                  def provided_features
         | 
| 17 | 
            -
                     | 
| 18 | 
            +
                    if Bolt::Util.windows?
         | 
| 19 | 
            +
                      ['powershell']
         | 
| 20 | 
            +
                    else
         | 
| 21 | 
            +
                      ['shell']
         | 
| 22 | 
            +
                    end
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  def default_input_method(executable)
         | 
| 26 | 
            +
                    input_method ||= Powershell.powershell_file?(executable) ? 'powershell' : 'both'
         | 
| 27 | 
            +
                    input_method
         | 
| 18 28 | 
             
                  end
         | 
| 19 29 |  | 
| 20 30 | 
             
                  def self.validate(_options); end
         | 
| 21 31 |  | 
| 22 32 | 
             
                  def initialize
         | 
| 23 33 | 
             
                    super
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                    if Bolt::Util.windows?
         | 
| 26 | 
            -
                      raise NotImplementedError, "The local transport is not yet implemented on Windows"
         | 
| 27 | 
            -
                    else
         | 
| 28 | 
            -
                      @conn = Shell.new
         | 
| 29 | 
            -
                    end
         | 
| 34 | 
            +
                    @conn = Shell.new
         | 
| 30 35 | 
             
                  end
         | 
| 31 36 |  | 
| 32 37 | 
             
                  def in_tmpdir(base)
         | 
| @@ -73,20 +78,32 @@ module Bolt | |
| 73 78 |  | 
| 74 79 | 
             
                      # unpack any Sensitive data AFTER we log
         | 
| 75 80 | 
             
                      arguments = unwrap_sensitive_args(arguments)
         | 
| 76 | 
            -
                      if  | 
| 77 | 
            -
                         | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 81 | 
            +
                      if Bolt::Util.windows?
         | 
| 82 | 
            +
                        if Powershell.powershell_file?(file)
         | 
| 83 | 
            +
                          command = Powershell.run_script(arguments, file)
         | 
| 84 | 
            +
                          output = @conn.execute(command, dir: dir, env: "powershell.exe")
         | 
| 85 | 
            +
                        else
         | 
| 86 | 
            +
                          path, args = *Powershell.process_from_extension(file)
         | 
| 87 | 
            +
                          args += Powershell.escape_arguments(arguments)
         | 
| 88 | 
            +
                          command = args.unshift(path).join(' ')
         | 
| 89 | 
            +
                          output = @conn.execute(command, dir: dir)
         | 
| 90 | 
            +
                        end
         | 
| 91 | 
            +
                      else
         | 
| 92 | 
            +
                        if arguments.empty?
         | 
| 93 | 
            +
                          # We will always provide separated arguments, so work-around Open3's handling of a single
         | 
| 94 | 
            +
                          # argument as the entire command string for script paths containing spaces.
         | 
| 95 | 
            +
                          arguments = ['']
         | 
| 96 | 
            +
                        end
         | 
| 97 | 
            +
                        output = @conn.execute(file, *arguments, dir: dir)
         | 
| 80 98 | 
             
                      end
         | 
| 81 | 
            -
                      output = @conn.execute(file, *arguments, dir: dir)
         | 
| 82 99 | 
             
                      Bolt::Result.for_command(target, output.stdout.string, output.stderr.string, output.exit_code)
         | 
| 83 100 | 
             
                    end
         | 
| 84 101 | 
             
                  end
         | 
| 85 102 |  | 
| 86 103 | 
             
                  def run_task(target, task, arguments, _options = {})
         | 
| 87 | 
            -
                    implementation =  | 
| 104 | 
            +
                    implementation = select_implementation(target, task)
         | 
| 88 105 | 
             
                    executable = implementation['path']
         | 
| 89 | 
            -
                    input_method = implementation['input_method'] | 
| 106 | 
            +
                    input_method = implementation['input_method']
         | 
| 90 107 | 
             
                    extra_files = implementation['files']
         | 
| 91 108 |  | 
| 92 109 | 
             
                    in_tmpdir(target.options['tmpdir']) do |dir|
         | 
| @@ -108,16 +125,43 @@ module Bolt | |
| 108 125 | 
             
                      copy_file(executable, script)
         | 
| 109 126 | 
             
                      File.chmod(0o750, script)
         | 
| 110 127 |  | 
| 111 | 
            -
                      #  | 
| 112 | 
            -
                      #  | 
| 128 | 
            +
                      # log the arguments with sensitive data redacted, do NOT log unwrapped_arguments
         | 
| 129 | 
            +
                      logger.debug("Running '#{script}' with #{arguments}")
         | 
| 113 130 | 
             
                      unwrapped_arguments = unwrap_sensitive_args(arguments)
         | 
| 131 | 
            +
             | 
| 114 132 | 
             
                      stdin = STDIN_METHODS.include?(input_method) ? JSON.dump(unwrapped_arguments) : nil
         | 
| 115 | 
            -
                      env = ENVIRONMENT_METHODS.include?(input_method) ? envify_params(unwrapped_arguments) : nil
         | 
| 116 133 |  | 
| 117 | 
            -
                       | 
| 118 | 
            -
             | 
| 134 | 
            +
                      if Bolt::Util.windows?
         | 
| 135 | 
            +
                        # WINDOWS
         | 
| 136 | 
            +
                        if ENVIRONMENT_METHODS.include?(input_method)
         | 
| 137 | 
            +
                          environment_params = envify_params(unwrapped_arguments).each_with_object([]) do |(arg, val), list|
         | 
| 138 | 
            +
                            list << Powershell.set_env(arg, val)
         | 
| 139 | 
            +
                          end
         | 
| 140 | 
            +
                          environment_params = environment_params.join("\n") + "\n"
         | 
| 141 | 
            +
                        else
         | 
| 142 | 
            +
                          environment_params = ""
         | 
| 143 | 
            +
                        end
         | 
| 119 144 |  | 
| 120 | 
            -
             | 
| 145 | 
            +
                        output =
         | 
| 146 | 
            +
                          if Powershell.powershell_file?(script) && stdin.nil?
         | 
| 147 | 
            +
                            command = Powershell.run_ps_task(arguments, script, input_method)
         | 
| 148 | 
            +
                            command = environment_params + Powershell.shell_init + command
         | 
| 149 | 
            +
                            if input_method == 'powershell'
         | 
| 150 | 
            +
                              @conn.execute(command, dir: dir, env: "powershell.exe")
         | 
| 151 | 
            +
                            else
         | 
| 152 | 
            +
                              @conn.execute(command, dir: dir, stdin: stdin, env: "powershell.exe")
         | 
| 153 | 
            +
                            end
         | 
| 154 | 
            +
                          else
         | 
| 155 | 
            +
                            path, args = *Powershell.process_from_extension(script)
         | 
| 156 | 
            +
                            command = args.unshift(path).join(' ')
         | 
| 157 | 
            +
                            command = environment_params + Powershell.shell_init + command
         | 
| 158 | 
            +
                            @conn.execute(command, dir: dir, stdin: stdin, env: "powershell.exe")
         | 
| 159 | 
            +
                          end
         | 
| 160 | 
            +
                      else
         | 
| 161 | 
            +
                        # POSIX
         | 
| 162 | 
            +
                        env = ENVIRONMENT_METHODS.include?(input_method) ? envify_params(unwrapped_arguments) : nil
         | 
| 163 | 
            +
                        output = @conn.execute(script, stdin: stdin, env: env, dir: dir)
         | 
| 164 | 
            +
                      end
         | 
| 121 165 | 
             
                      Bolt::Result.for_task(target, output.stdout.string, output.stderr.string, output.exit_code)
         | 
| 122 166 | 
             
                    end
         | 
| 123 167 | 
             
                  end
         |