Merge branch 'dev' into ui

# Conflicts:
#	app/main.py
This commit is contained in:
Oscar Krause 2023-01-04 11:19:32 +01:00
commit 6ef1216db6
7 changed files with 119 additions and 115 deletions

27
.DEBIAN/env.default Normal file
View File

@ -0,0 +1,27 @@
# Toggle debug mode
#DEBUG=false
# Where the client can find the DLS server
DLS_URL=127.0.0.1
DLS_PORT=443
# CORS configuration
## comma separated list without spaces
#CORS_ORIGINS="https://$DLS_URL:$DLS_PORT"
# Lease expiration in days
LEASE_EXPIRE_DAYS=90
LEASE_RENEWAL_PERIOD=0.2
# Database location
## https://docs.sqlalchemy.org/en/14/core/engines.html
DATABASE=sqlite:////etc/fastapi-dls/db.sqlite
# UUIDs for identifying the instance
#SITE_KEY_XID="00000000-0000-0000-0000-000000000000"
#INSTANCE_REF="10000000-0000-0000-0000-000000000001"
#ALLOTMENT_REF="20000000-0000-0000-0000-000000000001"
# Site-wide signing keys
INSTANCE_KEY_RSA=/etc/fastapi-dls/instance.private.pem
INSTANCE_KEY_PUB=/etc/fastapi-dls/instance.public.pem

View File

@ -0,0 +1,25 @@
[Unit]
Description=Service for fastapi-dls
Documentation=https://git.collinwebdesigns.de/oscar.krause/fastapi-dls
After=network.target
[Service]
User=www-data
Group=www-data
AmbientCapabilities=CAP_NET_BIND_SERVICE
WorkingDirectory=/usr/share/fastapi-dls/app
EnvironmentFile=/etc/fastapi-dls/env
ExecStart=uvicorn main:app \
--env-file /etc/fastapi-dls/env \
--host $DLS_URL --port $DLS_PORT \
--app-dir /usr/share/fastapi-dls/app \
--ssl-keyfile /etc/fastapi-dls/webserver.key \
--ssl-certfile /etc/fastapi-dls/webserver.crt \
--proxy-headers
Restart=always
KillSignal=SIGQUIT
Type=simple
NotifyAccess=all
[Install]
WantedBy=multi-user.target

View File

