feat: kubesphere 4.0 (#6115)
* feat: kubesphere 4.0 Signed-off-by: ci-bot <ci-bot@kubesphere.io> * feat: kubesphere 4.0 Signed-off-by: ci-bot <ci-bot@kubesphere.io> --------- Signed-off-by: ci-bot <ci-bot@kubesphere.io> Co-authored-by: ks-ci-bot <ks-ci-bot@example.com> Co-authored-by: joyceliu <joyceliu@yunify.com>
This commit is contained in:
committed by
GitHub
parent
b5015ec7b9
commit
447a51f08b
162
pkg/config/config.go
Normal file
162
pkg/config/config.go
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Please refer to the LICENSE file in the root directory of the project.
|
||||
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"gopkg.in/yaml.v3"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"kubesphere.io/utils/s3"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/auditing"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/authentication"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/authorization"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/controller/options"
|
||||
"kubesphere.io/kubesphere/pkg/models/composedapp"
|
||||
"kubesphere.io/kubesphere/pkg/models/terminal"
|
||||
"kubesphere.io/kubesphere/pkg/multicluster"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/cache"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
)
|
||||
|
||||
// Package config saves configuration for running KubeSphere components
|
||||
//
|
||||
// Config can be configured from command line flags and configuration file.
|
||||
// Command line flags hold higher priority than configuration file. But if
|
||||
// component Endpoint/Host/APIServer was left empty, all of that component
|
||||
// command line flags will be ignored, use configuration file instead.
|
||||
// For example, we have configuration file
|
||||
//
|
||||
// mysql:
|
||||
// host: mysql.kubesphere-system.svc
|
||||
// username: root
|
||||
// password: password
|
||||
//
|
||||
// At the same time, have command line flags like following:
|
||||
//
|
||||
// --mysql-host mysql.openpitrix-system.svc --mysql-username king --mysql-password 1234
|
||||
//
|
||||
// We will use `king:1234@mysql.openpitrix-system.svc` from command line flags rather
|
||||
// than `root:password@mysql.kubesphere-system.svc` from configuration file,
|
||||
// cause command line has higher priority. But if command line flags like following:
|
||||
//
|
||||
// --mysql-username root --mysql-password password
|
||||
//
|
||||
// we will `root:password@mysql.kubesphere-system.svc` as input, cause
|
||||
// mysql-host is missing in command line flags, all other mysql command line flags
|
||||
// will be ignored.
|
||||
|
||||
var (
|
||||
// singleton instance of config package
|
||||
_config = defaultConfig()
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultConfigurationName is the default name of configuration
|
||||
defaultConfigurationName = "kubesphere"
|
||||
|
||||
// DefaultConfigurationPath the default location of the configuration file
|
||||
defaultConfigurationPath = "/etc/kubesphere"
|
||||
|
||||
envPrefix = defaultConfigurationName
|
||||
)
|
||||
|
||||
type config struct {
|
||||
cfg *Config
|
||||
loadOnce sync.Once
|
||||
}
|
||||
|
||||
func (c *config) loadFromDisk() (*Config, error) {
|
||||
var err error
|
||||
c.loadOnce.Do(func() {
|
||||
if err = viper.ReadInConfig(); err != nil {
|
||||
return
|
||||
}
|
||||
err = viper.Unmarshal(c.cfg)
|
||||
})
|
||||
return c.cfg, err
|
||||
}
|
||||
|
||||
func defaultConfig() *config {
|
||||
viper.SetConfigName(defaultConfigurationName)
|
||||
viper.AddConfigPath(defaultConfigurationPath)
|
||||
|
||||
// Load from current working directory, only used for debugging
|
||||
viper.AddConfigPath(".")
|
||||
|
||||
// Load from Environment variables
|
||||
viper.SetEnvPrefix(envPrefix)
|
||||
viper.AutomaticEnv()
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
|
||||
return &config{
|
||||
cfg: New(),
|
||||
loadOnce: sync.Once{},
|
||||
}
|
||||
}
|
||||
|
||||
// Config defines everything needed for apiserver to deal with external services
|
||||
type Config struct {
|
||||
KubernetesOptions *k8s.Options `json:"kubernetes,omitempty" yaml:"kubernetes,omitempty" mapstructure:"kubernetes"`
|
||||
CacheOptions *cache.Options `json:"cache,omitempty" yaml:"cache,omitempty" mapstructure:"cache"`
|
||||
AuthenticationOptions *authentication.Options `json:"authentication,omitempty" yaml:"authentication,omitempty" mapstructure:"authentication"`
|
||||
AuthorizationOptions *authorization.Options `json:"authorization,omitempty" yaml:"authorization,omitempty" mapstructure:"authorization"`
|
||||
MultiClusterOptions *multicluster.Options `json:"multicluster,omitempty" yaml:"multicluster,omitempty" mapstructure:"multicluster"`
|
||||
AuditingOptions *auditing.Options `json:"auditing,omitempty" yaml:"auditing,omitempty" mapstructure:"auditing"`
|
||||
TerminalOptions *terminal.Options `json:"terminal,omitempty" yaml:"terminal,omitempty" mapstructure:"terminal"`
|
||||
HelmExecutorOptions *options.HelmExecutorOptions `json:"helmExecutor,omitempty" yaml:"helmExecutor,omitempty" mapstructure:"helmExecutor"`
|
||||
TelemetryOptions *options.TelemetryOptions `json:"telemetry,omitempty" yaml:"telemetry,omitempty" mapstructure:"telemetry"`
|
||||
ExtensionOptions *options.ExtensionOptions `json:"extension,omitempty" yaml:"extension,omitempty" mapstructure:"extension"`
|
||||
S3Options *s3.Options `json:"s3,omitempty" yaml:"s3,omitempty" mapstructure:"s3"`
|
||||
KubeSphereOptions *options.KubeSphereOptions `json:"kubesphere,omitempty" yaml:"kubesphere,omitempty" mapstructure:"kubesphere"`
|
||||
ComposedAppOptions *composedapp.Options `json:"composedApp,omitempty" yaml:"composedApp,omitempty" mapstructure:"composedApp"`
|
||||
ExperimentalOptions *ExperimentalOptions `json:"experimental,omitempty" yaml:"experimental,omitempty" mapstructure:"experimental"`
|
||||
}
|
||||
|
||||
// New config creates a default non-empty Config
|
||||
func New() *Config {
|
||||
return &Config{
|
||||
KubernetesOptions: k8s.NewKubernetesOptions(),
|
||||
CacheOptions: cache.NewCacheOptions(),
|
||||
AuthenticationOptions: authentication.NewOptions(),
|
||||
AuthorizationOptions: authorization.NewOptions(),
|
||||
MultiClusterOptions: multicluster.NewOptions(),
|
||||
TerminalOptions: terminal.NewOptions(),
|
||||
AuditingOptions: auditing.NewAuditingOptions(),
|
||||
TelemetryOptions: options.NewTelemetryOptions(),
|
||||
HelmExecutorOptions: options.NewHelmExecutorOptions(),
|
||||
ExtensionOptions: options.NewExtensionOptions(),
|
||||
S3Options: s3.NewS3Options(),
|
||||
KubeSphereOptions: options.NewKubeSphereOptions(),
|
||||
ComposedAppOptions: composedapp.NewOptions(),
|
||||
ExperimentalOptions: NewExperimentalOptions(),
|
||||
}
|
||||
}
|
||||
|
||||
// TryLoadFromDisk loads configuration from default location after server startup
|
||||
// return nil error if configuration file not exists
|
||||
func TryLoadFromDisk() (*Config, error) {
|
||||
return _config.loadFromDisk()
|
||||
}
|
||||
|
||||
// FromConfigMap returns KubeSphere running config by the given ConfigMap.
|
||||
func FromConfigMap(cm *corev1.ConfigMap) (*Config, error) {
|
||||
c := &Config{}
|
||||
value, ok := cm.Data[constants.KubeSphereConfigMapDataKey]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to get configmap kubesphere.yaml value")
|
||||
}
|
||||
|
||||
if err := yaml.Unmarshal([]byte(value), c); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal value from configmap. err: %s", err)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
88
pkg/config/config_test.go
Normal file
88
pkg/config/config_test.go
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Please refer to the LICENSE file in the root directory of the project.
|
||||
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"gopkg.in/yaml.v3"
|
||||
"kubesphere.io/utils/s3"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/auditing"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/authentication"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/authorization"
|
||||
"kubesphere.io/kubesphere/pkg/controller/options"
|
||||
"kubesphere.io/kubesphere/pkg/models/composedapp"
|
||||
"kubesphere.io/kubesphere/pkg/models/terminal"
|
||||
"kubesphere.io/kubesphere/pkg/multicluster"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/cache"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
)
|
||||
|
||||
func newTestConfig() (*Config, error) {
|
||||
var conf = &Config{
|
||||
KubernetesOptions: k8s.NewKubernetesOptions(),
|
||||
CacheOptions: cache.NewCacheOptions(),
|
||||
AuthorizationOptions: authorization.NewOptions(),
|
||||
AuthenticationOptions: authentication.NewOptions(),
|
||||
MultiClusterOptions: multicluster.NewOptions(),
|
||||
AuditingOptions: auditing.NewAuditingOptions(),
|
||||
TerminalOptions: terminal.NewOptions(),
|
||||
TelemetryOptions: options.NewTelemetryOptions(),
|
||||
HelmExecutorOptions: options.NewHelmExecutorOptions(),
|
||||
ExtensionOptions: options.NewExtensionOptions(),
|
||||
S3Options: s3.NewS3Options(),
|
||||
KubeSphereOptions: options.NewKubeSphereOptions(),
|
||||
ComposedAppOptions: &composedapp.Options{},
|
||||
ExperimentalOptions: NewExperimentalOptions(),
|
||||
}
|
||||
return conf, nil
|
||||
}
|
||||
|
||||
func saveTestConfig(t *testing.T, conf *Config) {
|
||||
content, err := yaml.Marshal(conf)
|
||||
if err != nil {
|
||||
t.Fatalf("error marshal config. %v", err)
|
||||
}
|
||||
err = os.WriteFile(fmt.Sprintf("%s.yaml", defaultConfigurationName), content, 0640)
|
||||
if err != nil {
|
||||
t.Fatalf("error write configuration file, %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func cleanTestConfig(t *testing.T) {
|
||||
file := fmt.Sprintf("%s.yaml", defaultConfigurationName)
|
||||
if _, err := os.Stat(file); os.IsNotExist(err) {
|
||||
t.Log("file not exists, skipping")
|
||||
return
|
||||
}
|
||||
|
||||
err := os.Remove(file)
|
||||
if err != nil {
|
||||
t.Fatalf("remove %s file failed", file)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
conf, err := newTestConfig()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
saveTestConfig(t, conf)
|
||||
defer cleanTestConfig(t)
|
||||
|
||||
conf2, err := TryLoadFromDisk()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if diff := cmp.Diff(conf, conf2); diff != "" {
|
||||
t.Fatal(diff)
|
||||
}
|
||||
}
|
||||
16
pkg/config/options.go
Normal file
16
pkg/config/options.go
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Please refer to the LICENSE file in the root directory of the project.
|
||||
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
type ExperimentalOptions struct {
|
||||
ValidationDirective string `json:"validationDirective" yaml:"validationDirective" mapstructure:"validationDirective"`
|
||||
}
|
||||
|
||||
func NewExperimentalOptions() *ExperimentalOptions {
|
||||
return &ExperimentalOptions{
|
||||
ValidationDirective: "",
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user