diff --git a/internal/controller/runtime/fsm/runtime_fsm_create_shoot.go b/internal/controller/runtime/fsm/runtime_fsm_create_shoot.go index aafc6028..6a064958 100644 --- a/internal/controller/runtime/fsm/runtime_fsm_create_shoot.go +++ b/internal/controller/runtime/fsm/runtime_fsm_create_shoot.go @@ -18,7 +18,7 @@ func sFnCreateShoot(ctx context.Context, m *fsm, s *systemState) (stateFn, *ctrl if s.instance.Spec.Shoot.EnforceSeedLocation != nil && *s.instance.Spec.Shoot.EnforceSeedLocation { seedAvailable, regionsWithSeeds, err := seedForRegionAvailable(ctx, m.ShootClient, s.instance.Spec.Shoot.Provider.Type, s.instance.Spec.Shoot.Region) if err != nil { - msg := fmt.Sprintf("Failed to verify whether seed for region %s exists.", s.instance.Spec.Shoot.Region) + msg := fmt.Sprintf("Failed to verify whether seed is available for the region %s.", s.instance.Spec.Shoot.Region) m.log.Error(err, msg) s.instance.UpdateStatePending( imv1.ConditionTypeRuntimeProvisioned, @@ -30,7 +30,7 @@ func sFnCreateShoot(ctx context.Context, m *fsm, s *systemState) (stateFn, *ctrl } if !seedAvailable { - msg := fmt.Sprintf("Seed for region %s doesn't exist. The followig regions have seeds assigned: %v.", s.instance.Spec.Shoot.Region, regionsWithSeeds) + msg := fmt.Sprintf("Cannot find available seed for the region %s. The followig regions have seeds ready: %v.", s.instance.Spec.Shoot.Region, regionsWithSeeds) m.log.Error(nil, msg) m.Metrics.IncRuntimeFSMStopCounter() return updateStatePendingWithErrorAndStop( diff --git a/internal/controller/runtime/fsm/seed.go b/internal/controller/runtime/fsm/seed.go index 583ed507..ebfe4fa3 100644 --- a/internal/controller/runtime/fsm/seed.go +++ b/internal/controller/runtime/fsm/seed.go @@ -3,7 +3,9 @@ package fsm import ( "context" gardener_types "github.com/gardener/gardener/pkg/apis/core/v1beta1" + v1beta1helper "github.com/gardener/gardener/pkg/apis/core/v1beta1/helper" "sigs.k8s.io/controller-runtime/pkg/client" + "slices" ) func seedForRegionAvailable(context context.Context, client client.Client, providerType, region string) (bool, []string, error) { @@ -11,21 +13,40 @@ func seedForRegionAvailable(context context.Context, client client.Client, provi var regionsWithSeeds []string err := client.List(context, &seedList) + if err != nil { return false, nil, err } for _, seed := range seedList.Items { - if seed.Spec.Provider.Type == providerType { + if seed.Spec.Provider.Type == providerType && + seedCanBeUsed(&seed) && + !slices.Contains(regionsWithSeeds, seed.Spec.Provider.Region) { regionsWithSeeds = append(regionsWithSeeds, seed.Spec.Provider.Region) } } - for _, seed := range seedList.Items { - if seed.Spec.Provider.Region == region && seed.Spec.Provider.Type == providerType { - return true, regionsWithSeeds, nil + return slices.Contains(regionsWithSeeds, region), regionsWithSeeds, nil +} + +func seedCanBeUsed(seed *gardener_types.Seed) bool { + return seed.DeletionTimestamp == nil && seed.Spec.Settings.Scheduling.Visible && verifySeedReadiness(seed) +} + +func verifySeedReadiness(seed *gardener_types.Seed) bool { + if seed.Status.LastOperation == nil { + return false + } + + if cond := v1beta1helper.GetCondition(seed.Status.Conditions, gardener_types.SeedGardenletReady); cond == nil || cond.Status != gardener_types.ConditionTrue { + return false + } + + if seed.Spec.Backup != nil { + if cond := v1beta1helper.GetCondition(seed.Status.Conditions, gardener_types.SeedBackupBucketsReady); cond == nil || cond.Status != gardener_types.ConditionTrue { + return false } } - return false, regionsWithSeeds, nil + return true } diff --git a/internal/controller/runtime/suite_test.go b/internal/controller/runtime/suite_test.go index 2739b02a..aa1dbb99 100644 --- a/internal/controller/runtime/suite_test.go +++ b/internal/controller/runtime/suite_test.go @@ -271,11 +271,29 @@ func fixSeedSequenceForProvisioning(providerType string) []*gardener_api.SeedLis func getSeedForRegion(providerType, region string) gardener_api.Seed { return gardener_api.Seed{ Spec: gardener_api.SeedSpec{ + Settings: &gardener_api.SeedSettings{ + Scheduling: &gardener_api.SeedSettingScheduling{ + Visible: true, + }, + }, Provider: gardener_api.SeedProvider{ Type: providerType, Region: region, }, }, + Status: gardener_api.SeedStatus{ + LastOperation: &gardener_api.LastOperation{}, + Conditions: []gardener_api.Condition{ + { + Type: gardener_api.SeedGardenletReady, + Status: gardener_api.ConditionTrue, + }, + { + Type: gardener_api.SeedBackupBucketsReady, + Status: gardener_api.ConditionTrue, + }, + }, + }, } }