package main import ( "fmt" "github.com/pelletier/go-toml" "os" ) type Config struct { ServerPort uint16 `toml:"port"` Users []User `toml:"user"` RRConfigs []RRConfig `toml:"rrconfig"` users map[string]*User rrconfigs map[string]*RRConfig } type User struct { Username string `toml:"username"` Password string `toml:"password"` Records []string `toml:"records"` records map[string]bool } type RRConfig struct { Recordname string `toml:"recordname"` Zonename string `toml:"zonename"` Nameserver string `toml:"nameserver"` Tsigalgo string `toml:"tsig_algo"` Tsigid string `toml:"tsig_id"` Tsigkey string `toml:"tsig_key"` Ttl int `toml:"ttl" default:"60"` } func LoadConfig(path string) (*Config, error) { var cfg Config f, err := os.Open(path) if err != nil { return nil, err } decoder := toml.NewDecoder(f).Strict(true) err = decoder.Decode(&cfg) if err != nil { return nil, err } return prepareConfig(&cfg) } func prepareConfig(cfg *Config) (*Config, error) { if len(cfg.Users) <= 0 || len(cfg.RRConfigs) <= 0 { return nil, fmt.Errorf("No users or resource record configs present.") } // temporary map for detecting duplicated or orphaned entries between // records and users globRecords := map[string]bool{} // populate user map cfg.users = map[string]*User{} for u := range cfg.Users { user := &cfg.Users[u] if _, ok := cfg.users[user.Username]; ok { return nil, fmt.Errorf("Duplicate username detected: %s", user.Username) } // initialize and populate user.records map user.records = make(map[string]bool) if len(user.Records) <= 0 { return nil, fmt.Errorf("User without records detected: %s", user.Username) } for _, record := range user.Records { // check for duplicate records if globRecords[record] { return nil, fmt.Errorf("Record associated with multiple users detected: %s", record) } // memorize record both in the user as well as in the temporary map user.records[record] = true globRecords[record] = true } cfg.users[user.Username] = user } // populate record map cfg.rrconfigs = map[string]*RRConfig{} for r := range cfg.RRConfigs { record := &cfg.RRConfigs[r] // check for duplicate record before verifying association to users if _, ok := cfg.rrconfigs[record.Recordname]; ok { return nil, fmt.Errorf("Duplicate record detected: %s", record.Recordname) } if !globRecords[record.Recordname] { return nil, fmt.Errorf("Record without associated user detected: %s", record.Recordname) } // need to remove record from globRecords for detecting orphaned records delete(globRecords, record.Recordname) cfg.rrconfigs[record.Recordname] = record } // check whether all records have been processed if len(globRecords) > 0 { missing := make([]string, len(globRecords)) i := 0 for k := range globRecords { missing[i] = k i++ } return nil, fmt.Errorf("Records associated to user missing: %v", missing) } return cfg, nil }