test_core.py 78 KB

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