Files
kubesphere/pkg/server/config/config.go
2019-09-28 00:12:55 +08:00

280 lines
9.2 KiB
Go

package config
import (
"fmt"
"github.com/emicklei/go-restful"
"github.com/spf13/viper"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/simple/client/alerting"
"kubesphere.io/kubesphere/pkg/simple/client/devops"
"kubesphere.io/kubesphere/pkg/simple/client/elasticsearch"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"kubesphere.io/kubesphere/pkg/simple/client/kubesphere"
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
"kubesphere.io/kubesphere/pkg/simple/client/notification"
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
"kubesphere.io/kubesphere/pkg/simple/client/prometheus"
"kubesphere.io/kubesphere/pkg/simple/client/redis"
"kubesphere.io/kubesphere/pkg/simple/client/s2is3"
"kubesphere.io/kubesphere/pkg/simple/client/servicemesh"
"kubesphere.io/kubesphere/pkg/simple/client/sonarqube"
"net/http"
)
// 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, case
// mysql-host is missing in command line flags, all other mysql command line flags
// will be ignored.
// InstallAPI installs api for config
func InstallAPI(c *restful.Container) {
ws := runtime.NewWebService(schema.GroupVersion{
Group: "",
Version: "v1alpha1",
})
ws.Route(ws.GET("/configz").
To(func(request *restful.Request, response *restful.Response) {
var conf = *sharedConfig
conf.stripEmptyOptions()
response.WriteAsJson(conf)
}).
Doc("Get system components configuration").
Produces(restful.MIME_JSON).
Writes(Config{}).
Returns(http.StatusOK, "ok", Config{}))
c.Add(ws)
}
// Load loads configuration after setup
func Load() error {
sharedConfig = newConfig()
viper.SetConfigName(DefaultConfigurationName)
viper.AddConfigPath(DefaultConfigurationPath)
viper.AddConfigPath(".")
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
klog.Warning("configuration file not found")
return nil
} else {
panic(fmt.Errorf("error parsing configuration file %s", err))
}
}
conf := newConfig()
if err := viper.Unmarshal(conf); err != nil {
klog.Error(fmt.Errorf("error unmarshal configuration %v", err))
return err
} else {
// make sure kubesphere options always exists
if conf.KubeSphereOptions == nil {
conf.KubeSphereOptions = kubesphere.NewKubeSphereOptions()
} else {
ksOptions := kubesphere.NewKubeSphereOptions()
conf.KubeSphereOptions.ApplyTo(ksOptions)
conf.KubeSphereOptions = ksOptions
}
conf.Apply(shadowConfig)
sharedConfig = conf
}
return nil
}
const (
// DefaultConfigurationName is the default name of configuration
DefaultConfigurationName = "kubesphere"
// DefaultConfigurationPath the default location of the configuration file
DefaultConfigurationPath = "/etc/kubesphere"
)
var (
// sharedConfig holds configuration across kubesphere
sharedConfig *Config
// shadowConfig contains options from commandline options
shadowConfig = &Config{}
)
type Config struct {
MySQLOptions *mysql.MySQLOptions `json:"mysql,omitempty" yaml:"mysql,omitempty" mapstructure:"mysql"`
DevopsOptions *devops.DevopsOptions `json:"devops,omitempty" yaml:"devops,omitempty" mapstructure:"devops"`
SonarQubeOptions *sonarqube.SonarQubeOptions `json:"sonarqube,omitempty" yaml:"sonarQube,omitempty" mapstructure:"sonarqube"`
KubernetesOptions *k8s.KubernetesOptions `json:"kubernetes,omitempty" yaml:"kubernetes,omitempty" mapstructure:"kubernetes"`
ServiceMeshOptions *servicemesh.ServiceMeshOptions `json:"servicemesh,omitempty" yaml:"servicemesh,omitempty" mapstructure:"servicemesh"`
LdapOptions *ldap.LdapOptions `json:"ldap,omitempty" yaml:"ldap,omitempty" mapstructure:"ldap"`
RedisOptions *redis.RedisOptions `json:"redis,omitempty" yaml:"redis,omitempty" mapstructure:"redis"`
S3Options *s2is3.S3Options `json:"s3,omitempty" yaml:"s3,omitempty" mapstructure:"s3"`
OpenPitrixOptions *openpitrix.OpenPitrixOptions `json:"openpitrix,omitempty" yaml:"openpitrix,omitempty" mapstructure:"openpitrix"`
MonitoringOptions *prometheus.PrometheusOptions `json:"monitoring,omitempty" yaml:"monitoring,omitempty" mapstructure:"monitoring"`
LoggingOptions *esclient.ElasticSearchOptions `json:"logging,omitempty" yaml:"logging,omitempty" mapstructure:"logging"`
// Options below are only loaded from configuration file, no command line flags for these options now.
KubeSphereOptions *kubesphere.KubeSphereOptions `json:"-" yaml:"kubesphere,omitempty" mapstructure:"kubesphere"`
// Options used for enabling components, not actually used now. Once we switch Alerting/Notification API to kubesphere,
// we can add these options to kubesphere command lines
AlertingOptions *alerting.AlertingOptions `json:"alerting,omitempty" yaml:"alerting,omitempty" mapstructure:"alerting"`
NotificationOptions *notification.NotificationOptions `json:"notification,omitempty" yaml:"notification,omitempty" mapstructure:"notification"`
}
func newConfig() *Config {
return &Config{
MySQLOptions: mysql.NewMySQLOptions(),
DevopsOptions: devops.NewDevopsOptions(),
SonarQubeOptions: sonarqube.NewSonarQubeOptions(),
KubernetesOptions: k8s.NewKubernetesOptions(),
ServiceMeshOptions: servicemesh.NewServiceMeshOptions(),
LdapOptions: ldap.NewLdapOptions(),
RedisOptions: redis.NewRedisOptions(),
S3Options: s2is3.NewS3Options(),
OpenPitrixOptions: openpitrix.NewOpenPitrixOptions(),
MonitoringOptions: prometheus.NewPrometheusOptions(),
KubeSphereOptions: kubesphere.NewKubeSphereOptions(),
AlertingOptions: alerting.NewAlertingOptions(),
NotificationOptions: notification.NewNotificationOptions(),
LoggingOptions: esclient.NewElasticSearchOptions(),
}
}
func Get() *Config {
return sharedConfig
}
func (c *Config) Apply(conf *Config) {
shadowConfig = conf
if conf.LoggingOptions != nil {
conf.LoggingOptions.ApplyTo(c.LoggingOptions)
}
if conf.KubeSphereOptions != nil {
conf.KubeSphereOptions.ApplyTo(c.KubeSphereOptions)
}
if conf.MonitoringOptions != nil {
conf.MonitoringOptions.ApplyTo(c.MonitoringOptions)
}
if conf.OpenPitrixOptions != nil {
conf.OpenPitrixOptions.ApplyTo(c.OpenPitrixOptions)
}
if conf.S3Options != nil {
conf.S3Options.ApplyTo(c.S3Options)
}
if conf.RedisOptions != nil {
conf.RedisOptions.ApplyTo(c.RedisOptions)
}
if conf.LdapOptions != nil {
conf.LdapOptions.ApplyTo(c.LdapOptions)
}
if conf.ServiceMeshOptions != nil {
conf.ServiceMeshOptions.ApplyTo(c.ServiceMeshOptions)
}
if conf.KubernetesOptions != nil {
conf.KubernetesOptions.ApplyTo(c.KubernetesOptions)
}
if conf.SonarQubeOptions != nil {
conf.SonarQubeOptions.ApplyTo(c.SonarQubeOptions)
}
if conf.DevopsOptions != nil {
conf.DevopsOptions.ApplyTo(c.DevopsOptions)
}
if conf.MySQLOptions != nil {
conf.MySQLOptions.ApplyTo(c.MySQLOptions)
}
}
func (c *Config) stripEmptyOptions() {
if c.MySQLOptions != nil && c.MySQLOptions.Host == "" {
c.MySQLOptions = nil
}
if c.RedisOptions != nil && c.RedisOptions.Host == "" {
c.RedisOptions = nil
}
if c.DevopsOptions != nil && c.DevopsOptions.Host == "" {
c.DevopsOptions = nil
}
if c.MonitoringOptions != nil && c.MonitoringOptions.Endpoint == "" &&
c.MonitoringOptions.SecondaryEndpoint == "" {
c.MonitoringOptions = nil
}
if c.SonarQubeOptions != nil && c.SonarQubeOptions.Host == "" {
c.SonarQubeOptions = nil
}
if c.LdapOptions != nil && c.LdapOptions.Host == "" {
c.LdapOptions = nil
}
if c.OpenPitrixOptions != nil && c.OpenPitrixOptions.IsEmpty() {
c.OpenPitrixOptions = nil
}
if c.ServiceMeshOptions != nil && c.ServiceMeshOptions.IstioPilotHost == "" &&
c.ServiceMeshOptions.ServicemeshPrometheusHost == "" &&
c.ServiceMeshOptions.JaegerQueryHost == "" {
c.ServiceMeshOptions = nil
}
if c.S3Options != nil && c.S3Options.Endpoint == "" {
c.S3Options = nil
}
if c.AlertingOptions != nil && c.AlertingOptions.Endpoint == "" {
c.AlertingOptions = nil
}
if c.LoggingOptions != nil && c.LoggingOptions.Host == "" {
c.LoggingOptions = nil
}
if c.NotificationOptions != nil && c.NotificationOptions.Endpoint == "" {
c.NotificationOptions = nil
}
}