Class: Bolt::Transport::Sudoable::Connection

Inherits:
Object
  • Object
show all
Defined in:
lib/bolt/transport/sudoable/connection.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(target) ⇒ Connection

Returns a new instance of Connection.



11
12
13
14
15
# File 'lib/bolt/transport/sudoable/connection.rb', line 11

def initialize(target)
  @target = target
  @run_as = nil
  @logger = Logging.logger[@target.safe_name]
end

Instance Attribute Details

#targetObject

Returns the value of attribute target.



9
10
11
# File 'lib/bolt/transport/sudoable/connection.rb', line 9

def target
  @target
end

Instance Method Details

#build_sudoable_command_str(command_str, sudo_str, sudo_id, options) ⇒ Object

A helper to build up a single string that contains all of the options for privilege escalation. A wrapper script is used to direct task input to stdin when a tty is allocated and thus we do not need to prepend_sudo_success when using the wrapper or when the task does not require stdin data.



88
89
90
91
92
93
94
# File 'lib/bolt/transport/sudoable/connection.rb', line 88

def build_sudoable_command_str(command_str, sudo_str, sudo_id, options)
  if options[:stdin] && !options[:wrapper]
    "#{sudo_str} #{prepend_sudo_success(sudo_id, command_str)}"
  else
    "#{sudo_str} #{command_str}"
  end
end

#execute(*_args) ⇒ Object

Raises:

  • (NotImplementedError)


71
72
73
74
# File 'lib/bolt/transport/sudoable/connection.rb', line 71

def execute(*_args)
  message = "#{self.class.name} must implement #{method} to execute commands"
  raise NotImplementedError, message
end

#inject_interpreter(interpreter, command) ⇒ Object

Returns string with the interpreter conditionally prepended



97
98
99
100
101
102
103
104
105
106
107
# File 'lib/bolt/transport/sudoable/connection.rb', line 97

def inject_interpreter(interpreter, command)
  if interpreter
    if command.is_a?(Array)
      command.unshift(interpreter)
    else
      command = [interpreter, command]
    end
  end

  command.is_a?(String) ? command : Shellwords.shelljoin(command)
end

#make_executable(path) ⇒ Object



32
33
34
35
36
37
38
# File 'lib/bolt/transport/sudoable/connection.rb', line 32

def make_executable(path)
  result = execute(['chmod', 'u+x', path])
  if result.exit_code != 0
    message = "Could not make file '#{path}' executable: #{result.stderr.string}"
    raise Bolt::Node::FileError.new(message, 'CHMOD_ERROR')
  end
end

#make_tempdirObject



40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/bolt/transport/sudoable/connection.rb', line 40

def make_tempdir
  tmpdir = @target.options.fetch('tmpdir', '/tmp')
  script_dir = @target.options.fetch('script-dir', SecureRandom.uuid)
  tmppath = File.join(tmpdir, script_dir)
  command = ['mkdir', '-m', 700, tmppath]

  result = execute(command)
  if result.exit_code != 0
    raise Bolt::Node::FileError.new("Could not make tempdir: #{result.stderr.string}", 'TEMPDIR_ERROR')
  end
  path = tmppath || result.stdout.string.chomp
  Sudoable::Tmpdir.new(self, path)
end

#prepend_sudo_success(sudo_id, command_str) ⇒ Object

In the case where a task is run with elevated privilege and needs stdin a random string is echoed to stderr indicating that the stdin is available for task input data because the sudo password has already either been provided on stdin or was not needed.



80
81
82
# File 'lib/bolt/transport/sudoable/connection.rb', line 80

def prepend_sudo_success(sudo_id, command_str)
  "sh -c 'echo #{sudo_id} 1>&2; #{command_str}'"
end

#run_asObject

This method allows the @run_as variable to be used as a per-operation override for the user to run as. When @run_as is unset, the user specified on the target will be used.



20
21
22
# File 'lib/bolt/transport/sudoable/connection.rb', line 20

def run_as
  @run_as || target.options['run-as']
end

#running_as(user) ⇒ Object

Run as the specified user for the duration of the block.



25
26
27
28
29
30
# File 'lib/bolt/transport/sudoable/connection.rb', line 25

def running_as(user)
  @run_as = user
  yield
ensure
  @run_as = nil
end

#with_tempdirObject

A helper to create and delete a tempdir on the remote system. Yields the directory name.



64
65
66
67
68
69
# File 'lib/bolt/transport/sudoable/connection.rb', line 64

def with_tempdir
  dir = make_tempdir
  yield dir
ensure
  dir&.delete
end

#write_executable(dir, file, filename = nil) ⇒ Object



54
55
56
57
58
59
60
# File 'lib/bolt/transport/sudoable/connection.rb', line 54

def write_executable(dir, file, filename = nil)
  filename ||= File.basename(file)
  remote_path = File.join(dir.to_s, filename)
  copy_file(file, remote_path)
  make_executable(remote_path)
  remote_path
end