Skip to content

SLURM Rest API

SLURM provides a REST API daemon which allows to submit and manage jobs.

Rest API server

the Maxwell cluster and the solaris sub-cluster have separate API server:

Authorization is handled through tokens. This can either be a JWKS keycloak token or a JWT SLURM token

Using JWT SLURM token

On Maxwell/Solaris you will need two tokens:

  • a revocable portal token. It is generated with username and password, and comes without expiry, but can be revoked.
  • a slurm token. It is generated with the portal token, but has a maximum lifetime of 24 hours. It can't be revoked.

BE AWARE: whoever knows your token has access to all your files on maxwell! We therefore disabled the ability to generate unlimited tokens using scontrol.

Token handling on Maxwell

on Maxwell nodes like display nodes, you can generate tokens with some convenience scripts. On Maxwell you could simply use sbatch to submit a job, so there is usually not much of an advantage in using the API. Anyhow to generate tokens

portal_token   # full path: /software/tools/bin/portal_token

generates the portal token and stores it in ~/.maxwell/portal.token.

slurm_token -l 84400

generates a slurm token valid for 24 hours.

export $(slurm_token -l 84400

generates a slurm token valid for 24 hours and stores it in the variable SLURM_TOKEN.

Token handling elsewhere

the REST API are not exposed outside the DESY network, but can be reached from any machine in the DESY network. To generate tokens you will usually not have the convenience commands, but it's easy enough to use simple curl commands or python scriplets.

Portal Token ... Using CURL

# creating a portal token
curl -u user https://max-slurm-rest.desy.de/reservation/get_new_token?cli_api=4.6.0

#it will ask for the password of the user.








.

... Using PYTHON

# creating a portal token
import requests
import getpass

user="user"
pw = getpass.getpass()

session = requests.Session()
session.auth = (user, pw)

url = "https://max-slurm-rest.desy.de/reservation/get_new_token?cli_api=4.6.0"
portal_token = session.get(url)
print(portal_token)

SLURM Token ... Using CURL

# creating a slurm jwt token
url = "https://max-slurm-rest.desy.de/reservation/get_new_slurm_token?cli_api=4.6.0&lifespan=86400&stu=hpcguest"
export SLURM_TOKEN=$(curl -u user $url | jq '.token' | tr -d '"')

# it will ask for the password, use the portal token! 
# Like before the slurm token with be stored in SLURM_TOKEN








.

... Using PYTHON

# creating a slurm jwt token
import requests
import getpass
import json

user="user"
# use portal token as password
portal_token = getpass.getpass()

session.auth = (user, portal_token)
url = f"https://max-slurm-rest.desy.de/reservation/get_new_slurm_token?cli_api=4.6.0&lifespan=86400&stu={user}"
response = session.get(url)
slurm_token = json.loads(response.text)['token']

print(slurm_token)

Job submission

To submit a job, the job-script has to be embedded into a json string. A very simple example for a job script:

Using CURL

# a sample file named job.json:

{
  "job":{
     "partition": "maxcpu", 
     "name":"testapi",
     "time_limit": {"set": True, "number": 1000},
     "current_working_directory":"/home/user",
     "environment":["PATH=/bin:/usr/bin/:/usr/local/bin/",
                    "LD_LIBRARY_PATH=/lib/:/lib64/:/usr/local/lib"]
   },
  "script":"#!/bin/bash -l\n
            srun hostname\n
            sleep 300\n
           "
}
# submit the job
curl -L -H "Content-Type: application/json" \
     -H X-SLURM-USER-NAME:user \
     -H X-SLURM-USER-TOKEN:$SLURM_TOKEN \
     -X POST https://max-slurm-rest.desy.de/sapi/slurm/v0.0.40/job/submit \
     -d@job.json















.

Using PYTHON

import requests
import json
from requests.auth import HTTPBasicAuth

SLURM_REST_API_URL = "https://max-slurm-rest.desy.de/sapi/slurm/v0.0.40/job/submit"
user = "user"  
SLURM_TOKEN = os.getenv(SLURM_TOKEN)

JOB_SCRIPT_FILE = "job_script.sh"
with open(JOB_SCRIPT_FILE, 'r') as file:
    job_script = file.read()

headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
    "X-SLURM-USER-NAME": user,
    "X-SLURM-USER-TOKEN": SLURM_TOKEN
}

payload = {
  "job":{
     "partition": "allcpu", 
     "name":"testapi",
     "time_limit": {"set": True, "number": 1000},
     "current_working_directory":"/home/hpcguest",
     "environment":["PATH=/bin:/usr/bin/:/usr/local/bin/",
                    "LD_LIBRARY_PATH=/lib/:/lib64/:/usr/local/lib"]
      },
    "script": job_script
}


