mirror of
https://github.com/valitydev/salt.git
synced 2024-11-06 16:45:27 +00:00
Merge pull request #30775 from Unity-Technologies/feature/mac_defaults
Added the ability to set OS X settings using defaults
This commit is contained in:
commit
330abcad12
90
salt/modules/mac_defaults.py
Normal file
90
salt/modules/mac_defaults.py
Normal file
@ -0,0 +1,90 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Set defaults on Mac OS
|
||||
|
||||
'''
|
||||
|
||||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
import logging
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
__virtualname__ = 'macdefaults'
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Only work on Mac OS
|
||||
'''
|
||||
if salt.utils.is_darwin():
|
||||
return __virtualname__
|
||||
return False
|
||||
|
||||
|
||||
def write(domain, key, value, type='string', user=None):
|
||||
'''
|
||||
Write a default to the system
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' macdefaults.write com.apple.CrashReporter DialogType Server
|
||||
|
||||
salt '*' macdefaults.write NSGlobalDomain ApplePersistence True type=bool
|
||||
|
||||
domain
|
||||
The name of the domain to write to
|
||||
|
||||
key
|
||||
The key of the given domain to write to
|
||||
|
||||
value
|
||||
The value to write to the given key
|
||||
|
||||
type
|
||||
The type of value to be written, vaid types are string, data, int[eger],
|
||||
float, bool[ean], date, array, array-add, dict, dict-add
|
||||
|
||||
user
|
||||
The user to write the defaults to
|
||||
|
||||
|
||||
'''
|
||||
if type == 'bool' or type == 'boolean':
|
||||
if value is True:
|
||||
value = 'TRUE'
|
||||
elif value is False:
|
||||
value = 'FALSE'
|
||||
|
||||
cmd = 'defaults write "{0}" "{1}" -{2} "{3}"'.format(domain, key, type, value)
|
||||
return __salt__['cmd.run_all'](cmd, runas=user)
|
||||
|
||||
|
||||
def read(domain, key, user=None):
|
||||
'''
|
||||
Write a default to the system
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' macdefaults.read com.apple.CrashReporter DialogType
|
||||
|
||||
salt '*' macdefaults.read NSGlobalDomain ApplePersistence
|
||||
|
||||
domain
|
||||
The name of the domain to read from
|
||||
|
||||
key
|
||||
The key of the given domain to read from
|
||||
|
||||
user
|
||||
The user to write the defaults to
|
||||
|
||||
'''
|
||||
cmd = 'defaults read "{0}" "{1}"'.format(domain, key)
|
||||
return __salt__['cmd.run'](cmd, runas=user)
|
78
salt/states/mac_defaults.py
Normal file
78
salt/states/mac_defaults.py
Normal file
@ -0,0 +1,78 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Writing/reading defaults from an OS X minion
|
||||
=======================
|
||||
|
||||
'''
|
||||
|
||||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
import logging
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
__virtualname__ = 'macdefaults'
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Only work on Mac OS
|
||||
'''
|
||||
if salt.utils.is_darwin():
|
||||
return __virtualname__
|
||||
return False
|
||||
|
||||
|
||||
def write(name, domain, value, vtype='string', user=None):
|
||||
'''
|
||||
Write a default to the system
|
||||
|
||||
name
|
||||
The key of the given domain to write to
|
||||
|
||||
domain
|
||||
The name of the domain to write to
|
||||
|
||||
value
|
||||
The value to write to the given key
|
||||
|
||||
vtype
|
||||
The type of value to be written, vaid types are string, data, int[eger],
|
||||
float, bool[ean], date, array, array-add, dict, dict-add
|
||||
|
||||
user
|
||||
The user to write the defaults to
|
||||
|
||||
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'result': True,
|
||||
'comment': '',
|
||||
'changes': {}}
|
||||
|
||||
def safe_cast(val, to_type, default=None):
|
||||
try:
|
||||
return to_type(val)
|
||||
except ValueError:
|
||||
return default
|
||||
|
||||
current_value = __salt__['macdefaults.read'](domain, name, user)
|
||||
|
||||
if (vtype in ['bool', 'boolean']) and ((value in [True, 'TRUE', 'YES'] and current_value == '1') or
|
||||
(value in [False, 'FALSE', 'NO'] and current_value == '0')):
|
||||
ret['comment'] += '{0} {1} is already set to {2}'.format(domain, name, value)
|
||||
elif vtype in ['int', 'integer'] and safe_cast(current_value, int) == safe_cast(value, int):
|
||||
ret['comment'] += '{0} {1} is already set to {2}'.format(domain, name, value)
|
||||
elif current_value == value:
|
||||
ret['comment'] += '{0} {1} is already set to {2}'.format(domain, name, value)
|
||||
else:
|
||||
out = __salt__['macdefaults.write'](domain, name, value, vtype, user)
|
||||
if out['retcode'] != 0:
|
||||
ret['result'] = False
|
||||
ret['comment'] = 'Failed to write default. {0}'.format(out['stdout'])
|
||||
else:
|
||||
ret['changes']['written'] = '{0} {1} is set to {2}'.format(domain, name, value)
|
||||
|
||||
return ret
|
75
tests/unit/modules/mac_defaults_test.py
Normal file
75
tests/unit/modules/mac_defaults_test.py
Normal file
@ -0,0 +1,75 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Import Salt Libs
|
||||
from salt.modules import mac_defaults as macdefaults
|
||||
|
||||
# Import Salt Testing Libs
|
||||
from salttesting import TestCase
|
||||
from salttesting.helpers import ensure_in_syspath
|
||||
from salttesting.mock import (
|
||||
MagicMock,
|
||||
patch
|
||||
)
|
||||
|
||||
ensure_in_syspath('../../')
|
||||
|
||||
macdefaults.__salt__ = {}
|
||||
|
||||
|
||||
class MacDefaultsTestCase(TestCase):
|
||||
|
||||
def test_write_default(self):
|
||||
'''
|
||||
Test writing a default setting
|
||||
'''
|
||||
mock = MagicMock()
|
||||
with patch.dict(macdefaults.__salt__, {'cmd.run_all': mock}):
|
||||
macdefaults.write('com.apple.CrashReporter', 'DialogType', 'Server')
|
||||
mock.assert_called_once_with('defaults write "com.apple.CrashReporter" "DialogType" -string "Server"',
|
||||
runas=None)
|
||||
|
||||
def test_write_with_user(self):
|
||||
'''
|
||||
Test writing a default setting with a specific user
|
||||
'''
|
||||
mock = MagicMock()
|
||||
with patch.dict(macdefaults.__salt__, {'cmd.run_all': mock}):
|
||||
macdefaults.write('com.apple.CrashReporter', 'DialogType', 'Server', user="frank")
|
||||
mock.assert_called_once_with('defaults write "com.apple.CrashReporter" "DialogType" -string "Server"',
|
||||
runas="frank")
|
||||
|
||||
def test_write_default_boolean(self):
|
||||
'''
|
||||
Test writing a default setting
|
||||
'''
|
||||
mock = MagicMock()
|
||||
with patch.dict(macdefaults.__salt__, {'cmd.run_all': mock}):
|
||||
macdefaults.write('com.apple.CrashReporter', 'Crash', True, type="boolean")
|
||||
mock.assert_called_once_with('defaults write "com.apple.CrashReporter" "Crash" -boolean "TRUE"',
|
||||
runas=None)
|
||||
|
||||
def test_read_default(self):
|
||||
'''
|
||||
Test reading a default setting
|
||||
'''
|
||||
mock = MagicMock()
|
||||
with patch.dict(macdefaults.__salt__, {'cmd.run': mock}):
|
||||
macdefaults.read('com.apple.CrashReporter', 'Crash')
|
||||
mock.assert_called_once_with('defaults read "com.apple.CrashReporter" "Crash"', runas=None)
|
||||
|
||||
def test_read_default_with_user(self):
|
||||
'''
|
||||
Test reading a default setting as a specific user
|
||||
'''
|
||||
mock = MagicMock()
|
||||
with patch.dict(macdefaults.__salt__, {'cmd.run': mock}):
|
||||
macdefaults.read('com.apple.CrashReporter', 'Crash', user="frank")
|
||||
mock.assert_called_once_with('defaults read "com.apple.CrashReporter" "Crash"', runas="frank")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
run_tests(MacDefaultsTestCase, needs_daemon=False)
|
147
tests/unit/states/mac_defaults_test.py
Normal file
147
tests/unit/states/mac_defaults_test.py
Normal file
@ -0,0 +1,147 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Import Salt Libs
|
||||
from salt.states import mac_defaults as macdefaults
|
||||
|
||||
# Import Salt Testing Libs
|
||||
from salttesting import TestCase
|
||||
from salttesting.helpers import ensure_in_syspath
|
||||
from salttesting.mock import (
|
||||
MagicMock,
|
||||
patch
|
||||
)
|
||||
|
||||
ensure_in_syspath('../../')
|
||||
|
||||
macdefaults.__salt__ = {}
|
||||
|
||||
|
||||
class MacDefaultsTestCase(TestCase):
|
||||
|
||||
def test_write(self):
|
||||
'''
|
||||
Test writing a default setting
|
||||
'''
|
||||
expected = {
|
||||
'changes': {'written': 'com.apple.CrashReporter DialogType is set to Server'},
|
||||
'comment': '',
|
||||
'name': 'DialogType',
|
||||
'result': True
|
||||
}
|
||||
|
||||
read_mock = MagicMock(return_value='Local')
|
||||
write_mock = MagicMock(return_value={'retcode': 0})
|
||||
with patch.dict(macdefaults.__salt__, {'macdefaults.read': read_mock,
|
||||
'macdefaults.write': write_mock}):
|
||||
out = macdefaults.write('DialogType', 'com.apple.CrashReporter', 'Server')
|
||||
read_mock.assert_called_once_with('com.apple.CrashReporter', 'DialogType', None)
|
||||
write_mock.assert_called_once_with('com.apple.CrashReporter', 'DialogType', 'Server', 'string', None)
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_write_set(self):
|
||||
'''
|
||||
Test writing a default setting that is already set
|
||||
'''
|
||||
expected = {
|
||||
'changes': {},
|
||||
'comment': 'com.apple.CrashReporter DialogType is already set to Server',
|
||||
'name': 'DialogType',
|
||||
'result': True
|
||||
}
|
||||
|
||||
read_mock = MagicMock(return_value='Server')
|
||||
write_mock = MagicMock(return_value={'retcode': 0})
|
||||
with patch.dict(macdefaults.__salt__, {'macdefaults.read': read_mock,
|
||||
'macdefaults.write': write_mock}):
|
||||
out = macdefaults.write('DialogType', 'com.apple.CrashReporter', 'Server')
|
||||
read_mock.assert_called_once_with('com.apple.CrashReporter', 'DialogType', None)
|
||||
assert not write_mock.called
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_write_boolean(self):
|
||||
'''
|
||||
Test writing a default setting with a boolean
|
||||
'''
|
||||
expected = {
|
||||
'changes': {'written': 'com.apple.something Key is set to True'},
|
||||
'comment': '',
|
||||
'name': 'Key',
|
||||
'result': True
|
||||
}
|
||||
|
||||
read_mock = MagicMock(return_value='0')
|
||||
write_mock = MagicMock(return_value={'retcode': 0})
|
||||
with patch.dict(macdefaults.__salt__, {'macdefaults.read': read_mock,
|
||||
'macdefaults.write': write_mock}):
|
||||
out = macdefaults.write('Key', 'com.apple.something', True, vtype='boolean')
|
||||
read_mock.assert_called_once_with('com.apple.something', 'Key', None)
|
||||
write_mock.assert_called_once_with('com.apple.something', 'Key', True, 'boolean', None)
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_write_boolean_match(self):
|
||||
'''
|
||||
Test writing a default setting with a boolean that is already set to the same value
|
||||
'''
|
||||
expected = {
|
||||
'changes': {},
|
||||
'comment': 'com.apple.something Key is already set to YES',
|
||||
'name': 'Key',
|
||||
'result': True
|
||||
}
|
||||
|
||||
read_mock = MagicMock(return_value='1')
|
||||
write_mock = MagicMock(return_value={'retcode': 0})
|
||||
with patch.dict(macdefaults.__salt__, {'macdefaults.read': read_mock,
|
||||
'macdefaults.write': write_mock}):
|
||||
out = macdefaults.write('Key', 'com.apple.something', 'YES', vtype='boolean')
|
||||
read_mock.assert_called_once_with('com.apple.something', 'Key', None)
|
||||
assert not write_mock.called
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_write_integer(self):
|
||||
'''
|
||||
Test writing a default setting with a integer
|
||||
'''
|
||||
expected = {
|
||||
'changes': {'written': 'com.apple.something Key is set to 1337'},
|
||||
'comment': '',
|
||||
'name': 'Key',
|
||||
'result': True
|
||||
}
|
||||
|
||||
read_mock = MagicMock(return_value='99')
|
||||
write_mock = MagicMock(return_value={'retcode': 0})
|
||||
with patch.dict(macdefaults.__salt__, {'macdefaults.read': read_mock,
|
||||
'macdefaults.write': write_mock}):
|
||||
out = macdefaults.write('Key', 'com.apple.something', 1337, vtype='integer')
|
||||
read_mock.assert_called_once_with('com.apple.something', 'Key', None)
|
||||
write_mock.assert_called_once_with('com.apple.something', 'Key', 1337, 'integer', None)
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_write_integer_match(self):
|
||||
'''
|
||||
Test writing a default setting with a integer that is already set to the same value
|
||||
'''
|
||||
expected = {
|
||||
'changes': {},
|
||||
'comment': 'com.apple.something Key is already set to 1337',
|
||||
'name': 'Key',
|
||||
'result': True
|
||||
}
|
||||
|
||||
read_mock = MagicMock(return_value='1337')
|
||||
write_mock = MagicMock(return_value={'retcode': 0})
|
||||
with patch.dict(macdefaults.__salt__, {'macdefaults.read': read_mock,
|
||||
'macdefaults.write': write_mock}):
|
||||
out = macdefaults.write('Key', 'com.apple.something', 1337, vtype='integer')
|
||||
read_mock.assert_called_once_with('com.apple.something', 'Key', None)
|
||||
assert not write_mock.called
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
run_tests(MacDefaultsTestCase, needs_daemon=False)
|
Loading…
Reference in New Issue
Block a user