diff --git a/helm/hook/hook.go b/helm/hook/hook.go index 8f06d44..02ef378 100644 --- a/helm/hook/hook.go +++ b/helm/hook/hook.go @@ -15,12 +15,38 @@ import ( var labelIgnoreResources = map[string]struct{}{ "rbac.authorization.k8s.io/v1/ClusterRole//castai-evictor": {}, "rbac.authorization.k8s.io/v1/ClusterRoleBinding//castai-evictor": {}, + "rbac.authorization.k8s.io/v1/Role//castai-evictor": {}, + "rbac.authorization.k8s.io/v1/RoleBinding//castai-evictor": {}, + + "rbac.authorization.k8s.io/v1/ClusterRole//castai-agent": {}, + "rbac.authorization.k8s.io/v1/ClusterRoleBinding//castai-agent": {}, + "rbac.authorization.k8s.io/v1/Role//castai-agent": {}, + "rbac.authorization.k8s.io/v1/RoleBinding//castai-agent": {}, + + "rbac.authorization.k8s.io/v1/ClusterRole//castai-spot-handler": {}, + "rbac.authorization.k8s.io/v1/ClusterRoleBinding//castai-spot-handler": {}, + "rbac.authorization.k8s.io/v1/Role//castai-spot-handler": {}, + "rbac.authorization.k8s.io/v1/RoleBinding//castai-spot-handler": {}, + + "rbac.authorization.k8s.io/v1/ClusterRole//castai-egressd": {}, + "rbac.authorization.k8s.io/v1/ClusterRoleBinding//castai-egressd": {}, + "rbac.authorization.k8s.io/v1/Role//castai-egressd": {}, + "rbac.authorization.k8s.io/v1/RoleBinding//castai-egressd": {}, "rbac.authorization.k8s.io/v1/ClusterRole//castai-kvisor": {}, "rbac.authorization.k8s.io/v1/ClusterRoleBinding//castai-kvisor": {}, + "rbac.authorization.k8s.io/v1/Role//castai-kvisor": {}, + "rbac.authorization.k8s.io/v1/RoleBinding//castai-kvisor": {}, "rbac.authorization.k8s.io/v1/ClusterRole//castai-kvisor-runtime": {}, "rbac.authorization.k8s.io/v1/ClusterRoleBinding//castai-kvisor-runtime": {}, + "rbac.authorization.k8s.io/v1/Role//castai-kvisor-runtime": {}, + "rbac.authorization.k8s.io/v1/RoleBinding//castai-kvisor-runtime": {}, + + "rbac.authorization.k8s.io/v1/ClusterRole//castai-cluster-controller": {}, + "rbac.authorization.k8s.io/v1/ClusterRoleBinding//castai-cluster-controller": {}, + "rbac.authorization.k8s.io/v1/Role//castai-cluster-controller": {}, + "rbac.authorization.k8s.io/v1/RoleBinding//castai-cluster-controller": {}, } const ( diff --git a/helm/hook/hook_test.go b/helm/hook/hook_test.go index 60053bd..d637ffd 100644 --- a/helm/hook/hook_test.go +++ b/helm/hook/hook_test.go @@ -2,7 +2,9 @@ package hook import ( "bytes" + "fmt" "testing" + "text/template" "time" "github.com/stretchr/testify/require" @@ -12,61 +14,94 @@ import ( "github.com/castai/cluster-controller/helm/hook/mock" ) -func TestIgnoreHook(t *testing.T) { - r := require.New(t) +type componentVersions struct { + appVersion string + chartVersion string + newAppVersion string + newChartVersion string +} - oldManifests := - `--- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app.kubernetes.io/instance: castai-evictor - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/name: castai-evictor - app.kubernetes.io/version: 0.5.1 - helm.sh/chart: castai-evictor-0.10.0 - name: castai-evictor - ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app.kubernetes.io/instance: castai-evictor - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/name: castai-evictor - app.kubernetes.io/version: 0.5.1 - helm.sh/chart: castai-evictor-0.10.0 - name: castai-evictor - namespace: castai-agent` - - newManifests := - `--- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app.kubernetes.io/instance: castai-evictor - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/name: castai-evictor - app.kubernetes.io/version: 0.6.0 - helm.sh/chart: castai-evictor-0.11.0 - name: castai-evictor - ---- -apiVersion: v1 -kind: Service +type k8sObjectDetails struct { + apiVersion string + updateLabels bool +} + +func renderManifestTemplate(apiVersion string, kind string, name string, appVersion string, chartVersion string) (string, error) { + vars := map[string]interface{}{ + "ApiVersion": apiVersion, + "Kind": kind, + "Name": name, + "AppVersion": appVersion, + "ChartVersion": chartVersion, + } + + manifestTemplate := `--- +apiVersion: {{ .ApiVersion }} +kind: {{ .Kind}} metadata: labels: - app.kubernetes.io/instance: castai-evictor + app.kubernetes.io/instance: {{ .Name }} app.kubernetes.io/managed-by: Helm - app.kubernetes.io/name: castai-evictor - app.kubernetes.io/version: 0.6.0 - helm.sh/chart: castai-evictor-0.11.0 - name: castai-evictor - namespace: castai-agent` + app.kubernetes.io/name: {{ .Name }} + app.kubernetes.io/version: {{ .AppVersion }} + {{- if .ChartVersion }} + helm.sh/chart: {{ .Name }}-{{ .ChartVersion }} + {{- end }} + name: {{ .Name }} +` + + tmpl, err := template.New("template").Parse(manifestTemplate) + if err != nil { + return "", fmt.Errorf("parsing manifest template: %w", err) + } + var renderedTemplate bytes.Buffer + if err := tmpl.Execute(&renderedTemplate, vars); err != nil { + return "", fmt.Errorf("rendering manifest template: %w", err) + } + + return renderedTemplate.String(), nil + +} + +func TestIgnoreHook(t *testing.T) { + r := require.New(t) + + components := map[string]componentVersions{ + "castai-evictor": {"0.5.1", "0.10.0", "0.6.0", "0.11.0"}, + "castai-agent": {"0.5.1", "0.10.0", "0.6.0", "0.11.0"}, + "castai-spot-handler": {"0.5.1", "0.10.0", "0.6.0", "0.11.0"}, + "castai-egressd": {"0.5.1", "0.10.0", "0.6.0", "0.11.0"}, + "castai-kvisor": {"0.5.1", "0.10.0", "0.6.0", "0.11.0"}, + "castai-kvisor-runtime": {"0.5.1", "0.10.0", "0.6.0", "0.11.0"}, + "castai-cluster-controller": {"v0.37.0", "0.52.0", "v0.38.0", "0.53.0"}, + } + + k8sObjects := map[string]k8sObjectDetails{ + "ClusterRoleBinding": {"rbac.authorization.k8s.io/v1", false}, + "ClusterRole": {"rbac.authorization.k8s.io/v1", false}, + "Role": {"rbac.authorization.k8s.io/v1", false}, + "RoleBinding": {"rbac.authorization.k8s.io/v1", false}, + "Service": {"v1", true}, + } + + // Generate old and new manifest strings. + var oldManifests, newManifests string + for name, c := range components { + for kind, d := range k8sObjects { + oldM, err := renderManifestTemplate(d.apiVersion, kind, name, c.appVersion, c.chartVersion) + if err != nil { + r.Error(err) + } + oldManifests += oldM + + newM, err := renderManifestTemplate(d.apiVersion, kind, name, c.newAppVersion, c.newChartVersion) + if err != nil { + r.Error(err) + } + newManifests += newM + } + } oldRelease := &release.Release{ Manifest: oldManifests, @@ -87,17 +122,26 @@ metadata: typed, err := cl.Build(fixedManifest, false) r.NoError(err) + // Iterate through Helm generated k8s objects. for _, res := range typed { u := res.Object.(*unstructured.Unstructured) - if u.GetKind() == "Service" { - r.Equal("0.6.0", u.GetLabels()[k8sVersionLabel]) - r.Equal("castai-evictor-0.11.0", u.GetLabels()[helmVersionLabel]) - } - - if u.GetKind() == "ClusterRoleBinding" { - r.Equal("0.5.1", u.GetLabels()[k8sVersionLabel]) - r.Equal("castai-evictor-0.10.0", u.GetLabels()[helmVersionLabel]) + // Assert all castai-components k8s resources pairs in one place. + for kind, d := range k8sObjects { + if u.GetKind() == kind { + if c, ok := components[u.GetName()]; ok { + // If labels should have been updated by post render hook - change them for correct assertion. + appVersion := c.appVersion + chartVersion := c.chartVersion + if d.updateLabels { + appVersion = c.newAppVersion + chartVersion = c.newChartVersion + } + + r.Equal(appVersion, u.GetLabels()[k8sVersionLabel]) + r.Equal(fmt.Sprintf("%s-%s", u.GetName(), chartVersion), u.GetLabels()[helmVersionLabel]) + } + } } }