session = requests.Session()

response = session.post(SLURM_REST_API_URL,
            headers=headers,
            data=json.dumps(payload)
        )

print(json.loads(response.text))

To convert a batch-job into a suitable script for curl:

cat job.script | sed 's|"|\\"|g' | sed ':a;N;$!ba;s|\n|\\n|g'

Job information

# all jobs
curl -L -s -H "Content-Type: application/json" -H X-SLURM-USER-NAME:$(whoami) -H X-SLURM-USER-TOKEN:$SLURM_TOKEN \
     -X GET https://max-slurm-rest.desy.de/sapi/slurm/v0.0.40/jobs

# to extract information about individual jobs use json parser like jq:
curl -L -s -H "Content-Type: application/json" -H X-SLURM-USER-NAME:$(whoami) -H X-SLURM-USER-TOKEN:$SLURM_TOKEN \
     -X GET https://max-slurm-rest.desy.de/sapi/slurm/v0.0.40/jobs > jobs.json
cat jobs.json | jq '.jobs[]| select(.job_id == 7752003)'
cat jobs.json | jq '.jobs[]| select(.user_name == "username")'  # replace username by a real username

# specific running or pending job
curl -L -s -H "Content-Type: application/json" -H X-SLURM-USER-NAME:$(whoami) -H X-SLURM-USER-TOKEN:$SLURM_TOKEN \
     -X GET https://max-slurm-rest.desy.de/sapi/slurm/v0.0.40/job/7750418

# a job already removed from the queue will report  `"error": "_handle_job_get: unknown job 7751560"`

# retrieve information about finished jobs:
curl -L -H "Content-Type: application/json" -H X-SLURM-USER-NAME:$(whoami) -H X-SLURM-USER-TOKEN:$SLURM_TOKEN \
     -X GET https://max-slurm-rest.desy.de/sapi/slurmdb/v0.0.40/job/7740309

Using Keycloak tokens - JWKS

stubs!

Simple sample:

KC_SERVER_URL="https://keycloak.desy.de/auth"
KC_REALM="production"
KC_CLIENT_ID="desy-public"

curl -fsSL -X POST "${KC_SERVER_URL}/realms/${KC_REALM}/protocol/openid-connect/token" \
  --header "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "password=${KC_USER_PASSWORD}" \
  --data-urlencode "username=${KC_USER_USERNAME}" \
  --data-urlencode "client_id=${KC_CLIENT_ID}" \
  --data-urlencode "scope=openid sun" \
  --data-urlencode "grant_type=password" | jq

provides access_token & refresh_token.

export SLURM_TOKEN="keycloak access_token"
curl -H "Content-Type: application/json" -H X-SLURM-USER-TOKEN:$SLURM_TOKEN      
     -X POST https://max-portal.desy.de/sapi/slurm/v0.0.40/job/submit --data-binary @job.json

and the job gets submitted. SLURM requires username or sun to be included in the token https://slurm.schedmd.com/jwt.html, so scope=sun is needed (openid is not).

Generating JWT as root

As a privileged user it's possible to create token for arbitrary users on maxwell:

#!/usr/bin/env python3
import sys
import os
import pprint
import json
import time
from datetime import datetime, timedelta, timezone

from jwt import JWT
from jwt.jwa import HS256
from jwt.jwk import jwk_from_dict
from jwt.utils import b64decode,b64encode

if len(sys.argv) != 3:
    sys.exit("generate_jwt.py [user name] [expiration time (seconds)]");

jwt_key = os.environ.get('JWT_KEY', '/etc/slurm/jwt_hs256.key')

with open(jwt_key, "rb") as f:
    priv_key = f.read()

signing_key = jwk_from_dict({
    'kty': 'oct',
    'k': b64encode(priv_key)
})

message = {
    "exp": int(time.time() + int(sys.argv[2])),
    "iat": int(time.time()),
    "sun": sys.argv[1]
}

a = JWT()
compact_jws = a.encode(message, signing_key, alg='HS256')
print("SLURM_TOKEN={}".format(compact_jws))

python3 generate_jwt.py user 3600 would generate the token - if you have a copy of the "secret key". Using keycloak tokens to submit jobs on behalf of users is a much better choice!

Documentation

topic url
General information about SLURMs REST API https://slurm.schedmd.com/rest.html
SLURM REST API reference https://slurm.schedmd.com/rest_api.html
Information about JSON web tokens https://slurm.schedmd.com/jwt.html
slides for the SLUG 2020 talk https://slurm.schedmd.com/SLUG20/REST_API.pdf
slides for the SLUG 2019 talk https://slurm.schedmd.com/SLUG19/REST_API.pdf