test_core.py 54 KB

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