test_core.py 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980
  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 platform
  10. import socket
  11. import textwrap
  12. import salt.grains.core as core
  13. import salt.modules.cmdmod
  14. import salt.modules.smbios
  15. # Import Salt Libs
  16. import salt.utils.dns
  17. import salt.utils.files
  18. import salt.utils.network
  19. import salt.utils.path
  20. import salt.utils.platform
  21. from salt._compat import ipaddress
  22. # Import 3rd-party libs
  23. from salt.ext import six
  24. from tests.support.mixins import LoaderModuleMockMixin
  25. from tests.support.mock import MagicMock, Mock, mock_open, patch
  26. from tests.support.unit import TestCase, skipIf
  27. # Import Salt Testing Libs
  28. try:
  29. import pytest
  30. except ImportError as import_error:
  31. pytest = None
  32. log = logging.getLogger(__name__)
  33. # Globals
  34. IPv4Address = ipaddress.IPv4Address
  35. IPv6Address = ipaddress.IPv6Address
  36. IP4_LOCAL = "127.0.0.1"
  37. IP4_ADD1 = "10.0.0.1"
  38. IP4_ADD2 = "10.0.0.2"
  39. IP6_LOCAL = "::1"
  40. IP6_ADD1 = "2001:4860:4860::8844"
  41. IP6_ADD2 = "2001:4860:4860::8888"
  42. IP6_ADD_SCOPE = "fe80::6238:e0ff:fe06:3f6b%enp2s0"
  43. OS_RELEASE_DIR = os.path.join(os.path.dirname(__file__), "os-releases")
  44. SOLARIS_DIR = os.path.join(os.path.dirname(__file__), "solaris")
  45. @skipIf(not pytest, False)
  46. class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin):
  47. """
  48. Test cases for core grains
  49. """
  50. def setup_loader_modules(self):
  51. return {core: {}}
  52. @patch("os.path.isfile")
  53. def test_parse_etc_os_release(self, path_isfile_mock):
  54. path_isfile_mock.side_effect = lambda x: x == "/usr/lib/os-release"
  55. with salt.utils.files.fopen(
  56. os.path.join(OS_RELEASE_DIR, "ubuntu-17.10")
  57. ) 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", "/usr/lib/os-release"
  62. )
  63. self.assertEqual(
  64. os_release,
  65. {
  66. "NAME": "Ubuntu",
  67. "VERSION": "17.10 (Artful Aardvark)",
  68. "ID": "ubuntu",
  69. "ID_LIKE": "debian",
  70. "PRETTY_NAME": "Ubuntu 17.10",
  71. "VERSION_ID": "17.10",
  72. "HOME_URL": "https://www.ubuntu.com/",
  73. "SUPPORT_URL": "https://help.ubuntu.com/",
  74. "BUG_REPORT_URL": "https://bugs.launchpad.net/ubuntu/",
  75. "PRIVACY_POLICY_URL": "https://www.ubuntu.com/legal/terms-and-policies/privacy-policy",
  76. "VERSION_CODENAME": "artful",
  77. "UBUNTU_CODENAME": "artful",
  78. },
  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 [
  86. (
  87. "cpe:/o:opensuse:leap:15.0",
  88. {
  89. "phase": None,
  90. "version": "15.0",
  91. "product": "leap",
  92. "vendor": "opensuse",
  93. "part": "operating system",
  94. },
  95. ),
  96. (
  97. "cpe:/o:vendor:product:42:beta",
  98. {
  99. "phase": "beta",
  100. "version": "42",
  101. "product": "product",
  102. "vendor": "vendor",
  103. "part": "operating system",
  104. },
  105. ),
  106. ]:
  107. ret = core._parse_cpe_name(cpe)
  108. for key in cpe_ret:
  109. assert key in ret
  110. assert cpe_ret[key] == ret[key]
  111. def test_parse_cpe_name_v23(self):
  112. """
  113. Parse correct CPE_NAME data v2.3 formatted
  114. :return:
  115. """
  116. for cpe, cpe_ret in [
  117. (
  118. "cpe:2.3:o:microsoft:windows_xp:5.1.601:beta:*:*:*:*:*:*",
  119. {
  120. "phase": "beta",
  121. "version": "5.1.601",
  122. "product": "windows_xp",
  123. "vendor": "microsoft",
  124. "part": "operating system",
  125. },
  126. ),
  127. (
  128. "cpe:2.3:h:corellian:millenium_falcon:1.0:*:*:*:*:*:*:*",
  129. {
  130. "phase": None,
  131. "version": "1.0",
  132. "product": "millenium_falcon",
  133. "vendor": "corellian",
  134. "part": "hardware",
  135. },
  136. ),
  137. (
  138. "cpe:2.3:*:dark_empire:light_saber:3.0:beta:*:*:*:*:*:*",
  139. {
  140. "phase": "beta",
  141. "version": "3.0",
  142. "product": "light_saber",
  143. "vendor": "dark_empire",
  144. "part": None,
  145. },
  146. ),
  147. ]:
  148. ret = core._parse_cpe_name(cpe)
  149. for key in cpe_ret:
  150. assert key in ret
  151. assert cpe_ret[key] == ret[key]
  152. def test_parse_cpe_name_broken(self):
  153. """
  154. Parse broken CPE_NAME data
  155. :return:
  156. """
  157. for cpe in [
  158. "cpe:broken",
  159. "cpe:broken:in:all:ways:*:*:*:*",
  160. "cpe:x:still:broken:123",
  161. "who:/knows:what:is:here",
  162. ]:
  163. assert core._parse_cpe_name(cpe) == {}
  164. def test_missing_os_release(self):
  165. with patch("salt.utils.files.fopen", mock_open(read_data={})):
  166. os_release = core._parse_os_release(
  167. "/etc/os-release", "/usr/lib/os-release"
  168. )
  169. self.assertEqual(os_release, {})
  170. @skipIf(not salt.utils.platform.is_windows(), "System is not Windows")
  171. def test__windows_platform_data(self):
  172. grains = core._windows_platform_data()
  173. keys = [
  174. "biosversion",
  175. "osrelease",
  176. "kernelrelease",
  177. "motherboard",
  178. "serialnumber",
  179. "timezone",
  180. "manufacturer",
  181. "kernelversion",
  182. "osservicepack",
  183. "virtual",
  184. "productname",
  185. "osfullname",
  186. "osmanufacturer",
  187. "osversion",
  188. "windowsdomain",
  189. ]
  190. for key in keys:
  191. self.assertIn(key, grains)
  192. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  193. def test_gnu_slash_linux_in_os_name(self):
  194. """
  195. Test to return a list of all enabled services
  196. """
  197. _path_exists_map = {"/proc/1/cmdline": False}
  198. _path_isfile_map = {}
  199. _cmd_run_map = {
  200. "dpkg --print-architecture": "amd64",
  201. }
  202. path_exists_mock = MagicMock(side_effect=lambda x: _path_exists_map[x])
  203. path_isfile_mock = MagicMock(
  204. side_effect=lambda x: _path_isfile_map.get(x, False)
  205. )
  206. cmd_run_mock = MagicMock(side_effect=lambda x: _cmd_run_map[x])
  207. empty_mock = MagicMock(return_value={})
  208. orig_import = __import__
  209. if six.PY2:
  210. built_in = "__builtin__"
  211. else:
  212. built_in = "builtins"
  213. def _import_mock(name, *args):
  214. if name == "lsb_release":
  215. raise ImportError("No module named lsb_release")
  216. return orig_import(name, *args)
  217. # - Skip the first if statement
  218. # - Skip the selinux/systemd stuff (not pertinent)
  219. # - Skip the init grain compilation (not pertinent)
  220. # - Ensure that lsb_release fails to import
  221. # - Skip all the /etc/*-release stuff (not pertinent)
  222. # - Mock linux_distribution to give us the OS name that we want
  223. # - Make a bunch of functions return empty dicts, we don't care about
  224. # these grains for the purposes of this test.
  225. # - Mock the osarch
  226. distro_mock = MagicMock(return_value=("Debian GNU/Linux", "8.3", ""))
  227. with patch.object(
  228. salt.utils.platform, "is_proxy", MagicMock(return_value=False)
  229. ), patch.object(
  230. core, "_linux_bin_exists", MagicMock(return_value=False)
  231. ), patch.object(
  232. os.path, "exists", path_exists_mock
  233. ), patch(
  234. "{0}.__import__".format(built_in), side_effect=_import_mock
  235. ), patch.object(
  236. os.path, "isfile", path_isfile_mock
  237. ), patch.object(
  238. core, "_parse_lsb_release", empty_mock
  239. ), patch.object(
  240. core, "_parse_os_release", empty_mock
  241. ), patch.object(
  242. core, "_parse_lsb_release", empty_mock
  243. ), patch.object(
  244. core, "linux_distribution", distro_mock
  245. ), patch.object(
  246. core, "_linux_cpudata", empty_mock
  247. ), patch.object(
  248. core, "_linux_gpu_data", empty_mock
  249. ), patch.object(
  250. core, "_memdata", empty_mock
  251. ), patch.object(
  252. core, "_hw_data", empty_mock
  253. ), patch.object(
  254. core, "_virtual", empty_mock
  255. ), patch.object(
  256. core, "_ps", empty_mock
  257. ), patch.dict(
  258. core.__salt__, {"cmd.run": cmd_run_mock}
  259. ):
  260. os_grains = core.os_data()
  261. self.assertEqual(os_grains.get("os_family"), "Debian")
  262. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  263. def test_suse_os_from_cpe_data(self):
  264. """
  265. Test if 'os' grain is parsed from CPE_NAME of /etc/os-release
  266. """
  267. _path_exists_map = {"/proc/1/cmdline": False}
  268. _os_release_map = {
  269. "NAME": "SLES",
  270. "VERSION": "12-SP1",
  271. "VERSION_ID": "12.1",
  272. "PRETTY_NAME": "SUSE Linux Enterprise Server 12 SP1",
  273. "ID": "sles",
  274. "ANSI_COLOR": "0;32",
  275. "CPE_NAME": "cpe:/o:suse:sles:12:sp1",
  276. }
  277. path_exists_mock = MagicMock(side_effect=lambda x: _path_exists_map[x])
  278. empty_mock = MagicMock(return_value={})
  279. osarch_mock = MagicMock(return_value="amd64")
  280. os_release_mock = MagicMock(return_value=_os_release_map)
  281. orig_import = __import__
  282. if six.PY2:
  283. built_in = "__builtin__"
  284. else:
  285. built_in = "builtins"
  286. def _import_mock(name, *args):
  287. if name == "lsb_release":
  288. raise ImportError("No module named lsb_release")
  289. return orig_import(name, *args)
  290. distro_mock = MagicMock(
  291. return_value=("SUSE Linux Enterprise Server ", "12", "x86_64")
  292. )
  293. # - Skip the first if statement
  294. # - Skip the selinux/systemd stuff (not pertinent)
  295. # - Skip the init grain compilation (not pertinent)
  296. # - Ensure that lsb_release fails to import
  297. # - Skip all the /etc/*-release stuff (not pertinent)
  298. # - Mock linux_distribution to give us the OS name that we want
  299. # - Mock the osarch
  300. with patch.object(
  301. salt.utils.platform, "is_proxy", MagicMock(return_value=False)
  302. ), patch.object(
  303. core, "_linux_bin_exists", MagicMock(return_value=False)
  304. ), patch.object(
  305. os.path, "exists", path_exists_mock
  306. ), patch(
  307. "{0}.__import__".format(built_in), side_effect=_import_mock
  308. ), patch.object(
  309. os.path, "isfile", MagicMock(return_value=False)
  310. ), patch.object(
  311. core, "_parse_os_release", os_release_mock
  312. ), patch.object(
  313. core, "_parse_lsb_release", empty_mock
  314. ), patch.object(
  315. core, "linux_distribution", distro_mock
  316. ), patch.object(
  317. core, "_linux_gpu_data", empty_mock
  318. ), patch.object(
  319. core, "_hw_data", empty_mock
  320. ), patch.object(
  321. core, "_linux_cpudata", empty_mock
  322. ), patch.object(
  323. core, "_virtual", empty_mock
  324. ), patch.dict(
  325. core.__salt__, {"cmd.run": osarch_mock}
  326. ):
  327. os_grains = core.os_data()
  328. self.assertEqual(os_grains.get("os_family"), "Suse")
  329. self.assertEqual(os_grains.get("os"), "SUSE")
  330. def _run_os_grains_tests(self, os_release_filename, os_release_map, expectation):
  331. path_isfile_mock = MagicMock(
  332. side_effect=lambda x: x in os_release_map.get("files", [])
  333. )
  334. empty_mock = MagicMock(return_value={})
  335. osarch_mock = MagicMock(return_value="amd64")
  336. if os_release_filename:
  337. os_release_data = core._parse_os_release(
  338. os.path.join(OS_RELEASE_DIR, os_release_filename)
  339. )
  340. else:
  341. os_release_data = os_release_map.get("os_release_file", {})
  342. os_release_mock = MagicMock(return_value=os_release_data)
  343. orig_import = __import__
  344. if six.PY2:
  345. built_in = "__builtin__"
  346. else:
  347. built_in = "builtins"
  348. def _import_mock(name, *args):
  349. if name == "lsb_release":
  350. raise ImportError("No module named lsb_release")
  351. return orig_import(name, *args)
  352. suse_release_file = os_release_map.get("suse_release_file")
  353. file_contents = {"/proc/1/cmdline": ""}
  354. if suse_release_file:
  355. file_contents["/etc/SuSE-release"] = suse_release_file
  356. # - Skip the first if statement
  357. # - Skip the selinux/systemd stuff (not pertinent)
  358. # - Skip the init grain compilation (not pertinent)
  359. # - Ensure that lsb_release fails to import
  360. # - Skip all the /etc/*-release stuff (not pertinent)
  361. # - Mock linux_distribution to give us the OS name that we want
  362. # - Mock the osarch
  363. distro_mock = MagicMock(return_value=os_release_map["linux_distribution"])
  364. with patch.object(
  365. salt.utils.platform, "is_proxy", MagicMock(return_value=False)
  366. ), patch.object(
  367. core, "_linux_bin_exists", MagicMock(return_value=False)
  368. ), patch.object(
  369. os.path, "exists", path_isfile_mock
  370. ), patch(
  371. "{0}.__import__".format(built_in), side_effect=_import_mock
  372. ), patch.object(
  373. os.path, "isfile", path_isfile_mock
  374. ), patch.object(
  375. core, "_parse_os_release", os_release_mock
  376. ), patch.object(
  377. core, "_parse_lsb_release", empty_mock
  378. ), patch(
  379. "salt.utils.files.fopen", mock_open(read_data=file_contents)
  380. ), patch.object(
  381. core, "linux_distribution", distro_mock
  382. ), patch.object(
  383. core, "_linux_gpu_data", empty_mock
  384. ), patch.object(
  385. core, "_linux_cpudata", empty_mock
  386. ), patch.object(
  387. core, "_virtual", empty_mock
  388. ), patch.dict(
  389. core.__salt__, {"cmd.run": osarch_mock}
  390. ):
  391. os_grains = core.os_data()
  392. grains = {
  393. k: v
  394. for k, v in os_grains.items()
  395. if k
  396. in set(
  397. [
  398. "os",
  399. "os_family",
  400. "osfullname",
  401. "oscodename",
  402. "osfinger",
  403. "osrelease",
  404. "osrelease_info",
  405. "osmajorrelease",
  406. ]
  407. )
  408. }
  409. self.assertEqual(grains, expectation)
  410. def _run_suse_os_grains_tests(self, os_release_map, expectation):
  411. os_release_map["linux_distribution"] = ("SUSE test", "version", "arch")
  412. expectation["os"] = "SUSE"
  413. expectation["os_family"] = "Suse"
  414. self._run_os_grains_tests(None, os_release_map, expectation)
  415. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  416. def test_suse_os_grains_sles11sp3(self):
  417. """
  418. Test if OS grains are parsed correctly in SLES 11 SP3
  419. """
  420. _os_release_map = {
  421. "suse_release_file": textwrap.dedent(
  422. """
  423. SUSE Linux Enterprise Server 11 (x86_64)
  424. VERSION = 11
  425. PATCHLEVEL = 3
  426. """
  427. ),
  428. "files": ["/etc/SuSE-release"],
  429. }
  430. expectation = {
  431. "oscodename": "SUSE Linux Enterprise Server 11 SP3",
  432. "osfullname": "SLES",
  433. "osrelease": "11.3",
  434. "osrelease_info": (11, 3),
  435. "osmajorrelease": 11,
  436. "osfinger": "SLES-11",
  437. }
  438. self._run_suse_os_grains_tests(_os_release_map, expectation)
  439. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  440. def test_suse_os_grains_sles11sp4(self):
  441. """
  442. Test if OS grains are parsed correctly in SLES 11 SP4
  443. """
  444. _os_release_map = {
  445. "os_release_file": {
  446. "NAME": "SLES",
  447. "VERSION": "11.4",
  448. "VERSION_ID": "11.4",
  449. "PRETTY_NAME": "SUSE Linux Enterprise Server 11 SP4",
  450. "ID": "sles",
  451. "ANSI_COLOR": "0;32",
  452. "CPE_NAME": "cpe:/o:suse:sles:11:4",
  453. },
  454. }
  455. expectation = {
  456. "oscodename": "SUSE Linux Enterprise Server 11 SP4",
  457. "osfullname": "SLES",
  458. "osrelease": "11.4",
  459. "osrelease_info": (11, 4),
  460. "osmajorrelease": 11,
  461. "osfinger": "SLES-11",
  462. }
  463. self._run_suse_os_grains_tests(_os_release_map, expectation)
  464. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  465. def test_suse_os_grains_sles12(self):
  466. """
  467. Test if OS grains are parsed correctly in SLES 12
  468. """
  469. _os_release_map = {
  470. "os_release_file": {
  471. "NAME": "SLES",
  472. "VERSION": "12",
  473. "VERSION_ID": "12",
  474. "PRETTY_NAME": "SUSE Linux Enterprise Server 12",
  475. "ID": "sles",
  476. "ANSI_COLOR": "0;32",
  477. "CPE_NAME": "cpe:/o:suse:sles:12",
  478. },
  479. }
  480. expectation = {
  481. "oscodename": "SUSE Linux Enterprise Server 12",
  482. "osfullname": "SLES",
  483. "osrelease": "12",
  484. "osrelease_info": (12,),
  485. "osmajorrelease": 12,
  486. "osfinger": "SLES-12",
  487. }
  488. self._run_suse_os_grains_tests(_os_release_map, expectation)
  489. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  490. def test_suse_os_grains_sles12sp1(self):
  491. """
  492. Test if OS grains are parsed correctly in SLES 12 SP1
  493. """
  494. _os_release_map = {
  495. "os_release_file": {
  496. "NAME": "SLES",
  497. "VERSION": "12-SP1",
  498. "VERSION_ID": "12.1",
  499. "PRETTY_NAME": "SUSE Linux Enterprise Server 12 SP1",
  500. "ID": "sles",
  501. "ANSI_COLOR": "0;32",
  502. "CPE_NAME": "cpe:/o:suse:sles:12:sp1",
  503. },
  504. }
  505. expectation = {
  506. "oscodename": "SUSE Linux Enterprise Server 12 SP1",
  507. "osfullname": "SLES",
  508. "osrelease": "12.1",
  509. "osrelease_info": (12, 1),
  510. "osmajorrelease": 12,
  511. "osfinger": "SLES-12",
  512. }
  513. self._run_suse_os_grains_tests(_os_release_map, expectation)
  514. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  515. def test_suse_os_grains_opensuse_leap_42_1(self):
  516. """
  517. Test if OS grains are parsed correctly in openSUSE Leap 42.1
  518. """
  519. _os_release_map = {
  520. "os_release_file": {
  521. "NAME": "openSUSE Leap",
  522. "VERSION": "42.1",
  523. "VERSION_ID": "42.1",
  524. "PRETTY_NAME": "openSUSE Leap 42.1 (x86_64)",
  525. "ID": "opensuse",
  526. "ANSI_COLOR": "0;32",
  527. "CPE_NAME": "cpe:/o:opensuse:opensuse:42.1",
  528. },
  529. }
  530. expectation = {
  531. "oscodename": "openSUSE Leap 42.1 (x86_64)",
  532. "osfullname": "Leap",
  533. "osrelease": "42.1",
  534. "osrelease_info": (42, 1),
  535. "osmajorrelease": 42,
  536. "osfinger": "Leap-42",
  537. }
  538. self._run_suse_os_grains_tests(_os_release_map, expectation)
  539. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  540. def test_suse_os_grains_tumbleweed(self):
  541. """
  542. Test if OS grains are parsed correctly in openSUSE Tumbleweed
  543. """
  544. _os_release_map = {
  545. "os_release_file": {
  546. "NAME": "openSUSE",
  547. "VERSION": "Tumbleweed",
  548. "VERSION_ID": "20160504",
  549. "PRETTY_NAME": "openSUSE Tumbleweed (20160504) (x86_64)",
  550. "ID": "opensuse",
  551. "ANSI_COLOR": "0;32",
  552. "CPE_NAME": "cpe:/o:opensuse:opensuse:20160504",
  553. },
  554. }
  555. expectation = {
  556. "oscodename": "openSUSE Tumbleweed (20160504) (x86_64)",
  557. "osfullname": "Tumbleweed",
  558. "osrelease": "20160504",
  559. "osrelease_info": (20160504,),
  560. "osmajorrelease": 20160504,
  561. "osfinger": "Tumbleweed-20160504",
  562. }
  563. self._run_suse_os_grains_tests(_os_release_map, expectation)
  564. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  565. def test_debian_7_os_grains(self):
  566. """
  567. Test if OS grains are parsed correctly in Debian 7 "wheezy"
  568. """
  569. _os_release_map = {
  570. "linux_distribution": ("debian", "7.11", ""),
  571. }
  572. expectation = {
  573. "os": "Debian",
  574. "os_family": "Debian",
  575. "oscodename": "wheezy",
  576. "osfullname": "Debian GNU/Linux",
  577. "osrelease": "7",
  578. "osrelease_info": (7,),
  579. "osmajorrelease": 7,
  580. "osfinger": "Debian-7",
  581. }
  582. self._run_os_grains_tests("debian-7", _os_release_map, expectation)
  583. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  584. def test_debian_8_os_grains(self):
  585. """
  586. Test if OS grains are parsed correctly in Debian 8 "jessie"
  587. """
  588. _os_release_map = {
  589. "linux_distribution": ("debian", "8.10", ""),
  590. }
  591. expectation = {
  592. "os": "Debian",
  593. "os_family": "Debian",
  594. "oscodename": "jessie",
  595. "osfullname": "Debian GNU/Linux",
  596. "osrelease": "8",
  597. "osrelease_info": (8,),
  598. "osmajorrelease": 8,
  599. "osfinger": "Debian-8",
  600. }
  601. self._run_os_grains_tests("debian-8", _os_release_map, expectation)
  602. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  603. def test_debian_9_os_grains(self):
  604. """
  605. Test if OS grains are parsed correctly in Debian 9 "stretch"
  606. """
  607. _os_release_map = {
  608. "linux_distribution": ("debian", "9.3", ""),
  609. }
  610. expectation = {
  611. "os": "Debian",
  612. "os_family": "Debian",
  613. "oscodename": "stretch",
  614. "osfullname": "Debian GNU/Linux",
  615. "osrelease": "9",
  616. "osrelease_info": (9,),
  617. "osmajorrelease": 9,
  618. "osfinger": "Debian-9",
  619. }
  620. self._run_os_grains_tests("debian-9", _os_release_map, expectation)
  621. def test_unicode_error(self):
  622. raise_unicode_mock = MagicMock(
  623. name="raise_unicode_error", side_effect=UnicodeError
  624. )
  625. with patch("salt.grains.core.hostname"):
  626. with patch("socket.getaddrinfo", raise_unicode_mock):
  627. ret = salt.grains.core.ip_fqdn()
  628. assert ret["fqdn_ip4"] == ret["fqdn_ip6"] == []
  629. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  630. def test_ubuntu_xenial_os_grains(self):
  631. """
  632. Test if OS grains are parsed correctly in Ubuntu 16.04 "Xenial Xerus"
  633. """
  634. _os_release_map = {
  635. "linux_distribution": ("Ubuntu", "16.04", "xenial"),
  636. }
  637. expectation = {
  638. "os": "Ubuntu",
  639. "os_family": "Debian",
  640. "oscodename": "xenial",
  641. "osfullname": "Ubuntu",
  642. "osrelease": "16.04",
  643. "osrelease_info": (16, 4),
  644. "osmajorrelease": 16,
  645. "osfinger": "Ubuntu-16.04",
  646. }
  647. self._run_os_grains_tests("ubuntu-16.04", _os_release_map, expectation)
  648. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  649. def test_ubuntu_artful_os_grains(self):
  650. """
  651. Test if OS grains are parsed correctly in Ubuntu 17.10 "Artful Aardvark"
  652. """
  653. _os_release_map = {
  654. "linux_distribution": ("Ubuntu", "17.10", "artful"),
  655. }
  656. expectation = {
  657. "os": "Ubuntu",
  658. "os_family": "Debian",
  659. "oscodename": "artful",
  660. "osfullname": "Ubuntu",
  661. "osrelease": "17.10",
  662. "osrelease_info": (17, 10),
  663. "osmajorrelease": 17,
  664. "osfinger": "Ubuntu-17.10",
  665. }
  666. self._run_os_grains_tests("ubuntu-17.10", _os_release_map, expectation)
  667. @skipIf(not salt.utils.platform.is_windows(), "System is not Windows")
  668. def test_windows_platform_data(self):
  669. """
  670. Test the _windows_platform_data function
  671. """
  672. grains = [
  673. "biosversion",
  674. "kernelrelease",
  675. "kernelversion",
  676. "manufacturer",
  677. "motherboard",
  678. "osfullname",
  679. "osmanufacturer",
  680. "osrelease",
  681. "osservicepack",
  682. "osversion",
  683. "productname",
  684. "serialnumber",
  685. "timezone",
  686. "virtual",
  687. "windowsdomain",
  688. "windowsdomaintype",
  689. ]
  690. returned_grains = core._windows_platform_data()
  691. for grain in grains:
  692. self.assertIn(grain, returned_grains)
  693. valid_types = ["Unknown", "Unjoined", "Workgroup", "Domain"]
  694. self.assertIn(returned_grains["windowsdomaintype"], valid_types)
  695. valid_releases = [
  696. "Vista",
  697. "7",
  698. "8",
  699. "8.1",
  700. "10",
  701. "2008Server",
  702. "2008ServerR2",
  703. "2012Server",
  704. "2012ServerR2",
  705. "2016Server",
  706. "2019Server",
  707. ]
  708. self.assertIn(returned_grains["osrelease"], valid_releases)
  709. def test__windows_os_release_grain(self):
  710. versions = {
  711. "Windows 10 Home": "10",
  712. "Windows 10 Pro": "10",
  713. "Windows 10 Pro for Workstations": "10",
  714. "Windows 10 Pro Education": "10",
  715. "Windows 10 Enterprise": "10",
  716. "Windows 10 Enterprise LTSB": "10",
  717. "Windows 10 Education": "10",
  718. "Windows 10 IoT Core": "10",
  719. "Windows 10 IoT Enterprise": "10",
  720. "Windows 10 S": "10",
  721. "Windows 8.1": "8.1",
  722. "Windows 8.1 Pro": "8.1",
  723. "Windows 8.1 Enterprise": "8.1",
  724. "Windows 8.1 OEM": "8.1",
  725. "Windows 8.1 with Bing": "8.1",
  726. "Windows 8": "8",
  727. "Windows 8 Pro": "8",
  728. "Windows 8 Enterprise": "8",
  729. "Windows 8 OEM": "8",
  730. "Windows 7 Starter": "7",
  731. "Windows 7 Home Basic": "7",
  732. "Windows 7 Home Premium": "7",
  733. "Windows 7 Professional": "7",
  734. "Windows 7 Enterprise": "7",
  735. "Windows 7 Ultimate": "7",
  736. "Windows Thin PC": "Thin",
  737. "Windows Vista Starter": "Vista",
  738. "Windows Vista Home Basic": "Vista",
  739. "Windows Vista Home Premium": "Vista",
  740. "Windows Vista Business": "Vista",
  741. "Windows Vista Enterprise": "Vista",
  742. "Windows Vista Ultimate": "Vista",
  743. "Windows Server 2019 Essentials": "2019Server",
  744. "Windows Server 2019 Standard": "2019Server",
  745. "Windows Server 2019 Datacenter": "2019Server",
  746. "Windows Server 2016 Essentials": "2016Server",
  747. "Windows Server 2016 Standard": "2016Server",
  748. "Windows Server 2016 Datacenter": "2016Server",
  749. "Windows Server 2012 R2 Foundation": "2012ServerR2",
  750. "Windows Server 2012 R2 Essentials": "2012ServerR2",
  751. "Windows Server 2012 R2 Standard": "2012ServerR2",
  752. "Windows Server 2012 R2 Datacenter": "2012ServerR2",
  753. "Windows Server 2012 Foundation": "2012Server",
  754. "Windows Server 2012 Essentials": "2012Server",
  755. "Windows Server 2012 Standard": "2012Server",
  756. "Windows Server 2012 Datacenter": "2012Server",
  757. "Windows MultiPoint Server 2012": "2012Server",
  758. "Windows Small Business Server 2011": "2011Server",
  759. "Windows MultiPoint Server 2011": "2011Server",
  760. "Windows Home Server 2011": "2011Server",
  761. "Windows MultiPoint Server 2010": "2010Server",
  762. "Windows Server 2008 R2 Foundation": "2008ServerR2",
  763. "Windows Server 2008 R2 Standard": "2008ServerR2",
  764. "Windows Server 2008 R2 Enterprise": "2008ServerR2",
  765. "Windows Server 2008 R2 Datacenter": "2008ServerR2",
  766. "Windows Server 2008 R2 for Itanium-based Systems": "2008ServerR2",
  767. "Windows Web Server 2008 R2": "2008ServerR2",
  768. "Windows Storage Server 2008 R2": "2008ServerR2",
  769. "Windows HPC Server 2008 R2": "2008ServerR2",
  770. "Windows Server 2008 Standard": "2008Server",
  771. "Windows Server 2008 Enterprise": "2008Server",
  772. "Windows Server 2008 Datacenter": "2008Server",
  773. "Windows Server 2008 for Itanium-based Systems": "2008Server",
  774. "Windows Server Foundation 2008": "2008Server",
  775. "Windows Essential Business Server 2008": "2008Server",
  776. "Windows HPC Server 2008": "2008Server",
  777. "Windows Small Business Server 2008": "2008Server",
  778. "Windows Storage Server 2008": "2008Server",
  779. "Windows Web Server 2008": "2008Server",
  780. }
  781. for caption in versions:
  782. version = core._windows_os_release_grain(caption, 1)
  783. self.assertEqual(
  784. version,
  785. versions[caption],
  786. "version: {0}\n"
  787. "found: {1}\n"
  788. "caption: {2}".format(version, versions[caption], caption),
  789. )
  790. embedded_versions = {
  791. "Windows Embedded 8.1 Industry Pro": "8.1",
  792. "Windows Embedded 8 Industry Pro": "8",
  793. "Windows POSReady 7": "7",
  794. "Windows Embedded Standard 7": "7",
  795. "Windows Embedded POSReady 2009": "2009",
  796. "Windows Embedded Standard 2009": "2009",
  797. "Windows XP Embedded": "XP",
  798. }
  799. for caption in embedded_versions:
  800. version = core._windows_os_release_grain(caption, 1)
  801. self.assertEqual(
  802. version,
  803. embedded_versions[caption],
  804. "{0} != {1}\n"
  805. "version: {0}\n"
  806. "found: {1}\n"
  807. "caption: {2}".format(version, embedded_versions[caption], caption),
  808. )
  809. # Special Cases
  810. # Windows Embedded Standard is Windows 7
  811. caption = "Windows Embedded Standard"
  812. with patch("platform.release", MagicMock(return_value="7")):
  813. version = core._windows_os_release_grain(caption, 1)
  814. self.assertEqual(version, "7")
  815. # Microsoft Hyper-V Server 2019
  816. # Issue https://github.com/saltstack/salt/issue/55212
  817. caption = "Microsoft Hyper-V Server"
  818. version = core._windows_os_release_grain(caption, 1)
  819. self.assertEqual(version, "2019Server")
  820. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  821. def test_linux_memdata(self):
  822. """
  823. Test memdata on Linux systems
  824. """
  825. _proc_meminfo = textwrap.dedent(
  826. """\
  827. MemTotal: 16277028 kB
  828. SwapTotal: 4789244 kB"""
  829. )
  830. with patch("salt.utils.files.fopen", mock_open(read_data=_proc_meminfo)):
  831. memdata = core._linux_memdata()
  832. self.assertEqual(memdata.get("mem_total"), 15895)
  833. self.assertEqual(memdata.get("swap_total"), 4676)
  834. @skipIf(salt.utils.platform.is_windows(), "System is Windows")
  835. def test_bsd_memdata(self):
  836. """
  837. Test to memdata on *BSD systems
  838. """
  839. _path_exists_map = {}
  840. _path_isfile_map = {}
  841. _cmd_run_map = {
  842. "freebsd-version -u": "10.3-RELEASE",
  843. "/sbin/sysctl -n hw.physmem": "2121781248",
  844. "/sbin/sysctl -n vm.swap_total": "419430400",
  845. }
  846. path_exists_mock = MagicMock(side_effect=lambda x: _path_exists_map[x])
  847. path_isfile_mock = MagicMock(
  848. side_effect=lambda x: _path_isfile_map.get(x, False)
  849. )
  850. cmd_run_mock = MagicMock(side_effect=lambda x: _cmd_run_map[x])
  851. empty_mock = MagicMock(return_value={})
  852. mock_freebsd_uname = (
  853. "FreeBSD",
  854. "freebsd10.3-hostname-8148",
  855. "10.3-RELEASE",
  856. "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",
  857. "amd64",
  858. "amd64",
  859. )
  860. with patch("platform.uname", MagicMock(return_value=mock_freebsd_uname)):
  861. with patch.object(
  862. salt.utils.platform, "is_linux", MagicMock(return_value=False)
  863. ):
  864. with patch.object(
  865. salt.utils.platform, "is_freebsd", MagicMock(return_value=True)
  866. ):
  867. # Skip the first if statement
  868. with patch.object(
  869. salt.utils.platform, "is_proxy", MagicMock(return_value=False)
  870. ):
  871. # Skip the init grain compilation (not pertinent)
  872. with patch.object(os.path, "exists", path_exists_mock):
  873. with patch("salt.utils.path.which") as mock:
  874. mock.return_value = "/sbin/sysctl"
  875. # Make a bunch of functions return empty dicts,
  876. # we don't care about these grains for the
  877. # purposes of this test.
  878. with patch.object(core, "_bsd_cpudata", empty_mock):
  879. with patch.object(core, "_hw_data", empty_mock):
  880. with patch.object(core, "_virtual", empty_mock):
  881. with patch.object(core, "_ps", empty_mock):
  882. # Mock the osarch
  883. with patch.dict(
  884. core.__salt__,
  885. {"cmd.run": cmd_run_mock},
  886. ):
  887. os_grains = core.os_data()
  888. self.assertEqual(os_grains.get("mem_total"), 2023)
  889. self.assertEqual(os_grains.get("swap_total"), 400)
  890. @skipIf(salt.utils.platform.is_windows(), "System is Windows")
  891. def test_docker_virtual(self):
  892. """
  893. Test if virtual grains are parsed correctly in Docker.
  894. """
  895. with patch.object(os.path, "isdir", MagicMock(return_value=False)):
  896. with patch.object(
  897. os.path,
  898. "isfile",
  899. MagicMock(
  900. side_effect=lambda x: True if x == "/proc/1/cgroup" else False
  901. ),
  902. ):
  903. for cgroup_substr in (
  904. ":/system.slice/docker",
  905. ":/docker/",
  906. ":/docker-ce/",
  907. ):
  908. cgroup_data = "10:memory{0}a_long_sha256sum".format(cgroup_substr)
  909. log.debug("Testing Docker cgroup substring '%s'", cgroup_substr)
  910. with patch(
  911. "salt.utils.files.fopen", mock_open(read_data=cgroup_data)
  912. ):
  913. with patch.dict(core.__salt__, {"cmd.run_all": MagicMock()}):
  914. grains = core._virtual({"kernel": "Linux"})
  915. self.assertEqual(grains.get("virtual_subtype"), "Docker")
  916. self.assertEqual(
  917. grains.get("virtual"), "container",
  918. )
  919. @skipIf(salt.utils.platform.is_windows(), "System is Windows")
  920. def test_lxc_virtual(self):
  921. """
  922. Test if virtual grains are parsed correctly in LXC.
  923. """
  924. with patch.object(os.path, "isdir", MagicMock(return_value=False)):
  925. with patch.object(
  926. os.path,
  927. "isfile",
  928. MagicMock(
  929. side_effect=lambda x: True if x == "/proc/1/cgroup" else False
  930. ),
  931. ):
  932. cgroup_data = "10:memory:/lxc/a_long_sha256sum"
  933. with patch("salt.utils.files.fopen", mock_open(read_data=cgroup_data)):
  934. with patch.dict(core.__salt__, {"cmd.run_all": MagicMock()}):
  935. grains = core._virtual({"kernel": "Linux"})
  936. self.assertEqual(grains.get("virtual_subtype"), "LXC")
  937. self.assertEqual(
  938. grains.get("virtual"), "container",
  939. )
  940. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  941. def test_xen_virtual(self):
  942. """
  943. Test if OS grains are parsed correctly in Ubuntu Xenial Xerus
  944. """
  945. with patch.multiple(
  946. os.path,
  947. isdir=MagicMock(side_effect=lambda x: x == "/sys/bus/xen"),
  948. isfile=MagicMock(
  949. side_effect=lambda x: x == "/sys/bus/xen/drivers/xenconsole"
  950. ),
  951. ):
  952. with patch.dict(core.__salt__, {"cmd.run": MagicMock(return_value="")}):
  953. log.debug("Testing Xen")
  954. self.assertEqual(
  955. core._virtual({"kernel": "Linux"}).get("virtual_subtype"),
  956. "Xen PV DomU",
  957. )
  958. def test_if_virtual_subtype_exists_virtual_should_fallback_to_virtual(self):
  959. def mockstat(path):
  960. if path == "/":
  961. return "fnord"
  962. elif path == "/proc/1/root/.":
  963. return "roscivs"
  964. return None
  965. with patch.dict(
  966. core.__salt__,
  967. {
  968. "cmd.run": MagicMock(return_value=""),
  969. "cmd.run_all": MagicMock(return_value={"retcode": 0, "stdout": ""}),
  970. },
  971. ):
  972. with patch.multiple(
  973. os.path,
  974. isfile=MagicMock(return_value=False),
  975. isdir=MagicMock(side_effect=lambda x: x == "/proc"),
  976. ):
  977. with patch.multiple(
  978. os, stat=MagicMock(side_effect=mockstat),
  979. ):
  980. grains = core._virtual({"kernel": "Linux"})
  981. assert grains.get("virtual_subtype") is not None
  982. assert grains.get("virtual") == "virtual"
  983. def _check_ipaddress(self, value, ip_v):
  984. """
  985. check if ip address in a list is valid
  986. """
  987. for val in value:
  988. assert isinstance(val, six.string_types)
  989. ip_method = "is_ipv{0}".format(ip_v)
  990. self.assertTrue(getattr(salt.utils.network, ip_method)(val))
  991. def _check_empty(self, key, value, empty):
  992. """
  993. if empty is False and value does not exist assert error
  994. if empty is True and value exists assert error
  995. """
  996. if not empty and not value:
  997. raise Exception("{0} is empty, expecting a value".format(key))
  998. elif empty and value:
  999. raise Exception(
  1000. "{0} is suppose to be empty. value: {1} \
  1001. exists".format(
  1002. key, value
  1003. )
  1004. )
  1005. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  1006. def test_fqdn_return(self):
  1007. """
  1008. test ip4 and ip6 return values
  1009. """
  1010. net_ip4_mock = [IP4_LOCAL, IP4_ADD1, IP4_ADD2]
  1011. net_ip6_mock = [IP6_LOCAL, IP6_ADD1, IP6_ADD2]
  1012. self._run_fqdn_tests(
  1013. net_ip4_mock, net_ip6_mock, ip4_empty=False, ip6_empty=False
  1014. )
  1015. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  1016. def test_fqdn6_empty(self):
  1017. """
  1018. test when ip6 is empty
  1019. """
  1020. net_ip4_mock = [IP4_LOCAL, IP4_ADD1, IP4_ADD2]
  1021. net_ip6_mock = []
  1022. self._run_fqdn_tests(net_ip4_mock, net_ip6_mock, ip4_empty=False)
  1023. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  1024. def test_fqdn4_empty(self):
  1025. """
  1026. test when ip4 is empty
  1027. """
  1028. net_ip4_mock = []
  1029. net_ip6_mock = [IP6_LOCAL, IP6_ADD1, IP6_ADD2]
  1030. self._run_fqdn_tests(net_ip4_mock, net_ip6_mock, ip6_empty=False)
  1031. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  1032. def test_fqdn_all_empty(self):
  1033. """
  1034. test when both ip4 and ip6 are empty
  1035. """
  1036. net_ip4_mock = []
  1037. net_ip6_mock = []
  1038. self._run_fqdn_tests(net_ip4_mock, net_ip6_mock)
  1039. def _run_fqdn_tests(
  1040. self, net_ip4_mock, net_ip6_mock, ip6_empty=True, ip4_empty=True
  1041. ):
  1042. def _check_type(key, value, ip4_empty, ip6_empty):
  1043. """
  1044. check type and other checks
  1045. """
  1046. assert isinstance(value, list)
  1047. if "4" in key:
  1048. self._check_empty(key, value, ip4_empty)
  1049. self._check_ipaddress(value, ip_v="4")
  1050. elif "6" in key:
  1051. self._check_empty(key, value, ip6_empty)
  1052. self._check_ipaddress(value, ip_v="6")
  1053. ip4_mock = [(2, 1, 6, "", (IP4_ADD1, 0)), (2, 3, 0, "", (IP4_ADD2, 0))]
  1054. ip6_mock = [
  1055. (10, 1, 6, "", (IP6_ADD1, 0, 0, 0)),
  1056. (10, 3, 0, "", (IP6_ADD2, 0, 0, 0)),
  1057. ]
  1058. with patch.dict(core.__opts__, {"ipv6": False}):
  1059. with patch.object(
  1060. salt.utils.network, "ip_addrs", MagicMock(return_value=net_ip4_mock)
  1061. ):
  1062. with patch.object(
  1063. salt.utils.network,
  1064. "ip_addrs6",
  1065. MagicMock(return_value=net_ip6_mock),
  1066. ):
  1067. with patch.object(
  1068. core.socket, "getaddrinfo", side_effect=[ip4_mock, ip6_mock]
  1069. ):
  1070. get_fqdn = core.ip_fqdn()
  1071. ret_keys = ["fqdn_ip4", "fqdn_ip6", "ipv4", "ipv6"]
  1072. for key in ret_keys:
  1073. value = get_fqdn[key]
  1074. _check_type(key, value, ip4_empty, ip6_empty)
  1075. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  1076. @patch.object(salt.utils.platform, "is_windows", MagicMock(return_value=False))
  1077. @patch("salt.grains.core.__opts__", {"ipv6": False})
  1078. def test_dns_return(self):
  1079. """
  1080. test the return for a dns grain. test for issue:
  1081. https://github.com/saltstack/salt/issues/41230
  1082. """
  1083. resolv_mock = {
  1084. "domain": "",
  1085. "sortlist": [],
  1086. "nameservers": [
  1087. ipaddress.IPv4Address(IP4_ADD1),
  1088. ipaddress.IPv6Address(IP6_ADD1),
  1089. IP6_ADD_SCOPE,
  1090. ],
  1091. "ip4_nameservers": [ipaddress.IPv4Address(IP4_ADD1)],
  1092. "search": ["test.saltstack.com"],
  1093. "ip6_nameservers": [ipaddress.IPv6Address(IP6_ADD1), IP6_ADD_SCOPE],
  1094. "options": [],
  1095. }
  1096. ret = {
  1097. "dns": {
  1098. "domain": "",
  1099. "sortlist": [],
  1100. "nameservers": [IP4_ADD1, IP6_ADD1, IP6_ADD_SCOPE],
  1101. "ip4_nameservers": [IP4_ADD1],
  1102. "search": ["test.saltstack.com"],
  1103. "ip6_nameservers": [IP6_ADD1, IP6_ADD_SCOPE],
  1104. "options": [],
  1105. }
  1106. }
  1107. with patch.object(
  1108. salt.utils.dns, "parse_resolv", MagicMock(return_value=resolv_mock)
  1109. ):
  1110. assert core.dns() == ret
  1111. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  1112. @patch(
  1113. "salt.utils.network.ip_addrs", MagicMock(return_value=["1.2.3.4", "5.6.7.8"])
  1114. )
  1115. @patch(
  1116. "salt.utils.network.ip_addrs6",
  1117. MagicMock(return_value=["fe80::a8b2:93ff:fe00:0", "fe80::a8b2:93ff:dead:beef"]),
  1118. )
  1119. @patch(
  1120. "salt.utils.network.socket.getfqdn", MagicMock(side_effect=lambda v: v)
  1121. ) # Just pass-through
  1122. def test_fqdns_return(self):
  1123. """
  1124. test the return for a dns grain. test for issue:
  1125. https://github.com/saltstack/salt/issues/41230
  1126. """
  1127. reverse_resolv_mock = [
  1128. ("foo.bar.baz", [], ["1.2.3.4"]),
  1129. ("rinzler.evil-corp.com", [], ["5.6.7.8"]),
  1130. ("foo.bar.baz", [], ["fe80::a8b2:93ff:fe00:0"]),
  1131. ("bluesniff.foo.bar", [], ["fe80::a8b2:93ff:dead:beef"]),
  1132. ]
  1133. ret = {"fqdns": ["bluesniff.foo.bar", "foo.bar.baz", "rinzler.evil-corp.com"]}
  1134. with patch.object(socket, "gethostbyaddr", side_effect=reverse_resolv_mock):
  1135. fqdns = core.fqdns()
  1136. self.assertIn("fqdns", fqdns)
  1137. self.assertEqual(len(fqdns["fqdns"]), len(ret["fqdns"]))
  1138. self.assertEqual(set(fqdns["fqdns"]), set(ret["fqdns"]))
  1139. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  1140. @patch("salt.utils.network.ip_addrs", MagicMock(return_value=["1.2.3.4"]))
  1141. @patch("salt.utils.network.ip_addrs6", MagicMock(return_value=[]))
  1142. def test_fqdns_socket_error(self):
  1143. """
  1144. test the behavior on non-critical socket errors of the dns grain
  1145. """
  1146. def _gen_gethostbyaddr(errno):
  1147. def _gethostbyaddr(_):
  1148. herror = socket.herror()
  1149. herror.errno = errno
  1150. raise herror
  1151. return _gethostbyaddr
  1152. for errno in (0, core.HOST_NOT_FOUND, core.NO_DATA):
  1153. mock_log = MagicMock()
  1154. with patch.object(
  1155. socket, "gethostbyaddr", side_effect=_gen_gethostbyaddr(errno)
  1156. ):
  1157. with patch("salt.grains.core.log", mock_log):
  1158. self.assertEqual(core.fqdns(), {"fqdns": []})
  1159. mock_log.debug.assert_called_once()
  1160. mock_log.error.assert_not_called()
  1161. mock_log = MagicMock()
  1162. with patch.object(socket, "gethostbyaddr", side_effect=_gen_gethostbyaddr(-1)):
  1163. with patch("salt.grains.core.log", mock_log):
  1164. self.assertEqual(core.fqdns(), {"fqdns": []})
  1165. mock_log.debug.assert_not_called()
  1166. mock_log.error.assert_called_once()
  1167. def test_core_virtual(self):
  1168. """
  1169. test virtual grain with cmd virt-what
  1170. """
  1171. virt = "kvm"
  1172. with patch.object(
  1173. salt.utils.platform, "is_windows", MagicMock(return_value=False)
  1174. ):
  1175. with patch.object(salt.utils.path, "which", MagicMock(return_value=True)):
  1176. with patch.dict(
  1177. core.__salt__,
  1178. {
  1179. "cmd.run_all": MagicMock(
  1180. return_value={
  1181. "pid": 78,
  1182. "retcode": 0,
  1183. "stderr": "",
  1184. "stdout": virt,
  1185. }
  1186. )
  1187. },
  1188. ):
  1189. osdata = {
  1190. "kernel": "test",
  1191. }
  1192. ret = core._virtual(osdata)
  1193. self.assertEqual(ret["virtual"], virt)
  1194. def test_solaris_sparc_s7zone(self):
  1195. """
  1196. verify productname grain for s7 zone
  1197. """
  1198. expectation = {
  1199. "productname": "SPARC S7-2",
  1200. "product": "SPARC S7-2",
  1201. }
  1202. with salt.utils.files.fopen(
  1203. os.path.join(SOLARIS_DIR, "prtconf.s7-zone")
  1204. ) as sparc_return_data:
  1205. this_sparc_return_data = "\n".join(sparc_return_data.readlines())
  1206. this_sparc_return_data += "\n"
  1207. self._check_solaris_sparc_productname_grains(
  1208. this_sparc_return_data, expectation
  1209. )
  1210. def test_solaris_sparc_s7(self):
  1211. """
  1212. verify productname grain for s7
  1213. """
  1214. expectation = {
  1215. "productname": "SPARC S7-2",
  1216. "product": "SPARC S7-2",
  1217. }
  1218. with salt.utils.files.fopen(
  1219. os.path.join(SOLARIS_DIR, "prtdiag.s7")
  1220. ) as sparc_return_data:
  1221. this_sparc_return_data = "\n".join(sparc_return_data.readlines())
  1222. this_sparc_return_data += "\n"
  1223. self._check_solaris_sparc_productname_grains(
  1224. this_sparc_return_data, expectation
  1225. )
  1226. def test_solaris_sparc_t5220(self):
  1227. """
  1228. verify productname grain for t5220
  1229. """
  1230. expectation = {
  1231. "productname": "SPARC Enterprise T5220",
  1232. "product": "SPARC Enterprise T5220",
  1233. }
  1234. with salt.utils.files.fopen(
  1235. os.path.join(SOLARIS_DIR, "prtdiag.t5220")
  1236. ) as sparc_return_data:
  1237. this_sparc_return_data = "\n".join(sparc_return_data.readlines())
  1238. this_sparc_return_data += "\n"
  1239. self._check_solaris_sparc_productname_grains(
  1240. this_sparc_return_data, expectation
  1241. )
  1242. def test_solaris_sparc_t5220zone(self):
  1243. """
  1244. verify productname grain for t5220 zone
  1245. """
  1246. expectation = {
  1247. "productname": "SPARC Enterprise T5220",
  1248. "product": "SPARC Enterprise T5220",
  1249. }
  1250. with salt.utils.files.fopen(
  1251. os.path.join(SOLARIS_DIR, "prtconf.t5220-zone")
  1252. ) as sparc_return_data:
  1253. this_sparc_return_data = "\n".join(sparc_return_data.readlines())
  1254. this_sparc_return_data += "\n"
  1255. self._check_solaris_sparc_productname_grains(
  1256. this_sparc_return_data, expectation
  1257. )
  1258. def _check_solaris_sparc_productname_grains(self, prtdata, expectation):
  1259. """
  1260. verify product grains on solaris sparc
  1261. """
  1262. import platform
  1263. path_isfile_mock = MagicMock(side_effect=lambda x: x in ["/etc/release"])
  1264. with salt.utils.files.fopen(
  1265. os.path.join(OS_RELEASE_DIR, "solaris-11.3")
  1266. ) as os_release_file:
  1267. os_release_content = os_release_file.readlines()
  1268. uname_mock = MagicMock(
  1269. return_value=("SunOS", "testsystem", "5.11", "11.3", "sunv4", "sparc")
  1270. )
  1271. with patch.object(platform, "uname", uname_mock), patch.object(
  1272. salt.utils.platform, "is_proxy", MagicMock(return_value=False)
  1273. ), patch.object(
  1274. salt.utils.platform, "is_linux", MagicMock(return_value=False)
  1275. ), patch.object(
  1276. salt.utils.platform, "is_windows", MagicMock(return_value=False)
  1277. ), patch.object(
  1278. salt.utils.platform, "is_smartos", MagicMock(return_value=False)
  1279. ), patch.object(
  1280. salt.utils.path, "which_bin", MagicMock(return_value=None)
  1281. ), patch.object(
  1282. os.path, "isfile", path_isfile_mock
  1283. ), patch(
  1284. "salt.utils.files.fopen", mock_open(read_data=os_release_content)
  1285. ) as os_release_file, patch.object(
  1286. core,
  1287. "_sunos_cpudata",
  1288. MagicMock(
  1289. return_value={
  1290. "cpuarch": "sparcv9",
  1291. "num_cpus": "1",
  1292. "cpu_model": "MOCK_CPU_MODEL",
  1293. "cpu_flags": [],
  1294. }
  1295. ),
  1296. ), patch.object(
  1297. core, "_memdata", MagicMock(return_value={"mem_total": 16384})
  1298. ), patch.object(
  1299. core, "_virtual", MagicMock(return_value={})
  1300. ), patch.object(
  1301. core, "_ps", MagicMock(return_value={})
  1302. ), patch.object(
  1303. salt.utils.path, "which", MagicMock(return_value=True)
  1304. ), patch.dict(
  1305. core.__salt__, {"cmd.run": MagicMock(return_value=prtdata)}
  1306. ):
  1307. os_grains = core.os_data()
  1308. grains = {
  1309. k: v for k, v in os_grains.items() if k in set(["product", "productname"])
  1310. }
  1311. self.assertEqual(grains, expectation)
  1312. @patch("os.path.isfile")
  1313. @patch("os.path.isdir")
  1314. def test_core_virtual_unicode(self, mock_file, mock_dir):
  1315. """
  1316. test virtual grain with unicode character in product_name file
  1317. """
  1318. def path_side_effect(path):
  1319. if path == "/sys/devices/virtual/dmi/id/product_name":
  1320. return True
  1321. return False
  1322. virt = "kvm"
  1323. mock_file.side_effect = path_side_effect
  1324. mock_dir.side_effect = path_side_effect
  1325. with patch.object(
  1326. salt.utils.platform, "is_windows", MagicMock(return_value=False)
  1327. ):
  1328. with patch.object(salt.utils.path, "which", MagicMock(return_value=True)):
  1329. with patch.dict(
  1330. core.__salt__,
  1331. {
  1332. "cmd.run_all": MagicMock(
  1333. return_value={
  1334. "pid": 78,
  1335. "retcode": 0,
  1336. "stderr": "",
  1337. "stdout": virt,
  1338. }
  1339. )
  1340. },
  1341. ):
  1342. with patch("salt.utils.files.fopen", mock_open(read_data="嗨")):
  1343. osdata = {
  1344. "kernel": "Linux",
  1345. }
  1346. ret = core._virtual(osdata)
  1347. self.assertEqual(ret["virtual"], virt)
  1348. @patch("salt.utils.path.which", MagicMock(return_value="/usr/sbin/sysctl"))
  1349. def test_osx_memdata_with_comma(self):
  1350. """
  1351. test osx memdata method when comma returns
  1352. """
  1353. def _cmd_side_effect(cmd):
  1354. if "hw.memsize" in cmd:
  1355. return "4294967296"
  1356. elif "vm.swapusage" in cmd:
  1357. return "total = 1024,00M used = 160,75M free = 863,25M (encrypted)"
  1358. with patch.dict(
  1359. core.__salt__, {"cmd.run": MagicMock(side_effect=_cmd_side_effect)}
  1360. ):
  1361. ret = core._osx_memdata()
  1362. assert ret["swap_total"] == 1024
  1363. assert ret["mem_total"] == 4096
  1364. @patch("salt.utils.path.which", MagicMock(return_value="/usr/sbin/sysctl"))
  1365. def test_osx_memdata(self):
  1366. """
  1367. test osx memdata
  1368. """
  1369. def _cmd_side_effect(cmd):
  1370. if "hw.memsize" in cmd:
  1371. return "4294967296"
  1372. elif "vm.swapusage" in cmd:
  1373. return "total = 0.00M used = 0.00M free = 0.00M (encrypted)"
  1374. with patch.dict(
  1375. core.__salt__, {"cmd.run": MagicMock(side_effect=_cmd_side_effect)}
  1376. ):
  1377. ret = core._osx_memdata()
  1378. assert ret["swap_total"] == 0
  1379. assert ret["mem_total"] == 4096
  1380. @skipIf(not core._DATEUTIL_TZ, "Missing dateutil.tz")
  1381. def test_locale_info_tzname(self):
  1382. # mock datetime.now().tzname()
  1383. # cant just mock now because it is read only
  1384. tzname = Mock(return_value="MDT_FAKE")
  1385. now_ret_object = Mock(tzname=tzname)
  1386. now = Mock(return_value=now_ret_object)
  1387. datetime = Mock(now=now)
  1388. with patch.object(core, "datetime", datetime=datetime) as datetime_module:
  1389. with patch.object(
  1390. core.dateutil.tz, "tzlocal", return_value=object
  1391. ) as tzlocal:
  1392. with patch.object(
  1393. salt.utils.platform, "is_proxy", return_value=False
  1394. ) as is_proxy:
  1395. ret = core.locale_info()
  1396. tzname.assert_called_once_with()
  1397. self.assertEqual(len(now_ret_object.method_calls), 1)
  1398. now.assert_called_once_with(object)
  1399. self.assertEqual(len(datetime.method_calls), 1)
  1400. self.assertEqual(len(datetime_module.method_calls), 1)
  1401. tzlocal.assert_called_once_with()
  1402. is_proxy.assert_called_once_with()
  1403. self.assertEqual(ret["locale_info"]["timezone"], "MDT_FAKE")
  1404. @skipIf(not core._DATEUTIL_TZ, "Missing dateutil.tz")
  1405. def test_locale_info_unicode_error_tzname(self):
  1406. # UnicodeDecodeError most have the default string encoding
  1407. unicode_error = UnicodeDecodeError(str("fake"), b"\x00\x00", 1, 2, str("fake"))
  1408. # mock datetime.now().tzname()
  1409. # cant just mock now because it is read only
  1410. tzname = Mock(return_value="MDT_FAKE")
  1411. now_ret_object = Mock(tzname=tzname)
  1412. now = Mock(return_value=now_ret_object)
  1413. datetime = Mock(now=now)
  1414. # mock tzname[0].decode()
  1415. decode = Mock(return_value="CST_FAKE")
  1416. tzname2 = (Mock(decode=decode,),)
  1417. with patch.object(core, "datetime", datetime=datetime) as datetime_module:
  1418. with patch.object(
  1419. core.dateutil.tz, "tzlocal", side_effect=unicode_error
  1420. ) as tzlocal:
  1421. with patch.object(
  1422. salt.utils.platform, "is_proxy", return_value=False
  1423. ) as is_proxy:
  1424. with patch.object(
  1425. core.salt.utils.platform, "is_windows", return_value=True
  1426. ) as is_windows:
  1427. with patch.object(core, "time", tzname=tzname2):
  1428. ret = core.locale_info()
  1429. tzname.assert_not_called()
  1430. self.assertEqual(len(now_ret_object.method_calls), 0)
  1431. now.assert_not_called()
  1432. self.assertEqual(len(datetime.method_calls), 0)
  1433. decode.assert_called_once_with("mbcs")
  1434. self.assertEqual(len(tzname2[0].method_calls), 1)
  1435. self.assertEqual(len(datetime_module.method_calls), 0)
  1436. tzlocal.assert_called_once_with()
  1437. is_proxy.assert_called_once_with()
  1438. is_windows.assert_called_once_with()
  1439. self.assertEqual(ret["locale_info"]["timezone"], "CST_FAKE")
  1440. @skipIf(core._DATEUTIL_TZ, "Not Missing dateutil.tz")
  1441. def test_locale_info_no_tz_tzname(self):
  1442. with patch.object(
  1443. salt.utils.platform, "is_proxy", return_value=False
  1444. ) as is_proxy:
  1445. with patch.object(
  1446. core.salt.utils.platform, "is_windows", return_value=True
  1447. ) as is_windows:
  1448. ret = core.locale_info()
  1449. is_proxy.assert_called_once_with()
  1450. is_windows.assert_not_called()
  1451. self.assertEqual(ret["locale_info"]["timezone"], "unknown")
  1452. def test_cwd_exists(self):
  1453. cwd_grain = core.cwd()
  1454. self.assertIsInstance(cwd_grain, dict)
  1455. self.assertTrue("cwd" in cwd_grain)
  1456. self.assertEqual(cwd_grain["cwd"], os.getcwd())
  1457. def test_cwd_is_cwd(self):
  1458. cwd = os.getcwd()
  1459. try:
  1460. # change directory
  1461. new_dir = os.path.split(cwd)[0]
  1462. os.chdir(new_dir)
  1463. cwd_grain = core.cwd()
  1464. self.assertEqual(cwd_grain["cwd"], new_dir)
  1465. finally:
  1466. # change back to original directory
  1467. os.chdir(cwd)
  1468. def test_virtual_set_virtual_grain(self):
  1469. osdata = {}
  1470. (
  1471. osdata["kernel"],
  1472. osdata["nodename"],
  1473. osdata["kernelrelease"],
  1474. osdata["kernelversion"],
  1475. osdata["cpuarch"],
  1476. _,
  1477. ) = platform.uname()
  1478. with patch.dict(
  1479. core.__salt__,
  1480. {
  1481. "cmd.run": salt.modules.cmdmod.run,
  1482. "cmd.run_all": salt.modules.cmdmod.run_all,
  1483. "cmd.retcode": salt.modules.cmdmod.retcode,
  1484. "smbios.get": salt.modules.smbios.get,
  1485. },
  1486. ):
  1487. virtual_grains = core._virtual(osdata)
  1488. self.assertIn("virtual", virtual_grains)
  1489. def test_virtual_has_virtual_grain(self):
  1490. osdata = {"virtual": "something"}
  1491. (
  1492. osdata["kernel"],
  1493. osdata["nodename"],
  1494. osdata["kernelrelease"],
  1495. osdata["kernelversion"],
  1496. osdata["cpuarch"],
  1497. _,
  1498. ) = platform.uname()
  1499. with patch.dict(
  1500. core.__salt__,
  1501. {
  1502. "cmd.run": salt.modules.cmdmod.run,
  1503. "cmd.run_all": salt.modules.cmdmod.run_all,
  1504. "cmd.retcode": salt.modules.cmdmod.retcode,
  1505. "smbios.get": salt.modules.smbios.get,
  1506. },
  1507. ):
  1508. virtual_grains = core._virtual(osdata)
  1509. self.assertIn("virtual", virtual_grains)
  1510. self.assertNotEqual(virtual_grains["virtual"], "physical")
  1511. @skipIf(not salt.utils.platform.is_windows(), "System is not Windows")
  1512. def test_windows_virtual_set_virtual_grain(self):
  1513. osdata = {}
  1514. (
  1515. osdata["kernel"],
  1516. osdata["nodename"],
  1517. osdata["kernelrelease"],
  1518. osdata["kernelversion"],
  1519. osdata["cpuarch"],
  1520. _,
  1521. ) = platform.uname()
  1522. with patch.dict(
  1523. core.__salt__,
  1524. {
  1525. "cmd.run": salt.modules.cmdmod.run,
  1526. "cmd.run_all": salt.modules.cmdmod.run_all,
  1527. "cmd.retcode": salt.modules.cmdmod.retcode,
  1528. "smbios.get": salt.modules.smbios.get,
  1529. },
  1530. ):
  1531. virtual_grains = core._windows_virtual(osdata)
  1532. self.assertIn("virtual", virtual_grains)
  1533. @skipIf(not salt.utils.platform.is_windows(), "System is not Windows")
  1534. def test_windows_virtual_has_virtual_grain(self):
  1535. osdata = {"virtual": "something"}
  1536. (
  1537. osdata["kernel"],
  1538. osdata["nodename"],
  1539. osdata["kernelrelease"],
  1540. osdata["kernelversion"],
  1541. osdata["cpuarch"],
  1542. _,
  1543. ) = platform.uname()
  1544. with patch.dict(
  1545. core.__salt__,
  1546. {
  1547. "cmd.run": salt.modules.cmdmod.run,
  1548. "cmd.run_all": salt.modules.cmdmod.run_all,
  1549. "cmd.retcode": salt.modules.cmdmod.retcode,
  1550. "smbios.get": salt.modules.smbios.get,
  1551. },
  1552. ):
  1553. virtual_grains = core._windows_virtual(osdata)
  1554. self.assertIn("virtual", virtual_grains)
  1555. self.assertNotEqual(virtual_grains["virtual"], "physical")
  1556. @skipIf(not salt.utils.platform.is_windows(), "System is not Windows")
  1557. def test_osdata_virtual_key_win(self):
  1558. with patch.dict(
  1559. core.__salt__,
  1560. {
  1561. "cmd.run": salt.modules.cmdmod.run,
  1562. "cmd.run_all": salt.modules.cmdmod.run_all,
  1563. "cmd.retcode": salt.modules.cmdmod.retcode,
  1564. "smbios.get": salt.modules.smbios.get,
  1565. },
  1566. ):
  1567. _windows_platform_data_ret = core.os_data()
  1568. _windows_platform_data_ret["virtual"] = "something"
  1569. with patch.object(
  1570. core, "_windows_platform_data", return_value=_windows_platform_data_ret
  1571. ) as _windows_platform_data:
  1572. osdata_grains = core.os_data()
  1573. _windows_platform_data.assert_called_once()
  1574. self.assertIn("virtual", osdata_grains)
  1575. self.assertNotEqual(osdata_grains["virtual"], "physical")
  1576. @skipIf(salt.utils.platform.is_windows(), "System is Windows")
  1577. def test_bsd_osfullname(self):
  1578. """
  1579. Test to ensure osfullname exists on *BSD systems
  1580. """
  1581. _path_exists_map = {}
  1582. _path_isfile_map = {}
  1583. _cmd_run_map = {
  1584. "freebsd-version -u": "10.3-RELEASE",
  1585. "/sbin/sysctl -n hw.physmem": "2121781248",
  1586. "/sbin/sysctl -n vm.swap_total": "419430400",
  1587. }
  1588. path_exists_mock = MagicMock(side_effect=lambda x: _path_exists_map[x])
  1589. path_isfile_mock = MagicMock(
  1590. side_effect=lambda x: _path_isfile_map.get(x, False)
  1591. )
  1592. cmd_run_mock = MagicMock(side_effect=lambda x: _cmd_run_map[x])
  1593. empty_mock = MagicMock(return_value={})
  1594. mock_freebsd_uname = (
  1595. "FreeBSD",
  1596. "freebsd10.3-hostname-8148",
  1597. "10.3-RELEASE",
  1598. "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",
  1599. "amd64",
  1600. "amd64",
  1601. )
  1602. with patch("platform.uname", MagicMock(return_value=mock_freebsd_uname)):
  1603. with patch.object(
  1604. salt.utils.platform, "is_linux", MagicMock(return_value=False)
  1605. ):
  1606. with patch.object(
  1607. salt.utils.platform, "is_freebsd", MagicMock(return_value=True)
  1608. ):
  1609. # Skip the first if statement
  1610. with patch.object(
  1611. salt.utils.platform, "is_proxy", MagicMock(return_value=False)
  1612. ):
  1613. # Skip the init grain compilation (not pertinent)
  1614. with patch.object(os.path, "exists", path_exists_mock):
  1615. with patch("salt.utils.path.which") as mock:
  1616. mock.return_value = "/sbin/sysctl"
  1617. # Make a bunch of functions return empty dicts,
  1618. # we don't care about these grains for the
  1619. # purposes of this test.
  1620. with patch.object(
  1621. core, "_bsd_cpudata", empty_mock
  1622. ), patch.object(
  1623. core, "_hw_data", empty_mock
  1624. ), patch.object(
  1625. core, "_virtual", empty_mock
  1626. ), patch.object(
  1627. core, "_ps", empty_mock
  1628. ), patch.dict(
  1629. core.__salt__, {"cmd.run": cmd_run_mock}
  1630. ):
  1631. os_grains = core.os_data()
  1632. self.assertIn("osfullname", os_grains)
  1633. self.assertEqual(os_grains.get("osfullname"), "FreeBSD")
  1634. def test_saltversioninfo(self):
  1635. """
  1636. test saltversioninfo core grain.
  1637. """
  1638. ret = core.saltversioninfo()
  1639. info = ret["saltversioninfo"]
  1640. assert isinstance(ret, dict)
  1641. assert isinstance(info, list)
  1642. try:
  1643. assert len(info) == 1
  1644. except AssertionError:
  1645. # We have a minor version we need to test
  1646. assert len(info) == 2
  1647. assert all([x is not None for x in info])
  1648. assert all([isinstance(x, int) for x in info])
  1649. def test_path(self):
  1650. comps = ["foo", "bar", "baz"]
  1651. path = os.path.pathsep.join(comps)
  1652. with patch.dict(os.environ, {"PATH": path}):
  1653. result = core.path()
  1654. assert result == {"path": path, "systempath": comps}, result
  1655. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  1656. @patch("os.path.exists")
  1657. @patch("salt.utils.platform.is_proxy")
  1658. def test__hw_data_linux_empty(self, is_proxy, exists):
  1659. is_proxy.return_value = False
  1660. exists.return_value = True
  1661. with patch("salt.utils.files.fopen", mock_open(read_data="")):
  1662. self.assertEqual(
  1663. core._hw_data({"kernel": "Linux"}),
  1664. {
  1665. "biosreleasedate": "",
  1666. "biosversion": "",
  1667. "manufacturer": "",
  1668. "productname": "",
  1669. "serialnumber": "",
  1670. "uuid": "",
  1671. },
  1672. )
  1673. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  1674. @patch("os.path.exists")
  1675. @patch("salt.utils.platform.is_proxy")
  1676. def test__hw_data_linux_unicode_error(self, is_proxy, exists):
  1677. def _fopen(*args):
  1678. class _File(object):
  1679. def __enter__(self):
  1680. return self
  1681. def __exit__(self, *args):
  1682. pass
  1683. def read(self):
  1684. raise UnicodeDecodeError("enconding", b"", 1, 2, "reason")
  1685. return _File()
  1686. is_proxy.return_value = False
  1687. exists.return_value = True
  1688. with patch("salt.utils.files.fopen", _fopen):
  1689. self.assertEqual(core._hw_data({"kernel": "Linux"}), {})
  1690. @skipIf(not salt.utils.platform.is_linux(), "System is not Linux")
  1691. def test_kernelparams_return(self):
  1692. expectations = [
  1693. (
  1694. "BOOT_IMAGE=/vmlinuz-3.10.0-693.2.2.el7.x86_64",
  1695. {
  1696. "kernelparams": [
  1697. ("BOOT_IMAGE", "/vmlinuz-3.10.0-693.2.2.el7.x86_64")
  1698. ]
  1699. },
  1700. ),
  1701. (
  1702. "root=/dev/mapper/centos_daemon-root",
  1703. {"kernelparams": [("root", "/dev/mapper/centos_daemon-root")]},
  1704. ),
  1705. (
  1706. "rhgb quiet ro",
  1707. {"kernelparams": [("rhgb", None), ("quiet", None), ("ro", None)]},
  1708. ),
  1709. ('param="value1"', {"kernelparams": [("param", "value1")]}),
  1710. (
  1711. 'param="value1 value2 value3"',
  1712. {"kernelparams": [("param", "value1 value2 value3")]},
  1713. ),
  1714. (
  1715. 'param="value1 value2 value3" LANG="pl" ro',
  1716. {
  1717. "kernelparams": [
  1718. ("param", "value1 value2 value3"),
  1719. ("LANG", "pl"),
  1720. ("ro", None),
  1721. ]
  1722. },
  1723. ),
  1724. ("ipv6.disable=1", {"kernelparams": [("ipv6.disable", "1")]}),
  1725. (
  1726. 'param="value1:value2:value3"',
  1727. {"kernelparams": [("param", "value1:value2:value3")]},
  1728. ),
  1729. (
  1730. 'param="value1,value2,value3"',
  1731. {"kernelparams": [("param", "value1,value2,value3")]},
  1732. ),
  1733. (
  1734. 'param="value1" param="value2" param="value3"',
  1735. {
  1736. "kernelparams": [
  1737. ("param", "value1"),
  1738. ("param", "value2"),
  1739. ("param", "value3"),
  1740. ]
  1741. },
  1742. ),
  1743. ]
  1744. for cmdline, expectation in expectations:
  1745. with patch("salt.utils.files.fopen", mock_open(read_data=cmdline)):
  1746. self.assertEqual(core.kernelparams(), expectation)
  1747. @patch("salt.utils.path.which", MagicMock(return_value="/usr/sbin/lspci"))
  1748. def test_linux_gpus(self):
  1749. """
  1750. Test GPU detection on Linux systems
  1751. """
  1752. def _cmd_side_effect(cmd):
  1753. ret = ""
  1754. for device in devices:
  1755. ret += textwrap.dedent(
  1756. """
  1757. Class: {0}
  1758. Vendor: {1}
  1759. Device: {2}
  1760. SVendor: Evil Corp.
  1761. SDevice: Graphics XXL
  1762. Rev: c1
  1763. NUMANode: 0"""
  1764. ).format(*device)
  1765. ret += "\n"
  1766. return ret.strip()
  1767. devices = [
  1768. [
  1769. "VGA compatible controller",
  1770. "Advanced Micro Devices, Inc. [AMD/ATI]",
  1771. "Vega [Radeon RX Vega]]",
  1772. "amd",
  1773. ], # AMD
  1774. [
  1775. "Audio device",
  1776. "Advanced Micro Devices, Inc. [AMD/ATI]",
  1777. "Device aaf8",
  1778. None,
  1779. ], # non-GPU device
  1780. [
  1781. "VGA compatible controller",
  1782. "NVIDIA Corporation",
  1783. "GK208 [GeForce GT 730]",
  1784. "nvidia",
  1785. ], # Nvidia
  1786. [
  1787. "VGA compatible controller",
  1788. "Intel Corporation",
  1789. "Device 5912",
  1790. "intel",
  1791. ], # Intel
  1792. [
  1793. "VGA compatible controller",
  1794. "ATI Technologies Inc",
  1795. "RC410 [Radeon Xpress 200M]",
  1796. "ati",
  1797. ], # ATI
  1798. [
  1799. "3D controller",
  1800. "NVIDIA Corporation",
  1801. "GeForce GTX 950M",
  1802. "nvidia",
  1803. ], # 3D controller
  1804. ]
  1805. with patch.dict(
  1806. core.__salt__, {"cmd.run": MagicMock(side_effect=_cmd_side_effect)}
  1807. ):
  1808. ret = core._linux_gpu_data()["gpus"]
  1809. count = 0
  1810. for device in devices:
  1811. if device[3] is None:
  1812. continue
  1813. assert ret[count]["model"] == device[2]
  1814. assert ret[count]["vendor"] == device[3]
  1815. count += 1