Skip to content

Commit

Permalink
feat: Implement MaintenanceWindow determination logic (kyma-project#2196
Browse files Browse the repository at this point in the history
)

* feat: Add metadata and status helpers to Kyma type

* add go sum

* cleanup go mod, add api to coverage

* remove api from unit-test coverage

* feat: MaintenanceWindow service

* chore(dependabot): bump k8s.io/apimachinery from 0.32.0 to 0.32.1 in /api (kyma-project#2185)

chore(dependabot): bump k8s.io/apimachinery in /api

Bumps [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) from 0.32.0 to 0.32.1.
- [Commits](kubernetes/apimachinery@v0.32.0...v0.32.1)

---
updated-dependencies:
- dependency-name: k8s.io/apimachinery
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(dependabot): bump sigs.k8s.io/controller-runtime from 0.19.4 to 0.20.0 (kyma-project#2192)

chore(dependabot): bump sigs.k8s.io/controller-runtime

Bumps [sigs.k8s.io/controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) from 0.19.4 to 0.20.0.
- [Release notes](https://github.com/kubernetes-sigs/controller-runtime/releases)
- [Changelog](https://github.com/kubernetes-sigs/controller-runtime/blob/main/RELEASE.md)
- [Commits](kubernetes-sigs/controller-runtime@v0.19.4...v0.20.0)

---
updated-dependencies:
- dependency-name: sigs.k8s.io/controller-runtime
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* feat: Add metadata and status helpers to Kyma type

* cleanup go mod, add api to coverage

* remove obsolete comment

* fix fake arguments in suite_test

* avoid handler name in suite_test

* rename to maintenanceWindow consistently

* underscore unused receiver arg

* omit receiver arg

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • Loading branch information
c-pius and dependabot[bot] committed Jan 21, 2025
1 parent dcf2572 commit 5d6ce78
Show file tree
Hide file tree
Showing 13 changed files with 533 additions and 176 deletions.
14 changes: 9 additions & 5 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import (
"github.com/kyma-project/lifecycle-manager/pkg/log"
"github.com/kyma-project/lifecycle-manager/pkg/matcher"
"github.com/kyma-project/lifecycle-manager/pkg/queue"
"github.com/kyma-project/lifecycle-manager/pkg/templatelookup"
"github.com/kyma-project/lifecycle-manager/pkg/watcher"

_ "k8s.io/client-go/plugin/pkg/client/auth"
Expand Down Expand Up @@ -192,15 +193,16 @@ func setupManager(flagVar *flags.FlagVar, cacheOptions cache.Options, scheme *ma
kymaMetrics := metrics.NewKymaMetrics(sharedMetrics)
mandatoryModulesMetrics := metrics.NewMandatoryModulesMetrics()

// The maintenance windows policy should be passed to the reconciler to be resolved: https://github.com/kyma-project/lifecycle-manager/issues/2101
_, err = maintenancewindows.InitializeMaintenanceWindowsPolicy(setupLog, maintenanceWindowPoliciesDirectory,
maintenanceWindow, err := maintenancewindows.InitializeMaintenanceWindow(setupLog,
maintenanceWindowPoliciesDirectory,
maintenanceWindowPolicyName)
if err != nil {
setupLog.Error(err, "unable to set maintenance windows policy")
}
setupKymaReconciler(mgr, descriptorProvider, skrContextProvider, eventRecorder, flagVar, options, skrWebhookManager,
kymaMetrics, setupLog)
setupManifestReconciler(mgr, flagVar, options, sharedMetrics, mandatoryModulesMetrics, setupLog, eventRecorder)
kymaMetrics, setupLog, maintenanceWindow)
setupManifestReconciler(mgr, flagVar, options, sharedMetrics, mandatoryModulesMetrics, setupLog,
eventRecorder)
setupMandatoryModuleReconciler(mgr, descriptorProvider, flagVar, options, mandatoryModulesMetrics, setupLog)
setupMandatoryModuleDeletionReconciler(mgr, descriptorProvider, eventRecorder, flagVar, options, setupLog)
if flagVar.EnablePurgeFinalizer {
Expand Down Expand Up @@ -277,7 +279,8 @@ func scheduleMetricsCleanup(kymaMetrics *metrics.KymaMetrics, cleanupIntervalInM

func setupKymaReconciler(mgr ctrl.Manager, descriptorProvider *provider.CachedDescriptorProvider,
skrContextFactory remote.SkrContextProvider, event event.Event, flagVar *flags.FlagVar, options ctrlruntime.Options,
skrWebhookManager *watcher.SKRWebhookManifestManager, kymaMetrics *metrics.KymaMetrics, setupLog logr.Logger,
skrWebhookManager *watcher.SKRWebhookManifestManager, kymaMetrics *metrics.KymaMetrics,
setupLog logr.Logger, maintenanceWindow templatelookup.MaintenanceWindow,
) {
options.RateLimiter = internal.RateLimiter(flagVar.FailureBaseDelay,
flagVar.FailureMaxDelay, flagVar.RateLimiterFrequency, flagVar.RateLimiterBurst)
Expand All @@ -303,6 +306,7 @@ func setupKymaReconciler(mgr ctrl.Manager, descriptorProvider *provider.CachedDe
Metrics: kymaMetrics,
RemoteCatalog: remote.NewRemoteCatalogFromKyma(mgr.GetClient(), skrContextFactory,
flagVar.RemoteSyncNamespace),
TemplateLookup: templatelookup.NewTemplateLookup(mgr.GetClient(), descriptorProvider, maintenanceWindow),
}).SetupWithManager(
mgr, options, kyma.SetupOptions{
ListenerAddr: flagVar.KymaListenerAddr,
Expand Down
3 changes: 2 additions & 1 deletion internal/controller/kyma/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ type Reconciler struct {
IsManagedKyma bool
Metrics *metrics.KymaMetrics
RemoteCatalog *remote.RemoteCatalog
TemplateLookup *templatelookup.TemplateLookup
}

// +kubebuilder:rbac:groups=operator.kyma-project.io,resources=kymas,verbs=get;list;watch;create;update;patch;delete
Expand Down Expand Up @@ -504,7 +505,7 @@ func (r *Reconciler) updateKyma(ctx context.Context, kyma *v1beta2.Kyma) error {
}

func (r *Reconciler) reconcileManifests(ctx context.Context, kyma *v1beta2.Kyma) error {
templates := templatelookup.NewTemplateLookup(client.Reader(r), r.DescriptorProvider).GetRegularTemplates(ctx, kyma)
templates := r.TemplateLookup.GetRegularTemplates(ctx, kyma)
prsr := parser.NewParser(r.Client, r.DescriptorProvider, r.InKCPMode, r.RemoteSyncNamespace)
modules := prsr.GenerateModulesFromTemplates(kyma, templates)

Expand Down
44 changes: 0 additions & 44 deletions internal/maintenancewindows/maintenance_policy_handler.go

This file was deleted.

112 changes: 0 additions & 112 deletions internal/maintenancewindows/maintenance_policy_handler_test.go

This file was deleted.

110 changes: 110 additions & 0 deletions internal/maintenancewindows/maintenance_window.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package maintenancewindows

import (
"errors"
"fmt"
"os"
"time"

"github.com/go-logr/logr"

"github.com/kyma-project/lifecycle-manager/api/v1beta2"
"github.com/kyma-project/lifecycle-manager/maintenancewindows/resolver"
)

var ErrNoMaintenanceWindowPolicyConfigured = errors.New("no maintenance window policy configured")

type MaintenanceWindowPolicy interface {
Resolve(runtime *resolver.Runtime, opts ...interface{}) (*resolver.ResolvedWindow, error)
}

type MaintenanceWindow struct {
// make this private once we refactor the API
// https://github.com/kyma-project/lifecycle-manager/issues/2190
MaintenanceWindowPolicy MaintenanceWindowPolicy
}

func InitializeMaintenanceWindow(log logr.Logger,
policiesDirectory, policyName string,
) (*MaintenanceWindow, error) {
if err := os.Setenv(resolver.PolicyPathENV, policiesDirectory); err != nil {
return nil, fmt.Errorf("failed to set the policy path env variable, %w", err)
}

policyFilePath := fmt.Sprintf("%s/%s.json", policiesDirectory, policyName)
if !MaintenancePolicyFileExists(policyFilePath) {
log.Info("maintenance windows policy file does not exist")
return &MaintenanceWindow{
MaintenanceWindowPolicy: nil,
}, nil
}

maintenancePolicyPool, err := resolver.GetMaintenancePolicyPool()
if err != nil {
return nil, fmt.Errorf("failed to get maintenance policy pool, %w", err)
}

maintenancePolicy, err := resolver.GetMaintenancePolicy(maintenancePolicyPool, policyName)
if err != nil {
return nil, fmt.Errorf("failed to get maintenance window policy, %w", err)
}

return &MaintenanceWindow{
MaintenanceWindowPolicy: maintenancePolicy,
}, nil
}

func MaintenancePolicyFileExists(policyFilePath string) bool {
if _, err := os.Stat(policyFilePath); os.IsNotExist(err) {
return false
}

return true
}

// IsRequired determines if a maintenance window is required to update the given module.
func (MaintenanceWindow) IsRequired(moduleTemplate *v1beta2.ModuleTemplate, kyma *v1beta2.Kyma) bool {
if !moduleTemplate.Spec.RequiresDowntime {
return false
}

if kyma.Spec.SkipMaintenanceWindows {
return false
}

// module not installed yet => no need for maintenance window
moduleStatus := kyma.Status.GetModuleStatus(moduleTemplate.Spec.ModuleName)
if moduleStatus == nil {
return false
}

// module already installed in this version => no need for maintenance window
installedVersion := moduleStatus.Version
return installedVersion != moduleTemplate.Spec.Version
}

// IsActive determines if a maintenance window is currently active.
func (mw MaintenanceWindow) IsActive(kyma *v1beta2.Kyma) (bool, error) {
if mw.MaintenanceWindowPolicy == nil {
return false, ErrNoMaintenanceWindowPolicyConfigured
}

runtime := &resolver.Runtime{
GlobalAccountID: kyma.GetGlobalAccount(),
Region: kyma.GetRegion(),
PlatformRegion: kyma.GetPlatformRegion(),
Plan: kyma.GetPlan(),
}

resolvedWindow, err := mw.MaintenanceWindowPolicy.Resolve(runtime)
if err != nil {
return false, err
}

now := time.Now()
if now.After(resolvedWindow.Begin) && now.Before(resolvedWindow.End) {
return true, nil
}

return false, nil
}
Loading

0 comments on commit 5d6ce78

Please sign in to comment.