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
|
require 'openssl'
require 'puppet'
require 'puppet/parser/interpreter'
require 'puppet/sslcertificates'
require 'xmlrpc/server'
require 'yaml'
module Puppet
class Server
class MasterError < Puppet::Error; end
class Master < Handler
attr_accessor :ast, :local
attr_reader :ca
@interface = XMLRPC::Service::Interface.new("puppetmaster") { |iface|
iface.add_method("string getconfig(string)")
iface.add_method("int freshness()")
}
def filetimeout
@interpreter.filetimeout
end
def filetimeout=(int)
@interpreter.filetimeout = int
end
# Tell a client whether there's a fresh config for it
def freshness(client = nil, clientip = nil)
if defined? @interpreter
return @interpreter.parsedate
else
return 0
end
end
def initialize(hash = {})
# FIXME this should all be s/:File/:Manifest/g or something
# build our AST
@file = hash[:File] || Puppet[:manifest]
hash.delete(:File)
if hash[:Local]
@local = hash[:Local]
else
@local = false
end
if hash.include?(:CA) and hash[:CA]
@ca = Puppet::SSLCertificates::CA.new()
else
@ca = nil
end
@parsecheck = hash[:FileTimeout] || 15
Puppet.debug("Creating interpreter")
args = {:Manifest => @file, :ParseCheck => @parsecheck}
if hash.include?(:UseNodes)
args[:UseNodes] = hash[:UseNodes]
elsif @local
args[:UseNodes] = false
end
# This is only used by the cfengine module
if hash.include?(:Classes)
args[:Classes] = hash[:Classes]
end
@interpreter = Puppet::Parser::Interpreter.new(args)
end
def getconfig(facts, format = "marshal", client = nil, clientip = nil)
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"
# XXX this should definitely be done in the protocol, somehow
case format
when "marshal":
begin
facts = Marshal::load(CGI.unescape(facts))
rescue => detail
raise XMLRPC::FaultException.new(
1, "Could not rebuild facts"
)
end
when "yaml":
begin
facts = YAML.load(CGI.unescape(facts))
rescue => detail
raise XMLRPC::FaultException.new(
1, "Could not rebuild facts"
)
end
else
raise XMLRPC::FaultException.new(
1, "Unavailable config format %s" % format
)
end
end
unless client
client = facts["hostname"]
clientip = facts["ipaddress"]
end
Puppet.notice("Compiling configuration for %s" % client)
begin
retobjects = @interpreter.run(client, facts)
rescue Puppet::Error => detail
Puppet.err detail
raise XMLRPC::FaultException.new(
1, detail.to_s
)
rescue => detail
Puppet.err detail.to_s
return ""
end
if @local
return retobjects
else
str = nil
case format
when "marshal":
str = Marshal::dump(retobjects)
when "yaml":
str = YAML.dump(retobjects)
else
raise XMLRPC::FaultException.new(
1, "Unavailable config format %s" % format
)
end
return CGI.escape(str)
end
end
def local?
if defined? @local and @local
return true
else
return false
end
end
end
end
end
|