kubeutil

package
v0.1.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 7, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

Documentation

Overview

Package kubeutil provides low-level Kubernetes utilities for controllers.

This package consolidates utility functions used across BubuStack controllers for common Kubernetes operations including:

  • Environment variable construction
  • Event recording
  • Finalizer management
  • Resource listing and deletion
  • Status patching with retry
  • DNS-1123 name generation
  • Duration configuration
  • Retry and periodic execution loops
  • JSON merge utilities
  • RBAC management
  • Service management
  • Validation status computation

Environment Variables

Build step config environment variables for pods:

envVars := kubeutil.ConfigEnvVars(jsonBytes)
kubeutil.AppendConfigEnvVar(&envVars, jsonBytes)

Event Recording

Record Kubernetes events with nil-safe logging fallback:

kubeutil.RecordEvent(recorder, logger, obj, corev1.EventTypeWarning, "Failed", "error message")

Finalizer Management

Ensure finalizers are present on objects:

added, err := kubeutil.EnsureFinalizer(ctx, client, obj, "my.finalizer.io")

Resource Listing and Deletion

List resources with label selectors:

err := kubeutil.ListByLabels(ctx, client, namespace, labels, &podList)

Delete resources with NotFound handling:

err := kubeutil.DeleteIfExists(ctx, client, obj, logger)

Status Patching

Retry status patches on conflicts:

err := kubeutil.RetryableStatusPatch(ctx, client, obj, func(o client.Object) {
    o.(*v1alpha1.StepRun).Status.Phase = enums.PhaseRunning
})

Name Generation

Generate DNS-1123 compliant names:

name := kubeutil.ComposeName("storyrun", "my-story", "step-1")

Duration Configuration

Resolve durations with fallbacks:

timeout := kubeutil.PositiveDurationOrDefault(userTimeout, 30*time.Second)
timeout := kubeutil.FirstPositiveDuration(step, story, default)

Retry and Periodic Execution

Retry with exponential backoff:

err := kubeutil.Retry(ctx, kubeutil.RetryConfig{MaxAttempts: 3}, fn, retryable)

Run periodic tasks:

err := kubeutil.Periodic(ctx, 10*time.Second, fn)

JSON Merge

Merge runtime.RawExtension with-blocks:

merged, err := kubeutil.MergeWithBlocks(base, overlay)

Merge string maps:

labels := kubeutil.MergeStringMaps(base, override)

RBAC Management

Ensure Roles and RoleBindings:

result, err := kubeutil.EnsureRole(ctx, client, scheme, owner, name, ns, rules, style)
result, err := kubeutil.EnsureRoleBinding(ctx, client, scheme, owner, name, ns, roleRef, subjects, style)

Service Management

Ensure Services with immutable field preservation:

svc, result, err := kubeutil.EnsureService(ctx, client, scheme, owner, desired)

Validation Status

Compute Ready conditions from validation/binding states:

outcome := kubeutil.ComputeValidationOutcome(kubeutil.ValidationParams{
    ValidationErrors: errs,
    SuccessReason:    "Valid",
})

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AppendConfigEnvVar

func AppendConfigEnvVar(envVars *[]corev1.EnvVar, raw []byte)

AppendConfigEnvVar appends the BUBU_STEP_CONFIG env var to envVars when raw is non-empty.

Arguments:

  • envVars *[]corev1.EnvVar: pointer to the env var slice to append to.
  • raw []byte: JSON configuration bytes.

Side Effects:

  • Appends to *envVars if raw is non-empty and envVars is non-nil.

func CloneServicePorts

func CloneServicePorts(ports []corev1.ServicePort) []corev1.ServicePort

CloneServicePorts returns a deep copy of the provided ServicePort slice.

Arguments:

  • ports []corev1.ServicePort: ports to clone.

Returns:

  • []corev1.ServicePort: cloned ports, or nil if empty.

func ComposeName

func ComposeName(parts ...string) string

ComposeName builds a DNS-1123 compliant resource name from the provided parts.

Arguments:

  • parts ...string: name segments to join with hyphens.

Returns:

  • string: DNS-1123 compliant name (max 63 characters).

