Documentation
¶
Overview ¶
Package nodejob runs a privileged, node-pinned Job that nsenters PID 1 and execs the on-host stratum binary, then gates on the Job result. It is the one implementation of a mechanism that internal/upgrade (rolling upgrades) and internal/certs (cluster CA rotation) both drive, so the two drivers cannot diverge. Every change to the privileged-Job runner — stale-Job guard, image pin, security-context tightening — lives here once.
The Job pod is deliberately hostPID/hostNetwork + privileged and runs a shell-free argv (nsenter execs the binary directly; no /bin/bash -c), so no interpreter ever re-parses a caller value.
Index ¶
- Constants
- Variables
- func Build(s Spec) *batchv1.Job
- func DeleteAndWait(ctx context.Context, cs kubernetes.Interface, namespace, name string) error
- func DeleteExactAndWait(ctx context.Context, cs kubernetes.Interface, j *batchv1.Job) error
- func Finished(j *batchv1.Job) bool
- func JobNode(j *batchv1.Job, labelKey string) string
- func Logs(ctx context.Context, cs kubernetes.Interface, s Spec) (string, error)
- func NodeLabelValue(node string) string
- func Ready(n *corev1.Node) bool
- func Run(ctx context.Context, cs kubernetes.Interface, s Spec) error
- func RunExitCode(ctx context.Context, cs kubernetes.Interface, s Spec) (int, error)
- func RunExitCodeLogs(ctx context.Context, cs kubernetes.Interface, s Spec) (int, string, error)
- func TruncName(name string) string
- func WaitReady(ctx context.Context, cs kubernetes.Interface, name string, attempts int) error
- type Spec
Constants ¶
const NodeAnnotation = "stratum.ciq.com/node"
NodeAnnotation carries the target node's name verbatim.
The label cannot: a node name is a DNS subdomain and may be 253 characters, while a label value may be 63. Build therefore puts a hash in the label when the name does not fit, and the full name here, where there is no limit.
Variables ¶
var ErrLogUnread = errors.New("its log could not be read")
ErrLogUnread marks a RunExitCodeLogs error whose Job did end with an exit status, returned beside it, but whose Pod's log could not be read: the apiserver reads it from the node's kubelet, which can be unreachable or untrusted while the Job's status still says how it ended.
Functions ¶
func Build ¶
Build renders the Job object for s. Pure — split out so the pod spec is unit-testable without a cluster.
func DeleteAndWait ¶
DeleteAndWait foreground-deletes a Job and waits until it is gone, so a fresh Create cannot race the old object.
func DeleteExactAndWait ¶
DeleteExactAndWait deletes exactly the Job object it was given, with its UID and resourceVersion as preconditions, so a Job recreated or changed since it was inspected (another run's, now running) is never the one removed. Then it waits for it to be gone.
func Finished ¶
Finished reports whether a Job has run to an end: it succeeded or failed, by its counters or its conditions. A Job being deleted is not finished until its Pod is: a deletion timestamp alone says nothing about the host.
func JobNode ¶
JobNode returns the node a Job targets. Jobs written before NodeAnnotation existed carry the name in the label, which was possible only because a node whose name did not fit could not have a Job at all.
func Logs ¶
Logs returns the log of s.Container in the Pod of the Job named s.Name, as RunExitCode reads its exit code: by the Job's UID, so an earlier Job's Pod cannot answer.
func NodeLabelValue ¶
NodeLabelValue returns node when it is a usable label value, or a stable hash of it when it is not. Selecting on LabelKey=NodeLabelValue(node) finds every Job targeting that node, whatever scheme named them.
func Run ¶
Run creates the Job (replacing a stale one from a prior run so its stale status cannot short-circuit the poll), waits for it to complete, deletes it on success, and returns an error on failure or timeout.
func RunExitCode ¶
RunExitCode runs a Job whose answer is its exit status rather than its success, and returns the container's exit code: 0 when the Job succeeded, the code it failed with otherwise. A failed Job is left in place for inspection, and the next Run or RunExitCode on it replaces it. An error means no exit status could be established (the Job timed out, or failed without its container terminating).
func RunExitCodeLogs ¶
RunExitCodeLogs is RunExitCode that also returns the log of the Job's Pod, for a Job that answers in its output as well as its exit status. The log of a succeeded Job is read before the Job is deleted, since Logs finds the Pod through the Job. An error also means the log could not be read; one that wraps ErrLogUnread had an exit status all the same, and returns it.
Types ¶
type Spec ¶
type Spec struct {
// Output receives cleanup warnings. Nil preserves stdout for standalone
// callers; operations serving MCP supply their own progress writer.
Output io.Writer
Namespace string
Name string // Job name; use TruncName to respect the 63-char limit
Node string // pod NodeName, and the value of the LabelKey label
LabelKey string // label whose value is Node (e.g. stratum.ciq.com/upgrade)
Container string // container name
Argv []string // full shell-free command: nsenter … -- <binary> …
ActiveDeadline time.Duration
PollAttempts int // completion polls, one every pollInterval
Kind string // noun for error messages, e.g. "per-node upgrade" / "carotate"
// Critical admits the pod as system-node-critical, as the static pods are:
// under node pressure the kubelet refuses every other new pod. It is also
// allowed to evict workload pods to make room, past every PDB, so only a
// Job on a node that has already been drained should set it.
Critical bool
}
Spec describes one privileged node Job. Namespace/Name/Node/LabelKey/Container/ Argv define the pod; ActiveDeadline and PollAttempts bound it; Kind names it in the error messages so each caller keeps its own wording.