Skip to content
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
2 changes: 1 addition & 1 deletion .github/workflows/checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
uses: actions/setup-go@v6
with:
check-latest: true
go-version: 1.26.2
go-version: 1.26.3
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v9
with:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
uses: actions/setup-go@v6
with:
check-latest: true
go-version: 1.26.2
go-version: 1.26.3
- name: Build all binaries
run: make build-all
code_coverage:
Expand Down Expand Up @@ -65,7 +65,7 @@ jobs:
uses: actions/setup-go@v6
with:
check-latest: true
go-version: 1.26.2
go-version: 1.26.3
- name: Run tests and generate coverage report
run: make test-with-envtest
- name: Archive code coverage results
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/codeql.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
uses: actions/setup-go@v6
with:
check-latest: true
go-version: 1.26.2
go-version: 1.26.3
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
Expand Down
12 changes: 9 additions & 3 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,21 @@ linters:
replace-allow-list:
# for go-pmtud
- github.com/mdlayher/arp
# for github.com/sapcc/vpa_butler
- k8s.io/client-go
# synced from greenhouse v0.9.0
# synced from greenhouse v0.11.1
- github.com/fluxcd/helm-controller/api
- github.com/fluxcd/kustomize-controller/api
- github.com/fluxcd/pkg/apis/kustomize
- github.com/fluxcd/pkg/apis/meta
- github.com/fluxcd/source-controller/api
- github.com/fluxcd/source-watcher/api/v2
- k8s.io/api
- k8s.io/apiextensions-apiserver
- k8s.io/apimachinery
- k8s.io/cli-runtime
- k8s.io/client-go
- k8s.io/component-base
- k8s.io/kubectl
- sigs.k8s.io/controller-runtime
toolchain-forbidden: true
go-version-pattern: 1\.\d+(\.0)?$
gosec:
Expand Down
2 changes: 1 addition & 1 deletion controller/careinstruction/careinstruction_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ func (r *CareInstructionReconciler) reconcileManager(ctx context.Context, careIn
Logger: r.WithValues("careInstruction", careInstruction.Name),
Name: shoot.GenerateName(careInstruction.Name),
CareInstruction: careInstruction.DeepCopy(),
EventRecorder: r.GetEventRecorderFor(shoot.GenerateName(careInstruction.Name)),
EventRecorder: r.GetEventRecorder(shoot.GenerateName(careInstruction.Name)),
}
if err := sc.SetupWithManager(shootControllerMgr); err != nil {
return err
Expand Down
39 changes: 22 additions & 17 deletions controller/careinstruction/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,39 @@ import (
"shoot-grafter/api/v1alpha1"
)

const metricLabelCareInstruction = "care_instruction"
const metricLabelNamespace = "namespace"
const metricLabelGardenNamespace = "garden_namespace"
const metricLabelShootName = "shoot_name"

var (
TotalTargetShootsGauge = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "shoot_grafter_total_target_shoots",
Help: "Total number of shoots matching the CareInstruction label selector",
},
[]string{"care_instruction", "namespace", "garden_namespace"},
[]string{metricLabelCareInstruction, metricLabelNamespace, metricLabelGardenNamespace},
)
CreatedClustersGauge = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "shoot_grafter_created_clusters",
Help: "Number of clusters created by the CareInstruction",
},
[]string{"care_instruction", "namespace", "garden_namespace"},
[]string{metricLabelCareInstruction, metricLabelNamespace, metricLabelGardenNamespace},
)
FailedClustersGauge = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "shoot_grafter_failed_clusters",
Help: "Number of clusters failed to be created by the CareInstruction",
},
[]string{"care_instruction", "namespace", "garden_namespace"},
[]string{metricLabelCareInstruction, metricLabelNamespace, metricLabelGardenNamespace},
)
ShootOnboardedGauge = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "shoot_grafter_shoot_onboarded",
Help: "Is shoot onboarded by the CareInstruction",
},
[]string{"care_instruction", "namespace", "garden_namespace", "shoot_name"},
[]string{metricLabelCareInstruction, metricLabelNamespace, metricLabelGardenNamespace, metricLabelShootName},
)
)

