mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-22 02:06:39 +00:00
[management] Legacy to embedded IdP migration tool (#5586)
This commit is contained in:
174
tools/idp-migrate/config.go
Normal file
174
tools/idp-migrate/config.go
Normal file
@@ -0,0 +1,174 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/netbirdio/netbird/util"
|
||||
)
|
||||
|
||||
type migrationConfig struct {
|
||||
// Data
|
||||
dashboardURL string
|
||||
apiURL string
|
||||
configPath string
|
||||
dataDir string
|
||||
idpSeedInfo string
|
||||
|
||||
// Options
|
||||
dryRun bool
|
||||
force bool
|
||||
skipConfig bool
|
||||
skipPopulateUserInfo bool
|
||||
|
||||
// Logging
|
||||
logLevel string
|
||||
}
|
||||
|
||||
func config() (*migrationConfig, error) {
|
||||
cfg, err := configFromArgs(os.Args[1:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := util.InitLog(cfg.logLevel, util.LogConsole); err != nil {
|
||||
return nil, fmt.Errorf("init logger: %w", err)
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func configFromArgs(args []string) (*migrationConfig, error) {
|
||||
var cfg migrationConfig
|
||||
var domain string
|
||||
|
||||
fs := flag.NewFlagSet("netbird-idp-migrate", flag.ContinueOnError)
|
||||
fs.StringVar(&domain, "domain", "", "domain for both dashboard and API")
|
||||
fs.StringVar(&cfg.dashboardURL, "dashboard-url", "", "dashboard URL")
|
||||
fs.StringVar(&cfg.apiURL, "api-url", "", "API URL")
|
||||
fs.StringVar(&cfg.configPath, "config", "", "path to management.json (required)")
|
||||
fs.StringVar(&cfg.dataDir, "datadir", "", "override data directory from config")
|
||||
fs.StringVar(&cfg.idpSeedInfo, "idp-seed-info", "", "base64-encoded connector JSON (overrides auto-detection)")
|
||||
fs.BoolVar(&cfg.dryRun, "dry-run", false, "preview changes without writing")
|
||||
fs.BoolVar(&cfg.force, "force", false, "skip confirmation prompt")
|
||||
fs.BoolVar(&cfg.skipConfig, "skip-config", false, "skip config generation (DB migration only)")
|
||||
fs.BoolVar(&cfg.skipPopulateUserInfo, "skip-populate-user-info", false, "skip populating user info (user id migration only)")
|
||||
fs.StringVar(&cfg.logLevel, "log-level", "info", "log level (debug, info, warn, error)")
|
||||
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
applyOverrides(&cfg, domain)
|
||||
|
||||
if err := validateConfig(&cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
// applyOverrides resolves domain configuration from broad to narrow sources.
|
||||
// The most granular value always wins:
|
||||
//
|
||||
// --domain flag (broadest, only fills blanks)
|
||||
// NETBIRD_DOMAIN env (overrides flags, sets both)
|
||||
// --api-domain / --dashboard-domain flags (more specific than --domain)
|
||||
// NETBIRD_API_URL / NETBIRD_DASHBOARD_URL env (most specific, always wins)
|
||||
//
|
||||
// Other env vars unconditionally override their corresponding flags.
|
||||
func applyOverrides(cfg *migrationConfig, domain string) {
|
||||
// --domain is a convenience shorthand: only fills in values not already
|
||||
// set by the more specific --api-domain / --dashboard-domain flags.
|
||||
if domain != "" {
|
||||
if cfg.apiURL == "" {
|
||||
cfg.apiURL = domain
|
||||
}
|
||||
if cfg.dashboardURL == "" {
|
||||
cfg.dashboardURL = domain
|
||||
}
|
||||
}
|
||||
|
||||
// Env vars override flags. Broad env var first, then narrow ones on top,
|
||||
// so the most granular value always wins.
|
||||
if val, ok := os.LookupEnv("NETBIRD_DOMAIN"); ok {
|
||||
cfg.dashboardURL = val
|
||||
cfg.apiURL = val
|
||||
}
|
||||
|
||||
if val, ok := os.LookupEnv("NETBIRD_API_URL"); ok {
|
||||
cfg.apiURL = val
|
||||
}
|
||||
|
||||
if val, ok := os.LookupEnv("NETBIRD_DASHBOARD_URL"); ok {
|
||||
cfg.dashboardURL = val
|
||||
}
|
||||
|
||||
if val, ok := os.LookupEnv("NETBIRD_CONFIG_PATH"); ok {
|
||||
cfg.configPath = val
|
||||
}
|
||||
|
||||
if val, ok := os.LookupEnv("NETBIRD_DATA_DIR"); ok {
|
||||
cfg.dataDir = val
|
||||
}
|
||||
|
||||
if val, ok := os.LookupEnv("NETBIRD_IDP_SEED_INFO"); ok {
|
||||
cfg.idpSeedInfo = val
|
||||
}
|
||||
|
||||
// Enforce dry run if any value is provided
|
||||
if sval, ok := os.LookupEnv("NETBIRD_DRY_RUN"); ok {
|
||||
if val, err := strconv.ParseBool(sval); err == nil {
|
||||
cfg.dryRun = val
|
||||
}
|
||||
}
|
||||
|
||||
cfg.dryRun = parseBool("NETBIRD_DRY_RUN", cfg.dryRun)
|
||||
cfg.force = parseBool("NETBIRD_FORCE", cfg.force)
|
||||
cfg.skipConfig = parseBool("NETBIRD_SKIP_CONFIG", cfg.skipConfig)
|
||||
cfg.skipPopulateUserInfo = parseBool("NETBIRD_SKIP_POPULATE_USER_INFO", cfg.skipPopulateUserInfo)
|
||||
|
||||
if val, ok := os.LookupEnv("NETBIRD_LOG_LEVEL"); ok {
|
||||
cfg.logLevel = val
|
||||
}
|
||||
}
|
||||
|
||||
func parseBool(varName string, defaultVal bool) bool {
|
||||
stringValue, ok := os.LookupEnv(varName)
|
||||
if !ok {
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
boolValue, err := strconv.ParseBool(stringValue)
|
||||
if err != nil {
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
return boolValue
|
||||
}
|
||||
|
||||
func validateConfig(cfg *migrationConfig) error {
|
||||
if cfg.configPath == "" {
|
||||
return fmt.Errorf("--config is required")
|
||||
}
|
||||
|
||||
if cfg.dataDir == "" {
|
||||
return fmt.Errorf("--datadir is required")
|
||||
}
|
||||
|
||||
if cfg.idpSeedInfo == "" {
|
||||
return fmt.Errorf("--idp-seed-info is required")
|
||||
}
|
||||
|
||||
if cfg.apiURL == "" {
|
||||
return fmt.Errorf("--api-domain is required")
|
||||
}
|
||||
|
||||
if cfg.dashboardURL == "" {
|
||||
return fmt.Errorf("--dashboard-domain is required")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user