Class: Bolt::Result

Inherits:
Object
  • Object
show all
Defined in:
lib/bolt/result.rb

Direct Known Subclasses

ApplyResult

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(target, error: nil, message: nil, value: nil, action: 'action', object: nil) ⇒ Result

Returns a new instance of Result.



105
106
107
108
109
110
111
112
113
114
115
# File 'lib/bolt/result.rb', line 105

def initialize(target, error: nil, message: nil, value: nil, action: 'action', object: nil)
  @target = target
  @value = value || {}
  @action = action
  @object = object
  if error && !error.is_a?(Hash)
    raise "TODO: how did we get a string error"
  end
  @value['_error'] = error if error
  @value['_output'] = message if message
end

Instance Attribute Details

#actionObject (readonly)

Returns the value of attribute action.



8
9
10
# File 'lib/bolt/result.rb', line 8

def action
  @action
end

#objectObject (readonly)

Returns the value of attribute object.



8
9
10
# File 'lib/bolt/result.rb', line 8

def object
  @object
end

#targetObject (readonly)

Returns the value of attribute target.



8
9
10
# File 'lib/bolt/result.rb', line 8

def target
  @target
end

#valueObject (readonly)

Returns the value of attribute value.



8
9
10
# File 'lib/bolt/result.rb', line 8

def value
  @value
end

Class Method Details

._pcore_init_from_hashObject



87
88
89
# File 'lib/bolt/result.rb', line 87

def self._pcore_init_from_hash
  raise "Result shouldn't be instantiated from a pcore_init class method. How did this get called?"
end

.for_command(target, stdout, stderr, exit_code, action, command) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/bolt/result.rb', line 25

def self.for_command(target, stdout, stderr, exit_code, action, command)
  value = {
    'stdout' => stdout,
    'stderr' => stderr,
    'exit_code' => exit_code
  }
  unless exit_code == 0
    value['_error'] = {
      'kind' => 'puppetlabs.tasks/command-error',
      'issue_code' => 'COMMAND_ERROR',
      'msg' => "The command failed with exit code #{exit_code}",
      'details' => { 'exit_code' => exit_code }
    }
  end
  new(target, value: value, action: action, object: command)
end

.for_task(target, stdout, stderr, exit_code, task) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/bolt/result.rb', line 42

def self.for_task(target, stdout, stderr, exit_code, task)
  stdout.force_encoding('utf-8') unless stdout.encoding == Encoding::UTF_8
  value = if stdout.valid_encoding?
            parse_hash(stdout) || { '_output' => stdout }
          else
            { '_error' => { 'kind' => 'puppetlabs.tasks/task-error',
                            'issue_code' => 'TASK_ERROR',
                            'msg' => 'The task result contained invalid UTF-8 on stdout',
                            'details' => {} } }
          end

  if exit_code != 0 && value['_error'].nil?
    msg = if stdout.empty?
            if stderr.empty?
              "The task failed with exit code #{exit_code} and no output"
            else
              "The task failed with exit code #{exit_code} and no stdout, but stderr contained:\n#{stderr}"
            end
          else
            "The task failed with exit code #{exit_code}"
          end
    value['_error'] = { 'kind' => 'puppetlabs.tasks/task-error',
                        'issue_code' => 'TASK_ERROR',
                        'msg' => msg,
                        'details' => { 'exit_code' => exit_code } }
  end
  new(target, value: value, action: 'task', object: task)
end

.for_upload(target, source, destination) ⇒ Object



78
79
80
# File 'lib/bolt/result.rb', line 78

def self.for_upload(target, source, destination)
  new(target, message: "Uploaded '#{source}' to '#{target.host}:#{destination}'", action: 'upload', object: source)
end

.from_asserted_args(target, value) ⇒ Object

Satisfies the Puppet datatypes API



83
84
85
# File 'lib/bolt/result.rb', line 83

def self.from_asserted_args(target, value)
  new(target, value: value)
end

.from_exception(target, exception, action: 'action') ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/bolt/result.rb', line 10

