// lldap-to-ldap migrates LLDAP directory data to standard LDAP (LDIF format). // Part of the NetKingdom IAM migration contract. package main import ( "flag" "fmt" "os" "github.com/rs/zerolog" "gopkg.in/yaml.v3" "keycape/internal/migration/lldapexport" "keycape/internal/migration/toldap" "keycape/internal/server/telemetry" ) func main() { inputFile := flag.String("input", "", "Path to canonical-export.yaml (required)") outputFile := flag.String("output", "export.ldif", "Path to write LDIF output") baseDN := flag.String("basedn", "dc=netkingdom,dc=local", "LDAP base DN") targetStr := flag.String("target", "openldap", "LDAP target: openldap | 389ds | ad") flag.Parse() if *inputFile == "" { fmt.Fprintln(os.Stderr, "lldap-to-ldap: -input is required") flag.Usage() os.Exit(1) } target, err := parseTarget(*targetStr) if err != nil { fmt.Fprintf(os.Stderr, "lldap-to-ldap: %v\n", err) os.Exit(1) } data, err := os.ReadFile(*inputFile) if err != nil { fmt.Fprintf(os.Stderr, "lldap-to-ldap: read %q: %v\n", *inputFile, err) os.Exit(1) } var export lldapexport.ExportResult if err := yaml.Unmarshal(data, &export); err != nil { fmt.Fprintf(os.Stderr, "lldap-to-ldap: parse YAML: %v\n", err) os.Exit(1) } log := zerolog.New(os.Stderr).With().Timestamp().Logger() em := telemetry.NewLogEmitter(log) gen := toldap.New(toldap.Config{ BaseDN: *baseDN, Target: target, }, em) ldif, err := gen.Generate(&export) if err != nil { fmt.Fprintf(os.Stderr, "lldap-to-ldap: generate: %v\n", err) os.Exit(1) } if err := os.WriteFile(*outputFile, []byte(ldif), 0o600); err != nil { fmt.Fprintf(os.Stderr, "lldap-to-ldap: write %q: %v\n", *outputFile, err) os.Exit(1) } fmt.Printf("lldap-to-ldap: wrote %s (%d bytes)\n", *outputFile, len(ldif)) } func parseTarget(s string) (toldap.Target, error) { switch s { case "openldap": return toldap.TargetOpenLDAP, nil case "389ds": return toldap.Target389DS, nil case "ad": return toldap.TargetAD, nil default: return "", fmt.Errorf("unknown target %q: must be one of openldap, 389ds, ad", s) } }