Skip to content

Commit e65c427

Browse files
committed
Reflow text to 80 chars per line.
Signed-off-by: Travis Mattera <[email protected]>
1 parent acef883 commit e65c427

File tree

1 file changed

+129
-129
lines changed
  • rfcs/0006-alternative-suspend-control

1 file changed

+129
-129
lines changed

rfcs/0006-alternative-suspend-control/README.md

+129-129
Original file line numberDiff line numberDiff line change
@@ -9,227 +9,227 @@
99

1010
## Summary
1111

12-
This RFC proposes an alternative method to indicate the suspended state of suspendable resources to flux controllers through object metadata. It presents an annotation key that can be used to suspend a resource from reconciliation as an alternative to the `.spec.suspend` field. It does not address the deprecation of the the `.spec.suspend` field from the resource apis. This annotation can optionally act as a vehicle for communicating contextual information about the suspended resource to users.
12+
This RFC proposes an alternative method to indicate the suspended state of
13+
suspendable resources to flux controllers through object metadata. It presents
14+
an annotation key that can be used to suspend a resource from reconciliation as
15+
an alternative to the `.spec.suspend` field. It does not address the
16+
deprecation of the the `.spec.suspend` field from the resource apis. This
17+
annotation can optionally act as a vehicle for communicating contextual
18+
information about the suspended resource to users.
1319

1420

1521
## Motivation
1622

17-
The current implementation of suspending a resource from reconciliation uses the `.spec.suspend` field. A change to this field results in a generation number increase which can be confusing when diffing.
23+
The current implementation of suspending a resource from reconciliation uses
24+
the `.spec.suspend` field. A change to this field results in a generation
25+
number increase which can be confusing when diffing.
1826

19-
Teams may wish to communicate information about the suspended resource, such as the reason for the suspension, in the object itself.
27+
Teams may wish to communicate information about the suspended resource, such as
28+
the reason for the suspension, in the object itself.
2029

2130
### Goals
2231

23-
The flux reconciliation loop will support recognizing a resource's suspend status based on either the `.spec.suspend` field or a specific metadata annotation key. The flux cli will similarly recognize this state with `get` commands and but will only manipulate the annotation key under `suspend` and `resume` commands. The flux cli will support optionally setting the suspend metadata annotation value with a user supplied string for a contextual message.
32+
The flux reconciliation loop will support recognizing a resource's suspend
33+
status based on either the `.spec.suspend` field or a specific metadata
34+
annotation key. The flux cli will similarly recognize this state with `get`
35+
commands and but will only manipulate the annotation key under `suspend` and
36+
`resume` commands. The flux cli will support optionally setting the suspend
37+
metadata annotation value with a user supplied string for a contextual message.
2438

2539
### Non-Goals
2640

27-
The deprecation plan for the `.spec.suspend` field is out of scope for this RFC.
41+
The deprecation plan for the `.spec.suspend` field is out of scope for this
42+
RFC.
2843

2944

3045
## Proposal
3146

32-
Register a flux resource metadata key `reconcile.fluxcd.io/suspended` with a suspend semantic to be interpreted by controllers and manipulated by the cli. The presence of the annotation key is an alternative to the `.spec.suspend: true` api field setting when considering if a resource is suspended or not. The annotation key is set by a `flux suspend` command and removed by a `flux resume` command. The annotation key value is open for communicating a message or reason for the object's suspension. The value can be set using a `--message` flag to the `suspend` command.
47+
Register a flux resource metadata key `reconcile.fluxcd.io/suspended` with a
48+
suspend semantic to be interpreted by controllers and manipulated by the cli.
49+
The presence of the annotation key is an alternative to the `.spec.suspend:
50+
true` api field setting when considering if a resource is suspended or not.
51+
The annotation key is set by a `flux suspend` command and removed by a `flux
52+
resume` command. The annotation key value is open for communicating a message
53+
or reason for the object's suspension. The value can be set using a
54+
`--message` flag to the `suspend` command.
3355

3456
### User Stories
3557

3658
#### Suspend/Resume without Generation Roll
3759

38-
Currently when a resource is set to suspended or resumed the `.spec.suspend` field is mutated which results in a roll of the generation number in the `.metadata.generation` and fields `.status.observedGeneration` number. The community believes that the generation change for this reason is not in alignment with gitops principles.
60+
Currently when a resource is set to suspended or resumed the `.spec.suspend`
61+
field is mutated which results in a roll of the generation number in the
62+
`.metadata.generation` and fields `.status.observedGeneration` number. The
63+
community believes that the generation change for this reason is not in
64+
alignment with gitops principles.
3965

