test_core.py 81 KB

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