// DecodeCheckDefinition is used to decode a check definition func DecodeCheckDefinition(raw interface{}) (*CheckDefinition, error) { if err := FixupCheckType(raw); err != nil { return nil, err } var md mapstructure.Metadata var result CheckDefinition msdec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ Metadata: &md, Result: &result, }) if err != nil { return nil, err } if err := msdec.Decode(raw); err != nil { return nil, err } return &result, nil }
// DecodeServiceDefinition is used to decode a service definition func DecodeServiceDefinition(raw interface{}) (*ServiceDefinition, error) { var sub interface{} rawMap, ok := raw.(map[string]interface{}) if !ok { goto AFTER_FIX } // If no 'tags', handle the deprecated 'tag' value. if _, ok := rawMap["tags"]; !ok { if tag, ok := rawMap["tag"]; ok { rawMap["tags"] = []interface{}{tag} } } for k, v := range rawMap { if strings.ToLower(k) == "check" { sub = v break } } if sub == nil { goto AFTER_FIX } if err := FixupCheckType(sub); err != nil { return nil, err } AFTER_FIX: var md mapstructure.Metadata var result ServiceDefinition msdec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ Metadata: &md, Result: &result, }) if err != nil { return nil, err } if err := msdec.Decode(raw); err != nil { return nil, err } return &result, nil }
// DecodeConfig reads the configuration from the given reader in JSON // format and decodes it into a proper Config structure. func DecodeConfig(r io.Reader) (*Config, error) { var raw interface{} var result Config dec := json.NewDecoder(r) if err := dec.Decode(&raw); err != nil { return nil, err } // Check the result type if obj, ok := raw.(map[string]interface{}); ok { // Check for a "services", "service" or "check" key, meaning // this is actually a definition entry if sub, ok := obj["services"]; ok { if list, ok := sub.([]interface{}); ok { for _, srv := range list { service, err := DecodeServiceDefinition(srv) if err != nil { return nil, err } result.Services = append(result.Services, service) } } } if sub, ok := obj["service"]; ok { service, err := DecodeServiceDefinition(sub) if err != nil { return nil, err } result.Services = append(result.Services, service) } if sub, ok := obj["checks"]; ok { if list, ok := sub.([]interface{}); ok { for _, chk := range list { check, err := DecodeCheckDefinition(chk) if err != nil { return nil, err } result.Checks = append(result.Checks, check) } } } if sub, ok := obj["check"]; ok { check, err := DecodeCheckDefinition(sub) if err != nil { return nil, err } result.Checks = append(result.Checks, check) } } // Decode var md mapstructure.Metadata msdec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ Metadata: &md, Result: &result, }) if err != nil { return nil, err } if err := msdec.Decode(raw); err != nil { return nil, err } // Check unused fields and verify that no bad configuration options were // passed to Consul. There are a few additional fields which don't directly // use mapstructure decoding, so we need to account for those as well. allowedKeys := []string{"service", "services", "check", "checks"} var unused []string for _, field := range md.Unused { if !strContains(allowedKeys, field) { unused = append(unused, field) } } if len(unused) > 0 { return nil, fmt.Errorf("Config has invalid keys: %s", strings.Join(unused, ",")) } // Handle time conversions if raw := result.DNSConfig.NodeTTLRaw; raw != "" { dur, err := time.ParseDuration(raw) if err != nil { return nil, fmt.Errorf("NodeTTL invalid: %v", err) } result.DNSConfig.NodeTTL = dur } if raw := result.DNSConfig.MaxStaleRaw; raw != "" { dur, err := time.ParseDuration(raw) if err != nil { return nil, fmt.Errorf("MaxStale invalid: %v", err) } result.DNSConfig.MaxStale = dur } if len(result.DNSConfig.ServiceTTLRaw) != 0 { if result.DNSConfig.ServiceTTL == nil { result.DNSConfig.ServiceTTL = make(map[string]time.Duration) } for service, raw := range result.DNSConfig.ServiceTTLRaw { dur, err := time.ParseDuration(raw) if err != nil { return nil, fmt.Errorf("ServiceTTL %s invalid: %v", service, err) } result.DNSConfig.ServiceTTL[service] = dur } } if raw := result.CheckUpdateIntervalRaw; raw != "" { dur, err := time.ParseDuration(raw) if err != nil { return nil, fmt.Errorf("CheckUpdateInterval invalid: %v", err) } result.CheckUpdateInterval = dur } if raw := result.ACLTTLRaw; raw != "" { dur, err := time.ParseDuration(raw) if err != nil { return nil, fmt.Errorf("ACL TTL invalid: %v", err) } result.ACLTTL = dur } if raw := result.RetryIntervalRaw; raw != "" { dur, err := time.ParseDuration(raw) if err != nil { return nil, fmt.Errorf("RetryInterval invalid: %v", err) } result.RetryInterval = dur } if raw := result.RetryIntervalWanRaw; raw != "" { dur, err := time.ParseDuration(raw) if err != nil { return nil, fmt.Errorf("RetryIntervalWan invalid: %v", err) } result.RetryIntervalWan = dur } // Merge the single recursor if result.DNSRecursor != "" { result.DNSRecursors = append(result.DNSRecursors, result.DNSRecursor) } return &result, nil }