test_disk.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  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. # Import Salt Testing Libs
  8. from tests.support.mixins import LoaderModuleMockMixin
  9. from tests.support.unit import TestCase
  10. from tests.support.mock import (
  11. MagicMock,
  12. patch)
  13. from os import path
  14. # Import Salt Libs
  15. import salt.states.disk as disk
  16. class DiskTestCase(TestCase, LoaderModuleMockMixin):
  17. '''
  18. Test disk state
  19. '''
  20. def setup_loader_modules(self):
  21. self.mock_data = {
  22. '/': {
  23. '1K-blocks': '41147472',
  24. 'available': '37087976',
  25. 'capacity': '6%',
  26. 'filesystem': '/dev/xvda1',
  27. 'used': '2172880'},
  28. '/dev': {
  29. '1K-blocks': '10240',
  30. 'available': '10240',
  31. 'capacity': '0%',
  32. 'filesystem': 'udev',
  33. 'used': '0'},
  34. '/run': {
  35. '1K-blocks': '410624',
  36. 'available': '379460',
  37. 'capacity': '8%',
  38. 'filesystem': 'tmpfs',
  39. 'used': '31164'},
  40. '/sys/fs/cgroup': {
  41. '1K-blocks': '1026556',
  42. 'available': '1026556',
  43. 'capacity': '0%',
  44. 'filesystem': 'tmpfs',
  45. 'used': '0'}
  46. }
  47. self.mock_data_path = {'/foo': {'available': '42', 'total': '100'}}
  48. self.addCleanup(delattr, self, 'mock_data')
  49. self.addCleanup(delattr, self, 'mock_data_path')
  50. return {disk: {'__salt__': {'disk.usage': MagicMock(return_value=self.mock_data), 'status.diskusage': MagicMock(return_value=self.mock_data_path)}}}
  51. def test_status_missing(self):
  52. '''
  53. Test disk.status when name not found
  54. '''
  55. mock_fs = '/mnt/cheese'
  56. mock_ret = {'name': mock_fs,
  57. 'result': False,
  58. 'comment': 'Disk mount /mnt/cheese not present. Directory /mnt/cheese does not exist or is not a directory',
  59. 'changes': {},
  60. 'data': {}}
  61. ret = disk.status(mock_fs)
  62. self.assertEqual(ret, mock_ret)
  63. def test_status_type_error(self):
  64. '''
  65. Test disk.status with incorrectly formatted arguments
  66. '''
  67. mock_fs = '/'
  68. mock_ret = {'name': mock_fs,
  69. 'result': False,
  70. 'comment': '',
  71. 'changes': {},
  72. 'data': {}}
  73. mock_ret['comment'] = 'maximum must be an integer '
  74. ret = disk.status(mock_fs, maximum=r'e^{i\pi}')
  75. self.assertEqual(ret, mock_ret)
  76. mock_ret['comment'] = 'minimum must be an integer '
  77. ret = disk.status(mock_fs, minimum=r'\cos\pi + i\sin\pi')
  78. self.assertEqual(ret, mock_ret)
  79. def test_status_range_error(self):
  80. '''
  81. Test disk.status with excessive extrema
  82. '''
  83. mock_fs = '/'
  84. mock_ret = {'name': mock_fs,
  85. 'result': False,
  86. 'comment': '',
  87. 'changes': {},
  88. 'data': {}}
  89. mock_ret['comment'] = 'maximum must be in the range [0, 100] '
  90. ret = disk.status(mock_fs, maximum='-1')
  91. self.assertEqual(ret, mock_ret)
  92. mock_ret['comment'] = 'minimum must be in the range [0, 100] '
  93. ret = disk.status(mock_fs, minimum='101')
  94. self.assertEqual(ret, mock_ret)
  95. def test_status_inverted_range(self):
  96. '''
  97. Test disk.status when minimum > maximum
  98. '''
  99. mock_fs = '/'
  100. mock_ret = {'name': mock_fs,
  101. 'result': False,
  102. 'comment': 'minimum must be less than maximum ',
  103. 'changes': {},
  104. 'data': {}}
  105. ret = disk.status(mock_fs, maximum='0', minimum='1')
  106. self.assertEqual(ret, mock_ret)
  107. def test_status_threshold(self):
  108. '''
  109. Test disk.status when filesystem triggers thresholds
  110. '''
  111. mock_min = 100
  112. mock_max = 0
  113. mock_fs = '/'
  114. mock_used = int(self.mock_data[mock_fs]['capacity'].strip('%'))
  115. mock_ret = {'name': mock_fs,
  116. 'result': False,
  117. 'comment': '',
  118. 'changes': {},
  119. 'data': self.mock_data[mock_fs]}
  120. mock_ret['comment'] = 'Disk used space is below minimum of {0} % at {1} %'.format(
  121. mock_min,
  122. mock_used
  123. )
  124. ret = disk.status(mock_fs, minimum=mock_min)
  125. self.assertEqual(ret, mock_ret)
  126. mock_ret['comment'] = 'Disk used space is above maximum of {0} % at {1} %'.format(
  127. mock_max,
  128. mock_used
  129. )
  130. ret = disk.status(mock_fs, maximum=mock_max)
  131. self.assertEqual(ret, mock_ret)
  132. def test_status_strip(self):
  133. '''
  134. Test disk.status appropriately strips unit info from numbers
  135. '''
  136. mock_fs = '/'
  137. mock_ret = {'name': mock_fs,
  138. 'result': True,
  139. 'comment': 'Disk used space in acceptable range',
  140. 'changes': {},
  141. 'data': self.mock_data[mock_fs]}
  142. ret = disk.status(mock_fs, minimum='0%')
  143. self.assertEqual(ret, mock_ret)
  144. ret = disk.status(mock_fs, minimum='0 %')
  145. self.assertEqual(ret, mock_ret)
  146. ret = disk.status(mock_fs, maximum='100%')
  147. self.assertEqual(ret, mock_ret)
  148. ret = disk.status(mock_fs, minimum='1024K', absolute=True)
  149. self.assertEqual(ret, mock_ret)
  150. ret = disk.status(mock_fs, minimum='1024KB', absolute=True)
  151. self.assertEqual(ret, mock_ret)
  152. ret = disk.status(mock_fs, maximum='4194304 KB', absolute=True)
  153. self.assertEqual(ret, mock_ret)
  154. def test_status(self):
  155. '''
  156. Test disk.status when filesystem meets thresholds
  157. '''
  158. mock_min = 0
  159. mock_max = 100
  160. mock_fs = '/'
  161. mock_ret = {'name': mock_fs,
  162. 'result': True,
  163. 'comment': 'Disk used space in acceptable range',
  164. 'changes': {},
  165. 'data': self.mock_data[mock_fs]}
  166. ret = disk.status(mock_fs, minimum=mock_min)
  167. self.assertEqual(ret, mock_ret)
  168. ret = disk.status(mock_fs, maximum=mock_max)
  169. self.assertEqual(ret, mock_ret)
  170. # Reset mock because it's an iterator to run the tests with the
  171. # absolute flag
  172. ret = {'name': mock_fs,
  173. 'result': False,
  174. 'comment': '',
  175. 'changes': {},
  176. 'data': {}}
  177. data_1 = {'capacity': '8 %', 'used': '8', 'available': '92'}
  178. data_2 = {'capacity': '22 %', 'used': '22', 'available': '78'}
  179. data_3 = {'capacity': '15 %', 'used': '15', 'available': '85'}
  180. mock = MagicMock(side_effect=[[], {mock_fs: data_1}, {mock_fs: data_2}, {mock_fs: data_3}])
  181. with patch.dict(disk.__salt__, {'disk.usage': mock}):
  182. mock = MagicMock(return_value=False)
  183. with patch.object(path, 'isdir', mock):
  184. comt = 'Disk mount / not present. Directory / does not exist or is not a directory'
  185. ret.update({'comment': comt})
  186. self.assertDictEqual(disk.status(mock_fs), ret)
  187. comt = 'minimum must be less than maximum '
  188. ret.update({'comment': comt})
  189. self.assertDictEqual(disk.status(mock_fs, '10', '20', absolute=True), ret)
  190. comt = 'Disk used space is below minimum of 10 KB at 8 KB'
  191. ret.update({'comment': comt, 'data': data_1})
  192. self.assertDictEqual(disk.status(mock_fs, '20', '10', absolute=True), ret)
  193. comt = 'Disk used space is above maximum of 20 KB at 22 KB'
  194. ret.update({'comment': comt, 'data': data_2})
  195. self.assertDictEqual(disk.status(mock_fs, '20', '10', absolute=True), ret)
  196. comt = 'Disk used space in acceptable range'
  197. ret.update({'comment': comt, 'result': True, 'data': data_3})
  198. self.assertDictEqual(disk.status(mock_fs, '20', '10', absolute=True), ret)
  199. def test_path_missing(self):
  200. mock_fs = '/bar'
  201. mock_ret = {'name': mock_fs,
  202. 'result': False,
  203. 'comment': 'Disk mount {0} not present. Directory {0} does not exist or is not a directory'.format(
  204. mock_fs),
  205. 'changes': {},
  206. 'data': {}}
  207. mock = MagicMock(return_value=False)
  208. with patch.object(path, 'isdir', mock):
  209. self.assertDictEqual(disk.status(mock_fs, '58', '55', absolute=True, free=False), mock_ret)
  210. # acceptable range
  211. def test_path_used_absolute_acceptable(self):
  212. mock_fs = '/foo'
  213. mock_ret = {'name': mock_fs,
  214. 'result': True,
  215. 'comment': 'Disk used space in acceptable range',
  216. 'changes': {},
  217. 'data': self.mock_data_path}
  218. mock = MagicMock(return_value=True)
  219. with patch.object(path, 'isdir', mock):
  220. self.assertDictEqual(disk.status(mock_fs, '58', '55', absolute=True, free=False), mock_ret)
  221. def test_path_used_relative_acceptable(self):
  222. mock_fs = '/foo'
  223. mock_ret = {'name': mock_fs,
  224. 'result': True,
  225. 'comment': 'Disk used space in acceptable range',
  226. 'changes': {},
  227. 'data': self.mock_data_path}
  228. mock = MagicMock(return_value=True)
  229. with patch.object(path, 'isdir', mock):
  230. self.assertDictEqual(disk.status(mock_fs, '100%', '57%', absolute=False, free=False), mock_ret)
  231. def test_path_free_absolute_acceptable(self):
  232. mock_fs = '/foo'
  233. mock_ret = {'name': mock_fs,
  234. 'result': True,
  235. 'comment': 'Disk used space in acceptable range',
  236. 'changes': {},
  237. 'data': self.mock_data_path}
  238. mock = MagicMock(return_value=True)
  239. with patch.object(path, 'isdir', mock):
  240. self.assertDictEqual(disk.status(mock_fs, '100', '42', absolute=True, free=True), mock_ret)
  241. def test_path_free_relative_acceptable(self):
  242. mock_fs = '/foo'
  243. mock_ret = {'name': mock_fs,
  244. 'result': True,
  245. 'comment': 'Disk used space in acceptable range',
  246. 'changes': {},
  247. 'data': self.mock_data_path}
  248. mock = MagicMock(return_value=True)
  249. with patch.object(path, 'isdir', mock):
  250. self.assertDictEqual(disk.status(mock_fs, '42%', '41%', absolute=False, free=True), mock_ret)
  251. def test_mount_used_absolute_acceptable(self):
  252. mock_fs = '/'
  253. mock_ret = {'name': mock_fs,
  254. 'result': True,
  255. 'comment': 'Disk used space in acceptable range',
  256. 'changes': {},
  257. 'data': self.mock_data[mock_fs]}
  258. self.assertDictEqual(disk.status(mock_fs, '2172881', '2172880', absolute=True, free=False), mock_ret)
  259. def test_mount_used_relative_acceptable(self):
  260. mock_fs = '/'
  261. mock_ret = {'name': mock_fs,
  262. 'result': True,
  263. 'comment': 'Disk used space in acceptable range',
  264. 'changes': {},
  265. 'data': self.mock_data[mock_fs]}
  266. self.assertDictEqual(disk.status(mock_fs, '7%', '6%', absolute=False, free=False), mock_ret)
  267. def test_mount_free_absolute_acceptable(self):
  268. mock_fs = '/'
  269. mock_ret = {'name': mock_fs,
  270. 'result': True,
  271. 'comment': 'Disk used space in acceptable range',
  272. 'changes': {},
  273. 'data': self.mock_data[mock_fs]}
  274. self.assertDictEqual(disk.status(mock_fs, '37087976', '37087975', absolute=True, free=True), mock_ret)
  275. def test_mount_free_relative_acceptable(self):
  276. mock_fs = '/'
  277. mock_ret = {'name': mock_fs,
  278. 'result': True,
  279. 'comment': 'Disk used space in acceptable range',
  280. 'changes': {},
  281. 'data': self.mock_data[mock_fs]}
  282. self.assertDictEqual(disk.status(mock_fs, '100%', '94%', absolute=False, free=True), mock_ret)
  283. # below minimum
  284. def test_path_used_absolute_below(self):
  285. mock_fs = '/foo'
  286. mock_ret = {'name': mock_fs,
  287. 'result': False,
  288. 'comment': 'Disk used space is below minimum of 59 KB at 58 KB',
  289. 'changes': {},
  290. 'data': self.mock_data_path}
  291. mock = MagicMock(return_value=True)
  292. with patch.object(path, 'isdir', mock):
  293. self.assertDictEqual(disk.status(mock_fs, '60', '59', absolute=True, free=False), mock_ret)
  294. def test_path_used_relative_below(self):
  295. mock_fs = '/foo'
  296. mock_ret = {'name': mock_fs,
  297. 'result': False,
  298. 'comment': 'Disk used space is below minimum of 59 % at 58.0 %',
  299. 'changes': {},
  300. 'data': self.mock_data_path}
  301. mock = MagicMock(return_value=True)
  302. with patch.object(path, 'isdir', mock):
  303. self.assertDictEqual(disk.status(mock_fs, '60%', '59%', absolute=False, free=False), mock_ret)
  304. def test_path_free_absolute_below(self):
  305. mock_fs = '/foo'
  306. mock_ret = {'name': mock_fs,
  307. 'result': False,
  308. 'comment': 'Disk available space is below minimum of 43 KB at 42 KB',
  309. 'changes': {},
  310. 'data': self.mock_data_path}
  311. mock = MagicMock(return_value=True)
  312. with patch.object(path, 'isdir', mock):
  313. self.assertDictEqual(disk.status(mock_fs, '100', '43', absolute=True, free=True), mock_ret)
  314. def test_path_free_relative_below(self):
  315. mock_fs = '/foo'
  316. mock_ret = {'name': mock_fs,
  317. 'result': False,
  318. 'comment': 'Disk available space is below minimum of 43 % at 42.0 %',
  319. 'changes': {},
  320. 'data': self.mock_data_path}
  321. mock = MagicMock(return_value=True)
  322. with patch.object(path, 'isdir', mock):
  323. self.assertDictEqual(disk.status(mock_fs, '100%', '43%', absolute=False, free=True), mock_ret)
  324. def test_mount_used_absolute_below(self):
  325. mock_fs = '/'
  326. mock_ret = {'name': mock_fs,
  327. 'result': False,
  328. 'comment': 'Disk used space is below minimum of 2172881 KB at 2172880 KB',
  329. 'changes': {},
  330. 'data': self.mock_data[mock_fs]}
  331. self.assertDictEqual(disk.status(mock_fs, '2172882', '2172881', absolute=True, free=False), mock_ret)
  332. def test_mount_used_relative_below(self):
  333. mock_fs = '/'
  334. mock_ret = {'name': mock_fs,
  335. 'result': False,
  336. 'comment': 'Disk used space is below minimum of 7 % at 6 %',
  337. 'changes': {},
  338. 'data': self.mock_data[mock_fs]}
  339. self.assertDictEqual(disk.status(mock_fs, '8%', '7%', absolute=False, free=False), mock_ret)
  340. def test_mount_free_absolute_below(self):
  341. mock_fs = '/'
  342. mock_ret = {'name': mock_fs,
  343. 'result': False,
  344. 'comment': 'Disk available space is below minimum of 37087977 KB at 37087976 KB',
  345. 'changes': {},
  346. 'data': self.mock_data[mock_fs]}
  347. self.assertDictEqual(disk.status(mock_fs, '37087978', '37087977', absolute=True, free=True), mock_ret)
  348. def test_mount_free_relative_below(self):
  349. mock_fs = '/'
  350. mock_ret = {'name': mock_fs,
  351. 'result': False,
  352. 'comment': 'Disk available space is below minimum of 95 % at 94 %',
  353. 'changes': {},
  354. 'data': self.mock_data[mock_fs]}
  355. self.assertDictEqual(disk.status(mock_fs, '100%', '95%', absolute=False, free=True), mock_ret)
  356. # above maximum
  357. def test_path_used_absolute_above(self):
  358. mock_fs = '/foo'
  359. mock_ret = {'name': mock_fs,
  360. 'result': False,
  361. 'comment': 'Disk used space is above maximum of 57 KB at 58 KB',
  362. 'changes': {},
  363. 'data': self.mock_data_path}
  364. mock = MagicMock(return_value=True)
  365. with patch.object(path, 'isdir', mock):
  366. self.assertDictEqual(disk.status(mock_fs, '57', '56', absolute=True, free=False), mock_ret)
  367. def test_path_used_relative_above(self):
  368. mock_fs = '/foo'
  369. mock_ret = {'name': mock_fs,
  370. 'result': False,
  371. 'comment': 'Disk used space is above maximum of 57 % at 58.0 %',
  372. 'changes': {},
  373. 'data': self.mock_data_path}
  374. mock = MagicMock(return_value=True)
  375. with patch.object(path, 'isdir', mock):
  376. self.assertDictEqual(disk.status(mock_fs, '57%', '56%', absolute=False, free=False), mock_ret)
  377. def test_path_free_absolute_above(self):
  378. mock_fs = '/foo'
  379. mock_ret = {'name': mock_fs,
  380. 'result': False,
  381. 'comment': 'Disk available space is above maximum of 41 KB at 42 KB',
  382. 'changes': {},
  383. 'data': self.mock_data_path}
  384. mock = MagicMock(return_value=True)
  385. with patch.object(path, 'isdir', mock):
  386. self.assertDictEqual(disk.status(mock_fs, '41', '40', absolute=True, free=True), mock_ret)
  387. def test_path_free_relative_above(self):
  388. mock_fs = '/foo'
  389. mock_ret = {'name': mock_fs,
  390. 'result': False,
  391. 'comment': 'Disk available space is above maximum of 41 % at 42.0 %',
  392. 'changes': {},
  393. 'data': self.mock_data_path}
  394. mock = MagicMock(return_value=True)
  395. with patch.object(path, 'isdir', mock):
  396. self.assertDictEqual(disk.status(mock_fs, '41%', '40%', absolute=False, free=True), mock_ret)
  397. def test_mount_used_absolute_above(self):
  398. mock_fs = '/'
  399. mock_ret = {'name': mock_fs,
  400. 'result': False,
  401. 'comment': 'Disk used space is above maximum of 2172879 KB at 2172880 KB',
  402. 'changes': {},
  403. 'data': self.mock_data[mock_fs]}
  404. self.assertDictEqual(disk.status(mock_fs, '2172879', '2172878', absolute=True, free=False), mock_ret)
  405. def test_mount_used_relative_above(self):
  406. mock_fs = '/'
  407. mock_ret = {'name': mock_fs,
  408. 'result': False,
  409. 'comment': 'Disk used space is above maximum of 5 % at 6 %',
  410. 'changes': {},
  411. 'data': self.mock_data[mock_fs]}
  412. self.assertDictEqual(disk.status(mock_fs, '5%', '4%', absolute=False, free=False), mock_ret)
  413. def test_mount_free_absolute_above(self):
  414. mock_fs = '/'
  415. mock_ret = {'name': mock_fs,
  416. 'result': False,
  417. 'comment': 'Disk available space is above maximum of 37087975 KB at 37087976 KB',
  418. 'changes': {},
  419. 'data': self.mock_data[mock_fs]}
  420. self.assertDictEqual(disk.status(mock_fs, '37087975', '37087974', absolute=True, free=True), mock_ret)
  421. def test_mount_free_relative_above(self):
  422. mock_fs = '/'
  423. mock_ret = {'name': mock_fs,
  424. 'result': False,
  425. 'comment': 'Disk available space is above maximum of 93 % at 94 %',
  426. 'changes': {},
  427. 'data': self.mock_data[mock_fs]}
  428. self.assertDictEqual(disk.status(mock_fs, '93%', '92%', absolute=False, free=True), mock_ret)