Skip to content

Commit

Permalink
YDBOPS-9679 dynconfig CMS ReplaceConfig (#214)
Browse files Browse the repository at this point in the history
  • Loading branch information
kobzonega authored Sep 26, 2024
1 parent 56e6f09 commit d8d4809
Show file tree
Hide file tree
Showing 16 changed files with 858 additions and 75 deletions.
21 changes: 1 addition & 20 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,15 @@
*.dylib
*.test
*.out
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
.idea/**/contentModel.xml
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
.idea/**/gradle.xml
.idea/**/libraries
cmake-build-*/
.idea/**/mongoSettings.xml
*.iws
out/
.idea/*
.idea_modules/
atlassian-ide-plugin.xml
.idea/replstate.xml
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
.idea/httpRequests
.idea/caches/build_file_checksums.ser

bin/
config/
Expand Down
6 changes: 4 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,15 @@ kind-load:
docker tag cr.yandex/yc/ydb-operator:latest kind/ydb-operator:current
kind load docker-image kind/ydb-operator:current --name kind-ydb-operator

opts ?= ''

.PHONY: unit-test
unit-test: manifests generate fmt vet envtest ## Run unit tests
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use --arch=amd64 $(ENVTEST_K8S_VERSION) -p path)" go test -v -timeout 900s -p 1 ./internal/... -ginkgo.v -coverprofile cover.out
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use --arch=amd64 $(ENVTEST_K8S_VERSION) -p path)" go test -v -timeout 900s -p 1 ./internal/... -ginkgo.v -coverprofile cover.out $(opts)

.PHONY: e2e-test
e2e-test: manifests generate fmt vet docker-build kind-init kind-load ## Run e2e tests
go test -v -timeout 3600s -p 1 ./e2e/... -ginkgo.v
go test -v -timeout 3600s -p 1 ./e2e/... -ginkgo.v $(opts)

.PHONY: test
test: unit-test e2e-test ## Run all tests
Expand Down
84 changes: 61 additions & 23 deletions api/v1alpha1/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package v1alpha1

import (
"bytes"
"errors"
"fmt"
"strconv"

Expand Down Expand Up @@ -60,19 +61,22 @@ func BuildConfiguration(cr *Storage, crDB *Database) ([]byte, error) {
rawYamlConfiguration = cr.Spec.Configuration
}

dynconfig, err := ParseDynconfig(rawYamlConfiguration)
if err == nil {
if dynconfig.Config["hosts"] == nil {
success, dynConfig, err := ParseDynConfig(rawYamlConfiguration)
if success {
if err != nil {
return nil, fmt.Errorf("failed to parse dynconfig, error: %w", err)
}
if dynConfig.Config["hosts"] == nil {
hosts := generateHosts(cr)
dynconfig.Config["hosts"] = hosts
dynConfig.Config["hosts"] = hosts
}

return yaml.Marshal(dynconfig)
return yaml.Marshal(dynConfig)
}

err = yaml.Unmarshal([]byte(rawYamlConfiguration), &config)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to serialize YAML config, error: %w", err)
}

if config["hosts"] == nil {
Expand All @@ -84,28 +88,62 @@ func BuildConfiguration(cr *Storage, crDB *Database) ([]byte, error) {
}

func ParseConfiguration(rawYamlConfiguration string) (schema.Configuration, error) {
configuration := schema.Configuration{}

dynconfig, err := ParseDynconfig(rawYamlConfiguration)
if err == nil {
config, err := yaml.Marshal(dynconfig.Config)
if err != nil {
return configuration, err
}
rawYamlConfiguration = string(config)
}

dec := yaml.NewDecoder(bytes.NewReader([]byte(rawYamlConfiguration)))
dec.KnownFields(false)
err = dec.Decode(&configuration)

return configuration, err
var configuration schema.Configuration
err := dec.Decode(&configuration)
if err != nil {
return schema.Configuration{}, nil
}

return configuration, nil
}

func ParseDynconfig(rawYamlConfiguration string) (schema.Dynconfig, error) {
dynconfig := schema.Dynconfig{}
func ParseDynConfig(rawYamlConfiguration string) (bool, schema.DynConfig, error) {
dec := yaml.NewDecoder(bytes.NewReader([]byte(rawYamlConfiguration)))
dec.KnownFields(true)
err := dec.Decode(&dynconfig)
return dynconfig, err

var dynConfig schema.DynConfig
err := dec.Decode(&dynConfig)
if err != nil {
return false, schema.DynConfig{}, fmt.Errorf("error unmarshal yaml to dynconfig: %w", err)
}

err = validateDynConfig(dynConfig)
if err != nil {
return true, dynConfig, fmt.Errorf("error validate dynconfig: %w", err)
}

return true, dynConfig, err
}

func validateDynConfig(dynConfig schema.DynConfig) error {
if _, exist := dynConfig.Config["yaml_config_enabled"]; !exist {
return errors.New("failed to find mandatory `yaml_config_enabled` field inside config")
}

if _, exist := dynConfig.Config["static_erasure"]; !exist {
return errors.New("failed to find mandatory `static_erasure` field inside config")
}

if _, exist := dynConfig.Config["host_configs"]; !exist {
return errors.New("failed to find mandatory `host_configs` field inside config")
}

if _, exist := dynConfig.Config["blob_storage_config"]; !exist {
return errors.New("failed to find mandatory `blob_storage_config` field inside config")
}

return nil
}

func GetConfigForCMS(dynConfig schema.DynConfig) ([]byte, error) {
delete(dynConfig.Config, "static_erasure")
delete(dynConfig.Config, "host_configs")
delete(dynConfig.Config, "nameservice_config")
delete(dynConfig.Config, "blob_storage_config")
delete(dynConfig.Config, "hosts")

return yaml.Marshal(dynConfig)
}
37 changes: 35 additions & 2 deletions api/v1alpha1/storage_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/golang-jwt/jwt/v4"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"gopkg.in/yaml.v3"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/utils/strings/slices"
Expand Down Expand Up @@ -195,7 +196,23 @@ func isSignAlgorithmSupported(alg string) bool {
func (r *Storage) ValidateCreate() error {
storagelog.Info("validate create", "name", r.Name)

configuration, err := ParseConfiguration(r.Spec.Configuration)
var rawYamlConfiguration string
success, dynConfig, err := ParseDynConfig(r.Spec.Configuration)
if success {
if err != nil {
return fmt.Errorf("failed to parse dynconfig, error: %w", err)
}
config, err := yaml.Marshal(dynConfig.Config)
if err != nil {
return fmt.Errorf("failed to serialize YAML config, error: %w", err)
}
rawYamlConfiguration = string(config)
} else {
rawYamlConfiguration = r.Spec.Configuration
}

var configuration schema.Configuration
configuration, err = ParseConfiguration(rawYamlConfiguration)
if err != nil {
return fmt.Errorf("failed to parse configuration, error: %w", err)
}
Expand Down Expand Up @@ -293,7 +310,23 @@ func hasUpdatesBesidesFrozen(oldStorage, newStorage *Storage) (bool, string) {
func (r *Storage) ValidateUpdate(old runtime.Object) error {
storagelog.Info("validate update", "name", r.Name)

configuration, err := ParseConfiguration(r.Spec.Configuration)
var rawYamlConfiguration string
success, dynConfig, err := ParseDynConfig(r.Spec.Configuration)
if success {
if err != nil {
return fmt.Errorf("failed to parse dynconfig, error: %w", err)
}
config, err := yaml.Marshal(dynConfig.Config)
if err != nil {
return fmt.Errorf("failed to serialize YAML config, error: %w", err)
}
rawYamlConfiguration = string(config)
} else {
rawYamlConfiguration = r.Spec.Configuration
}

var configuration schema.Configuration
configuration, err = ParseConfiguration(rawYamlConfiguration)
if err != nil {
return fmt.Errorf("failed to parse configuration, error: %w", err)
}
Expand Down
4 changes: 2 additions & 2 deletions deploy/ydb-operator/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.5.25
version: 0.5.26

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "0.5.25"
appVersion: "0.5.26"
111 changes: 111 additions & 0 deletions e2e/tests/data/storage-block-4-2-dynconfig.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
metadata:
kind: MainConfig
cluster: ""
version: 0
allowed_labels: {}
selector_config: []
config:
yaml_config_enabled: true
static_erasure: block-4-2
host_configs:
- drive:
- path: SectorMap:1:1
type: SSD
host_config_id: 1
domains_config:
domain:
- name: Root
storage_pool_types:
- kind: ssd
pool_config:
box_id: 1
erasure_species: block-4-2
kind: ssd
pdisk_filter:
- property:
- type: SSD
vdisk_kind: Default
state_storage:
- ring:
node: [1, 2, 3, 4, 5, 6, 7, 8]
nto_select: 5
ssid: 1
table_service_config:
sql_version: 1
actor_system_config:
executor:
- name: System
threads: 1
type: BASIC
- name: User
threads: 1
type: BASIC
- name: Batch
threads: 1
type: BASIC
- name: IO
threads: 1
time_per_mailbox_micro_secs: 100
type: IO
- name: IC
spin_threshold: 10
threads: 4
time_per_mailbox_micro_secs: 100
type: BASIC
scheduler:
progress_threshold: 10000
resolution: 256
spin_threshold: 0
blob_storage_config:
service_set:
groups:
- erasure_species: block-4-2
rings:
- fail_domains:
- vdisk_locations:
- node_id: storage-0
pdisk_category: SSD
path: SectorMap:1:1
- vdisk_locations:
- node_id: storage-1
pdisk_category: SSD
path: SectorMap:1:1
- vdisk_locations:
- node_id: storage-2
pdisk_category: SSD
path: SectorMap:1:1
- vdisk_locations:
- node_id: storage-3
pdisk_category: SSD
path: SectorMap:1:1
- vdisk_locations:
- node_id: storage-4
pdisk_category: SSD
path: SectorMap:1:1
- vdisk_locations:
- node_id: storage-5
pdisk_category: SSD
path: SectorMap:1:1
- vdisk_locations:
- node_id: storage-6
pdisk_category: SSD
path: SectorMap:1:1
- vdisk_locations:
- node_id: storage-7
pdisk_category: SSD
path: SectorMap:1:1
channel_profile_config:
profile:
- channel:
- erasure_species: block-4-2
pdisk_category: 1
storage_pool_kind: ssd
- erasure_species: block-4-2
pdisk_category: 1
storage_pool_kind: ssd
- erasure_species: block-4-2
pdisk_category: 1
storage_pool_kind: ssd
profile_id: 0
grpc_config:
port: 2135
Loading

0 comments on commit d8d4809

Please sign in to comment.