flux

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Aug 4, 2026 License: MPL-2.0 Imports: 21 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func KustomizationDestroyEligible

func KustomizationDestroyEligible(k blueprintv1alpha1.Kustomization) bool

KustomizationDestroyEligible mirrors the gate inside DeleteBlueprint so the destroy-plan set matches the destroy-execute set. DestroyOnly kustomizations are skipped (they're hooks applied during destroy, not user-visible resources to preview), and any pinned destroy=false are skipped. The explicit nil check on Destroy mirrors componentDestroyEnabled on the terraform side: ToBool happens to handle a nil receiver today, but the guard reads more clearly at the call site and survives future refactors of ToBool without breakage.

Types

type Action

type Action int

Action enumerates the kinds of changes a kustomization plan can produce for a single Kubernetes resource. ActionUnknown is reserved for inputs that don't correspond to any operator-visible change (flux "unchanged"/"skipped" or unrecognised verbs) and is dropped from rendered resource lists. Replacement is intentionally absent: flux's SSA layer models replacements as a delete + create pair rather than a single banner verb, so no input can map to it.

const (
	ActionUnknown Action = iota
	ActionCreate
	ActionUpdate
	ActionDelete
)

type BaseNotifier

type BaseNotifier struct {
	// contains filtered or unexported fields
}

BaseNotifier implements Notifier by PATCHing the blueprint's flux source resources in the configured gitops namespace. Each call constructs its own ctx-bounded fan-out; instances should not be shared across goroutines.

func (*BaseNotifier) Notify

func (n *BaseNotifier) Notify(ctx context.Context, blueprint *blueprintv1alpha1.Blueprint) error

Notify annotates every flux source declared by the blueprint with the current timestamp under reconcile.fluxcd.io/requestedAt, causing source-controller to re-fetch them immediately instead of waiting for the next scheduled interval. The blueprint.Repository entry is annotated under blueprint.Metadata.Name; each blueprint.Sources entry under its own Name. Local template sources (no URL) are skipped. OCI URLs (oci://) route to OCIRepository; every other protocol to GitRepository. Per-source PATCH errors are logged and swallowed so one unreachable source does not abort the rest. Returns nil for every cluster-state condition; returns an error only for nil blueprint.

func (*BaseNotifier) ReconcileHelmReleases

func (n *BaseNotifier) ReconcileHelmReleases(ctx context.Context, refs []HelmReleaseRef, force bool) error

ReconcileHelmReleases annotates each referenced HelmRelease with reconcile.fluxcd.io/requestedAt (and, when force is set, reconcile.fluxcd.io/forceAt) so helm-controller reconciles it immediately. force is how a HelmRelease that failed to install/upgrade and stalled — e.g. because a secret it needs was not yet present — is made to retry now that the secret exists; a plain reconcile of the owning Kustomization does not, since the release spec is unchanged. Best-effort like Notify: per-ref PATCH errors are logged and swallowed, nil is returned for every cluster-state condition, and an empty refs list is a no-op.

func (*BaseNotifier) ReconcileKustomizations

func (n *BaseNotifier) ReconcileKustomizations(ctx context.Context, names []string) error

ReconcileKustomizations annotates each named Kustomization in the gitops namespace with the current timestamp under reconcile.fluxcd.io/requestedAt, causing kustomize-controller to re-reconcile it immediately — re-evaluating its dependency readiness and re-applying — instead of waiting for its scheduled interval. Unlike Notify, which pokes sources to re-fetch git (and only progresses dependents when the artifact revision changes), this advances already-applied Kustomizations, so a dependency chain unblocked mid-flight (e.g. by a just-placed secret) progresses in seconds rather than one interval per hop. Best-effort like Notify: per-name PATCH errors are logged and swallowed, a nil is returned for every cluster-state condition, and an empty names list is a no-op.

type FluxStack

type FluxStack struct {
	// contains filtered or unexported fields
}

FluxStack manages Flux kustomization operations by invoking the flux CLI. It resolves the target namespace from configuration, checks cluster state, and selects between a standard diff (kustomization exists) and a scratch diff (kustomization not yet deployed) for each requested component.

func (*FluxStack) Plan

func (s *FluxStack) Plan(blueprint *blueprintv1alpha1.Blueprint, componentID string) error

Plan runs flux diff for a single kustomization identified by componentID. Requires the flux CLI to be installed. Returns an error if the flux CLI is not found, the kustomization name is not in the blueprint, or the diff fails. If the kustomization does not yet exist in the cluster, the plan is generated from the blueprint definition via --kustomization-file.

func (*FluxStack) PlanAll

func (s *FluxStack) PlanAll(blueprint *blueprintv1alpha1.Blueprint) error

PlanAll runs flux diff for every non-destroyOnly kustomization in the blueprint. The flux CLI is only required when there are kustomizations to plan; blueprints with no non-destroyOnly kustomizations succeed without it.

func (*FluxStack) PlanAllJSON

func (s *FluxStack) PlanAllJSON(blueprint *blueprintv1alpha1.Blueprint) error

PlanAllJSON runs kustomize build for every non-destroyOnly kustomization in the blueprint, converts the rendered YAML manifests to JSON, and writes a JSON array of {"kustomization": name, "resources": [...]} objects to stdout. Requires the kustomize CLI.

func (*FluxStack) PlanComponentSummary

func (s *FluxStack) PlanComponentSummary(blueprint *blueprintv1alpha1.Blueprint, name string) KustomizePlan

PlanComponentSummary plans a single kustomization by name and returns its structured result. Only the requested kustomization is planned. If the kustomization is not found, a result with a non-nil Err is returned rather than an error, consistent with PlanSummary.

func (*FluxStack) PlanDestroyComponentSummary

func (s *FluxStack) PlanDestroyComponentSummary(blueprint *blueprintv1alpha1.Blueprint, name string) KustomizePlan

PlanDestroyComponentSummary returns the destroy preview for a single named kustomization. A pinned destroy=false or DestroyOnly kustomization returns Err — DeleteBlueprint would skip it, so producing a plan would mislead.

func (*FluxStack) PlanDestroySummary

func (s *FluxStack) PlanDestroySummary(blueprint *blueprintv1alpha1.Blueprint) ([]KustomizePlan, error)

PlanDestroySummary returns the per-kustomization preview of what `windsor destroy` will tear down at the flux layer. Unlike PlanSummary, this is sourced from the cluster's live state — specifically the .status.inventory.entries on each Kustomization, which is exactly what flux uses to drive prune behavior — rather than from `kustomize build` of the blueprint. Showing blueprint-derived resources for a destroy preview would lie when the cluster has drifted, so we read truth from the cluster.

The kustomization set mirrors DeleteBlueprint's eligibility gate: regular kustomizations only (DestroyOnly hooks are applied during destroy and are not user-facing here), and any pinned with destroy=false are filtered out. A kustomization that is absent from the cluster yields IsNew=true so the renderer shows "(not deployed)". A missing kubeconfig is treated the same way: kustomizations are cluster-scoped resources, so "no cluster reachable" implies "nothing deployed" by definition. This keeps `windsor destroy` idempotent — after the cluster's terraform component tears down the kubeconfig, a subsequent destroy can still plan and run terraform-only teardown rather than failing to query a cluster that no longer exists. Other cluster errors still propagate, since they can indicate transient connectivity problems where falling back would produce a misleading plan.

func (*FluxStack) PlanJSON

func (s *FluxStack) PlanJSON(blueprint *blueprintv1alpha1.Blueprint, componentID string) error

PlanJSON runs kustomize build for a single kustomization identified by componentID, converts the rendered YAML manifests to JSON, and writes a JSON array of {"kustomization": name, "resources": [...]} objects to stdout. Unlike Plan, this always uses kustomize build regardless of cluster state, producing the full desired state as JSON for machine consumption. Requires the kustomize CLI.

func (*FluxStack) PlanSummary

func (s *FluxStack) PlanSummary(blueprint *blueprintv1alpha1.Blueprint) ([]KustomizePlan, []string)

PlanSummary runs a best-effort plan for every non-destroyOnly kustomization in the blueprint, returning per-component counts without printing raw output. The second return value carries upgrade hints to display to the user when a required CLI tool is absent. Missing tools degrade gracefully: each component row is marked Degraded=true rather than returning an error entry. Cluster connectivity failures are also handled gracefully: when KustomizationExists returns an error the kustomization is treated as new and planned via kustomize build instead.

type HelmReleaseRef

type HelmReleaseRef struct {
	Namespace string
	Name      string
}

HelmReleaseRef identifies a HelmRelease to reconcile by its namespace and name.

type KustomizePlan

type KustomizePlan struct {
	Name      string
	Added     int
	Removed   int
	IsNew     bool
	Degraded  bool
	Resources []ResourceChange
	Err       error
}

KustomizePlan holds the plan result for a single Flux kustomization. For kustomizations that already exist in the cluster, Added and Removed count diff lines from "flux diff". For new kustomizations (no cluster or not yet deployed), Added counts rendered resources from "kustomize build" and IsNew is true. Resources is the per-resource change list extracted from flux diff (existing kustomizations) or kustomize build (new kustomizations); it is empty when Degraded is true or when the diff produced no parseable resource banners. Degraded is true when the required CLI tool was absent and no counts could be produced. Err is non-nil when the component could not be planned.

type MockNotifier

type MockNotifier struct {
	NotifyFunc                  func(ctx context.Context, blueprint *blueprintv1alpha1.Blueprint) error
	ReconcileKustomizationsFunc func(ctx context.Context, names []string) error
	ReconcileHelmReleasesFunc   func(ctx context.Context, refs []HelmReleaseRef, force bool) error
}

MockNotifier is a mock implementation of the Notifier interface for testing. Tests set NotifyFunc to control behavior; the default implementation returns nil to keep callers' "best-effort" semantics unchanged when no override is set.

func NewMockNotifier

func NewMockNotifier() *MockNotifier

NewMockNotifier returns a MockNotifier with no overrides configured.

func (*MockNotifier) Notify

func (m *MockNotifier) Notify(ctx context.Context, blueprint *blueprintv1alpha1.Blueprint) error

Notify implements the Notifier interface. Delegates to NotifyFunc when set and otherwise returns nil to match the Notifier's best-effort contract.

func (*MockNotifier) ReconcileHelmReleases

func (m *MockNotifier) ReconcileHelmReleases(ctx context.Context, refs []HelmReleaseRef, force bool) error

ReconcileHelmReleases implements the Notifier interface. Delegates to ReconcileHelmReleasesFunc when set and otherwise returns nil to match the Notifier's best-effort contract.

func (*MockNotifier) ReconcileKustomizations

func (m *MockNotifier) ReconcileKustomizations(ctx context.Context, names []string) error

ReconcileKustomizations implements the Notifier interface. Delegates to ReconcileKustomizationsFunc when set and otherwise returns nil to match the Notifier's best-effort contract.

type MockStack

type MockStack struct {
	PlanFunc                        func(blueprint *blueprintv1alpha1.Blueprint, componentID string) error
	PlanAllFunc                     func(blueprint *blueprintv1alpha1.Blueprint) error
	PlanJSONFunc                    func(blueprint *blueprintv1alpha1.Blueprint, componentID string) error
	PlanAllJSONFunc                 func(blueprint *blueprintv1alpha1.Blueprint) error
	PlanSummaryFunc                 func(blueprint *blueprintv1alpha1.Blueprint) ([]KustomizePlan, []string)
	PlanComponentSummaryFunc        func(blueprint *blueprintv1alpha1.Blueprint, name string) KustomizePlan
	PlanDestroySummaryFunc          func(blueprint *blueprintv1alpha1.Blueprint) ([]KustomizePlan, error)
	PlanDestroyComponentSummaryFunc func(blueprint *blueprintv1alpha1.Blueprint, name string) KustomizePlan
}

MockStack is a mock implementation of the Stack interface for testing.

func NewMockStack

func NewMockStack() *MockStack

NewMockStack creates a new mock stack.

func (*MockStack) Plan

func (m *MockStack) Plan(blueprint *blueprintv1alpha1.Blueprint, componentID string) error

Plan is a mock implementation of the Plan method.

func (*MockStack) PlanAll

func (m *MockStack) PlanAll(blueprint *blueprintv1alpha1.Blueprint) error

PlanAll is a mock implementation of the PlanAll method.

func (*MockStack) PlanAllJSON

func (m *MockStack) PlanAllJSON(blueprint *blueprintv1alpha1.Blueprint) error

PlanAllJSON is a mock implementation of the PlanAllJSON method.

func (*MockStack) PlanComponentSummary

func (m *MockStack) PlanComponentSummary(blueprint *blueprintv1alpha1.Blueprint, name string) KustomizePlan

PlanComponentSummary is a mock implementation of the PlanComponentSummary method.

func (*MockStack) PlanDestroyComponentSummary

func (m *MockStack) PlanDestroyComponentSummary(blueprint *blueprintv1alpha1.Blueprint, name string) KustomizePlan

PlanDestroyComponentSummary is a mock implementation of the PlanDestroyComponentSummary method.

func (*MockStack) PlanDestroySummary

func (m *MockStack) PlanDestroySummary(blueprint *blueprintv1alpha1.Blueprint) ([]KustomizePlan, error)

PlanDestroySummary is a mock implementation of the PlanDestroySummary method.

func (*MockStack) PlanJSON

func (m *MockStack) PlanJSON(blueprint *blueprintv1alpha1.Blueprint, componentID string) error

PlanJSON is a mock implementation of the PlanJSON method.

func (*MockStack) PlanSummary

func (m *MockStack) PlanSummary(blueprint *blueprintv1alpha1.Blueprint) ([]KustomizePlan, []string)

PlanSummary is a mock implementation of the PlanSummary method.

type Notifier

type Notifier interface {
	Notify(ctx context.Context, blueprint *blueprintv1alpha1.Blueprint) error
	ReconcileKustomizations(ctx context.Context, names []string) error
	ReconcileHelmReleases(ctx context.Context, refs []HelmReleaseRef, force bool) error
}

Notifier requests an immediate flux reconcile for the blueprint's sources. Implementations are best-effort: Notify returns nil whenever the blueprint has no remote sources, the cluster is unreachable, or individual PATCH calls fail. Hard errors are only returned for programming mistakes (nil blueprint), never for cluster state.

func NewNotifier

func NewNotifier(rt *runtime.Runtime, kubeClient client.KubernetesClient, opts ...*BaseNotifier) Notifier

NewNotifier creates a BaseNotifier. Panics if runtime or kubeClient are nil. Accepts an optional override struct for injecting test shims and a log writer; matches the opts-pattern used by NewStack.

type NotifierShims

type NotifierShims struct {
	Now func() time.Time
}

NotifierShims provides mockable wrappers around I/O the Notifier performs outside of its KubernetesClient. Only the clock is injectable here — the patch call goes through KubernetesClient which already has its own mock.

func NewNotifierShims

func NewNotifierShims() *NotifierShims

NewNotifierShims builds NotifierShims wired to the real clock.

type ResourceChange

type ResourceChange struct {
	Address string
	Action  Action
}

ResourceChange identifies one Kubernetes resource changed by a kustomization plan along with its action. Address follows flux's own banner convention, "<Kind>/<namespace>/<name>" for namespaced resources and "<Kind>/<name>" for cluster-scoped ones.

type Shims

type Shims struct {
	LookPath  func(file string) (string, error)
	MkdirAll  func(path string, perm os.FileMode) error
	RemoveAll func(path string) error
	ReadFile  func(name string) ([]byte, error)
	WriteFile func(name string, data []byte, perm os.FileMode) error
}

Shims provides mockable wrappers around system and runtime functions

func NewShims

func NewShims() *Shims

NewShims creates a new Shims instance with default implementations

type Stack

type Stack interface {
	Plan(blueprint *blueprintv1alpha1.Blueprint, componentID string) error
	PlanAll(blueprint *blueprintv1alpha1.Blueprint) error
	PlanJSON(blueprint *blueprintv1alpha1.Blueprint, componentID string) error
	PlanAllJSON(blueprint *blueprintv1alpha1.Blueprint) error
	PlanSummary(blueprint *blueprintv1alpha1.Blueprint) ([]KustomizePlan, []string)
	PlanComponentSummary(blueprint *blueprintv1alpha1.Blueprint, name string) KustomizePlan
	PlanDestroySummary(blueprint *blueprintv1alpha1.Blueprint) ([]KustomizePlan, error)
	PlanDestroyComponentSummary(blueprint *blueprintv1alpha1.Blueprint, name string) KustomizePlan
}

Stack defines the interface for Flux kustomization operations.

func NewStack

func NewStack(rt *runtime.Runtime, kubernetesManager kubernetes.KubernetesManager, opts ...*FluxStack) Stack

NewStack creates a new FluxStack. Panics if runtime or kubernetesManager are nil.

Jump to

Keyboard shortcuts

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