Skip to content
Draft
3 changes: 2 additions & 1 deletion api/v1alpha1/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ const (
AnnotationNodeHost = "ydb.tech/node-host"
AnnotationNodeDomain = "ydb.tech/node-domain"

AnnotationValueTrue = "true"
RemoteFinalizerKey = "ydb.tech/remote-finalizer"
StorageFinalizerKey = "ydb.tech/storage-finalizer"

legacyTenantNameFormat = "/%s/%s"
)
Expand Down
87 changes: 79 additions & 8 deletions internal/annotations/annotations.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,86 @@
package annotations

import (
corev1 "k8s.io/api/core/v1"

"github.com/ydb-platform/ydb-kubernetes-operator/api/v1alpha1"
)

const (
PrimaryResourceStorageAnnotation = "ydb.tech/primary-resource-storage"
PrimaryResourceDatabaseAnnotation = "ydb.tech/primary-resource-database"
RemoteResourceVersionAnnotation = "ydb.tech/remote-resource-version"
ConfigurationChecksum = "ydb.tech/configuration-checksum"
StorageFinalizerKey = "ydb.tech/storage-finalizer"
RemoteFinalizerKey = "ydb.tech/remote-finalizer"
LastAppliedAnnotation = "ydb.tech/last-applied"
PrimaryResourceStorage = "ydb.tech/primary-resource-storage"
PrimaryResourceDatabase = "ydb.tech/primary-resource-database"
RemoteResourceVersion = "ydb.tech/remote-resource-version"
ConfigurationChecksum = "ydb.tech/configuration-checksum"
LastApplied = "ydb.tech/last-applied"
)

var (
AcceptedDNSPolicy = []string{
string(corev1.DNSClusterFirstWithHostNet),
string(corev1.DNSClusterFirst),
string(corev1.DNSDefault),
string(corev1.DNSNone),
}
SupportedAnnotations = map[string]struct{}{
v1alpha1.AnnotationSkipInitialization: {},
v1alpha1.AnnotationUpdateStrategyOnDelete: {},
v1alpha1.AnnotationUpdateDNSPolicy: {},
v1alpha1.AnnotationDisableLivenessProbe: {},
v1alpha1.AnnotationDataCenter: {},
v1alpha1.AnnotationGRPCPublicHost: {},
v1alpha1.AnnotationNodeHost: {},
v1alpha1.AnnotationNodeDomain: {},
}
)

type Annotations map[string]string

func Common(objAnnotations Annotations) Annotations {
annotations := Annotations{}

annotations.Merge(getSupportedAnnotations(objAnnotations))

return annotations
}

func (an Annotations) Merge(other map[string]string) map[string]string {
if other == nil {
return an
}

for k, v := range other {
an[k] = v
}

return an
}

func (an Annotations) AsMap() map[string]string {
return an
}

func (an Annotations) Copy() Annotations {
res := Annotations{}

for k, v := range an {
res[k] = v
}

return res
}

func getSupportedAnnotations(annotations map[string]string) map[string]string {
common := make(map[string]string)

for key, value := range annotations {
if _, exists := SupportedAnnotations[key]; exists {
common[key] = value
}
}

return common
}

