Source code for bootils.launcher

# -*- coding: utf-8 -*-
# pylint: disable=bad-continuation
""" Service launcher and processc control.
"""
# Copyright ©  2015 1&1 Group <btw-users@googlegroups.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import absolute_import, unicode_literals, print_function

import grp
import pwd
import signal

# from . import …


[docs]def signal2int(sig_spec): """ Convert given signal specification to its integer value. Parameters: sig_spec (int or str): Either already an int, a number as a string, or a case-insensitive signal name. Returns: int: Signal number. Raises: ValueError: Bad / unknown signal name, or bad input type. """ try: signo = int(sig_spec) except (TypeError, ValueError): try: sig_name = sig_spec.upper() if not sig_name.startswith('SIG'): sig_name = 'SIG' + sig_name signo = getattr(signal, sig_name) except (TypeError, ValueError, AttributeError): raise ValueError('Bad signal specification {!r}'.format(sig_spec)) return signo
[docs]def check_uid(uid): """ Get numerical UID of a user. Raises: KeyError: Unknown user name. """ try: return 0 + uid # already numerical? except TypeError: if uid.isdigit(): return int(uid) else: return pwd.getpwnam(uid).pw_uid
[docs]def check_gid(gid): """ Get numerical GID of a group. Raises: KeyError: Unknown group name. """ try: return 0 + gid # already numerical? except TypeError: if gid.isdigit(): return int(gid) else: return grp.getgrnam(gid).gr_gid
[docs]class LauncherBase(object): """ Process launch & management. """ def __init__(self, config): self.config = config
[docs] def init_environ(self): """ Initialize process environment and return its old state. """ # Note that though we don't change the environment ourselves, # we save it as a service to our derived classes old_umask = None old_cwd = os.getcwd() old_environ = os.environ.copy() try: # Order is important here! umask_str = self.config.get("umask") if umask_str: old_umask = os.umask(int(umask_str, 8)) os.chdir(self.service_base_path) self._snapshot_log_offset() except: # restore state and re-raise if old_umask is not None: os.umask(old_umask) os.chdir(old_cwd) raise else: return old_umask, old_cwd, old_environ
[docs] def restore_environ(self, oldstate): """ Restore process environment to previous state as returned by :py:ref:`init_environ`. """ old_umask, old_cwd, old_environ = oldstate # Handle process parameters if old_umask is not None: os.umask(old_umask) os.chdir(old_cwd) # Handle environment for key, val in old_environ.items(): if os.environ.get(key) != val: #log.trace("Restoring %s=%r" % (key, val)) os.environ[key] = val for key in set(os.environ.keys()) - set(old_environ.keys()): #log.trace("Removing environment variable %s" % (key,)) del os.environ[key]