Skip to content

Commit f28af00

Browse files
committed
Store digest of latest image in ImagePolicy's status
Signed-off-by: Matheus Pimenta <[email protected]>
1 parent 9e84252 commit f28af00

26 files changed

+2279
-877
lines changed

api/v1beta1/zz_generated.deepcopy.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v1beta2/condition_types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,7 @@ const (
3232

3333
// ReadOperationFailedReason signals a failure caused by a read operation.
3434
ReadOperationFailedReason string = "ReadOperationFailed"
35+
36+
// IntervalNotConfiguredReason signals that the interval is missing.
37+
IntervalNotConfiguredReason string = "IntervalNotConfigured"
3538
)

api/v1beta2/imagepolicy_types.go

Lines changed: 95 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2022 The Flux authors
2+
Copyright 2023 The Flux authors
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -17,17 +17,21 @@ limitations under the License.
1717
package v1beta2
1818

1919
import (
20+
"time"
21+
2022
"github.com/fluxcd/pkg/apis/meta"
2123
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2224
)
2325

2426
const ImagePolicyKind = "ImagePolicy"
2527

2628
// Deprecated: Use ImageFinalizer.
27-
const ImagePolicyFinalizer = "finalizers.fluxcd.io"
29+
const ImagePolicyFinalizer = ImageFinalizer
2830

