Compare commits

..

No commits in common. "e3745d7fa8a6a4ae4e45e6c33dc66b0520b04247" and "164b5ebc44ecdbebac92d804e153131838874fcd" have entirely different histories.

8 changed files with 28 additions and 93 deletions

View File

@ -1 +1,2 @@
/etc/fastapi-dls/env /etc/fastapi-dls/env
/etc/systemd/system/fastapi-dls.service

View File

@ -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

View File

@ -1,9 +1,8 @@
#!/bin/bash #!/bin/bash
# is removed automatically if [[ -f /etc/systemd/system/fastapi-dls.service ]]; then
#if [ "$1" = purge ] && [ -d /usr/share/fastapi-dls ]; then echo "> Removing service file."
# echo "> Removing app." rm /etc/systemd/system/fastapi-dls.service
# rm -r /usr/share/fastapi-dls fi
#fi
echo -e "> Done." # todo

View File

@ -1,3 +1,5 @@
#!/bin/bash #!/bin/bash
echo -e "> Starting uninstallation of 'fastapi-dls'!" echo -e "> Starting uninstallation of 'fastapi-dls'!"
# todo

View File

@ -206,17 +206,13 @@ 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 (optional) ## Let's Encrypt Certificate
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.
@ -270,67 +266,26 @@ 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"
``` ```
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).
## Windows ## Windows
**Power-Shell** (run as administrator!) Download file and place it into `C:\Program Files\NVIDIA Corporation\vGPU Licensing\ClientConfigToken`.
Now restart `NvContainerLocalSystem` service.
Download *client-token* and place it into `C:\Program Files\NVIDIA Corporation\vGPU Licensing\ClientConfigToken`: **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 `NvContainerLocalSystem` service:
```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 Restart-Service NVDisplay.ContainerLocalSystem
'C:\Program Files\NVIDIA Corporation\NVSMI\nvidia-smi.exe' -q | Select-String "License"
``` ```
Check licensing status: ## Endpoints
```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 /`

View File

@ -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, timedelta 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, JWTError from jose import jws, jwk, jwt, JWTError
@ -43,7 +43,6 @@ 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)
@ -152,8 +151,7 @@ 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:
serialize = dict(renewal_period=LEASE_RENEWAL_PERIOD, renewal_delta=LEASE_RENEWAL_DELTA) x['leases'] = list(map(lambda _: _.serialize(), Lease.find_by_origin_ref(db, origin.origin_ref)))
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)
@ -170,8 +168,7 @@ 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():
serialize = dict(renewal_period=LEASE_RENEWAL_PERIOD, renewal_delta=LEASE_RENEWAL_DELTA) x = lease.serialize()
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:

View File

@ -1,5 +1,4 @@
from datetime import datetime, timedelta import datetime
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
@ -82,10 +81,7 @@ 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, renewal_period: float, renewal_delta: timedelta) -> dict: def serialize(self) -> 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,
@ -93,7 +89,6 @@ 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
@ -138,7 +133,7 @@ class Lease(Base):
return entity return entity
@staticmethod @staticmethod
def renew(engine: Engine, lease: "Lease", lease_expires: datetime, lease_updated: datetime): def renew(engine: Engine, lease: "Lease", lease_expires: datetime.datetime, lease_updated: datetime.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))
@ -161,20 +156,6 @@ 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]

View File

@ -1 +1 @@
VERSION=1.3.3 VERSION=1.3.2