func parseResources(result *structs.Resources, list *ast.ObjectList) error { list = list.Elem() if len(list.Items) == 0 { return nil } if len(list.Items) > 1 { return fmt.Errorf("only one 'resource' block allowed per task") } // Get our resource object o := list.Items[0] // We need this later var listVal *ast.ObjectList if ot, ok := o.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return fmt.Errorf("resource: should be an object") } var m map[string]interface{} if err := hcl.DecodeObject(&m, o.Val); err != nil { return err } delete(m, "network") if err := mapstructure.WeakDecode(m, result); err != nil { return err } // Parse the network resources if o := listVal.Filter("network"); len(o.Items) > 0 { if len(o.Items) > 1 { return fmt.Errorf("only one 'network' resource allowed") } var r structs.NetworkResource var m map[string]interface{} if err := hcl.DecodeObject(&m, o.Items[0].Val); err != nil { return err } if err := mapstructure.WeakDecode(m, &r); err != nil { return err } var networkObj *ast.ObjectList if ot, ok := o.Items[0].Val.(*ast.ObjectType); ok { networkObj = ot.List } else { return fmt.Errorf("resource: should be an object") } if err := parsePorts(networkObj, &r); err != nil { return err } result.Networks = []*structs.NetworkResource{&r} } return nil }
func parseTelemetry(result *Config, list *ast.ObjectList) error { if len(list.Items) > 1 { return fmt.Errorf("only one 'telemetry' block is permitted") } // Get our one item item := list.Items[0] // Check for invalid keys valid := []string{ "statsite_address", "statsd_address", "disable_hostname", } if err := checkHCLKeys(item.Val, valid); err != nil { return multierror.Prefix(err, "telemetry:") } var t Telemetry if err := hcl.DecodeObject(&t, item.Val); err != nil { return multierror.Prefix(err, "telemetry:") } if result.Telemetry == nil { result.Telemetry = &Telemetry{} } if err := hcl.DecodeObject(&result.Telemetry, item.Val); err != nil { return multierror.Prefix(err, "telemetry:") } return nil }
func parseResources(result *structs.Resources, obj *hclobj.Object) error { if obj.Len() > 1 { return fmt.Errorf("only one 'resource' block allowed per task") } for _, o := range obj.Elem(false) { var m map[string]interface{} if err := hcl.DecodeObject(&m, o); err != nil { return err } delete(m, "network") if err := mapstructure.WeakDecode(m, result); err != nil { return err } // Parse the network resources if o := o.Get("network", false); o != nil { if o.Len() > 1 { return fmt.Errorf("only one 'network' resource allowed") } var r structs.NetworkResource var m map[string]interface{} if err := hcl.DecodeObject(&m, o); err != nil { return err } if err := mapstructure.WeakDecode(m, &r); err != nil { return err } // Keep track of labels we've already seen so we can ensure there // are no collisions when we turn them into environment variables. // lowercase:NomalCase so we can get the first for the error message seenLabel := map[string]string{} for _, label := range r.DynamicPorts { if !reDynamicPorts.MatchString(label) { return errDynamicPorts } first, seen := seenLabel[strings.ToLower(label)] if seen { return fmt.Errorf("Found a port label collision: `%s` overlaps with previous `%s`", label, first) } else { seenLabel[strings.ToLower(label)] = label } } result.Networks = []*structs.NetworkResource{&r} } } return nil }
func loadConfigVariables(hclConfig *ast.ObjectList) ([]*tfcfg.Variable, error) { hclConfig = hclConfig.Children() result := make([]*tfcfg.Variable, 0, len(hclConfig.Items)) if len(hclConfig.Items) == 0 { return result, nil } for _, item := range hclConfig.Items { n := item.Keys[0].Token.Value().(string) var listVal *ast.ObjectList if ot, ok := item.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return nil, fmt.Errorf("variable '%s': should be a block", n) } var config map[string]interface{} if err := hcl.DecodeObject(&config, item.Val); err != nil { return nil, err } variable := &tfcfg.Variable{ Name: n, } if a := listVal.Filter("default"); len(a.Items) > 0 { err := hcl.DecodeObject(&variable.Default, a.Items[0].Val) if err != nil { return nil, fmt.Errorf( "error reading variable %s default: %s", n, err, ) } } if a := listVal.Filter("description"); len(a.Items) > 0 { err := hcl.DecodeObject(&variable.Description, a.Items[0].Val) if err != nil { return nil, fmt.Errorf( "error reading variable %s description: %s", n, err, ) } } if a := listVal.Filter("type"); len(a.Items) > 0 { err := hcl.DecodeObject(&variable.DeclaredType, a.Items[0].Val) if err != nil { return nil, fmt.Errorf( "error reading variable %s type: %s", n, err, ) } } result = append(result, variable) } return result, nil }
// LoadOutputsHcl recurses into the given HCL object and turns // it into a mapping of outputs. func loadOutputsHcl(list *ast.ObjectList) ([]*Output, error) { list = list.Children() if len(list.Items) == 0 { return nil, fmt.Errorf( "'output' must be followed by exactly one string: a name") } // Go through each object and turn it into an actual result. result := make([]*Output, 0, len(list.Items)) for _, item := range list.Items { n := item.Keys[0].Token.Value().(string) var listVal *ast.ObjectList if ot, ok := item.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return nil, fmt.Errorf("output '%s': should be an object", n) } var config map[string]interface{} if err := hcl.DecodeObject(&config, item.Val); err != nil { return nil, err } // Delete special keys delete(config, "depends_on") rawConfig, err := NewRawConfig(config) if err != nil { return nil, fmt.Errorf( "Error reading config for output %s: %s", n, err) } // If we have depends fields, then add those in var dependsOn []string if o := listVal.Filter("depends_on"); len(o.Items) > 0 { err := hcl.DecodeObject(&dependsOn, o.Items[0].Val) if err != nil { return nil, fmt.Errorf( "Error reading depends_on for output %q: %s", n, err) } } result = append(result, &Output{ Name: n, RawConfig: rawConfig, DependsOn: dependsOn, }) } return result, nil }
// LoadProvidersHcl recurses into the given HCL object and turns // it into a mapping of provider configs. func loadProvidersHcl(os *hclobj.Object) ([]*ProviderConfig, error) { var objects []*hclobj.Object // Iterate over all the "provider" blocks and get the keys along with // their raw configuration objects. We'll parse those later. for _, o1 := range os.Elem(false) { for _, o2 := range o1.Elem(true) { objects = append(objects, o2) } } if len(objects) == 0 { return nil, nil } // Go through each object and turn it into an actual result. result := make([]*ProviderConfig, 0, len(objects)) for _, o := range objects { var config map[string]interface{} if err := hcl.DecodeObject(&config, o); err != nil { return nil, err } delete(config, "alias") rawConfig, err := NewRawConfig(config) if err != nil { return nil, fmt.Errorf( "Error reading config for provider config %s: %s", o.Key, err) } // If we have an alias field, then add those in var alias string if a := o.Get("alias", false); a != nil { err := hcl.DecodeObject(&alias, a) if err != nil { return nil, fmt.Errorf( "Error reading alias for provider[%s]: %s", o.Key, err) } } result = append(result, &ProviderConfig{ Name: o.Key, Alias: alias, RawConfig: rawConfig, }) } return result, nil }
// LoadProvidersHcl recurses into the given HCL object and turns // it into a mapping of provider configs. func loadProvidersHcl(list *ast.ObjectList) ([]*ProviderConfig, error) { list = list.Children() if len(list.Items) == 0 { return nil, nil } // Go through each object and turn it into an actual result. result := make([]*ProviderConfig, 0, len(list.Items)) for _, item := range list.Items { n := item.Keys[0].Token.Value().(string) var listVal *ast.ObjectList if ot, ok := item.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return nil, fmt.Errorf("module '%s': should be an object", n) } var config map[string]interface{} if err := hcl.DecodeObject(&config, item.Val); err != nil { return nil, err } delete(config, "alias") rawConfig, err := NewRawConfig(config) if err != nil { return nil, fmt.Errorf( "Error reading config for provider config %s: %s", n, err) } // If we have an alias field, then add those in var alias string if a := listVal.Filter("alias"); len(a.Items) > 0 { err := hcl.DecodeObject(&alias, a.Items[0].Val) if err != nil { return nil, fmt.Errorf( "Error reading alias for provider[%s]: %s", n, err) } } result = append(result, &ProviderConfig{ Name: n, Alias: alias, RawConfig: rawConfig, }) } return result, nil }
func loadConfigProviders(hclConfig *ast.ObjectList) ([]*tfcfg.ProviderConfig, error) { hclConfig = hclConfig.Children() result := make([]*tfcfg.ProviderConfig, 0, len(hclConfig.Items)) if len(hclConfig.Items) == 0 { return result, nil } for _, item := range hclConfig.Items { n := item.Keys[0].Token.Value().(string) var listVal *ast.ObjectList if ot, ok := item.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return nil, fmt.Errorf("provider '%s': should be a block", n) } var config map[string]interface{} if err := hcl.DecodeObject(&config, item.Val); err != nil { return nil, err } delete(config, "alias") rawConfig, err := tfcfg.NewRawConfig(config) if err != nil { return nil, fmt.Errorf( "error reading provider config %s: %s", n, err, ) } // If we have an alias, add it in var alias string if a := listVal.Filter("alias"); len(a.Items) > 0 { err := hcl.DecodeObject(&alias, a.Items[0].Val) if err != nil { return nil, fmt.Errorf( "error reading provider %s alias: %s", n, err, ) } } result = append(result, &tfcfg.ProviderConfig{ Name: n, Alias: alias, RawConfig: rawConfig, }) } return result, nil }
func loadConfigModules(hclConfig *ast.ObjectList) ([]*tfcfg.Module, error) { hclConfig = hclConfig.Children() result := make([]*tfcfg.Module, 0, len(hclConfig.Items)) if len(hclConfig.Items) == 0 { return result, nil } for _, item := range hclConfig.Items { n := item.Keys[0].Token.Value().(string) var listVal *ast.ObjectList if ot, ok := item.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return nil, fmt.Errorf("module '%s': should be a block", n) } var config map[string]interface{} if err := hcl.DecodeObject(&config, item.Val); err != nil { return nil, err } delete(config, "source") rawConfig, err := tfcfg.NewRawConfig(config) if err != nil { return nil, fmt.Errorf( "error reading module config %s: %s", n, err, ) } var source string if a := listVal.Filter("source"); len(a.Items) > 0 { err := hcl.DecodeObject(&source, a.Items[0].Val) if err != nil { return nil, fmt.Errorf( "error reading module %s source: %s", n, err, ) } } result = append(result, &tfcfg.Module{ Name: n, Source: source, RawConfig: rawConfig, }) } return result, nil }
func parseUpdate(result *structs.UpdateStrategy, obj *hclobj.Object) error { if obj.Len() > 1 { return fmt.Errorf("only one 'update' block allowed per job") } for _, o := range obj.Elem(false) { var m map[string]interface{} if err := hcl.DecodeObject(&m, o); err != nil { return err } for _, key := range []string{"stagger", "Stagger"} { if raw, ok := m[key]; ok { switch v := raw.(type) { case string: dur, err := time.ParseDuration(v) if err != nil { return fmt.Errorf("invalid stagger time '%s'", raw) } m[key] = dur case int: m[key] = time.Duration(v) * time.Second default: return fmt.Errorf("invalid type for stagger time '%s'", raw) } } } if err := mapstructure.WeakDecode(m, result); err != nil { return err } } return nil }
func parseRestartPolicy(final **structs.RestartPolicy, list *ast.ObjectList) error { list = list.Elem() if len(list.Items) > 1 { return fmt.Errorf("only one 'restart' block allowed") } // Get our job object obj := list.Items[0] var m map[string]interface{} if err := hcl.DecodeObject(&m, obj.Val); err != nil { return err } var result structs.RestartPolicy dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ DecodeHook: mapstructure.StringToTimeDurationHookFunc(), WeaklyTypedInput: true, Result: &result, }) if err != nil { return err } if err := dec.Decode(m); err != nil { return err } *final = &result return nil }
func parseConstraints(result *[]*structs.Constraint, obj *hclobj.Object) error { for _, o := range obj.Elem(false) { var m map[string]interface{} if err := hcl.DecodeObject(&m, o); err != nil { return err } m["LTarget"] = m["attribute"] m["RTarget"] = m["value"] m["Operand"] = m["operator"] // Default constraint to being hard if _, ok := m["hard"]; !ok { m["hard"] = true } // Build the constraint var c structs.Constraint if err := mapstructure.WeakDecode(m, &c); err != nil { return err } if c.Operand == "" { c.Operand = "=" } *result = append(*result, &c) } return nil }
// ParseSSHHelperConfig parses the given contents as a string for the SSHHelper // configuration. func ParseSSHHelperConfig(contents string) (*SSHHelperConfig, error) { root, err := hcl.Parse(string(contents)) if err != nil { return nil, fmt.Errorf("ssh_helper: error parsing config: %s", err) } list, ok := root.Node.(*ast.ObjectList) if !ok { return nil, fmt.Errorf("ssh_helper: error parsing config: file doesn't contain a root object") } valid := []string{ "vault_addr", "ssh_mount_point", "ca_cert", "ca_path", "allowed_cidr_list", "allowed_roles", "tls_skip_verify", } if err := checkHCLKeys(list, valid); err != nil { return nil, multierror.Prefix(err, "ssh_helper:") } var c SSHHelperConfig c.SSHMountPoint = SSHHelperDefaultMountPoint if err := hcl.DecodeObject(&c, list); err != nil { return nil, multierror.Prefix(err, "ssh_helper:") } if c.VaultAddr == "" { return nil, fmt.Errorf("ssh_helper: missing config 'vault_addr'") } return &c, nil }
func parseProject(result *File, obj *hclobj.Object) error { if obj.Len() > 1 { return fmt.Errorf("only one 'project' block allowed") } // Check for invalid keys valid := []string{"name", "infrastructure"} if err := checkHCLKeys(obj, valid); err != nil { return multierror.Prefix(err, "project:") } var m map[string]interface{} if err := hcl.DecodeObject(&m, obj); err != nil { return err } // Parse the project var proj Project result.Project = &proj if err := mapstructure.WeakDecode(m, &proj); err != nil { return err } return nil }
// ParseConfig parses the given configuration as a string. func ParseConfig(contents string) (*DefaultConfig, error) { root, err := hcl.Parse(contents) if err != nil { return nil, err } // Top-level item should be the object list list, ok := root.Node.(*ast.ObjectList) if !ok { return nil, fmt.Errorf("Failed to parse config: does not contain a root object") } valid := []string{ "token_helper", } if err := checkHCLKeys(list, valid); err != nil { return nil, err } var c DefaultConfig if err := hcl.DecodeObject(&c, list); err != nil { return nil, err } return &c, nil }
func parseProject(result *File, list *ast.ObjectList) error { if len(list.Items) > 1 { return fmt.Errorf("only one 'project' block allowed") } // Get our one item item := list.Items[0] // Check for invalid keys valid := []string{"name", "infrastructure"} if err := checkHCLKeys(item.Val, valid); err != nil { return multierror.Prefix(err, "project:") } var m map[string]interface{} if err := hcl.DecodeObject(&m, item.Val); err != nil { return err } // Parse the project var proj Project result.Project = &proj if err := mapstructure.WeakDecode(m, &proj); err != nil { return err } return nil }
func parseTelemetry(result **Telemetry, list *ast.ObjectList) error { list = list.Elem() if len(list.Items) > 1 { return fmt.Errorf("only one 'telemetry' block allowed") } // Get our telemetry object listVal := list.Items[0].Val // Check for invalid keys valid := []string{ "statsite_address", "statsd_address", "disable_hostname", } if err := checkHCLKeys(listVal, valid); err != nil { return err } var m map[string]interface{} if err := hcl.DecodeObject(&m, listVal); err != nil { return err } var telemetry Telemetry if err := mapstructure.WeakDecode(m, &telemetry); err != nil { return err } *result = &telemetry return nil }
func parseUpdate(result *structs.UpdateStrategy, list *ast.ObjectList) error { list = list.Elem() if len(list.Items) > 1 { return fmt.Errorf("only one 'update' block allowed per job") } // Get our resource object o := list.Items[0] var m map[string]interface{} if err := hcl.DecodeObject(&m, o.Val); err != nil { return err } // Check for invalid keys valid := []string{ "stagger", "max_parallel", } if err := checkHCLKeys(o.Val, valid); err != nil { return err } dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ DecodeHook: mapstructure.StringToTimeDurationHookFunc(), WeaklyTypedInput: true, Result: result, }) if err != nil { return err } return dec.Decode(m) }
// LoadSSHHelperConfig loads ssh-helper's configuration from the file and populates the corresponding // in-memory structure. // // Vault address is a required parameter. // Mount point defaults to "ssh". func LoadSSHHelperConfig(path string) (*SSHHelperConfig, error) { var config SSHHelperConfig contents, err := ioutil.ReadFile(path) if !os.IsNotExist(err) { obj, err := hcl.Parse(string(contents)) if err != nil { return nil, err } if err := hcl.DecodeObject(&config, obj); err != nil { return nil, err } } else { return nil, err } if config.VaultAddr == "" { return nil, fmt.Errorf("config missing vault_addr") } if config.SSHMountPoint == "" { config.SSHMountPoint = SSHHelperDefaultMountPoint } return &config, nil }
func parsePorts(networkObj *ast.ObjectList, nw *structs.NetworkResource) error { portsObjList := networkObj.Filter("port") knownPortLabels := make(map[string]bool) for _, port := range portsObjList.Items { if len(port.Keys) == 0 { return fmt.Errorf("ports must be named") } label := port.Keys[0].Token.Value().(string) if !reDynamicPorts.MatchString(label) { return errPortLabel } l := strings.ToLower(label) if knownPortLabels[l] { return fmt.Errorf("found a port label collision: %s", label) } var p map[string]interface{} var res structs.Port if err := hcl.DecodeObject(&p, port.Val); err != nil { return err } if err := mapstructure.WeakDecode(p, &res); err != nil { return err } res.Label = label if res.Value > 0 { nw.ReservedPorts = append(nw.ReservedPorts, res) } else { nw.DynamicPorts = append(nw.DynamicPorts, res) } knownPortLabels[l] = true } return nil }
// LoadOutputsHcl recurses into the given HCL object and turns // it into a mapping of outputs. func loadOutputsHcl(list *ast.ObjectList) ([]*Output, error) { list = list.Children() if len(list.Items) == 0 { return nil, nil } // Go through each object and turn it into an actual result. result := make([]*Output, 0, len(list.Items)) for _, item := range list.Items { n := item.Keys[0].Token.Value().(string) var config map[string]interface{} if err := hcl.DecodeObject(&config, item.Val); err != nil { return nil, err } rawConfig, err := NewRawConfig(config) if err != nil { return nil, fmt.Errorf( "Error reading config for output %s: %s", n, err) } result = append(result, &Output{ Name: n, RawConfig: rawConfig, }) } return result, nil }
func parseChecks(service *structs.Service, checkObjs *ast.ObjectList) error { service.Checks = make([]*structs.ServiceCheck, len(checkObjs.Items)) for idx, co := range checkObjs.Items { var check structs.ServiceCheck var cm map[string]interface{} if err := hcl.DecodeObject(&cm, co.Val); err != nil { return err } dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ DecodeHook: mapstructure.StringToTimeDurationHookFunc(), WeaklyTypedInput: true, Result: &check, }) if err != nil { return err } if err := dec.Decode(cm); err != nil { return err } service.Checks[idx] = &check } return nil }
func loadConfigOutputs(hclConfig *ast.ObjectList) ([]*tfcfg.Output, error) { hclConfig = hclConfig.Children() result := make([]*tfcfg.Output, 0, len(hclConfig.Items)) if len(hclConfig.Items) == 0 { return result, nil } for _, item := range hclConfig.Items { n := item.Keys[0].Token.Value().(string) if _, ok := item.Val.(*ast.ObjectType); !ok { return nil, fmt.Errorf("output '%s': should be a block", n) } var config map[string]interface{} if err := hcl.DecodeObject(&config, item.Val); err != nil { return nil, err } rawConfig, err := tfcfg.NewRawConfig(config) if err != nil { return nil, fmt.Errorf( "error reading output config %s: %s", n, err, ) } result = append(result, &tfcfg.Output{ Name: n, RawConfig: rawConfig, }) } return result, nil }
func parseFoundations(result *Infrastructure, list *ast.ObjectList) error { list = list.Children() if len(list.Items) == 0 { return nil } // Go through each object and turn it into an actual result. collection := make([]*Foundation, 0, len(list.Items)) seen := make(map[string]struct{}) for _, item := range list.Items { n := item.Keys[0].Token.Value().(string) // Make sure we haven't already found this if _, ok := seen[n]; ok { return fmt.Errorf("foundation '%s' defined more than once", n) } seen[n] = struct{}{} var m map[string]interface{} if err := hcl.DecodeObject(&m, item.Val); err != nil { return err } var f Foundation f.Name = n f.Config = m collection = append(collection, &f) } // Set the results result.Foundations = collection return nil }
func parseLocalDisk(result **structs.LocalDisk, list *ast.ObjectList) error { list = list.Elem() if len(list.Items) > 1 { return fmt.Errorf("only one 'local_disk' block allowed") } // Get our local_disk object obj := list.Items[0] // Check for invalid keys valid := []string{ "sticky", "disk", } if err := checkHCLKeys(obj.Val, valid); err != nil { return err } var m map[string]interface{} if err := hcl.DecodeObject(&m, obj.Val); err != nil { return err } var localDisk structs.LocalDisk if err := mapstructure.WeakDecode(m, &localDisk); err != nil { return err } *result = &localDisk return nil }
// LoadConfig reads the configuration from the given path. If path is // empty, then the default path will be used, or the environment variable // if set. func LoadConfig(path string) (*Config, error) { if path == "" { path = DefaultConfigPath } if v := os.Getenv(ConfigPathEnv); v != "" { path = v } path, err := homedir.Expand(path) if err != nil { return nil, fmt.Errorf("Error expanding config path: %s", err) } var config Config contents, err := ioutil.ReadFile(path) if !os.IsNotExist(err) { if err != nil { return nil, err } obj, err := hcl.Parse(string(contents)) if err != nil { return nil, err } if err := hcl.DecodeObject(&config, obj); err != nil { return nil, err } } return &config, nil }
func parseAdvertise(result **AdvertiseAddrs, list *ast.ObjectList) error { list = list.Elem() if len(list.Items) > 1 { return fmt.Errorf("only one 'advertise' block allowed") } // Get our advertise object listVal := list.Items[0].Val // Check for invalid keys valid := []string{ "http", "rpc", "serf", } if err := checkHCLKeys(listVal, valid); err != nil { return err } var m map[string]interface{} if err := hcl.DecodeObject(&m, listVal); err != nil { return err } var advertise AdvertiseAddrs if err := mapstructure.WeakDecode(m, &advertise); err != nil { return err } *result = &advertise return nil }
func loadKVFile(rawPath string) (map[string]interface{}, error) { path, err := homedir.Expand(rawPath) if err != nil { return nil, fmt.Errorf( "Error expanding path: %s", err) } // Read the HCL file and prepare for parsing d, err := ioutil.ReadFile(path) if err != nil { return nil, fmt.Errorf( "Error reading %s: %s", path, err) } // Parse it obj, err := hcl.Parse(string(d)) if err != nil { return nil, fmt.Errorf( "Error parsing %s: %s", path, err) } var result map[string]interface{} if err := hcl.DecodeObject(&result, obj); err != nil { return nil, fmt.Errorf( "Error decoding Terraform vars file: %s\n\n"+ "The vars file should be in the format of `key = \"value\"`.\n"+ "Decoding errors are usually caused by an invalid format.", err) } return result, nil }
func parseAtlas(result **AtlasConfig, list *ast.ObjectList) error { list = list.Elem() if len(list.Items) > 1 { return fmt.Errorf("only one 'atlas' block allowed") } // Get our atlas object listVal := list.Items[0].Val // Check for invalid keys valid := []string{ "infrastructure", "token", "join", "endpoint", } if err := checkHCLKeys(listVal, valid); err != nil { return err } var m map[string]interface{} if err := hcl.DecodeObject(&m, listVal); err != nil { return err } var atlas AtlasConfig if err := mapstructure.WeakDecode(m, &atlas); err != nil { return err } *result = &atlas return nil }
func parseDetect(result *Config, obj *hclobj.Object) error { // 从map中获取所有实际对象的key值 objects := make([]*hclobj.Object, 0, 2) for _, o1 := range obj.Elem(false) { for _, o2 := range o1.Elem(true) { objects = append(objects, o2) } } if len(objects) == 0 { return nil } // 检查每个对象,返回实际结果 collection := make([]*Detector, 0, len(objects)) for _, o := range objects { var m map[string]interface{} if err := hcl.DecodeObject(&m, o); err != nil { return err } var d Detector if err := mapstructure.WeakDecode(m, &d); err != nil { return fmt.Errorf("解析detector错误 '%s' : %s", o.Key, err) } d.Type = o.Key collection = append(collection, &d) } result.Detectors = collection return nil }