Merge branch 'dev' into ui

This commit is contained in:
Oscar Krause 2023-01-03 20:45:51 +01:00
commit 139fdd3472
7 changed files with 174 additions and 20 deletions

View File

@ -267,20 +267,31 @@ deploy:pacman:
- 'echo "EXPORT_NAME: ${EXPORT_NAME}"' - 'echo "EXPORT_NAME: ${EXPORT_NAME}"'
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${EXPORT_NAME} "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/${PACKAGE_NAME}/${PACKAGE_VERSION}/${EXPORT_NAME}"' - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${EXPORT_NAME} "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/${PACKAGE_NAME}/${PACKAGE_VERSION}/${EXPORT_NAME}"'
release: release:prepare:
image: registry.gitlab.com/gitlab-org/release-cli:latest stage: .pre
stage: .post
rules: rules:
- if: $CI_COMMIT_TAG - if: $CI_COMMIT_TAG
when: never when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
before_script: script:
- set -a # make variables from "source" command available to release-cli
- source version.env - source version.env
- echo &VERSION
artifacts:
reports:
dotenv: version.env
release:
image: registry.gitlab.com/gitlab-org/release-cli:latest
stage: .post
needs:
- job: release:prepare
artifacts: true
rules:
- if: $CI_COMMIT_TAG
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
script: script:
- echo "Running release-job for $VERSION" - echo "Running release-job for $VERSION"
after_script:
- set +a
release: release:
name: $CI_PROJECT_TITLE $version name: $CI_PROJECT_TITLE $version
description: Release of $CI_PROJECT_TITLE version $VERSION description: Release of $CI_PROJECT_TITLE version $VERSION

View File

@ -11,7 +11,8 @@ Only the clients need a connection to this service on configured port.
## ToDo's ## ToDo's
- Support http mode for using external https proxy (disable uvicorn ssl for using behind proxy) - check why windows guests display "can't acquire license" although in log there is no message displayed and license is
also acquired successfully
## Endpoints ## Endpoints
@ -102,6 +103,8 @@ docker run -e DLS_URL=`hostname -i` -e DLS_PORT=443 -p 443:443 -v $WORKING_DIR:/
**Docker-Compose / Deploy stack** **Docker-Compose / Deploy stack**
Goto [`docker-compose.yml`](docker-compose.yml) for more advanced example.
```yaml ```yaml
version: '3.9' version: '3.9'
@ -316,7 +319,7 @@ Successfully tested with this package versions:
## Linux ## Linux
```shell ```shell
curl --insecure -L -X GET https://<dls-hostname-or-ip>/client-token -o /etc/nvidia/ClientConfigToken/client_configuration_token.tok 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
nvidia-smi -q | grep "License" nvidia-smi -q | grep "License"
``` ```
@ -439,7 +442,10 @@ Dec 20 17:53:34 ubuntu-grid-server nvidia-gridd[10354]: License acquired success
</details> </details>
### Error on releasing leases on shutdown ### Error on releasing leases on shutdown (fixed in 1.3 by using reverse proxy)
**UPDATE for version `1.3`**: This issue can be fixed by using a reverse proxy (e.g. `nginx`). Please read section
below.
The driver wants to release current leases on shutting down windows. This endpoint needs to be a http endpoint and The driver wants to release current leases on shutting down windows. This endpoint needs to be a http endpoint and
is currently not implemented. The error message looks like and safely can be ignored (since we have no license is currently not implemented. The error message looks like and safely can be ignored (since we have no license
@ -452,6 +458,21 @@ limitation :P):
<0>:End Logging <0>:End Logging
``` ```
#### log with 1.3 and nginx as reverse proxy
```
<1>:NLS initialized
<2>:NLS initialized
<1>:Valid GRID license not found. GPU features and performance will be fully degraded. To enable full functionality please configure licensing details.
<1>:License acquired successfully. (Info: 192.168.178.33, NVIDIA RTX Virtual Workstation; Expiry: 2023-1-4 16:48:20 GMT)
<2>:Valid GRID license not found. GPU features and performance will be fully degraded. To enable full functionality please configure licensing details.
<2>:License acquired successfully from local trusted store. (Info: 192.168.178.33, NVIDIA RTX Virtual Workstation; Expiry: 2023-1-4 16:48:20 GMT)
<2>:End Logging
<1>:End Logging
<0>:License returned successfully. (Info: 192.168.178.33)
<0>:End Logging
```
# Credits # Credits
Thanks to vGPU community and all who uses this project and report bugs. Thanks to vGPU community and all who uses this project and report bugs.

View File

@ -46,7 +46,7 @@ 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(hours=1) # days=1
LEASE_EXPIRE_DELTA = relativedelta(days=int(env('LEASE_EXPIRE_DAYS', 90))) 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}']
@ -484,7 +484,7 @@ async def leasing_v1_lessor_lease_remove(request: Request):
@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')) 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})

