mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 00:55:19 +00:00
Move some functions into mac_utils
This commit is contained in:
parent
125586264b
commit
455146500a
@ -8,14 +8,13 @@ from __future__ import absolute_import, unicode_literals, print_function
|
||||
# Import python libs
|
||||
import os
|
||||
import re
|
||||
import plistlib
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils.decorators as decorators
|
||||
import salt.utils.files
|
||||
import salt.utils.path
|
||||
import salt.utils.platform
|
||||
import salt.utils.stringutils
|
||||
import salt.utils.mac_utils
|
||||
from salt.exceptions import CommandExecutionError
|
||||
from salt.utils.versions import LooseVersion as _LooseVersion
|
||||
|
||||
@ -53,73 +52,6 @@ def __virtual__():
|
||||
return __virtualname__
|
||||
|
||||
|
||||
def _launchd_paths():
|
||||
'''
|
||||
Paths where launchd services can be found
|
||||
'''
|
||||
return [
|
||||
'/Library/LaunchAgents',
|
||||
'/Library/LaunchDaemons',
|
||||
'/System/Library/LaunchAgents',
|
||||
'/System/Library/LaunchDaemons',
|
||||
]
|
||||
|
||||
|
||||
@decorators.memoize
|
||||
def _available_services():
|
||||
'''
|
||||
Return a dictionary of all available services on the system
|
||||
'''
|
||||
available_services = dict()
|
||||
for launch_dir in _launchd_paths():
|
||||
for root, dirs, files in salt.utils.path.os_walk(launch_dir):
|
||||
for file_name in files:
|
||||
|
||||
# Must be a plist file
|
||||
if not file_name.endswith('.plist'):
|
||||
continue
|
||||
|
||||
# Follow symbolic links of files in _launchd_paths
|
||||
file_path = os.path.join(root, file_name)
|
||||
true_path = os.path.realpath(file_path)
|
||||
|
||||
# ignore broken symlinks
|
||||
if not os.path.exists(true_path):
|
||||
continue
|
||||
|
||||
try:
|
||||
# This assumes most of the plist files
|
||||
# will be already in XML format
|
||||
with salt.utils.files.fopen(file_path):
|
||||
plist = plistlib.readPlist(true_path)
|
||||
|
||||
except Exception:
|
||||
# If plistlib is unable to read the file we'll need to use
|
||||
# the system provided plutil program to do the conversion
|
||||
cmd = '/usr/bin/plutil -convert xml1 -o - -- "{0}"'.format(
|
||||
true_path)
|
||||
plist_xml = __salt__['cmd.run'](cmd, output_loglevel='quiet')
|
||||
if six.PY2:
|
||||
plist = plistlib.readPlistFromString(plist_xml)
|
||||
else:
|
||||
plist = plistlib.readPlistFromBytes(
|
||||
salt.utils.stringutils.to_bytes(plist_xml))
|
||||
|
||||
try:
|
||||
available_services[plist.Label.lower()] = {
|
||||
'file_name': file_name,
|
||||
'file_path': true_path,
|
||||
'plist': plist}
|
||||
except AttributeError:
|
||||
# Handle malformed plist files
|
||||
available_services[os.path.basename(file_name).lower()] = {
|
||||
'file_name': file_name,
|
||||
'file_path': true_path,
|
||||
'plist': plist}
|
||||
|
||||
return available_services
|
||||
|
||||
|
||||
def _get_service(name):
|
||||
'''
|
||||
Get information about a service. If the service is not found, raise an
|
||||
@ -130,7 +62,7 @@ def _get_service(name):
|
||||
:return: The service information for the service, otherwise an Error
|
||||
:rtype: dict
|
||||
'''
|
||||
services = _available_services()
|
||||
services = salt.utils.mac_utils.available_services()
|
||||
name = name.lower()
|
||||
|
||||
if name in services:
|
||||
@ -195,26 +127,7 @@ def launchctl(sub_cmd, *args, **kwargs):
|
||||
|
||||
salt '*' service.launchctl debug org.cups.cupsd
|
||||
'''
|
||||
# Get return type
|
||||
return_stdout = kwargs.pop('return_stdout', False)
|
||||
|
||||
# Construct command
|
||||
cmd = ['launchctl', sub_cmd]
|
||||
cmd.extend(args)
|
||||
|
||||
# Run command
|
||||
kwargs['python_shell'] = False
|
||||
ret = __salt__['cmd.run_all'](cmd, **kwargs)
|
||||
|
||||
# Raise an error or return successful result
|
||||
if ret['retcode']:
|
||||
out = 'Failed to {0} service:\n'.format(sub_cmd)
|
||||
out += 'stdout: {0}\n'.format(ret['stdout'])
|
||||
out += 'stderr: {0}\n'.format(ret['stderr'])
|
||||
out += 'retcode: {0}\n'.format(ret['retcode'])
|
||||
raise CommandExecutionError(out)
|
||||
else:
|
||||
return ret['stdout'] if return_stdout else True
|
||||
return salt.utils.mac_utils.launchctl(sub_cmd=sub_cmd, *args, *kwargs)
|
||||
|
||||
|
||||
def list_(name=None, runas=None):
|
||||
@ -541,7 +454,7 @@ def get_all(runas=None):
|
||||
enabled = get_enabled(runas=runas)
|
||||
|
||||
# Get list of all services
|
||||
available = list(_available_services().keys())
|
||||
available = list(salt.utils.mac_utils.available_services().keys())
|
||||
|
||||
# Return composite list
|
||||
return sorted(set(enabled + available))
|
||||
|
@ -8,6 +8,7 @@ System module for sleeping, restarting, and shutting down the system on Mac OS X
|
||||
Using this module will enable ``atrun`` on the system if it is disabled.
|
||||
'''
|
||||
from __future__ import absolute_import, unicode_literals, print_function
|
||||
import os
|
||||
|
||||
# Import python libs
|
||||
try: # python 3
|
||||
@ -18,9 +19,10 @@ except ImportError: # python 2
|
||||
import getpass
|
||||
|
||||
# Import salt libs
|
||||
from salt.ext import six
|
||||
import salt.utils.mac_utils
|
||||
import salt.utils.platform
|
||||
from salt.exceptions import SaltInvocationError
|
||||
from salt.exceptions import SaltInvocationError, CommandExecutionError
|
||||
|
||||
__virtualname__ = 'system'
|
||||
|
||||
@ -47,15 +49,71 @@ def _atrun_enabled():
|
||||
'''
|
||||
Check to see if atrun is enabled on the system
|
||||
'''
|
||||
return __salt__['service.enabled']('com.apple.atrun')
|
||||
name = 'com.apple.atrun'
|
||||
services = salt.utils.mac_utils.available_services()
|
||||
label = None
|
||||
|
||||
if name in services:
|
||||
label = services[name]['plist']['Label']
|
||||
else:
|
||||
for service in six.itervalues(services):
|
||||
if service['file_path'].lower() == name:
|
||||
# Match on full path
|
||||
label = service['plist']['Label']
|
||||
break
|
||||
basename, ext = os.path.splitext(service['file_name'])
|
||||
if basename.lower() == name:
|
||||
# Match on basename
|
||||
label = service['plist']['Label']
|
||||
break
|
||||
|
||||
if not label:
|
||||
return False
|
||||
|
||||
try:
|
||||
# Collect information on service: will raise an error if it fails
|
||||
salt.utils.mac_utils.launchctl('list',
|
||||
label,
|
||||
return_stdout=True,
|
||||
output_loglevel='quiet')
|
||||
return True
|
||||
except CommandExecutionError:
|
||||
return False
|
||||
|
||||
|
||||
def _enable_atrun():
|
||||
'''
|
||||
Enable and start the atrun daemon
|
||||
'''
|
||||
__salt__['service.enable']('com.apple.atrun')
|
||||
__salt__['service.start']('com.apple.atrun')
|
||||
name = 'com.apple.atrun'
|
||||
services = salt.utils.mac_utils.available_services()
|
||||
label = None
|
||||
path = None
|
||||
|
||||
if name in services:
|
||||
label = services[name]['plist']['Label']
|
||||
path = services[name]['file_path']
|
||||
else:
|
||||
for service in six.itervalues(services):
|
||||
if service['file_path'].lower() == name:
|
||||
# Match on full path
|
||||
label = service['plist']['Label']
|
||||
path = service['file_path']
|
||||
break
|
||||
basename, ext = os.path.splitext(service['file_name'])
|
||||
if basename.lower() == name:
|
||||
# Match on basename
|
||||
label = service['plist']['Label']
|
||||
path = service['file_path']
|
||||
break
|
||||
|
||||
if not label:
|
||||
return False
|
||||
|
||||
salt.utils.mac_utils.launchctl('enable',
|
||||
'system/{0}'.format(label),
|
||||
output_loglevel='quiet')
|
||||
salt.utils.mac_utils.launchctl('load', path, output_loglevel='quiet')
|
||||
return _atrun_enabled()
|
||||
|
||||
|
||||
|
@ -1,572 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
The service salt util for macOS
|
||||
.. versionadded:: 2016.11.10
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
import logging
|
||||
|
||||
# Import python libs
|
||||
import os
|
||||
import re
|
||||
import plistlib
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
import salt.utils.decorators as decorators
|
||||
from salt.exceptions import CommandExecutionError
|
||||
|
||||
# Import 3rd party libs
|
||||
import salt.ext.six as six
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
LAUNCHD_PATHS = [
|
||||
'/Library/LaunchAgents',
|
||||
'/Library/LaunchDaemons',
|
||||
'/System/Library/LaunchAgents',
|
||||
'/System/Library/LaunchDaemons',
|
||||
]
|
||||
|
||||
__func_alias__ = {
|
||||
'list_': 'list',
|
||||
}
|
||||
|
||||
|
||||
@decorators.memoize
|
||||
def _available_services():
|
||||
'''
|
||||
Return a dictionary of all available services on the system
|
||||
'''
|
||||
available_services = dict()
|
||||
for launch_dir in LAUNCHD_PATHS:
|
||||
for root, dirs, files in os.walk(launch_dir):
|
||||
for file_name in files:
|
||||
|
||||
# Must be a plist file
|
||||
if not file_name.endswith('.plist'):
|
||||
continue
|
||||
|
||||
# Follow symbolic links of files in LAUNCHD_PATHS
|
||||
file_path = os.path.join(root, file_name)
|
||||
true_path = os.path.realpath(file_path)
|
||||
|
||||
# ignore broken symlinks
|
||||
if not os.path.exists(true_path):
|
||||
continue
|
||||
|
||||
try:
|
||||
# This assumes most of the plist files
|
||||
# will be already in XML format
|
||||
with salt.utils.fopen(file_path):
|
||||
plist = plistlib.readPlist(true_path)
|
||||
|
||||
except Exception:
|
||||
# If plistlib is unable to read the file we'll need to use
|
||||
# the system provided plutil program to do the conversion
|
||||
cmd = '/usr/bin/plutil -convert xml1 -o - -- "{0}"'.format(
|
||||
true_path)
|
||||
plist_xml = __salt__['cmd.run'](cmd, output_loglevel='quiet')
|
||||
if six.PY2:
|
||||
plist = plistlib.readPlistFromString(plist_xml)
|
||||
else:
|
||||
plist = plistlib.readPlistFromBytes(
|
||||
salt.utils.to_bytes(plist_xml))
|
||||
|
||||
try:
|
||||
available_services[plist.Label.lower()] = {
|
||||
'file_name': file_name,
|
||||
'file_path': true_path,
|
||||
'plist': plist}
|
||||
except AttributeError:
|
||||
# Handle malformed plist files
|
||||
available_services[os.path.basename(file_name).lower()] = {
|
||||
'file_name': file_name,
|
||||
'file_path': true_path,
|
||||
'plist': plist}
|
||||
|
||||
return available_services
|
||||
|
||||
|
||||
def _get_service(name):
|
||||
'''
|
||||
Get information about a service. If the service is not found, raise an
|
||||
error
|
||||
|
||||
Args:
|
||||
name (str): Service label, file name, or full path
|
||||
|
||||
Returns:
|
||||
dict: The service information for the service
|
||||
|
||||
Raises:
|
||||
CommandExecutionError: If service is not found
|
||||
'''
|
||||
services = _available_services()
|
||||
name = name.lower()
|
||||
|
||||
if name in services:
|
||||
# Match on label
|
||||
return services[name]
|
||||
|
||||
for service in six.itervalues(services):
|
||||
if service['file_path'].lower() == name:
|
||||
# Match on full path
|
||||
return service
|
||||
basename, ext = os.path.splitext(service['file_name'])
|
||||
if basename.lower() == name:
|
||||
# Match on basename
|
||||
return service
|
||||
|
||||
# Could not find service
|
||||
raise CommandExecutionError('Service not found: {0}'.format(name))
|
||||
|
||||
|
||||
def show(name):
|
||||
'''
|
||||
Show properties of a launchctl service
|
||||
|
||||
Args:
|
||||
name (str): Service label, file name, or full path
|
||||
|
||||
Returns:
|
||||
dict: The service information if the service is found
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
import salt.utils.mac_service
|
||||
salt.utils.mac_service.show('org.cups.cupsd') # service label
|
||||
salt.utils.mac_service.show('org.cups.cupsd.plist') # file name
|
||||
salt.utils.mac_service.show('/System/Library/LaunchDaemons/org.cups.cupsd.plist') # full path
|
||||
'''
|
||||
return _get_service(name)
|
||||
|
||||
|
||||
def launchctl(sub_cmd, *args, **kwargs):
|
||||
'''
|
||||
Run a launchctl command and raise an error if it fails
|
||||
|
||||
Args: additional args are passed to launchctl
|
||||
sub_cmd (str): Sub command supplied to launchctl
|
||||
|
||||
Kwargs: passed to ``cmd.run_all``
|
||||
return_stdout (bool): A keyword argument. If true return the stdout of
|
||||
the launchctl command
|
||||
|
||||
Returns:
|
||||
bool: ``True`` if successful
|
||||
str: The stdout of the launchctl command if requested
|
||||
|
||||
Raises:
|
||||
CommandExecutionError: Tf command fails
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
import salt.utils.mac_service
|
||||
salt.utils.mac_service.launchctl('debug', 'org.cups.cupsd')
|
||||
'''
|
||||
# Get return type
|
||||
return_stdout = kwargs.pop('return_stdout', False)
|
||||
|
||||
# Construct command
|
||||
cmd = ['launchctl', sub_cmd]
|
||||
cmd.extend(args)
|
||||
|
||||
# Run command
|
||||
kwargs['python_shell'] = False
|
||||
ret = __salt__['cmd.run_all'](cmd, **kwargs)
|
||||
|
||||
# Raise an error or return successful result
|
||||
if ret['retcode']:
|
||||
out = 'Failed to {0} service:\n'.format(sub_cmd)
|
||||
out += 'stdout: {0}\n'.format(ret['stdout'])
|
||||
out += 'stderr: {0}\n'.format(ret['stderr'])
|
||||
out += 'retcode: {0}\n'.format(ret['retcode'])
|
||||
raise CommandExecutionError(out)
|
||||
else:
|
||||
return ret['stdout'] if return_stdout else True
|
||||
|
||||
|
||||
def list_(name=None, runas=None):
|
||||
'''
|
||||
Run launchctl list and return the output
|
||||
|
||||
Args:
|
||||
name (str): The name of the service to list
|
||||
runas (str): User to run launchctl commands
|
||||
|
||||
Returns:
|
||||
str: If a name is passed returns information about the named service,
|
||||
otherwise returns a list of all services and pids
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
import salt.utils.mac_service
|
||||
salt.utils.mac_service.list()
|
||||
salt.utils.mac_service.list('org.cups.cupsd')
|
||||
'''
|
||||
if name:
|
||||
# Get service information and label
|
||||
service = _get_service(name)
|
||||
label = service['plist']['Label']
|
||||
|
||||
# Collect information on service: will raise an error if it fails
|
||||
return launchctl('list',
|
||||
label,
|
||||
return_stdout=True,
|
||||
output_loglevel='trace',
|
||||
runas=runas)
|
||||
|
||||
# Collect information on all services: will raise an error if it fails
|
||||
return launchctl('list',
|
||||
return_stdout=True,
|
||||
output_loglevel='trace',
|
||||
runas=runas)
|
||||
|
||||
|
||||
def enable(name, runas=None):
|
||||
'''
|
||||
Enable a launchd service. Raises an error if the service fails to be enabled
|
||||
|
||||
Args:
|
||||
name (str): Service label, file name, or full path
|
||||
runas (str): User to run launchctl commands
|
||||
|
||||
Returns:
|
||||
bool: ``True`` if successful or if the service is already enabled
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
import salt.utils.mac_service
|
||||
salt.utils.mac_service.enable('org.cups.cupsd')
|
||||
'''
|
||||
# Get service information and label
|
||||
service = _get_service(name)
|
||||
label = service['plist']['Label']
|
||||
|
||||
# Enable the service: will raise an error if it fails
|
||||
return launchctl('enable', 'system/{0}'.format(label), runas=runas)
|
||||
|
||||
|
||||
def disable(name, runas=None):
|
||||
'''
|
||||
Disable a launchd service. Raises an error if the service fails to be
|
||||
disabled
|
||||
|
||||
Args:
|
||||
name (str): Service label, file name, or full path
|
||||
runas (str): User to run launchctl commands
|
||||
|
||||
Returns:
|
||||
bool: ``True`` if successful or if the service is already disabled
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
import salt.utils.mac_service
|
||||
salt.utils.mac_service.disable('org.cups.cupsd')
|
||||
'''
|
||||
# Get service information and label
|
||||
service = _get_service(name)
|
||||
label = service['plist']['Label']
|
||||
|
||||
# disable the service: will raise an error if it fails
|
||||
return launchctl('disable', 'system/{0}'.format(label), runas=runas)
|
||||
|
||||
|
||||
def start(name, runas=None):
|
||||
'''
|
||||
Start a launchd service. Raises an error if the service fails to start
|
||||
|
||||
.. note::
|
||||
To start a service in macOS the service must be enabled first. Use
|
||||
``service.enable`` to enable the service.
|
||||
|
||||
Args:
|
||||
name (str): Service label, file name, or full path
|
||||
runas (str): User to run launchctl commands
|
||||
|
||||
Returns:
|
||||
bool: ``True`` if successful or if the service is already running
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
import salt.utils.mac_service
|
||||
salt.utils.mac_service.start('org.cups.cupsd')
|
||||
'''
|
||||
# Get service information and file path
|
||||
service = _get_service(name)
|
||||
path = service['file_path']
|
||||
|
||||
# Load the service: will raise an error if it fails
|
||||
return launchctl('load', path, runas=runas)
|
||||
|
||||
|
||||
def stop(name, runas=None):
|
||||
'''
|
||||
Stop a launchd service. Raises an error if the service fails to stop
|
||||
|
||||
.. note::
|
||||
Though ``service.stop`` will unload a service in macOS, the service
|
||||
will start on next boot unless it is disabled. Use ``service.disable``
|
||||
to disable the service
|
||||
|
||||
Args:
|
||||
name (str): Service label, file name, or full path
|
||||
runas (str): User to run launchctl commands
|
||||
|
||||
Return:
|
||||
bool: ``True`` if successful or if the service is already stopped
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
import salt.utils.mac_service
|
||||
salt.utils.mac_service.stop('org.cups.cupsd')
|
||||
'''
|
||||
# Get service information and file path
|
||||
service = _get_service(name)
|
||||
path = service['file_path']
|
||||
|
||||
# Disable the Launch Daemon: will raise an error if it fails
|
||||
return launchctl('unload', path, runas=runas)
|
||||
|
||||
|
||||
def restart(name, runas=None):
|
||||
'''
|
||||
Unloads and reloads a launchd service. Raises an error if the service
|
||||
fails to reload
|
||||
|
||||
Args:
|
||||
name (str): Service label, file name, or full path
|
||||
runas (str): User to run launchctl commands
|
||||
|
||||
Returns:
|
||||
bool: ``True`` if successful
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
import salt.utils.mac_service
|
||||
salt.utils.mac_service.restart('org.cups.cupsd')
|
||||
'''
|
||||
# Restart the service: will raise an error if it fails
|
||||
if enabled(name):
|
||||
stop(name, runas=runas)
|
||||
start(name, runas=runas)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def status(name, sig=None, runas=None):
|
||||
'''
|
||||
Return the status for a service.
|
||||
|
||||
Args:
|
||||
name (str): Used to find the service from launchctl. Can be any part of
|
||||
the service name or a regex expression.
|
||||
|
||||
sig (str): Find the service with status.pid instead. Note that ``name``
|
||||
must still be provided.
|
||||
|
||||
runas (str): User to run launchctl commands
|
||||
|
||||
Returns:
|
||||
str: The PID for the service if it is running, otherwise an empty string
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
import salt.utils.mac_service
|
||||
salt.utils.mac_service.status('cups')
|
||||
'''
|
||||
# Find service with ps
|
||||
if sig:
|
||||
return __salt__['status.pid'](sig)
|
||||
|
||||
output = list_(runas=runas)
|
||||
|
||||
# Used a string here instead of a list because that's what the linux version
|
||||
# of this module does
|
||||
pids = ''
|
||||
for line in output.splitlines():
|
||||
if 'PID' in line:
|
||||
continue
|
||||
if re.search(name, line):
|
||||
if line.split()[0].isdigit():
|
||||
if pids:
|
||||
pids += '\n'
|
||||
pids += line.split()[0]
|
||||
|
||||
return pids
|
||||
|
||||
|
||||
def available(name):
|
||||
'''
|
||||
Check that the given service is available.
|
||||
|
||||
Args:
|
||||
name (str): The name of the service
|
||||
|
||||
Returns:
|
||||
bool: True if the service is available, otherwise False
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
import salt.utils.mac_service
|
||||
salt.utils.mac_service.available('com.openssh.sshd')
|
||||
'''
|
||||
try:
|
||||
_get_service(name)
|
||||
return True
|
||||
except CommandExecutionError:
|
||||
return False
|
||||
|
||||
|
||||
def missing(name):
|
||||
'''
|
||||
The inverse of service.available
|
||||
Check that the given service is not available.
|
||||
|
||||
Args:
|
||||
name (str): The name of the service
|
||||
|
||||
Returns:
|
||||
bool: True if the service is not available, otherwise False
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
import salt.utils.mac_service
|
||||
salt.utils.mac_service.missing('com.openssh.sshd')
|
||||
'''
|
||||
return not available(name)
|
||||
|
||||
|
||||
def enabled(name, runas=None):
|
||||
'''
|
||||
Check if the specified service is enabled
|
||||
|
||||
Args:
|
||||
name (str): The name of the service to look up
|
||||
runas (str): User to run launchctl commands
|
||||
|
||||
Returns:
|
||||
bool: True if the specified service enabled, otherwise False
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
import salt.utils.mac_service
|
||||
salt.utils.mac_service.enabled('org.cups.cupsd')
|
||||
'''
|
||||
# Try to list the service. If it can't be listed, it's not enabled
|
||||
try:
|
||||
list_(name=name, runas=runas)
|
||||
return True
|
||||
except CommandExecutionError:
|
||||
return False
|
||||
|
||||
|
||||
def disabled(name, runas=None):
|
||||
'''
|
||||
Check if the specified service is not enabled. This is the opposite of
|
||||
``service.enabled``
|
||||
|
||||
Args:
|
||||
name (str): The name to look up
|
||||
runas (str): User to run launchctl commands
|
||||
|
||||
Returns:
|
||||
bool: True if the specified service is NOT enabled, otherwise False
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
import salt.utils.mac_service
|
||||
salt.utils.mac_service.disabled('org.cups.cupsd')
|
||||
'''
|
||||
# A service is disabled if it is not enabled
|
||||
return not enabled(name, runas=runas)
|
||||
|
||||
|
||||
def get_all(runas=None):
|
||||
'''
|
||||
Return a list of services that are enabled or available. Can be used to
|
||||
find the name of a service.
|
||||
|
||||
Args:
|
||||
runas (str): User to run launchctl commands
|
||||
|
||||
Return:
|
||||
list: A list of all the services available or enabled
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
import salt.utils.mac_service
|
||||
salt.utils.mac_service.get_all()
|
||||
'''
|
||||
# Get list of enabled services
|
||||
enabled = get_enabled(runas=runas)
|
||||
|
||||
# Get list of all services
|
||||
available = list(_available_services().keys())
|
||||
|
||||
# Return composite list
|
||||
return sorted(set(enabled + available))
|
||||
|
||||
|
||||
def get_enabled(runas=None):
|
||||
'''
|
||||
Return a list of all services that are enabled. Can be used to find the
|
||||
name of a service.
|
||||
|
||||
Args:
|
||||
runas (str): User to run launchctl commands
|
||||
|
||||
Returns:
|
||||
list: A list of all the services enabled on the system
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
import salt.utils.mac_service
|
||||
salt.utils.mac_service.get_enabled()
|
||||
'''
|
||||
# Collect list of enabled services
|
||||
stdout = list_(runas=runas)
|
||||
service_lines = [line for line in stdout.splitlines()]
|
||||
|
||||
# Construct list of enabled services
|
||||
enabled = []
|
||||
for line in service_lines:
|
||||
# Skip header line
|
||||
if line.startswith('PID'):
|
||||
continue
|
||||
|
||||
pid, status, label = line.split('\t')
|
||||
enabled.append(label)
|
||||
|
||||
return sorted(set(enabled))
|
@ -9,15 +9,19 @@ from __future__ import absolute_import, unicode_literals
|
||||
import logging
|
||||
import subprocess
|
||||
import os
|
||||
import plistlib
|
||||
import time
|
||||
|
||||
# Import Salt Libs
|
||||
import salt.modules.cmdmod
|
||||
import salt.utils.args
|
||||
import salt.utils.decorators as decorators
|
||||
import salt.utils.files
|
||||
import salt.utils.path
|
||||
import salt.utils.platform
|
||||
import salt.utils.stringutils
|
||||
import salt.utils.timed_subprocess
|
||||
import salt.grains.extra
|
||||
from salt.ext import six
|
||||
from salt.exceptions import CommandExecutionError, SaltInvocationError,\
|
||||
TimedProcTimeoutError
|
||||
|
||||
@ -227,3 +231,121 @@ def confirm_updated(value, check_fun, normalize_ret=False, wait=5):
|
||||
return True
|
||||
time.sleep(1)
|
||||
return False
|
||||
|
||||
|
||||
def launchctl(sub_cmd, *args, **kwargs):
|
||||
'''
|
||||
Run a launchctl command and raise an error if it fails
|
||||
|
||||
Args: additional args are passed to launchctl
|
||||
sub_cmd (str): Sub command supplied to launchctl
|
||||
|
||||
Kwargs: passed to ``cmd.run_all``
|
||||
return_stdout (bool): A keyword argument. If true return the stdout of
|
||||
the launchctl command
|
||||
|
||||
Returns:
|
||||
bool: ``True`` if successful
|
||||
str: The stdout of the launchctl command if requested
|
||||
|
||||
Raises:
|
||||
CommandExecutionError: If command fails
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
import salt.utils.mac_service
|
||||
salt.utils.mac_service.launchctl('debug', 'org.cups.cupsd')
|
||||
'''
|
||||
# Get return type
|
||||
return_stdout = kwargs.pop('return_stdout', False)
|
||||
|
||||
# Construct command
|
||||
cmd = ['launchctl', sub_cmd]
|
||||
cmd.extend(args)
|
||||
|
||||
# Run command
|
||||
kwargs['python_shell'] = False
|
||||
ret = salt.modules.cmdmod.run_all(cmd, **kwargs)
|
||||
|
||||
# Raise an error or return successful result
|
||||
if ret['retcode']:
|
||||
out = 'Failed to {0} service:\n'.format(sub_cmd)
|
||||
out += 'stdout: {0}\n'.format(ret['stdout'])
|
||||
out += 'stderr: {0}\n'.format(ret['stderr'])
|
||||
out += 'retcode: {0}\n'.format(ret['retcode'])
|
||||
raise CommandExecutionError(out)
|
||||
else:
|
||||
return ret['stdout'] if return_stdout else True
|
||||
|
||||
|
||||
@decorators.memoize
|
||||
def available_services():
|
||||
'''
|
||||
Return a dictionary of all available services on the system
|
||||
|
||||
Returns:
|
||||
dict: All available services
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
import salt.utils.mac_service
|
||||
salt.utils.mac_service.available_services()
|
||||
'''
|
||||
launchd_paths = [
|
||||
'/Library/LaunchAgents',
|
||||
'/Library/LaunchDaemons',
|
||||
'/System/Library/LaunchAgents',
|
||||
'/System/Library/LaunchDaemons',
|
||||
]
|
||||
_available_services = dict()
|
||||
for launch_dir in launchd_paths:
|
||||
for root, dirs, files in salt.utils.path.os_walk(launch_dir):
|
||||
for file_name in files:
|
||||
|
||||
# Must be a plist file
|
||||
if not file_name.endswith('.plist'):
|
||||
continue
|
||||
|
||||
# Follow symbolic links of files in _launchd_paths
|
||||
file_path = os.path.join(root, file_name)
|
||||
true_path = os.path.realpath(file_path)
|
||||
|
||||
# ignore broken symlinks
|
||||
if not os.path.exists(true_path):
|
||||
continue
|
||||
|
||||
try:
|
||||
# This assumes most of the plist files
|
||||
# will be already in XML format
|
||||
with salt.utils.files.fopen(file_path):
|
||||
plist = plistlib.readPlist(true_path)
|
||||
|
||||
except Exception:
|
||||
# If plistlib is unable to read the file we'll need to use
|
||||
# the system provided plutil program to do the conversion
|
||||
cmd = '/usr/bin/plutil -convert xml1 -o - -- "{0}"'.format(
|
||||
true_path)
|
||||
plist_xml = salt.modules.cmdmod.run(cmd, output_loglevel='quiet')
|
||||
if six.PY2:
|
||||
plist = plistlib.readPlistFromString(plist_xml)
|
||||
else:
|
||||
plist = plistlib.readPlistFromBytes(
|
||||
salt.utils.stringutils.to_bytes(plist_xml))
|
||||
|
||||
try:
|
||||
_available_services[plist.Label.lower()] = {
|
||||
'file_name': file_name,
|
||||
'file_path': true_path,
|
||||
'plist': plist}
|
||||
except AttributeError:
|
||||
# Handle malformed plist files
|
||||
_available_services[os.path.basename(file_name).lower()] = {
|
||||
'file_name': file_name,
|
||||
'file_path': true_path,
|
||||
'plist': plist}
|
||||
|
||||
return _available_services
|
||||
|
Loading…
Reference in New Issue
Block a user