Compare commits

..

29 Commits

Author SHA1 Message Date
Oscar Krause
e536321c00 Merge branch 'v18.x-support' into 'main'
v18.x support / NLS 3.4.x compatibility

See merge request oscar.krause/fastapi-dls!46
2025-04-14 13:38:23 +02:00
Oscar Krause
fda73a95d3 test "X-NLS-Signature" upper/lowercase 2025-04-14 13:38:21 +02:00
Oscar Krause
3f6ff0b178 changed "feature_name" 2025-04-14 13:38:21 +02:00
Oscar Krause
c9068ad034 updated attributes to match nvidia-nls response order 2025-04-14 13:38:21 +02:00
Oscar Krause
c98aa76d5e x-nls-signature 2025-04-14 13:38:21 +02:00
Oscar Krause
c31aedb28d test "x-nls-signature" 2025-04-14 13:38:21 +02:00
Oscar Krause
b12eb87077 fixed missing code 2025-04-14 13:38:21 +02:00
Oscar Krause
3415b2b9ec test with "X-NLS-Signature" 2025-04-14 13:38:21 +02:00
Oscar Krause
6edc88662d implemented client_challenge on lease apis 2025-04-14 13:38:21 +02:00
Oscar Krause
bac32a77c8 set "offline_lease" to false 2025-04-14 13:38:21 +02:00
Oscar Krause
f851370db4 added EMPTY (!!!) X-NLS-Signature response header 2025-04-14 13:38:21 +02:00
Oscar Krause
10428820f8 added debug headers 2025-04-14 13:38:21 +02:00
Oscar Krause
9dc3643fdd code styling 2025-04-14 13:38:21 +02:00
Oscar Krause
ea612bf2e7 added new "protocol_version" to client-token 2025-04-14 13:38:21 +02:00
Oscar Krause
3c1a1d89a4 fixes 2025-04-14 13:38:21 +02:00
Oscar Krause
27b131a789 also debug response 2025-04-14 13:38:21 +02:00
Oscar Krause
a8e14c0ed0 fixed datetime format 2025-04-14 13:38:21 +02:00
Oscar Krause
b0fe646b03 added missing lessor attributes 2025-04-14 13:38:21 +02:00
Oscar Krause
38ae14f6cf fixes 2025-04-14 13:38:21 +02:00
Oscar Krause
e967bda446 added debugging 2025-04-14 13:38:21 +02:00
Oscar Krause
cf6fc9a4ce updated new responses for 18.x drivers 2025-04-14 13:38:21 +02:00
Oscar Krause
5a98df563a created "init_config_token_demo" 2025-04-14 13:38:21 +02:00
Oscar Krause
50a9d70b77 added test and code for /leasing/v1/config-token
ref. https://git.collinwebdesigns.de/nvidia/nls/-/blob/main/src/test/test_config_token.py
2025-04-14 13:38:21 +02:00
Oscar Krause
cca169881c implemented initial endpoint for /leasing/v1/config-token 2025-04-14 13:38:21 +02:00
Oscar Krause
426da28382 added logging 2025-04-14 13:38:21 +02:00
Oscar Krause
d249ef34bc added debugging 2025-04-14 13:38:21 +02:00
Oscar Krause
e94db9c33b added endpoint '/leasing/v1/config-token' 2025-04-14 13:38:21 +02:00
Oscar Krause
f9c7475250 ci fixes 2025-04-14 13:37:27 +02:00
Oscar Krause
00dafdc63a do not run duplicated pipeline on feature-branches 2025-04-14 11:17:25 +02:00
3 changed files with 40 additions and 39 deletions

View File

