/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: 2012-05-07 20:46:51 UTC
  • Revision ID: teddy@recompile.se-20120507204651-qx5o5ztwmau54mh4
* mandos-monitor: Speedup: Use properties from D-Bus
                  GetAllClientsWithProperties() call.  Also use
                  super() properly - only use keyword arguments and
                  strip them off as "kwargs" is passed on.
  (MandosClientPropertyCache.__init__): Take new "properties"
                                        argument; use it to skip
                                        calling D-Bus GetAll() method.
                                        Call super().  Bind self._
  (MandosClientPropertyCache._property_changed): New helper function.
  (MandosClientPropertyCache.property_changed): Changed to take
                                                keyword arguments.
  (MandosClientPropertyCache.delete): Bug fix: Don't call
                                      super().__init__().
  (MandosClientWidget.__init__): Don't take *args.  Strip used keyword
                                 arguments before calling super().
  (MandosClientWidget.property_changed): Removed dead code.
  (MandosClientWidget.delete): Don't take *args.
  (MandosClientWidget.property_changed): Don't take "value" argument,
                                         since it is not used.
  (ConstrainedListBox.keypress): Take *args, **kwargs and pass them on
                                 to super().

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
4
4
# Mandos Monitor - Control and monitor the Mandos server
5
5
6
 
# Copyright © 2009-2013 Teddy Hogeborn
7
 
# Copyright © 2009-2013 Björn Påhlsson
 
6
# Copyright © 2009-2012 Teddy Hogeborn
 
7
# Copyright © 2009-2012 Björn Påhlsson
8
8
9
9
# This program is free software: you can redistribute it and/or modify
10
10
# it under the terms of the GNU General Public License as published by
25
25
 
26
26
from __future__ import (division, absolute_import, print_function,
27
27
                        unicode_literals)
28
 
try:
29
 
    from future_builtins import *
30
 
except ImportError:
31
 
    pass
 
28
 
 
29
from future_builtins import *
32
30
 
33
31
import sys
34
32
import os
40
38
import urwid
41
39
 
42
40
from dbus.mainloop.glib import DBusGMainLoop
43
 
try:
44
 
    import gobject
45
 
except ImportError:
46
 
    from gi.repository import GObject as gobject
 
41
import gobject
47
42
 
48
43
import dbus
49
44
 
 
45
import UserList
 
46
 
50
47
import locale
51
48
 
52
 
if sys.version_info[0] == 2:
53
 
    str = unicode
54
 
 
55
49
locale.setlocale(locale.LC_ALL, '')
56
50
 
57
51
import logging
61
55
domain = 'se.recompile'
62
56
server_interface = domain + '.Mandos'
63
57
client_interface = domain + '.Mandos.Client'
64
 
version = "1.6.2"
 
58
version = "1.5.3"
 
59
 
 
60
# Always run in monochrome mode
 
61
urwid.curses_display.curses.has_colors = lambda : False
 
62
 
 
63
# Urwid doesn't support blinking, but we want it.  Since we have no
 
64
# use for underline on its own, we make underline also always blink.
 
65
urwid.curses_display.curses.A_UNDERLINE |= (
 
66
    urwid.curses_display.curses.A_BLINK)
65
67
 
66
68
def isoformat_to_datetime(iso):
67
69
    "Parse an ISO 8601 date string to a datetime.datetime()"
132
134
        self.logger = logger
133
135
        
134
136
        self._update_timer_callback_tag = None
 
137
        self._update_timer_callback_lock = 0
135
138
        
136
139
        # The widget shown normally
137
140
        self._text_widget = urwid.Text("")
141
144
        self.update()
142
145
        self.opened = False
143
146
        
 
147
        last_checked_ok = isoformat_to_datetime(self.properties
 
148
                                                ["LastCheckedOK"])
 
149
        
 
150
        if self.properties ["LastCheckerStatus"] != 0:
 
151
            self.using_timer(True)
 
152
        
 
153
        if self.need_approval:
 
154
            self.using_timer(True)
 
155
        
