Browse Source

drop BoardStatus from the db.. all user is managed by BoardImpl now..

This may come back in the future, but it will be in BoardImpl, and will
contain more state such that a resume will have all the attribute's
current state in addition to checkout and the like.
main
John-Mark Gurney 3 years ago
parent
commit
d89c90ffda
2 changed files with 37 additions and 57 deletions
  1. +36
    -48
      bitelab/__init__.py
  2. +1
    -9
      bitelab/data.py

+ 36
- 48
bitelab/__init__.py View File

@@ -320,7 +320,7 @@ class BoardImpl:
self.setupscript = setupscript self.setupscript = setupscript
self.options = options self.options = options
self.reserved = False self.reserved = False
self.user = None
self._user = None
self.attrmap = {} self.attrmap = {}
self.lock = asyncio.Lock() self.lock = asyncio.Lock()
for i in options: for i in options:
@@ -364,7 +364,7 @@ class BoardImpl:


self.add_info(json.loads(stdout)) self.add_info(json.loads(stdout))


self.user = user
self._user = user
self.reserved = True self.reserved = True


await self.activate() await self.activate()
@@ -400,6 +400,7 @@ class BoardImpl:


self.clean_info() self.clean_info()


self._user = None
self.reserved = False self.reserved = False


async def update_attrs(self, **attrs): async def update_attrs(self, **attrs):
@@ -470,6 +471,10 @@ class BoardImpl:
for i in set(self.attrcache) - set(self.attrmap): for i in set(self.attrcache) - set(self.attrmap):
del self.attrcache[i] del self.attrcache[i]


@property
def user(self):
return self._user

@property @property
def attrs(self): def attrs(self):
return dict(self.attrcache) return dict(self.attrcache)
@@ -597,11 +602,6 @@ def get_data(settings: config.Settings = Depends(get_settings)):
async def real_get_boardmanager(settings, data): async def real_get_boardmanager(settings, data):
brdmgr = BoardManager.from_settings(settings) 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 return brdmgr


_global_lock = asyncio.Lock() _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: if user is None:
user = await lookup_user(token, data) 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( raise BITEError(
status_code=HTTP_400_BAD_REQUEST, status_code=HTTP_400_BAD_REQUEST,
errobj=Error(error='Board not reserved.', errobj=Error(error='Board not reserved.',
board=Board.from_orm(brd))) board=Board.from_orm(brd)))


if user != brduser.user:
if user != brd.user:
raise BITEError( raise BITEError(
status_code=HTTP_403_FORBIDDEN, 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))) board=Board.from_orm(brd)))


