/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-05 09:27:47 UTC
  • Revision ID: teddy@recompile.se-20120505092747-d8s061chuhlt961h
* mandos-ctl (print_clients): Bug fix: Don't show "Extended Timeout"
                              as milliseconds.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
#     GNU General Public License for more details.
18
18
19
19
# You should have received a copy of the GNU General Public License
20
 
# along with this program.  If not, see
21
 
# <http://www.gnu.org/licenses/>.
 
20
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
21
23
22
# Contact the authors at <mandos@recompile.se>.
24
23
26
25
from __future__ import (division, absolute_import, print_function,
27
26
                        unicode_literals)
28
27
 
29
 
from future_builtins import *
30
 
 
31
28
import sys
32
29
import os
33
30
import signal
86
83
    properties and calls a hook function when any of them are
87
84
    changed.
88
85
    """
89
 
    def __init__(self, proxy_object=None, properties=None, **kwargs):
 
86
    def __init__(self, proxy_object=None, *args, **kwargs):
90
87
        self.proxy = proxy_object # Mandos Client proxy object
91
 
        self.properties = dict() if properties is None else properties
 
88
        
 
89
        self.properties = dict()
92
90
        self.property_changed_match = (
93
91
            self.proxy.connect_to_signal("PropertyChanged",
94
 
                                         self._property_changed,
 
92
                                         self.property_changed,
95
93
                                         client_interface,
96
94
                                         byte_arrays=True))
97
95
        
98
 
        if properties is None:
99
 
            self.properties.update(
100
 
                self.proxy.GetAll(client_interface,
101
 
                                  dbus_interface
102
 
                                  = dbus.PROPERTIES_IFACE))
103
 
        
104
 
        super(MandosClientPropertyCache, self).__init__(**kwargs)
105
 
    
106
 
    def _property_changed(self, property, value):
107
 
        """Helper which takes positional arguments"""
108
 
        return self.property_changed(property=property, value=value)
 
96
        self.properties.update(
 
97
            self.proxy.GetAll(client_interface,
 
98
                              dbus_interface = dbus.PROPERTIES_IFACE))
 
99
 
 
100
        #XXX This breaks good super behaviour
 
101
#        super(MandosClientPropertyCache, self).__init__(
 
102
#            *args, **kwargs)
109
103
    
110
104
    def property_changed(self, property=None, value=None):
111
105
        """This is called whenever we get a PropertyChanged signal
114
108
        # Update properties dict with new value
115
109
        self.properties[property] = value
116
110
    
117
 
    def delete(self):
 
111
    def delete(self, *args, **kwargs):
118
112
        self.property_changed_match.remove()
 
113
        super(MandosClientPropertyCache, self).__init__(
 
114
            *args, **kwargs)
119
115
 
120
116
 
121
117
class MandosClientWidget(urwid.FlowWidget, MandosClientPropertyCache):
123
119
    """
124
120
    
125
121
    def __init__(self, server_proxy_object=None, update_hook=None,
126
 
                 delete_hook=None, logger=None, **kwargs):
 
122
                 delete_hook=None, logger=None, *args, **kwargs):
127
123
        # Called on update
128
124
        self.update_hook = update_hook
129
125
        # Called on delete
134
130
        self.logger = logger
135
131
        
136
132
        self._update_timer_callback_tag = None
 
133
        self._update_timer_callback_lock = 0
137
134
        
138
135
        # The widget shown normally
139
136
        self._text_widget = urwid.Text("")
140
137
        # The widget shown when we have focus
141
138
        self._focus_text_widget = urwid.Text("")
142
 
        super(MandosClientWidget, self).__init__(**kwargs)
 
139
        super(MandosClientWidget, self).__init__(
 
140
            update_hook=update_hook, delete_hook=delete_hook,
 
141
            *args, **kwargs)
143
142
        self.update()
144
143
        self.opened = False
145
144
        
 
145
        last_checked_ok = isoformat_to_datetime(self.properties
 
146
                                                ["LastCheckedOK"])
 
147
        
 
148
        if self.properties ["LastCheckerStatus"] != 0:
 
149
            self.using_timer(True)
 
150
        
 
151
        if self.need_approval:
 
152
            self.using_timer(True)
 
153
        
146
154
        self.match_objects = (
147
155
            self.proxy.connect_to_signal("CheckerCompleted",
148
156
                                         self.checker_completed,
167
175
        #self.logger('Created client {0}'
168
176
        #            .format(self.properties["Name"]))
169
177
    
 
178
    def property_changed(self, property=None, value=None):
 
179
        super(self, MandosClientWidget).property_changed(property,
 
180
                                                         value)
 
181
        if property == "ApprovalPending":
 
182
            using_timer(bool(value))
 
183
        if property == "LastCheckerStatus":
 
184
            using_timer(value != 0)
 
185
            #self.logger('Checker for client {0} (command "{1}") was '
 
186
            #            ' successful'.format(self.properties["Name"],
 
187
            #                                 command))
 
188
    
170
189
    def using_timer(self, flag):
171
190
        """Call this method with True or False when timer should be
172
191
        activated or deactivated.
