/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

merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
170
170
# End of Avahi example code
171
171
 
172
172
 
173
 
def _datetime_to_dbus_struct(dt, variant_level=0):
174
 
    """Convert a UTC datetime.datetime() to a D-Bus struct.
175
 
    The format is special to this application, since we could not find
176
 
    any other standard way."""
177
 
    return dbus.Struct((dbus.Int16(dt.year),
178
 
                        dbus.Byte(dt.month),
179
 
                        dbus.Byte(dt.day),
180
 
                        dbus.Byte(dt.hour),
181
 
                        dbus.Byte(dt.minute),
182
 
                        dbus.Byte(dt.second),
183
 
                        dbus.UInt32(dt.microsecond)),
184
 
                       signature="nyyyyyu",
185
 
                       variant_level=variant_level)
 
173
def _datetime_to_dbus(dt, variant_level=0):
 
174
    """Convert a UTC datetime.datetime() to a D-Bus type."""
 
175
    return dbus.String(dt.isoformat(), variant_level=variant_level)
186
176
 
187
177
 
188
178
class Client(dbus.service.Object):
194
184
    secret:     bytestring; sent verbatim (over TLS) to client
195
185
    host:       string; available for use by the checker command
196
186
    created:    datetime.datetime(); (UTC) object creation
197
 
    last_started: datetime.datetime(); (UTC)
198
 
    started:    bool()
 
187
    last_enabled: datetime.datetime(); (UTC)
 
188
    enabled:    bool()
199
189
    last_checked_ok: datetime.datetime(); (UTC) or None
200
190
    timeout:    datetime.timedelta(); How long from last_checked_ok
201
191
                                      until this client is invalid
202
192
    interval:   datetime.timedelta(); How often to start a new checker
203
 
    stop_hook:  If set, called by stop() as stop_hook(self)
 
193
    disable_hook:  If set, called by disable() as disable_hook(self)
204
194
    checker:    subprocess.Popen(); a running checker process used
205
195
                                    to see if the client lives.
206
196
                                    'None' if no process is running.
207
197
    checker_initiator_tag: a gobject event source tag, or None
208
 
    stop_initiator_tag:    - '' -
 
198
    disable_initiator_tag:    - '' -
209
199
    checker_callback_tag:  - '' -
210
200
    checker_command: string; External command which is run to check if
211
201
                     client lives.  %() expansions are done at
249
239
    interval = property(lambda self: self._interval, _set_interval)
250
240
    del _set_interval
251
241
    
252
 
    def __init__(self, name = None, stop_hook=None, config=None):
 
242
    def __init__(self, name = None, disable_hook=None, config=None):
253
243
        """Note: the 'checker' key in 'config' sets the
254
244
        'checker_command' attribute and *not* the 'checker'
255
245
        attribute."""
280
270
                            % self.name)
281
271
        self.host = config.get("host", "")
282
272
        self.created = datetime.datetime.utcnow()
283
 
        self.started = False
284
 
        self.last_started = None
 
273
        self.enabled = False
 
274
        self.last_enabled = None
285
275
        self.last_checked_ok = None
286
276
        self.timeout = string_to_delta(config["timeout"])
287
277
        self.interval = string_to_delta(config["interval"])
288
 
        self.stop_hook = stop_hook
 
278
        self.disable_hook = disable_hook
289
279
        self.checker = None
290
280
        self.checker_initiator_tag = None
291
 
        self.stop_initiator_tag = None
 
281
        self.disable_initiator_tag = None
292
282
        self.checker_callback_tag = None
293
283
        self.checker_command = config["checker"]
294
284
    
295
 
    def start(self):
 
285
    def enable(self):
296
286
        """Start this client's checker and timeout hooks"""
297
 
        self.last_started = datetime.datetime.utcnow()
 
287
        self.last_enabled = datetime.datetime.utcnow()
298
288
        # Schedule a new checker to be started an 'interval' from now,
299
289
        # and every interval from then on.
