Skip to content
Open
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
52 changes: 48 additions & 4 deletions pkg/config/app/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/apache/dubbo-admin/pkg/config/log"
"github.com/apache/dubbo-admin/pkg/config/observability"
"github.com/apache/dubbo-admin/pkg/config/store"
"github.com/apache/dubbo-admin/pkg/config/versioning"
)

type AdminConfig struct {
Expand All @@ -51,6 +52,8 @@ type AdminConfig struct {
Engine *engine.Config `json:"engine" yaml:"engine"`
// EventBus configuration
EventBus *eventbus.Config `json:"eventBus,omitempty" yaml:"eventBus,omitempty"`
// Versioning configuration for governor-managed traffic rules.
Versioning *versioning.Config `json:"versioning,omitempty" yaml:"versioning,omitempty"`
}

var _ = &AdminConfig{}
Expand All @@ -65,10 +68,12 @@ var DefaultAdminConfig = func() AdminConfig {
Diagnostics: diagnostics.DefaultDiagnosticsConfig(),
Console: console.DefaultConsoleConfig(),
EventBus: &eventBusCfg,
Versioning: versioning.Default(),
}
}

func (c AdminConfig) Sanitize() {
func (c *AdminConfig) Sanitize() {
c.ensureDefaults()
c.Engine.Sanitize()
for _, d := range c.Discovery {
d.Sanitize()
Expand All @@ -78,9 +83,11 @@ func (c AdminConfig) Sanitize() {
c.Observability.Sanitize()
c.Diagnostics.Sanitize()
c.Log.Sanitize()
c.Versioning.Sanitize()
}

func (c AdminConfig) PreProcess() error {
func (c *AdminConfig) PreProcess() error {
c.ensureDefaults()
discoveryPreProcess := func() error {
for _, d := range c.Discovery {
if err := d.PreProcess(); err != nil {
Expand All @@ -97,10 +104,12 @@ func (c AdminConfig) PreProcess() error {
c.Observability.PreProcess(),
c.Diagnostics.PreProcess(),
c.Log.PreProcess(),
c.Versioning.PreProcess(),
)
}

func (c AdminConfig) PostProcess() error {
func (c *AdminConfig) PostProcess() error {
c.ensureDefaults()
discoveryPostProcess := func() error {
for _, d := range c.Discovery {
if err := d.PostProcess(); err != nil {
Expand All @@ -117,10 +126,12 @@ func (c AdminConfig) PostProcess() error {
c.Observability.PostProcess(),
c.Diagnostics.PostProcess(),
c.Log.PostProcess(),
c.Versioning.PostProcess(),
)
}

func (c AdminConfig) Validate() error {
func (c *AdminConfig) Validate() error {
c.ensureDefaults()
if c.Log == nil {
c.Log = log.DefaultLogConfig()
} else if err := c.Log.Validate(); err != nil {
Expand Down Expand Up @@ -171,9 +182,42 @@ func (c AdminConfig) Validate() error {
} else if err := c.EventBus.Validate(); err != nil {
return bizerror.Wrap(err, bizerror.ConfigError, "event bus config validation failed")
}
if c.Versioning == nil {
c.Versioning = versioning.Default()
} else if err := c.Versioning.Validate(); err != nil {
return bizerror.Wrap(err, bizerror.ConfigError, "versioning config validation failed")
}
return nil
}

func (c *AdminConfig) ensureDefaults() {
if c.Log == nil {
c.Log = log.DefaultLogConfig()
}
if c.Store == nil {
c.Store = store.DefaultStoreConfig()
}
if c.Diagnostics == nil {
c.Diagnostics = diagnostics.DefaultDiagnosticsConfig()
}
if c.Console == nil {
c.Console = console.DefaultConsoleConfig()
}
if c.Observability == nil {
c.Observability = observability.DefaultObservabilityConfig()
}
if c.Engine == nil {
c.Engine = engine.DefaultResourceEngineConfig()
}
if c.EventBus == nil {
cfg := eventbus.Default()
c.EventBus = &cfg
}
if c.Versioning == nil {
c.Versioning = versioning.Default()
}
}

// FindDiscovery finds the DiscoveryConfig by id, returns nil if not found
func (c AdminConfig) FindDiscovery(id string) *discovery.Config {
for _, d := range c.Discovery {
Expand Down
44 changes: 44 additions & 0 deletions pkg/config/app/admin_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package app

import (
"testing"

"github.com/apache/dubbo-admin/pkg/config/versioning"
"github.com/stretchr/testify/require"
)

func TestAdminConfigVersioningDefaultsWhenMissing(t *testing.T) {
cfg := DefaultAdminConfig()
cfg.Versioning = nil

require.NotPanics(t, func() {
cfg.Sanitize()
})
require.NotNil(t, cfg.Versioning)
require.Equal(t, versioning.DefaultRollbackWaitMs, cfg.Versioning.RollbackWaitMs)

cfg.Versioning = nil
require.NoError(t, cfg.PreProcess())
require.NotNil(t, cfg.Versioning)

cfg.Versioning = nil
require.NoError(t, cfg.PostProcess())
require.NotNil(t, cfg.Versioning)
}
90 changes: 90 additions & 0 deletions pkg/config/versioning/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package versioning

import (
"encoding/json"

"github.com/apache/dubbo-admin/pkg/common/bizerror"
"github.com/apache/dubbo-admin/pkg/config"
)

const (
DefaultEnabled = true
DefaultMaxVersionsPerRule = int64(5)
DefaultCoalesceWindowMs = int64(2000)
DefaultAdminHintTTLSec = int64(30)
DefaultRollbackWaitMs = int64(5000)
)

type Config struct {
config.BaseConfig
Enabled bool `json:"enabled" yaml:"enabled"`
MaxVersionsPerRule int64 `json:"maxVersionsPerRule" yaml:"maxVersionsPerRule"`
CoalesceWindowMs int64 `json:"coalesceWindowMs" yaml:"coalesceWindowMs"`
AdminHintTTLSec int64 `json:"adminHintTTLSec" yaml:"adminHintTTLSec"`
RollbackWaitMs int64 `json:"rollbackWaitTimeoutMs" yaml:"rollbackWaitTimeoutMs"`
}

func (c *Config) UnmarshalJSON(data []byte) error {
type config Config
defaults := Default()
*c = *defaults
return json.Unmarshal(data, (*config)(c))
}

func Default() *Config {
return &Config{
Enabled: DefaultEnabled,
MaxVersionsPerRule: DefaultMaxVersionsPerRule,
CoalesceWindowMs: DefaultCoalesceWindowMs,
AdminHintTTLSec: DefaultAdminHintTTLSec,
RollbackWaitMs: DefaultRollbackWaitMs,
}
}

func (c *Config) Sanitize() {
if c.MaxVersionsPerRule <= 0 {
c.MaxVersionsPerRule = DefaultMaxVersionsPerRule
}
if c.CoalesceWindowMs < 0 {
c.CoalesceWindowMs = DefaultCoalesceWindowMs
}
if c.AdminHintTTLSec <= 0 {
c.AdminHintTTLSec = DefaultAdminHintTTLSec
}
if c.RollbackWaitMs < 0 {
c.RollbackWaitMs = DefaultRollbackWaitMs
}
}

func (c *Config) Validate() error {
if c.MaxVersionsPerRule <= 0 {
return bizerror.New(bizerror.ConfigError, "versioning.maxVersionsPerRule must be greater than 0")
}
if c.CoalesceWindowMs < 0 {
return bizerror.New(bizerror.ConfigError, "versioning.coalesceWindowMs must be greater than or equal to 0")
}
if c.AdminHintTTLSec <= 0 {
return bizerror.New(bizerror.ConfigError, "versioning.adminHintTTLSec must be greater than 0")
}
if c.RollbackWaitMs < 0 {
return bizerror.New(bizerror.ConfigError, "versioning.rollbackWaitTimeoutMs must be greater than or equal to 0")
}
return nil
}
53 changes: 53 additions & 0 deletions pkg/config/versioning/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package versioning

import (
"testing"

"github.com/stretchr/testify/require"
"sigs.k8s.io/yaml"
)

func TestConfigDefaultsRollbackWaitOnYAMLUnmarshal(t *testing.T) {
var cfg Config
require.NoError(t, yaml.Unmarshal([]byte("enabled: false\n"), &cfg))

require.False(t, cfg.Enabled)
require.Equal(t, DefaultMaxVersionsPerRule, cfg.MaxVersionsPerRule)
require.Equal(t, DefaultCoalesceWindowMs, cfg.CoalesceWindowMs)
require.Equal(t, DefaultAdminHintTTLSec, cfg.AdminHintTTLSec)
require.Equal(t, DefaultRollbackWaitMs, cfg.RollbackWaitMs)
}

func TestConfigValidateRollbackWait(t *testing.T) {
cfg := Default()
cfg.RollbackWaitMs = 0
require.NoError(t, cfg.Validate())

cfg.RollbackWaitMs = -1
require.ErrorContains(t, cfg.Validate(), "versioning.rollbackWaitTimeoutMs")
}

func TestConfigSanitizePreservesExplicitZeroRollbackWait(t *testing.T) {
cfg := Default()
cfg.RollbackWaitMs = 0
cfg.Sanitize()

require.Equal(t, int64(0), cfg.RollbackWaitMs)
}
14 changes: 14 additions & 0 deletions pkg/console/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/apache/dubbo-admin/pkg/console/counter"
"github.com/apache/dubbo-admin/pkg/core/manager"
"github.com/apache/dubbo-admin/pkg/core/runtime"
"github.com/apache/dubbo-admin/pkg/core/versioning"
)

type Context interface {
Expand All @@ -35,6 +36,7 @@ type Context interface {

AppContext() ctx.Context
LockManager() lock.Lock
RuleVersioning() versioning.Service
}

var _ Context = &context{}
Expand Down Expand Up @@ -81,3 +83,15 @@ func (c *context) LockManager() lock.Lock {
}
return distributedLock
}

func (c *context) RuleVersioning() versioning.Service {
comp, err := c.coreRt.GetComponent(versioning.ComponentType)
if err != nil {
return nil
}
versioningComp, ok := comp.(versioning.Component)
if !ok {
return nil
}
return versioningComp.Service()
}
26 changes: 18 additions & 8 deletions pkg/console/handler/condition_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,12 @@ func PutConditionRuleWithRuleName(cs consolectx.Context) gin.HandlerFunc {
util.HandleArgumentError(c, err)
return
}

if err := service.UpdateConditionRule(cs, res); err != nil {
util.HandleServiceError(c, err)
opts, ok := mutationOptions(c)
if !ok {
return
}
if err := service.UpdateConditionRuleWithOptions(cs, res, opts); err != nil {
writeVersioningResp(c, nil, err)
return
} else {
c.JSON(http.StatusOK, model.GenConditionRuleToResp(res.Spec))
Expand All @@ -118,9 +121,12 @@ func PostConditionRuleWithRuleName(cs consolectx.Context) gin.HandlerFunc {
util.HandleArgumentError(c, err)
return
}

if err := service.CreateConditionRule(cs, res); err != nil {
c.JSON(http.StatusOK, model.NewErrorResp(err.Error()))
opts, ok := mutationOptions(c)
if !ok {
return
}
if err := service.CreateConditionRuleWithOptions(cs, res, opts); err != nil {
writeVersioningResp(c, nil, err)
return
} else {
c.JSON(http.StatusOK, model.GenConditionRuleToResp(res.Spec))
Expand All @@ -137,8 +143,12 @@ func DeleteConditionRuleWithRuleName(cs consolectx.Context) gin.HandlerFunc {
fmt.Sprintf("ruleName must end with %s", constants.ConditionRuleDotSuffix))))
return
}
if err := service.DeleteConditionRule(cs, ruleName, mesh); err != nil {
c.JSON(http.StatusOK, model.NewErrorResp(err.Error()))
opts, ok := mutationOptions(c)
if !ok {
return
}
if err := service.DeleteConditionRuleWithOptions(cs, ruleName, mesh, opts); err != nil {
writeVersioningResp(c, nil, err)
return
}
c.JSON(http.StatusOK, model.NewSuccessResp(""))
Expand Down
Loading
Loading