package resource import ( "fmt" "sort" "github.com/hashicorp/terraform/terraform" ) // Map is a map of resources that are supported, and provides helpers for // more easily implementing a ResourceProvider. type Map struct { Mapping map[string]Resource } func (m *Map) Validate( t string, c *terraform.ResourceConfig) ([]string, []error) { r, ok := m.Mapping[t] if !ok { return nil, []error{fmt.Errorf("Unknown resource type: %s", t)} } // If there is no validator set, then it is valid if r.ConfigValidator == nil { return nil, nil } return r.ConfigValidator.Validate(c) } // Apply performs a create or update depending on the diff, and calls // the proper function on the matching Resource. func (m *Map) Apply( info *terraform.InstanceInfo, s *terraform.InstanceState, d *terraform.InstanceDiff, meta interface{}) (*terraform.InstanceState, error) { r, ok := m.Mapping[info.Type] if !ok { return nil, fmt.Errorf("Unknown resource type: %s", info.Type) } if d.Destroy || d.RequiresNew() { if s.ID != "" { // Destroy the resource if it is created err := r.Destroy(s, meta) if err != nil { return s, err } s.ID = "" } // If we're only destroying, and not creating, then return now. // Otherwise, we continue so that we can create a new resource. if !d.RequiresNew() { return nil, nil } } var result *terraform.InstanceState var err error if s.ID == "" { result, err = r.Create(s, d, meta) } else { if r.Update == nil { return s, fmt.Errorf( "Resource type '%s' doesn't support update", info.Type) } result, err = r.Update(s, d, meta) } if result != nil { if result.Attributes == nil { result.Attributes = make(map[string]string) } result.Attributes["id"] = result.ID } return result, err } // Diff performs a diff on the proper resource type. func (m *Map) Diff( info *terraform.InstanceInfo, s *terraform.InstanceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.InstanceDiff, error) { r, ok := m.Mapping[info.Type] if !ok { return nil, fmt.Errorf("Unknown resource type: %s", info.Type) } return r.Diff(s, c, meta) } // Refresh performs a Refresh on the proper resource type. // // Refresh on the Resource won't be called if the state represents a // non-created resource (ID is blank). // // An error is returned if the resource isn't registered. func (m *Map) Refresh( info *terraform.InstanceInfo, s *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) { // If the resource isn't created, don't refresh. if s.ID == "" { return s, nil } r, ok := m.Mapping[info.Type] if !ok { return nil, fmt.Errorf("Unknown resource type: %s", info.Type) } return r.Refresh(s, meta) } // Resources returns all the resources that are supported by this // resource map and can be used to satisfy the Resources method of // a ResourceProvider. func (m *Map) Resources() []terraform.ResourceType { ks := make([]string, 0, len(m.Mapping)) for k, _ := range m.Mapping { ks = append(ks, k) } sort.Strings(ks) rs := make([]terraform.ResourceType, 0, len(m.Mapping)) for _, k := range ks { rs = append(rs, terraform.ResourceType{ Name: k, }) } return rs }