mirror of
https://gitea.publichub.eu/oscar.krause/fastapi-dls.git
synced 2024-11-22 22:38:48 +00:00
Merge branch 'dev' into ui
This commit is contained in:
commit
139fdd3472
@ -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
|
||||||
|
27
README.md
27
README.md
@ -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.
|
||||||
|
@ -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})
|
||||||
|
@ -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:
|
||||||
|
@ -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
114
docker-compose.yml
Normal 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:
|
22
test/main.py
22
test/main.py
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user