Fix flux trace for HRs from OCIRepositorys
Before:
```
$ flux -n default trace pod default-podinfo-585856f49c-4jl4m
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x2 addr=0x40 pc=0x10618da70]
goroutine 1 [running]:
main.traceHelm({0x106dd7b28, 0x14000201490}, {0x12f34c0d8, 0x14000783100}, {{0x1400071e130?, 0x1061e7795?}, {0x1400071e109?, 0x1000d9c84?}}, 0x140006a6030)
/home/runner/work/flux2/flux2/cmd/flux/trace.go:404 +0x2f0
main.traceObject({0x106dd7b28, 0x14000201490}, {0x12f34c0d8, 0x14000783100}, 0x140006a6030)
/home/runner/work/flux2/flux2/cmd/flux/trace.go:134 +0x11c
main.traceObjects({0x106dd7b28, 0x14000201490}, {0x12f34c0d8, 0x14000783100}, {0x140006a6040, 0x1, 0x0?})
/home/runner/work/flux2/flux2/cmd/flux/trace.go:112 +0x74
main.traceCmdRun(0x14000592800?, {0x140003aea80, 0x2, 0x4})
/home/runner/work/flux2/flux2/cmd/flux/trace.go:107 +0x180
github.com/spf13/cobra.(*Command).execute(0x108341980, {0x140003aea40, 0x4, 0x4})
/home/runner/go/pkg/mod/github.com/spf13/cobra@v1.8.1/command.go:985 +0x834
github.com/spf13/cobra.(*Command).ExecuteC(0x108329280)
/home/runner/go/pkg/mod/github.com/spf13/cobra@v1.8.1/command.go:1117 +0x344
github.com/spf13/cobra.(*Command).Execute(...)
/home/runner/go/pkg/mod/github.com/spf13/cobra@v1.8.1/command.go:1041
main.main()
/home/runner/work/flux2/flux2/cmd/flux/main.go:189 +0x78
```
After:
```
$ ~/dev/flux/flux2/bin/flux -n default trace pod default-podinfo-585856f49c-4jl4m
Object: Pod/default-podinfo-585856f49c-4jl4m
Namespace: default
Status: Managed by Flux
---
HelmRelease: podinfo
Namespace: flux-system
Target: default
Revision: 6.8.0+2360bdf32ddc
Status: Last reconciled at 2025-05-14 16:10:37 +0200 CEST
Message: Helm install succeeded for release default/default-podinfo.v1 with chart podinfo@6.8.0+2360bdf32ddc
---
OCIRepository: podinfo
Namespace: flux-system
URL: oci://ghcr.io/stefanprodan/charts/podinfo
Tag: 6.8.0
Revision: 6.8.0@sha256:2360bdf32ddc50c05f8e128118173343b0a012a338daf145b16e0da9c80081a4
Status: Last reconciled at 2025-05-14 16:09:17 +0200 CEST
Message: stored artifact for digest '6.8.0@sha256:2360bdf32ddc50c05f8e128118173343b0a012a338daf145b16e0da9c80081a4'
```
Signed-off-by: Max Jonas Werner <max@coppersoft.com>
This commit is contained in:
18
cmd/flux/testdata/trace/deployment-hr-ocirepo.golden
vendored
Normal file
18
cmd/flux/testdata/trace/deployment-hr-ocirepo.golden
vendored
Normal file
@@ -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'
|
||||
86
cmd/flux/testdata/trace/deployment-hr-ocirepo.yaml
vendored
Normal file
86
cmd/flux/testdata/trace/deployment-hr-ocirepo.yaml
vendored
Normal file
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user