Files
unkin-agent 3f14554fae
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
read facts from PuppetDB's query API
- rename internal/pdbmux to internal/puppetdb
- fetch facts with one GET /pdb/query/v4/facts AST query per node
- drop the per-node fallback route and its two response shapes
- rename --pdb to --puppetdb, CATALOG_DIFF_PDB to CATALOG_DIFF_PUPPETDB and
  pdb_url to puppetdb_url
- describe the fact source generically in the README and AGENTS.md
2026-09-12 17:49:57 +10:00

114 lines
3.4 KiB
Go

// Package config loads the shared configuration for the puppet-catalog-tools
// binaries. Precedence (lowest to highest): defaults < config file < env vars
// < CLI flags (applied by the caller).
package config
import (
"fmt"
"os"
"path/filepath"
"gopkg.in/yaml.v3"
)
const (
appName = "puppet-catalog-tools"
configFileName = "config.yaml"
// DefaultServerURL is the k8s OpenVoxServer compiler pool. The legacy VM
// masters behind puppet.query.consul remain reachable via --server.
DefaultServerURL = "https://puppet.k8s.syd1.au.unkin.net:8140"
// DefaultPuppetDBURL is the PuppetDB facts are read from.
DefaultPuppetDBURL = "https://pdbmux.k8s.syd1.au.unkin.net"
// DefaultBaseEnvironment is the environment branches are diffed against.
DefaultBaseEnvironment = "develop"
)
// Config holds every configurable value. Fields map 1:1 to config file keys.
type Config struct {
ServerURL string `yaml:"server_url"`
PuppetDBURL string `yaml:"puppetdb_url"`
Cert string `yaml:"cert"`
Key string `yaml:"key"`
CACert string `yaml:"cacert"`
BaseEnvironment string `yaml:"base_environment"`
}
// Default returns the built-in configuration.
func Default() Config {
return Config{
ServerURL: DefaultServerURL,
PuppetDBURL: DefaultPuppetDBURL,
BaseEnvironment: DefaultBaseEnvironment,
}
}
// Dir returns the XDG config directory for these tools.
func Dir() string {
base := os.Getenv("XDG_CONFIG_HOME")
if base == "" {
home, _ := os.UserHomeDir()
base = filepath.Join(home, ".config")
}
return filepath.Join(base, appName)
}
// Path returns the full path to the config file.
func Path() string { return filepath.Join(Dir(), configFileName) }
// Load reads the config file (if present), then applies env var overrides.
func Load() (Config, error) {
cfg := Default()
path := Path()
data, err := os.ReadFile(path)
if err != nil && !os.IsNotExist(err) {
return cfg, fmt.Errorf("reading config %s: %w", path, err)
}
if err == nil {
if err := yaml.Unmarshal(data, &cfg); err != nil {
return cfg, fmt.Errorf("parsing config %s: %w", path, err)
}
}
env := map[string]*string{
"CATALOG_DIFF_SERVER": &cfg.ServerURL,
"CATALOG_DIFF_PUPPETDB": &cfg.PuppetDBURL,
"CATALOG_DIFF_CERT": &cfg.Cert,
"CATALOG_DIFF_KEY": &cfg.Key,
"CATALOG_DIFF_CACERT": &cfg.CACert,
"CATALOG_DIFF_BASE_ENVIRONMENT": &cfg.BaseEnvironment,
}
for name, field := range env {
if v := os.Getenv(name); v != "" {
*field = v
}
}
return cfg, nil
}
// WriteDefault creates the config directory and writes a default config file.
// It refuses to overwrite an existing file.
func WriteDefault() (string, error) {
if err := os.MkdirAll(Dir(), 0o755); err != nil {
return "", fmt.Errorf("creating config dir: %w", err)
}
path := Path()
if _, err := os.Stat(path); err == nil {
return "", fmt.Errorf("config already exists at %s", path)
}
data, err := yaml.Marshal(Default())
if err != nil {
return "", err
}
header := "# puppet-catalog-tools configuration\n" +
"# Overridable with CATALOG_DIFF_SERVER, CATALOG_DIFF_PUPPETDB,\n" +
"# CATALOG_DIFF_CERT, CATALOG_DIFF_KEY, CATALOG_DIFF_CACERT,\n" +
"# CATALOG_DIFF_BASE_ENVIRONMENT.\n\n"
if err := os.WriteFile(path, append([]byte(header), data...), 0o644); err != nil {
return "", fmt.Errorf("writing config: %w", err)
}
return path, nil
}