Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Manage labels and annotations for a HelmChart #631

Merged
merged 2 commits into from
Mar 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions api/v2beta1/helmrelease_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,11 +219,32 @@ func (in HelmReleaseSpec) GetUninstall() Uninstall {
// generate a v1beta2.HelmChart object in the same namespace as the referenced
// v1beta2.Source.
type HelmChartTemplate struct {
// ObjectMeta holds the template for metadata like labels and annotations.
// +optional
ObjectMeta HelmChartTemplateObjectMeta `json:"metadata,omitempty"`
stefanprodan marked this conversation as resolved.
Show resolved Hide resolved

// Spec holds the template for the v1beta2.HelmChartSpec for this HelmRelease.
// +required
Spec HelmChartTemplateSpec `json:"spec"`
}

// HelmChartTemplateObjectMeta defines the template for the ObjectMeta of a
// v1beta2.HelmChart.
type HelmChartTemplateObjectMeta struct {
// Map of string keys and values that can be used to organize and categorize
// (scope and select) objects.
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
// +optional
Labels map[string]string `json:"labels,omitempty"`

// Annotations is an unstructured key value map stored with a resource that may be
// set by external tools to store and retrieve arbitrary metadata. They are not
// queryable and should be preserved when modifying objects.
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
// +optional
Annotations map[string]string `json:"annotations,omitempty"`
}

// HelmChartTemplateSpec defines the template from which the controller will
// generate a v1beta2.HelmChartSpec object.
type HelmChartTemplateSpec struct {
Expand Down
30 changes: 30 additions & 0 deletions api/v2beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions config/crd/bases/helm.toolkit.fluxcd.io_helmreleases.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,27 @@ spec:
description: Chart defines the template of the v1beta2.HelmChart that
should be created for this HelmRelease.
properties:
metadata:
description: ObjectMeta holds the template for metadata like labels
and annotations.
properties:
annotations:
additionalProperties:
type: string
description: 'Annotations is an unstructured key value map
stored with a resource that may be set by external tools
to store and retrieve arbitrary metadata. They are not queryable
and should be preserved when modifying objects. More info:
https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/'
type: object
labels:
additionalProperties:
type: string
description: 'Map of string keys and values that can be used
to organize and categorize (scope and select) objects. More
info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/'
type: object
type: object
spec:
description: Spec holds the template for the v1beta2.HelmChartSpec
for this HelmRelease.
Expand Down
65 changes: 65 additions & 0 deletions docs/api/helmrelease.md
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,20 @@ v1beta2.Source.</p>
<tbody>
<tr>
<td>
<code>metadata</code><br>
<em>
<a href="#helm.toolkit.fluxcd.io/v2beta1.HelmChartTemplateObjectMeta">
HelmChartTemplateObjectMeta
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>ObjectMeta holds the template for metadata like labels and annotations.</p>
</td>
</tr>
<tr>
<td>
<code>spec</code><br>
<em>
<a href="#helm.toolkit.fluxcd.io/v2beta1.HelmChartTemplateSpec">
Expand Down Expand Up @@ -591,6 +605,57 @@ Chart dependencies, which are not bundled in the umbrella chart artifact, are no
</table>
</div>
</div>
<h3 id="helm.toolkit.fluxcd.io/v2beta1.HelmChartTemplateObjectMeta">HelmChartTemplateObjectMeta
</h3>
<p>
(<em>Appears on:</em>
<a href="#helm.toolkit.fluxcd.io/v2beta1.HelmChartTemplate">HelmChartTemplate</a>)
</p>
<p>HelmChartTemplateObjectMeta defines the template for the ObjectMeta of a
v1beta2.HelmChart.</p>
<div class="md-typeset__scrollwrap">
<div class="md-typeset__table">
<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>labels</code><br>
<em>
map[string]string
</em>
</td>
<td>
<em>(Optional)</em>
<p>Map of string keys and values that can be used to organize and categorize
(scope and select) objects.
More info: <a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/">https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/</a></p>
</td>
</tr>
<tr>
<td>
<code>annotations</code><br>
<em>
map[string]string
</em>
</td>
<td>
<em>(Optional)</em>
<p>Annotations is an unstructured key value map stored with a resource that may be
set by external tools to store and retrieve arbitrary metadata. They are not
queryable and should be preserved when modifying objects.
More info: <a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/">https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/</a></p>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<h3 id="helm.toolkit.fluxcd.io/v2beta1.HelmChartTemplateSpec">HelmChartTemplateSpec
</h3>
<p>
Expand Down
30 changes: 27 additions & 3 deletions docs/spec/v2beta1/helmreleases.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,32 @@ type KubeConfig struct {
// generate a v1beta1.HelmChart object in the same namespace as the referenced
// v1beta1.Source.
type HelmChartTemplate struct {
// ObjectMeta holds the template for metadata like labels and annotations.
// +optional
ObjectMeta HelmChartTemplateObjectMeta `json:"metadata,omitempty"`

// Spec holds the template for the v1beta1.HelmChartSpec for this HelmRelease.
// +required
Spec HelmChartTemplateSpec `json:"spec"`
}

// HelmChartTemplateObjectMeta defines the template for the ObjectMeta of a
// v1beta2.HelmChart.
type HelmChartTemplateObjectMeta struct {
// Map of string keys and values that can be used to organize and categorize
// (scope and select) objects.
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
// +optional
Labels map[string]string `json:"labels,omitempty"`

// Annotations is an unstructured key value map stored with a resource that may be
// set by external tools to store and retrieve arbitrary metadata. They are not
// queryable and should be preserved when modifying objects.
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
// +optional
Annotations map[string]string `json:"annotations,omitempty"`
}

// HelmChartTemplateSpec defines the template from which the controller will
// generate a v1beta1.HelmChartSpec object.
type HelmChartTemplateSpec struct {
Expand Down Expand Up @@ -681,7 +702,7 @@ of the `HelmRelease`. These can be overridden respectively via `spec.targetNames

## Helm chart template

The `spec.chart.spec` values are used by the helm-controller as a template
The `spec.chart` values are used by the helm-controller as a template
to create a new `HelmChart` resource with the given spec.

The `spec.chart.spec.sourceRef` is a reference to an object managed by
Expand All @@ -699,8 +720,8 @@ The `HelmChart` is created in the same namespace as the `sourceRef`,
with a name matching the `HelmRelease` `<metadata.namespace>-<metadata.name>`.

> **Note** that on multi-tenant clusters, platform admins can disable cross-namespace references
> with the `--no-cross-namespace-refs=true` flag. When this flag is set, the helmrelease can only
> refer to sources in the same namespace as the helmrelease object.
> with the `--no-cross-namespace-refs=true` flag. When this flag is set, the HelmRelease can only
> refer to sources in the same namespace as the HelmRelease object.

The `chart.spec.chart` can either contain:

Expand All @@ -713,6 +734,9 @@ The `chart.spec.version` can be a fixed semver, or any semver range
(i.e. `>=4.0.0 <5.0.0`). It is ignored for `HelmRelease` resources
that reference a `GitRepository` or `Bucket` source.

Annotations and labels can be added by configuring the respective `.spec.chart.metadata`
fields.

## Values overrides

The simplest way to define values overrides is inline via `spec.values`.
Expand Down
14 changes: 12 additions & 2 deletions internal/controllers/helmrelease_controller_chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
_ "github.com/opencontainers/go-digest/blake3"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader"
apiequality "k8s.io/apimachinery/pkg/api/equality"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
Expand Down Expand Up @@ -82,6 +83,9 @@ func (r *HelmReleaseReconciler) reconcileChart(ctx context.Context, hr *v2.HelmR
case helmChartRequiresUpdate(hr, &helmChart):
ctrl.LoggerFrom(ctx).Info("chart diverged from template", strings.ToLower(sourcev1.HelmChartKind), chartName.String())
helmChart.Spec = hc.Spec
helmChart.Labels = hc.Labels
helmChart.Annotations = hc.Annotations

if err = r.Client.Update(ctx, &helmChart); err != nil {
return nil, err
}
Expand Down Expand Up @@ -196,8 +200,10 @@ func buildHelmChartFromTemplate(hr *v2.HelmRelease) *sourcev1.HelmChart {
template := hr.Spec.Chart
return &sourcev1.HelmChart{
ObjectMeta: metav1.ObjectMeta{
Name: hr.GetHelmChartName(),
Namespace: hr.Spec.Chart.GetNamespace(hr.Namespace),
Name: hr.GetHelmChartName(),
Namespace: hr.Spec.Chart.GetNamespace(hr.Namespace),
Labels: hr.Spec.Chart.ObjectMeta.Labels,
Annotations: hr.Spec.Chart.ObjectMeta.Annotations,
},
Spec: sourcev1.HelmChartSpec{
Chart: template.Spec.Chart,
Expand Down Expand Up @@ -239,6 +245,10 @@ func helmChartRequiresUpdate(hr *v2.HelmRelease, chart *sourcev1.HelmChart) bool
return true
case template.Spec.ValuesFile != chart.Spec.ValuesFile:
return true
case !apiequality.Semantic.DeepEqual(template.ObjectMeta.Annotations, chart.Annotations):
return true
case !apiequality.Semantic.DeepEqual(template.ObjectMeta.Labels, chart.Labels):
return true
case !reflect.DeepEqual(templateVerificationToSourceVerification(template.Spec.Verify), chart.Spec.Verify):
return true
default:
Expand Down
14 changes: 14 additions & 0 deletions internal/controllers/helmrelease_controller_chart_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,20 @@ func Test_helmChartRequiresUpdate(t *testing.T) {
},
want: true,
},
{
name: "detects labels change",
modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) {
hr.Spec.Chart.ObjectMeta.Labels = map[string]string{"foo": "bar"}
},
want: true,
},
{
name: "detects annotations change",
modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) {
hr.Spec.Chart.ObjectMeta.Annotations = map[string]string{"foo": "bar"}
},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down