test_core.py 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240
  1. # -*- coding: utf-8 -*-
  2. '''
  3. :codeauthor: Erik Johnson <erik@saltstack.com>
  4. '''
  5. # Import Python libs
  6. from __future__ import absolute_import, print_function, unicode_literals
  7. import logging
  8. import os
  9. import socket
  10. import textwrap
  11. # Import Salt Testing Libs
  12. try:
  13. import pytest
  14. except ImportError as import_error:
  15. pytest = None
  16. from tests.support.mixins import LoaderModuleMockMixin
  17. from tests.support.unit import TestCase, skipIf
  18. from tests.support.mock import (
  19. Mock,
  20. MagicMock,
  21. patch,
  22. mock_open,
  23. )
  24. # Import Salt Libs
  25. import salt.utils.dns
  26. import salt.utils.files
  27. import salt.utils.network
  28. import salt.utils.platform
  29. import salt.utils.path
  30. import salt.grains.core as core
  31. # Import 3rd-party libs
  32. from salt.ext import six
  33. from salt._compat import ipaddress
  34. log = logging.getLogger(__name__)
  35. # Globals
  36. IPv4Address = ipaddress.IPv4Address
  37. IPv6Address = ipaddress.IPv6Address
  38. IP4_LOCAL = '127.0.0.1'
  39. IP4_ADD1 = '10.0.0.1'
  40. IP4_ADD2 = '10.0.0.2'
  41. IP6_LOCAL = '::1'
  42. IP6_ADD1 = '2001:4860:4860::8844'
  43. IP6_ADD2 = '2001:4860:4860::8888'
  44. IP6_ADD_SCOPE = 'fe80::6238:e0ff:fe06:3f6b%enp2s0'
  45. OS_RELEASE_DIR = os.path.join(os.path.dirname(__file__), "os-releases")
  46. SOLARIS_DIR = os.path.join(os.path.dirname(__file__), 'solaris')
  47. @skipIf(not pytest, False)
  48. class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin):
  49. '''
  50. Test cases for core grains
  51. '''
  52. def setup_loader_modules(self):
  53. return {core: {}}
  54. @patch("os.path.isfile")
  55. def test_parse_etc_os_release(self, path_isfile_mock):
  56. path_isfile_mock.side_effect = lambda x: x == "/usr/lib/os-release"
  57. with salt.utils.files.fopen(os.path.join(OS_RELEASE_DIR, "ubuntu-17.10")) as os_release_file:
  58. os_release_content = os_release_file.read()
  59. with patch("salt.utils.files.fopen", mock_open(read_data=os_release_content)):
  60. os_release = core._parse_os_release(
  61. '/etc/os-release',
  62. '/usr/lib/os-release')
  63. self.assertEqual(os_release, {
  64. "NAME": "Ubuntu",
  65. "VERSION": "17.10 (Artful Aardvark)",
  66. "ID": "ubuntu",
  67. "ID_LIKE": "debian",
  68. "PRETTY_NAME": "Ubuntu 17.10",
  69. "VERSION_ID": "17.10",
  70. "HOME_URL": "https://www.ubuntu.com/",
  71. "SUPPORT_URL": "https://help.ubuntu.com/",
  72. "BUG_REPORT_URL": "https://bugs.launchpad.net/ubuntu/",
  73. "PRIVACY_POLICY_URL": "https://www.ubuntu.com/legal/terms-and-policies/privacy-policy",
  74. "VERSION_CODENAME": "artful",
  75. "UBUNTU_CODENAME": "artful",
  76. })
  77. def test_parse_cpe_name_wfn(self):
  78. '''
  79. Parse correct CPE_NAME data WFN formatted
  80. :return:
  81. '''
  82. for cpe, cpe_ret in [('cpe:/o:opensuse:leap:15.0',
  83. {'phase': None, 'version': '15.0', 'product': 'leap',
  84. 'vendor': 'opensuse', 'part': 'operating system'}),
  85. ('cpe:/o:vendor:product:42:beta',
  86. {'phase': 'beta', 'version': '42', 'product': 'product',
  87. 'vendor': 'vendor', 'part': 'operating system'})]:
  88. ret = core._parse_cpe_name(cpe)
  89. for key in cpe_ret:
  90. assert key in ret
  91. assert cpe_ret[key] == ret[key]
  92. def test_parse_cpe_name_v23(self):
  93. '''
  94. Parse correct CPE_NAME data v2.3 formatted
  95. :return:
  96. '''
  97. for cpe, cpe_ret in [('cpe:2.3:o:microsoft:windows_xp:5.1.601:beta:*:*:*:*:*:*',
  98. {'phase': 'beta', 'version': '5.1.601', 'product': 'windows_xp',
  99. 'vendor': 'microsoft', 'part': 'operating system'}),
  100. ('cpe:2.3:h:corellian:millenium_falcon:1.0:*:*:*:*:*:*:*',
  101. {'phase': None, 'version': '1.0', 'product': 'millenium_falcon',
  102. 'vendor': 'corellian', 'part': 'hardware'}),
  103. ('cpe:2.3:*:dark_empire:light_saber:3.0:beta:*:*:*:*:*:*',
  104. {'phase': 'beta', 'version': '3.0', 'product': 'light_saber',
  105. 'vendor': 'dark_empire', 'part': None})]:
  106. ret = core._parse_cpe_name(cpe)
  107. for key in cpe_ret:
  108. assert key in ret
  109. assert cpe_ret[key] == ret[key]
  110. def test_parse_cpe_name_broken(self):
  111. '''
  112. Parse broken CPE_NAME data
  113. :return:
  114. '''
  115. for cpe in ['cpe:broken', 'cpe:broken:in:all:ways:*:*:*:*',
  116. 'cpe:x:still:broken:123', 'who:/knows:what:is:here']:
  117. assert core._parse_cpe_name(cpe) == {}
  118. def test_missing_os_release(self):
  119. with patch('salt.utils.files.fopen', mock_open(read_data={})):
  120. os_release = core._parse_os_release('/etc/os-release', '/usr/lib/os-release')
  121. self.assertEqual(os_release, {})
  122. @skipIf(not salt.utils.platform.is_windows(), 'System is not Windows')
  123. def test__windows_platform_data(self):
  124. grains = core._windows_platform_data()
  125. keys = ['biosversion',
  126. 'osrelease',
  127. 'kernelrelease',
  128. 'motherboard',
  129. 'serialnumber',
  130. 'timezone',
  131. 'manufacturer',
  132. 'kernelversion',
  133. 'osservicepack',
  134. 'virtual',
  135. 'productname',
  136. 'osfullname',
  137. 'osmanufacturer',
  138. 'osversion',
  139. 'windowsdomain']
  140. for key in keys:
  141. self.assertIn(key, grains)
  142. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  143. def test_gnu_slash_linux_in_os_name(self):
  144. '''
  145. Test to return a list of all enabled services
  146. '''
  147. _path_exists_map = {
  148. '/proc/1/cmdline': False
  149. }
  150. _path_isfile_map = {}
  151. _cmd_run_map = {
  152. 'dpkg --print-architecture': 'amd64',
  153. }
  154. path_exists_mock = MagicMock(side_effect=lambda x: _path_exists_map[x])
  155. path_isfile_mock = MagicMock(
  156. side_effect=lambda x: _path_isfile_map.get(x, False)
  157. )
  158. cmd_run_mock = MagicMock(
  159. side_effect=lambda x: _cmd_run_map[x]
  160. )
  161. empty_mock = MagicMock(return_value={})
  162. orig_import = __import__
  163. if six.PY2:
  164. built_in = '__builtin__'
  165. else:
  166. built_in = 'builtins'
  167. def _import_mock(name, *args):
  168. if name == 'lsb_release':
  169. raise ImportError('No module named lsb_release')
  170. return orig_import(name, *args)
  171. # - Skip the first if statement
  172. # - Skip the selinux/systemd stuff (not pertinent)
  173. # - Skip the init grain compilation (not pertinent)
  174. # - Ensure that lsb_release fails to import
  175. # - Skip all the /etc/*-release stuff (not pertinent)
  176. # - Mock linux_distribution to give us the OS name that we want
  177. # - Make a bunch of functions return empty dicts, we don't care about
  178. # these grains for the purposes of this test.
  179. # - Mock the osarch
  180. distro_mock = MagicMock(return_value=('Debian GNU/Linux', '8.3', ''))
  181. with patch.object(salt.utils.platform, 'is_proxy',
  182. MagicMock(return_value=False)), \
  183. patch.object(core, '_linux_bin_exists',
  184. MagicMock(return_value=False)), \
  185. patch.object(os.path, 'exists', path_exists_mock), \
  186. patch('{0}.__import__'.format(built_in), side_effect=_import_mock), \
  187. patch.object(os.path, 'isfile', path_isfile_mock), \
  188. patch.object(core, '_parse_lsb_release', empty_mock), \
  189. patch.object(core, '_parse_os_release', empty_mock), \
  190. patch.object(core, '_parse_lsb_release', empty_mock), \
  191. patch.object(core, 'linux_distribution', distro_mock), \
  192. patch.object(core, '_linux_cpudata', empty_mock), \
  193. patch.object(core, '_linux_gpu_data', empty_mock), \
  194. patch.object(core, '_memdata', empty_mock), \
  195. patch.object(core, '_hw_data', empty_mock), \
  196. patch.object(core, '_virtual', empty_mock), \
  197. patch.object(core, '_ps', empty_mock), \
  198. patch.dict(core.__salt__, {'cmd.run': cmd_run_mock}):
  199. os_grains = core.os_data()
  200. self.assertEqual(os_grains.get('os_family'), 'Debian')
  201. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  202. def test_suse_os_from_cpe_data(self):
  203. '''
  204. Test if 'os' grain is parsed from CPE_NAME of /etc/os-release
  205. '''
  206. _path_exists_map = {
  207. '/proc/1/cmdline': False
  208. }
  209. _os_release_map = {
  210. 'NAME': 'SLES',
  211. 'VERSION': '12-SP1',
  212. 'VERSION_ID': '12.1',
  213. 'PRETTY_NAME': 'SUSE Linux Enterprise Server 12 SP1',
  214. 'ID': 'sles',
  215. 'ANSI_COLOR': '0;32',
  216. 'CPE_NAME': 'cpe:/o:suse:sles:12:sp1'
  217. }
  218. path_exists_mock = MagicMock(side_effect=lambda x: _path_exists_map[x])
  219. empty_mock = MagicMock(return_value={})
  220. osarch_mock = MagicMock(return_value="amd64")
  221. os_release_mock = MagicMock(return_value=_os_release_map)
  222. orig_import = __import__
  223. if six.PY2:
  224. built_in = '__builtin__'
  225. else:
  226. built_in = 'builtins'
  227. def _import_mock(name, *args):
  228. if name == 'lsb_release':
  229. raise ImportError('No module named lsb_release')
  230. return orig_import(name, *args)
  231. distro_mock = MagicMock(
  232. return_value=('SUSE Linux Enterprise Server ', '12', 'x86_64')
  233. )
  234. # - Skip the first if statement
  235. # - Skip the selinux/systemd stuff (not pertinent)
  236. # - Skip the init grain compilation (not pertinent)
  237. # - Ensure that lsb_release fails to import
  238. # - Skip all the /etc/*-release stuff (not pertinent)
  239. # - Mock linux_distribution to give us the OS name that we want
  240. # - Mock the osarch
  241. with patch.object(salt.utils.platform, 'is_proxy',
  242. MagicMock(return_value=False)), \
  243. patch.object(core, '_linux_bin_exists',
  244. MagicMock(return_value=False)), \
  245. patch.object(os.path, 'exists', path_exists_mock), \
  246. patch('{0}.__import__'.format(built_in),
  247. side_effect=_import_mock), \
  248. patch.object(os.path, 'isfile', MagicMock(return_value=False)), \
  249. patch.object(core, '_parse_os_release', os_release_mock), \
  250. patch.object(core, '_parse_lsb_release', empty_mock), \
  251. patch.object(core, 'linux_distribution', distro_mock), \
  252. patch.object(core, '_linux_gpu_data', empty_mock), \
  253. patch.object(core, '_hw_data', empty_mock), \
  254. patch.object(core, '_linux_cpudata', empty_mock), \
  255. patch.object(core, '_virtual', empty_mock), \
  256. patch.dict(core.__salt__, {'cmd.run': osarch_mock}):
  257. os_grains = core.os_data()
  258. self.assertEqual(os_grains.get('os_family'), 'Suse')
  259. self.assertEqual(os_grains.get('os'), 'SUSE')
  260. def _run_os_grains_tests(self, os_release_filename, os_release_map, expectation):
  261. path_isfile_mock = MagicMock(side_effect=lambda x: x in os_release_map.get('files', []))
  262. empty_mock = MagicMock(return_value={})
  263. osarch_mock = MagicMock(return_value="amd64")
  264. if os_release_filename:
  265. os_release_data = core._parse_os_release(
  266. os.path.join(OS_RELEASE_DIR, os_release_filename)
  267. )
  268. else:
  269. os_release_data = os_release_map.get('os_release_file', {})
  270. os_release_mock = MagicMock(return_value=os_release_data)
  271. orig_import = __import__
  272. if six.PY2:
  273. built_in = '__builtin__'
  274. else:
  275. built_in = 'builtins'
  276. def _import_mock(name, *args):
  277. if name == 'lsb_release':
  278. raise ImportError('No module named lsb_release')
  279. return orig_import(name, *args)
  280. suse_release_file = os_release_map.get('suse_release_file')
  281. file_contents = {'/proc/1/cmdline': ''}
  282. if suse_release_file:
  283. file_contents['/etc/SuSE-release'] = suse_release_file
  284. # - Skip the first if statement
  285. # - Skip the selinux/systemd stuff (not pertinent)
  286. # - Skip the init grain compilation (not pertinent)
  287. # - Ensure that lsb_release fails to import
  288. # - Skip all the /etc/*-release stuff (not pertinent)
  289. # - Mock linux_distribution to give us the OS name that we want
  290. # - Mock the osarch
  291. distro_mock = MagicMock(return_value=os_release_map['linux_distribution'])
  292. with patch.object(salt.utils.platform, 'is_proxy', MagicMock(return_value=False)), \
  293. patch.object(core, '_linux_bin_exists', MagicMock(return_value=False)), \
  294. patch.object(os.path, 'exists', path_isfile_mock), \
  295. patch('{0}.__import__'.format(built_in), side_effect=_import_mock), \
  296. patch.object(os.path, 'isfile', path_isfile_mock), \
  297. patch.object(core, '_parse_os_release', os_release_mock), \
  298. patch.object(core, '_parse_lsb_release', empty_mock), \
  299. patch('salt.utils.files.fopen', mock_open(read_data=file_contents)), \
  300. patch.object(core, 'linux_distribution', distro_mock), \
  301. patch.object(core, '_linux_gpu_data', empty_mock), \
  302. patch.object(core, '_linux_cpudata', empty_mock), \
  303. patch.object(core, '_virtual', empty_mock), \
  304. patch.dict(core.__salt__, {'cmd.run': osarch_mock}):
  305. os_grains = core.os_data()
  306. grains = {k: v for k, v in os_grains.items()
  307. if k in set(["os", "os_family", "osfullname", "oscodename", "osfinger",
  308. "osrelease", "osrelease_info", "osmajorrelease"])}
  309. self.assertEqual(grains, expectation)
  310. def _run_suse_os_grains_tests(self, os_release_map, expectation):
  311. os_release_map['linux_distribution'] = ('SUSE test', 'version', 'arch')
  312. expectation['os'] = 'SUSE'
  313. expectation['os_family'] = 'Suse'
  314. self._run_os_grains_tests(None, os_release_map, expectation)
  315. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  316. def test_suse_os_grains_sles11sp3(self):
  317. '''
  318. Test if OS grains are parsed correctly in SLES 11 SP3
  319. '''
  320. _os_release_map = {
  321. 'suse_release_file': textwrap.dedent('''
  322. SUSE Linux Enterprise Server 11 (x86_64)
  323. VERSION = 11
  324. PATCHLEVEL = 3
  325. '''),
  326. 'files': ["/etc/SuSE-release"],
  327. }
  328. expectation = {
  329. 'oscodename': 'SUSE Linux Enterprise Server 11 SP3',
  330. 'osfullname': "SLES",
  331. 'osrelease': '11.3',
  332. 'osrelease_info': (11, 3),
  333. 'osmajorrelease': 11,
  334. 'osfinger': 'SLES-11',
  335. }
  336. self._run_suse_os_grains_tests(_os_release_map, expectation)
  337. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  338. def test_suse_os_grains_sles11sp4(self):
  339. '''
  340. Test if OS grains are parsed correctly in SLES 11 SP4
  341. '''
  342. _os_release_map = {
  343. 'os_release_file': {
  344. 'NAME': 'SLES',
  345. 'VERSION': '11.4',
  346. 'VERSION_ID': '11.4',
  347. 'PRETTY_NAME': 'SUSE Linux Enterprise Server 11 SP4',
  348. 'ID': 'sles',
  349. 'ANSI_COLOR': '0;32',
  350. 'CPE_NAME': 'cpe:/o:suse:sles:11:4'
  351. },
  352. }
  353. expectation = {
  354. 'oscodename': 'SUSE Linux Enterprise Server 11 SP4',
  355. 'osfullname': "SLES",
  356. 'osrelease': '11.4',
  357. 'osrelease_info': (11, 4),
  358. 'osmajorrelease': 11,
  359. 'osfinger': 'SLES-11',
  360. }
  361. self._run_suse_os_grains_tests(_os_release_map, expectation)
  362. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  363. def test_suse_os_grains_sles12(self):
  364. '''
  365. Test if OS grains are parsed correctly in SLES 12
  366. '''
  367. _os_release_map = {
  368. 'os_release_file': {
  369. 'NAME': 'SLES',
  370. 'VERSION': '12',
  371. 'VERSION_ID': '12',
  372. 'PRETTY_NAME': 'SUSE Linux Enterprise Server 12',
  373. 'ID': 'sles',
  374. 'ANSI_COLOR': '0;32',
  375. 'CPE_NAME': 'cpe:/o:suse:sles:12'
  376. },
  377. }
  378. expectation = {
  379. 'oscodename': 'SUSE Linux Enterprise Server 12',
  380. 'osfullname': "SLES",
  381. 'osrelease': '12',
  382. 'osrelease_info': (12,),
  383. 'osmajorrelease': 12,
  384. 'osfinger': 'SLES-12',
  385. }
  386. self._run_suse_os_grains_tests(_os_release_map, expectation)
  387. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  388. def test_suse_os_grains_sles12sp1(self):
  389. '''
  390. Test if OS grains are parsed correctly in SLES 12 SP1
  391. '''
  392. _os_release_map = {
  393. 'os_release_file': {
  394. 'NAME': 'SLES',
  395. 'VERSION': '12-SP1',
  396. 'VERSION_ID': '12.1',
  397. 'PRETTY_NAME': 'SUSE Linux Enterprise Server 12 SP1',
  398. 'ID': 'sles',
  399. 'ANSI_COLOR': '0;32',
  400. 'CPE_NAME': 'cpe:/o:suse:sles:12:sp1'
  401. },
  402. }
  403. expectation = {
  404. 'oscodename': 'SUSE Linux Enterprise Server 12 SP1',
  405. 'osfullname': "SLES",
  406. 'osrelease': '12.1',
  407. 'osrelease_info': (12, 1),
  408. 'osmajorrelease': 12,
  409. 'osfinger': 'SLES-12',
  410. }
  411. self._run_suse_os_grains_tests(_os_release_map, expectation)
  412. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  413. def test_suse_os_grains_opensuse_leap_42_1(self):
  414. '''
  415. Test if OS grains are parsed correctly in openSUSE Leap 42.1
  416. '''
  417. _os_release_map = {
  418. 'os_release_file': {
  419. 'NAME': 'openSUSE Leap',
  420. 'VERSION': '42.1',
  421. 'VERSION_ID': '42.1',
  422. 'PRETTY_NAME': 'openSUSE Leap 42.1 (x86_64)',
  423. 'ID': 'opensuse',
  424. 'ANSI_COLOR': '0;32',
  425. 'CPE_NAME': 'cpe:/o:opensuse:opensuse:42.1'
  426. },
  427. }
  428. expectation = {
  429. 'oscodename': 'openSUSE Leap 42.1 (x86_64)',
  430. 'osfullname': "Leap",
  431. 'osrelease': '42.1',
  432. 'osrelease_info': (42, 1),
  433. 'osmajorrelease': 42,
  434. 'osfinger': 'Leap-42',
  435. }
  436. self._run_suse_os_grains_tests(_os_release_map, expectation)
  437. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  438. def test_suse_os_grains_tumbleweed(self):
  439. '''
  440. Test if OS grains are parsed correctly in openSUSE Tumbleweed
  441. '''
  442. _os_release_map = {
  443. 'os_release_file': {
  444. 'NAME': 'openSUSE',
  445. 'VERSION': 'Tumbleweed',
  446. 'VERSION_ID': '20160504',
  447. 'PRETTY_NAME': 'openSUSE Tumbleweed (20160504) (x86_64)',
  448. 'ID': 'opensuse',
  449. 'ANSI_COLOR': '0;32',
  450. 'CPE_NAME': 'cpe:/o:opensuse:opensuse:20160504'
  451. },
  452. }
  453. expectation = {
  454. 'oscodename': 'openSUSE Tumbleweed (20160504) (x86_64)',
  455. 'osfullname': "Tumbleweed",
  456. 'osrelease': '20160504',
  457. 'osrelease_info': (20160504,),
  458. 'osmajorrelease': 20160504,
  459. 'osfinger': 'Tumbleweed-20160504',
  460. }
  461. self._run_suse_os_grains_tests(_os_release_map, expectation)
  462. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  463. def test_debian_7_os_grains(self):
  464. '''
  465. Test if OS grains are parsed correctly in Debian 7 "wheezy"
  466. '''
  467. _os_release_map = {
  468. 'linux_distribution': ('debian', '7.11', ''),
  469. }
  470. expectation = {
  471. 'os': 'Debian',
  472. 'os_family': 'Debian',
  473. 'oscodename': 'wheezy',
  474. 'osfullname': 'Debian GNU/Linux',
  475. 'osrelease': '7',
  476. 'osrelease_info': (7,),
  477. 'osmajorrelease': 7,
  478. 'osfinger': 'Debian-7',
  479. }
  480. self._run_os_grains_tests("debian-7", _os_release_map, expectation)
  481. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  482. def test_debian_8_os_grains(self):
  483. '''
  484. Test if OS grains are parsed correctly in Debian 8 "jessie"
  485. '''
  486. _os_release_map = {
  487. 'linux_distribution': ('debian', '8.10', ''),
  488. }
  489. expectation = {
  490. 'os': 'Debian',
  491. 'os_family': 'Debian',
  492. 'oscodename': 'jessie',
  493. 'osfullname': 'Debian GNU/Linux',
  494. 'osrelease': '8',
  495. 'osrelease_info': (8,),
  496. 'osmajorrelease': 8,
  497. 'osfinger': 'Debian-8',
  498. }
  499. self._run_os_grains_tests("debian-8", _os_release_map, expectation)
  500. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  501. def test_debian_9_os_grains(self):
  502. '''
  503. Test if OS grains are parsed correctly in Debian 9 "stretch"
  504. '''
  505. _os_release_map = {
  506. 'linux_distribution': ('debian', '9.3', ''),
  507. }
  508. expectation = {
  509. 'os': 'Debian',
  510. 'os_family': 'Debian',
  511. 'oscodename': 'stretch',
  512. 'osfullname': 'Debian GNU/Linux',
  513. 'osrelease': '9',
  514. 'osrelease_info': (9,),
  515. 'osmajorrelease': 9,
  516. 'osfinger': 'Debian-9',
  517. }
  518. self._run_os_grains_tests("debian-9", _os_release_map, expectation)
  519. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  520. def test_ubuntu_xenial_os_grains(self):
  521. '''
  522. Test if OS grains are parsed correctly in Ubuntu 16.04 "Xenial Xerus"
  523. '''
  524. _os_release_map = {
  525. 'linux_distribution': ('Ubuntu', '16.04', 'xenial'),
  526. }
  527. expectation = {
  528. 'os': 'Ubuntu',
  529. 'os_family': 'Debian',
  530. 'oscodename': 'xenial',
  531. 'osfullname': 'Ubuntu',
  532. 'osrelease': '16.04',
  533. 'osrelease_info': (16, 4),
  534. 'osmajorrelease': 16,
  535. 'osfinger': 'Ubuntu-16.04',
  536. }
  537. self._run_os_grains_tests("ubuntu-16.04", _os_release_map, expectation)
  538. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  539. def test_ubuntu_artful_os_grains(self):
  540. '''
  541. Test if OS grains are parsed correctly in Ubuntu 17.10 "Artful Aardvark"
  542. '''
  543. _os_release_map = {
  544. 'linux_distribution': ('Ubuntu', '17.10', 'artful'),
  545. }
  546. expectation = {
  547. 'os': 'Ubuntu',
  548. 'os_family': 'Debian',
  549. 'oscodename': 'artful',
  550. 'osfullname': 'Ubuntu',
  551. 'osrelease': '17.10',
  552. 'osrelease_info': (17, 10),
  553. 'osmajorrelease': 17,
  554. 'osfinger': 'Ubuntu-17.10',
  555. }
  556. self._run_os_grains_tests("ubuntu-17.10", _os_release_map, expectation)
  557. @skipIf(not salt.utils.platform.is_windows(), 'System is not Windows')
  558. def test_windows_platform_data(self):
  559. '''
  560. Test the _windows_platform_data function
  561. '''
  562. grains = ['biosversion', 'kernelrelease', 'kernelversion',
  563. 'manufacturer', 'motherboard', 'osfullname', 'osmanufacturer',
  564. 'osrelease', 'osservicepack', 'osversion', 'productname',
  565. 'serialnumber', 'timezone', 'virtual', 'windowsdomain',
  566. 'windowsdomaintype']
  567. returned_grains = core._windows_platform_data()
  568. for grain in grains:
  569. self.assertIn(grain, returned_grains)
  570. valid_types = ['Unknown', 'Unjoined', 'Workgroup', 'Domain']
  571. self.assertIn(returned_grains['windowsdomaintype'], valid_types)
  572. valid_releases = ['Vista', '7', '8', '8.1', '10', '2008Server',
  573. '2008ServerR2', '2012Server', '2012ServerR2',
  574. '2016Server', '2019Server']
  575. self.assertIn(returned_grains['osrelease'], valid_releases)
  576. def test__windows_os_release_grain(self):
  577. versions = {
  578. 'Windows 10 Home': '10',
  579. 'Windows 10 Pro': '10',
  580. 'Windows 10 Pro for Workstations': '10',
  581. 'Windows 10 Pro Education': '10',
  582. 'Windows 10 Enterprise': '10',
  583. 'Windows 10 Enterprise LTSB': '10',
  584. 'Windows 10 Education': '10',
  585. 'Windows 10 IoT Core': '10',
  586. 'Windows 10 IoT Enterprise': '10',
  587. 'Windows 10 S': '10',
  588. 'Windows 8.1': '8.1',
  589. 'Windows 8.1 Pro': '8.1',
  590. 'Windows 8.1 Enterprise': '8.1',
  591. 'Windows 8.1 OEM': '8.1',
  592. 'Windows 8.1 with Bing': '8.1',
  593. 'Windows 8': '8',
  594. 'Windows 8 Pro': '8',
  595. 'Windows 8 Enterprise': '8',
  596. 'Windows 8 OEM': '8',
  597. 'Windows 7 Starter': '7',
  598. 'Windows 7 Home Basic': '7',
  599. 'Windows 7 Home Premium': '7',
  600. 'Windows 7 Professional': '7',
  601. 'Windows 7 Enterprise': '7',
  602. 'Windows 7 Ultimate': '7',
  603. 'Windows Thin PC': 'Thin',
  604. 'Windows Vista Starter': 'Vista',
  605. 'Windows Vista Home Basic': 'Vista',
  606. 'Windows Vista Home Premium': 'Vista',
  607. 'Windows Vista Business': 'Vista',
  608. 'Windows Vista Enterprise': 'Vista',
  609. 'Windows Vista Ultimate': 'Vista',
  610. 'Windows Server 2019 Essentials': '2019Server',
  611. 'Windows Server 2019 Standard': '2019Server',
  612. 'Windows Server 2019 Datacenter': '2019Server',
  613. 'Windows Server 2016 Essentials': '2016Server',
  614. 'Windows Server 2016 Standard': '2016Server',
  615. 'Windows Server 2016 Datacenter': '2016Server',
  616. 'Windows Server 2012 R2 Foundation': '2012ServerR2',
  617. 'Windows Server 2012 R2 Essentials': '2012ServerR2',
  618. 'Windows Server 2012 R2 Standard': '2012ServerR2',
  619. 'Windows Server 2012 R2 Datacenter': '2012ServerR2',
  620. 'Windows Server 2012 Foundation': '2012Server',
  621. 'Windows Server 2012 Essentials': '2012Server',
  622. 'Windows Server 2012 Standard': '2012Server',
  623. 'Windows Server 2012 Datacenter': '2012Server',
  624. 'Windows MultiPoint Server 2012': '2012Server',
  625. 'Windows Small Business Server 2011': '2011Server',
  626. 'Windows MultiPoint Server 2011': '2011Server',
  627. 'Windows Home Server 2011': '2011Server',
  628. 'Windows MultiPoint Server 2010': '2010Server',
  629. 'Windows Server 2008 R2 Foundation': '2008ServerR2',
  630. 'Windows Server 2008 R2 Standard': '2008ServerR2',
  631. 'Windows Server 2008 R2 Enterprise': '2008ServerR2',
  632. 'Windows Server 2008 R2 Datacenter': '2008ServerR2',
  633. 'Windows Server 2008 R2 for Itanium-based Systems': '2008ServerR2',
  634. 'Windows Web Server 2008 R2': '2008ServerR2',
  635. 'Windows Storage Server 2008 R2': '2008ServerR2',
  636. 'Windows HPC Server 2008 R2': '2008ServerR2',
  637. 'Windows Server 2008 Standard': '2008Server',
  638. 'Windows Server 2008 Enterprise': '2008Server',
  639. 'Windows Server 2008 Datacenter': '2008Server',
  640. 'Windows Server 2008 for Itanium-based Systems': '2008Server',
  641. 'Windows Server Foundation 2008': '2008Server',
  642. 'Windows Essential Business Server 2008': '2008Server',
  643. 'Windows HPC Server 2008': '2008Server',
  644. 'Windows Small Business Server 2008': '2008Server',
  645. 'Windows Storage Server 2008': '2008Server',
  646. 'Windows Web Server 2008': '2008Server'
  647. }
  648. for caption in versions:
  649. version = core._windows_os_release_grain(caption, 1)
  650. self.assertEqual(
  651. version,
  652. versions[caption],
  653. 'version: {0}\n'
  654. 'found: {1}\n'
  655. 'caption: {2}'.format(version, versions[caption], caption)
  656. )
  657. embedded_versions = {
  658. 'Windows Embedded 8.1 Industry Pro': '8.1',
  659. 'Windows Embedded 8 Industry Pro': '8',
  660. 'Windows POSReady 7': '7',
  661. 'Windows Embedded Standard 7': '7',
  662. 'Windows Embedded POSReady 2009': '2009',
  663. 'Windows Embedded Standard 2009': '2009',
  664. 'Windows XP Embedded': 'XP',
  665. }
  666. for caption in embedded_versions:
  667. version = core._windows_os_release_grain(caption, 1)
  668. self.assertEqual(
  669. version,
  670. embedded_versions[caption],
  671. '{0} != {1}\n'
  672. 'version: {0}\n'
  673. 'found: {1}\n'
  674. 'caption: {2}'.format(version, embedded_versions[caption], caption)
  675. )
  676. # Special Cases
  677. # Windows Embedded Standard is Windows 7
  678. caption = 'Windows Embedded Standard'
  679. with patch('platform.release', MagicMock(return_value='7')):
  680. version = core._windows_os_release_grain(caption, 1)
  681. self.assertEqual(version, '7')
  682. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  683. def test_linux_memdata(self):
  684. '''
  685. Test memdata on Linux systems
  686. '''
  687. _proc_meminfo = textwrap.dedent('''\
  688. MemTotal: 16277028 kB
  689. SwapTotal: 4789244 kB''')
  690. with patch('salt.utils.files.fopen', mock_open(read_data=_proc_meminfo)):
  691. memdata = core._linux_memdata()
  692. self.assertEqual(memdata.get('mem_total'), 15895)
  693. self.assertEqual(memdata.get('swap_total'), 4676)
  694. @skipIf(salt.utils.platform.is_windows(), 'System is Windows')
  695. def test_bsd_memdata(self):
  696. '''
  697. Test to memdata on *BSD systems
  698. '''
  699. _path_exists_map = {}
  700. _path_isfile_map = {}
  701. _cmd_run_map = {
  702. 'freebsd-version -u': '10.3-RELEASE',
  703. '/sbin/sysctl -n hw.physmem': '2121781248',
  704. '/sbin/sysctl -n vm.swap_total': '419430400'
  705. }
  706. path_exists_mock = MagicMock(side_effect=lambda x: _path_exists_map[x])
  707. path_isfile_mock = MagicMock(
  708. side_effect=lambda x: _path_isfile_map.get(x, False)
  709. )
  710. cmd_run_mock = MagicMock(
  711. side_effect=lambda x: _cmd_run_map[x]
  712. )
  713. empty_mock = MagicMock(return_value={})
  714. mock_freebsd_uname = ('FreeBSD',
  715. 'freebsd10.3-hostname-8148',
  716. '10.3-RELEASE',
  717. 'FreeBSD 10.3-RELEASE #0 r297264: Fri Mar 25 02:10:02 UTC 2016 root@releng1.nyi.freebsd.org:/usr/obj/usr/src/sys/GENERIC',
  718. 'amd64',
  719. 'amd64')
  720. with patch('platform.uname',
  721. MagicMock(return_value=mock_freebsd_uname)):
  722. with patch.object(salt.utils.platform, 'is_linux',
  723. MagicMock(return_value=False)):
  724. with patch.object(salt.utils.platform, 'is_freebsd',
  725. MagicMock(return_value=True)):
  726. # Skip the first if statement
  727. with patch.object(salt.utils.platform, 'is_proxy',
  728. MagicMock(return_value=False)):
  729. # Skip the init grain compilation (not pertinent)
  730. with patch.object(os.path, 'exists', path_exists_mock):
  731. with patch('salt.utils.path.which') as mock:
  732. mock.return_value = '/sbin/sysctl'
  733. # Make a bunch of functions return empty dicts,
  734. # we don't care about these grains for the
  735. # purposes of this test.
  736. with patch.object(
  737. core,
  738. '_bsd_cpudata',
  739. empty_mock):
  740. with patch.object(
  741. core,
  742. '_hw_data',
  743. empty_mock):
  744. with patch.object(
  745. core,
  746. '_virtual',
  747. empty_mock):
  748. with patch.object(
  749. core,
  750. '_ps',
  751. empty_mock):
  752. # Mock the osarch
  753. with patch.dict(
  754. core.__salt__,
  755. {'cmd.run': cmd_run_mock}):
  756. os_grains = core.os_data()
  757. self.assertEqual(os_grains.get('mem_total'), 2023)
  758. self.assertEqual(os_grains.get('swap_total'), 400)
  759. @skipIf(salt.utils.platform.is_windows(), 'System is Windows')
  760. def test_docker_virtual(self):
  761. '''
  762. Test if OS grains are parsed correctly in Ubuntu Xenial Xerus
  763. '''
  764. with patch.object(os.path, 'isdir', MagicMock(return_value=False)):
  765. with patch.object(os.path,
  766. 'isfile',
  767. MagicMock(side_effect=lambda x: True if x == '/proc/1/cgroup' else False)):
  768. for cgroup_substr in (':/system.slice/docker', ':/docker/',
  769. ':/docker-ce/'):
  770. cgroup_data = \
  771. '10:memory{0}a_long_sha256sum'.format(cgroup_substr)
  772. log.debug(
  773. 'Testing Docker cgroup substring \'%s\'', cgroup_substr)
  774. with patch('salt.utils.files.fopen', mock_open(read_data=cgroup_data)):
  775. with patch.dict(core.__salt__, {'cmd.run_all': MagicMock()}):
  776. self.assertEqual(
  777. core._virtual({'kernel': 'Linux'}).get('virtual_subtype'),
  778. 'Docker'
  779. )
  780. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  781. def test_xen_virtual(self):
  782. '''
  783. Test if OS grains are parsed correctly in Ubuntu Xenial Xerus
  784. '''
  785. with patch.object(os.path, 'isfile', MagicMock(return_value=False)):
  786. with patch.dict(core.__salt__, {'cmd.run': MagicMock(return_value='')}), \
  787. patch.object(os.path,
  788. 'isfile',
  789. MagicMock(side_effect=lambda x: True if x == '/sys/bus/xen/drivers/xenconsole' else False)):
  790. log.debug('Testing Xen')
  791. self.assertEqual(
  792. core._virtual({'kernel': 'Linux'}).get('virtual_subtype'),
  793. 'Xen PV DomU'
  794. )
  795. def _check_ipaddress(self, value, ip_v):
  796. '''
  797. check if ip address in a list is valid
  798. '''
  799. for val in value:
  800. assert isinstance(val, six.string_types)
  801. ip_method = 'is_ipv{0}'.format(ip_v)
  802. self.assertTrue(getattr(salt.utils.network, ip_method)(val))
  803. def _check_empty(self, key, value, empty):
  804. '''
  805. if empty is False and value does not exist assert error
  806. if empty is True and value exists assert error
  807. '''
  808. if not empty and not value:
  809. raise Exception("{0} is empty, expecting a value".format(key))
  810. elif empty and value:
  811. raise Exception("{0} is suppose to be empty. value: {1} \
  812. exists".format(key, value))
  813. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  814. def test_fqdn_return(self):
  815. '''
  816. test ip4 and ip6 return values
  817. '''
  818. net_ip4_mock = [IP4_LOCAL, IP4_ADD1, IP4_ADD2]
  819. net_ip6_mock = [IP6_LOCAL, IP6_ADD1, IP6_ADD2]
  820. self._run_fqdn_tests(net_ip4_mock, net_ip6_mock,
  821. ip4_empty=False, ip6_empty=False)
  822. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  823. def test_fqdn6_empty(self):
  824. '''
  825. test when ip6 is empty
  826. '''
  827. net_ip4_mock = [IP4_LOCAL, IP4_ADD1, IP4_ADD2]
  828. net_ip6_mock = []
  829. self._run_fqdn_tests(net_ip4_mock, net_ip6_mock,
  830. ip4_empty=False)
  831. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  832. def test_fqdn4_empty(self):
  833. '''
  834. test when ip4 is empty
  835. '''
  836. net_ip4_mock = []
  837. net_ip6_mock = [IP6_LOCAL, IP6_ADD1, IP6_ADD2]
  838. self._run_fqdn_tests(net_ip4_mock, net_ip6_mock,
  839. ip6_empty=False)
  840. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  841. def test_fqdn_all_empty(self):
  842. '''
  843. test when both ip4 and ip6 are empty
  844. '''
  845. net_ip4_mock = []
  846. net_ip6_mock = []
  847. self._run_fqdn_tests(net_ip4_mock, net_ip6_mock)
  848. def _run_fqdn_tests(self, net_ip4_mock, net_ip6_mock,
  849. ip6_empty=True, ip4_empty=True):
  850. def _check_type(key, value, ip4_empty, ip6_empty):
  851. '''
  852. check type and other checks
  853. '''
  854. assert isinstance(value, list)
  855. if '4' in key:
  856. self._check_empty(key, value, ip4_empty)
  857. self._check_ipaddress(value, ip_v='4')
  858. elif '6' in key:
  859. self._check_empty(key, value, ip6_empty)
  860. self._check_ipaddress(value, ip_v='6')
  861. ip4_mock = [(2, 1, 6, '', (IP4_ADD1, 0)),
  862. (2, 3, 0, '', (IP4_ADD2, 0))]
  863. ip6_mock = [(10, 1, 6, '', (IP6_ADD1, 0, 0, 0)),
  864. (10, 3, 0, '', (IP6_ADD2, 0, 0, 0))]
  865. with patch.dict(core.__opts__, {'ipv6': False}):
  866. with patch.object(salt.utils.network, 'ip_addrs',
  867. MagicMock(return_value=net_ip4_mock)):
  868. with patch.object(salt.utils.network, 'ip_addrs6',
  869. MagicMock(return_value=net_ip6_mock)):
  870. with patch.object(core.socket, 'getaddrinfo', side_effect=[ip4_mock, ip6_mock]):
  871. get_fqdn = core.ip_fqdn()
  872. ret_keys = ['fqdn_ip4', 'fqdn_ip6', 'ipv4', 'ipv6']
  873. for key in ret_keys:
  874. value = get_fqdn[key]
  875. _check_type(key, value, ip4_empty, ip6_empty)
  876. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  877. @patch.object(salt.utils.platform, 'is_windows', MagicMock(return_value=False))
  878. @patch('salt.grains.core.__opts__', {'ipv6': False})
  879. def test_dns_return(self):
  880. '''
  881. test the return for a dns grain. test for issue:
  882. https://github.com/saltstack/salt/issues/41230
  883. '''
  884. resolv_mock = {'domain': '', 'sortlist': [], 'nameservers':
  885. [ipaddress.IPv4Address(IP4_ADD1),
  886. ipaddress.IPv6Address(IP6_ADD1),
  887. IP6_ADD_SCOPE], 'ip4_nameservers':
  888. [ipaddress.IPv4Address(IP4_ADD1)],
  889. 'search': ['test.saltstack.com'], 'ip6_nameservers':
  890. [ipaddress.IPv6Address(IP6_ADD1),
  891. IP6_ADD_SCOPE], 'options': []}
  892. ret = {'dns': {'domain': '', 'sortlist': [], 'nameservers':
  893. [IP4_ADD1, IP6_ADD1,
  894. IP6_ADD_SCOPE], 'ip4_nameservers':
  895. [IP4_ADD1], 'search': ['test.saltstack.com'],
  896. 'ip6_nameservers': [IP6_ADD1, IP6_ADD_SCOPE],
  897. 'options': []}}
  898. with patch.object(salt.utils.dns, 'parse_resolv', MagicMock(return_value=resolv_mock)):
  899. assert core.dns() == ret
  900. @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
  901. @patch.object(salt.utils, 'is_windows', MagicMock(return_value=False))
  902. @patch('salt.utils.network.ip_addrs', MagicMock(return_value=['1.2.3.4', '5.6.7.8']))
  903. @patch('salt.utils.network.ip_addrs6',
  904. MagicMock(return_value=['fe80::a8b2:93ff:fe00:0', 'fe80::a8b2:93ff:dead:beef']))
  905. @patch('salt.utils.network.socket.getfqdn', MagicMock(side_effect=lambda v: v)) # Just pass-through
  906. def test_fqdns_return(self):
  907. '''
  908. test the return for a dns grain. test for issue:
  909. https://github.com/saltstack/salt/issues/41230
  910. '''
  911. reverse_resolv_mock = [('foo.bar.baz', [], ['1.2.3.4']),
  912. ('rinzler.evil-corp.com', [], ['5.6.7.8']),
  913. ('foo.bar.baz', [], ['fe80::a8b2:93ff:fe00:0']),
  914. ('bluesniff.foo.bar', [], ['fe80::a8b2:93ff:dead:beef'])]
  915. ret = {'fqdns': ['bluesniff.foo.bar', 'foo.bar.baz', 'rinzler.evil-corp.com']}
  916. with patch.object(socket, 'gethostbyaddr', side_effect=reverse_resolv_mock):
  917. fqdns = core.fqdns()
  918. self.assertIn('fqdns', fqdns)
  919. self.assertEqual(len(fqdns['fqdns']), len(ret['fqdns']))
  920. self.assertEqual(set(fqdns['fqdns']), set(ret['fqdns']))
  921. def test_core_virtual(self):
  922. '''
  923. test virtual grain with cmd virt-what
  924. '''
  925. virt = 'kvm'
  926. with patch.object(salt.utils.platform, 'is_windows',
  927. MagicMock(return_value=False)):
  928. with patch.object(salt.utils.path, 'which',
  929. MagicMock(return_value=True)):
  930. with patch.dict(core.__salt__, {'cmd.run_all':
  931. MagicMock(return_value={'pid': 78,
  932. 'retcode': 0,
  933. 'stderr': '',
  934. 'stdout': virt})}):
  935. osdata = {'kernel': 'test', }
  936. ret = core._virtual(osdata)
  937. self.assertEqual(ret['virtual'], virt)
  938. def test_solaris_sparc_s7zone(self):
  939. '''
  940. verify productname grain for s7 zone
  941. '''
  942. expectation = {
  943. 'productname': 'SPARC S7-2',
  944. 'product': 'SPARC S7-2',
  945. }
  946. with salt.utils.files.fopen(os.path.join(SOLARIS_DIR, 'prtconf.s7-zone')) as sparc_return_data:
  947. this_sparc_return_data = '\n'.join(sparc_return_data.readlines())
  948. this_sparc_return_data += '\n'
  949. self._check_solaris_sparc_productname_grains(this_sparc_return_data, expectation)
  950. def test_solaris_sparc_s7(self):
  951. '''
  952. verify productname grain for s7
  953. '''
  954. expectation = {
  955. 'productname': 'SPARC S7-2',
  956. 'product': 'SPARC S7-2',
  957. }
  958. with salt.utils.files.fopen(os.path.join(SOLARIS_DIR, 'prtdiag.s7')) as sparc_return_data:
  959. this_sparc_return_data = '\n'.join(sparc_return_data.readlines())
  960. this_sparc_return_data += '\n'
  961. self._check_solaris_sparc_productname_grains(this_sparc_return_data, expectation)
  962. def test_solaris_sparc_t5220(self):
  963. '''
  964. verify productname grain for t5220
  965. '''
  966. expectation = {
  967. 'productname': 'SPARC Enterprise T5220',
  968. 'product': 'SPARC Enterprise T5220',
  969. }
  970. with salt.utils.files.fopen(os.path.join(SOLARIS_DIR, 'prtdiag.t5220')) as sparc_return_data:
  971. this_sparc_return_data = '\n'.join(sparc_return_data.readlines())
  972. this_sparc_return_data += '\n'
  973. self._check_solaris_sparc_productname_grains(this_sparc_return_data, expectation)
  974. def test_solaris_sparc_t5220zone(self):
  975. '''
  976. verify productname grain for t5220 zone
  977. '''
  978. expectation = {
  979. 'productname': 'SPARC Enterprise T5220',
  980. 'product': 'SPARC Enterprise T5220',
  981. }
  982. with salt.utils.files.fopen(os.path.join(SOLARIS_DIR, 'prtconf.t5220-zone')) as sparc_return_data:
  983. this_sparc_return_data = '\n'.join(sparc_return_data.readlines())
  984. this_sparc_return_data += '\n'
  985. self._check_solaris_sparc_productname_grains(this_sparc_return_data, expectation)
  986. def _check_solaris_sparc_productname_grains(self, prtdata, expectation):
  987. '''
  988. verify product grains on solaris sparc
  989. '''
  990. import platform
  991. path_isfile_mock = MagicMock(side_effect=lambda x: x in ['/etc/release'])
  992. with salt.utils.files.fopen(os.path.join(OS_RELEASE_DIR, "solaris-11.3")) as os_release_file:
  993. os_release_content = os_release_file.readlines()
  994. uname_mock = MagicMock(return_value=(
  995. 'SunOS', 'testsystem', '5.11', '11.3', 'sunv4', 'sparc'
  996. ))
  997. with patch.object(platform, 'uname', uname_mock), \
  998. patch.object(salt.utils.platform, 'is_proxy',
  999. MagicMock(return_value=False)), \
  1000. patch.object(salt.utils.platform, 'is_linux',
  1001. MagicMock(return_value=False)), \
  1002. patch.object(salt.utils.platform, 'is_windows',
  1003. MagicMock(return_value=False)), \
  1004. patch.object(salt.utils.platform, 'is_smartos',
  1005. MagicMock(return_value=False)), \
  1006. patch.object(salt.utils.path, 'which_bin',
  1007. MagicMock(return_value=None)), \
  1008. patch.object(os.path, 'isfile', path_isfile_mock), \
  1009. patch('salt.utils.files.fopen',
  1010. mock_open(read_data=os_release_content)) as os_release_file, \
  1011. patch.object(core, '_sunos_cpudata',
  1012. MagicMock(return_value={
  1013. 'cpuarch': 'sparcv9',
  1014. 'num_cpus': '1',
  1015. 'cpu_model': 'MOCK_CPU_MODEL',
  1016. 'cpu_flags': []})), \
  1017. patch.object(core, '_memdata',
  1018. MagicMock(return_value={'mem_total': 16384})), \
  1019. patch.object(core, '_virtual',
  1020. MagicMock(return_value={})), \
  1021. patch.object(core, '_ps', MagicMock(return_value={})), \
  1022. patch.object(salt.utils.path, 'which',
  1023. MagicMock(return_value=True)), \
  1024. patch.dict(core.__salt__,
  1025. {'cmd.run': MagicMock(return_value=prtdata)}):
  1026. os_grains = core.os_data()
  1027. grains = {k: v for k, v in os_grains.items()
  1028. if k in set(['product', 'productname'])}
  1029. self.assertEqual(grains, expectation)
  1030. @patch('os.path.isfile')
  1031. @patch('os.path.isdir')
  1032. def test_core_virtual_unicode(self, mock_file, mock_dir):
  1033. '''
  1034. test virtual grain with unicode character in product_name file
  1035. '''
  1036. def path_side_effect(path):
  1037. if path == '/sys/devices/virtual/dmi/id/product_name':
  1038. return True
  1039. return False
  1040. virt = 'kvm'
  1041. mock_file.side_effect = path_side_effect
  1042. mock_dir.side_effect = path_side_effect
  1043. with patch.object(salt.utils.platform, 'is_windows',
  1044. MagicMock(return_value=False)):
  1045. with patch.object(salt.utils.path, 'which',
  1046. MagicMock(return_value=True)):
  1047. with patch.dict(core.__salt__, {'cmd.run_all':
  1048. MagicMock(return_value={'pid': 78,
  1049. 'retcode': 0,
  1050. 'stderr': '',
  1051. 'stdout': virt})}):
  1052. with patch('salt.utils.files.fopen',
  1053. mock_open(read_data='嗨')):
  1054. osdata = {'kernel': 'Linux', }
  1055. ret = core._virtual(osdata)
  1056. self.assertEqual(ret['virtual'], virt)
  1057. @patch('salt.utils.path.which', MagicMock(return_value='/usr/sbin/sysctl'))
  1058. def test_osx_memdata_with_comma(self):
  1059. '''
  1060. test osx memdata method when comma returns
  1061. '''
  1062. def _cmd_side_effect(cmd):
  1063. if 'hw.memsize' in cmd:
  1064. return '4294967296'
  1065. elif 'vm.swapusage' in cmd:
  1066. return 'total = 1024,00M used = 160,75M free = 863,25M (encrypted)'
  1067. with patch.dict(core.__salt__, {'cmd.run': MagicMock(side_effect=_cmd_side_effect)}):
  1068. ret = core._osx_memdata()
  1069. assert ret['swap_total'] == 1024
  1070. assert ret['mem_total'] == 4096
  1071. @patch('salt.utils.path.which', MagicMock(return_value='/usr/sbin/sysctl'))
  1072. def test_osx_memdata(self):
  1073. '''
  1074. test osx memdata
  1075. '''
  1076. def _cmd_side_effect(cmd):
  1077. if 'hw.memsize' in cmd:
  1078. return '4294967296'
  1079. elif 'vm.swapusage' in cmd:
  1080. return 'total = 0.00M used = 0.00M free = 0.00M (encrypted)'
  1081. with patch.dict(core.__salt__, {'cmd.run': MagicMock(side_effect=_cmd_side_effect)}):
  1082. ret = core._osx_memdata()
  1083. assert ret['swap_total'] == 0
  1084. assert ret['mem_total'] == 4096
  1085. @skipIf(not core._DATEUTIL_TZ, 'Missing dateutil.tz')
  1086. def test_locale_info_tzname(self):
  1087. # mock datetime.now().tzname()
  1088. # cant just mock now because it is read only
  1089. tzname = Mock(return_value='MDT_FAKE')
  1090. now_ret_object = Mock(tzname=tzname)
  1091. now = Mock(return_value=now_ret_object)
  1092. datetime = Mock(now=now)
  1093. with patch.object(core, 'datetime', datetime=datetime) as datetime_module:
  1094. with patch.object(core.dateutil.tz, 'tzlocal', return_value=object) as tzlocal:
  1095. with patch.object(salt.utils.platform, 'is_proxy', return_value=False) as is_proxy:
  1096. ret = core.locale_info()
  1097. tzname.assert_called_once_with()
  1098. self.assertEqual(len(now_ret_object.method_calls), 1)
  1099. now.assert_called_once_with(object)
  1100. self.assertEqual(len(datetime.method_calls), 1)
  1101. self.assertEqual(len(datetime_module.method_calls), 1)
  1102. tzlocal.assert_called_once_with()
  1103. is_proxy.assert_called_once_with()
  1104. self.assertEqual(ret['locale_info']['timezone'], 'MDT_FAKE')
  1105. @skipIf(not core._DATEUTIL_TZ, 'Missing dateutil.tz')
  1106. def test_locale_info_unicode_error_tzname(self):
  1107. # UnicodeDecodeError most have the default string encoding
  1108. unicode_error = UnicodeDecodeError(str('fake'), b'\x00\x00', 1, 2, str('fake'))
  1109. # mock datetime.now().tzname()
  1110. # cant just mock now because it is read only
  1111. tzname = Mock(return_value='MDT_FAKE')
  1112. now_ret_object = Mock(tzname=tzname)
  1113. now = Mock(return_value=now_ret_object)
  1114. datetime = Mock(now=now)
  1115. # mock tzname[0].decode()
  1116. decode = Mock(return_value='CST_FAKE')
  1117. tzname2 = (Mock(decode=decode,),)
  1118. with patch.object(core, 'datetime', datetime=datetime) as datetime_module:
  1119. with patch.object(core.dateutil.tz, 'tzlocal', side_effect=unicode_error) as tzlocal:
  1120. with patch.object(salt.utils.platform, 'is_proxy', return_value=False) as is_proxy:
  1121. with patch.object(core.salt.utils.platform, 'is_windows', return_value=True) as is_windows:
  1122. with patch.object(core, 'time', tzname=tzname2):
  1123. ret = core.locale_info()
  1124. tzname.assert_not_called()
  1125. self.assertEqual(len(now_ret_object.method_calls), 0)
  1126. now.assert_not_called()
  1127. self.assertEqual(len(datetime.method_calls), 0)
  1128. decode.assert_called_once_with('mbcs')
  1129. self.assertEqual(len(tzname2[0].method_calls), 1)
  1130. self.assertEqual(len(datetime_module.method_calls), 0)
  1131. tzlocal.assert_called_once_with()
  1132. is_proxy.assert_called_once_with()
  1133. is_windows.assert_called_once_with()
  1134. self.assertEqual(ret['locale_info']['timezone'], 'CST_FAKE')
  1135. @skipIf(core._DATEUTIL_TZ, 'Not Missing dateutil.tz')
  1136. def test_locale_info_no_tz_tzname(self):
  1137. with patch.object(salt.utils.platform, 'is_proxy', return_value=False) as is_proxy:
  1138. with patch.object(core.salt.utils.platform, 'is_windows', return_value=True) as is_windows:
  1139. ret = core.locale_info()
  1140. is_proxy.assert_called_once_with()
  1141. is_windows.assert_not_called()
  1142. self.assertEqual(ret['locale_info']['timezone'], 'unknown')