Documentation
¶
Overview ¶
Package cluster provides types and operations for sind cluster management.
Create, Delete, DeleteAll, WorkerAdd, WorkerRemove, PowerOn, PowerReboot and PowerCycle change state that every cluster of a realm shares and take no lock themselves: their caller holds the realm lock, state.LockRealm with the docker client as LockOptions.Client, for the whole operation.
Index ¶
- Constants
- Variables
- func BuildContainerExecArgs(container docker.ContainerName, user, workDir string, isTTY bool, ...) []string
- func BuildRunArgs(cfg RunConfig) []string
- func BuildSSHArgs(sshContainer docker.ContainerName, node, cluster, realm string, isTTY bool, ...) []string
- func CheckDaemon(ctx context.Context, client *docker.Client) error
- func CheckNsdelegate(ctx context.Context, client *docker.Client, image string) error
- func ComposeProject(realm, clusterName string) string
- func ContainerLogArgs(realm, node, cluster string, follow bool) []string
- func ContainerName(realm, cluster, shortName string) docker.ContainerName
- func ContainerPrefix(realm, cluster string) string
- func CreateClusterNetwork(ctx context.Context, client *docker.Client, realm, clusterName string) error
- func CreateClusterVolume(ctx context.Context, client *docker.Client, realm, clusterName string, ...) error
- func CreateNode(ctx context.Context, client *docker.Client, meshMgr *mesh.Manager, ...) (docker.ContainerID, error)
- func DNSName(shortName, cluster, realm string) string
- func DNSSearchDomain(cluster, realm string) string
- func DaemonSupport(info *docker.DaemonInfo) error
- func DataMountPath(labels docker.Labels) string
- func DataPathWarning(hostPath string) string
- func Delete(ctx context.Context, client *docker.Client, meshMgr *mesh.Manager, ...) error
- func DeleteAll(ctx context.Context, client *docker.Client, meshMgr *mesh.Manager) error
- func DeleteContainers(ctx context.Context, client *docker.Client, ...) error
- func DeleteNetwork(ctx context.Context, client *docker.Client, name docker.NetworkName) error
- func DeleteVolumes(ctx context.Context, client *docker.Client, volumes []docker.VolumeName) error
- func DeregisterMesh(ctx context.Context, meshMgr *mesh.Manager, clusterName string, ...) error
- func DetectCVMFS(ctx context.Context, client *docker.Client, image string) (config.StorageType, error)
- func DiscoverClusterNames(ctx context.Context, client *docker.Client, realm string) ([]string, error)
- func EnterTarget(ctx context.Context, client *docker.Client, realm, clusterName string) (target, workDir string, err error)
- func GetNodeNames(ctx context.Context, client *docker.Client, realm string) ([]string, error)
- func HasOtherClusters(ctx context.Context, client *docker.Client, realm, clusterName string) (bool, error)
- func HomeDir(user string) string
- func IdentityFromLabels(labels docker.Labels) config.IdentityMode
- func IsManaged(labels docker.Labels) bool
- func NetworkName(realm, cluster string) docker.NetworkName
- func NodeLabels(realm, clusterName string, role config.Role, managed bool, ...) docker.Labels
- func NodeShortNames(nodes []config.Node) []string
- func OtherRealms(ctx context.Context, client *docker.Client, realm, clusterName string) ([]string, error)
- func PowerCut(ctx context.Context, client *docker.Client, realm, clusterName string, ...) error
- func PowerCycle(ctx context.Context, client *docker.Client, meshMgr *mesh.Manager, ...) error
- func PowerFreeze(ctx context.Context, client *docker.Client, realm, clusterName string, ...) error
- func PowerOn(ctx context.Context, client *docker.Client, meshMgr *mesh.Manager, ...) error
- func PowerReboot(ctx context.Context, client *docker.Client, meshMgr *mesh.Manager, ...) error
- func PowerShutdown(ctx context.Context, client *docker.Client, realm, clusterName string, ...) error
- func PowerUnfreeze(ctx context.Context, client *docker.Client, realm, clusterName string, ...) error
- func PreflightCheck(ctx context.Context, client *docker.Client, realm string, cfg *config.Cluster) error
- func ServiceLogArgs(realm, node, cluster, service string, follow bool) []string
- func VolumeName(realm, cluster string, volumeType VolumeType) docker.VolumeName
- func WorkerRemove(ctx context.Context, client *docker.Client, meshMgr *mesh.Manager, ...) error
- func WriteClusterConfig(ctx context.Context, client *docker.Client, realm string, cfg *config.Cluster, ...) error
- func WriteMungeKey(ctx context.Context, client *docker.Client, realm, clusterName string, ...) error
- type AuthKey
- type AuthType
- type Cluster
- type HAStatus
- type LinuxGroup
- type LinuxUser
- type LinuxUsers
- type MountPoint
- type NetworkHealth
- type NetworkSummary
- type Node
- type NodeDetail
- type NodeHealth
- type NodeStatus
- type NodeSummary
- type RealmSummary
- type Resources
- type RunConfig
- type ServiceHealth
- type State
- type Status
- type Summary
- type VolumeSummary
- type VolumeType
- type WorkerAddOptions
Constants ¶
const ( // CVMFSPath is where the nodes mount CVMFS, and where the Docker host // has it for the bind mount. CVMFSPath = "/cvmfs" // CVMFSVolumeDriver is the name of the Docker volume plugin that // provides CVMFS. CVMFSVolumeDriver = "cvmfs" // CVMFSVolume is the plugin volume the nodes mount. All clusters share // it, so sind never removes it. CVMFSVolume docker.VolumeName = "cvmfs" )
CVMFS on the nodes (storage.cvmfs).
const ( PositionPrimary = "primary" PositionBackup = "backup" )
Controller positions in a primary/backup pair, matching the order of the SlurmctldHost lines and the labels scontrol ping uses.
const ( LabelRealm = "sind.realm" LabelCluster = "sind.cluster" LabelRole = "sind.role" LabelManaged = "sind.managed" LabelSlurmVersion = "sind.slurm.version" // LabelDataHostPath records the host directory the node bind-mounts as // its data (storage.dataStorage.hostPath), empty for the cluster's data // volume. LabelDataHostPath = "sind.data.hostpath" // LabelDataMountPath records the data mount point // (storage.dataStorage.mountPath, DefaultDataMountPath by default). LabelDataMountPath = "sind.data.mountpath" // LabelCVMFS records how the node mounts CVMFS (storage.cvmfs): "volume" // for the cvmfs volume plugin, "hostPath" for the Docker host's /cvmfs, // empty for none. LabelCVMFS = "sind.cvmfs" // LabelUsers and LabelGroups record the cluster users and groups // (users, groups), as space-separated entries (see LinuxUsers.Labels). LabelUsers = "sind.users" LabelGroups = "sind.groups" // LabelIdentity records the identity mode (identity) of the cluster: // local, nssSlurm or clientIds. LabelIdentity = "sind.identity" )
Label keys used on sind containers.
Docker merges the image's labels into a container's, so a label sind leaves out can come from the image. Every node container therefore gets each of these labels, with an empty value where there is nothing to record, and readers treat an empty or missing label alike, as nodes created by earlier sind versions lack some of them.
const ControllerBackupShortName = slurm.BackupControllerHost
ControllerBackupShortName is the hostname of the backup controller created when the controller node spec sets backupController: true. It matches the second SlurmctldHost line in the generated slurm.conf.
const DNSSuffix = "sind"
DNSSuffix is the base domain for all sind DNS names.
const DefaultDataMountPath = "/data"
DefaultDataMountPath is the default mount path for the shared data volume.
const DefaultReadinessInterval = probe.DefaultInterval
DefaultReadinessInterval is the delay between readiness probe rounds that Create and WorkerAdd use for a readinessInterval of zero or less.
const HomeMountPath = "/home"
HomeMountPath is where the nodes of a cluster with users mount the cluster's home volume, which holds the users' home directories.
const MaskMunge = "ln -sf /dev/null /etc/systemd/system/munge.service\n"
MaskMunge is the line the node entrypoint starts with under identity clientIds: it masks munge.service before systemd starts, as auth/slurm replaces munge and the node has no munge key.
const NodeEntrypoint = `` /* 197-byte string literal not displayed */
NodeEntrypoint is the shell script every node container starts with, as PID 1, before it execs systemd. It moves itself into init.scope and enables all available controllers in the root cgroup's cgroup.subtree_control.
docker exec places its process in the container's root cgroup unless that cgroup has controllers enabled; runc then falls back to init's cgroup. A process in the root cgroup makes every later write to its cgroup.subtree_control fail with EBUSY (cgroup v2's no internal processes rule). Without this script, a docker exec of sind's that lands before systemd has enabled controllers keeps systemd from ever doing so, and daemons with Delegate=yes get none: slurmd then cannot use the memory or cpu controller, which jobacct_gather/cgroup needs. Each controller is enabled on its own, as one write of all of them fails as a whole if the kernel refuses one. Failures are ignored so the node still boots.
const RunTmpfsSize = "64m"
RunTmpfsSize is the size of every node's /run tmpfs. /run holds systemd's runtime state, the daemons' sockets and pid files, and journald's volatile journal, which journald keeps to a tenth of the file system; without a size it could grow to half the host's memory, all of it charged to the node. systemd wants 16M free on /run to reload.
const TaskAffinityCapability = "SYS_NICE"
TaskAffinityCapability is the capability managed workers get when the cluster's TaskPlugin includes task/affinity: slurmstepd, as root, sets each task's CPU affinity after the task has become the job's user, and changing the affinity of another user's process needs CAP_SYS_NICE, which Docker drops by default. Without it, every job of a user other than root fails with task_g_set_affinity.
Variables ¶
var ( // ErrClusterExists reports that resources with the names of the // cluster to create exist already (PreflightCheck, Create). ErrClusterExists = errors.New("cluster resources exist") // ErrClusterNotFound reports that a cluster, or its controller, does // not exist in the realm (GetStatus, WorkerAdd). ErrClusterNotFound = errors.New("cluster not found") // ErrNodeNotFound reports that a named node does not exist in its // cluster (power operations, WorkerRemove). ErrNodeNotFound = errors.New("node not found") // ErrNodesConfMissing reports that the controller has no // sind-nodes.conf, so sind cannot add managed workers (WorkerAdd). ErrNodesConfMissing = errors.New("sind-nodes.conf not found on controller: managed workers require sind-generated Slurm configuration; use --unmanaged to add nodes without modifying Slurm config") // ErrNotReady reports that the nodes or Slurm of a Create or WorkerAdd // did not become ready within its wait limit (config.Cluster.Wait, // WorkerAddOptions.Wait). ErrNotReady = errors.New("not ready") // ErrNetworkFull reports that the nodes of a Create or WorkerAdd do // not fit on the realm's mesh or the cluster network, Docker bridge // networks of at most docker.MaxBridgeEndpoints containers // (PreflightCheck, Create, WorkerAdd). ErrNetworkFull = errors.New("network full") )
Errors that library callers can test for with errors.Is. The errors pkg/cluster returns wrap them and carry their own message.
var ( // ErrRootlessDaemon is a daemon in rootless mode. ErrRootlessDaemon = errors.New("the Docker daemon runs in rootless mode") // ErrUsernsRemap is a daemon that remaps user namespaces. ErrUsernsRemap = errors.New("the Docker daemon runs with userns-remap") // ErrCgroupV1 is a daemon that runs containers on cgroup v1. ErrCgroupV1 = errors.New("the Docker daemon runs containers on cgroup v1") // ErrDockerTooOld is a Docker Engine older than doctor.MinDockerMajor. ErrDockerTooOld = errors.New("the Docker Engine is too old") // ErrNoNsdelegate is a Docker host whose cgroup2 hierarchy is mounted // without nsdelegate (CheckNsdelegate). ErrNoNsdelegate = errors.New("the Docker host mounts cgroup2 without nsdelegate") )
The errors DaemonSupport wraps for a Docker daemon that cannot run sind nodes.
var AllVolumeTypes = []VolumeType{VolumeConfig, VolumeMunge, VolumeData, VolumeState, VolumeHome}
AllVolumeTypes lists the cluster volume types in creation order.
var AuthTypes = []AuthType{AuthMunge, AuthSlurm, AuthJWT}
AuthTypes are the authentication types GetAuthKey takes.
Functions ¶
func BuildContainerExecArgs ¶ added in v0.3.0
func BuildContainerExecArgs(container docker.ContainerName, user, workDir string, isTTY bool, command []string) []string
BuildContainerExecArgs builds docker CLI arguments for running a command directly inside a cluster container via docker exec. The command runs as root in workDir, the node's data mount point (see EnterTarget), or, when user names a cluster user, as that user in its home directory. When command is nil, an interactive login shell is started.
func BuildRunArgs ¶
BuildRunArgs returns the docker arguments for creating a node container. The returned slice does not include "create" or "run -d" — the caller passes these args to Client.CreateContainer or Client.RunContainer.
func BuildSSHArgs ¶
func BuildSSHArgs(sshContainer docker.ContainerName, node, cluster, realm string, isTTY bool, sshOptions, command []string) []string
BuildSSHArgs builds the docker CLI arguments for running SSH through the sind-ssh relay container. The returned args are suitable for passing to docker directly (e.g. "docker exec -i -t sind-ssh ssh ...").
node is the short name (e.g. "worker-0"), cluster is the cluster name, isTTY controls whether -t is added to docker exec, sshOptions are passed through to SSH before the target, and command is the optional remote command.
func CheckDaemon ¶ added in v0.11.0
CheckDaemon asks the Docker daemon what it is and returns DaemonSupport's verdict. Call it before mesh.Manager.EnsureMesh and Create, so that an unsupported daemon fails before anything is pulled or created.
func CheckNsdelegate ¶ added in v0.11.0
CheckNsdelegate reads the cgroup2 mount of the Docker daemon's kernel in a throwaway container of image (doctor.ProbeCgroupInfo), and returns an error that wraps ErrNoNsdelegate, with the commands that enable it, when the mount lacks nsdelegate, or ErrCgroupV1 when the container has no cgroup2 at doctor.CgroupRoot. Unlike `sind doctor` for a daemon on this machine, it looks at the daemon's kernel wherever that runs. Create and WorkerAdd call it before they create a node container: without nsdelegate the failure would show only later, as a node or Slurm daemon that does not become ready.
func ComposeProject ¶
ComposeProject returns the Docker Compose project name for a cluster.
func ContainerLogArgs ¶
ContainerLogArgs builds docker CLI arguments for streaming container logs. node is the short name (e.g. "controller", "worker-0"), cluster is the cluster name, and follow controls whether --follow is added.
func ContainerName ¶
func ContainerName(realm, cluster, shortName string) docker.ContainerName
ContainerName returns the Docker container name for a node. shortName is the node's hostname, e.g. "controller", "db", "api", "submitter", "worker-0".
func ContainerPrefix ¶
ContainerPrefix returns the container name prefix for a cluster, used to extract short names from full container names.
func CreateClusterNetwork ¶
func CreateClusterNetwork(ctx context.Context, client *docker.Client, realm, clusterName string) error
CreateClusterNetwork creates the cluster-specific Docker bridge network.
func CreateClusterVolume ¶ added in v0.9.0
func CreateClusterVolume(ctx context.Context, client *docker.Client, realm, clusterName string, vtype VolumeType) error
CreateClusterVolume creates a single cluster volume.
func CreateNode ¶
func CreateNode(ctx context.Context, client *docker.Client, meshMgr *mesh.Manager, cfg RunConfig) (docker.ContainerID, error)
CreateNode creates a node container on its cluster network and the mesh network, and starts it. Returns the container ID.
func DNSName ¶
DNSName returns the fully qualified DNS name for a node. shortName is the node's hostname, e.g. "controller", "worker-0".
func DNSSearchDomain ¶
DNSSearchDomain returns the DNS search domain for a cluster.
func DaemonSupport ¶ added in v0.11.0
func DaemonSupport(info *docker.DaemonInfo) error
DaemonSupport returns nil when the daemon that info describes can run sind nodes. Every node starts with --security-opt writable-cgroups=true, which Docker refuses on a daemon in rootless mode or with userns-remap, and only at `docker start`: after the images are pulled and the cluster's network and volumes created. A node's entrypoint and systemd need cgroup v2; on cgroup v1 the node never becomes ready. Docker Engines before doctor.MinDockerMajor know neither writable-cgroups nor the gw-priority of the nodes' network endpoints, and refuse every node at `docker create`. A version that does not parse passes, as `sind doctor` reports it.
func DataMountPath ¶ added in v0.10.0
DataMountPath returns where a node container mounts the cluster's data: its LabelDataMountPath, or DefaultDataMountPath without one.
func DataPathWarning ¶ added in v0.11.0
DataPathWarning returns a warning when a cluster's data host path is the host's root directory or the user's home directory ($HOME), which every node then mounts read-write: typically by accident, from sind create cluster run there with the default --data . It returns "" for any other path.
func Delete ¶
func Delete(ctx context.Context, client *docker.Client, meshMgr *mesh.Manager, clusterName string) error
Delete orchestrates the full cluster deletion flow.
The caller holds the realm lock (state.LockRealm) until Delete returns.
Deleting a non-existent cluster is not an error. The function handles partial clusters (e.g., from a failed creation) by removing whatever resources exist.
HasOtherClusters?
│
deleteClusterResources deregisters from the mesh only if other clusters remain
│
yes → done
no → CleanupMesh
Whether other clusters remain does not depend on this cluster's containers, so Delete settles it first: when the mesh goes too, removing the nodes' DNS records and known_hosts entries would be wasted work.
func DeleteAll ¶ added in v0.11.0
DeleteAll deletes every cluster of the realm, in parallel, and then the realm's mesh. It finds the clusters by the labels of their containers, networks and volumes, and removes the mesh even when it finds no cluster: a create that was killed can leave a mesh behind without one.
A cluster that fails to delete does not stop the others. The mesh then stays for what is left, the clusters that were deleted are deregistered from it, and DeleteAll returns the failures, joined.
func DeleteContainers ¶
func DeleteContainers(ctx context.Context, client *docker.Client, containers []docker.ContainerListEntry) error
DeleteContainers force-removes the given containers in parallel (docker rm -f). A container that is already gone is logged and treated as success — the caller asked for the resource removed, not for a particular state transition. Like DeleteVolumes, it tries every container even when one fails, so that one failure does not cancel the removals still waiting for a docker call slot, and returns every failure.
func DeleteNetwork ¶
DeleteNetwork removes the cluster network. A network that is already gone is logged and treated as success.
func DeleteVolumes ¶
DeleteVolumes removes the given cluster volumes in parallel. Each removal retries past the dockerd async-cleanup race that follows `docker rm -f`. A volume that is already gone is logged and treated as success. Every volume is attempted; the errors of those that could not be removed are joined in argument order.
func DeregisterMesh ¶
func DeregisterMesh(ctx context.Context, meshMgr *mesh.Manager, clusterName string, containers []docker.ContainerListEntry) error
DeregisterMesh removes DNS records and known_hosts entries for all containers in batch, starting a stopped mesh first (see deregisterHostnames). This is the inverse of registerMesh during cluster creation. Failures are logged and swallowed: the cluster is being torn down, and stale entries in a mesh helper that's already unreachable will be overwritten on next register or cleared when the mesh itself is torn down.
func DetectCVMFS ¶ added in v0.11.0
func DetectCVMFS(ctx context.Context, client *docker.Client, image string) (config.StorageType, error)
DetectCVMFS picks how the nodes mount CVMFS: config.StorageVolume when the cvmfs Docker volume plugin is installed and enabled, otherwise config.StorageHostPath, a bind mount of the Docker host's /cvmfs. The bind mount is tried in a throwaway container of image first, so a host without /cvmfs, or one whose /cvmfs Docker cannot propagate into containers, fails before any node is created.
func DiscoverClusterNames ¶ added in v0.3.0
func DiscoverClusterNames(ctx context.Context, client *docker.Client, realm string) ([]string, error)
DiscoverClusterNames finds cluster names from orphaned networks and volumes that may not have containers. This supplements GetClusters (which only finds clusters with running containers) for cleanup operations.
Filters on both the realm and cluster labels so mesh resources (which carry only the realm label) are skipped, and resources from other realms can't match even when names collide. The network and volume listings run concurrently.
func EnterTarget ¶
func EnterTarget(ctx context.Context, client *docker.Client, realm, clusterName string) (target, workDir string, err error)
EnterTarget determines the target node for sind enter and sind exec, and the directory they start in: the node's data mount point. The target is "submitter" if present in the cluster, otherwise the controller: in a primary/backup pair the one in control, falling back to "controller" when that cannot be determined. In an unmanaged cluster sind does not know which controller is in control, so the running one is picked, preferring "controller".
func GetNodeNames ¶ added in v0.11.0
GetNodeNames returns the nodes of every cluster in the realm as NODE.CLUSTER, ordered by cluster name, then like GetNodes. It lists the realm's containers once and inspects none, for shell completion.
func HasOtherClusters ¶
func HasOtherClusters(ctx context.Context, client *docker.Client, realm, clusterName string) (bool, error)
HasOtherClusters checks whether any sind cluster containers exist besides the named cluster. This is used to decide whether to clean up mesh infrastructure after deleting a cluster.
A container belongs to clusterName only if its sind.cluster label says so. The name prefix "<realm>-<clusterName>-" cannot tell: it also matches the containers of cluster "<clusterName>-2". A realm container without a cluster label counts as another cluster, which keeps the mesh.
func IdentityFromLabels ¶ added in v0.11.0
func IdentityFromLabels(labels docker.Labels) config.IdentityMode
IdentityFromLabels returns the identity mode a node container's LabelIdentity records, local without one.
func IsManaged ¶ added in v0.10.0
IsManaged reports whether a node container's labels mark it as managed by sind: its Slurm configuration is sind's and sind runs its Slurm daemon. On a controller it tells whether the whole cluster is managed. Containers created before sind recorded LabelManaged count as managed.
func NetworkName ¶
func NetworkName(realm, cluster string) docker.NetworkName
NetworkName returns the Docker network name for a cluster.
func NodeLabels ¶
func NodeLabels(realm, clusterName string, role config.Role, managed bool, slurmVersion, dataHostPath string, containerNumber int) docker.Labels
NodeLabels returns the standard labels for a node container. managed records whether sind manages Slurm on the node (see IsManaged). containerNumber is the 1-based instance number for compose compatibility. The slurm version label is always set, empty when sind does not know the version (unmanaged clusters), and so is the data host path label, empty in Docker volume mode: the image's labels would otherwise show through on the container, and the sind-node image carries a slurm version label.
func NodeShortNames ¶
NodeShortNames returns the short hostname for each node defined in the config, including the backup controller when enabled. Worker nodes are indexed sequentially across all worker groups, matching the indexing used in slurm.ManagedWorkers.
func OtherRealms ¶ added in v0.11.0
func OtherRealms(ctx context.Context, client *docker.Client, realm, clusterName string) ([]string, error)
OtherRealms returns, sorted, the realms other than realm that hold a node container of a cluster named clusterName. Labels that are not valid realm names are left out.
func PowerCut ¶
func PowerCut(ctx context.Context, client *docker.Client, realm, clusterName string, shortNames []string) error
PowerCut immediately kills the specified nodes (docker kill).
func PowerCycle ¶
func PowerCycle(ctx context.Context, client *docker.Client, meshMgr *mesh.Manager, clusterName string, shortNames []string) error
PowerCycle hard-restarts the specified nodes: it kills them all (docker kill), then starts them as PowerOn does.
func PowerFreeze ¶
func PowerFreeze(ctx context.Context, client *docker.Client, realm, clusterName string, shortNames []string) error
PowerFreeze suspends all processes in the specified nodes (docker pause). The containers remain running but are completely unresponsive.
func PowerOn ¶
func PowerOn(ctx context.Context, client *docker.Client, meshMgr *mesh.Manager, clusterName string, shortNames []string) error
PowerOn starts the specified stopped nodes (docker start). It first starts the realm's mesh DNS and SSH relay if they are stopped, as after a host reboot, and afterwards points the started nodes' mesh DNS records at their addresses: Docker can give a node another address each time it starts.
func PowerReboot ¶
func PowerReboot(ctx context.Context, client *docker.Client, meshMgr *mesh.Manager, clusterName string, shortNames []string) error
PowerReboot gracefully restarts the specified nodes: it stops them all (docker stop), then starts them as PowerOn does.
func PowerShutdown ¶
func PowerShutdown(ctx context.Context, client *docker.Client, realm, clusterName string, shortNames []string) error
PowerShutdown gracefully stops the specified nodes (docker stop).
func PowerUnfreeze ¶
func PowerUnfreeze(ctx context.Context, client *docker.Client, realm, clusterName string, shortNames []string) error
PowerUnfreeze resumes the specified frozen nodes (docker unpause).
func PreflightCheck ¶
func PreflightCheck(ctx context.Context, client *docker.Client, realm string, cfg *config.Cluster) error
PreflightCheck verifies that no Docker resources conflict with the cluster that would be created from the given configuration. It checks for existing networks, volumes, and containers with matching names, and that the realm's mesh and the cluster network have room for the nodes (checkBridgePorts).
Container existence is checked with a single `docker ps` filtered by the cluster's realm + name labels; this keeps the call count constant regardless of node count.
func ServiceLogArgs ¶
ServiceLogArgs builds docker CLI arguments for streaming service journal logs. node is the short name, cluster is the cluster name, service is the systemd unit name (e.g. "slurmctld", "slurmd"), and follow controls whether --follow is added.
func VolumeName ¶
func VolumeName(realm, cluster string, volumeType VolumeType) docker.VolumeName
VolumeName returns the Docker volume name for a cluster resource.
func WorkerRemove ¶
func WorkerRemove(ctx context.Context, client *docker.Client, meshMgr *mesh.Manager, clusterName string, shortNames []string) error
WorkerRemove removes worker nodes from a cluster.
The caller holds the realm lock (state.LockRealm) until WorkerRemove returns.
For managed nodes (those present in sind-nodes.conf), the flow is:
- Read sind-nodes.conf through the controller, which has to run
- Update sind-nodes.conf to remove the node definitions and reconfigure slurmctld, while DNS + known_hosts are deregistered
- Stop + remove containers
For unmanaged nodes, and every node of an unmanaged cluster, step 1 and the Slurm part of step 2 are skipped: the Slurm configuration of an unmanaged cluster is the user's, even if it contains a sind-nodes.conf. So is a configuration without sind-nodes.conf.
func WriteClusterConfig ¶
func WriteClusterConfig(ctx context.Context, client *docker.Client, realm string, cfg *config.Cluster, image string) error
WriteClusterConfig generates and writes slurm.conf, sind-nodes.conf, and cgroup.conf to the config volume. Uses a temporary container to access the volume.
With a managed db node it also writes slurmdbd.conf, and the slurmdbd.conf.d fragments of a map-form slurmdbd section, and turns on accounting in slurm.conf; an unmanaged db node gets neither. With identity clientIds it writes a new slurm.key, the key of auth/slurm, which every node reads from the config volume, and with a managed api node a new jwt_hs256.key, the key of auth/jwt, and the JWT parameters in slurm.conf and slurmdbd.conf. These files can hold secrets, such as a StoragePass, and every node mounts the config volume: they are written with mode 0600, so that others can never read them, and slurmdbd refuses a slurmdbd.conf, auth/slurm a slurm.key and auth/jwt a jwt_hs256.key, that others may read. docker cp writes files as root, so the helper then runs (like the munge helper) to give them to SlurmUser with docker exec, and the fragments' directory too, with mode 0700.
Types ¶
type AuthKey ¶ added in v0.11.0
AuthKey is a key that authenticates a cluster's Slurm traffic.
func GetAuthKey ¶ added in v0.11.0
func GetAuthKey(ctx context.Context, client *docker.Client, realm, clusterName string, authType AuthType) (*AuthKey, error)
GetAuthKey reads a key that authenticates a cluster's Slurm traffic from one of its node containers: for authType munge the munge key, for slurm slurm.key, with identity clientIds, and for jwt jwt_hs256.key, with a managed api node. An empty authType is the cluster's AuthType: slurm with identity clientIds, munge otherwise. A type the cluster does not use is an error that says why.
type AuthType ¶ added in v0.11.0
type AuthType string
AuthType is a Slurm authentication plugin a cluster uses, auth/<type>, and so which key GetAuthKey returns.
const ( // AuthMunge is auth/munge: munged on every node, with the munge key. AuthMunge AuthType = "munge" // AuthSlurm is auth/slurm, with slurm.key, under identity clientIds. AuthSlurm AuthType = "slurm" // AuthJWT is auth/jwt, with jwt_hs256.key, the alternative // authentication of slurmrestd's tokens on a cluster with a managed api // node. AuthJWT AuthType = "jwt" )
Authentication types.
type Cluster ¶
Cluster represents a live sind cluster as it exists in Docker. This is distinct from config.Cluster, which represents the configuration input.
func Create ¶
func Create(ctx context.Context, client *docker.Client, meshMgr *mesh.Manager, cfg *config.Cluster, readinessInterval time.Duration) (result *Cluster, retErr error)
Create orchestrates the full cluster creation flow.
The caller holds the realm lock (state.LockRealm) from before mesh.Manager.EnsureMesh until Create returns, and checks the daemon with CheckDaemon before either.
The caller must ensure mesh infrastructure exists (via mesh.Manager.EnsureMesh) before calling Create, and apply the config's defaults (config.Cluster.ApplyDefaults). Create validates the config first, and refuses a config realm other than meshMgr.Realm, the realm it creates the cluster in. The context deadline controls the overall timeout; readinessInterval controls the polling interval for readiness probes, and zero or less means DefaultReadinessInterval. cfg.Wait, when positive, limits how long Create waits for the nodes and Slurm to become ready, counted for each node from when its container has started, so that image pulls do not count; the steps after the nodes are ready end cfg.Wait after the last node container started. When the limit is reached, Create rolls back and returns an error that wraps ErrNotReady.
┌ PreflightCheck → createResources ─────────────────┐
├ resolveInfra (DNS IP ║ SSH key ║ Slurm version) ──┤
├ DetectCVMFS (storage.cvmfs only) ─────────────────┼→ setupNodes
├ CheckNsdelegate ──────────────────────────────────┤
└ pullImages (missing images; all with cfg.Pull) ───┘
│
registerMesh ║ enableSlurm → createSlurmAccounts (accounts only) ║ createHomes (users only)
│
*Cluster
Each distinct image the daemon does not have, or with cfg.Pull each distinct image, is pulled once, concurrently, and the steps that run one (the helpers of createResources, the Slurm version, DetectCVMFS, CheckNsdelegate) wait for the pull; nothing is created with --pull always, and no node container's docker create pulls (see startPull). A failed check rolls back what the other branches have created by then; no node container exists yet.
An unmanaged cluster (managed: false on the controller) gets the same containers, volumes and munge key, but sind writes no Slurm configuration, does not discover the Slurm version and enables no Slurm daemon.
type HAStatus ¶ added in v0.10.0
type HAStatus struct {
Position string `json:"position"` // "primary" or "backup"
InControl bool `json:"in_control"` // this controller currently runs the cluster
}
HAStatus describes a controller's place in a primary/backup pair.
type LinuxGroup ¶ added in v0.11.0
type LinuxGroup struct {
Name string
GID int
// Members are the users that have the group as a supplementary group.
// As in /etc/group, users with it as their primary group are not
// listed.
Members []string
}
LinuxGroup is a group sind creates on the nodes that get the cluster users.
type LinuxUser ¶ added in v0.11.0
LinuxUser is a user account sind creates on the nodes that get the cluster users.
type LinuxUsers ¶ added in v0.11.0
type LinuxUsers struct {
Users []LinuxUser
Groups []LinuxGroup
}
LinuxUsers are the user accounts and groups of a cluster (users and groups), with every ID resolved: each user without a primary group has a private group of its own name with gid = uid.
func LinuxUsersFromLabels ¶ added in v0.11.0
func LinuxUsersFromLabels(labels docker.Labels) (LinuxUsers, error)
LinuxUsersFromLabels returns the users and groups a node container's LabelUsers and LabelGroups record (see LinuxUsers.Labels), empty when it has neither.
func NewLinuxUsers ¶ added in v0.11.0
func NewLinuxUsers(cfg *config.Cluster) LinuxUsers
NewLinuxUsers resolves the users and groups of a cluster config, after ApplyDefaults has assigned their IDs: the private groups, in user order, then the declared groups with their members.
func (LinuxUsers) IsEmpty ¶ added in v0.11.0
func (l LinuxUsers) IsEmpty() bool
IsEmpty reports whether the cluster has neither users nor groups.
func (LinuxUsers) Labels ¶ added in v0.11.0
func (l LinuxUsers) Labels() docker.Labels
Labels returns the labels that record the users and groups on every node container (LabelUsers and LabelGroups), so that workers added later get the same ones. Both are space-separated entries, not comma-separated: docker ps joins all labels of a container with commas. Both are set, empty without users or groups, so that no image label of that name shows through.
sind.users name:uid:gid ... alice:1000:1000 bob:2002:3000 sind.groups name:gid[:member+...] ... alice:1000 hpc:3000:alice
type MountPoint ¶ added in v0.3.0
type MountPoint struct {
Path string `json:"path"` // mount path inside the container (e.g. "/etc/slurm")
Source string `json:"source"` // volume name or host path
Type config.StorageType `json:"type"` // "volume" or "hostPath"
OK bool `json:"ok"` // true if the Docker volume exists (always true for hostPath)
}
MountPoint describes a volume or bind mount on cluster containers.
func GetMountPoints ¶ added in v0.3.0
func GetMountPoints(ctx context.Context, client *docker.Client, realm, clusterName string, containers []*docker.ContainerInfo) ([]MountPoint, error)
GetMountPoints returns the mount points for a cluster, checking volume existence for Docker volumes. containers are the cluster's node containers as docker inspect reports them, whose labels, unlike those docker ps lists, keep values with commas (see docker.ContainerInfo).
The data mount is what Docker mounts at a node's data mount point (the sind.data.mountpath label, or /data): a host-path bind mount or a Docker volume, the cluster's data volume when no node has one. The sind.users label adds the home volume at /home, and the sind.cvmfs label /cvmfs from the cvmfs plugin volume or the host's /cvmfs. With identity clientIds (the sind.identity label) there is no munge volume.
type NetworkHealth ¶
type NetworkHealth struct {
Mesh bool `json:"mesh_ok"` // sind-mesh network exists
MeshName string `json:"mesh_name"` // mesh network name (e.g. "sind-mesh")
MeshDriver string `json:"mesh_driver"` // mesh network driver (e.g. "bridge")
MeshSubnet string `json:"mesh_subnet"` // mesh network subnet
MeshGateway string `json:"mesh_gateway"` // mesh network gateway
DNS bool `json:"dns_ok"` // sind-dns container running
DNSName string `json:"dns_name"` // DNS container name (e.g. "sind-dns")
SSH bool `json:"ssh_ok"` // sind-ssh relay container running
SSHName string `json:"ssh_name"` // SSH relay container name (e.g. "sind-ssh")
Cluster bool `json:"cluster_ok"` // cluster network exists
ClusterName string `json:"cluster_name"` // cluster network name (e.g. "sind-dev-net")
ClusterDriver string `json:"cluster_driver"` // cluster network driver (e.g. "bridge")
ClusterSubnet string `json:"cluster_subnet"` // cluster network subnet
ClusterGateway string `json:"cluster_gateway"` // cluster network gateway
}
NetworkHealth holds the health and IPAM details of cluster networking.
func GetNetworkHealth ¶
func GetNetworkHealth(ctx context.Context, client *docker.Client, realm, clusterName string) (*NetworkHealth, error)
GetNetworkHealth checks the health of mesh, DNS, SSH relay, and cluster networking. The DNS and SSH relay containers count as healthy only while they run: after a host reboot they exist but are stopped.
type NetworkSummary ¶
type NetworkSummary struct {
Name string `json:"name"`
Driver string `json:"driver"`
Subnet string `json:"subnet"`
Gateway string `json:"gateway"`
}
NetworkSummary holds summary information about a sind network.
func GetNetworks ¶
func GetNetworks(ctx context.Context, client *docker.Client, realm string) ([]*NetworkSummary, error)
GetNetworks lists all sind-related Docker networks with IPAM details. This includes per-cluster networks (sind-<cluster>-net) and the mesh network (sind-mesh), but not the realm lock (state.LockNetworkName), which carries the realm label while a command holds it.
type Node ¶
type Node struct {
Name string // short name: "controller", "worker-0"
Role config.Role // "controller", "db", "api", "submitter", "worker"
ContainerID docker.ContainerID // Docker container ID
IP string // container IP address
State State
}
Node represents a running node in a sind cluster.
func WorkerAdd ¶
func WorkerAdd(ctx context.Context, client *docker.Client, meshMgr *mesh.Manager, opts WorkerAddOptions, readinessInterval time.Duration) (result []*Node, retErr error)
WorkerAdd adds worker nodes to an existing cluster.
The caller holds the realm lock (state.LockRealm) until WorkerAdd returns.
For managed workers (default), the flow is:
- Validate: options, controller exists, room on the realm's mesh and the cluster network (see checkBridgePorts), sind-nodes.conf present
- Inspect the controller and the newest worker, for the cluster's settings and the new workers' shape
- Check an explicit image: its Slurm version, its identity support; meanwhile check the Docker host for nsdelegate (CheckNsdelegate) in a container of the controller's image
- Create worker container(s)
- Wait for readiness, inject SSH keys, collect host keys
- Register DNS + known_hosts, while sind-nodes.conf gets the new nodes, slurmctld is reconfigured and slurmd starts on the new nodes
For unmanaged workers (Unmanaged=true), the Slurm steps are skipped. Workers added to an unmanaged cluster are always unmanaged. A failure after the first container exists removes the new containers, mesh entries and NodeName lines again. readinessInterval is the delay between readiness probe rounds, as for Create.
type NodeDetail ¶ added in v0.9.0
type NodeDetail struct {
Container string `json:"container"`
Cluster string `json:"cluster"`
Role config.Role `json:"role"`
Managed bool `json:"managed"` // sind manages Slurm on the node (see IsManaged)
FQDN string `json:"fqdn"`
IP string `json:"ip"`
Status docker.ContainerState `json:"status"`
Services ServiceHealth `json:"services"`
HA *HAStatus `json:"ha,omitempty"` // controllers of a primary/backup pair only
}
NodeDetail holds the full identity and health information for a single node as reported by 'sind get node'. It extends NodeSummary with a per-service health map. All readiness-checked services (munge, sshd, and on managed nodes the role's Slurm service, or mariadb and slurmdbd on a db node) are reported under Services.
type NodeHealth ¶
type NodeHealth struct {
State docker.ContainerState `json:"status"` // container state from Docker (e.g. "running", "exited")
IP string `json:"ip"` // container IP address
Services ServiceHealth `json:"services"` // all readiness-checked services (munge unless identity clientIds, sshd, and on managed nodes the role's slurmctld/slurmd, mariadb and slurmdbd, slurmrestd, or sackd)
HA *HAStatus `json:"ha,omitempty"` // controllers of a primary/backup pair only
}
NodeHealth holds the health status of a single node.
func GetNodeHealth ¶
func GetNodeHealth(ctx context.Context, client *docker.Client, info *docker.ContainerInfo, role config.Role, realm, clusterName string) (*NodeHealth, error)
GetNodeHealth checks the health of a single node container, from its docker inspect result, which the caller already holds. If the container is not running, remaining checks are skipped and default to false. The role determines which Slurm service is checked; unmanaged nodes (see IsManaged) get none. clusterName is used to select the cluster network IP.
type NodeStatus ¶
type NodeStatus struct {
Name string `json:"name"` // DNS-style name: "controller.dev"
Role config.Role `json:"role"` // "controller", "db", "api", "submitter", "worker"
Managed bool `json:"managed"` // sind manages Slurm on the node (see IsManaged)
Health *NodeHealth `json:"health"` //nolint:revive // nested health is intentional
}
NodeStatus combines node identity with health information.
type NodeSummary ¶
type NodeSummary struct {
Container string `json:"container"` // Docker container name
Cluster string `json:"cluster"` // cluster name
Role config.Role `json:"role"`
FQDN string `json:"fqdn"` // DNS name
IP string `json:"ip"` // container IP on cluster network
State State `json:"status"`
}
NodeSummary holds summary information about a node in a sind cluster.
func GetAllNodes ¶ added in v0.9.0
GetAllNodes lists all nodes across all clusters in the realm.
type RealmSummary ¶ added in v0.9.0
RealmSummary holds summary information about a sind realm.
type Resources ¶
type Resources struct {
Containers []docker.ContainerListEntry
Network docker.NetworkName
NetworkExists bool
Volumes []docker.VolumeName
}
Resources holds the Docker resources belonging to a cluster.
func ListClusterResources ¶
func ListClusterResources(ctx context.Context, client *docker.Client, realm, clusterName string) (*Resources, error)
ListClusterResources discovers all Docker resources belonging to the named cluster. Containers are found by label filter; network and volumes are checked by name convention and skipped when their labels name another realm or cluster. The three lookups run concurrently.
type RunConfig ¶
type RunConfig struct {
Realm string // realm name (e.g. "sind")
ClusterName string // cluster name
ShortName string // node hostname: "controller", "worker-0"
Role config.Role // "controller", "db", "api", "submitter", "worker"
Image string // container image
CPUs int // CPU limit
Memory string // memory limit (e.g. "2g")
TmpSize string // /tmp tmpfs size (e.g. "1g")
SlurmVersion string // slurm version for labels (optional)
DNSIP string // mesh DNS container IP (optional)
DataHostPath string // host path for data volume (empty = use docker volume)
DataMountPath string // mount point for data (default: /data)
Managed bool // sind manages Slurm on the node: its configuration and daemon (see IsManaged)
ContainerNumber int // 1-based compose container instance number
CapAdd []string // extra Linux capabilities (e.g. "SYS_ADMIN")
CapDrop []string // dropped Linux capabilities
Devices []string // host devices to expose (e.g. "/dev/fuse")
SecurityOpt []string // extra security options
// CVMFS is how the node mounts /cvmfs: config.StorageVolume for the
// plugin volume, config.StorageHostPath for the host's /cvmfs, or empty
// for none (see DetectCVMFS).
CVMFS config.StorageType
// MeshNetwork is the realm's mesh network, which the node joins next to
// its cluster network; CreateNode sets it from its mesh.Manager.
MeshNetwork docker.NetworkName
// Users are the cluster users and groups. The node records them in its
// labels, and with users it mounts the home volume at HomeMountPath.
Users LinuxUsers
// AddUsers creates the users and groups on the node (see
// nodeGetsUsers).
AddUsers bool
// Identity is the cluster's identity mode. With clientIds, munge is
// masked and the node mounts no munge volume.
Identity config.IdentityMode
// NSSSlurm switches the node's passwd and group lookups to nss_slurm
// first: managed workers with identity nssSlurm or clientIds.
NSSSlurm bool
// StoragePass is, on a managed db node, the StoragePass the slurmdbd
// section sets: the password of slurmdbd's MariaDB account, which
// authenticates with unix_socket without one (see accountingSQL).
StoragePass string
// TaskAffinity is set on managed workers of a cluster whose slurm.conf
// enables task/affinity (see slurm.TaskAffinity): they get
// TaskAffinityCapability.
TaskAffinity bool
}
RunConfig holds the parameters needed to build docker run arguments for creating a node container.
func NodeRunConfigs ¶
func NodeRunConfigs(cfg *config.Cluster, realm, dnsIP, slurmVersion string, cvmfs config.StorageType) []RunConfig
NodeRunConfigs builds RunConfig entries for all nodes in the cluster config. Worker nodes are indexed sequentially across all worker groups. In an unmanaged cluster every node is unmanaged; otherwise only workers, db and api nodes with managed: false are. cvmfs is the backend every node mounts CVMFS with (see DetectCVMFS), empty for none. The identity mode decides which nodes get the cluster users and groups (see nodeGetsUsers) and which resolve them with nss_slurm. Managed workers get TaskAffinity when the slurm.conf sind generates enables task/affinity.
type ServiceHealth ¶ added in v0.7.0
ServiceHealth maps a readiness-check service to its health status.
type State ¶ added in v0.2.0
type State string
State represents the state of a cluster or node.
const ( StateRunning State = "running" StateStopped State = "stopped" StatePaused State = "paused" StateMixed State = "mixed" // cluster: nodes in different states StateEmpty State = "empty" // cluster: no nodes exist StateUnknown State = "unknown" // node: unrecognised container state )
Possible cluster/node states.
type Status ¶
type Status struct {
Name string `json:"name"`
SlurmVersion string `json:"slurm_version"`
State State `json:"status"`
Nodes []*NodeStatus `json:"nodes"`
Network *NetworkHealth `json:"network"`
Mounts []MountPoint `json:"mounts"`
}
Status holds the full status of a sind cluster.
type Summary ¶ added in v0.2.0
type Summary struct {
Name string `json:"name"`
SlurmVersion string `json:"slurm_version"`
State State `json:"status"`
NodeCount int `json:"nodes"`
Submitters int `json:"submitters"`
Controllers int `json:"controllers"`
DBs int `json:"dbs"`
APIs int `json:"apis"`
Workers int `json:"workers"`
}
Summary holds summary information about a sind cluster.
type VolumeSummary ¶
VolumeSummary holds summary information about a sind volume.
func GetVolumes ¶
GetVolumes lists all sind-related Docker volumes.
type VolumeType ¶ added in v0.7.0
type VolumeType string
VolumeType identifies a cluster volume kind.
const ( VolumeConfig VolumeType = "config" VolumeMunge VolumeType = "munge" VolumeData VolumeType = "data" // VolumeState holds the slurmctld StateSaveLocation shared by the // primary and backup controller. Only clusters with a backup controller // have it. VolumeState VolumeType = "state" // VolumeHome holds the home directories of the cluster users. Only // clusters with users have it. VolumeHome VolumeType = "home" )
Cluster volume types.
type WorkerAddOptions ¶
type WorkerAddOptions struct {
ClusterName string
Count int // 0 or less adds one worker
Image string
CPUs int
Memory string
TmpSize string
Unmanaged bool
Pull bool // pull Image first; needs Image
// Wait, when positive, limits how long WorkerAdd waits for the new
// workers to become ready, counted as for Create's config.Cluster.Wait.
Wait time.Duration
CapAdd []string
CapDrop []string
Devices []string
SecurityOpt []string
}
WorkerAddOptions holds the parameters for adding worker nodes to a cluster. The image, resources and privileges are the new workers' shape: each one left at its zero value is taken from the cluster's newest worker (see workerShape). For the lists CapAdd, CapDrop, Devices and SecurityOpt, the zero value is nil: an empty list that is not nil replaces the newest worker's list too, so the new workers get none.
func (WorkerAddOptions) Check ¶ added in v0.11.0
func (o WorkerAddOptions) Check() error
Check reports the first option WorkerAdd cannot act on: a negative CPU count, a memory or /tmp size sind cannot read, Pull without Image, an unknown capability, a device path that is not absolute or an unknown security option. It calls docker for none of them, so that the CLI can reject them as usage errors before it takes the realm lock.