def self.from_exception(target, exception, action: 'action')
  if exception.is_a?(Bolt::Error)
    error = exception.to_h
  else
    error = {
      'kind' => 'puppetlabs.tasks/exception-error',
      'issue_code' => 'EXCEPTION',
      'msg' => exception.message,
      'details' => { 'class' => exception.class.to_s }
    }
    error['details']['stack_trace'] = exception.backtrace.join('\n') if exception.backtrace
  end
  Result.new(target, error: error, action: action)
end

.parse_hash(string) ⇒ Object



71
72
73
74
75
76
# File 'lib/bolt/result.rb', line 71

def self.parse_hash(string)
  value = JSON.parse(string)
  value if value.is_a? Hash
rescue JSON::ParserError
  nil
end

Instance Method Details

#==(other) ⇒ Object



139
140
141
# File 'lib/bolt/result.rb', line 139

def ==(other)
  eql?(other)
end

#[](key) ⇒ Object



135
136
137
# File 'lib/bolt/result.rb', line 135

def [](key)
  value[key]
end

#_pcore_init_from_hash(init_hash) ⇒ Object



91
92
93
94
# File 'lib/bolt/result.rb', line 91

def _pcore_init_from_hash(init_hash)
  opts = init_hash.reject { |k, _v| k == 'target' }
  initialize(init_hash['target'], opts.transform_keys(&:to_sym))
end

#_pcore_init_hashObject



96
97
98
99
100
101
102
103
# File 'lib/bolt/result.rb', line 96

def _pcore_init_hash
  { 'target' => @target,
    'error' => @value['_error'],
    'message' => @value['_output'],
    'value' => @value,
    'action' => @action,
    'object' => @object }
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


129
130
131
132
133
# File 'lib/bolt/result.rb', line 129

def eql?(other)
  self.class == other.class &&
    target == other.target &&
    value == other.value
end

#errorObject

Warning: This will fail outside of a compilation. Use error_hash inside bolt. Is it crazy for this to behave differently outside a compiler?



195
196
197
198
199
200
# File 'lib/bolt/result.rb', line 195

def error
  if error_hash
    Puppet::DataTypes::Error.from_asserted_hash(error_hash)

  end
end

#error_hashObject

This allows access to errors outside puppet compilation it should be prefered over error in bolt code



188
189
190
# File 'lib/bolt/result.rb', line 188

def error_hash
  value['_error']
end

#generic_valueObject



125
126
127
# File 'lib/bolt/result.rb', line 125

def generic_value
  safe_value.reject { |k, _| %w[_error _output].include? k }
end

#messageObject



117
118
119
# File 'lib/bolt/result.rb', line 117

def message
  @value['_output']
end

#message?Boolean

Returns:

  • (Boolean)


121
122
123
# File 'lib/bolt/result.rb', line 121

def message?
  message && !message.strip.empty?
end

#ok?Boolean Also known as: ok, success?

Returns:

  • (Boolean)


180
181
182
# File 'lib/bolt/result.rb', line 180

def ok?
  error_hash.nil?
end

#safe_valueObject

This is the value with all non-UTF-8 characters removed, suitable for printing or converting to JSON. It should only be possible to have non-UTF-8 characters in stdout/stderr keys as they are not allowed from tasks but we scrub the whole thing just in case.



155
156
157
158
159
160
161
162
163
164
# File 'lib/bolt/result.rb', line 155

def safe_value
  Bolt::Util.walk_vals(value) do |val|
    if val.is_a?(String)
      # Replace invalid bytes with hex codes, ie. \xDE\xAD\xBE\xEF
      val.scrub { |c| c.bytes.map { |b| "\\x" + b.to_s(16).upcase }.join }
    else
      val
    end
  end
end

#statusObject



176
177
178
# File 'lib/bolt/result.rb', line 176

def status
  ok? ? 'success' : 'failure'
end

#to_dataObject



166
167
168
169
170
171
172
173
174
# File 'lib/bolt/result.rb', line 166

def to_data
  {
    "target" => @target.name,
    "action" => action,
    "object" => object,
    "status" => status,
    "value" => safe_value
  }
end

#to_json(opts = nil) ⇒ Object



143
144
145
# File 'lib/bolt/result.rb', line 143

def to_json(opts = nil)
  to_data.to_json(opts)
end

#to_sObject



147
148
149
# File 'lib/bolt/result.rb', line 147

def to_s
  to_json
end