Add snapshot and revert to libvirt driver
This patch allows to create and revert snapshots using libvirt driver. Change-Id: Id6bc0a3daf14f5e664d068bc8d2348e48e561a9b
This commit is contained in:
parent
01801c3ecd
commit
f92fd9ca8b
@ -165,6 +165,20 @@ class NodeCollection(object):
|
||||
LOG.info('Reset nodes: %s', self)
|
||||
self.power_management.reset(self.get_macs())
|
||||
|
||||
def snapshot(self, snapshot_name, suspend=True):
|
||||
"""Create snapshot for all nodes
|
||||
|
||||
"""
|
||||
LOG.info('Create snapshot "%s" for nodes: %s', snapshot_name, self)
|
||||
self.power_management.snapshot(self.get_macs(), snapshot_name, suspend)
|
||||
|
||||
def revert(self, snapshot_name, resume=True):
|
||||
"""Revert snapshot for all nodes
|
||||
|
||||
"""
|
||||
LOG.info('Revert snapshot "%s" for nodes: %s', snapshot_name, self)
|
||||
self.power_management.revert(self.get_macs(), snapshot_name, resume)
|
||||
|
||||
@public
|
||||
def disconnect(self, network_name):
|
||||
"""Disconnect nodes from <network_name> network
|
||||
|
@ -32,3 +32,9 @@ class PowerManagement(base_driver.BaseDriver):
|
||||
@abc.abstractmethod
|
||||
def reset(self, hosts):
|
||||
pass
|
||||
|
||||
def snapshot(self, hosts, snapshot_name, suspend=True):
|
||||
raise NotImplementedError
|
||||
|
||||
def revert(self, hosts, snapshot_name, resume=True):
|
||||
raise NotImplementedError
|
||||
|
@ -100,10 +100,16 @@ class IPMIDriver(power_management.PowerManagement):
|
||||
LOG.info('Node reset: %s', mac_address)
|
||||
|
||||
def poweroff(self, mac_addresses_list):
|
||||
utils.run(self._poweroff, mac_addresses_list)
|
||||
kwargs_list = [dict(mac_address=mac_address)
|
||||
for mac_address in mac_addresses_list]
|
||||
utils.run(self._poweroff, kwargs_list)
|
||||
|
||||
def poweron(self, mac_addresses_list):
|
||||
utils.run(self._poweron, mac_addresses_list)
|
||||
kwargs_list = [dict(mac_address=mac_address)
|
||||
for mac_address in mac_addresses_list]
|
||||
utils.run(self._poweron, kwargs_list)
|
||||
|
||||
def reset(self, mac_addresses_list):
|
||||
utils.run(self._reset, mac_addresses_list)
|
||||
kwargs_list = [dict(mac_address=mac_address)
|
||||
for mac_address in mac_addresses_list]
|
||||
utils.run(self._reset, kwargs_list)
|
||||
|
@ -28,7 +28,6 @@ class LibvirtDriver(power_management.PowerManagement):
|
||||
'$schema': 'http://json-schema.org/draft-04/schema#',
|
||||
'properties': {
|
||||
'connection_uri': {'type': 'string'},
|
||||
|
||||
},
|
||||
'required': ['connection_uri'],
|
||||
'additionalProperties': False,
|
||||
@ -79,11 +78,56 @@ class LibvirtDriver(power_management.PowerManagement):
|
||||
domain.reset()
|
||||
LOG.info('Domain reset: %s', mac_address)
|
||||
|
||||
def _snapshot(self, mac_address, snapshot_name, suspend):
|
||||
LOG.debug('Create snapshot "%s" for domain with MAC address: %s',
|
||||
snapshot_name, mac_address)
|
||||
domain = self._find_domain_by_mac_address(mac_address)
|
||||
if suspend:
|
||||
domain.suspend()
|
||||
domain.snapshotCreateXML(
|
||||
'<domainsnapshot><name>{}</name></domainsnapshot>'.format(
|
||||
snapshot_name))
|
||||
if suspend:
|
||||
domain.resume()
|
||||
LOG.debug('Created snapshot "%s" for domain with MAC address: %s',
|
||||
snapshot_name, mac_address)
|
||||
|
||||
def _revert(self, mac_address, snapshot_name, resume):
|
||||
LOG.debug('Revert snapshot "%s" for domain with MAC address: %s',
|
||||
snapshot_name, mac_address)
|
||||
domain = self._find_domain_by_mac_address(mac_address)
|
||||
snapshot = domain.snapshotLookupByName(snapshot_name)
|
||||
domain.revertToSnapshot(snapshot)
|
||||
if resume:
|
||||
domain.resume()
|
||||
LOG.debug('Reverted snapshot "%s" for domain with MAC address: %s',
|
||||
snapshot_name, mac_address)
|
||||
|
||||
def poweroff(self, mac_addresses_list):
|
||||
utils.run(self._poweroff, mac_addresses_list)
|
||||
kwargs_list = [dict(mac_address=mac_address)
|
||||
for mac_address in mac_addresses_list]
|
||||
utils.run(self._poweroff, kwargs_list)
|
||||
|
||||
def poweron(self, mac_addresses_list):
|
||||
utils.run(self._poweron, mac_addresses_list)
|
||||
kwargs_list = [dict(mac_address=mac_address)
|
||||
for mac_address in mac_addresses_list]
|
||||
utils.run(self._poweron, kwargs_list)
|
||||
|
||||
def reset(self, mac_addresses_list):
|
||||
utils.run(self._reset, mac_addresses_list)
|
||||
kwargs_list = [dict(mac_address=mac_address)
|
||||
for mac_address in mac_addresses_list]
|
||||
utils.run(self._reset, kwargs_list)
|
||||
|
||||
def snapshot(self, mac_addresses_list, snapshot_name, suspend=True):
|
||||
kwargs_list = [dict(mac_address=mac_address,
|
||||
snapshot_name=snapshot_name,
|
||||
suspend=suspend)
|
||||
for mac_address in mac_addresses_list]
|
||||
utils.run(self._snapshot, kwargs_list)
|
||||
|
||||
def revert(self, mac_addresses_list, snapshot_name, resume=True):
|
||||
kwargs_list = [dict(mac_address=mac_address,
|
||||
snapshot_name=snapshot_name,
|
||||
resume=resume)
|
||||
for mac_address in mac_addresses_list]
|
||||
utils.run(self._revert, kwargs_list)
|
||||
|
@ -198,3 +198,15 @@ class NodeCollectionTestCase(test.TestCase):
|
||||
self.mock_cloud_management.execute_on_cloud.assert_called_once_with(
|
||||
['10.0.0.2', '10.0.0.3', '10.0.0.4', '10.0.0.5'],
|
||||
{'command': 'reboot now'})
|
||||
|
||||
def test_snapshot(self):
|
||||
self.node_collection.snapshot('foo')
|
||||
self.mock_power_management.snapshot.assert_called_once_with(
|
||||
['09:7b:74:90:63:c1', '09:7b:74:90:63:c2',
|
||||
'09:7b:74:90:63:c3', '09:7b:74:90:63:c4'], 'foo', True)
|
||||
|
||||
def test_revert(self):
|
||||
self.node_collection.revert('foo')
|
||||
self.mock_power_management.revert.assert_called_once_with(
|
||||
['09:7b:74:90:63:c1', '09:7b:74:90:63:c2',
|
||||
'09:7b:74:90:63:c3', '09:7b:74:90:63:c4'], 'foo', True)
|
||||
|
@ -89,5 +89,7 @@ class IPMIDriverTestCase(test.TestCase):
|
||||
def test_driver_actions(self, action, mock_run):
|
||||
macs_list = ['00:00:00:00:00:00', '00:00:00:00:00:01']
|
||||
getattr(self.driver, action)(macs_list)
|
||||
mock_run.assert_called_once_with(getattr(self.driver, '_%s' % action),
|
||||
macs_list)
|
||||
mock_run.assert_called_once_with(
|
||||
getattr(self.driver, '_%s' % action),
|
||||
[{'mac_address': '00:00:00:00:00:00'},
|
||||
{'mac_address': '00:00:00:00:00:01'}])
|
||||
|
@ -77,10 +77,74 @@ class LibvirtDriverTestCase(test.TestCase):
|
||||
domain = mock__find_domain_by_mac_address.return_value
|
||||
getattr(domain, actions[1]).assert_called_once_with()
|
||||
|
||||
@mock.patch(DRIVER_PATH + '.LibvirtDriver._find_domain_by_mac_address')
|
||||
def test__snapshot(self, mock__find_domain_by_mac_address):
|
||||
self.driver._snapshot('52:54:00:f9:b8:f9', 'foo', suspend=False)
|
||||
domain = mock__find_domain_by_mac_address.return_value
|
||||
domain.snapshotCreateXML.assert_called_once_with(
|
||||
'<domainsnapshot><name>foo</name></domainsnapshot>')
|
||||
|
||||
@mock.patch(DRIVER_PATH + '.LibvirtDriver._find_domain_by_mac_address')
|
||||
def test__snapshot_suspend(self, mock__find_domain_by_mac_address):
|
||||
self.driver._snapshot('52:54:00:f9:b8:f9', 'foo', suspend=True)
|
||||
domain = mock__find_domain_by_mac_address.return_value
|
||||
domain.assert_has_calls((
|
||||
mock.call.suspend(),
|
||||
mock.call.snapshotCreateXML(
|
||||
'<domainsnapshot><name>foo</name></domainsnapshot>'),
|
||||
mock.call.resume(),
|
||||
))
|
||||
|
||||
@mock.patch(DRIVER_PATH + '.LibvirtDriver._find_domain_by_mac_address')
|
||||
def test__revert(self, mock__find_domain_by_mac_address):
|
||||
self.driver._revert('52:54:00:f9:b8:f9', 'foo', resume=False)
|
||||
domain = mock__find_domain_by_mac_address.return_value
|
||||
snapshot = domain.snapshotLookupByName.return_value
|
||||
domain.snapshotLookupByName.assert_called_once_with('foo')
|
||||
domain.revertToSnapshot.assert_called_once_with(snapshot)
|
||||
self.assertFalse(domain.resume.called)
|
||||
|
||||
@mock.patch(DRIVER_PATH + '.LibvirtDriver._find_domain_by_mac_address')
|
||||
def test__revert_resume(self, mock__find_domain_by_mac_address):
|
||||
self.driver._revert('52:54:00:f9:b8:f9', 'foo', resume=True)
|
||||
domain = mock__find_domain_by_mac_address.return_value
|
||||
snapshot = domain.snapshotLookupByName.return_value
|
||||
domain.snapshotLookupByName.assert_called_once_with('foo')
|
||||
domain.revertToSnapshot.assert_called_once_with(snapshot)
|
||||
domain.resume.assert_called_once_with()
|
||||
|
||||
@mock.patch('os_faults.utils.run')
|
||||
@ddt.data('poweroff', 'poweron', 'reset')
|
||||
def test_driver_actions(self, action, mock_run):
|
||||
macs_list = ['52:54:00:f9:b8:f9', '52:54:00:ab:64:42']
|
||||
getattr(self.driver, action)(macs_list)
|
||||
mock_run.assert_called_once_with(getattr(self.driver, '_%s' % action),
|
||||
macs_list)
|
||||
mock_run.assert_called_once_with(
|
||||
getattr(self.driver, '_%s' % action),
|
||||
[{'mac_address': '52:54:00:f9:b8:f9'},
|
||||
{'mac_address': '52:54:00:ab:64:42'}])
|
||||
|
||||
@mock.patch('os_faults.utils.run')
|
||||
def test_driver_snapshot(self, mock_run):
|
||||
macs_list = ['52:54:00:f9:b8:f9', '52:54:00:ab:64:42']
|
||||
self.driver.snapshot(macs_list, 'foo_snap')
|
||||
mock_run.assert_called_once_with(
|
||||
self.driver._snapshot,
|
||||
[{'mac_address': '52:54:00:f9:b8:f9',
|
||||
'snapshot_name': 'foo_snap',
|
||||
'suspend': True},
|
||||
{'mac_address': '52:54:00:ab:64:42',
|
||||
'snapshot_name': 'foo_snap',
|
||||
'suspend': True}])
|
||||
|
||||
@mock.patch('os_faults.utils.run')
|
||||
def test_driver_revert(self, mock_run):
|
||||
macs_list = ['52:54:00:f9:b8:f9', '52:54:00:ab:64:42']
|
||||
self.driver.revert(macs_list, 'foo_snap', resume=False)
|
||||
mock_run.assert_called_once_with(
|
||||
self.driver._revert,
|
||||
[{'mac_address': '52:54:00:f9:b8:f9',
|
||||
'snapshot_name': 'foo_snap',
|
||||
'resume': False},
|
||||
{'mac_address': '52:54:00:ab:64:42',
|
||||
'snapshot_name': 'foo_snap',
|
||||
'resume': False}])
|
||||
|
@ -27,7 +27,7 @@ class UtilsTestCase(test.TestCase):
|
||||
|
||||
def test_run(self):
|
||||
target = mock.Mock()
|
||||
utils.run(target, ['01', '02'])
|
||||
utils.run(target, [{'mac_address': '01'}, {'mac_address': '02'}])
|
||||
target.assert_has_calls([mock.call(mac_address='01'),
|
||||
mock.call(mac_address='02')])
|
||||
|
||||
@ -35,7 +35,8 @@ class UtilsTestCase(test.TestCase):
|
||||
target = mock.Mock()
|
||||
target.side_effect = MyException()
|
||||
self.assertRaises(error.PowerManagementError,
|
||||
utils.run, target, ['01', '02'])
|
||||
utils.run, target, [{'mac_address': '01'},
|
||||
{'mac_address': '02'}])
|
||||
|
||||
def test_start_thread(self):
|
||||
target = mock.Mock()
|
||||
|
@ -20,10 +20,10 @@ from os_faults.api import error
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def run(target, mac_addresses_list):
|
||||
def run(target, kwargs_list):
|
||||
tw = ThreadsWrapper(target)
|
||||
for mac_address in mac_addresses_list:
|
||||
tw.start_thread(mac_address=mac_address)
|
||||
for kwargs in kwargs_list:
|
||||
tw.start_thread(**kwargs)
|
||||
tw.join_threads()
|
||||
|
||||
if tw.errors:
|
||||
|
Loading…
x
Reference in New Issue
Block a user