generated from kyma-project/template-repository
-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Creating Gardener Cluster CR as part of cluster provisioning #293
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
3d9c5a1
Creating Gardener Cluster CR
koala7659 8227960
restore original code
koala7659 52d94d5
continue work on Gardener cluster creation
koala7659 e75430b
fix compilation error
koala7659 39717ab
fixing bugs discovered during testing
koala7659 d8e1cb5
remove unnecessary comment
koala7659 8a0d444
Merge remote-tracking branch 'origin/main' into create-gardener-cr
koala7659 658dcef
fix linter error for formatting error string
koala7659 109f4a7
Merge remote-tracking branch 'origin/main' into create-gardener-cr
koala7659 711dee4
unit tests implementation for creating gardener cluster CR
koala7659 dfb2290
Adjusting integration tests to verify creation of GardenerCluster CR
koala7659 36eafa4
Linter fixes
koala7659 5436f54
Typo fix and enable sequence verification
koala7659 3d66037
Change name of the label kyma name to operator.kyma-project.io/kyma-…
koala7659 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
internal/controller/runtime/fsm/runtime_fsm_create_kubeconfig.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package fsm | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
gardener "github.com/gardener/gardener/pkg/apis/core/v1beta1" | ||
imv1 "github.com/kyma-project/infrastructure-manager/api/v1" | ||
k8serrors "k8s.io/apimachinery/pkg/api/errors" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/types" | ||
ctrl "sigs.k8s.io/controller-runtime" | ||
) | ||
|
||
func sFnCreateKubeconfig(ctx context.Context, m *fsm, s *systemState) (stateFn, *ctrl.Result, error) { | ||
m.log.Info("Create Gardener Cluster CR state") | ||
|
||
runtimeID := s.instance.Labels[imv1.LabelKymaRuntimeID] | ||
|
||
var cluster imv1.GardenerCluster | ||
err := m.Get(ctx, types.NamespacedName{ | ||
Namespace: s.instance.Namespace, | ||
Name: runtimeID, | ||
}, &cluster) | ||
|
||
if err != nil { | ||
if !k8serrors.IsNotFound(err) { | ||
m.log.Error(err, "GardenerCluster CR read error", "name", runtimeID) | ||
s.instance.UpdateStatePending(imv1.ConditionTypeRuntimeKubeconfigReady, imv1.ConditionReasonKubernetesAPIErr, "False", err.Error()) | ||
return updateStatusAndStop() | ||
} | ||
|
||
m.log.Info("GardenerCluster CR not found, creating a new one", "Name", runtimeID) | ||
err = m.Create(ctx, makeGardenerClusterForRuntime(s.instance, s.shoot)) | ||
if err != nil { | ||
m.log.Error(err, "GardenerCluster CR create error", "name", runtimeID) | ||
s.instance.UpdateStatePending(imv1.ConditionTypeRuntimeKubeconfigReady, imv1.ConditionReasonKubernetesAPIErr, "False", err.Error()) | ||
return updateStatusAndStop() | ||
} | ||
|
||
m.log.Info("Gardener Cluster CR created, waiting for readiness", "Name", runtimeID) | ||
s.instance.UpdateStatePending(imv1.ConditionTypeRuntimeKubeconfigReady, imv1.ConditionReasonGardenerCRCreated, "Unknown", "Gardener Cluster CR created, waiting for readiness") | ||
return updateStatusAndRequeueAfter(controlPlaneRequeueDuration) | ||
} | ||
|
||
if cluster.Status.State != imv1.ReadyState { | ||
m.log.Info("GardenerCluster CR is not ready yet, requeue", "Name", runtimeID, "State", cluster.Status.State) | ||
return requeueAfter(controlPlaneRequeueDuration) | ||
} | ||
|
||
m.log.Info("GardenerCluster CR is ready", "Name", runtimeID) | ||
|
||
return ensureStatusConditionIsSetAndContinue(&s.instance, | ||
imv1.ConditionTypeRuntimeKubeconfigReady, | ||
imv1.ConditionReasonGardenerCRReady, | ||
"Gardener Cluster CR is ready.", | ||
sFnProcessShoot) | ||
} | ||
|
||
func makeGardenerClusterForRuntime(runtime imv1.Runtime, shoot *gardener.Shoot) *imv1.GardenerCluster { | ||
gardenCluster := &imv1.GardenerCluster{ | ||
TypeMeta: metav1.TypeMeta{ | ||
Kind: "GardenerCluster", | ||
APIVersion: imv1.GroupVersion.String(), | ||
}, | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: runtime.Labels[imv1.LabelKymaRuntimeID], | ||
Namespace: runtime.Namespace, | ||
Annotations: map[string]string{ | ||
"skr-domain": *shoot.Spec.DNS.Domain, | ||
}, | ||
Labels: map[string]string{ | ||
imv1.LabelKymaInstanceID: runtime.Labels[imv1.LabelKymaInstanceID], | ||
imv1.LabelKymaRuntimeID: runtime.Labels[imv1.LabelKymaRuntimeID], | ||
imv1.LabelKymaBrokerPlanID: runtime.Labels[imv1.LabelKymaBrokerPlanID], | ||
imv1.LabelKymaBrokerPlanName: runtime.Labels[imv1.LabelKymaBrokerPlanName], | ||
imv1.LabelKymaGlobalAccountID: runtime.Labels[imv1.LabelKymaGlobalAccountID], | ||
imv1.LabelKymaSubaccountID: runtime.Labels[imv1.LabelKymaSubaccountID], // BTW most likely this value will be missing | ||
imv1.LabelKymaName: runtime.Labels[imv1.LabelKymaName], | ||
|
||
// values from Runtime CR fields | ||
imv1.LabelKymaPlatformRegion: runtime.Spec.Shoot.PlatformRegion, | ||
imv1.LabelKymaRegion: runtime.Spec.Shoot.Region, | ||
imv1.LabelKymaShootName: shoot.Name, | ||
|
||
// hardcoded values | ||
imv1.LabelKymaManagedBy: "infrastructure-manager", | ||
imv1.LabelKymaInternal: "true", | ||
}, | ||
}, | ||
Spec: imv1.GardenerClusterSpec{ | ||
Shoot: imv1.Shoot{ | ||
Name: shoot.Name, | ||
}, | ||
Kubeconfig: imv1.Kubeconfig{ | ||
Secret: imv1.Secret{ | ||
Name: fmt.Sprintf("kubeconfig-%s", runtime.Labels[imv1.LabelKymaRuntimeID]), | ||
Namespace: runtime.Namespace, | ||
Key: "config", | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
return gardenCluster | ||
} |
166 changes: 166 additions & 0 deletions
166
internal/controller/runtime/fsm/runtime_fsm_create_kubeconfig_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
package fsm | ||
|
||
/* | ||
import ( | ||
"context" | ||
"time" | ||
|
||
gardener "github.com/gardener/gardener/pkg/apis/core/v1beta1" | ||
imv1 "github.com/kyma-project/infrastructure-manager/api/v1" | ||
. "github.com/onsi/ginkgo/v2" //nolint:revive | ||
. "github.com/onsi/gomega" //nolint:revive | ||
"github.com/onsi/gomega/types" | ||
"k8s.io/apimachinery/pkg/api/meta" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
util "k8s.io/apimachinery/pkg/util/runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
) | ||
|
||
var _ = Describe("KIM sFnCreateKubeconfig", func() { | ||
now := metav1.NewTime(time.Now()) | ||
|
||
testCtx, cancel := context.WithTimeout(context.Background(), time.Second) | ||
defer cancel() | ||
|
||
// GIVEN | ||
|
||
testScheme := runtime.NewScheme() | ||
util.Must(imv1.AddToScheme(testScheme)) | ||
|
||
withTestSchemeAndObjects := func(objs ...client.Object) fakeFSMOpt { | ||
return func(fsm *fsm) error { | ||
return withFakedK8sClient(testScheme, objs...)(fsm) | ||
} | ||
} | ||
|
||
testRtWithLables := imv1.Runtime{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "test-instance", | ||
Namespace: "default", | ||
Labels: map[string]string{ | ||
imv1.LabelKymaRuntimeID: "059dbc39-fd2b-4186-b0e5-8a1bc8ede5b8", | ||
imv1.LabelKymaInstanceID: "test-instance", | ||
imv1.LabelKymaBrokerPlanID: "broker-plan-id", | ||
imv1.LabelKymaGlobalAccountID: "461f6292-8085-41c8-af0c-e185f39b5e18", | ||
imv1.LabelKymaGlobalSubaccountID: "c5ad84ae-3d1b-4592-bee1-f022661f7b30", | ||
imv1.LabelKymaRegion: "region", | ||
imv1.LabelKymaBrokerPlanName: "aws", | ||
imv1.LabelKymaName: "caadafae-1234-1234-1234-123456789abc", | ||
}, | ||
}, | ||
} | ||
|
||
testRtWithFinalizerNoProvisioningCondition := imv1.Runtime{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "test-instance", | ||
Namespace: "default", | ||
Finalizers: []string{"test-me-plz"}, | ||
}, | ||
} | ||
|
||
testRtWithFinalizerAndProvisioningCondition := imv1.Runtime{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "test-instance", | ||
Namespace: "default", | ||
Finalizers: []string{"test-me-plz"}, | ||
}, | ||
} | ||
|
||
provisioningCondition := metav1.Condition{ | ||
Type: string(imv1.ConditionTypeRuntimeProvisioned), | ||
Status: metav1.ConditionUnknown, | ||
LastTransitionTime: now, | ||
Reason: "Test reason", | ||
Message: "Test message", | ||
} | ||
meta.SetStatusCondition(&testRtWithFinalizerAndProvisioningCondition.Status.Conditions, provisioningCondition) | ||
|
||
testShoot := gardener.Shoot{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "test-instance", | ||
Namespace: "default", | ||
}, | ||
} | ||
|
||
testFunction := buildTestFunction(sFnCreateKubeconfig) | ||
|
||
// WHEN/THAN | ||
|
||
DescribeTable( | ||
"transition graph validation", | ||
testFunction, | ||
Entry( | ||
"should return nothing when CR is being deleted without finalizer and shoot is missing", | ||
testCtx, | ||
must(newFakeFSM, withTestFinalizer), | ||
&systemState{instance: testRtWithDeletionTimestamp}, | ||
testOpts{ | ||
MatchExpectedErr: BeNil(), | ||
MatchNextFnState: BeNil(), | ||
}, | ||
), | ||
Entry( | ||
"should return sFnUpdateStatus when CR is being deleted with finalizer and shoot is missing - Remove finalizer", | ||
testCtx, | ||
must(newFakeFSM, withTestFinalizer, withTestSchemeAndObjects(&testRtWithLables)), | ||
&systemState{instance: testRtWithDeletionTimestampAndFinalizer}, | ||
testOpts{ | ||
MatchExpectedErr: BeNil(), | ||
MatchNextFnState: haveName("sFnProcessShoot"), | ||
}, | ||
), | ||
Entry( | ||
"should return sFnDeleteShoot and no error when CR is being deleted with finalizer and shoot exists", | ||
testCtx, | ||
must(newFakeFSM, withTestFinalizer), | ||
&systemState{instance: testRtWithDeletionTimestampAndFinalizer, shoot: &testShoot}, | ||
testOpts{ | ||
MatchExpectedErr: BeNil(), | ||
MatchNextFnState: haveName("sFnDeleteShoot"), | ||
}, | ||
), | ||
Entry( | ||
"should return sFnUpdateStatus and no error when CR has been created without finalizer - Add finalizer", | ||
testCtx, | ||
must(newFakeFSM, withTestFinalizer, withTestSchemeAndObjects(&testRt)), | ||
&systemState{instance: testRt}, | ||
testOpts{ | ||
MatchExpectedErr: BeNil(), | ||
MatchNextFnState: BeNil(), | ||
StateMatch: []types.GomegaMatcher{haveFinalizer("test-me-plz")}, | ||
}, | ||
), | ||
Entry( | ||
"should return sFnUpdateStatus and no error when there is no Provisioning Condition - Add condition", | ||
testCtx, | ||
must(newFakeFSM, withTestFinalizer), | ||
&systemState{instance: testRtWithFinalizerNoProvisioningCondition}, | ||
testOpts{ | ||
MatchExpectedErr: BeNil(), | ||
MatchNextFnState: haveName("sFnUpdateStatus"), | ||
}, | ||
), | ||
Entry( | ||
"should return sFnCreateStatus and no error when exists Provisioning Condition and shoot is missing", | ||
testCtx, | ||
must(newFakeFSM, withTestFinalizer), | ||
&systemState{instance: testRtWithFinalizerAndProvisioningCondition}, | ||
testOpts{ | ||
MatchExpectedErr: BeNil(), | ||
MatchNextFnState: haveName("sFnCreateShoot"), | ||
}, | ||
), | ||
Entry( | ||
"should return sFnSelectShootProcessing and no error when exists Provisioning Condition and shoot exists", | ||
testCtx, | ||
must(newFakeFSM, withTestFinalizer), | ||
&systemState{instance: testRtWithFinalizerAndProvisioningCondition, shoot: &testShoot}, | ||
testOpts{ | ||
MatchExpectedErr: BeNil(), | ||
MatchNextFnState: haveName("sFnSelectShootProcessing"), | ||
}, | ||
), | ||
) | ||
}) | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
entry says that it should return
sFnUpdateStatus
while matcher isMatchNextFnState: BeNil(),