| Trees | Indices | Help |
|---|
|
|
1 #!/usr/bin/python2
2 #
3 # Python client for checking periodically for posted actions
4 # on the Spacewalk servers.
5 #
6 # Copyright (c) 2000--2018 Red Hat, Inc.
7 #
8 # This software is licensed to you under the GNU General Public License,
9 # version 2 (GPLv2). There is NO WARRANTY for this software, express or
10 # implied, including the implied warranties of MERCHANTABILITY or FITNESS
11 # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
12 # along with this software; if not, see
13 # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
14 #
15 # Red Hat trademarks are not licensed under GPLv2. No permission is
16 # granted to use or replicate Red Hat trademarks that are incorporated
17 # in this software or its documentation.
18 #
19 # In addition, as a special exception, the copyright holders give
20 # permission to link the code of portions of this program with the
21 # OpenSSL library under certain conditions as described in each
22 # individual source file, and distribute linked combinations
23 # including the two.
24 # You must obey the GNU General Public License in all respects
25 # for all of the code used other than OpenSSL. If you modify
26 # file(s) with this exception, you may extend this exception to your
27 # version of the file(s), but you are not obligated to do so. If you
28 # do not wish to do so, delete this exception statement from your
29 # version. If you delete this exception statement from all source
30 # files in the program, then also delete it here.
31
32 import base64
33 import os
34 import sys
35 import socket
36
37 import gettext
38 t = gettext.translation('rhn-client-tools', fallback=True)
39 # Python 3 translations don't have a ugettext method
40 if not hasattr(t, 'ugettext'):
41 t.ugettext = t.gettext
42 _ = t.ugettext
43
44 import OpenSSL
45
46 # disable sgmlop module
47 # it breaks rhn_check when loaded during xmlrpclib import
48 sys.modules['sgmlop'] = None
49
50 from up2date_client import getMethod
51 from up2date_client import up2dateErrors
52 from up2date_client import up2dateAuth
53 from up2date_client import up2dateLog
54 from up2date_client import rpcServer
55 from up2date_client import config
56 from up2date_client import clientCaps
57 from up2date_client import capabilities
58 from up2date_client import rhncli, rhnserver
59
60 from rhn import SSL
61 from rhn import rhnLockfile
62 from rhn.i18n import bstr, sstr
63 from rhn.tb import raise_with_tb
64
65 try: # python2
66 import xmlrpclib
67 except ImportError: # python3
68 import xmlrpc.client as xmlrpclib
69 long = int
70
71 if 'sgmlop' in sys.modules:
72 del sys.modules['sgmlop']
73
74 cfg = config.initUp2dateConfig()
75 log = up2dateLog.initLog()
76
77 # action version we understand
78 ACTION_VERSION = 2
79
80 # lock file to check if we're disabled at the server's request
81 DISABLE_FILE = "/etc/sysconfig/rhn/disable"
82
83 # Actions that will run each time we execute.
84 LOCAL_ACTIONS = [("packages.checkNeedUpdate", ("rhnsd=1",))]
88
90 super(CheckCli, self).__init__()
91
92 self.rhns_ca_cert = cfg['sslCACert']
93 self.server = None
94
96 """ Process all the actions we have in the queue. """
97 CheckCli.__check_instance_lock()
98 CheckCli.__check_rhn_disabled()
99 CheckCli.__check_has_system_id()
100
101 self.server = CheckCli.__get_server()
102
103 CheckCli.__update_system_id()
104
105 self.__run_remote_actions()
106 CheckCli.__run_local_actions()
107
108 s = rhnserver.RhnServer()
109 if s.capabilities.hasCapability('staging_content', 1) and cfg['stagingContent'] != 0:
110 self.__check_future_actions()
111
112 sys.exit(0)
113
115 try:
116 action = self.server.queue.get(up2dateAuth.getSystemId(),
117 ACTION_VERSION, status_report)
118
119 return action
120 except xmlrpclib.Fault:
121 f = sys.exc_info()[1]
122 if f.faultCode == -31:
123 raise_with_tb(up2dateErrors.InsuffMgmntEntsError(f.faultString))
124 else:
125 print("Could not retrieve action item from server %s" % self.server)
126 print("Error code: %d%s" % (f.faultCode, f.faultString))
127 sys.exit(-1)
128 # XXX: what if no SSL in socket?
129 except SSL.socket_error:
130 print("ERROR: SSL handshake to %s failed" % self.server)
131 print("""
132 This could signal that you are *NOT* talking to a server
133 whose certificate was signed by a Certificate Authority
134 listed in the %s file or that the
135 RHNS-CA-CERT file is invalid.""" % self.rhns_ca_cert)
136 sys.exit(-1)
137 except socket.error:
138 print("Could not retrieve action from %s.\n"\
139 "Possible networking problem?" % str(self.server))
140 sys.exit(-1)
141 except up2dateErrors.ServerCapabilityError:
142 print(sys.exc_info()[1])
143 sys.exit(1)
144 except OpenSSL.SSL.Error:
145 print("ERROR: SSL errors detected")
146 print("%s" % sys.exc_info()[1])
147 sys.exit(-1)
148
150 try:
151 actions = self.server.queue.get_future_actions(up2dateAuth.getSystemId(),
152 time_window)
153 return actions
154 except xmlrpclib.Fault:
155 f = sys.exc_info()[1]
156 if f.faultCode == -31:
157 raise_with_tb(up2dateErrors.InsuffMgmntEntsError(f.faultString))
158 else:
159 print("Could not retrieve action item from server %s" % self.server)
160 print("Error code: %d%s" % (f.faultCode, f.faultString))
161 sys.exit(-1)
162 # XXX: what if no SSL in socket?
163 except SSL.socket_error:
164 print("ERROR: SSL handshake to %s failed" % self.server)
165 print("""
166 This could signal that you are *NOT* talking to a server
167 whose certificate was signed by a Certificate Authority
168 listed in the %s file or that the
169 RHNS-CA-CERT file is invalid.""" % self.rhns_ca_cert)
170 sys.exit(-1)
171 except socket.error:
172 print("Could not retrieve action from %s.\n"\
173 "Possible networking problem?" % str(self.server))
174 sys.exit(-1)
175 except up2dateErrors.ServerCapabilityError:
176 print(sys.exc_info()[1])
177 sys.exit(1)
178 except SSL.Error:
179 print("ERROR: SSL errors detected")
180 print("%s" % sys.exc_info()[1])
181 sys.exit(-1)
182
187
189 """ Retrieve scheduled actions and cache them if possible """
190 time_window = cfg['stagingContentWindow'] or 24;
191 actions = self.__query_future_actions(time_window)
192 for action in actions:
193 self.handle_action(action, cache_only=1)
194
196 # the list of caps the client needs
197 caps = capabilities.Capabilities()
198
199 status_report = CheckCli.__build_status_report()
200
201 action = self.__get_action(status_report)
202 while action != "" and action != {}:
203 self.__verify_server_capabilities(caps)
204
205 if self.is_valid_action(action):
206 try:
207 up2dateAuth.updateLoginInfo()
208 except up2dateErrors.ServerCapabilityError:
209 print(sys.exc_info()[1])
210 sys.exit(1)
211 self.handle_action(action)
212
213 action = self.__get_action(status_report)
214
216 response_headers = self.server.get_response_headers()
217 caps.populate(response_headers)
218 # do we actually want to validte here?
219 try:
220 caps.validate()
221 except up2dateErrors.ServerCapabilityError:
222 print(sys.exc_info()[1])
223 sys.exit(1)
224
226 """ Parse action data and returns (method, params) """
227 data = action['action']
228 parser, decoder = xmlrpclib.getparser()
229 parser.feed(bstr(data))
230 parser.close()
231 params = decoder.close()
232 method = decoder.getmethodname()
233 return (method, params)
234
236 """ Submit a response for an action_id. """
237
238 # get a new server object with fresh headers
239 self.server = CheckCli.__get_server()
240
241 try:
242 ret = self.server.queue.submit(up2dateAuth.getSystemId(),
243 action_id, status, message, data)
244 except xmlrpclib.Fault:
245 f = sys.exc_info()[1]
246 print("Could not submit results to server %s" % self.server)
247 print("Error code: %d%s" % (f.faultCode, f.faultString))
248 sys.exit(-1)
249 # XXX: what if no SSL in socket?
250 except SSL.socket_error:
251 print("ERROR: SSL handshake to %s failed" % self.server)
252 print("""
253 This could signal that you are *NOT* talking to a server
254 whose certificate was signed by a Certificate Authority
255 listed in the %s file or that the
256 RHNS-CA-CERT file is invalid.""" % self.rhns_ca_cert)
257 sys.exit(-1)
258 except socket.error:
259 print("Could not submit to %s.\n"\
260 "Possible networking problem?" % str(self.server))
261 sys.exit(-1)
262 return ret
263
265 """ Wrapper handler for the action we're asked to do. """
266 log.log_debug("handle_action", action)
267 log.log_debug("handle_action actionid = %s, version = %s" % (
268 action['id'], action['version']))
269
270 data = {}
271 action_lock = '/var/lib/up2date/action.%s' % str(action['id'])
272 if os.path.exists(action_lock):
273 ret = 255
274 if not cache_only:
275 if os.path.getsize(action_lock) > 0:
276 data['base64enc'] = 1
277 data['return_code'] = 255
278 data['process_start'] = '1970-01-01 00:00:00' # dummy values as we have no idea of start
279 data['process_end'] = '1970-01-01 00:00:00' # and especially about the end
280 with open(action_lock) as f:
281 data['output'] = base64.encodestring(f.read())
282 log.log_debug("Sending back response", (255, "Previous run of action didn't completed sucessfully, aborting.", data))
283 ret = self.submit_response(action['id'], 255, "Previous run of action didn't completed sucessfully, aborting.", data)
284 os.remove(action_lock)
285 return ret
286
287 open(action_lock, 'a').close()
288
289 (method, params) = self.__parse_action_data(action)
290 (status, message, data) = CheckCli.__run_action(method, params, {'cache_only': cache_only})
291 ret = 0
292 if not cache_only:
293 log.log_debug("Sending back response", (status, message, data))
294 ret = self.submit_response(action['id'], status, message, data)
295 os.remove(action_lock)
296 return ret
297
298
300 log.log_debug("check_action", action)
301
302 # be very paranoid of what we get back
303 if type(action) != type({}):
304 print("Got unparseable action response from server")
305 sys.exit(-1)
306
307 for key in ['id', 'version', 'action']:
308 if not key in action:
309 print("Got invalid response - missing '%s'" % key)
310 sys.exit(-1)
311 try:
312 ver = int(action['version'])
313 except ValueError:
314 ver = -1
315 if ver > ACTION_VERSION or ver < 0:
316 print("Got unknown action version %d" % ver)
317 print(action)
318 # the -99 here is kind of magic
319 self.submit_response(action["id"],
320 xmlrpclib.Fault(-99, "Can not handle this version"))
321 return False
322 return True
323
324 @staticmethod
326 """ Initialize a server connection and set up capability info. """
327 server = rpcServer.getServer()
328
329 # load the new client caps if they exist
330 clientCaps.loadLocalCaps()
331
332 headerlist = clientCaps.caps.headerFormat()
333 for (headerName, value) in headerlist:
334 server.add_header(headerName, value)
335
336 return server
337
338 @staticmethod
340 try:
341 up2dateAuth.maybeUpdateVersion()
342 except up2dateErrors.CommunicationError:
343 print(sys.exc_info()[1])
344 sys.exit(1)
345
346 @staticmethod
348 status_report = {}
349 status_report["uname"] = list(os.uname())
350
351 if os.access("/proc/uptime", os.R_OK):
352 uptime = open("/proc/uptime", "r").read().split()
353 try:
354 status_report["uptime"] = [int(float(a)) for a in uptime]
355 except (TypeError, ValueError):
356 status_report["uptime"] = [a[:-3] for a in uptime]
357 except:
358 pass
359
360 # We need to fit into xmlrpc's integer limits
361 if status_report['uptime'][1] > long(2)**31-1:
362 status_report['uptime'][1] = -1
363
364 return status_report
365
366 @staticmethod
368 """
369 Hit any actions that we want to always run.
370
371 If we want to run any actions everytime rhnsd runs rhn_check,
372 we can add them to the list LOCAL_ACTIONS
373 """
374
375 for method_params in LOCAL_ACTIONS:
376 method = method_params[0]
377 params = method_params[1]
378 (status, message, data) = CheckCli.__run_action(method, params)
379 log.log_debug("local action status: ", (status, message, data))
380
381 @staticmethod
383 log.log_debug("do_call ", method, params, kwargs)
384
385 method = getMethod.getMethod(method, "rhn.actions")
386 retval = method(*params, **kwargs)
387
388 return retval
389
390 @staticmethod
392 try:
393 (status, message, data) = CheckCli.__do_call(method, params, kwargs)
394 except getMethod.GetMethodException:
395 log.log_debug("Attempt to call an unsupported action ", method,
396 params)
397 status = 6
398 message = "Invalid function call attempted"
399 data = {}
400 except:
401 log.log_exception(*sys.exc_info())
402 # The action code failed in some way. let's let the server know.
403 status = 6,
404 message = "Fatal error in Python code occurred"
405 data = {}
406 return (status, message, data)
407
408 @staticmethod
410 """ If we're disabled, go down (almost) quietly. """
411 if os.path.exists(DISABLE_FILE):
412 print("RHN service is disabled. Check %s" % DISABLE_FILE)
413 sys.exit(0)
414
415 @staticmethod
417 """ Retrieve the system_id. This is required. """
418 if not up2dateAuth.getSystemId():
419 print("ERROR: unable to read system id.")
420 sys.exit(-1)
421
422 @staticmethod
424 lock = None
425 try:
426 lock = rhnLockfile.Lockfile('/var/run/rhn_check.pid')
427 except rhnLockfile.LockfileLockedException:
428 sys.stderr.write(sstr(_("Attempting to run more than one instance of rhn_check. Exiting.\n")))
429 sys.exit(0)
430
431 if __name__ == "__main__":
432 cli = CheckCli()
433 cli.run()
434
| Trees | Indices | Help |
|---|
| Generated by Epydoc 3.0.1 on Wed Mar 4 07:37:45 2020 | http://epydoc.sourceforge.net |