@ -16,12 +16,12 @@ build:docker:
interruptible: true interruptible: true
stage: build stage: build
rules: rules:
- if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH # deployment is in "deploy:docker:"
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
changes: changes:
- app/**/* - app/**/*
- Dockerfile - Dockerfile
- requirements.txt - requirements.txt
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
tags: [ docker ] tags: [ docker ]
before_script: before_script:
- docker buildx inspect - docker buildx inspect
@ -41,19 +41,17 @@ build:apt:
interruptible: true interruptible: true
stage: build stage: build
rules: rules:
- if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_TAG - if: $CI_COMMIT_TAG
variables: variables:
VERSION: $CI_COMMIT_REF_NAME VERSION: $CI_COMMIT_REF_NAME
- if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
changes: changes:
- app/**/* - app/**/*
- .DEBIAN/**/* - .DEBIAN/**/*
- .gitlab-ci.yml - .gitlab-ci.yml
variables: variables:
VERSION: "0.0.1" VERSION: "0.0.1"
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
variables:
VERSION: "0.0.1"
before_script: before_script:
- echo -e "VERSION=$VERSION\nCOMMIT=$CI_COMMIT_SHA" > version.env - echo -e "VERSION=$VERSION\nCOMMIT=$CI_COMMIT_SHA" > version.env
# install build dependencies # install build dependencies
@ -94,16 +92,13 @@ build:pacman:
- if: $CI_COMMIT_TAG - if: $CI_COMMIT_TAG
variables: variables:
VERSION: $CI_COMMIT_REF_NAME VERSION: $CI_COMMIT_REF_NAME
- if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
changes: changes:
- app/**/* - app/**/*
- .PKGBUILD/**/* - .PKGBUILD/**/*
- .gitlab-ci.yml - .gitlab-ci.yml
variables: variables:
VERSION: "0.0.1" VERSION: "0.0.1"
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
variables:
VERSION: "0.0.1"
before_script: before_script:
#- echo -e "VERSION=$VERSION\nCOMMIT=$CI_COMMIT_SHA" > version.env #- echo -e "VERSION=$VERSION\nCOMMIT=$CI_COMMIT_SHA" > version.env
# install build dependencies # install build dependencies
@ -168,11 +163,12 @@ test:
.test:apt: .test:apt:
stage: test stage: test
rules: rules:
- if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH - if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
changes: changes:
- app/**/* - app/**/*
- .DEBIAN/**/* - .DEBIAN/**/*
- if: $CI_PIPELINE_SOURCE == 'merge_request_event' - .gitlab-ci.yml
needs: needs:
- job: build:apt - job: build:apt
artifacts: true artifacts: true
@ -217,11 +213,12 @@ test:apt:
test:pacman:archlinux: test:pacman:archlinux:
image: archlinux:base image: archlinux:base
rules: rules:
- if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH - if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
changes: changes:
- app/**/* - app/**/*
- .PKGBUILD/**/* - .PKGBUILD/**/*
- if: $CI_PIPELINE_SOURCE == 'merge_request_event' - .gitlab-ci.yml
needs: needs:
- job: build:pacman - job: build:pacman
artifacts: true artifacts: true

View File