Behavior:

  • Joins parts with hyphens.
  • When the result exceeds 63 characters, truncates and appends a deterministic FNV-1a hash suffix for uniqueness.
  • Results are stable across reconciliations for the same inputs.

func ConfigEnvVars

func ConfigEnvVars(raw []byte) []corev1.EnvVar

ConfigEnvVars returns a slice containing the BUBU_STEP_CONFIG env var when raw is non-empty, otherwise it returns nil.

Arguments:

  • raw []byte: JSON configuration bytes.

Returns:

  • []corev1.EnvVar: slice containing the config env var, or nil if raw is empty.

func DeleteIfExists

func DeleteIfExists(ctx context.Context, c client.Client, obj client.Object, logger DeleteLogger) error

DeleteIfExists deletes the provided object using background propagation and treats IsNotFound as success so controllers can safely converge deletes.

Arguments:

  • ctx context.Context: context for the delete operation.
  • c client.Client: Kubernetes client.
  • obj client.Object: the object to delete.
  • logger DeleteLogger: optional logger for operation details.

Returns:

  • error: nil on success (including NotFound), or the delete error.

func EnsureFinalizer

func EnsureFinalizer(ctx context.Context, c client.Client, obj client.Object, finalizer string) (bool, error)

EnsureFinalizer adds the supplied finalizer to obj (if missing) using a merge patch.

Arguments:

  • ctx context.Context: context for the patch operation.
  • c client.Client: Kubernetes client.
  • obj client.Object: the object to add the finalizer to.
  • finalizer string: the finalizer string to add.

Returns:

  • bool: true when the finalizer was added, false if already present.
  • error: patch error or nil on success.

Behavior:

  • Returns (false, nil) if the finalizer is already present.
  • Uses merge patch for atomic finalizer addition.

func EnsureRole

func EnsureRole(
	ctx context.Context,
	c client.Client,
	scheme *runtime.Scheme,
	owner client.Object,
	name string,
	namespace string,
	rules []rbacv1.PolicyRule,
	style ReferenceStyle,
) (controllerutil.OperationResult, error)

EnsureRole CreateOrUpdates a namespaced Role with the supplied rules and owner reference.

Arguments:

  • ctx context.Context: context for the operation.
  • c client.Client: Kubernetes client.
  • scheme *runtime.Scheme: scheme for setting owner references.
  • owner client.Object: the owner object for the Role.
  • name string: Role name.
  • namespace string: Role namespace.
  • rules []rbacv1.PolicyRule: Role rules.
  • style ReferenceStyle: how to set the owner reference.

Returns:

  • controllerutil.OperationResult: result of the operation.
  • error: any error encountered.

func EnsureRoleBinding

func EnsureRoleBinding(
	ctx context.Context,
	c client.Client,
	scheme *runtime.Scheme,
	owner client.Object,
	name string,
	namespace string,
	roleRef rbacv1.RoleRef,
	subjects []rbacv1.Subject,
	style ReferenceStyle,
) (controllerutil.OperationResult, error)

EnsureRoleBinding CreateOrUpdates a namespaced RoleBinding with the supplied RoleRef, subjects, and owner reference.

Arguments:

  • ctx context.Context: context for the operation.
  • c client.Client: Kubernetes client.
  • scheme *runtime.Scheme: scheme for setting owner references.
  • owner client.Object: the owner object for the RoleBinding.
  • name string: RoleBinding name.
  • namespace string: RoleBinding namespace.
  • roleRef rbacv1.RoleRef: the role reference.
  • subjects []rbacv1.Subject: the subjects.
  • style ReferenceStyle: how to set the owner reference.

Returns:

  • controllerutil.OperationResult: result of the operation.
  • error: any error encountered.

func EnsureSecretCopy

func EnsureSecretCopy(
	ctx context.Context,
	reader client.Reader,
	writer client.Client,
	sourceNamespace string,
	targetNamespace string,
	name string,
	auth ...SecretCopyAuthorization,
) error

EnsureSecretCopy ensures a Secret exists in targetNamespace, copying data from sourceNamespace.

Behavior:

  • Returns early when name is empty or namespaces are equal.
  • Requires explicit authorization for cross-namespace copies.
  • Creates the target Secret if missing, marking it as managed.
  • Updates the target Secret only when it is marked as managed.

