/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: 2009-12-25 23:13:47 UTC
  • Revision ID: teddy@fukt.bsnet.se-20091225231347-gg9u9ru0wj0f24hh
More consistent terminology: Clients are no longer "invalid" - they
are "disabled".  All code and documentation changed to reflect this.

D=Bus API change: The "properties" argument was removed from the
"ClientAdded" signal on interface "se.bsnet.fukt.Mandos".  All code in
both "mandos" and "mandos-monitor" changed to reflect this.

* mandos: Replaced "with closing(F)" with simply "with F" in all
          places where F is a file object.
  (Client.still_valid): Removed.  All callers changed to look at
                        "Client.enabled" instead.
  (dbus_service_property): Check for unsupported signatures with the
                           "byte_arrays" option.
  (DBusObjectWithProperties.Set): - '' -
  (ClientHandler.handle): Use the reverse pipe to receive the
                          "Client.enabled" attribute instead of the
                          now-removed "Client.still_valid()" method.
  (ForkingMixInWithPipe): Renamed to "ForkingMixInWithPipes" (all
                          users changed).  Now also create a reverse
                          pipe for sending data to the child process.
  (ForkingMixInWithPipes.add_pipe): Now takes two pipe fd's as
                                    arguments.  All callers changed.
  (IPv6_TCPServer.handle_ipc): Take an additional "reply_fd" argument
                               (all callers changed).  Close the reply
                               pipe when the child data pipe is
                               closed.  New "GETATTR" IPC method; will
                               pickle client attribute and send it
                               over the reply pipe FD.
  (MandosDBusService.ClientAdded): Removed "properties" argument.  All
                                   emitters changed.
* mandos-clients.conf.xml (DESCRIPTION, OPTIONS): Use
                                                  "enabled/disabled"
                                                  terminology.
* mandos-ctl: Option "--is-valid" renamed to "--is-enabled".
* mandos-monitor: Enable user locale.  Try to log exceptions.
  (MandosClientPropertyCache.__init__): Removed "properties" argument.
                                        All callers changed.
  (UserInterface.add_new_client): Remove "properties" argument.  All
                                  callers changed.  Supply "logger"
                                  argument to MandosClientWidget().
  (UserInterface.add_client): New "logger" argument.  All callers
                              changed.
* mandos.xml (BUGS, SECURITY/CLIENTS): Use "enabled/disabled"
                                       terminology.

Show diffs side-by-side

added added

removed removed

Lines of Context:
37
37
urwid.curses_display.curses.A_UNDERLINE |= (
38
38
    urwid.curses_display.curses.A_BLINK)
39
39
 
40
 
def isoformat_to_datetime(iso):
41
 
    "Parse an ISO 8601 date string to a datetime.datetime()"
42
 
    if not iso:
43
 
        return None
44
 
    d, t = iso.split(u"T", 1)
45
 
    year, month, day = d.split(u"-", 2)
46
 
    hour, minute, second = t.split(u":", 2)
47
 
    second, fraction = divmod(float(second), 1)
48
 
    return datetime.datetime(int(year),
49
 
                             int(month),
50
 
                             int(day),
51
 
                             int(hour),
52
 
                             int(minute),
53
 
                             int(second),           # Whole seconds
54
 
                             int(fraction*1000000)) # Microseconds
