Skip to content

Commit

Permalink
webhook defaulter for configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
kobzonega committed Jan 22, 2024
1 parent 5738230 commit 94d65df
Show file tree
Hide file tree
Showing 18 changed files with 406 additions and 543 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ kind-load:

.PHONY: test
test: manifests generate fmt vet docker-build kind-init kind-load envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test -timeout 1800s -p 1 ./... -coverprofile cover.out
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test -timeout 1800s -p 1 ./... -ginkgo.v -coverprofile cover.out

.PHONY: clean
clean:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package configuration
package v1alpha1

import (
"crypto/sha256"
Expand All @@ -8,7 +8,6 @@ import (

"gopkg.in/yaml.v3"

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

Expand All @@ -25,20 +24,20 @@ func hash(text string) string {
return fmt.Sprintf("%x", h.Sum(nil))
}

func generateSomeDefaults(cr *v1alpha1.Storage, crDB *v1alpha1.Database) schema.Configuration {
func generateSomeDefaults(cr *Storage, crDB *Database) schema.Configuration {
var hosts []schema.Host

for i := 0; i < int(cr.Spec.Nodes); i++ {
datacenter := "az-1"
if cr.Spec.Erasure == v1alpha1.ErasureMirror3DC {
if cr.Spec.Erasure == ErasureMirror3DC {
datacenter = fmt.Sprintf("az-%d", i%3)
}

hosts = append(hosts, schema.Host{
Host: fmt.Sprintf("%v-%d", cr.GetName(), i),
HostConfigID: 1, // TODO
NodeID: i + 1,
Port: v1alpha1.InterconnectPort,
Port: InterconnectPort,
WalleLocation: schema.WalleLocation{
Body: 12340 + i,
DataCenter: datacenter,
Expand Down Expand Up @@ -90,7 +89,7 @@ func tryFillMissingSections(
}
}

func Build(cr *v1alpha1.Storage, crDB *v1alpha1.Database) (map[string]string, error) {
func buildConfiguration(cr *Storage, crDB *Database) (string, error) {
config := make(map[string]interface{})

// If any kind of configuration exists on Database object, then
Expand All @@ -106,20 +105,16 @@ func Build(cr *v1alpha1.Storage, crDB *v1alpha1.Database) (map[string]string, er

err := yaml.Unmarshal([]byte(rawYamlConfiguration), &config)
if err != nil {
return nil, err
return "", err
}

generatedConfig := generateSomeDefaults(cr, crDB)
tryFillMissingSections(config, generatedConfig)

data, err := yaml.Marshal(config)
if err != nil {
return nil, err
return "", err
}

result := string(data)

return map[string]string{
v1alpha1.ConfigFileName: result,
}, nil
return string(data), nil
}
12 changes: 8 additions & 4 deletions api/v1alpha1/database_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,18 @@ type DatabaseSpec struct {
}

type DatabaseClusterSpec struct {
// Encryption configuration
// +optional
Encryption *EncryptionConfig `json:"encryption,omitempty"`

// YDB Storage cluster reference
// +required
StorageClusterRef NamespacedRef `json:"storageClusterRef"`

// YDB Storage Node broker address
// +optional
StorageEndpoint string `json:"storageEndpoint"`

// Encryption configuration
// +optional
Encryption *EncryptionConfig `json:"encryption,omitempty"`

// (Optional) YDB Image
// +optional
Image *PodImage `json:"image,omitempty"`
Expand Down
96 changes: 65 additions & 31 deletions api/v1alpha1/database_webhook.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package v1alpha1

import (
"context"
"errors"
"fmt"
"strings"

v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/webhook"

Expand All @@ -27,13 +30,12 @@ func (r *Database) SetupWebhookWithManager(mgr ctrl.Manager) error {
manager = mgr
return ctrl.NewWebhookManagedBy(mgr).
For(r).
WithDefaulter(&DatabaseDefaulter{Client: mgr.GetClient()}).
Complete()
}

//+kubebuilder:webhook:path=/mutate-ydb-tech-v1alpha1-database,mutating=true,failurePolicy=fail,sideEffects=None,groups=ydb.tech,resources=databases,verbs=create;update,versions=v1alpha1,name=mutate-database.ydb.tech,admissionReviewVersions=v1

var _ webhook.Defaulter = &Database{}

func (r *Database) GetDatabasePath() string {
if r.Spec.Path != "" {
return r.Spec.Path
Expand All @@ -45,66 +47,98 @@ func (r *Database) GetLegacyDatabasePath() string {
return fmt.Sprintf(legacyTenantNameFormat, r.Spec.Domain, r.Name) // FIXME: review later in context of multiple namespaces
}

// DatabaseDefaulter mutates Databases
// +k8s:deepcopy-gen=false
type DatabaseDefaulter struct {
Client client.Client
}

// Default implements webhook.Defaulter so a webhook will be registered for the type
func (r *Database) Default() {
databaselog.Info("default", "name", r.Name)
func (r *DatabaseDefaulter) Default(ctx context.Context, obj runtime.Object) error {
database := obj.(*Database)
databaselog.Info("default", "name", database.Name)

if r.Spec.StorageClusterRef.Namespace == "" {
r.Spec.StorageClusterRef.Namespace = r.Namespace
if database.Spec.StorageClusterRef.Namespace == "" {
database.Spec.StorageClusterRef.Namespace = database.Namespace
}

if r.Spec.ServerlessResources != nil {
if r.Spec.ServerlessResources.SharedDatabaseRef.Namespace == "" {
r.Spec.ServerlessResources.SharedDatabaseRef.Namespace = r.Namespace
if database.Spec.ServerlessResources != nil {
if database.Spec.ServerlessResources.SharedDatabaseRef.Namespace == "" {
database.Spec.ServerlessResources.SharedDatabaseRef.Namespace = database.Namespace
}
}

if r.Spec.Image == nil && r.Spec.Image.Name == "" {
if r.Spec.YDBVersion == "" {
r.Spec.Image.Name = fmt.Sprintf(ImagePathFormat, RegistryPath, DefaultTag)
storage := &Storage{}
err := r.Client.Get(ctx, types.NamespacedName{
Namespace: database.Spec.StorageClusterRef.Namespace,
Name: database.Spec.StorageClusterRef.Name,
}, storage)
if err != nil {
return err
}

if database.Spec.StorageEndpoint == "" {
database.Spec.StorageEndpoint = storage.GetGRPCEndpointWithProto()
}

configuration, err := buildConfiguration(storage, database)
if err != nil {
return err
}
database.Spec.Configuration = configuration

if database.Spec.Image == nil && database.Spec.Image.Name == "" {
if database.Spec.YDBVersion == "" {
database.Spec.Image.Name = fmt.Sprintf(ImagePathFormat, RegistryPath, DefaultTag)
} else {
r.Spec.Image.Name = fmt.Sprintf(ImagePathFormat, RegistryPath, r.Spec.YDBVersion)
database.Spec.Image.Name = fmt.Sprintf(ImagePathFormat, RegistryPath, database.Spec.YDBVersion)
}
}

if r.Spec.Image.PullPolicyName == nil {
if database.Spec.Image.PullPolicyName == nil {
policy := v1.PullIfNotPresent
r.Spec.Image.PullPolicyName = &policy
database.Spec.Image.PullPolicyName = &policy
}

if database.Spec.Service.GRPC.TLSConfiguration == nil {
database.Spec.Service.GRPC.TLSConfiguration = &TLSConfiguration{Enabled: false}
}

if r.Spec.Service.GRPC.TLSConfiguration == nil {
r.Spec.Service.GRPC.TLSConfiguration = &TLSConfiguration{Enabled: false}
if database.Spec.Service.Interconnect.TLSConfiguration == nil {
database.Spec.Service.Interconnect.TLSConfiguration = &TLSConfiguration{Enabled: false}
}

if r.Spec.Service.Interconnect.TLSConfiguration == nil {
r.Spec.Service.Interconnect.TLSConfiguration = &TLSConfiguration{Enabled: false}
if database.Spec.Service.Datastreams.TLSConfiguration == nil {
database.Spec.Service.Datastreams.TLSConfiguration = &TLSConfiguration{Enabled: false}
}

if r.Spec.Service.Datastreams.TLSConfiguration == nil {
r.Spec.Service.Datastreams.TLSConfiguration = &TLSConfiguration{Enabled: false}
if database.Spec.Domain == "" {
database.Spec.Domain = DefaultDatabaseDomain
}

if r.Spec.Domain == "" {
r.Spec.Domain = DefaultDatabaseDomain
if database.Spec.Path == "" {
database.Spec.Path = database.GetLegacyDatabasePath()
}

if r.Spec.Path == "" {
r.Spec.Path = r.GetLegacyDatabasePath()
if database.Spec.StorageEndpoint == "" {
database.Spec.Path = database.GetLegacyDatabasePath()
}

if r.Spec.Encryption == nil {
r.Spec.Encryption = &EncryptionConfig{Enabled: false}
if database.Spec.Encryption == nil {
database.Spec.Encryption = &EncryptionConfig{Enabled: false}
}

if r.Spec.Datastreams == nil {
r.Spec.Datastreams = &DatastreamsConfig{Enabled: false}
if database.Spec.Datastreams == nil {
database.Spec.Datastreams = &DatastreamsConfig{Enabled: false}
}

if r.Spec.Monitoring == nil {
r.Spec.Monitoring = &MonitoringOptions{
if database.Spec.Monitoring == nil {
database.Spec.Monitoring = &MonitoringOptions{
Enabled: false,
}
}

return nil
}

//+kubebuilder:webhook:path=/validate-ydb-tech-v1alpha1-database,mutating=true,failurePolicy=fail,sideEffects=None,groups=ydb.tech,resources=databases,verbs=create;update,versions=v1alpha1,name=validate-database.ydb.tech,admissionReviewVersions=v1
Expand Down
19 changes: 0 additions & 19 deletions api/v1alpha1/databasenodeset_types.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package v1alpha1

import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/ydb-platform/ydb-kubernetes-operator/internal/controllers/constants"
Expand All @@ -13,10 +12,6 @@ type DatabaseNodeSetSpec struct {
// +required
DatabaseRef NamespacedRef `json:"databaseRef"`

// YDB Storage Node broker address
// +required
StorageEndpoint string `json:"storageEndpoint"`

DatabaseClusterSpec `json:",inline"`

DatabaseNodeSpec `json:",inline"`
Expand Down Expand Up @@ -57,20 +52,6 @@ type DatabaseNodeSetSpecInline struct {
Remote bool `json:"remote,omitempty"`

DatabaseNodeSpec `json:",inline"`

// (Optional) If specified, the pod's topologySpreadConstraints.
// All topologySpreadConstraints are ANDed.
// +optional
// +patchMergeKey=topologyKey
// +patchStrategy=merge
// +listType=map
// +listMapKey=topologyKey
// +listMapKey=whenUnsatisfiable
TopologySpreadConstraints []corev1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty" patchStrategy:"merge" patchMergeKey:"topologyKey"`

// (Optional) If specified, the pod's priorityClassName.
// +optional
PriorityClassName string `json:"priorityClassName,omitempty"`
}

//+kubebuilder:object:root=true
Expand Down
Loading

0 comments on commit 94d65df

Please sign in to comment.