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 }
// 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 (j *Job) parseGroups(list *ast.ObjectList) error { list = list.Children() if len(list.Items) == 0 { return nil } 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("group '%s' defined more than once", n) } seen[n] = struct{}{} // We need this later obj, ok := item.Val.(*ast.ObjectType) if !ok { return fmt.Errorf("group '%s': should be an object", n) } // Build the group with the basic decode tg := &TaskGroup{} tg.Name = TaskGroupName(n) if err := tg.parse(obj); err != nil { return maskAny(err) } j.Groups = append(j.Groups, tg) } return nil }
func parseImport(result *File, 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([]*Import, 0, len(list.Items)) seen := make(map[string]struct{}) for _, item := range list.Items { key := item.Keys[0].Token.Value().(string) // Make sure we haven't already found this import if _, ok := seen[key]; ok { return fmt.Errorf("import '%s' defined more than once", key) } seen[key] = struct{}{} // Check for invalid keys if err := checkHCLKeys(item.Val, nil); err != nil { return multierror.Prefix(err, fmt.Sprintf( "import '%s':", key)) } collection = append(collection, &Import{ Source: key, }) } result.Imports = collection 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 }
// parse a list of tasks func (tasks *parseTaskList) parseTasks(list *ast.ObjectList, anonymousGroup bool) error { list = list.Children() if len(list.Items) == 0 { return nil } // Get all the maps of keys to the actual object seen := make(map[string]struct{}) for _, item := range list.Items { n := item.Keys[0].Token.Value().(string) if _, ok := seen[n]; ok { return fmt.Errorf("task '%s' defined more than once", n) } seen[n] = struct{}{} obj, ok := item.Val.(*ast.ObjectType) if !ok { return fmt.Errorf("task '%s': should be an object", n) } t := &parseTask{} t.Name = TaskName(n) if err := t.parse(obj, anonymousGroup); err != nil { return maskAny(err) } *tasks = append(*tasks, t) } 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, 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 }
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 }
// 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 }
// Parse a Cluster func (c *Cluster) parse(list *ast.ObjectList) error { list = list.Children() if len(list.Items) != 1 { return fmt.Errorf("only one 'cluster' block allowed") } // Get our cluster object obj := list.Items[0] // Decode the object excludeList := []string{ "default-options", "docker", "fleet", "quark", } if err := Decode(obj.Val, excludeList, nil, c); err != nil { return maskAny(err) } c.Stack = obj.Keys[0].Token.Value().(string) // Value should be an object var listVal *ast.ObjectList if ot, ok := obj.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return errgo.Newf("cluster '%s' value: should be an object", c.Stack) } // If we have quark object, parse it if o := listVal.Filter("quark"); len(o.Items) > 0 { for _, o := range o.Elem().Items { if obj, ok := o.Val.(*ast.ObjectType); ok { if err := c.QuarkOptions.parse(obj, *c); err != nil { return maskAny(err) } } else { return maskAny(errgo.WithCausef(nil, ValidationError, "docker of cluster '%s' is not an object", c.Stack)) } } } return nil }
func loadConfigTargets(hclConfig *ast.ObjectList) ([]*TargetConfig, error) { hclConfig = hclConfig.Children() result := make([]*TargetConfig, 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("target '%s': should be a block", n) } target := &TargetConfig{ Name: n, } var err error target.Providers, err = loadConfigProviders(listVal.Filter("provider")) if err != nil { return nil, err } target.Modules, err = loadConfigModules(listVal.Filter("module")) if err != nil { return nil, err } target.Outputs, err = loadConfigOutputs(listVal.Filter("output")) if err != nil { return nil, err } result = append(result, target) } return result, nil }
// Given a handle to a HCL object, this recurses into the structure // and pulls out a list of managed resources. // // The resulting resources may not be unique, but each resource // represents exactly one "resource" block in the HCL configuration. // We leave it up to another pass to merge them together. func loadManagedResourcesHcl(list *ast.ObjectList) ([]*Resource, error) { list = list.Children() if len(list.Items) == 0 { return nil, nil } // Where all the results will go var result []*Resource // Now go over all the types and their children in order to get // all of the actual resources. for _, item := range list.Items { // GH-4385: We detect a pure provisioner resource and give the user // an error about how to do it cleanly. if len(item.Keys) == 4 && item.Keys[2].Token.Value().(string) == "provisioner" { return nil, fmt.Errorf( "position %s: provisioners in a resource should be wrapped in a list\n\n"+ "Example: \"provisioner\": [ { \"local-exec\": ... } ]", item.Pos()) } // HCL special case: if we're parsing JSON then directly nested // items will show up as additional "keys". We need to unwrap them // since we expect only two keys. Example: // // { "foo": { "bar": { "baz": {} } } } // // Will show up with Keys being: []string{"foo", "bar", "baz"} // when we really just want the first two. To fix this we unwrap // them into the right value. if len(item.Keys) > 2 && item.Keys[0].Token.JSON { for len(item.Keys) > 2 { // Pop off the last key n := len(item.Keys) key := item.Keys[n-1] item.Keys[n-1] = nil item.Keys = item.Keys[:n-1] // Wrap our value in a list item.Val = &ast.ObjectType{ List: &ast.ObjectList{ Items: []*ast.ObjectItem{ &ast.ObjectItem{ Keys: []*ast.ObjectKey{key}, Val: item.Val, }, }, }, } } } if len(item.Keys) != 2 { return nil, fmt.Errorf( "position %s: resource must be followed by exactly two strings, a type and a name", item.Pos()) } t := item.Keys[0].Token.Value().(string) k := item.Keys[1].Token.Value().(string) var listVal *ast.ObjectList if ot, ok := item.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return nil, fmt.Errorf("resources %s[%s]: should be an object", t, k) } var config map[string]interface{} if err := hcl.DecodeObject(&config, item.Val); err != nil { return nil, fmt.Errorf( "Error reading config for %s[%s]: %s", t, k, err) } // Remove the fields we handle specially delete(config, "connection") delete(config, "count") delete(config, "depends_on") delete(config, "provisioner") delete(config, "provider") delete(config, "lifecycle") rawConfig, err := NewRawConfig(config) if err != nil { return nil, fmt.Errorf( "Error reading config for %s[%s]: %s", t, k, err) } // If we have a count, then figure it out var count string = "1" if o := listVal.Filter("count"); len(o.Items) > 0 { err = hcl.DecodeObject(&count, o.Items[0].Val) if err != nil { return nil, fmt.Errorf( "Error parsing count for %s[%s]: %s", t, k, err) } } countConfig, err := NewRawConfig(map[string]interface{}{ "count": count, }) if err != nil { return nil, err } countConfig.Key = "count" // 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 %s[%s]: %s", t, k, err) } } // If we have connection info, then parse those out var connInfo map[string]interface{} if o := listVal.Filter("connection"); len(o.Items) > 0 { err := hcl.DecodeObject(&connInfo, o.Items[0].Val) if err != nil { return nil, fmt.Errorf( "Error reading connection info for %s[%s]: %s", t, k, err) } } // If we have provisioners, then parse those out var provisioners []*Provisioner if os := listVal.Filter("provisioner"); len(os.Items) > 0 { var err error provisioners, err = loadProvisionersHcl(os, connInfo) if err != nil { return nil, fmt.Errorf( "Error reading provisioners for %s[%s]: %s", t, k, err) } } // If we have a provider, then parse it out var provider string if o := listVal.Filter("provider"); len(o.Items) > 0 { err := hcl.DecodeObject(&provider, o.Items[0].Val) if err != nil { return nil, fmt.Errorf( "Error reading provider for %s[%s]: %s", t, k, err) } } // Check if the resource should be re-created before // destroying the existing instance var lifecycle ResourceLifecycle if o := listVal.Filter("lifecycle"); len(o.Items) > 0 { // Check for invalid keys valid := []string{"create_before_destroy", "ignore_changes", "prevent_destroy"} if err := checkHCLKeys(o.Items[0].Val, valid); err != nil { return nil, multierror.Prefix(err, fmt.Sprintf( "%s[%s]:", t, k)) } var raw map[string]interface{} if err = hcl.DecodeObject(&raw, o.Items[0].Val); err != nil { return nil, fmt.Errorf( "Error parsing lifecycle for %s[%s]: %s", t, k, err) } if err := mapstructure.WeakDecode(raw, &lifecycle); err != nil { return nil, fmt.Errorf( "Error parsing lifecycle for %s[%s]: %s", t, k, err) } } result = append(result, &Resource{ Mode: ManagedResourceMode, Name: k, Type: t, RawCount: countConfig, RawConfig: rawConfig, Provisioners: provisioners, Provider: provider, DependsOn: dependsOn, Lifecycle: lifecycle, }) } return result, nil }
// Parse a Cluster func (c *Cluster) parse(list *ast.ObjectList) error { list = list.Children() if len(list.Items) != 1 { return fmt.Errorf("only one 'cluster' block allowed") } // Get our cluster object obj := list.Items[0] // Decode the object excludeList := []string{ "default-options", "docker", "fleet", "quark", } if err := hclutil.Decode(obj.Val, excludeList, nil, c); err != nil { return maskAny(err) } c.Stack = obj.Keys[0].Token.Value().(string) // Value should be an object var listVal *ast.ObjectList if ot, ok := obj.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return errgo.Newf("cluster '%s' value: should be an object", c.Stack) } // If we have docker object, parse it if o := listVal.Filter("docker"); len(o.Items) > 0 { for _, o := range o.Elem().Items { if obj, ok := o.Val.(*ast.ObjectType); ok { if err := c.DockerOptions.parse(obj, *c); err != nil { return maskAny(err) } } else { return maskAny(errgo.WithCausef(nil, ValidationError, "docker of cluster '%s' is not an object", c.Stack)) } } } // If we have fleet object, parse it if o := listVal.Filter("fleet"); len(o.Items) > 0 { for _, o := range o.Elem().Items { if obj, ok := o.Val.(*ast.ObjectType); ok { if err := c.FleetOptions.parse(obj, *c); err != nil { return maskAny(err) } } else { return maskAny(errgo.WithCausef(nil, ValidationError, "fleet of cluster '%s' is not an object", c.Stack)) } } } // Parse default-options if o := listVal.Filter("default-options"); len(o.Items) > 0 { for _, o := range o.Elem().Items { var m map[string]interface{} if err := hcl.DecodeObject(&m, o.Val); err != nil { return maskAny(err) } // Merge key/value pairs into myself for k, v := range m { c.DefaultOptions.SetKeyValue(k, v) } } } return nil }
func parseTasks(jobName string, taskGroupName string, result *[]*structs.Task, 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. 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("task '%s' defined more than once", n) } seen[n] = struct{}{} // We need this later var listVal *ast.ObjectList if ot, ok := item.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return fmt.Errorf("group '%s': should be an object", n) } // Check for invalid keys valid := []string{ "artifact", "config", "constraint", "driver", "env", "kill_timeout", "logs", "meta", "resources", "service", "user", "vault", } if err := checkHCLKeys(listVal, valid); err != nil { return multierror.Prefix(err, fmt.Sprintf("'%s' ->", n)) } var m map[string]interface{} if err := hcl.DecodeObject(&m, item.Val); err != nil { return err } delete(m, "artifact") delete(m, "config") delete(m, "constraint") delete(m, "env") delete(m, "logs") delete(m, "meta") delete(m, "resources") delete(m, "service") delete(m, "vault") // Build the task var t structs.Task t.Name = n if taskGroupName == "" { taskGroupName = n } dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ DecodeHook: mapstructure.StringToTimeDurationHookFunc(), WeaklyTypedInput: true, Result: &t, }) if err != nil { return err } if err := dec.Decode(m); err != nil { return err } // If we have env, then parse them if o := listVal.Filter("env"); len(o.Items) > 0 { for _, o := range o.Elem().Items { var m map[string]interface{} if err := hcl.DecodeObject(&m, o.Val); err != nil { return err } if err := mapstructure.WeakDecode(m, &t.Env); err != nil { return err } } } if o := listVal.Filter("service"); len(o.Items) > 0 { if err := parseServices(jobName, taskGroupName, &t, o); err != nil { return multierror.Prefix(err, fmt.Sprintf("'%s',", n)) } } // If we have config, then parse that if o := listVal.Filter("config"); len(o.Items) > 0 { for _, o := range o.Elem().Items { var m map[string]interface{} if err := hcl.DecodeObject(&m, o.Val); err != nil { return err } if err := mapstructure.WeakDecode(m, &t.Config); err != nil { return err } } // Instantiate a driver to validate the configuration d, err := driver.NewDriver( t.Driver, driver.NewEmptyDriverContext(), ) if err != nil { return multierror.Prefix(err, fmt.Sprintf("'%s', config ->", n)) } if err := d.Validate(t.Config); err != nil { return multierror.Prefix(err, fmt.Sprintf("'%s', config ->", n)) } } // Parse constraints if o := listVal.Filter("constraint"); len(o.Items) > 0 { if err := parseConstraints(&t.Constraints, o); err != nil { return multierror.Prefix(err, fmt.Sprintf( "'%s', constraint ->", n)) } } // Parse out meta fields. These are in HCL as a list so we need // to iterate over them and merge them. if metaO := listVal.Filter("meta"); len(metaO.Items) > 0 { for _, o := range metaO.Elem().Items { var m map[string]interface{} if err := hcl.DecodeObject(&m, o.Val); err != nil { return err } if err := mapstructure.WeakDecode(m, &t.Meta); err != nil { return err } } } // If we have resources, then parse that if o := listVal.Filter("resources"); len(o.Items) > 0 { var r structs.Resources if err := parseResources(&r, o); err != nil { return multierror.Prefix(err, fmt.Sprintf("'%s',", n)) } t.Resources = &r } // If we have logs then parse that logConfig := structs.DefaultLogConfig() if o := listVal.Filter("logs"); len(o.Items) > 0 { if len(o.Items) > 1 { return fmt.Errorf("only one logs block is allowed in a Task. Number of logs block found: %d", len(o.Items)) } var m map[string]interface{} logsBlock := o.Items[0] // Check for invalid keys valid := []string{ "max_files", "max_file_size", } if err := checkHCLKeys(logsBlock.Val, valid); err != nil { return multierror.Prefix(err, fmt.Sprintf("'%s', logs ->", n)) } if err := hcl.DecodeObject(&m, logsBlock.Val); err != nil { return err } if err := mapstructure.WeakDecode(m, &logConfig); err != nil { return err } } t.LogConfig = logConfig // Parse artifacts if o := listVal.Filter("artifact"); len(o.Items) > 0 { if err := parseArtifacts(&t.Artifacts, o); err != nil { return multierror.Prefix(err, fmt.Sprintf("'%s', artifact ->", n)) } } // If we have a vault block, then parse that if o := listVal.Filter("vault"); len(o.Items) > 0 { var v structs.Vault if err := parseVault(&v, o); err != nil { return multierror.Prefix(err, fmt.Sprintf("'%s', vault ->", n)) } t.Vault = &v } *result = append(*result, &t) } return nil }
func parseTasks(jobName string, taskGroupName string, result *[]*structs.Task, 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. 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("task '%s' defined more than once", n) } seen[n] = struct{}{} // We need this later var listVal *ast.ObjectList if ot, ok := item.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return fmt.Errorf("group '%s': should be an object", n) } var m map[string]interface{} if err := hcl.DecodeObject(&m, item.Val); err != nil { return err } delete(m, "config") delete(m, "env") delete(m, "constraint") delete(m, "service") delete(m, "meta") delete(m, "resources") // Build the task var t structs.Task t.Name = n if taskGroupName == "" { taskGroupName = n } dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ DecodeHook: mapstructure.StringToTimeDurationHookFunc(), WeaklyTypedInput: true, Result: &t, }) if err != nil { return err } if err := dec.Decode(m); err != nil { return err } // If we have env, then parse them if o := listVal.Filter("env"); len(o.Items) > 0 { for _, o := range o.Elem().Items { var m map[string]interface{} if err := hcl.DecodeObject(&m, o.Val); err != nil { return err } if err := mapstructure.WeakDecode(m, &t.Env); err != nil { return err } } } if o := listVal.Filter("service"); len(o.Items) > 0 { if err := parseServices(jobName, taskGroupName, &t, o); err != nil { return err } } // If we have config, then parse that if o := listVal.Filter("config"); len(o.Items) > 0 { for _, o := range o.Elem().Items { var m map[string]interface{} if err := hcl.DecodeObject(&m, o.Val); err != nil { return err } if err := mapstructure.WeakDecode(m, &t.Config); err != nil { return err } } } // Parse constraints if o := listVal.Filter("constraint"); len(o.Items) > 0 { if err := parseConstraints(&t.Constraints, o); err != nil { return err } } // Parse out meta fields. These are in HCL as a list so we need // to iterate over them and merge them. if metaO := listVal.Filter("meta"); len(metaO.Items) > 0 { for _, o := range metaO.Elem().Items { var m map[string]interface{} if err := hcl.DecodeObject(&m, o.Val); err != nil { return err } if err := mapstructure.WeakDecode(m, &t.Meta); err != nil { return err } } } // If we have resources, then parse that if o := listVal.Filter("resources"); len(o.Items) > 0 { var r structs.Resources if err := parseResources(&r, o); err != nil { return fmt.Errorf("task '%s': %s", t.Name, err) } t.Resources = &r } *result = append(*result, &t) } return nil }
// Given a handle to a HCL object, this recurses into the structure // and pulls out a list of modules. // // The resulting modules may not be unique, but each module // represents exactly one module definition in the HCL configuration. // We leave it up to another pass to merge them together. func loadModulesHcl(list *ast.ObjectList) ([]*Module, error) { list = list.Children() if len(list.Items) == 0 { return nil, nil } // Where all the results will go var result []*Module // Now go over all the types and their children in order to get // all of the actual resources. for _, item := range list.Items { k := 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", k) } var config map[string]interface{} if err := hcl.DecodeObject(&config, item.Val); err != nil { return nil, fmt.Errorf( "Error reading config for %s: %s", k, err) } // Remove the fields we handle specially delete(config, "source") rawConfig, err := NewRawConfig(config) if err != nil { return nil, fmt.Errorf( "Error reading config for %s: %s", k, err) } // If we have a count, then figure it out var source string if o := listVal.Filter("source"); len(o.Items) > 0 { err = hcl.DecodeObject(&source, o.Items[0].Val) if err != nil { return nil, fmt.Errorf( "Error parsing source for %s: %s", k, err) } } result = append(result, &Module{ Name: k, Source: source, RawConfig: rawConfig, }) } return result, nil }
func parseInfra(result *File, 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([]*Infrastructure, 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("infrastructure '%s' defined more than once", n) } seen[n] = struct{}{} // Check for invalid keys valid := []string{"name", "type", "flavor", "foundation"} if err := checkHCLKeys(item.Val, valid); err != nil { return multierror.Prefix(err, fmt.Sprintf( "infrastructure '%s':", n)) } var listVal *ast.ObjectList if ot, ok := item.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return fmt.Errorf("infrastructure '%s': should be an object", n) } var m map[string]interface{} if err := hcl.DecodeObject(&m, item.Val); err != nil { return err } var infra Infrastructure if err := mapstructure.WeakDecode(m, &infra); err != nil { return fmt.Errorf( "error parsing infrastructure '%s': %s", n, err) } infra.Name = n if infra.Type == "" { infra.Type = infra.Name } // Parse the foundations if we have any if o2 := listVal.Filter("foundation"); len(o2.Items) > 0 { if err := parseFoundations(&infra, o2); err != nil { return fmt.Errorf("error parsing 'foundation': %s", err) } } collection = append(collection, &infra) } result.Infrastructure = collection return nil }
func (j *Job) parse(list *ast.ObjectList) error { list = list.Children() if len(list.Items) != 1 { return fmt.Errorf("only one 'job' block allowed") } // Get our job object obj := list.Items[0] // Decode the object if err := hclutil.Decode(obj.Val, []string{"group", "task", "constraint", "dependency"}, nil, j); err != nil { return maskAny(err) } j.Name = JobName(obj.Keys[0].Token.Value().(string)) // Value should be an object var listVal *ast.ObjectList if ot, ok := obj.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return errgo.Newf("job '%s' value: should be an object", j.Name) } // If we have tasks outside, do those if o := listVal.Filter("task"); len(o.Items) > 0 { tmp := parseTaskList{} if err := tmp.parseTasks(o, true); err != nil { return err } for _, t := range tmp { tg := &TaskGroup{ Name: TaskGroupName(t.Name), Count: t.Count, Global: t.Global, Constraints: t.Constraints, Tasks: []*Task{&t.Task}, } j.Groups = append(j.Groups, tg) } } // Parse the task groups if o := listVal.Filter("group"); len(o.Items) > 0 { if err := j.parseGroups(o); err != nil { return fmt.Errorf("error parsing 'group': %s", err) } } // Parse constraints if o := listVal.Filter("constraint"); len(o.Items) > 0 { for _, o := range o.Elem().Items { if obj, ok := o.Val.(*ast.ObjectType); ok { c := Constraint{} if err := c.parse(obj); err != nil { return maskAny(err) } j.Constraints = append(j.Constraints, c) } else { return maskAny(errgo.WithCausef(nil, ValidationError, "constraint of job %s is not an object", j.Name)) } } } // Parse dependencies if o := listVal.Filter("dependency"); len(o.Items) > 0 { for _, o := range o.Items { if obj, ok := o.Val.(*ast.ObjectType); ok { d := Dependency{} d.Name = LinkName(o.Keys[0].Token.Value().(string)) if err := d.parse(obj); err != nil { return maskAny(err) } j.Dependencies = append(j.Dependencies, d) } else { return maskAny(errgo.WithCausef(nil, ValidationError, "dependency of job %s is not an object", j.Name)) } } } return nil }
func loadProvisionersHcl(list *ast.ObjectList, connInfo map[string]interface{}) ([]*Provisioner, 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([]*Provisioner, 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("provisioner '%s': should be an object", n) } var config map[string]interface{} if err := hcl.DecodeObject(&config, item.Val); err != nil { return nil, err } // Delete the "connection" section, handle separately delete(config, "connection") rawConfig, err := NewRawConfig(config) if err != nil { return nil, err } // Check if we have a provisioner-level connection // block that overrides the resource-level var subConnInfo map[string]interface{} if o := listVal.Filter("connection"); len(o.Items) > 0 { err := hcl.DecodeObject(&subConnInfo, o.Items[0].Val) if err != nil { return nil, err } } // Inherit from the resource connInfo any keys // that are not explicitly overriden. if connInfo != nil && subConnInfo != nil { for k, v := range connInfo { if _, ok := subConnInfo[k]; !ok { subConnInfo[k] = v } } } else if subConnInfo == nil { subConnInfo = connInfo } // Parse the connInfo connRaw, err := NewRawConfig(subConnInfo) if err != nil { return nil, err } result = append(result, &Provisioner{ Type: n, RawConfig: rawConfig, ConnInfo: connRaw, }) } return result, nil }
// Given a handle to a HCL object, this recurses into the structure // and pulls out a list of resources. // // The resulting resources may not be unique, but each resource // represents exactly one resource definition in the HCL configuration. // We leave it up to another pass to merge them together. func loadResourcesHcl(list *ast.ObjectList) ([]*Resource, error) { list = list.Children() if len(list.Items) == 0 { return nil, nil } // Where all the results will go var result []*Resource // Now go over all the types and their children in order to get // all of the actual resources. for _, item := range list.Items { if len(item.Keys) != 2 { // TODO: bad error message return nil, fmt.Errorf("resource needs exactly 2 names") } t := item.Keys[0].Token.Value().(string) k := item.Keys[1].Token.Value().(string) var listVal *ast.ObjectList if ot, ok := item.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return nil, fmt.Errorf("resources %s[%s]: should be an object", t, k) } var config map[string]interface{} if err := hcl.DecodeObject(&config, item.Val); err != nil { return nil, fmt.Errorf( "Error reading config for %s[%s]: %s", t, k, err) } // Remove the fields we handle specially delete(config, "connection") delete(config, "count") delete(config, "depends_on") delete(config, "provisioner") delete(config, "provider") delete(config, "lifecycle") rawConfig, err := NewRawConfig(config) if err != nil { return nil, fmt.Errorf( "Error reading config for %s[%s]: %s", t, k, err) } // If we have a count, then figure it out var count string = "1" if o := listVal.Filter("count"); len(o.Items) > 0 { err = hcl.DecodeObject(&count, o.Items[0].Val) if err != nil { return nil, fmt.Errorf( "Error parsing count for %s[%s]: %s", t, k, err) } } countConfig, err := NewRawConfig(map[string]interface{}{ "count": count, }) if err != nil { return nil, err } countConfig.Key = "count" // 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 %s[%s]: %s", t, k, err) } } // If we have connection info, then parse those out var connInfo map[string]interface{} if o := listVal.Filter("connection"); len(o.Items) > 0 { err := hcl.DecodeObject(&connInfo, o.Items[0].Val) if err != nil { return nil, fmt.Errorf( "Error reading connection info for %s[%s]: %s", t, k, err) } } // If we have provisioners, then parse those out var provisioners []*Provisioner if os := listVal.Filter("provisioner"); len(os.Items) > 0 { var err error provisioners, err = loadProvisionersHcl(os, connInfo) if err != nil { return nil, fmt.Errorf( "Error reading provisioners for %s[%s]: %s", t, k, err) } } // If we have a provider, then parse it out var provider string if o := listVal.Filter("provider"); len(o.Items) > 0 { err := hcl.DecodeObject(&provider, o.Items[0].Val) if err != nil { return nil, fmt.Errorf( "Error reading provider for %s[%s]: %s", t, k, err) } } // Check if the resource should be re-created before // destroying the existing instance var lifecycle ResourceLifecycle if o := listVal.Filter("lifecycle"); len(o.Items) > 0 { var raw map[string]interface{} if err = hcl.DecodeObject(&raw, o.Items[0].Val); err != nil { return nil, fmt.Errorf( "Error parsing lifecycle for %s[%s]: %s", t, k, err) } if err := mapstructure.WeakDecode(raw, &lifecycle); err != nil { return nil, fmt.Errorf( "Error parsing lifecycle for %s[%s]: %s", t, k, err) } } result = append(result, &Resource{ Name: k, Type: t, RawCount: countConfig, RawConfig: rawConfig, Provisioners: provisioners, Provider: provider, DependsOn: dependsOn, Lifecycle: lifecycle, }) } return result, nil }
// Given a handle to a HCL object, this recurses into the structure // and pulls out a list of resources. // // The resulting resources may not be unique, but each resource // represents exactly one resource definition in the HCL configuration. // We leave it up to another pass to merge them together. func loadResourcesHcl(list *ast.ObjectList) ([]*Resource, error) { list = list.Children() if len(list.Items) == 0 { return nil, nil } // Where all the results will go var result []*Resource // Now go over all the types and their children in order to get // all of the actual resources. for _, item := range list.Items { // GH-4385: We detect a pure provisioner resource and give the user // an error about how to do it cleanly. if len(item.Keys) == 4 && item.Keys[2].Token.Value().(string) == "provisioner" { return nil, fmt.Errorf( "position %s: provisioners in a resource should be wrapped in a list\n\n"+ "Example: \"provisioner\": [ { \"local-exec\": ... } ]", item.Pos()) } if len(item.Keys) != 2 { return nil, fmt.Errorf( "position %s: resource must be followed by exactly two strings, a type and a name", item.Pos()) } t := item.Keys[0].Token.Value().(string) k := item.Keys[1].Token.Value().(string) var listVal *ast.ObjectList if ot, ok := item.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return nil, fmt.Errorf("resources %s[%s]: should be an object", t, k) } var config map[string]interface{} if err := hcl.DecodeObject(&config, item.Val); err != nil { return nil, fmt.Errorf( "Error reading config for %s[%s]: %s", t, k, err) } // Remove the fields we handle specially delete(config, "connection") delete(config, "count") delete(config, "depends_on") delete(config, "provisioner") delete(config, "provider") delete(config, "lifecycle") rawConfig, err := NewRawConfig(config) if err != nil { return nil, fmt.Errorf( "Error reading config for %s[%s]: %s", t, k, err) } // If we have a count, then figure it out var count string = "1" if o := listVal.Filter("count"); len(o.Items) > 0 { err = hcl.DecodeObject(&count, o.Items[0].Val) if err != nil { return nil, fmt.Errorf( "Error parsing count for %s[%s]: %s", t, k, err) } } countConfig, err := NewRawConfig(map[string]interface{}{ "count": count, }) if err != nil { return nil, err } countConfig.Key = "count" // 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 %s[%s]: %s", t, k, err) } } // If we have connection info, then parse those out var connInfo map[string]interface{} if o := listVal.Filter("connection"); len(o.Items) > 0 { err := hcl.DecodeObject(&connInfo, o.Items[0].Val) if err != nil { return nil, fmt.Errorf( "Error reading connection info for %s[%s]: %s", t, k, err) } } // If we have provisioners, then parse those out var provisioners []*Provisioner if os := listVal.Filter("provisioner"); len(os.Items) > 0 { var err error provisioners, err = loadProvisionersHcl(os, connInfo) if err != nil { return nil, fmt.Errorf( "Error reading provisioners for %s[%s]: %s", t, k, err) } } // If we have a provider, then parse it out var provider string if o := listVal.Filter("provider"); len(o.Items) > 0 { err := hcl.DecodeObject(&provider, o.Items[0].Val) if err != nil { return nil, fmt.Errorf( "Error reading provider for %s[%s]: %s", t, k, err) } } // Check if the resource should be re-created before // destroying the existing instance var lifecycle ResourceLifecycle if o := listVal.Filter("lifecycle"); len(o.Items) > 0 { // Check for invalid keys valid := []string{"create_before_destroy", "ignore_changes", "prevent_destroy"} if err := checkHCLKeys(o.Items[0].Val, valid); err != nil { return nil, multierror.Prefix(err, fmt.Sprintf( "%s[%s]:", t, k)) } var raw map[string]interface{} if err = hcl.DecodeObject(&raw, o.Items[0].Val); err != nil { return nil, fmt.Errorf( "Error parsing lifecycle for %s[%s]: %s", t, k, err) } if err := mapstructure.WeakDecode(raw, &lifecycle); err != nil { return nil, fmt.Errorf( "Error parsing lifecycle for %s[%s]: %s", t, k, err) } } result = append(result, &Resource{ Name: k, Type: t, RawCount: countConfig, RawConfig: rawConfig, Provisioners: provisioners, Provider: provider, DependsOn: dependsOn, Lifecycle: lifecycle, }) } return result, nil }
// LoadVariablesHcl recurses into the given HCL object and turns // it into a list of variables. func loadVariablesHcl(list *ast.ObjectList) ([]*Variable, error) { list = list.Children() if len(list.Items) == 0 { return nil, fmt.Errorf( "'variable' must be followed by exactly one strings: a name") } // hclVariable is the structure each variable is decoded into type hclVariable struct { DeclaredType string `hcl:"type"` Default interface{} Description string Fields []string `hcl:",decodedFields"` } // Go through each object and turn it into an actual result. result := make([]*Variable, 0, len(list.Items)) for _, item := range list.Items { // Clean up items from JSON unwrapHCLObjectKeysFromJSON(item, 1) // Verify the keys if len(item.Keys) != 1 { return nil, fmt.Errorf( "position %s: 'variable' must be followed by exactly one strings: a name", item.Pos()) } n := item.Keys[0].Token.Value().(string) /* // TODO: catch extra fields // Decode into raw map[string]interface{} so we know ALL fields var config map[string]interface{} if err := hcl.DecodeObject(&config, item.Val); err != nil { return nil, err } */ // Decode into hclVariable to get typed values var hclVar hclVariable if err := hcl.DecodeObject(&hclVar, item.Val); err != nil { return nil, err } // Defaults turn into a slice of map[string]interface{} and // we need to make sure to convert that down into the // proper type for Config. if ms, ok := hclVar.Default.([]map[string]interface{}); ok { def := make(map[string]interface{}) for _, m := range ms { for k, v := range m { def[k] = v } } hclVar.Default = def } // Build the new variable and do some basic validation newVar := &Variable{ Name: n, DeclaredType: hclVar.DeclaredType, Default: hclVar.Default, Description: hclVar.Description, } if err := newVar.ValidateTypeAndDefault(); err != nil { return nil, err } result = append(result, newVar) } return result, nil }
func parseGroups(result *structs.Job, 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([]*structs.TaskGroup, 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("group '%s' defined more than once", n) } seen[n] = struct{}{} // We need this later var listVal *ast.ObjectList if ot, ok := item.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return fmt.Errorf("group '%s': should be an object", n) } // Check for invalid keys valid := []string{ "count", "constraint", "restart", "meta", "task", "local_disk", } if err := checkHCLKeys(listVal, valid); err != nil { return multierror.Prefix(err, fmt.Sprintf("'%s' ->", n)) } var m map[string]interface{} if err := hcl.DecodeObject(&m, item.Val); err != nil { return err } delete(m, "constraint") delete(m, "meta") delete(m, "task") delete(m, "restart") delete(m, "local_disk") // Default count to 1 if not specified if _, ok := m["count"]; !ok { m["count"] = 1 } // Build the group with the basic decode var g structs.TaskGroup g.Name = n if err := mapstructure.WeakDecode(m, &g); err != nil { return err } // Parse constraints if o := listVal.Filter("constraint"); len(o.Items) > 0 { if err := parseConstraints(&g.Constraints, o); err != nil { return multierror.Prefix(err, fmt.Sprintf("'%s', constraint ->", n)) } } // Parse restart policy if o := listVal.Filter("restart"); len(o.Items) > 0 { if err := parseRestartPolicy(&g.RestartPolicy, o); err != nil { return multierror.Prefix(err, fmt.Sprintf("'%s', restart ->", n)) } } // Parse local disk g.LocalDisk = structs.DefaultLocalDisk() if o := listVal.Filter("local_disk"); len(o.Items) > 0 { if err := parseLocalDisk(&g.LocalDisk, o); err != nil { return multierror.Prefix(err, fmt.Sprintf("'%s', local_disk ->", n)) } } // Parse out meta fields. These are in HCL as a list so we need // to iterate over them and merge them. if metaO := listVal.Filter("meta"); len(metaO.Items) > 0 { for _, o := range metaO.Elem().Items { var m map[string]interface{} if err := hcl.DecodeObject(&m, o.Val); err != nil { return err } if err := mapstructure.WeakDecode(m, &g.Meta); err != nil { return err } } } // Parse tasks if o := listVal.Filter("task"); len(o.Items) > 0 { if err := parseTasks(result.Name, g.Name, &g.Tasks, o); err != nil { return multierror.Prefix(err, fmt.Sprintf("'%s', task:", n)) } } collection = append(collection, &g) } result.TaskGroups = append(result.TaskGroups, collection...) return nil }
// Given a handle to a HCL object, this recurses into the structure // and pulls out a list of data sources. // // The resulting data sources may not be unique, but each one // represents exactly one data definition in the HCL configuration. // We leave it up to another pass to merge them together. func loadDataResourcesHcl(list *ast.ObjectList) ([]*Resource, error) { list = list.Children() if len(list.Items) == 0 { return nil, nil } // Where all the results will go var result []*Resource // Now go over all the types and their children in order to get // all of the actual resources. for _, item := range list.Items { if len(item.Keys) != 2 { return nil, fmt.Errorf( "position %s: 'data' must be followed by exactly two strings: a type and a name", item.Pos()) } t := item.Keys[0].Token.Value().(string) k := item.Keys[1].Token.Value().(string) var listVal *ast.ObjectList if ot, ok := item.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return nil, fmt.Errorf("data sources %s[%s]: should be an object", t, k) } var config map[string]interface{} if err := hcl.DecodeObject(&config, item.Val); err != nil { return nil, fmt.Errorf( "Error reading config for %s[%s]: %s", t, k, err) } // Remove the fields we handle specially delete(config, "depends_on") delete(config, "provider") delete(config, "count") rawConfig, err := NewRawConfig(config) if err != nil { return nil, fmt.Errorf( "Error reading config for %s[%s]: %s", t, k, err) } // If we have a count, then figure it out var count string = "1" if o := listVal.Filter("count"); len(o.Items) > 0 { err = hcl.DecodeObject(&count, o.Items[0].Val) if err != nil { return nil, fmt.Errorf( "Error parsing count for %s[%s]: %s", t, k, err) } } countConfig, err := NewRawConfig(map[string]interface{}{ "count": count, }) if err != nil { return nil, err } countConfig.Key = "count" // 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 %s[%s]: %s", t, k, err) } } // If we have a provider, then parse it out var provider string if o := listVal.Filter("provider"); len(o.Items) > 0 { err := hcl.DecodeObject(&provider, o.Items[0].Val) if err != nil { return nil, fmt.Errorf( "Error reading provider for %s[%s]: %s", t, k, err) } } result = append(result, &Resource{ Mode: DataResourceMode, Name: k, Type: t, RawCount: countConfig, RawConfig: rawConfig, Provider: provider, Provisioners: []*Provisioner{}, DependsOn: dependsOn, Lifecycle: ResourceLifecycle{}, }) } return result, nil }
func parseJob(result *structs.Job, list *ast.ObjectList) error { list = list.Children() if len(list.Items) != 1 { return fmt.Errorf("only one 'job' block allowed") } // Get our job object obj := list.Items[0] // Decode the full thing into a map[string]interface for ease var m map[string]interface{} if err := hcl.DecodeObject(&m, obj.Val); err != nil { return err } delete(m, "constraint") delete(m, "meta") delete(m, "update") delete(m, "periodic") // Set the ID and name to the object key result.ID = obj.Keys[0].Token.Value().(string) result.Name = result.ID // Defaults result.Priority = 50 result.Region = "global" result.Type = "service" // Decode the rest if err := mapstructure.WeakDecode(m, result); err != nil { return err } // Value should be an object var listVal *ast.ObjectList if ot, ok := obj.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return fmt.Errorf("job '%s' value: should be an object", result.ID) } // Check for invalid keys valid := []string{ "id", "name", "region", "all_at_once", "type", "priority", "datacenters", "constraint", "update", "periodic", "meta", "task", "group", "vault_token", } if err := checkHCLKeys(listVal, valid); err != nil { return multierror.Prefix(err, "job:") } // Parse constraints if o := listVal.Filter("constraint"); len(o.Items) > 0 { if err := parseConstraints(&result.Constraints, o); err != nil { return multierror.Prefix(err, "constraint ->") } } // If we have an update strategy, then parse that if o := listVal.Filter("update"); len(o.Items) > 0 { if err := parseUpdate(&result.Update, o); err != nil { return multierror.Prefix(err, "update ->") } } // If we have a periodic definition, then parse that if o := listVal.Filter("periodic"); len(o.Items) > 0 { if err := parsePeriodic(&result.Periodic, o); err != nil { return multierror.Prefix(err, "periodic ->") } } // Parse out meta fields. These are in HCL as a list so we need // to iterate over them and merge them. if metaO := listVal.Filter("meta"); len(metaO.Items) > 0 { for _, o := range metaO.Elem().Items { var m map[string]interface{} if err := hcl.DecodeObject(&m, o.Val); err != nil { return err } if err := mapstructure.WeakDecode(m, &result.Meta); err != nil { return err } } } // If we have tasks outside, create TaskGroups for them if o := listVal.Filter("task"); len(o.Items) > 0 { var tasks []*structs.Task if err := parseTasks(result.Name, "", &tasks, o); err != nil { return multierror.Prefix(err, "task:") } result.TaskGroups = make([]*structs.TaskGroup, len(tasks), len(tasks)*2) for i, t := range tasks { result.TaskGroups[i] = &structs.TaskGroup{ Name: t.Name, Count: 1, LocalDisk: structs.DefaultLocalDisk(), Tasks: []*structs.Task{t}, } } } // Parse the task groups if o := listVal.Filter("group"); len(o.Items) > 0 { if err := parseGroups(result, o); err != nil { return multierror.Prefix(err, "group:") } } return nil }
func parseJob(result *structs.Job, list *ast.ObjectList) error { list = list.Children() if len(list.Items) != 1 { return fmt.Errorf("only one 'job' block allowed") } // Get our job object obj := list.Items[0] // Decode the full thing into a map[string]interface for ease var m map[string]interface{} if err := hcl.DecodeObject(&m, obj.Val); err != nil { return err } delete(m, "constraint") delete(m, "meta") delete(m, "update") // Set the ID and name to the object key result.ID = obj.Keys[0].Token.Value().(string) result.Name = result.ID // Defaults result.Priority = 50 result.Region = "global" result.Type = "service" // Decode the rest if err := mapstructure.WeakDecode(m, result); err != nil { return err } // Value should be an object var listVal *ast.ObjectList if ot, ok := obj.Val.(*ast.ObjectType); ok { listVal = ot.List } else { return fmt.Errorf("job '%s' value: should be an object", result.ID) } // Parse constraints if o := listVal.Filter("constraint"); len(o.Items) > 0 { if err := parseConstraints(&result.Constraints, o); err != nil { return err } } // If we have an update strategy, then parse that if o := listVal.Filter("update"); len(o.Items) > 0 { if err := parseUpdate(&result.Update, o); err != nil { return err } } // Parse out meta fields. These are in HCL as a list so we need // to iterate over them and merge them. if metaO := listVal.Filter("meta"); len(metaO.Items) > 0 { for _, o := range metaO.Elem().Items { var m map[string]interface{} if err := hcl.DecodeObject(&m, o.Val); err != nil { return err } if err := mapstructure.WeakDecode(m, &result.Meta); err != nil { return err } } } // If we have tasks outside, create TaskGroups for them if o := listVal.Filter("task"); len(o.Items) > 0 { var tasks []*structs.Task if err := parseTasks(result.Name, "", &tasks, o); err != nil { return err } result.TaskGroups = make([]*structs.TaskGroup, len(tasks), len(tasks)*2) for i, t := range tasks { result.TaskGroups[i] = &structs.TaskGroup{ Name: t.Name, Count: 1, Tasks: []*structs.Task{t}, RestartPolicy: structs.NewRestartPolicy(result.Type), } } } // Parse the task groups if o := listVal.Filter("group"); len(o.Items) > 0 { if err := parseGroups(result, o); err != nil { return fmt.Errorf("error parsing 'group': %s", err) } } return nil }