@ -3,89 +3,26 @@
WORKING_DIR=/usr/share/fastapi-dls WORKING_DIR=/usr/share/fastapi-dls
CONFIG_DIR=/etc/fastapi-dls CONFIG_DIR=/etc/fastapi-dls
echo "> Create config directory ..." if [[ ! -f $CONFIG_DIR/instance.private.pem ]]; then
mkdir -p $CONFIG_DIR echo "> Create dls-instance keypair ..."
openssl genrsa -out $CONFIG_DIR/instance.private.pem 2048
# normally we would define services in `conffiles` and as separate file, but we like to keep thinks simple. openssl rsa -in $CONFIG_DIR/instance.private.pem -outform PEM -pubout -out $CONFIG_DIR/instance.public.pem
echo "> Install service ..." else
cat <<EOF >/etc/systemd/system/fastapi-dls.service echo "> Create dls-instance keypair skipped! (exists)"
[Unit]
Description=Service for fastapi-dls
Documentation=https://git.collinwebdesigns.de/oscar.krause/fastapi-dls
After=network.target
[Service]
User=www-data
Group=www-data
AmbientCapabilities=CAP_NET_BIND_SERVICE
WorkingDirectory=$WORKING_DIR/app
EnvironmentFile=$CONFIG_DIR/env
ExecStart=uvicorn main:app \\
--env-file /etc/fastapi-dls/env \\
--host \$DLS_URL --port \$DLS_PORT \\
--app-dir $WORKING_DIR/app \\
--ssl-keyfile /etc/fastapi-dls/webserver.key \\
--ssl-certfile /etc/fastapi-dls/webserver.crt \\
--proxy-headers
Restart=always
KillSignal=SIGQUIT
Type=simple
NotifyAccess=all
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
# normally we would define configfiles in `conffiles` and as separate file, but we like to keep thinks simple.
if [[ ! -f $CONFIG_DIR/env ]]; then
echo "> Writing initial config ..."
touch $CONFIG_DIR/env
cat <<EOF >$CONFIG_DIR/env
# Toggle debug mode
#DEBUG=false
# Where the client can find the DLS server
DLS_URL=127.0.0.1
DLS_PORT=443
# CORS configuration
## comma separated list without spaces
#CORS_ORIGINS="https://$DLS_URL:$DLS_PORT"
# Lease expiration in days
LEASE_EXPIRE_DAYS=90
# Database location
## https://docs.sqlalchemy.org/en/14/core/engines.html
DATABASE=sqlite:///$CONFIG_DIR/db.sqlite
# UUIDs for identifying the instance
#SITE_KEY_XID="00000000-0000-0000-0000-000000000000"
#INSTANCE_REF="00000000-0000-0000-0000-000000000000"
# Site-wide signing keys
INSTANCE_KEY_RSA=$CONFIG_DIR/instance.private.pem
INSTANCE_KEY_PUB=$CONFIG_DIR/instance.public.pem
EOF
fi fi
echo "> Create dls-instance keypair ..."
openssl genrsa -out $CONFIG_DIR/instance.private.pem 2048
openssl rsa -in $CONFIG_DIR/instance.private.pem -outform PEM -pubout -out $CONFIG_DIR/instance.public.pem
while true; do while true; do
read -p "> Do you wish to create self-signed webserver certificate? [Y/n]" yn [[ -f $CONFIG_DIR/webserver.key ]] && default_answer="N" || default_answer="Y"
yn=${yn:-y} # ${parameter:-word} If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted. [[ $default_answer == "Y" ]] && V="Y/n" || V="y/N"
read -p "> Do you wish to create self-signed webserver certificate? [${V}]" yn
yn=${yn:-$default_answer} # ${parameter:-word} If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted.
case $yn in case $yn in
[Yy]*) [Yy]*)
echo "> Generating keypair ..."
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout $CONFIG_DIR/webserver.key -out $CONFIG_DIR/webserver.crt openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout $CONFIG_DIR/webserver.key -out $CONFIG_DIR/webserver.crt
break break
;; ;;
[Nn]*) break ;; [Nn]*) echo "> Generating keypair skipped! (exists)"; break ;;
*) echo "Please answer [y] or [n]." ;; *) echo "Please answer [y] or [n]." ;;
esac esac
done done
@ -115,7 +52,7 @@ cat <<EOF
# Service should be up and running. # # Service should be up and running. #
# Webservice is listen to https://localhost # # Webservice is listen to https://localhost #
# # # #
# Configuration is stored in ${CONFIG_DIR}/env # # Configuration is stored in /etc/fastapi-dls/env. #
# # # #
# # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

View File

@ -47,7 +47,10 @@ build:apt:
- cp README.md version.env build/usr/share/fastapi-dls - cp README.md version.env build/usr/share/fastapi-dls
# create conf file # create conf file
- mkdir -p build/etc/fastapi-dls - mkdir -p build/etc/fastapi-dls
- touch build/etc/fastapi-dls/env - cp .DEBIAN/env.default build/etc/fastapi-dls/env
# create service file
- mkdir -p build/etc/systemd/system
- cp .DEBIAN/fastapi-dls.service build/etc/systemd/system
# cd into "build/" # cd into "build/"
- cd build/ - cd build/
script: script:
@ -143,6 +146,7 @@ test:
--proxy-headers & --proxy-headers &
- FASTAPI_DLS_PID=$! - FASTAPI_DLS_PID=$!
- echo "Started service with pid $FASTAPI_DLS_PID" - echo "Started service with pid $FASTAPI_DLS_PID"
- cat /etc/fastapi-dls/env
# testing service # testing service
- if [ "`curl --insecure -s https://127.0.0.1/-/health | jq .status`" != "up" ]; then echo "Success"; else "Error"; fi - if [ "`curl --insecure -s https://127.0.0.1/-/health | jq .status`" != "up" ]; then echo "Success"; else "Error"; fi
# cleanup # cleanup

View File

