Commit ac32cc74 authored by Jérome Perrin's avatar Jérome Perrin

proxy: implement software destruction

proxy was just removing the software from database when destruction was
requested. Instead, keep it as requested_state = "destroyed" and return
this information to the node, so that nodes properly destroy the
software.
parent 7b1f6675
...@@ -257,6 +257,14 @@ def setComputerPartitionConnectionXml(): ...@@ -257,6 +257,14 @@ def setComputerPartitionConnectionXml():
def buildingSoftwareRelease(): def buildingSoftwareRelease():
return 'Ignored' return 'Ignored'
@app.route('/destroyedSoftwareRelease', methods=['POST'])
def destroyedSoftwareRelease():
execute_db(
'software',
'DELETE FROM %s WHERE url = ? and computer_reference=? ',
[request.form['url'], request.form['computer_id']])
return 'OK'
@app.route('/availableSoftwareRelease', methods=['POST']) @app.route('/availableSoftwareRelease', methods=['POST'])
def availableSoftwareRelease(): def availableSoftwareRelease():
return 'Ignored' return 'Ignored'
...@@ -322,12 +330,16 @@ def registerComputerPartition(): ...@@ -322,12 +330,16 @@ def registerComputerPartition():
def supplySupply(): def supplySupply():
url = request.form['url'] url = request.form['url']
computer_id = request.form['computer_id'] computer_id = request.form['computer_id']
if request.form['state'] == 'destroyed': state = request.form['state']
execute_db('software', 'DELETE FROM %s WHERE url = ? AND computer_reference=?', if state not in ('available', 'destroyed'):
[url, computer_id]) raise ValueError("Wrong state %s" % state)
else:
execute_db('software', 'INSERT OR REPLACE INTO %s VALUES(?, ?)', [url, computer_id]) execute_db(
return '%r added' % url 'software',
'INSERT OR REPLACE INTO %s VALUES(?, ?, ?)',
[url, computer_id, state])
return 'Supplied %r to be %s' % (url, state)
@app.route('/requestComputerPartition', methods=['POST']) @app.route('/requestComputerPartition', methods=['POST'])
......
...@@ -120,7 +120,7 @@ class SoftwareRelease(SlapDocument): ...@@ -120,7 +120,7 @@ class SoftwareRelease(SlapDocument):
Contains Software Release information Contains Software Release information
""" """
def __init__(self, software_release=None, computer_guid=None, **kw): def __init__(self, software_release=None, computer_guid=None, requested_state='available', **kw):
""" """
Makes easy initialisation of class parameters Makes easy initialisation of class parameters
......
...@@ -327,7 +327,7 @@ class MasterMixin(BasicMixin, unittest.TestCase): ...@@ -327,7 +327,7 @@ class MasterMixin(BasicMixin, unittest.TestCase):
computer_partition.__dict__.update(software_instance.__dict__) computer_partition.__dict__.update(software_instance.__dict__)
return computer_partition return computer_partition
def supply(self, url, computer_id=None, state=''): def supply(self, url, computer_id=None, state='available'):
if not computer_id: if not computer_id:
computer_id = self.computer_id computer_id = self.computer_id
request_dict = {'url':url, 'computer_id': computer_id, 'state':state} request_dict = {'url':url, 'computer_id': computer_id, 'state':state}
...@@ -347,12 +347,73 @@ class MasterMixin(BasicMixin, unittest.TestCase): ...@@ -347,12 +347,73 @@ class MasterMixin(BasicMixin, unittest.TestCase):
""" """
Return computer information as stored in proxy for corresponding id Return computer information as stored in proxy for corresponding id
""" """
rv = self.app.get('/getFullComputerInformation?computer_id=%s' % self.computer_id) computer = self.getFullComputerInformation()
computer = loads(rv.data)
for instance in computer._computer_partition_list: for instance in computer._computer_partition_list:
if instance._partition_id == computer_partition_id: if instance._partition_id == computer_partition_id:
return instance return instance
def getFullComputerInformation(self):
return loads(self.app.get('/getFullComputerInformation?computer_id=%s' % self.computer_id).data)
class TestSoftwareInstallation(MasterMixin, unittest.TestCase):
def setUp(self):
super(TestSoftwareInstallation, self).setUp()
self.software_release_url = self.id()
def assertSoftwareState(self, state):
# Check that the software was requested in `state`
sr, = self.getFullComputerInformation()._software_release_list
self.assertEqual(sr.getState(), state)
def test_installation_success(self):
self.supply(self.software_release_url)
self.assertSoftwareState('available')
self.app.post('/buildingSoftwareRelease', data={
'url': self.software_release_url,
'computer_id': self.computer_id
})
# there's no intermediate "building" state, because state is
# the "requested state".
self.assertSoftwareState('available')
self.app.post('/availableSoftwareRelease', data={
'url': self.software_release_url,
'computer_id': self.computer_id
})
self.assertSoftwareState('available')
def test_installation_failed(self):
self.supply(self.software_release_url)
self.assertSoftwareState('available')
self.app.post('/buildingSoftwareRelease', data={
'url': self.software_release_url,
'computer_id': self.computer_id
})
self.assertSoftwareState('available')
self.app.post('/softwareReleaseError', data={
'url': self.software_release_url,
'computer_id': self.computer_id
})
self.assertSoftwareState('available')
def test_destroyed(self):
self.supply(self.software_release_url)
self.assertSoftwareState('available')
self.supply(self.software_release_url, state="destroyed")
self.assertSoftwareState('destroyed')
self.app.post('/destroyedSoftwareRelease', data={
'url': self.software_release_url,
'computer_id': self.computer_id
})
# this really remove the software from DB
self.assertEqual([], self.getFullComputerInformation()._software_release_list)
class TestRequest(MasterMixin): class TestRequest(MasterMixin):
""" """
...@@ -702,6 +763,7 @@ class TestSlaveRequest(MasterMixin): ...@@ -702,6 +763,7 @@ class TestSlaveRequest(MasterMixin):
shared=True, filter_kw=dict(instance_guid=partition._instance_guid)) shared=True, filter_kw=dict(instance_guid=partition._instance_guid))
self.assertEqual(slave._partition_id, partition._partition_id) self.assertEqual(slave._partition_id, partition._partition_id)
class TestMultiNodeSupport(MasterMixin): class TestMultiNodeSupport(MasterMixin):
def test_multi_node_support_different_software_release_list(self): def test_multi_node_support_different_software_release_list(self):
""" """
...@@ -775,17 +837,33 @@ class TestMultiNodeSupport(MasterMixin): ...@@ -775,17 +837,33 @@ class TestMultiNodeSupport(MasterMixin):
computer_0 = loads(self.app.get('/getFullComputerInformation?computer_id=COMP-0').data) computer_0 = loads(self.app.get('/getFullComputerInformation?computer_id=COMP-0').data)
computer_1 = loads(self.app.get('/getFullComputerInformation?computer_id=COMP-1').data) computer_1 = loads(self.app.get('/getFullComputerInformation?computer_id=COMP-1').data)
self.assertEqual(len(computer_0._software_release_list), 0) # at this point, software is requested to be destroyed on COMP-0
self.assertEqual(len(computer_1._software_release_list), 1) self.assertEqual(
computer_0._software_release_list[0].getURI(),
software_release_url
)
self.assertEqual(
computer_0._software_release_list[0].getComputerId(),
'COMP-0'
)
self.assertEqual(
computer_0._software_release_list[0].getState(),
'destroyed'
)
# but is still requested for installation on COMP-1
self.assertEqual( self.assertEqual(
computer_1._software_release_list[0]._software_release, computer_1._software_release_list[0].getURI(),
software_release_url software_release_url
) )
self.assertEqual( self.assertEqual(
computer_1._software_release_list[0]._computer_guid, computer_1._software_release_list[0].getComputerId(),
'COMP-1' 'COMP-1'
) )
self.assertEqual(
computer_1._software_release_list[0].getState(),
'available'
)
def test_multi_node_support_instance_default_computer(self): def test_multi_node_support_instance_default_computer(self):
""" """
...@@ -974,6 +1052,7 @@ class TestMultiNodeSupport(MasterMixin): ...@@ -974,6 +1052,7 @@ class TestMultiNodeSupport(MasterMixin):
except slapos.slap.NotFoundError: except slapos.slap.NotFoundError:
self.fail('Could not fetch informations for registered computer.') self.fail('Could not fetch informations for registered computer.')
class TestMultiMasterSupport(MasterMixin): class TestMultiMasterSupport(MasterMixin):
""" """
Test multimaster support in slapproxy. Test multimaster support in slapproxy.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment