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
|
#!/usr/local/bin/ruby -w
# $Id$
# the available clients
require 'puppet'
require 'puppet/function'
require 'puppet/type'
#require 'puppet/fact'
require 'facter'
require 'puppet/transaction'
require 'puppet/transportable'
require 'puppet/metric'
require 'http-access2'
require 'soap/rpc/driver'
require 'soap/rpc/httpserver'
#require 'webrick/https'
require 'logger'
module Puppet
class ClientError < RuntimeError; end
#---------------------------------------------------------------
class Client < SOAP::RPC::HTTPServer
include Puppet
def Client.facts
facts = {}
Facter.each { |name,fact|
facts[name] = fact.downcase
}
facts
end
def initialize(hash)
# to whom do we connect?
@server = nil
@nil = nil
@url = hash[:Server]
if hash.include?(:Listen) and hash[:Listen] == false
Puppet.debug "We're a local client"
@localonly = true
@driver = @url
else
Puppet.debug "We're a networked client"
@localonly = false
@driver = SOAP::RPC::Driver.new(@url, 'urn:puppet-server')
@driver.add_method("getconfig", "name", "facts")
end
unless @localonly
hash.delete(:Server)
Puppet.debug "Server is %s" % @url
hash[:BindAddress] ||= "0.0.0.0"
hash[:Port] ||= 17444
#hash[:Debug] ||= true
hash[:AccessLog] ||= []
super(hash)
end
end
def getconfig
Puppet.debug "server is %s" % @url
#client.loadproperty('files/sslclient.properties')
Puppet.debug("getting config")
objects = nil
facts = Client.facts
Puppet.info "Facts are %s" % facts.inspect
textfacts = Marshal::dump(facts)
if @localonly
objects = @driver.getconfig(self,facts)
else
objects = @driver.getconfig(facts["hostname"],textfacts)
end
self.config(objects)
end
# this method is how the client receives the tree of Transportable
# objects
# for now, just descend into the tree and perform and necessary
# manipulations
def config(tree)
Puppet.debug("Calling config")
# XXX this is kind of a problem; if the user changes the state file
# after this, then we have to reload the file and everything...
Puppet::Storage.init
Puppet::Storage.load
container = Marshal::load(tree).to_type
# this is a gross hack... but i don't see a good way around it
# set all of the variables to empty
Puppet::Transaction.init
# for now we just evaluate the top-level container, but eventually
# there will be schedules and such associated with each object,
# and probably with the container itself
transaction = container.evaluate
#transaction = Puppet::Transaction.new(objects)
transaction.toplevel = true
transaction.evaluate
Puppet::Metric.gather
Puppet::Metric.tally
if Puppet[:rrdgraph] == true
Metric.store
Metric.graph
end
Puppet::Storage.store
self.shutdown
end
def callfunc(name,args)
Puppet.debug("Calling callfunc on %s" % name)
if function = Puppet::Function[name]
#debug("calling function %s" % function)
value = function.call(args)
#debug("from %s got %s" % [name,value])
return value
else
raise "Function '%s' not found" % name
end
end
private
def on_init
@default_namespace = 'urn:puppet-client'
add_method(self, 'config', 'config')
add_method(self, 'callfunc', 'name', 'arguments')
end
def cert(filename)
OpenSSL::X509::Certificate.new(File.open(File.join(@dir, filename)) { |f|
f.read
})
end
def key(filename)
OpenSSL::PKey::RSA.new(File.open(File.join(@dir, filename)) { |f|
f.read
})
end
end
#---------------------------------------------------------------
end
|