Class: Bolt::Transport::Orch::Connection

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

Constant Summary collapse

CONTEXT_KEYS =
Set.new(%i[plan_name description params]).freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts, plan_context, logger) ⇒ Connection

Returns a new instance of Connection.


19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/bolt/transport/orch/connection.rb', line 19

def initialize(opts, plan_context, logger)
  require 'addressable/uri'

  @logger = logger
  @key = self.class.get_key(opts)
  client_opts = opts.slice('token-file', 'cacert', 'job-poll-interval', 'job-poll-timeout', 'read-timeout')

  if opts['service-url']
    uri = Addressable::URI.parse(opts['service-url'])
    uri&.port ||= 8143
    client_opts['service-url'] = uri.to_s
  end

  client_opts['User-Agent'] = "Bolt/#{VERSION}"

  %w[token-file cacert].each do |f|
    client_opts[f] = File.expand_path(client_opts[f]) if client_opts[f]
  end
  logger.debug("Creating orchestrator client for #{client_opts}")
  @client = OrchestratorClient.new(client_opts, true)
  @plan_context = plan_context
  @plan_job = start_plan(@plan_context)
  logger.debug("Started plan #{@plan_job}")
  @environment = opts["task-environment"]
end

Instance Attribute Details

#keyObject (readonly)

Returns the value of attribute key.


7
8
9
# File 'lib/bolt/transport/orch/connection.rb', line 7

def key
  @key
end

#loggerObject (readonly)

Returns the value of attribute logger.


7
8
9
# File 'lib/bolt/transport/orch/connection.rb', line 7

def logger
  @logger
end

Class Method Details

.get_key(opts) ⇒ Object


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

def self.get_key(opts)
  [
    opts['service-url'],
    opts['task-environment'],
    opts['token-file']
  ].join('-')
end

Instance Method Details

#build_request(targets, task, arguments, description = nil) ⇒ Object


75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/bolt/transport/orch/connection.rb', line 75

def build_request(targets, task, arguments, description = nil)
  body = { task: task.name,
           environment: @environment,
           noop: arguments['_noop'],
           params: arguments.reject { |k, _| k.start_with?('_') },
           scope: {
             nodes: get_certnames(targets)
           } }
  body[:description] = description if description
  body[:plan_job] = @plan_job if @plan_job
  body
end

#finish_plan(plan_result) ⇒ Object


61
62
63
64
65
66
67
68
69
# File 'lib/bolt/transport/orch/connection.rb', line 61

def finish_plan(plan_result)
  if @plan_job
    @client.command.plan_finish(
      plan_job: @plan_job,
      result: plan_result.value || '',
      status: plan_result.status
    )
  end
end

#get_certnames(targets) ⇒ Object


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

def get_certnames(targets)
  targets.map { |t| t.host || t.name }
end

#query_inventory(targets) ⇒ Object


104
105
106
# File 'lib/bolt/transport/orch/connection.rb', line 104

def query_inventory(targets)
  @client.post('inventory', nodes: get_certnames(targets))
end

#run_task(targets, task, arguments, options) ⇒ Object


88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/bolt/transport/orch/connection.rb', line 88

def run_task(targets, task, arguments, options)
  body = build_request(targets, task, arguments, options[:description])
  @client.run_task(body)
rescue OrchestratorClient::ApiError => e
  if e.data['kind'] == 'puppetlabs.orchestrator/plan-already-finished'
    @logger.debug("Retrying the task")
    # Instead of recursing, just retry once
    @plan_job = start_plan(@plan_context)
    # Rebuild the request with the new plan job ID
    body = build_request(targets, task, arguments, options[:description])
    @client.run_task(body)
  else
    raise e
  end
end

#start_plan(plan_context) ⇒ Object


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/bolt/transport/orch/connection.rb', line 45

def start_plan(plan_context)
  if plan_context
    begin
      opts = plan_context.select { |k, _| CONTEXT_KEYS.include? k }
      @client.command.plan_start(opts)['name']
    rescue OrchestratorClient::ApiError => e
      if e.code == '404'
        @logger.debug("Orchestrator #{key} does not support plans")
      else
        @logger.error("Failed to start a plan with orchestrator #{key}: #{e.message}")
      end
      nil
    end
  end
end