diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py index be296f0decd5..d37115ad1c28 100644 --- a/salt/modules/aptpkg.py +++ b/salt/modules/aptpkg.py @@ -18,6 +18,9 @@ import re import logging import time +import fnmatch +import datetime + # Import third party libs # pylint: disable=no-name-in-module,import-error,redefined-builtin @@ -384,6 +387,7 @@ def install(name=None, pkgs=None, sources=None, reinstall=False, + downloadonly=False, ignore_epoch=False, **kwargs): ''' @@ -730,6 +734,9 @@ def install(name=None, cmd.extend(downgrade) cmds.append(cmd) + if downloadonly: + cmd.append("--download-only") + if to_reinstall: all_pkgs.extend(to_reinstall) cmd = copy.deepcopy(cmd_prefix) @@ -2846,3 +2853,37 @@ def _get_http_proxy_url(): ) return http_proxy_url + + +def list_downloaded(root=None, **kwargs): + ''' + .. versionadded:: 3000? + + List prefetched packages downloaded by apt in the local disk. + + root + operate on a different root directory. + + CLI example: + + .. code-block:: bash + + salt '*' pkg.list_downloaded + ''' + CACHE_DIR = '/var/cache/apt' + if root: + CACHE_DIR = os.path.join(root, os.path.relpath(CACHE_DIR, os.path.sep)) + + ret = {} + for root, dirnames, filenames in salt.utils.path.os_walk(CACHE_DIR): + for filename in fnmatch.filter(filenames, '*.deb'): + package_path = os.path.join(root, filename) + pkg_info = __salt__['lowpkg.bin_pkg_info'](package_path) + pkg_timestamp = int(os.path.getctime(package_path)) + ret.setdefault(pkg_info['name'], {})[pkg_info['version']] = { + 'path': package_path, + 'size': os.path.getsize(package_path), + 'creation_date_time_t': pkg_timestamp, + 'creation_date_time': datetime.datetime.utcfromtimestamp(pkg_timestamp).isoformat(), + } + return ret diff --git a/salt/states/pkg.py b/salt/states/pkg.py index 7388024421e5..a13d4184002f 100644 --- a/salt/states/pkg.py +++ b/salt/states/pkg.py @@ -2035,7 +2035,7 @@ def downloaded(name, (if specified). Currently supported for the following pkg providers: - :mod:`yumpkg ` and :mod:`zypper ` + :mod:`yumpkg `, :mod:`zypper ` and :mod:`zypper ` :param str name: The name of the package to be downloaded. This parameter is ignored if @@ -2174,7 +2174,7 @@ def downloaded(name, if not ret['changes'] and not ret['comment']: ret['result'] = True - ret['comment'] = 'Packages are already downloaded: ' \ + ret['comment'] = 'Packages downloaded: ' \ '{0}'.format(', '.join(targets)) return ret diff --git a/tests/unit/modules/test_aptpkg.py b/tests/unit/modules/test_aptpkg.py index c5e5310357ae..1ef1a37fd2f7 100644 --- a/tests/unit/modules/test_aptpkg.py +++ b/tests/unit/modules/test_aptpkg.py @@ -523,6 +523,32 @@ def test_show(self): self.assert_called_once(refresh_mock) refresh_mock.reset_mock() + @patch('salt.utils.path.os_walk', MagicMock(return_value=[('test', 'test', 'test')])) + @patch('os.path.getsize', MagicMock(return_value=123456)) + @patch('os.path.getctime', MagicMock(return_value=1234567890.123456)) + @patch('fnmatch.filter', MagicMock(return_value=['/var/cache/apt/archive/test_package.rpm'])) + def test_list_downloaded(self): + ''' + Test downloaded packages listing. + :return: + ''' + DOWNLOADED_RET = { + 'test-package': { + '1.0': { + 'path': '/var/cache/apt/archive/test_package.rpm', + 'size': 123456, + 'creation_date_time_t': 1234567890, + 'creation_date_time': '2009-02-13T23:31:30', + } + } + } + + with patch.dict(aptpkg.__salt__, {'lowpkg.bin_pkg_info': MagicMock(return_value={'name': 'test-package', + 'version': '1.0'})}): + list_downloaded = aptpkg.list_downloaded() + self.assertEqual(len(list_downloaded), 1) + self.assertDictEqual(list_downloaded, DOWNLOADED_RET) + @skipIf(pytest is None, 'PyTest is missing') class AptUtilsTestCase(TestCase, LoaderModuleMockMixin):