Example #1
0
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
}
Example #2
0
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 {
				staggerTime, err := toDuration(raw)
				if err != nil {
					return fmt.Errorf("Invalid stagger time: %v", err)
				}
				m[key] = staggerTime
			}
		}

		if err := mapstructure.WeakDecode(m, result); err != nil {
			return err
		}
	}
	return nil
}
Example #3
0
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
}
Example #4
0
func parseDetect(result *Config, obj *hclobj.Object) error {
	// Get all the maps of keys to the actual object
	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
	}

	// Go through each object and turn it into an actual result.
	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(
				"error parsing detector '%s': %s", o.Key, err)
		}

		d.Type = o.Key
		collection = append(collection, &d)
	}

	result.Detectors = collection
	return nil
}
Example #5
0
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
}
Example #6
0
func parseRawModules(objModules *hclObj.Object, errors *multierror.Error) (output []modules.ModuleSpec) {
	//iterate over each module
	for _, ms := range objModules.Elem(true) {
		// lets build the mod params ...
		rawParams := ms.Elem(true)
		params := params.NewModuleParams()
		for _, p := range rawParams {
			switch p.Value.(type) {
			case string:
				params[p.Key] = p.Value
			case int:
				params[p.Key] = p.Value

			case []*hclObj.Object:
				propertyValues := make([]interface{}, 0)
				for _, pv := range p.Elem(true) {
					propertyValues = append(propertyValues, pv.Value)
				}
				params[p.Key] = propertyValues
			}

		}
		// build the module
		module := modprobe.Find(ms.Key, params)
		output = append(output, module)
	}

	return output
}
Example #7
0
func parseInfra(result *File, obj *hclobj.Object) error {
	// Get all the maps of keys to the actual object
	objects := make(map[string]*hclobj.Object)
	for _, o1 := range obj.Elem(false) {
		for _, o2 := range o1.Elem(true) {
			if _, ok := objects[o2.Key]; ok {
				return fmt.Errorf(
					"infrastructure '%s' defined more than once",
					o2.Key)
			}

			objects[o2.Key] = o2
		}
	}

	if len(objects) == 0 {
		return nil
	}

	// Go through each object and turn it into an actual result.
	collection := make([]*Infrastructure, 0, len(objects))
	for n, o := range objects {
		// Check for invalid keys
		valid := []string{"name", "type", "flavor", "foundation"}
		if err := checkHCLKeys(o, valid); err != nil {
			return multierror.Prefix(err, fmt.Sprintf(
				"infrastructure '%s':", n))
		}

		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); 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 := o.Get("foundation", false); o != nil {
			if err := parseFoundations(&infra, o2); err != nil {
				return fmt.Errorf("error parsing 'foundation': %s", err)
			}
		}

		collection = append(collection, &infra)
	}

	result.Infrastructure = collection
	return nil
}
Example #8
0
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
		}

		// If "version" is provided, set the operand
		// to "version" and the value to the "RTarget"
		if constraint, ok := m[structs.ConstraintVersion]; ok {
			m["Operand"] = structs.ConstraintVersion
			m["RTarget"] = constraint
		}

		// If "regexp" is provided, set the operand
		// to "regexp" and the value to the "RTarget"
		if constraint, ok := m[structs.ConstraintRegex]; ok {
			m["Operand"] = structs.ConstraintRegex
			m["RTarget"] = constraint
		}

		if value, ok := m[structs.ConstraintDistinctHosts]; ok {
			enabled, err := strconv.ParseBool(value.(string))
			if err != nil {
				return err
			}

			// If it is not enabled, skip the constraint.
			if !enabled {
				continue
			}

			m["Operand"] = structs.ConstraintDistinctHosts
		}

		// 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
}
Example #9
0
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
}
Example #10
0
// 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
}
Example #11
0
func checkHCLKeys(obj *hclobj.Object, valid []string) error {
	validMap := make(map[string]struct{}, len(valid))
	for _, v := range valid {
		validMap[v] = struct{}{}
	}

	var result error
	for _, o := range obj.Elem(true) {
		if _, ok := validMap[o.Key]; !ok {
			result = multierror.Append(result, fmt.Errorf(
				"invald key: %s", o.Key))
		}
	}

	return result
}
Example #12
0
func (d *decoder) decodeSlice(name string, o *hcl.Object, result reflect.Value) error {
	// If we have an interface, then we can address the interface,
	// but not the slice itself, so get the element but set the interface
	set := result
	if result.Kind() == reflect.Interface {
		result = result.Elem()
	}

	// Create the slice if it isn't nil
	resultType := result.Type()
	resultElemType := resultType.Elem()
	if result.IsNil() {
		resultSliceType := reflect.SliceOf(resultElemType)
		result = reflect.MakeSlice(
			resultSliceType, 0, 0)
	}

	// Determine how we're doing this
	expand := true
	switch o.Type {
	case hcl.ValueTypeObject:
		expand = false
	default:
		// Array or anything else: we expand values and take it all
	}

	i := 0
	for _, o := range o.Elem(expand) {
		fieldName := fmt.Sprintf("%s[%d]", name, i)

		// Decode
		val := reflect.Indirect(reflect.New(resultElemType))
		if err := d.decode(fieldName, o, val); err != nil {
			return err
		}

		// Append it onto the slice
		result = reflect.Append(result, val)

		i += 1
	}

	set.Set(result)
	return nil
}
Example #13
0
func loadListeners(os *hclobj.Object) ([]*Listener, error) {
	var allNames []*hclobj.Object

	// Really confusing iteration. The key is the false/true parameter
	// of whether we're expanding or not. We first iterate over all
	// the "listeners"
	for _, o1 := range os.Elem(false) {
		// Iterate expand to get the list of types
		for _, o2 := range o1.Elem(true) {
			switch o2.Type {
			case hclobj.ValueTypeList:
				// This switch is for JSON, to allow them to do this:
				//
				// "tcp": [{ ... }, { ... }]
				//
				// To configure multiple listeners of the same type.
				for _, o3 := range o2.Elem(true) {
					o3.Key = o2.Key
					allNames = append(allNames, o3)
				}
			case hclobj.ValueTypeObject:
				// This is for the standard `listener "tcp" { ... }` syntax
				allNames = append(allNames, o2)
			}
		}
	}

	if len(allNames) == 0 {
		return nil, nil
	}

	// Now go over all the types and their children in order to get
	// all of the actual resources.
	result := make([]*Listener, 0, len(allNames))
	for _, obj := range allNames {
		k := obj.Key

		var config map[string]string
		if err := hcl.DecodeObject(&config, obj); err != nil {
			return nil, fmt.Errorf(
				"Error reading config for %s: %s",
				k,
				err)
		}

		result = append(result, &Listener{
			Type:   k,
			Config: config,
		})
	}

	return result, nil
}
Example #14
0
// LoadProvidersHcl recurses into the given HCL object and turns
// it into a mapping of provider configs.
func loadProvidersHcl(os *hclobj.Object) ([]*ProviderConfig, error) {
	objects := make(map[string]*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[o2.Key] = 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 n, o := range objects {
		var config map[string]interface{}

		if err := hcl.DecodeObject(&config, o); err != nil {
			return nil, err
		}

		rawConfig, err := NewRawConfig(config)
		if err != nil {
			return nil, fmt.Errorf(
				"Error reading config for provider config %s: %s",
				n,
				err)
		}

		result = append(result, &ProviderConfig{
			Name:      n,
			RawConfig: rawConfig,
		})
	}

	return result, nil
}
Example #15
0
func parseImport(result *File, obj *hclobj.Object) error {
	// Get all the maps of keys to the actual object
	objects := make([]*hclobj.Object, 0, 3)
	set := make(map[string]struct{})
	for _, o1 := range obj.Elem(false) {
		for _, o2 := range o1.Elem(true) {
			if _, ok := set[o2.Key]; ok {
				return fmt.Errorf(
					"imported '%s' more than once",
					o2.Key)
			}

			objects = append(objects, o2)
			set[o2.Key] = struct{}{}
		}
	}

	if len(objects) == 0 {
		return nil
	}

	// Go through each object and turn it into an actual result.
	collection := make([]*Import, 0, len(objects))
	for _, o := range objects {
		// Check for invalid keys
		if err := checkHCLKeys(o, nil); err != nil {
			return multierror.Prefix(err, fmt.Sprintf(
				"import '%s':", o.Key))
		}

		collection = append(collection, &Import{
			Source: o.Key,
		})
	}

	result.Imports = collection
	return nil
}
Example #16
0
func parseFoundations(result *Infrastructure, obj *hclobj.Object) error {
	// Get all the maps of keys to the actual object
	objects := make(map[string]*hclobj.Object)
	for _, o1 := range obj.Elem(false) {
		for _, o2 := range o1.Elem(true) {
			if _, ok := objects[o2.Key]; ok {
				return fmt.Errorf(
					"foundation '%s' defined more than once",
					o2.Key)
			}

			objects[o2.Key] = o2
		}
	}

	if len(objects) == 0 {
		return nil
	}

	// Go through each object and turn it into an actual result.
	collection := make([]*Foundation, 0, len(objects))
	for n, o := range objects {
		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); 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
}
Example #17
0
func parseCustomizations(result *File, obj *hclobj.Object) error {
	// Get all the maps of keys to the actual object
	objects := make(map[string]*hclobj.Object)
	for _, o1 := range obj.Elem(false) {
		for _, o2 := range o1.Elem(true) {
			if _, ok := objects[o2.Key]; ok {
				return fmt.Errorf(
					"customization '%s' defined more than once",
					o2.Key)
			}

			objects[o2.Key] = o2
		}
	}

	if len(objects) == 0 {
		return nil
	}

	// Go through each object and turn it into an actual result.
	collection := make([]*Customization, 0, len(objects))
	for n, o := range objects {
		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); err != nil {
			return err
		}

		var c Customization
		c.Type = strings.ToLower(n)
		c.Config = m

		collection = append(collection, &c)
	}

	result.Customization = &CustomizationSet{Raw: collection}
	return nil
}
Example #18
0
func loadBackend(os *hclobj.Object) (*Backend, error) {
	var allNames []*hclobj.Object

	// See loadListeners
	for _, o1 := range os.Elem(false) {
		// Iterate expand to get the list of types
		for _, o2 := range o1.Elem(true) {
			// Iterate non-expand to get the full list of types
			for _, o3 := range o2.Elem(false) {
				allNames = append(allNames, o3)
			}
		}
	}

	if len(allNames) == 0 {
		return nil, nil
	}
	if len(allNames) > 1 {
		keys := make([]string, 0, len(allNames))
		for _, o := range allNames {
			keys = append(keys, o.Key)
		}

		return nil, fmt.Errorf(
			"Multiple backends declared. Only one is allowed: %v", keys)
	}

	// Now go over all the types and their children in order to get
	// all of the actual resources.
	var result Backend
	obj := allNames[0]
	result.Type = obj.Key

	var config map[string]string
	if err := hcl.DecodeObject(&config, obj); err != nil {
		return nil, fmt.Errorf(
			"Error reading config for backend %s: %s",
			result.Type,
			err)
	}

	if v, ok := config["advertise_addr"]; ok {
		result.AdvertiseAddr = v
		delete(config, "advertise_addr")
	}

	result.Config = config
	return &result, nil
}
Example #19
0
// 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(os *hclobj.Object) ([]*Resource, error) {
	var allTypes []*hclobj.Object

	// HCL object iteration is really nasty. Below is likely to make
	// no sense to anyone approaching this code. Luckily, it is very heavily
	// tested. If working on a bug fix or feature, we recommend writing a
	// test first then doing whatever you want to the code below. If you
	// break it, the tests will catch it. Likewise, if you change this,
	// MAKE SURE you write a test for your change, because its fairly impossible
	// to reason about this mess.
	//
	// Functionally, what the code does below is get the libucl.Objects
	// for all the TYPES, such as "aws_security_group".
	for _, o1 := range os.Elem(false) {
		// Iterate the inner to get the list of types
		for _, o2 := range o1.Elem(true) {
			// Iterate all of this type to get _all_ the types
			for _, o3 := range o2.Elem(false) {
				allTypes = append(allTypes, o3)
			}
		}
	}

	// 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 _, t := range allTypes {
		for _, obj := range t.Elem(true) {
			k := obj.Key

			var config map[string]interface{}
			if err := hcl.DecodeObject(&config, obj); err != nil {
				return nil, fmt.Errorf(
					"Error reading config for %s[%s]: %s",
					t.Key,
					k,
					err)
			}

			// Remove the fields we handle specially
			delete(config, "connection")
			delete(config, "count")
			delete(config, "depends_on")
			delete(config, "provisioner")
			delete(config, "lifecycle")

			rawConfig, err := NewRawConfig(config)
			if err != nil {
				return nil, fmt.Errorf(
					"Error reading config for %s[%s]: %s",
					t.Key,
					k,
					err)
			}

			// If we have a count, then figure it out
			var count string = "1"
			if o := obj.Get("count", false); o != nil {
				err = hcl.DecodeObject(&count, o)
				if err != nil {
					return nil, fmt.Errorf(
						"Error parsing count for %s[%s]: %s",
						t.Key,
						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 := obj.Get("depends_on", false); o != nil {
				err := hcl.DecodeObject(&dependsOn, o)
				if err != nil {
					return nil, fmt.Errorf(
						"Error reading depends_on for %s[%s]: %s",
						t.Key,
						k,
						err)
				}
			}

			// If we have connection info, then parse those out
			var connInfo map[string]interface{}
			if o := obj.Get("connection", false); o != nil {
				err := hcl.DecodeObject(&connInfo, o)
				if err != nil {
					return nil, fmt.Errorf(
						"Error reading connection info for %s[%s]: %s",
						t.Key,
						k,
						err)
				}
			}

			// If we have provisioners, then parse those out
			var provisioners []*Provisioner
			if os := obj.Get("provisioner", false); os != nil {
				var err error
				provisioners, err = loadProvisionersHcl(os, connInfo)
				if err != nil {
					return nil, fmt.Errorf(
						"Error reading provisioners for %s[%s]: %s",
						t.Key,
						k,
						err)
				}
			}

			// Check if the resource should be re-created before
			// destroying the existing instance
			var lifecycle ResourceLifecycle
			if o := obj.Get("lifecycle", false); o != nil {
				err = hcl.DecodeObject(&lifecycle, o)
				if err != nil {
					return nil, fmt.Errorf(
						"Error parsing lifecycle for %s[%s]: %s",
						t.Key,
						k,
						err)
				}
			}

			result = append(result, &Resource{
				Name:         k,
				Type:         t.Key,
				RawCount:     countConfig,
				RawConfig:    rawConfig,
				Provisioners: provisioners,
				DependsOn:    dependsOn,
				Lifecycle:    lifecycle,
			})
		}
	}

	return result, nil
}
Example #20
0
// 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(os *hclobj.Object) ([]*Module, error) {
	var allNames []*hclobj.Object

	// See loadResourcesHcl for why this exists. Don't touch this.
	for _, o1 := range os.Elem(false) {
		// Iterate the inner to get the list of types
		for _, o2 := range o1.Elem(true) {
			// Iterate all of this type to get _all_ the types
			for _, o3 := range o2.Elem(false) {
				allNames = append(allNames, o3)
			}
		}
	}

	// 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 _, obj := range allNames {
		k := obj.Key

		var config map[string]interface{}
		if err := hcl.DecodeObject(&config, obj); 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 := obj.Get("source", false); o != nil {
			err = hcl.DecodeObject(&source, o)
			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
}
Example #21
0
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
}
Example #22
0
func parseTasks(result *[]*structs.Task, obj *hclobj.Object) error {
	// Get all the maps of keys to the actual object
	objects := make([]*hclobj.Object, 0, 5)
	set := make(map[string]struct{})
	for _, o1 := range obj.Elem(false) {
		for _, o2 := range o1.Elem(true) {
			if _, ok := set[o2.Key]; ok {
				return fmt.Errorf(
					"group '%s' defined more than once",
					o2.Key)
			}

			objects = append(objects, o2)
			set[o2.Key] = struct{}{}
		}
	}

	if len(objects) == 0 {
		return nil
	}

	for _, o := range objects {
		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); err != nil {
			return err
		}
		delete(m, "config")
		delete(m, "constraint")
		delete(m, "meta")
		delete(m, "resources")

		// Build the task
		var t structs.Task
		t.Name = o.Key
		if err := mapstructure.WeakDecode(m, &t); err != nil {
			return err
		}

		// If we have config, then parse that
		if o := o.Get("config", false); o != nil {
			for _, o := range o.Elem(false) {
				var m map[string]interface{}
				if err := hcl.DecodeObject(&m, o); err != nil {
					return err
				}
				if err := mapstructure.WeakDecode(m, &t.Config); err != nil {
					return err
				}
			}
		}

		// Parse constraints
		if o := o.Get("constraint", false); o != nil {
			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 := o.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, &t.Meta); err != nil {
					return err
				}
			}
		}

		// If we have resources, then parse that
		if o := o.Get("resources", false); o != nil {
			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
}
Example #23
0
func loadProvisionersHcl(os *hclobj.Object, connInfo map[string]interface{}) ([]*Provisioner, error) {
	pos := make([]*hclobj.Object, 0, int(os.Len()))

	// Accumulate all the actual provisioner configuration objects. We
	// have to iterate twice here:
	//
	//  1. The first iteration is of the list of `provisioner` blocks.
	//  2. The second iteration is of the dictionary within the
	//      provisioner which will have only one element which is the
	//      type of provisioner to use along with tis config.
	//
	// In JSON it looks kind of like this:
	//
	//   [
	//     {
	//       "shell": {
	//         ...
	//       }
	//     }
	//   ]
	//
	for _, o1 := range os.Elem(false) {
		for _, o2 := range o1.Elem(true) {
			pos = append(pos, o2)
		}
	}

	// Short-circuit if there are no items
	if len(pos) == 0 {
		return nil, nil
	}

	result := make([]*Provisioner, 0, len(pos))
	for _, po := range pos {
		var config map[string]interface{}
		if err := hcl.DecodeObject(&config, po); err != nil {
			return nil, err
		}

		// Delete the "connection" section, handle seperately
		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 := po.Get("connection", false); o != nil {
			err := hcl.DecodeObject(&subConnInfo, o)
			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:      po.Key,
			RawConfig: rawConfig,
			ConnInfo:  connRaw,
		})
	}

	return result, nil
}
Example #24
0
func parseGroups(result *structs.Job, obj *hclobj.Object) error {
	// Get all the maps of keys to the actual object
	objects := make(map[string]*hclobj.Object)
	for _, o1 := range obj.Elem(false) {
		for _, o2 := range o1.Elem(true) {
			if _, ok := objects[o2.Key]; ok {
				return fmt.Errorf(
					"group '%s' defined more than once",
					o2.Key)
			}

			objects[o2.Key] = o2
		}
	}

	if len(objects) == 0 {
		return nil
	}

	// Go through each object and turn it into an actual result.
	collection := make([]*structs.TaskGroup, 0, len(objects))
	for n, o := range objects {
		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); err != nil {
			return err
		}
		delete(m, "constraint")
		delete(m, "meta")
		delete(m, "task")

		// 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 := o.Get("constraint", false); o != nil {
			if err := parseConstraints(&g.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 := o.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, &g.Meta); err != nil {
					return err
				}
			}
		}

		// Parse tasks
		if o := o.Get("task", false); o != nil {
			if err := parseTasks(&g.Tasks, o); err != nil {
				return err
			}
		}

		collection = append(collection, &g)
	}

	result.TaskGroups = append(result.TaskGroups, collection...)
	return nil
}
Example #25
0
func (d *decoder) decodeMap(name string, o *hcl.Object, result reflect.Value) error {
	if o.Type != hcl.ValueTypeObject {
		return fmt.Errorf("%s: not an object type for map (%s)", name, o.Type)
	}

	// If we have an interface, then we can address the interface,
	// but not the slice itself, so get the element but set the interface
	set := result
	if result.Kind() == reflect.Interface {
		result = result.Elem()
	}

	resultType := result.Type()
	resultElemType := resultType.Elem()
	resultKeyType := resultType.Key()
	if resultKeyType.Kind() != reflect.String {
		return fmt.Errorf(
			"%s: map must have string keys", name)
	}

	// Make a map if it is nil
	resultMap := result
	if result.IsNil() {
		resultMap = reflect.MakeMap(
			reflect.MapOf(resultKeyType, resultElemType))
	}

	// Go through each element and decode it.
	for _, o := range o.Elem(false) {
		if o.Value == nil {
			continue
		}

		for _, o := range o.Elem(true) {
			// Make the field name
			fieldName := fmt.Sprintf("%s.%s", name, o.Key)

			// Get the key/value as reflection values
			key := reflect.ValueOf(o.Key)
			val := reflect.Indirect(reflect.New(resultElemType))

			// If we have a pre-existing value in the map, use that
			oldVal := resultMap.MapIndex(key)
			if oldVal.IsValid() {
				val.Set(oldVal)
			}

			// Decode!
			if err := d.decode(fieldName, o, val); err != nil {
				return err
			}

			// Set the value on the map
			resultMap.SetMapIndex(key, val)
		}
	}

	// Set the final map if we can
	set.Set(resultMap)
	return nil
}