mirror of
https://gitea.publichub.eu/oscar.krause/fastapi-dls.git
synced 2026-04-08 22:15:47 +03:00
Compare commits
54 Commits
cd4674caad
...
1.4.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
699dbf6fac | ||
|
|
317699ff58 | ||
|
|
55446f7d9c | ||
|
|
88c78efcd9 | ||
|
|
fb3ac4291f | ||
|
|
15f14cac11 | ||
|
|
018d7c34fc | ||
|
|
1aee423120 | ||
|
|
a6b2f2a942 | ||
|
|
e33024db86 | ||
|
|
4ad15f0849 | ||
|
|
7bad0359af | ||
|
|
59a7c9f15a | ||
|
|
bc6d692f0a | ||
|
|
63c37c6334 | ||
|
|
fa2c06972e | ||
|
|
e4e6387b2a | ||
|
|
f2be9dca8d | ||
|
|
52dd425583 | ||
|
|
286399d79a | ||
|
|
4ab1a2ed22 | ||
|
|
459c0e21af | ||
|
|
98ef64211b | ||
|
|
0b4bb65546 | ||
|
|
47624f5019 | ||
|
|
2b9d7821c0 | ||
|
|
45f5108717 | ||
|
|
a7fe8b867e | ||
|
|
78214df9cc | ||
|
|
4245d5a582 | ||
|
|
9b5a387169 | ||
|
|
9377d5ce28 | ||
|
|
7489307db8 | ||
|
|
d41314e81d | ||
|
|
a1123d5451 | ||
|
|
93cf719454 | ||
|
|
0dc8f6c582 | ||
|
|
4b0219b85a | ||
|
|
8edbb25c16 | ||
|
|
49a24f0b68 | ||
|
|
8af3c8e2b3 | ||
|
|
3c321a202c | ||
|
|
1b7d8bc0dc | ||
|
|
23ccea538f | ||
|
|
6a54c05fbb | ||
|
|
006d3a1833 | ||
|
|
42fe066e1a | ||
|
|
ef542ec821 | ||
|
|
5b39598487 | ||
|
|
65de4d0534 | ||
|
|
58ffa752f3 | ||
|
|
fd4fa84dc5 | ||
|
|
5ff3295658 | ||
|
|
ca38ebe3fd |
@@ -1,10 +0,0 @@
|
||||
# https://packages.ubuntu.com
|
||||
fastapi==0.91.0
|
||||
uvicorn[standard]==0.15.0
|
||||
python-jose[pycryptodome]==3.3.0
|
||||
pycryptodome==3.11.0
|
||||
python-dateutil==2.8.2
|
||||
sqlalchemy==1.4.46
|
||||
markdown==3.4.3
|
||||
python-dotenv==0.21.0
|
||||
jinja2==3.1.2
|
||||
@@ -1,10 +0,0 @@
|
||||
# https://packages.ubuntu.com
|
||||
fastapi==0.101.0
|
||||
uvicorn[standard]==0.23.2
|
||||
python-jose[pycryptodome]==3.3.0
|
||||
pycryptodome==3.11.0
|
||||
python-dateutil==2.8.2
|
||||
sqlalchemy==1.4.47
|
||||
markdown==3.4.4
|
||||
python-dotenv==1.0.0
|
||||
jinja2==3.1.2
|
||||
10
.DEBIAN/requirements-ubuntu-24.10.txt
Normal file
10
.DEBIAN/requirements-ubuntu-24.10.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
# https://packages.ubuntu.com
|
||||
fastapi==0.110.3
|
||||
uvicorn[standard]==0.30.3
|
||||
python-jose[pycryptodome]==3.3.0
|
||||
pycryptodome==3.20.0
|
||||
python-dateutil==2.9.0
|
||||
sqlalchemy==2.0.32
|
||||
markdown==3.6
|
||||
python-dotenv==1.0.1
|
||||
jinja2==3.1.3
|
||||
@@ -48,6 +48,7 @@ package() {
|
||||
install -Dm755 "$srcdir/$pkgname/app/main.py" "$pkgdir/opt/$pkgname/main.py"
|
||||
install -Dm755 "$srcdir/$pkgname/app/orm.py" "$pkgdir/opt/$pkgname/orm.py"
|
||||
install -Dm755 "$srcdir/$pkgname/app/util.py" "$pkgdir/opt/$pkgname/util.py"
|
||||
install -Dm755 "$srcdir/$pkgname/app/middleware.py" "$pkgdir/opt/$pkgname/middleware.py"
|
||||
install -Dm644 "$srcdir/$pkgname.default" "$pkgdir/etc/default/$pkgname"
|
||||
install -Dm644 "$srcdir/$pkgname.service" "$pkgdir/usr/lib/systemd/system/$pkgname.service"
|
||||
install -Dm644 "$srcdir/$pkgname.tmpfiles" "$pkgdir/usr/lib/tmpfiles.d/$pkgname.conf"
|
||||
|
||||
@@ -20,6 +20,7 @@ build:docker:
|
||||
changes:
|
||||
- app/**/*
|
||||
- Dockerfile
|
||||
- requirements.txt
|
||||
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
|
||||
tags: [ docker ]
|
||||
before_script:
|
||||
@@ -141,14 +142,19 @@ test:
|
||||
DATABASE: sqlite:///../app/db.sqlite
|
||||
parallel:
|
||||
matrix:
|
||||
- IMAGE: [ 'python:3.11-slim-bookworm', 'python:3.12-slim-bullseye' ]
|
||||
REQUIREMENTS:
|
||||
- requirements.txt
|
||||
- .DEBIAN/requirements-bookworm-12.txt
|
||||
- .DEBIAN/requirements-ubuntu-23.10.txt
|
||||
- .DEBIAN/requirements-ubuntu-24.04.txt
|
||||
- IMAGE: [ 'python:3.12-slim-bookworm' ]
|
||||
REQUIREMENTS: [ 'requirements.txt' ]
|
||||
- IMAGE: [ 'debian:bookworm' ] # EOL: June 06, 2026
|
||||
REQUIREMENTS: [ '.DEBIAN/requirements-bookworm-12.txt' ]
|
||||
- IMAGE: [ 'ubuntu:24.04' ] # EOL: April 2036
|
||||
REQUIREMENTS: [ '.DEBIAN/requirements-ubuntu-24.04.txt' ]
|
||||
- IMAGE: [ 'ubuntu:24.10' ]
|
||||
REQUIREMENTS: [ '.DEBIAN/requirements-ubuntu-24.10.txt' ]
|
||||
before_script:
|
||||
- apt-get update && apt-get install -y python3-dev gcc
|
||||
- apt-get update && apt-get install -y python3-dev python3-pip python3-venv gcc
|
||||
- python3 -m venv venv
|
||||
- source venv/bin/activate
|
||||
- pip install --upgrade pip
|
||||
- pip install -r $REQUIREMENTS
|
||||
- pip install pytest httpx
|
||||
- mkdir -p app/cert
|
||||
@@ -162,7 +168,7 @@ test:
|
||||
dotenv: version.env
|
||||
junit: ['**/report.xml']
|
||||
|
||||
.test:linux:
|
||||
.test:apt:
|
||||
stage: test
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
|
||||
@@ -201,15 +207,15 @@ test:
|
||||
- apt-get purge -qq -y fastapi-dls
|
||||
- apt-get autoremove -qq -y && apt-get clean -qq
|
||||
|
||||
test:debian:
|
||||
extends: .test:linux
|
||||
test:apt:debian:
|
||||
extends: .test:apt
|
||||
image: debian:bookworm-slim
|
||||
|
||||
test:ubuntu:
|
||||
extends: .test:linux
|
||||
test:apt:ubuntu:
|
||||
extends: .test:apt
|
||||
image: ubuntu:24.04
|
||||
|
||||
test:archlinux:
|
||||
test:pacman:archlinux:
|
||||
image: archlinux:base
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
|
||||
@@ -250,7 +256,7 @@ semgrep-sast:
|
||||
|
||||
test_coverage:
|
||||
# extends: test
|
||||
image: python:3.11-slim-bookworm
|
||||
image: python:3.12-slim-bookworm
|
||||
allow_failure: true
|
||||
stage: test
|
||||
rules:
|
||||
@@ -297,13 +303,17 @@ gemnasium-python-dependency_scanning:
|
||||
|
||||
deploy:docker:
|
||||
extends: .deploy
|
||||
image: docker:dind
|
||||
stage: deploy
|
||||
tags: [ docker ]
|
||||
before_script:
|
||||
- echo "Building docker image for commit $CI_COMMIT_SHA with version $CI_COMMIT_REF_NAME"
|
||||
- docker buildx inspect
|
||||
- docker buildx create --use
|
||||
script:
|
||||
- echo "========== GitLab-Registry =========="
|
||||
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||
- IMAGE=$CI_REGISTRY/$CI_PROJECT_PATH/$CI_COMMIT_REF_NAME
|
||||
- IMAGE=$CI_REGISTRY/$CI_PROJECT_PATH
|
||||
- docker buildx build --progress=plain --platform $DOCKER_BUILDX_PLATFORM --build-arg VERSION=$CI_COMMIT_REF_NAME --build-arg COMMIT=$CI_COMMIT_SHA --tag $IMAGE:$CI_COMMIT_REF_NAME --push .
|
||||
- docker buildx build --progress=plain --platform $DOCKER_BUILDX_PLATFORM --build-arg VERSION=$CI_COMMIT_REF_NAME --build-arg COMMIT=$CI_COMMIT_SHA --tag $IMAGE:latest --push .
|
||||
- echo "========== Docker-Hub =========="
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM python:3.11-alpine
|
||||
FROM python:3.12-alpine
|
||||
|
||||
ARG VERSION
|
||||
ARG COMMIT=""
|
||||
@@ -10,7 +10,7 @@ RUN apk update \
|
||||
&& apk add --no-cache --virtual build-deps gcc g++ python3-dev musl-dev pkgconfig \
|
||||
&& apk add --no-cache curl postgresql postgresql-dev mariadb-dev sqlite-dev \
|
||||
&& pip install --no-cache-dir --upgrade uvicorn \
|
||||
&& pip install --no-cache-dir psycopg2==2.9.9 mysqlclient==2.2.4 pysqlite3==0.5.2 \
|
||||
&& pip install --no-cache-dir psycopg2==2.9.10 mysqlclient==2.2.6 pysqlite3==0.5.4 \
|
||||
&& pip install --no-cache-dir -r /tmp/requirements.txt \
|
||||
&& apk del build-deps
|
||||
|
||||
|
||||
135
README.md
135
README.md
@@ -2,7 +2,8 @@
|
||||
|
||||
Minimal Delegated License Service (DLS).
|
||||
|
||||
Compatibility tested with official NLS 2.0.1, 2.1.0, 3.1.0. For Driver compatibility see [here](#setup-client).
|
||||
Compatibility tested with official NLS 2.0.1, 2.1.0, 3.1.0, 3.3.1. For Driver compatibility
|
||||
see [compatibility matrix](#vgpu-software-compatibility-matrix).
|
||||
|
||||
This service can be used without internet connection.
|
||||
Only the clients need a connection to this service on configured port.
|
||||
@@ -42,6 +43,9 @@ Tested with Ubuntu 22.10 (EOL!) (from Proxmox templates), actually its consuming
|
||||
|
||||
- Make sure your timezone is set correct on you fastapi-dls server and your client
|
||||
|
||||
This guide does not show how to install vGPU host drivers! Look at the official documentation packed with the driver
|
||||
releases.
|
||||
|
||||
## Docker
|
||||
|
||||
Docker-Images are available here for Intel (x86), AMD (amd64) and ARM (arm64):
|
||||
@@ -326,11 +330,11 @@ Packages are available here:
|
||||
|
||||
Successful tested with:
|
||||
|
||||
- Debian 12 (Bookworm) (EOL: tba.)
|
||||
- Ubuntu 22.10 (Kinetic Kudu) (EOL: July 20, 2023)
|
||||
- Ubuntu 23.04 (Lunar Lobster) (EOL: January 2024)
|
||||
- Ubuntu 23.10 (Mantic Minotaur) (EOL: July 2024)
|
||||
- Ubuntu 24.04 (Noble Numbat) (EOL: April 2036)
|
||||
- **Debian 12 (Bookworm)** (EOL: June 06, 2026)
|
||||
- *Ubuntu 22.10 (Kinetic Kudu)* (EOL: July 20, 2023)
|
||||
- *Ubuntu 23.04 (Lunar Lobster)* (EOL: January 2024)
|
||||
- *Ubuntu 23.10 (Mantic Minotaur)* (EOL: July 2024)
|
||||
- **Ubuntu 24.04 (Noble Numbat)** (EOL: April 2036)
|
||||
|
||||
Not working with:
|
||||
|
||||
@@ -406,21 +410,22 @@ After first success you have to replace `--issue` with `--renew`.
|
||||
|
||||
# Configuration
|
||||
|
||||
| Variable | Default | Usage |
|
||||
|------------------------|----------------------------------------|------------------------------------------------------------------------------------------------------|
|
||||
| `DEBUG` | `false` | Toggles `fastapi` debug mode |
|
||||
| `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 |
|
||||
| `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_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) |
|
||||
| `CORS_ORIGINS` | `https://{DLS_URL}` | Sets `Access-Control-Allow-Origin` header (comma separated string) \*2 |
|
||||
| `SITE_KEY_XID` | `00000000-0000-0000-0000-000000000000` | Site identification uuid |
|
||||
| `INSTANCE_REF` | `10000000-0000-0000-0000-000000000001` | Instance identification uuid |
|
||||
| `ALLOTMENT_REF` | `20000000-0000-0000-0000-000000000001` | Allotment identification uuid |
|
||||
| `INSTANCE_KEY_RSA` | `<app-dir>/cert/instance.private.pem` | Site-wide private RSA key for singing JWTs \*3 |
|
||||
| `INSTANCE_KEY_PUB` | `<app-dir>/cert/instance.public.pem` | Site-wide public key \*3 |
|
||||
| Variable | Default | Usage |
|
||||
|--------------------------|----------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `DEBUG` | `false` | Toggles `fastapi` debug mode |
|
||||
| `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 |
|
||||
| `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_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) |
|
||||
| `CORS_ORIGINS` | `https://{DLS_URL}` | Sets `Access-Control-Allow-Origin` header (comma separated string) \*2 |
|
||||
| `SITE_KEY_XID` | `00000000-0000-0000-0000-000000000000` | Site identification uuid |
|
||||
| `INSTANCE_REF` | `10000000-0000-0000-0000-000000000001` | Instance identification uuid |
|
||||
| `ALLOTMENT_REF` | `20000000-0000-0000-0000-000000000001` | Allotment identification uuid |
|
||||
| `INSTANCE_KEY_RSA` | `<app-dir>/cert/instance.private.pem` | Site-wide private RSA key for singing JWTs \*3 |
|
||||
| `INSTANCE_KEY_PUB` | `<app-dir>/cert/instance.public.pem` | Site-wide public key \*3 |
|
||||
| `SUPPORT_MALFORMED_JSON` | `false` | Support parsing for mal formatted "mac_address_list" ([Issue](https://git.collinwebdesigns.de/oscar.krause/fastapi-dls/-/issues/1)) |
|
||||
|
||||
\*1 For example, if the lease period is one day and the renewal period is 20%, the client attempts to renew its license
|
||||
every 4.8 hours. If network connectivity is lost, the loss of connectivity is detected during license renewal and the
|
||||
@@ -434,32 +439,8 @@ client has 19.2 hours in which to re-establish connectivity before its license e
|
||||
|
||||
**The token file has to be copied! It's not enough to C&P file contents, because there can be special characters.**
|
||||
|
||||
Successfully tested with this package versions:
|
||||
|
||||
| vGPU Suftware | Driver Branch | Linux vGPU Manager | Linux Driver | Windows Driver | Release Date | EOL Date |
|
||||
|:-------------:|:-------------:|--------------------|--------------|----------------|--------------:|--------------:|
|
||||
| `17.2` | R550 | `550.90.05` | `550.90.07` | `552.55` | June 2024 | February 2025 |
|
||||
| `17.1` | R550 | `550.54.16` | `550.54.15` | `551.78` | March 2024 | |
|
||||
| `17.0` | R550 | `550.54.10` | `550.54.14` | `551.61` | February 2024 | |
|
||||
| `16.6` | R535 | `535.183.04` | `535.183.01` | `538.67` | June 2024 | July 2026 |
|
||||
| `16.5` | R535 | `535.161.05` | `535.161.08` | `538.46` | February 2024 | |
|
||||
| `16.4` | R535 | `535.161.05` | `535.161.07` | `538.33` | February 2024 | |
|
||||
| `16.3` | R535 | `535.154.02` | `535.154.05` | `538.15` | January 2024 | |
|
||||
| `16.2` | R535 | `535.129.03` | `535.129.03` | `537.70` | October 2023 | |
|
||||
| `16.1` | R535 | `535.104.06` | `535.104.05` | `537.13` | August 2023 | |
|
||||
| `16.0` | R535 | `535.54.06` | `535.54.03` | `536.22` | July 2023 | |
|
||||
| `15.4` | R525 | `525.147.01` | `525.147.05` | `529.19` | June 2023 | October 2023 |
|
||||
| `15.3` | R525 | `525.125.03` | `525.125.06` | `529.11` | June 2023 | |
|
||||
| `15.2` | R525 | `525.105.14` | `525.105.17` | `528.89` | March 2023 | |
|
||||
| `15.1` | R525 | `525.85.07` | `525.85.05` | `528.24` | January 2023 | |
|
||||
| `15.0` | R525 | `525.60.12` | `525.60.13` | `527.41` | December 2022 | |
|
||||
| `14.4` | R510 | `510.108.03` | `510.108.03` | `514.08` | December 2022 | February 2023 |
|
||||
| `14.3` | R510 | `510.108.03` | `510.108.03` | `513.91` | November 2022 | |
|
||||
|
||||
- https://docs.nvidia.com/grid/index.html
|
||||
- https://docs.nvidia.com/grid/gpus-supported-by-vgpu.html
|
||||
|
||||
*To get the latest drivers, visit Nvidia or search in Discord-Channel `GPU Unlocking` (Server-ID: `829786927829745685`) on channel `licensing` `biggerthanshit`
|
||||
This guide does not show how to install vGPU guest drivers! Look at the official documentation packed with the driver
|
||||
releases.
|
||||
|
||||
## Linux
|
||||
|
||||
@@ -535,33 +516,32 @@ Done. For more information check [troubleshoot section](#troubleshoot).
|
||||
8. Set schedule to `At First Array Start Only`
|
||||
9. Click on Apply
|
||||
|
||||
|
||||
# Endpoints
|
||||
# API Endpoints
|
||||
|
||||
<details>
|
||||
<summary>show</summary>
|
||||
|
||||
### `GET /`
|
||||
**`GET /`**
|
||||
|
||||
Redirect to `/-/readme`.
|
||||
|
||||
### `GET /-/health`
|
||||
**`GET /-/health`**
|
||||
|
||||
Status endpoint, used for *healthcheck*.
|
||||
|
||||
### `GET /-/config`
|
||||
**`GET /-/config`**
|
||||
|
||||
Shows current runtime environment variables and their values.
|
||||
|
||||
### `GET /-/readme`
|
||||
**`GET /-/readme`**
|
||||
|
||||
HTML rendered README.md.
|
||||
|
||||
### `GET /-/manage`
|
||||
**`GET /-/manage`**
|
||||
|
||||
Shows a very basic UI to delete origins or leases.
|
||||
|
||||
### `GET /-/origins?leases=false`
|
||||
**`GET /-/origins?leases=false`**
|
||||
|
||||
List registered origins.
|
||||
|
||||
@@ -569,11 +549,11 @@ List registered origins.
|
||||
|-----------------|---------|--------------------------------------|
|
||||
| `leases` | `false` | Include referenced leases per origin |
|
||||
|
||||
### `DELETE /-/origins`
|
||||
**`DELETE /-/origins`**
|
||||
|
||||
Deletes all origins and their leases.
|
||||
|
||||
### `GET /-/leases?origin=false`
|
||||
**`GET /-/leases?origin=false`**
|
||||
|
||||
List current leases.
|
||||
|
||||
@@ -581,15 +561,15 @@ List current leases.
|
||||
|-----------------|---------|-------------------------------------|
|
||||
| `origin` | `false` | Include referenced origin per lease |
|
||||
|
||||
### `DELETE /-/lease/{lease_ref}`
|
||||
**`DELETE /-/lease/{lease_ref}`**
|
||||
|
||||
Deletes an lease.
|
||||
|
||||
### `GET /-/client-token`
|
||||
**`GET /-/client-token`**
|
||||
|
||||
Generate client token, (see [installation](#installation)).
|
||||
|
||||
### Others
|
||||
**Others**
|
||||
|
||||
There are many other internal api endpoints for handling authentication and lease process.
|
||||
</details>
|
||||
@@ -616,9 +596,9 @@ Logs are available in `C:\Users\Public\Documents\Nvidia\LoggingLog.NVDisplay.Con
|
||||
|
||||
## Linux
|
||||
|
||||
### `uvicorn.error:Invalid HTTP request received.`
|
||||
### Invalid HTTP request
|
||||
|
||||
This message can be ignored.
|
||||
This error message: `uvicorn.error:Invalid HTTP request received.` can be ignored.
|
||||
|
||||
- Ref. https://github.com/encode/uvicorn/issues/441
|
||||
|
||||
@@ -744,11 +724,40 @@ The error message can safely be ignored (since we have no license limitation :P)
|
||||
|
||||
</details>
|
||||
|
||||
# vGPU Software Compatibility Matrix
|
||||
|
||||
Successfully tested with this package versions.
|
||||
|
||||
| vGPU Suftware | Driver Branch | Linux vGPU Manager | Linux Driver | Windows Driver | Release Date | EOL Date |
|
||||
|:-------------:|:-------------:|--------------------|--------------|----------------|--------------:|--------------:|
|
||||
| `17.4` | R550 | `550.127.06` | `550.127.05` | `553.24` | October 2024 | February 2025 |
|
||||
| `17.3` | R550 | `550.90.05` | `550.90.07` | `552.74` | July 2024 | |
|
||||
| `17.2` | R550 | `550.90.05` | `550.90.07` | `552.55` | June 2024 | |
|
||||
| `17.1` | R550 | `550.54.16` | `550.54.15` | `551.78` | March 2024 | |
|
||||
| `17.0` | R550 | `550.54.10` | `550.54.14` | `551.61` | February 2024 | |
|
||||
| `16.8` | R535 | `535.216.01` | `535.216.01` | `538.95` | October 2024 | July 2026 |
|
||||
| `16.7` | R535 | `535.183.04` | `535.183.06` | `538.78` | July 2024 | |
|
||||
| `16.6` | R535 | `535.183.04` | `535.183.01` | `538.67` | June 2024 | |
|
||||
| `16.5` | R535 | `535.161.05` | `535.161.08` | `538.46` | February 2024 | |
|
||||
| `16.4` | R535 | `535.161.05` | `535.161.07` | `538.33` | February 2024 | |
|
||||
| `16.3` | R535 | `535.154.02` | `535.154.05` | `538.15` | January 2024 | |
|
||||
| `16.2` | R535 | `535.129.03` | `535.129.03` | `537.70` | October 2023 | |
|
||||
| `16.1` | R535 | `535.104.06` | `535.104.05` | `537.13` | August 2023 | |
|
||||
| `16.0` | R535 | `535.54.06` | `535.54.03` | `536.22` | July 2023 | |
|
||||
| `15.4` | R525 | `525.147.01` | `525.147.05` | `529.19` | June 2023 | December 2023 |
|
||||
| `14.4` | R510 | `510.108.03` | `510.108.03` | `514.08` | December 2022 | February 2023 |
|
||||
|
||||
- https://docs.nvidia.com/grid/index.html
|
||||
- https://docs.nvidia.com/grid/gpus-supported-by-vgpu.html
|
||||
|
||||
*To get the latest drivers, visit Nvidia or search in Discord-Channel `GPU Unlocking` (Server-ID: `829786927829745685`)
|
||||
on channel `licensing`
|
||||
|
||||
# Credits
|
||||
|
||||
Thanks to vGPU community and all who uses this project and report bugs.
|
||||
|
||||
Special thanks to
|
||||
Special thanks to:
|
||||
|
||||
- @samicrusader who created build file for **ArchLinux**
|
||||
- @cyrus who wrote the section for **openSUSE**
|
||||
|
||||
19
app/main.py
19
app/main.py
@@ -54,6 +54,14 @@ CORS_ORIGINS = str(env('CORS_ORIGINS', '')).split(',') if (env('CORS_ORIGINS'))
|
||||
jwt_encode_key = jwk.construct(INSTANCE_KEY_RSA.export_key().decode('utf-8'), algorithm=ALGORITHMS.RS256)
|
||||
jwt_decode_key = jwk.construct(INSTANCE_KEY_PUB.export_key().decode('utf-8'), algorithm=ALGORITHMS.RS256)
|
||||
|
||||
# Logging
|
||||
LOG_LEVEL = logging.DEBUG if DEBUG else logging.INFO
|
||||
logging.basicConfig(format='[{levelname:^7}] [{module:^15}] {message}', style='{')
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(LOG_LEVEL)
|
||||
logging.getLogger('util').setLevel(LOG_LEVEL)
|
||||
logging.getLogger('NV').setLevel(LOG_LEVEL)
|
||||
|
||||
|
||||
# FastAPI
|
||||
@asynccontextmanager
|
||||
@@ -88,14 +96,11 @@ app.add_middleware(
|
||||
allow_methods=['*'],
|
||||
allow_headers=['*'],
|
||||
)
|
||||
if bool(env('SUPPORT_MALFORMED_JSON', False)):
|
||||
from middleware import PatchMalformedJsonMiddleware
|
||||
|
||||
# Logging
|
||||
LOG_LEVEL = logging.DEBUG if DEBUG else logging.INFO
|
||||
logging.basicConfig(format='[{levelname:^7}] [{module:^15}] {message}', style='{')
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(LOG_LEVEL)
|
||||
logging.getLogger('util').setLevel(LOG_LEVEL)
|
||||
logging.getLogger('NV').setLevel(LOG_LEVEL)
|
||||
logger.info(f'Enabled "PatchMalformedJsonMiddleware"!')
|
||||
app.add_middleware(PatchMalformedJsonMiddleware, enabled=True)
|
||||
|
||||
|
||||
# Helper
|
||||
|
||||
43
app/middleware.py
Normal file
43
app/middleware.py
Normal file
@@ -0,0 +1,43 @@
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
from starlette.requests import Request
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PatchMalformedJsonMiddleware(BaseHTTPMiddleware):
|
||||
# see oscar.krause/fastapi-dls#1
|
||||
|
||||
REGEX = '(\"mac_address_list\"\:\s?\[)([\w\d])'
|
||||
|
||||
def __init__(self, app, enabled: bool):
|
||||
super().__init__(app)
|
||||
self.enabled = enabled
|
||||
|
||||
async def dispatch(self, request: Request, call_next):
|
||||
body = await request.body()
|
||||
content_type = request.headers.get('Content-Type')
|
||||
|
||||
if self.enabled and content_type == 'application/json':
|
||||
body = body.decode()
|
||||
try:
|
||||
json.loads(body)
|
||||
except json.decoder.JSONDecodeError:
|
||||
logger.warning(f'Malformed json received! Try to fix it, "PatchMalformedJsonMiddleware" is enabled.')
|
||||
s = PatchMalformedJsonMiddleware.fix_json(body)
|
||||
logger.debug(f'Fixed JSON: "{s}"')
|
||||
s = json.loads(s) # ensure json is now valid
|
||||
# set new body
|
||||
request._body = json.dumps(s).encode('utf-8')
|
||||
|
||||
response = await call_next(request)
|
||||
return response
|
||||
|
||||
@staticmethod
|
||||
def fix_json(s: str) -> str:
|
||||
s = s.replace('\t', '')
|
||||
s = s.replace('\n', '')
|
||||
return re.sub(PatchMalformedJsonMiddleware.REGEX, r'\1"\2', s)
|
||||
22
app/orm.py
22
app/orm.py
@@ -1,4 +1,4 @@
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from sqlalchemy import Column, VARCHAR, CHAR, ForeignKey, DATETIME, update, and_, inspect, text
|
||||
@@ -66,7 +66,17 @@ class Origin(Base):
|
||||
if origin_refs is None:
|
||||
deletions = session.query(Origin).delete()
|
||||
else:
|
||||
deletions = session.query(Origin).filter(Origin.origin_ref in origin_refs).delete()
|
||||
deletions = session.query(Origin).filter(Origin.origin_ref.in_(origin_refs)).delete()
|
||||
session.commit()
|
||||
session.close()
|
||||
return deletions
|
||||
|
||||
@staticmethod
|
||||
def delete_expired(engine: Engine) -> int:
|
||||
session = sessionmaker(bind=engine)()
|
||||
origins = session.query(Origin).join(Lease, Origin.origin_ref == Lease.origin_ref, isouter=True).filter(Lease.lease_ref.is_(None)).all()
|
||||
origin_refs = [origin.origin_ref for origin in origins]
|
||||
deletions = session.query(Origin).filter(Origin.origin_ref.in_(origin_refs)).delete()
|
||||
session.commit()
|
||||
session.close()
|
||||
return deletions
|
||||
@@ -94,10 +104,10 @@ class Lease(Base):
|
||||
'lease_ref': self.lease_ref,
|
||||
'origin_ref': self.origin_ref,
|
||||
# 'scope_ref': self.scope_ref,
|
||||
'lease_created': self.lease_created.isoformat(),
|
||||
'lease_expires': self.lease_expires.isoformat(),
|
||||
'lease_updated': self.lease_updated.isoformat(),
|
||||
'lease_renewal': lease_renewal.isoformat(),
|
||||
'lease_created': self.lease_created.replace(tzinfo=timezone.utc).isoformat(),
|
||||
'lease_expires': self.lease_expires.replace(tzinfo=timezone.utc).isoformat(),
|
||||
'lease_updated': self.lease_updated.replace(tzinfo=timezone.utc).isoformat(),
|
||||
'lease_renewal': lease_renewal.replace(tzinfo=timezone.utc).isoformat(),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
fastapi==0.111.0
|
||||
uvicorn[standard]==0.29.0
|
||||
fastapi==0.115.5
|
||||
uvicorn[standard]==0.32.0
|
||||
python-jose==3.3.0
|
||||
pycryptodome==3.20.0
|
||||
pycryptodome==3.21.0
|
||||
python-dateutil==2.8.2
|
||||
sqlalchemy==2.0.30
|
||||
markdown==3.6
|
||||
sqlalchemy==2.0.36
|
||||
markdown==3.7
|
||||
python-dotenv==1.0.1
|
||||
|
||||
@@ -4,7 +4,7 @@ logging.basicConfig()
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
URL = 'https://docs.nvidia.com/grid/'
|
||||
URL = 'https://docs.nvidia.com/vgpu/index.html'
|
||||
|
||||
BRANCH_STATUS_KEY, SOFTWARE_BRANCH_KEY, = 'vGPU Branch Status', 'vGPU Software Branch'
|
||||
VGPU_KEY, GRID_KEY, DRIVER_BRANCH_KEY = 'vGPU Software', 'vGPU Software', 'Driver Branch'
|
||||
@@ -25,15 +25,15 @@ def __driver_versions(html: 'BeautifulSoup'):
|
||||
return _
|
||||
|
||||
# find wrapper for "DriverVersions" and find tables
|
||||
data = html.find('div', {'id': 'DriverVersions'})
|
||||
tables = data.findAll('table')
|
||||
for table in tables:
|
||||
# parse software-branch (e.g. "vGPU software 17 Releases" and remove " Releases" for "matrix_key")
|
||||
software_branch = table.parent.find_previous_sibling('button', {'class': 'accordion'}).text.strip()
|
||||
data = html.find('div', {'id': 'driver-versions'})
|
||||
items = data.findAll('bsp-accordion', {'class': 'Accordion-items-item'})
|
||||
for item in items:
|
||||
software_branch = item.find('div', {'class': 'Accordion-items-item-title'}).text.strip()
|
||||
software_branch = software_branch.replace(' Releases', '')
|
||||
matrix_key = software_branch.lower()
|
||||
|
||||
# driver version info from table-heads (ths) and table-rows (trs)
|
||||
table = item.find('table')
|
||||
ths, trs = table.find_all('th'), table.find_all('tr')
|
||||
headers, releases = [header.text.strip() for header in ths], []
|
||||
for trs in trs:
|
||||
@@ -50,7 +50,7 @@ def __driver_versions(html: 'BeautifulSoup'):
|
||||
|
||||
def __release_branches(html: 'BeautifulSoup'):
|
||||
# find wrapper for "AllReleaseBranches" and find table
|
||||
data = html.find('div', {'id': 'AllReleaseBranches'})
|
||||
data = html.find('div', {'id': 'all-release-branches'})
|
||||
table = data.find('table')
|
||||
|
||||
# branch releases info from table-heads (ths) and table-rows (trs)
|
||||
|
||||
14
test/main.py
14
test/main.py
@@ -1,7 +1,8 @@
|
||||
import sys
|
||||
from base64 import b64encode as b64enc
|
||||
from hashlib import sha256
|
||||
from calendar import timegm
|
||||
from datetime import datetime
|
||||
from hashlib import sha256
|
||||
from os.path import dirname, join
|
||||
from uuid import uuid4, UUID
|
||||
|
||||
@@ -9,7 +10,6 @@ from dateutil.relativedelta import relativedelta
|
||||
from jose import jwt, jwk
|
||||
from jose.constants import ALGORITHMS
|
||||
from starlette.testclient import TestClient
|
||||
import sys
|
||||
|
||||
# add relative path to use packages as they were in the app/ dir
|
||||
sys.path.append('../')
|
||||
@@ -18,6 +18,7 @@ sys.path.append('../app')
|
||||
from app import main
|
||||
from app.util import load_key
|
||||
|
||||
# main.app.add_middleware(PatchMalformedJsonMiddleware, enabled=True)
|
||||
client = TestClient(main.app)
|
||||
|
||||
ORIGIN_REF, ALLOTMENT_REF, SECRET = str(uuid4()), '20000000-0000-0000-0000-000000000001', 'HelloWorld'
|
||||
@@ -106,6 +107,15 @@ def test_auth_v1_origin():
|
||||
assert response.json().get('origin_ref') == ORIGIN_REF
|
||||
|
||||
|
||||
def test_auth_v1_origin_malformed_json(): # see oscar.krause/fastapi-dls#1
|
||||
from middleware import PatchMalformedJsonMiddleware
|
||||
|
||||
# test regex (temporary, until this section is merged into main.py
|
||||
s = '{"environment": {"fingerprint": {"mac_address_list": [ff:ff:ff:ff:ff:ff"]}}'
|
||||
replaced = PatchMalformedJsonMiddleware.fix_json(s)
|
||||
assert replaced == '{"environment": {"fingerprint": {"mac_address_list": ["ff:ff:ff:ff:ff:ff"]}}'
|
||||
|
||||
|
||||
def auth_v1_origin_update():
|
||||
payload = {
|
||||
"registration_pending": False,
|
||||
|
||||
Reference in New Issue
Block a user