diff --git a/bitelab/__init__.py b/bitelab/__init__.py index f2ac26f..ca56147 100644 --- a/bitelab/__init__.py +++ b/bitelab/__init__.py @@ -320,7 +320,7 @@ class BoardImpl: self.setupscript = setupscript self.options = options self.reserved = False - self.user = None + self._user = None self.attrmap = {} self.lock = asyncio.Lock() for i in options: @@ -364,7 +364,7 @@ class BoardImpl: self.add_info(json.loads(stdout)) - self.user = user + self._user = user self.reserved = True await self.activate() @@ -400,6 +400,7 @@ class BoardImpl: self.clean_info() + self._user = None self.reserved = False async def update_attrs(self, **attrs): @@ -470,6 +471,10 @@ class BoardImpl: for i in set(self.attrcache) - set(self.attrmap): del self.attrcache[i] + @property + def user(self): + return self._user + @property def attrs(self): return dict(self.attrcache) @@ -597,11 +602,6 @@ def get_data(settings: config.Settings = Depends(get_settings)): async def real_get_boardmanager(settings, data): brdmgr = BoardManager.from_settings(settings) - # Clean up the database - # XXX - This isn't a complete fix, we need a better solution. - all = await data.BoardStatus.objects.all() - await asyncio.gather(*(x.delete() for x in all)) - return brdmgr _global_lock = asyncio.Lock() @@ -647,18 +647,16 @@ async def validate_board_params(board_id, data, brdmgr, user=None, token=None): if user is None: user = await lookup_user(token, data) - try: - brduser = await data.BoardStatus.objects.get(board=board_id) - except orm.exceptions.NoMatch: + if brd.user is None: raise BITEError( status_code=HTTP_400_BAD_REQUEST, errobj=Error(error='Board not reserved.', board=Board.from_orm(brd))) - if user != brduser.user: + if user != brd.user: raise BITEError( status_code=HTTP_403_FORBIDDEN, - errobj=Error(error='Board reserved by %s.' % repr(brduser.user), + errobj=Error(error='Board reserved by %s.' % repr(brd.user), board=Board.from_orm(brd))) yield brd @@ -725,18 +723,7 @@ async def reserve_board(board_id_or_class, brd = brdmgr.boards[board_id] async with brd.lock: - try: - obrdreq = await data.BoardStatus.objects.create(board=board_id, - user=user) - # XXX - There is a bug in orm where the returned - # object has an incorrect board value - # see: https://github.com/encode/orm/issues/47 - #assert obrdreq.board == board_id and \ - # obrdreq.user == user - brdreq = await data.BoardStatus.objects.get(board=board_id, - user=user) - # XXX - orm isn't doing it's job here - except sqlite3.IntegrityError: + if brd.user is not None: raise BITEError( status_code=HTTP_409_CONFLICT, errobj=Error(error='Board currently reserved.', @@ -747,7 +734,6 @@ async def reserve_board(board_id_or_class, try: await brd.reserve(user, sshpubkey) except Exception as e: - await brdreq.delete() if isinstance(e, RuntimeError): retcode, stderr = e.args raise BITEError( @@ -890,21 +876,19 @@ async def release_board(board_id, user: str = Depends(lookup_user), # XXX - how to handle a release error? await log_event('release', user=user, board=brd) - try: - brduser = await data.BoardStatus.objects.get(board=board_id) - if user != brduser.user: - raise BITEError( - status_code=HTTP_403_FORBIDDEN, - errobj=Error(error='Board reserved by %s.' % repr(brduser.user), - board=Board.from_orm(brd))) - - except orm.exceptions.NoMatch: + if brd.user is None: raise BITEError( status_code=HTTP_400_BAD_REQUEST, errobj=Error(error='Board not reserved.', board=Board.from_orm(brd)), ) + if user != brd.user: + raise BITEError( + status_code=HTTP_403_FORBIDDEN, + errobj=Error(error='Board reserved by %s.' % repr(brd.user), + board=Board.from_orm(brd))) + try: await brd.release() except RuntimeError as e: @@ -914,8 +898,6 @@ async def release_board(board_id, user: str = Depends(lookup_user), board=Board.from_orm(brd)), ) - await data.BoardStatus.delete(brduser) - await brd.update() return brd @@ -1040,9 +1022,16 @@ class TestWebSocket(TestCommon): shutil.rmtree(self.basetempdir) self.basetempdir = None + @patch('bitelab.snmp.snmpset') + @patch('bitelab.snmp.snmpget') @patch('asyncio.create_subprocess_exec') @timeout(2) - async def test_exec_sshd(self, cse): + async def test_exec_sshd(self, cse, sg, ss): + + # that snmpget and snmpset returns False + sg.return_value = False + ss.return_value = False + def wrapper(corofun): async def foo(*args, **kwargs): r = await corofun(*args, **kwargs) @@ -1077,8 +1066,6 @@ class TestWebSocket(TestCommon): # that when the board is reserved by the wrong user wrap_subprocess_exec(cse, stdout=b'{}', retcode=0) brd = self.brdmgr.boards['cora-1'] - obrdreq = await self.data.BoardStatus.objects.create( - board='cora-1', user='bar') async with brd.lock: await brd.reserve('bar') @@ -1086,12 +1073,10 @@ class TestWebSocket(TestCommon): with self.assertRaisesRegex(RuntimeError, 'Board reserved by \'bar\'.'): await client.exec([ 'sshd', '-i' ], stdin=1, stdout=2) - brduser = await self.data.BoardStatus.objects.get(board='cora-1') - obrdreq = await self.data.BoardStatus.delete(brduser) - # that when the board is reserved by the correct user - obrdreq = await self.data.BoardStatus.objects.create( - board='cora-1', user='foo') + async with brd.lock: + await brd.release() + await brd.reserve('foo') echodata = b'somedata' wrap_subprocess_exec(cse, stdout=echodata, retcode=0) @@ -1197,8 +1182,6 @@ class TestBiteLabAPI(TestCommon): attrs = dict(iface='a', ip='b', devfsrule='c') async with brd.lock: await brd.reserve('foo') - obrdreq = await data.BoardStatus.objects.create( - board='cora-1', user='foo') brd.attrcache.update(attrs) # that when the script fails @@ -1214,6 +1197,7 @@ class TestBiteLabAPI(TestCommon): # and returns the correct data info = Error(error='Failed to release board, ret: 1, stderr: b\'error\'', board=Board(name='cora-1', + user='foo', brdclass='cora-z7s', reserved=True, attrs=attrs, @@ -1291,6 +1275,7 @@ class TestBiteLabAPI(TestCommon): # and returns the correct data brdinfo = Board(name='cora-1', + user='foo', brdclass='cora-z7s', reserved=True, attrs=dict(power=False, @@ -1351,6 +1336,7 @@ class TestBiteLabAPI(TestCommon): # and returns the correct data info = { 'name': 'cora-1', + 'user': None, 'brdclass': 'cora-z7s', 'reserved': False, 'attrs': { 'power': False }, @@ -1402,6 +1388,7 @@ class TestBiteLabAPI(TestCommon): info = { 'cora-1': { 'name': 'cora-1', + 'user': None, 'brdclass': 'cora-z7s', 'reserved': False, 'attrs': { 'power': False }, @@ -1426,6 +1413,7 @@ class TestBiteLabAPI(TestCommon): # and returns the correct data info = { 'name': 'cora-1', + 'user': None, 'brdclass': 'cora-z7s', 'reserved': False, 'attrs': { 'power': True }, @@ -1465,8 +1453,6 @@ class TestBiteLabAPI(TestCommon): brd = self.brdmgr.boards['cora-1'] async with brd.lock: await brd.reserve('foo') - obrdreq = await data.BoardStatus.objects.create( - board='cora-1', user='foo') # that setting the board attributes res = await self.client.post('/board/cora-1/attrs', @@ -1483,6 +1469,7 @@ class TestBiteLabAPI(TestCommon): # and returns the correct data info = { 'name': 'cora-1', + 'user': 'foo', 'brdclass': 'cora-z7s', 'reserved': True, 'attrs': { 'power': False }, @@ -1509,6 +1496,7 @@ class TestBiteLabAPI(TestCommon): # and returns the correct data info = { 'name': 'cora-1', + 'user': 'foo', 'brdclass': 'cora-z7s', 'reserved': True, 'attrs': { 'power': True }, diff --git a/bitelab/data.py b/bitelab/data.py index 6d7648c..201d16d 100644 --- a/bitelab/data.py +++ b/bitelab/data.py @@ -53,6 +53,7 @@ class BoardClassInfo(BaseModel): class Board(BaseModel): name: str + user: Optional[str] brdclass: str reserved: bool attrs: Dict[str, Any] = Field(default_factory=dict) @@ -76,15 +77,6 @@ class DataWrapper(object): def make_orm(database): metadata = sqlalchemy.MetaData() - class BoardStatus(orm.Model): - __tablename__ = 'boardstatus' - __database__ = database - __metadata__ = metadata - - board = orm.Text(primary_key=True) - user = orm.Text(index=True) - time_reserved = orm.DateTime(default=lambda: datetime.utcnow()) - class APIKey(orm.Model): __tablename__ = 'apikeys' __database__ = database