package graph import ( "fmt" "regexp" "strings" ) var subRe = regexp.MustCompile(`\$\{([^!].+?)\}`) func getRefs(t map[string]interface{}) []string { return findRefs(t) } func findRefs(t map[string]interface{}) []string { refs := make([]string, 0) for key, value := range t { switch key { case "Ref": refs = append(refs, value.(string)) case "Fn::GetAtt": switch v := value.(type) { case string: parts := strings.Split(v, ".") refs = append(refs, parts[0]) case []interface{}: if s, ok := v[0].(string); ok { refs = append(refs, s) } default: fmt.Printf("Malformed GetAtt: %T\n", v) } case "Fn::Sub": switch v := value.(type) { case string: for _, groups := range subRe.FindAllStringSubmatch(v, 1) { refs = append(refs, groups[1]) } case []interface{}: switch { case len(v) != 2: fmt.Printf("Malformed Sub: %T\n", v) default: switch parts := v[1].(type) { case map[string]interface{}: for _, part := range parts { switch p := part.(type) { case map[string]interface{}: refs = append(refs, findRefs(p)...) default: fmt.Printf("Malformed Sub: %T\n", v) } } default: fmt.Printf("Malformed Sub: %T\n", v) } } default: fmt.Printf("Malformed Sub: %T\n", v) } default: for _, tree := range findTrees(value) { refs = append(refs, findRefs(tree)...) } } } return refs } func findTrees(value interface{}) []map[string]interface{} { trees := make([]map[string]interface{}, 0) switch v := value.(type) { case map[string]interface{}: trees = append(trees, v) case []interface{}: for _, child := range v { trees = append(trees, findTrees(child)...) } } return trees }