Browse Source

first stages of reworking so that BoardImpl implements all the logic

for reserve/release, relocating this logic out of the API logic.
main
John-Mark Gurney 3 years ago
parent
commit
c372051af2
2 changed files with 58 additions and 10 deletions
  1. +57
    -9
      bitelab/__init__.py
  2. +1
    -1
      bitelab/testing.py

+ 57
- 9
bitelab/__init__.py View File

@@ -235,6 +235,15 @@ class TimeOut(Attribute):
@_tbprinter @_tbprinter
async def timeout_coro(self): async def timeout_coro(self):
async with self._brd.lock: async with self._brd.lock:
# we don't want to cancel ourselves while
# releasing the board, otherwise it'll stop
# in the middle!
#
# Note: not sure if we need to await on the
# task to clean things up though.

self._task = None

await self._brd.release() await self._brd.release()


def timeout_callback(self): def timeout_callback(self):
@@ -280,7 +289,15 @@ class BoardImpl:
be destroyed before the operation completes. be destroyed before the operation completes.
''' '''


def __init__(self, name, brdclass, options):
def __init__(self, name: str, brdclass: str, options):
'''
name: name of the board.
brdclass: class that the board belongs to.
options: list of tuples, the first item of the tuple,
being the factory to call, and the second item, the
keyword args to use when calling the factory.
'''

self.name = name self.name = name
self.brdclass = brdclass self.brdclass = brdclass
self.options = options self.options = options
@@ -302,42 +319,72 @@ class BoardImpl:
return repr(Board.from_orm(self)) return repr(Board.from_orm(self))


async def reserve(self): async def reserve(self):
'''Reserve the board.'''

assert self.lock.locked() and not self.reserved assert self.lock.locked() and not self.reserved


self.reserved = True self.reserved = True


await self.activate()

async def release(self): async def release(self):
'''Release the board.'''

assert self.lock.locked() and self.reserved assert self.lock.locked() and self.reserved


await self.deactivate()

self.reserved = False self.reserved = False


async def update_attrs(self, **attrs): async def update_attrs(self, **attrs):
'''Set the various attrs that are specified.'''

assert self.lock.locked() and self.reserved assert self.lock.locked() and self.reserved


for i in attrs: for i in attrs:
self.attrcache[i] = await self.attrmap[i].setvalue(attrs[i]) self.attrcache[i] = await self.attrmap[i].setvalue(attrs[i])


async def update(self): async def update(self):
'''Update the attr cache w/ current values.'''

for i in self.attrmap: for i in self.attrmap:
self.attrcache[i] = await self.attrmap[i].getvalue() self.attrcache[i] = await self.attrmap[i].getvalue()


async def activate(self): async def activate(self):
'''Activate the attributes. This means that the board
has been reserved. This is for things like adding an
ethernet interface to the jail's vnet, or starting the
timeout.'''

assert self.lock.locked() and self.reserved assert self.lock.locked() and self.reserved


for i in self.attrmap.values(): for i in self.attrmap.values():
await i.activate(self) await i.activate(self)


async def deactivate(self): async def deactivate(self):
'''Deactivate the attributes. This should be called
just before release. This is to clean up anything like
scheduled tasks.'''

assert self.lock.locked() and self.reserved assert self.lock.locked() and self.reserved


for i in self.attrmap.values(): for i in self.attrmap.values():
await i.deactivate(self) await i.deactivate(self)


def add_info(self, d): def add_info(self, d):
'''Add some additional data that will be returned for
the current reservation. All the data added here will
be removed when the board is deactivated, by clean_info.
'''

self.attrcache.update(d) self.attrcache.update(d)


def clean_info(self): def clean_info(self):
# clean up attributes
'''Remove any attributes that aren't in the attrmap.

This is to clean up after the add_info call.
'''

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]


@@ -1007,7 +1054,7 @@ class TestWebSocket(TestCommon):
# IsolatedAsyncioTestCase was added. The tearDown has to happen # IsolatedAsyncioTestCase was added. The tearDown has to happen
# with the event loop running, otherwise the task and other things # with the event loop running, otherwise the task and other things
# do not get cleaned up properly. # do not get cleaned up properly.
class TestBiteLab(TestCommon):
class TestBiteLabAPI(TestCommon):
async def asyncSetUp(self): async def asyncSetUp(self):
await super().asyncSetUp() await super().asyncSetUp()


@@ -1059,7 +1106,7 @@ class TestBiteLab(TestCommon):
# that when the setup script will fail # that when the setup script will fail
wrap_subprocess_exec(cse, stderr=b'error', retcode=1) wrap_subprocess_exec(cse, stderr=b'error', retcode=1)


# that the cora-1 board is reserved
# and that the cora-1 board is reserved
data = self.data data = self.data
brd = self.brdmgr.boards['cora-1'] brd = self.brdmgr.boards['cora-1']
attrs = dict(iface='a', ip='b', devfsrule='c') attrs = dict(iface='a', ip='b', devfsrule='c')
@@ -1377,6 +1424,11 @@ class TestBiteLab(TestCommon):
self.assertEqual(res.json(), info) self.assertEqual(res.json(), info)


class TestBoardImpl(unittest.IsolatedAsyncioTestCase): class TestBoardImpl(unittest.IsolatedAsyncioTestCase):
async def xtest_reserve(self):
# that when the board is reserved
async with brd.lock:
await brd.reserve()

async def test_activate(self): async def test_activate(self):
# that a board impl # that a board impl
opttup = create_autospec, dict(spec=Attribute) opttup = create_autospec, dict(spec=Attribute)
@@ -1385,7 +1437,6 @@ class TestBoardImpl(unittest.IsolatedAsyncioTestCase):


async with brd.lock: async with brd.lock:
await brd.reserve() await brd.reserve()
await brd.activate()


opt.activate.assert_called_with(brd) opt.activate.assert_called_with(brd)


@@ -1397,7 +1448,7 @@ class TestBoardImpl(unittest.IsolatedAsyncioTestCase):


async with brd.lock: async with brd.lock:
await brd.reserve() await brd.reserve()
await brd.deactivate()
await brd.release()


opt.deactivate.assert_called_with(brd) opt.deactivate.assert_called_with(brd)


@@ -1625,7 +1676,6 @@ class TestAttrs(unittest.IsolatedAsyncioTestCase):
# that when reserved/activated # that when reserved/activated
async with brd.lock: async with brd.lock:
await brd.reserve() await brd.reserve()
await brd.activate()


evt = asyncio.Event() evt = asyncio.Event()
loop = asyncio.get_running_loop() loop = asyncio.get_running_loop()
@@ -1638,9 +1688,7 @@ class TestAttrs(unittest.IsolatedAsyncioTestCase):
# that when reserved/activated/deactivated/released # that when reserved/activated/deactivated/released
async with brd.lock: async with brd.lock:
await brd.reserve() await brd.reserve()
await brd.activate()
exp = to._exp exp = to._exp
await brd.deactivate()
await brd.release() await brd.release()


# that the expiration is no longer there # that the expiration is no longer there


+ 1
- 1
bitelab/testing.py View File

@@ -30,6 +30,6 @@


from .snmp import TestSNMPPower, TestSNMPWrapper from .snmp import TestSNMPPower, TestSNMPWrapper
from .data import TestDatabase from .data import TestDatabase
from . import TestBiteLab, TestUnhashLRU, TestAttrs, TestBoardImpl
from . import TestBiteLabAPI, TestUnhashLRU, TestAttrs, TestBoardImpl
from . import TestWebSocket, TestLogEvent from . import TestWebSocket, TestLogEvent
from .__main__ import TestClient, TestExecClient from .__main__ import TestClient, TestExecClient

Loading…
Cancel
Save