Skip to content

Commit

Permalink
Add virt.pool_deleted state
Browse files Browse the repository at this point in the history
The new virt.pool_deleted state takes care of removing a virtual storage
pool and optionally the contained volumes.
  • Loading branch information
cbosdo committed Dec 16, 2019
1 parent f530047 commit d2194f0
Show file tree
Hide file tree
Showing 2 changed files with 218 additions and 0 deletions.
110 changes: 110 additions & 0 deletions salt/states/virt.py
Original file line number Diff line number Diff line change
Expand Up @@ -802,3 +802,113 @@ def pool_running(name,
ret['result'] = False

return ret


def pool_deleted(name,
purge=False,
connection=None,
username=None,
password=None):
'''
Deletes a virtual storage pool.
:param name: the name of the pool to delete.
:param purge:
if ``True``, the volumes contained in the pool will be deleted as well as the pool itself.
Note that these will be lost for ever. If ``False`` the pool will simply be undefined.
(Default: ``False``)
:param connection: libvirt connection URI, overriding defaults
:param username: username to connect with, overriding defaults
:param password: password to connect with, overriding defaults
In order to be purged a storage pool needs to be running to get the list of volumes to delete.
Some libvirt storage drivers may not implement deleting, those actions are implemented on a
best effort idea. In any case check the result's comment property to see if any of the action
was unsupported.
.. code-block::yaml
pool_name:
uyuni_virt.pool_deleted:
- purge: True
.. versionadded:: Neon
'''
ret = {'name': name, 'changes': {}, 'result': True, 'comment': ''}

try:
info = __salt__['virt.pool_info'](name, connection=connection, username=username, password=password)
if info:
ret['changes']['stopped'] = False
ret['changes']['deleted'] = False
ret['changes']['undefined'] = False
ret['changes']['deleted_volumes'] = []
unsupported = []

if info[name]['state'] == 'running':
if purge:
unsupported_volume_delete = ['iscsi', 'iscsi-direct', 'mpath', 'scsi']
if info[name]['type'] not in unsupported_volume_delete:
__salt__['virt.pool_refresh'](name,
connection=connection,
username=username,
password=password)
volumes = __salt__['virt.pool_list_volumes'](name,
connection=connection,
username=username,
password=password)
for volume in volumes:
# Not supported for iSCSI and SCSI drivers
deleted = __opts__['test']
if not __opts__['test']:
deleted = __salt__['virt.volume_delete'](name,
volume,
connection=connection,
username=username,
password=password)
if deleted:
ret['changes']['deleted_volumes'].append(volume)
else:
unsupported.append('deleting volume')

if not __opts__['test']:
ret['changes']['stopped'] = __salt__['virt.pool_stop'](name,
connection=connection,
username=username,
password=password)
else:
ret['changes']['stopped'] = True

if purge:
supported_pool_delete = ['dir', 'fs', 'netfs', 'logical', 'vstorage', 'zfs']
if info[name]['type'] in supported_pool_delete:
if not __opts__['test']:
ret['changes']['deleted'] = __salt__['virt.pool_delete'](name,
connection=connection,
username=username,
password=password)
else:
ret['changes']['deleted'] = True
else:
unsupported.append('deleting pool')

if not __opts__['test']:
ret['changes']['undefined'] = __salt__['virt.pool_undefine'](name,
connection=connection,
username=username,
password=password)
else:
ret['changes']['undefined'] = True
ret['result'] = None

if unsupported:
ret['comment'] = 'Unsupported actions for pool of type "{0}": {1}'.format(info[name]['type'],
', '.join(unsupported))
else:
ret['comment'] = 'Storage pool could not be found: {0}'.format(name)
except libvirt.libvirtError as err:
ret['comment'] = 'Failed deleting pool: {0}'.format(err.get_error_message())
ret['result'] = False

return ret
108 changes: 108 additions & 0 deletions tests/unit/states/test_virt.py
Original file line number Diff line number Diff line change
Expand Up @@ -701,3 +701,111 @@ def test_pool_running(self):
ptype='logical',
target='/dev/base',
source={'devices': [{'path': '/dev/sda'}]}), ret)

