GitRepo: Add observed content config in status
Replace content config checksum with explicit artifact content config observations. It makes the observations of the controller more transparent and easier to debug. Introduces `observedIgnore`, `observedRecurseSubmodules` and `observedInclude` status fields. Signed-off-by: Sunny <darkowlzz@protonmail.com>
This commit is contained in:
parent
278a223bc6
commit
e996848555
|
@ -224,9 +224,27 @@ type GitRepositoryStatus struct {
|
|||
// be used to determine if the content of the included repository has
|
||||
// changed.
|
||||
// It has the format of `<algo>:<checksum>`, for example: `sha256:<checksum>`.
|
||||
//
|
||||
// Deprecated: Replaced with explicit fields for observed artifact content
|
||||
// config in the status.
|
||||
// +optional
|
||||
ContentConfigChecksum string `json:"contentConfigChecksum,omitempty"`
|
||||
|
||||
// ObservedIgnore is the observed exclusion patterns used for constructing
|
||||
// the source artifact.
|
||||
// +optional
|
||||
ObservedIgnore *string `json:"observedIgnore,omitempty"`
|
||||
|
||||
// ObservedRecurseSubmodules is the observed resource submodules
|
||||
// configuration used to produce the current Artifact.
|
||||
// +optional
|
||||
ObservedRecurseSubmodules bool `json:"observedRecurseSubmodules,omitempty"`
|
||||
|
||||
// ObservedInclude is the observed list of GitRepository resources used to
|
||||
// to produce the current Artifact.
|
||||
// +optional
|
||||
ObservedInclude []GitRepositoryInclude `json:"observedInclude,omitempty"`
|
||||
|
||||
meta.ReconcileRequestStatus `json:",inline"`
|
||||
}
|
||||
|
||||
|
|
|
@ -346,6 +346,16 @@ func (in *GitRepositoryStatus) DeepCopyInto(out *GitRepositoryStatus) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if in.ObservedIgnore != nil {
|
||||
in, out := &in.ObservedIgnore, &out.ObservedIgnore
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
if in.ObservedInclude != nil {
|
||||
in, out := &in.ObservedInclude, &out.ObservedInclude
|
||||
*out = make([]GitRepositoryInclude, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
out.ReconcileRequestStatus = in.ReconcileRequestStatus
|
||||
}
|
||||
|
||||
|
|
|
@ -658,13 +658,14 @@ spec:
|
|||
type: object
|
||||
type: array
|
||||
contentConfigChecksum:
|
||||
description: 'ContentConfigChecksum is a checksum of all the configurations
|
||||
description: "ContentConfigChecksum is a checksum of all the configurations
|
||||
related to the content of the source artifact: - .spec.ignore -
|
||||
.spec.recurseSubmodules - .spec.included and the checksum of the
|
||||
included artifacts observed in .status.observedGeneration version
|
||||
of the object. This can be used to determine if the content of the
|
||||
included repository has changed. It has the format of `<algo>:<checksum>`,
|
||||
for example: `sha256:<checksum>`.'
|
||||
for example: `sha256:<checksum>`. \n Deprecated: Replaced with explicit
|
||||
fields for observed artifact content config in the status."
|
||||
type: string
|
||||
includedArtifacts:
|
||||
description: IncludedArtifacts contains a list of the last successfully
|
||||
|
@ -723,6 +724,44 @@ spec:
|
|||
the GitRepository object.
|
||||
format: int64
|
||||
type: integer
|
||||
observedIgnore:
|
||||
description: ObservedIgnore is the observed exclusion patterns used
|
||||
for constructing the source artifact.
|
||||
type: string
|
||||
observedInclude:
|
||||
description: ObservedInclude is the observed list of GitRepository
|
||||
resources used to to produce the current Artifact.
|
||||
items:
|
||||
description: GitRepositoryInclude specifies a local reference to
|
||||
a GitRepository which Artifact (sub-)contents must be included,
|
||||
and where they should be placed.
|
||||
properties:
|
||||
fromPath:
|
||||
description: FromPath specifies the path to copy contents from,
|
||||
defaults to the root of the Artifact.
|
||||
type: string
|
||||
repository:
|
||||
description: GitRepositoryRef specifies the GitRepository which
|
||||
Artifact contents must be included.
|
||||
properties:
|
||||
name:
|
||||
description: Name of the referent.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
toPath:
|
||||
description: ToPath specifies the path to copy contents to,
|
||||
defaults to the name of the GitRepositoryRef.
|
||||
type: string
|
||||
required:
|
||||
- repository
|
||||
type: object
|
||||
type: array
|
||||
observedRecurseSubmodules:
|
||||
description: ObservedRecurseSubmodules is the observed resource submodules
|
||||
configuration used to produce the current Artifact.
|
||||
type: boolean
|
||||
url:
|
||||
description: URL is the dynamic fetch link for the latest Artifact.
|
||||
It is provided on a "best effort" basis, and using the precise GitRepositoryStatus.Artifact
|
||||
|
|
|
@ -18,12 +18,10 @@ package controllers
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -33,6 +31,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
kuberecorder "k8s.io/client-go/tools/record"
|
||||
"k8s.io/utils/pointer"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
@ -507,8 +506,8 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context,
|
|||
// If it's a partial commit obtained from an existing artifact, check if the
|
||||
// reconciliation can be skipped if other configurations have not changed.
|
||||
if !git.IsConcreteCommit(*commit) {
|
||||
// Calculate content configuration checksum.
|
||||
if r.calculateContentConfigChecksum(obj, includes) == obj.Status.ContentConfigChecksum {
|
||||
// Check if the content config contributing to the artifact has changed.
|
||||
if !gitContentConfigChanged(obj, includes) {
|
||||
ge := serror.NewGeneric(
|
||||
fmt.Errorf("no changes since last reconcilation: observed revision '%s'",
|
||||
commit.String()), sourcev1.GitOperationSucceedReason,
|
||||
|
@ -559,27 +558,24 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context,
|
|||
//
|
||||
// The inspection of the given data to the object is differed, ensuring any
|
||||
// stale observations like v1beta2.ArtifactOutdatedCondition are removed.
|
||||
// If the given Artifact and/or artifactSet (includes) and the content config
|
||||
// checksum do not differ from the object's current, it returns early.
|
||||
// If the given Artifact and/or artifactSet (includes) and observed artifact
|
||||
// content config do not differ from the object's current, it returns early.
|
||||
// Source ignore patterns are loaded, and the given directory is archived while
|
||||
// taking these patterns into account.
|
||||
// On a successful archive, the Artifact, Includes and new content config
|
||||
// checksum in the Status of the object are set, and the symlink in the Storage
|
||||
// is updated to its path.
|
||||
// On a successful archive, the Artifact, Includes, observed ignore, recurse
|
||||
// submodules and observed include in the Status of the object are set, and the
|
||||
// symlink in the Storage is updated to its path.
|
||||
func (r *GitRepositoryReconciler) reconcileArtifact(ctx context.Context,
|
||||
obj *sourcev1.GitRepository, commit *git.Commit, includes *artifactSet, dir string) (sreconcile.Result, error) {
|
||||
|
||||
// Create potential new artifact with current available metadata
|
||||
artifact := r.Storage.NewArtifactFor(obj.Kind, obj.GetObjectMeta(), commit.String(), fmt.Sprintf("%s.tar.gz", commit.Hash.String()))
|
||||
|
||||
// Calculate the content config checksum.
|
||||
ccc := r.calculateContentConfigChecksum(obj, includes)
|
||||
|
||||
// Set the ArtifactInStorageCondition if there's no drift.
|
||||
defer func() {
|
||||
if obj.GetArtifact().HasRevision(artifact.Revision) &&
|
||||
!includes.Diff(obj.Status.IncludedArtifacts) &&
|
||||
obj.Status.ContentConfigChecksum == ccc {
|
||||
!gitContentConfigChanged(obj, includes) {
|
||||
conditions.Delete(obj, sourcev1.ArtifactOutdatedCondition)
|
||||
conditions.MarkTrue(obj, sourcev1.ArtifactInStorageCondition, meta.SucceededReason,
|
||||
"stored artifact for revision '%s'", artifact.Revision)
|
||||
|
@ -589,7 +585,7 @@ func (r *GitRepositoryReconciler) reconcileArtifact(ctx context.Context,
|
|||
// The artifact is up-to-date
|
||||
if obj.GetArtifact().HasRevision(artifact.Revision) &&
|
||||
!includes.Diff(obj.Status.IncludedArtifacts) &&
|
||||
obj.Status.ContentConfigChecksum == ccc {
|
||||
!gitContentConfigChanged(obj, includes) {
|
||||
r.eventLogf(ctx, obj, events.EventTypeTrace, sourcev1.ArtifactUpToDateReason, "artifact up-to-date with remote revision: '%s'", artifact.Revision)
|
||||
return sreconcile.ResultSuccess, nil
|
||||
}
|
||||
|
@ -652,10 +648,13 @@ func (r *GitRepositoryReconciler) reconcileArtifact(ctx context.Context,
|
|||
return sreconcile.ResultEmpty, e
|
||||
}
|
||||
|
||||
// Record it on the object
|
||||
// Record the observations on the object.
|
||||
obj.Status.Artifact = artifact.DeepCopy()
|
||||
obj.Status.IncludedArtifacts = *includes
|
||||
obj.Status.ContentConfigChecksum = ccc
|
||||
obj.Status.ContentConfigChecksum = "" // To be removed in the next API version.
|
||||
obj.Status.ObservedIgnore = obj.Spec.Ignore
|
||||
obj.Status.ObservedRecurseSubmodules = obj.Spec.RecurseSubmodules
|
||||
obj.Status.ObservedInclude = obj.Spec.Include
|
||||
|
||||
// Update symlink on a "best effort" basis
|
||||
url, err := r.Storage.Symlink(artifact, "latest.tar.gz")
|
||||
|
@ -825,39 +824,6 @@ func (r *GitRepositoryReconciler) fetchIncludes(ctx context.Context, obj *source
|
|||
return &artifacts, nil
|
||||
}
|
||||
|
||||
// calculateContentConfigChecksum calculates a checksum of all the
|
||||
// configurations that result in a change in the source artifact. It can be used
|
||||
// to decide if further reconciliation is needed when an artifact already exists
|
||||
// for a set of configurations.
|
||||
func (r *GitRepositoryReconciler) calculateContentConfigChecksum(obj *sourcev1.GitRepository, includes *artifactSet) string {
|
||||
c := []byte{}
|
||||
// Consider the ignore rules and recurse submodules.
|
||||
if obj.Spec.Ignore != nil {
|
||||
c = append(c, []byte(*obj.Spec.Ignore)...)
|
||||
}
|
||||
c = append(c, []byte(strconv.FormatBool(obj.Spec.RecurseSubmodules))...)
|
||||
|
||||
// Consider the included repository attributes.
|
||||
for _, incl := range obj.Spec.Include {
|
||||
c = append(c, []byte(incl.GitRepositoryRef.Name+incl.FromPath+incl.ToPath)...)
|
||||
}
|
||||
|
||||
// Consider the checksum and revision of all the included remote artifact.
|
||||
// This ensures that if the included repos get updated, this checksum changes.
|
||||
// NOTE: The content of an artifact may change at the same revision if the
|
||||
// ignore rules change. Hence, consider both checksum and revision to
|
||||
// capture changes in artifact checksum as well.
|
||||
// TODO: Fix artifactSet.Diff() to consider checksum as well.
|
||||
if includes != nil {
|
||||
for _, incl := range *includes {
|
||||
c = append(c, []byte(incl.Checksum)...)
|
||||
c = append(c, []byte(incl.Revision)...)
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("sha256:%x", sha256.Sum256(c))
|
||||
}
|
||||
|
||||
// verifyCommitSignature verifies the signature of the given Git commit, if a
|
||||
// verification mode is specified on the object.
|
||||
// If the signature can not be verified or the verification fails, it records
|
||||
|
@ -978,3 +944,64 @@ func (r *GitRepositoryReconciler) eventLogf(ctx context.Context, obj runtime.Obj
|
|||
}
|
||||
r.Eventf(obj, eventType, reason, msg)
|
||||
}
|
||||
|
||||
// gitContentConfigChanged evaluates the current spec with the observations of
|
||||
// the artifact in the status to determine if artifact content configuration has
|
||||
// changed and requires rebuilding the artifact.
|
||||
func gitContentConfigChanged(obj *sourcev1.GitRepository, includes *artifactSet) bool {
|
||||
if !pointer.StringEqual(obj.Spec.Ignore, obj.Status.ObservedIgnore) {
|
||||
return true
|
||||
}
|
||||
if obj.Spec.RecurseSubmodules != obj.Status.ObservedRecurseSubmodules {
|
||||
return true
|
||||
}
|
||||
if len(obj.Spec.Include) != len(obj.Status.ObservedInclude) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Convert artifactSet to index addressable artifacts and ensure that it and
|
||||
// the included artifacts include all the include from the spec.
|
||||
artifacts := []*sourcev1.Artifact(*includes)
|
||||
if len(obj.Spec.Include) != len(artifacts) {
|
||||
return true
|
||||
}
|
||||
if len(obj.Spec.Include) != len(obj.Status.IncludedArtifacts) {
|
||||
return true
|
||||
}
|
||||
|
||||
// The order of spec.include, status.IncludeArtifacts and
|
||||
// status.observedInclude are the same. Compare the values by index.
|
||||
for index, incl := range obj.Spec.Include {
|
||||
observedIncl := obj.Status.ObservedInclude[index]
|
||||
observedInclArtifact := obj.Status.IncludedArtifacts[index]
|
||||
currentIncl := artifacts[index]
|
||||
|
||||
// Check if the include are the same in spec and status.
|
||||
if !gitRepositoryIncludeEqual(incl, observedIncl) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check if the included repositories are still the same.
|
||||
if observedInclArtifact.Revision != currentIncl.Revision {
|
||||
return true
|
||||
}
|
||||
if observedInclArtifact.Checksum != currentIncl.Checksum {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Returns true if both GitRepositoryIncludes are equal.
|
||||
func gitRepositoryIncludeEqual(a, b sourcev1.GitRepositoryInclude) bool {
|
||||
if a.GitRepositoryRef != b.GitRepositoryRef {
|
||||
return false
|
||||
}
|
||||
if a.FromPath != b.FromPath {
|
||||
return false
|
||||
}
|
||||
if a.ToPath != b.ToPath {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -143,7 +143,6 @@ Oomb3gD/TRf/nAdVED+k81GdLzciYdUGtI71/qI47G0nMBluLRE=
|
|||
=/4e+
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
`
|
||||
emptyContentConfigChecksum = "sha256:fcbcf165908dd18a9e49f7ff27810176db8e9f63b4352213741664245224f8aa"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -685,8 +684,6 @@ func TestGitRepositoryReconciler_reconcileSource_checkoutStrategy(t *testing.T)
|
|||
Revision: "staging/" + latestRev,
|
||||
Path: randStringRunes(10),
|
||||
},
|
||||
// Checksum with all the relevant fields unset.
|
||||
ContentConfigChecksum: emptyContentConfigChecksum,
|
||||
}
|
||||
conditions.MarkTrue(obj, sourcev1.ArtifactInStorageCondition, meta.SucceededReason, "foo")
|
||||
},
|
||||
|
@ -709,8 +706,6 @@ func TestGitRepositoryReconciler_reconcileSource_checkoutStrategy(t *testing.T)
|
|||
Revision: "staging/" + latestRev,
|
||||
Path: randStringRunes(10),
|
||||
},
|
||||
// Checksum with all the relevant fields unset.
|
||||
ContentConfigChecksum: emptyContentConfigChecksum,
|
||||
}
|
||||
conditions.MarkTrue(obj, sourcev1.ArtifactInStorageCondition, meta.SucceededReason, "foo")
|
||||
},
|
||||
|
@ -835,6 +830,9 @@ func TestGitRepositoryReconciler_reconcileArtifact(t *testing.T) {
|
|||
includes: artifactSet{&sourcev1.Artifact{Revision: "main/revision"}},
|
||||
beforeFunc: func(obj *sourcev1.GitRepository) {
|
||||
obj.Spec.Interval = metav1.Duration{Duration: interval}
|
||||
obj.Spec.Include = []sourcev1.GitRepositoryInclude{
|
||||
{GitRepositoryRef: meta.LocalObjectReference{Name: "foo"}},
|
||||
}
|
||||
},
|
||||
afterFunc: func(t *WithT, obj *sourcev1.GitRepository) {
|
||||
t.Expect(obj.GetArtifact()).ToNot(BeNil())
|
||||
|
@ -850,12 +848,15 @@ func TestGitRepositoryReconciler_reconcileArtifact(t *testing.T) {
|
|||
{
|
||||
name: "Up-to-date artifact should not update status",
|
||||
dir: "testdata/git/repository",
|
||||
includes: artifactSet{&sourcev1.Artifact{Revision: "main/revision"}},
|
||||
includes: artifactSet{&sourcev1.Artifact{Revision: "main/revision", Checksum: "some-checksum"}},
|
||||
beforeFunc: func(obj *sourcev1.GitRepository) {
|
||||
obj.Spec.Interval = metav1.Duration{Duration: interval}
|
||||
obj.Spec.Include = []sourcev1.GitRepositoryInclude{
|
||||
{GitRepositoryRef: meta.LocalObjectReference{Name: "foo"}},
|
||||
}
|
||||
obj.Status.Artifact = &sourcev1.Artifact{Revision: "main/revision"}
|
||||
obj.Status.IncludedArtifacts = []*sourcev1.Artifact{{Revision: "main/revision", Checksum: "some-checksum"}}
|
||||
obj.Status.ContentConfigChecksum = "sha256:f825d11a1c5987e033d2cb36449a3b0435a6abc9b2bfdbcdcc7c49bf40e9285d"
|
||||
obj.Status.ObservedInclude = obj.Spec.Include
|
||||
},
|
||||
afterFunc: func(t *WithT, obj *sourcev1.GitRepository) {
|
||||
t.Expect(obj.Status.URL).To(BeEmpty())
|
||||
|
@ -2145,53 +2146,6 @@ func TestGitRepositoryReconciler_fetchIncludes(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGitRepositoryReconciler_calculateContentConfigChecksum(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
obj := &sourcev1.GitRepository{}
|
||||
r := &GitRepositoryReconciler{}
|
||||
|
||||
emptyChecksum := r.calculateContentConfigChecksum(obj, nil)
|
||||
g.Expect(emptyChecksum).To(Equal(emptyContentConfigChecksum))
|
||||
|
||||
// Ignore modified.
|
||||
obj.Spec.Ignore = pointer.String("some-rule")
|
||||
ignoreModChecksum := r.calculateContentConfigChecksum(obj, nil)
|
||||
g.Expect(emptyChecksum).ToNot(Equal(ignoreModChecksum))
|
||||
|
||||
// Recurse submodules modified.
|
||||
obj.Spec.RecurseSubmodules = true
|
||||
submodModChecksum := r.calculateContentConfigChecksum(obj, nil)
|
||||
g.Expect(ignoreModChecksum).ToNot(Equal(submodModChecksum))
|
||||
|
||||
// Include modified.
|
||||
obj.Spec.Include = []sourcev1.GitRepositoryInclude{
|
||||
{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo"},
|
||||
FromPath: "aaa",
|
||||
ToPath: "bbb",
|
||||
},
|
||||
}
|
||||
artifacts := &artifactSet{
|
||||
&sourcev1.Artifact{Revision: "some-revision-1", Checksum: "some-checksum-1"},
|
||||
}
|
||||
includeModChecksum := r.calculateContentConfigChecksum(obj, artifacts)
|
||||
g.Expect(submodModChecksum).ToNot(Equal(includeModChecksum))
|
||||
|
||||
// Artifact modified revision.
|
||||
artifacts = &artifactSet{
|
||||
&sourcev1.Artifact{Revision: "some-revision-2", Checksum: "some-checksum-1"},
|
||||
}
|
||||
artifactModChecksum := r.calculateContentConfigChecksum(obj, artifacts)
|
||||
g.Expect(includeModChecksum).ToNot(Equal(artifactModChecksum))
|
||||
|
||||
// Artifact modified checksum.
|
||||
artifacts = &artifactSet{
|
||||
&sourcev1.Artifact{Revision: "some-revision-2", Checksum: "some-checksum-2"},
|
||||
}
|
||||
artifactCsumModChecksum := r.calculateContentConfigChecksum(obj, artifacts)
|
||||
g.Expect(artifactModChecksum).ToNot(Equal(artifactCsumModChecksum))
|
||||
}
|
||||
|
||||
func resetChmod(path string, dirMode os.FileMode, fileMode os.FileMode) error {
|
||||
err := filepath.Walk(path,
|
||||
func(path string, info os.FileInfo, err error) error {
|
||||
|
@ -2212,3 +2166,371 @@ func resetChmod(path string, dirMode os.FileMode, fileMode os.FileMode) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestGitRepositoryIncludeEqual(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
a sourcev1.GitRepositoryInclude
|
||||
b sourcev1.GitRepositoryInclude
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "different refs",
|
||||
a: sourcev1.GitRepositoryInclude{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo"},
|
||||
},
|
||||
b: sourcev1.GitRepositoryInclude{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "bar"},
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "same refs",
|
||||
a: sourcev1.GitRepositoryInclude{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo"},
|
||||
},
|
||||
b: sourcev1.GitRepositoryInclude{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo"},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "different from paths",
|
||||
a: sourcev1.GitRepositoryInclude{FromPath: "foo"},
|
||||
b: sourcev1.GitRepositoryInclude{FromPath: "bar"},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "same from paths",
|
||||
a: sourcev1.GitRepositoryInclude{FromPath: "foo"},
|
||||
b: sourcev1.GitRepositoryInclude{FromPath: "foo"},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "different to paths",
|
||||
a: sourcev1.GitRepositoryInclude{ToPath: "foo"},
|
||||
b: sourcev1.GitRepositoryInclude{ToPath: "bar"},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "same to paths",
|
||||
a: sourcev1.GitRepositoryInclude{ToPath: "foo"},
|
||||
b: sourcev1.GitRepositoryInclude{ToPath: "foo"},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "same all",
|
||||
a: sourcev1.GitRepositoryInclude{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo-ref"},
|
||||
FromPath: "foo-path",
|
||||
ToPath: "bar-path",
|
||||
},
|
||||
b: sourcev1.GitRepositoryInclude{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo-ref"},
|
||||
FromPath: "foo-path",
|
||||
ToPath: "bar-path",
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
g.Expect(gitRepositoryIncludeEqual(tt.a, tt.b)).To(Equal(tt.want))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitContentConfigChanged(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
obj sourcev1.GitRepository
|
||||
artifacts []*sourcev1.Artifact
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "no content config",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "unobserved ignore",
|
||||
obj: sourcev1.GitRepository{
|
||||
Spec: sourcev1.GitRepositorySpec{Ignore: pointer.String("foo")},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "observed ignore",
|
||||
obj: sourcev1.GitRepository{
|
||||
Spec: sourcev1.GitRepositorySpec{Ignore: pointer.String("foo")},
|
||||
Status: sourcev1.GitRepositoryStatus{ObservedIgnore: pointer.String("foo")},
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "unobserved recurse submodules",
|
||||
obj: sourcev1.GitRepository{
|
||||
Spec: sourcev1.GitRepositorySpec{RecurseSubmodules: true},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "observed recurse submodules",
|
||||
obj: sourcev1.GitRepository{
|
||||
Spec: sourcev1.GitRepositorySpec{RecurseSubmodules: true},
|
||||
Status: sourcev1.GitRepositoryStatus{ObservedRecurseSubmodules: true},
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "unobserved include",
|
||||
obj: sourcev1.GitRepository{
|
||||
Spec: sourcev1.GitRepositorySpec{
|
||||
Include: []sourcev1.GitRepositoryInclude{
|
||||
{GitRepositoryRef: meta.LocalObjectReference{Name: "foo"}, FromPath: "bar", ToPath: "baz"},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "observed include",
|
||||
obj: sourcev1.GitRepository{
|
||||
Spec: sourcev1.GitRepositorySpec{
|
||||
Include: []sourcev1.GitRepositoryInclude{
|
||||
{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo"},
|
||||
FromPath: "bar",
|
||||
ToPath: "baz",
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: sourcev1.GitRepositoryStatus{
|
||||
ObservedInclude: []sourcev1.GitRepositoryInclude{
|
||||
{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo"},
|
||||
FromPath: "bar",
|
||||
ToPath: "baz",
|
||||
},
|
||||
},
|
||||
IncludedArtifacts: []*sourcev1.Artifact{{Revision: "aaa", Checksum: "bbb"}},
|
||||
},
|
||||
},
|
||||
artifacts: []*sourcev1.Artifact{
|
||||
{Revision: "aaa", Checksum: "bbb"},
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "observed include but different artifact revision",
|
||||
obj: sourcev1.GitRepository{
|
||||
Spec: sourcev1.GitRepositorySpec{
|
||||
Include: []sourcev1.GitRepositoryInclude{
|
||||
{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo"},
|
||||
FromPath: "bar",
|
||||
ToPath: "baz",
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: sourcev1.GitRepositoryStatus{
|
||||
ObservedInclude: []sourcev1.GitRepositoryInclude{
|
||||
{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo"},
|
||||
FromPath: "bar",
|
||||
ToPath: "baz",
|
||||
},
|
||||
},
|
||||
IncludedArtifacts: []*sourcev1.Artifact{{Revision: "aaa", Checksum: "bbb"}},
|
||||
},
|
||||
},
|
||||
artifacts: []*sourcev1.Artifact{
|
||||
{Revision: "ccc", Checksum: "bbb"},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "observed include but different artifact checksum",
|
||||
obj: sourcev1.GitRepository{
|
||||
Spec: sourcev1.GitRepositorySpec{
|
||||
Include: []sourcev1.GitRepositoryInclude{
|
||||
{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo"},
|
||||
FromPath: "bar",
|
||||
ToPath: "baz",
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: sourcev1.GitRepositoryStatus{
|
||||
ObservedInclude: []sourcev1.GitRepositoryInclude{
|
||||
{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo"},
|
||||
FromPath: "bar",
|
||||
ToPath: "baz",
|
||||
},
|
||||
},
|
||||
IncludedArtifacts: []*sourcev1.Artifact{{Revision: "aaa", Checksum: "bbb"}},
|
||||
},
|
||||
},
|
||||
artifacts: []*sourcev1.Artifact{
|
||||
{Revision: "aaa", Checksum: "ddd"},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "observed include but updated spec",
|
||||
obj: sourcev1.GitRepository{
|
||||
Spec: sourcev1.GitRepositorySpec{
|
||||
Include: []sourcev1.GitRepositoryInclude{
|
||||
{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo2"},
|
||||
FromPath: "bar",
|
||||
ToPath: "baz",
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: sourcev1.GitRepositoryStatus{
|
||||
ObservedInclude: []sourcev1.GitRepositoryInclude{
|
||||
{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo"},
|
||||
FromPath: "bar",
|
||||
ToPath: "baz",
|
||||
},
|
||||
},
|
||||
IncludedArtifacts: []*sourcev1.Artifact{{Revision: "aaa", Checksum: "bbb"}},
|
||||
},
|
||||
},
|
||||
artifacts: []*sourcev1.Artifact{
|
||||
{Revision: "aaa", Checksum: "bbb"},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "different number of include and observed include",
|
||||
obj: sourcev1.GitRepository{
|
||||
Spec: sourcev1.GitRepositorySpec{
|
||||
Include: []sourcev1.GitRepositoryInclude{
|
||||
{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo"},
|
||||
FromPath: "bar",
|
||||
ToPath: "baz",
|
||||
},
|
||||
{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo2"},
|
||||
FromPath: "bar",
|
||||
ToPath: "baz",
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: sourcev1.GitRepositoryStatus{
|
||||
IncludedArtifacts: []*sourcev1.Artifact{
|
||||
{Revision: "aaa", Checksum: "bbb"},
|
||||
{Revision: "ccc", Checksum: "ccc"},
|
||||
},
|
||||
},
|
||||
},
|
||||
artifacts: []*sourcev1.Artifact{
|
||||
{Revision: "aaa", Checksum: "bbb"},
|
||||
{Revision: "ccc", Checksum: "ddd"},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "different number of include and artifactset",
|
||||
obj: sourcev1.GitRepository{
|
||||
Spec: sourcev1.GitRepositorySpec{
|
||||
Include: []sourcev1.GitRepositoryInclude{
|
||||
{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo"},
|
||||
FromPath: "bar",
|
||||
ToPath: "baz",
|
||||
},
|
||||
{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo2"},
|
||||
FromPath: "bar",
|
||||
ToPath: "baz",
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: sourcev1.GitRepositoryStatus{
|
||||
ObservedInclude: []sourcev1.GitRepositoryInclude{
|
||||
{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo"},
|
||||
FromPath: "bar",
|
||||
ToPath: "baz",
|
||||
},
|
||||
{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo2"},
|
||||
FromPath: "bar",
|
||||
ToPath: "baz",
|
||||
},
|
||||
},
|
||||
IncludedArtifacts: []*sourcev1.Artifact{
|
||||
{Revision: "aaa", Checksum: "bbb"},
|
||||
{Revision: "ccc", Checksum: "ccc"},
|
||||
},
|
||||
},
|
||||
},
|
||||
artifacts: []*sourcev1.Artifact{
|
||||
{Revision: "aaa", Checksum: "bbb"},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "different number of include and included artifacts",
|
||||
obj: sourcev1.GitRepository{
|
||||
Spec: sourcev1.GitRepositorySpec{
|
||||
Include: []sourcev1.GitRepositoryInclude{
|
||||
{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo"},
|
||||
FromPath: "bar",
|
||||
ToPath: "baz",
|
||||
},
|
||||
{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo2"},
|
||||
FromPath: "bar",
|
||||
ToPath: "baz",
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: sourcev1.GitRepositoryStatus{
|
||||
ObservedInclude: []sourcev1.GitRepositoryInclude{
|
||||
{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo"},
|
||||
FromPath: "bar",
|
||||
ToPath: "baz",
|
||||
},
|
||||
{
|
||||
GitRepositoryRef: meta.LocalObjectReference{Name: "foo2"},
|
||||
FromPath: "bar",
|
||||
ToPath: "baz",
|
||||
},
|
||||
},
|
||||
IncludedArtifacts: []*sourcev1.Artifact{
|
||||
{Revision: "aaa", Checksum: "bbb"},
|
||||
},
|
||||
},
|
||||
},
|
||||
artifacts: []*sourcev1.Artifact{
|
||||
{Revision: "aaa", Checksum: "bbb"},
|
||||
{Revision: "ccc", Checksum: "ccc"},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
includes := artifactSet(tt.artifacts)
|
||||
g.Expect(gitContentConfigChanged(&tt.obj, &includes)).To(Equal(tt.want))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1539,7 +1539,8 @@ github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus
|
|||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#source.toolkit.fluxcd.io/v1beta2.GitRepositorySpec">GitRepositorySpec</a>)
|
||||
<a href="#source.toolkit.fluxcd.io/v1beta2.GitRepositorySpec">GitRepositorySpec</a>,
|
||||
<a href="#source.toolkit.fluxcd.io/v1beta2.GitRepositoryStatus">GitRepositoryStatus</a>)
|
||||
</p>
|
||||
<p>GitRepositoryInclude specifies a local reference to a GitRepository which
|
||||
Artifact (sub-)contents must be included, and where they should be placed.</p>
|
||||
|
@ -1969,6 +1970,49 @@ observed in .status.observedGeneration version of the object. This can
|
|||
be used to determine if the content of the included repository has
|
||||
changed.
|
||||
It has the format of <code><algo>:<checksum></code>, for example: <code>sha256:<checksum></code>.</p>
|
||||
<p>Deprecated: Replaced with explicit fields for observed artifact content
|
||||
config in the status.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>observedIgnore</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>ObservedIgnore is the observed exclusion patterns used for constructing
|
||||
the source artifact.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>observedRecurseSubmodules</code><br>
|
||||
<em>
|
||||
bool
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>ObservedRecurseSubmodules is the observed resource submodules
|
||||
configuration used to produce the current Artifact.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>observedInclude</code><br>
|
||||
<em>
|
||||
<a href="#source.toolkit.fluxcd.io/v1beta2.GitRepositoryInclude">
|
||||
[]GitRepositoryInclude
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>ObservedInclude is the observed list of GitRepository resources used to
|
||||
to produce the current Artifact.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
|
@ -854,6 +854,79 @@ configurations of the GitRepository that indicate a change in source and
|
|||
records it in `.status.contentConfigChecksum`. This field is used to determine
|
||||
if the source artifact needs to be rebuilt.
|
||||
|
||||
**Deprecation Note:** `contentConfigChecksum` is no longer used and will be
|
||||
removed in the next API version. The individual components used for generating
|
||||
content configuration checksum now have explicit fields in the status. This
|
||||
makes the observations used by the controller for making artifact rebuild
|
||||
decisions more transparent and easier to debug.
|
||||
|
||||
### Observed Ignore
|
||||
|
||||
The source-controller reports an observed ignore in the GitRepository's
|
||||
`.status.observedIgnore`. The observed ignore is the latest `.spec.ignore` value
|
||||
which resulted in a [ready state](#ready-gitrepository), or stalled due to error
|
||||
it can not recover from without human intervention.
|
||||
The value is the same as the [ignore in spec](#ignore).
|
||||
It indicates the ignore rules used in building the current artifact in storage.
|
||||
It is also used by the controller to determine if an artifact needs to be
|
||||
rebuilt.
|
||||
|
||||
Example:
|
||||
```yaml
|
||||
status:
|
||||
...
|
||||
observedIgnore: |
|
||||
cue
|
||||
pkg
|
||||
...
|
||||
```
|
||||
|
||||
### Observed Recurse Submodules
|
||||
|
||||
The source-controller reports an observed recurse submodule in the
|
||||
GitRepository's `.status.observedRecurseSubmodules`. The observed recurse
|
||||
submodules is the latest `.spec.recurseSubmodules` value which resulted in a
|
||||
[ready state](#ready-gitrepository), or stalled due to error it can not recover
|
||||
from without human intervention. The value is the same as the
|
||||
[recurse submodules in spec](#recurse-submodules). It indicates the recurse
|
||||
submodules configuration used in building the current artifact in storage. It is
|
||||
also used by the controller to determine if an artifact needs to be rebuilt.
|
||||
|
||||
Example:
|
||||
```yaml
|
||||
status:
|
||||
...
|
||||
observedRecurseSubmodules: true
|
||||
...
|
||||
```
|
||||
|
||||
### Observed Include
|
||||
|
||||
The source-controller reports observed include in the GitRepository's
|
||||
`.status.observedInclude`. The observed include is the latest
|
||||
`.spec.recurseSubmodules` value which resulted in a
|
||||
[ready state](#ready-gitrepository), or stalled due to error it can not recover
|
||||
from without human intervention. The value is the same as the
|
||||
[include in spec](#include). It indicates the include configuration used in
|
||||
building the current artifact in storage. It is also used by the controller to
|
||||
determine if an artifact needs to be rebuilt.
|
||||
|
||||
Example:
|
||||
```yaml
|
||||
status:
|
||||
...
|
||||
observedInclude:
|
||||
- fromPath: deploy/webapp
|
||||
repository:
|
||||
name: repo1
|
||||
toPath: foo
|
||||
- fromPath: deploy/secure
|
||||
repository:
|
||||
name: repo2
|
||||
toPath: bar
|
||||
...
|
||||
```
|
||||
|
||||
### Observed Generation
|
||||
|
||||
The source-controller reports an [observed generation][typical-status-properties]
|
||||
|
|
Loading…
Reference in New Issue