40-
The flux controllers should recognize that a resource is suspended or unsuspended from the presence of a special metadata key -- this key can be added, removed or changed without patching the object and rolling the generation number.
66+
The flux controllers should recognize that a resource is suspended or
67+
unsuspended from the presence of a special metadata key -- this key can be
68+
added, removed or changed without patching the object and rolling the
69+
generation number.
4170

4271
#### Seeing Suspend State
4372

44-
Users should be able to see the effective suspend state of the resource with a `flux get` command. The display should mirror what the controllers interpret the suspend state to be. This story is included to capture current functionality that should be preserved.
73+
Users should be able to see the effective suspend state of the resource with a
74+
`flux get` command. The display should mirror what the controllers interpret
75+
the suspend state to be. This story is included to capture current
76+
functionality that should be preserved.
4577

4678
#### Suspend with a Reason
4779

48-
Often there is a purpose behind suspending a resource with the flux cli, whether it be during incident response, source manifest cutovers, or various other scenarios. The `flux diff` command provides a great UX for determining what will change if a suspended resource is resumed, but it doesn't help explain _why_ something is paused or when it would be ok to resume reconciliation. On distributed teams this can become a point of friction as it needs to be communicated among group stakeholders.
80+
Often there is a purpose behind suspending a resource with the flux cli,
81+
whether it be during incident response, source manifest cutovers, or various
82+
other scenarios. The `flux diff` command provides a great UX for determining
83+
what will change if a suspended resource is resumed, but it doesn't help
84+
explain _why_ something is paused or when it would be ok to resume
85+
reconciliation. On distributed teams this can become a point of friction as it
86+
needs to be communicated among group stakeholders.
4987

50-
Flux users should have a way to succinctly signal to other users why a resource is suspended on the resource itself.
88+
Flux users should have a way to succinctly signal to other users why a resource
89+
is suspended on the resource itself.
5190

5291
### Alternatives
5392

5493
#### More `.spec`
5594

56-
The existing `.spec.suspend` could be expanded with fields for the above semantics. This would drive more generation number changes and would require a change to the apis.
95+
The existing `.spec.suspend` could be expanded with fields for the above
96+
semantics. This would drive more generation number changes and would require a
97+
change to the apis.
5798

5899

59100
## Design Details
60101

61102
Implementing this RFC would involve the controllers and the cli.
62103

63-
This feature would create an alternate path to suspending an object and would not violate the current apis.
104+
This feature would create an alternate path to suspending an object and would
105+
not violate the current apis.
64106

65107
### Common
66108

67-
The `reconcile.fluxcd.io/suspended` annotation key string and a getter function would be made avaiable for controllers the cli to recognize and manipulate the suspend object metadata.
109+
The `reconcile.fluxcd.io/suspended` annotation key string and a getter function
110+
would be made avaiable for controllers the cli to recognize and manipulate the
111+
suspend object metadata.
68112