173
192
        """
174
 
        if flag and self._update_timer_callback_tag is None:
 
193
        old = self._update_timer_callback_lock
 
194
        if flag:
 
195
            self._update_timer_callback_lock += 1
 
196
        else:
 
197
            self._update_timer_callback_lock -= 1
 
198
        if old == 0 and self._update_timer_callback_lock:
175
199
            # Will update the shown timer value every second
176
200
            self._update_timer_callback_tag = (gobject.timeout_add
177
201
                                               (1000,
178
202
                                                self.update_timer))
179
 
        elif not (flag or self._update_timer_callback_tag is None):
 
203
        elif old and self._update_timer_callback_lock == 0:
180
204
            gobject.source_remove(self._update_timer_callback_tag)
181
205
            self._update_timer_callback_tag = None
182
206
    
224
248
            message = 'Client {0} will get its secret in {1} seconds'
225
249
        self.logger(message.format(self.properties["Name"],
226
250
                                   timeout/1000))
 
251
        self.using_timer(True)
227
252
    
228
253
    def rejected(self, reason):
229
254
        self.logger('Client {0} was rejected; reason: {1}'
255
280
                          "bold-underline-blink":
256
281
                              "bold-underline-blink-standout",
257
282
                          }
258
 
        
 
283
 
259
284
        # Rebuild focus and non-focus widgets using current properties
260
 
        
 
285
 
261
286
        # Base part of a client. Name!
262
287
        base = '{name}: '.format(name=self.properties["Name"])
263
288
        if not self.properties["Enabled"]:
264
289
            message = "DISABLED"
265
 
            self.using_timer(False)
266
290
        elif self.properties["ApprovalPending"]:
267
291
            timeout = datetime.timedelta(milliseconds
268
292
                                         = self.properties
270
294
            last_approval_request = isoformat_to_datetime(
271
295
                self.properties["LastApprovalRequest"])
272
296
            if last_approval_request is not None:
273
 
                timer = max(timeout - (datetime.datetime.utcnow()
274
 
                                       - last_approval_request),
275
 
                            datetime.timedelta())
 
297
                timer = timeout - (datetime.datetime.utcnow()
 
298
                                   - last_approval_request)
276
299
            else:
277
300
                timer = datetime.timedelta()
278
301
            if self.properties["ApprovedByDefault"]:
280
303
            else:
281
304
                message = "Denial in {0}. (a)pprove?"
282
305
            message = message.format(unicode(timer).rsplit(".", 1)[0])
283
 
            self.using_timer(True)
284
306
        elif self.properties["LastCheckerStatus"] != 0:
285
 
            # When checker has failed, show timer until client expires
 
307
            # When checker has failed, print a timer until client expires
286
308
            expires = self.properties["Expires"]
287
309
            if expires == "":
288
310
                timer = datetime.timedelta(0)
289
311
            else:
290
 
                expires = (datetime.datetime.strptime
291
 
                           (expires, '%Y-%m-%dT%H:%M:%S.%f'))
292
 
                timer = max(expires - datetime.datetime.utcnow(),
293
 
                            datetime.timedelta())
 
312
                expires = datetime.datetime.strptime(expires,
 
313
                                                     '%Y-%m-%dT%H:%M:%S.%f')
 
314
                timer = expires - datetime.datetime.utcnow()
294
315
            message = ('A checker has failed! Time until client'
295
316
                       ' gets disabled: {0}'
296
317
                       .format(unicode(timer).rsplit(".", 1)[0]))
297
 
            self.using_timer(True)
298
318
        else:
299
319
            message = "enabled"
300
 
            self.using_timer(False)
301
320
        self._text = "{0}{1}".format(base, message)
302
 
        
 
321
            
303
322
        if not urwid.supports_unicode():
304
323
            self._text = self._text.encode("ascii", "replace")
305
324
        textlist = [("normal", self._text)]
322
341
        self.update()
323
342
        return True             # Keep calling this
324
343
    
325
 
    def delete(self, **kwargs):
 
344
    def delete(self, *args, **kwargs):
326
345
        if self._update_timer_callback_tag is not None:
327
346
            gobject.source_remove(self._update_timer_callback_tag)
328
347
            self._update_timer_callback_tag = None
331
350
        self.match_objects = ()
332
351
        if self.delete_hook is not None:
333
352
            self.delete_hook(self)
334
 
        return super(MandosClientWidget, self).delete(**kwargs)
 
353
        return super(MandosClientWidget, self).delete(*args, **kwargs)
335
354
    
336
355
    def render(self, maxcolrow, focus=False):
337
356
        """Render differently if we have focus.
379
398
        else:
380
399
            return key
381
400
    
382
 
    def property_changed(self, property=None, **kwargs):
 
401
    def property_changed(self, property=None, value=None,
 
402
                         *args, **kwargs):
383
403
        """Call self.update() if old value is not new value.
384
404
        This overrides the method from MandosClientPropertyCache"""
385
405
        property_name = unicode(property)
386
406
        old_value = self.properties.get(property_name)
387
407
        super(MandosClientWidget, self).property_changed(
388
 
            property=property, **kwargs)
 
408
            property=property, value=value, *args, **kwargs)
389
409
        if self.properties.get(property_name) != old_value:
390
410
            self.update()
391
411
 
395
415
    "down" key presses, thus not allowing any containing widgets to
396
416
    use them as an excuse to shift focus away from this widget.
397
417
    """
398
 
    def keypress(self, *args, **kwargs):
399
 
        ret = super(ConstrainedListBox, self).keypress(*args, **kwargs)
 
418
    def keypress(self, maxcolrow, key):
 
419
        ret = super(ConstrainedListBox, self).keypress(maxcolrow, key)
400
420
        if ret in ("up", "down"):
401
421
            return
402
422
        return ret
617
637
                                               logger
618
638
                                               =self.log_message),
619
639
                            path=path)
620
 
        
 
640
 
621
641
        self.refresh()
622
642
        self._input_callback_tag = (gobject.io_add_watch
623
643
                                    (sys.stdin.fileno(),