github.com/bigkraig/terraform@v0.6.4-0.20151219155159-c90d1b074e31/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 sm := schemaMap(p.Schema) 65 if err := sm.InternalValidate(sm); err != nil { 66 return err 67 } 68 69 for k, r := range p.ResourcesMap { 70 if err := r.InternalValidate(nil); err != nil { 71 return fmt.Errorf("%s: %s", k, err) 72 } 73 } 74 75 return nil 76 } 77 78 // Meta returns the metadata associated with this provider that was 79 // returned by the Configure call. It will be nil until Configure is called. 80 func (p *Provider) Meta() interface{} { 81 return p.meta 82 } 83 84 // SetMeta can be used to forcefully set the Meta object of the provider. 85 // Note that if Configure is called the return value will override anything 86 // set here. 87 func (p *Provider) SetMeta(v interface{}) { 88 p.meta = v 89 } 90 91 // Input implementation of terraform.ResourceProvider interface. 92 func (p *Provider) Input( 93 input terraform.UIInput, 94 c *terraform.ResourceConfig) (*terraform.ResourceConfig, error) { 95 return schemaMap(p.Schema).Input(input, c) 96 } 97 98 // Validate implementation of terraform.ResourceProvider interface. 99 func (p *Provider) Validate(c *terraform.ResourceConfig) ([]string, []error) { 100 if err := p.InternalValidate(); err != nil { 101 return nil, []error{fmt.Errorf( 102 "Internal validation of the provider failed! This is always a bug\n"+ 103 "with the provider itself, and not a user issue. Please report\n"+ 104 "this bug:\n\n%s", err)} 105 } 106 107 return schemaMap(p.Schema).Validate(c) 108 } 109 110 // ValidateResource implementation of terraform.ResourceProvider interface. 111 func (p *Provider) ValidateResource( 112 t string, c *terraform.ResourceConfig) ([]string, []error) { 113 r, ok := p.ResourcesMap[t] 114 if !ok { 115 return nil, []error{fmt.Errorf( 116 "Provider doesn't support resource: %s", t)} 117 } 118 119 return r.Validate(c) 120 } 121 122 // Configure implementation of terraform.ResourceProvider interface. 123 func (p *Provider) Configure(c *terraform.ResourceConfig) error { 124 // No configuration 125 if p.ConfigureFunc == nil { 126 return nil 127 } 128 129 sm := schemaMap(p.Schema) 130 131 // Get a ResourceData for this configuration. To do this, we actually 132 // generate an intermediary "diff" although that is never exposed. 133 diff, err := sm.Diff(nil, c) 134 if err != nil { 135 return err 136 } 137 138 data, err := sm.Data(nil, diff) 139 if err != nil { 140 return err 141 } 142 143 meta, err := p.ConfigureFunc(data) 144 if err != nil { 145 return err 146 } 147 148 p.meta = meta 149 return nil 150 } 151 152 // Apply implementation of terraform.ResourceProvider interface. 153 func (p *Provider) Apply( 154 info *terraform.InstanceInfo, 155 s *terraform.InstanceState, 156 d *terraform.InstanceDiff) (*terraform.InstanceState, error) { 157 r, ok := p.ResourcesMap[info.Type] 158 if !ok { 159 return nil, fmt.Errorf("unknown resource type: %s", info.Type) 160 } 161 162 return r.Apply(s, d, p.meta) 163 } 164 165 // Diff implementation of terraform.ResourceProvider interface. 166 func (p *Provider) Diff( 167 info *terraform.InstanceInfo, 168 s *terraform.InstanceState, 169 c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { 170 r, ok := p.ResourcesMap[info.Type] 171 if !ok { 172 return nil, fmt.Errorf("unknown resource type: %s", info.Type) 173 } 174 175 return r.Diff(s, c) 176 } 177 178 // Refresh implementation of terraform.ResourceProvider interface. 179 func (p *Provider) Refresh( 180 info *terraform.InstanceInfo, 181 s *terraform.InstanceState) (*terraform.InstanceState, error) { 182 r, ok := p.ResourcesMap[info.Type] 183 if !ok { 184 return nil, fmt.Errorf("unknown resource type: %s", info.Type) 185 } 186 187 return r.Refresh(s, p.meta) 188 } 189 190 // Resources implementation of terraform.ResourceProvider interface. 191 func (p *Provider) Resources() []terraform.ResourceType { 192 keys := make([]string, 0, len(p.ResourcesMap)) 193 for k, _ := range p.ResourcesMap { 194 keys = append(keys, k) 195 } 196 sort.Strings(keys) 197 198 result := make([]terraform.ResourceType, 0, len(keys)) 199 for _, k := range keys { 200 result = append(result, terraform.ResourceType{ 201 Name: k, 202 }) 203 } 204 205 return result 206 }