test_pkg.py 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126
  1. # -*- coding: utf-8 -*-
  2. '''
  3. tests for pkg state
  4. '''
  5. # Import Python libs
  6. from __future__ import absolute_import, print_function, unicode_literals
  7. import logging
  8. import os
  9. import time
  10. # Import Salt Testing libs
  11. from tests.support.case import ModuleCase
  12. from tests.support.mixins import SaltReturnAssertsMixin
  13. from tests.support.unit import skipIf
  14. from tests.support.helpers import (
  15. destructiveTest,
  16. requires_system_grains,
  17. requires_salt_modules,
  18. flaky
  19. )
  20. # Import Salt libs
  21. import salt.utils.path
  22. import salt.utils.pkg.rpm
  23. import salt.utils.platform
  24. # Import 3rd-party libs
  25. from salt.ext import six
  26. from salt.ext.six.moves import range # pylint: disable=import-error,redefined-builtin
  27. log = logging.getLogger(__name__)
  28. _PKG_TARGETS = {
  29. 'Arch': ['sl', 'libpng'],
  30. 'Debian': ['python-plist', 'apg'],
  31. 'RedHat': ['units', 'zsh-html'],
  32. 'FreeBSD': ['aalib', 'pth'],
  33. 'Suse': ['aalib', 'htop'],
  34. 'MacOS': ['libpng', 'jpeg'],
  35. 'Windows': ['putty', '7zip'],
  36. }
  37. _PKG_CAP_TARGETS = {
  38. 'Suse': [('perl(ZNC)', 'znc-perl')],
  39. }
  40. _PKG_TARGETS_32 = {
  41. 'CentOS': 'xz-devel.i686'
  42. }
  43. # Test packages with dot in pkg name
  44. # (https://github.com/saltstack/salt/issues/8614)
  45. _PKG_TARGETS_DOT = {
  46. 'RedHat': {'5': 'python-migrate0.5',
  47. '6': 'tomcat6-el-2.1-api',
  48. '7': 'tomcat-el-2.2-api'}
  49. }
  50. # Test packages with epoch in version
  51. # (https://github.com/saltstack/salt/issues/31619)
  52. _PKG_TARGETS_EPOCH = {
  53. 'RedHat': {'7': 'comps-extras'},
  54. }
  55. _WILDCARDS_SUPPORTED = ('Arch', 'Debian', 'RedHat')
  56. @flaky
  57. @destructiveTest
  58. @requires_salt_modules('pkg.version', 'pkg.latest_version')
  59. class PkgTest(ModuleCase, SaltReturnAssertsMixin):
  60. '''
  61. pkg.installed state tests
  62. '''
  63. RUN_FUNCTION_TIMEOUT = 600
  64. @classmethod
  65. @requires_system_grains
  66. def setUpClass(cls, grains):
  67. cls.grains = grains
  68. cls.__testcontext__ = {}
  69. @classmethod
  70. def tearDownClass(cls):
  71. cls.grains = None
  72. cls.__testcontext__ = None
  73. def setUp(self):
  74. '''
  75. Ensure that we only refresh the first time we run a test
  76. '''
  77. super(PkgTest, self).setUp()
  78. if 'refresh' not in self.__testcontext__:
  79. self.run_function('pkg.refresh_db')
  80. self.__testcontext__['refresh'] = True
  81. def _pkgmgr_avail(self):
  82. '''
  83. Return True if the package manager is available for use
  84. '''
  85. def proc_fd_lsof(path):
  86. '''
  87. Return True if any entry in /proc/locks points to path. Example data:
  88. .. code-block:: bash
  89. # cat /proc/locks
  90. 1: FLOCK ADVISORY WRITE 596 00:0f:10703 0 EOF
  91. 2: FLOCK ADVISORY WRITE 14590 00:0f:11282 0 EOF
  92. 3: POSIX ADVISORY WRITE 653 00:0f:11422 0 EOF
  93. '''
  94. import glob
  95. # https://www.centos.org/docs/5/html/5.2/Deployment_Guide/s2-proc-locks.html
  96. locks = self.run_function('cmd.run', ['cat /proc/locks']).splitlines()
  97. for line in locks:
  98. fields = line.split()
  99. try:
  100. major, minor, inode = fields[5].split(':')
  101. inode = int(inode)
  102. except (IndexError, ValueError):
  103. return False
  104. for fd in glob.glob('/proc/*/fd'):
  105. fd_path = os.path.realpath(fd)
  106. # If the paths match and the inode is locked
  107. if fd_path == path and os.stat(fd_path).st_ino == inode:
  108. return True
  109. return False
  110. def get_lock(path):
  111. '''
  112. Return True if any locks are found for path
  113. '''
  114. # Try lsof if it's available
  115. if salt.utils.path.which('lsof'):
  116. lock = self.run_function('cmd.run', ['lsof {0}'.format(path)])
  117. return True if len(lock) else False
  118. # Try to find any locks on path from /proc/locks
  119. elif self.grains.get('kernel') == 'Linux':
  120. return proc_fd_lsof(path)
  121. return False
  122. if 'Debian' in self.grains.get('os_family', ''):
  123. for path in ['/var/lib/apt/lists/lock']:
  124. if get_lock(path):
  125. return False
  126. return True
  127. def _latest_version(self, *names):
  128. '''
  129. Helper function which ensures that we don't make any unnecessary calls to
  130. pkg.latest_version to figure out what version we need to install. This
  131. won't stop pkg.latest_version from being run in a pkg.latest state, but it
  132. will reduce the amount of times we check the latest version here in the
  133. test suite.
  134. '''
  135. key = 'latest_version'
  136. if key not in self.__testcontext__:
  137. self.__testcontext__[key] = {}
  138. targets = [x for x in names if x not in self.__testcontext__[key]]
  139. if targets:
  140. result = self.run_function('pkg.latest_version', targets, refresh=False)
  141. try:
  142. self.__testcontext__[key].update(result)
  143. except ValueError:
  144. # Only a single target, pkg.latest_version returned a string
  145. self.__testcontext__[key][targets[0]] = result
  146. ret = dict([(x, self.__testcontext__[key][x]) for x in names])
  147. if len(names) == 1:
  148. return ret[names[0]]
  149. return ret
  150. def test_pkg_001_installed(self):
  151. '''
  152. This is a destructive test as it installs and then removes a package
  153. '''
  154. # Skip test if package manager not available
  155. if not self._pkgmgr_avail():
  156. self.skipTest('Package manager is not available')
  157. os_family = self.grains.get('os_family', '')
  158. pkg_targets = _PKG_TARGETS.get(os_family, [])
  159. # Make sure that we have targets that match the os_family. If this
  160. # fails then the _PKG_TARGETS dict above needs to have an entry added,
  161. # with two packages that are not installed before these tests are run
  162. self.assertTrue(pkg_targets)
  163. target = pkg_targets[0]
  164. version = self.run_function('pkg.version', [target])
  165. # If this assert fails, we need to find new targets, this test needs to
  166. # be able to test successful installation of packages, so this package
  167. # needs to not be installed before we run the states below
  168. self.assertFalse(version)
  169. ret = self.run_state('pkg.installed', name=target, refresh=False)
  170. self.assertSaltTrueReturn(ret)
  171. ret = self.run_state('pkg.removed', name=target)
  172. self.assertSaltTrueReturn(ret)
  173. def test_pkg_002_installed_with_version(self):
  174. '''
  175. This is a destructive test as it installs and then removes a package
  176. '''
  177. # Skip test if package manager not available
  178. if not self._pkgmgr_avail():
  179. self.skipTest('Package manager is not available')
  180. os_family = self.grains.get('os_family', '')
  181. pkg_targets = _PKG_TARGETS.get(os_family, [])
  182. # Don't perform this test on FreeBSD since version specification is not
  183. # supported.
  184. if os_family == 'FreeBSD':
  185. self.skip('Version specification not supported on FreeBSD')
  186. # Make sure that we have targets that match the os_family. If this
  187. # fails then the _PKG_TARGETS dict above needs to have an entry added,
  188. # with two packages that are not installed before these tests are run
  189. self.assertTrue(pkg_targets)
  190. if os_family == 'Arch':
  191. for idx in range(13):
  192. if idx == 12:
  193. raise Exception('Package database locked after 60 seconds, '
  194. 'bailing out')
  195. if not os.path.isfile('/var/lib/pacman/db.lck'):
  196. break
  197. time.sleep(5)
  198. target = pkg_targets[0]
  199. version = self._latest_version(target)
  200. # If this assert fails, we need to find new targets, this test needs to
  201. # be able to test successful installation of packages, so this package
  202. # needs to not be installed before we run the states below
  203. self.assertTrue(version)
  204. ret = self.run_state('pkg.installed',
  205. name=target,
  206. version=version,
  207. refresh=False)
  208. self.assertSaltTrueReturn(ret)
  209. ret = self.run_state('pkg.removed', name=target)
  210. self.assertSaltTrueReturn(ret)
  211. def test_pkg_003_installed_multipkg(self):
  212. '''
  213. This is a destructive test as it installs and then removes two packages
  214. '''
  215. # Skip test if package manager not available
  216. if not self._pkgmgr_avail():
  217. self.skipTest('Package manager is not available')
  218. os_family = self.grains.get('os_family', '')
  219. pkg_targets = _PKG_TARGETS.get(os_family, [])
  220. # Make sure that we have targets that match the os_family. If this
  221. # fails then the _PKG_TARGETS dict above needs to have an entry added,
  222. # with two packages that are not installed before these tests are run
  223. self.assertTrue(pkg_targets)
  224. version = self.run_function('pkg.version', pkg_targets)
  225. # If this assert fails, we need to find new targets, this test needs to
  226. # be able to test successful installation of packages, so these
  227. # packages need to not be installed before we run the states below
  228. try:
  229. self.assertFalse(any(version.values()))
  230. except AssertionError:
  231. self.assertSaltTrueReturn(self.run_state('pkg.removed', name=None, pkgs=pkg_targets))
  232. try:
  233. ret = self.run_state('pkg.installed',
  234. name=None,
  235. pkgs=pkg_targets,
  236. refresh=False)
  237. self.assertSaltTrueReturn(ret)
  238. finally:
  239. ret = self.run_state('pkg.removed', name=None, pkgs=pkg_targets)
  240. self.assertSaltTrueReturn(ret)
  241. def test_pkg_004_installed_multipkg_with_version(self):
  242. '''
  243. This is a destructive test as it installs and then removes two packages
  244. '''
  245. # Skip test if package manager not available
  246. if not self._pkgmgr_avail():
  247. self.skipTest('Package manager is not available')
  248. os_family = self.grains.get('os_family', '')
  249. pkg_targets = _PKG_TARGETS.get(os_family, [])
  250. # Don't perform this test on FreeBSD since version specification is not
  251. # supported.
  252. if os_family == 'FreeBSD':
  253. return
  254. # Make sure that we have targets that match the os_family. If this
  255. # fails then the _PKG_TARGETS dict above needs to have an entry added,
  256. # with two packages that are not installed before these tests are run
  257. self.assertTrue(bool(pkg_targets))
  258. if os_family == 'Arch':
  259. for idx in range(13):
  260. if idx == 12:
  261. raise Exception('Package database locked after 60 seconds, '
  262. 'bailing out')
  263. if not os.path.isfile('/var/lib/pacman/db.lck'):
  264. break
  265. time.sleep(5)
  266. version = self._latest_version(pkg_targets[0])
  267. # If this assert fails, we need to find new targets, this test needs to
  268. # be able to test successful installation of packages, so these
  269. # packages need to not be installed before we run the states below
  270. self.assertTrue(bool(version))
  271. pkgs = [{pkg_targets[0]: version}, pkg_targets[1]]
  272. try:
  273. ret = self.run_state('pkg.installed',
  274. name=None,
  275. pkgs=pkgs,
  276. refresh=False)
  277. self.assertSaltTrueReturn(ret)
  278. finally:
  279. ret = self.run_state('pkg.removed', name=None, pkgs=pkg_targets)
  280. self.assertSaltTrueReturn(ret)
  281. def test_pkg_005_installed_32bit(self):
  282. '''
  283. This is a destructive test as it installs and then removes a package
  284. '''
  285. # Skip test if package manager not available
  286. if not self._pkgmgr_avail():
  287. self.skipTest('Package manager is not available')
  288. os_name = self.grains.get('os', '')
  289. target = _PKG_TARGETS_32.get(os_name, '')
  290. # _PKG_TARGETS_32 is only populated for platforms for which Salt has to
  291. # munge package names for 32-bit-on-x86_64 (Currently only Ubuntu and
  292. # RHEL-based). Don't actually perform this test on other platforms.
  293. if target:
  294. # CentOS 5 has .i386 arch designation for 32-bit pkgs
  295. if os_name == 'CentOS' \
  296. and self.grains['osrelease'].startswith('5.'):
  297. target = target.replace('.i686', '.i386')
  298. version = self.run_function('pkg.version', [target])
  299. # If this assert fails, we need to find a new target. This test
  300. # needs to be able to test successful installation of packages, so
  301. # the target needs to not be installed before we run the states
  302. # below
  303. self.assertFalse(bool(version))
  304. ret = self.run_state('pkg.installed',
  305. name=target,
  306. refresh=False)
  307. self.assertSaltTrueReturn(ret)
  308. ret = self.run_state('pkg.removed', name=target)
  309. self.assertSaltTrueReturn(ret)
  310. def test_pkg_006_installed_32bit_with_version(self):
  311. '''
  312. This is a destructive test as it installs and then removes a package
  313. '''
  314. # Skip test if package manager not available
  315. if not self._pkgmgr_avail():
  316. self.skipTest('Package manager is not available')
  317. os_name = self.grains.get('os', '')
  318. target = _PKG_TARGETS_32.get(os_name, '')
  319. # _PKG_TARGETS_32 is only populated for platforms for which Salt has to
  320. # munge package names for 32-bit-on-x86_64 (Currently only Ubuntu and
  321. # RHEL-based). Don't actually perform this test on other platforms.
  322. if not target:
  323. self.skipTest('No targets configured for this test')
  324. if self.grains.get('os_family', '') == 'Arch':
  325. for idx in range(13):
  326. if idx == 12:
  327. raise Exception('Package database locked after 60 seconds, '
  328. 'bailing out')
  329. if not os.path.isfile('/var/lib/pacman/db.lck'):
  330. break
  331. time.sleep(5)
  332. # CentOS 5 has .i386 arch designation for 32-bit pkgs
  333. if os_name == 'CentOS' \
  334. and self.grains['osrelease'].startswith('5.'):
  335. target = target.replace('.i686', '.i386')
  336. version = self._latest_version(target)
  337. # If this assert fails, we need to find a new target. This test
  338. # needs to be able to test successful installation of the package, so
  339. # the target needs to not be installed before we run the states
  340. # below
  341. self.assertTrue(bool(version))
  342. ret = self.run_state('pkg.installed',
  343. name=target,
  344. version=version,
  345. refresh=False)
  346. self.assertSaltTrueReturn(ret)
  347. ret = self.run_state('pkg.removed', name=target)
  348. self.assertSaltTrueReturn(ret)
  349. def test_pkg_007_with_dot_in_pkgname(self):
  350. '''
  351. This tests for the regression found in the following issue:
  352. https://github.com/saltstack/salt/issues/8614
  353. This is a destructive test as it installs a package
  354. '''
  355. # Skip test if package manager not available
  356. if not self._pkgmgr_avail():
  357. self.skipTest('Package manager is not available')
  358. os_family = self.grains.get('os_family', '')
  359. os_version = self.grains.get('osmajorrelease')
  360. target = _PKG_TARGETS_DOT.get(os_family, {}).get(os_version)
  361. if not target:
  362. self.skipTest('No targets configured for this test')
  363. version = self._latest_version(target)
  364. # If this assert fails, we need to find a new target. This test
  365. # needs to be able to test successful installation of the package, so
  366. # the target needs to not be installed before we run the
  367. # pkg.installed state below
  368. self.assertTrue(bool(version))
  369. ret = self.run_state('pkg.installed', name=target, refresh=False)
  370. self.assertSaltTrueReturn(ret)
  371. ret = self.run_state('pkg.removed', name=target)
  372. self.assertSaltTrueReturn(ret)
  373. def test_pkg_008_epoch_in_version(self):
  374. '''
  375. This tests for the regression found in the following issue:
  376. https://github.com/saltstack/salt/issues/8614
  377. This is a destructive test as it installs a package
  378. '''
  379. # Skip test if package manager not available
  380. if not self._pkgmgr_avail():
  381. self.skipTest('Package manager is not available')
  382. os_family = self.grains.get('os_family', '')
  383. os_version = self.grains.get('osmajorrelease')
  384. target = _PKG_TARGETS_EPOCH.get(os_family, {}).get(os_version)
  385. if not target:
  386. self.skipTest('No targets configured for this test')
  387. version = self._latest_version(target)
  388. # If this assert fails, we need to find a new target. This test
  389. # needs to be able to test successful installation of the package, so
  390. # the target needs to not be installed before we run the
  391. # pkg.installed state below
  392. self.assertTrue(bool(version))
  393. ret = self.run_state('pkg.installed',
  394. name=target,
  395. version=version,
  396. refresh=False)
  397. self.assertSaltTrueReturn(ret)
  398. ret = self.run_state('pkg.removed', name=target)
  399. self.assertSaltTrueReturn(ret)
  400. @skipIf(salt.utils.platform.is_windows(), 'minion is windows')
  401. def test_pkg_009_latest_with_epoch(self):
  402. '''
  403. This tests for the following issue:
  404. https://github.com/saltstack/salt/issues/31014
  405. This is a destructive test as it installs a package
  406. '''
  407. # Skip test if package manager not available
  408. if not self._pkgmgr_avail():
  409. self.skipTest('Package manager is not available')
  410. test_name = 'bash-completion'
  411. if self.grains.get('os') == 'Amazon' and self.grains.get('osmajorrelease') != 2:
  412. test_name = 'bash-doc'
  413. ret = self.run_state('pkg.installed',
  414. name=test_name,
  415. refresh=False)
  416. self.assertSaltTrueReturn(ret)
  417. @requires_salt_modules('pkg.info_installed')
  418. def test_pkg_010_latest_with_epoch_and_info_installed(self):
  419. '''
  420. Need to check to ensure the package has been
  421. installed after the pkg_latest_epoch sls
  422. file has been run. This needs to be broken up into
  423. a separate method so I can add the requires_salt_modules
  424. decorator to only the pkg.info_installed command.
  425. '''
  426. # Skip test if package manager not available
  427. if not self._pkgmgr_avail():
  428. self.skipTest('Package manager is not available')
  429. package = 'bash-completion'
  430. if self.grains.get('os') == 'Amazon' and self.grains.get('osmajorrelease') != 2:
  431. package = 'bash-doc'
  432. pkgquery = 'version'
  433. ret = self.run_function('pkg.info_installed', [package])
  434. self.assertTrue(pkgquery in six.text_type(ret))
  435. def test_pkg_011_latest(self):
  436. '''
  437. This tests pkg.latest with a package that has no epoch (or a zero
  438. epoch).
  439. '''
  440. # Skip test if package manager not available
  441. if not self._pkgmgr_avail():
  442. self.skipTest('Package manager is not available')
  443. os_family = self.grains.get('os_family', '')
  444. pkg_targets = _PKG_TARGETS.get(os_family, [])
  445. # Make sure that we have targets that match the os_family. If this
  446. # fails then the _PKG_TARGETS dict above needs to have an entry added,
  447. # with two packages that are not installed before these tests are run
  448. self.assertTrue(pkg_targets)
  449. target = pkg_targets[0]
  450. version = self._latest_version(target)
  451. # If this assert fails, we need to find new targets, this test needs to
  452. # be able to test successful installation of packages, so this package
  453. # needs to not be installed before we run the states below
  454. self.assertTrue(version)
  455. ret = self.run_state('pkg.latest', name=target, refresh=False)
  456. self.assertSaltTrueReturn(ret)
  457. ret = self.run_state('pkg.removed', name=target)
  458. self.assertSaltTrueReturn(ret)
  459. def test_pkg_012_latest_only_upgrade(self):
  460. '''
  461. WARNING: This test will pick a package with an available upgrade (if
  462. there is one) and upgrade it to the latest version.
  463. '''
  464. os_family = self.grains.get('os_family', '')
  465. if os_family != 'Debian':
  466. self.skipTest('Minion is not Debian/Ubuntu')
  467. # Skip test if package manager not available
  468. if not self._pkgmgr_avail():
  469. self.skipTest('Package manager is not available')
  470. pkg_targets = _PKG_TARGETS.get(os_family, [])
  471. # Make sure that we have targets that match the os_family. If this
  472. # fails then the _PKG_TARGETS dict above needs to have an entry added,
  473. # with two packages that are not installed before these tests are run
  474. self.assertTrue(pkg_targets)
  475. target = pkg_targets[0]
  476. version = self._latest_version(target)
  477. # If this assert fails, we need to find new targets, this test needs to
  478. # be able to test that the state fails when you try to run the state
  479. # with only_upgrade=True on a package which is not already installed,
  480. # so the targeted package needs to not be installed before we run the
  481. # state below.
  482. self.assertTrue(version)
  483. ret = self.run_state('pkg.latest', name=target, refresh=False,
  484. only_upgrade=True)
  485. self.assertSaltFalseReturn(ret)
  486. # Now look for updates and try to run the state on a package which is
  487. # already up-to-date.
  488. installed_pkgs = self.run_function('pkg.list_pkgs')
  489. updates = self.run_function('pkg.list_upgrades', refresh=False)
  490. for pkgname in updates:
  491. if pkgname in installed_pkgs:
  492. target = pkgname
  493. break
  494. else:
  495. target = ''
  496. log.warning(
  497. 'No available upgrades to installed packages, skipping '
  498. 'only_upgrade=True test with already-installed package. For '
  499. 'best results run this test on a machine with upgrades '
  500. 'available.'
  501. )
  502. if target:
  503. ret = self.run_state('pkg.latest', name=target, refresh=False,
  504. only_upgrade=True)
  505. self.assertSaltTrueReturn(ret)
  506. new_version = self.run_function('pkg.version', [target])
  507. self.assertEqual(new_version, updates[target])
  508. ret = self.run_state('pkg.latest', name=target, refresh=False,
  509. only_upgrade=True)
  510. self.assertEqual(
  511. ret['pkg_|-{0}_|-{0}_|-latest'.format(target)]['comment'],
  512. 'Package {0} is already up-to-date'.format(target)
  513. )
  514. def test_pkg_013_installed_with_wildcard_version(self):
  515. '''
  516. This is a destructive test as it installs and then removes a package
  517. '''
  518. # Skip test if package manager not available
  519. if not self._pkgmgr_avail():
  520. self.skipTest('Package manager is not available')
  521. os_family = self.grains.get('os_family', '')
  522. if os_family not in _WILDCARDS_SUPPORTED:
  523. self.skipTest(
  524. 'Wildcards only supported on {0}'.format(
  525. ', '.join(_WILDCARDS_SUPPORTED)
  526. )
  527. )
  528. pkg_targets = _PKG_TARGETS.get(os_family, [])
  529. # Make sure that we have targets that match the os_family. If this
  530. # fails then the _PKG_TARGETS dict above needs to have an entry added,
  531. # with two packages that are not installed before these tests are run
  532. self.assertTrue(pkg_targets)
  533. target = pkg_targets[0]
  534. version = self.run_function('pkg.version', [target])
  535. # If this assert fails, we need to find new targets, this test needs to
  536. # be able to test successful installation of packages, so this package
  537. # needs to not be installed before we run the states below
  538. self.assertFalse(version)
  539. ret = self.run_state(
  540. 'pkg.installed',
  541. name=target,
  542. version='*',
  543. refresh=False,
  544. )
  545. self.assertSaltTrueReturn(ret)
  546. # Repeat state, should pass
  547. ret = self.run_state(
  548. 'pkg.installed',
  549. name=target,
  550. version='*',
  551. refresh=False,
  552. )
  553. expected_comment = (
  554. 'All specified packages are already installed and are at the '
  555. 'desired version'
  556. )
  557. self.assertSaltTrueReturn(ret)
  558. self.assertEqual(ret[next(iter(ret))]['comment'], expected_comment)
  559. # Repeat one more time with unavailable version, test should fail
  560. ret = self.run_state(
  561. 'pkg.installed',
  562. name=target,
  563. version='93413*',
  564. refresh=False,
  565. )
  566. self.assertSaltFalseReturn(ret)
  567. # Clean up
  568. ret = self.run_state('pkg.removed', name=target)
  569. self.assertSaltTrueReturn(ret)
  570. def test_pkg_014_installed_with_comparison_operator(self):
  571. '''
  572. This is a destructive test as it installs and then removes a package
  573. '''
  574. # Skip test if package manager not available
  575. if not self._pkgmgr_avail():
  576. self.skipTest('Package manager is not available')
  577. os_family = self.grains.get('os_family', '')
  578. if os_family not in ('Debian', 'RedHat'):
  579. self.skipTest('Comparison operator not specially implemented')
  580. pkg_targets = _PKG_TARGETS.get(os_family, [])
  581. # Make sure that we have targets that match the os_family. If this
  582. # fails then the _PKG_TARGETS dict above needs to have an entry added,
  583. # with two packages that are not installed before these tests are run
  584. self.assertTrue(pkg_targets)
  585. target = pkg_targets[0]
  586. version = self.run_function('pkg.version', [target])
  587. # If this assert fails, we need to find new targets, this test needs to
  588. # be able to test successful installation of packages, so this package
  589. # needs to not be installed before we run the states below
  590. self.assertFalse(version)
  591. latest_version = self.run_function(
  592. 'pkg.latest_version',
  593. [target],
  594. refresh=False)
  595. try:
  596. ret = self.run_state(
  597. 'pkg.installed',
  598. name=target,
  599. version='<9999999',
  600. refresh=False,
  601. )
  602. self.assertSaltTrueReturn(ret)
  603. # The version that was installed should be the latest available
  604. version = self.run_function('pkg.version', [target])
  605. self.assertTrue(version, latest_version)
  606. finally:
  607. # Clean up
  608. ret = self.run_state('pkg.removed', name=target)
  609. self.assertSaltTrueReturn(ret)
  610. def test_pkg_014_installed_missing_release(self): # pylint: disable=unused-argument
  611. '''
  612. Tests that a version number missing the release portion still resolves
  613. as correctly installed. For example, version 2.0.2 instead of 2.0.2-1.el7
  614. '''
  615. os_family = self.grains.get('os_family', '')
  616. if os_family.lower() != 'redhat':
  617. self.skipTest('Test only runs on RedHat OS family')
  618. pkg_targets = _PKG_TARGETS.get(os_family, [])
  619. # Make sure that we have targets that match the os_family. If this
  620. # fails then the _PKG_TARGETS dict above needs to have an entry added,
  621. # with two packages that are not installed before these tests are run
  622. self.assertTrue(pkg_targets)
  623. target = pkg_targets[0]
  624. version = self.run_function('pkg.version', [target])
  625. # If this assert fails, we need to find new targets, this test needs to
  626. # be able to test successful installation of packages, so this package
  627. # needs to not be installed before we run the states below
  628. self.assertFalse(version)
  629. ret = self.run_state(
  630. 'pkg.installed',
  631. name=target,
  632. version=salt.utils.pkg.rpm.version_to_evr(version)[1],
  633. refresh=False,
  634. )
  635. self.assertSaltTrueReturn(ret)
  636. # Clean up
  637. ret = self.run_state('pkg.removed', name=target)
  638. self.assertSaltTrueReturn(ret)
  639. @requires_salt_modules('pkg.group_install')
  640. def test_group_installed_handle_missing_package_group(self): # pylint: disable=unused-argument
  641. '''
  642. Tests that a CommandExecutionError is caught and the state returns False when
  643. the package group is missing. Before this fix, the state would stacktrace.
  644. See Issue #35819 for bug report.
  645. '''
  646. # Skip test if package manager not available
  647. if not self._pkgmgr_avail():
  648. self.skipTest('Package manager is not available')
  649. # Group install not available message
  650. grp_install_msg = 'pkg.group_install not available for this platform'
  651. # Run the pkg.group_installed state with a fake package group
  652. ret = self.run_state('pkg.group_installed', name='handle_missing_pkg_group',
  653. skip=['foo-bar-baz'])
  654. ret_comment = ret['pkg_|-handle_missing_pkg_group_|-handle_missing_pkg_group_|-group_installed']['comment']
  655. # Not all package managers support group_installed. Skip this test if not supported.
  656. if ret_comment == grp_install_msg:
  657. self.skipTest(grp_install_msg)
  658. # Test state should return False and should have the right comment
  659. self.assertSaltFalseReturn(ret)
  660. self.assertEqual(ret_comment, 'An error was encountered while installing/updating group '
  661. '\'handle_missing_pkg_group\': Group \'handle_missing_pkg_group\' '
  662. 'not found.')
  663. @skipIf(salt.utils.platform.is_windows(), 'minion is windows')
  664. def test_pkg_cap_001_installed(self):
  665. '''
  666. This is a destructive test as it installs and then removes a package
  667. '''
  668. # Skip test if package manager not available
  669. if not self._pkgmgr_avail():
  670. self.skipTest('Package manager is not available')
  671. os_family = self.grains.get('os_family', '')
  672. pkg_cap_targets = _PKG_CAP_TARGETS.get(os_family, [])
  673. if not len(pkg_cap_targets) > 0:
  674. self.skipTest('Capability not provided')
  675. target, realpkg = pkg_cap_targets[0]
  676. version = self.run_function('pkg.version', [target])
  677. realver = self.run_function('pkg.version', [realpkg])
  678. # If this assert fails, we need to find new targets, this test needs to
  679. # be able to test successful installation of packages, so this package
  680. # needs to not be installed before we run the states below
  681. self.assertFalse(version)
  682. self.assertFalse(realver)
  683. try:
  684. ret = self.run_state('pkg.installed', name=target, refresh=False, resolve_capabilities=True, test=True)
  685. self.assertInSaltComment("The following packages would be installed/updated: {0}".format(realpkg), ret)
  686. ret = self.run_state('pkg.installed', name=target, refresh=False, resolve_capabilities=True)
  687. self.assertSaltTrueReturn(ret)
  688. finally:
  689. ret = self.run_state('pkg.removed', name=realpkg)
  690. self.assertSaltTrueReturn(ret)
  691. @skipIf(salt.utils.platform.is_windows(), 'minion is windows')
  692. def test_pkg_cap_002_already_installed(self):
  693. '''
  694. This is a destructive test as it installs and then removes a package
  695. '''
  696. # Skip test if package manager not available
  697. if not self._pkgmgr_avail():
  698. self.skipTest('Package manager is not available')
  699. os_family = self.grains.get('os_family', '')
  700. pkg_cap_targets = _PKG_CAP_TARGETS.get(os_family, [])
  701. if not len(pkg_cap_targets) > 0:
  702. self.skipTest('Capability not provided')
  703. target, realpkg = pkg_cap_targets[0]
  704. version = self.run_function('pkg.version', [target])
  705. realver = self.run_function('pkg.version', [realpkg])
  706. # If this assert fails, we need to find new targets, this test needs to
  707. # be able to test successful installation of packages, so this package
  708. # needs to not be installed before we run the states below
  709. self.assertFalse(version)
  710. self.assertFalse(realver)
  711. try:
  712. # install the package
  713. ret = self.run_state('pkg.installed', name=realpkg, refresh=False)
  714. self.assertSaltTrueReturn(ret)
  715. # Try to install again. Nothing should be installed this time.
  716. ret = self.run_state('pkg.installed', name=target, refresh=False, resolve_capabilities=True, test=True)
  717. self.assertInSaltComment("All specified packages are already installed", ret)
  718. ret = self.run_state('pkg.installed', name=target, refresh=False, resolve_capabilities=True)
  719. self.assertSaltTrueReturn(ret)
  720. self.assertInSaltComment("packages are already installed", ret)
  721. finally:
  722. ret = self.run_state('pkg.removed', name=realpkg)
  723. self.assertSaltTrueReturn(ret)
  724. @skipIf(salt.utils.platform.is_windows(), 'minion is windows')
  725. def test_pkg_cap_003_installed_multipkg_with_version(self):
  726. '''
  727. This is a destructive test as it installs and then removes two packages
  728. '''
  729. # Skip test if package manager not available
  730. if not self._pkgmgr_avail():
  731. self.skipTest('Package manager is not available')
  732. os_family = self.grains.get('os_family', '')
  733. pkg_cap_targets = _PKG_CAP_TARGETS.get(os_family, [])
  734. if not len(pkg_cap_targets) > 0:
  735. self.skipTest('Capability not provided')
  736. pkg_targets = _PKG_TARGETS.get(os_family, [])
  737. # Don't perform this test on FreeBSD since version specification is not
  738. # supported.
  739. if os_family == 'FreeBSD':
  740. return
  741. # Make sure that we have targets that match the os_family. If this
  742. # fails then the _PKG_TARGETS dict above needs to have an entry added,
  743. # with two packages that are not installed before these tests are run
  744. self.assertTrue(pkg_cap_targets)
  745. self.assertTrue(pkg_targets)
  746. if os_family == 'Arch':
  747. for idx in range(13):
  748. if idx == 12:
  749. raise Exception('Package database locked after 60 seconds, '
  750. 'bailing out')
  751. if not os.path.isfile('/var/lib/pacman/db.lck'):
  752. break
  753. time.sleep(5)
  754. capability, realpkg = pkg_cap_targets[0]
  755. version = self._latest_version(pkg_targets[0])
  756. realver = self._latest_version(realpkg)
  757. # If this assert fails, we need to find new targets, this test needs to
  758. # be able to test successful installation of packages, so these
  759. # packages need to not be installed before we run the states below
  760. self.assertTrue(version)
  761. self.assertTrue(realver)
  762. try:
  763. pkgs = [{pkg_targets[0]: version}, pkg_targets[1], {capability: realver}]
  764. ret = self.run_state('pkg.installed',
  765. name='test_pkg_cap_003_installed_multipkg_with_version-install',
  766. pkgs=pkgs,
  767. refresh=False)
  768. self.assertSaltFalseReturn(ret)
  769. ret = self.run_state('pkg.installed',
  770. name='test_pkg_cap_003_installed_multipkg_with_version-install-capability',
  771. pkgs=pkgs,
  772. refresh=False, resolve_capabilities=True, test=True)
  773. self.assertInSaltComment("packages would be installed/updated", ret)
  774. self.assertInSaltComment("{0}={1}".format(realpkg, realver), ret)
  775. ret = self.run_state('pkg.installed',
  776. name='test_pkg_cap_003_installed_multipkg_with_version-install-capability',
  777. pkgs=pkgs,
  778. refresh=False, resolve_capabilities=True)
  779. self.assertSaltTrueReturn(ret)
  780. cleanup_pkgs = pkg_targets
  781. cleanup_pkgs.append(realpkg)
  782. finally:
  783. ret = self.run_state('pkg.removed',
  784. name='test_pkg_cap_003_installed_multipkg_with_version-remove',
  785. pkgs=cleanup_pkgs)
  786. self.assertSaltTrueReturn(ret)
  787. @skipIf(salt.utils.platform.is_windows(), 'minion is windows')
  788. def test_pkg_cap_004_latest(self):
  789. '''
  790. This tests pkg.latest with a package that has no epoch (or a zero
  791. epoch).
  792. '''
  793. # Skip test if package manager not available
  794. if not self._pkgmgr_avail():
  795. self.skipTest('Package manager is not available')
  796. os_family = self.grains.get('os_family', '')
  797. pkg_cap_targets = _PKG_CAP_TARGETS.get(os_family, [])
  798. if not len(pkg_cap_targets) > 0:
  799. self.skipTest('Capability not provided')
  800. target, realpkg = pkg_cap_targets[0]
  801. version = self.run_function('pkg.version', [target])
  802. realver = self.run_function('pkg.version', [realpkg])
  803. # If this assert fails, we need to find new targets, this test needs to
  804. # be able to test successful installation of packages, so this package
  805. # needs to not be installed before we run the states below
  806. self.assertFalse(version)
  807. self.assertFalse(realver)
  808. try:
  809. ret = self.run_state('pkg.latest', name=target, refresh=False, resolve_capabilities=True, test=True)
  810. self.assertInSaltComment("The following packages would be installed/upgraded: {0}".format(realpkg), ret)
  811. ret = self.run_state('pkg.latest', name=target, refresh=False, resolve_capabilities=True)
  812. self.assertSaltTrueReturn(ret)
  813. ret = self.run_state('pkg.latest', name=target, refresh=False, resolve_capabilities=True)
  814. self.assertSaltTrueReturn(ret)
  815. self.assertInSaltComment("is already up-to-date", ret)
  816. finally:
  817. ret = self.run_state('pkg.removed', name=realpkg)
  818. self.assertSaltTrueReturn(ret)
  819. @skipIf(salt.utils.platform.is_windows(), 'minion is windows')
  820. def test_pkg_cap_005_downloaded(self):
  821. '''
  822. This is a destructive test as it installs and then removes a package
  823. '''
  824. # Skip test if package manager not available
  825. if not self._pkgmgr_avail():
  826. self.skipTest('Package manager is not available')
  827. os_family = self.grains.get('os_family', '')
  828. pkg_cap_targets = _PKG_CAP_TARGETS.get(os_family, [])
  829. if not len(pkg_cap_targets) > 0:
  830. self.skipTest('Capability not provided')
  831. target, realpkg = pkg_cap_targets[0]
  832. version = self.run_function('pkg.version', [target])
  833. realver = self.run_function('pkg.version', [realpkg])
  834. # If this assert fails, we need to find new targets, this test needs to
  835. # be able to test successful installation of packages, so this package
  836. # needs to not be installed before we run the states below
  837. self.assertFalse(version)
  838. self.assertFalse(realver)
  839. ret = self.run_state('pkg.downloaded', name=target, refresh=False)
  840. self.assertSaltFalseReturn(ret)
  841. ret = self.run_state('pkg.downloaded', name=target, refresh=False, resolve_capabilities=True, test=True)
  842. self.assertInSaltComment("The following packages would be downloaded: {0}".format(realpkg), ret)
  843. ret = self.run_state('pkg.downloaded', name=target, refresh=False, resolve_capabilities=True)
  844. self.assertSaltTrueReturn(ret)
  845. @skipIf(salt.utils.platform.is_windows(), 'minion is windows')
  846. def test_pkg_cap_006_uptodate(self):
  847. '''
  848. This is a destructive test as it installs and then removes a package
  849. '''
  850. # Skip test if package manager not available
  851. if not self._pkgmgr_avail():
  852. self.skipTest('Package manager is not available')
  853. os_family = self.grains.get('os_family', '')
  854. pkg_cap_targets = _PKG_CAP_TARGETS.get(os_family, [])
  855. if not len(pkg_cap_targets) > 0:
  856. self.skipTest('Capability not provided')
  857. target, realpkg = pkg_cap_targets[0]
  858. version = self.run_function('pkg.version', [target])
  859. realver = self.run_function('pkg.version', [realpkg])
  860. # If this assert fails, we need to find new targets, this test needs to
  861. # be able to test successful installation of packages, so this package
  862. # needs to not be installed before we run the states below
  863. self.assertFalse(version)
  864. self.assertFalse(realver)
  865. try:
  866. ret = self.run_state('pkg.installed', name=target,
  867. refresh=False, resolve_capabilities=True)
  868. self.assertSaltTrueReturn(ret)
  869. ret = self.run_state('pkg.uptodate',
  870. name='test_pkg_cap_006_uptodate',
  871. pkgs=[target],
  872. refresh=False,
  873. resolve_capabilities=True)
  874. self.assertSaltTrueReturn(ret)
  875. self.assertInSaltComment("System is already up-to-date", ret)
  876. finally:
  877. ret = self.run_state('pkg.removed', name=realpkg)
  878. self.assertSaltTrueReturn(ret)
  879. @skipIf(True, 'WAR ROOM TEMPORARY SKIP') # needs to be rewritten to allow for dnf on Fedora 30 and RHEL 8
  880. @requires_salt_modules('pkg.hold', 'pkg.unhold')
  881. def test_pkg_015_installed_held(self): # pylint: disable=unused-argument
  882. '''
  883. Tests that a package can be held even when the package is already installed.
  884. '''
  885. os_family = self.grains.get('os_family', '')
  886. if os_family.lower() != 'redhat' and os_family.lower() != 'debian':
  887. self.skipTest('Test only runs on RedHat or Debian family')
  888. pkg_targets = _PKG_TARGETS.get(os_family, [])
  889. if os_family.lower() == 'redhat':
  890. # If we're in the Red Hat family first we ensure that
  891. # the yum-plugin-versionlock package is installed
  892. ret = self.run_state(
  893. 'pkg.installed',
  894. name='yum-plugin-versionlock',
  895. refresh=False,
  896. )
  897. self.assertSaltTrueReturn(ret)
  898. # Make sure that we have targets that match the os_family. If this
  899. # fails then the _PKG_TARGETS dict above needs to have an entry added,
  900. # with two packages that are not installed before these tests are run
  901. self.assertTrue(pkg_targets)
  902. target = pkg_targets[0]
  903. # First we ensure that the package is installed
  904. ret = self.run_state(
  905. 'pkg.installed',
  906. name=target,
  907. refresh=False,
  908. )
  909. self.assertSaltTrueReturn(ret)
  910. # Then we check that the package is now held
  911. ret = self.run_state(
  912. 'pkg.installed',
  913. name=target,
  914. hold=True,
  915. refresh=False,
  916. )
  917. # changes from pkg.hold for Red Hat family are different
  918. if os_family.lower() == 'redhat':
  919. target_changes = {'new': 'hold', 'old': ''}
  920. elif os_family.lower() == 'debian':
  921. target_changes = {'new': 'hold', 'old': 'install'}
  922. try:
  923. tag = 'pkg_|-{0}_|-{0}_|-installed'.format(target)
  924. self.assertSaltTrueReturn(ret)
  925. self.assertIn(tag, ret)
  926. self.assertIn('changes', ret[tag])
  927. self.assertIn(target, ret[tag]['changes'])
  928. self.assertEqual(ret[tag]['changes'][target], target_changes)
  929. finally:
  930. # Clean up, unhold package and remove
  931. self.run_function('pkg.unhold', name=target)
  932. ret = self.run_state('pkg.removed', name=target)
  933. self.assertSaltTrueReturn(ret)
  934. if os_family.lower() == 'redhat':
  935. ret = self.run_state('pkg.removed',
  936. name='yum-plugin-versionlock')
  937. self.assertSaltTrueReturn(ret)