Arguments:

  • ctx context.Context: request-scoped context.
  • reader client.Reader: reader for source Secret (use APIReader if available).
  • writer client.Client: writer for creating/updating the target Secret.
  • sourceNamespace string: namespace holding the source Secret.
  • targetNamespace string: namespace to receive the Secret copy.
  • name string: Secret name.
  • auth SecretCopyAuthorization: explicit cross-namespace authorization policies.

Returns:

  • error: on read/create/update failures.

func EnsureService

func EnsureService(
	ctx context.Context,
	c client.Client,
	scheme *runtime.Scheme,
	owner client.Object,
	desired *corev1.Service,
) (*corev1.Service, controllerutil.OperationResult, error)

EnsureService converges the live Service to match the desired spec by creating it when absent or patching metadata/spec differences. The returned OperationResult matches controllerutil.CreateOrUpdate semantics.

Arguments:

  • ctx context.Context: context for the operation.
  • c client.Client: Kubernetes client.
  • scheme *runtime.Scheme: scheme for setting owner references.
  • owner client.Object: the owner object for the Service.
  • desired *corev1.Service: the desired Service specification.

Returns:

  • *corev1.Service: the resulting Service.
  • controllerutil.OperationResult: result of the operation.
  • error: any error encountered.

func FirstPositiveDuration

func FirstPositiveDuration(values ...time.Duration) time.Duration

FirstPositiveDuration returns the first positive duration from the provided list.

Arguments:

  • values ...time.Duration: durations to check in order.

Returns:

  • time.Duration: the first positive value, or 0 if none are positive.

func ListByLabels

func ListByLabels(
	ctx context.Context,
	c client.Client,
	namespace string,
	labels map[string]string,
	list client.ObjectList,
) error

ListByLabels fetches objects in a namespace that match the provided labels.

Arguments:

  • ctx context.Context: context for the list operation.
  • c client.Client: Kubernetes client.
  • namespace string: namespace to list in; empty string lists cluster-wide.
  • labels map[string]string: label selector; empty map matches all labels.
  • list client.ObjectList: the list object to populate with results.

Returns:

  • error: list error or nil on success.

Behavior:

  • Applies namespace filter when namespace is non-empty.
  • Applies label matching when labels is non-empty.

func MergeStringMaps

func MergeStringMaps(maps ...map[string]string) map[string]string

MergeStringMaps returns a copy that contains the union of the provided maps, applying them in order so later maps override earlier keys.

Arguments:

  • maps ...map[string]string: maps to merge in order.

Returns:

  • map[string]string: merged map, or nil if all inputs are empty.

func MergeWithBlocks

func MergeWithBlocks(engramWith, stepWith *runtime.RawExtension) (*runtime.RawExtension, error)

MergeWithBlocks merges two runtime.RawExtension values representing JSON "with" blocks. Values from the stepWith overlay the engramWith while preserving nested structures.

Arguments:

  • engramWith *runtime.RawExtension: base configuration.
  • stepWith *runtime.RawExtension: overlay configuration.

Returns:

  • *runtime.RawExtension: merged configuration.
  • error: JSON parsing/marshaling errors.

func Periodic

func Periodic(
	ctx context.Context,
	interval time.Duration,
	fn func(context.Context) error,
) error

Periodic executes fn every interval until the context is canceled. Returning an error from fn stops the loop early and surfaces the error to the caller.

Arguments:

  • ctx context.Context: context for cancellation.
  • interval time.Duration: how often to execute fn.
  • fn func(context.Context) error: the function to execute periodically.

Returns:

  • error: nil when context is canceled, or the error from fn.

func PositiveDurationOrDefault

func PositiveDurationOrDefault(candidate, fallback time.Duration) time.Duration

PositiveDurationOrDefault returns candidate when it is greater than zero, otherwise it falls back to the provided default value.

Arguments:

  • candidate time.Duration: the preferred duration.
  • fallback time.Duration: the default duration to use if candidate <= 0.

Returns:

  • time.Duration: candidate if positive, otherwise fallback.

func PreserveImmutableServiceFields

func PreserveImmutableServiceFields(current, desired *corev1.Service)

