Repository navigation
Expand file tree
/
Copy pathconstants.go
More file actions
244 lines (222 loc) · 15.2 KB
/
Copy pathconstants.go
File metadata and controls
244 lines (222 loc) · 15.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
// SPDX-License-Identifier: Apache-2.0
// Package controller contains shared constants for all controllers.
package controller
import (
"context"
"time"
fluxmeta "github.com/fluxcd/pkg/apis/meta"
"sigs.k8s.io/controller-runtime/pkg/event"
configv1alpha3 "github.com/ConfigButler/gitops-reverser/api/v1alpha3"
"github.com/ConfigButler/gitops-reverser/internal/types"
"github.com/ConfigButler/gitops-reverser/internal/watch"
)
// WatchManagerInterface defines the interface for watch manager reconciliation.
// This allows for easier testing by enabling mock implementations.
type WatchManagerInterface interface {
// TriggerRuleChange marks the GitTarget a rule names as needing a new plan pass, and returns.
// The watch-plane owner runs the pass once that target has been quiet for its settle window.
//
// It replaces a ReconcileForRuleChange that did the work inline, on the controller worker
// that observed the rule: a discovery call, a namespace list, a full re-projection, and then a
// replan of every running GitTarget. A rule edit now replans the ONE target the rule names.
TriggerRuleChange(gitDest types.ResourceReference)
// TriggerAllRuleChange marks every declared GitTarget. It is the rule-DELETION path only: the
// object is already gone, so it cannot be read for the target it named and the owner does not
// pretend to narrow the invalidation.
TriggerAllRuleChange()
ResolveWatchRuleResources(ctx context.Context, rule configv1alpha3.WatchRule) (bool, string)
ResolveClusterWatchRuleResources(ctx context.Context, rule configv1alpha3.ClusterWatchRule) (bool, string)
// CollectionOverlapForWatchRule and CollectionOverlapForClusterWatchRule report
// whether a compiled rule is refused because its collections overlap a different collection on
// the same GitTarget; the older rule keeps the collection.
CollectionOverlapForWatchRule(rule configv1alpha3.WatchRule) (bool, string)
CollectionOverlapForClusterWatchRule(rule configv1alpha3.ClusterWatchRule) (bool, string)
StreamSummaryForGitTarget(gitDest types.ResourceReference) watch.StreamSummary
StreamSummaryForWatchRule(rule configv1alpha3.WatchRule) watch.StreamSummary
StreamSummaryForClusterWatchRule(rule configv1alpha3.ClusterWatchRule) watch.StreamSummary
// ClusterResourcesSelectedFor is what the watch planner selects for a ClusterWatchRule item in
// the cluster a GitTarget mirrors from, so the compile checks those types against the grant.
ClusterResourcesSelectedFor(target configv1alpha3.GitTarget) watch.ClusterResourceSelection
// StreamStateEvents is the channel a rule controller wires via source.Channel so a stream
// reaching (or leaving) Streaming re-reconciles the rules that project it, instead of leaving
// them to discover it on RequeueStreamSettleInterval. A stream coming up is the last thing
// that has to happen before a rule can honestly report StreamsRunning=True, and the data plane
// is the only thing that knows when it did.
//
// Every call registers a NEW subscriber: a Go channel has one consumer, and three controllers
// project this state. It may return nil when no data plane is wired.
StreamStateEvents() <-chan event.GenericEvent
}
const (
// ConditionTypeReady indicates whether the resource is ready.
ConditionTypeReady = "Ready"
// ConditionTypeResourcesResolved indicates whether rule resources resolved to concrete GVRs.
ConditionTypeResourcesResolved = "ResourcesResolved"
// ConditionTypeReconciling is the kstatus progress condition. It is abnormal-true.
ConditionTypeReconciling = "Reconciling"
// ConditionTypeStalled is the kstatus blocked condition. It is abnormal-true.
ConditionTypeStalled = "Stalled"
// ConditionTypeStreamsRunning indicates whether watched type streams are routing live events.
ConditionTypeStreamsRunning = "StreamsRunning"
// ConditionTypeGitPathAccepted indicates whether the GitTarget path is safe to materialize.
ConditionTypeGitPathAccepted = "GitPathAccepted"
// ConditionTypeRenderMatchesLive indicates whether every current render scope agrees with live.
ConditionTypeRenderMatchesLive = "RenderMatchesLive"
// ConditionTypeGitTargetReady indicates whether the referenced GitTarget is ready for writes.
ConditionTypeGitTargetReady = "GitTargetReady"
// ConditionTypeSourceNamespaceAuthorized reports whether a rule's EFFECTIVE source namespace
// is authorized for the observed generation. It is positive and state-style, and it is set for
// every rule, its own namespace included, so the effective authorization is always visible and
// automation has ONE condition to inspect.
//
// It is deliberately distinct from GitTargetReady, which stays the health of the referenced
// GitTarget and must never be reused for source authorization. Its three values are not
// interchangeable: False is a refusal (terminal, Stalled=True), while Unknown means the answer is
// still being established (the rule is blocked by validation), which must not be rendered as a
// permanent failure.
ConditionTypeSourceNamespaceAuthorized = "SourceNamespaceAuthorized"
// ConditionTypePushed indicates whether a CommitRequest's commit reached the
// remote repository.
ConditionTypePushed = "Pushed"
// ConditionTypeApplied reports, for a CommitRequest with catchUp: AfterPush, whether
// its GitTarget's applier applied a commit that holds the request's: Unknown while it applies or
// retries, True once applied, False when there was nothing to apply. It never affects Ready.
ConditionTypeApplied = "Applied"
// KubeProviderConditionValidated reports whether a KubeProvider's credential is safe and
// resolvable: an inCluster provider is Validated while the installation lists it in
// --in-cluster-kube-providers; a secretRef provider once its kubeconfig Secret is present,
// keyed, and passes the exec/TLS/file-reference safety policy. It is asserted WITHOUT a network
// dial — runtime reachability is the GitTarget's SourceClusterReachable.
KubeProviderConditionValidated = "Validated"
// KubeProviderConditionAuditFactsReceived reports whether an attribution fact has ever been
// published on this provider's audit route (spec.attribution.auditRoute, defaulting to
// <namespace>.<name>). It is Unknown from creation until the first fact, with the reason naming
// which silence it is (see the three below), and True (ReasonFactsReceived) from then on. It
// NEVER regresses: the persisted status is the latch, so a restart — or the memory transport,
// whose in-process state is lost with the process — keeps it True. Later silence is a quiet cluster, not a fault, which is why there is
// no False state, no grace window and no timer.
//
// It is deliberately NOT part of Ready: a provider reading a route nobody posts under mirrors
// perfectly and loses only the commit AUTHOR, so reporting it through Ready would tell every
// kstatus reader the object is broken. It is absent entirely when the operator runs with
// --author-attribution=false, where no fact was ever expected.
KubeProviderConditionAuditFactsReceived = "AuditFactsReceived"
// The three AuditFactsReceived=Unknown reasons below separate the silences by SCOPE, because
// they send the reader to three different places. None of them repeats "AuditFacts" (the
// condition type says it) or "yet" (the Unknown status says it). They are evaluated in the
// order listed: a failing transport makes every route look silent, so no route may be judged
// while it holds; and with nothing delivered at all, no route can be the one at fault.
// ReasonTransportUnavailable is the AuditFactsReceived=Unknown reason when the last append to
// the fact transport failed. Nothing can be concluded about any route's configuration while
// this holds. The fix is the operator's transport, not the reader's audit webhook.
ReasonTransportUnavailable = "TransportUnavailable"
// ReasonNoAuditDelivery is the AuditFactsReceived=Unknown reason when no audit request has ever
// reached this operator, on any route. Nothing is posting to it, so the fix is the API server's
// audit webhook configuration and its connectivity, never this provider's route.
ReasonNoAuditDelivery = "NoAuditDelivery"
// ReasonRouteUnused is the AuditFactsReceived=Unknown reason when audit requests ARE arriving
// and nothing has ever landed on this provider's route. That is the one case where the route
// itself is the thing to look at.
//
// It deliberately does not claim the facts went to some OTHER route, which would be the sharper
// message: requests can also arrive and produce no fact anywhere, when the audit policy's level
// or verbs leave nothing attributable. This reason stays true for both.
ReasonRouteUnused = "RouteUnused"
// ReasonFactsReceived is the AuditFactsReceived=True reason: a fact has arrived on the route,
// and that answer is latched.
ReasonFactsReceived = "Received"
// ReasonInCluster is the Validated=True reason for an inCluster provider the installation
// allows. A secretRef provider that validates reports the shared ReasonSucceeded instead.
ReasonInCluster = "InCluster"
// ReasonKubeConfigInvalid is the Validated=False reason for a malformed or unsafe kubeconfig
// whose specific cause is carried in the message.
ReasonKubeConfigInvalid = "KubeConfigInvalid"
// MsgSnapshotCompleted is returned as the condition message when the initial
// cluster snapshot has been successfully committed to Git.
MsgSnapshotCompleted = "Initial snapshot reconciliation completed"
// RequeueSteadyInterval is the unified control-plane periodic reconcile fallback.
// The control plane no longer watches Secrets (docs/rbac.md),
// so out-of-band credential and age-key changes are picked up on this steady cadence
// instead of via a Secret informer. It replaces the former split of a 2-minute
// transient-retry, a 5-minute auth/secret, and a 10-minute revalidation interval with
// a single 5-minute fallback for the GitProvider, GitTarget, WatchRule, and
// ClusterWatchRule reconcilers. The fast stream-settle loop below is separate.
RequeueSteadyInterval = 5 * time.Minute
// RemotePublicationInterval is the FLOOR on how often one GitTarget writes status.remote: at
// most one such write per target per interval, whatever the branch's commit rate.
//
// It is a floor and not a deadline. What a target publishes is what it holds when it
// reconciles, so the lag is its own cadence; this only stops a target reconciling in a tight
// loop from writing the stanza every time. The one place it also acts as a delay is a
// reconcile that has just ASKED the remote where the branch is, which comes back after this
// long to publish the answer rather than leaving it undelivered for a tick.
//
// One minute: short enough that a target being asked questions answers promptly, long enough
// that ten folders sharing a busy branch cost ten status writes a minute, not ten per commit.
RemotePublicationInterval = 1 * time.Minute
// DefaultGitRefreshInterval is how often an IDLE branch's remote state is re-proved. A target
// that is publishing renews its observation on every push and never waits for this.
DefaultGitRefreshInterval = 10 * time.Minute
// DefaultCommitRequestTTL is how long a CommitRequest is kept once it finishes. Each save leaves
// one object behind, so without an expiry they accumulate in etcd for as long as the namespace
// lives. Two days leaves a weekend's worth of saves to inspect.
DefaultCommitRequestTTL = 48 * time.Hour
// RequeueStreamSettleInterval is the requeue interval while a Ready GitTarget still
// has streams pending replay completion. Stream status is computed during reconcile, so
// this keeps status.streams fresh while watches converge.
RequeueStreamSettleInterval = 10 * time.Second
// RequeueCollectionOverlapInterval is how often a rule refused for a CollectionOverlap
// re-checks the conflict. It is a fallback: the stream-state event of the sibling rule that
// cleared it usually arrives first, but that event is best-effort.
RequeueCollectionOverlapInterval = 30 * time.Second
// RequeueReceiverTokenInterval is how often a GitReceiver whose token Secret or "token" key is
// missing looks again. Secrets are not watched, so nothing else tells it the token arrived, and
// until it does no delivery can reach the receiver: Flux or Argo CD applying a GitReceiver and
// its Secret in one pass, in either order, must not leave the path unpublished for a steady
// interval.
RequeueReceiverTokenInterval = 30 * time.Second
// RequeueWriteLostInterval is how soon a reconcile whose status write lost the optimistic-lock
// race comes back. It is short because there is nothing to wait FOR: the write was rejected
// against a resourceVersion this reconcile had already read, so the only thing that has to
// happen before the retry can succeed is the informer cache catching up with a write that is
// already durable — milliseconds, not a settle window.
//
// It used to borrow RequeueStreamSettleInterval, which put the recovery ten seconds out and
// made every lost write a ten-second window of published-but-stale status. Two unrelated
// cadences shared one constant; only the coincidence that both were "soon" hid it.
RequeueWriteLostInterval = 100 * time.Millisecond
// RetryInitialDuration is the initial duration for exponential backoff retry.
RetryInitialDuration = 100 * time.Millisecond
// RetryBackoffFactor is the multiplicative factor for exponential backoff.
RetryBackoffFactor = 2.0
// RetryBackoffJitter is the jitter factor for retry backoff.
RetryBackoffJitter = 0.1
// RetryMaxSteps is the maximum number of retry attempts.
RetryMaxSteps = 5
// The generic condition reasons below are ALIASES of github.com/fluxcd/pkg/apis/meta, a module
// this project already depends on. Sharing the vocabulary is the point: one alerting rule
// written against reason=Succeeded works across every kind here AND across every Flux kind in
// the same cluster, which is not true of a per-project spelling. Domain
// reasons (UnsupportedContent, WriteBoundaryRefused, SourceMismatch, ...) stay ours:
// those carry information a generic reason cannot, and declaring them is exactly what the
// upstream vocabulary asks projects to do.
// ReasonSucceeded is the reason on a healthy, fully reconciled object. It replaces the former
// "OK"/"Ready" spellings, which restated the condition type instead of answering "why".
ReasonSucceeded = fluxmeta.SucceededReason
// ReasonProgressing indicates that a stream or control-plane gate is still converging.
ReasonProgressing = fluxmeta.ProgressingReason
// ReasonFailed indicates that reconciliation is blocked until a human fixes the object or
// dependency. fluxmeta has no Stalled reason, and a reason restating the Stalled type would
// answer nothing, so this is the upstream Failed.
ReasonFailed = fluxmeta.FailedReason
// ReasonSecretNotFound indicates that the referenced secret was not found.
ReasonSecretNotFound = "SecretNotFound"
// ReasonSecretMalformed indicates that the referenced secret is invalid.
ReasonSecretMalformed = "SecretMalformed"
// ReasonConnectionFailed indicates that the connection to the provider failed.
ReasonConnectionFailed = "ConnectionFailed"
// ReasonCommitConfigInvalid indicates the commit configuration is invalid.
ReasonCommitConfigInvalid = "CommitConfigInvalid"
// ReasonEncryptionConfigInvalid indicates encryption configuration is invalid.
ReasonEncryptionConfigInvalid = "EncryptionConfigInvalid"
)