mirror of
https://gitea.publichub.eu/oscar.krause/fastapi-dls.git
synced 2024-11-22 06:18:48 +00:00
Merge branch 'dev' into 'main'
1.3.3 See merge request oscar.krause/fastapi-dls!21
This commit is contained in:
commit
e3745d7fa8
@ -1,2 +1 @@
|
|||||||
/etc/fastapi-dls/env
|
/etc/fastapi-dls/env
|
||||||
/etc/systemd/system/fastapi-dls.service
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
WORKING_DIR=/usr/share/fastapi-dls
|
WORKING_DIR=/usr/share/fastapi-dls
|
||||||
CONFIG_DIR=/etc/fastapi-dls
|
CONFIG_DIR=/etc/fastapi-dls
|
||||||
|
|
||||||
if [[ ! -f $CONFIG_DIR/instance.private.pem ]]; then
|
if [ ! -f $CONFIG_DIR/instance.private.pem ]; then
|
||||||
echo "> Create dls-instance keypair ..."
|
echo "> Create dls-instance keypair ..."
|
||||||
openssl genrsa -out $CONFIG_DIR/instance.private.pem 2048
|
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
|
openssl rsa -in $CONFIG_DIR/instance.private.pem -outform PEM -pubout -out $CONFIG_DIR/instance.public.pem
|
||||||
@ -12,8 +12,8 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
[[ -f $CONFIG_DIR/webserver.key ]] && default_answer="N" || default_answer="Y"
|
[ -f $CONFIG_DIR/webserver.key ] && default_answer="N" || default_answer="Y"
|
||||||
[[ $default_answer == "Y" ]] && V="Y/n" || V="y/N"
|
[ $default_answer == "Y" ] && V="Y/n" || V="y/N"
|
||||||
read -p "> Do you wish to create self-signed webserver certificate? [${V}]" yn
|
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.
|
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
|
||||||
@ -27,7 +27,7 @@ while true; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ -f $CONFIG_DIR/webserver.key ]]; then
|
if [ -f $CONFIG_DIR/webserver.key ]; then
|
||||||
echo "> Starting service ..."
|
echo "> Starting service ..."
|
||||||
systemctl start fastapi-dls.service
|
systemctl start fastapi-dls.service
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
if [[ -f /etc/systemd/system/fastapi-dls.service ]]; then
|
# is removed automatically
|
||||||
echo "> Removing service file."
|
#if [ "$1" = purge ] && [ -d /usr/share/fastapi-dls ]; then
|
||||||
rm /etc/systemd/system/fastapi-dls.service
|
# echo "> Removing app."
|
||||||
fi
|
# rm -r /usr/share/fastapi-dls
|
||||||
|
#fi
|
||||||
|
|
||||||
# todo
|
echo -e "> Done."
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
echo -e "> Starting uninstallation of 'fastapi-dls'!"
|
echo -e "> Starting uninstallation of 'fastapi-dls'!"
|
||||||
|
|
||||||
# todo
|
|
||||||
|
73
README.md
73
README.md
@ -206,13 +206,17 @@ Packages are available here:
|
|||||||
```shell
|
```shell
|
||||||
pacman -Sy
|
pacman -Sy
|
||||||
FILENAME=/opt/fastapi-dls.pkg.tar.zst
|
FILENAME=/opt/fastapi-dls.pkg.tar.zst
|
||||||
url -o $FILENAME <download-url>
|
|
||||||
|
curl -o $FILENAME <download-url>
|
||||||
|
# or
|
||||||
|
wget -O $FILENAME <download-url>
|
||||||
|
|
||||||
pacman -U --noconfirm fastapi-dls.pkg.tar.zst
|
pacman -U --noconfirm fastapi-dls.pkg.tar.zst
|
||||||
```
|
```
|
||||||
|
|
||||||
Start with `systemctl start fastapi-dls.service` and enable autostart with `systemctl enable fastapi-dls.service`.
|
Start with `systemctl start fastapi-dls.service` and enable autostart with `systemctl enable fastapi-dls.service`.
|
||||||
|
|
||||||
## Let's Encrypt Certificate
|
## Let's Encrypt Certificate (optional)
|
||||||
|
|
||||||
If you're using installation via docker, you can use `traefik`. Please refer to their documentation.
|
If you're using installation via docker, you can use `traefik`. Please refer to their documentation.
|
||||||
|
|
||||||
@ -266,26 +270,67 @@ Successfully tested with this package versions:
|
|||||||
|
|
||||||
## Linux
|
## Linux
|
||||||
|
|
||||||
|
Download *client-token* and place it into `/etc/nvidia/ClientConfigToken`:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl --insecure -L -X GET https://<dls-hostname-or-ip>/-/client-token -o /etc/nvidia/ClientConfigToken/client_configuration_token_$(date '+%d-%m-%Y-%H-%M-%S').tok
|
||||||
|
# or
|
||||||
|
wget --no-check-certificate -O /etc/nvidia/ClientConfigToken/client_configuration_token_$(date '+%d-%m-%Y-%H-%M-%S').tok https://<dls-hostname-or-ip>/-/client-token
|
||||||
|
```
|
||||||
|
|
||||||
|
Restart `nvidia-gridd` service:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl --insecure -L -X GET https://<dls-hostname-or-ip>/client-token -o /etc/nvidia/ClientConfigToken/client_configuration_token_$(date '+%d-%m-%Y-%H-%M-%S').tok
|
|
||||||
service nvidia-gridd restart
|
service nvidia-gridd restart
|
||||||
|
```
|
||||||
|
|
||||||
|
Check licensing status:
|
||||||
|
|
||||||
|
```shell
|
||||||
nvidia-smi -q | grep "License"
|
nvidia-smi -q | grep "License"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Windows
|
Output should be something like:
|
||||||
|
|
||||||
Download file and place it into `C:\Program Files\NVIDIA Corporation\vGPU Licensing\ClientConfigToken`.
|
```text
|
||||||
Now restart `NvContainerLocalSystem` service.
|
vGPU Software Licensed Product
|
||||||
|
License Status : Licensed (Expiry: YYYY-M-DD hh:mm:ss GMT)
|
||||||
**Power-Shell**
|
|
||||||
|
|
||||||
```Shell
|
|
||||||
curl.exe --insecure -L -X GET https://<dls-hostname-or-ip>/client-token -o "C:\Program Files\NVIDIA Corporation\vGPU Licensing\ClientConfigToken\client_configuration_token_$($(Get-Date).tostring('dd-MM-yy-hh-mm-ss')).tok"
|
|
||||||
Restart-Service NVDisplay.ContainerLocalSystem
|
|
||||||
'C:\Program Files\NVIDIA Corporation\NVSMI\nvidia-smi.exe' -q | Select-String "License"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Endpoints
|
Done. For more information check [troubleshoot section](#troubleshoot).
|
||||||
|
|
||||||
|
## Windows
|
||||||
|
|
||||||
|
**Power-Shell** (run as administrator!)
|
||||||
|
|
||||||
|
Download *client-token* and place it into `C:\Program Files\NVIDIA Corporation\vGPU Licensing\ClientConfigToken`:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl.exe --insecure -L -X GET https://<dls-hostname-or-ip>/-/client-token -o "C:\Program Files\NVIDIA Corporation\vGPU Licensing\ClientConfigToken\client_configuration_token_$($(Get-Date).tostring('dd-MM-yy-hh-mm-ss')).tok"
|
||||||
|
```
|
||||||
|
|
||||||
|
Restart `NvContainerLocalSystem` service:
|
||||||
|
|
||||||
|
```Shell
|
||||||
|
Restart-Service NVDisplay.ContainerLocalSystem
|
||||||
|
```
|
||||||
|
|
||||||
|
Check licensing status:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
& 'C:\Program Files\NVIDIA Corporation\NVSMI\nvidia-smi.exe' -q | Select-String "License"
|
||||||
|
```
|
||||||
|
|
||||||
|
Output should be something like:
|
||||||
|
|
||||||
|
```text
|
||||||
|
vGPU Software Licensed Product
|
||||||
|
License Status : Licensed (Expiry: YYYY-M-DD hh:mm:ss GMT)
|
||||||
|
```
|
||||||
|
|
||||||
|
Done. For more information check [troubleshoot section](#troubleshoot).
|
||||||
|
|
||||||
|
# Endpoints
|
||||||
|
|
||||||
### `GET /`
|
### `GET /`
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ from dotenv import load_dotenv
|
|||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.requests import Request
|
from fastapi.requests import Request
|
||||||
from json import loads as json_loads
|
from json import loads as json_loads
|
||||||
from datetime import datetime
|
from datetime import datetime, timedelta
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
from calendar import timegm
|
from calendar import timegm
|
||||||
from jose import jws, jwk, jwt, JWTError
|
from jose import jws, jwk, jwt, JWTError
|
||||||
@ -43,6 +43,7 @@ INSTANCE_KEY_PUB = load_key(str(env('INSTANCE_KEY_PUB', join(dirname(__file__),
|
|||||||
TOKEN_EXPIRE_DELTA = relativedelta(days=int(env('TOKEN_EXPIRE_DAYS', 1)), hours=int(env('TOKEN_EXPIRE_HOURS', 0)))
|
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))
|
||||||
|
LEASE_RENEWAL_DELTA = timedelta(days=int(env('LEASE_EXPIRE_DAYS', 90)), hours=int(env('LEASE_EXPIRE_HOURS', 0)))
|
||||||
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}']
|
||||||
|
|
||||||
jwt_encode_key = jwk.construct(INSTANCE_KEY_RSA.export_key().decode('utf-8'), algorithm=ALGORITHMS.RS256)
|
jwt_encode_key = jwk.construct(INSTANCE_KEY_RSA.export_key().decode('utf-8'), algorithm=ALGORITHMS.RS256)
|
||||||
@ -151,7 +152,8 @@ async def _origins(request: Request, leases: bool = False):
|
|||||||
for origin in session.query(Origin).all():
|
for origin in session.query(Origin).all():
|
||||||
x = origin.serialize()
|
x = origin.serialize()
|
||||||
if leases:
|
if leases:
|
||||||
x['leases'] = list(map(lambda _: _.serialize(), Lease.find_by_origin_ref(db, origin.origin_ref)))
|
serialize = dict(renewal_period=LEASE_RENEWAL_PERIOD, renewal_delta=LEASE_RENEWAL_DELTA)
|
||||||
|
x['leases'] = list(map(lambda _: _.serialize(**serialize), Lease.find_by_origin_ref(db, origin.origin_ref)))
|
||||||
response.append(x)
|
response.append(x)
|
||||||
session.close()
|
session.close()
|
||||||
return JSONr(response)
|
return JSONr(response)
|
||||||
@ -168,7 +170,8 @@ async def _leases(request: Request, origin: bool = False):
|
|||||||
session = sessionmaker(bind=db)()
|
session = sessionmaker(bind=db)()
|
||||||
response = []
|
response = []
|
||||||
for lease in session.query(Lease).all():
|
for lease in session.query(Lease).all():
|
||||||
x = lease.serialize()
|
serialize = dict(renewal_period=LEASE_RENEWAL_PERIOD, renewal_delta=LEASE_RENEWAL_DELTA)
|
||||||
|
x = lease.serialize(**serialize)
|
||||||
if origin:
|
if origin:
|
||||||
lease_origin = session.query(Origin).filter(Origin.origin_ref == lease.origin_ref).first()
|
lease_origin = session.query(Origin).filter(Origin.origin_ref == lease.origin_ref).first()
|
||||||
if lease_origin is not None:
|
if lease_origin is not None:
|
||||||
|
25
app/orm.py
25
app/orm.py
@ -1,4 +1,5 @@
|
|||||||
import datetime
|
from datetime import datetime, timedelta
|
||||||
|
from dateutil.relativedelta import relativedelta
|
||||||
|
|
||||||
from sqlalchemy import Column, VARCHAR, CHAR, ForeignKey, DATETIME, update, and_, inspect
|
from sqlalchemy import Column, VARCHAR, CHAR, ForeignKey, DATETIME, update, and_, inspect
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
@ -81,7 +82,10 @@ class Lease(Base):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f'Lease(origin_ref={self.origin_ref}, lease_ref={self.lease_ref}, expires={self.lease_expires})'
|
return f'Lease(origin_ref={self.origin_ref}, lease_ref={self.lease_ref}, expires={self.lease_expires})'
|
||||||
|
|
||||||
def serialize(self) -> dict:
|
def serialize(self, renewal_period: float, renewal_delta: timedelta) -> dict:
|
||||||
|
lease_renewal = int(Lease.calculate_renewal(renewal_period, renewal_delta).total_seconds())
|
||||||
|
lease_renewal = self.lease_updated + relativedelta(seconds=lease_renewal)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'lease_ref': self.lease_ref,
|
'lease_ref': self.lease_ref,
|
||||||
'origin_ref': self.origin_ref,
|
'origin_ref': self.origin_ref,
|
||||||
@ -89,6 +93,7 @@ class Lease(Base):
|
|||||||
'lease_created': self.lease_created.isoformat(),
|
'lease_created': self.lease_created.isoformat(),
|
||||||
'lease_expires': self.lease_expires.isoformat(),
|
'lease_expires': self.lease_expires.isoformat(),
|
||||||
'lease_updated': self.lease_updated.isoformat(),
|
'lease_updated': self.lease_updated.isoformat(),
|
||||||
|
'lease_renewal': lease_renewal.isoformat(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -133,7 +138,7 @@ class Lease(Base):
|
|||||||
return entity
|
return entity
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def renew(engine: Engine, lease: "Lease", lease_expires: datetime.datetime, lease_updated: datetime.datetime):
|
def renew(engine: Engine, lease: "Lease", lease_expires: datetime, lease_updated: datetime):
|
||||||
session = sessionmaker(bind=engine)()
|
session = sessionmaker(bind=engine)()
|
||||||
x = dict(lease_expires=lease_expires, lease_updated=lease_updated)
|
x = dict(lease_expires=lease_expires, lease_updated=lease_updated)
|
||||||
session.execute(update(Lease).where(and_(Lease.origin_ref == lease.origin_ref, Lease.lease_ref == lease.lease_ref)).values(**x))
|
session.execute(update(Lease).where(and_(Lease.origin_ref == lease.origin_ref, Lease.lease_ref == lease.lease_ref)).values(**x))
|
||||||
@ -156,6 +161,20 @@ class Lease(Base):
|
|||||||
session.close()
|
session.close()
|
||||||
return deletions
|
return deletions
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def calculate_renewal(renewal_period: float, delta: timedelta) -> timedelta:
|
||||||
|
"""
|
||||||
|
import datetime
|
||||||
|
LEASE_RENEWAL_PERIOD=0.2 # 20%
|
||||||
|
delta = datetime.timedelta(days=1)
|
||||||
|
renew = delta.total_seconds() * LEASE_RENEWAL_PERIOD
|
||||||
|
renew = datetime.timedelta(seconds=renew)
|
||||||
|
expires = delta - renew # 19.2
|
||||||
|
"""
|
||||||
|
renew = delta.total_seconds() * renewal_period
|
||||||
|
renew = timedelta(seconds=renew)
|
||||||
|
return renew
|
||||||
|
|
||||||
|
|
||||||
def init(engine: Engine):
|
def init(engine: Engine):
|
||||||
tables = [Origin, Lease]
|
tables = [Origin, Lease]
|
||||||
|
@ -1 +1 @@
|
|||||||
VERSION=1.3.2
|
VERSION=1.3.3
|
||||||
|
Loading…
Reference in New Issue
Block a user