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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
|
require 'puppet'
require 'puppet/server'
module Puppet
# Serve Puppet elements. Useful for querying, copying, and, um, other stuff.
class Server::Resource < Server::Handler
attr_accessor :local
@interface = XMLRPC::Service::Interface.new("resource") { |iface|
iface.add_method("string apply(string, string)")
iface.add_method("string describe(string, string, array, array)")
iface.add_method("string list(string, array, string)")
}
# Apply a TransBucket as a transaction.
def apply(bucket, format = "yaml", client = nil, clientip = nil)
unless @local
begin
case format
when "yaml":
bucket = YAML::load(Base64.decode64(bucket))
else
raise Puppet::Error, "Unsupported format '%s'" % format
end
rescue => detail
raise Puppet::Error, "Could not load YAML TransBucket: %s" % detail
end
end
component = bucket.to_type
# Create a client, but specify the remote machine as the server
# because the class requires it, even though it's unused
client = Puppet::Client::MasterClient.new(:Server => client||"localhost")
# Set the objects
client.objects = component
# And then apply the configuration. This way we're reusing all
# the code in there. It should probably just be separated out, though.
transaction = client.apply
# And then clean up
component.remove
# It'd be nice to return some kind of report, but... at this point
# we have no such facility.
return "success"
end
# Describe a given object. This returns the 'is' values for every property
# available on the object type.
def describe(type, name, retrieve = nil, ignore = [], format = "yaml", client = nil, clientip = nil)
Puppet.info "Describing %s[%s]" % [type.to_s.capitalize, name]
@local = true unless client
typeklass = nil
unless typeklass = Puppet.type(type)
raise Puppet::Error, "Puppet type %s is unsupported" % type
end
obj = nil
retrieve ||= :all
ignore ||= []
if obj = typeklass[name]
obj[:check] = retrieve
else
begin
obj = typeklass.create(:name => name, :check => retrieve)
rescue Puppet::Error => detail
raise Puppet::Error, "%s[%s] could not be created: %s" %
[type, name, detail]
end
end
unless obj
raise XMLRPC::FaultException.new(
1, "Could not create %s[%s]" % [type, name]
)
end
trans = obj.to_trans
# Now get rid of any attributes they specifically don't want
ignore.each do |st|
if trans.include? st
trans.delete(st)
end
end
# And get rid of any attributes that are nil
trans.each do |attr, value|
if value.nil?
trans.delete(attr)
end
end
unless @local
case format
when "yaml":
trans = Base64.encode64(YAML::dump(trans))
else
raise XMLRPC::FaultException.new(
1, "Unavailable config format %s" % format
)
end
end
return trans
end
# Create a new fileserving module.
def initialize(hash = {})
if hash[:Local]
@local = hash[:Local]
else
@local = false
end
end
# List all of the elements of a given type.
def list(type, ignore = [], base = nil, format = "yaml", client = nil, clientip = nil)
@local = true unless client
typeklass = nil
unless typeklass = Puppet.type(type)
raise Puppet::Error, "Puppet type %s is unsupported" % type
end
# They can pass in false
ignore ||= []
ignore = [ignore] unless ignore.is_a? Array
bucket = TransBucket.new
bucket.type = typeklass.name
typeklass.list.each do |obj|
next if ignore.include? obj.name
object = TransObject.new(obj.name, typeklass.name)
bucket << object
end
unless @local
case format
when "yaml":
begin
bucket = Base64.encode64(YAML::dump(bucket))
rescue => detail
Puppet.err detail
raise XMLRPC::FaultException.new(
1, detail.to_s
)
end
else
raise XMLRPC::FaultException.new(
1, "Unavailable config format %s" % format
)
end
end
return bucket
end
private
def authcheck(file, mount, client, clientip)
unless mount.allowed?(client, clientip)
mount.warning "%s cannot access %s" %
[client, file]
raise Puppet::Server::AuthorizationError, "Cannot access %s" % mount
end
end
# Deal with ignore parameters.
def handleignore(children, path, ignore)
ignore.each { |ignore|
Dir.glob(File.join(path,ignore), File::FNM_DOTMATCH) { |match|
children.delete(File.basename(match))
}
}
return children
end
def to_s
"resource"
end
end
end
# $Id$
|