yield brd yield brd
@@ -725,18 +723,7 @@ async def reserve_board(board_id_or_class,
brd = brdmgr.boards[board_id] brd = brdmgr.boards[board_id]


async with brd.lock: 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( raise BITEError(
status_code=HTTP_409_CONFLICT, status_code=HTTP_409_CONFLICT,
errobj=Error(error='Board currently reserved.', errobj=Error(error='Board currently reserved.',
@@ -747,7 +734,6 @@ async def reserve_board(board_id_or_class,
try: try:
await brd.reserve(user, sshpubkey) await brd.reserve(user, sshpubkey)
except Exception as e: except Exception as e:
await brdreq.delete()
if isinstance(e, RuntimeError): if isinstance(e, RuntimeError):
retcode, stderr = e.args retcode, stderr = e.args
raise BITEError( raise BITEError(
@@ -890,21 +876,19 @@ async def release_board(board_id, user: str = Depends(lookup_user),
# XXX - how to handle a release error? # XXX - how to handle a release error?
await log_event('release', user=user, board=brd) 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( raise BITEError(
status_code=HTTP_400_BAD_REQUEST, status_code=HTTP_400_BAD_REQUEST,
errobj=Error(error='Board not reserved.', errobj=Error(error='Board not reserved.',
board=Board.from_orm(brd)), 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: try:
await brd.release() await brd.release()
except RuntimeError as e: except RuntimeError as e:
@@ -914,8 +898,6 @@ async def release_board(board_id, user: str = Depends(lookup_user),
board=Board.from_orm(brd)), board=Board.from_orm(brd)),
) )


await data.BoardStatus.delete(brduser)

await brd.update() await brd.update()


return brd return brd
@@ -1040,9 +1022,16 @@ class TestWebSocket(TestCommon):
shutil.rmtree(self.basetempdir) shutil.rmtree(self.basetempdir)
self.basetempdir = None self.basetempdir = None


@patch('bitelab.snmp.snmpset')
@patch('bitelab.snmp.snmpget')
@patch('asyncio.create_subprocess_exec') @patch('asyncio.create_subprocess_exec')
@timeout(2) @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): def wrapper(corofun):
async def foo(*args, **kwargs): async def foo(*args, **kwargs):
r = await corofun(*args, **kwargs) r = await corofun(*args, **kwargs)
@@ -1077,8 +1066,6 @@ class TestWebSocket(TestCommon):
# that when the board is reserved by the wrong user # that when the board is reserved by the wrong user
wrap_subprocess_exec(cse, stdout=b'{}', retcode=0) wrap_subprocess_exec(cse, stdout=b'{}', retcode=0)
brd = self.brdmgr.boards['cora-1'] brd = self.brdmgr.boards['cora-1']
obrdreq = await self.data.BoardStatus.objects.create(
board='cora-1', user='bar')
async with brd.lock: async with brd.lock:
await brd.reserve('bar') await brd.reserve('bar')


@@ -1086,12 +1073,10 @@ class TestWebSocket(TestCommon):
with self.assertRaisesRegex(RuntimeError, 'Board reserved by \'bar\'.'): with self.assertRaisesRegex(RuntimeError, 'Board reserved by \'bar\'.'):
await client.exec([ 'sshd', '-i' ], stdin=1, stdout=2) 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 # 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' echodata = b'somedata'
wrap_subprocess_exec(cse, stdout=echodata, retcode=0) wrap_subprocess_exec(cse, stdout=echodata, retcode=0)
@@ -1197,8 +1182,6 @@ class TestBiteLabAPI(TestCommon):
attrs = dict(iface='a', ip='b', devfsrule='c') attrs = dict(iface='a', ip='b', devfsrule='c')
async with brd.lock: async with brd.lock:
await brd.reserve('foo') await brd.reserve('foo')
obrdreq = await data.BoardStatus.objects.create(
board='cora-1', user='foo')
brd.attrcache.update(attrs) brd.attrcache.update(attrs)


# that when the script fails # that when the script fails
@@ -1214,6 +1197,7 @@ class TestBiteLabAPI(TestCommon):
# and returns the correct data # and returns the correct data
info = Error(error='Failed to release board, ret: 1, stderr: b\'error\'', info = Error(error='Failed to release board, ret: 1, stderr: b\'error\'',
board=Board(name='cora-1', board=Board(name='cora-1',
user='foo',
brdclass='cora-z7s', brdclass='cora-z7s',
reserved=True, reserved=True,
attrs=attrs, attrs=attrs,
@@ -1291,6 +1275,7 @@ class TestBiteLabAPI(TestCommon):


# and returns the correct data # and returns the correct data
brdinfo = Board(name='cora-1', brdinfo = Board(name='cora-1',
user='foo',
brdclass='cora-z7s', brdclass='cora-z7s',
reserved=True, reserved=True,
attrs=dict(power=False, attrs=dict(power=False,
@@ -1351,6 +1336,7 @@ class TestBiteLabAPI(TestCommon):
# and returns the correct data # and returns the correct data
info = { info = {
'name': 'cora-1', 'name': 'cora-1',
'user': None,
'brdclass': 'cora-z7s', 'brdclass': 'cora-z7s',
'reserved': False, 'reserved': False,
'attrs': { 'power': False }, 'attrs': { 'power': False },
@@ -1402,6 +1388,7 @@ class TestBiteLabAPI(TestCommon):
info = { info = {
'cora-1': { 'cora-1': {
'name': 'cora-1', 'name': 'cora-1',
'user': None,
'brdclass': 'cora-z7s', 'brdclass': 'cora-z7s',
'reserved': False, 'reserved': False,
'attrs': { 'power': False }, 'attrs': { 'power': False },
@@ -1426,6 +1413,7 @@ class TestBiteLabAPI(TestCommon):
# and returns the correct data # and returns the correct data
info = { info = {
'name': 'cora-1', 'name': 'cora-1',
'user': None,
'brdclass': 'cora-z7s', 'brdclass': 'cora-z7s',
'reserved': False, 'reserved': False,
'attrs': { 'power': True }, 'attrs': { 'power': True },
@@ -1465,8 +1453,6 @@ class TestBiteLabAPI(TestCommon):
brd = self.brdmgr.boards['cora-1'] brd = self.brdmgr.boards['cora-1']
async with brd.lock: async with brd.lock:
await brd.reserve('foo') await brd.reserve('foo')
obrdreq = await data.BoardStatus.objects.create(
board='cora-1', user='foo')


# that setting the board attributes # that setting the board attributes
res = await self.client.post('/board/cora-1/attrs', res = await self.client.post('/board/cora-1/attrs',
@@ -1483,6 +1469,7 @@ class TestBiteLabAPI(TestCommon):
# and returns the correct data # and returns the correct data
info = { info = {
'name': 'cora-1', 'name': 'cora-1',
'user': 'foo',
'brdclass': 'cora-z7s', 'brdclass': 'cora-z7s',
'reserved': True, 'reserved': True,
'attrs': { 'power': False }, 'attrs': { 'power': False },
@@ -1509,6 +1496,7 @@ class TestBiteLabAPI(TestCommon):
# and returns the correct data # and returns the correct data
info = { info = {
'name': 'cora-1', 'name': 'cora-1',
'user': 'foo',
'brdclass': 'cora-z7s', 'brdclass': 'cora-z7s',
'reserved': True, 'reserved': True,
'attrs': { 'power': True }, 'attrs': { 'power': True },


+ 1
- 9
bitelab/data.py View File

@@ -53,6 +53,7 @@ class BoardClassInfo(BaseModel):


class Board(BaseModel): class Board(BaseModel):
name: str name: str
user: Optional[str]
brdclass: str brdclass: str
reserved: bool reserved: bool
attrs: Dict[str, Any] = Field(default_factory=dict) attrs: Dict[str, Any] = Field(default_factory=dict)
@@ -76,15 +77,6 @@ class DataWrapper(object):
def make_orm(database): def make_orm(database):
metadata = sqlalchemy.MetaData() 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): class APIKey(orm.Model):
__tablename__ = 'apikeys' __tablename__ = 'apikeys'
__database__ = database __database__ = database


Loading…
Cancel
Save