Configuration Reference (spur.conf)#
spur.conf is a TOML file describing controller, node, accounting, scheduling,
and network settings. The default location is /etc/spur/spur.conf (the Ansible
layout installs it at <spur_home>/etc/spur.conf). Only cluster_name is
required; every section has a default and may be omitted, and unknown keys are
silently ignored. The controller validates the file on load.
The sections below are grouped by subsystem. Every field lists its type, default, and meaning.
Note
spurctld reads every section of spur.conf. spurd reads the same file
but only for local agent settings ([hooks], [devices], rlimits.memlock,
[cluster], and [mpi]); its identity and networking come from CLI flags.
Node CPU, memory, and GRES are declared to the controller under [[nodes]] here.
Minimal configuration#
A working single-node configuration needs a cluster name, one partition, and the node(s) that back it. Accounting, WireGuard, and the k0s cluster manager are all off unless explicitly configured.
cluster_name = "mi300x-cluster"
[controller]
listen_addr = "[::]:6817"
state_dir = "/var/spool/spur"
max_batch_requeue = 5
[scheduler]
plugin = "backfill"
interval_secs = 1
max_jobs_per_cycle = 10000
fairshare_halflife_days = 14
[accounting]
database_url = "postgresql://spur:spur@localhost/spur"
[auth]
plugin = "none"
[[partitions]]
name = "gpu"
default = true
state = "UP"
nodes = "mi300,mi300-2"
max_time = "7-00:00:00"
default_time = "1:00:00"
min_nodes = 1
priority_tier = 1
[[nodes]]
names = "mi300"
cpus = 256
memory_mb = 2321924
gres = ["gpu:mi300x:8"]
[[nodes]]
names = "mi300-2"
cpus = 256
memory_mb = 2321904
gres = ["gpu:mi300x:8"]
[network]
wg_enabled = false
agent_port = 6818
[logging]
level = "info"
format = "text"
The full annotated example — including label selectors, account restrictions, and
the k0s cluster manager — lives at examples/spur.conf in the repository.
Top-level keys#
Field |
Type |
Default |
Description |
|---|---|---|---|
|
string |
(required) |
Cluster name. An empty value fails to load with |
|
table<string, integer> |
|
Cluster-wide license pool, e.g. |
[controller]#
Controller daemon (spurctld) network endpoints, state storage, job-ID range,
and Raft high-availability topology.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
string |
|
gRPC listen address serving |
|
string |
|
REST API listen address. |
|
[string] |
|
Controller hostname(s); the first is primary. Clients and agents build
failover endpoints from these hosts plus the port of |
|
string |
|
Directory where the controller persists Raft log and scheduler state. |
|
integer |
|
Highest job ID before the counter wraps. |
|
integer |
|
Job ID assigned to the first submitted job. |
|
[string] |
|
Raft HA peers as |
|
integer |
none |
This controller’s Raft ID. Normally unset (single-node always uses |
|
string |
|
Internal Raft gRPC listen address, separate from the client API. |
|
integer |
none |
Seconds without a heartbeat before a node is marked Down. Unset by default; the controller applies a 90-second fallback when absent. |
|
integer |
|
Maximum automatic requeues (excluding preemption) before a job is held with
|
[accounting]#
PostgreSQL-backed accounting, fairshare, and QOS enforcement. Accounting runs
in-process inside spurctld (served on port 6817) — there is no separate
slurmdbd.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
string |
|
PostgreSQL connection string. A non-empty value enables accounting; empty
disables it entirely. Example: |
|
integer |
|
How often (seconds) to refresh fairshare and QOS caches from the database. |
|
string |
|
Cluster-wide fallback QOS, applied at submit when a job resolves to no QOS
(the analog of Slurm’s |
|
bool |
|
Reject at submit any job that still has no QOS after the resolution chain.
Mirrors Slurm’s |
See Accounting, Accounts, Users, and QOS for how default_qos and require_qos interact with the
per-job QOS resolution chain.
[scheduler]#
Scheduling loop cadence, per-cycle limits, and fairshare decay.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
string |
|
Scheduler plugin name. |
|
integer |
|
How often (seconds) the scheduler runs. |
|
integer |
|
Maximum number of jobs evaluated per scheduling cycle. |
|
integer |
|
Fairshare usage decay half-life, in days. |
|
integer |
|
Cluster-wide fallback wall-time (minutes) for a job that sets no |
|
string |
|
Whether partition wall-time limits are enforced at submit. |
|
integer |
|
Maximum seconds a job may sit in COMPLETING before it is force-finished. |
|
integer |
|
Reap an interactive allocation ( |
|
integer |
|
Grace minutes after a reservation ends before its still-running jobs are cancelled. |
[auth]#
Authentication plugin for client requests.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
string |
|
Authentication plugin. |
|
string |
none |
JWT secret key, given as a file path or inline value. Required by the |
Note
munge is accepted as a value but is not documented here as a supported
plugin. Use jwt for cryptographic authentication or none to trust OS
identity. See Accounting, Accounts, Users, and QOS for how identity maps to accounts and admin
rights.
[[partitions]]#
An array of tables — one [[partitions]] block per partition (queue). Membership
is the union of the nodes hostlist pattern and the selector label match.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
string |
(required) |
Partition (queue) name. |
|
bool |
|
Mark this as the cluster default partition. |
|
string |
|
Partition state, parsed case-insensitively: |
|
string |
|
Hostlist pattern of member nodes, e.g. |
|
table<string, string> |
|
Label selector; a node joins if it matches all key=value pairs. Unioned
with |
|
string |
UNLIMITED |
Maximum wall time. Slurm format: |
|
string |
UNLIMITED |
Default wall time for jobs that omit |
|
integer |
none |
Maximum nodes per job. |
|
integer |
|
Minimum nodes per job. |
|
[string] |
|
Accounts permitted to submit to this partition (allow-list). |
|
[string] |
|
Accounts denied submission to this partition (deny-list). |
|
integer |
|
Partition priority tier; a higher tier preempts a lower one. |
|
string |
|
Preemption mode: |
[[nodes]]#
An array of tables declaring node capacity to the controller. Match nodes by
hostlist pattern (names) or by label (selector).
Field |
Type |
Default |
Description |
|---|---|---|---|
|
string |
|
Hostlist pattern, e.g. |
|
table<string, string> |
|
Apply this config to nodes matching all key=value pairs. |
|
integer |
|
CPU count. |
|
integer |
|
Memory in MB. |
|
[string] |
|
Generic resources, e.g. |
|
[string] |
|
Node features/tags for |
|
string |
none |
Override address when it differs from the hostname. |
|
integer |
|
Scheduling weight; higher is preferred. |
[network]#
WireGuard mesh networking and the agent port.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
bool |
|
Enable WireGuard mesh networking. |
|
string |
|
CIDR for WireGuard address allocation. Validated as an IPv4 CIDR when
|
|
string |
|
WireGuard interface name. |
|
integer |
|
WireGuard listen port. |
|
integer |
|
|
[logging]#
Field |
Type |
Default |
Description |
|---|---|---|---|
|
string |
|
Log level. |
|
string |
|
Log format. |
|
string |
none |
Log file path. Unset logs to stderr. |
[rlimits]#
POSIX RLIMIT_* values spurd applies to job steps at launch.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
string |
|
|
Note
memlock = "unlimited" lets RDMA and NCCL workloads pin memory out of the box.
Lower it only when a hard cap is required.
[mpi]#
PMIx plugin settings for --mpi=pmix jobs (batch launch and srun steps).
Field |
Type |
Default |
Description |
|---|---|---|---|
|
string |
|
Directory searched for the PMIx plugin when |
|
string |
|
Explicit path to the PMIx plugin. When empty, the plugin resolves to
|
|
string |
|
Base directory for per-step PMIx scratch (namespace and rank state). |
|
string |
|
Minimum PMIx library version accepted when loading the plugin. |
[update]#
Startup update checks and optional auto-download.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
bool |
|
Check for updates on daemon startup. |
|
bool |
|
Automatically download and install updates. |
|
string |
|
Release channel: |
|
string |
|
Directory for the update-check cache file. |
Note
Daemons never auto-restart, even with auto_update = true. A downloaded update
takes effect on the next manual restart.
[admission]#
Controls which nodes may register with the controller.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
string |
|
Node admission mode. |
See Accounting, Accounts, Users, and QOS for managing admission tokens with spur token.
[devices]#
GPU and generic-resource discovery.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
bool |
|
Discover GPUs from AMD KFD sysfs when the CDI cache is empty (AMD only). |
|
[string] |
|
Extra directories to scan for CDI specs, beyond |
|
[table] |
|
File-based or countable GRES pools; see below. |
Each [[devices.gres]] entry uses Slurm GRES syntax with fields name
(required), type, file, multiple_files, count, cores, links,
and flags ([string]). Examples:
[[devices.gres]]
name = "gpu"
file = "/dev/dri/renderD[128-129]"
flags = ["amd_gpu_env"]
[[devices.gres]]
name = "bandwidth"
type = "lustre"
count = 4096
flags = ["count_only"]
[isolation]#
Job isolation layers. Each degrades gracefully when the platform does not support it.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
bool |
|
Run jobs as the submitting user’s UID/GID (requires a root |
|
bool |
|
PID and mount namespace isolation (requires root). |
|
bool |
|
seccomp-BPF syscall filter (kernel 3.5+; blocks ptrace/mount/bpf). |
|
bool |
|
Landlock filesystem access control (kernel 5.13+, native-host only). |
[metrics]#
OpenMetrics HTTP export from spurctld.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
bool |
|
Start the metrics HTTP server. |
|
string |
|
Metrics HTTP listen address; the port is used when |
|
string |
|
|
|
bool |
|
Reserved for a per-job/user/account metrics route; that route returns 404 until implemented. |
[rest_api]#
Field |
Type |
Default |
Description |
|---|---|---|---|
|
bool |
|
Start the Slurm-compatible REST server (default port 6820). |
[hooks]#
Prolog/epilog scripts. Each field is an optional fully-qualified path; unset means no hook. These map one-to-one to Slurm’s prolog/epilog parameters.
Spur field |
Slurm equivalent |
Runs on |
|---|---|---|
|
|
compute node, before job launch |
|
|
compute node, at job termination |
|
|
controller, at allocation |
|
|
controller, at termination |
|
|
compute node, before each step |
|
|
compute node, after each step |
|
|
srun node, before step dispatch |
|
|
srun node, after step completion |
[notifications]#
Job-event notification transports.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
string |
none |
URL to POST job-event notifications to. |
|
string |
none |
SMTP command for mail, e.g. |
|
string |
none |
From address, e.g. |
[power]#
Idle-node suspend and resume.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
integer |
none |
Idle seconds before a node is suspended. |
|
string |
none |
Suspend command; |
|
string |
none |
Resume command; |
Kubernetes modes#
Spur has two distinct, mutually exclusive Kubernetes modes. [kubernetes] lets
Spur run inside an existing cluster and accept SpurJob CRDs; [cluster]
lets Spur own and provision a k0s cluster.
[kubernetes]#
Field |
Type |
Default |
Description |
|---|---|---|---|
|
bool |
|
Enable K8s integration (accept |
|
string |
none |
Path to a kubeconfig; empty uses in-cluster config. |
|
string |
|
Namespace for |
|
string |
|
Label selector for nodes in the Spur pool. |
[cluster]#
Spur-managed k0s cluster. When disabled (the default), spurd never touches
systemd or k0s.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
bool |
|
Enable the Spur-managed k0s cluster. |
|
string |
|
Kubernetes distribution. Only |
|
string |
|
Pod network CIDR. Prefix must be |
|
string |
|
Service network CIDR. |
|
string |
|
CNI mode: |
|
integer |
|
CNI MTU, leaving headroom for WireGuard overhead. |
|
string |
none |
Hostname running the k0s control plane; empty picks one from inventory. |
|
string |
|
|
|
string |
|
On-node directory for local-path PVs. Must be absolute and free of quotes, backslashes, whitespace, and control characters. |
See Spur-Managed Kubernetes (k0s) for provisioning a Spur-owned cluster.
[federation], [topology], [burst_buffer]#
[federation]Peer clusters for cross-cluster job routing. Each
[[federation.clusters]]entry hasname(string) andaddress(string, e.g."http://peer-ctrl:6817"). Defaults to no peers.[topology]Optional switch-hierarchy configuration for locality-aware scheduling.
plugin(string, default"none") selects the model:"tree"for a switch hierarchy,"block"for fixed-size blocks, or"none"to disable. In tree mode, each[[topology.switches]]entry hasname(string),nodes(hostlist pattern for a leaf switch), andswitches(comma-separated child switch names for an aggregation switch). In block mode,block_size(integer) sets the number of nodes per block. Defaults to no topology.[burst_buffer]Burst-buffer capacity.
total_gb(integer, default0) sets total capacity in GiB; jobs reserve via--bb capacity=NNN.0disables burst buffers, and requesting jobs stay pending withBurstBufferResources.
Validation#
The controller validates spur.conf on load and refuses to start on error:
cluster_namemust be non-empty.controller.max_batch_requeuemust be>= 1.When
[cluster]is enabled:distromust be"k0s".network.wg_cidr,cluster.pod_cidr, andcluster.service_cidrmust be valid IPv4 CIDRs, andpod_cidrmust be<= /24.The three CIDRs must not overlap.
storage_provisionermust belocal-pathornone.local_path_dirmust be absolute and clean when the local-path provisioner is used.
Environment overrides#
Note
Config-file fields are not overridable by environment variables.
SPUR_CONTROLLER_ADDR is a CLI-level override that sets the controller address
for client commands (sacctmgr, scontrol, spur token); it does not
affect any spur.conf field.