func CompareLastAppliedAnnotation(map1, map2 map[string]string) bool {
value1 := getLastAppliedAnnotation(map1)
value2 := getLastAppliedAnnotation(map2)
Expand All @@ -18,7 +89,7 @@ func CompareLastAppliedAnnotation(map1, map2 map[string]string) bool {

func getLastAppliedAnnotation(annotations map[string]string) string {
for key, value := range annotations {
if key == LastAppliedAnnotation {
if key == LastApplied {
return value
}
}
Expand Down
47 changes: 47 additions & 0 deletions internal/annotations/annotations_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package annotations_test

import (
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
ydbannotations "github.com/ydb-platform/ydb-kubernetes-operator/internal/annotations"
)

func TestLabels(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Label suite")
}

var _ = Describe("Testing annotations", func() {
It("merges two sets of annotations", func() {
fstLabels := ydbannotations.Annotations{
"a": "a",
"b": "b",
}

sndLabels := ydbannotations.Annotations{
"c": "c",
"d": "d",
}

Expect(fstLabels.Merge(sndLabels)).To(BeEquivalentTo(map[string]string{
"a": "a",
"b": "b",
"c": "c",
"d": "d",
}))
})

It("sets correct defaults", func() {
Expect(ydbannotations.Common(map[string]string{
"ydb.tech/skip-initialization": "true",
"ydb.tech/node-host": "ydb-testing.k8s-c.yandex.net",
"ydb.tech/last-applied": "some-body",
"sample-annotation": "test",
})).To(BeEquivalentTo(map[string]string{
"ydb.tech/skip-initialization": "true",
"ydb.tech/node-host": "ydb-testing.k8s-c.yandex.net",
}))
})
})
21 changes: 12 additions & 9 deletions internal/controllers/database/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package database
import (
"context"
"fmt"
"strconv"

ydb "github.com/ydb-platform/ydb-go-sdk/v3"
corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -34,15 +35,17 @@ func (r *Reconciler) setInitPipelineStatus(
}

// This block is special internal logic that skips all Database initialization.
if value, ok := database.Annotations[v1alpha1.AnnotationSkipInitialization]; ok && value == v1alpha1.AnnotationValueTrue {
r.Log.Info("Database initialization disabled (with annotation), proceed with caution")
r.Recorder.Event(
database,
corev1.EventTypeWarning,
"SkippingInit",
"Skipping initialization due to skip annotation present, be careful!",
)
return r.setInitDatabaseCompleted(ctx, database, "Database initialization not performed because initialization is skipped")
if value, ok := database.Annotations[v1alpha1.AnnotationSkipInitialization]; ok {
if isTrue, _ := strconv.ParseBool(value); isTrue {
r.Log.Info("Database initialization disabled (with annotation), proceed with caution")
r.Recorder.Event(
database,
corev1.EventTypeWarning,
"SkippingInit",
"Skipping initialization due to skip annotation present, be careful!",
)
return r.setInitDatabaseCompleted(ctx, database, "Database initialization not performed because initialization is skipped")
}
}

if meta.IsStatusConditionTrue(database.Status.Conditions, OldDatabaseInitializedCondition) {
Expand Down
34 changes: 17 additions & 17 deletions internal/controllers/remotedatabasenodeset/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/go-logr/logr"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
apilabels "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/selection"
"k8s.io/apimachinery/pkg/types"
Expand All @@ -25,7 +25,7 @@ import (
"github.com/ydb-platform/ydb-kubernetes-operator/api/v1alpha1"
ydbannotations "github.com/ydb-platform/ydb-kubernetes-operator/internal/annotations"
. "github.com/ydb-platform/ydb-kubernetes-operator/internal/controllers/constants" //nolint:revive,stylecheck
ydblabels "github.com/ydb-platform/ydb-kubernetes-operator/internal/labels"
"github.com/ydb-platform/ydb-kubernetes-operator/internal/labels"
"github.com/ydb-platform/ydb-kubernetes-operator/internal/resources"
)

Expand Down Expand Up @@ -72,15 +72,15 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
// The object is not being deleted, so if it does not have our finalizer,
// then lets add the finalizer and update the object. This is equivalent
// to registering our finalizer.
if !controllerutil.ContainsFinalizer(remoteDatabaseNodeSet, ydbannotations.RemoteFinalizerKey) {
controllerutil.AddFinalizer(remoteDatabaseNodeSet, ydbannotations.RemoteFinalizerKey)
if !controllerutil.ContainsFinalizer(remoteDatabaseNodeSet, v1alpha1.RemoteFinalizerKey) {
controllerutil.AddFinalizer(remoteDatabaseNodeSet, v1alpha1.RemoteFinalizerKey)
if err := r.RemoteClient.Update(ctx, remoteDatabaseNodeSet); err != nil {
return ctrl.Result{RequeueAfter: DefaultRequeueDelay}, err
}
}
} else {
// The object is being deleted
if controllerutil.ContainsFinalizer(remoteDatabaseNodeSet, ydbannotations.RemoteFinalizerKey) {
if controllerutil.ContainsFinalizer(remoteDatabaseNodeSet, v1alpha1.RemoteFinalizerKey) {
// our finalizer is present, so lets handle any external dependency
if err := r.deleteExternalResources(ctx, remoteDatabaseNodeSet); err != nil {
// if fail to delete the external dependency here, return with error
Expand All @@ -89,7 +89,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
}

// remove our finalizer from the list and update it.
controllerutil.RemoveFinalizer(remoteDatabaseNodeSet, ydbannotations.RemoteFinalizerKey)
controllerutil.RemoveFinalizer(remoteDatabaseNodeSet, v1alpha1.RemoteFinalizerKey)
if err := r.RemoteClient.Update(ctx, remoteDatabaseNodeSet); err != nil {
return ctrl.Result{RequeueAfter: DefaultRequeueDelay}, err
}
Expand Down Expand Up @@ -119,7 +119,7 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager, remoteCluster *cluster.C
requests := make([]reconcile.Request, 0)

annotations := mapObj.GetAnnotations()
primaryResourceName, exist := annotations[ydbannotations.PrimaryResourceDatabaseAnnotation]
primaryResourceName, exist := annotations[ydbannotations.PrimaryResourceDatabase]
if exist {
databaseNodeSets := &v1alpha1.DatabaseNodeSetList{}
if err := r.Client.List(
Expand Down Expand Up @@ -192,32 +192,32 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager, remoteCluster *cluster.C
Complete(r)
}

func buildLocalSelector() (labels.Selector, error) {
labelRequirements := []labels.Requirement{}
localClusterRequirement, err := labels.NewRequirement(
ydblabels.RemoteClusterKey,
func buildLocalSelector() (apilabels.Selector, error) {
labelRequirements := []apilabels.Requirement{}
localClusterRequirement, err := apilabels.NewRequirement(
labels.RemoteClusterKey,
selection.Exists,
[]string{},
)
if err != nil {
return nil, err
}
labelRequirements = append(labelRequirements, *localClusterRequirement)
return labels.NewSelector().Add(labelRequirements...), nil
return apilabels.NewSelector().Add(labelRequirements...), nil
}

func BuildRemoteSelector(remoteCluster string) (labels.Selector, error) {
labelRequirements := []labels.Requirement{}
remoteClusterRequirement, err := labels.NewRequirement(
ydblabels.RemoteClusterKey,
func BuildRemoteSelector(remoteCluster string) (apilabels.Selector, error) {
labelRequirements := []apilabels.Requirement{}
remoteClusterRequirement, err := apilabels.NewRequirement(
labels.RemoteClusterKey,
selection.Equals,
[]string{remoteCluster},
)
if err != nil {
return nil, err
}
labelRequirements = append(labelRequirements, *remoteClusterRequirement)
return labels.NewSelector().Add(labelRequirements...), nil
return apilabels.NewSelector().Add(labelRequirements...), nil
}

func (r *Reconciler) deleteExternalResources(
Expand Down
32 changes: 16 additions & 16 deletions internal/controllers/remotedatabasenodeset/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -529,25 +529,25 @@ var _ = Describe("RemoteDatabaseNodeSet controller tests", func() {
return err
}

primaryResourceStorage, exist := remoteSecret.Annotations[ydbannotations.PrimaryResourceStorageAnnotation]
primaryResourceStorage, exist := remoteSecret.Annotations[ydbannotations.PrimaryResourceStorage]
if !exist {
return fmt.Errorf("annotation %s does not exist on remoteSecret %s", ydbannotations.PrimaryResourceStorageAnnotation, remoteSecret.Name)
return fmt.Errorf("annotation %s does not exist on remoteSecret %s", ydbannotations.PrimaryResourceStorage, remoteSecret.Name)
}
if primaryResourceStorage != foundRemoteStorageNodeSet.Spec.StorageRef.Name {
return fmt.Errorf("primaryResourceName %s does not equal storageRef name %s", primaryResourceStorage, foundRemoteDatabaseNodeSet.Spec.DatabaseRef.Name)
}

primaryResourceDatabase, exist := remoteSecret.Annotations[ydbannotations.PrimaryResourceDatabaseAnnotation]
primaryResourceDatabase, exist := remoteSecret.Annotations[ydbannotations.PrimaryResourceDatabase]
if !exist {
return fmt.Errorf("annotation %s does not exist on remoteSecret %s", ydbannotations.PrimaryResourceDatabaseAnnotation, remoteSecret.Name)
return fmt.Errorf("annotation %s does not exist on remoteSecret %s", ydbannotations.PrimaryResourceDatabase, remoteSecret.Name)
}
if primaryResourceDatabase != foundRemoteDatabaseNodeSet.Spec.DatabaseRef.Name {
return fmt.Errorf("primaryResourceName %s does not equal databaseRef name %s", primaryResourceDatabase, foundRemoteDatabaseNodeSet.Spec.DatabaseRef.Name)
}

remoteRV, exist := remoteSecret.Annotations[ydbannotations.RemoteResourceVersionAnnotation]
remoteRV, exist := remoteSecret.Annotations[ydbannotations.RemoteResourceVersion]
if !exist {
return fmt.Errorf("annotation %s does not exist on remoteSecret %s", ydbannotations.RemoteResourceVersionAnnotation, remoteSecret.Name)
return fmt.Errorf("annotation %s does not exist on remoteSecret %s", ydbannotations.RemoteResourceVersion, remoteSecret.Name)
}
if localSecret.GetResourceVersion() != remoteRV {
return fmt.Errorf("localRV %s does not equal remoteRV %s", localSecret.GetResourceVersion(), remoteRV)
Expand Down Expand Up @@ -620,22 +620,22 @@ var _ = Describe("RemoteDatabaseNodeSet controller tests", func() {
return err
}

_, exist := remoteSecret.Annotations[ydbannotations.PrimaryResourceStorageAnnotation]
_, exist := remoteSecret.Annotations[ydbannotations.PrimaryResourceStorage]
if exist {
return fmt.Errorf("annotation %s still exist on remoteSecret %s", ydbannotations.PrimaryResourceStorageAnnotation, remoteSecret.Name)
return fmt.Errorf("annotation %s still exist on remoteSecret %s", ydbannotations.PrimaryResourceStorage, remoteSecret.Name)
}

primaryResourceDatabase, exist := remoteSecret.Annotations[ydbannotations.PrimaryResourceDatabaseAnnotation]
primaryResourceDatabase, exist := remoteSecret.Annotations[ydbannotations.PrimaryResourceDatabase]
if !exist {
return fmt.Errorf("annotation %s does not exist on remoteSecret %s", ydbannotations.PrimaryResourceDatabaseAnnotation, remoteSecret.Name)
return fmt.Errorf("annotation %s does not exist on remoteSecret %s", ydbannotations.PrimaryResourceDatabase, remoteSecret.Name)
}
if primaryResourceDatabase != foundRemoteDatabaseNodeSet.Spec.DatabaseRef.Name {
return fmt.Errorf("primaryResourceName %s does not equal databaseRef name %s", primaryResourceDatabase, foundRemoteDatabaseNodeSet.Spec.DatabaseRef.Name)
}

remoteRV, exist := remoteSecret.Annotations[ydbannotations.RemoteResourceVersionAnnotation]
remoteRV, exist := remoteSecret.Annotations[ydbannotations.RemoteResourceVersion]
if !exist {
return fmt.Errorf("annotation %s does not exist on remoteSecret %s", ydbannotations.RemoteResourceVersionAnnotation, remoteSecret.Name)
return fmt.Errorf("annotation %s does not exist on remoteSecret %s", ydbannotations.RemoteResourceVersion, remoteSecret.Name)
}
if localSecret.GetResourceVersion() != remoteRV {
return fmt.Errorf("localRV %s does not equal remoteRV %s", localSecret.GetResourceVersion(), remoteRV)
Expand Down Expand Up @@ -686,17 +686,17 @@ var _ = Describe("RemoteDatabaseNodeSet controller tests", func() {
return err
}

primaryResourceDatabase, exist := remoteSecret.Annotations[ydbannotations.PrimaryResourceDatabaseAnnotation]
primaryResourceDatabase, exist := remoteSecret.Annotations[ydbannotations.PrimaryResourceDatabase]
if !exist {
return fmt.Errorf("annotation %s does not exist on remoteSecret %s", ydbannotations.PrimaryResourceDatabaseAnnotation, remoteSecret.Name)
return fmt.Errorf("annotation %s does not exist on remoteSecret %s", ydbannotations.PrimaryResourceDatabase, remoteSecret.Name)
}
if primaryResourceDatabase != foundRemoteDatabaseNodeSet.Spec.DatabaseRef.Name {
return fmt.Errorf("primaryResourceName %s does not equal databaseRef name %s", primaryResourceDatabase, foundRemoteDatabaseNodeSet.Spec.DatabaseRef.Name)
}

remoteRV, exist := remoteSecret.Annotations[ydbannotations.RemoteResourceVersionAnnotation]
remoteRV, exist := remoteSecret.Annotations[ydbannotations.RemoteResourceVersion]
if !exist {
return fmt.Errorf("annotation %s does not exist on remoteSecret %s", ydbannotations.RemoteResourceVersionAnnotation, remoteSecret.Name)
return fmt.Errorf("annotation %s does not exist on remoteSecret %s", ydbannotations.RemoteResourceVersion, remoteSecret.Name)
}
if localSecret.GetResourceVersion() != remoteRV {
return fmt.Errorf("localRV %s does not equal remoteRV %s", localSecret.GetResourceVersion(), remoteRV)
Expand Down
4 changes: 2 additions & 2 deletions internal/controllers/remotedatabasenodeset/remote_objects.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ func (r *Reconciler) removeUnusedRemoteObjects(
// Remove annotation if no one another DatabaseNodeSet
if !existInDatabase {
// Try to update existing object in local cluster by rawPatch
patch := []byte(fmt.Sprintf(`{"metadata": {"annotations": {"%s": null}}}`, ydbannotations.PrimaryResourceStorageAnnotation))
patch := []byte(fmt.Sprintf(`{"metadata": {"annotations": {"%s": null}}}`, ydbannotations.PrimaryResourceStorage))
updateErr := r.Client.Patch(ctx, localObj, client.RawPatch(types.StrategicMergePatchType, patch))
if updateErr != nil {
r.Recorder.Event(
Expand All @@ -298,7 +298,7 @@ func (r *Reconciler) removeUnusedRemoteObjects(
}

// Delete resource if annotation `ydb.tech/primary-resource-storage` does not exist
_, existInStorage := localObj.GetAnnotations()[ydbannotations.PrimaryResourceStorageAnnotation]
_, existInStorage := localObj.GetAnnotations()[ydbannotations.PrimaryResourceStorage]
if !existInStorage {
// Try to delete unused resource from local cluster
deleteErr := r.Client.Delete(ctx, localObj)
Expand Down
Loading
Loading