@ -7,6 +7,7 @@ from hashlib import sha256
from json import loads as json_loads from json import loads as json_loads
from os import getenv as env from os import getenv as env
from os.path import join, dirname, isfile from os.path import join, dirname, isfile
from random import randbytes
from uuid import uuid4 from uuid import uuid4
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
@ -369,8 +370,8 @@ async def auth_v1_code(request: Request):
response = { response = {
"auth_code": auth_code, "auth_code": auth_code,
"prompts": None,
"sync_timestamp": cur_time.strftime(DT_FORMAT), "sync_timestamp": cur_time.strftime(DT_FORMAT),
"prompts": None
} }
return JSONr(response) return JSONr(response)
@ -403,18 +404,18 @@ async def auth_v1_token(request: Request):
'iss': 'https://cls.nvidia.org', 'iss': 'https://cls.nvidia.org',
'aud': 'https://cls.nvidia.org', 'aud': 'https://cls.nvidia.org',
'exp': timegm(access_expires_on.timetuple()), 'exp': timegm(access_expires_on.timetuple()),
'origin_ref': origin_ref,
'key_ref': SITE_KEY_XID, 'key_ref': SITE_KEY_XID,
'kid': SITE_KEY_XID, 'kid': SITE_KEY_XID,
'origin_ref': origin_ref,
} }
auth_token = jwt.encode(new_payload, key=jwt_encode_key, headers={'kid': payload.get('kid')}, algorithm=ALGORITHMS.RS256) auth_token = jwt.encode(new_payload, key=jwt_encode_key, headers={'kid': payload.get('kid')}, algorithm=ALGORITHMS.RS256)
response = { response = {
"expires": access_expires_on.strftime(DT_FORMAT),
"auth_token": auth_token, "auth_token": auth_token,
"expires": access_expires_on.strftime(DT_FORMAT),
"prompts": None,
"sync_timestamp": cur_time.strftime(DT_FORMAT), "sync_timestamp": cur_time.strftime(DT_FORMAT),
"prompts": None
} }
return JSONr(response) return JSONr(response)
@ -689,21 +690,21 @@ async def leasing_v1_lessor(request: Request):
lease_ref = str(uuid4()) lease_ref = str(uuid4())
expires = cur_time + LEASE_EXPIRE_DELTA expires = cur_time + LEASE_EXPIRE_DELTA
lease_result_list.append({ lease_result_list.append({
"ordinal": None,
"error": None, "error": None,
# https://docs.nvidia.com/license-system/latest/nvidia-license-system-user-guide/index.html # https://docs.nvidia.com/license-system/latest/nvidia-license-system-user-guide/index.html
"lease": { "lease": {
"ref": lease_ref,
"created": cur_time.strftime(DT_FORMAT), "created": cur_time.strftime(DT_FORMAT),
"expires": expires.strftime(DT_FORMAT), "expires": expires.strftime(DT_FORMAT),
"recommended_lease_renewal": LEASE_RENEWAL_PERIOD,
"offline_lease": "false", # todo
"license_type": "CONCURRENT_COUNTED_SINGLE",
"lease_intent_id": None,
"metadata": None,
"feature_name": "GRID-Virtual-WS", # todo "feature_name": "GRID-Virtual-WS", # todo
"lease_intent_id": None,
"license_type": "CONCURRENT_COUNTED_SINGLE",
"metadata": None,
"offline_lease": False, # todo
"product_name": "NVIDIA RTX Virtual Workstation", # todo "product_name": "NVIDIA RTX Virtual Workstation", # todo
} "recommended_lease_renewal": LEASE_RENEWAL_PERIOD,
"ref": lease_ref,
},
"ordinal": None,
}) })
data = Lease(origin_ref=origin_ref, lease_ref=lease_ref, lease_created=cur_time, lease_expires=expires) data = Lease(origin_ref=origin_ref, lease_ref=lease_ref, lease_created=cur_time, lease_expires=expires)
@ -712,19 +713,15 @@ async def leasing_v1_lessor(request: Request):
response = { response = {
"client_challenge": j.get('client_challenge'), "client_challenge": j.get('client_challenge'),
"lease_result_list": lease_result_list, "lease_result_list": lease_result_list,
"prompts": None,
"result_code": None, "result_code": None,
"sync_timestamp": cur_time.strftime(DT_FORMAT), "sync_timestamp": cur_time.strftime(DT_FORMAT),
"prompts": None
} }
logger.debug(response) logger.debug(response)
si_certificate_filename = join(dirname(__file__), 'cert/my_demo_si_certificate.pem') signature = f'b\'{randbytes(256).hex()}\''
my_si_certificate = Cert.from_file(si_certificate_filename) return JSONr(response, headers={'access-control-expose-headers': 'X-NLS-Signature', 'X-NLS-Signature': signature})
signature = my_si_certificate.signature().hex()
signature = f'b\'{signature}\''
return JSONr(response, headers={'X-NLS-Signature': signature})
# venv/lib/python3.9/site-packages/nls_services_lease/test/test_lease_multi_controller.py # venv/lib/python3.9/site-packages/nls_services_lease/test/test_lease_multi_controller.py
@ -740,8 +737,8 @@ async def leasing_v1_lessor_lease(request: Request):
response = { response = {
"active_lease_list": active_lease_list, "active_lease_list": active_lease_list,
"prompts": None,
"sync_timestamp": cur_time.strftime(DT_FORMAT), "sync_timestamp": cur_time.strftime(DT_FORMAT),
"prompts": None
} }
return JSONr(response) return JSONr(response)
@ -763,17 +760,20 @@ async def leasing_v1_lease_renew(request: Request, lease_ref: str):
expires = cur_time + LEASE_EXPIRE_DELTA expires = cur_time + LEASE_EXPIRE_DELTA
response = { response = {
"client_challenge": j.get('client_challenge'), "client_challenge": j.get('client_challenge'),
"lease_ref": lease_ref,
"expires": expires.strftime(DT_FORMAT), "expires": expires.strftime(DT_FORMAT),
"recommended_lease_renewal": LEASE_RENEWAL_PERIOD, "feature_expired": False,
"lease_ref": lease_ref,
"metadata": None,
"offline_lease": True, "offline_lease": True,
"prompts": None, "prompts": None,
"recommended_lease_renewal": LEASE_RENEWAL_PERIOD,
"sync_timestamp": cur_time.strftime(DT_FORMAT), "sync_timestamp": cur_time.strftime(DT_FORMAT),
} }
Lease.renew(db, entity, expires, cur_time) Lease.renew(db, entity, expires, cur_time)
return JSONr(response) signature = f'b\'{randbytes(256).hex()}\''
return JSONr(response, headers={'access-control-expose-headers': 'X-NLS-Signature', 'X-NLS-Signature': signature})
# venv/lib/python3.9/site-packages/nls_services_lease/test/test_lease_single_controller.py # venv/lib/python3.9/site-packages/nls_services_lease/test/test_lease_single_controller.py
@ -817,8 +817,8 @@ async def leasing_v1_lessor_lease_remove(request: Request):
response = { response = {
"released_lease_list": released_lease_list, "released_lease_list": released_lease_list,
"release_failure_list": None, "release_failure_list": None,
"prompts": None,
"sync_timestamp": cur_time.strftime(DT_FORMAT), "sync_timestamp": cur_time.strftime(DT_FORMAT),
"prompts": None
} }
return JSONr(response) return JSONr(response)
@ -839,8 +839,8 @@ async def leasing_v1_lessor_shutdown(request: Request):
response = { response = {
"released_lease_list": released_lease_list, "released_lease_list": released_lease_list,
"release_failure_list": None, "release_failure_list": None,
"prompts": None,
"sync_timestamp": cur_time.strftime(DT_FORMAT), "sync_timestamp": cur_time.strftime(DT_FORMAT),
"prompts": None
} }
return JSONr(response) return JSONr(response)

View File

@ -212,6 +212,8 @@ def test_leasing_v1_lessor():
client_challenge = response.json().get('client_challenge') client_challenge = response.json().get('client_challenge')
assert client_challenge == payload.get('client_challenge') assert client_challenge == payload.get('client_challenge')
signature = eval(response.headers.get('X-NLS-Signature'))
assert len(signature) == 512
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
@ -242,6 +244,8 @@ def test_leasing_v1_lease_renew():
client_challenge = response.json().get('client_challenge') client_challenge = response.json().get('client_challenge')
assert client_challenge == payload.get('client_challenge') assert client_challenge == payload.get('client_challenge')
signature = eval(response.headers.get('X-NLS-Signature'))
assert len(signature) == 512
lease_ref = response.json().get('lease_ref') lease_ref = response.json().get('lease_ref')
assert len(lease_ref) == 36 assert len(lease_ref) == 36