func parseRestartPolicy(result *structs.RestartPolicy, obj *hclobj.Object) error { var restartHclObj *hclobj.Object var m map[string]interface{} if restartHclObj = obj.Get("restart", false); restartHclObj == nil { return nil } if err := hcl.DecodeObject(&m, restartHclObj); err != nil { return err } if delay, ok := m["delay"]; ok { d, err := toDuration(delay) if err != nil { return fmt.Errorf("Invalid Delay time in restart policy: %v", err) } result.Delay = d } if interval, ok := m["interval"]; ok { i, err := toDuration(interval) if err != nil { return fmt.Errorf("Invalid Interval time in restart policy: %v", err) } result.Interval = i } if attempts, ok := m["attempts"]; ok { a, err := toInteger(attempts) if err != nil { return fmt.Errorf("Invalid value in attempts: %v", err) } result.Attempts = a } return nil }
func parseRawObject(key string, hcltree *hclObj.Object, errors *multierror.Error) (apisOut []*hclObj.Object) { if apis := hcltree.Get(key, false); apis != nil { for _, api := range apis.Elem(true) { apisOut = append(apisOut, api) } } else { errors = multierror.Append(errors, fmt.Errorf("No job_store was specified in the configuration")) } return apisOut }
func parseRawBool(key string, hcltree *hclObj.Object, errors *multierror.Error) bool { if rawValue := hcltree.Get(key, false); rawValue != nil { if rawValue.Type != hclObj.ValueTypeBool { errors = multierror.Append(errors, fmt.Errorf("Invalid type assigned to property: %s. Expected string type, Found %s", key, rawValue.Type)) } else { return rawValue.Value.(bool) } } else { errors = multierror.Append(errors, fmt.Errorf("Property: %s not specified in the configuration", key)) } return false }
func parseRawArray(key string, object *hclObj.Object, errors *multierror.Error) []string { output := []string{} if rawValue := object.Get(key, false); rawValue != nil { switch rawValue.Type { case hclObj.ValueTypeString: output = append(output, rawValue.Value.(string)) case hclObj.ValueTypeList: for _, m := range rawValue.Elem(true) { output = append(output, m.Value.(string)) } } } return output }
func parseJobTrigger(jobNode *hclObj.Object, errors *multierror.Error) TriggerConfig { var triggerConfig TriggerConfig if t := jobNode.Get("trigger", false); t != nil { err := hcl.DecodeObject(&triggerConfig, t) if err != nil { errors = multierror.Append(errors, err) } } return triggerConfig // cron := parseCron(jobNode.Get("trigger", false), errors) // maxExecs := parseMaxExecutions(jobNode.Get("trigger", false), errors) // return TriggerConfig{ // Cron: cron, // MaxExecutions: maxExecs, // } }
func parseMaxExecutions(jobNode *hclObj.Object, errors *multierror.Error) string { if rawCron := jobNode.Get("max_executions", false); rawCron != nil { if rawCron.Len() > 1 { errors = multierror.Append(errors, fmt.Errorf("max_executions was specified more than once")) } else { if rawCron.Type != hclObj.ValueTypeString { errors = multierror.Append(errors, fmt.Errorf("max_executions was specified as an invalid type - expected string, found %s", rawCron.Type)) } else { return rawCron.Value.(string) } } } else { errors = multierror.Append(errors, fmt.Errorf("No max_executions was specified in the configuration")) } return "" }
func parseVersion(hcltree *hclObj.Object, errors *multierror.Error) string { if rawVersion := hcltree.Get("version", false); rawVersion != nil { if rawVersion.Len() > 1 { errors = multierror.Append(errors, fmt.Errorf("Version was specified more than once")) } else { if rawVersion.Type != hclObj.ValueTypeString { errors = multierror.Append(errors, fmt.Errorf("Version was specified as an invalid type - expected string, found %s", rawVersion.Type)) } else { return rawVersion.Value.(string) } } } else { errors = multierror.Append(errors, fmt.Errorf("No version was specified in the configuration")) } return "*** Error" }
func parseRawChain(hclObj *hclObj.Object, errors *multierror.Error) chain.ChainSpec { if rawChain := hclObj.Get("chain", false); rawChain != nil { // iterate over all modules for a given chain for _, mod := range rawChain.Elem(true) { modules := parseRawModules(mod, errors) return chain.NewWithModules(modules) } } return chain.New() }
func parseJobs(hcltree *hclObj.Object, errors *multierror.Error) []JobConfig { outputConfig := make([]JobConfig, 0) if rawJobs := hcltree.Get("job", false); rawJobs != nil { if rawJobs.Type != hclObj.ValueTypeObject { errors = multierror.Append(errors, fmt.Errorf("job was specified as an invalid type - expected list, found %s", rawJobs.Type)) } else { arrayJobs := rawJobs.Elem(true) for _, job := range arrayJobs { outputConfig = append(outputConfig, parseJob(job, errors)) } } } else { if len(outputConfig) == 0 { errors = multierror.Append(errors, fmt.Errorf("No job_store was specified in the configuration")) } } return outputConfig }
func parseJobStore(hcltree *hclObj.Object, errors *multierror.Error) []string { hosts := make([]string, 0) if jobStore := hcltree.Get("job_store", false); jobStore != nil { if jobStore.Len() > 1 { errors = multierror.Append(errors, fmt.Errorf("job_store was specified more than once")) } else { if jobStore.Type != hclObj.ValueTypeList { errors = multierror.Append(errors, fmt.Errorf("job_store was specified as an invalid type - expected string, found %s", jobStore.Type)) } else { for _, host := range jobStore.Elem(true) { hosts = append(hosts, host.Value.(string)) } return hosts } } } else { errors = multierror.Append(errors, fmt.Errorf("No job_store was specified in the configuration")) } return []string{} }
func parseJob(result *structs.Job, obj *hclobj.Object) error { if obj.Len() > 1 { return fmt.Errorf("only one 'job' block allowed") } // Get our job object obj = obj.Elem(true)[0] // Decode the full thing into a map[string]interface for ease var m map[string]interface{} if err := hcl.DecodeObject(&m, obj); 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.Key result.Name = obj.Key // Defaults result.Priority = 50 result.Region = "global" result.Type = "service" // Decode the rest if err := mapstructure.WeakDecode(m, result); err != nil { return err } // Parse constraints if o := obj.Get("constraint", false); o != nil { if err := parseConstraints(&result.Constraints, o); err != nil { return err } } // If we have an update strategy, then parse that if o := obj.Get("update", false); o != nil { 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 := obj.Get("meta", false); metaO != nil { for _, o := range metaO.Elem(false) { var m map[string]interface{} if err := hcl.DecodeObject(&m, o); err != nil { return err } if err := mapstructure.WeakDecode(m, &result.Meta); err != nil { return err } } } // If we have tasks outside, do those if o := obj.Get("task", false); o != nil { var tasks []*structs.Task if err := parseTasks(&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}, } } } // Parse the task groups if o := obj.Get("group", false); o != nil { if err := parseGroups(result, o); err != nil { return fmt.Errorf("error parsing 'group': %s", err) } } return nil }
func (d *decoder) decodeStruct(name string, o *hcl.Object, result reflect.Value) error { if o.Type != hcl.ValueTypeObject { return fmt.Errorf( "%s: not an object type for struct (%s)", name, o.Type) } // This slice will keep track of all the structs we'll be decoding. // There can be more than one struct if there are embedded structs // that are squashed. structs := make([]reflect.Value, 1, 5) structs[0] = result // Compile the list of all the fields that we're going to be decoding // from all the structs. fields := make(map[*reflect.StructField]reflect.Value) for len(structs) > 0 { structVal := structs[0] structs = structs[1:] structType := structVal.Type() for i := 0; i < structType.NumField(); i++ { fieldType := structType.Field(i) if fieldType.Anonymous { fieldKind := fieldType.Type.Kind() if fieldKind != reflect.Struct { return fmt.Errorf( "%s: unsupported type to struct: %s", fieldType.Name, fieldKind) } // We have an embedded field. We "squash" the fields down // if specified in the tag. squash := false tagParts := strings.Split(fieldType.Tag.Get(tagName), ",") for _, tag := range tagParts[1:] { if tag == "squash" { squash = true break } } if squash { structs = append( structs, result.FieldByName(fieldType.Name)) continue } } // Normal struct field, store it away fields[&fieldType] = structVal.Field(i) } } usedKeys := make(map[string]struct{}) decodedFields := make([]string, 0, len(fields)) decodedFieldsVal := make([]reflect.Value, 0) unusedKeysVal := make([]reflect.Value, 0) for fieldType, field := range fields { if !field.IsValid() { // This should never happen panic("field is not valid") } // If we can't set the field, then it is unexported or something, // and we just continue onwards. if !field.CanSet() { continue } fieldName := fieldType.Name // This is whether or not we expand the object into its children // later. expand := false tagValue := fieldType.Tag.Get(tagName) tagParts := strings.SplitN(tagValue, ",", 2) if len(tagParts) >= 2 { switch tagParts[1] { case "expand": expand = true case "decodedFields": decodedFieldsVal = append(decodedFieldsVal, field) continue case "key": field.SetString(o.Key) continue case "unusedKeys": unusedKeysVal = append(unusedKeysVal, field) continue } } if tagParts[0] != "" { fieldName = tagParts[0] } // Find the element matching this name obj := o.Get(fieldName, true) if obj == nil { continue } // Track the used key usedKeys[fieldName] = struct{}{} // Create the field name and decode. We range over the elements // because we actually want the value. fieldName = fmt.Sprintf("%s.%s", name, fieldName) for _, obj := range obj.Elem(expand) { if err := d.decode(fieldName, obj, field); err != nil { return err } } decodedFields = append(decodedFields, fieldType.Name) } if len(decodedFieldsVal) > 0 { // Sort it so that it is deterministic sort.Strings(decodedFields) for _, v := range decodedFieldsVal { v.Set(reflect.ValueOf(decodedFields)) } } // If we want to know what keys are unused, compile that if len(unusedKeysVal) > 0 { /* unusedKeys := make([]string, 0, int(obj.Len())-len(usedKeys)) for _, elem := range obj.Elem { k := elem.Key() if _, ok := usedKeys[k]; !ok { unusedKeys = append(unusedKeys, k) } } if len(unusedKeys) == 0 { unusedKeys = nil } for _, v := range unusedKeysVal { v.Set(reflect.ValueOf(unusedKeys)) } */ } return nil }