config.go 8.8 KB
Newer Older
1 2 3 4 5 6 7
package config

import (
	"fmt"
	"github.com/emicklei/go-restful"
	"github.com/spf13/viper"
	"k8s.io/apimachinery/pkg/runtime/schema"
8
	"kubesphere.io/kubesphere/pkg/api/iam"
9
	"kubesphere.io/kubesphere/pkg/apiserver/runtime"
J
Jeff 已提交
10
	"kubesphere.io/kubesphere/pkg/simple/client/alerting"
Z
zryfish 已提交
11
	"kubesphere.io/kubesphere/pkg/simple/client/cache"
R
runzexia 已提交
12
	"kubesphere.io/kubesphere/pkg/simple/client/devops/jenkins"
13
	"kubesphere.io/kubesphere/pkg/simple/client/k8s"
J
Jeff 已提交
14
	"kubesphere.io/kubesphere/pkg/simple/client/kubesphere"
15
	"kubesphere.io/kubesphere/pkg/simple/client/ldap"
G
Guangzhe Huang 已提交
16
	"kubesphere.io/kubesphere/pkg/simple/client/logging/elasticsearch"
G
Guangzhe Huang 已提交
17
	"kubesphere.io/kubesphere/pkg/simple/client/monitoring/prometheus"
18
	"kubesphere.io/kubesphere/pkg/simple/client/mysql"
J
Jeff 已提交
19
	"kubesphere.io/kubesphere/pkg/simple/client/notification"
20
	"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
Z
zryfish 已提交
21
	"kubesphere.io/kubesphere/pkg/simple/client/s3"
22 23 24
	"kubesphere.io/kubesphere/pkg/simple/client/servicemesh"
	"kubesphere.io/kubesphere/pkg/simple/client/sonarqube"
	"net/http"
J
Jeff 已提交
25 26
	"reflect"
	"strings"
27 28
)

J
Jeff 已提交
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
// 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
//
52
// we will `root:password@mysql.kubesphere-system.svc` as input, cause
J
Jeff 已提交
53 54 55
// mysql-host is missing in command line flags, all other mysql command line flags
// will be ignored.

56
const (
J
Jeff 已提交
57
	// DefaultConfigurationName is the default name of configuration
58
	defaultConfigurationName = "kubesphere"
J
Jeff 已提交
59 60

	// DefaultConfigurationPath the default location of the configuration file
61
	defaultConfigurationPath = "/etc/kubesphere"
62 63
)

64
// Config defines everything needed for apiserver to deal with external services
65
type Config struct {
Z
zryfish 已提交
66
	MySQLOptions       *mysql.Options         `json:"mysql,omitempty" yaml:"mysql,omitempty" mapstructure:"mysql"`
R
runzexia 已提交
67
	DevopsOptions      *jenkins.Options       `json:"devops,omitempty" yaml:"devops,omitempty" mapstructure:"devops"`
Z
zryfish 已提交
68 69 70 71 72 73 74 75
	SonarQubeOptions   *sonarqube.Options     `json:"sonarqube,omitempty" yaml:"sonarQube,omitempty" mapstructure:"sonarqube"`
	KubernetesOptions  *k8s.KubernetesOptions `json:"kubernetes,omitempty" yaml:"kubernetes,omitempty" mapstructure:"kubernetes"`
	ServiceMeshOptions *servicemesh.Options   `json:"servicemesh,omitempty" yaml:"servicemesh,omitempty" mapstructure:"servicemesh"`
	LdapOptions        *ldap.Options          `json:"ldap,omitempty" yaml:"ldap,omitempty" mapstructure:"ldap"`
	RedisOptions       *cache.Options         `json:"redis,omitempty" yaml:"redis,omitempty" mapstructure:"redis"`
	S3Options          *s3.Options            `json:"s3,omitempty" yaml:"s3,omitempty" mapstructure:"s3"`
	OpenPitrixOptions  *openpitrix.Options    `json:"openpitrix,omitempty" yaml:"openpitrix,omitempty" mapstructure:"openpitrix"`
	MonitoringOptions  *prometheus.Options    `json:"monitoring,omitempty" yaml:"monitoring,omitempty" mapstructure:"monitoring"`
G
Guangzhe Huang 已提交
76
	LoggingOptions     *elasticsearch.Options `json:"logging,omitempty" yaml:"logging,omitempty" mapstructure:"logging"`
J
Jeff 已提交
77 78

	// Options below are only loaded from configuration file, no command line flags for these options now.
Z
zryfish 已提交
79
	KubeSphereOptions *kubesphere.Options `json:"-" yaml:"kubesphere,omitempty" mapstructure:"kubesphere"`
J
Jeff 已提交
80

81 82
	AuthenticateOptions *iam.AuthenticationOptions `json:"authenticate,omitempty" yaml:"authenticate,omitempty" mapstructure:"authenticate"`

J
Jeff 已提交
83 84
	// 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
Z
zryfish 已提交
85 86
	AlertingOptions     *alerting.Options     `json:"alerting,omitempty" yaml:"alerting,omitempty" mapstructure:"alerting"`
	NotificationOptions *notification.Options `json:"notification,omitempty" yaml:"notification,omitempty" mapstructure:"notification"`
87 88
}

