config/config.go (108 lines of code) (raw):
/*
* 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 config
import (
"errors"
"fmt"
"net"
"os"
"strings"
"github.com/apache/kvrocks-controller/store/engine/consul"
"github.com/apache/kvrocks-controller/store/engine/raft"
"github.com/go-playground/validator/v10"
"github.com/apache/kvrocks-controller/logger"
"github.com/apache/kvrocks-controller/store/engine/etcd"
"github.com/apache/kvrocks-controller/store/engine/zookeeper"
)
type AdminConfig struct {
Addr string `yaml:"addr"`
}
type FailOverConfig struct {
PingIntervalSeconds int `yaml:"ping_interval_seconds"`
MaxPingCount int64 `yaml:"max_ping_count"`
}
type ControllerConfig struct {
FailOver *FailOverConfig `yaml:"failover"`
}
type LogConfig struct {
Level string `yaml:"level"`
Filename string `yaml:"filename"`
MaxBackups int `yaml:"max_backups"`
MaxAge int `yaml:"max_age"`
MaxSize int `yaml:"max_size"`
Compress bool `yaml:"compress"`
}
const defaultPort = 9379
type Config struct {
Addr string `yaml:"addr"`
StorageType string `yaml:"storage_type"`
Etcd *etcd.Config `yaml:"etcd"`
Zookeeper *zookeeper.Config `yaml:"zookeeper"`
Raft *raft.Config `yaml:"raft"`
Consul *consul.Config `yaml:"consul"`
Admin AdminConfig `yaml:"admin"`
Controller *ControllerConfig `yaml:"controller"`
Log *LogConfig `yaml:"log"`
}
func DefaultFailOverConfig() *FailOverConfig {
return &FailOverConfig{
PingIntervalSeconds: 3,
MaxPingCount: 5,
}
}
func Default() *Config {
c := &Config{
Etcd: &etcd.Config{
Addrs: []string{"127.0.0.1:2379"},
},
Controller: &ControllerConfig{
FailOver: DefaultFailOverConfig(),
},
}
c.Addr = c.getAddr()
return c
}
func (c *Config) Validate() error {
if c.Controller.FailOver.MaxPingCount < 3 {
return errors.New("max ping count required >= 3")
}
if c.Controller.FailOver.PingIntervalSeconds < 1 {
return errors.New("ping interval required >= 1s")
}
hostPort := strings.Split(c.Addr, ":")
if hostPort[0] == "0.0.0.0" || hostPort[0] == "127.0.0.1" {
logger.Get().Warn("Leader forward may not work if the host is " + hostPort[0])
}
return nil
}
func (c *Config) getAddr() string {
// env has higher priority than configuration.
// case: get addr from env
checker := validator.New()
host := os.Getenv("KVROCKS_CONTROLLER_HTTP_HOST")
port := os.Getenv("KVROCKS_CONTROLLER_HTTP_PORT")
addr := host + ":" + port
err := checker.Var(addr, "required,tcp_addr")
if err == nil {
return fmt.Sprintf("%s:%s", host, port)
}
if c.Addr != "" {
return c.Addr
}
// case: addr is empty
ip := getLocalIP()
if ip != "" {
return fmt.Sprintf("%s:%d", ip, defaultPort)
}
return fmt.Sprintf("127.0.0.1:%d", defaultPort)
}
// getLocalIP returns the non loopback local IP of the host.
func getLocalIP() string {
addrs, err := net.InterfaceAddrs()
if err != nil {
return ""
}
for _, address := range addrs {
// check the address type and if it is not a loopback the display it
ipnet, ok := address.(*net.IPNet)
if ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
return ipnet.IP.String()
}
}
}
return ""
}