summaryrefslogtreecommitdiffstats
path: root/lib/puppet/network/handler/master.rb
blob: 25c4318b82ebf3e48443a303320a6b3cc4d29a49 (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
require 'openssl'
require 'puppet'
require 'puppet/parser/interpreter'
require 'puppet/sslcertificates'
require 'xmlrpc/server'
require 'yaml'

class Puppet::Network::Handler
    class MasterError < Puppet::Error; end
    class Master < Handler
        desc "Puppet's configuration interface.  Used for all interactions related to
        generating client configurations."

        include Puppet::Util

        attr_accessor :ast
        attr_reader :ca

        @interface = XMLRPC::Service::Interface.new("puppetmaster") { |iface|
                iface.add_method("string getconfig(string)")
                iface.add_method("int freshness()")
        }

        # Tell a client whether there's a fresh config for it
        def freshness(client = nil, clientip = nil)
            client ||= Facter.value("hostname")
            config_handler.version(client, clientip)
        end

        def initialize(hash = {})
            args = {}

            # Allow specification of a code snippet or of a file
            if code = hash[:Code]
                args[:Code] = code
            elsif man = hash[:Manifest]
                args[:Manifest] = man
            end

            if hash[:Local]
                @local = hash[:Local]
            else
                @local = false
            end

            args[:Local] = true

            if hash.include?(:CA) and hash[:CA]
                @ca = Puppet::SSLCertificates::CA.new()
            else
                @ca = nil
            end

            Puppet.debug("Creating interpreter")

            if hash.include?(:UseNodes)
                args[:UseNodes] = hash[:UseNodes]
            elsif @local
                args[:UseNodes] = false
            end

            # This is only used by the cfengine module, or if --loadclasses was
            # specified in +puppet+.
            if hash.include?(:Classes)
                args[:Classes] = hash[:Classes]
            end

            @config_handler = Puppet::Network::Handler.handler(:configuration).new(args)
        end

        # Call our various handlers; this handler is getting deprecated.
        def getconfig(facts, format = "marshal", client = nil, clientip = nil)
            facts = decode_facts(facts)
            client, clientip = clientname(client, clientip, facts)

            # Pass the facts to the fact handler
            Puppet::Node::Facts.new(client, facts).save

            # And get the configuration from the config handler
            config = config_handler.configuration(client)

            return translate(config.extract)
        end

        private

        # Manipulate the client name as appropriate.
        def clientname(name, ip, facts)
            # Always use the hostname from Facter.
            client = facts["hostname"]
            clientip = facts["ipaddress"]
            if Puppet[:node_name] == 'cert'
                if name
                    client = name
                end
                if ip
                    clientip = ip
                end
            end

            return client, clientip
        end

        def config_handler
            unless defined? @config_handler
                @config_handler = Puppet::Network::Handler.handler(:config).new :local => local?
            end
            @config_handler
        end

        # 
        def decode_facts(facts)
            if @local
                # we don't need to do anything, since we should already
                # have raw objects
                Puppet.debug "Our client is local"
            else
                Puppet.debug "Our client is remote"

                begin
                    facts = YAML.load(CGI.unescape(facts))
                rescue => detail
                    raise XMLRPC::FaultException.new(
                        1, "Could not rebuild facts"
                    )
                end
            end

            return facts
        end

        # Translate our configuration appropriately for sending back to a client.
        def translate(config)
            if local?
                config
            else
                CGI.escape(config.to_yaml(:UseBlock => true))
            end
        end
    end
end