This repository contains scripts and documentation to facilitate the generation of Globus access tokens for the ALCF Facility API.
For access, please contact ALCF Support.
Create and activate a Python 3 (>=3.10.7) virtual environment:
python3 -m venv venv
source venv/bin/activateInstall dependencies:
pip install -r requirements.txtEither clone this repository, or download the script directly:
wget https://raw.githubusercontent.com/argonne-lcf/alcf-facility-api-token/refs/heads/main/alcf_facility_api_globus_token.pyGenerate the authentication flow URL with the command below. Copy-paste the URL to your browser, authenticate with your ALCF credentials, and copy-paste the resulting authorization code in your terminal.
python alcf_facility_api_globus_token.py authenticateThe command above generates both an access token and a refresh token, stored at ~/.globus/app/8b84fc2d-49e9-49ea-b54d-b3a29a70cf31/alcf_facility_api_app/tokens.json.
Token Validity: Access tokens are valid for 48 hours. The get_access_token command will automatically refresh your token if it has expired. Refresh tokens are valid for 7 days, after which you will need to manually reauthenticate with your ALCF credentials.
You can retrieve your token in several ways:
Bash:
python alcf_facility_api_globus_token.py get_access_tokenEnvironment variable:
access_token=$(python alcf_facility_api_globus_token.py get_access_token)Python:
from alcf_facility_api_globus_token import get_access_token
access_token = get_access_token()All examples below use the Python requests library. Make sure to execute the following before each example.
import requests
from alcf_facility_api_globus_token import get_access_token
access_token = get_access_token()
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}Discover available resources through the /status/resources endpoint.
response = requests.get("https://api.alcf.anl.gov/api/v1/status/resources")
print(response.status_code)
print(response.json())Submits a new job to the scheduler on the target compute resource.
# Polaris
resource_id = "55c1c993-1124-47f9-b823-514ba3849a9a"
# This block is equivalent to the body of a `qsub` script (excluding `#PBS` directives)
commands = "echo Start; sleep 10; echo End"
# Submit to IRI API
response = requests.post(
f"https://api.alcf.anl.gov/api/v1/compute/job/{resource_id}",
json={
"executable": "/bin/bash",
"arguments": ["-c", commands],
"name": "my_job",
"stdout_path": "/home/<username>/logs",
"stderr_path": "/home/<username>/logs",
"resources": {
"memory": 2222,
"node_count": 1
},
"attributes": {
"duration": 300,
"queue_name": "debug",
"account": "<project_account>",
"custom_attributes": {"filesystems": "eagle"}
}
},
headers=headers
)
print(response.status_code)
print(response.json())Returns a paginated list of jobs on the target resource. Set historical to true to include completed jobs.
# Polaris
resource_id = "55c1c993-1124-47f9-b823-514ba3849a9a"
# Submit to IRI API
response = requests.post(
f"https://api.alcf.anl.gov/api/v1/compute/status/{resource_id}",
params={
"historical": "false",
"limit": 10,
"offset": 0
},
headers=headers
)
print(response.status_code)
print(response.json())Returns the status and details of a single job by its ID. Set historical to true if the job has already completed.
# Polaris
resource_id = "55c1c993-1124-47f9-b823-514ba3849a9a"
job_id = "<job_id>"
# Submit to IRI API
response = requests.get(
f"https://api.alcf.anl.gov/api/v1/compute/status/{resource_id}/{job_id}",
params={"historical": "true"},
headers=headers
)
print(response.status_code)
print(response.json())Cancels a queued or running job. Returns HTTP 204 No Content on success.
# Polaris
resource_id = "55c1c993-1124-47f9-b823-514ba3849a9a"
job_id = "<job_id>"
# Submit to IRI API
response = requests.delete(
f"https://api.alcf.anl.gov/api/v1/compute/cancel/{resource_id}/{job_id}",
headers=headers
)
print(response.status_code)
print("Job canceled." if response.status_code == 204 else response.json())Note: All filesystem operations are asynchronous and will return a task ID. Please see the Get a Task section for how to retrieve your results.
Returns the contents of a directory on the specified resource.
# Eagle
resource_id = "1c3ad9d4-2e91-42bc-becb-72b1fde1235c"
# Submit to IRI API
response = requests.get(
f"https://api.alcf.anl.gov/api/v1/filesystem/ls/{resource_id}",
params={"path": "/eagle/<your-project>"},
headers=headers
)
print(response.status_code)
print(response.json())Creates a new directory at the specified path. Set parent to True to create any missing parent directories.
# Eagle
resource_id = "1c3ad9d4-2e91-42bc-becb-72b1fde1235c"
# Submit to IRI API
response = requests.post(
f"https://api.alcf.anl.gov/api/v1/filesystem/mkdir/{resource_id}",
json={
"path": "/eagle/<your-project>/my_new_dir",
"parent": False
},
headers=headers
)
print(response.status_code)
print(response.json())Returns a portion of a file starting at a given byte offset and reading up to size bytes.
# Eagle
resource_id = "1c3ad9d4-2e91-42bc-becb-72b1fde1235c"
# Submit to IRI API
response = requests.get(
f"https://api.alcf.anl.gov/api/v1/filesystem/view/{resource_id}",
params={
"path": "/eagle/<your-project>/file.txt",
"size": 10,
"offset": 0
},
headers=headers
)
print(response.status_code)
print(response.json())Returns the first N lines of a file, similar to the Unix head command.
# Eagle
resource_id = "1c3ad9d4-2e91-42bc-becb-72b1fde1235c"
# Submit to IRI API
response = requests.get(
f"https://api.alcf.anl.gov/api/v1/filesystem/head/{resource_id}",
params={
"path": "/eagle/<your-project>/file.txt",
"lines": 3
},
headers=headers
)
print(response.status_code)
print(response.json())Changes the owner and/or group of a file or directory.
# Eagle
resource_id = "1c3ad9d4-2e91-42bc-becb-72b1fde1235c"
# Submit to IRI API
response = requests.put(
f"https://api.alcf.anl.gov/api/v1/filesystem/chown/{resource_id}",
json={
"path": "/eagle/<your-project>/file.txt",
"owner": "<username>",
"group": "<group>"
},
headers=headers
)
print(response.status_code)
print(response.json())Changes the permissions of a file or directory using an octal mode string.
# Eagle
resource_id = "1c3ad9d4-2e91-42bc-becb-72b1fde1235c"
# Submit to IRI API
response = requests.put(
f"https://api.alcf.anl.gov/api/v1/filesystem/chmod/{resource_id}",
json={
"path": "/eagle/<your-project>/file.txt",
"mode": "700"
},
headers=headers
)
print(response.status_code)
print(response.json())Retrieves the status and result of an asynchronous task by its ID.
# Task ID returned by filesystem operations
task_id = "<task_id>"
response = requests.get(
f"https://api.alcf.anl.gov/api/v1/task/{task_id}",
headers=headers
)
print(response.status_code)
print(response.json())- Permission Denied: Your token may have expired or you may not be authenticated with your ALCF credentials. Logout from Globus at app.globus.org/logout, clear your browser cache or use an incognito browser, and re-authenticate with
python alcf_facility_api_globus_token.py authenticate. - IdentityMismatchError: Detected a change in identity: This happens when trying to get an access token using a Globus identity that is not linked to the one you previously used to generate your access tokens. Locate your tokens file (typically at
~/.globus/app/8b84fc2d-49e9-49ea-b54d-b3a29a70cf31/alcf_facility_api_app/tokens.json), delete it, and restart the authentication process.
For those who own the appropriate Globus Client credentials, you can introspect your token with the introspect_token.py script. First, add your credentials in a .env file:
GLOBUS_SERVICE_API_CLIENT_ID=....
GLOBUS_SERVICE_API_CLIENT_SECRET=....Then execute the introspection script to verify your token for any issues (e.g. session_info, policy_evaluations):
python introspect_token.pyFor questions or support, please contact ALCF Support.