2931
// ImagePolicySpec defines the parameters for calculating the
3032
// ImagePolicy.
33+
// +kubebuilder:validation:XValidation:rule="!has(self.interval) || (has(self.digestReflectionPolicy) && self.digestReflectionPolicy == 'Always')", message="spec.interval is only accepted when spec.digestReflectionPolicy is set to 'Always'"
34+
// +kubebuilder:validation:XValidation:rule="has(self.interval) || !has(self.digestReflectionPolicy) || self.digestReflectionPolicy != 'Always'", message="spec.interval must be set when spec.digestReflectionPolicy is set to 'Always'"
3135
type ImagePolicySpec struct {
3236
// ImageRepositoryRef points at the object specifying the image
3337
// being scanned
@@ -42,8 +46,46 @@ type ImagePolicySpec struct {
4246
// ordered and compared.
4347
// +optional
4448
FilterTags *TagFilter `json:"filterTags,omitempty"`
49+
// DigestReflectionPolicy governs the setting of the `.status.latestRef.digest` field.
50+
//
51+
// Never: The digest field will always be set to the empty string.
52+
//
53+
// IfNotPresent: The digest field will be set to the digest of the elected
54+
// latest image if the field is empty and the image did not change.
55+
//
56+
// Always: The digest field will always be set to the digest of the elected
57+
// latest image.
58+
//
59+
// Default: Never.
60+
// +kubebuilder:default:=Never
61+
DigestReflectionPolicy ReflectionPolicy `json:"digestReflectionPolicy,omitempty"`
62+
63+
// Interval is the length of time to wait between
64+
// refreshing the digest of the latest tag when the
65+
// reflection policy is set to "Always".
66+
//
67+
// Defaults to 10m.
68+
// +kubebuilder:validation:Type=string
69+
// +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$"
70+
// +optional
71+
Interval *metav1.Duration `json:"interval,omitempty"`
4572
}
4673

74+
// ReflectionPolicy describes a policy for if/when to reflect a value from the registry in a certain resource field.
75+
// +kubebuilder:validation:Enum=Always;IfNotPresent;Never
76+
type ReflectionPolicy string
77+
78+
const (
79+
// ReflectAlways means that a value is always reflected with the latest value from the registry even if this would
80+
// overwrite an existing value in the object.
81+
ReflectAlways ReflectionPolicy = "Always"
82+
// ReflectIfNotPresent means that the target value is only reflected from the registry if it is empty. It will
83+
// never be overwritten afterwards, even if it changes in the registry.
84+
ReflectIfNotPresent ReflectionPolicy = "IfNotPresent"
85+
// ReflectNever means that no reflection will happen at all.
86+
ReflectNever ReflectionPolicy = "Never"
87+
)
88+
4789
// ImagePolicyChoice is a union of all the types of policy that can be
4890
// supplied.
4991
type ImagePolicyChoice struct {
@@ -101,30 +143,63 @@ type TagFilter struct {
101143
Extract string `json:"extract"`
102144
}
103145

146+
// ImageRef represents an image reference.
147+
type ImageRef struct {
148+
// Name is the bare image's name.
149+
// +required
150+
Name string `json:"name"`
151+
// Tag is the image's tag.
152+
// +required
153+
Tag string `json:"tag"`
154+
// Digest is the image's digest.
155+
// +optional
156+
Digest string `json:"digest,omitempty"`
157+
}
158+
159+
func (in *ImageRef) String() string {
160+
res := in.Name + ":" + in.Tag
161+
if in.Digest != "" {
162+
res += "@" + in.Digest
163+
}
164+
return res
165+
}
166+
104167
// ImagePolicyStatus defines the observed state of ImagePolicy
105168
type ImagePolicyStatus struct {
106169
// LatestImage gives the first in the list of images scanned by
107170
// the image repository, when filtered and ordered according to
108171
// the policy.
172+
//
173+
// Deprecated: Replaced by the composite "latestRef" field.
109174
LatestImage string `json:"latestImage,omitempty"`
110175
// ObservedPreviousImage is the observed previous LatestImage. It is used
111176
// to keep track of the previous and current images.
177+
//
178+
// Deprecated: Replaced by the composite "observedPreviousRef" field.
112179
// +optional
113180
ObservedPreviousImage string `json:"observedPreviousImage,omitempty"`
181+
// LatestRef gives the first in the list of images scanned by
182+
// the image repository, when filtered and ordered according
183+
// to the policy.
184+
LatestRef *ImageRef `json:"latestRef,omitempty"`
185+
// ObservedPreviousRef is the observed previous LatestRef. It is used
186+
// to keep track of the previous and current images.
187+
// +optional
188+
ObservedPreviousRef *ImageRef `json:"observedPreviousRef,omitempty"`
114189
// +optional
115190
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
116191
// +optional
117192
Conditions []metav1.Condition `json:"conditions,omitempty"`
118193
}
119194

120195
// GetConditions returns the status conditions of the object.
121-
func (p ImagePolicy) GetConditions() []metav1.Condition {
122-
return p.Status.Conditions
196+
func (in *ImagePolicy) GetConditions() []metav1.Condition {
197+
return in.Status.Conditions
123198
}
124199

125200
// SetConditions sets the status conditions on the object.
126-
func (p *ImagePolicy) SetConditions(conditions []metav1.Condition) {
127-
p.Status.Conditions = conditions
201+
func (in *ImagePolicy) SetConditions(conditions []metav1.Condition) {
202+
in.Status.Conditions = conditions
128203
}
129204

130205
// +kubebuilder:storageversion
@@ -142,6 +217,20 @@ type ImagePolicy struct {
142217
Status ImagePolicyStatus `json:"status,omitempty"`
143218
}
144219

220+
func (in *ImagePolicy) GetDigestReflectionPolicy() ReflectionPolicy {
221+
if in.Spec.DigestReflectionPolicy != "" {
222+
return in.Spec.DigestReflectionPolicy
223+
}
224+
return ReflectNever
225+
}
226+
227+
func (in *ImagePolicy) GetInterval() time.Duration {
228+
if in.GetDigestReflectionPolicy() == ReflectAlways {
229+
return in.Spec.Interval.Duration
230+
}
231+
return 0
232+
}
233+
145234
//+kubebuilder:object:root=true
146235

147236
// ImagePolicyList contains a list of ImagePolicy

api/v1beta2/imagerepository_types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import (
2828
const ImageRepositoryKind = "ImageRepository"
2929

3030
// Deprecated: Use ImageFinalizer.
31-
const ImageRepositoryFinalizer = "finalizers.fluxcd.io"
31+
const ImageRepositoryFinalizer = ImageFinalizer
3232

3333
// ImageRepositorySpec defines the parameters for scanning an image
3434
// repository, e.g., `fluxcd/flux`.

api/v1beta2/zz_generated.deepcopy.go

Lines changed: 31 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/image.toolkit.fluxcd.io_imagepolicies.yaml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,25 @@ spec:
237237
ImagePolicySpec defines the parameters for calculating the
238238
ImagePolicy.
239239
properties:
240+
digestReflectionPolicy:
241+
default: Never
242+
description: |-
243+
DigestReflectionPolicy governs the setting of the `.status.latestRef.digest` field.
244+
245+
Never: The digest field will always be set to the empty string.
246+
247+
IfNotPresent: The digest field will be set to the digest of the elected
248+
latest image if the field is empty and the image did not change.
249+
250+
Always: The digest field will always be set to the digest of the elected
251+
latest image.
252+
253+
Default: Never.
254+
enum:
255+
- Always
256+
- IfNotPresent
257+
- Never
258+
type: string
240259
filterTags:
241260
description: |-
242261
FilterTags enables filtering for only a subset of tags based on a set of
@@ -269,6 +288,15 @@ spec:
269288
required:
270289
- name
271290
type: object
291+
interval:
292+
description: |-
293+
Interval is the length of time to wait between
294+
refreshing the digest of the latest tag when the
295+
reflection policy is set to "Always".
296+
297+
Defaults to 10m.
298+
pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
299+
type: string
272300
policy:
273301
description: |-
274302
Policy gives the particulars of the policy to be followed in
@@ -322,6 +350,15 @@ spec:
322350
- imageRepositoryRef
323351
- policy
324352
type: object
353+
x-kubernetes-validations:
354+
- message: spec.interval is only accepted when spec.digestReflectionPolicy
355+
is set to 'Always'
356+
rule: '!has(self.interval) || (has(self.digestReflectionPolicy) && self.digestReflectionPolicy
357+
== ''Always'')'
358+
- message: spec.interval must be set when spec.digestReflectionPolicy
359+
is set to 'Always'
360+
rule: has(self.interval) || !has(self.digestReflectionPolicy) || self.digestReflectionPolicy
361+
!= 'Always'
325362
status:
326363
default:
327364
observedGeneration: -1
@@ -388,15 +425,56 @@ spec:
388425
LatestImage gives the first in the list of images scanned by
389426
the image repository, when filtered and ordered according to
390427
the policy.
428+
429+
Deprecated: Replaced by the composite "latestRef" field.
391430
type: string
431+
latestRef:
432+
description: |-
433+
LatestRef gives the first in the list of images scanned by
434+
the image repository, when filtered and ordered according
435+
to the policy.
436+
properties:
437+
digest:
438+
description: Digest is the image's digest.
439+
type: string
440+
name:
441+
description: Name is the bare image's name.
442+
type: string
443+
tag:
444+
description: Tag is the image's tag.
445+
type: string
446+
required:
447+
- name
448+
- tag
449+
type: object
392450
observedGeneration:
393451
format: int64
394452
type: integer
395453
observedPreviousImage:
396454
description: |-
397455
ObservedPreviousImage is the observed previous LatestImage. It is used
398456
to keep track of the previous and current images.
457+
458+
Deprecated: Replaced by the composite "observedPreviousRef" field.
399459
type: string
460+
observedPreviousRef:
461+
description: |-
462+
ObservedPreviousRef is the observed previous LatestRef. It is used
463+
to keep track of the previous and current images.
464+
properties:
465+
digest:
466+
description: Digest is the image's digest.
467+
type: string
468+
name:
469+
description: Name is the bare image's name.
470+
type: string
471+
tag:
472+
description: Tag is the image's tag.
473+
type: string
474+
required:
475+
- name
476+
- tag
477+
type: object
400478
type: object
401479
type: object
402480
served: true

0 commit comments

Comments
 (0)