Skip to content
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: add default backend in the configuration file #968

Merged
merged 1 commit into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pkg/apis/core/v1/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ type Config struct {
}

const (
DefaultBackendName = "default"

BackendCurrent = "current"
BackendType = "type"
BackendConfigItems = "configs"
Expand Down
25 changes: 7 additions & 18 deletions pkg/backend/backend.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package backend

import (
"errors"
"fmt"

v1 "kusionstack.io/kusion/pkg/apis/core/v1"
Expand Down Expand Up @@ -29,28 +28,18 @@ type Backend interface {
// input name is empty, use the current backend. If no current backend is specified or backends config is empty,
// and the input name is empty, use the default local storage.
func NewBackend(name string) (Backend, error) {
var emptyCfg bool
cfg, err := config.GetConfig()
if errors.Is(err, config.ErrEmptyConfig) {
emptyCfg = true
} else if err != nil {
if err != nil {
return nil, err
} else if cfg.Backends == nil {
emptyCfg = true
}

var bkCfg *v1.BackendConfig
if name == "" && (emptyCfg || cfg.Backends.Current == "") {
// if empty backends config or empty current backend, use default local storage
bkCfg = &v1.BackendConfig{Type: v1.BackendTypeLocal}
} else {
if name == "" {
name = cfg.Backends.Current
}
bkCfg = cfg.Backends.Backends[name]
if bkCfg == nil {
return nil, fmt.Errorf("config of backend %s does not exist", name)
}
if name == "" {
name = cfg.Backends.Current
}
bkCfg = cfg.Backends.Backends[name]
if bkCfg == nil {
return nil, fmt.Errorf("config of backend %s does not exist", name)
}

var storage Backend
Expand Down
5 changes: 4 additions & 1 deletion pkg/backend/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ func mockConfig() *v1.Config {
Backends: &v1.BackendConfigs{
Current: "pre",
Backends: map[string]*v1.BackendConfig{
v1.DefaultBackendName: {
Type: v1.BackendTypeLocal,
},
"dev": {
Type: v1.BackendTypeLocal,
Configs: map[string]any{
Expand Down Expand Up @@ -76,7 +79,7 @@ func TestNewBackend(t *testing.T) {
success: true,
cfg: func() *v1.Config {
cfg := mockConfig()
cfg.Backends.Current = ""
cfg.Backends.Current = v1.DefaultBackendName
return cfg
}(),
envs: nil,
Expand Down
92 changes: 53 additions & 39 deletions pkg/config/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,13 @@ import (
const configFile = "config.yaml"

var (
ErrEmptyConfig = errors.New("empty config")
ErrEmptyConfigItem = errors.New("empty config item")
ErrConflictConfigItemType = errors.New("type of the config item conflicts between saved and registered")
ErrEmptyConfigItemKey = errors.New("empty config item key")
ErrEmptyConfigItemValue = errors.New("empty config item value")
ErrUnsupportedConfigItem = errors.New("unsupported config item")
ErrEmptyBackendName = errors.New("backend name should not be empty")
ErrInvalidBackendName = errors.New("backend name should not be current")
ErrEmptyConfigItem = errors.New("empty config item")
ErrConflictConfigItemType = errors.New("type of the config item conflicts between saved and registered")
ErrEmptyConfigItemKey = errors.New("empty config item key")
ErrEmptyConfigItemValue = errors.New("empty config item value")
ErrUnsupportedConfigItem = errors.New("unsupported config item")
ErrEmptyBackendName = errors.New("backend name should not be empty")
ErrInvalidBackendNameCurrent = errors.New("backend name should not be current")
)

// operator is used to execute the config management operation.
Expand All @@ -48,10 +47,47 @@ func newOperator() (*operator, error) {
return nil, fmt.Errorf("get kusion data folder failed, %w", err)
}

return &operator{
o := &operator{
configFilePath: filepath.Join(kusionDataDir, configFile),
registeredItems: newRegisteredItems(),
}, nil
config: &v1.Config{},
}

if err = o.initDefaultConfig(); err != nil {
return nil, err
}
return o, nil
}

// initDefaultConfig reads config from the config file and inits default config, which is called when new
// an operator. Now it inits the default backend.
func (o *operator) initDefaultConfig() error {
if err := o.readConfig(); err != nil {
return err
}

// set default backend config
if o.config.Backends == nil {
o.config.Backends = &v1.BackendConfigs{}
}
if o.config.Backends.Backends == nil {
o.config.Backends.Backends = make(map[string]*v1.BackendConfig)
}
var needWrite bool
defaultBackend := &v1.BackendConfig{Type: v1.BackendTypeLocal}
if !reflect.DeepEqual(o.config.Backends.Backends[v1.DefaultBackendName], defaultBackend) {
needWrite = true
o.config.Backends.Backends[v1.DefaultBackendName] = defaultBackend
}
if o.config.Backends.Current == "" {
needWrite = true
o.config.Backends.Current = v1.DefaultBackendName
}

if needWrite {
return o.writeConfig()
}
return nil
}

// readConfig reads config from config file.
Expand All @@ -68,9 +104,6 @@ func (o *operator) readConfig() error {
if err = yaml.Unmarshal(content, cfg); err != nil {
return fmt.Errorf("unmarshal kusion config failed, %w", err)
}
if reflect.ValueOf(*cfg).IsZero() {
cfg = nil
}
o.config = cfg
return nil
}
Expand Down Expand Up @@ -204,15 +237,12 @@ func (o *operator) deleteConfigItem(key string) error {
if err != nil {
return err
}
if info.validateDeleteFunc != nil {
if err = info.validateDeleteFunc(o.config, key); err != nil {
if info.validateUnsetFunc != nil {
if err = info.validateUnsetFunc(o.config, key); err != nil {
return err
}
}

if o.config == nil {
return nil
}
cfg, err := convertToCfgMap(o.config)
if err != nil {
return err
Expand All @@ -232,10 +262,6 @@ func (o *operator) deleteConfigItem(key string) error {
// getConfigItemWithLaxType gets the value of the specified config item from config, where the type of the
// value is that in the converted config map.
func getConfigItemWithLaxType(config *v1.Config, key string) (any, error) {
if config == nil {
return nil, ErrEmptyConfigItem
}

cfg, err := convertToCfgMap(config)
if err != nil {
return nil, err
Expand All @@ -251,9 +277,6 @@ func setItemInConfig(config *v1.Config, info *itemInfo, key string, value any) (
return nil, err
}

if config == nil {
config = &v1.Config{}
}
cfg, err := convertToCfgMap(config)
if err != nil {
return nil, err
Expand All @@ -267,9 +290,6 @@ func setItemInConfig(config *v1.Config, info *itemInfo, key string, value any) (
// tidyConfig is used to clean dirty empty block.
func tidyConfig(configAddr **v1.Config) {
config := *configAddr
if config == nil {
return
}

if config.Backends != nil {
for name, cfg := range config.Backends.Backends {
Expand All @@ -281,16 +301,10 @@ func tidyConfig(configAddr **v1.Config) {
}
}
if len(config.Backends.Backends) == 0 {
config.Backends.Backends = nil
}
if reflect.ValueOf(*config.Backends).IsZero() {
config.Backends = nil
config.Backends.Backends = make(map[string]*v1.BackendConfig)
}
}

if reflect.ValueOf(*config).IsZero() {
config = nil
}
*configAddr = config
}

Expand All @@ -299,8 +313,8 @@ func validateConfigItem(config *v1.Config, info *itemInfo, key string, value any
if reflect.ValueOf(value).IsZero() {
return ErrEmptyConfigItemValue
}
if info.validateFunc != nil {
return info.validateFunc(config, key, value)
if info.ValidateSetFunc != nil {
return info.ValidateSetFunc(config, key, value)
}
return nil
}
Expand Down Expand Up @@ -384,8 +398,8 @@ func convertBackendKey(key string) (string, error) {
if fields[1] == v1.BackendCurrent && len(fields) == 2 {
return key, nil
}
if fields[1] == v1.BackendCurrent && len(fields) > 2 {
return "", ErrInvalidBackendName
if fields[1] == v1.BackendCurrent {
return "", ErrInvalidBackendNameCurrent
}
if fields[1] == "" {
return "", ErrEmptyBackendName
Expand Down
Loading
Loading