Make `flux trace` work with OCIRepository

* Added support for OCIRepositories to `flux trace`
* Changed indentation to compensate new, longer field name "Source
  Revision"
* Added unit tests for the new output

closes #2970

Signed-off-by: Max Jonas Werner <max@e13.dev>
pull/2971/head
Max Jonas Werner 2 years ago
parent 75a879c770
commit b810aea6cc
No known key found for this signature in database
GPG Key ID: EB525E0F02B52140

@ -0,0 +1,21 @@
Object: HelmRelease/podinfo
Namespace: {{ .ns }}
Status: Managed by Flux
---
Kustomization: infrastructure
Namespace: {{ .fluxns }}
Path: ./infrastructure
Revision: main/696f056df216eea4f9401adbee0ff744d4df390f
Status: Last reconciled at {{ .kustomizationLastReconcile }}
Message: Applied revision: main/696f056df216eea4f9401adbee0ff744d4df390f
---
OCIRepository: flux-system
Namespace: {{ .fluxns }}
URL: oci://ghcr.io/example/repo
Tag: 1.2.3
Revision: dbdb109711ffb3be77504d2670dbe13c24dd63d8d7f1fb489d350e5bfe930dd3
Origin Revision: 6.1.6/450796ddb2ab6724ee1cc32a4be56da032d1cca0
Origin Source: https://github.com/stefanprodan/podinfo.git
Status: Last reconciled at {{ .ociRepositoryLastReconcile }}
Message: stored artifact for digest 'dbdb109711ffb3be77504d2670dbe13c24dd63d8d7f1fb489d350e5bfe930dd3'

@ -0,0 +1,92 @@
---
apiVersion: v1
kind: Namespace
metadata:
name: {{ .fluxns }}
---
apiVersion: v1
kind: Namespace
metadata:
name: {{ .ns }}
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
labels:
kustomize.toolkit.fluxcd.io/name: infrastructure
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
name: podinfo
namespace: {{ .ns }}
spec:
chart:
spec:
chart: podinfo
sourceRef:
kind: HelmRepository
name: podinfo
namespace: {{ .fluxns }}
interval: 5m
status:
conditions:
- lastTransitionTime: "2021-07-16T15:42:20Z"
message: Release reconciliation succeeded
reason: ReconciliationSucceeded
status: "True"
type: Ready
helmChart: {{ .fluxns }}/podinfo-podinfo
lastAppliedRevision: 6.0.0
lastAttemptedRevision: 6.0.0
lastAttemptedValuesChecksum: c31db75d05b7515eba2eef47bd71038c74b2e531
---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: infrastructure
namespace: {{ .fluxns }}
spec:
path: ./infrastructure
sourceRef:
kind: OCIRepository
name: flux-system
validation: client
interval: 5m
prune: false
status:
conditions:
- lastTransitionTime: "2021-08-01T04:52:56Z"
message: 'Applied revision: main/696f056df216eea4f9401adbee0ff744d4df390f'
reason: ReconciliationSucceeded
status: "True"
type: Ready
lastAppliedRevision: main/696f056df216eea4f9401adbee0ff744d4df390f
---
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: OCIRepository
metadata:
labels:
kustomize.toolkit.fluxcd.io/name: flux-system
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
name: flux-system
namespace: {{ .fluxns }}
spec:
interval: 10m0s
provider: generic
ref:
tag: 1.2.3
timeout: 60s
url: oci://ghcr.io/example/repo
status:
artifact:
lastUpdateTime: "2022-08-10T10:07:59Z"
metadata:
org.opencontainers.image.revision: 6.1.6/450796ddb2ab6724ee1cc32a4be56da032d1cca0
org.opencontainers.image.source: https://github.com/stefanprodan/podinfo.git
path: "example"
revision: dbdb109711ffb3be77504d2670dbe13c24dd63d8d7f1fb489d350e5bfe930dd3
url: "example"
conditions:
- lastTransitionTime: "2021-07-20T00:48:16Z"
message: "stored artifact for digest 'dbdb109711ffb3be77504d2670dbe13c24dd63d8d7f1fb489d350e5bfe930dd3'"
reason: Succeed
status: "True"
type: Ready

