scriptling.nomad
The scriptling.nomad library provides a client for the HashiCorp Nomad HTTP API, covering CSI storage volumes and jobs. All operations go through a NomadClient obtained from Client().
Available Functions
| Function | Description |
|---|---|
Client(addr, **kwargs) |
Create a Nomad client |
Client() returns a NomadClient with the following methods:
| Method | Description |
|---|---|
csi_volumes_list(**kwargs) |
List CSI volumes |
csi_volume_get(id, **kwargs) |
Get details for a CSI volume |
csi_volume_register(id, volume, **kwargs) |
Register (create) a CSI volume |
csi_volume_deregister(id, **kwargs) |
Deregister (delete) a CSI volume |
jobs_list(**kwargs) |
List jobs |
job_get(id, **kwargs) |
Get the full specification and status for a job |
job_register(job) |
Register (create or update) a job |
job_stop(id, **kwargs) |
Stop a job |
wait_job_stopped(id, **kwargs) |
Wait for a job to reach the “dead” status |
job_validate(job) |
Validate a job specification without submitting it |
job_plan(id, job, **kwargs) |
Dry-run a job registration and return the scheduler plan |
jobs_parse(hcl, **kwargs) |
Convert an HCL job specification into Nomad’s JSON job format |
Functions
Client(addr, token="", insecure=False, timeout=10)
Creates a NomadClient bound to a Nomad HTTP API endpoint.
Parameters:
addr(str): Nomad HTTP API address, e.g."http://127.0.0.1:4646".token(str, optional): ACL token, sent as theX-Nomad-Tokenheader on every request. Default:"".insecure(bool, optional): Skip TLS certificate verification. Default:False.timeout(float, optional): Per-request HTTP timeout in seconds. Default:10.
Returns: NomadClient: a client bound to the given address.
import scriptling.nomad as nomad
c = nomad.Client("https://nomad.example.com:4646", token="secret")
c = nomad.Client("https://nomad.example.com:4646", token="secret", timeout=5)NomadClient.csi_volumes_list(namespace="*", plugin_id="")
Lists CSI volumes.
Parameters:
namespace(str, optional): Namespace to list,"*"for all namespaces. Default:"*".plugin_id(str, optional): Filter by CSI plugin ID. Default:"": no filter.
Returns: list of dict, each with keys:
id(str): Volume ID.name(str): Volume name.namespace(str): Namespace.plugin_id(str): CSI plugin ID.provider(str): CSI provider name.schedulable(bool): Whether the volume can currently be scheduled.controllers_healthy(int): Number of healthy controller plugins.nodes_healthy(int): Number of healthy node plugins.
for v in c.csi_volumes_list(plugin_id="ceph-csi"):
if v["id"].startswith("qaannon") or v["id"].startswith("qaprod"):
print(v["id"])NomadClient.csi_volume_get(id, namespace="")
Returns full details for a single CSI volume.
Parameters:
id(str): Volume ID.namespace(str, optional): Namespace. Default:"": Nomad’s default namespace.
Returns: dict: the full volume specification and status, as returned by the Nomad API.
vol = c.csi_volume_get("qaprod-data-01")
print(vol["Provider"])NomadClient.csi_volume_register(id, volume, namespace="")
Registers (creates) a CSI volume.
Parameters:
id(str): Volume ID.volume(dict): Volume specification in Nomad’s CSI volume JSON format.namespace(str, optional): Namespace. Default:"": Nomad’s default namespace.
Returns: None
c.csi_volume_register("qaprod-data-01", {
"Name": "qaprod-data-01",
"PluginID": "ceph-csi",
"Capacity": 10 * 1024 * 1024 * 1024,
"AccessMode": "single-node-writer",
"AttachmentMode": "file-system",
})NomadClient.csi_volume_deregister(id, namespace="", force=False)
Deregisters (deletes) a CSI volume.
Parameters:
id(str): Volume ID.namespace(str, optional): Namespace. Default:"": Nomad’s default namespace.force(bool, optional): Force detach any remaining claims first. Default:False.
Returns: None
c.csi_volume_deregister("qaprod-orphaned-01", force=True)NomadClient.jobs_list(namespace="*", prefix="")
Lists jobs.
Parameters:
namespace(str, optional): Namespace to list,"*"for all namespaces. Default:"*".prefix(str, optional): Filter by job ID prefix. Default:"": no filter.
Returns: list of dict, each with keys:
id(str): Job ID.name(str): Job name.namespace(str): Namespace.type(str): Job type, e.g."service","batch","system".status(str): Current status, e.g."running","pending","dead".priority(int): Job priority.
for j in c.jobs_list(prefix="qaannon"):
print(j["id"], j["status"])NomadClient.job_get(id, namespace="")
Returns the full specification and status for a job.
Parameters:
id(str): Job ID.namespace(str, optional): Namespace. Default:"": Nomad’s default namespace.
Returns: dict: job specification and status, as returned by the Nomad API.
job = c.job_get("qaprod-api")
print(job["Status"])NomadClient.job_register(job)
Registers (creates or updates) a job.
Parameters:
job(dict): Job specification in Nomad’s JSON job format, e.g. fromjobs_parse()orjob_get()["Job"].
Returns: dict with keys:
EvalID(str): Evaluation ID created for this registration.EvalCreateIndex(int)JobModifyIndex(int)Warnings(str)
parsed = c.jobs_parse(hcl_text)
result = c.job_register(parsed)
print(result["EvalID"])NomadClient.job_stop(id, namespace="", purge=False)
Stops a job.
Parameters:
id(str): Job ID.namespace(str, optional): Namespace. Default:"": Nomad’s default namespace.purge(bool, optional): Fully remove the job from Nomad’s state instead of leaving it stopped. Default:False.
Returns: dict with keys EvalID (str), EvalCreateIndex (int), JobModifyIndex (int).
c.job_stop("qaprod-old-job", purge=True)NomadClient.wait_job_stopped(id, namespace="", timeout=30)
Polls a job’s status until it reaches "dead", or the timeout elapses.
Parameters:
id(str): Job ID.namespace(str, optional): Namespace. Default:"": Nomad’s default namespace.timeout(int, optional): Maximum time to wait in seconds. Default:30.
Returns: bool: True if the job is stopped, False if the timeout was reached.
c.job_stop("qaprod-old-job")
if not c.wait_job_stopped("qaprod-old-job", timeout=60):
print("job did not stop in time")NomadClient.job_validate(job)
Validates a job specification without submitting it.
Parameters:
job(dict): Job specification in Nomad’s JSON job format.
Returns: dict with keys DriverConfigValidated (bool), ValidationErrors (list), Warnings (str).
result = c.job_validate(parsed_job)
if result["ValidationErrors"]:
print(result["ValidationErrors"])NomadClient.job_plan(id, job, diff=False)
Dry-runs a job registration and returns the resulting scheduler plan, without actually registering the job.
Parameters:
id(str): Job ID.job(dict): Job specification in Nomad’s JSON job format.diff(bool, optional): Include a diff against the current job version. Default:False.
Returns: dict: plan result, including keys such as JobModifyIndex (int), Annotations (dict), FailedTGAllocs (dict).
plan = c.job_plan("qaprod-api", parsed_job, diff=True)NomadClient.jobs_parse(hcl, canonicalize=False)
Converts an HCL job specification into Nomad’s JSON job format, so it can be passed to job_register(), job_validate(), or job_plan().
Parameters:
hcl(str): Job specification in HCL format.canonicalize(bool, optional): Fill in default values for optional fields. Default:False.
Returns: dict: job specification in Nomad’s JSON job format.
parsed = c.jobs_parse(open("job.nomad.hcl").read())
c.job_register(parsed)Full Example
Reconcile CSI volumes against a source-of-truth list, deregistering anything Nomad has that shouldn’t exist:
import scriptling.nomad as nomad
c = nomad.Client("https://nomad.example.com:4646", token="secret")
expected = set(open("expected_volumes.txt").read().split())
for v in c.csi_volumes_list(namespace="*"):
vid = v["id"]
if not (vid.startswith("qaannon") or vid.startswith("qaprod")):
continue
if vid in expected:
continue
print(f"Removing orphaned volume: {vid}")
c.csi_volume_deregister(vid, force=True)Security Considerations
This is an extended library, requiring registration in Go, see Library Registration.
scriptling.nomad grants full control over the Nomad cluster reachable at the address and ACL token passed to Client(), including deregistering CSI volumes and stopping or registering jobs: this is a significant risk, comparable to direct infrastructure access. There is no allowlist parameter for this library; scope the ACL token to the minimum policy needed for the task, and never register this library for untrusted code. For a full risk breakdown across all libraries, see the Security Guide.
See Also
- scriptling.container - Container lifecycle management for Docker, Podman, and Apple Containers
- Library Registration - Registering extended libraries when embedding in Go
- Security Guide - Security guidance for host-provided libraries