test_pkg.py 45 KB

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