diff --git a/cmd/flux/testdata/trace/deployment-hr-ocirepo.golden b/cmd/flux/testdata/trace/deployment-hr-ocirepo.golden new file mode 100644 index 00000000..34b03f37 --- /dev/null +++ b/cmd/flux/testdata/trace/deployment-hr-ocirepo.golden @@ -0,0 +1,18 @@ + +Object: deployment/podinfo +Namespace: {{ .ns }} +Status: Managed by Flux +--- +HelmRelease: podinfo +Namespace: {{ .ns }} +Revision: 6.3.5 +Status: Last reconciled at {{ .helmReleaseLastReconcile }} +Message: Release reconciliation succeeded +--- +OCIRepository: podinfo-charts +Namespace: {{ .fluxns }} +URL: oci://ghcr.io/stefanprodan/charts/podinfo +Tag: 6.8.0 +Revision: sha256:dbdb109711ffb3be77504d2670dbe13c24dd63d8d7f1fb489d350e5bfe930dd3 +Status: Last reconciled at {{ .ociRepositoryLastReconcile }} +Message: stored artifact for digest 'sha256:dbdb109711ffb3be77504d2670dbe13c24dd63d8d7f1fb489d350e5bfe930dd3' diff --git a/cmd/flux/testdata/trace/deployment-hr-ocirepo.yaml b/cmd/flux/testdata/trace/deployment-hr-ocirepo.yaml new file mode 100644 index 00000000..29f0c1b5 --- /dev/null +++ b/cmd/flux/testdata/trace/deployment-hr-ocirepo.yaml @@ -0,0 +1,86 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .fluxns }} +--- +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .ns }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/name: podinfo + app.kubernetes.io/managed-by: Helm + helm.toolkit.fluxcd.io/name: podinfo + helm.toolkit.fluxcd.io/namespace: {{ .ns }} + name: podinfo + namespace: {{ .ns }} +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: podinfo + template: + metadata: + labels: + app.kubernetes.io/name: podinfo + spec: + containers: + - name: hello + command: [ "echo hello world" ] + image: busybox +--- +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: podinfo + namespace: {{ .ns }} +spec: + chartRef: + kind: OCIRepository + name: podinfo-charts + namespace: {{ .fluxns }} + interval: 5m +status: + conditions: + - lastTransitionTime: "2021-07-16T15:42:20Z" + message: Release reconciliation succeeded + reason: ReconciliationSucceeded + status: "True" + type: Ready + lastAttemptedRevision: 6.3.5 +--- +apiVersion: source.toolkit.fluxcd.io/v1beta2 +kind: OCIRepository +metadata: + labels: + kustomize.toolkit.fluxcd.io/name: flux-system + kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }} + name: podinfo-charts + namespace: {{ .fluxns }} +spec: + interval: 10m0s + provider: generic + ref: + tag: 6.8.0 + timeout: 60s + url: oci://ghcr.io/stefanprodan/charts/podinfo +status: + artifact: + lastUpdateTime: "2022-08-10T10:07:59Z" + metadata: + org.opencontainers.image.revision: 6.1.6@sha1:450796ddb2ab6724ee1cc32a4be56da032d1cca0 + org.opencontainers.image.source: https://github.com/stefanprodan/podinfo.git + path: "example" + revision: sha256:dbdb109711ffb3be77504d2670dbe13c24dd63d8d7f1fb489d350e5bfe930dd3 + url: "example" + conditions: + - lastTransitionTime: "2021-07-20T00:48:16Z" + message: "stored artifact for digest 'sha256:dbdb109711ffb3be77504d2670dbe13c24dd63d8d7f1fb489d350e5bfe930dd3'" + reason: Succeed + status: "True" + type: Ready diff --git a/cmd/flux/trace.go b/cmd/flux/trace.go index a62e9a52..9946daae 100644 --- a/cmd/flux/trace.go +++ b/cmd/flux/trace.go @@ -401,38 +401,65 @@ func traceHelm(ctx context.Context, kubeClient client.Client, hrName types.Names var hrGitRepository *sourcev1.GitRepository var hrGitRepositoryReady *metav1.Condition - if hr.Spec.Chart.Spec.SourceRef.Kind == sourcev1.GitRepositoryKind { - hrGitRepository = &sourcev1.GitRepository{} - sourceNamespace := hr.Namespace - if hr.Spec.Chart.Spec.SourceRef.Namespace != "" { - sourceNamespace = hr.Spec.Chart.Spec.SourceRef.Namespace - } - err = kubeClient.Get(ctx, types.NamespacedName{ - Namespace: sourceNamespace, - Name: hr.Spec.Chart.Spec.SourceRef.Name, - }, hrGitRepository) - if err != nil { - return "", fmt.Errorf("failed to find GitRepository: %w", err) - } - hrGitRepositoryReady = meta.FindStatusCondition(hrGitRepository.Status.Conditions, fluxmeta.ReadyCondition) - } - var hrHelmRepository *sourcev1.HelmRepository var hrHelmRepositoryReady *metav1.Condition - if hr.Spec.Chart.Spec.SourceRef.Kind == sourcev1.HelmRepositoryKind { - hrHelmRepository = &sourcev1.HelmRepository{} - sourceNamespace := hr.Namespace - if hr.Spec.Chart.Spec.SourceRef.Namespace != "" { - sourceNamespace = hr.Spec.Chart.Spec.SourceRef.Namespace + var hrOCIRepository *sourcev1b2.OCIRepository + var hrOCIRepositoryReady *metav1.Condition + if hr.Spec.Chart == nil { + if hr.Spec.ChartRef != nil { + switch hr.Spec.ChartRef.Kind { + case sourcev1b2.OCIRepositoryKind: + hrOCIRepository = &sourcev1b2.OCIRepository{} + sourceNamespace := hr.Namespace + if hr.Spec.ChartRef.Namespace != "" { + sourceNamespace = hr.Spec.ChartRef.Namespace + } + err = kubeClient.Get(ctx, types.NamespacedName{ + Namespace: sourceNamespace, + Name: hr.Spec.ChartRef.Name, + }, hrOCIRepository) + if err != nil { + return "", fmt.Errorf("failed to find OCIRepository: %w", err) + } + hrOCIRepositoryReady = meta.FindStatusCondition(hrOCIRepository.Status.Conditions, fluxmeta.ReadyCondition) + } + kubeClient.Get(ctx, types.NamespacedName{ + Namespace: hr.Spec.ChartRef.Namespace, + Name: hr.Spec.ChartRef.Name, + }, hrOCIRepository) } - err = kubeClient.Get(ctx, types.NamespacedName{ - Namespace: sourceNamespace, - Name: hr.Spec.Chart.Spec.SourceRef.Name, - }, hrHelmRepository) - if err != nil { - return "", fmt.Errorf("failed to find HelmRepository: %w", err) + } else { + if hr.Spec.Chart.Spec.SourceRef.Kind == sourcev1.GitRepositoryKind { + hrGitRepository = &sourcev1.GitRepository{} + sourceNamespace := hr.Namespace + if hr.Spec.Chart.Spec.SourceRef.Namespace != "" { + sourceNamespace = hr.Spec.Chart.Spec.SourceRef.Namespace + } + err = kubeClient.Get(ctx, types.NamespacedName{ + Namespace: sourceNamespace, + Name: hr.Spec.Chart.Spec.SourceRef.Name, + }, hrGitRepository) + if err != nil { + return "", fmt.Errorf("failed to find GitRepository: %w", err) + } + hrGitRepositoryReady = meta.FindStatusCondition(hrGitRepository.Status.Conditions, fluxmeta.ReadyCondition) + } + + if hr.Spec.Chart.Spec.SourceRef.Kind == sourcev1.HelmRepositoryKind { + hrHelmRepository = &sourcev1.HelmRepository{} + sourceNamespace := hr.Namespace + if hr.Spec.Chart.Spec.SourceRef.Namespace != "" { + sourceNamespace = hr.Spec.Chart.Spec.SourceRef.Namespace + } + err = kubeClient.Get(ctx, types.NamespacedName{ + Namespace: sourceNamespace, + Name: hr.Spec.Chart.Spec.SourceRef.Name, + }, hrHelmRepository) + if err != nil { + return "", fmt.Errorf("failed to find HelmRepository: %w", err) + } + hrHelmRepositoryReady = meta.FindStatusCondition(hrHelmRepository.Status.Conditions, fluxmeta.ReadyCondition) } - hrHelmRepositoryReady = meta.FindStatusCondition(hrHelmRepository.Status.Conditions, fluxmeta.ReadyCondition) } var traceTmpl = ` @@ -515,6 +542,34 @@ Message: {{.GitRepositoryReady.Message}} 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}} +{{- end }} +{{- if .OCIRepositoryReady }} +{{- if eq .OCIRepositoryReady.Status "False" }} +Status: Last reconciliation failed at {{.OCIRepositoryReady.LastTransitionTime}} +{{- else }} +Status: Last reconciled at {{.OCIRepositoryReady.LastTransitionTime}} +{{- end }} +Message: {{.OCIRepositoryReady.Message}} +{{- else }} +Status: Unknown +{{- end }} +{{- end }} ` traceResult := struct { @@ -528,6 +583,9 @@ Status: Unknown GitRepositoryReady *metav1.Condition HelmRepository *sourcev1.HelmRepository HelmRepositoryReady *metav1.Condition + OCIRepository *sourcev1b2.OCIRepository + OCIRepositoryReady *metav1.Condition + Annotations map[string]string }{ ObjectName: obj.GetKind() + "/" + obj.GetName(), ObjectNamespace: obj.GetNamespace(), @@ -539,6 +597,8 @@ Status: Unknown GitRepositoryReady: hrGitRepositoryReady, HelmRepository: hrHelmRepository, HelmRepositoryReady: hrHelmRepositoryReady, + OCIRepository: hrOCIRepository, + OCIRepositoryReady: hrOCIRepositoryReady, } t, err := template.New("tmpl").Parse(traceTmpl) diff --git a/cmd/flux/trace_test.go b/cmd/flux/trace_test.go index 0f11f6da..c3fca3b5 100644 --- a/cmd/flux/trace_test.go +++ b/cmd/flux/trace_test.go @@ -85,6 +85,18 @@ func TestTrace(t *testing.T) { "ociRepositoryLastReconcile": toLocalTime(t, "2021-07-20T00:48:16Z"), }, }, + { + "Deployment from HelmRelease from OCI registry", + "trace podinfo --kind deployment --api-version=apps/v1", + "testdata/trace/deployment-hr-ocirepo.yaml", + "testdata/trace/deployment-hr-ocirepo.golden", + map[string]string{ + "ns": allocateNamespace("podinfo"), + "fluxns": allocateNamespace("flux-system"), + "helmReleaseLastReconcile": toLocalTime(t, "2021-07-16T15:42:20Z"), + "ociRepositoryLastReconcile": toLocalTime(t, "2021-07-20T00:48:16Z"), + }, + }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) {