Skip to content

Commit

Permalink
Add support for creating HR with .spec.ChartRef
Browse files Browse the repository at this point in the history
Signed-off-by: Soule BA <bah.soule@gmail.com>
  • Loading branch information
souleb committed May 10, 2024
1 parent 73242e2 commit ca7b48d
Show file tree
Hide file tree
Showing 10 changed files with 224 additions and 39 deletions.
63 changes: 42 additions & 21 deletions cmd/flux/create_helmrelease.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,17 @@ var createHelmReleaseCmd = &cobra.Command{
--source=HelmRepository/podinfo \
--chart=podinfo \
--values=./values.yaml \
--export > podinfo-release.yaml`,
--export > podinfo-release.yaml
# Create a HelmRelease using a chart from a HelmChart resource
flux create hr podinfo \
--namespace=default \
--chart-ref=HelmChart/podinfo.flux-system \
# Create a HelmRelease using a chart from an OCIRepository resource
flux create hr podinfo \
--namespace=default \
--chart-ref=OCIRepository/podinfo.flux-system`,
RunE: createHelmReleaseCmdRun,
}

Expand All @@ -114,6 +124,7 @@ type helmReleaseFlags struct {
dependsOn []string
chart string
chartVersion string
chartRef string
targetNamespace string
createNamespace bool
valuesFiles []string
Expand Down Expand Up @@ -144,14 +155,15 @@ func init() {
createHelmReleaseCmd.Flags().StringSliceVar(&helmReleaseArgs.valuesFrom, "values-from", nil, "a Kubernetes object reference that contains the values.yaml data key in the format '<kind>/<name>', where kind must be one of: (Secret,ConfigMap)")
createHelmReleaseCmd.Flags().Var(&helmReleaseArgs.crds, "crds", helmReleaseArgs.crds.Description())
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.kubeConfigSecretRef, "kubeconfig-secret-ref", "", "the name of the Kubernetes Secret that contains a key with the kubeconfig file for connecting to a remote cluster")
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.chartRef, "chart-ref", "", "the name of the HelmChart resource to use as source for the HelmRelease")
createCmd.AddCommand(createHelmReleaseCmd)
}

func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
name := args[0]

if helmReleaseArgs.chart == "" {
return fmt.Errorf("chart name or path is required")
if helmReleaseArgs.chart == "" && helmReleaseArgs.chartRef == "" {
return fmt.Errorf("chart or chart-ref is required")
}

sourceLabels, err := parseLabels()
Expand Down Expand Up @@ -181,21 +193,36 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
Duration: createArgs.interval,
},
TargetNamespace: helmReleaseArgs.targetNamespace,
Suspend: false,
},
}

Chart: helmv2.HelmChartTemplate{
Spec: helmv2.HelmChartTemplateSpec{
Chart: helmReleaseArgs.chart,
Version: helmReleaseArgs.chartVersion,
SourceRef: helmv2.CrossNamespaceObjectReference{
Kind: helmReleaseArgs.source.Kind,
Name: helmReleaseArgs.source.Name,
Namespace: helmReleaseArgs.source.Namespace,
},
ReconcileStrategy: helmReleaseArgs.reconcileStrategy,
switch {
case helmReleaseArgs.chart != "":
helmRelease.Spec.Chart = &helmv2.HelmChartTemplate{
Spec: helmv2.HelmChartTemplateSpec{
Chart: helmReleaseArgs.chart,
Version: helmReleaseArgs.chartVersion,
SourceRef: helmv2.CrossNamespaceObjectReference{
Kind: helmReleaseArgs.source.Kind,
Name: helmReleaseArgs.source.Name,
Namespace: helmReleaseArgs.source.Namespace,
},
ReconcileStrategy: helmReleaseArgs.reconcileStrategy,
},
Suspend: false,
},
}
if helmReleaseArgs.chartInterval != 0 {
helmRelease.Spec.Chart.Spec.Interval = &metav1.Duration{
Duration: helmReleaseArgs.chartInterval,
}
}
case helmReleaseArgs.chartRef != "":
kind, name, ns := utils.ParseObjectKindNameNamespace(helmReleaseArgs.chartRef)
helmRelease.Spec.ChartRef = &helmv2.CrossNamespaceSourceReference{
Kind: kind,
Name: name,
Namespace: ns,
}
}

if helmReleaseArgs.kubeConfigSecretRef != "" {
Expand All @@ -206,12 +233,6 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
}
}

if helmReleaseArgs.chartInterval != 0 {
helmRelease.Spec.Chart.Spec.Interval = &metav1.Duration{
Duration: helmReleaseArgs.chartInterval,
}
}