55
 
 
56
40
class MandosClientPropertyCache(object):
57
41
    """This wraps a Mandos Client D-Bus proxy object, caches the
58
42
    properties and calls a hook function when any of them are
66
50
                                     self.property_changed,
67
51
                                     client_interface,
68
52
                                     byte_arrays=True)
69
 
        
 
53
 
70
54
        self.properties.update(
71
55
            self.proxy.GetAll(client_interface,
72
56
                              dbus_interface = dbus.PROPERTIES_IFACE))
96
80
        # Logger
97
81
        self.logger = logger
98
82
        
99
 
        self._update_timer_callback_tag = None
100
 
        self.last_checker_failed = False
101
 
        
102
83
        # The widget shown normally
103
84
        self._text_widget = urwid.Text(u"")
104
85
        # The widget shown when we have focus
124
105
                                     self.rejected,
125
106
                                     client_interface,
126
107
                                     byte_arrays=True)
127
 
        last_checked_ok = isoformat_to_datetime(self.properties
128
 
                                                ["last_checked_ok"])
129
 
        if last_checked_ok is None:
130
 
            self.last_checker_failed = True
131
 
        else:
132
 
            self.last_checker_failed = ((datetime.datetime.utcnow()
133
 
                                         - last_checked_ok)
134
 
                                        > datetime.timedelta
135
 
                                        (milliseconds=
136
 
                                         self.properties["interval"]))
137
 
        if self.last_checker_failed:
138
 
            self._update_timer_callback_tag = (gobject.timeout_add
139
 
                                               (1000,
140
 
                                                self.update_timer))
141
108
    
142
109
    def checker_completed(self, exitstatus, condition, command):
143
110
        if exitstatus == 0:
144
 
            if self.last_checker_failed:
145
 
                self.last_checker_failed = False
146
 
                gobject.source_remove(self._update_timer_callback_tag)
147
 
                self._update_timer_callback_tag = None
148
111
            self.logger(u'Checker for client %s (command "%s")'
149
112
                        u' was successful'
150
113
                        % (self.properties[u"name"], command))
151
 
            self.update()
152
114
            return
153
 
        # Checker failed
154
 
        if not self.last_checker_failed:
155
 
            self.last_checker_failed = True
156
 
            self._update_timer_callback_tag = (gobject.timeout_add
157
 
                                               (1000,
158
 
                                                self.update_timer))
159
115
        if os.WIFEXITED(condition):
160
116
            self.logger(u'Checker for client %s (command "%s")'
161
117
                        u' failed with exit code %s'
162
118
                        % (self.properties[u"name"], command,
163
119
                           os.WEXITSTATUS(condition)))
164
 
        elif os.WIFSIGNALED(condition):
 
120
            return
 
121
        if os.WIFSIGNALED(condition):
165
122
            self.logger(u'Checker for client %s (command "%s")'
166
123
                        u' was killed by signal %s'
167
124
                        % (self.properties[u"name"], command,
168
125
                           os.WTERMSIG(condition)))
169
 
        elif os.WCOREDUMP(condition):
 
126
            return
 
127
        if os.WCOREDUMP(condition):
170
128
            self.logger(u'Checker for client %s (command "%s")'
171
129
                        u' dumped core'
172
130
                        % (self.properties[u"name"], command))
173
 
        else:
174
 
            self.logger(u'Checker for client %s completed mysteriously')
175
 
        self.update()
 
131
        self.logger(u'Checker for client %s completed mysteriously')
176
132
    
177
133
    def checker_started(self, command):
178
134
        self.logger(u'Client %s started checker "%s"'
214
170
                          }
215
171
        
216
172
        # Rebuild focus and non-focus widgets using current properties
217
 
        self._text = (u'%(name)s: %(enabled)s%(timer)s'
 
173
        self._text = (u'%(name)s: %(enabled)s'
218
174
                      % { u"name": self.properties[u"name"],
219
175
                          u"enabled":
220
176
                              (u"enabled"
221
177
                               if self.properties[u"enabled"]
222
 
                               else u"DISABLED"),
223
 
                          u"timer": (unicode(datetime.timedelta
224
 
                                             (milliseconds =
225
 
                                              self.properties
226
 
                                              [u"timeout"])
227
 
                                             - (datetime.datetime
228
 
                                                .utcnow()
229
 
                                                - isoformat_to_datetime
230
 
                                                (max((self.properties
231
 
                                                 ["last_checked_ok"]
232
 
                                                 or
233
 
                                                 self.properties
234
 
                                                 ["created"]),
235
 
                                                    self.properties[u"last_enabled"]))))
236
 
                                     if (self.last_checker_failed
237
 
                                         and self.properties
238
 
                                         [u"enabled"])
239
 
                                     else u"")})
 
178
                               else u"DISABLED")})
240
179
        if not urwid.supports_unicode():
241
180
            self._text = self._text.encode("ascii", "replace")
242
181
        textlist = [(u"normal", self._text)]
253
192
        if self.update_hook is not None:
254
193
            self.update_hook()
255
194
    
256
 
    def update_timer(self):
257
 
        "called by gobject"
258
 
        self.update()
259
 
        return True             # Keep calling this
260
 
    
261
195
    def delete(self):
262
 
        if self._update_timer_callback_tag is not None:
263
 
            gobject.source_remove(self._update_timer_callback_tag)
264
 
            self._update_timer_callback_tag = None
265
196
        if self.delete_hook is not None:
266
197
            self.delete_hook(self)
267
198