Skip to content

Commit 2f1f568

Browse files
RafalKoreptachrisseto
authored andcommitted
operator: synchronize {Cluster,}Roles with operator manifests
Prior to this commit the operator chart's declared permissions had grown out of sync with those declared by the operator itself. This commit re-synchronizes the permissions, adds in regression tests to prevent such drift from happening again, and releases the updated chart. Co-authored-by: Rafal Korepta <rafal.korepta@gmail.com>
1 parent e326f1f commit 2f1f568

File tree

12 files changed

+7983
-6508
lines changed

12 files changed

+7983
-6508
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,14 @@
225225
#### Fixed
226226
#### Removed
227227
228+
### [0.4.33](https://github.com/redpanda-data/helm-charts/releases/tag/operator-0.4.33) - 2024-11-6
229+
#### Added
230+
* Missing permissions for ClusterRoles, ClusterRoleBindings, Horizontal Pod Autoscaler, cert-manager/Certificate,
231+
cert-manager/Issuer, redpanda/Users, and redpanda/Schemas.
232+
#### Changed
233+
#### Fixed
234+
#### Removed
235+
228236
### [0.4.32](https://github.com/redpanda-data/helm-charts/releases/tag/operator-0.4.32) - 2024-10-31
229237
#### Added
230238
* Strategic merge of Pod volumes

charts/operator/Chart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ type: application
66
# The chart version and the app version are not the same and will not track
77
# together. The chart version is a semver representation of changes to this
88
# chart.
9-
version: 0.4.32
9+
version: 0.4.33
1010

1111
# This is the default version of the operator being deployed.
1212
# ** NOTE for maintainers: please enssure the artifacthub image annotation is updated before merging

charts/operator/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
description: Find the default values and descriptions of settings in the Redpanda Operator Helm chart.
44
---
55

