~ahasenack/landscape-client/landscape-client-1.5.5-0ubuntu0.9.04.0

« back to all changes in this revision

Viewing changes to landscape/manager/processkiller.py

  • Committer: Bazaar Package Importer
  • Author(s): Rick Clark
  • Date: 2008-09-08 16:35:57 UTC
  • mto: This revision was merged to the branch mainline in revision 2.
  • Revision ID: james.westby@ubuntu.com-20080908163557-fl0d2oc35hur473w
Tags: upstream-1.0.18
ImportĀ upstreamĀ versionĀ 1.0.18

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import os
 
2
import signal
 
3
import logging
 
4
from datetime import datetime
 
5
 
 
6
from landscape.lib.process import ProcessInformation
 
7
from landscape.manager.manager import ManagerPlugin
 
8
 
 
9
 
 
10
class ProcessNotFoundError(Exception):
 
11
    pass
 
12
 
 
13
 
 
14
class ProcessMismatchError(Exception):
 
15
    pass
 
16
 
 
17
 
 
18
class SignalProcessError(Exception):
 
19
    pass
 
20
 
 
21
 
 
22
class ProcessKiller(ManagerPlugin):
 
23
    """
 
24
    A management plugin that signals processes upon receiving a message from
 
25
    the server.
 
26
    """
 
27
    def __init__(self, process_info=None):
 
28
        if process_info is None:
 
29
            process_info = ProcessInformation()
 
30
        self.process_info = process_info
 
31
 
 
32
    def register(self, registry):
 
33
        super(ProcessKiller, self).register(registry)
 
34
        registry.register_message("signal-process", self._handle_signal_process)
 
35
 
 
36
    def _handle_signal_process(self, message):
 
37
        self.call_with_operation_result(message, self.signal_process,
 
38
                                        message["pid"], message["name"],
 
39
                                        message["start-time"],
 
40
                                        message["signal"])
 
41
 
 
42
    def signal_process(self, pid, name, start_time, signame):
 
43
        logging.info("Sending %s signal to the process with PID %d.",
 
44
                     signame, pid)
 
45
        process_info = self.process_info.get_process_info(pid)
 
46
        if not process_info:
 
47
            start_time = datetime.utcfromtimestamp(start_time)
 
48
            message = ("The process %s with PID %d that started at %s UTC was "
 
49
                       "not found") % (name, pid, start_time)
 
50
            raise ProcessNotFoundError(message)
 
51
        elif abs(process_info["start-time"] - start_time) > 2:
 
52
            # We don't check that the start time matches precisely because
 
53
            # the way we obtain boot times isn't very precise, and this may
 
54
            # cascade into having imprecise process start times.
 
55
            expected_time = datetime.utcfromtimestamp(start_time)
 
56
            actual_time = datetime.utcfromtimestamp(process_info["start-time"])
 
57
            message = ("The process %s with PID %d that started at "
 
58
                       "%s UTC was not found.  A process with the same "
 
59
                       "PID that started at %s UTC was found and not "
 
60
                       "sent the %s signal") % (name, pid, expected_time,
 
61
                                                actual_time, signame)
 
62
            raise ProcessMismatchError(message)
 
63
 
 
64
        signum = getattr(signal, "SIG%s" % (signame,))
 
65
        try:
 
66
            os.kill(pid, signum)
 
67
        except:
 
68
            # XXX Nothing is indicating what the problem was.
 
69
            message = ("Attempting to send the %s signal to the process "
 
70
                       "%s with PID %d failed") % (signame, name, pid)
 
71
            raise SignalProcessError(message)