View File

@ -41,7 +41,6 @@ class Origin(Base):
def create_or_update(engine: Engine, origin: "Origin"): def create_or_update(engine: Engine, origin: "Origin"):
session = sessionmaker(bind=engine)() session = sessionmaker(bind=engine)()
entity = session.query(Origin).filter(Origin.origin_ref == origin.origin_ref).first() entity = session.query(Origin).filter(Origin.origin_ref == origin.origin_ref).first()
print(entity)
if entity is None: if entity is None:
session.add(origin) session.add(origin)
else: else:

View File

@ -34,6 +34,7 @@ nvidia-gridd[2986]: License acquired successfully. (Info: license.nvidia.space,
Most variables and configs are stored in `/var/lib/docker/volumes/configurations/_data`. Most variables and configs are stored in `/var/lib/docker/volumes/configurations/_data`.
Files can be modified with `docker cp <container-id>:/venv/... /opt/localfile/...` and back. Files can be modified with `docker cp <container-id>:/venv/... /opt/localfile/...` and back.
(May you need to fix permissions with `docker exec -u 0 <container-id> chown nonroot:nonroot /venv/...`)
## Dive / Docker image inspector ## Dive / Docker image inspector

114
docker-compose.yml Normal file
View File

@ -0,0 +1,114 @@
version: '3.9'
x-dls-variables: &dls-variables
DLS_URL: localhost # REQUIRED
DLS_PORT: 443 # must match nginx listen port
LEASE_EXPIRE_DAYS: 90
DATABASE: sqlite:////app/database/db.sqlite
DEBUG: false
services:
web:
image: nginx
ports:
# thees are ports where nginx (!) is listen to
- "80:80" # for "/leasing/v1/lessor/shutdown" used by windows guests, can't be changed!
- "443:443" # first part must match "DLS_PORT"
volumes:
- /opt/docker/fastapi-dls/cert:/opt/cert
healthcheck:
test: [ "CMD", "curl", "--insecure", "--fail", "https://localhost/-/health" ]
interval: 10s
timeout: 5s
retries: 3
start_period: 30s
command: |
bash -c 'bash -s <<"EOF"
cat > /etc/nginx/nginx.conf <<"EON"
daemon off;
user root;
worker_processes auto;
events {
worker_connections 1024;
}
http {
gzip on;
gzip_disable "msie6";
include /etc/nginx/mime.types;
upstream dls-backend {
server dls:443;
}
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
root /var/www/html;
index index.html;
server_name _;
ssl_certificate "/opt/cert/webserver.crt";
ssl_certificate_key "/opt/cert/webserver.key";
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_protocols TLSv1.3 TLSv1.2;
# ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305";
# ssl_ciphers PROFILE=SYSTEM;
ssl_prefer_server_ciphers on;
location / {
proxy_ssl_verify off;
proxy_set_header Host $$http_host;
proxy_set_header X-Real-IP $$remote_addr;
proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $$scheme;
proxy_pass https://dls-backend$$request_uri;
}
location = /-/health {
access_log off;
add_header 'Content-Type' 'application/json';
return 200; # '{\"status\":\"up\",\"service\":\"nginx\"}';
}
}
server {
listen 80;
listen [::]:80;
root /var/www/html;
index index.html;
server_name _;
location /leasing/v1/lessor/shutdown {
proxy_ssl_verify off;
proxy_set_header Host $$http_host;
proxy_set_header X-Real-IP $$remote_addr;
proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $$scheme;
proxy_pass https://dls-backend/leasing/v1/lessor/shutdown;
}
location / {
return 301 https://$$host$$request_uri;
}
}
}
EON
nginx
EOF'
dls:
image: collinwebdesigns/fastapi-dls:latest
restart: always
environment:
<<: *dls-variables
volumes:
- /opt/docker/fastapi-dls/cert:/app/cert
- db:/app/database
volumes:
db:

