2 require 'puppet/network/handler'
4 # Serve Puppet elements. Useful for querying, copying, and, um, other stuff.
5 class Puppet::Network::Handler
6 class Resource < Handler
7 desc "An interface for interacting with client-based resources that can
8 be used for querying or managing remote machines without using Puppet's
11 The ``describe`` and ``list`` methods return TransBuckets containing
12 TransObject instances (``describe`` returns a single TransBucket),
13 and the ``apply`` method accepts a TransBucket of TransObjects and
19 @interface = XMLRPC::Service::Interface.new("resource") { |iface|
20 iface.add_method("string apply(string, string)")
21 iface.add_method("string describe(string, string, array, array)")
22 iface.add_method("string list(string, array, string)")
27 # Apply a TransBucket as a transaction.
28 def apply(bucket, format = "yaml", client = nil, clientip = nil)
33 bucket = YAML::load(Base64.decode64(bucket))
35 raise Puppet::Error, "Unsupported format '%s'" % format
38 raise Puppet::Error, "Could not load YAML TransBucket: %s" % detail
42 catalog = bucket.to_catalog
44 # And then apply the catalog. This way we're reusing all
45 # the code in there. It should probably just be separated out, though.
46 transaction = catalog.apply
51 # It'd be nice to return some kind of report, but... at this point
52 # we have no such facility.
56 # Describe a given object. This returns the 'is' values for every property
57 # available on the object type.
58 def describe(type, name, retrieve = nil, ignore = [], format = "yaml", client = nil, clientip = nil)
59 Puppet.info "Describing %s[%s]" % [type.to_s.capitalize, name]
60 @local = true unless client
62 unless typeklass = Puppet.type(type)
63 raise Puppet::Error, "Puppet type %s is unsupported" % type
71 if obj = typeklass[name]
72 obj[:check] = retrieve
75 obj = typeklass.create(:name => name, :check => retrieve)
76 rescue Puppet::Error => detail
77 raise Puppet::Error, "%s[%s] could not be created: %s" %
83 raise XMLRPC::FaultException.new(
84 1, "Could not create %s[%s]" % [type, name]
90 # Now get rid of any attributes they specifically don't want
97 # And get rid of any attributes that are nil
98 trans.each do |attr, value|
107 trans = Base64.encode64(YAML::dump(trans))
109 raise XMLRPC::FaultException.new(
110 1, "Unavailable config format %s" % format
118 # Create a new fileserving module.
119 def initialize(hash = {})
121 @local = hash[:Local]
127 # List all of the elements of a given type.
128 def list(type, ignore = [], base = nil, format = "yaml", client = nil, clientip = nil)
129 @local = true unless client
131 unless typeklass = Puppet.type(type)
132 raise Puppet::Error, "Puppet type %s is unsupported" % type
135 # They can pass in false
137 ignore = [ignore] unless ignore.is_a? Array
138 bucket = Puppet::TransBucket.new
139 bucket.type = typeklass.name
141 typeklass.instances.each do |obj|
142 next if ignore.include? obj.name
144 #object = Puppet::TransObject.new(obj.name, typeklass.name)
145 bucket << obj.to_trans
152 bucket = Base64.encode64(YAML::dump(bucket))
155 raise XMLRPC::FaultException.new(
160 raise XMLRPC::FaultException.new(
161 1, "Unavailable config format %s" % format
171 def authcheck(file, mount, client, clientip)
172 unless mount.allowed?(client, clientip)
173 mount.warning "%s cannot access %s" %
175 raise Puppet::AuthorizationError, "Cannot access %s" % mount
179 # Deal with ignore parameters.
180 def handleignore(children, path, ignore)
181 ignore.each { |ignore|
182 Dir.glob(File.join(path,ignore), File::FNM_DOTMATCH) { |match|
183 children.delete(File.basename(match))