File: services.py

package info (click to toggle)
freeipa 4.13.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 367,240 kB
  • sloc: javascript: 562,763; python: 310,289; ansic: 49,809; sh: 7,176; makefile: 2,589; xml: 343; sed: 16
file content (209 lines) | stat: -rw-r--r-- 7,270 bytes parent folder | download | duplicates (4)
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#
# Copyright (C) 2020 FreeIPA Contributors, see COPYING for license
#

import os
import logging
import time
import contextlib

from ipaplatform.base import services as base_services
from ipapython import ipautil, dogtag
from ipaplatform.paths import paths

logger = logging.getLogger(__name__)

suse_system_units = dict(
    (x, "%s.service" % x) for x in base_services.wellknownservices
)
suse_system_units["httpd"] = "apache2.service"
suse_system_units["dirsrv"] = "dirsrv@.service"
suse_system_units["pki-tomcatd"] = "pki-tomcatd@pki-tomcat.service"
suse_system_units["pki_tomcatd"] = suse_system_units["pki-tomcatd"]
suse_system_units["ipa-otpd"] = "ipa-otpd.socket"
suse_system_units["ipa-dnskeysyncd"] = "ipa-dnskeysyncd.service"
suse_system_units["named-regular"] = "named.service"
suse_system_units["named-pkcs11"] = "named.service"
suse_system_units["named"] = "named.service"
suse_system_units["ods-enforcerd"] = "ods-enforcerd.service"
suse_system_units["ods_enforcerd"] = suse_system_units["ods-enforcerd"]
suse_system_units["ods-signerd"] = "ods-signerd.service"
suse_system_units["ods_signerd"] = suse_system_units["ods-signerd"]


class SuseService(base_services.SystemdService):
    system_units = suse_system_units

    def __init__(self, service_name, api=None):
        systemd_name = service_name
        if service_name in self.system_units:
            systemd_name = self.system_units[service_name]
        else:
            if "." not in service_name:
                systemd_name = "%s.service" % (service_name)
        super().__init__(service_name, systemd_name, api)


class SuseDirectoryService(SuseService):
    def is_installed(self, instance_name):
        file_path = "{}/{}-{}".format(
            paths.ETC_DIRSRV, "slapd", instance_name
        )
        return os.path.exists(file_path)

    def restart(
        self, instance_name="", capture_output=True, wait=True, ldapi=False
    ):
        # We need to explicitly enable instances to install proper symlinks as
        # dirsrv.target.wants/ dependencies. Standard systemd service class
        # does it on enable() method call. Unfortunately, ipa-server-install
        # does not do explicit dirsrv.enable() because the service startup is
        # handled by ipactl.
        #
        # If we wouldn't do this, our instances will not be started as systemd
        # would not have any clue about instances (PKI-IPA and the domain we
        # serve) at all. Thus, hook into dirsrv.restart().

        if instance_name:
            elements = self.systemd_name.split("@")

            srv_etc = os.path.join(
                paths.ETC_SYSTEMD_SYSTEM_DIR, self.systemd_name
            )
            srv_tgt = os.path.join(
                paths.ETC_SYSTEMD_SYSTEM_DIR,
                self.SYSTEMD_SRV_TARGET % (elements[0]),
            )
            srv_lnk = os.path.join(
                srv_tgt, self.service_instance(instance_name)
            )

            if not os.path.exists(srv_etc):
                self.enable(instance_name)
            elif not os.path.samefile(srv_etc, srv_lnk):
                os.unlink(srv_lnk)
                os.symlink(srv_etc, srv_lnk)

        with self._wait(instance_name, wait, ldapi) as wait:
            super().restart(
                instance_name, capture_output=capture_output, wait=wait
            )

    def start(
        self, instance_name="", capture_output=True, wait=True, ldapi=False
    ):
        with self._wait(instance_name, wait, ldapi) as wait:
            super().start(
                instance_name, capture_output=capture_output, wait=wait
            )

    @contextlib.contextmanager
    def _wait(self, instance_name, wait, ldapi):
        if ldapi:
            instance_name = self.service_instance(instance_name)
            if instance_name.endswith(".service"):
                instance_name = instance_name[:-8]
            if instance_name.startswith("dirsrv"):
                # this is intentional, return the empty string if the instance
                # name is 'dirsrv'
                instance_name = instance_name[7:]
            if not instance_name:
                ldapi = False
        if ldapi:
            yield False
            socket_name = paths.SLAPD_INSTANCE_SOCKET_TEMPLATE % instance_name
            ipautil.wait_for_open_socket(
                socket_name, self.api.env.startup_timeout
            )
        else:
            yield wait


class SuseIPAService(SuseService):
    # Credits to upstream developer
    def enable(self, instance_name=""):
        super().enable(instance_name)
        self.restart(instance_name)


class SuseCAService(SuseService):
    # Credits to upstream developer
    def wait_until_running(self):
        logger.debug("Waiting until the CA is running")
        timeout = float(self.api.env.startup_timeout)
        op_timeout = time.time() + timeout
        while time.time() < op_timeout:
            try:
                # check status of CA instance on this host, not remote ca_host
                status = dogtag.ca_status(self.api.env.host)
            except Exception as e:
                status = "check interrupted due to error: %s" % e
            logger.debug("The CA status is: %s", status)
            if status == "running":
                break
            logger.debug("Waiting for CA to start...")
            time.sleep(1)
        else:
            raise RuntimeError("CA did not start in %ss" % timeout)

    def is_running(self, instance_name="", wait=True):
        if instance_name:
            return super().is_running(instance_name)
        try:
            status = dogtag.ca_status()
            if status == "running":
                return True
            elif status == "starting" and wait:
                # Exception is raised if status is 'starting' even after wait
                self.wait_until_running()
                return True
        except Exception as e:
            logger.debug("Failed to check CA status: %s", e)
        return False


# For services which have no SUSE counterpart
class SuseNoService(base_services.PlatformService):
    def start(self):
        pass

    def stop(self):
        pass

    def restart(self):
        pass

    def disable(self):
        pass

def suse_service_class_factory(name, api):
    if name == "dirsrv":
        return SuseDirectoryService(name, api)
    if name == 'domainname':
        return SuseNoService(name, api)
    if name == "ipa":
        return SuseIPAService(name, api)
    if name in ("pki-tomcatd", "pki_tomcatd"):
        return SuseCAService(name, api)
    return SuseService(name, api)


class SuseServices(base_services.KnownServices):
    def service_class_factory(self, name, api=None):
        return suse_service_class_factory(name, api)

    # Credits to upstream developer
    def __init__(self):
        # pylint: disable=ipa-forbidden-import
        import ipalib

        # pylint: enable=ipa-forbidden-import
        services = dict()
        for s in base_services.wellknownservices:
            services[s] = self.service_class_factory(s, ipalib.api)
        super().__init__(services)


timedate_services = base_services.timedate_services
service = suse_service_class_factory
knownservices = SuseServices()