mirror of
https://github.com/safing/portbase
synced 2025-04-17 07:59:09 +00:00
Update config release levels and add expertise levels
This commit is contained in:
parent
adc359c15b
commit
807095f9bc
8 changed files with 132 additions and 67 deletions
2
config/doc.go
Normal file
2
config/doc.go
Normal file
|
@ -0,0 +1,2 @@
|
|||
// Package config provides a versatile configuration management system.
|
||||
package config
|
72
config/expertise.go
Normal file
72
config/expertise.go
Normal file
|
@ -0,0 +1,72 @@
|
|||
// Package config ... (linter fix)
|
||||
//nolint:dupl
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Expertise Level constants
|
||||
const (
|
||||
ExpertiseLevelUser uint8 = 0
|
||||
ExpertiseLevelExpert uint8 = 1
|
||||
ExpertiseLevelDeveloper uint8 = 2
|
||||
|
||||
ExpertiseLevelNameUser = "user"
|
||||
ExpertiseLevelNameExpert = "expert"
|
||||
ExpertiseLevelNameDeveloper = "developer"
|
||||
|
||||
expertiseLevelKey = "core/expertiseLevel"
|
||||
)
|
||||
|
||||
var (
|
||||
expertiseLevel *int32
|
||||
)
|
||||
|
||||
func init() {
|
||||
var expertiseLevelVal int32
|
||||
expertiseLevel = &expertiseLevelVal
|
||||
|
||||
registerExpertiseLevelOption()
|
||||
}
|
||||
|
||||
func registerExpertiseLevelOption() {
|
||||
err := Register(&Option{
|
||||
Name: "Expertise Level",
|
||||
Key: expertiseLevelKey,
|
||||
Description: "The Expertise Level controls the perceived complexity. Higher settings will show you more complex settings and information. This might also affect various other things relying on this setting. Modified settings in higher expertise levels stay in effect when switching back. (Unlike the Release Level)",
|
||||
|
||||
OptType: OptTypeString,
|
||||
ExpertiseLevel: ExpertiseLevelUser,
|
||||
ReleaseLevel: ExpertiseLevelUser,
|
||||
|
||||
RequiresRestart: false,
|
||||
DefaultValue: ExpertiseLevelNameUser,
|
||||
|
||||
ExternalOptType: "string list",
|
||||
ValidationRegex: fmt.Sprintf("^(%s|%s|%s)$", ExpertiseLevelNameUser, ExpertiseLevelNameExpert, ExpertiseLevelNameDeveloper),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func updateExpertiseLevel() {
|
||||
new := findStringValue(expertiseLevelKey, "")
|
||||
switch new {
|
||||
case ExpertiseLevelNameUser:
|
||||
atomic.StoreInt32(expertiseLevel, int32(ExpertiseLevelUser))
|
||||
case ExpertiseLevelNameExpert:
|
||||
atomic.StoreInt32(expertiseLevel, int32(ExpertiseLevelExpert))
|
||||
case ExpertiseLevelNameDeveloper:
|
||||
atomic.StoreInt32(expertiseLevel, int32(ExpertiseLevelDeveloper))
|
||||
default:
|
||||
atomic.StoreInt32(expertiseLevel, int32(ExpertiseLevelUser))
|
||||
}
|
||||
}
|
||||
|
||||
// GetExpertiseLevel returns the current active expertise level.
|
||||
func GetExpertiseLevel() uint8 {
|
||||
return uint8(atomic.LoadInt32(expertiseLevel))
|
||||
}
|
|
@ -81,21 +81,7 @@ func findValue(key string) interface{} {
|
|||
option.Lock()
|
||||
defer option.Unlock()
|
||||
|
||||
// check if option is active
|
||||
optionActive := true
|
||||
switch getReleaseLevel() {
|
||||
case ReleaseLevelStable:
|
||||
// In stable, only stable is active
|
||||
optionActive = option.ReleaseLevel == ReleaseLevelStable
|
||||
case ReleaseLevelBeta:
|
||||
// In beta, only stable and beta are active
|
||||
optionActive = option.ReleaseLevel == ReleaseLevelStable || option.ReleaseLevel == ReleaseLevelBeta
|
||||
case ReleaseLevelExperimental:
|
||||
// In experimental, everything is active
|
||||
optionActive = true
|
||||
}
|
||||
|
||||
if optionActive && option.activeValue != nil {
|
||||
if option.ReleaseLevel <= getReleaseLevel() && option.activeValue != nil {
|
||||
return option.activeValue
|
||||
}
|
||||
|
||||
|
|
|
@ -160,21 +160,21 @@ func TestReleaseLevel(t *testing.T) {
|
|||
|
||||
// test option level stable
|
||||
subsystemOption.ReleaseLevel = ReleaseLevelStable
|
||||
err = SetConfigOption(releaseLevelKey, ReleaseLevelStable)
|
||||
err = SetConfigOption(releaseLevelKey, ReleaseLevelNameStable)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !testSubsystem() {
|
||||
t.Error("should be active")
|
||||
}
|
||||
err = SetConfigOption(releaseLevelKey, ReleaseLevelBeta)
|
||||
err = SetConfigOption(releaseLevelKey, ReleaseLevelNameBeta)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !testSubsystem() {
|
||||
t.Error("should be active")
|
||||
}
|
||||
err = SetConfigOption(releaseLevelKey, ReleaseLevelExperimental)
|
||||
err = SetConfigOption(releaseLevelKey, ReleaseLevelNameExperimental)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -184,21 +184,21 @@ func TestReleaseLevel(t *testing.T) {
|
|||
|
||||
// test option level beta
|
||||
subsystemOption.ReleaseLevel = ReleaseLevelBeta
|
||||
err = SetConfigOption(releaseLevelKey, ReleaseLevelStable)
|
||||
err = SetConfigOption(releaseLevelKey, ReleaseLevelNameStable)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if testSubsystem() {
|
||||
t.Errorf("should be inactive: opt=%s system=%s", subsystemOption.ReleaseLevel, releaseLevel)
|
||||
t.Errorf("should be inactive: opt=%d system=%d", subsystemOption.ReleaseLevel, getReleaseLevel())
|
||||
}
|
||||
err = SetConfigOption(releaseLevelKey, ReleaseLevelBeta)
|
||||
err = SetConfigOption(releaseLevelKey, ReleaseLevelNameBeta)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !testSubsystem() {
|
||||
t.Error("should be active")
|
||||
}
|
||||
err = SetConfigOption(releaseLevelKey, ReleaseLevelExperimental)
|
||||
err = SetConfigOption(releaseLevelKey, ReleaseLevelNameExperimental)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -208,21 +208,21 @@ func TestReleaseLevel(t *testing.T) {
|
|||
|
||||
// test option level experimental
|
||||
subsystemOption.ReleaseLevel = ReleaseLevelExperimental
|
||||
err = SetConfigOption(releaseLevelKey, ReleaseLevelStable)
|
||||
err = SetConfigOption(releaseLevelKey, ReleaseLevelNameStable)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if testSubsystem() {
|
||||
t.Error("should be inactive")
|
||||
}
|
||||
err = SetConfigOption(releaseLevelKey, ReleaseLevelBeta)
|
||||
err = SetConfigOption(releaseLevelKey, ReleaseLevelNameBeta)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if testSubsystem() {
|
||||
t.Error("should be inactive")
|
||||
}
|
||||
err = SetConfigOption(releaseLevelKey, ReleaseLevelExperimental)
|
||||
err = SetConfigOption(releaseLevelKey, ReleaseLevelNameExperimental)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -17,14 +17,6 @@ const (
|
|||
OptTypeStringArray uint8 = 2
|
||||
OptTypeInt uint8 = 3
|
||||
OptTypeBool uint8 = 4
|
||||
|
||||
ExpertiseLevelUser uint8 = 1
|
||||
ExpertiseLevelExpert uint8 = 2
|
||||
ExpertiseLevelDeveloper uint8 = 3
|
||||
|
||||
ReleaseLevelStable = "stable"
|
||||
ReleaseLevelBeta = "beta"
|
||||
ReleaseLevelExperimental = "experimental"
|
||||
)
|
||||
|
||||
func getTypeName(t uint8) string {
|
||||
|
@ -50,9 +42,9 @@ type Option struct {
|
|||
Key string // in path format: category/sub/key
|
||||
Description string
|
||||
|
||||
ReleaseLevel string
|
||||
ExpertiseLevel uint8
|
||||
OptType uint8
|
||||
ExpertiseLevel uint8
|
||||
ReleaseLevel uint8
|
||||
|
||||
RequiresRestart bool
|
||||
DefaultValue interface{}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sync"
|
||||
|
@ -10,21 +9,21 @@ import (
|
|||
var (
|
||||
optionsLock sync.RWMutex
|
||||
options = make(map[string]*Option)
|
||||
|
||||
// ErrIncompleteCall is return when RegisterOption is called with empty mandatory values.
|
||||
ErrIncompleteCall = errors.New("could not register config option: all fields, except for the validationRegex are mandatory")
|
||||
)
|
||||
|
||||
// Register registers a new configuration option.
|
||||
func Register(option *Option) error {
|
||||
|
||||
if option.Name == "" ||
|
||||
option.Key == "" ||
|
||||
option.Description == "" ||
|
||||
option.OptType == 0 ||
|
||||
option.ExpertiseLevel == 0 ||
|
||||
option.ReleaseLevel == "" {
|
||||
return ErrIncompleteCall
|
||||
if option.Name == "" {
|
||||
return fmt.Errorf("failed to register option: please set option.Name")
|
||||
}
|
||||
if option.Key == "" {
|
||||
return fmt.Errorf("failed to register option: please set option.Key")
|
||||
}
|
||||
if option.Description == "" {
|
||||
return fmt.Errorf("failed to register option: please set option.Description")
|
||||
}
|
||||
if option.OptType == 0 {
|
||||
return fmt.Errorf("failed to register option: please set option.OptType")
|
||||
}
|
||||
|
||||
if option.ValidationRegex != "" {
|
||||
|
@ -37,7 +36,6 @@ func Register(option *Option) error {
|
|||
|
||||
optionsLock.Lock()
|
||||
defer optionsLock.Unlock()
|
||||
|
||||
options[option.Key] = option
|
||||
|
||||
return nil
|
||||
|
|
|
@ -1,38 +1,51 @@
|
|||
// Package config ... (linter fix)
|
||||
//nolint:dupl
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Release Level constants
|
||||
const (
|
||||
releaseLevelKey = "core/release_level"
|
||||
ReleaseLevelStable uint8 = 0
|
||||
ReleaseLevelBeta uint8 = 1
|
||||
ReleaseLevelExperimental uint8 = 2
|
||||
|
||||
ReleaseLevelNameStable = "stable"
|
||||
ReleaseLevelNameBeta = "beta"
|
||||
ReleaseLevelNameExperimental = "experimental"
|
||||
|
||||
releaseLevelKey = "core/releaseLevel"
|
||||
)
|
||||
|
||||
var (
|
||||
releaseLevel = ReleaseLevelStable
|
||||
releaseLevelLock sync.Mutex
|
||||
releaseLevel *int32
|
||||
)
|
||||
|
||||
func init() {
|
||||
var releaseLevelVal int32
|
||||
releaseLevel = &releaseLevelVal
|
||||
|
||||
registerReleaseLevelOption()
|
||||
}
|
||||
|
||||
func registerReleaseLevelOption() {
|
||||
err := Register(&Option{
|
||||
Name: "Release Selection",
|
||||
Name: "Release Level",
|
||||
Key: releaseLevelKey,
|
||||
Description: "Select maturity level of features that should be available",
|
||||
Description: "The Release Level changes which features are available to you. Some beta or experimental features are also available in the stable release channel. Unavailable settings are set to the default value.",
|
||||
|
||||
OptType: OptTypeString,
|
||||
ExpertiseLevel: ExpertiseLevelExpert,
|
||||
ReleaseLevel: ReleaseLevelStable,
|
||||
|
||||
RequiresRestart: false,
|
||||
DefaultValue: ReleaseLevelStable,
|
||||
DefaultValue: ReleaseLevelNameStable,
|
||||
|
||||
ExternalOptType: "string list",
|
||||
ValidationRegex: fmt.Sprintf("^(%s|%s|%s)$", ReleaseLevelStable, ReleaseLevelBeta, ReleaseLevelExperimental),
|
||||
ValidationRegex: fmt.Sprintf("^(%s|%s|%s)$", ReleaseLevelNameStable, ReleaseLevelNameBeta, ReleaseLevelNameExperimental),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -41,17 +54,18 @@ func registerReleaseLevelOption() {
|
|||
|
||||
func updateReleaseLevel() {
|
||||
new := findStringValue(releaseLevelKey, "")
|
||||
releaseLevelLock.Lock()
|
||||
if new == "" {
|
||||
releaseLevel = ReleaseLevelStable
|
||||
} else {
|
||||
releaseLevel = new
|
||||
switch new {
|
||||
case ReleaseLevelNameStable:
|
||||
atomic.StoreInt32(releaseLevel, int32(ReleaseLevelStable))
|
||||
case ReleaseLevelNameBeta:
|
||||
atomic.StoreInt32(releaseLevel, int32(ReleaseLevelBeta))
|
||||
case ReleaseLevelNameExperimental:
|
||||
atomic.StoreInt32(releaseLevel, int32(ReleaseLevelExperimental))
|
||||
default:
|
||||
atomic.StoreInt32(releaseLevel, int32(ReleaseLevelStable))
|
||||
}
|
||||
releaseLevelLock.Unlock()
|
||||
}
|
||||
|
||||
func getReleaseLevel() string {
|
||||
releaseLevelLock.Lock()
|
||||
defer releaseLevelLock.Unlock()
|
||||
return releaseLevel
|
||||
func getReleaseLevel() uint8 {
|
||||
return uint8(atomic.LoadInt32(releaseLevel))
|
||||
}
|
||||
|
|
|
@ -36,8 +36,9 @@ func Changed() <-chan struct{} {
|
|||
}
|
||||
|
||||
func signalChanges() {
|
||||
// refetch and save release level
|
||||
// refetch and save release level and expertise level
|
||||
updateReleaseLevel()
|
||||
updateExpertiseLevel()
|
||||
|
||||
// reset validity flag
|
||||
validityFlagLock.Lock()
|
||||
|
|
Loading…
Add table
Reference in a new issue