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
|
import hashlib
import logging
import lxml.etree
import select
import socket
import time
import xmlrpclib
from Bcfg2.Component import Component, exposed
import Bcfg2.Server.Core
logger = logging.getLogger('server')
def critical_error(operation):
'''Log and err, traceback and return an xmlrpc fault to client'''
logger.error(operation, exc_info=1)
raise xmlrpclib.Fault(7, "Critical unexpected failure: %s" % (operation))
class SetupError(Exception):
'''Used when the server cant be setup'''
pass
class bcfg2_server(Component,
Bcfg2.Server.Core.Core):
'''XML RPC interfaces for the server core'''
name = 'bcfg2-server'
def __init__(self, setup):
Component.__init__(self)
Bcfg2.Server.Core.Core.__init__(self, setup['repo'], setup['plugins'],
setup['password'],
setup['encoding'], setup['filemonitor'])
self.ca = setup['ca']
self.process_initial_fam_events()
def process_initial_fam_events(self):
events = False
while True:
try:
rsockinfo = select.select([self.fam.fileno()], [], [], 15)[0]
if not rsockinfo:
if events:
break
else:
logger.error("Hit event timeout without getting "
"any events; GAMIN/FAM problem?")
continue
events = True
i = 0
while self.fam.Service() or i < 10:
i += 1
time.sleep(0.1)
except socket.error:
continue
@exposed
def GetProbes(self, address):
'''Fetch probes for a particular client'''
resp = lxml.etree.Element('probes')
try:
name = self.metadata.resolve_client(address)
meta = self.build_metadata(name)
for plugin in [p for p in list(self.plugins.values()) \
if isinstance(p, Bcfg2.Server.Plugin.Probing)]:
for probe in plugin.GetProbes(meta):
resp.append(probe)
return lxml.etree.tostring(resp, encoding='UTF-8',
xml_declaration=True)
except Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError:
warning = 'Client metadata resolution error for %s; check server log' % address[0]
self.logger.warning(warning)
raise xmlrpclib.Fault(6, warning)
except:
critical_error("error determining client probes")
@exposed
def RecvProbeData(self, address, probedata):
'''Receive probe data from clients'''
try:
name = self.metadata.resolve_client(address)
meta = self.build_metadata(name)
except Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError:
warning = 'metadata consistency error'
self.logger.warning(warning)
raise xmlrpclib.Fault(6, warning)
# clear dynamic groups
self.metadata.cgroups[meta.hostname] = []
try:
xpdata = lxml.etree.XML(probedata)
except:
self.logger.error("Failed to parse probe data from client %s" % \
(address[0]))
return False
sources = []
[sources.append(data.get('source')) for data in xpdata
if data.get('source') not in sources]
for source in sources:
if source not in self.plugins:
self.logger.warning("Failed to locate plugin %s" % (source))
continue
dl = [data for data in xpdata if data.get('source') == source]
try:
self.plugins[source].ReceiveData(meta, dl)
except:
logger.error("Failed to process probe data from client %s" % \
(address[0]), exc_info=1)
return True
@exposed
def AssertProfile(self, address, profile):
'''Set profile for a client'''
try:
client = self.metadata.resolve_client(address)
self.metadata.set_profile(client, profile, address)
except (Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError,
Bcfg2.Server.Plugins.Metadata.MetadataRuntimeError):
warning = 'metadata consistency error'
self.logger.warning(warning)
raise xmlrpclib.Fault(6, warning)
return True
@exposed
def GetConfig(self, address, checksum=False):
'''Build config for a client'''
try:
client = self.metadata.resolve_client(address)
config = self.BuildConfiguration(client)
if checksum:
for cfile in config.findall('.//ConfigFile'):
if cfile.text != None:
csum = hashlib.md5()
csum.update(cfile.text)
cfile.set('checksum', csum.hexdigest())
cfile.text = None
return lxml.etree.tostring(config, encoding='UTF-8',
xml_declaration=True)
except Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError:
self.logger.warning("Metadata consistency failure for %s" % (address))
raise xmlrpclib.Fault(6, "Metadata consistency failure")
@exposed
def RecvStats(self, address, stats):
'''Act on statistics upload'''
sdata = lxml.etree.XML(stats)
client = self.metadata.resolve_client(address)
self.process_statistics(client, sdata)
return "<ok/>"
def authenticate(self, cert, user, password, address):
if self.ca:
acert = cert
else:
# no ca, so no cert validation can be done
acert = None
return self.metadata.AuthenticateConnection(acert, user, password, address)
@exposed
def GetDecisionList(self, address, mode):
client = self.metadata.resolve_client(address)
meta = self.build_metadata(client)
return self.GetDecisions(meta, mode)
|