@ -109,7 +109,7 @@ Goto [`docker-compose.yml`](docker-compose.yml) for more advanced example.
version: '3.9' version: '3.9'
x-dls-variables: &dls-variables x-dls-variables: &dls-variables
DLS_URL: localhost # REQUIRED DLS_URL: localhost # REQUIRED, change to your ip or hostname
DLS_PORT: 443 DLS_PORT: 443
LEASE_EXPIRE_DAYS: 90 LEASE_EXPIRE_DAYS: 90
DATABASE: sqlite:////app/database/db.sqlite DATABASE: sqlite:////app/database/db.sqlite
@ -290,6 +290,7 @@ After first success you have to replace `--issue` with `--renew`.
| `DEBUG` | `false` | Toggles `fastapi` debug mode | | `DEBUG` | `false` | Toggles `fastapi` debug mode |
| `DLS_URL` | `localhost` | Used in client-token to tell guest driver where dls instance is reachable | | `DLS_URL` | `localhost` | Used in client-token to tell guest driver where dls instance is reachable |
| `DLS_PORT` | `443` | Used in client-token to tell guest driver where dls instance is reachable | | `DLS_PORT` | `443` | Used in client-token to tell guest driver where dls instance is reachable |
| `TOKEN_EXPIRE_DAYS` | `1` | Client auth-token validity (used for authenticate client against api, **not `.tok` file!**) |
| `LEASE_EXPIRE_DAYS` | `90` | Lease time in days | | `LEASE_EXPIRE_DAYS` | `90` | Lease time in days |
| `LEASE_RENEWAL_PERIOD` | `0.15` | The percentage of the lease period that must elapse before a licensed client can renew a license \*1 | | `LEASE_RENEWAL_PERIOD` | `0.15` | The percentage of the lease period that must elapse before a licensed client can renew a license \*1 |
| `DATABASE` | `sqlite:///db.sqlite` | See [official SQLAlchemy docs](https://docs.sqlalchemy.org/en/14/core/engines.html) | | `DATABASE` | `sqlite:///db.sqlite` | See [official SQLAlchemy docs](https://docs.sqlalchemy.org/en/14/core/engines.html) |

View File

@ -6,16 +6,16 @@ from os.path import join, dirname
from os import getenv as env from os import getenv as env
from dotenv import load_dotenv from dotenv import load_dotenv
from fastapi import FastAPI, HTTPException from fastapi import FastAPI
from fastapi.requests import Request from fastapi.requests import Request
import json from json import loads as json_loads
from datetime import datetime from datetime import datetime
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from calendar import timegm from calendar import timegm
from jose import jws, jwk, jwt from jose import jws, jwk, jwt, JWTError
from jose.constants import ALGORITHMS from jose.constants import ALGORITHMS
from starlette.middleware.cors import CORSMiddleware from starlette.middleware.cors import CORSMiddleware
from starlette.responses import StreamingResponse, JSONResponse, Response, RedirectResponse from starlette.responses import StreamingResponse, JSONResponse as JSONr, HTMLResponse as HTMLr, Response, RedirectResponse
from sqlalchemy import create_engine from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import sessionmaker
from starlette.staticfiles import StaticFiles from starlette.staticfiles import StaticFiles
@ -47,7 +47,7 @@ INSTANCE_REF = str(env('INSTANCE_REF', '10000000-0000-0000-0000-000000000001'))
ALLOTMENT_REF = str(env('ALLOTMENT_REF', '20000000-0000-0000-0000-000000000001')) ALLOTMENT_REF = str(env('ALLOTMENT_REF', '20000000-0000-0000-0000-000000000001'))
INSTANCE_KEY_RSA = load_key(str(env('INSTANCE_KEY_RSA', join(dirname(__file__), 'cert/instance.private.pem')))) INSTANCE_KEY_RSA = load_key(str(env('INSTANCE_KEY_RSA', join(dirname(__file__), 'cert/instance.private.pem'))))
INSTANCE_KEY_PUB = load_key(str(env('INSTANCE_KEY_PUB', join(dirname(__file__), 'cert/instance.public.pem')))) INSTANCE_KEY_PUB = load_key(str(env('INSTANCE_KEY_PUB', join(dirname(__file__), 'cert/instance.public.pem'))))
TOKEN_EXPIRE_DELTA = relativedelta(hours=1) # days=1 TOKEN_EXPIRE_DELTA = relativedelta(days=int(env('TOKEN_EXPIRE_DAYS', 1)), hours=int(env('TOKEN_EXPIRE_HOURS', 0)))
LEASE_EXPIRE_DELTA = relativedelta(days=int(env('LEASE_EXPIRE_DAYS', 90)), hours=int(env('LEASE_EXPIRE_HOURS', 0))) LEASE_EXPIRE_DELTA = relativedelta(days=int(env('LEASE_EXPIRE_DAYS', 90)), hours=int(env('LEASE_EXPIRE_HOURS', 0)))
LEASE_RENEWAL_PERIOD = float(env('LEASE_RENEWAL_PERIOD', 0.15)) LEASE_RENEWAL_PERIOD = float(env('LEASE_RENEWAL_PERIOD', 0.15))
CORS_ORIGINS = str(env('CORS_ORIGINS', '')).split(',') if (env('CORS_ORIGINS')) else [f'https://{DLS_URL}'] CORS_ORIGINS = str(env('CORS_ORIGINS', '')).split(',') if (env('CORS_ORIGINS')) else [f'https://{DLS_URL}']
@ -85,12 +85,12 @@ async def _index(request: Request):
@app.get('/-/health', summary='* Health') @app.get('/-/health', summary='* Health')
async def _health(request: Request): async def _health(request: Request):
return JSONResponse({'status': 'up'}) return JSONr({'status': 'up'})
@app.get('/-/config', summary='* Config', description='returns environment variables.') @app.get('/-/config', summary='* Config', description='returns environment variables.')
async def _config(): async def _config():
return JSONResponse({ return JSONr({
'VERSION': str(VERSION), 'VERSION': str(VERSION),
'COMMIT': str(COMMIT), 'COMMIT': str(COMMIT),
'DEBUG': str(DEBUG), 'DEBUG': str(DEBUG),
@ -98,7 +98,7 @@ async def _config():
'DLS_PORT': str(DLS_PORT), 'DLS_PORT': str(DLS_PORT),
'SITE_KEY_XID': str(SITE_KEY_XID), 'SITE_KEY_XID': str(SITE_KEY_XID),
'INSTANCE_REF': str(INSTANCE_REF), 'INSTANCE_REF': str(INSTANCE_REF),
'ALLOTMENT_REF': [ALLOTMENT_REF], 'ALLOTMENT_REF': [str(ALLOTMENT_REF)],
'TOKEN_EXPIRE_DELTA': str(TOKEN_EXPIRE_DELTA), 'TOKEN_EXPIRE_DELTA': str(TOKEN_EXPIRE_DELTA),
'LEASE_EXPIRE_DELTA': str(LEASE_EXPIRE_DELTA), 'LEASE_EXPIRE_DELTA': str(LEASE_EXPIRE_DELTA),
'LEASE_RENEWAL_PERIOD': str(LEASE_RENEWAL_PERIOD), 'LEASE_RENEWAL_PERIOD': str(LEASE_RENEWAL_PERIOD),
@ -146,7 +146,7 @@ async def _origins(request: Request, leases: bool = False):
x['leases'] = list(map(lambda _: _.serialize(), Lease.find_by_origin_ref(db, origin.origin_ref))) x['leases'] = list(map(lambda _: _.serialize(), Lease.find_by_origin_ref(db, origin.origin_ref)))
response.append(x) response.append(x)
session.close() session.close()
return JSONResponse(response) return JSONr(response)
@app.delete('/-/origins', summary='* Origins') @app.delete('/-/origins', summary='* Origins')
@ -159,7 +159,7 @@ async def _origins_delete(request: Request):
async def _origins_delete_origin_ref(request: Request, origin_ref: str): async def _origins_delete_origin_ref(request: Request, origin_ref: str):
if Origin.delete(db, origin_ref) == 1: if Origin.delete(db, origin_ref) == 1:
return Response(status_code=201) return Response(status_code=201)
raise JSONResponse(status_code=404, content={'status': 404, 'detail': 'lease not found'}) raise JSONr(status_code=404, content={'status': 404, 'detail': 'lease not found'})
@app.get('/-/leases', summary='* Leases') @app.get('/-/leases', summary='* Leases')
@ -173,14 +173,14 @@ async def _leases(request: Request, origin: bool = False):
x['origin'] = session.query(Origin).filter(Origin.origin_ref == lease.origin_ref).first().serialize() x['origin'] = session.query(Origin).filter(Origin.origin_ref == lease.origin_ref).first().serialize()
response.append(x) response.append(x)
session.close() session.close()
return JSONResponse(response) return JSONr(response)
@app.delete('/-/lease/{lease_ref}', summary='* Lease') @app.delete('/-/lease/{lease_ref}', summary='* Lease')
async def _lease_delete(request: Request, lease_ref: str): async def _lease_delete(request: Request, lease_ref: str):
if Lease.delete(db, lease_ref) == 1: if Lease.delete(db, lease_ref) == 1:
return Response(status_code=201) return Response(status_code=201)
raise HTTPException(status_code=404, detail='lease not found') return JSONr(status_code=404, content={'status': 404, 'detail': 'lease not found'})
# venv/lib/python3.9/site-packages/nls_core_service_instance/service_instance_token_manager.py # venv/lib/python3.9/site-packages/nls_core_service_instance/service_instance_token_manager.py
@ -232,7 +232,7 @@ async def _client_token():
# venv/lib/python3.9/site-packages/nls_services_auth/test/test_origins_controller.py # venv/lib/python3.9/site-packages/nls_services_auth/test/test_origins_controller.py
@app.post('/auth/v1/origin', description='find or create an origin') @app.post('/auth/v1/origin', description='find or create an origin')
async def auth_v1_origin(request: Request): async def auth_v1_origin(request: Request):
j, cur_time = json.loads((await request.body()).decode('utf-8')), datetime.utcnow() j, cur_time = json_loads((await request.body()).decode('utf-8')), datetime.utcnow()
origin_ref = j.get('candidate_origin_ref') origin_ref = j.get('candidate_origin_ref')
logging.info(f'> [ origin ]: {origin_ref}: {j}') logging.info(f'> [ origin ]: {origin_ref}: {j}')
@ -256,13 +256,13 @@ async def auth_v1_origin(request: Request):
"sync_timestamp": cur_time.isoformat() "sync_timestamp": cur_time.isoformat()
} }
return JSONResponse(response) return JSONr(response)
# venv/lib/python3.9/site-packages/nls_services_auth/test/test_origins_controller.py # venv/lib/python3.9/site-packages/nls_services_auth/test/test_origins_controller.py
@app.post('/auth/v1/origin/update', description='update an origin evidence') @app.post('/auth/v1/origin/update', description='update an origin evidence')
async def auth_v1_origin_update(request: Request): async def auth_v1_origin_update(request: Request):
j, cur_time = json.loads((await request.body()).decode('utf-8')), datetime.utcnow() j, cur_time = json_loads((await request.body()).decode('utf-8')), datetime.utcnow()
origin_ref = j.get('origin_ref') origin_ref = j.get('origin_ref')
logging.info(f'> [ update ]: {origin_ref}: {j}') logging.info(f'> [ update ]: {origin_ref}: {j}')
@ -282,14 +282,14 @@ async def auth_v1_origin_update(request: Request):
"sync_timestamp": cur_time.isoformat() "sync_timestamp": cur_time.isoformat()
} }
return JSONResponse(response) return JSONr(response)
# venv/lib/python3.9/site-packages/nls_services_auth/test/test_auth_controller.py # venv/lib/python3.9/site-packages/nls_services_auth/test/test_auth_controller.py
# venv/lib/python3.9/site-packages/nls_core_auth/auth.py - CodeResponse # venv/lib/python3.9/site-packages/nls_core_auth/auth.py - CodeResponse
@app.post('/auth/v1/code', description='get an authorization code') @app.post('/auth/v1/code', description='get an authorization code')
async def auth_v1_code(request: Request): async def auth_v1_code(request: Request):
j, cur_time = json.loads((await request.body()).decode('utf-8')), datetime.utcnow() j, cur_time = json_loads((await request.body()).decode('utf-8')), datetime.utcnow()
origin_ref = j.get('origin_ref') origin_ref = j.get('origin_ref')
logging.info(f'> [ code ]: {origin_ref}: {j}') logging.info(f'> [ code ]: {origin_ref}: {j}')
@ -314,22 +314,27 @@ async def auth_v1_code(request: Request):
"prompts": None "prompts": None
} }
return JSONResponse(response) return JSONr(response)
# venv/lib/python3.9/site-packages/nls_services_auth/test/test_auth_controller.py # venv/lib/python3.9/site-packages/nls_services_auth/test/test_auth_controller.py
# venv/lib/python3.9/site-packages/nls_core_auth/auth.py - TokenResponse # venv/lib/python3.9/site-packages/nls_core_auth/auth.py - TokenResponse
@app.post('/auth/v1/token', description='exchange auth code and verifier for token') @app.post('/auth/v1/token', description='exchange auth code and verifier for token')
async def auth_v1_token(request: Request): async def auth_v1_token(request: Request):
j, cur_time = json.loads((await request.body()).decode('utf-8')), datetime.utcnow() j, cur_time = json_loads((await request.body()).decode('utf-8')), datetime.utcnow()
payload = jwt.decode(token=j.get('auth_code'), key=jwt_decode_key)
try:
payload = jwt.decode(token=j.get('auth_code'), key=jwt_decode_key)
except JWTError as e:
return JSONr(status_code=400, content={'status': 400, 'title': 'invalid token', 'detail': str(e)})
origin_ref = payload.get('origin_ref') origin_ref = payload.get('origin_ref')
logging.info(f'> [ auth ]: {origin_ref}: {j}') logging.info(f'> [ auth ]: {origin_ref}: {j}')
# validate the code challenge # validate the code challenge
if payload.get('challenge') != b64enc(sha256(j.get('code_verifier').encode('utf-8')).digest()).rstrip(b'=').decode('utf-8'): challenge = b64enc(sha256(j.get('code_verifier').encode('utf-8')).digest()).rstrip(b'=').decode('utf-8')
raise HTTPException(status_code=401, detail='expected challenge did not match verifier') if payload.get('challenge') != challenge:
return JSONr(status_code=401, content={'status': 401, 'detail': 'expected challenge did not match verifier'})
access_expires_on = cur_time + TOKEN_EXPIRE_DELTA access_expires_on = cur_time + TOKEN_EXPIRE_DELTA
@ -352,13 +357,18 @@ async def auth_v1_token(request: Request):
"sync_timestamp": cur_time.isoformat(), "sync_timestamp": cur_time.isoformat(),
} }
return JSONResponse(response) return JSONr(response)
# venv/lib/python3.9/site-packages/nls_services_lease/test/test_lease_multi_controller.py # venv/lib/python3.9/site-packages/nls_services_lease/test/test_lease_multi_controller.py
@app.post('/leasing/v1/lessor', description='request multiple leases (borrow) for current origin') @app.post('/leasing/v1/lessor', description='request multiple leases (borrow) for current origin')
async def leasing_v1_lessor(request: Request): async def leasing_v1_lessor(request: Request):
j, token, cur_time = json.loads((await request.body()).decode('utf-8')), __get_token(request), datetime.utcnow() j, token, cur_time = json_loads((await request.body()).decode('utf-8')), __get_token(request), datetime.utcnow()
try:
token = __get_token(request)
except JWTError:
return JSONr(status_code=401, content={'status': 401, 'detail': 'token is not valid'})
origin_ref = token.get('origin_ref') origin_ref = token.get('origin_ref')
scope_ref_list = j.get('scope_ref_list') scope_ref_list = j.get('scope_ref_list')
@ -367,7 +377,7 @@ async def leasing_v1_lessor(request: Request):
lease_result_list = [] lease_result_list = []
for scope_ref in scope_ref_list: for scope_ref in scope_ref_list:
# if scope_ref not in [ALLOTMENT_REF]: # if scope_ref not in [ALLOTMENT_REF]:
# raise HTTPException(status_code=500, detail=f'no service instances found for scopes: ["{scope_ref}"]') # return JSONr(status_code=500, detail=f'no service instances found for scopes: ["{scope_ref}"]')
lease_ref = str(uuid4()) lease_ref = str(uuid4())
expires = cur_time + LEASE_EXPIRE_DELTA expires = cur_time + LEASE_EXPIRE_DELTA
@ -394,7 +404,7 @@ async def leasing_v1_lessor(request: Request):
"prompts": None "prompts": None
} }
return JSONResponse(response) return JSONr(response)
# venv/lib/python3.9/site-packages/nls_services_lease/test/test_lease_multi_controller.py # venv/lib/python3.9/site-packages/nls_services_lease/test/test_lease_multi_controller.py
@ -414,7 +424,7 @@ async def leasing_v1_lessor_lease(request: Request):
"prompts": None "prompts": None
} }
return JSONResponse(response) return JSONr(response)
# venv/lib/python3.9/site-packages/nls_services_lease/test/test_lease_single_controller.py # venv/lib/python3.9/site-packages/nls_services_lease/test/test_lease_single_controller.py
@ -428,7 +438,7 @@ async def leasing_v1_lease_renew(request: Request, lease_ref: str):
entity = Lease.find_by_origin_ref_and_lease_ref(db, origin_ref, lease_ref) entity = Lease.find_by_origin_ref_and_lease_ref(db, origin_ref, lease_ref)
if entity is None: if entity is None:
raise HTTPException(status_code=404, detail='requested lease not available') return JSONr(status_code=404, content={'status': 404, 'detail': 'requested lease not available'})
expires = cur_time + LEASE_EXPIRE_DELTA expires = cur_time + LEASE_EXPIRE_DELTA
response = { response = {
@ -442,7 +452,7 @@ async def leasing_v1_lease_renew(request: Request, lease_ref: str):
Lease.renew(db, entity, expires, cur_time) Lease.renew(db, entity, expires, cur_time)
return JSONResponse(response) return JSONr(response)
# venv/lib/python3.9/site-packages/nls_services_lease/test/test_lease_single_controller.py # venv/lib/python3.9/site-packages/nls_services_lease/test/test_lease_single_controller.py
@ -455,12 +465,12 @@ async def leasing_v1_lease_delete(request: Request, lease_ref: str):
entity = Lease.find_by_lease_ref(db, lease_ref) entity = Lease.find_by_lease_ref(db, lease_ref)
if entity.origin_ref != origin_ref: if entity.origin_ref != origin_ref:
raise HTTPException(status_code=403, detail='access or operation forbidden') return JSONr(status_code=403, content={'status': 403, 'detail': 'access or operation forbidden'})
if entity is None: if entity is None:
raise HTTPException(status_code=404, detail='requested lease not available') return JSONr(status_code=404, content={'status': 404, 'detail': 'requested lease not available'})
if Lease.delete(db, lease_ref) == 0: if Lease.delete(db, lease_ref) == 0:
raise HTTPException(status_code=404, detail='lease not found') return JSONr(status_code=404, content={'status': 404, 'detail': 'lease not found'})
response = { response = {
"lease_ref": lease_ref, "lease_ref": lease_ref,
@ -468,7 +478,7 @@ async def leasing_v1_lease_delete(request: Request, lease_ref: str):
"sync_timestamp": cur_time.isoformat(), "sync_timestamp": cur_time.isoformat(),
} }
return JSONResponse(response) return JSONr(response)
# venv/lib/python3.9/site-packages/nls_services_lease/test/test_lease_multi_controller.py # venv/lib/python3.9/site-packages/nls_services_lease/test/test_lease_multi_controller.py
@ -489,12 +499,12 @@ async def leasing_v1_lessor_lease_remove(request: Request):
"prompts": None "prompts": None
} }
return JSONResponse(response) return JSONr(response)
@app.post('/leasing/v1/lessor/shutdown', description='shutdown all leases') @app.post('/leasing/v1/lessor/shutdown', description='shutdown all leases')
async def leasing_v1_lessor_shutdown(request: Request): async def leasing_v1_lessor_shutdown(request: Request):
j, cur_time = json.loads((await request.body()).decode('utf-8')), datetime.utcnow() j, cur_time = json_loads((await request.body()).decode('utf-8')), datetime.utcnow()
token = j.get('token') token = j.get('token')
token = jwt.decode(token=token, key=jwt_decode_key, algorithms=ALGORITHMS.RS256, options={'verify_aud': False}) token = jwt.decode(token=token, key=jwt_decode_key, algorithms=ALGORITHMS.RS256, options={'verify_aud': False})
@ -511,7 +521,7 @@ async def leasing_v1_lessor_shutdown(request: Request):
"prompts": None "prompts": None
} }
return JSONResponse(response) return JSONr(response)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -1,7 +1,7 @@
version: '3.9' version: '3.9'
x-dls-variables: &dls-variables x-dls-variables: &dls-variables
DLS_URL: localhost # REQUIRED DLS_URL: localhost # REQUIRED, change to your ip or hostname
DLS_PORT: 443 # must match nginx listen port DLS_PORT: 443 # must match nginx listen port
LEASE_EXPIRE_DAYS: 90 LEASE_EXPIRE_DAYS: 90
DATABASE: sqlite:////app/database/db.sqlite DATABASE: sqlite:////app/database/db.sqlite