~allenap/maas/xxx-a-thon

« back to all changes in this revision

Viewing changes to src/maasserver/service_monitor.py

  • Committer: Gavin Panella
  • Date: 2016-03-22 21:14:34 UTC
  • mfrom: (4657.1.157 maas)
  • Revision ID: gavin.panella@canonical.com-20160322211434-xzuovio86zvzo2js
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2016 Canonical Ltd.  This software is licensed under the
 
2
# GNU Affero General Public License version 3 (see the file LICENSE).
 
3
 
 
4
"""Services monitored on regiond."""
 
5
 
 
6
__all__ = [
 
7
    ]
 
8
 
 
9
from datetime import timedelta
 
10
 
 
11
from maasserver.models.regioncontrollerprocess import RegionControllerProcess
 
12
from maasserver.models.service import Service
 
13
from maasserver.utils.orm import transactional
 
14
from maasserver.utils.threads import deferToDatabase
 
15
from provisioningserver.config import is_dev_environment
 
16
from provisioningserver.logger import get_maas_logger
 
17
from provisioningserver.utils.service_monitor import (
 
18
    AlwaysOnService,
 
19
    ServiceMonitor,
 
20
)
 
21
from twisted.application.internet import TimerService
 
22
from twisted.internet import reactor
 
23
from twisted.internet.defer import inlineCallbacks
 
24
from twisted.python import log
 
25
 
 
26
 
 
27
maaslog = get_maas_logger("service_monitor_service")
 
28
 
 
29
 
 
30
class BIND9Service(AlwaysOnService):
 
31
    """Monitored bind9 service."""
 
32
 
 
33
    name = "bind9"
 
34
    service_name = "bind9"
 
35
 
 
36
 
 
37
class ProxyService(AlwaysOnService):
 
38
    """Monitored proxy service."""
 
39
 
 
40
    name = "proxy"
 
41
    service_name = "maas-proxy"
 
42
 
 
43
 
 
44
# Global service monitor for regiond.
 
45
service_monitor = ServiceMonitor(
 
46
    BIND9Service(),
 
47
    ProxyService(),
 
48
)
 
49
 
 
50
 
 
51
class ServiceMonitorService(TimerService, object):
 
52
    """Service to monitor external services that the region requires."""
 
53
 
 
54
    check_interval = timedelta(minutes=1).total_seconds()
 
55
 
 
56
    def __init__(self, advertisingService, clock=reactor):
 
57
        # Call self.monitorServices() every self.check_interval.
 
58
        super(ServiceMonitorService, self).__init__(
 
59
            self.check_interval, self.monitorServices)
 
60
        self.clock = clock
 
61
        self.advertisingService = advertisingService
 
62
 
 
63
    def monitorServices(self):
 
64
        """Monitors all of the external services and makes sure they
 
65
        stay running.
 
66
        """
 
67
        if is_dev_environment():
 
68
            log.msg(
 
69
                "Skipping check of services; they're not running under "
 
70
                "the supervision of systemd.")
 
71
        else:
 
72
            d = service_monitor.ensureServices()
 
73
            d.addCallback(self._updateDatabase)
 
74
            d.addErrback(
 
75
                log.err, "Failed to monitor services and update database.")
 
76
            return d
 
77
 
 
78
    @inlineCallbacks
 
79
    def _updateDatabase(self, services):
 
80
        """Update database about services status."""
 
81
        processId = yield self.advertisingService.processId.get()
 
82
        services = yield self._buildServices(services)
 
83
        yield deferToDatabase(self._saveIntoDatabase, processId, services)
 
84
 
 
85
    @transactional
 
86
    def _saveIntoDatabase(self, processId, services):
 
87
        """Save the `services` in the the database for process by `processId`.
 
88
        """
 
89
        process = RegionControllerProcess.objects.get(id=processId)
 
90
        for service in services:
 
91
            Service.objects.update_service_for(
 
92
                process.region, service["name"],
 
93
                service["status"], service["status_info"])
 
94
 
 
95
    @inlineCallbacks
 
96
    def _buildServices(self, services):
 
97
        """Build the list of services so they can be updated into the database.
 
98
        """
 
99
        msg_services = []
 
100
        for name, state in services.items():
 
101
            service = service_monitor.getServiceByName(name)
 
102
            status, status_info = yield state.get_status_and_status_info_for(
 
103
                service)
 
104
            msg_services.append({
 
105
                "name": name,
 
106
                "status": status,
 
107
                "status_info": status_info,
 
108
            })
 
109
        return msg_services