Skip to content

Commit

Permalink
refactor(plugins): standardize and combine plugin controllers (#861)
Browse files Browse the repository at this point in the history
* refactor(plugins): implement standard interface for HelmController

* refactor(plugins): refactor initClientGetter

* refactor(plugins): combine PluginWorkloadStatusController into HelmController, tests not passing

* refactor(plugins): check only components of ready condition that are under test

* feat(plugins): implement plugin option checksum calculation, skipping drift detection when checksum has not changed

* refactor(plugins): merge HelmChartTest into HelmController

* refactor(plugins): rename HelmController to PluginController, rename merged reconciler files

* Automatic generation of CRD API Docs

* (chore): resolves conflict for openapi

* Automatic generation of CRD API Docs

* Automatic application of license header

* (chore): rename pluginHelm to plugin

* refactor(plugins): improve plugin option checksum calculation

---------

Co-authored-by: k.zagorski <k.zagorski@accenture.com>
Co-authored-by: Cloud Operator <169066274+cloud-operator@users.noreply.github.com>
Co-authored-by: Abhijith Ravindra <137736216+abhijith-darshan@users.noreply.github.com>
Co-authored-by: abhijith-darshan <abhijith.ravindra@sap.com>
Co-authored-by: License Bot <license_bot@github.com>
  • Loading branch information
6 people authored Feb 4, 2025
1 parent 2a93ec4 commit 6e00ff0
Show file tree
Hide file tree
Showing 16 changed files with 520 additions and 428 deletions.
4 changes: 4 additions & 0 deletions charts/manager/crds/greenhouse.sap_plugins.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ spec:
of the release.
format: date-time
type: string
pluginOptionChecksum:
description: PluginOptionChecksum is the checksum of plugin option
values.
type: string
status:
description: Status is the status of a HelmChart release.
type: string
Expand Down
11 changes: 1 addition & 10 deletions charts/manager/templates/manager-role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ rules:
- organizations/status
- plugindefinitions/status
- pluginpresets/status
- plugins/status
- teammemberships/status
- teamrolebindings/status
- teams/status
Expand All @@ -113,16 +114,6 @@ rules:
- list
- update
- watch
- apiGroups:
- greenhouse.sap
resources:
- plugins/status
verbs:
- get
- list
- patch
- update
- watch
- apiGroups:
- rbac
resources:
Expand Down
12 changes: 2 additions & 10 deletions cmd/greenhouse/controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,14 @@ var knownControllers = map[string]func(controllerName string, mgr ctrl.Manager)
"teamRoleBindingController": (&teamrbaccontrollers.TeamRoleBindingReconciler{}).SetupWithManager,

// Plugin controllers.
// "pluginPropagation": (&plugincontrollers.PluginPropagationReconciler{}).SetupWithManager,
"pluginWorkLoadStatus": (&plugincontrollers.WorkLoadStatusReconciler{
"plugin": (&plugincontrollers.PluginReconciler{
KubeRuntimeOpts: kubeClientOpts,
}).SetupWithManager,

// Plugin controllers.
"pluginHelm": (&plugincontrollers.HelmReconciler{
KubeRuntimeOpts: kubeClientOpts,
}).SetupWithManager,
"pluginPreset": (&plugincontrollers.PluginPresetReconciler{}).SetupWithManager,
"pluginChartTest": (&plugincontrollers.HelmChartTestReconciler{}).SetupWithManager,
"pluginPreset": (&plugincontrollers.PluginPresetReconciler{}).SetupWithManager,

// Cluster controllers
"bootStrap": (&clustercontrollers.BootstrapReconciler{}).SetupWithManager,
"clusterReconciler": startClusterReconciler,
// "clusterPropagation": (&clustercontrollers.ClusterPropagationReconciler{}).SetupWithManager,
}

// knownControllers lists the name of known controllers.
Expand Down
11 changes: 11 additions & 0 deletions docs/reference/api/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,17 @@ <h3 id="greenhouse.sap/v1alpha1.HelmReleaseStatus">HelmReleaseStatus
<p>LastDeployed is the timestamp of the last deployment of the release.</p>
</td>
</tr>
<tr>
<td>
<code>pluginOptionChecksum</code><br>
<em>
string
</em>
</td>
<td>
<p>PluginOptionChecksum is the checksum of plugin option values.</p>
</td>
</tr>
</tbody>
</table>
</div>
Expand Down
3 changes: 3 additions & 0 deletions docs/reference/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,9 @@ components:
description: LastDeployed is the timestamp of the last deployment of the release.
format: date-time
type: string
pluginOptionChecksum:
description: PluginOptionChecksum is the checksum of plugin option values.
type: string
status:
description: Status is the status of a HelmChart release.
type: string
Expand Down
10 changes: 10 additions & 0 deletions pkg/apis/greenhouse/v1alpha1/plugin_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ type HelmReleaseStatus struct {
FirstDeployed metav1.Time `json:"firstDeployed,omitempty"`
// LastDeployed is the timestamp of the last deployment of the release.
LastDeployed metav1.Time `json:"lastDeployed,omitempty"`
// PluginOptionChecksum is the checksum of plugin option values.
PluginOptionChecksum string `json:"pluginOptionChecksum,omitempty"`
}

//+kubebuilder:object:root=true
Expand Down Expand Up @@ -160,3 +162,11 @@ type PluginList struct {
func init() {
SchemeBuilder.Register(&Plugin{}, &PluginList{})
}

func (o *Plugin) GetConditions() StatusConditions {
return o.Status.StatusConditions
}

func (o *Plugin) SetCondition(condition Condition) {
o.Status.StatusConditions.SetConditions(condition)
}
150 changes: 0 additions & 150 deletions pkg/controllers/plugin/helm_chart_test_controller.go

This file was deleted.

95 changes: 95 additions & 0 deletions pkg/controllers/plugin/helm_chart_testing.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors
// SPDX-License-Identifier: Apache-2.0

package plugin

import (
"context"
"fmt"
"reflect"
"strings"

"github.com/prometheus/client_golang/prometheus"
"sigs.k8s.io/controller-runtime/pkg/metrics"

greenhousev1alpha1 "github.com/cloudoperators/greenhouse/pkg/apis/greenhouse/v1alpha1"
"github.com/cloudoperators/greenhouse/pkg/helm"
)

var (
chartTestRunsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "greenhouse_plugin_chart_test_runs_total",
Help: "Total number of Helm Chart test runs with their results",
},
[]string{"cluster", "plugin", "namespace", "result"})
)

func init() {
metrics.Registry.MustRegister(chartTestRunsTotal)
}

func (r *PluginReconciler) reconcileHelmChartTest(ctx context.Context, plugin *greenhousev1alpha1.Plugin) (*reconcileResult, error) {
// Nothing to do when the status of the plugin is empty and when the plugin does not have a Helm Chart
if reflect.DeepEqual(plugin.Status, greenhousev1alpha1.PluginStatus{}) || plugin.Status.HelmChart == nil {
return nil, nil
}

if plugin.Spec.Disabled {
return nil, nil
}

// Helm Chart Test cannot be done as the Helm Chart deployment is not successful
if plugin.Status.HelmReleaseStatus.Status != "deployed" {
return nil, nil
}

restClientGetter, err := initClientGetter(ctx, r.Client, r.kubeClientOpts, *plugin)
if err != nil {
return nil, fmt.Errorf("cannot access cluster: %s", err.Error())
}

// Check if we should continue with reconciliation or requeue if cluster is scheduled for deletion
result, err := shouldReconcileOrRequeue(ctx, r.Client, plugin)
if err != nil {
return nil, err
}
if result != nil {
return &reconcileResult{requeueAfter: result.requeueAfter}, nil
}

hasHelmChartTest, err := helm.HelmChartTest(ctx, restClientGetter, plugin)
prometheusLabels := prometheus.Labels{
"cluster": plugin.Spec.ClusterName,
"plugin": plugin.Name,
"namespace": plugin.Namespace,
}
if err != nil {
errStr := fmt.Sprintf("Helm Chart testing failed: %s. To debug, please run `helm test %s`command in your remote cluster %s.", err.Error(), plugin.Name, plugin.Spec.ClusterName)
errStr = strings.ReplaceAll(errStr, "\n", "")
errStr = strings.ReplaceAll(errStr, "\t", " ")
errStr = strings.ReplaceAll(errStr, "*", "")
plugin.SetCondition(greenhousev1alpha1.FalseCondition(greenhousev1alpha1.HelmChartTestSucceededCondition, "", errStr))

prometheusLabels["result"] = "Error"
chartTestRunsTotal.With(prometheusLabels).Inc()

return nil, err
}

if !hasHelmChartTest {
plugin.SetCondition(greenhousev1alpha1.TrueCondition(greenhousev1alpha1.HelmChartTestSucceededCondition, "",
"No Helm Chart Tests defined by the PluginDefinition"))

prometheusLabels["result"] = "NoTests"
chartTestRunsTotal.With(prometheusLabels).Inc()
} else {
plugin.SetCondition(greenhousev1alpha1.TrueCondition(greenhousev1alpha1.HelmChartTestSucceededCondition, "",
"Helm Chart Test is successful"))

prometheusLabels["result"] = "Success"
chartTestRunsTotal.With(prometheusLabels).Inc()
}

return nil, nil
}
Loading

0 comments on commit 6e00ff0

Please sign in to comment.