/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to mandos-monitor

  • Committer: Teddy Hogeborn
  • Date: 2019-11-03 18:44:41 UTC
  • Revision ID: teddy@recompile.se-20191103184441-1vhjuf06hjqgfohh
mandos-monitor: Use Python's standard loggging module

* mandos-monitor: Use Python's standard loggging module, also for
                  warnings.  Suppress BytesWarning from urwid when
                  exiting.
  (log): New global logger object.  This replaces UserInterface
        log_message().
  (MandosClientWidget.__init__): Remove "logger" argument.
  (MandosClientWidget.using_timer): Wrap self.update_timer using new
                                    glib_safely() function.
  (glib_safely): New function to log any exceptions instead of letting
                 exceptions propagate up to GLib.
  (UserInterface.__init__): Remove "log_level" argument.  Set new
                            "loghandler" attribute, instance of new
                            "UILogHandler".
  (UserInterface.log_message): Removed.
  (UserInterface.log_message_raw): Renamed to "add_log_line"; all
                                   callers changed.  Also fix
                                   off-by-one error in max_log_length
                                   logic.
  (UserInterface.run): Add self.loghandler to logger "log". Wrap
                       self.process_input using new glib_safely()
                       function.
  (UserInterface.stop): Remove self.loghandler from logger "log".
  (UserInterface.process_input): Make verbosity toggle affect log
                                 level of logger "log".
  (UILogHandler): New.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/python3 -bbI
 
1
#!/usr/bin/python3 -bb
2
2
# -*- mode: python; coding: utf-8 -*-
3
3
#
4
4
# Mandos Monitor - Control and monitor the Mandos server
5
5
#
6
 
# Copyright © 2009-2024 Teddy Hogeborn
7
 
# Copyright © 2009-2024 Björn Påhlsson
 
6
# Copyright © 2009-2019 Teddy Hogeborn
 
7
# Copyright © 2009-2019 Björn Påhlsson
8
8
#
9
9
# This file is part of Mandos.
10
10
#
23
23
#
24
24
# Contact the authors at <mandos@recompile.se>.
25
25
#
 
26
 
26
27
from __future__ import (division, absolute_import, print_function,
27
28
                        unicode_literals)
28
 
 
29
29
try:
30
30
    from future_builtins import *
31
31
except ImportError:
32
32
    pass
33
33
 
34
34
import sys
35
 
import logging
36
35
import os
37
36
import warnings
38
37
import datetime
39
 
import locale
40
38
 
41
39
import urwid.curses_display
42
40
import urwid
46
44
 
47
45
import dbus
48
46
 
 
47
import locale
 
48
 
 
49
import logging
 
50
 
49
51
if sys.version_info.major == 2:
50
 
    __metaclass__ = type
51
52
    str = unicode
52
 
    input = raw_input
53
 
 
54
 
# Show warnings by default
55
 
if not sys.warnoptions:
56
 
    warnings.simplefilter("default")
57
53
 
58
54
log = logging.getLogger(os.path.basename(sys.argv[0]))
59
55
logging.basicConfig(level="NOTSET", # Show all messages
61
57
 
62
58
logging.captureWarnings(True)   # Show warnings via the logging system
63
59
 
64
 
locale.setlocale(locale.LC_ALL, "")
 
60
locale.setlocale(locale.LC_ALL, '')
65
61
 
66
 
logging.getLogger("dbus.proxies").setLevel(logging.CRITICAL)
67
 
logging.getLogger("urwid").setLevel(logging.INFO)
 
62
logging.getLogger('dbus.proxies').setLevel(logging.CRITICAL)
68
63
 
69
64
# Some useful constants
70
 
domain = "se.recompile"
71
 
server_interface = domain + ".Mandos"
72
 
client_interface = domain + ".Mandos.Client"
73
 
version = "1.8.18"
 
65
domain = 'se.recompile'
 
66
server_interface = domain + '.Mandos'
 
67
client_interface = domain + '.Mandos.Client'
 
68
version = "1.8.9"
74
69
 
75
70
try:
76
71
    dbus.OBJECT_MANAGER_IFACE
95
90
                             int(fraction*1000000))  # Microseconds
96
91
 
97
92
 
98
 
class MandosClientPropertyCache:
 
93
class MandosClientPropertyCache(object):
99
94
    """This wraps a Mandos Client D-Bus proxy object, caches the
100
95
    properties and calls a hook function when any of them are
101
96
    changed.
128
123
        self.property_changed_match.remove()
129
124
 
130
125
 
131
 
class MandosClientWidget(MandosClientPropertyCache, urwid.Widget):
 
126
class MandosClientWidget(urwid.FlowWidget, MandosClientPropertyCache):
132
127
    """A Mandos Client which is visible on the screen.