def test_pool_deleted(self):
'''
Test the pool_deleted state
'''
# purge=False test case, stopped pool
with patch.dict(virt.__salt__, {
'virt.pool_info': MagicMock(return_value={'test01': {'state': 'stopped', 'type': 'dir'}}),
'virt.pool_undefine': MagicMock(return_value=True)
}):
expected = {
'name': 'test01',
'changes': {
'stopped': False,
'deleted_volumes': [],
'deleted': False,
'undefined': True,
},
'result': True,
'comment': '',
}

with patch.dict(virt.__opts__, {'test': False}):
self.assertDictEqual(expected, virt.pool_deleted('test01'))

with patch.dict(virt.__opts__, {'test': True}):
expected['result'] = None
self.assertDictEqual(expected, virt.pool_deleted('test01'))

# purge=False test case
with patch.dict(virt.__salt__, {
'virt.pool_info': MagicMock(return_value={'test01': {'state': 'running', 'type': 'dir'}}),
'virt.pool_undefine': MagicMock(return_value=True),
'virt.pool_stop': MagicMock(return_value=True)
}):
expected = {
'name': 'test01',
'changes': {
'stopped': True,
'deleted_volumes': [],
'deleted': False,
'undefined': True,
},
'result': True,
'comment': '',
}

with patch.dict(virt.__opts__, {'test': False}):
self.assertDictEqual(expected, virt.pool_deleted('test01'))

with patch.dict(virt.__opts__, {'test': True}):
expected['result'] = None
self.assertDictEqual(expected, virt.pool_deleted('test01'))

# purge=True test case

with patch.dict(virt.__salt__, {
'virt.pool_info': MagicMock(return_value={'test01': {'state': 'running', 'type': 'dir'}}),
'virt.pool_list_volumes': MagicMock(return_value=['vm01.qcow2', 'vm02.qcow2']),
'virt.pool_refresh': MagicMock(return_value=True),
'virt.volume_delete': MagicMock(return_value=True),
'virt.pool_stop': MagicMock(return_value=True),
'virt.pool_delete': MagicMock(return_value=True),
'virt.pool_undefine': MagicMock(return_value=True)
}):
expected = {
'name': 'test01',
'changes': {
'stopped': True,
'deleted_volumes': ['vm01.qcow2', 'vm02.qcow2'],
'deleted': True,
'undefined': True,
},
'result': True,
'comment': '',
}

with patch.dict(virt.__opts__, {'test': False}):
self.assertDictEqual(expected, virt.pool_deleted('test01', purge=True))

with patch.dict(virt.__opts__, {'test': True}):
expected['result'] = None
self.assertDictEqual(expected, virt.pool_deleted('test01', purge=True))

# Case of backend not unsupporting delete operations
with patch.dict(virt.__salt__, {
'virt.pool_info': MagicMock(return_value={'test01': {'state': 'running', 'type': 'iscsi'}}),
'virt.pool_stop': MagicMock(return_value=True),
'virt.pool_undefine': MagicMock(return_value=True)
}):
expected = {
'name': 'test01',
'changes': {
'stopped': True,
'deleted_volumes': [],
'deleted': False,
'undefined': True,
},
'result': True,
'comment': 'Unsupported actions for pool of type "iscsi": deleting volume, deleting pool',
}

with patch.dict(virt.__opts__, {'test': False}):
self.assertDictEqual(expected, virt.pool_deleted('test01', purge=True))

with patch.dict(virt.__opts__, {'test': True}):
expected['result'] = None
self.assertDictEqual(expected, virt.pool_deleted('test01', purge=True))

0 comments on commit d2194f0

Please sign in to comment.