Files
tf_provider/TOOLS/yaml-generator/internal/config/config.go
T

194 lines
4.5 KiB
Go

// Package config — загрузка конфигурации, токенов и списка сервисов.
package config
import (
"errors"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"yaml-generator/internal/normalize"
)
// Config — конфигурация генератора.
type Config struct {
APIEndpoint string
APIToken string
Services []ServiceRef
SingleServiceID int
SingleServiceName string
OutputDir string
}
// ServiceRef — ссылка на сервис (ID + имя).
type ServiceRef struct {
ID int
Name string
}
// Load читает конфигурацию из переменных окружения и файлов.
func Load() (Config, error) {
apiEndpoint := getenvDefault("NUBES_API_ENDPOINT", "https://lk-api-gateway.ngcloud.ru/api/v1/svc")
apiEndpoint = normalize.APIEndpoint(apiEndpoint)
apiToken, err := loadToken()
if err != nil {
return Config{}, err
}
singleID := 0
if raw := strings.TrimSpace(os.Getenv("NUBES_SERVICE_ID")); raw != "" {
val, err := strconv.Atoi(raw)
if err != nil {
return Config{}, fmt.Errorf("invalid NUBES_SERVICE_ID: %s", raw)
}
singleID = val
}
singleName := strings.TrimSpace(os.Getenv("NUBES_SERVICE_NAME"))
outputDir := strings.TrimSpace(os.Getenv("NUBES_OUTPUT_DIR"))
services := []ServiceRef{}
if singleID == 0 {
listPath := strings.TrimSpace(os.Getenv("NUBES_SERVICES_FILE"))
if listPath == "" {
repoRoot, err := FindRepoRoot()
if err != nil {
return Config{}, err
}
listPath = filepath.Join(repoRoot, "devops", "config", "services_list.txt")
}
list, err := ReadServicesList(listPath)
if err != nil {
return Config{}, err
}
services = list
}
return Config{
APIEndpoint: apiEndpoint,
APIToken: apiToken,
Services: services,
SingleServiceID: singleID,
SingleServiceName: singleName,
OutputDir: outputDir,
}, nil
}
func getenvDefault(key string, def string) string {
val := strings.TrimSpace(os.Getenv(key))
if val == "" {
return def
}
return val
}
func loadToken() (string, error) {
if tok := strings.TrimSpace(os.Getenv("NUBES_API_TOKEN")); tok != "" {
return tok, nil
}
if tf := strings.TrimSpace(os.Getenv("TOKEN_FILE")); tf != "" {
b, err := os.ReadFile(tf)
if err != nil {
return "", err
}
return strings.TrimSpace(string(b)), nil
}
repoRoot, err := FindRepoRoot()
if err != nil {
return "", err
}
latest, err := findLatestToken(repoRoot)
if err != nil {
return "", err
}
if latest == "" {
return "", errors.New("NUBES_API_TOKEN or TOKEN_FILE is required")
}
b, err := os.ReadFile(latest)
if err != nil {
return "", err
}
return strings.TrimSpace(string(b)), nil
}
func findLatestToken(dir string) (string, error) {
entries, err := os.ReadDir(dir)
if err != nil {
return "", err
}
var latest string
var latestTime int64
for _, e := range entries {
if e.IsDir() || !strings.HasSuffix(e.Name(), ".token") {
continue
}
info, err := e.Info()
if err != nil {
continue
}
mt := info.ModTime().Unix()
if mt > latestTime {
latestTime = mt
latest = filepath.Join(dir, e.Name())
}
}
return latest, nil
}
// ReadServicesList читает список сервисов из файла.
func ReadServicesList(path string) ([]ServiceRef, error) {
b, err := os.ReadFile(path)
if err != nil {
return nil, err
}
lines := strings.Split(string(b), "\n")
services := []ServiceRef{}
for _, raw := range lines {
line := strings.TrimSpace(strings.ReplaceAll(raw, "\r", ""))
if line == "" || strings.HasPrefix(line, "#") {
continue
}
if strings.Contains(line, "#") {
line = strings.TrimSpace(strings.SplitN(line, "#", 2)[0])
}
parts := strings.Fields(line)
if len(parts) == 0 {
continue
}
id, err := strconv.Atoi(parts[0])
if err != nil {
return nil, fmt.Errorf("invalid service id in %s: %s", path, parts[0])
}
name := ""
if len(parts) > 1 {
name = parts[1]
}
services = append(services, ServiceRef{ID: id, Name: name})
}
return services, nil
}
// FindRepoRoot ищет корень репозитория по директории provider.
func FindRepoRoot() (string, error) {
wd, err := os.Getwd()
if err != nil {
return "", err
}
current := wd
for i := 0; i < 8; i++ {
candidate := filepath.Join(current, "provider")
info, err := os.Stat(candidate)
if err == nil && info.IsDir() {
return candidate, nil
}
parent := filepath.Dir(current)
if parent == current {
break
}
current = parent
}
return "", errors.New("failed to locate provider repo root")
}