if helmReleaseArgs.createNamespace {
if helmRelease.Spec.Install == nil {
helmRelease.Spec.Install = &helmv2.Install{}
Expand Down
81 changes: 81 additions & 0 deletions cmd/flux/create_helmrelease_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//go:build unit
// +build unit

/*
Copyright 2024 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import "testing"

func TestCreateHelmRelease(t *testing.T) {
tmpl := map[string]string{
"fluxns": allocateNamespace("flux-system"),
}
setupHRSource(t, tmpl)

tests := []struct {
name string
args string
assert assertFunc
}{
{
name: "missing name",
args: "create helmrelease --export",
assert: assertError("name is required"),
},
{
name: "missing chart template and chartRef",
args: "create helmrelease podinfo --export",
assert: assertError("chart or chart-ref is required"),
},
{
name: "unknown source kind",
args: "create helmrelease podinfo --source foobar/podinfo --chart podinfo --export",
assert: assertError(`invalid argument "foobar/podinfo" for "--source" flag: source kind 'foobar' is not supported, must be one of: HelmRepository, GitRepository, Bucket`),
},
{
name: "basic helmrelease",
args: "create helmrelease podinfo --source Helmrepository/podinfo --chart podinfo --export",
assert: assertGoldenTemplateFile("testdata/create_hr/basic.yaml", tmpl),
},
{
name: "chart with OCIRepository source",
args: "create helmrelease podinfo --chart-ref OCIRepository/podinfo --export",
assert: assertGoldenTemplateFile("testdata/create_hr/or_basic.yaml", tmpl),
},
{
name: "chart with HelmChart source",
args: "create helmrelease podinfo --chart-ref HelmChart/podinfo --export",
assert: assertGoldenTemplateFile("testdata/create_hr/hc_basic.yaml", tmpl),
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := cmdTestCase{
args: tt.args + " -n " + tmpl["fluxns"],
assert: tt.assert,
}
cmd.runTestCmd(t)
})
}
}

func setupHRSource(t *testing.T, tmpl map[string]string) {
t.Helper()
testEnv.CreateObjectFile("./testdata/create_hr/setup-source.yaml", tmpl, t)
}
30 changes: 19 additions & 11 deletions cmd/flux/reconcile_helmrelease.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (

helmv2 "github.com/fluxcd/helm-controller/api/v2"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1b2 "github.com/fluxcd/source-controller/api/v1beta2"
)

var reconcileHrCmd = &cobra.Command{
Expand Down Expand Up @@ -68,23 +69,30 @@ func (obj helmReleaseAdapter) reconcileSource() bool {
}

func (obj helmReleaseAdapter) getSource() (reconcileSource, types.NamespacedName) {
cmd := reconcileWithSourceCommand{
apiType: helmChartType,
object: helmChartAdapter{&sourcev1.HelmChart{}},
force: true,
}

var (
name string
ns string
ns string
cmd reconcileCommand
)
switch {
case obj.Spec.Chart != &helmv2.HelmChart{}:
case obj.Spec.ChartRef != nil:
name, ns = obj.Spec.ChartRef.Name, obj.Spec.ChartRef.Namespace
cmd = reconcileCommand{
apiType: ociRepositoryType,
object: ociRepositoryAdapter{&sourcev1b2.OCIRepository{}},
}
if obj.Spec.ChartRef.Kind == sourcev1.HelmChartKind {
cmd.apiType = helmChartType
cmd.object = helmChartAdapter{&sourcev1.HelmChart{}}
}
default:
// default case assumes the HelmRelease is using a HelmChartTemplate
ns = obj.Spec.Chart.Spec.SourceRef.Namespace
name = fmt.Sprintf("%s-%s", obj.Namespace, obj.Name)
case obj.Spec.ChartRef != nil:
ns = obj.Spec.ChartRef.Namespace
name = obj.Spec.ChartRef.Name
cmd = reconcileCommand{
apiType: helmChartType,
object: helmChartAdapter{&sourcev1.HelmChart{}},
}
}

if ns == "" {
Expand Down
15 changes: 15 additions & 0 deletions cmd/flux/testdata/create_hr/basic.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: podinfo
namespace: {{ .fluxns }}
spec:
chart:
spec:
chart: podinfo
reconcileStrategy: ChartVersion
sourceRef:
kind: HelmRepository
name: podinfo
interval: 0s
11 changes: 11 additions & 0 deletions cmd/flux/testdata/create_hr/hc_basic.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: podinfo
namespace: {{ .fluxns }}
spec:
chartRef:
kind: HelmChart
name: podinfo
interval: 0s
11 changes: 11 additions & 0 deletions cmd/flux/testdata/create_hr/or_basic.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: podinfo
namespace: {{ .fluxns }}
spec:
chartRef:
kind: OCIRepository
name: podinfo
interval: 0s
40 changes: 40 additions & 0 deletions cmd/flux/testdata/create_hr/setup-source.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
apiVersion: v1
kind: Namespace
metadata:
name: {{ .fluxns }}
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: podinfo
namespace: {{ .fluxns }}
spec:
interval: 1m0s
provider: generic
type: oci
url: oci://ghcr.io/stefanprodan/charts
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmChart
metadata:
name: podinfo
namespace: {{ .fluxns }}
spec:
interval: 1m0s
chart: podinfo
sourceRef:
kind: HelmRepository
name: podinfo
---
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: OCIRepository
metadata:
name: podinfo
namespace: flux-system
spec:
interval: 10m
url: oci://ghcr.io/stefanprodan/manifests/podinfo
ref:
tag: latest
---
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
► annotating GitRepository thrfg in {{ .ns }} namespace
✔ GitRepository annotated
◎ waiting for GitRepository reconciliation
✔ fetched revision 6.3.5@sha1:67e2c98a60dc92283531412a9e604dd4bae005a9
► annotating HelmChart {{ .ns }}-thrfg in {{ .ns }} namespace
✔ HelmChart annotated
◎ waiting for HelmChart reconciliation
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ require (
github.com/distribution/distribution/v3 v3.0.0-alpha.1
github.com/fluxcd/cli-utils v0.36.0-flux.7
github.com/fluxcd/go-git-providers v0.20.1
github.com/fluxcd/helm-controller/api v1.0.0
github.com/fluxcd/helm-controller/api v1.0.1
github.com/fluxcd/image-automation-controller/api v0.38.0
github.com/fluxcd/image-reflector-controller/api v0.32.0
github.com/fluxcd/kustomize-controller/api v1.3.0
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,10 @@ github.com/fluxcd/gitkit v0.6.0 h1:iNg5LTx6ePo+Pl0ZwqHTAkhbUHxGVSY3YCxCdw7VIFg=
github.com/fluxcd/gitkit v0.6.0/go.mod h1:svOHuKi0fO9HoawdK4HfHAJJseZDHHjk7I3ihnCIqNo=
github.com/fluxcd/go-git-providers v0.20.1 h1:ER10UUup3y/lAyANvMjgaYI/9av/upetF2PTi3aCqvs=
github.com/fluxcd/go-git-providers v0.20.1/go.mod h1:FhBThaf3/kyKCBg4v0mKcQqQB2rPDv/L8baH3+nFtHc=
github.com/fluxcd/helm-controller/api v1.0.0 h1:sn7bNtqBPwn2Y5H4UBBUHFiE2G0tSLfsENVaOipNXpo=
github.com/fluxcd/helm-controller/api v1.0.0/go.mod h1:/6AD5a2qjo/ttxVM8GR33syLZwqigta60DCLdy8GrME=
github.com/fluxcd/helm-controller/api v1.0.1-0.20240510105801-bc1219fbc19d h1:quR3V3sIPkzM0FLnyoo3e8rOs3OEABVwK0At7WXG+y4=
github.com/fluxcd/helm-controller/api v1.0.1-0.20240510105801-bc1219fbc19d/go.mod h1:/6AD5a2qjo/ttxVM8GR33syLZwqigta60DCLdy8GrME=
github.com/fluxcd/helm-controller/api v1.0.1 h1:Gn9qEVuif6D5+gHmVwTEZkR4+nmLOcOhKx4Sw2gL2EA=
github.com/fluxcd/helm-controller/api v1.0.1/go.mod h1:/6AD5a2qjo/ttxVM8GR33syLZwqigta60DCLdy8GrME=
github.com/fluxcd/image-automation-controller/api v0.38.0 h1:+phX67uf0INGDC4sghsPPNUiE8taVp7AcWgJH8LkiUk=
github.com/fluxcd/image-automation-controller/api v0.38.0/go.mod h1:FfWWRxG03514+MUNJ+uN6fXzjwdbqsJqCggukIZ1tx8=
github.com/fluxcd/image-reflector-controller/api v0.32.0 h1:mb/v9JzRHcjLcnGqmgsq0+yCcoOyae/TrOWae9T87PE=
Expand Down

0 comments on commit ca7b48d

Please sign in to comment.