PreserveImmutableServiceFields copies ClusterIP/IPFamilies metadata from the existing Service into the desired Service so patches do not attempt to mutate immutable fields.

Arguments:

  • current *corev1.Service: the existing Service.
  • desired *corev1.Service: the desired Service to update.

func RecordEvent

func RecordEvent(
	recorder events.EventRecorder,
	logger logr.Logger,
	obj client.Object,
	eventType string,
	reason string,
	message string,
)

RecordEvent emits a Kubernetes event for obj when a recorder is configured, or logs the event metadata when the recorder is nil. Messages are trimmed before emission so controllers can pass multi-line errors safely.

Arguments:

  • recorder events.EventRecorder: events API event recorder (may be nil in tests).
  • logger logr.Logger: contextual logger used when recorder is nil.
  • obj client.Object: Kubernetes object receiving the event; required.
  • eventType string: event type (e.g., corev1.EventTypeWarning).
  • reason string: short, CamelCase reason for the event.
  • message string: human-readable description of the event.

Behavior:

  • No-op if obj is nil or message is empty after trimming.
  • Emits via recorder.Eventf when recorder is non-nil.
  • Falls back to logger.Info when recorder is nil.

func Retry

func Retry(
	ctx context.Context,
	cfg RetryConfig,
	fn func(context.Context) error,
	retryable func(error) bool,
) error

Retry invokes fn until it succeeds, the context is canceled, or MaxAttempts is reached. The retryable callback decides whether a returned error should trigger another attempt.

Arguments:

  • ctx context.Context: context for cancellation.
  • cfg RetryConfig: retry configuration.
  • fn func(context.Context) error: the function to retry.
  • retryable func(error) bool: determines if an error is retryable.

Returns:

  • error: nil on success, or the last error after exhausting retries.

func RetryableStatusPatch

func RetryableStatusPatch(ctx context.Context, cl client.Client, obj client.Object, updateFunc UpdateFunc) error

RetryableStatusPatch patches the /status subresource of obj using a merge patch, retrying on optimistic-concurrency conflicts.

The function:

  1. GETs the latest object by key,
  2. deep-copies it as the patch base,
  3. applies updateFunc to the fresh copy,
  4. PATCHes status with client.MergeFrom(original).

Arguments:

  • ctx context.Context: context for the operations.
  • cl client.Client: Kubernetes client.
  • obj client.Object: the object whose status to patch.
  • updateFunc UpdateFunc: function that mutates status fields only.

Returns:

  • error: non-conflict failures or retry budget exhaustion.

Behavior:

  • updateFunc must only mutate status fields, not spec/metadata.
  • Works on fresh copies to avoid mutating caller's in-memory objects.

func RetryableStatusUpdate

func RetryableStatusUpdate(ctx context.Context, cl client.Client, obj client.Object, updateFunc UpdateFunc) error

RetryableStatusUpdate updates an object's status using optimistic concurrency.

Arguments:

  • ctx context.Context: context for the operations.
  • cl client.Client: Kubernetes client.
  • obj client.Object: the object whose status to update.
  • updateFunc UpdateFunc: function that mutates status fields.

Returns:

  • error: non-conflict failures or retry budget exhaustion.

func StoryRunEngramRunnerSubject

func StoryRunEngramRunnerSubject(storyRun, namespace string) rbacv1.Subject

StoryRunEngramRunnerSubject returns the canonical ServiceAccount subject for a StoryRun.

Arguments:

  • storyRun string: the StoryRun name.
  • namespace string: the namespace.

Returns:

  • rbacv1.Subject: the ServiceAccount subject.

Types

type DeleteLogger

type DeleteLogger interface {
	Info(msg string, keysAndValues ...any)
	Error(err error, msg string, keysAndValues ...any)
}

DeleteLogger captures the logging interface required by DeleteIfExists.

type ReferenceStyle

type ReferenceStyle int

ReferenceStyle selects how RBAC resources should attach owner references.

const (
	// ControllerReference sets a controller reference via controllerutil.SetControllerReference.
	ControllerReference ReferenceStyle = iota
	// OwnerReference sets a non-controller owner reference via controllerutil.SetOwnerReference.
	OwnerReference
)

type RetryConfig

