lliendo/Radar

View on GitHub
radar/platform_setup/__init__.py

Summary

Maintainability
A
40 mins
Test Coverage
# -*- coding: utf-8 -*-

"""
This file is part of Radar.

Radar is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Radar is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Lesser GNU General Public License for more details.

You should have received a copy of the Lesser GNU General Public License
along with Radar. If not, see <http://www.gnu.org/licenses/>.

Copyright 2015 Lucas Liendo.
"""


from abc import ABCMeta
from io import open
from os import getpid, mkdir
from os.path import dirname, isfile as file_exists
from signal import signal, SIGTERM, SIGINT
from platform import system as platform_name
from errno import EEXIST


class UnixSetupError(Exception):
    pass


class Platform(object):

    __metaclass__ = ABCMeta

    SUPPORTED_OS_TYPES = [
        'BSD',
        'Linux',
        'Windows'
    ]

    @staticmethod
    def get_platform_type():
        unixes = ['Linux', 'Darwin', 'FreeBSD', 'NetBSD', 'OpenBSD']
        platform = platform_name()
        return 'Unix' if platform in unixes else platform

    @staticmethod
    def get_os_type():
        bsds = ['Darwin', 'FreeBSD', 'NetBSD', 'OpenBSD']
        platform = platform_name()
        platform = 'BSD' if platform in bsds else platform
        return 'Unknown' if platform not in Platform.SUPPORTED_OS_TYPES else platform


class UnixSetup(object):

    __metaclass__ = ABCMeta

    def __new__(cls, *args, **kwargs):
        try:
            global chown, getpwnam, getgrnam, seteuid, setegid, setgroups
            from os import chown, seteuid, setegid, setgroups
            from pwd import getpwnam
            from grp import getgrnam
        except ImportError as e:
            raise UnixSetupError('Error - Couldn\'t import Unix permission functions. Details : {:}.'.format(e))

        return object.__new__(cls, *args, **kwargs)

    def _create_dir(self, path):
        try:
            mkdir(path)
        except OSError as e:
            if e.errno != EEXIST:
                raise UnixSetupError('Error - Couldn\'t create directory : \'{:}\'. Details : {:}.'.format(
                    path, e.strerror))

    def _write_pid_file(self, pidfile, user, group):
        self._create_dir(dirname(pidfile))

        if file_exists(pidfile):
            raise UnixSetupError('Error - \'{:}\' exists. Process already running ?.'.format(pidfile))

        try:
            with open(pidfile, 'w') as fd:
                fd.write(u'{:}'.format(getpid()))

            chown(pidfile, getpwnam(user).pw_uid, getgrnam(group).gr_gid)
        except IOError as e:
            raise UnixSetupError('Error - Couldn\'t write pidfile \'{:}\'. Details : {:}.'.format(pidfile, e))
        except OSError as e:
            raise UnixSetupError('Error - Couldn\'t change permissions for pidfile \'{:}\'. Details : {:}.'.format(pidfile, e))

    def _install_signal_handlers(self, launcher):
        signal(SIGTERM, launcher.stop)
        signal(SIGINT, launcher.stop)

    def _switch_process_owner(self, user, group):
        try:
            setgroups([])
            setegid(getgrnam(group).gr_gid)
            seteuid(getpwnam(user).pw_uid)
        except OSError as e:
            raise UnixSetupError('Error - Couldn\'t switch process owner \'{:}.{:}\'. Details {:}.'.format(
                user, group, e))
        except KeyError:
            raise UnixSetupError('Error - User or group \'{:}.{:}\' does not exist.'.format(user, group))


class WindowsSetup(object):

    __metaclass__ = ABCMeta

    def _install_signal_handlers(self, launcher):
        signal(SIGTERM, launcher.stop)
        signal(SIGINT, launcher.stop)