View File

@ -50,7 +50,7 @@ def test_health():
def test_config(): def test_config():
response = client.get('/-/') response = client.get('/-/config')
assert response.status_code == 200 assert response.status_code == 200
@ -184,7 +184,9 @@ def test_leasing_v1_lessor():
lease_result_list = response.json().get('lease_result_list') lease_result_list = response.json().get('lease_result_list')
assert len(lease_result_list) == 1 assert len(lease_result_list) == 1
assert len(lease_result_list[0]['lease']['ref']) == 36
assert str(UUID(lease_result_list[0]['lease']['ref'])) == lease_result_list[0]['lease']['ref'] assert str(UUID(lease_result_list[0]['lease']['ref'])) == lease_result_list[0]['lease']['ref']
return lease_result_list[0]['lease']['ref'] return lease_result_list[0]['lease']['ref']
@ -194,33 +196,38 @@ def test_leasing_v1_lessor_lease():
active_lease_list = response.json().get('active_lease_list') active_lease_list = response.json().get('active_lease_list')
assert len(active_lease_list) == 1 assert len(active_lease_list) == 1
assert len(active_lease_list[0]) == 36
assert str(UUID(active_lease_list[0])) == active_lease_list[0] assert str(UUID(active_lease_list[0])) == active_lease_list[0]
def test_leasing_v1_lease_renew(): def test_leasing_v1_lease_renew():
response = client.get('/leasing/v1/lessor/leases', headers={'authorization': __bearer_token(ORIGIN_REF)}) response = client.get('/leasing/v1/lessor/leases', headers={'authorization': __bearer_token(ORIGIN_REF)})
active_lease_list = response.json().get('active_lease_list') active_lease_list = response.json().get('active_lease_list')
lease_ref = active_lease_list[0] active_lease_ref = active_lease_list[0]
### ###
response = client.put(f'/leasing/v1/lease/{lease_ref}', headers={'authorization': __bearer_token(ORIGIN_REF)}) response = client.put(f'/leasing/v1/lease/{active_lease_ref}', headers={'authorization': __bearer_token(ORIGIN_REF)})
assert response.status_code == 200 assert response.status_code == 200
assert response.json().get('lease_ref') == lease_ref lease_ref = response.json().get('lease_ref')
assert len(lease_ref) == 36
assert lease_ref == active_lease_ref
def test_leasing_v1_lease_delete(): def test_leasing_v1_lease_delete():
response = client.get('/leasing/v1/lessor/leases', headers={'authorization': __bearer_token(ORIGIN_REF)}) response = client.get('/leasing/v1/lessor/leases', headers={'authorization': __bearer_token(ORIGIN_REF)})
active_lease_list = response.json().get('active_lease_list') active_lease_list = response.json().get('active_lease_list')
lease_ref = active_lease_list[0] active_lease_ref = active_lease_list[0]
### ###
response = client.delete(f'/leasing/v1/lease/{lease_ref}', headers={'authorization': __bearer_token(ORIGIN_REF)}) response = client.delete(f'/leasing/v1/lease/{active_lease_ref}', headers={'authorization': __bearer_token(ORIGIN_REF)})
assert response.status_code == 200 assert response.status_code == 200
assert response.json().get('lease_ref') == lease_ref lease_ref = response.json().get('lease_ref')
assert len(lease_ref) == 36
assert lease_ref == active_lease_ref
def test_leasing_v1_lessor_lease_remove(): def test_leasing_v1_lessor_lease_remove():
@ -231,4 +238,5 @@ def test_leasing_v1_lessor_lease_remove():
released_lease_list = response.json().get('released_lease_list') released_lease_list = response.json().get('released_lease_list')
assert len(released_lease_list) == 1 assert len(released_lease_list) == 1
assert len(released_lease_list[0]) == 36
assert released_lease_list[0] == lease_ref assert released_lease_list[0] == lease_ref