69-
```
70-
# github.com/fluxcd/pkg/apis/meta
113+
``` # github.com/fluxcd/pkg/apis/meta
71114
72115
73-
// SuspendAnnotation is the annotation used to indicate an object is suspended and optionally to store metadata about why a resource
74-
// was set to suspended.
116+
// SuspendAnnotation is the annotation used to indicate an object is suspended
117+
and optionally to store metadata about why a resource // was set to suspended.
75118
const SuspendedAnnotation string = "reconcile.fluxcd.io/suspended"
76119
77-
// SuspendAnnotationValue returns a value for the suspended annotation, which can be used to detect
78-
// changes; and, a boolean indicating whether the annotation was set.
79-
func SuspendedAnnotationValue(annotations map[string]string) (string, bool) {
80-
suspend, ok := annotations[SuspendedAnnotation]
81-
return suspend, ok
82-
}
120+
// SuspendAnnotationValue returns a value for the suspended annotation, which
121+
can be used to detect // changes; and, a boolean indicating whether the
122+
annotation was set. func SuspendedAnnotationValue(annotations
123+
map[string]string) (string, bool) { suspend, ok :=
124+
annotations[SuspendedAnnotation] return suspend, ok }
83125
84-
// SetSuspendedAnnotation sets a suspend key with a supplied string value in an object's metadata annotations
85-
func SetSuspendedAnnotation(annotations *map[string]string, token string) {
86-
if annotations == nil {
87-
annotations = &map[string]string{}
88-
}
89-
if token != "" {
90-
(*annotations)[SuspendedAnnotation] = token
91-
} else {
92-
(*annotations)[SuspendedAnnotation] = "true"
93-
}
94-
}
126+
// SetSuspendedAnnotation sets a suspend key with a supplied string value in an
127+
object's metadata annotations func SetSuspendedAnnotation(annotations
128+
*map[string]string, token string) { if annotations == nil { annotations =
129+
&map[string]string{} } if token != "" { (*annotations)[SuspendedAnnotation] =
130+
token } else { (*annotations)[SuspendedAnnotation] = "true" } }
95131
96-
// UnsetSuspendedAnnotation removes a suspend key from an object's metadata annotations
97-
func UnsetSuspendedAnnotation(annotations *map[string]string) {
98-
delete(*annotations, SuspendedAnnotation)
99-
}
100-
```
132+
// UnsetSuspendedAnnotation removes a suspend key from an object's metadata
133+
annotations func UnsetSuspendedAnnotation(annotations *map[string]string) {
134+
delete(*annotations, SuspendedAnnotation) } ```
101135
102-
An event predicate would skip attempting to reconcile a resource with the suspend annotation set.
136+
An event predicate would skip attempting to reconcile a resource with the
137+
suspend annotation set.
103138
104-
```
105-
# github.com/fluxcd/pkg/apis/predicates
139+
``` # github.com/fluxcd/pkg/apis/predicates
106140
107141
# suspended.go
108142
109-
// Update implements the default UpdateEvent filter for filtering by meta.SuspendedAnnotation existence
110-
func (SuspendedPredicate) Update(e event.UpdateEvent) bool {
111-
if e.ObjectOld == nil || e.ObjectNew == nil {
112-
return false
113-
}
143+
// Update implements the default UpdateEvent filter for filtering by
144+
meta.SuspendedAnnotation existence func (SuspendedPredicate) Update(e
145+
event.UpdateEvent) bool { if e.ObjectOld == nil || e.ObjectNew == nil { return
146+
false }
114147
115-
if _, ok := metav1.SuspendedAnnotationValue(e.ObjectNew.GetAnnotations()); !ok {
116-
return true
117-
}
118-
return false
119-
}
120-
```
148+
if _, ok := metav1.SuspendedAnnotationValue(e.ObjectNew.GetAnnotations());
149+
!ok { return true } return false } ```
121150
122151
### Controllers
123152
124-
Flux controllers would skip reconciling a resource based on an `OR` of (1) the api `.spec.suspend` and (2) the existence of the suspend metadata annotation key.
153+
Flux controllers would skip reconciling a resource based on an `OR` of (1) the
154+
api `.spec.suspend` and (2) the existence of the suspend metadata annotation
155+
key.
125156
126-
```
127-
# github.com/fluxcd/kustomize-controller/api/v1
128-
# kustomization_types.go
129-
130-
// IsSuspended returns the effective suspend state of the object.
131-
func (in Kustomization) IsSuspended() bool {
132-
if in.Spec.Suspend {
133-
return true
134-
}
135-
if _, ok := meta.SuspendedAnnotationValue(in.Annotations); ok {
136-
return true
137-
}
138-
return false
139-
}
157+
``` # github.com/fluxcd/kustomize-controller/api/v1 # kustomization_types.go
140158
141-
# github.com/fluxcd/kustomize-controller/controller
142-
# kustomization_controller.go
159+
// IsSuspended returns the effective suspend state of the object. func (in
160+
Kustomization) IsSuspended() bool { if in.Spec.Suspend { return true } if _, ok
161+
:= meta.SuspendedAnnotationValue(in.Annotations); ok { return true } return
162+
false }
143163
144-
// Skip reconciliation if the object is suspended.
145-
// if obj.Spec.Suspend { // no longer using `.spec.suspend` directly
146-
if obj.Status.IsSuspended {
147-
log.Info("Reconciliation is suspended for this object")
148-
return ctrl.Result{}, nil
149-
}
150-
```
164+
# github.com/fluxcd/kustomize-controller/controller #
165+
kustomization_controller.go
166+
167+
// Skip reconciliation if the object is suspended. // if obj.Spec.Suspend { //
168+
no longer using `.spec.suspend` directly if obj.Status.IsSuspended {
169+
log.Info("Reconciliation is suspended for this object") return ctrl.Result{},
170+
nil } ```
151171
152172
### cli
153173
154174
The flux cli would recognize the suspend state from the suspend object status.
155175
156-
```
157-
# github.com/fluxcd/flux2/main
176+
``` # github.com/fluxcd/flux2/main
158177
159178
# get_source_git.go
160179
161-
func (a *gitRepositoryListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
162-
...
163-
return append(nameColumns(&item, includeNamespace, includeKind),
164-
// revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg)
165-
revision, strings.Title(strconv.FormatBool(item.IsSuspended)), status, msg)
166-
}
167-
```
180+
func (a *gitRepositoryListAdapter) summariseItem(i int, includeNamespace bool,
181+
includeKind bool) []string { ... return append(nameColumns(&item,
182+
includeNamespace, includeKind), // revision,
183+
strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg) revision,
184+
strings.Title(strconv.FormatBool(item.IsSuspended)), status, msg) } ```
168185
169-
The flux cli would manipulate the suspend metadata but forgo toggling the `.spec.suspend` setting. An optional `--message|-m` flag would support setting the suspended annotation value to a user-specified string.
186+
The flux cli would manipulate the suspend metadata but forgo toggling the
187+
`.spec.suspend` setting. An optional `--message|-m` flag would support setting
188+
the suspended annotation value to a user-specified string.
170189
171-
```
172-
# github.com/fluxcd/flux2/main
190+
``` # github.com/fluxcd/flux2/main
173191
174192
# suspend.go
175193
176-
type SuspendFlags struct {
177-
...
178-
message string
179-
}
194+
type SuspendFlags struct { ... message string }
180195
181-
func init() {
182-
...
183-
suspendCmd.PersistentFlags().StringVarP(&suspendArgs.message, "message", "m", "",
184-
"set a message about why the resource is suspended, the message will show up under the reconcile.fluxcd.io/suspended annotation")
185-
...
186-
}
196+
func init() { ... suspendCmd.PersistentFlags().StringVarP(&suspendArgs.message,
197+
"message", "m", "", "set a message about why the resource is suspended, the
198+
message will show up under the reconcile.fluxcd.io/suspended annotation") ... }
187199
188-
type suspendable interface {
189-
...
190-
// setSuspended()
191-
setSuspended(message string)
200+
type suspendable interface { ... // setSuspended() setSuspended(message string)
192201
}
193202
194-
type suspendCommand struct {
195-
...
196-
// obj.setSuspended()
197-
obj.setSuspended(suspendArgs.message)
198-
}
203+
type suspendCommand struct { ... // obj.setSuspended()
204+
obj.setSuspended(suspendArgs.message) }
199205
200206
# suspend_helmrelease.go
201207
202-
func (obj helmReleaseAdapter) isSuspended() bool {
203-
return obj.HelmRelease.IsSuspended() // use the resource api spec method
204-
}
208+
func (obj helmReleaseAdapter) isSuspended() bool { return
209+
obj.HelmRelease.IsSuspended() // use the resource
210+
api spec method }
205211
206212
func (obj helmReleaseAdapter) setSuspended(message string) {
207-
meta.SetSuspendedAnnotation(&obj.HelmRelease.Annotations, message) // use the common annotation setter
208-
}
213+
meta.SetSuspendedAnnotation(&obj.HelmRelease.Annotations, message) // use the
214+
common annotation setter }
209215
210216
# resume_helmrelease.go
211217
212218
func (obj helmReleaseAdapter) setUnsuspended() {
213-
meta.UnsetSuspendedAnnotation(&obj.HelmRelease.Annotations) // use the common annotation unsetter
214-
}
215-
```
219+
meta.UnsetSuspendedAnnotation(&obj.HelmRelease.Annotations) // use the
220+
common annotation unsetter } ```
216221
217222
### Metrics
218223
219-
Custom metrics can be [configured under kube-state-metrics](https://fluxcd.io/flux/monitoring/custom-metrics/#adding-custom-metrics) using the object metadata annotation path.
224+
Custom metrics can be [configured under
225+
kube-state-metrics](https://fluxcd.io/flux/monitoring/custom-metrics/#adding-custom-metrics)
226+
using the object metadata annotation path.
220227
221228
```
222-
- name: "resource_info"
223-
help: "The current state of a GitOps Toolkit resource."
224-
each:
225-
type: Info
226-
info:
227-
labelsFromPath:
228-
name: [metadata, name]
229-
labelsFromPath:
230-
...
231-
suspendedAnnotation: [ metadata, annotations, reconcile.fluxcd.io/suspended ]
232-
```
229+
- name: "resource_info" help: "The current state of a GitOps Toolkit resource."
230+
each: type: Info info: labelsFromPath: name: [metadata, name] labelsFromPath:
231+
... suspendedAnnotation: [ metadata, annotations,
232+
reconcile.fluxcd.io/suspended ] ```
233233

234234
## Implementation History
235235

0 commit comments

Comments
 (0)