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()
|