func FnSub()

in intrinsics/fnsub.go [11:67]


func FnSub(name string, input interface{}, template interface{}) interface{} {

	// Input can either be a string for this type of Fn::Sub call:
	// { "Fn::Sub": "some-string-with-a-${variable}" }

	// or it will be an array of length two for named replacements
	// { "Fn::Sub": [ "some ${replaced}", { "replaced": "value" } ] }

	switch val := input.(type) {

	case []interface{}:
		// Replace each of the variables in element 0 with the items in element 1
		if src, ok := val[0].(string); ok {
			// The seconds element is a map of variables to replace
			if replacements, ok := val[1].(map[string]interface{}); ok {
				// Loop through the replacements
				for key, replacement := range replacements {
					// Check the replacement is a string
					if value, ok := replacement.(string); ok {
						src = strings.Replace(src, "${"+key+"}", value, -1)
					}
				}
				return src
			}
		}

	case string:
		// Look up references for each of the variables
		regex := regexp.MustCompile(`\$\{([\.:0-9A-Za-z]+)\}`)
		variables := regex.FindAllStringSubmatch(val, -1)
		for _, variable := range variables {

			var resolved interface{}
			if strings.Contains(variable[1], ".") {
				// If the variable name has a . in it, use Fn::GetAtt to resolve it
				resolved = FnGetAtt("Fn::GetAtt", strings.Split(variable[1], "."), template)
			} else {
				// The variable name doesn't have a . in it, so use Ref
				resolved = Ref("Ref", variable[1], template)
			}

			if resolved != nil {
				if replacement, ok := resolved.(string); ok {
					val = strings.Replace(val, variable[0], replacement, -1)
				}
			} else {
				// The reference couldn't be resolved, so just strip the variable
				val = strings.Replace(val, variable[0], "", -1)
			}

		}
		return val
	}

	return nil

}