Skip to content

Commit

Permalink
Merge pull request #631 from raffis/feat-chart-metadata
Browse files Browse the repository at this point in the history
feat: manage label and annotations for a helmchart
  • Loading branch information
hiddeco authored Mar 29, 2023
2 parents af59329 + a72a2fc commit 5a1c513
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 5 deletions.
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"`

// 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

0 comments on commit 5a1c513

Please sign in to comment.