test_pkg.py 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139
  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', 'htop'],
  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. @requires_system_grains
  401. def test_pkg_009_latest_with_epoch(self, grains=None):
  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 pkgmgr_avail(self.run_function, self.run_function('grains.items')):
  409. self.skipTest('Package manager is not available')
  410. test_name = 'bash-completion'
  411. if grains.get('os') == 'Amazon' and 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. @requires_system_grains
  419. def test_pkg_010_latest_with_epoch_and_info_installed(self, grains=None):
  420. '''
  421. Need to check to ensure the package has been
  422. installed after the pkg_latest_epoch sls
  423. file has been run. This needs to be broken up into
  424. a separate method so I can add the requires_salt_modules
  425. decorator to only the pkg.info_installed command.
  426. '''
  427. # Skip test if package manager not available
  428. if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
  429. self.skipTest('Package manager is not available')
  430. package = 'bash-completion'
  431. if grains.get('os') == 'Amazon' and grains.get('osmajorrelease') != 2:
  432. package = 'bash-doc'
  433. pkgquery = 'version'
  434. ret = self.run_function('pkg.info_installed', [package])
  435. self.assertTrue(pkgquery in six.text_type(ret))
  436. @requires_system_grains
  437. def test_pkg_011_latest(self, grains=None):
  438. '''
  439. This tests pkg.latest with a package that has no epoch (or a zero
  440. epoch).
  441. '''
  442. # Skip test if package manager not available
  443. if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
  444. self.skipTest('Package manager is not available')
  445. os_family = grains.get('os_family', '')
  446. pkg_targets = _PKG_TARGETS.get(os_family, [])
  447. # Make sure that we have targets that match the os_family. If this
  448. # fails then the _PKG_TARGETS dict above needs to have an entry added,
  449. # with two packages that are not installed before these tests are run
  450. self.assertTrue(pkg_targets)
  451. target = pkg_targets[0]
  452. version = latest_version(self.run_function, target)
  453. # If this assert fails, we need to find new targets, this test needs to
  454. # be able to test successful installation of packages, so this package
  455. # needs to not be installed before we run the states below
  456. self.assertTrue(version)
  457. ret = self.run_state('pkg.latest', name=target, refresh=False)
  458. self.assertSaltTrueReturn(ret)
  459. ret = self.run_state('pkg.removed', name=target)
  460. self.assertSaltTrueReturn(ret)
  461. @requires_system_grains
  462. def test_pkg_012_latest_only_upgrade(self, grains=None):
  463. '''
  464. WARNING: This test will pick a package with an available upgrade (if
  465. there is one) and upgrade it to the latest version.
  466. '''
  467. os_family = grains.get('os_family', '')
  468. if os_family != 'Debian':
  469. self.skipTest('Minion is not Debian/Ubuntu')
  470. # Skip test if package manager not available
  471. if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
  472. self.skipTest('Package manager is not available')
  473. pkg_targets = _PKG_TARGETS.get(os_family, [])
  474. # Make sure that we have targets that match the os_family. If this
  475. # fails then the _PKG_TARGETS dict above needs to have an entry added,
  476. # with two packages that are not installed before these tests are run
  477. self.assertTrue(pkg_targets)
  478. target = pkg_targets[0]
  479. version = latest_version(self.run_function, target)
  480. # If this assert fails, we need to find new targets, this test needs to
  481. # be able to test that the state fails when you try to run the state
  482. # with only_upgrade=True on a package which is not already installed,
  483. # so the targeted package needs to not be installed before we run the
  484. # state below.
  485. self.assertTrue(version)
  486. ret = self.run_state('pkg.latest', name=target, refresh=False,
  487. only_upgrade=True)
  488. self.assertSaltFalseReturn(ret)
  489. # Now look for updates and try to run the state on a package which is
  490. # already up-to-date.
  491. installed_pkgs = self.run_function('pkg.list_pkgs')
  492. updates = self.run_function('pkg.list_upgrades', refresh=False)
  493. for pkgname in updates:
  494. if pkgname in installed_pkgs:
  495. target = pkgname
  496. break
  497. else:
  498. target = ''
  499. log.warning(
  500. 'No available upgrades to installed packages, skipping '
  501. 'only_upgrade=True test with already-installed package. For '
  502. 'best results run this test on a machine with upgrades '
  503. 'available.'
  504. )
  505. if target:
  506. ret = self.run_state('pkg.latest', name=target, refresh=False,
  507. only_upgrade=True)
  508. self.assertSaltTrueReturn(ret)
  509. new_version = self.run_function('pkg.version', [target])
  510. self.assertEqual(new_version, updates[target])
  511. ret = self.run_state('pkg.latest', name=target, refresh=False,
  512. only_upgrade=True)
  513. self.assertEqual(
  514. ret['pkg_|-{0}_|-{0}_|-latest'.format(target)]['comment'],
  515. 'Package {0} is already up-to-date'.format(target)
  516. )
  517. @requires_system_grains
  518. def test_pkg_013_installed_with_wildcard_version(self, grains=None):
  519. '''
  520. This is a destructive test as it installs and then removes a package
  521. '''
  522. # Skip test if package manager not available
  523. if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
  524. self.skipTest('Package manager is not available')
  525. os_family = grains.get('os_family', '')
  526. if os_family not in _WILDCARDS_SUPPORTED:
  527. self.skipTest(
  528. 'Wildcards only supported on {0}'.format(
  529. ', '.join(_WILDCARDS_SUPPORTED)
  530. )
  531. )
  532. pkg_targets = _PKG_TARGETS.get(os_family, [])
  533. # Make sure that we have targets that match the os_family. If this
  534. # fails then the _PKG_TARGETS dict above needs to have an entry added,
  535. # with two packages that are not installed before these tests are run
  536. self.assertTrue(pkg_targets)
  537. target = pkg_targets[0]
  538. version = self.run_function('pkg.version', [target])
  539. # If this assert fails, we need to find new targets, this test needs to
  540. # be able to test successful installation of packages, so this package
  541. # needs to not be installed before we run the states below
  542. self.assertFalse(version)
  543. ret = self.run_state(
  544. 'pkg.installed',
  545. name=target,
  546. version='*',
  547. refresh=False,
  548. )
  549. self.assertSaltTrueReturn(ret)
  550. # Repeat state, should pass
  551. ret = self.run_state(
  552. 'pkg.installed',
  553. name=target,
  554. version='*',
  555. refresh=False,
  556. )
  557. expected_comment = (
  558. 'All specified packages are already installed and are at the '
  559. 'desired version'
  560. )
  561. self.assertSaltTrueReturn(ret)
  562. self.assertEqual(ret[next(iter(ret))]['comment'], expected_comment)
  563. # Repeat one more time with unavailable version, test should fail
  564. ret = self.run_state(
  565. 'pkg.installed',
  566. name=target,
  567. version='93413*',
  568. refresh=False,
  569. )
  570. self.assertSaltFalseReturn(ret)
  571. # Clean up
  572. ret = self.run_state('pkg.removed', name=target)
  573. self.assertSaltTrueReturn(ret)
  574. @requires_system_grains
  575. def test_pkg_014_installed_with_comparison_operator(self, grains=None):
  576. '''
  577. This is a destructive test as it installs and then removes a package
  578. '''
  579. # Skip test if package manager not available
  580. if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
  581. self.skipTest('Package manager is not available')
  582. os_family = grains.get('os_family', '')
  583. if os_family not in ('Debian', 'RedHat'):
  584. self.skipTest('Comparison operator not specially implemented')
  585. pkg_targets = _PKG_TARGETS.get(os_family, [])
  586. # Make sure that we have targets that match the os_family. If this
  587. # fails then the _PKG_TARGETS dict above needs to have an entry added,
  588. # with two packages that are not installed before these tests are run
  589. self.assertTrue(pkg_targets)
  590. target = pkg_targets[0]
  591. version = self.run_function('pkg.version', [target])
  592. # If this assert fails, we need to find new targets, this test needs to
  593. # be able to test successful installation of packages, so this package
  594. # needs to not be installed before we run the states below
  595. self.assertFalse(version)
  596. latest_version = self.run_function(
  597. 'pkg.latest_version',
  598. [target],
  599. refresh=False)
  600. try:
  601. ret = self.run_state(
  602. 'pkg.installed',
  603. name=target,
  604. version='<9999999',
  605. refresh=False,
  606. )
  607. self.assertSaltTrueReturn(ret)
  608. # The version that was installed should be the latest available
  609. version = self.run_function('pkg.version', [target])
  610. self.assertTrue(version, latest_version)
  611. finally:
  612. # Clean up
  613. ret = self.run_state('pkg.removed', name=target)
  614. self.assertSaltTrueReturn(ret)
  615. @requires_system_grains
  616. def test_pkg_014_installed_missing_release(self, grains=None): # pylint: disable=unused-argument
  617. '''
  618. Tests that a version number missing the release portion still resolves
  619. as correctly installed. For example, version 2.0.2 instead of 2.0.2-1.el7
  620. '''
  621. os_family = grains.get('os_family', '')
  622. if os_family.lower() != 'redhat':
  623. self.skipTest('Test only runs on RedHat OS family')
  624. pkg_targets = _PKG_TARGETS.get(os_family, [])
  625. # Make sure that we have targets that match the os_family. If this
  626. # fails then the _PKG_TARGETS dict above needs to have an entry added,
  627. # with two packages that are not installed before these tests are run
  628. self.assertTrue(pkg_targets)
  629. target = pkg_targets[0]
  630. version = self.run_function('pkg.version', [target])
  631. # If this assert fails, we need to find new targets, this test needs to
  632. # be able to test successful installation of packages, so this package
  633. # needs to not be installed before we run the states below
  634. self.assertFalse(version)
  635. ret = self.run_state(
  636. 'pkg.installed',
  637. name=target,
  638. version=salt.utils.pkg.rpm.version_to_evr(version)[1],
  639. refresh=False,
  640. )
  641. self.assertSaltTrueReturn(ret)
  642. # Clean up
  643. ret = self.run_state('pkg.removed', name=target)
  644. self.assertSaltTrueReturn(ret)
  645. @requires_salt_modules('pkg.group_install')
  646. @requires_system_grains
  647. def test_group_installed_handle_missing_package_group(self, grains=None): # pylint: disable=unused-argument
  648. '''
  649. Tests that a CommandExecutionError is caught and the state returns False when
  650. the package group is missing. Before this fix, the state would stacktrace.
  651. See Issue #35819 for bug report.
  652. '''
  653. # Skip test if package manager not available
  654. if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
  655. self.skipTest('Package manager is not available')
  656. # Group install not available message
  657. grp_install_msg = 'pkg.group_install not available for this platform'
  658. # Run the pkg.group_installed state with a fake package group
  659. ret = self.run_state('pkg.group_installed', name='handle_missing_pkg_group',
  660. skip=['foo-bar-baz'])
  661. ret_comment = ret['pkg_|-handle_missing_pkg_group_|-handle_missing_pkg_group_|-group_installed']['comment']
  662. # Not all package managers support group_installed. Skip this test if not supported.
  663. if ret_comment == grp_install_msg:
  664. self.skipTest(grp_install_msg)
  665. # Test state should return False and should have the right comment
  666. self.assertSaltFalseReturn(ret)
  667. self.assertEqual(ret_comment, 'An error was encountered while installing/updating group '
  668. '\'handle_missing_pkg_group\': Group \'handle_missing_pkg_group\' '
  669. 'not found.')
  670. @skipIf(salt.utils.platform.is_windows(), 'minion is windows')
  671. @requires_system_grains
  672. def test_pkg_cap_001_installed(self, grains=None):
  673. '''
  674. This is a destructive test as it installs and then removes a package
  675. '''
  676. # Skip test if package manager not available
  677. if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
  678. self.skipTest('Package manager is not available')
  679. os_family = grains.get('os_family', '')
  680. pkg_cap_targets = _PKG_CAP_TARGETS.get(os_family, [])
  681. if not len(pkg_cap_targets) > 0:
  682. self.skipTest('Capability not provided')
  683. target, realpkg = pkg_cap_targets[0]
  684. version = self.run_function('pkg.version', [target])
  685. realver = self.run_function('pkg.version', [realpkg])
  686. # If this assert fails, we need to find new targets, this test needs to
  687. # be able to test successful installation of packages, so this package
  688. # needs to not be installed before we run the states below
  689. self.assertFalse(version)
  690. self.assertFalse(realver)
  691. try:
  692. ret = self.run_state('pkg.installed', name=target, refresh=False, resolve_capabilities=True, test=True)
  693. self.assertInSaltComment("The following packages would be installed/updated: {0}".format(realpkg), ret)
  694. ret = self.run_state('pkg.installed', name=target, refresh=False, resolve_capabilities=True)
  695. self.assertSaltTrueReturn(ret)
  696. finally:
  697. ret = self.run_state('pkg.removed', name=realpkg)
  698. self.assertSaltTrueReturn(ret)
  699. @skipIf(salt.utils.platform.is_windows(), 'minion is windows')
  700. @requires_system_grains
  701. def test_pkg_cap_002_already_installed(self, grains=None):
  702. '''
  703. This is a destructive test as it installs and then removes a package
  704. '''
  705. # Skip test if package manager not available
  706. if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
  707. self.skipTest('Package manager is not available')
  708. os_family = grains.get('os_family', '')
  709. pkg_cap_targets = _PKG_CAP_TARGETS.get(os_family, [])
  710. if not len(pkg_cap_targets) > 0:
  711. self.skipTest('Capability not provided')
  712. target, realpkg = pkg_cap_targets[0]
  713. version = self.run_function('pkg.version', [target])
  714. realver = self.run_function('pkg.version', [realpkg])
  715. # If this assert fails, we need to find new targets, this test needs to
  716. # be able to test successful installation of packages, so this package
  717. # needs to not be installed before we run the states below
  718. self.assertFalse(version)
  719. self.assertFalse(realver)
  720. try:
  721. # install the package
  722. ret = self.run_state('pkg.installed', name=realpkg, refresh=False)
  723. self.assertSaltTrueReturn(ret)
  724. # Try to install again. Nothing should be installed this time.
  725. ret = self.run_state('pkg.installed', name=target, refresh=False, resolve_capabilities=True, test=True)
  726. self.assertInSaltComment("All specified packages are already installed", ret)
  727. ret = self.run_state('pkg.installed', name=target, refresh=False, resolve_capabilities=True)
  728. self.assertSaltTrueReturn(ret)
  729. self.assertInSaltComment("packages are already installed", ret)
  730. finally:
  731. ret = self.run_state('pkg.removed', name=realpkg)
  732. self.assertSaltTrueReturn(ret)
  733. @skipIf(salt.utils.platform.is_windows(), 'minion is windows')
  734. @requires_system_grains
  735. def test_pkg_cap_003_installed_multipkg_with_version(self, grains=None):
  736. '''
  737. This is a destructive test as it installs and then removes two packages
  738. '''
  739. # Skip test if package manager not available
  740. if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
  741. self.skipTest('Package manager is not available')
  742. os_family = grains.get('os_family', '')
  743. pkg_cap_targets = _PKG_CAP_TARGETS.get(os_family, [])
  744. if not len(pkg_cap_targets) > 0:
  745. self.skipTest('Capability not provided')
  746. pkg_targets = _PKG_TARGETS.get(os_family, [])
  747. # Don't perform this test on FreeBSD since version specification is not
  748. # supported.
  749. if os_family == 'FreeBSD':
  750. return
  751. # Make sure that we have targets that match the os_family. If this
  752. # fails then the _PKG_TARGETS dict above needs to have an entry added,
  753. # with two packages that are not installed before these tests are run
  754. self.assertTrue(pkg_cap_targets)
  755. self.assertTrue(pkg_targets)
  756. if os_family == 'Arch':
  757. for idx in range(13):
  758. if idx == 12:
  759. raise Exception('Package database locked after 60 seconds, '
  760. 'bailing out')
  761. if not os.path.isfile('/var/lib/pacman/db.lck'):
  762. break
  763. time.sleep(5)
  764. capability, realpkg = pkg_cap_targets[0]
  765. version = latest_version(self.run_function, pkg_targets[0])
  766. realver = latest_version(self.run_function, realpkg)
  767. # If this assert fails, we need to find new targets, this test needs to
  768. # be able to test successful installation of packages, so these
  769. # packages need to not be installed before we run the states below
  770. self.assertTrue(version)
  771. self.assertTrue(realver)
  772. try:
  773. pkgs = [{pkg_targets[0]: version}, pkg_targets[1], {capability: realver}]
  774. ret = self.run_state('pkg.installed',
  775. name='test_pkg_cap_003_installed_multipkg_with_version-install',
  776. pkgs=pkgs,
  777. refresh=False)
  778. self.assertSaltFalseReturn(ret)
  779. ret = self.run_state('pkg.installed',
  780. name='test_pkg_cap_003_installed_multipkg_with_version-install-capability',
  781. pkgs=pkgs,
  782. refresh=False, resolve_capabilities=True, test=True)
  783. self.assertInSaltComment("packages would be installed/updated", ret)
  784. self.assertInSaltComment("{0}={1}".format(realpkg, realver), ret)
  785. ret = self.run_state('pkg.installed',
  786. name='test_pkg_cap_003_installed_multipkg_with_version-install-capability',
  787. pkgs=pkgs,
  788. refresh=False, resolve_capabilities=True)
  789. self.assertSaltTrueReturn(ret)
  790. cleanup_pkgs = pkg_targets
  791. cleanup_pkgs.append(realpkg)
  792. finally:
  793. ret = self.run_state('pkg.removed',
  794. name='test_pkg_cap_003_installed_multipkg_with_version-remove',
  795. pkgs=cleanup_pkgs)
  796. self.assertSaltTrueReturn(ret)
  797. @skipIf(salt.utils.platform.is_windows(), 'minion is windows')
  798. @requires_system_grains
  799. def test_pkg_cap_004_latest(self, grains=None):
  800. '''
  801. This tests pkg.latest with a package that has no epoch (or a zero
  802. epoch).
  803. '''
  804. # Skip test if package manager not available
  805. if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
  806. self.skipTest('Package manager is not available')
  807. os_family = grains.get('os_family', '')
  808. pkg_cap_targets = _PKG_CAP_TARGETS.get(os_family, [])
  809. if not len(pkg_cap_targets) > 0:
  810. self.skipTest('Capability not provided')
  811. target, realpkg = pkg_cap_targets[0]
  812. version = self.run_function('pkg.version', [target])
  813. realver = self.run_function('pkg.version', [realpkg])
  814. # If this assert fails, we need to find new targets, this test needs to
  815. # be able to test successful installation of packages, so this package
  816. # needs to not be installed before we run the states below
  817. self.assertFalse(version)
  818. self.assertFalse(realver)
  819. try:
  820. ret = self.run_state('pkg.latest', name=target, refresh=False, resolve_capabilities=True, test=True)
  821. self.assertInSaltComment("The following packages would be installed/upgraded: {0}".format(realpkg), ret)
  822. ret = self.run_state('pkg.latest', name=target, refresh=False, resolve_capabilities=True)
  823. self.assertSaltTrueReturn(ret)
  824. ret = self.run_state('pkg.latest', name=target, refresh=False, resolve_capabilities=True)
  825. self.assertSaltTrueReturn(ret)
  826. self.assertInSaltComment("is already up-to-date", ret)
  827. finally:
  828. ret = self.run_state('pkg.removed', name=realpkg)
  829. self.assertSaltTrueReturn(ret)
  830. @skipIf(salt.utils.platform.is_windows(), 'minion is windows')
  831. @requires_system_grains
  832. def test_pkg_cap_005_downloaded(self, grains=None):
  833. '''
  834. This is a destructive test as it installs and then removes a package
  835. '''
  836. # Skip test if package manager not available
  837. if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
  838. self.skipTest('Package manager is not available')
  839. os_family = grains.get('os_family', '')
  840. pkg_cap_targets = _PKG_CAP_TARGETS.get(os_family, [])
  841. if not len(pkg_cap_targets) > 0:
  842. self.skipTest('Capability not provided')
  843. target, realpkg = pkg_cap_targets[0]
  844. version = self.run_function('pkg.version', [target])
  845. realver = self.run_function('pkg.version', [realpkg])
  846. # If this assert fails, we need to find new targets, this test needs to
  847. # be able to test successful installation of packages, so this package
  848. # needs to not be installed before we run the states below
  849. self.assertFalse(version)
  850. self.assertFalse(realver)
  851. ret = self.run_state('pkg.downloaded', name=target, refresh=False)
  852. self.assertSaltFalseReturn(ret)
  853. ret = self.run_state('pkg.downloaded', name=target, refresh=False, resolve_capabilities=True, test=True)
  854. self.assertInSaltComment("The following packages would be downloaded: {0}".format(realpkg), ret)
  855. ret = self.run_state('pkg.downloaded', name=target, refresh=False, resolve_capabilities=True)
  856. self.assertSaltTrueReturn(ret)
  857. @skipIf(salt.utils.platform.is_windows(), 'minion is windows')
  858. @requires_system_grains
  859. def test_pkg_cap_006_uptodate(self, grains=None):
  860. '''
  861. This is a destructive test as it installs and then removes a package
  862. '''
  863. # Skip test if package manager not available
  864. if not pkgmgr_avail(self.run_function, self.run_function('grains.items')):
  865. self.skipTest('Package manager is not available')
  866. os_family = grains.get('os_family', '')
  867. pkg_cap_targets = _PKG_CAP_TARGETS.get(os_family, [])
  868. if not len(pkg_cap_targets) > 0:
  869. self.skipTest('Capability not provided')
  870. target, realpkg = pkg_cap_targets[0]
  871. version = self.run_function('pkg.version', [target])
  872. realver = self.run_function('pkg.version', [realpkg])
  873. # If this assert fails, we need to find new targets, this test needs to
  874. # be able to test successful installation of packages, so this package
  875. # needs to not be installed before we run the states below
  876. self.assertFalse(version)
  877. self.assertFalse(realver)
  878. try:
  879. ret = self.run_state('pkg.installed', name=target,
  880. refresh=False, resolve_capabilities=True)
  881. self.assertSaltTrueReturn(ret)
  882. ret = self.run_state('pkg.uptodate',
  883. name='test_pkg_cap_006_uptodate',
  884. pkgs=[target],
  885. refresh=False,
  886. resolve_capabilities=True)
  887. self.assertSaltTrueReturn(ret)
  888. self.assertInSaltComment("System is already up-to-date", ret)
  889. finally:
  890. ret = self.run_state('pkg.removed', name=realpkg)
  891. self.assertSaltTrueReturn(ret)
  892. @skipIf(True, 'WAR ROOM TEMPORARY SKIP') # needs to be rewritten to allow for dnf on Fedora 30 and RHEL 8
  893. @requires_salt_modules('pkg.hold', 'pkg.unhold')
  894. @requires_system_grains
  895. def test_pkg_015_installed_held(self, grains=None): # pylint: disable=unused-argument
  896. '''
  897. Tests that a package can be held even when the package is already installed.
  898. '''
  899. os_family = grains.get('os_family', '')
  900. if os_family.lower() != 'redhat' and os_family.lower() != 'debian':
  901. self.skipTest('Test only runs on RedHat or Debian family')
  902. pkg_targets = _PKG_TARGETS.get(os_family, [])
  903. if os_family.lower() == 'redhat':
  904. # If we're in the Red Hat family first we ensure that
  905. # the yum-plugin-versionlock package is installed
  906. ret = self.run_state(
  907. 'pkg.installed',
  908. name='yum-plugin-versionlock',
  909. refresh=False,
  910. )
  911. self.assertSaltTrueReturn(ret)
  912. # Make sure that we have targets that match the os_family. If this
  913. # fails then the _PKG_TARGETS dict above needs to have an entry added,
  914. # with two packages that are not installed before these tests are run
  915. self.assertTrue(pkg_targets)
  916. target = pkg_targets[0]
  917. # First we ensure that the package is installed
  918. ret = self.run_state(
  919. 'pkg.installed',
  920. name=target,
  921. refresh=False,
  922. )
  923. self.assertSaltTrueReturn(ret)
  924. # Then we check that the package is now held
  925. ret = self.run_state(
  926. 'pkg.installed',
  927. name=target,
  928. hold=True,
  929. refresh=False,
  930. )
  931. # changes from pkg.hold for Red Hat family are different
  932. if os_family.lower() == 'redhat':
  933. target_changes = {'new': 'hold', 'old': ''}
  934. elif os_family.lower() == 'debian':
  935. target_changes = {'new': 'hold', 'old': 'install'}
  936. try:
  937. tag = 'pkg_|-{0}_|-{0}_|-installed'.format(target)
  938. self.assertSaltTrueReturn(ret)
  939. self.assertIn(tag, ret)
  940. self.assertIn('changes', ret[tag])
  941. self.assertIn(target, ret[tag]['changes'])
  942. self.assertEqual(ret[tag]['changes'][target], target_changes)
  943. finally:
  944. # Clean up, unhold package and remove
  945. self.run_function('pkg.unhold', name=target)
  946. ret = self.run_state('pkg.removed', name=target)
  947. self.assertSaltTrueReturn(ret)
  948. if os_family.lower() == 'redhat':
  949. ret = self.run_state('pkg.removed',
  950. name='yum-plugin-versionlock')
  951. self.assertSaltTrueReturn(ret)