This file is indexed.

/usr/lib/python3/dist-packages/provisioningserver/rackdservices/service_monitor_service.py is in python3-maas-provisioningserver 2.4.0~beta2-6865-gec43e47e6-0ubuntu1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# Copyright 2015-2016 Canonical Ltd.  This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).

"""Service to periodically check that all the other services that MAAS depends
on stays running."""


__all__ = [
    "ServiceMonitorService"
]

from datetime import timedelta

from provisioningserver.config import is_dev_environment
from provisioningserver.logger import (
    get_maas_logger,
    LegacyLogger,
)
from provisioningserver.rpc.exceptions import NoConnectionsAvailable
from provisioningserver.rpc.region import UpdateServices
from provisioningserver.service_monitor import service_monitor
from provisioningserver.utils.twisted import (
    pause,
    retries,
)
from twisted.application.internet import TimerService
from twisted.internet.defer import inlineCallbacks


maaslog = get_maas_logger("service_monitor_service")
log = LegacyLogger()


class ServiceMonitorService(TimerService, object):
    """Service to monitor external services that the cluster requires."""

    # Services that we don't perform any checks on at the moment and we
    # always considered working as since they run in the same process as rackd.
    # "rackd" should not show in this list as the region controller handles
    # updating the status of "rackd". This is because its status all depends
    # on the connections across the multiple regions.
    ALWAYS_RUNNING_SERVICES = [
        {
            "name": "http",
            "status": "running",
            "status_info": "",
        },
        {
            "name": "tftp",
            "status": "running",
            "status_info": "",
        },
    ]

    check_interval = timedelta(seconds=30).total_seconds()

    def __init__(self, client_service, clock):
        # Call self.monitorServices() every self.check_interval.
        super(ServiceMonitorService, self).__init__(
            self.check_interval, self.monitorServices)
        self.client_service = client_service
        self.clock = clock

    def monitorServices(self):
        """Monitors all of the external services and makes sure they
        stay running.
        """
        if is_dev_environment():
            log.msg(
                "Skipping check of services; they're not running under "
                "the supervision of systemd.")
        else:
            d = self._getConnection()
            d.addCallback(self._ensureServices)
            d.addCallback(self._updateRegion)
            d.addErrback(
                log.err, "Failed to monitor services and update region.")
            return d

    @inlineCallbacks
    def _getConnection(self):
        """Get a connection to the region."""
        client = None
        for elapsed, remaining, wait in retries(30, 10, self.clock):
            try:
                client = yield self.client_service.getClientNow()
                break
            except NoConnectionsAvailable:
                yield pause(wait, self.clock)
        else:
            maaslog.error(
                "Can't update service statuses, no RPC "
                "connection to region.")
        return client

    @inlineCallbacks
    def _ensureServices(self, client):
        if client:
            services = yield service_monitor.ensureServices()
            return (client, services)
        return None, None

    @inlineCallbacks
    def _updateRegion(self, result):
        """Update region about services status."""
        client, services = result
        if client:
            services = yield self._buildServices(services)
            yield client(
                UpdateServices,
                system_id=client.localIdent,
                services=services)

    @inlineCallbacks
    def _buildServices(self, services):
        """Build the list of services to be sent over RPC."""
        msg_services = list(self.ALWAYS_RUNNING_SERVICES)
        for name, state in services.items():
            service = service_monitor.getServiceByName(name)
            status, status_info = yield state.getStatusInfo(service)
            msg_services.append({
                "name": name,
                "status": status,
                "status_info": status_info,
            })
        return msg_services