Skip to content

Commit

Permalink
Add nvidia-smi function
Browse files Browse the repository at this point in the history
Signed-off-by: Han Verstraete (OpenFaaS Ltd) <[email protected]>
  • Loading branch information
welteki committed Jan 22, 2025
1 parent dab6684 commit bfa65ea
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 2 deletions.
2 changes: 2 additions & 0 deletions invoke-function/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
source 'https://rubygems.org'

139 changes: 139 additions & 0 deletions invoke-function/handler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
require 'net/http'
require 'uri'
require 'json'

class Handler
def run(req)
begin
# Fetch a token from an Idp
token = fetch_oauth_token

# Exchange the token for on OpenFaaS function token
openfaas_token = exchange_oauth_token(token)
puts openfaas_token

# Invoke a function with the token
result = invoke_function(openfaas_token)
return result
rescue => e
return "Error: #{e.message}"
end
end
end

# Function to fetch OAuth token using client credentials
def fetch_oauth_token
# Retrieve client_id and client_secret from environment variables
client_id = ENV['CLIENT_ID']
client_secret = File.read("./client-secret.txt")

# Check if the client_id and client_secret are present
if client_id.nil? || client_secret.nil?
raise "Client ID or Client Secret is not set in environment variables."
end

# OAuth authority token endpoint
token_url = "https://auth.exit.welteki.dev/realms/openfaas/protocol/openid-connect/token"

# Create URI object
uri = URI(token_url)

# Create the HTTP object
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true if uri.scheme == 'https'

# Define the request parameters
request_params = {
'grant_type' => 'client_credentials',
'client_id' => client_id,
'client_secret' => client_secret
}

# Create the POST request
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data(request_params)
request['Content-Type'] = 'application/x-www-form-urlencoded'

# Execute the request
response = http.request(request)

# Parse the response
result = JSON.parse(response.body)

# Check the response for errors
if response.code != '200'
puts "Error: #{response.code}"
raise "Failed to retrieve token: #{result['error_description'] || 'Unknown error'}"
end

# Return the access token
result['access_token']
end

# Function to exchange an OAuth token for an OpenFaaS function token
def exchange_oauth_token(token)
# OAuth authority token endpoint
token_url = "https://gw.exit.welteki.dev/oauth/token"

# Create URI object
uri = URI(token_url)

# Create the HTTP object
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true if uri.scheme == 'https'

# Define the request parameters
request_params = {
'subject_token' => token,
'subject_token_type' => 'urn:ietf:params:oauth:token-type:id_token',
'grant_type' => 'urn:ietf:params:oauth:grant-type:token-exchange',
'scope' => 'functions'
}

# Create the POST request
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data(request_params)
request['Content-Type'] = 'application/x-www-form-urlencoded'

# Execute the request
response = http.request(request)

# Parse the response
result = JSON.parse(response.body)

# Check the response for errors
if response.code != '200'
puts "Error: #{response.code}"
raise "Failed to retrieve token: #{result['error_description'] || 'Unknown error'}"
end

# Return the access token
result['access_token']
end

def invoke_function(token)
function_url = "https://gw.exit.welteki.dev/function/env"

# Create URI object
uri = URI(function_url)

# Create the HTTP object
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true if uri.scheme == 'https'

# Create the GET request
request = Net::HTTP::Get.new(uri.request_uri)
request['Authorization'] = "Bearer: #{token}"

# Execute the request
response = http.request(request)

# Check the response for errors
if response.code != '200'
puts "Error: #{response.code}"
raise "Failed to invoke function: code #{response.code}, body: #{response.body}"
end

# Return response body
response.body
end
13 changes: 13 additions & 0 deletions nvidia-smi/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM ghcr.io/openfaas/classic-watchdog:0.3.2 AS watchdog

FROM ubuntu:24.04

COPY --from=watchdog /fwatchdog /usr/bin/fwatchdog
RUN chmod +x /usr/bin/fwatchdog

USER 1000

ENV fprocess="nvidia-smi"

HEALTHCHECK --interval=3s CMD [ -e /tmp/.lock ] || exit 1
CMD ["fwatchdog"]
7 changes: 5 additions & 2 deletions stack.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,14 @@ functions:
lang: golang-middleware
handler: ./markdown
image: ${SERVER:-ghcr.io}/${OWNER:-openfaas}/markdown-fn:${TAG:-latest}

nvidia-smi:
lang: dockerfile
handler: ./nvidia-smi
image: ${SERVER:-ghcr.io}/${OWNER:-openfaas}/nvidia-smi:${TAG:-latest}


configuration:
templates:
- name: golang-middleware
source: https://github.com/openfaas/golang-http-template


0 comments on commit bfa65ea

Please sign in to comment.