300
290
        self.checker_initiator_tag = (gobject.timeout_add
302
292
                                       self.start_checker))
303
293
        # Also start a new checker *right now*.
304
294
        self.start_checker()
305
 
        # Schedule a stop() when 'timeout' has passed
306
 
        self.stop_initiator_tag = (gobject.timeout_add
 
295
        # Schedule a disable() when 'timeout' has passed
 
296
        self.disable_initiator_tag = (gobject.timeout_add
307
297
                                   (self._timeout_milliseconds,
308
 
                                    self.stop))
309
 
        self.started = True
 
298
                                    self.disable))
 
299
        self.enabled = True
310
300
        # Emit D-Bus signal
311
 
        self.PropertyChanged(dbus.String(u"started"),
 
301
        self.PropertyChanged(dbus.String(u"enabled"),
312
302
                             dbus.Boolean(True, variant_level=1))
313
 
        self.PropertyChanged(dbus.String(u"last_started"),
314
 
                             (_datetime_to_dbus_struct
315
 
                              (self.last_started, variant_level=1)))
 
303
        self.PropertyChanged(dbus.String(u"last_enabled"),
 
304
                             (_datetime_to_dbus(self.last_enabled,
 
305
                                                variant_level=1)))
316
306
    
317
 
    def stop(self):
318
 
        """Stop this client."""
319
 
        if not getattr(self, "started", False):
 
307
    def disable(self):
 
308
        """Disable this client."""
 
309
        if not getattr(self, "enabled", False):
320
310
            return False
321
 
        logger.info(u"Stopping client %s", self.name)
322
 
        if getattr(self, "stop_initiator_tag", False):
323
 
            gobject.source_remove(self.stop_initiator_tag)
324
 
            self.stop_initiator_tag = None
 
311
        logger.info(u"Disabling client %s", self.name)
 
312
        if getattr(self, "disable_initiator_tag", False):
 
313
            gobject.source_remove(self.disable_initiator_tag)
 
314
            self.disable_initiator_tag = None
325
315
        if getattr(self, "checker_initiator_tag", False):
326
316
            gobject.source_remove(self.checker_initiator_tag)
327
317
            self.checker_initiator_tag = None
328
318
        self.stop_checker()
329
 
        if self.stop_hook:
330
 
            self.stop_hook(self)
331
 
        self.started = False
 
319
        if self.disable_hook:
 
320
            self.disable_hook(self)
 
321
        self.enabled = False
332
322
        # Emit D-Bus signal
333
 
        self.PropertyChanged(dbus.String(u"started"),
 
323
        self.PropertyChanged(dbus.String(u"enabled"),
334
324
                             dbus.Boolean(False, variant_level=1))
335
325
        # Do not run this again if called by a gobject.timeout_add
336
326
        return False
337
327
    
338
328
    def __del__(self):
339
 
        self.stop_hook = None
340
 
        self.stop()
 
329
        self.disable_hook = None
 
330
        self.disable()
341
331
    
342
332
    def checker_callback(self, pid, condition, command):
343
333
        """The checker has completed, so take appropriate actions."""
376
366
        alive and well.
377
367
        """
378
368
        self.last_checked_ok = datetime.datetime.utcnow()
379
 
        gobject.source_remove(self.stop_initiator_tag)
380
 
        self.stop_initiator_tag = (gobject.timeout_add
381
 
                                   (self._timeout_milliseconds,
382
 
                                    self.stop))
 
369
        gobject.source_remove(self.disable_initiator_tag)
 
370
        self.disable_initiator_tag = (gobject.timeout_add
 
371
                                      (self._timeout_milliseconds,
 
372
                                       self.disable))
383
373
        self.PropertyChanged(dbus.String(u"last_checked_ok"),
384
 
                             (_datetime_to_dbus_struct
385
 
                              (self.last_checked_ok,
386
 
                               variant_level=1)))
 
374
                             (_datetime_to_dbus(self.last_checked_ok,
 
375
                                                variant_level=1)))
387
376
    
388
377
    def start_checker(self):
389
378
        """Start a new checker subprocess if one is not running.
458
447
    
459
448
    def still_valid(self):
460
449
        """Has the timeout not yet passed for this client?"""
461
 
        if not getattr(self, "started", False):
 
450
        if not getattr(self, "enabled", False):
462
451
            return False
463
452
        now = datetime.datetime.utcnow()
464
453
        if self.last_checked_ok is None:
497
486
                dbus.String("host"):
498
487
                    dbus.String(self.host, variant_level=1),
499
488
                dbus.String("created"):
500
 
                    _datetime_to_dbus_struct(self.created,
501
 
                                             variant_level=1),
502
 
                dbus.String("last_started"):
503
 
                    (_datetime_to_dbus_struct(self.last_started,
504
 
                                              variant_level=1)
505
 
                     if self.last_started is not None
 
489
                    _datetime_to_dbus(self.created, variant_level=1),
 
490
                dbus.String("last_enabled"):
 
491
                    (_datetime_to_dbus(self.last_enabled,
 
492
                                       variant_level=1)
 
493
                     if self.last_enabled is not None
506
494
                     else dbus.Boolean(False, variant_level=1)),
507
 
                dbus.String("started"):
508
 
                    dbus.Boolean(self.started, variant_level=1),
 
495
                dbus.String("enabled"):
 
496
                    dbus.Boolean(self.enabled, variant_level=1),
509
497
                dbus.String("last_checked_ok"):
510
 
                    (_datetime_to_dbus_struct(self.last_checked_ok,
511
 
                                              variant_level=1)
 
498
                    (_datetime_to_dbus(self.last_checked_ok,
 
499
                                       variant_level=1)
512
500
                     if self.last_checked_ok is not None
513
501
                     else dbus.Boolean (False, variant_level=1)),
514
502
                dbus.String("timeout"):
565
553
    def SetTimeout(self, milliseconds):
566
554
        self.timeout = datetime.timedelta(0, 0, 0, milliseconds)
567
555
    
568
 
    # Start - method
569
 
    Start = dbus.service.method(_interface)(start)
570
 
    Start.__name__ = "Start"
 
556
    # Enable - method
 
557
    Enable = dbus.service.method(_interface)(enable)
 
558
    Enable.__name__ = "Enable"
571
559
    
572
560
    # StartChecker - method
573
561
    @dbus.service.method(_interface)
575
563
        "D-Bus method"
576
564
        self.start_checker()
577
565
    
578
 
    # Stop - method
 
566
    # Disable - method
579
567
    @dbus.service.method(_interface)
580
 
    def Stop(self):
 
568
    def Disable(self):
581
569
        "D-Bus method"
582
 
        self.stop()
 
570
        self.disable()
583
571
    
584
572
    # StopChecker - method
585
573
    StopChecker = dbus.service.method(_interface)(stop_checker)
1077
1065
        
1078
1066
        while clients:
1079
1067
            client = clients.pop()
1080
 
            client.stop_hook = None
1081
 
            client.stop()
 
1068
            client.disable_hook = None
 
1069
            client.disable()
1082
1070
    
1083
1071
    atexit.register(cleanup)
1084
1072
    
1119
1107
        def RemoveClient(self, object_path):
1120
1108
            for c in clients:
1121
1109
                if c.dbus_object_path == object_path:
1122
 
                    c.stop()
 
1110
                    c.disable()
1123
1111
                    clients.remove(c)
1124
1112
                    return
1125
1113
            raise KeyError
1132
1120
        # Emit D-Bus signal
1133
1121
        mandos_server.ClientAdded(client.dbus_object_path,
1134
1122
                                  client.GetAllProperties())
1135
 
        client.start()
 
1123
        client.enable()
1136
1124
    
1137
1125
    tcp_server.enable()
1138
1126
    tcp_server.server_activate()