package main import ( "bufio" "fmt" "os" "strings" ) type HostConfig struct { Name string IP string User string KeyPath string SSHArgs string } type Inventory struct { Router HostConfig Workers map[string]HostConfig } func ParseInventory(path string) (*Inventory, error) { file, err := os.Open(path) if err != nil { return nil, fmt.Errorf("could not open inventory: %w", err) } defer file.Close() inv := &Inventory{ Workers: make(map[string]HostConfig), } var currentGroup string scanner := bufio.NewScanner(file) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if line == "" || strings.HasPrefix(line, ";") || strings.HasPrefix(line, "#") { continue } if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") { currentGroup = strings.Trim(line, "[]") continue } parts := strings.Fields(line) if len(parts) < 2 { continue } config := HostConfig{Name: parts[0]} for _, part := range parts[1:] { kv := strings.SplitN(part, "=", 2) if len(kv) != 2 { continue } val := strings.Trim(kv[1], "'\"") switch kv[0] { case "ansible_host": config.IP = val case "ansible_user": config.User = val case "ansible_ssh_private_key_file": config.KeyPath = val case "ansible_ssh_common_args": config.SSHArgs = val } } if currentGroup == "router" { inv.Router = config } else if currentGroup == "workers" { inv.Workers[config.Name] = config } } if err := scanner.Err(); err != nil { return nil, err } return inv, nil }