133
128
    """
134
129
 
135
 
    _sizing = frozenset(["flow"])
136
 
 
137
130
    def __init__(self, server_proxy_object=None, update_hook=None,
138
131
                 delete_hook=None, **kwargs):
139
132
        # Called on update
174
167
                                         self.rejected,
175
168
                                         client_interface,
176
169
                                         byte_arrays=True))
177
 
        log.debug("Created client %s", self.properties["Name"])
 
170
        log.debug('Created client %s', self.properties["Name"])
178
171
 
179
172
    def using_timer(self, flag):
180
173
        """Call this method with True or False when timer should be
192
185
    def checker_completed(self, exitstatus, condition, command):
193
186
        if exitstatus == 0:
194
187
            log.debug('Checker for client %s (command "%s")'
195
 
                      " succeeded", self.properties["Name"], command)
 
188
                      ' succeeded', self.properties["Name"], command)
196
189
            self.update()
197
190
            return
198
191
        # Checker failed
199
192
        if os.WIFEXITED(condition):
200
193
            log.info('Checker for client %s (command "%s") failed'
201
 
                     " with exit code %d", self.properties["Name"],
 
194
                     ' with exit code %d', self.properties["Name"],
202
195
                     command, os.WEXITSTATUS(condition))
203
196
        elif os.WIFSIGNALED(condition):
204
197
            log.info('Checker for client %s (command "%s") was'
205
 
                     " killed by signal %d", self.properties["Name"],
 
198
                     ' killed by signal %d', self.properties["Name"],
206
199
                     command, os.WTERMSIG(condition))
207
200
        self.update()
208
201
 
228
221
 
229
222
    def selectable(self):
230
223
        """Make this a "selectable" widget.
231
 
        This overrides the method from urwid.Widget."""
 
224
        This overrides the method from urwid.FlowWidget."""
232
225
        return True
233
226
 
234
227
    def rows(self, maxcolrow, focus=False):
235
228
        """How many rows this widget will occupy might depend on
236
229
        whether we have focus or not.
237
 
        This overrides the method from urwid.Widget"""
 
230
        This overrides the method from urwid.FlowWidget"""
238
231
        return self.current_widget(focus).rows(maxcolrow, focus=focus)
239
232
 
240
233
    def current_widget(self, focus=False):
256
249
        # Rebuild focus and non-focus widgets using current properties
257
250
 
258
251
        # Base part of a client. Name!
259
 
        base = "{name}: ".format(name=self.properties["Name"])
 
252
        base = '{name}: '.format(name=self.properties["Name"])
260
253
        if not self.properties["Enabled"]:
261
254
            message = "DISABLED"
262
255
            self.using_timer(False)
284
277
                timer = datetime.timedelta(0)
285
278
            else:
286
279
                expires = (datetime.datetime.strptime
287
 
                           (expires, "%Y-%m-%dT%H:%M:%S.%f"))
 
280
                           (expires, '%Y-%m-%dT%H:%M:%S.%f'))
288
281
                timer = max(expires - datetime.datetime.utcnow(),
289
282
                            datetime.timedelta())
290
 
            message = ("A checker has failed! Time until client"
291
 
                       " gets disabled: {}"
 
283
            message = ('A checker has failed! Time until client'
 
284
                       ' gets disabled: {}'
292
285
                       .format(str(timer).rsplit(".", 1)[0]))
293
286
            self.using_timer(True)
294
287
        else:
332
325
 
333
326
    def render(self, maxcolrow, focus=False):
334
327
        """Render differently if we have focus.
335
 
        This overrides the method from urwid.Widget"""
 
328
        This overrides the method from urwid.FlowWidget"""
336
329
        return self.current_widget(focus).render(maxcolrow,
337
330
                                                 focus=focus)
338
331
 
339
332
    def keypress(self, maxcolrow, key):
340
333
        """Handle keys.
341
 
        This overrides the method from urwid.Widget"""
 
334
        This overrides the method from urwid.FlowWidget"""
342
335
        if key == "+":
343
336
            self.proxy.Set(client_interface, "Enabled",
344
337
                           dbus.Boolean(True), ignore_reply=True,
415
408
        return ret
416
409
 
417
410
 
418
 
class UserInterface:
 
411
class UserInterface(object):
419
412
    """This is the entire user interface - the whole screen
420
413
    with boxes, lists of client widgets, etc.
421
414
    """
478
471
                           "Mandos Monitor version " + version))
479
472
        self.add_log_line(("bold", "q: Quit  ?: Help"))
480
473
 
481
 
        self.busname = domain + ".Mandos"
 
474
        self.busname = domain + '.Mandos'
482
475
        self.main_loop = GLib.MainLoop()
483
476
 
484
477
    def client_not_found(self, key_id, address):