diff --git a/.DEBIAN/control b/.DEBIAN/control index c2f6ccd..b58c41c 100644 --- a/.DEBIAN/control +++ b/.DEBIAN/control @@ -2,7 +2,7 @@ Package: fastapi-dls Version: 0.0 Architecture: all Maintainer: Oscar Krause oscar.krause@collinwebdesigns.de -Depends: python3, python3-fastapi, python3-uvicorn, python3-dotenv, python3-dateutil, python3-josepy, python3-sqlalchemy, python3-pycryptodome, python3-markdown, uvicorn, openssl +Depends: python3, python3-fastapi, python3-uvicorn, python3-dotenv, python3-dateutil, python3-josepy, python3-sqlalchemy, python3-cryptography, python3-markdown, uvicorn, openssl Recommends: curl Installed-Size: 10240 Homepage: https://git.collinwebdesigns.de/oscar.krause/fastapi-dls diff --git a/.DEBIAN/requirements-bookworm-12.txt b/.DEBIAN/requirements-bookworm-12.txt index 223c64c..c3fe52e 100644 --- a/.DEBIAN/requirements-bookworm-12.txt +++ b/.DEBIAN/requirements-bookworm-12.txt @@ -1,8 +1,8 @@ # https://packages.debian.org/hu/ fastapi==0.92.0 uvicorn[standard]==0.17.6 -python-jose[pycryptodome]==3.3.0 -pycryptodome==3.11.0 +python-jose[cryptography]==3.3.0 +cryptography==38.0.4 python-dateutil==2.8.2 sqlalchemy==1.4.46 markdown==3.4.1 diff --git a/.DEBIAN/requirements-ubuntu-24.04.txt b/.DEBIAN/requirements-ubuntu-24.04.txt index 7cb653b..0ba3025 100644 --- a/.DEBIAN/requirements-ubuntu-24.04.txt +++ b/.DEBIAN/requirements-ubuntu-24.04.txt @@ -1,8 +1,8 @@ # https://packages.ubuntu.com fastapi==0.101.0 uvicorn[standard]==0.27.1 -python-jose[pycryptodome]==3.3.0 -pycryptodome==3.20.0 +python-jose[cryptography]==3.3.0 +cryptography==41.0.7 python-dateutil==2.8.2 sqlalchemy==1.4.50 markdown==3.5.2 diff --git a/.DEBIAN/requirements-ubuntu-24.10.txt b/.DEBIAN/requirements-ubuntu-24.10.txt index 7a65314..59f9361 100644 --- a/.DEBIAN/requirements-ubuntu-24.10.txt +++ b/.DEBIAN/requirements-ubuntu-24.10.txt @@ -1,8 +1,8 @@ # https://packages.ubuntu.com fastapi==0.110.3 uvicorn[standard]==0.30.3 -python-jose[pycryptodome]==3.3.0 -pycryptodome==3.20.0 +python-jose[cryptography]==3.3.0 +cryptography==42.0.5 python-dateutil==2.9.0 sqlalchemy==2.0.32 markdown==3.6 diff --git a/.PKGBUILD/PKGBUILD b/.PKGBUILD/PKGBUILD index 09f606b..2504aaa 100644 --- a/.PKGBUILD/PKGBUILD +++ b/.PKGBUILD/PKGBUILD @@ -8,7 +8,7 @@ pkgdesc='NVIDIA DLS server implementation with FastAPI' arch=('any') url='https://git.collinwebdesigns.de/oscar.krause/fastapi-dls' license=('MIT') -depends=('python' 'python-jose' 'python-starlette' 'python-httpx' 'python-fastapi' 'python-dotenv' 'python-dateutil' 'python-sqlalchemy' 'python-pycryptodome' 'uvicorn' 'python-markdown' 'openssl') +depends=('python' 'python-jose' 'python-starlette' 'python-httpx' 'python-fastapi' 'python-dotenv' 'python-dateutil' 'python-sqlalchemy' 'python-cryptography' 'uvicorn' 'python-markdown' 'openssl') provider=("$pkgname") install="$pkgname.install" backup=('etc/default/fastapi-dls') @@ -39,7 +39,7 @@ check() { package() { install -d "$pkgdir/usr/share/doc/$pkgname" install -d "$pkgdir/var/lib/$pkgname/cert" - cp -r "$srcdir/$pkgname/doc"/* "$pkgdir/usr/share/doc/$pkgname/" + #cp -r "$srcdir/$pkgname/doc"/* "$pkgdir/usr/share/doc/$pkgname/" install -Dm644 "$srcdir/$pkgname/README.md" "$pkgdir/usr/share/doc/$pkgname/README.md" install -Dm644 "$srcdir/$pkgname/version.env" "$pkgdir/usr/share/doc/$pkgname/version.env" diff --git a/FAQ.md b/FAQ.md deleted file mode 100644 index 4ddd379..0000000 --- a/FAQ.md +++ /dev/null @@ -1,17 +0,0 @@ -# FAQ - -## `Failed to acquire license from (Info: - Error: The allowed time to process response has expired)` - -- Did your timezone settings are correct on fastapi-dls **and your guest**? - -- Did you download the client-token more than an hour ago? - -Please download a new client-token. The guest have to register within an hour after client-token was created. - - -## `jose.exceptions.JWTError: Signature verification failed.` - -- Did you recreated `instance.public.pem` / `instance.private.pem`? - -Then you have to download a **new** client-token on each of your guests. - diff --git a/README.md b/README.md index 3d18a01..f928f84 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,12 @@ Minimal Delegated License Service (DLS). +> [!note] > Compatibility tested with official NLS 2.0.1, 2.1.0, 3.1.0, 3.3.1, 3.4.0. For Driver compatibility -see [compatibility matrix](#vgpu-software-compatibility-matrix). -Drivers are only supported until **17.x releases**. +> see [compatibility matrix](#vgpu-software-compatibility-matrix). + +> [!warning] 18.x Drivers are not yet supported! +> Drivers are only supported until **17.x releases**. This service can be used without internet connection. Only the clients need a connection to this service on configured port. @@ -83,7 +86,7 @@ docker run -e DLS_URL=`hostname -i` -e DLS_PORT=443 -p 443:443 -v $WORKING_DIR:/ See [`examples`](examples) directory for more advanced examples (with reverse proxy usage). -> Adjust *REQUIRED* variables as needed +> Adjust `REQUIRED` variables as needed ```yaml version: '3.9' @@ -330,14 +333,14 @@ Packages are available here: - [GitLab-Registry](https://git.collinwebdesigns.de/oscar.krause/fastapi-dls/-/packages) -Successful tested with: +Successful tested with (**LTS Version**): - **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) -- *Ubuntu 24.10 (Oracular Oriole)* (EOL: tba.) +- **Ubuntu 24.04 (Noble Numbat)** (EOL: Apr 2029) +- *Ubuntu 24.10 (Oracular Oriole)* (EOL: Jul 2025) Not working with: @@ -600,6 +603,21 @@ Logs are available in `C:\Users\Public\Documents\Nvidia\LoggingLog.NVDisplay.Con # Known Issues +## Generic + +### `Failed to acquire license from (Info: - Error: The allowed time to process response has expired)` + +- Did your timezone settings are correct on fastapi-dls **and your guest**? +- Did you download the client-token more than an hour ago? + +Please download a new client-token. The guest have to register within an hour after client-token was created. + +### `jose.exceptions.JWTError: Signature verification failed.` + +- Did you recreate `instance.public.pem` / `instance.private.pem`? + +Then you have to download a **new** client-token on each of your guests. + ## Linux ### Invalid HTTP request diff --git a/app/main.py b/app/main.py index 850a6a2..f11ba5c 100644 --- a/app/main.py +++ b/app/main.py @@ -21,7 +21,7 @@ from starlette.middleware.cors import CORSMiddleware from starlette.responses import StreamingResponse, JSONResponse as JSONr, HTMLResponse as HTMLr, Response, RedirectResponse from orm import Origin, Lease, init as db_init, migrate -from util import load_key, load_file +from util import PrivateKey, PublicKey, load_file # Load variables load_dotenv('../version.env') @@ -42,8 +42,8 @@ DLS_PORT = int(env('DLS_PORT', '443')) SITE_KEY_XID = str(env('SITE_KEY_XID', '00000000-0000-0000-0000-000000000000')) INSTANCE_REF = str(env('INSTANCE_REF', '10000000-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_PUB = load_key(str(env('INSTANCE_KEY_PUB', join(dirname(__file__), 'cert/instance.public.pem')))) +INSTANCE_KEY_RSA = PrivateKey.from_file(str(env('INSTANCE_KEY_RSA', join(dirname(__file__), 'cert/instance.private.pem')))) +INSTANCE_KEY_PUB = PublicKey.from_file(str(env('INSTANCE_KEY_PUB', join(dirname(__file__), 'cert/instance.public.pem')))) 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_RENEWAL_PERIOD = float(env('LEASE_RENEWAL_PERIOD', 0.15)) @@ -51,8 +51,8 @@ LEASE_RENEWAL_DELTA = timedelta(days=int(env('LEASE_EXPIRE_DAYS', 90)), hours=in CLIENT_TOKEN_EXPIRE_DELTA = relativedelta(years=12) 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_decode_key = jwk.construct(INSTANCE_KEY_PUB.export_key().decode('utf-8'), algorithm=ALGORITHMS.RS256) +jwt_encode_key = jwk.construct(INSTANCE_KEY_RSA.pem(), algorithm=ALGORITHMS.RS256) +jwt_decode_key = jwk.construct(INSTANCE_KEY_PUB.pem(), algorithm=ALGORITHMS.RS256) # Logging LOG_LEVEL = logging.DEBUG if DEBUG else logging.INFO @@ -264,10 +264,10 @@ async def _client_token(): }, "service_instance_public_key_configuration": { "service_instance_public_key_me": { - "mod": hex(INSTANCE_KEY_PUB.public_key().n)[2:], - "exp": int(INSTANCE_KEY_PUB.public_key().e), + "mod": hex(INSTANCE_KEY_PUB.raw().public_numbers().n)[2:], + "exp": int(INSTANCE_KEY_PUB.raw().public_numbers().e), }, - "service_instance_public_key_pem": INSTANCE_KEY_PUB.export_key().decode('utf-8'), + "service_instance_public_key_pem": INSTANCE_KEY_PUB.pem().decode('utf-8'), "key_retention_mode": "LATEST_ONLY" }, } diff --git a/app/util.py b/app/util.py index b5b1ff1..1aae17b 100644 --- a/app/util.py +++ b/app/util.py @@ -1,8 +1,81 @@ import logging +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey, RSAPublicKey, generate_private_key +from cryptography.hazmat.primitives.serialization import load_pem_private_key, load_pem_public_key + logging.basicConfig() +class PrivateKey: + + def __init__(self, data: bytes): + self.__key = load_pem_private_key(data, password=None) + + @staticmethod + def from_file(filename: str) -> "PrivateKey": + log = logging.getLogger(__name__) + log.debug(f'Importing RSA-Private-Key from "{filename}"') + + with open(filename, 'rb') as f: + data = f.read() + + return PrivateKey(data=data.strip()) + + def raw(self) -> RSAPrivateKey: + return self.__key + + def pem(self) -> bytes: + return self.__key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption() + ) + + def public_key(self) -> "PublicKey": + data = self.__key.public_key().public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo + ) + return PublicKey(data=data) + + @staticmethod + def generate(public_exponent: int = 65537, key_size: int = 2048) -> "PrivateKey": + log = logging.getLogger(__name__) + log.debug(f'Generating RSA-Key') + key = generate_private_key(public_exponent=public_exponent, key_size=key_size) + data = key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption() + ) + return PrivateKey(data=data) + + +class PublicKey: + + def __init__(self, data: bytes): + self.__key = load_pem_public_key(data) + + @staticmethod + def from_file(filename: str) -> "PublicKey": + log = logging.getLogger(__name__) + log.debug(f'Importing RSA-Public-Key from "{filename}"') + + with open(filename, 'rb') as f: + data = f.read() + + return PublicKey(data=data.strip()) + + def raw(self) -> RSAPublicKey: + return self.__key + + def pem(self) -> bytes: + return self.__key.public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo + ) + def load_file(filename: str) -> bytes: log = logging.getLogger(f'{__name__}') log.debug(f'Loading contents of file "{filename}') @@ -11,33 +84,6 @@ def load_file(filename: str) -> bytes: return content -def load_key(filename: str) -> "RsaKey": - try: - # Crypto | Cryptodome on Debian - from Crypto.PublicKey import RSA - from Crypto.PublicKey.RSA import RsaKey - except ModuleNotFoundError: - from Cryptodome.PublicKey import RSA - from Cryptodome.PublicKey.RSA import RsaKey - - log = logging.getLogger(__name__) - log.debug(f'Importing RSA-Key from "{filename}"') - return RSA.import_key(extern_key=load_file(filename), passphrase=None) - - -def generate_key() -> "RsaKey": - try: - # Crypto | Cryptodome on Debian - from Crypto.PublicKey import RSA - from Crypto.PublicKey.RSA import RsaKey - except ModuleNotFoundError: - from Cryptodome.PublicKey import RSA - from Cryptodome.PublicKey.RSA import RsaKey - log = logging.getLogger(__name__) - log.debug(f'Generating RSA-Key') - return RSA.generate(bits=2048) - - class NV: __DRIVER_MATRIX_FILENAME = 'static/driver_matrix.json' __DRIVER_MATRIX: None | dict = None # https://docs.nvidia.com/grid/ => "Driver Versions" diff --git a/doc/Database.md b/doc/Database.md deleted file mode 100644 index 5a838a3..0000000 --- a/doc/Database.md +++ /dev/null @@ -1,26 +0,0 @@ -# Database structure - -## `request_routing.service_instance` - -| xid | org_name | -|----------------------------------------|--------------------------| -| `10000000-0000-0000-0000-000000000000` | `lic-000000000000000000` | - -- `xid` is used as `SERVICE_INSTANCE_XID` - -## `request_routing.license_allotment_service_instance` - -| xid | service_instance_xid | license_allotment_xid | -|----------------------------------------|----------------------------------------|----------------------------------------| -| `90000000-0000-0000-0000-000000000001` | `10000000-0000-0000-0000-000000000000` | `80000000-0000-0000-0000-000000000001` | - -- `xid` is only a primary-key and never used as foreign-key or reference -- `license_allotment_xid` must be used to fetch `xid`'s from `request_routing.license_allotment_reference` - -## `request_routing.license_allotment_reference` - -| xid | license_allotment_xid | -|----------------------------------------|----------------------------------------| -| `20000000-0000-0000-0000-000000000001` | `80000000-0000-0000-0000-000000000001` | - -- `xid` is used as `scope_ref_list` on token request diff --git a/doc/Reverse Engineering Notes.md b/doc/Reverse Engineering Notes.md deleted file mode 100644 index fd1f67f..0000000 --- a/doc/Reverse Engineering Notes.md +++ /dev/null @@ -1,186 +0,0 @@ -# Reverse Engineering Notes - -[[_TOC_]] - -# Usefully commands - -## Check licensing status - -- `nvidia-smi -q | grep "License"` - -**Output** - -``` -vGPU Software Licensed Product - License Status : Licensed (Expiry: 2023-1-14 12:59:52 GMT) -``` - -## Track licensing progress - -- NVIDIA Grid Log: `journalctl -u nvidia-gridd -f` - -``` -systemd[1]: Started NVIDIA Grid Daemon. -nvidia-gridd[2986]: Configuration parameter ( ServerAddress ) not set -nvidia-gridd[2986]: vGPU Software package (0) -nvidia-gridd[2986]: Ignore service provider and node-locked licensing -nvidia-gridd[2986]: NLS initialized -nvidia-gridd[2986]: Acquiring license. (Info: license.nvidia.space; NVIDIA RTX Virtual Workstation) -nvidia-gridd[2986]: License acquired successfully. (Info: license.nvidia.space, NVIDIA RTX Virtual Workstation; Expiry: 2023-1-29 22:3:0 GMT) -``` - -# Docker DLS-Container File-System - -- More about Docker Images https://git.collinwebdesigns.de/nvidia/nls - -## Configuration data - -Most variables and configs are stored in `/var/lib/docker/volumes/configurations/_data`. - -Files can be modified with `docker cp :/venv/... /opt/localfile/...` and back. -(May you need to fix permissions with `docker exec -u 0 chown nonroot:nonroot /venv/...`) - -Config-Variables are in `etc/dls/config/service_env.conf`. - - -## Site Key Uri - `/etc/dls/config/site_key_uri.bin` - -``` -base64-content... -``` - -## DB Password - `/etc/dls/config/dls_db_password.bin` - -``` -# docker cp -a :/etc/dls/config/dls_db_password.bin /tmp/dls_db_password.bin -base64-content... -``` - -**Decrypt database password** - -``` -cat dls_db_password.bin | base64 -d > dls_db_password.bin.raw -openssl rsautl -decrypt -inkey /tmp/private-key.pem -in dls_db_password.bin.raw -``` - -# Docker Postgres-Container - -- It's enough to manipulate database licenses. There must not be changed any line of code to bypass licensing - validations. - -## Inspect - -Valid users are `dls_writer` and `postgres`. - -```shell -docker exec -it psql -h localhost -U postgres -``` - -## External Access - -Or you can modify `docker-compose.yaml` to forward Postgres port. To create a superuser for external access, use `docker exec` from above and rund the following: - -```sql -CREATE USER admin WITH LOGIN SUPERUSER PASSWORD 'admin'; -``` - -# Dive / Docker image inspector - -- `dive dls:appliance` - -The source code is stored in `/venv/lib/python3.9/site-packages/nls_*`. - -Image-Reference: - -``` -Tags: (unavailable) -Id: d1c7976a5d2b3681ff6c5a30f8187e4015187a83f3f285ba4a37a45458bd6b98 -Digest: sha256:311223c5af7a298ec1104f5dc8c3019bfb0e1f77256dc3d995244ffb295a97 -1f -Command: -#(nop) ADD file:c1900d3e3a29c29a743a8da86c437006ec5d2aa873fb24e48033b6bf492bb37b in / -``` - -# Logging / Stack Trace - -- https://docs.nvidia.com/license-system/latest/nvidia-license-system-user-guide/index.html#troubleshooting-dls-instance - -**Failed licensing log** - -``` -{ - "activity": 100, - "context": { - "SERVICE_INSTANCE_ID": "b43d6e46-d6d0-4943-8b8d-c66a5f6e0d38", - "SERVICE_INSTANCE_NAME": "DEFAULT_2022-12-14_12:48:30", - "description": "borrow failed: NotFoundError(no pool features found for: NVIDIA RTX Virtual Workstation)", - "event_type": null, - "function_name": "_evt", - "lineno": 54, - "module_name": "nls_dal_lease_dls.event", - "operation_id": "e72a8ca7-34cc-4e11-b80c-273592085a24", - "origin_ref": "3f7f5a50-a26b-425b-8d5e-157f63e72b1c", - "service_name": "nls_services_lease" - }, - "detail": { - "oc": { - "license_allotment_xid": "10c4317f-7c4c-11ed-a524-0e4252a7e5f1", - "origin_ref": "3f7f5a50-a26b-425b-8d5e-157f63e72b1c", - "service_instance_xid": "b43d6e46-d6d0-4943-8b8d-c66a5f6e0d38" - }, - "operation_id": "e72a8ca7-34cc-4e11-b80c-273592085a24" - }, - "id": "0cc9e092-3b92-4652-8d9e-7622ef85dc79", - "metadata": {}, - "ts": "2022-12-15T10:25:36.827661Z" -} - -{ - "activity": 400, - "context": { - "SERVICE_INSTANCE_ID": "b43d6e46-d6d0-4943-8b8d-c66a5f6e0d38", - "SERVICE_INSTANCE_NAME": "DEFAULT_2022-12-14_12:48:30", - "description": "lease_multi_create failed: no pool features found for: NVIDIA RTX Virtual Workstation", - "event_by": "system", - "function_name": "lease_multi_create", - "level": "warning", - "lineno": 157, - "module_name": "nls_services_lease.controllers.lease_multi_controller", - "operation_id": "e72a8ca7-34cc-4e11-b80c-273592085a24", - "service_name": "nls_services_lease" - }, - "detail": { - "_msg": "lease_multi_create failed: no pool features found for: NVIDIA RTX Virtual Workstation", - "exec_info": ["NotFoundError", "NotFoundError(no pool features found for: NVIDIA RTX Virtual Workstation)", " File \"/venv/lib/python3.9/site-packages/nls_services_lease/controllers/lease_multi_controller.py\", line 127, in lease_multi_create\n data = _leaseMulti.lease_multi_create(event_args)\n File \"/venv/lib/python3.9/site-packages/nls_core_lease/lease_multi.py\", line 208, in lease_multi_create\n raise e\n File \"/venv/lib/python3.9/site-packages/nls_core_lease/lease_multi.py\", line 184, in lease_multi_create\n self._try_proposals(oc, mlr, results, detail)\n File \"/venv/lib/python3.9/site-packages/nls_core_lease/lease_multi.py\", line 219, in _try_proposals\n lease = self._leases.create(creator)\n File \"/venv/lib/python3.9/site-packages/nls_dal_lease_dls/leases.py\", line 230, in create\n features = self._get_features(creator)\n File \"/venv/lib/python3.9/site-packages/nls_dal_lease_dls/leases.py\", line 148, in _get_features\n self._explain_not_available(cur, creator)\n File \"/venv/lib/python3.9/site-packages/nls_dal_lease_dls/leases.py\", line 299, in _explain_not_available\n raise NotFoundError(f'no pool features found for: {lcc.product_name}')\n"], - "operation_id": "e72a8ca7-34cc-4e11-b80c-273592085a24" - }, - "id": "282801b9-d612-40a5-9145-b56d8e420dac", - "metadata": {}, - "ts": "2022-12-15T10:25:36.831673Z" -} - -``` - -**Stack Trace** - -``` -"NotFoundError", "NotFoundError(no pool features found for: NVIDIA RTX Virtual Workstation)", " File \"/venv/lib/python3.9/site-packages/nls_services_lease/controllers/lease_multi_controller.py\", line 127, in lease_multi_create - data = _leaseMulti.lease_multi_create(event_args) - File \"/venv/lib/python3.9/site-packages/nls_core_lease/lease_multi.py\", line 208, in lease_multi_create - raise e - File \"/venv/lib/python3.9/site-packages/nls_core_lease/lease_multi.py\", line 184, in lease_multi_create - self._try_proposals(oc, mlr, results, detail) - File \"/venv/lib/python3.9/site-packages/nls_core_lease/lease_multi.py\", line 219, in _try_proposals - lease = self._leases.create(creator) - File \"/venv/lib/python3.9/site-packages/nls_dal_lease_dls/leases.py\", line 230, in create - features = self._get_features(creator) - File \"/venv/lib/python3.9/site-packages/nls_dal_lease_dls/leases.py\", line 148, in _get_features - self._explain_not_available(cur, creator) - File \"/venv/lib/python3.9/site-packages/nls_dal_lease_dls/leases.py\", line 299, in _explain_not_available - raise NotFoundError(f'no pool features found for: {lcc.product_name}') -" -``` - -# Nginx - -- NGINX uses `/opt/certs/cert.pem` and `/opt/certs/key.pem` diff --git a/requirements.txt b/requirements.txt index 6faecca..78e826b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,8 @@ -fastapi==0.115.8 +fastapi==0.115.11 uvicorn[standard]==0.34.0 -python-jose==3.4.0 -pycryptodome==3.21.0 -python-dateutil==2.8.2 -sqlalchemy==2.0.38 +python-jose[cryptography]==3.4.0 +cryptography==44.0.2 +python-dateutil==2.9.0 +sqlalchemy==2.0.39 markdown==3.7 python-dotenv==1.0.1 diff --git a/test/main.py b/test/main.py index a10f2c7..653548f 100644 --- a/test/main.py +++ b/test/main.py @@ -16,7 +16,7 @@ sys.path.append('../') sys.path.append('../app') from app import main -from app.util import load_key +from util import PrivateKey, PublicKey client = TestClient(main.app) @@ -25,11 +25,11 @@ ORIGIN_REF, ALLOTMENT_REF, SECRET = str(uuid4()), '20000000-0000-0000-0000-00000 # INSTANCE_KEY_RSA = generate_key() # INSTANCE_KEY_PUB = INSTANCE_KEY_RSA.public_key() -INSTANCE_KEY_RSA = load_key(str(join(dirname(__file__), '../app/cert/instance.private.pem'))) -INSTANCE_KEY_PUB = load_key(str(join(dirname(__file__), '../app/cert/instance.public.pem'))) +INSTANCE_KEY_RSA = PrivateKey.from_file(str(join(dirname(__file__), '../app/cert/instance.private.pem'))) +INSTANCE_KEY_PUB = PublicKey.from_file(str(join(dirname(__file__), '../app/cert/instance.public.pem'))) -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) +jwt_encode_key = jwk.construct(INSTANCE_KEY_RSA.pem(), algorithm=ALGORITHMS.RS256) +jwt_decode_key = jwk.construct(INSTANCE_KEY_PUB.pem(), algorithm=ALGORITHMS.RS256) def __bearer_token(origin_ref: str) -> str: @@ -187,8 +187,6 @@ def test_leasing_v1_lessor(): assert len(lease_result_list[0]['lease']['ref']) == 36 assert str(UUID(lease_result_list[0]['lease']['ref'])) == lease_result_list[0]['lease']['ref'] - return lease_result_list[0]['lease']['ref'] - def test_leasing_v1_lessor_lease(): response = client.get('/leasing/v1/lessor/leases', headers={'authorization': __bearer_token(ORIGIN_REF)}) @@ -231,7 +229,23 @@ def test_leasing_v1_lease_delete(): def test_leasing_v1_lessor_lease_remove(): - lease_ref = test_leasing_v1_lessor() + # see "test_leasing_v1_lessor()" + payload = { + 'fulfillment_context': { + 'fulfillment_class_ref_list': [] + }, + 'lease_proposal_list': [{ + 'license_type_qualifiers': {'count': 1}, + 'product': {'name': 'NVIDIA RTX Virtual Workstation'} + }], + 'proposal_evaluation_mode': 'ALL_OF', + 'scope_ref_list': [ALLOTMENT_REF] + } + + response = client.post('/leasing/v1/lessor', json=payload, headers={'authorization': __bearer_token(ORIGIN_REF)}) + lease_result_list = response.json().get('lease_result_list') + lease_ref = lease_result_list[0]['lease']['ref'] + # response = client.delete('/leasing/v1/lessor/leases', headers={'authorization': __bearer_token(ORIGIN_REF)}) assert response.status_code == 200