test_disk.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. # -*- coding: utf-8 -*-
  2. """
  3. Tests for disk state
  4. """
  5. # Import Python libs
  6. from __future__ import absolute_import, print_function, unicode_literals
  7. from os import path
  8. import pytest
  9. # Import Salt Libs
  10. import salt.states.disk as disk
  11. # Import Salt Testing Libs
  12. from tests.support.mixins import LoaderModuleMockMixin
  13. from tests.support.mock import MagicMock, patch
  14. from tests.support.unit import TestCase
  15. class DiskTestCase(TestCase, LoaderModuleMockMixin):
  16. """
  17. Test disk state
  18. """
  19. def setup_loader_modules(self):
  20. self.mock_data = {
  21. "/": {
  22. "1K-blocks": "41147472",
  23. "available": "37087976",
  24. "capacity": "6%",
  25. "filesystem": "/dev/xvda1",
  26. "used": "2172880",
  27. },
  28. "/dev": {
  29. "1K-blocks": "10240",
  30. "available": "10240",
  31. "capacity": "0%",
  32. "filesystem": "udev",
  33. "used": "0",
  34. },
  35. "/run": {
  36. "1K-blocks": "410624",
  37. "available": "379460",
  38. "capacity": "8%",
  39. "filesystem": "tmpfs",
  40. "used": "31164",
  41. },
  42. "/sys/fs/cgroup": {
  43. "1K-blocks": "1026556",
  44. "available": "1026556",
  45. "capacity": "0%",
  46. "filesystem": "tmpfs",
  47. "used": "0",
  48. },
  49. }
  50. self.mock_data_path = {"/foo": {"available": "42", "total": "100"}}
  51. self.addCleanup(delattr, self, "mock_data")
  52. self.addCleanup(delattr, self, "mock_data_path")
  53. return {
  54. disk: {
  55. "__salt__": {
  56. "disk.usage": MagicMock(return_value=self.mock_data),
  57. "status.diskusage": MagicMock(return_value=self.mock_data_path),
  58. }
  59. }
  60. }
  61. def test_status_missing(self):
  62. """
  63. Test disk.status when name not found
  64. """
  65. mock_fs = "/mnt/cheese"
  66. mock_ret = {
  67. "name": mock_fs,
  68. "result": False,
  69. "comment": "Disk mount /mnt/cheese not present. Directory /mnt/cheese does not exist or is not a directory",
  70. "changes": {},
  71. "data": {},
  72. }
  73. ret = disk.status(mock_fs)
  74. self.assertEqual(ret, mock_ret)
  75. def test_status_type_error(self):
  76. """
  77. Test disk.status with incorrectly formatted arguments
  78. """
  79. mock_fs = "/"
  80. mock_ret = {
  81. "name": mock_fs,
  82. "result": False,
  83. "comment": "",
  84. "changes": {},
  85. "data": {},
  86. }
  87. mock_ret["comment"] = "maximum must be an integer "
  88. ret = disk.status(mock_fs, maximum=r"e^{i\pi}")
  89. self.assertEqual(ret, mock_ret)
  90. mock_ret["comment"] = "minimum must be an integer "
  91. ret = disk.status(mock_fs, minimum=r"\cos\pi + i\sin\pi")
  92. self.assertEqual(ret, mock_ret)
  93. @pytest.mark.slow_test(seconds=1) # Test takes >0.1 and <=1 seconds
  94. def test_status_range_error(self):
  95. """
  96. Test disk.status with excessive extrema
  97. """
  98. mock_fs = "/"
  99. mock_ret = {
  100. "name": mock_fs,
  101. "result": False,
  102. "comment": "",
  103. "changes": {},
  104. "data": {},
  105. }
  106. mock_ret["comment"] = "maximum must be in the range [0, 100] "
  107. ret = disk.status(mock_fs, maximum="-1")
  108. self.assertEqual(ret, mock_ret)
  109. mock_ret["comment"] = "minimum must be in the range [0, 100] "
  110. ret = disk.status(mock_fs, minimum="101")
  111. self.assertEqual(ret, mock_ret)
  112. def test_status_inverted_range(self):
  113. """
  114. Test disk.status when minimum > maximum
  115. """
  116. mock_fs = "/"
  117. mock_ret = {
  118. "name": mock_fs,
  119. "result": False,
  120. "comment": "minimum must be less than maximum ",
  121. "changes": {},
  122. "data": {},
  123. }
  124. ret = disk.status(mock_fs, maximum="0", minimum="1")
  125. self.assertEqual(ret, mock_ret)
  126. def test_status_threshold(self):
  127. """
  128. Test disk.status when filesystem triggers thresholds
  129. """
  130. mock_min = 100
  131. mock_max = 0
  132. mock_fs = "/"
  133. mock_used = int(self.mock_data[mock_fs]["capacity"].strip("%"))
  134. mock_ret = {
  135. "name": mock_fs,
  136. "result": False,
  137. "comment": "",
  138. "changes": {},
  139. "data": self.mock_data[mock_fs],
  140. }
  141. mock_ret[
  142. "comment"
  143. ] = "Disk used space is below minimum of {0} % at {1} %".format(
  144. mock_min, mock_used
  145. )
  146. ret = disk.status(mock_fs, minimum=mock_min)
  147. self.assertEqual(ret, mock_ret)
  148. mock_ret[
  149. "comment"
  150. ] = "Disk used space is above maximum of {0} % at {1} %".format(
  151. mock_max, mock_used
  152. )
  153. ret = disk.status(mock_fs, maximum=mock_max)
  154. self.assertEqual(ret, mock_ret)
  155. def test_status_strip(self):
  156. """
  157. Test disk.status appropriately strips unit info from numbers
  158. """
  159. mock_fs = "/"
  160. mock_ret = {
  161. "name": mock_fs,
  162. "result": True,
  163. "comment": "Disk used space in acceptable range",
  164. "changes": {},
  165. "data": self.mock_data[mock_fs],
  166. }
  167. ret = disk.status(mock_fs, minimum="0%")
  168. self.assertEqual(ret, mock_ret)
  169. ret = disk.status(mock_fs, minimum="0 %")
  170. self.assertEqual(ret, mock_ret)
  171. ret = disk.status(mock_fs, maximum="100%")
  172. self.assertEqual(ret, mock_ret)
  173. ret = disk.status(mock_fs, minimum="1024K", absolute=True)
  174. self.assertEqual(ret, mock_ret)
  175. ret = disk.status(mock_fs, minimum="1024KB", absolute=True)
  176. self.assertEqual(ret, mock_ret)
  177. ret = disk.status(mock_fs, maximum="4194304 KB", absolute=True)
  178. self.assertEqual(ret, mock_ret)
  179. def test_status(self):
  180. """
  181. Test disk.status when filesystem meets thresholds
  182. """
  183. mock_min = 0
  184. mock_max = 100
  185. mock_fs = "/"
  186. mock_ret = {
  187. "name": mock_fs,
  188. "result": True,
  189. "comment": "Disk used space in acceptable range",
  190. "changes": {},
  191. "data": self.mock_data[mock_fs],
  192. }
  193. ret = disk.status(mock_fs, minimum=mock_min)
  194. self.assertEqual(ret, mock_ret)
  195. ret = disk.status(mock_fs, maximum=mock_max)
  196. self.assertEqual(ret, mock_ret)
  197. # Reset mock because it's an iterator to run the tests with the
  198. # absolute flag
  199. ret = {
  200. "name": mock_fs,
  201. "result": False,
  202. "comment": "",
  203. "changes": {},
  204. "data": {},
  205. }
  206. data_1 = {"capacity": "8 %", "used": "8", "available": "92"}
  207. data_2 = {"capacity": "22 %", "used": "22", "available": "78"}
  208. data_3 = {"capacity": "15 %", "used": "15", "available": "85"}
  209. mock = MagicMock(
  210. side_effect=[[], {mock_fs: data_1}, {mock_fs: data_2}, {mock_fs: data_3}]
  211. )
  212. with patch.dict(disk.__salt__, {"disk.usage": mock}):
  213. mock = MagicMock(return_value=False)
  214. with patch.object(path, "isdir", mock):
  215. comt = "Disk mount / not present. Directory / does not exist or is not a directory"
  216. ret.update({"comment": comt})
  217. self.assertDictEqual(disk.status(mock_fs), ret)
  218. comt = "minimum must be less than maximum "
  219. ret.update({"comment": comt})
  220. self.assertDictEqual(
  221. disk.status(mock_fs, "10", "20", absolute=True), ret
  222. )
  223. comt = "Disk used space is below minimum of 10 KB at 8 KB"
  224. ret.update({"comment": comt, "data": data_1})
  225. self.assertDictEqual(
  226. disk.status(mock_fs, "20", "10", absolute=True), ret
  227. )
  228. comt = "Disk used space is above maximum of 20 KB at 22 KB"
  229. ret.update({"comment": comt, "data": data_2})
  230. self.assertDictEqual(
  231. disk.status(mock_fs, "20", "10", absolute=True), ret
  232. )
  233. comt = "Disk used space in acceptable range"
  234. ret.update({"comment": comt, "result": True, "data": data_3})
  235. self.assertDictEqual(
  236. disk.status(mock_fs, "20", "10", absolute=True), ret
  237. )
  238. def test_path_missing(self):
  239. mock_fs = "/bar"
  240. mock_ret = {
  241. "name": mock_fs,
  242. "result": False,
  243. "comment": "Disk mount {0} not present. Directory {0} does not exist or is not a directory".format(
  244. mock_fs
  245. ),
  246. "changes": {},
  247. "data": {},
  248. }
  249. mock = MagicMock(return_value=False)
  250. with patch.object(path, "isdir", mock):
  251. self.assertDictEqual(
  252. disk.status(mock_fs, "58", "55", absolute=True, free=False), mock_ret
  253. )
  254. # acceptable range
  255. def test_path_used_absolute_acceptable(self):
  256. mock_fs = "/foo"
  257. mock_ret = {
  258. "name": mock_fs,
  259. "result": True,
  260. "comment": "Disk used space in acceptable range",
  261. "changes": {},
  262. "data": self.mock_data_path,
  263. }
  264. mock = MagicMock(return_value=True)
  265. with patch.object(path, "isdir", mock):
  266. self.assertDictEqual(
  267. disk.status(mock_fs, "58", "55", absolute=True, free=False), mock_ret
  268. )
  269. def test_path_used_relative_acceptable(self):
  270. mock_fs = "/foo"
  271. mock_ret = {
  272. "name": mock_fs,
  273. "result": True,
  274. "comment": "Disk used space in acceptable range",
  275. "changes": {},
  276. "data": self.mock_data_path,
  277. }
  278. mock = MagicMock(return_value=True)
  279. with patch.object(path, "isdir", mock):
  280. self.assertDictEqual(
  281. disk.status(mock_fs, "100%", "57%", absolute=False, free=False),
  282. mock_ret,
  283. )
  284. def test_path_free_absolute_acceptable(self):
  285. mock_fs = "/foo"
  286. mock_ret = {
  287. "name": mock_fs,
  288. "result": True,
  289. "comment": "Disk used space in acceptable range",
  290. "changes": {},
  291. "data": self.mock_data_path,
  292. }
  293. mock = MagicMock(return_value=True)
  294. with patch.object(path, "isdir", mock):
  295. self.assertDictEqual(
  296. disk.status(mock_fs, "100", "42", absolute=True, free=True), mock_ret
  297. )
  298. def test_path_free_relative_acceptable(self):
  299. mock_fs = "/foo"
  300. mock_ret = {
  301. "name": mock_fs,
  302. "result": True,
  303. "comment": "Disk used space in acceptable range",
  304. "changes": {},
  305. "data": self.mock_data_path,
  306. }
  307. mock = MagicMock(return_value=True)
  308. with patch.object(path, "isdir", mock):
  309. self.assertDictEqual(
  310. disk.status(mock_fs, "42%", "41%", absolute=False, free=True), mock_ret
  311. )
  312. def test_mount_used_absolute_acceptable(self):
  313. mock_fs = "/"
  314. mock_ret = {
  315. "name": mock_fs,
  316. "result": True,
  317. "comment": "Disk used space in acceptable range",
  318. "changes": {},
  319. "data": self.mock_data[mock_fs],
  320. }
  321. self.assertDictEqual(
  322. disk.status(mock_fs, "2172881", "2172880", absolute=True, free=False),
  323. mock_ret,
  324. )
  325. def test_mount_used_relative_acceptable(self):
  326. mock_fs = "/"
  327. mock_ret = {
  328. "name": mock_fs,
  329. "result": True,
  330. "comment": "Disk used space in acceptable range",
  331. "changes": {},
  332. "data": self.mock_data[mock_fs],
  333. }
  334. self.assertDictEqual(
  335. disk.status(mock_fs, "7%", "6%", absolute=False, free=False), mock_ret
  336. )
  337. def test_mount_free_absolute_acceptable(self):
  338. mock_fs = "/"
  339. mock_ret = {
  340. "name": mock_fs,
  341. "result": True,
  342. "comment": "Disk used space in acceptable range",
  343. "changes": {},
  344. "data": self.mock_data[mock_fs],
  345. }
  346. self.assertDictEqual(
  347. disk.status(mock_fs, "37087976", "37087975", absolute=True, free=True),
  348. mock_ret,
  349. )
  350. def test_mount_free_relative_acceptable(self):
  351. mock_fs = "/"
  352. mock_ret = {
  353. "name": mock_fs,
  354. "result": True,
  355. "comment": "Disk used space in acceptable range",
  356. "changes": {},
  357. "data": self.mock_data[mock_fs],
  358. }
  359. self.assertDictEqual(
  360. disk.status(mock_fs, "100%", "94%", absolute=False, free=True), mock_ret
  361. )
  362. # below minimum
  363. def test_path_used_absolute_below(self):
  364. mock_fs = "/foo"
  365. mock_ret = {
  366. "name": mock_fs,
  367. "result": False,
  368. "comment": "Disk used space is below minimum of 59 KB at 58 KB",
  369. "changes": {},
  370. "data": self.mock_data_path,
  371. }
  372. mock = MagicMock(return_value=True)
  373. with patch.object(path, "isdir", mock):
  374. self.assertDictEqual(
  375. disk.status(mock_fs, "60", "59", absolute=True, free=False), mock_ret
  376. )
  377. def test_path_used_relative_below(self):
  378. mock_fs = "/foo"
  379. mock_ret = {
  380. "name": mock_fs,
  381. "result": False,
  382. "comment": "Disk used space is below minimum of 59 % at 58.0 %",
  383. "changes": {},
  384. "data": self.mock_data_path,
  385. }
  386. mock = MagicMock(return_value=True)
  387. with patch.object(path, "isdir", mock):
  388. self.assertDictEqual(
  389. disk.status(mock_fs, "60%", "59%", absolute=False, free=False), mock_ret
  390. )
  391. def test_path_free_absolute_below(self):
  392. mock_fs = "/foo"
  393. mock_ret = {
  394. "name": mock_fs,
  395. "result": False,
  396. "comment": "Disk available space is below minimum of 43 KB at 42 KB",
  397. "changes": {},
  398. "data": self.mock_data_path,
  399. }
  400. mock = MagicMock(return_value=True)
  401. with patch.object(path, "isdir", mock):
  402. self.assertDictEqual(
  403. disk.status(mock_fs, "100", "43", absolute=True, free=True), mock_ret
  404. )
  405. def test_path_free_relative_below(self):
  406. mock_fs = "/foo"
  407. mock_ret = {
  408. "name": mock_fs,
  409. "result": False,
  410. "comment": "Disk available space is below minimum of 43 % at 42.0 %",
  411. "changes": {},
  412. "data": self.mock_data_path,
  413. }
  414. mock = MagicMock(return_value=True)
  415. with patch.object(path, "isdir", mock):
  416. self.assertDictEqual(
  417. disk.status(mock_fs, "100%", "43%", absolute=False, free=True), mock_ret
  418. )
  419. def test_mount_used_absolute_below(self):
  420. mock_fs = "/"
  421. mock_ret = {
  422. "name": mock_fs,
  423. "result": False,
  424. "comment": "Disk used space is below minimum of 2172881 KB at 2172880 KB",
  425. "changes": {},
  426. "data": self.mock_data[mock_fs],
  427. }
  428. self.assertDictEqual(
  429. disk.status(mock_fs, "2172882", "2172881", absolute=True, free=False),
  430. mock_ret,
  431. )
  432. def test_mount_used_relative_below(self):
  433. mock_fs = "/"
  434. mock_ret = {
  435. "name": mock_fs,
  436. "result": False,
  437. "comment": "Disk used space is below minimum of 7 % at 6 %",
  438. "changes": {},
  439. "data": self.mock_data[mock_fs],
  440. }
  441. self.assertDictEqual(
  442. disk.status(mock_fs, "8%", "7%", absolute=False, free=False), mock_ret
  443. )
  444. def test_mount_free_absolute_below(self):
  445. mock_fs = "/"
  446. mock_ret = {
  447. "name": mock_fs,
  448. "result": False,
  449. "comment": "Disk available space is below minimum of 37087977 KB at 37087976 KB",
  450. "changes": {},
  451. "data": self.mock_data[mock_fs],
  452. }
  453. self.assertDictEqual(
  454. disk.status(mock_fs, "37087978", "37087977", absolute=True, free=True),
  455. mock_ret,
  456. )
  457. def test_mount_free_relative_below(self):
  458. mock_fs = "/"
  459. mock_ret = {
  460. "name": mock_fs,
  461. "result": False,
  462. "comment": "Disk available space is below minimum of 95 % at 94 %",
  463. "changes": {},
  464. "data": self.mock_data[mock_fs],
  465. }
  466. self.assertDictEqual(
  467. disk.status(mock_fs, "100%", "95%", absolute=False, free=True), mock_ret
  468. )
  469. # above maximum
  470. def test_path_used_absolute_above(self):
  471. mock_fs = "/foo"
  472. mock_ret = {
  473. "name": mock_fs,
  474. "result": False,
  475. "comment": "Disk used space is above maximum of 57 KB at 58 KB",
  476. "changes": {},
  477. "data": self.mock_data_path,
  478. }
  479. mock = MagicMock(return_value=True)
  480. with patch.object(path, "isdir", mock):
  481. self.assertDictEqual(
  482. disk.status(mock_fs, "57", "56", absolute=True, free=False), mock_ret
  483. )
  484. def test_path_used_relative_above(self):
  485. mock_fs = "/foo"
  486. mock_ret = {
  487. "name": mock_fs,
  488. "result": False,
  489. "comment": "Disk used space is above maximum of 57 % at 58.0 %",
  490. "changes": {},
  491. "data": self.mock_data_path,
  492. }
  493. mock = MagicMock(return_value=True)
  494. with patch.object(path, "isdir", mock):
  495. self.assertDictEqual(
  496. disk.status(mock_fs, "57%", "56%", absolute=False, free=False), mock_ret
  497. )
  498. def test_path_free_absolute_above(self):
  499. mock_fs = "/foo"
  500. mock_ret = {
  501. "name": mock_fs,
  502. "result": False,
  503. "comment": "Disk available space is above maximum of 41 KB at 42 KB",
  504. "changes": {},
  505. "data": self.mock_data_path,
  506. }
  507. mock = MagicMock(return_value=True)
  508. with patch.object(path, "isdir", mock):
  509. self.assertDictEqual(
  510. disk.status(mock_fs, "41", "40", absolute=True, free=True), mock_ret
  511. )
  512. def test_path_free_relative_above(self):
  513. mock_fs = "/foo"
  514. mock_ret = {
  515. "name": mock_fs,
  516. "result": False,
  517. "comment": "Disk available space is above maximum of 41 % at 42.0 %",
  518. "changes": {},
  519. "data": self.mock_data_path,
  520. }
  521. mock = MagicMock(return_value=True)
  522. with patch.object(path, "isdir", mock):
  523. self.assertDictEqual(
  524. disk.status(mock_fs, "41%", "40%", absolute=False, free=True), mock_ret
  525. )
  526. def test_mount_used_absolute_above(self):
  527. mock_fs = "/"
  528. mock_ret = {
  529. "name": mock_fs,
  530. "result": False,
  531. "comment": "Disk used space is above maximum of 2172879 KB at 2172880 KB",
  532. "changes": {},
  533. "data": self.mock_data[mock_fs],
  534. }
  535. self.assertDictEqual(
  536. disk.status(mock_fs, "2172879", "2172878", absolute=True, free=False),
  537. mock_ret,
  538. )
  539. def test_mount_used_relative_above(self):
  540. mock_fs = "/"
  541. mock_ret = {
  542. "name": mock_fs,
  543. "result": False,
  544. "comment": "Disk used space is above maximum of 5 % at 6 %",
  545. "changes": {},
  546. "data": self.mock_data[mock_fs],
  547. }
  548. self.assertDictEqual(
  549. disk.status(mock_fs, "5%", "4%", absolute=False, free=False), mock_ret
  550. )
  551. def test_mount_free_absolute_above(self):
  552. mock_fs = "/"
  553. mock_ret = {
  554. "name": mock_fs,
  555. "result": False,
  556. "comment": "Disk available space is above maximum of 37087975 KB at 37087976 KB",
  557. "changes": {},
  558. "data": self.mock_data[mock_fs],
  559. }
  560. self.assertDictEqual(
  561. disk.status(mock_fs, "37087975", "37087974", absolute=True, free=True),
  562. mock_ret,
  563. )
  564. def test_mount_free_relative_above(self):
  565. mock_fs = "/"
  566. mock_ret = {
  567. "name": mock_fs,
  568. "result": False,
  569. "comment": "Disk available space is above maximum of 93 % at 94 %",
  570. "changes": {},
  571. "data": self.mock_data[mock_fs],
  572. }
  573. self.assertDictEqual(
  574. disk.status(mock_fs, "93%", "92%", absolute=False, free=True), mock_ret
  575. )