@ -1,19 +1,19 @@
Object: HelmRelease/podinfo Object: HelmRelease/podinfo
Namespace: {{ .ns }} Namespace: {{ .ns }}
Status: Managed by Flux Status: Managed by Flux
--- ---
Kustomization: infrastructure Kustomization: infrastructure
Namespace: {{ .fluxns }} Namespace: {{ .fluxns }}
Path: ./infrastructure Path: ./infrastructure
Revision: main/696f056df216eea4f9401adbee0ff744d4df390f Revision: main/696f056df216eea4f9401adbee0ff744d4df390f
Status: Last reconciled at {{ .kustomizationLastReconcile }} Status: Last reconciled at {{ .kustomizationLastReconcile }}
Message: Applied revision: main/696f056df216eea4f9401adbee0ff744d4df390f Message: Applied revision: main/696f056df216eea4f9401adbee0ff744d4df390f
--- ---
GitRepository: flux-system GitRepository: flux-system
Namespace: {{ .fluxns }} Namespace: {{ .fluxns }}
URL: ssh://git@github.com/example/repo URL: ssh://git@github.com/example/repo
Branch: main Branch: main
Revision: main/696f056df216eea4f9401adbee0ff744d4df390f Revision: main/696f056df216eea4f9401adbee0ff744d4df390f
Status: Last reconciled at {{ .gitRepositoryLastReconcile }} Status: Last reconciled at {{ .gitRepositoryLastReconcile }}
Message: Fetched revision: main/696f056df216eea4f9401adbee0ff744d4df390f Message: Fetched revision: main/696f056df216eea4f9401adbee0ff744d4df390f