Expand All @@ -59,29 +64,29 @@ func UpdateCareInstructionMetrics(careInstruction *v1alpha1.CareInstruction) {

func updateTotalTargetShootsMetric(careInstruction *v1alpha1.CareInstruction) {
metricLabels := prometheus.Labels{
"care_instruction": careInstruction.Name,
"namespace": careInstruction.Namespace,
"garden_namespace": careInstruction.Spec.GardenNamespace,
metricLabelCareInstruction: careInstruction.Name,
metricLabelNamespace: careInstruction.Namespace,
metricLabelGardenNamespace: careInstruction.Spec.GardenNamespace,
}
totalTargetShoots := careInstruction.Status.TotalTargetShoots
TotalTargetShootsGauge.With(metricLabels).Set(float64(totalTargetShoots))
}

func updateCreatedClustersMetric(careInstruction *v1alpha1.CareInstruction) {
metricLabels := prometheus.Labels{
"care_instruction": careInstruction.Name,
"namespace": careInstruction.Namespace,
"garden_namespace": careInstruction.Spec.GardenNamespace,
metricLabelCareInstruction: careInstruction.Name,
metricLabelNamespace: careInstruction.Namespace,
metricLabelGardenNamespace: careInstruction.Spec.GardenNamespace,
}
createdCount := careInstruction.Status.CreatedClusters
CreatedClustersGauge.With(metricLabels).Set(float64(createdCount))
}

func updateFailedClustersMetric(careInstruction *v1alpha1.CareInstruction) {
metricLabels := prometheus.Labels{
"care_instruction": careInstruction.Name,
"namespace": careInstruction.Namespace,
"garden_namespace": careInstruction.Spec.GardenNamespace,
metricLabelCareInstruction: careInstruction.Name,
metricLabelNamespace: careInstruction.Namespace,
metricLabelGardenNamespace: careInstruction.Spec.GardenNamespace,
}
failedCount := careInstruction.Status.FailedClusters
FailedClustersGauge.With(metricLabels).Set(float64(failedCount))
Expand All @@ -90,10 +95,10 @@ func updateFailedClustersMetric(careInstruction *v1alpha1.CareInstruction) {
func updateOnboardedShootsMetrics(careInstruction *v1alpha1.CareInstruction) {
for _, ss := range careInstruction.Status.Shoots {
metricLabels := prometheus.Labels{
"care_instruction": careInstruction.Name,
"namespace": careInstruction.Namespace,
"garden_namespace": careInstruction.Spec.GardenNamespace,
"shoot_name": ss.Name,
metricLabelCareInstruction: careInstruction.Name,
metricLabelNamespace: careInstruction.Namespace,
metricLabelGardenNamespace: careInstruction.Spec.GardenNamespace,
metricLabelShootName: ss.Name,
}
if ss.Status == v1alpha1.ShootStatusOnboarded {
ShootOnboardedGauge.With(metricLabels).Set(float64(1))
Expand Down
14 changes: 8 additions & 6 deletions controller/shoot/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"sigs.k8s.io/yaml"
)

const authConfigMapKey = "config.yaml"

// configureOIDCAuthentication configures OIDC authentication for the Shoot by:
// 1. Fetching the AuthenticationConfiguration ConfigMap from Greenhouse cluster
// 2. Merging it with any existing configuration on the Garden cluster
Expand Down Expand Up @@ -47,14 +49,14 @@ func (r *ShootController) configureOIDCAuthentication(ctx context.Context, shoot
}

// Verify the ConfigMap contains config.yaml
if greenhouseAuthConfigMap.Data == nil || greenhouseAuthConfigMap.Data["config.yaml"] == "" {
if greenhouseAuthConfigMap.Data == nil || greenhouseAuthConfigMap.Data[authConfigMapKey] == "" {
return fmt.Errorf("AuthenticationConfiguration ConfigMap %s does not contain config.yaml",
r.CareInstruction.Spec.AuthenticationConfigMapName)
}

// Parse the Greenhouse authentication configuration
var greenhouseAuthConfig apiserverv1beta1.AuthenticationConfiguration
if err := yaml.Unmarshal([]byte(greenhouseAuthConfigMap.Data["config.yaml"]), &greenhouseAuthConfig); err != nil {
if err := yaml.Unmarshal([]byte(greenhouseAuthConfigMap.Data[authConfigMapKey]), &greenhouseAuthConfig); err != nil {
return fmt.Errorf("failed to parse Greenhouse AuthenticationConfiguration: %w", err)
}

Expand Down Expand Up @@ -90,7 +92,7 @@ func (r *ShootController) configureOIDCAuthentication(ctx context.Context, shoot
Namespace: shoot.Namespace,
},
Data: map[string]string{
"config.yaml": "",
authConfigMapKey: "",
},
}
}
Expand Down Expand Up @@ -162,8 +164,8 @@ func (r *ShootController) mergeAuthenticationConfigurations(gardenConfigMap *cor
var gardenAuthConfig apiserverv1beta1.AuthenticationConfiguration

// Parse existing Garden configuration if present
if gardenConfigMap.Data != nil && gardenConfigMap.Data["config.yaml"] != "" {
existingConfigYAML := gardenConfigMap.Data["config.yaml"]
if gardenConfigMap.Data != nil && gardenConfigMap.Data[authConfigMapKey] != "" {
existingConfigYAML := gardenConfigMap.Data[authConfigMapKey]
if err := yaml.Unmarshal([]byte(existingConfigYAML), &gardenAuthConfig); err != nil {
return fmt.Errorf("failed to parse existing Garden AuthenticationConfiguration: %w", err)
}
Expand Down Expand Up @@ -212,7 +214,7 @@ func (r *ShootController) mergeAuthenticationConfigurations(gardenConfigMap *cor
if gardenConfigMap.Data == nil {
gardenConfigMap.Data = make(map[string]string)
}
gardenConfigMap.Data["config.yaml"] = string(mergedConfigYAML)
gardenConfigMap.Data[authConfigMapKey] = string(mergedConfigYAML)

return nil
}
17 changes: 5 additions & 12 deletions controller/shoot/shoot_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/record"
"k8s.io/client-go/tools/events"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -40,13 +40,13 @@ type ShootController struct {
logr.Logger
Name string
CareInstruction *v1alpha1.CareInstruction
EventRecorder record.EventRecorder // EventRecorder to emit events on the Greenhouse cluster
EventRecorder events.EventRecorder // EventRecorder to emit events on the Greenhouse cluster
}

// emitEvent safely emits an event if EventRecorder is available
func (r *ShootController) emitEvent(object client.Object, eventType, reason, message string) {
if r.EventRecorder != nil {
r.EventRecorder.Event(object, eventType, reason, message)
r.EventRecorder.Eventf(object, nil, eventType, reason, reason, "%s", message)
} else {
r.Info("Event (EventRecorder not available)", "type", eventType, "reason", reason, "message", message)
}
Expand Down Expand Up @@ -148,13 +148,6 @@ func (r *ShootController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl
return ctrl.Result{}, nil
}

// Specify which labels to propagate from the Shoot to the Secret - LabelPropagator needs to have the labels set on the source object.
// TODO: change when LabelPropagator is extended to accommodate this scenario.
if shoot.Annotations == nil {
shoot.Annotations = make(map[string]string)
}
shoot.Annotations[lifecycle.PropagateLabelsAnnotation] = strings.Join(r.CareInstruction.Spec.PropagateLabels, ",")

// Specify which labels should be propagated from the Secret (by Greenhouse to create Cluster)
labelKeysToPropagate := r.CareInstruction.Spec.PropagateLabels

Expand Down Expand Up @@ -227,8 +220,8 @@ func (r *ShootController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl
}
maps.Copy(secret.Labels, secretLabels)

// Transport Shoot labels to the Secret
secret = (lifecycle.NewPropagator(&shoot, secret).Apply()).(*corev1.Secret)
// Copy Shoot labels to the Secret
secret = (lifecycle.NewPropagator(&shoot, secret).CopyLabels(r.CareInstruction.Spec.PropagateLabels)).(*corev1.Secret)
return nil
})
if err != nil {
Expand Down
7 changes: 1 addition & 6 deletions controller/shoot/shoot_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ var _ = Describe("Shoot Controller", func() {
Logger: ctrl.Log.WithName("controllers").WithName("ShootController"),
Name: "ShootController",
CareInstruction: careInstruction,
EventRecorder: greenhouseMgr.GetEventRecorderFor("ShootController"), // Get EventRecorder from Greenhouse manager
EventRecorder: greenhouseMgr.GetEventRecorder("ShootController"),
}).SetupWithManager(mgr)).To(Succeed(), "there must be no error setting up the controller with the manager")

careInstructionWebhook := &webhookv1alpha1.CareInstructionWebhook{}
Expand Down Expand Up @@ -313,7 +313,6 @@ var _ = Describe("Shoot Controller", func() {
"quux": "corge",
},
Annotations: map[string]string{
"greenhouse.sap/last-applied-propagator": "{\"labelKeys\":[\"foo\",\"baz\"]}",
"greenhouse.sap/propagate-labels": "foo,baz,quux,shoot-grafter.cloudoperators.dev/careinstruction",
greenhouseapis.SecretAPIServerURLAnnotation: "https://api-server.test-shoot-1.example.com",
},
Expand Down Expand Up @@ -394,7 +393,6 @@ var _ = Describe("Shoot Controller", func() {
"quux": "corge",
},
Annotations: map[string]string{
"greenhouse.sap/last-applied-propagator": "{\"labelKeys\":[\"foo\",\"baz\"]}",
"greenhouse.sap/propagate-labels": "foo,baz,quux,shoot-grafter.cloudoperators.dev/careinstruction",
greenhouseapis.SecretAPIServerURLAnnotation: "https://api-server.test-shoot-1.example.com",
},
Expand All @@ -414,7 +412,6 @@ var _ = Describe("Shoot Controller", func() {
"quux": "corge",
},
Annotations: map[string]string{
"greenhouse.sap/last-applied-propagator": "{\"labelKeys\":[\"foo\",\"baz\"]}",
"greenhouse.sap/propagate-labels": "foo,baz,quux,shoot-grafter.cloudoperators.dev/careinstruction",
greenhouseapis.SecretAPIServerURLAnnotation: "https://api-server.test-shoot-2.example.com",
},
Expand Down Expand Up @@ -494,7 +491,6 @@ var _ = Describe("Shoot Controller", func() {
"quux": "corge",
},
Annotations: map[string]string{
"greenhouse.sap/last-applied-propagator": "{\"labelKeys\":[\"foo\",\"baz\"]}",
"greenhouse.sap/propagate-labels": "foo,baz,quux,shoot-grafter.cloudoperators.dev/careinstruction",
greenhouseapis.SecretAPIServerURLAnnotation: "https://api-server.test-shoot-1.example.com",
},
Expand Down Expand Up @@ -776,7 +772,6 @@ var _ = Describe("Shoot Controller", func() {
"quux": "corge",
}), "should have the expected labels")
g.Expect(secret.Annotations).To(Equal(map[string]string{
"greenhouse.sap/last-applied-propagator": "{\"labelKeys\":[\"foo\",\"baz\"]}",
"greenhouse.sap/propagate-labels": "foo,baz,quux,shoot-grafter.cloudoperators.dev/careinstruction",
greenhouseapis.SecretAPIServerURLAnnotation: "https://api-server.test-shoot.example.com",
}), "should have the expected annotations")
Expand Down
Loading
Loading