summaryrefslogtreecommitdiffstats
path: root/lib/puppet/network/handler/resource.rb
blob: 2937aa7be082e7be089e8b7e40973781b9987da9 (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
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
require 'puppet'
require 'puppet/network/handler'

# Serve Puppet elements.  Useful for querying, copying, and, um, other stuff.
class Puppet::Network::Handler
    class Resource < 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::Network::Client.client(:Master).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 = Puppet::TransBucket.new
            bucket.type = typeklass.name

            typeklass.list.each do |obj|
                next if ignore.include? obj.name

                #object = Puppet::TransObject.new(obj.name, typeklass.name)
                bucket << obj.to_trans
            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::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$