@ -37,6 +37,7 @@ import (
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1" helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2" kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
fluxmeta "github.com/fluxcd/pkg/apis/meta" fluxmeta "github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/oci"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
@ -219,10 +220,12 @@ func traceKustomization(ctx context.Context, kubeClient client.Client, ksName ty
} }
ksReady := meta.FindStatusCondition(ks.Status.Conditions, fluxmeta.ReadyCondition) ksReady := meta.FindStatusCondition(ks.Status.Conditions, fluxmeta.ReadyCondition)
var ksRepository *sourcev1.GitRepository var gitRepository *sourcev1.GitRepository
var ociRepository *sourcev1.OCIRepository
var ksRepositoryReady *metav1.Condition var ksRepositoryReady *metav1.Condition
if ks.Spec.SourceRef.Kind == sourcev1.GitRepositoryKind { switch ks.Spec.SourceRef.Kind {
ksRepository = &sourcev1.GitRepository{} case sourcev1.GitRepositoryKind:
gitRepository = &sourcev1.GitRepository{}
sourceNamespace := ks.Namespace sourceNamespace := ks.Namespace
if ks.Spec.SourceRef.Namespace != "" { if ks.Spec.SourceRef.Namespace != "" {
sourceNamespace = ks.Spec.SourceRef.Namespace sourceNamespace = ks.Spec.SourceRef.Namespace
@ -230,61 +233,109 @@ func traceKustomization(ctx context.Context, kubeClient client.Client, ksName ty
err = kubeClient.Get(ctx, types.NamespacedName{ err = kubeClient.Get(ctx, types.NamespacedName{
Namespace: sourceNamespace, Namespace: sourceNamespace,
Name: ks.Spec.SourceRef.Name, Name: ks.Spec.SourceRef.Name,
}, ksRepository) }, gitRepository)
if err != nil { if err != nil {
return "", fmt.Errorf("failed to find GitRepository: %w", err) return "", fmt.Errorf("failed to find GitRepository: %w", err)
} }
ksRepositoryReady = meta.FindStatusCondition(ksRepository.Status.Conditions, fluxmeta.ReadyCondition) ksRepositoryReady = meta.FindStatusCondition(gitRepository.Status.Conditions, fluxmeta.ReadyCondition)
case sourcev1.OCIRepositoryKind:
ociRepository = &sourcev1.OCIRepository{}
sourceNamespace := ks.Namespace
if ks.Spec.SourceRef.Namespace != "" {
sourceNamespace = ks.Spec.SourceRef.Namespace
}
err = kubeClient.Get(ctx, types.NamespacedName{
Namespace: sourceNamespace,
Name: ks.Spec.SourceRef.Name,
}, ociRepository)
if err != nil {
return "", fmt.Errorf("failed to find OCIRepository: %w", err)
}
ksRepositoryReady = meta.FindStatusCondition(ociRepository.Status.Conditions, fluxmeta.ReadyCondition)
} }
var traceTmpl = ` var traceTmpl = `
Object: {{.ObjectName}} Object: {{.ObjectName}}
{{- if .ObjectNamespace }} {{- if .ObjectNamespace }}
Namespace: {{.ObjectNamespace}} Namespace: {{.ObjectNamespace}}
{{- end }} {{- end }}
Status: Managed by Flux Status: Managed by Flux
{{- if .Kustomization }} {{- if .Kustomization }}
--- ---
Kustomization: {{.Kustomization.Name}} Kustomization: {{.Kustomization.Name}}
Namespace: {{.Kustomization.Namespace}} Namespace: {{.Kustomization.Namespace}}
{{- if .Kustomization.Spec.TargetNamespace }} {{- if .Kustomization.Spec.TargetNamespace }}
Target: {{.Kustomization.Spec.TargetNamespace}} Target: {{.Kustomization.Spec.TargetNamespace}}
{{- end }} {{- end }}
Path: {{.Kustomization.Spec.Path}} Path: {{.Kustomization.Spec.Path}}
Revision: {{.Kustomization.Status.LastAppliedRevision}} Revision: {{.Kustomization.Status.LastAppliedRevision}}
{{- if .KustomizationReady }} {{- if .KustomizationReady }}
Status: Last reconciled at {{.KustomizationReady.LastTransitionTime}} Status: Last reconciled at {{.KustomizationReady.LastTransitionTime}}
Message: {{.KustomizationReady.Message}} Message: {{.KustomizationReady.Message}}
{{- else }} {{- else }}
Status: Unknown Status: Unknown
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- if .GitRepository }} {{- if .GitRepository }}
--- ---
GitRepository: {{.GitRepository.Name}} GitRepository: {{.GitRepository.Name}}
Namespace: {{.GitRepository.Namespace}} Namespace: {{.GitRepository.Namespace}}
URL: {{.GitRepository.Spec.URL}} URL: {{.GitRepository.Spec.URL}}
{{- if .GitRepository.Spec.Reference }} {{- if .GitRepository.Spec.Reference }}
{{- if .GitRepository.Spec.Reference.Tag }} {{- if .GitRepository.Spec.Reference.Tag }}
Tag: {{.GitRepository.Spec.Reference.Tag}} Tag: {{.GitRepository.Spec.Reference.Tag}}
{{- else if .GitRepository.Spec.Reference.SemVer }} {{- else if .GitRepository.Spec.Reference.SemVer }}
Tag: {{.GitRepository.Spec.Reference.SemVer}} Tag: {{.GitRepository.Spec.Reference.SemVer}}
{{- else if .GitRepository.Spec.Reference.Branch }} {{- else if .GitRepository.Spec.Reference.Branch }}
Branch: {{.GitRepository.Spec.Reference.Branch}} Branch: {{.GitRepository.Spec.Reference.Branch}}
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- if .GitRepository.Status.Artifact }} {{- if .GitRepository.Status.Artifact }}
Revision: {{.GitRepository.Status.Artifact.Revision}} Revision: {{.GitRepository.Status.Artifact.Revision}}
{{- end }} {{- end }}
{{- if .GitRepositoryReady }} {{- if .RepositoryReady }}
{{- if eq .GitRepositoryReady.Status "False" }} {{- if eq .RepositoryReady.Status "False" }}
Status: Last reconciliation failed at {{.GitRepositoryReady.LastTransitionTime}} Status: Last reconciliation failed at {{.RepositoryReady.LastTransitionTime}}
{{- else }} {{- else }}
Status: Last reconciled at {{.GitRepositoryReady.LastTransitionTime}} Status: Last reconciled at {{.RepositoryReady.LastTransitionTime}}
{{- end }} {{- end }}
Message: {{.GitRepositoryReady.Message}} Message: {{.RepositoryReady.Message}}
{{- else }} {{- else }}
Status: Unknown Status: Unknown
{{- end }}
{{- end }}
{{- if .OCIRepository }}
---
OCIRepository: {{.OCIRepository.Name}}
Namespace: {{.OCIRepository.Namespace}}
URL: {{.OCIRepository.Spec.URL}}
{{- if .OCIRepository.Spec.Reference }}
{{- if .OCIRepository.Spec.Reference.Tag }}
Tag: {{.OCIRepository.Spec.Reference.Tag}}
{{- else if .OCIRepository.Spec.Reference.SemVer }}
Tag: {{.OCIRepository.Spec.Reference.SemVer}}
{{- else if .OCIRepository.Spec.Reference.Digest }}
Digest: {{.OCIRepository.Spec.Reference.Digest}}
{{- end }}
{{- end }}
{{- if .OCIRepository.Status.Artifact }}
Revision: {{.OCIRepository.Status.Artifact.Revision}}
{{- if .OCIRepository.Status.Artifact.Metadata }}
{{- $metadata := .OCIRepository.Status.Artifact.Metadata }}
{{- range $k, $v := .Annotations }}
{{ with (index $metadata $v) }}{{ $k }}{{ . }}{{ end }}
{{- end }}
{{- end }}
{{- end }}
{{- if .RepositoryReady }}
{{- if eq .RepositoryReady.Status "False" }}
Status: Last reconciliation failed at {{.RepositoryReady.LastTransitionTime}}
{{- else }}
Status: Last reconciled at {{.RepositoryReady.LastTransitionTime}}
{{- end }}
Message: {{.RepositoryReady.Message}}
{{- else }}
Status: Unknown
{{- end }} {{- end }}
{{- end }} {{- end }}
` `
@ -295,14 +346,18 @@ Status: Unknown
Kustomization *kustomizev1.Kustomization Kustomization *kustomizev1.Kustomization
KustomizationReady *metav1.Condition KustomizationReady *metav1.Condition
GitRepository *sourcev1.GitRepository GitRepository *sourcev1.GitRepository
GitRepositoryReady *metav1.Condition OCIRepository *sourcev1.OCIRepository
RepositoryReady *metav1.Condition
Annotations map[string]string
}{ }{
ObjectName: obj.GetKind() + "/" + obj.GetName(), ObjectName: obj.GetKind() + "/" + obj.GetName(),
ObjectNamespace: obj.GetNamespace(), ObjectNamespace: obj.GetNamespace(),
Kustomization: ks, Kustomization: ks,
KustomizationReady: ksReady, KustomizationReady: ksReady,
GitRepository: ksRepository, GitRepository: gitRepository,
GitRepositoryReady: ksRepositoryReady, OCIRepository: ociRepository,
RepositoryReady: ksRepositoryReady,
Annotations: map[string]string{"Origin Source: ": oci.SourceAnnotation, "Origin Revision: ": oci.RevisionAnnotation},
} }
t, err := template.New("tmpl").Parse(traceTmpl) t, err := template.New("tmpl").Parse(traceTmpl)

@ -57,6 +57,18 @@ func TestTrace(t *testing.T) {
"gitRepositoryLastReconcile": toLocalTime(t, "2021-07-20T00:48:16Z"), "gitRepositoryLastReconcile": toLocalTime(t, "2021-07-20T00:48:16Z"),
}, },
}, },
{
"HelmRelease from OCI registry",
"trace podinfo --kind HelmRelease --api-version=helm.toolkit.fluxcd.io/v2beta1",
"testdata/trace/helmrelease-oci.yaml",
"testdata/trace/helmrelease-oci.golden",
map[string]string{
"ns": allocateNamespace("podinfo"),
"fluxns": allocateNamespace("flux-system"),
"kustomizationLastReconcile": toLocalTime(t, "2021-08-01T04:52:56Z"),
"ociRepositoryLastReconcile": toLocalTime(t, "2021-07-20T00:48:16Z"),
},
},
} }
for _, tc := range cases { for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {

Loading…
Cancel
Save