summaryrefslogtreecommitdiffstats
path: root/lib/puppet/indirector/face.rb
blob: 1371c647e032916dccf11dc79e49da50fbf17c3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
require 'puppet/face'

class Puppet::Indirector::Face < Puppet::Face
  option "--terminus TERMINUS" do
    summary "The indirector terminus to use for this action"
    description <<-EOT
Indirector faces expose indirected subsystems of Puppet. These
subsystems are each able to retrieve and alter a specific type of data
(with the familiar actions of `find`, `search`, `save`, and `destroy`)
from an arbitrary number of pluggable backends. In Puppet parlance,
these backends are called terminuses.

Almost all indirected subsystems have a `rest` terminus that interacts
with the puppet master's data. Most of them have additional terminuses
for various local data models, which are in turn used by the indirected
subsystem on the puppet master whenever it receives a remote request.

The terminus for an action is often determined by context, but
occasionally needs to be set explicitly. See the "Notes" section of this
face's manpage for more details.
    EOT

    before_action do |action, args, options|
      set_terminus(options[:terminus])
    end

    after_action do |action, args, options|
      indirection.reset_terminus_class
    end
  end

  def self.indirections
    Puppet::Indirector::Indirection.instances.collect { |t| t.to_s }.sort
  end

  def self.terminus_classes(indirection)
    Puppet::Indirector::Terminus.terminus_classes(indirection.to_sym).collect { |t| t.to_s }.sort
  end

  def call_indirection_method(method, key, options)
    begin
      result = indirection.__send__(method, key, options)
    rescue => detail
      puts detail.backtrace if Puppet[:trace]
      raise "Could not call '#{method}' on '#{indirection_name}': #{detail}"
    end

    return result
  end

  action :destroy do
    summary "Delete an object"
    when_invoked { |key, options| call_indirection_method(:destroy, key, options) }
  end

  action :find do
    summary "Retrieve an object by name"
    when_invoked { |key, options| call_indirection_method(:find, key, options) }
  end

  action :save do
    summary "Create or modify an object"
    notes <<-EOT
      Save actions cannot currently be invoked from the command line, and are
      for API use only.
    EOT
    when_invoked { |key, options| call_indirection_method(:save, key, options) }
  end

  action :search do
    summary "Search for an object"
    when_invoked { |key, options| call_indirection_method(:search, key, options) }
  end

  # Print the configuration for the current terminus class
  action :info do
    summary "Print the default terminus class for this face"
    description <<-EOT
      TK So this is per-face, right? No way to tell what the default terminus
      is per-action, for subsystems that switch to REST for save but query
      locally for find?
    EOT

    when_invoked do |*args|
      if t = indirection.terminus_class
        puts "Run mode '#{Puppet.run_mode.name}': #{t}"
      else
        $stderr.puts "No default terminus class for run mode '#{Puppet.run_mode.name}'"
      end
    end
  end

  attr_accessor :from

  def indirection_name
    @indirection_name || name.to_sym
  end

  # Here's your opportunity to override the indirection name.  By default it
  # will be the same name as the face.
  def set_indirection_name(name)
    @indirection_name = name
  end

  # Return an indirection associated with a face, if one exists;
  # One usually does.
  def indirection
    unless @indirection
      @indirection = Puppet::Indirector::Indirection.instance(indirection_name)
      @indirection or raise "Could not find terminus for #{indirection_name}"
    end
    @indirection
  end

  def set_terminus(from)
    begin
      indirection.terminus_class = from
    rescue => detail
      raise "Could not set '#{indirection.name}' terminus to '#{from}' (#{detail}); valid terminus types are #{self.class.terminus_classes(indirection.name).join(", ") }"
    end
  end
end