mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 17:09:03 +00:00
451 lines
15 KiB
Python
451 lines
15 KiB
Python
# -*- coding: utf-8 -*-
|
|
'''
|
|
Tests for salt.states.zpool
|
|
|
|
:codeauthor: Jorge Schrauwen <sjorge@blackdot.be>
|
|
:maintainer: Jorge Schrauwen <sjorge@blackdot.be>
|
|
:maturity: new
|
|
:depends: salt.utils.zfs, salt.modules.zpool
|
|
:platform: illumos,freebsd,linux
|
|
'''
|
|
# Import Python libs
|
|
from __future__ import absolute_import, unicode_literals, print_function
|
|
|
|
# Import Salt Testing Libs
|
|
from tests.support.mixins import LoaderModuleMockMixin
|
|
from tests.support.unit import skipIf, TestCase
|
|
from tests.support.mock import (
|
|
NO_MOCK,
|
|
NO_MOCK_REASON,
|
|
MagicMock,
|
|
patch)
|
|
|
|
# Import test data from salt.utils.zfs test
|
|
from tests.unit.utils.test_zfs import utils_patch
|
|
|
|
# Import Salt Execution module to test
|
|
import salt.utils.zfs
|
|
import salt.states.zpool as zpool
|
|
|
|
# Import Salt Utils
|
|
import salt.loader
|
|
from salt.utils.odict import OrderedDict
|
|
|
|
|
|
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
|
class ZpoolTestCase(TestCase, LoaderModuleMockMixin):
|
|
'''
|
|
Test cases for salt.states.zpool
|
|
'''
|
|
def setup_loader_modules(self):
|
|
self.opts = opts = salt.config.DEFAULT_MINION_OPTS
|
|
utils = salt.loader.utils(opts, whitelist=['zfs'])
|
|
zpool_obj = {
|
|
zpool: {
|
|
'__opts__': opts,
|
|
'__grains__': {'kernel': 'SunOS'},
|
|
'__utils__': utils,
|
|
}
|
|
}
|
|
|
|
return zpool_obj
|
|
|
|
def test_absent_without_pool(self):
|
|
'''
|
|
Test zpool absent without a pool
|
|
'''
|
|
ret = {'name': 'myzpool',
|
|
'result': True,
|
|
'comment': 'storage pool myzpool is absent',
|
|
'changes': {}}
|
|
|
|
mock_exists = MagicMock(return_value=False)
|
|
with patch.dict(zpool.__salt__, {'zpool.exists': mock_exists}), \
|
|
patch.dict(zpool.__utils__, utils_patch):
|
|
self.assertEqual(zpool.absent('myzpool'), ret)
|
|
|
|
def test_absent_destroy_pool(self):
|
|
'''
|
|
Test zpool absent destroying pool
|
|
'''
|
|
ret = {
|
|
'name': 'myzpool',
|
|
'result': True,
|
|
'comment': 'storage pool myzpool was destroyed',
|
|
'changes': {'myzpool': 'destroyed'},
|
|
}
|
|
|
|
mock_exists = MagicMock(return_value=True)
|
|
mock_destroy = MagicMock(return_value=OrderedDict([
|
|
('destroyed', True),
|
|
]))
|
|
with patch.dict(zpool.__salt__, {'zpool.exists': mock_exists}), \
|
|
patch.dict(zpool.__salt__, {'zpool.destroy': mock_destroy}), \
|
|
patch.dict(zpool.__utils__, utils_patch):
|
|
self.assertEqual(zpool.absent('myzpool'), ret)
|
|
|
|
def test_absent_exporty_pool(self):
|
|
'''
|
|
Test zpool absent exporting pool
|
|
'''
|
|
ret = {
|
|
'name': 'myzpool',
|
|
'result': True,
|
|
'comment': 'storage pool myzpool was exported',
|
|
'changes': {'myzpool': 'exported'},
|
|
}
|
|
|
|
mock_exists = MagicMock(return_value=True)
|
|
mock_destroy = MagicMock(return_value=OrderedDict([
|
|
('exported', True),
|
|
]))
|
|
with patch.dict(zpool.__salt__, {'zpool.exists': mock_exists}), \
|
|
patch.dict(zpool.__salt__, {'zpool.export': mock_destroy}), \
|
|
patch.dict(zpool.__utils__, utils_patch):
|
|
self.assertEqual(zpool.absent('myzpool', export=True), ret)
|
|
|
|
def test_absent_busy(self):
|
|
'''
|
|
Test zpool absent on a busy pool
|
|
'''
|
|
ret = {
|
|
'name': 'myzpool',
|
|
'result': False,
|
|
'comment': "\n".join([
|
|
"cannot unmount '/myzpool': Device busy",
|
|
"cannot export 'myzpool': pool is busy",
|
|
]),
|
|
'changes': {},
|
|
}
|
|
|
|
mock_exists = MagicMock(return_value=True)
|
|
mock_destroy = MagicMock(return_value=OrderedDict([
|
|
('exported', False),
|
|
('error', "\n".join([
|
|
"cannot unmount '/myzpool': Device busy",
|
|
"cannot export 'myzpool': pool is busy",
|
|
])),
|
|
]))
|
|
with patch.dict(zpool.__salt__, {'zpool.exists': mock_exists}), \
|
|
patch.dict(zpool.__salt__, {'zpool.export': mock_destroy}), \
|
|
patch.dict(zpool.__utils__, utils_patch):
|
|
self.assertEqual(zpool.absent('myzpool', export=True), ret)
|
|
|
|
def test_present_import_success(self):
|
|
'''
|
|
Test zpool present with import allowed and unimported pool
|
|
'''
|
|
ret = {'name': 'myzpool',
|
|
'result': True,
|
|
'comment': 'storage pool myzpool was imported',
|
|
'changes': {'myzpool': 'imported'}}
|
|
|
|
config = {
|
|
'import': True,
|
|
}
|
|
|
|
mock_exists = MagicMock(return_value=False)
|
|
mock_import = MagicMock(return_value=OrderedDict([
|
|
('imported', True),
|
|
]))
|
|
with patch.dict(zpool.__salt__, {'zpool.exists': mock_exists}), \
|
|
patch.dict(zpool.__salt__, {'zpool.import': mock_import}), \
|
|
patch.dict(zpool.__utils__, utils_patch):
|
|
self.assertEqual(zpool.present('myzpool', config=config), ret)
|
|
|
|
def test_present_import_fail(self):
|
|
'''
|
|
Test zpool present with import allowed and no unimported pool or layout
|
|
'''
|
|
ret = {'name': 'myzpool',
|
|
'result': False,
|
|
'comment': 'storage pool myzpool was not imported, no (valid) layout specified for creation',
|
|
'changes': {}}
|
|
|
|
config = {
|
|
'import': True,
|
|
}
|
|
|
|
mock_exists = MagicMock(return_value=False)
|
|
mock_import = MagicMock(return_value=OrderedDict([
|
|
('imported', False),
|
|
]))
|
|
with patch.dict(zpool.__salt__, {'zpool.exists': mock_exists}), \
|
|
patch.dict(zpool.__salt__, {'zpool.import': mock_import}), \
|
|
patch.dict(zpool.__utils__, utils_patch):
|
|
self.assertEqual(zpool.present('myzpool', config=config), ret)
|
|
|
|
def test_present_create_success(self):
|
|
'''
|
|
Test zpool present with non existing pool
|
|
'''
|
|
ret = {'name': 'myzpool',
|
|
'result': True,
|
|
'comment': 'storage pool myzpool was created',
|
|
'changes': {'myzpool': 'created'}}
|
|
|
|
config = {
|
|
'import': False,
|
|
}
|
|
layout = [
|
|
OrderedDict([('mirror', ['disk0', 'disk1'])]),
|
|
OrderedDict([('mirror', ['disk2', 'disk3'])]),
|
|
]
|
|
properties = {
|
|
'autoexpand': True,
|
|
}
|
|
filesystem_properties = {
|
|
'quota': '5G',
|
|
}
|
|
|
|
mock_exists = MagicMock(return_value=False)
|
|
mock_create = MagicMock(return_value=OrderedDict([
|
|
('created', True),
|
|
('vdevs', OrderedDict([
|
|
('mirror-0', ['/dev/dsk/disk0', '/dev/dsk/disk1']),
|
|
('mirror-1', ['/dev/dsk/disk2', '/dev/dsk/disk3']),
|
|
])),
|
|
]))
|
|
with patch.dict(zpool.__salt__, {'zpool.exists': mock_exists}), \
|
|
patch.dict(zpool.__salt__, {'zpool.create': mock_create}), \
|
|
patch.dict(zpool.__utils__, utils_patch):
|
|
self.assertEqual(
|
|
zpool.present(
|
|
'myzpool',
|
|
config=config,
|
|
layout=layout,
|
|
properties=properties,
|
|
filesystem_properties=filesystem_properties,
|
|
),
|
|
ret,
|
|
)
|
|
|
|
def test_present_create_fail(self):
|
|
'''
|
|
Test zpool present with non existing pool (without a layout)
|
|
'''
|
|
ret = {'name': 'myzpool',
|
|
'result': False,
|
|
'comment': 'storage pool myzpool was not imported, no (valid) layout specified for creation',
|
|
'changes': {}}
|
|
|
|
config = {
|
|
'import': False,
|
|
}
|
|
|
|
mock_exists = MagicMock(return_value=False)
|
|
with patch.dict(zpool.__salt__, {'zpool.exists': mock_exists}), \
|
|
patch.dict(zpool.__utils__, utils_patch):
|
|
self.assertEqual(zpool.present('myzpool', config=config), ret)
|
|
|
|
def test_present_create_passthrough_fail(self):
|
|
'''
|
|
Test zpool present with non existing pool (without a layout)
|
|
'''
|
|
ret = {'name': 'myzpool',
|
|
'result': False,
|
|
'comment': "\n".join([
|
|
"invalid vdev specification",
|
|
"use 'force=True' to override the following errors:",
|
|
"/data/salt/vdisk0 is part of exported pool 'zsalt'",
|
|
"/data/salt/vdisk1 is part of exported pool 'zsalt'",
|
|
]),
|
|
'changes': {}}
|
|
|
|
config = {
|
|
'force': False,
|
|
'import': False,
|
|
}
|
|
layout = [
|
|
OrderedDict([('mirror', ['disk0', 'disk1'])]),
|
|
OrderedDict([('mirror', ['disk2', 'disk3'])]),
|
|
]
|
|
properties = {
|
|
'autoexpand': True,
|
|
}
|
|
filesystem_properties = {
|
|
'quota': '5G',
|
|
}
|
|
|
|
mock_exists = MagicMock(return_value=False)
|
|
mock_create = MagicMock(return_value=OrderedDict([
|
|
('created', False),
|
|
('error', "\n".join([
|
|
"invalid vdev specification",
|
|
"use 'force=True' to override the following errors:",
|
|
"/data/salt/vdisk0 is part of exported pool 'zsalt'",
|
|
"/data/salt/vdisk1 is part of exported pool 'zsalt'",
|
|
])),
|
|
]))
|
|
with patch.dict(zpool.__salt__, {'zpool.exists': mock_exists}), \
|
|
patch.dict(zpool.__salt__, {'zpool.create': mock_create}), \
|
|
patch.dict(zpool.__utils__, utils_patch):
|
|
self.assertEqual(
|
|
zpool.present(
|
|
'myzpool',
|
|
config=config,
|
|
layout=layout,
|
|
properties=properties,
|
|
filesystem_properties=filesystem_properties,
|
|
),
|
|
ret,
|
|
)
|
|
|
|
def test_present_update_success(self):
|
|
'''
|
|
Test zpool present with an existing pool that needs an update
|
|
'''
|
|
ret = {'name': 'myzpool',
|
|
'result': True,
|
|
'comment': 'properties updated',
|
|
'changes': {'myzpool': {'autoexpand': False}}}
|
|
|
|
config = {
|
|
'import': False,
|
|
}
|
|
layout = [
|
|
OrderedDict([('mirror', ['disk0', 'disk1'])]),
|
|
OrderedDict([('mirror', ['disk2', 'disk3'])]),
|
|
]
|
|
properties = {
|
|
'autoexpand': False,
|
|
}
|
|
|
|
mock_exists = MagicMock(return_value=True)
|
|
mock_get = MagicMock(return_value=OrderedDict([
|
|
('comment', 'salt managed pool'),
|
|
('freeing', 0),
|
|
('listsnapshots', False),
|
|
('leaked', 0),
|
|
('feature@obsolete_counts', 'enabled'),
|
|
('feature@sha512', 'enabled'),
|
|
('delegation', True),
|
|
('dedupditto', '0'),
|
|
('dedupratio', '1.00x'),
|
|
('autoexpand', True),
|
|
('feature@bookmarks', 'enabled'),
|
|
('allocated', 115712),
|
|
('guid', 1591906802560842214),
|
|
('feature@large_blocks', 'enabled'),
|
|
('size', 2113929216),
|
|
('feature@enabled_txg', 'active'),
|
|
('feature@hole_birth', 'active'),
|
|
('capacity', 0),
|
|
('feature@multi_vdev_crash_dump', 'enabled'),
|
|
('feature@extensible_dataset', 'enabled'),
|
|
('cachefile', '-'),
|
|
('bootfs', '-'),
|
|
('autoreplace', True),
|
|
('readonly', False),
|
|
('version', '-'),
|
|
('health', 'ONLINE'),
|
|
('expandsize', '-'),
|
|
('feature@embedded_data', 'active'),
|
|
('feature@lz4_compress', 'active'),
|
|
('feature@async_destroy', 'enabled'),
|
|
('feature@skein', 'enabled'),
|
|
('feature@empty_bpobj', 'enabled'),
|
|
('feature@spacemap_histogram', 'active'),
|
|
('bootsize', '-'),
|
|
('free', 2113813504),
|
|
('feature@device_removal', 'enabled'),
|
|
('failmode', 'wait'),
|
|
('feature@filesystem_limits', 'enabled'),
|
|
('feature@edonr', 'enabled'),
|
|
('altroot', '-'),
|
|
('fragmentation', '0%'),
|
|
]))
|
|
mock_set = MagicMock(return_value=OrderedDict([
|
|
('set', True),
|
|
]))
|
|
with patch.dict(zpool.__salt__, {'zpool.exists': mock_exists}), \
|
|
patch.dict(zpool.__salt__, {'zpool.get': mock_get}), \
|
|
patch.dict(zpool.__salt__, {'zpool.set': mock_set}), \
|
|
patch.dict(zpool.__utils__, utils_patch):
|
|
self.assertEqual(
|
|
zpool.present(
|
|
'myzpool',
|
|
config=config,
|
|
layout=layout,
|
|
properties=properties,
|
|
),
|
|
ret,
|
|
)
|
|
|
|
def test_present_update_nochange_success(self):
|
|
'''
|
|
Test zpool present with non existing pool
|
|
'''
|
|
ret = {'name': 'myzpool',
|
|
'result': True,
|
|
'comment': 'no update needed',
|
|
'changes': {}}
|
|
|
|
config = {
|
|
'import': False,
|
|
}
|
|
layout = [
|
|
OrderedDict([('mirror', ['disk0', 'disk1'])]),
|
|
OrderedDict([('mirror', ['disk2', 'disk3'])]),
|
|
]
|
|
properties = {
|
|
'autoexpand': True,
|
|
}
|
|
|
|
mock_exists = MagicMock(return_value=True)
|
|
mock_get = MagicMock(return_value=OrderedDict([
|
|
('comment', 'salt managed pool'),
|
|
('freeing', 0),
|
|
('listsnapshots', False),
|
|
('leaked', 0),
|
|
('feature@obsolete_counts', 'enabled'),
|
|
('feature@sha512', 'enabled'),
|
|
('delegation', True),
|
|
('dedupditto', '0'),
|
|
('dedupratio', '1.00x'),
|
|
('autoexpand', True),
|
|
('feature@bookmarks', 'enabled'),
|
|
('allocated', 115712),
|
|
('guid', 1591906802560842214),
|
|
('feature@large_blocks', 'enabled'),
|
|
('size', 2113929216),
|
|
('feature@enabled_txg', 'active'),
|
|
('feature@hole_birth', 'active'),
|
|
('capacity', 0),
|
|
('feature@multi_vdev_crash_dump', 'enabled'),
|
|
('feature@extensible_dataset', 'enabled'),
|
|
('cachefile', '-'),
|
|
('bootfs', '-'),
|
|
('autoreplace', True),
|
|
('readonly', False),
|
|
('version', '-'),
|
|
('health', 'ONLINE'),
|
|
('expandsize', '-'),
|
|
('feature@embedded_data', 'active'),
|
|
('feature@lz4_compress', 'active'),
|
|
('feature@async_destroy', 'enabled'),
|
|
('feature@skein', 'enabled'),
|
|
('feature@empty_bpobj', 'enabled'),
|
|
('feature@spacemap_histogram', 'active'),
|
|
('bootsize', '-'),
|
|
('free', 2113813504),
|
|
('feature@device_removal', 'enabled'),
|
|
('failmode', 'wait'),
|
|
('feature@filesystem_limits', 'enabled'),
|
|
('feature@edonr', 'enabled'),
|
|
('altroot', '-'),
|
|
('fragmentation', '0%'),
|
|
]))
|
|
with patch.dict(zpool.__salt__, {'zpool.exists': mock_exists}), \
|
|
patch.dict(zpool.__salt__, {'zpool.get': mock_get}), \
|
|
patch.dict(zpool.__utils__, utils_patch):
|
|
self.assertEqual(
|
|
zpool.present(
|
|
'myzpool',
|
|
config=config,
|
|
layout=layout,
|
|
properties=properties,
|
|
),
|
|
ret,
|
|
)
|