6-
![Version: 0.4.32](https://img.shields.io/badge/Version-0.4.32-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v2.2.5-24.2.7](https://img.shields.io/badge/AppVersion-v2.2.5--24.2.7-informational?style=flat-square)
6+
![Version: 0.4.33](https://img.shields.io/badge/Version-0.4.33-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v2.2.5-24.2.7](https://img.shields.io/badge/AppVersion-v2.2.5--24.2.7-informational?style=flat-square)
77

88
This page describes the official Redpanda Operator Helm Chart. In particular, this page describes the contents of the chart’s [`values.yaml` file](https://github.com/redpanda-data/helm-charts/blob/main/charts/operator/values.yaml). Each of the settings is listed and described on this page, along with any default values.
99

charts/operator/chart_test.go

Lines changed: 105 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,99 @@
11
package operator
22

33
import (
4+
"bytes"
45
"encoding/json"
56
"fmt"
7+
"log"
68
"os"
9+
"os/exec"
710
"regexp"
811
"slices"
912
"strconv"
1013
"testing"
1114

1215
fuzz "github.com/google/gofuzz"
1316
"github.com/redpanda-data/helm-charts/pkg/helm"
17+
"github.com/redpanda-data/helm-charts/pkg/kube"
1418
"github.com/redpanda-data/helm-charts/pkg/testutil"
1519
"github.com/santhosh-tekuri/jsonschema/v5"
20+
"github.com/stretchr/testify/assert"
1621
"github.com/stretchr/testify/require"
1722
"golang.org/x/tools/txtar"
1823
corev1 "k8s.io/api/core/v1"
24+
rbacv1 "k8s.io/api/rbac/v1"
25+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
1926
"k8s.io/apimachinery/pkg/api/resource"
2027
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2128
"k8s.io/apimachinery/pkg/util/intstr"
2229
"k8s.io/utils/ptr"
30+
"sigs.k8s.io/kustomize/api/konfig"
31+
"sigs.k8s.io/kustomize/kustomize/v5/commands/build"
32+
"sigs.k8s.io/kustomize/kyaml/filesys"
2333
"sigs.k8s.io/yaml"
2434
)
2535

36+
func TestMain(m *testing.M) {
37+
// Chart deps are kept within ./charts as a tgz archive, which is git
38+
// ignored. Helm dep build will ensure that ./charts is in sync with
39+
// Chart.lock, which is tracked by git.
40+
// This is performed in TestMain as there may be many tests that run the
41+
// redpanda helm chart.
42+
out, err := exec.Command("helm", "repo", "add", "prometheus", "https://prometheus-community.github.io/helm-charts").CombinedOutput()
43+
if err != nil {
44+
log.Fatalf("failed to run helm repo add: %s", out)
45+
}
46+
47+
out, err = exec.Command("helm", "dep", "build", ".").CombinedOutput()
48+
if err != nil {
49+
log.Fatalf("failed to run helm dep build: %s", out)
50+
}
51+
52+
os.Exit(m.Run())
53+
}
54+
55+
func TestHelmKustomizeEquivalence(t *testing.T) {
56+
ctx := testutil.Context(t)
57+
client, err := helm.New(helm.Options{ConfigHome: testutil.TempDir(t)})
58+
require.NoError(t, err)
59+
60+
values := PartialValues{FullnameOverride: ptr.To("redpanda"), RBAC: &PartialRBAC{CreateAdditionalControllerCRs: ptr.To(true)}}
61+
62+
rendered, err := client.Template(ctx, ".", helm.TemplateOptions{
63+
Name: "redpanda",
64+
Namespace: "",
65+
Values: values,
66+
})
67+
require.NoError(t, err)
68+
69+
fSys := filesys.MakeFsOnDisk()
70+
buffy := new(bytes.Buffer)
71+
cmd := build.NewCmdBuild(
72+
fSys, build.MakeHelp(konfig.ProgramName, "build"), buffy)
73+
require.NoError(t, cmd.RunE(cmd, []string{"testdata"}))
74+
75+
helmObjs, err := kube.DecodeYAML(rendered, Scheme)
76+
require.NoError(t, err)
77+
78+
require.NoError(t, apiextensionsv1.AddToScheme(Scheme))
79+
kustomizeObjs, err := kube.DecodeYAML(buffy.Bytes(), Scheme)
80+
require.NoError(t, err)
81+
82+
helmClusterRoleRules, helmRoleRules := ExtractRules(helmObjs)
83+
kClusterRoleRules, kRoleRules := ExtractRules(kustomizeObjs)
84+
85+
assert.JSONEq(t, jsonStr(helmRoleRules), jsonStr(kRoleRules), "difference in Roles\n--- Helm / Missing from Kustomize\n+++ Kustomize / Missing from Helm")
86+
assert.JSONEq(t, jsonStr(helmClusterRoleRules), jsonStr(kClusterRoleRules), "difference in ClusterRoles\n--- Helm / Missing from Kustomize\n+++ Kustomize / Missing from Helm")
87+
}
88+
89+
func jsonStr(in any) string {
90+
out, err := json.Marshal(in)
91+
if err != nil {
92+
panic(err)
93+
}
94+
return string(out)
95+
}
96+
2697
// TestValues asserts that the chart's values.yaml file can be losslessly
2798
// loaded into our type [Values] struct.
2899
// NB: values.yaml should round trip through [Values], not [PartialValues], as
@@ -48,12 +119,6 @@ func TestTemplate(t *testing.T) {
48119
client, err := helm.New(helm.Options{ConfigHome: testutil.TempDir(t)})
49120
require.NoError(t, err)
50121

51-
// Chart deps are kept within ./charts as a tgz archive, which is git
52-
// ignored. Helm dep build will ensure that ./charts is in sync with
53-
// Chart.lock, which is tracked by git.
54-
require.NoError(t, client.RepoAdd(ctx, "prometheus", "https://prometheus-community.github.io/helm-charts"))
55-
require.NoError(t, client.DependencyBuild(ctx, "."), "failed to refresh helm dependencies")
56-
57122
casesArchive, err := txtar.ParseFile("testdata/template-cases.txtar")
58123
require.NoError(t, err)
59124

@@ -222,3 +287,37 @@ func makeSureTagIsNotEmptyString(values PartialValues, fuzzer *fuzz.Fuzzer) {
222287
}
223288
}
224289
}
290+
291+
func CalculateRoleRules(rules []rbacv1.PolicyRule) map[string]map[string]struct{} {
292+
flattened := map[string]map[string]struct{}{}
293+
for _, rule := range rules {
294+
for _, api := range rule.APIGroups {
295+
for _, res := range rule.Resources {
296+
key := fmt.Sprintf("%s#%s", api, res)
297+
298+
if _, ok := flattened[key]; !ok {
299+
flattened[key] = map[string]struct{}{}
300+
}
301+
302+
for _, verb := range rule.Verbs {
303+
flattened[key][verb] = struct{}{}
304+
}
305+
}
306+
}
307+
}
308+
return flattened
309+
}
310+
311+
func ExtractRules(objs []kube.Object) (map[string]map[string]struct{}, map[string]map[string]struct{}) {
312+
var rules []rbacv1.PolicyRule
313+
var clusterRules []rbacv1.PolicyRule
314+
for _, o := range objs {
315+
switch obj := o.(type) {
316+
case *rbacv1.Role:
317+
rules = append(rules, obj.Rules...)
318+
case *rbacv1.ClusterRole:
319+
clusterRules = append(clusterRules, obj.Rules...)
320+
}
321+
}
322+
return CalculateRoleRules(clusterRules), CalculateRoleRules(rules)
323+
}

0 commit comments

Comments
 (0)