inplaceupdate

package
v0.0.3 Latest Latest
Warning

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

Go to latest
Published: May 20, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Index

Constants

View Source
const (
	PodAnnotationInPlaceUpdateStateKey = "agentbox.navix.sh/inplace-update-state"

	InplaceUpdatePhaseStarting  = "starting"
	InplaceUpdatePhaseStopping  = "stopping"
	InplaceUpdatePhaseCompleted = "completed"
)

Variables

View Source
var (
	ErrNoContainers          = errors.New("pod has no containers")
	ErrContainerNotFound     = errors.New("container not found in pod")
	ErrUnexpectedPodPhase    = errors.New("pod phase does not match expected value")
	ErrNoIdlePodsAvailable   = errors.New("no idle sandboxes available for creating")
	ErrTargetImageIsRequired = errors.New("target image is required")
)

Functions

func GetPodPhaseDuration

func GetPodPhaseDuration(pod *corev1.Pod, phase string, now time.Time) (time.Duration, bool, error)

GetPodPhaseDuration returns how long the pod has been in the requested sandbox phase. It uses GetPodPhaseSince and subtracts it from now. When now.IsZero(), time.Now().UTC() is used. The returned bool is false when the pod is not currently in that phase.

func GetPodPhaseSince

func GetPodPhaseSince(pod *corev1.Pod, phase string) (time.Time, bool, error)

GetPodPhaseSince returns the timestamp when the pod entered the requested sandbox phase.

For Starting/Stopping, the timestamp comes from InplaceUpdateState.UpdateTimestamp recorded when the transition was triggered. For Running/Idle, it comes from the completed InplaceUpdateState timestamp refreshed by MarkUpdateCompleted. When the pod has no matching in-place update state (for example, a freshly created idle pod), the method falls back to metadata.creationTimestamp.

The returned bool is false when the pod is not currently in the requested phase. When phase is empty, the pod's current sandbox phase label is used.

func GetSandboxPhase

func GetSandboxPhase(pod *corev1.Pod) string

func HasUnexpectedRestart

func HasUnexpectedRestart(pod *corev1.Pod) bool

HasUnexpectedRestart returns true if any container in the pod has a different containerID than what was recorded in StableContainerStatuses. A containerID change indicates the container was killed and restarted by kubelet (e.g., OOM-kill, crash) while the pod was in Running phase.

Design note: we intentionally do NOT use restartCount as a signal here. kubelet reports containerID, restartCount, and Ready in separate status patches, which means the controller-runtime informer cache can reflect an intermediate state where imageID/Ready are already updated but restartCount has not yet incremented. Using only containerID avoids this race: containerID is assigned atomically when a new container is created, so a change unambiguously indicates a container replacement event. If stable.ContainerID is empty (cache lag prevented snapshotting), we skip the check to avoid a false positive.

func IsInplaceUpdateCompleted

func IsInplaceUpdateCompleted(ctx context.Context, sandboxPool *agentsv1alpha1.SandboxPool, pod *corev1.Pod, resolver imageresolver.DigestResolver) bool

func MarkUpdateCompleted

func MarkUpdateCompleted(ctx context.Context, c client.Client, sandboxPool *agentsv1alpha1.SandboxPool, pod *corev1.Pod, resolver imageresolver.DigestResolver) (*corev1.Pod, error)

MarkUpdateCompleted marks the in-place update as completed for the given pod. It returns the updated pod object as seen by the API server after the update, or nil if no update was performed (e.g., already completed or phase mismatch). Callers should replace their in-memory pod with the returned object to avoid operating on stale informer-cache data within the same reconcile loop.

func TriggerUpdateWithOptions

func TriggerUpdateWithOptions(ctx context.Context, c client.Client, pod *corev1.Pod, opts UpdateOptions) (*corev1.Pod, error)

Types

type InplaceUpdateContainerStatus

type InplaceUpdateContainerStatus struct {
	ImageID string `json:"imageID,omitempty"`
	// ContainerID is the container ID at the moment the in-place update was
	// triggered. It is used as a secondary completion signal: even when the
	// target image has the same digest as the previous one (e.g. rolling back
	// after a failed pull of a non-existent image), a changed containerID
	// proves that the old container was replaced and the new one is running.
	ContainerID string `json:"containerID,omitempty"`
}

type InplaceUpdateState

type InplaceUpdateState struct {
	Phase string `json:"phase"`

	TargetImage string `json:"targetImage,omitempty"`

	TargetImages map[string]string `json:"targetImages,omitempty"`

	TargetPodPhase string `json:"targetPodPhase,omitempty"`

	UpdateTimestamp metav1.Time `json:"updateTimestamp,omitempty"`

	LastContainerStatuses map[string]InplaceUpdateContainerStatus `json:"lastContainerStatuses,omitempty"`

	// StableContainerStatuses is populated when the update phase transitions to
	// Completed and TargetPodPhase==Running. It records containerID+restartCount
	// so the controller can detect unexpected restarts while phase=running.
	StableContainerStatuses map[string]StableContainerStatus `json:"stableContainerStatuses,omitempty"`
}

InplaceUpdateState is serialized into Pod annotation to track an in-flight update.

func GetInplaceUpdateState

func GetInplaceUpdateState(pod *corev1.Pod) (*InplaceUpdateState, error)

func GetPodInPlaceUpdateState

func GetPodInPlaceUpdateState(pod *corev1.Pod) (*InplaceUpdateState, error)

type StableContainerStatus

type StableContainerStatus struct {
	ContainerID  string `json:"containerID,omitempty"`
	RestartCount int32  `json:"restartCount"`
}

StableContainerStatus records the container state after an in-place update completes. Used by the controller to detect unexpected restarts (e.g., OOM).

type UpdateOptions

type UpdateOptions struct {
	ContainerImages   map[string]string
	Labels            map[string]string
	Annotations       map[string]string
	RemoveLabels      []string
	RemoveAnnotations []string
	TargetPodPhase    string

	// UpdatePodPhase is the intermediate phase label set on the Pod while the
	// in-place image update is in progress (before the new image is pulled).
	// Use PodPhaseStarting for Idle→Running transitions and PodPhaseStopping
	// for Running→Idle transitions. Defaults to PodPhaseStarting when empty.
	UpdatePodPhase string

	ExpectedCurrentSandboxPhase string

	// DisableRetry, when true, causes TriggerUpdateWithOptions to return
	// immediately on a conflict error instead of retrying. This is appropriate
	// for optimistic operations (e.g. unexpected-restart detection) where
	// retrying on stale data could misfire: the caller should skip the pod and
	// let the next Reconcile re-observe the true state before acting.
	DisableRetry bool
}

Jump to

Keyboard shortcuts

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