89 90
// newConfig creates a default non-empty Config
func New() *Config {
91
	return &Config{
J
Jeff 已提交
92
		MySQLOptions:        mysql.NewMySQLOptions(),
R
runzexia 已提交
93
		DevopsOptions:       jenkins.NewDevopsOptions(),
J
Jeff 已提交
94 95 96
		SonarQubeOptions:    sonarqube.NewSonarQubeOptions(),
		KubernetesOptions:   k8s.NewKubernetesOptions(),
		ServiceMeshOptions:  servicemesh.NewServiceMeshOptions(),
H
hongming 已提交
97
		LdapOptions:         ldap.NewOptions(),
Z
zryfish 已提交
98 99
		RedisOptions:        cache.NewRedisOptions(),
		S3Options:           s3.NewS3Options(),
H
hongming 已提交
100
		OpenPitrixOptions:   openpitrix.NewOptions(),
J
Jeff 已提交
101 102 103 104
		MonitoringOptions:   prometheus.NewPrometheusOptions(),
		KubeSphereOptions:   kubesphere.NewKubeSphereOptions(),
		AlertingOptions:     alerting.NewAlertingOptions(),
		NotificationOptions: notification.NewNotificationOptions(),
G
Guangzhe Huang 已提交
105
		LoggingOptions:      elasticsearch.NewElasticSearchOptions(),
106
		AuthenticateOptions: iam.NewAuthenticateOptions(),
107 108 109
	}
}

110 111 112 113 114
// TryLoadFromDisk loads configuration from default location after server startup
// return nil error if configuration file not exists
func TryLoadFromDisk() (*Config, error) {
	viper.SetConfigName(defaultConfigurationName)
	viper.AddConfigPath(defaultConfigurationPath)
115

116 117
	// Load from current working directory, only used for debugging
	viper.AddConfigPath(".")
118

119 120 121 122 123 124
	if err := viper.ReadInConfig(); err != nil {
		if _, ok := err.(viper.ConfigFileNotFoundError); ok {
			return nil, err
		} else {
			return nil, fmt.Errorf("error parsing configuration file %s", err)
		}
J
Jeff 已提交
125 126
	}

127 128 129 130 131 132 133 134 135 136 137 138
	conf := New()
	if err := viper.Unmarshal(conf); err != nil {
		return nil, 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
		}
J
Jeff 已提交
139 140
	}

141 142
	return conf, nil
}
143

