mirror of
https://github.com/valitydev/salt.git
synced 2024-11-08 01:18:58 +00:00
Merge pull request #47256 from weswhet/add-mac_service-update
add macOS mac_service update.
This commit is contained in:
commit
de84f6fbd6
@ -2,6 +2,24 @@
|
||||
'''
|
||||
The service module for macOS
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
This module has support for services in the following locations.
|
||||
|
||||
.. code-block:: bash
|
||||
/System/Library/LaunchDaemons/
|
||||
/System/Library/LaunchAgents/
|
||||
/Library/LaunchDaemons/
|
||||
/Library/LaunchAgents/
|
||||
|
||||
# As of version "Fluorine" support for user-specific services were added.
|
||||
/Users/foo/Library/LaunchAgents/
|
||||
|
||||
.. note::
|
||||
|
||||
As of version "Fluorine", if a service is located in a ``LaunchAgent`` path
|
||||
and a ``runas`` user is NOT specified the current console user will be used
|
||||
to properly interact with the service.
|
||||
|
||||
'''
|
||||
from __future__ import absolute_import, unicode_literals, print_function
|
||||
|
||||
@ -62,7 +80,7 @@ def _get_service(name):
|
||||
:return: The service information for the service, otherwise an Error
|
||||
:rtype: dict
|
||||
'''
|
||||
services = salt.utils.mac_utils.available_services()
|
||||
services = __utils__['mac_utils.available_services']()
|
||||
name = name.lower()
|
||||
|
||||
if name in services:
|
||||
@ -113,6 +131,68 @@ def _always_running_service(name):
|
||||
return False
|
||||
|
||||
|
||||
def _get_domain_target(name, service_target=False):
|
||||
'''
|
||||
Returns the domain/service target and path for a service. This is used to
|
||||
determine whether or not a service should be loaded in a user space or
|
||||
system space.
|
||||
|
||||
:param str name: Service label, file name, or full path
|
||||
|
||||
:param bool service_target: Whether to return a full
|
||||
service target. This is needed for the enable and disable
|
||||
subcommands of /bin/launchctl. Defaults to False
|
||||
|
||||
:return: Tuple of the domain/service target and the path to the service.
|
||||
|
||||
:rtype: tuple
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
'''
|
||||
|
||||
# Get service information
|
||||
service = _get_service(name)
|
||||
|
||||
# get the path to the service
|
||||
path = service['file_path']
|
||||
|
||||
# most of the time we'll be at the system level.
|
||||
domain_target = 'system'
|
||||
|
||||
# check if a LaunchAgent as we should treat these differently.
|
||||
if 'LaunchAgents' in path:
|
||||
# Get the console user so we can service in the correct session
|
||||
uid = __utils__['mac_utils.console_user']()
|
||||
domain_target = 'gui/{}'.format(uid)
|
||||
|
||||
# check to see if we need to make it a full service target.
|
||||
if service_target is True:
|
||||
domain_target = '{}/{}'.format(domain_target, service['plist']['Label'])
|
||||
|
||||
return (domain_target, path)
|
||||
|
||||
|
||||
def _launch_agent(name):
|
||||
'''
|
||||
Checks to see if the provided service is a LaunchAgent
|
||||
|
||||
:param str name: Service label, file name, or full path
|
||||
|
||||
:return: True if a LaunchAgent, False if not.
|
||||
|
||||
:rtype: bool
|
||||
|
||||
.. versionadded:: Fluorine
|
||||
'''
|
||||
|
||||
# Get the path to the service.
|
||||
path = _get_service(name)['file_path']
|
||||
|
||||
if 'LaunchAgents' not in path:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def show(name):
|
||||
'''
|
||||
Show properties of a launchctl service
|
||||
@ -158,7 +238,7 @@ def launchctl(sub_cmd, *args, **kwargs):
|
||||
|
||||
salt '*' service.launchctl debug org.cups.cupsd
|
||||
'''
|
||||
return salt.utils.mac_utils.launchctl(sub_cmd, *args, **kwargs)
|
||||
return __utils__['mac_utils.launchctl'](sub_cmd, *args, **kwargs)
|
||||
|
||||
|
||||
def list_(name=None, runas=None):
|
||||
@ -185,6 +265,11 @@ def list_(name=None, runas=None):
|
||||
service = _get_service(name)
|
||||
label = service['plist']['Label']
|
||||
|
||||
# we can assume if we are trying to list a LaunchAgent we need
|
||||
# to run as a user, if not provided, we'll use the console user.
|
||||
if not runas and _launch_agent(name):
|
||||
runas = __utils__['mac_utils.console_user'](username=True)
|
||||
|
||||
# Collect information on service: will raise an error if it fails
|
||||
return launchctl('list',
|
||||
label,
|
||||
@ -216,12 +301,11 @@ def enable(name, runas=None):
|
||||
|
||||
salt '*' service.enable org.cups.cupsd
|
||||
'''
|
||||
# Get service information and label
|
||||
service = _get_service(name)
|
||||
label = service['plist']['Label']
|
||||
# Get the domain target. enable requires a full <service-target>
|
||||
service_target = _get_domain_target(name, service_target=True)[0]
|
||||
|
||||
# Enable the service: will raise an error if it fails
|
||||
return launchctl('enable', 'system/{0}'.format(label), runas=runas)
|
||||
return launchctl('enable', service_target, runas=runas)
|
||||
|
||||
|
||||
def disable(name, runas=None):
|
||||
@ -242,12 +326,11 @@ def disable(name, runas=None):
|
||||
|
||||
salt '*' service.disable org.cups.cupsd
|
||||
'''
|
||||
# Get service information and label
|
||||
service = _get_service(name)
|
||||
label = service['plist']['Label']
|
||||
# Get the service target. enable requires a full <service-target>
|
||||
service_target = _get_domain_target(name, service_target=True)[0]
|
||||
|
||||
# disable the service: will raise an error if it fails
|
||||
return launchctl('disable', 'system/{0}'.format(label), runas=runas)
|
||||
return launchctl('disable', service_target, runas=runas)
|
||||
|
||||
|
||||
def start(name, runas=None):
|
||||
@ -271,12 +354,11 @@ def start(name, runas=None):
|
||||
|
||||
salt '*' service.start org.cups.cupsd
|
||||
'''
|
||||
# Get service information and file path
|
||||
service = _get_service(name)
|
||||
path = service['file_path']
|
||||
# Get the domain target.
|
||||
domain_target, path = _get_domain_target(name)
|
||||
|
||||
# Load the service: will raise an error if it fails
|
||||
return launchctl('load', path, runas=runas)
|
||||
# Load (bootstrap) the service: will raise an error if it fails
|
||||
return launchctl('bootstrap', domain_target, path, runas=runas)
|
||||
|
||||
|
||||
def stop(name, runas=None):
|
||||
@ -301,12 +383,11 @@ def stop(name, runas=None):
|
||||
|
||||
salt '*' service.stop org.cups.cupsd
|
||||
'''
|
||||
# Get service information and file path
|
||||
service = _get_service(name)
|
||||
path = service['file_path']
|
||||
# Get the domain target.
|
||||
domain_target, path = _get_domain_target(name)
|
||||
|
||||
# Disable the Launch Daemon: will raise an error if it fails
|
||||
return launchctl('unload', path, runas=runas)
|
||||
# Stop (bootout) the service: will raise an error if it fails
|
||||
return launchctl('bootout', domain_target, path, runas=runas)
|
||||
|
||||
|
||||
def restart(name, runas=None):
|
||||
@ -368,6 +449,9 @@ def status(name, sig=None, runas=None):
|
||||
if not _always_running_service(name) and enabled(name):
|
||||
return 'loaded'
|
||||
|
||||
if not runas and _launch_agent(name):
|
||||
runas = __utils__['mac_utils.console_user'](username=True)
|
||||
|
||||
output = list_(runas=runas)
|
||||
|
||||
# Used a string here instead of a list because that's what the linux version
|
||||
@ -493,7 +577,7 @@ def get_all(runas=None):
|
||||
enabled = get_enabled(runas=runas)
|
||||
|
||||
# Get list of all services
|
||||
available = list(salt.utils.mac_utils.available_services().keys())
|
||||
available = list(__utils__['mac_utils.available_services']().keys())
|
||||
|
||||
# Return composite list
|
||||
return sorted(set(enabled + available))
|
||||
@ -514,7 +598,6 @@ def get_enabled(runas=None):
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' service.get_enabled
|
||||
salt '*' service.get_enabled running=True
|
||||
'''
|
||||
# Collect list of enabled services
|
||||
stdout = list_(runas=runas)
|
||||
|
@ -11,6 +11,7 @@ import subprocess
|
||||
import os
|
||||
import plistlib
|
||||
import time
|
||||
import pwd
|
||||
|
||||
# Import Salt Libs
|
||||
import salt.modules.cmdmod
|
||||
@ -294,6 +295,15 @@ def _available_services():
|
||||
'/System/Library/LaunchAgents',
|
||||
'/System/Library/LaunchDaemons',
|
||||
]
|
||||
|
||||
try:
|
||||
for user in os.listdir('/Users/'):
|
||||
agent_path = '/Users/{}/Library/LaunchAgents/'.format(user)
|
||||
if os.path.isdir(agent_path):
|
||||
launchd_paths.append(agent_path)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
_available_services = dict()
|
||||
for launch_dir in launchd_paths:
|
||||
for root, dirs, files in salt.utils.path.os_walk(launch_dir):
|
||||
@ -359,3 +369,37 @@ def available_services():
|
||||
salt.utils.mac_service.available_services()
|
||||
'''
|
||||
return _available_services()
|
||||
|
||||
|
||||
def console_user(username=False):
|
||||
'''
|
||||
Gets the UID or Username of the current console user.
|
||||
|
||||
:return: The uid or username of the console user.
|
||||
|
||||
:param bool username: Whether to return the username of the console
|
||||
user instead of the UID. Defaults to False
|
||||
|
||||
:rtype: Interger of the UID, or a string of the username.
|
||||
|
||||
Raises:
|
||||
CommandExecutionError: If we fail to get the UID.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
import salt.utils.mac_service
|
||||
salt.utils.mac_service.console_user()
|
||||
'''
|
||||
try:
|
||||
# returns the 'st_uid' stat from the /dev/console file.
|
||||
uid = os.stat('/dev/console')[4]
|
||||
except (OSError, IndexError):
|
||||
# we should never get here but raise an error if so
|
||||
raise CommandExecutionError('Failed to get a UID for the console user.')
|
||||
|
||||
if username:
|
||||
return pwd.getpwuid(uid)[0]
|
||||
|
||||
return uid
|
||||
|
Loading…
Reference in New Issue
Block a user