saltstack/salt

View on GitHub
salt/utils/systemd.py

Summary

Maintainability
B
4 hrs
Test Coverage
# -*- coding: utf-8 -*-
'''
Contains systemd related help files
'''
# import python libs
from __future__ import absolute_import, print_function, unicode_literals
import logging
import os
import re
import subprocess

# Import Salt libs
from salt.exceptions import SaltInvocationError
import salt.utils.stringutils

log = logging.getLogger(__name__)


def booted(context=None):
    '''
    Return True if the system was booted with systemd, False otherwise.  If the
    loader context dict ``__context__`` is passed, this function will set the
    ``salt.utils.systemd.booted`` key to represent if systemd is running and
    keep the logic below from needing to be run again during the same salt run.
    '''
    contextkey = 'salt.utils.systemd.booted'
    if isinstance(context, dict):
        # Can't put this if block on the same line as the above if block,
        # because it willl break the elif below.
        if contextkey in context:
            return context[contextkey]
    elif context is not None:
        raise SaltInvocationError('context must be a dictionary if passed')

    try:
        # This check does the same as sd_booted() from libsystemd-daemon:
        # http://www.freedesktop.org/software/systemd/man/sd_booted.html
        ret = bool(os.stat('/run/systemd/system'))
    except OSError:
        ret = False

    try:
        context[contextkey] = ret
    except TypeError:
        pass

    return ret


def version(context=None):
    '''
    Attempts to run systemctl --version. Returns None if unable to determine
    version.
    '''
    contextkey = 'salt.utils.systemd.version'
    if isinstance(context, dict):
        # Can't put this if block on the same line as the above if block,
        # because it will break the elif below.
        if contextkey in context:
            return context[contextkey]
    elif context is not None:
        raise SaltInvocationError('context must be a dictionary if passed')
    stdout = subprocess.Popen(
        ['systemctl', '--version'],
        close_fds=True,
        stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()[0]
    outstr = salt.utils.stringutils.to_str(stdout)
    try:
        ret = int(re.search(r'\w+ ([0-9]+)', outstr.splitlines()[0]).group(1))
    except (AttributeError, IndexError, ValueError):
        log.error(
            'Unable to determine systemd version from systemctl '
            '--version, output follows:\n%s', outstr
        )
        return None
    else:
        try:
            context[contextkey] = ret
        except TypeError:
            pass
        return ret


def has_scope(context=None):
    '''
    Scopes were introduced in systemd 205, this function returns a boolean
    which is true when the minion is systemd-booted and running systemd>=205.
    '''
    if not booted(context):
        return False
    _sd_version = version(context)
    if _sd_version is None:
        return False
    return _sd_version >= 205