144 145 146 147 148 149
// InstallAPI installs api for config
func (conf *Config) InstallAPI(c *restful.Container) {
	ws := runtime.NewWebService(schema.GroupVersion{
		Group:   "",
		Version: "v1alpha1",
	})
150

151 152 153 154 155 156 157 158 159
	ws.Route(ws.GET("/configz").
		To(func(request *restful.Request, response *restful.Response) {
			conf.stripEmptyOptions()
			response.WriteAsJson(conf.toMap())
		}).
		Doc("Get system components configuration").
		Produces(restful.MIME_JSON).
		Writes(Config{}).
		Returns(http.StatusOK, "ok", Config{}))
160

161 162
	c.Add(ws)
}
163

164 165 166 167
// convertToMap simply converts config to map[string]bool
// to hide sensitive information
func (conf *Config) toMap() map[string]bool {
	result := make(map[string]bool, 0)
168

169 170
	if conf == nil {
		return result
171 172
	}

173
	c := reflect.Indirect(reflect.ValueOf(conf))
174

175 176 177 178 179
	for i := 0; i < c.NumField(); i++ {
		name := strings.Split(c.Type().Field(i).Tag.Get("json"), ",")[0]
		if strings.HasPrefix(name, "-") {
			continue
		}
180

181 182 183 184 185
		if c.Field(i).IsNil() {
			result[name] = false
		} else {
			result[name] = true
		}
186
	}
187 188

	return result
189
}
J
Jeff 已提交
190

191 192 193
func (conf *Config) stripEmptyOptions() {
	if conf.MySQLOptions != nil && conf.MySQLOptions.Host == "" {
		conf.MySQLOptions = nil
J
Jeff 已提交
194 195
	}

196 197
	if conf.RedisOptions != nil && conf.RedisOptions.RedisURL == "" {
		conf.RedisOptions = nil
J
Jeff 已提交
198 199
	}

200 201
	if conf.DevopsOptions != nil && conf.DevopsOptions.Host == "" {
		conf.DevopsOptions = nil
J
Jeff 已提交
202 203
	}

204 205 206
	if conf.MonitoringOptions != nil && conf.MonitoringOptions.Endpoint == "" &&
		conf.MonitoringOptions.SecondaryEndpoint == "" {
		conf.MonitoringOptions = nil
J
Jeff 已提交
207 208
	}

209 210
	if conf.SonarQubeOptions != nil && conf.SonarQubeOptions.Host == "" {
		conf.SonarQubeOptions = nil
J
Jeff 已提交
211 212
	}

213 214
	if conf.LdapOptions != nil && conf.LdapOptions.Host == "" {
		conf.LdapOptions = nil
J
Jeff 已提交
215 216
	}

217 218
	if conf.OpenPitrixOptions != nil && conf.OpenPitrixOptions.IsEmpty() {
		conf.OpenPitrixOptions = nil
J
Jeff 已提交
219 220
	}

221 222 223 224
	if conf.ServiceMeshOptions != nil && conf.ServiceMeshOptions.IstioPilotHost == "" &&
		conf.ServiceMeshOptions.ServicemeshPrometheusHost == "" &&
		conf.ServiceMeshOptions.JaegerQueryHost == "" {
		conf.ServiceMeshOptions = nil
J
Jeff 已提交
225 226
	}

227 228
	if conf.S3Options != nil && conf.S3Options.Endpoint == "" {
		conf.S3Options = nil
J
Jeff 已提交
229 230
	}

231 232
	if conf.AlertingOptions != nil && conf.AlertingOptions.Endpoint == "" {
		conf.AlertingOptions = nil
J
Jeff 已提交
233 234
	}

235 236
	if conf.LoggingOptions != nil && conf.LoggingOptions.Host == "" {
		conf.LoggingOptions = nil
J
Jeff 已提交
237 238
	}

239 240
	if conf.NotificationOptions != nil && conf.NotificationOptions.Endpoint == "" {
		conf.NotificationOptions = nil
J
Jeff 已提交
241 242
	}

J
Jeff 已提交
243
}