type RetryConfig struct {
	// MaxAttempts controls how many times fn is invoked before giving up.
	// Values <= 0 default to a single attempt.
	MaxAttempts int
	// InitialDelay determines how long Retry waits before the second attempt.
	// Values <= 0 default to 250 milliseconds.
	InitialDelay time.Duration
	// Multiplier controls the exponential backoff multiplier applied after each wait.
	// Values <= 0 default to 1 (no backoff).
	Multiplier float64
}

RetryConfig specifies how Retry executes the provided function.

type SecretCopyAuthorization

type SecretCopyAuthorization struct {
	AllowedNames []string
}

SecretCopyAuthorization constrains which Secrets may be copied across namespaces by EnsureSecretCopy.

func AllowSecretCopyNames

func AllowSecretCopyNames(names ...string) SecretCopyAuthorization

AllowSecretCopyNames authorizes cross-namespace copies for the provided Secret names only.

type UpdateFunc

type UpdateFunc func(obj client.Object)

UpdateFunc is a function that mutates an object.

type ValidationOutcome

type ValidationOutcome struct {
	ReadyStatus      metav1.ConditionStatus
	ReadyReason      string
	ReadyMessage     string
	ValidationStatus enums.ValidationStatus
	ValidationErrors []string
	// contains filtered or unexported fields
}

ValidationOutcome encapsulates the Ready condition data plus the enums.ValidationStatus value that callers should persist.

func ComputeValidationOutcome

func ComputeValidationOutcome(p ValidationParams) ValidationOutcome

ComputeValidationOutcome normalizes validation/binding inputs into a single Ready condition + validation status tuple so controllers present consistent messaging. All slices are defensively copied to avoid aliasing caller data.

Arguments:

  • p ValidationParams: the validation parameters.

Returns:

  • ValidationOutcome: computed Ready condition and validation status.

func (ValidationOutcome) AggregatedErrors

func (o ValidationOutcome) AggregatedErrors() []string

AggregatedErrors returns the combined validation+binding error slice, guaranteeing a nil slice when no errors were supplied. Callers can store this in their status structs without additional copying.

type ValidationParams

type ValidationParams struct {
	// ValidationErrors lists spec validation failures (trimmed human-readable text).
	ValidationErrors []string
	// BindingErrors lists runtime/binding failures that should surface alongside
	// validation errors when present.
	BindingErrors []string
	// BindingSummary allows callers to provide an already-compacted summary to
	// avoid rejoining binding errors; when empty, BindingErrors are joined with "; ".
	BindingSummary string

	// ReadyBindings/TotalBindings/PendingBindings describe live binding counts.
	// Pending logic only activates when TotalBindings > 0, ReadyBindings == 0,
	// and PendingBindings > 0 (mirroring existing controller behavior).
	ReadyBindings   int
	TotalBindings   int
	PendingBindings int

	// SuccessReason/SuccessMessage annotate the Ready condition when all checks pass.
	SuccessReason  string
	SuccessMessage string

	// ValidationFailedReason describes the Ready condition reason when spec validation fails.
	ValidationFailedReason string
	// BindingFailedReason is used when runtime/binding errors exist; defaults to
	// ValidationFailedReason when omitted.
	BindingFailedReason string
	// PendingReason labels the Ready condition while bindings negotiate; defaults
	// to ValidationFailedReason when omitted.
	PendingReason string

	// SuccessStatus / ValidationFailedStatus / BindingFailedStatus / PendingStatus
	// let callers override the enums.ValidationStatus assigned for each scenario.
	// When left empty they default to Valid / Invalid / Invalid / Unknown.
	SuccessStatus          enums.ValidationStatus
	ValidationFailedStatus enums.ValidationStatus
	BindingFailedStatus    enums.ValidationStatus
	PendingStatus          enums.ValidationStatus

	// PendingMessageFormatter renders the Ready condition message for the pending
	// state when provided; otherwise we fall back to a generic
	// "awaiting reconciliation (%d pending)" string.
	PendingMessageFormatter func(pending int) string
}

ValidationParams captures the aggregated validation/binding context required to derive a Ready condition snapshot plus the corresponding enums.ValidationStatus value for controllers. Callers supply controller-specific reason/message text so Ready conditions remain informative while the helper enforces consistent state transitions across controllers.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL