|
|
@@ -35,7 +35,10 @@ from unittest.mock import patch, AsyncMock, Mock |
|
|
|
|
|
|
|
from . import BiteAuth, Board |
|
|
|
|
|
|
|
import argparse |
|
|
|
import asyncio |
|
|
|
import contextlib |
|
|
|
import io |
|
|
|
import os |
|
|
|
import sys |
|
|
|
import unittest |
|
|
@@ -78,14 +81,35 @@ def output_board(brd): |
|
|
|
for i in sorted(brd.attrs): |
|
|
|
print('\t%s\t%s' % (i, repr(brd.attrs[i]))) |
|
|
|
|
|
|
|
def get_sshpubkey(fname): |
|
|
|
raise OSError |
|
|
|
|
|
|
|
async def real_main(): |
|
|
|
baseurl = os.environ['BITELAB_URL'] |
|
|
|
authkey = os.environ['BITELAB_AUTH'] |
|
|
|
|
|
|
|
client = AsyncClient(base_url=baseurl) |
|
|
|
|
|
|
|
parser = argparse.ArgumentParser() |
|
|
|
subparsers = parser.add_subparsers(title='subcommands', |
|
|
|
dest='subparser_name', |
|
|
|
description='valid subcommands', help='additional help') |
|
|
|
|
|
|
|
parse_list = subparsers.add_parser('list', help='list available board classes') |
|
|
|
|
|
|
|
parser_reserve = subparsers.add_parser('reserve', aliases=[ 'release' ], help='reserve/release a board') |
|
|
|
parser_reserve.add_argument('-i', metavar='identity_file', type=str, help='file name for ssh public key') |
|
|
|
parser_reserve.add_argument('board', type=str, help='name of the board or class') |
|
|
|
|
|
|
|
parser_set = subparsers.add_parser('set', help='set attributes on a board') |
|
|
|
parser_set.add_argument('setvars', type=str, nargs='+', help='name of the board or class') |
|
|
|
parser_set.add_argument('board', type=str, help='name of the board or class') |
|
|
|
|
|
|
|
args = parser.parse_args() |
|
|
|
#print(repr(args), file=sys.stderr) |
|
|
|
|
|
|
|
try: |
|
|
|
if sys.argv[1] == 'list': |
|
|
|
if args.subparser_name == 'list': |
|
|
|
res = await client.get('board/classes', |
|
|
|
auth=BiteAuth(authkey), **_httpxargs) |
|
|
|
|
|
|
@@ -96,18 +120,21 @@ async def real_main(): |
|
|
|
print('\t' + i) |
|
|
|
|
|
|
|
res.close() |
|
|
|
elif sys.argv[1] in ('reserve', 'release'): |
|
|
|
elif args.subparser_name in ('reserve', 'release'): |
|
|
|
kwargs = _httpxargs.copy() |
|
|
|
with contextlib.suppress(OSError): |
|
|
|
kwargs['json'] = dict(sshpubkey=get_sshpubkey(args.i)) |
|
|
|
res = await client.post('board/%s/%s' % |
|
|
|
(urllib.parse.quote(sys.argv[2], safe=''), |
|
|
|
sys.argv[1]), |
|
|
|
auth=BiteAuth(authkey), **_httpxargs) |
|
|
|
(urllib.parse.quote(args.board, safe=''), |
|
|
|
args.subparser_name), |
|
|
|
auth=BiteAuth(authkey), **kwargs) |
|
|
|
|
|
|
|
check_res_code(res) |
|
|
|
|
|
|
|
brd = Board.parse_obj(res.json()) |
|
|
|
output_board(brd) |
|
|
|
|
|
|
|
elif sys.argv[1] == 'set': |
|
|
|
elif args.subparser_name == 'set': |
|
|
|
board_id = sys.argv[-1] |
|
|
|
res = await client.post('board/%s/attrs' % |
|
|
|
urllib.parse.quote(board_id, safe=''), |
|
|
@@ -202,8 +229,44 @@ class TestClient(unittest.TestCase): |
|
|
|
|
|
|
|
# XXX - add error cases for UI |
|
|
|
|
|
|
|
@patch('bitelab.__main__.get_sshpubkey') |
|
|
|
@patch.dict(sys.__dict__, dict(argv=[ '', 'reserve', 'cora-z7s' ])) |
|
|
|
def test_reserve(self): |
|
|
|
def test_reserve(self, gspk): |
|
|
|
gspk.side_effect = OSError() |
|
|
|
ac = self.ac |
|
|
|
acp = self.acp |
|
|
|
acp.return_value.status_code = HTTP_200_OK |
|
|
|
acp.return_value.json.return_value = Board(name='cora-1', |
|
|
|
brdclass='cora-z7s', reserved=True, |
|
|
|
attrs={ |
|
|
|
'ip': '172.20.20.5', |
|
|
|
'power': False, |
|
|
|
}).dict() |
|
|
|
|
|
|
|
keydata = 'randomkeydata' |
|
|
|
|
|
|
|
ret, stdout = self.runMain() |
|
|
|
|
|
|
|
output = '''Name:\tcora-1 |
|
|
|
Class:\tcora-z7s |
|
|
|
Attributes: |
|
|
|
\tip\t'172.20.20.5' |
|
|
|
\tpower\tFalse |
|
|
|
''' |
|
|
|
|
|
|
|
self.assertEqual(ret, 0) |
|
|
|
self.assertEqual(stdout, output) |
|
|
|
|
|
|
|
ac.assert_called_with(base_url='http://someserver/') |
|
|
|
|
|
|
|
#args = { 'sshpubkey': keydata } |
|
|
|
acp.assert_called_with('board/cora-z7s/reserve', |
|
|
|
#json=args, |
|
|
|
auth=BiteAuth('thisisanapikey'), **_httpxargs) |
|
|
|
|
|
|
|
@patch('bitelab.__main__.get_sshpubkey') |
|
|
|
@patch.dict(sys.__dict__, dict(argv=[ '', 'reserve', '-i', 'fixtures/testsshkey.pub', 'cora-z7s' ])) |
|
|
|
def test_reserve_ssh(self, gspk): |
|
|
|
ac = self.ac |
|
|
|
acp = self.acp |
|
|
|
acp.return_value.status_code = HTTP_200_OK |
|
|
@@ -214,6 +277,9 @@ class TestClient(unittest.TestCase): |
|
|
|
'power': False, |
|
|
|
}).dict() |
|
|
|
|
|
|
|
keydata = 'keydata' |
|
|
|
gspk.return_value = keydata |
|
|
|
|
|
|
|
ret, stdout = self.runMain() |
|
|
|
|
|
|
|
output = '''Name:\tcora-1 |
|
|
@@ -228,7 +294,9 @@ Attributes: |
|
|
|
|
|
|
|
ac.assert_called_with(base_url='http://someserver/') |
|
|
|
|
|
|
|
acp.assert_called_with('board/cora-z7s/reserve', auth=BiteAuth('thisisanapikey'), **_httpxargs) |
|
|
|
acp.assert_called_with('board/cora-z7s/reserve', |
|
|
|
json=dict(sshpubkey=keydata), |
|
|
|
auth=BiteAuth('thisisanapikey'), **_httpxargs) |
|
|
|
|
|
|
|
@patch.dict(sys.__dict__, dict(argv=[ '', 'release', 'cora-z7s' ])) |
|
|
|
def test_release(self): |
|
|
@@ -257,7 +325,8 @@ Attributes: |
|
|
|
acp.assert_called_with('board/cora-z7s/release', |
|
|
|
auth=BiteAuth('thisisanapikey'), **_httpxargs) |
|
|
|
|
|
|
|
@patch.dict(sys.__dict__, dict(argv=[ '', 'set', 'power=on', 'cora-z7s' ])) |
|
|
|
@patch('bitelab.__main__._typeconv', dict(power=makebool, other=makebool)) |
|
|
|
@patch.dict(sys.__dict__, dict(argv=[ '', 'set', 'power=on', 'other=off', 'cora-z7s' ])) |
|
|
|
def test_set(self): |
|
|
|
ac = self.ac |
|
|
|
acp = self.acp |
|
|
@@ -284,7 +353,7 @@ Attributes: |
|
|
|
ac.assert_called_with(base_url='http://someserver/') |
|
|
|
|
|
|
|
acp.assert_called_with('board/cora-z7s/attrs', |
|
|
|
auth=BiteAuth('thisisanapikey'), json=dict(power=True), |
|
|
|
auth=BiteAuth('thisisanapikey'), json=dict(power=True, other=False), |
|
|
|
**_httpxargs) |
|
|
|
|
|
|
|
def test_make_attrs(self): |
|
|
|