github.com/ndarilek/terraform@v0.3.8-0.20150320140257-d3135c1b2bac/helper/schema/provider.go (about) 1 package schema 2 3 import ( 4 "errors" 5 "fmt" 6 "sort" 7 8 "github.com/hashicorp/terraform/terraform" 9 ) 10 11 // Provider represents a resource provider in Terraform, and properly 12 // implements all of the ResourceProvider API. 13 // 14 // By defining a schema for the configuration of the provider, the 15 // map of supporting resources, and a configuration function, the schema 16 // framework takes over and handles all the provider operations for you. 17 // 18 // After defining the provider structure, it is unlikely that you'll require any 19 // of the methods on Provider itself. 20 type Provider struct { 21 // Schema is the schema for the configuration of this provider. If this 22 // provider has no configuration, this can be omitted. 23 // 24 // The keys of this map are the configuration keys, and the value is 25 // the schema describing the value of the configuration. 26 Schema map[string]*Schema 27 28 // ResourcesMap is the list of available resources that this provider 29 // can manage, along with their Resource structure defining their 30 // own schemas and CRUD operations. 31 // 32 // Provider automatically handles routing operations such as Apply, 33 // Diff, etc. to the proper resource. 34 ResourcesMap map[string]*Resource 35 36 // ConfigureFunc is a function for configuring the provider. If the 37 // provider doesn't need to be configured, this can be omitted. 38 // 39 // See the ConfigureFunc documentation for more information. 40 ConfigureFunc ConfigureFunc 41 42 meta interface{} 43 } 44 45 // ConfigureFunc is the function used to configure a Provider. 46 // 47 // The interface{} value returned by this function is stored and passed into 48 // the subsequent resources as the meta parameter. This return value is 49 // usually used to pass along a configured API client, a configuration 50 // structure, etc. 51 type ConfigureFunc func(*ResourceData) (interface{}, error) 52 53 // InternalValidate should be called to validate the structure 54 // of the provider. 55 // 56 // This should be called in a unit test for any provider to verify 57 // before release that a provider is properly configured for use with 58 // this library. 59 func (p *Provider) InternalValidate() error { 60 if p == nil { 61 return errors.New("provider is nil") 62 } 63 64 if err := schemaMap(p.Schema).InternalValidate(); err != nil { 65 return err 66 } 67 68 for k, r := range p.ResourcesMap { 69 if err := r.InternalValidate(); err != nil { 70 return fmt.Errorf("%s: %s", k, err) 71 } 72 } 73 74 return nil 75 } 76 77 // Meta returns the metadata associated with this provider that was 78 // returned by the Configure call. It will be nil until Configure is called. 79 func (p *Provider) Meta() interface{} { 80 return p.meta 81 } 82 83 // SetMeta can be used to forcefully set the Meta object of the provider. 84 // Note that if Configure is called the return value will override anything 85 // set here. 86 func (p *Provider) SetMeta(v interface{}) { 87 p.meta = v 88 } 89 90 // Input implementation of terraform.ResourceProvider interface. 91 func (p *Provider) Input( 92 input terraform.UIInput, 93 c *terraform.ResourceConfig) (*terraform.ResourceConfig, error) { 94 return schemaMap(p.Schema).Input(input, c) 95 } 96 97 // Validate implementation of terraform.ResourceProvider interface. 98 func (p *Provider) Validate(c *terraform.ResourceConfig) ([]string, []error) { 99 return schemaMap(p.Schema).Validate(c) 100 } 101 102 // ValidateResource implementation of terraform.ResourceProvider interface. 103 func (p *Provider) ValidateResource( 104 t string, c *terraform.ResourceConfig) ([]string, []error) { 105 r, ok := p.ResourcesMap[t] 106 if !ok { 107 return nil, []error{fmt.Errorf( 108 "Provider doesn't support resource: %s", t)} 109 } 110 111 return r.Validate(c) 112 } 113 114 // Configure implementation of terraform.ResourceProvider interface. 115 func (p *Provider) Configure(c *terraform.ResourceConfig) error { 116 // No configuration 117 if p.ConfigureFunc == nil { 118 return nil 119 } 120 121 sm := schemaMap(p.Schema) 122 123 // Get a ResourceData for this configuration. To do this, we actually 124 // generate an intermediary "diff" although that is never exposed. 125 diff, err := sm.Diff(nil, c) 126 if err != nil { 127 return err 128 } 129 130 data, err := sm.Data(nil, diff) 131 if err != nil { 132 return err 133 } 134 135 meta, err := p.ConfigureFunc(data) 136 if err != nil { 137 return err 138 } 139 140 p.meta = meta 141 return nil 142 } 143 144 // Apply implementation of terraform.ResourceProvider interface. 145 func (p *Provider) Apply( 146 info *terraform.InstanceInfo, 147 s *terraform.InstanceState, 148 d *terraform.InstanceDiff) (*terraform.InstanceState, error) { 149 r, ok := p.ResourcesMap[info.Type] 150 if !ok { 151 return nil, fmt.Errorf("unknown resource type: %s", info.Type) 152 } 153 154 return r.Apply(s, d, p.meta) 155 } 156 157 // Diff implementation of terraform.ResourceProvider interface. 158 func (p *Provider) Diff( 159 info *terraform.InstanceInfo, 160 s *terraform.InstanceState, 161 c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { 162 r, ok := p.ResourcesMap[info.Type] 163 if !ok { 164 return nil, fmt.Errorf("unknown resource type: %s", info.Type) 165 } 166 167 return r.Diff(s, c) 168 } 169 170 // Refresh implementation of terraform.ResourceProvider interface. 171 func (p *Provider) Refresh( 172 info *terraform.InstanceInfo, 173 s *terraform.InstanceState) (*terraform.InstanceState, error) { 174 r, ok := p.ResourcesMap[info.Type] 175 if !ok { 176 return nil, fmt.Errorf("unknown resource type: %s", info.Type) 177 } 178 179 return r.Refresh(s, p.meta) 180 } 181 182 // Resources implementation of terraform.ResourceProvider interface. 183 func (p *Provider) Resources() []terraform.ResourceType { 184 keys := make([]string, 0, len(p.ResourcesMap)) 185 for k, _ := range p.ResourcesMap { 186 keys = append(keys, k) 187 } 188 sort.Strings(keys) 189 190 result := make([]terraform.ResourceType, 0, len(keys)) 191 for _, k := range keys { 192 result = append(result, terraform.ResourceType{ 193 Name: k, 194 }) 195 } 196 197 return result 198 }