| @@ -50,6 +50,7 @@ from .mocks import * | |||||
| import asyncio | import asyncio | ||||
| import contextlib | import contextlib | ||||
| import json | import json | ||||
| import logging | |||||
| import orm | import orm | ||||
| import os | import os | ||||
| import socket | import socket | ||||
| @@ -356,8 +357,18 @@ async def release_board(board_id, user: str = Depends(lookup_user), | |||||
| settings.setup_script, 'release', brd.name, user, | settings.setup_script, 'release', brd.name, user, | ||||
| stdout=subprocess.PIPE, stderr=subprocess.PIPE) | stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||||
| stdout, stderr = await sub.communicate() | stdout, stderr = await sub.communicate() | ||||
| if sub.returncode: | |||||
| raise RuntimeError(sub.returncode, stderr) | |||||
| retcode = sub.returncode | |||||
| if retcode: | |||||
| logging.error('release script failure: ' + | |||||
| 'board: %s, ret: %s, stderr: %s' % (repr(brd.name), | |||||
| retcode, repr(stderr))) | |||||
| raise BITEError( | |||||
| status_code=HTTP_500_INTERNAL_SERVER_ERROR, | |||||
| errobj=Error(error= | |||||
| 'Failed to release board, ret: %d, stderr: %s' % | |||||
| (retcode, repr(stderr)), | |||||
| board=Board.from_orm(brd)), | |||||
| ) | |||||
| await data.BoardStatus.delete(brduser) | await data.BoardStatus.delete(brduser) | ||||
| await brd.release() | await brd.release() | ||||
| @@ -509,6 +520,47 @@ class TestBiteLab(unittest.IsolatedAsyncioTestCase): | |||||
| self.assertEqual(res.json(), { 'cora-z7s': BoardClassInfo(**{ | self.assertEqual(res.json(), { 'cora-z7s': BoardClassInfo(**{ | ||||
| 'arch': 'arm-armv7', 'clsname': 'cora-z7s', }) }) | 'arch': 'arm-armv7', 'clsname': 'cora-z7s', }) }) | ||||
| @patch('asyncio.create_subprocess_exec') | |||||
| @patch('bitelab.snmp.snmpget') | |||||
| @patch('logging.error') | |||||
| async def test_board_release_script_fail(self, le, sg, cse): | |||||
| # that when snmpget returns False | |||||
| sg.return_value = False | |||||
| # that when the setup script will fail | |||||
| wrap_subprocess_exec(cse, stderr=b'error', retcode=1) | |||||
| # that the cora-1 board is reserved | |||||
| data = self.data | |||||
| brd = self.brdmgr.boards['cora-1'] | |||||
| async with brd.lock: | |||||
| await brd.reserve() | |||||
| obrdreq = await data.BoardStatus.objects.create( | |||||
| board='cora-1', user='foo') | |||||
| # that when the correct user releases the board | |||||
| res = await self.client.post('/board/cora-1/release', | |||||
| auth=BiteAuth('thisisanapikey')) | |||||
| # it fails | |||||
| self.assertEqual(res.status_code, HTTP_500_INTERNAL_SERVER_ERROR) | |||||
| # and returns the correct data | |||||
| info = Error(error='Failed to release board, ret: 1, stderr: b\'error\'', | |||||
| board=Board(name='cora-1', | |||||
| brdclass='cora-z7s', | |||||
| reserved=True, | |||||
| ), | |||||
| ).dict() | |||||
| self.assertEqual(res.json(), info) | |||||
| # and that it called the release script | |||||
| cse.assert_called_with(self.settings.setup_script, 'release', | |||||
| 'cora-1', 'foo', stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |||||
| # and that the error got logged | |||||
| le.assert_called_with('release script failure: board: \'cora-1\', ret: 1, stderr: b\'error\'') | |||||
| @patch('asyncio.create_subprocess_exec') | @patch('asyncio.create_subprocess_exec') | ||||
| @patch('bitelab.snmp.snmpget') | @patch('bitelab.snmp.snmpget') | ||||
| async def test_board_reserve_release(self, sg, cse): | async def test_board_reserve_release(self, sg, cse): | ||||