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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
# An actual indirection.
class Puppet::Indirector::Indirection
@@indirections = []
# Clear all cached termini from all indirections.
def self.clear_cache
@@indirections.each { |ind| ind.clear_cache }
end
# Find an indirection by name. This is provided so that Terminus classes
# can specifically hook up with the indirections they are associated with.
def self.instance(name)
@@indirections.find { |i| i.name == name }
end
attr_accessor :name, :model
# Create and return our cache terminus.
def cache
raise(Puppet::DevError, "Tried to cache when no cache class was set") unless cache_class
terminus(cache_class)
end
# Should we use a cache?
def cache?
cache_class ? true : false
end
attr_reader :cache_class
# Define a terminus class to be used for caching.
def cache_class=(class_name)
validate_terminus_class(class_name)
@cache_class = class_name
end
# Clear our cached list of termini, and reset the cache name
# so it's looked up again.
# This is only used for testing.
def clear_cache
@termini.clear
end
# This is only used for testing.
def delete
@@indirections.delete(self) if @@indirections.include?(self)
end
def initialize(model, name, options = {})
@model = model
@name = name
@termini = {}
@cache_class = nil
raise(ArgumentError, "Indirection %s is already defined" % @name) if @@indirections.find { |i| i.name == @name }
@@indirections << self
if mod = options[:extend]
extend(mod)
options.delete(:extend)
end
# This is currently only used for cache_class and terminus_class.
options.each do |name, value|
begin
send(name.to_s + "=", value)
rescue NoMethodError
raise ArgumentError, "%s is not a valid Indirection parameter" % name
end
end
end
# Return the singleton terminus for this indirection.
def terminus(terminus_name = nil)
# Get the name of the terminus.
unless terminus_name ||= terminus_class
raise Puppet::DevError, "No terminus specified for %s; cannot redirect" % self.name
end
return @termini[terminus_name] ||= make_terminus(terminus_name)
end
attr_reader :terminus_class
# Specify the terminus class to use.
def terminus_class=(terminus_class)
validate_terminus_class(terminus_class)
@terminus_class = terminus_class
end
# This is used by terminus_class= and cache=.
def validate_terminus_class(terminus_class)
unless terminus_class and terminus_class.to_s != ""
raise ArgumentError, "Invalid terminus name %s" % terminus_class.inspect
end
unless Puppet::Indirector::Terminus.terminus_class(self.name, terminus_class)
raise ArgumentError, "Could not find terminus %s for indirection %s" % [terminus_class, self.name]
end
end
def find(key, *args)
# Select the appropriate terminus if there's a hook
# for doing so. This allows the caller to pass in some kind
# of URI that the indirection can use for routing to the appropriate
# terminus.
if respond_to?(:select_terminus)
terminus_name = select_terminus(key, *args)
else
terminus_name = terminus_class
end
# See if our instance is in the cache and up to date.
if cache? and cache.has_most_recent?(key, terminus(terminus_name).version(key))
Puppet.info "Using cached %s %s" % [self.name, key]
return cache.find(key, *args)
end
# Otherwise, return the result from the terminus, caching if appropriate.
if result = terminus(terminus_name).find(key, *args)
result.version ||= Time.now.utc
if cache?
Puppet.info "Caching %s %s" % [self.name, key]
cache.save(result, *args)
end
return result
end
end
def destroy(*args)
terminus.destroy(*args)
end
def search(*args)
terminus.search(*args)
end
# these become instance methods
def save(instance, *args)
instance.version ||= Time.now.utc
dest = cache? ? cache : terminus
return if dest.has_most_recent?(instance.name, instance.version)
Puppet.info "Caching %s %s" % [self.name, instance.name] if cache?
cache.save(instance, *args) if cache?
terminus.save(instance, *args)
end
def version(*args)
terminus.version(*args)
end
private
# Create a new terminus instance.
def make_terminus(terminus_class)
# Load our terminus class.
unless klass = Puppet::Indirector::Terminus.terminus_class(self.name, terminus_class)
raise ArgumentError, "Could not find terminus %s for indirection %s" % [terminus_class, self.name]
end
return klass.new
end
end
|