test_zfs.py 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093
  1. # -*- coding: utf-8 -*-
  2. """
  3. Tests for salt.modules.zfs
  4. :codeauthor: Nitin Madhok <nmadhok@clemson.edu>, Jorge Schrauwen <sjorge@blackdot.be>
  5. :maintainer: Jorge Schrauwen <sjorge@blackdot.be>
  6. :maturity: new
  7. :depends: salt.utils.zfs
  8. :platform: illumos,freebsd,linux
  9. """
  10. from __future__ import absolute_import, print_function, unicode_literals
  11. import salt.loader
  12. import salt.modules.zfs as zfs
  13. import salt.utils.zfs
  14. from salt.utils.dateutils import strftime
  15. from salt.utils.odict import OrderedDict
  16. from tests.support.helpers import slowTest
  17. from tests.support.mixins import LoaderModuleMockMixin
  18. from tests.support.mock import MagicMock, patch
  19. from tests.support.unit import TestCase
  20. from tests.support.zfs import ZFSMockData
  21. # Skip this test case if we don't have access to mock!
  22. class ZfsTestCase(TestCase, LoaderModuleMockMixin):
  23. """
  24. This class contains a set of functions that test salt.modules.zfs module
  25. """
  26. def setup_loader_modules(self):
  27. self.opts = opts = salt.config.DEFAULT_MINION_OPTS.copy()
  28. self.utils_patch = ZFSMockData().get_patched_utils()
  29. for key in ("opts", "utils_patch"):
  30. self.addCleanup(delattr, self, key)
  31. utils = salt.loader.utils(
  32. opts, whitelist=["zfs", "args", "systemd", "path", "platform"]
  33. )
  34. zfs_obj = {zfs: {"__opts__": opts, "__utils__": utils}}
  35. return zfs_obj
  36. def test_exists_success(self):
  37. """
  38. Tests successful return of exists function
  39. """
  40. ret = {}
  41. ret[
  42. "stdout"
  43. ] = "NAME USED AVAIL REFER MOUNTPOINT\nmyzpool/mydataset 30K 157G 30K /myzpool/mydataset"
  44. ret["stderr"] = ""
  45. ret["retcode"] = 0
  46. mock_cmd = MagicMock(return_value=ret)
  47. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  48. zfs.__utils__, self.utils_patch
  49. ):
  50. self.assertTrue(zfs.exists("myzpool/mydataset"))
  51. def test_exists_failure_not_exists(self):
  52. """
  53. Tests unsuccessful return of exists function if dataset does not exist
  54. """
  55. ret = {}
  56. ret["stdout"] = ""
  57. ret["stderr"] = "cannot open 'myzpool/mydataset': dataset does not exist"
  58. ret["retcode"] = 1
  59. mock_cmd = MagicMock(return_value=ret)
  60. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  61. zfs.__utils__, self.utils_patch
  62. ):
  63. self.assertFalse(zfs.exists("myzpool/mydataset"))
  64. def test_exists_failure_invalid_name(self):
  65. """
  66. Tests unsuccessful return of exists function if dataset name is invalid
  67. """
  68. ret = {}
  69. ret["stdout"] = ""
  70. ret["stderr"] = "cannot open 'myzpool/': invalid dataset name"
  71. ret["retcode"] = 1
  72. mock_cmd = MagicMock(return_value=ret)
  73. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  74. zfs.__utils__, self.utils_patch
  75. ):
  76. self.assertFalse(zfs.exists("myzpool/"))
  77. def test_create_success(self):
  78. """
  79. Tests successful return of create function on ZFS file system creation
  80. """
  81. res = OrderedDict([("created", True)])
  82. ret = {}
  83. ret["stdout"] = ""
  84. ret["stderr"] = ""
  85. ret["retcode"] = 0
  86. mock_cmd = MagicMock(return_value=ret)
  87. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  88. zfs.__utils__, self.utils_patch
  89. ):
  90. self.assertEqual(res, zfs.create("myzpool/mydataset"))
  91. def test_create_success_with_create_parent(self):
  92. """
  93. Tests successful return of create function when ``create_parent=True``
  94. """
  95. res = OrderedDict([("created", True)])
  96. ret = {}
  97. ret["stdout"] = ""
  98. ret["stderr"] = ""
  99. ret["retcode"] = 0
  100. mock_cmd = MagicMock(return_value=ret)
  101. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  102. zfs.__utils__, self.utils_patch
  103. ):
  104. self.assertEqual(
  105. res, zfs.create("myzpool/mydataset/mysubdataset", create_parent=True)
  106. )
  107. def test_create_success_with_properties(self):
  108. """
  109. Tests successful return of create function on ZFS file system creation (with properties)
  110. """
  111. res = OrderedDict([("created", True)])
  112. ret = {}
  113. ret["stdout"] = ""
  114. ret["stderr"] = ""
  115. ret["retcode"] = 0
  116. mock_cmd = MagicMock(return_value=ret)
  117. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  118. zfs.__utils__, self.utils_patch
  119. ):
  120. self.assertEqual(
  121. res,
  122. zfs.create(
  123. "myzpool/mydataset",
  124. properties={"mountpoint": "/export/zfs", "sharenfs": "on"},
  125. ),
  126. )
  127. def test_create_error_missing_dataset(self):
  128. """
  129. Tests unsuccessful return of create function if dataset name is missing
  130. """
  131. res = OrderedDict(
  132. [
  133. ("created", False),
  134. ("error", "cannot create 'myzpool': missing dataset name"),
  135. ]
  136. )
  137. ret = {}
  138. ret["stdout"] = ""
  139. ret["stderr"] = "cannot create 'myzpool': missing dataset name"
  140. ret["retcode"] = 1
  141. mock_cmd = MagicMock(return_value=ret)
  142. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  143. zfs.__utils__, self.utils_patch
  144. ):
  145. self.assertEqual(res, zfs.create("myzpool"))
  146. def test_create_error_trailing_slash(self):
  147. """
  148. Tests unsuccessful return of create function if trailing slash in name is present
  149. """
  150. res = OrderedDict(
  151. [
  152. ("created", False),
  153. ("error", "cannot create 'myzpool/': trailing slash in name"),
  154. ]
  155. )
  156. ret = {}
  157. ret["stdout"] = ""
  158. ret["stderr"] = "cannot create 'myzpool/': trailing slash in name"
  159. ret["retcode"] = 1
  160. mock_cmd = MagicMock(return_value=ret)
  161. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  162. zfs.__utils__, self.utils_patch
  163. ):
  164. self.assertEqual(res, zfs.create("myzpool/"))
  165. def test_create_error_no_such_pool(self):
  166. """
  167. Tests unsuccessful return of create function if the pool is not present
  168. """
  169. res = OrderedDict(
  170. [
  171. ("created", False),
  172. ("error", "cannot create 'myzpool/mydataset': no such pool 'myzpool'"),
  173. ]
  174. )
  175. ret = {}
  176. ret["stdout"] = ""
  177. ret["stderr"] = "cannot create 'myzpool/mydataset': no such pool 'myzpool'"
  178. ret["retcode"] = 1
  179. mock_cmd = MagicMock(return_value=ret)
  180. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  181. zfs.__utils__, self.utils_patch
  182. ):
  183. self.assertEqual(res, zfs.create("myzpool/mydataset"))
  184. def test_create_error_missing_parent(self):
  185. """
  186. Tests unsuccessful return of create function if the parent datasets do not exist
  187. """
  188. res = OrderedDict(
  189. [
  190. ("created", False),
  191. (
  192. "error",
  193. "cannot create 'myzpool/mydataset/mysubdataset': parent does not exist",
  194. ),
  195. ]
  196. )
  197. ret = {}
  198. ret["stdout"] = ""
  199. ret[
  200. "stderr"
  201. ] = "cannot create 'myzpool/mydataset/mysubdataset': parent does not exist"
  202. ret["retcode"] = 1
  203. mock_cmd = MagicMock(return_value=ret)
  204. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  205. zfs.__utils__, self.utils_patch
  206. ):
  207. self.assertEqual(res, zfs.create("myzpool/mydataset/mysubdataset"))
  208. def test_destroy_success(self):
  209. """
  210. Tests successful return of destroy function on ZFS file system destruction
  211. """
  212. res = OrderedDict([("destroyed", True)])
  213. ret = {}
  214. ret["stdout"] = ""
  215. ret["stderr"] = ""
  216. ret["retcode"] = 0
  217. mock_cmd = MagicMock(return_value=ret)
  218. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  219. zfs.__utils__, self.utils_patch
  220. ):
  221. self.assertEqual(res, zfs.destroy("myzpool/mydataset"))
  222. def test_destroy_error_not_exists(self):
  223. """
  224. Tests failure return of destroy function on ZFS file system destruction
  225. """
  226. res = OrderedDict(
  227. [
  228. ("destroyed", False),
  229. ("error", "cannot open 'myzpool/mydataset': dataset does not exist"),
  230. ]
  231. )
  232. ret = {}
  233. ret["stdout"] = ""
  234. ret["stderr"] = "cannot open 'myzpool/mydataset': dataset does not exist"
  235. ret["retcode"] = 1
  236. mock_cmd = MagicMock(return_value=ret)
  237. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  238. zfs.__utils__, self.utils_patch
  239. ):
  240. self.assertEqual(res, zfs.destroy("myzpool/mydataset"))
  241. def test_destroy_error_has_children(self):
  242. """
  243. Tests failure return of destroy function on ZFS file system destruction
  244. """
  245. res = OrderedDict(
  246. [
  247. ("destroyed", False),
  248. (
  249. "error",
  250. "\n".join(
  251. [
  252. "cannot destroy 'myzpool/mydataset': filesystem has children",
  253. "use 'recursive=True' to destroy the following datasets:",
  254. "myzpool/mydataset@snapshot",
  255. ]
  256. ),
  257. ),
  258. ]
  259. )
  260. ret = {}
  261. ret["stdout"] = ""
  262. ret["stderr"] = "\n".join(
  263. [
  264. "cannot destroy 'myzpool/mydataset': filesystem has children",
  265. "use '-r' to destroy the following datasets:",
  266. "myzpool/mydataset@snapshot",
  267. ]
  268. )
  269. ret["retcode"] = 1
  270. mock_cmd = MagicMock(return_value=ret)
  271. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  272. zfs.__utils__, self.utils_patch
  273. ):
  274. self.assertEqual(res, zfs.destroy("myzpool/mydataset"))
  275. @slowTest
  276. def test_rename_success(self):
  277. """
  278. Tests successful return of rename function
  279. """
  280. res = OrderedDict([("renamed", True)])
  281. ret = {}
  282. ret["stdout"] = ""
  283. ret["stderr"] = ""
  284. ret["retcode"] = 0
  285. mock_cmd = MagicMock(return_value=ret)
  286. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  287. zfs.__utils__, self.utils_patch
  288. ):
  289. self.assertEqual(res, zfs.rename("myzpool/mydataset", "myzpool/newdataset"))
  290. def test_rename_error_not_exists(self):
  291. """
  292. Tests failure return of rename function
  293. """
  294. res = OrderedDict(
  295. [
  296. ("renamed", False),
  297. ("error", "cannot open 'myzpool/mydataset': dataset does not exist"),
  298. ]
  299. )
  300. ret = {}
  301. ret["stdout"] = ""
  302. ret["stderr"] = "cannot open 'myzpool/mydataset': dataset does not exist"
  303. ret["retcode"] = 1
  304. mock_cmd = MagicMock(return_value=ret)
  305. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  306. zfs.__utils__, self.utils_patch
  307. ):
  308. self.assertEqual(res, zfs.rename("myzpool/mydataset", "myzpool/newdataset"))
  309. def test_list_success(self):
  310. """
  311. Tests zfs list
  312. """
  313. res = OrderedDict(
  314. [
  315. (
  316. "myzpool",
  317. OrderedDict(
  318. [
  319. ("used", 849329782784),
  320. ("avail", 1081258016768),
  321. ("refer", 98304),
  322. ("mountpoint", "/myzpool"),
  323. ]
  324. ),
  325. ),
  326. ]
  327. )
  328. ret = {}
  329. ret["retcode"] = 0
  330. ret["stdout"] = "myzpool\t791G\t1007G\t96K\t/myzpool"
  331. ret["stderr"] = ""
  332. mock_cmd = MagicMock(return_value=ret)
  333. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  334. zfs.__utils__, self.utils_patch
  335. ):
  336. self.assertEqual(res, zfs.list_("myzpool"))
  337. @slowTest
  338. def test_list_parsable_success(self):
  339. """
  340. Tests zfs list with parsable set to False
  341. """
  342. res = OrderedDict(
  343. [
  344. (
  345. "myzpool",
  346. OrderedDict(
  347. [
  348. ("used", "791G"),
  349. ("avail", "1007G"),
  350. ("refer", "96K"),
  351. ("mountpoint", "/myzpool"),
  352. ]
  353. ),
  354. ),
  355. ]
  356. )
  357. ret = {}
  358. ret["retcode"] = 0
  359. ret["stdout"] = "myzpool\t791G\t1007G\t96K\t/myzpool"
  360. ret["stderr"] = ""
  361. mock_cmd = MagicMock(return_value=ret)
  362. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  363. zfs.__utils__, self.utils_patch
  364. ):
  365. self.assertEqual(res, zfs.list_("myzpool", parsable=False))
  366. def test_list_custom_success(self):
  367. """
  368. Tests zfs list
  369. """
  370. res = OrderedDict(
  371. [
  372. (
  373. "myzpool",
  374. OrderedDict(
  375. [
  376. ("canmount", True),
  377. ("used", 849329782784),
  378. ("avail", 1081258016768),
  379. ("compression", False),
  380. ]
  381. ),
  382. ),
  383. ]
  384. )
  385. ret = {}
  386. ret["retcode"] = 0
  387. ret["stdout"] = "myzpool\ton\t791G\t1007G\toff"
  388. ret["stderr"] = ""
  389. mock_cmd = MagicMock(return_value=ret)
  390. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  391. zfs.__utils__, self.utils_patch
  392. ):
  393. self.assertEqual(
  394. res, zfs.list_("myzpool", properties="canmount,used,avail,compression")
  395. )
  396. def test_list_custom_parsable_success(self):
  397. """
  398. Tests zfs list
  399. """
  400. res = OrderedDict(
  401. [
  402. (
  403. "myzpool",
  404. OrderedDict(
  405. [
  406. ("canmount", "on"),
  407. ("used", "791G"),
  408. ("avail", "1007G"),
  409. ("compression", "off"),
  410. ]
  411. ),
  412. ),
  413. ]
  414. )
  415. ret = {}
  416. ret["retcode"] = 0
  417. ret["stdout"] = "myzpool\ton\t791G\t1007G\toff"
  418. ret["stderr"] = ""
  419. mock_cmd = MagicMock(return_value=ret)
  420. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  421. zfs.__utils__, self.utils_patch
  422. ):
  423. self.assertEqual(
  424. res,
  425. zfs.list_(
  426. "myzpool",
  427. properties="canmount,used,avail,compression",
  428. parsable=False,
  429. ),
  430. )
  431. def test_list_error_no_dataset(self):
  432. """
  433. Tests zfs list
  434. """
  435. res = OrderedDict()
  436. ret = {}
  437. ret["retcode"] = 1
  438. ret["stdout"] = "cannot open 'myzpool': dataset does not exist"
  439. ret["stderr"] = ""
  440. mock_cmd = MagicMock(return_value=ret)
  441. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  442. zfs.__utils__, self.utils_patch
  443. ):
  444. self.assertEqual(res, zfs.list_("myzpool"))
  445. @slowTest
  446. def test_list_mount_success(self):
  447. """
  448. Tests zfs list_mount
  449. """
  450. res = OrderedDict(
  451. [("myzpool/data", "/data"), ("myzpool/data/ares", "/data/ares")]
  452. )
  453. ret = {}
  454. ret["retcode"] = 0
  455. ret["stdout"] = "\n".join(
  456. ["myzpool/data\t\t\t\t/data", "myzpool/data/ares\t\t\t/data/ares"]
  457. )
  458. ret["stderr"] = ""
  459. mock_cmd = MagicMock(return_value=ret)
  460. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  461. zfs.__utils__, self.utils_patch
  462. ):
  463. self.assertEqual(res, zfs.list_mount())
  464. def test_mount_success(self):
  465. """
  466. Tests zfs mount of filesystem
  467. """
  468. res = OrderedDict([("mounted", True)])
  469. ret = {}
  470. ret["stdout"] = ""
  471. ret["stderr"] = ""
  472. ret["retcode"] = 0
  473. mock_cmd = MagicMock(return_value=ret)
  474. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  475. zfs.__utils__, self.utils_patch
  476. ):
  477. self.assertEqual(res, zfs.mount("myzpool/mydataset"))
  478. def test_mount_failure(self):
  479. """
  480. Tests zfs mount of already mounted filesystem
  481. """
  482. res = OrderedDict(
  483. [
  484. ("mounted", False),
  485. (
  486. "error",
  487. "cannot mount 'myzpool/mydataset': filesystem already mounted",
  488. ),
  489. ]
  490. )
  491. ret = {}
  492. ret["stdout"] = ""
  493. ret["stderr"] = "cannot mount 'myzpool/mydataset': filesystem already mounted"
  494. ret["retcode"] = 1
  495. mock_cmd = MagicMock(return_value=ret)
  496. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  497. zfs.__utils__, self.utils_patch
  498. ):
  499. self.assertEqual(res, zfs.mount("myzpool/mydataset"))
  500. def test_unmount_success(self):
  501. """
  502. Tests zfs unmount of filesystem
  503. """
  504. res = OrderedDict([("unmounted", True)])
  505. ret = {}
  506. ret["stdout"] = ""
  507. ret["stderr"] = ""
  508. ret["retcode"] = 0
  509. mock_cmd = MagicMock(return_value=ret)
  510. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  511. zfs.__utils__, self.utils_patch
  512. ):
  513. self.assertEqual(res, zfs.unmount("myzpool/mydataset"))
  514. def test_unmount_failure(self):
  515. """
  516. Tests zfs unmount of already mounted filesystem
  517. """
  518. res = OrderedDict(
  519. [
  520. ("unmounted", False),
  521. ("error", "cannot mount 'myzpool/mydataset': not currently mounted"),
  522. ]
  523. )
  524. ret = {}
  525. ret["stdout"] = ""
  526. ret["stderr"] = "cannot mount 'myzpool/mydataset': not currently mounted"
  527. ret["retcode"] = 1
  528. mock_cmd = MagicMock(return_value=ret)
  529. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  530. zfs.__utils__, self.utils_patch
  531. ):
  532. self.assertEqual(res, zfs.unmount("myzpool/mydataset"))
  533. def test_inherit_success(self):
  534. """
  535. Tests zfs inherit of compression property
  536. """
  537. res = OrderedDict([("inherited", True)])
  538. ret = {"pid": 45193, "retcode": 0, "stderr": "", "stdout": ""}
  539. mock_cmd = MagicMock(return_value=ret)
  540. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  541. zfs.__utils__, self.utils_patch
  542. ):
  543. self.assertEqual(res, zfs.inherit("compression", "myzpool/mydataset"))
  544. def test_inherit_failure(self):
  545. """
  546. Tests zfs inherit of canmount
  547. """
  548. res = OrderedDict(
  549. [
  550. ("inherited", False),
  551. ("error", "'canmount' property cannot be inherited"),
  552. ]
  553. )
  554. ret = {
  555. "pid": 43898,
  556. "retcode": 1,
  557. "stderr": "'canmount' property cannot be inherited",
  558. "stdout": "",
  559. }
  560. mock_cmd = MagicMock(return_value=ret)
  561. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  562. zfs.__utils__, self.utils_patch
  563. ):
  564. self.assertEqual(res, zfs.inherit("canmount", "myzpool/mydataset"))
  565. @slowTest
  566. def test_diff(self):
  567. """
  568. Tests zfs diff
  569. """
  570. res = [
  571. "1517063879.144517494\tM\t\t/data/test/",
  572. "1517063875.296592355\t+\t\t/data/test/world",
  573. "1517063879.274438467\t+\t\t/data/test/hello",
  574. ]
  575. ret = {}
  576. ret["retcode"] = 0
  577. ret["stdout"] = "\n".join(
  578. [
  579. "1517063879.144517494\tM\t\t/data/test/",
  580. "1517063875.296592355\t+\t\t/data/test/world",
  581. "1517063879.274438467\t+\t\t/data/test/hello",
  582. ]
  583. )
  584. ret["stderr"] = ""
  585. mock_cmd = MagicMock(return_value=ret)
  586. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  587. zfs.__utils__, self.utils_patch
  588. ):
  589. self.assertEqual(
  590. res, zfs.diff("myzpool/mydataset@yesterday", "myzpool/mydataset")
  591. )
  592. def test_diff_parsed_time(self):
  593. """
  594. Tests zfs diff
  595. """
  596. ## NOTE: do not hardcode parsed timestamps, timezone play a role here.
  597. ## zfs diff output seems to be timezone aware
  598. res = OrderedDict(
  599. [
  600. (
  601. strftime(1517063879.144517494, "%Y-%m-%d.%H:%M:%S.%f"),
  602. "M\t\t/data/test/",
  603. ),
  604. (
  605. strftime(1517063875.296592355, "%Y-%m-%d.%H:%M:%S.%f"),
  606. "+\t\t/data/test/world",
  607. ),
  608. (
  609. strftime(1517063879.274438467, "%Y-%m-%d.%H:%M:%S.%f"),
  610. "+\t\t/data/test/hello",
  611. ),
  612. ]
  613. )
  614. ret = {}
  615. ret["retcode"] = 0
  616. ret["stdout"] = "\n".join(
  617. [
  618. "1517063879.144517494\tM\t\t/data/test/",
  619. "1517063875.296592355\t+\t\t/data/test/world",
  620. "1517063879.274438467\t+\t\t/data/test/hello",
  621. ]
  622. )
  623. ret["stderr"] = ""
  624. mock_cmd = MagicMock(return_value=ret)
  625. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  626. zfs.__utils__, self.utils_patch
  627. ):
  628. self.assertEqual(
  629. res, zfs.diff("myzpool/data@yesterday", "myzpool/data", parsable=False)
  630. )
  631. @slowTest
  632. def test_rollback_success(self):
  633. """
  634. Tests zfs rollback success
  635. """
  636. res = OrderedDict([("rolledback", True)])
  637. ret = {"pid": 56502, "retcode": 0, "stderr": "", "stdout": ""}
  638. mock_cmd = MagicMock(return_value=ret)
  639. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  640. zfs.__utils__, self.utils_patch
  641. ):
  642. self.assertEqual(res, zfs.rollback("myzpool/mydataset@yesterday"))
  643. @slowTest
  644. def test_rollback_failure(self):
  645. """
  646. Tests zfs rollback failure
  647. """
  648. res = OrderedDict(
  649. [
  650. ("rolledback", False),
  651. (
  652. "error",
  653. "\n".join(
  654. [
  655. "cannot rollback to 'myzpool/mydataset@yesterday': more recent snapshots or bookmarks exist",
  656. "use 'recursive=True' to force deletion of the following snapshots and bookmarks:",
  657. "myzpool/mydataset@today",
  658. ]
  659. ),
  660. ),
  661. ]
  662. )
  663. ret = {
  664. "pid": 57471,
  665. "retcode": 1,
  666. "stderr": "cannot rollback to 'myzpool/mydataset@yesterday': more recent snapshots or bookmarks "
  667. "exist\nuse '-r' to force deletion of the following snapshots and "
  668. "bookmarks:\nmyzpool/mydataset@today",
  669. "stdout": "",
  670. }
  671. mock_cmd = MagicMock(return_value=ret)
  672. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  673. zfs.__utils__, self.utils_patch
  674. ):
  675. self.assertEqual(res, zfs.rollback("myzpool/mydataset@yesterday"))
  676. def test_clone_success(self):
  677. """
  678. Tests zfs clone success
  679. """
  680. res = OrderedDict([("cloned", True)])
  681. ret = {"pid": 64532, "retcode": 0, "stderr": "", "stdout": ""}
  682. mock_cmd = MagicMock(return_value=ret)
  683. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  684. zfs.__utils__, self.utils_patch
  685. ):
  686. self.assertEqual(
  687. res, zfs.clone("myzpool/mydataset@yesterday", "myzpool/yesterday")
  688. )
  689. def test_clone_failure(self):
  690. """
  691. Tests zfs clone failure
  692. """
  693. res = OrderedDict(
  694. [
  695. ("cloned", False),
  696. (
  697. "error",
  698. "cannot create 'myzpool/archive/yesterday': parent does not exist",
  699. ),
  700. ]
  701. )
  702. ret = {
  703. "pid": 64864,
  704. "retcode": 1,
  705. "stderr": "cannot create 'myzpool/archive/yesterday': parent does not exist",
  706. "stdout": "",
  707. }
  708. mock_cmd = MagicMock(return_value=ret)
  709. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  710. zfs.__utils__, self.utils_patch
  711. ):
  712. self.assertEqual(
  713. res,
  714. zfs.clone("myzpool/mydataset@yesterday", "myzpool/archive/yesterday"),
  715. )
  716. @slowTest
  717. def test_promote_success(self):
  718. """
  719. Tests zfs promote success
  720. """
  721. res = OrderedDict([("promoted", True)])
  722. ret = {"pid": 69075, "retcode": 0, "stderr": "", "stdout": ""}
  723. mock_cmd = MagicMock(return_value=ret)
  724. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  725. zfs.__utils__, self.utils_patch
  726. ):
  727. self.assertEqual(res, zfs.promote("myzpool/yesterday"))
  728. def test_promote_failure(self):
  729. """
  730. Tests zfs promote failure
  731. """
  732. res = OrderedDict(
  733. [
  734. ("promoted", False),
  735. (
  736. "error",
  737. "cannot promote 'myzpool/yesterday': not a cloned filesystem",
  738. ),
  739. ]
  740. )
  741. ret = {
  742. "pid": 69209,
  743. "retcode": 1,
  744. "stderr": "cannot promote 'myzpool/yesterday': not a cloned filesystem",
  745. "stdout": "",
  746. }
  747. mock_cmd = MagicMock(return_value=ret)
  748. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  749. zfs.__utils__, self.utils_patch
  750. ):
  751. self.assertEqual(res, zfs.promote("myzpool/yesterday"))
  752. @slowTest
  753. def test_bookmark_success(self):
  754. """
  755. Tests zfs bookmark success
  756. """
  757. with patch("salt.utils.path.which", MagicMock(return_value="/usr/bin/man")):
  758. res = OrderedDict([("bookmarked", True)])
  759. ret = {"pid": 20990, "retcode": 0, "stderr": "", "stdout": ""}
  760. mock_cmd = MagicMock(return_value=ret)
  761. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  762. zfs.__utils__, self.utils_patch
  763. ):
  764. self.assertEqual(
  765. res,
  766. zfs.bookmark(
  767. "myzpool/mydataset@yesterday", "myzpool/mydataset#important"
  768. ),
  769. )
  770. @slowTest
  771. def test_holds_success(self):
  772. """
  773. Tests zfs holds success
  774. """
  775. res = OrderedDict(
  776. [
  777. ("important", "Wed Dec 23 21:06 2015"),
  778. ("release-1.0", "Wed Dec 23 21:08 2015"),
  779. ]
  780. )
  781. ret = {
  782. "pid": 40216,
  783. "retcode": 0,
  784. "stderr": "",
  785. "stdout": "myzpool/mydataset@baseline\timportant \tWed Dec 23 21:06 2015\nmyzpool/mydataset@baseline\trelease-1.0\tWed Dec 23 21:08 2015",
  786. }
  787. mock_cmd = MagicMock(return_value=ret)
  788. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  789. zfs.__utils__, self.utils_patch
  790. ):
  791. self.assertEqual(res, zfs.holds("myzpool/mydataset@baseline"))
  792. def test_holds_failure(self):
  793. """
  794. Tests zfs holds failure
  795. """
  796. res = OrderedDict(
  797. [
  798. (
  799. "error",
  800. "cannot open 'myzpool/mydataset@baseline': dataset does not exist",
  801. ),
  802. ]
  803. )
  804. ret = {
  805. "pid": 40993,
  806. "retcode": 1,
  807. "stderr": "cannot open 'myzpool/mydataset@baseline': dataset does not exist",
  808. "stdout": "no datasets available",
  809. }
  810. mock_cmd = MagicMock(return_value=ret)
  811. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  812. zfs.__utils__, self.utils_patch
  813. ):
  814. self.assertEqual(res, zfs.holds("myzpool/mydataset@baseline"))
  815. def test_hold_success(self):
  816. """
  817. Tests zfs hold success
  818. """
  819. res = OrderedDict([("held", True)])
  820. ret = {"pid": 50876, "retcode": 0, "stderr": "", "stdout": ""}
  821. mock_cmd = MagicMock(return_value=ret)
  822. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  823. zfs.__utils__, self.utils_patch
  824. ):
  825. self.assertEqual(
  826. res,
  827. zfs.hold(
  828. "important",
  829. "myzpool/mydataset@baseline",
  830. "myzpool/mydataset@release-1.0",
  831. ),
  832. )
  833. def test_hold_failure(self):
  834. """
  835. Tests zfs hold failure
  836. """
  837. res = OrderedDict(
  838. [
  839. ("held", False),
  840. (
  841. "error",
  842. "cannot hold snapshot 'myzpool/mydataset@baseline': tag already exists on this dataset",
  843. ),
  844. ]
  845. )
  846. ret = {
  847. "pid": 51006,
  848. "retcode": 1,
  849. "stderr": "cannot hold snapshot 'myzpool/mydataset@baseline': tag already exists on this dataset",
  850. "stdout": "",
  851. }
  852. mock_cmd = MagicMock(return_value=ret)
  853. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  854. zfs.__utils__, self.utils_patch
  855. ):
  856. self.assertEqual(res, zfs.hold("important", "myzpool/mydataset@baseline"))
  857. def test_release_success(self):
  858. """
  859. Tests zfs release success
  860. """
  861. res = OrderedDict([("released", True)])
  862. ret = {"pid": 50876, "retcode": 0, "stderr": "", "stdout": ""}
  863. mock_cmd = MagicMock(return_value=ret)
  864. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  865. zfs.__utils__, self.utils_patch
  866. ):
  867. self.assertEqual(
  868. res,
  869. zfs.release(
  870. "important",
  871. "myzpool/mydataset@baseline",
  872. "myzpool/mydataset@release-1.0",
  873. ),
  874. )
  875. @slowTest
  876. def test_release_failure(self):
  877. """
  878. Tests zfs release failure
  879. """
  880. res = OrderedDict(
  881. [
  882. ("released", False),
  883. (
  884. "error",
  885. "cannot release hold from snapshot 'myzpool/mydataset@baseline': no such tag on this dataset",
  886. ),
  887. ]
  888. )
  889. ret = {
  890. "pid": 51006,
  891. "retcode": 1,
  892. "stderr": "cannot release hold from snapshot 'myzpool/mydataset@baseline': no such tag on this dataset",
  893. "stdout": "",
  894. }
  895. mock_cmd = MagicMock(return_value=ret)
  896. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  897. zfs.__utils__, self.utils_patch
  898. ):
  899. self.assertEqual(
  900. res, zfs.release("important", "myzpool/mydataset@baseline")
  901. )
  902. def test_snapshot_success(self):
  903. """
  904. Tests zfs snapshot success
  905. """
  906. res = OrderedDict([("snapshotted", True)])
  907. ret = {"pid": 69125, "retcode": 0, "stderr": "", "stdout": ""}
  908. mock_cmd = MagicMock(return_value=ret)
  909. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  910. zfs.__utils__, self.utils_patch
  911. ):
  912. self.assertEqual(res, zfs.snapshot("myzpool/mydataset@baseline"))
  913. def test_snapshot_failure(self):
  914. """
  915. Tests zfs snapshot failure
  916. """
  917. res = OrderedDict(
  918. [
  919. ("snapshotted", False),
  920. (
  921. "error",
  922. "cannot create snapshot 'myzpool/mydataset@baseline': dataset already exists",
  923. ),
  924. ]
  925. )
  926. ret = {
  927. "pid": 68526,
  928. "retcode": 1,
  929. "stderr": "cannot create snapshot 'myzpool/mydataset@baseline': dataset already exists",
  930. "stdout": "",
  931. }
  932. mock_cmd = MagicMock(return_value=ret)
  933. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  934. zfs.__utils__, self.utils_patch
  935. ):
  936. self.assertEqual(res, zfs.snapshot("myzpool/mydataset@baseline"))
  937. def test_snapshot_failure2(self):
  938. """
  939. Tests zfs snapshot failure
  940. """
  941. res = OrderedDict(
  942. [
  943. ("snapshotted", False),
  944. ("error", "cannot open 'myzpool/mydataset': dataset does not exist"),
  945. ]
  946. )
  947. ret = {
  948. "pid": 69256,
  949. "retcode": 2,
  950. "stderr": "cannot open 'myzpool/mydataset': dataset does not exist\nusage:\n\tsnapshot [-r] [-o property=value] ... <filesystem|volume>@<snap> ...\n\nFor the property list, run: zfs set|get\n\nFor the delegated permission list, run: zfs allow|unallow",
  951. "stdout": "",
  952. }
  953. mock_cmd = MagicMock(return_value=ret)
  954. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  955. zfs.__utils__, self.utils_patch
  956. ):
  957. self.assertEqual(res, zfs.snapshot("myzpool/mydataset@baseline"))
  958. def test_set_success(self):
  959. """
  960. Tests zfs set success
  961. """
  962. res = OrderedDict([("set", True)])
  963. ret = {"pid": 79736, "retcode": 0, "stderr": "", "stdout": ""}
  964. mock_cmd = MagicMock(return_value=ret)
  965. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  966. zfs.__utils__, self.utils_patch
  967. ):
  968. self.assertEqual(res, zfs.set("myzpool/mydataset", compression="lz4"))
  969. @slowTest
  970. def test_set_failure(self):
  971. """
  972. Tests zfs set failure
  973. """
  974. res = OrderedDict(
  975. [
  976. ("set", False),
  977. (
  978. "error",
  979. "cannot set property for 'myzpool/mydataset': 'canmount' must be one of 'on | off | noauto'",
  980. ),
  981. ]
  982. )
  983. ret = {
  984. "pid": 79887,
  985. "retcode": 1,
  986. "stderr": "cannot set property for 'myzpool/mydataset': 'canmount' must be one of 'on | off | noauto'",
  987. "stdout": "",
  988. }
  989. mock_cmd = MagicMock(return_value=ret)
  990. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  991. zfs.__utils__, self.utils_patch
  992. ):
  993. self.assertEqual(res, zfs.set("myzpool/mydataset", canmount="lz4"))
  994. def test_get_success(self):
  995. """
  996. Tests zfs get success
  997. """
  998. res = OrderedDict(
  999. [
  1000. (
  1001. "myzpool",
  1002. OrderedDict([("used", OrderedDict([("value", 906238099456)]))]),
  1003. ),
  1004. ]
  1005. )
  1006. ret = {
  1007. "pid": 562,
  1008. "retcode": 0,
  1009. "stderr": "",
  1010. "stdout": "myzpool\tused\t906238099456",
  1011. }
  1012. mock_cmd = MagicMock(return_value=ret)
  1013. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  1014. zfs.__utils__, self.utils_patch
  1015. ):
  1016. self.assertEqual(res, zfs.get("myzpool", properties="used", fields="value"))
  1017. def test_get_parsable_success(self):
  1018. """
  1019. Tests zfs get with parsable output
  1020. """
  1021. res = OrderedDict(
  1022. [("myzpool", OrderedDict([("used", OrderedDict([("value", "844G")]))]))]
  1023. )
  1024. ret = {
  1025. "pid": 562,
  1026. "retcode": 0,
  1027. "stderr": "",
  1028. "stdout": "myzpool\tused\t906238099456",
  1029. }
  1030. mock_cmd = MagicMock(return_value=ret)
  1031. with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict(
  1032. zfs.__utils__, self.utils_patch
  1033. ):
  1034. self.assertEqual(
  1035. res,
  1036. zfs.get("myzpool", properties="used", fields="value", parsable=False),
  1037. )