Skip to content

Commit b8a7aec

Browse files
committed
Merge branch 'master' into YDBOPS-9692
2 parents 6659d67 + 11716fc commit b8a7aec

File tree

23 files changed

+1398
-731
lines changed

23 files changed

+1398
-731
lines changed

api/v1alpha1/const.go

+6
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ const (
4444
DefaultDatabaseDomain = "Root"
4545
DefaultDatabaseEncryptionPin = "EmptyPin"
4646

47+
LabelDeploymentKey = "deployment"
48+
LabelDeploymentValueKubernetes = "kubernetes"
49+
LabelSharedDatabaseKey = "shared"
50+
LabelSharedDatabaseValueTrue = "true"
51+
LabelSharedDatabaseValueFalse = "false"
52+
4753
AnnotationUpdateStrategyOnDelete = "ydb.tech/update-strategy-on-delete"
4854
AnnotationUpdateDNSPolicy = "ydb.tech/update-dns-policy"
4955
AnnotationSkipInitialization = "ydb.tech/skip-initialization"

deploy/ydb-operator/Chart.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ type: application
1515
# This is the chart version. This version number should be incremented each time you make changes
1616
# to the chart and its templates, including the app version.
1717
# Versions are expected to follow Semantic Versioning (https://semver.org/)
18-
version: 0.5.7
18+
version: 0.5.13
1919

2020
# This is the version number of the application being deployed. This version number should be
2121
# incremented each time you make changes to the application. Versions are not expected to
2222
# follow Semantic Versioning. They should reflect the version the application is using.
2323
# It is recommended to use it with quotes.
24-
appVersion: "0.5.7"
24+
appVersion: "0.5.13"

internal/controllers/constants/constants.go

+19-6
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,23 @@ const (
1919
OldStorageInitializedCondition = "StorageReady"
2020
OldDatabaseInitializedCondition = "TenantInitialized"
2121

22-
StoragePausedCondition = "StoragePaused"
23-
StorageInitializedCondition = "StorageInitialized"
24-
StorageNodeSetReadyCondition = "StorageNodeSetReady"
25-
DatabasePausedCondition = "DatabasePaused"
26-
DatabaseInitializedCondition = "DatabaseInitialized"
27-
DatabaseNodeSetReadyCondition = "DatabaseNodeSetReady"
22+
StoragePreparedCondition = "StoragePrepared"
23+
StorageInitializedCondition = "StorageInitialized"
24+
StorageProvisionedCondition = "StorageProvisioned"
25+
StoragePausedCondition = "StoragePaused"
26+
StorageReadyCondition = "StorageReady"
27+
28+
DatabasePreparedCondition = "DatabasePrepared"
29+
DatabaseInitializedCondition = "DatabaseInitialized"
30+
DatabaseProvisionedCondition = "DatabaseProvisioned"
31+
DatabasePausedCondition = "DatabasePaused"
32+
DatabaseReadyCondition = "DatabaseReady"
33+
34+
NodeSetPreparedCondition = "NodeSetPrepared"
35+
NodeSetProvisionedCondition = "NodeSetProvisioned"
36+
NodeSetReadyCondition = "NodeSetReady"
37+
NodeSetPausedCondition = "NodeSetPaused"
38+
2839
RemoteResourceSyncedCondition = "ResourceSynced"
2940

3041
Stop = true
@@ -48,6 +59,7 @@ const (
4859
DatabasePaused ClusterState = "Paused"
4960

5061
DatabaseNodeSetPending ClusterState = "Pending"
62+
DatabaseNodeSetPreparing ClusterState = "Preparing"
5163
DatabaseNodeSetProvisioning ClusterState = "Provisioning"
5264
DatabaseNodeSetReady ClusterState = "Ready"
5365
DatabaseNodeSetPaused ClusterState = "Paused"
@@ -60,6 +72,7 @@ const (
6072
StoragePaused ClusterState = "Paused"
6173

6274
StorageNodeSetPending ClusterState = "Pending"
75+
StorageNodeSetPreparing ClusterState = "Preparing"
6376
StorageNodeSetProvisioning ClusterState = "Provisioning"
6477
StorageNodeSetReady ClusterState = "Ready"
6578
StorageNodeSetPaused ClusterState = "Paused"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package database_test
2+
3+
import (
4+
"context"
5+
"errors"
6+
"path/filepath"
7+
"strings"
8+
"testing"
9+
10+
. "github.com/onsi/ginkgo/v2"
11+
. "github.com/onsi/gomega"
12+
appsv1 "k8s.io/api/apps/v1"
13+
corev1 "k8s.io/api/core/v1"
14+
"k8s.io/apimachinery/pkg/api/meta"
15+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
16+
"k8s.io/apimachinery/pkg/types"
17+
"sigs.k8s.io/controller-runtime/pkg/client"
18+
"sigs.k8s.io/controller-runtime/pkg/manager"
19+
20+
"github.com/ydb-platform/ydb-kubernetes-operator/api/v1alpha1"
21+
testobjects "github.com/ydb-platform/ydb-kubernetes-operator/e2e/tests/test-objects"
22+
. "github.com/ydb-platform/ydb-kubernetes-operator/internal/controllers/constants"
23+
"github.com/ydb-platform/ydb-kubernetes-operator/internal/controllers/database"
24+
"github.com/ydb-platform/ydb-kubernetes-operator/internal/controllers/storage"
25+
"github.com/ydb-platform/ydb-kubernetes-operator/internal/test"
26+
)
27+
28+
var (
29+
k8sClient client.Client
30+
ctx context.Context
31+
)
32+
33+
func TestAPIs(t *testing.T) {
34+
RegisterFailHandler(Fail)
35+
36+
test.SetupK8STestManager(&ctx, &k8sClient, func(mgr *manager.Manager) []test.Reconciler {
37+
return []test.Reconciler{
38+
&storage.Reconciler{
39+
Client: k8sClient,
40+
Scheme: (*mgr).GetScheme(),
41+
},
42+
&database.Reconciler{
43+
Client: k8sClient,
44+
Scheme: (*mgr).GetScheme(),
45+
},
46+
}
47+
})
48+
49+
RunSpecs(t, "Database controller medium tests suite")
50+
}
51+
52+
var _ = Describe("Database controller medium tests", func() {
53+
var namespace corev1.Namespace
54+
var storageSample v1alpha1.Storage
55+
56+
BeforeEach(func() {
57+
namespace = corev1.Namespace{
58+
ObjectMeta: metav1.ObjectMeta{
59+
Name: testobjects.YdbNamespace,
60+
},
61+
}
62+
Expect(k8sClient.Create(ctx, &namespace)).Should(Succeed())
63+
storageSample = *testobjects.DefaultStorage(filepath.Join("..", "..", "..", "e2e", "tests", "data", "storage-block-4-2-config.yaml"))
64+
Expect(k8sClient.Create(ctx, &storageSample)).Should(Succeed())
65+
66+
By("checking that Storage created on local cluster...")
67+
foundStorage := v1alpha1.Storage{}
68+
Eventually(func() bool {
69+
Expect(k8sClient.Get(ctx, types.NamespacedName{
70+
Name: storageSample.Name,
71+
Namespace: testobjects.YdbNamespace,
72+
}, &foundStorage))
73+
return foundStorage.Status.State == StorageInitializing
74+
}, test.Timeout, test.Interval).Should(BeTrue())
75+
76+
By("set condition Initialized to Storage...")
77+
Eventually(func() error {
78+
foundStorage := v1alpha1.Storage{}
79+
Expect(k8sClient.Get(ctx, types.NamespacedName{
80+
Name: storageSample.Name,
81+
Namespace: testobjects.YdbNamespace,
82+
}, &foundStorage))
83+
meta.SetStatusCondition(&foundStorage.Status.Conditions, metav1.Condition{
84+
Type: StorageInitializedCondition,
85+
Status: metav1.ConditionTrue,
86+
Reason: ReasonCompleted,
87+
})
88+
return k8sClient.Status().Update(ctx, &foundStorage)
89+
}, test.Timeout, test.Interval).ShouldNot(HaveOccurred())
90+
})
91+
92+
AfterEach(func() {
93+
Expect(k8sClient.Delete(ctx, &storageSample)).Should(Succeed())
94+
Expect(k8sClient.Delete(ctx, &namespace)).Should(Succeed())
95+
})
96+
97+
It("Checking field propagation to objects", func() {
98+
By("Check that Shared Database was created...")
99+
databaseSample := *testobjects.DefaultDatabase()
100+
databaseSample.Spec.SharedResources = &v1alpha1.DatabaseResources{
101+
StorageUnits: []v1alpha1.StorageUnit{
102+
{
103+
UnitKind: "ssd",
104+
Count: 1,
105+
},
106+
},
107+
}
108+
Expect(k8sClient.Create(ctx, &databaseSample)).Should(Succeed())
109+
110+
By("Check that StatefulSet was created...")
111+
databaseStatefulSet := appsv1.StatefulSet{}
112+
foundStatefulSets := appsv1.StatefulSetList{}
113+
Eventually(func() error {
114+
err := k8sClient.List(ctx, &foundStatefulSets, client.InNamespace(
115+
testobjects.YdbNamespace))
116+
if err != nil {
117+
return err
118+
}
119+
for idx, statefulSet := range foundStatefulSets.Items {
120+
if statefulSet.Name == testobjects.DatabaseName {
121+
databaseStatefulSet = foundStatefulSets.Items[idx]
122+
return nil
123+
}
124+
}
125+
return errors.New("failed to find StatefulSet")
126+
}, test.Timeout, test.Interval).ShouldNot(HaveOccurred())
127+
128+
By("Check that args `--label` propagated to pods...", func() {
129+
podContainerArgs := databaseStatefulSet.Spec.Template.Spec.Containers[0].Args
130+
var labelArgKey string
131+
var labelArgValue string
132+
for idx, arg := range podContainerArgs {
133+
if arg == "--label" {
134+
labelArgKey = strings.Split(podContainerArgs[idx+1], "=")[0]
135+
labelArgValue = strings.Split(podContainerArgs[idx+1], "=")[1]
136+
if labelArgKey == v1alpha1.LabelDeploymentKey {
137+
Expect(labelArgValue).Should(BeEquivalentTo(v1alpha1.LabelDeploymentValueKubernetes))
138+
}
139+
if labelArgKey == v1alpha1.LabelSharedDatabaseKey {
140+
Expect(labelArgValue).Should(BeEquivalentTo(v1alpha1.LabelSharedDatabaseValueTrue))
141+
}
142+
}
143+
}
144+
})
145+
})
146+
})

internal/controllers/database/init.go

+29-68
Original file line numberDiff line numberDiff line change
@@ -17,62 +17,35 @@ import (
1717
"github.com/ydb-platform/ydb-kubernetes-operator/internal/resources"
1818
)
1919

20-
func (r *Reconciler) processSkipInitPipeline(
20+
func (r *Reconciler) setInitPipelineStatus(
2121
ctx context.Context,
2222
database *resources.DatabaseBuilder,
2323
) (bool, ctrl.Result, error) {
24-
r.Log.Info("running step processSkipInitPipeline")
25-
r.Log.Info("Database initialization disabled (with annotation), proceed with caution")
26-
27-
r.Recorder.Event(
28-
database,
29-
corev1.EventTypeWarning,
30-
"SkippingInit",
31-
"Skipping database creation due to skip annotation present, be careful!",
32-
)
33-
34-
return r.setInitDatabaseCompleted(
35-
ctx,
36-
database,
37-
"Database creation not performed because initialization is skipped",
38-
)
39-
}
40-
41-
func (r *Reconciler) setInitialStatus(
42-
ctx context.Context,
43-
database *resources.DatabaseBuilder,
44-
) (bool, ctrl.Result, error) {
45-
r.Log.Info("running step setInitialStatus")
46-
47-
if meta.IsStatusConditionTrue(database.Status.Conditions, OldDatabaseInitializedCondition) {
24+
if database.Status.State == DatabasePreparing {
4825
meta.SetStatusCondition(&database.Status.Conditions, metav1.Condition{
4926
Type: DatabaseInitializedCondition,
50-
Status: "True",
51-
Reason: ReasonCompleted,
52-
Message: "Database initialized successfully",
27+
Status: metav1.ConditionFalse,
28+
Reason: ReasonInProgress,
29+
Message: "Database has not been initialized yet",
5330
})
54-
database.Status.State = DatabaseReady
55-
return r.updateStatus(ctx, database)
31+
database.Status.State = DatabaseInitializing
32+
return r.updateStatus(ctx, database, StatusUpdateRequeueDelay)
5633
}
5734

35+
// This block is special internal logic that skips all Database initialization.
5836
if value, ok := database.Annotations[v1alpha1.AnnotationSkipInitialization]; ok && value == v1alpha1.AnnotationValueTrue {
59-
if meta.FindStatusCondition(database.Status.Conditions, DatabaseInitializedCondition) == nil ||
60-
meta.IsStatusConditionFalse(database.Status.Conditions, DatabaseInitializedCondition) {
61-
return r.processSkipInitPipeline(ctx, database)
62-
}
63-
return Stop, ctrl.Result{RequeueAfter: DefaultRequeueDelay}, nil
37+
r.Log.Info("Database initialization disabled (with annotation), proceed with caution")
38+
r.Recorder.Event(
39+
database,
40+
corev1.EventTypeWarning,
41+
"SkippingInit",
42+
"Skipping initialization due to skip annotation present, be careful!",
43+
)
44+
return r.setInitDatabaseCompleted(ctx, database, "Database initialization not performed because initialization is skipped")
6445
}
6546

66-
if database.Status.State == DatabasePending ||
67-
meta.FindStatusCondition(database.Status.Conditions, DatabaseInitializedCondition) == nil {
68-
meta.SetStatusCondition(&database.Status.Conditions, metav1.Condition{
69-
Type: DatabaseInitializedCondition,
70-
Status: "False",
71-
Reason: ReasonInProgress,
72-
Message: "Database has not been initialized yet",
73-
})
74-
database.Status.State = DatabasePreparing
75-
return r.updateStatus(ctx, database)
47+
if meta.IsStatusConditionTrue(database.Status.Conditions, OldDatabaseInitializedCondition) {
48+
return r.setInitDatabaseCompleted(ctx, database, "Database initialized successfully")
7649
}
7750

7851
return Continue, ctrl.Result{Requeue: false}, nil
@@ -85,26 +58,17 @@ func (r *Reconciler) setInitDatabaseCompleted(
8558
) (bool, ctrl.Result, error) {
8659
meta.SetStatusCondition(&database.Status.Conditions, metav1.Condition{
8760
Type: DatabaseInitializedCondition,
88-
Status: "True",
61+
Status: metav1.ConditionTrue,
8962
Reason: ReasonCompleted,
9063
Message: message,
9164
})
92-
database.Status.State = DatabaseProvisioning
93-
94-
return r.updateStatus(ctx, database)
65+
return r.updateStatus(ctx, database, StatusUpdateRequeueDelay)
9566
}
9667

97-
func (r *Reconciler) initializeDatabase(
68+
func (r *Reconciler) initializeTenant(
9869
ctx context.Context,
9970
database *resources.DatabaseBuilder,
10071
) (bool, ctrl.Result, error) {
101-
r.Log.Info("running step initializeDatabase")
102-
103-
if database.Status.State == DatabasePreparing {
104-
database.Status.State = DatabaseInitializing
105-
return r.updateStatus(ctx, database)
106-
}
107-
10872
path := database.GetDatabasePath()
10973
var storageUnits []v1alpha1.StorageUnit
11074
var shared bool
@@ -150,16 +114,15 @@ func (r *Reconciler) initializeDatabase(
150114
return Stop, ctrl.Result{RequeueAfter: SharedDatabaseAwaitRequeueDelay}, err
151115
}
152116

153-
if sharedDatabaseCr.Status.State != "Ready" {
117+
if !meta.IsStatusConditionTrue(sharedDatabaseCr.Status.Conditions, DatabaseProvisionedCondition) {
154118
r.Recorder.Event(
155119
database,
156120
corev1.EventTypeWarning,
157121
"Pending",
158122
fmt.Sprintf(
159-
"Referenced shared Database (%s, %s) in a bad state: %s != Ready",
123+
"Referenced shared Database (%s, %s) is not Provisioned",
160124
database.Spec.ServerlessResources.SharedDatabaseRef.Name,
161125
database.Spec.ServerlessResources.SharedDatabaseRef.Namespace,
162-
sharedDatabaseCr.Status.State,
163126
),
164127
)
165128
return Stop, ctrl.Result{RequeueAfter: SharedDatabaseAwaitRequeueDelay}, err
@@ -213,7 +176,12 @@ func (r *Reconciler) initializeDatabase(
213176
"InitializingFailed",
214177
fmt.Sprintf("Error creating tenant %s: %s", tenant.Path, err),
215178
)
216-
return Stop, ctrl.Result{RequeueAfter: DatabaseInitializationRequeueDelay}, err
179+
meta.SetStatusCondition(&database.Status.Conditions, metav1.Condition{
180+
Type: DatabaseInitializedCondition,
181+
Status: metav1.ConditionFalse,
182+
Reason: ReasonInProgress,
183+
})
184+
return r.updateStatus(ctx, database, DatabaseInitializationRequeueDelay)
217185
}
218186
r.Recorder.Event(
219187
database,
@@ -222,12 +190,5 @@ func (r *Reconciler) initializeDatabase(
222190
fmt.Sprintf("Tenant %s created", tenant.Path),
223191
)
224192

225-
r.Recorder.Event(
226-
database,
227-
corev1.EventTypeNormal,
228-
"DatabaseReady",
229-
"Database is initialized",
230-
)
231-
232193
return r.setInitDatabaseCompleted(ctx, database, "Database initialized successfully")
233194
}

0 commit comments

Comments
 (0)