Skip to content

Commit

Permalink
Refactor mf config
Browse files Browse the repository at this point in the history
  • Loading branch information
bonzofenix committed Sep 18, 2024
1 parent e753aa7 commit 909b56c
Show file tree
Hide file tree
Showing 2 changed files with 190 additions and 157 deletions.
324 changes: 179 additions & 145 deletions src/autoscaler/metricsforwarder/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,10 @@ import (
"gopkg.in/yaml.v3"
)

// There are 3 type of errors that this package can return:
// - ErrReadYaml
// - ErrReadEnvironment
// - ErrReadVCAPEnvironment

var (
ErrReadYaml = errors.New("failed to read config file")
ErrReadJson = errors.New("failed to read vcap_services json")
ErrMetricsforwarderConfigNotFound = errors.New("Configuration error: metricsforwarder config service not found")
ErrMetricsforwarderConfigNotFound = errors.New("metricsforwarder config service not found")
)

const (
Expand All @@ -36,6 +31,16 @@ const (
DefaultValidDuration = 1 * time.Second
)

type LoggregatorConfig struct {
MetronAddress string `yaml:"metron_address"`
TLS models.TLSCerts `yaml:"tls"`
}
type SyslogConfig struct {
ServerAddress string `yaml:"server_address"`
Port int `yaml:"port"`
TLS models.TLSCerts `yaml:"tls"`
}

type Config struct {
Logging helpers.LoggingConfig `yaml:"logging"`
Server helpers.ServerConfig `yaml:"server"`
Expand All @@ -51,66 +56,28 @@ type Config struct {
StoredProcedureConfig *models.StoredProcedureConfig `yaml:"stored_procedure_binding_credential_config"`
}

var defaultServerConfig = helpers.ServerConfig{
Port: 6110,
}

var defaultHealthConfig = helpers.HealthConfig{
ServerConfig: helpers.ServerConfig{
Port: 8081,
},
}

var defaultLoggingConfig = helpers.LoggingConfig{
Level: "info",
}

type LoggingConfig struct {
Level string `yaml:"level"`
}

type LoggregatorConfig struct {
MetronAddress string `yaml:"metron_address"`
TLS models.TLSCerts `yaml:"tls"`
}

type SyslogConfig struct {
ServerAddress string `yaml:"server_address"`
Port int `yaml:"port"`
TLS models.TLSCerts `yaml:"tls"`
}

func decodeYamlFile(filepath string, c *Config) error {
r, err := os.Open(filepath)
func LoadConfig(filepath string, vcapReader configutil.VCAPConfigurationReader) (*Config, error) {
conf := defaultConfig()

if err != nil {
_, _ = fmt.Fprintf(os.Stdout, "failed to open config file '%s' : %s\n", filepath, err.Error())
return err
if err := loadYamlFile(filepath, &conf); err != nil {
return nil, err
}

dec := yaml.NewDecoder(r)
dec.KnownFields(true)
err = dec.Decode(c)

if err != nil {
return fmt.Errorf("%w: %w", ErrReadYaml, err)
if err := loadVcapConfig(&conf, vcapReader); err != nil {
return nil, err
}

defer r.Close()
return nil
return &conf, nil
}

func LoadConfig(filepath string, vcapReader configutil.VCAPConfigurationReader) (*Config, error) {
var conf Config
var err error

conf = Config{
Server: defaultServerConfig,
Logging: defaultLoggingConfig,
func defaultConfig() Config {
return Config{
Server: helpers.ServerConfig{Port: 6110},
Logging: helpers.LoggingConfig{Level: "info"},
LoggregatorConfig: LoggregatorConfig{
MetronAddress: DefaultMetronAddress,
},
Health: defaultHealthConfig,
Health: helpers.HealthConfig{ServerConfig: helpers.ServerConfig{Port: 8081}},
CacheTTL: DefaultCacheTTL,
CacheCleanupInterval: DefaultCacheCleanupInterval,
PolicyPollerInterval: DefaultPolicyPollerInterval,
Expand All @@ -119,125 +86,192 @@ func LoadConfig(filepath string, vcapReader configutil.VCAPConfigurationReader)
ValidDuration: DefaultValidDuration,
},
}
}

if filepath != "" {
err = decodeYamlFile(filepath, &conf)
if err != nil {
return nil, err
}
func loadYamlFile(filepath string, conf *Config) error {
if filepath == "" {
return nil
}
file, err := os.Open(filepath)
if err != nil {
fmt.Fprintf(os.Stdout, "failed to open config file '%s': %s\n", filepath, err)
return ErrReadYaml
}
defer file.Close()

if vcapReader.IsRunningOnCF() {
conf.Server.Port = vcapReader.GetPort()
dec := yaml.NewDecoder(file)
dec.KnownFields(true)
if err := dec.Decode(conf); err != nil {
return fmt.Errorf("%w: %v", ErrReadYaml, err)
}
return nil
}

data, err := vcapReader.GetServiceCredentialContent("config", "metricsforwarder")
if err != nil {
return &conf, fmt.Errorf("%w: %w", ErrMetricsforwarderConfigNotFound, err)
}
func loadVcapConfig(conf *Config, vcapReader configutil.VCAPConfigurationReader) error {
if !vcapReader.IsRunningOnCF() {
return nil
}

err = yaml.Unmarshal(data, &conf)
if err != nil {
return &conf, fmt.Errorf("%w: %w", ErrReadJson, err)
}
conf.Server.Port = vcapReader.GetPort()
if err := loadMetricsforwarderConfig(conf, vcapReader); err != nil {
return err
}

if conf.Db == nil {
conf.Db = make(map[string]db.DatabaseConfig)
}
if conf.Db == nil {
conf.Db = make(map[string]db.DatabaseConfig)
}

currentPolicyDb, ok := conf.Db[db.PolicyDb]
if !ok {
conf.Db[db.PolicyDb] = db.DatabaseConfig{}
}
if err := configurePolicyDb(conf, vcapReader); err != nil {
return err
}

currentPolicyDb.URL, err = vcapReader.MaterializeDBFromService(db.PolicyDb)
if err != nil {
return &conf, err
}
conf.Db[db.PolicyDb] = currentPolicyDb

if conf.CredHelperImpl == "stored_procedure" {
currentStoredProcedureDb, ok := conf.Db[db.StoredProcedureDb]
if !ok {
conf.Db[db.StoredProcedureDb] = db.DatabaseConfig{}
}

currentStoredProcedureDb.URL, err = vcapReader.MaterializeDBFromService(db.StoredProcedureDb)
if err != nil {
return &conf, err
}

dbURL, err := url.Parse(currentStoredProcedureDb.URL)
if err != nil {
return &conf, err
}

if conf.StoredProcedureConfig != nil {
if conf.StoredProcedureConfig.Username != "" {
currentStoredProcedureDb.URL = strings.Replace(currentStoredProcedureDb.URL, dbURL.User.Username(), conf.StoredProcedureConfig.Username, 1)
}

if conf.StoredProcedureConfig.Password != "" {
bindingPassword, _ := dbURL.User.Password()
currentStoredProcedureDb.URL = strings.Replace(currentStoredProcedureDb.URL, bindingPassword, conf.StoredProcedureConfig.Password, 1)
}
}

conf.Db[db.StoredProcedureDb] = currentStoredProcedureDb
if conf.CredHelperImpl == "stored_procedure" {
if err := configureStoredProcedureDb(conf, vcapReader); err != nil {
return err
}
}

if err := configureSyslogTLS(conf, vcapReader); err != nil {
return err
}

conf.SyslogConfig.TLS, err = vcapReader.MaterializeTLSConfigFromService("syslog-client")
return nil
}

func loadMetricsforwarderConfig(conf *Config, vcapReader configutil.VCAPConfigurationReader) error {
data, err := vcapReader.GetServiceCredentialContent("config", "metricsforwarder")
if err != nil {
return &conf, err
return fmt.Errorf("%w: %v", ErrMetricsforwarderConfigNotFound, err)
}
return yaml.Unmarshal(data, conf)
}

return &conf, nil
func configurePolicyDb(conf *Config, vcapReader configutil.VCAPConfigurationReader) error {

currentPolicyDb, ok := conf.Db[db.PolicyDb]
if !ok {
conf.Db[db.PolicyDb] = db.DatabaseConfig{}
}

dbURL, err := vcapReader.MaterializeDBFromService(db.PolicyDb)
currentPolicyDb.URL = dbURL
if err != nil {
return err
}
conf.Db[db.PolicyDb] = currentPolicyDb
return nil
}

func (c *Config) UsingSyslog() bool {
return c.SyslogConfig.ServerAddress != "" && c.SyslogConfig.Port != 0
func configureStoredProcedureDb(conf *Config, vcapReader configutil.VCAPConfigurationReader) error {
currentStoredProcedureDb, exists := conf.Db[db.StoredProcedureDb]
if !exists {
conf.Db[db.StoredProcedureDb] = db.DatabaseConfig{}
}

dbURL, err := vcapReader.MaterializeDBFromService(db.StoredProcedureDb)

currentStoredProcedureDb.URL = dbURL
parsedUrl, err := url.Parse(currentStoredProcedureDb.URL)
if err != nil {
return err
}

if conf.StoredProcedureConfig != nil {
if conf.StoredProcedureConfig.Username != "" {
currentStoredProcedureDb.URL = strings.Replace(currentStoredProcedureDb.URL, parsedUrl.User.Username(), conf.StoredProcedureConfig.Username, 1)
}
if conf.StoredProcedureConfig.Password != "" {
bindingPassword, _ := parsedUrl.User.Password()
currentStoredProcedureDb.URL = strings.Replace(currentStoredProcedureDb.URL, bindingPassword, conf.StoredProcedureConfig.Password, 1)
}
}
conf.Db[db.StoredProcedureDb] = currentStoredProcedureDb

return nil
}

func configureSyslogTLS(conf *Config, vcapReader configutil.VCAPConfigurationReader) error {
tls, err := vcapReader.MaterializeTLSConfigFromService("syslog-client")
if err != nil {
return err
}
conf.SyslogConfig.TLS = tls
return nil
}

func (c *Config) Validate() error {
if err := c.validateDbConfig(); err != nil {
return err
}
if err := c.validateSyslogOrLoggregator(); err != nil {
return err
}
if err := c.validateRateLimit(); err != nil {
return err
}
if err := c.validateCredHelperImpl(); err != nil {
return err
}
return c.Health.Validate()
}

func (c *Config) validateDbConfig() error {
if c.Db[db.PolicyDb].URL == "" {
return fmt.Errorf("Configuration error: Policy DB url is empty")
return errors.New("Policy DB url is empty")
}
return nil
}

func (c *Config) validateSyslogOrLoggregator() error {
if c.UsingSyslog() {
if c.SyslogConfig.TLS.CACertFile == "" {
return fmt.Errorf("Configuration error: SyslogServer Loggregator CACert is empty")
}
if c.SyslogConfig.TLS.CertFile == "" {
return fmt.Errorf("Configuration error: SyslogServer ClientCert is empty")
}
if c.SyslogConfig.TLS.KeyFile == "" {
return fmt.Errorf("Configuration error: SyslogServer ClientKey is empty")
}
} else {
if c.LoggregatorConfig.TLS.CACertFile == "" {
return fmt.Errorf("Configuration error: Loggregator CACert is empty")
}
if c.LoggregatorConfig.TLS.CertFile == "" {
return fmt.Errorf("Configuration error: Loggregator ClientCert is empty")
}
if c.LoggregatorConfig.TLS.KeyFile == "" {
return fmt.Errorf("Configuration error: Loggregator ClientKey is empty")
}
return c.validateSyslogConfig()
}
return c.validateLoggregatorConfig()
}

if c.RateLimit.MaxAmount <= 0 {
return fmt.Errorf("Configuration error: RateLimit.MaxAmount is equal or less than zero")
func (c *Config) validateSyslogConfig() error {
if c.SyslogConfig.TLS.CACertFile == "" {
return errors.New("SyslogServer Loggregator CACert is empty")
}
if c.RateLimit.ValidDuration <= 0*time.Nanosecond {
return fmt.Errorf("Configuration error: RateLimit.ValidDuration is equal or less than zero nanosecond")
if c.SyslogConfig.TLS.CertFile == "" {
return errors.New("SyslogServer ClientCert is empty")
}
if c.CredHelperImpl == "" {
return fmt.Errorf("Configuration error: CredHelperImpl is empty")
if c.SyslogConfig.TLS.KeyFile == "" {
return errors.New("SyslogServer ClientKey is empty")
}
return nil
}

if err := c.Health.Validate(); err != nil {
return err
func (c *Config) validateLoggregatorConfig() error {
if c.LoggregatorConfig.TLS.CACertFile == "" {
return errors.New("Loggregator CACert is empty")
}
if c.LoggregatorConfig.TLS.CertFile == "" {
return errors.New("Loggregator ClientCert is empty")
}
if c.LoggregatorConfig.TLS.KeyFile == "" {
return errors.New("Loggregator ClientKey is empty")
}
return nil
}

func (c *Config) validateRateLimit() error {
if c.RateLimit.MaxAmount <= 0 {
return errors.New("RateLimit.MaxAmount is less than or equal to zero")
}
if c.RateLimit.ValidDuration <= 0 {
return errors.New("RateLimit.ValidDuration is less than or equal to zero")
}
return nil
}

func (c *Config) validateCredHelperImpl() error {
if c.CredHelperImpl == "" {
return errors.New("CredHelperImpl is empty")
}
return nil
}

func (c *Config) UsingSyslog() bool {
return c.SyslogConfig.ServerAddress != "" && c.SyslogConfig.Port != 0
}
Loading

0 comments on commit 909b56c

Please sign in to comment.