144
156
        self.match_objects = (
145
157
            self.proxy.connect_to_signal("CheckerCompleted",
146
158
                                         self.checker_completed,
165
177
        #self.logger('Created client {0}'
166
178
        #            .format(self.properties["Name"]))
167
179
    
 
180
    def property_changed(self, property=None, value=None):
 
181
        super(self, MandosClientWidget).property_changed(property,
 
182
                                                         value)
 
183
        if property == "ApprovalPending":
 
184
            using_timer(bool(value))
 
185
        if property == "LastCheckerStatus":
 
186
            using_timer(value != 0)
 
187
            #self.logger('Checker for client {0} (command "{1}") was '
 
188
            #            ' successful'.format(self.properties["Name"],
 
189
            #                                 command))
 
190
    
168
191
    def using_timer(self, flag):
169
192
        """Call this method with True or False when timer should be
170
193
        activated or deactivated.
171
194
        """
172
 
        if flag and self._update_timer_callback_tag is None:
 
195
        old = self._update_timer_callback_lock
 
196
        if flag:
 
197
            self._update_timer_callback_lock += 1
 
198
        else:
 
199
            self._update_timer_callback_lock -= 1
 
200
        if old == 0 and self._update_timer_callback_lock:
173
201
            # Will update the shown timer value every second
174
202
            self._update_timer_callback_tag = (gobject.timeout_add
175
203
                                               (1000,
176
204
                                                self.update_timer))
177
 
        elif not (flag or self._update_timer_callback_tag is None):
 
205
        elif old and self._update_timer_callback_lock == 0:
178
206
            gobject.source_remove(self._update_timer_callback_tag)
179
207
            self._update_timer_callback_tag = None
180
208
    
208
236
           to log in the future. """
209
237
        #self.logger('Client {0} started checker "{1}"'
210
238
        #            .format(self.properties["Name"],
211
 
        #                    str(command)))
 
239
        #                    unicode(command)))
212
240
        pass
213
241
    
214
242
    def got_secret(self):
222
250
            message = 'Client {0} will get its secret in {1} seconds'
223
251
        self.logger(message.format(self.properties["Name"],
224
252
                                   timeout/1000))
 
253
        self.using_timer(True)
225
254
    
226
255
    def rejected(self, reason):
227
256
        self.logger('Client {0} was rejected; reason: {1}'
253
282
                          "bold-underline-blink":
254
283
                              "bold-underline-blink-standout",
255
284
                          }
256
 
        
 
285
 
257
286
        # Rebuild focus and non-focus widgets using current properties
258
 
        
 
287
 
259
288
        # Base part of a client. Name!
260
289
        base = '{name}: '.format(name=self.properties["Name"])
261
290
        if not self.properties["Enabled"]:
262
291
            message = "DISABLED"
263
 
            self.using_timer(False)
264
292
        elif self.properties["ApprovalPending"]:
265
293
            timeout = datetime.timedelta(milliseconds
266
294
                                         = self.properties
268
296
            last_approval_request = isoformat_to_datetime(
269
297
                self.properties["LastApprovalRequest"])
270
298
            if last_approval_request is not None:
271
 
                timer = max(timeout - (datetime.datetime.utcnow()
272
 
                                       - last_approval_request),
273
 
                            datetime.timedelta())
 
299
                timer = timeout - (datetime.datetime.utcnow()
 
300
                                   - last_approval_request)
274
301
            else:
275
302
                timer = datetime.timedelta()
276
303
            if self.properties["ApprovedByDefault"]:
277
304
                message = "Approval in {0}. (d)eny?"
278
305
            else:
279
306
                message = "Denial in {0}. (a)pprove?"
280
 
            message = message.format(str(timer).rsplit(".", 1)[0])
281
 
            self.using_timer(True)
 
307
            message = message.format(unicode(timer).rsplit(".", 1)[0])
282
308
        elif self.properties["LastCheckerStatus"] != 0:
283
309
            # When checker has failed, show timer until client expires
284
310
            expires = self.properties["Expires"]
287
313
            else:
288
314
                expires = (datetime.datetime.strptime
289
315
                           (expires, '%Y-%m-%dT%H:%M:%S.%f'))
290
 
                timer = max(expires - datetime.datetime.utcnow(),
291
 
                            datetime.timedelta())
 
316
                timer = expires - datetime.datetime.utcnow()
292
317
            message = ('A checker has failed! Time until client'
293
318
                       ' gets disabled: {0}'
294
 
                       .format(str(timer).rsplit(".", 1)[0]))
295
 
            self.using_timer(True)
 
319
                       .format(unicode(timer).rsplit(".", 1)[0]))
296
320
        else:
297
321
            message = "enabled"
298
 
            self.using_timer(False)
299
322
        self._text = "{0}{1}".format(base, message)
300
 
        
 
323
            
301
324
        if not urwid.supports_unicode():
302
325
            self._text = self._text.encode("ascii", "replace")
303
326
        textlist = [("normal", self._text)]
380
403
    def property_changed(self, property=None, **kwargs):
381
404
        """Call self.update() if old value is not new value.
382
405
        This overrides the method from MandosClientPropertyCache"""
383
 
        property_name = str(property)
 
406
        property_name = unicode(property)
384
407
        old_value = self.properties.get(property_name)
385
408
        super(MandosClientWidget, self).property_changed(
386
409
            property=property, **kwargs)
413
436
                ("normal",
414
437
                 "default", "default", None),
415
438
                ("bold",
416
 
                 "bold", "default", "bold"),
 
439
                 "default", "default", "bold"),
417
440
                ("underline-blink",
418
 
                 "underline,blink", "default", "underline,blink"),
 
441
                 "default", "default", "underline"),
419
442
                ("standout",
420
 
                 "standout", "default", "standout"),
 
443
                 "default", "default", "standout"),
421
444
                ("bold-underline-blink",
422
 
                 "bold,underline,blink", "default", "bold,underline,blink"),
 
445
                 "default", "default", ("bold", "underline")),
423
446
                ("bold-standout",
424
 
                 "bold,standout", "default", "bold,standout"),
 
447
                 "default", "default", ("bold", "standout")),
425
448
                ("underline-blink-standout",
426
 
                 "underline,blink,standout", "default",
427
 
                 "underline,blink,standout"),
 
449
                 "default", "default", ("underline", "standout")),
428
450
                ("bold-underline-blink-standout",
429
 
                 "bold,underline,blink,standout", "default",
430
 
                 "bold,underline,blink,standout"),
 
451
                 "default", "default", ("bold", "underline",
 
452
                                          "standout")),
431
453
                ))
432
454
        
433
455
        if urwid.supports_unicode():
488
510
        self.topwidget = urwid.Pile(self.uilist)
489
511
    
490
512
    def log_message(self, message):
491
 
        """Log message formatted with timestamp"""
492
513
        timestamp = datetime.datetime.now().isoformat()
493
514
        self.log_message_raw(timestamp + ": " + message)
494
515
    
507
528
        self.log_visible = not self.log_visible
508
529
        self.rebuild()
509
530
        #self.log_message("Log visibility changed to: "
510
 
        #                 + str(self.log_visible))
 
531
        #                 + unicode(self.log_visible))
511
532
    
512
533
    def change_log_display(self):
513
534
        """Change type of log display.
553
574
        if path is None:
554
575
            path = client.proxy.object_path
555
576
        self.clients_dict[path] = client
556
 
        self.clients.sort(key=lambda c: c.properties["Name"])
 
577
        self.clients.sort(None, lambda c: c.properties["Name"])
557
578
        self.refresh()
558
579
    
559
580
    def remove_client(self, client, path=None):
561
582
        if path is None:
562
583
            path = client.proxy.object_path
563
584
        del self.clients_dict[path]
 
585
        if not self.clients_dict:
 
586
            # Work around bug in Urwid 0.9.8.3 - if a SimpleListWalker
 
587
            # is completely emptied, we need to recreate it.
 
588
            self.clients = urwid.SimpleListWalker([])
 
589
            self.rebuild()
564
590
        self.refresh()
565
591
    
566
592
    def refresh(self):
579
605
        try:
580
606
            mandos_clients = (self.mandos_serv
581
607
                              .GetAllClientsWithProperties())
582
 
            if not mandos_clients:
583
 
                self.log_message_raw(("bold", "Note: Server has no clients."))
584
608
        except dbus.exceptions.DBusException:
585
 
            self.log_message_raw(("bold", "Note: No Mandos server running."))
586
609
            mandos_clients = dbus.Dictionary()
587
610
        
588
611
        (self.mandos_serv
600
623
                            self.client_not_found,
601
624
                            dbus_interface=server_interface,
602
625
                            byte_arrays=True))
603
 
        for path, client in mandos_clients.items():
 
626
        for path, client in mandos_clients.iteritems():
604
627
            client_proxy_object = self.bus.get_object(self.busname,
605
628
                                                      path)
606
629
            self.add_client(MandosClientWidget(server_proxy_object
718
741
    ui.run()
719
742
except KeyboardInterrupt:
720
743
    ui.screen.stop()
721
 
except Exception as e:
722
 
    ui.log_message(str(e))
 
744
except Exception, e:
 
745
    ui.log_message(unicode(e))
723
746
    ui.screen.stop()
724
747
    raise