Init
This commit is contained in:
201
internal/config/config.go
Normal file
201
internal/config/config.go
Normal file
@@ -0,0 +1,201 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"git.benadis.ru/gitops/benadis-rac/internal/constants"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Config представляет основную конфигурацию приложения
|
||||
type Config struct {
|
||||
RACPath string `yaml:"rac_path"`
|
||||
ConnectionTimeout string `yaml:"connection_timeout"`
|
||||
CommandTimeout string `yaml:"command_timeout"`
|
||||
RetryCount int `yaml:"retry_count"`
|
||||
RetryDelay string `yaml:"retry_delay"`
|
||||
}
|
||||
|
||||
// GetConnectionTimeout возвращает ConnectionTimeout как time.Duration
|
||||
func (c *Config) GetConnectionTimeout() (time.Duration, error) {
|
||||
return time.ParseDuration(c.ConnectionTimeout)
|
||||
}
|
||||
|
||||
// GetCommandTimeout возвращает CommandTimeout как time.Duration
|
||||
func (c *Config) GetCommandTimeout() (time.Duration, error) {
|
||||
return time.ParseDuration(c.CommandTimeout)
|
||||
}
|
||||
|
||||
// GetRetryDelay возвращает RetryDelay как time.Duration
|
||||
func (c *Config) GetRetryDelay() (time.Duration, error) {
|
||||
return time.ParseDuration(c.RetryDelay)
|
||||
}
|
||||
|
||||
// ProjectCredentials представляет учетные данные для конкретного проекта
|
||||
type ProjectCredentials struct {
|
||||
ClusterAdmin string `yaml:"cluster_admin,omitempty"`
|
||||
ClusterAdminPassword string `yaml:"cluster_admin_password,omitempty"`
|
||||
DBAdmin string `yaml:"db_admin,omitempty"`
|
||||
DBAdminPassword string `yaml:"db_admin_password,omitempty"`
|
||||
}
|
||||
|
||||
// Secret представляет секретную конфигурацию
|
||||
type Secret struct {
|
||||
ClusterAdmin string `yaml:"cluster_admin"`
|
||||
ClusterAdminPassword string `yaml:"cluster_admin_password"`
|
||||
DBAdmin string `yaml:"db_admin"`
|
||||
DBAdminPassword string `yaml:"db_admin_password"`
|
||||
Projects map[string]*ProjectCredentials `yaml:"projects,omitempty"`
|
||||
}
|
||||
|
||||
// ServiceModeConfig представляет конфигурацию service-mode из project.yaml
|
||||
type ServiceModeConfig struct {
|
||||
ServerHost string `yaml:"server_host"`
|
||||
ServerPort int `yaml:"server_port"`
|
||||
RACPort int `yaml:"rac_port"`
|
||||
LogLevel string `yaml:"log_level"`
|
||||
ServerName string `yaml:"server_name"`
|
||||
BaseName string `yaml:"base_name"`
|
||||
Command string `yaml:"command"`
|
||||
}
|
||||
|
||||
// ProjectConfig представляет конфигурацию проекта
|
||||
type ProjectConfig struct {
|
||||
ServiceMode *ServiceModeConfig `yaml:"service-mode"`
|
||||
}
|
||||
|
||||
// AppConfig объединяет все конфигурации
|
||||
type AppConfig struct {
|
||||
Config *Config
|
||||
Secret *Secret
|
||||
Project *ProjectConfig
|
||||
}
|
||||
|
||||
// LoadConfig загружает конфигурацию из файлов
|
||||
func LoadConfig(configPath, secretPath, projectPath string) (*AppConfig, error) {
|
||||
config, err := loadConfigFile(configPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(constants.ErrLoadConfig, err)
|
||||
}
|
||||
|
||||
secret, err := loadSecretFile(secretPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(constants.ErrLoadSecret, err)
|
||||
}
|
||||
|
||||
project, err := loadProjectFile(projectPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load project config: %w", err)
|
||||
}
|
||||
|
||||
return &AppConfig{
|
||||
Config: config,
|
||||
Secret: secret,
|
||||
Project: project,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// loadConfigFile загружает основной конфигурационный файл
|
||||
func loadConfigFile(path string) (*Config, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read config file: %w", err)
|
||||
}
|
||||
|
||||
var config Config
|
||||
if err := yaml.Unmarshal(data, &config); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
|
||||
}
|
||||
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
// loadSecretFile загружает файл с секретами
|
||||
func loadSecretFile(path string) (*Secret, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read secret file: %w", err)
|
||||
}
|
||||
|
||||
var secret Secret
|
||||
if err := yaml.Unmarshal(data, &secret); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal secret: %w", err)
|
||||
}
|
||||
|
||||
return &secret, nil
|
||||
}
|
||||
|
||||
// loadProjectFile загружает файл с настройками проекта
|
||||
func loadProjectFile(path string) (*ProjectConfig, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read project file: %w", err)
|
||||
}
|
||||
|
||||
var project ProjectConfig
|
||||
if err := yaml.Unmarshal(data, &project); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal project: %w", err)
|
||||
}
|
||||
|
||||
return &project, nil
|
||||
}
|
||||
|
||||
// Validate проверяет корректность конфигурации
|
||||
func (ac *AppConfig) Validate() error {
|
||||
if ac.Config.RACPath == "" {
|
||||
return fmt.Errorf(constants.ErrRACPathRequired)
|
||||
}
|
||||
if ac.Project == nil || ac.Project.ServiceMode == nil {
|
||||
return fmt.Errorf("project service-mode configuration is required")
|
||||
}
|
||||
if ac.Project.ServiceMode.ServerHost == "" {
|
||||
return fmt.Errorf(constants.ErrServerHostRequired)
|
||||
}
|
||||
if ac.Project.ServiceMode.BaseName == "" {
|
||||
return fmt.Errorf(constants.ErrBaseNameRequired)
|
||||
}
|
||||
if ac.Secret.ClusterAdmin == "" {
|
||||
return fmt.Errorf(constants.ErrClusterAdminRequired)
|
||||
}
|
||||
if ac.Secret.DBAdmin == "" {
|
||||
return fmt.Errorf(constants.ErrDBAdminRequired)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetRACAddress возвращает адрес для подключения к RAC
|
||||
func (ac *AppConfig) GetRACAddress() string {
|
||||
return fmt.Sprintf("%s:%d", ac.Project.ServiceMode.ServerHost, ac.Project.ServiceMode.RACPort)
|
||||
}
|
||||
|
||||
// GetClusterCredentials возвращает учетные данные кластера с учетом приоритета проекта
|
||||
func (ac *AppConfig) GetClusterCredentials(projectName string) (string, string) {
|
||||
// Проверяем настройки для конкретного проекта
|
||||
if ac.Secret.Projects != nil {
|
||||
if projectCreds, exists := ac.Secret.Projects[projectName]; exists {
|
||||
if projectCreds.ClusterAdmin != "" {
|
||||
return projectCreds.ClusterAdmin, projectCreds.ClusterAdminPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
// Возвращаем глобальные настройки
|
||||
return ac.Secret.ClusterAdmin, ac.Secret.ClusterAdminPassword
|
||||
}
|
||||
|
||||
// GetDBCredentials возвращает учетные данные базы данных с учетом приоритета проекта
|
||||
func (ac *AppConfig) GetDBCredentials(projectName string) (string, string) {
|
||||
// Проверяем настройки для конкретного проекта
|
||||
if ac.Secret.Projects != nil {
|
||||
if projectCreds, exists := ac.Secret.Projects[projectName]; exists {
|
||||
if projectCreds.DBAdmin != "" {
|
||||
return projectCreds.DBAdmin, projectCreds.DBAdminPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
// Возвращаем глобальные настройки
|
||||
return ac.Secret.DBAdmin, ac.Secret.DBAdminPassword
|
||||
}
|
||||
209
internal/config/config_test.go
Normal file
209
internal/config/config_test.go
Normal file
@@ -0,0 +1,209 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestLoadConfig(t *testing.T) {
|
||||
// Создаем временные файлы для тестирования
|
||||
configContent := `server_host: localhost
|
||||
server_port: 1540
|
||||
rac_port: 1545
|
||||
rac_path: "/path/to/rac"
|
||||
connection_timeout: 30s
|
||||
command_timeout: 60s
|
||||
retry_count: 3
|
||||
retry_delay: 5s
|
||||
log_level: Debug
|
||||
server_name: "Test Server"`
|
||||
|
||||
secretContent := `cluster_admin: "admin"
|
||||
cluster_admin_password: "password"
|
||||
db_admin: "dbadmin"
|
||||
db_admin_password: "dbpassword"`
|
||||
|
||||
projectContent := `service-mode:
|
||||
server_host: "localhost"
|
||||
server_port: 1540
|
||||
rac_port: 1545
|
||||
base_name: "TestDB"
|
||||
log_level: "Info"`
|
||||
|
||||
// Создаем временные файлы
|
||||
configFile, err := os.CreateTemp("", "config_*.yaml")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp config file: %v", err)
|
||||
}
|
||||
defer os.Remove(configFile.Name())
|
||||
|
||||
secretFile, err := os.CreateTemp("", "secret_*.yaml")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp secret file: %v", err)
|
||||
}
|
||||
defer os.Remove(secretFile.Name())
|
||||
|
||||
projectFile, err := os.CreateTemp("", "project_*.yaml")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp project file: %v", err)
|
||||
}
|
||||
defer os.Remove(projectFile.Name())
|
||||
|
||||
// Записываем содержимое
|
||||
if _, err := configFile.WriteString(configContent); err != nil {
|
||||
t.Fatalf("Failed to write config file: %v", err)
|
||||
}
|
||||
configFile.Close()
|
||||
|
||||
if _, err := secretFile.WriteString(secretContent); err != nil {
|
||||
t.Fatalf("Failed to write secret file: %v", err)
|
||||
}
|
||||
secretFile.Close()
|
||||
|
||||
if _, err := projectFile.WriteString(projectContent); err != nil {
|
||||
t.Fatalf("Failed to write project file: %v", err)
|
||||
}
|
||||
projectFile.Close()
|
||||
|
||||
// Тестируем загрузку конфигурации
|
||||
appConfig, err := LoadConfig(configFile.Name(), secretFile.Name(), projectFile.Name())
|
||||
if err != nil {
|
||||
t.Fatalf("LoadConfig failed: %v", err)
|
||||
}
|
||||
|
||||
// Проверяем основную конфигурацию
|
||||
if appConfig.Project.ServiceMode.ServerHost != "localhost" {
|
||||
t.Errorf("Expected ServerHost 'localhost', got '%s'", appConfig.Project.ServiceMode.ServerHost)
|
||||
}
|
||||
|
||||
if appConfig.Project.ServiceMode.ServerPort != 1540 {
|
||||
t.Errorf("Expected ServerPort 1540, got %d", appConfig.Project.ServiceMode.ServerPort)
|
||||
}
|
||||
|
||||
if appConfig.Project.ServiceMode.RACPort != 1545 {
|
||||
t.Errorf("Expected RACPort 1545, got %d", appConfig.Project.ServiceMode.RACPort)
|
||||
}
|
||||
|
||||
connectionTimeout, err := appConfig.Config.GetConnectionTimeout()
|
||||
if err != nil {
|
||||
t.Errorf("Failed to parse ConnectionTimeout: %v", err)
|
||||
}
|
||||
if connectionTimeout != 30*time.Second {
|
||||
t.Errorf("Expected ConnectionTimeout 30s, got %v", connectionTimeout)
|
||||
}
|
||||
|
||||
// Проверяем секретную конфигурацию
|
||||
if appConfig.Secret.ClusterAdmin != "admin" {
|
||||
t.Errorf("Expected ClusterAdmin 'admin', got '%s'", appConfig.Secret.ClusterAdmin)
|
||||
}
|
||||
|
||||
if appConfig.Secret.DBAdminPassword != "dbpassword" {
|
||||
t.Errorf("Expected DBAdminPassword 'dbpassword', got '%s'", appConfig.Secret.DBAdminPassword)
|
||||
}
|
||||
|
||||
// Проверяем проектную конфигурацию
|
||||
if appConfig.Project.ServiceMode.BaseName != "TestDB" {
|
||||
t.Errorf("Expected BaseName 'TestDB', got '%s'", appConfig.Project.ServiceMode.BaseName)
|
||||
}
|
||||
|
||||
if appConfig.Project.ServiceMode.LogLevel != "Info" {
|
||||
t.Errorf("Expected LogLevel 'Info', got '%s'", appConfig.Project.ServiceMode.LogLevel)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
config *AppConfig
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
name: "valid config",
|
||||
config: &AppConfig{
|
||||
Config: &Config{
|
||||
RACPath: "/path/to/rac",
|
||||
},
|
||||
Secret: &Secret{
|
||||
ClusterAdmin: "admin",
|
||||
DBAdmin: "dbadmin",
|
||||
},
|
||||
Project: &ProjectConfig{
|
||||
ServiceMode: &ServiceModeConfig{
|
||||
ServerHost: "localhost",
|
||||
BaseName: "TestDB",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "missing server host",
|
||||
config: &AppConfig{
|
||||
Config: &Config{
|
||||
RACPath: "/path/to/rac",
|
||||
},
|
||||
Secret: &Secret{
|
||||
ClusterAdmin: "admin",
|
||||
DBAdmin: "dbadmin",
|
||||
},
|
||||
Project: &ProjectConfig{
|
||||
ServiceMode: &ServiceModeConfig{
|
||||
ServerHost: "",
|
||||
BaseName: "TestDB",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "missing cluster admin",
|
||||
config: &AppConfig{
|
||||
Config: &Config{
|
||||
RACPath: "/path/to/rac",
|
||||
},
|
||||
Secret: &Secret{
|
||||
ClusterAdmin: "",
|
||||
DBAdmin: "dbadmin",
|
||||
},
|
||||
Project: &ProjectConfig{
|
||||
ServiceMode: &ServiceModeConfig{
|
||||
ServerHost: "localhost",
|
||||
BaseName: "TestDB",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.config.Validate()
|
||||
if tt.expectErr && err == nil {
|
||||
t.Error("Expected error but got none")
|
||||
}
|
||||
if !tt.expectErr && err != nil {
|
||||
t.Errorf("Expected no error but got: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRACAddress(t *testing.T) {
|
||||
config := &AppConfig{
|
||||
Project: &ProjectConfig{
|
||||
ServiceMode: &ServiceModeConfig{
|
||||
ServerHost: "example.com",
|
||||
RACPort: 1545,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expected := "example.com:1545"
|
||||
actual := config.GetRACAddress()
|
||||
|
||||
if actual != expected {
|
||||
t.Errorf("Expected '%s', got '%s'", expected, actual)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user