mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge pull request #33522 from jfindlay/mac_pkg
rework modules.mac_brew.latest_version to work around brew version inconsistency
This commit is contained in:
commit
0bc881b4da
3 changed files with 188 additions and 65 deletions
|
@ -18,6 +18,9 @@ import logging
|
|||
import salt.utils
|
||||
from salt.exceptions import CommandExecutionError, MinionError
|
||||
|
||||
# Import third party libs
|
||||
import json
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# Define the module's virtual name
|
||||
|
@ -51,7 +54,9 @@ def _tap(tap, runas=None):
|
|||
return True
|
||||
|
||||
cmd = 'brew tap {0}'.format(tap)
|
||||
if _call_brew(cmd)['retcode']:
|
||||
try:
|
||||
_call_brew(cmd)
|
||||
except CommandExecutionError:
|
||||
log.error('Failed to tap "{0}"'.format(tap))
|
||||
return False
|
||||
|
||||
|
@ -73,11 +78,18 @@ def _call_brew(cmd, redirect_stderr=False):
|
|||
'''
|
||||
user = __salt__['file.get_user'](_homebrew_bin())
|
||||
runas = user if user != __opts__['user'] else None
|
||||
return __salt__['cmd.run_all'](cmd,
|
||||
runas=runas,
|
||||
output_loglevel='trace',
|
||||
python_shell=False,
|
||||
redirect_stderr=redirect_stderr)
|
||||
ret = __salt__['cmd.run_all'](cmd,
|
||||
runas=runas,
|
||||
output_loglevel='trace',
|
||||
python_shell=False,
|
||||
redirect_stderr=redirect_stderr)
|
||||
if ret['retcode'] != 0:
|
||||
raise CommandExecutionError(
|
||||
'stdout: {stdout}\n'
|
||||
'stderr: {stderr}\n'
|
||||
'retcode: {retcode}\n'.format(**ret)
|
||||
)
|
||||
return ret
|
||||
|
||||
|
||||
def list_pkgs(versions_as_list=False, **kwargs):
|
||||
|
@ -147,9 +159,6 @@ def latest_version(*names, **kwargs):
|
|||
Return the latest version of the named package available for upgrade or
|
||||
installation
|
||||
|
||||
Note that this currently not fully implemented but needs to return
|
||||
something to avoid a traceback when calling pkg.latest.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -158,28 +167,36 @@ def latest_version(*names, **kwargs):
|
|||
salt '*' pkg.latest_version <package1> <package2> <package3>
|
||||
'''
|
||||
refresh = salt.utils.is_true(kwargs.pop('refresh', True))
|
||||
|
||||
if refresh:
|
||||
refresh_db()
|
||||
|
||||
if len(names) <= 0:
|
||||
return ''
|
||||
else:
|
||||
ret = {}
|
||||
pkg_upgrades = 'brew outdated --verbose'
|
||||
pkg_installed = list_pkgs()
|
||||
call = _call_brew(pkg_upgrades)
|
||||
# Get dictionaries of installed and upgradeable packages
|
||||
installed = list_pkgs()
|
||||
upgrade = list_upgrades()
|
||||
|
||||
for name in names:
|
||||
ret[name] = ''
|
||||
if name in pkg_installed:
|
||||
if name in call['stdout']:
|
||||
updates = call['stdout'].split()[-1].strip(")")
|
||||
ret[name] = updates
|
||||
if len(names) == 0:
|
||||
return ''
|
||||
ret = {}
|
||||
|
||||
for name in names:
|
||||
if name in installed:
|
||||
if name in upgrade:
|
||||
ret[name] = upgrade[name]
|
||||
else:
|
||||
new_version = __salt__['cmd.run']('brew info {0}'.format(name))
|
||||
to_install = new_version.split("\n")[0].split()[2]
|
||||
ret[name] = ''.join(to_install)
|
||||
ret[name] = ''
|
||||
else:
|
||||
pkg_info = _info(name)
|
||||
|
||||
# brew does not include the revision in the version string for
|
||||
# uninstalled packages, but it does for installed packages, so
|
||||
# append it here so that the pkg.uptodate function works
|
||||
version = pkg_info[name]['versions']['stable']
|
||||
revision = pkg_info[name]['revision']
|
||||
if revision > 0:
|
||||
version += '_{0}'.format(revision)
|
||||
ret[name] = version
|
||||
|
||||
# Return a string if only one package name passed
|
||||
if len(names) == 1:
|
||||
return ret[names[0]]
|
||||
return ret
|
||||
|
@ -387,20 +404,20 @@ def list_upgrades(refresh=True):
|
|||
if refresh:
|
||||
refresh_db()
|
||||
|
||||
cmd = 'brew outdated'
|
||||
call = _call_brew(cmd)
|
||||
if call['retcode'] != 0:
|
||||
comment = ''
|
||||
if 'stderr' in call:
|
||||
comment += call['stderr']
|
||||
if 'stdout' in call:
|
||||
comment += call['stdout']
|
||||
raise CommandExecutionError(
|
||||
'{0}'.format(comment)
|
||||
)
|
||||
else:
|
||||
out = call['stdout']
|
||||
return out.splitlines()
|
||||
res = _call_brew(['brew', 'outdated', '--json=v1'])
|
||||
ret = {}
|
||||
|
||||
try:
|
||||
data = json.loads(res['stdout'])
|
||||
except ValueError as err:
|
||||
msg = 'unable to interpret output from "brew outdated": {0}'.format(err)
|
||||
log.error(msg)
|
||||
raise CommandExecutionError(msg)
|
||||
|
||||
for pkg in data:
|
||||
# current means latest available to brew
|
||||
ret[pkg['name']] = pkg['current_version']
|
||||
return ret
|
||||
|
||||
|
||||
def upgrade_available(pkg):
|
||||
|
@ -457,3 +474,49 @@ def upgrade(refresh=True):
|
|||
ret['changes'] = salt.utils.compare_dicts(old, new)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def _info(*names):
|
||||
'''
|
||||
Return the information of the named package(s)
|
||||
|
||||
.. versionadded:: 2016.3.1
|
||||
|
||||
names
|
||||
The names of the packages for which to return information.
|
||||
'''
|
||||
cmd = ['brew', 'info', '--json=v1']
|
||||
cmd.extend(names)
|
||||
res = _call_brew(cmd)
|
||||
ret = {}
|
||||
|
||||
try:
|
||||
data = json.loads(res['stdout'])
|
||||
except ValueError as err:
|
||||
msg = 'unable to interpret output from "brew info": {0}'.format(err)
|
||||
log.error(msg)
|
||||
raise CommandExecutionError(msg)
|
||||
|
||||
for pkg in data:
|
||||
ret[pkg['name']] = pkg
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def info_installed(*names):
|
||||
'''
|
||||
Return the information of the named package(s) installed on the system.
|
||||
|
||||
.. versionadded:: 2016.3.1
|
||||
|
||||
names
|
||||
The names of the packages for which to return information.
|
||||
|
||||
CLI example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' pkg.info_installed <package1>
|
||||
salt '*' pkg.info_installed <package1> <package2> <package3> ...
|
||||
'''
|
||||
return _info(*names)
|
||||
|
|
|
@ -12,7 +12,6 @@ from salttesting import skipIf
|
|||
from salttesting.helpers import (
|
||||
destructiveTest,
|
||||
ensure_in_syspath,
|
||||
requires_system_grains
|
||||
)
|
||||
ensure_in_syspath('../../')
|
||||
|
||||
|
@ -21,12 +20,17 @@ import integration
|
|||
import salt.utils
|
||||
from salt.exceptions import CommandExecutionError
|
||||
|
||||
# Import third party libs
|
||||
import salt.ext.six as six
|
||||
|
||||
# Brew doesn't support local package installation - So, let's
|
||||
# Grab some small packages available online for brew
|
||||
ADD_PKG = 'algol68g'
|
||||
DEL_PKG = 'acme'
|
||||
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(os.geteuid() != 0, 'You must be logged in as root to run this test')
|
||||
class BrewModuleTest(integration.ModuleCase):
|
||||
'''
|
||||
Integration tests for the brew module
|
||||
|
@ -51,10 +55,7 @@ class BrewModuleTest(integration.ModuleCase):
|
|||
'You must have brew installed to run these tests'
|
||||
)
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(os.geteuid() != 0, 'You must be logged in as root to run this test')
|
||||
@requires_system_grains
|
||||
def test_brew_install(self, grains=None):
|
||||
def test_brew_install(self):
|
||||
'''
|
||||
Tests the installation of packages
|
||||
'''
|
||||
|
@ -70,10 +71,7 @@ class BrewModuleTest(integration.ModuleCase):
|
|||
self.run_function('pkg.remove', [ADD_PKG])
|
||||
raise
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(os.geteuid() != 0, 'You must be logged in as root to run this test')
|
||||
@requires_system_grains
|
||||
def test_remove(self, grains=None):
|
||||
def test_remove(self):
|
||||
'''
|
||||
Tests the removal of packages
|
||||
'''
|
||||
|
@ -96,10 +94,7 @@ class BrewModuleTest(integration.ModuleCase):
|
|||
self.run_function('pkg.remove', [DEL_PKG])
|
||||
raise
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(os.geteuid() != 0, 'You must be logged in as root to run this test')
|
||||
@requires_system_grains
|
||||
def test_mac_brew_pkg_version(self, grains=None):
|
||||
def test_version(self):
|
||||
'''
|
||||
Test pkg.version for mac. Installs
|
||||
a package and then checks we can get
|
||||
|
@ -129,20 +124,79 @@ class BrewModuleTest(integration.ModuleCase):
|
|||
self.run_function('pkg.remove', [ADD_PKG])
|
||||
raise
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(os.geteuid() != 0, 'You must be logged in as root to run this test')
|
||||
@requires_system_grains
|
||||
def test_mac_brew_refresh_db(self, grains=None):
|
||||
def test_latest_version(self):
|
||||
'''
|
||||
Test pkg.latest_version:
|
||||
- get the latest version available
|
||||
- install the package
|
||||
- get the latest version available
|
||||
- check that the latest version is empty after installing it
|
||||
'''
|
||||
try:
|
||||
self.run_function('pkg.remove', [ADD_PKG])
|
||||
uninstalled_latest = self.run_function('pkg.latest_version', [ADD_PKG])
|
||||
|
||||
self.run_function('pkg.install', [ADD_PKG])
|
||||
installed_latest = self.run_function('pkg.latest_version', [ADD_PKG])
|
||||
version = self.run_function('pkg.version', [ADD_PKG])
|
||||
try:
|
||||
self.assertTrue(isinstance(uninstalled_latest, six.string_types))
|
||||
self.assertEqual(installed_latest, '')
|
||||
except AssertionError:
|
||||
self.run_function('pkg.remove', [ADD_PKG])
|
||||
raise
|
||||
except CommandExecutionError:
|
||||
self.run_function('pkg.remove', [ADD_PKG])
|
||||
raise
|
||||
|
||||
def test_refresh_db(self):
|
||||
'''
|
||||
Integration test to ensure pkg.refresh_db works with brew
|
||||
'''
|
||||
refresh_brew = self.run_function('pkg.refresh_db')
|
||||
self.assertTrue(refresh_brew)
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(os.geteuid() != 0, 'You must be logged in as root to run this test')
|
||||
@requires_system_grains
|
||||
def tearDown(self, grains=None):
|
||||
def test_list_upgrades(self):
|
||||
'''
|
||||
Test pkg.list_upgrades: data is in the form {'name1': 'version1',
|
||||
'name2': 'version2', ... }
|
||||
'''
|
||||
try:
|
||||
upgrades = self.run_function('pkg.list_upgrades')
|
||||
try:
|
||||
self.assertTrue(isinstance(upgrades, dict))
|
||||
if len(upgrades):
|
||||
for name in upgrades:
|
||||
self.assertTrue(isinstance(name, six.string_types))
|
||||
self.assertTrue(isinstance(upgrades[name], six.string_types))
|
||||
except AssertionError:
|
||||
self.run_function('pkg.remove', [ADD_PKG])
|
||||
raise
|
||||
except CommandExecutionError:
|
||||
self.run_function('pkg.remove', [ADD_PKG])
|
||||
raise
|
||||
|
||||
def test_info_installed(self):
|
||||
'''
|
||||
Test pkg.info_installed: info returned has certain fields used by
|
||||
mac_brew.latest_version
|
||||
'''
|
||||
try:
|
||||
self.run_function('pkg.install', [ADD_PKG])
|
||||
info = self.run_function('pkg.info_installed', [ADD_PKG])
|
||||
try:
|
||||
self.assertTrue(ADD_PKG in info)
|
||||
self.assertTrue('versions' in info[ADD_PKG])
|
||||
self.assertTrue('revision' in info[ADD_PKG])
|
||||
self.assertTrue('stable' in info[ADD_PKG]['versions'])
|
||||
except AssertionError:
|
||||
self.run_function('pkg.remove', [ADD_PKG])
|
||||
raise
|
||||
except CommandExecutionError:
|
||||
self.run_function('pkg.remove', [ADD_PKG])
|
||||
raise
|
||||
|
||||
def tearDown(self):
|
||||
'''
|
||||
Clean up after tests
|
||||
'''
|
||||
|
|
|
@ -8,6 +8,7 @@ from __future__ import absolute_import
|
|||
|
||||
# Import Salt Libs
|
||||
from salt.modules import mac_brew
|
||||
from salt.exceptions import CommandExecutionError
|
||||
|
||||
# Import Salt Testing Libs
|
||||
from salttesting import skipIf, TestCase
|
||||
|
@ -38,7 +39,8 @@ class BrewTestCase(TestCase):
|
|||
'''
|
||||
Tests the return of the list of taps
|
||||
'''
|
||||
mock_taps = MagicMock(return_value={'stdout': TAPS_STRING})
|
||||
mock_taps = MagicMock(return_value={'stdout': TAPS_STRING,
|
||||
'retcode': 0})
|
||||
mock_user = MagicMock(return_value='foo')
|
||||
mock_cmd = MagicMock(return_value='')
|
||||
with patch.dict(mac_brew.__salt__, {'file.get_user': mock_user,
|
||||
|
@ -60,7 +62,9 @@ class BrewTestCase(TestCase):
|
|||
'''
|
||||
Tests if the tap installation failed
|
||||
'''
|
||||
mock_failure = MagicMock(return_value={'retcode': 1})
|
||||
mock_failure = MagicMock(return_value={'stdout': '',
|
||||
'stderr': '',
|
||||
'retcode': 1})
|
||||
mock_user = MagicMock(return_value='foo')
|
||||
mock_cmd = MagicMock(return_value='')
|
||||
with patch.dict(mac_brew.__salt__, {'cmd.run_all': mock_failure,
|
||||
|
@ -147,10 +151,12 @@ class BrewTestCase(TestCase):
|
|||
Tests an update of homebrew package repository failure
|
||||
'''
|
||||
mock_user = MagicMock(return_value='foo')
|
||||
mock_failure = MagicMock(return_value={'retcode': 1})
|
||||
mock_failure = MagicMock(return_value={'stdout': '',
|
||||
'stderr': '',
|
||||
'retcode': 1})
|
||||
with patch.dict(mac_brew.__salt__, {'file.get_user': mock_user,
|
||||
'cmd.run_all': mock_failure}):
|
||||
self.assertFalse(mac_brew.refresh_db())
|
||||
self.assertRaises(CommandExecutionError, mac_brew.refresh_db)
|
||||
|
||||
@patch('salt.modules.mac_brew._homebrew_bin',
|
||||
MagicMock(return_value=HOMEBREW_BIN))
|
||||
|
|
Loading…
Add table
Reference in a new issue