github.com/nicgrayson/terraform@v0.4.3-0.20150415203910-c4de50829380/terraform/resource_address.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "regexp" 6 "strconv" 7 ) 8 9 // ResourceAddress is a way of identifying an individual resource (or, 10 // eventually, a subset of resources) within the state. It is used for Targets. 11 type ResourceAddress struct { 12 Index int 13 InstanceType InstanceType 14 Name string 15 Type string 16 } 17 18 func ParseResourceAddress(s string) (*ResourceAddress, error) { 19 matches, err := tokenizeResourceAddress(s) 20 if err != nil { 21 return nil, err 22 } 23 resourceIndex := -1 24 if matches["index"] != "" { 25 var err error 26 if resourceIndex, err = strconv.Atoi(matches["index"]); err != nil { 27 return nil, err 28 } 29 } 30 instanceType := TypePrimary 31 if matches["instance_type"] != "" { 32 var err error 33 if instanceType, err = ParseInstanceType(matches["instance_type"]); err != nil { 34 return nil, err 35 } 36 } 37 38 return &ResourceAddress{ 39 Index: resourceIndex, 40 InstanceType: instanceType, 41 Name: matches["name"], 42 Type: matches["type"], 43 }, nil 44 } 45 46 func (addr *ResourceAddress) Equals(raw interface{}) bool { 47 other, ok := raw.(*ResourceAddress) 48 if !ok { 49 return false 50 } 51 52 indexMatch := (addr.Index == -1 || 53 other.Index == -1 || 54 addr.Index == other.Index) 55 56 return (indexMatch && 57 addr.InstanceType == other.InstanceType && 58 addr.Name == other.Name && 59 addr.Type == other.Type) 60 } 61 62 func ParseInstanceType(s string) (InstanceType, error) { 63 switch s { 64 case "primary": 65 return TypePrimary, nil 66 case "deposed": 67 return TypeDeposed, nil 68 case "tainted": 69 return TypeTainted, nil 70 default: 71 return TypeInvalid, fmt.Errorf("Unexpected value for InstanceType field: %q", s) 72 } 73 } 74 75 func tokenizeResourceAddress(s string) (map[string]string, error) { 76 // Example of portions of the regexp below using the 77 // string "aws_instance.web.tainted[1]" 78 re := regexp.MustCompile(`\A` + 79 // "aws_instance" 80 `(?P<type>\w+)\.` + 81 // "web" 82 `(?P<name>\w+)` + 83 // "tainted" (optional, omission implies: "primary") 84 `(?:\.(?P<instance_type>\w+))?` + 85 // "1" (optional, omission implies: "0") 86 `(?:\[(?P<index>\d+)\])?` + 87 `\z`) 88 groupNames := re.SubexpNames() 89 rawMatches := re.FindAllStringSubmatch(s, -1) 90 if len(rawMatches) != 1 { 91 return nil, fmt.Errorf("Problem parsing address: %q", s) 92 } 93 matches := make(map[string]string) 94 for i, m := range rawMatches[0] { 95 matches[groupNames[i]] = m 96 } 97 return matches, nil 98 }