175 lines
7.2 KiB
Python
175 lines
7.2 KiB
Python
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#
|
|
# --------------------------------
|
|
# Please keep distribution of this code to NVIDIA and partners only
|
|
# --------------------------------
|
|
# EXAMPLE CODE TO GET NGC API KEY FROM NTS
|
|
# This script demonstrates how to get an NGC API key using the NVIDIA GPU Cloud (NGC) Token Service.
|
|
# The script uses either nvidia-smi or pynvml library to get the GPU device information
|
|
# This device info is sent to an NVIDIA service for validation to exchange for a token
|
|
#
|
|
# WARNING - this is only sample code please do not use in production, just as an reference
|
|
#
|
|
# NOTE - plan to update your client code once PDI is available in NVML and nvidia-smi
|
|
# for now the example will hash a UUID into a pdi-like 64 bit hex string
|
|
|
|
import re
|
|
import subprocess
|
|
|
|
import pynvml as nvml
|
|
import requests
|
|
|
|
|
|
def get_device_info_nvml():
|
|
try:
|
|
nvml.nvmlInit()
|
|
deviceCount = nvml.nvmlDeviceGetCount()
|
|
deviceInfo = []
|
|
for i in range(deviceCount):
|
|
handle = nvml.nvmlDeviceGetHandleByIndex(i)
|
|
uuid = nvml.nvmlDeviceGetUUID(handle)
|
|
name = nvml.nvmlDeviceGetName(handle)
|
|
brand = nvml.nvmlDeviceGetBrand(handle)
|
|
architecture = nvml.nvmlDeviceGetArchitecture(handle)
|
|
pciDeviceId = nvml.nvmlDeviceGetPciInfo(handle).pciDeviceId
|
|
pciDeviceId_64bit = format(pciDeviceId, 'X')
|
|
# pdi = 'Unknown' # nvml.nvmlDeviceGetPDI(handle) # TODO - PDI is not available in NVML API yet
|
|
fakePdi = int(hash(uuid) % 2**64) # hash the uuid to a 16 bit integer
|
|
pdi = fakePdi # TODO - just until PDI is available in NVML API
|
|
pdi_64bit = format(pdi, 'X')
|
|
# Map brand and architecture to human-readable strings
|
|
# brand_str = get_brand_name(brand)
|
|
# architecture_str = get_architecture_name(architecture)
|
|
|
|
deviceInfo.append({
|
|
'uuid': uuid,
|
|
'pdi': f"0x{pdi_64bit}",
|
|
'name': name,
|
|
'brand': brand,
|
|
'architecture': architecture,
|
|
'pci_device_id': f"0x{pciDeviceId_64bit}",
|
|
})
|
|
nvml.nvmlShutdown()
|
|
print("NVML device info:")
|
|
print(deviceInfo)
|
|
return deviceInfo
|
|
except nvml.NVMLError as e:
|
|
print(f"NVML Error: {e}")
|
|
nvml.nvmlShutdown()
|
|
return []
|
|
|
|
def get_device_info_smi():
|
|
try:
|
|
output = subprocess.check_output(['nvidia-smi', '-q'], text=True)
|
|
deviceInfo = []
|
|
uuid_pattern = re.compile(r"GPU UUID\s*:\s*(.+)")
|
|
pdi_pattern = re.compile(r"PDI\s*:\s*(.+)")
|
|
name_pattern = re.compile(r"Product Name\s*:\s*(.+)")
|
|
brand_pattern = re.compile(r"Product Brand\s*:\s*(.+)")
|
|
arch_pattern = re.compile(r"Product Architecture\s*:\s*(.+)")
|
|
pci_pattern = re.compile(r"Device Id\s*:\s*(.+)")
|
|
|
|
matches = {
|
|
"uuid": uuid_pattern.search(output),
|
|
"pdi": pdi_pattern.search(output),
|
|
"name": name_pattern.search(output),
|
|
"brand": brand_pattern.search(output),
|
|
"architecture": arch_pattern.search(output),
|
|
"pci_device_id": pci_pattern.search(output),
|
|
}
|
|
|
|
# TODO - just until PDI is available in NVML API
|
|
if not matches["pdi"]:
|
|
fakePdi = int(hash(matches["uuid"].group(1).strip()) % 2**64) # hash the uuid to a 16 bit integer for testing
|
|
pdi_64bit = format(fakePdi, 'X')
|
|
matches["pdi"] = re.match(r"(.+)", f"0x{pdi_64bit}")
|
|
|
|
deviceInfo.append({k: (m.group(1).strip() if m else "Unknown") for k, m in matches.items()})
|
|
print("SMI device info:")
|
|
print(deviceInfo)
|
|
return deviceInfo
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"nvidia-smi error: {e}")
|
|
return []
|
|
|
|
def validate_device_info(deviceInfo):
|
|
matchInName = ['RTX', 'OTHER DEVICE NAME TEST']
|
|
for device in deviceInfo:
|
|
if any(keyword in device.get('name', '') for keyword in matchInName):
|
|
print(f"Valid device name {device['name']} found")
|
|
return True
|
|
matchInBrandString = ['GeForce','5']
|
|
for device in deviceInfo:
|
|
if any(keyword in str(device.get('brand', '')) for keyword in matchInBrandString):
|
|
print(f"Valid device brand {device['brand']} found")
|
|
return True
|
|
print("No valid device found in the list")
|
|
return False
|
|
|
|
def get_ngc_key_from_device_info(deviceInfo):
|
|
# Optional - check env for vars
|
|
# if NGC_API_KEY or NGC_CLI_API_KEY decide if the client should use that instead
|
|
# the key will still need to be setup properly with Catalog Access, and the owner will need an NVAIE sub # noqa: E501
|
|
# or be a member of the NVIDIA developer program (https://developer.nvidia.com/developer-program)
|
|
# apiKey = os.environ.get('NGC_API_KEY')
|
|
# if apiKey:
|
|
# print("Using the API key from the environment variable instead of calling API") # noqa: E501
|
|
# return apiKey
|
|
|
|
ngcKeyServiceUrl = 'https://nts.ngc.nvidia.com/v1/token'
|
|
payload = {
|
|
"client_id": "comfyui",
|
|
"pdi": deviceInfo[0].get('pdi', 'Unknown') if deviceInfo else 'Unknown',
|
|
"access_policy_name": "nim-dev",
|
|
"device": deviceInfo[0] if deviceInfo else {}
|
|
}
|
|
print(f"debug Payload: {payload}")
|
|
try:
|
|
response = requests.post(ngcKeyServiceUrl, headers={'Accept': 'application/json'}, json=payload) # noqa: E501
|
|
print(f"Response: {response}")
|
|
response.raise_for_status()
|
|
keyData = response.json()
|
|
print(f"Key data: {keyData}")
|
|
return keyData.get('access_token')
|
|
except requests.RequestException as e:
|
|
print(f"Error fetching API key: {e}")
|
|
return None
|
|
|
|
def get_ngc_key():
|
|
# two different examples of getting device info
|
|
# note: branch/architecture, nvidia-smi gives strings, NVML gives ints
|
|
deviceInfoNvml = get_device_info_nvml()
|
|
deviceInfoSmi = get_device_info_smi()
|
|
|
|
# client check option - TBD if needed by client development team
|
|
# if not validate_device_info(deviceInfoNvml):
|
|
# print("Device info validation failed - exiting")
|
|
# exit(1)
|
|
|
|
key = get_ngc_key_from_device_info(deviceInfoNvml)
|
|
if key:
|
|
print(f"Key: {key}")
|
|
return key
|
|
else:
|
|
raise Exception("Error getting NGC API key. Please follow the instructions in the README to set up your NGC API key.") # noqa: E501
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# deviceInfoNvml = get_device_info_nvml()
|
|
# deviceInfoSmi = get_device_info_smi()
|
|
# assert deviceInfoNvml[0]["pdi"] == deviceInfoSmi[0]["pdi"]
|
|
# key = get_ngc_key_from_device_info(deviceInfoSmi)
|
|
get_ngc_key()
|