github.com/ggiamarchi/terraform@v0.3.7-0.20150607194748-ed2a66a46a71/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 return schemaMap(p.Schema).Validate(c) 101 } 102 103 // ValidateResource implementation of terraform.ResourceProvider interface. 104 func (p *Provider) ValidateResource( 105 t string, c *terraform.ResourceConfig) ([]string, []error) { 106 r, ok := p.ResourcesMap[t] 107 if !ok { 108 return nil, []error{fmt.Errorf( 109 "Provider doesn't support resource: %s", t)} 110 } 111 112 return r.Validate(c) 113 } 114 115 // Configure implementation of terraform.ResourceProvider interface. 116 func (p *Provider) Configure(c *terraform.ResourceConfig) error { 117 // No configuration 118 if p.ConfigureFunc == nil { 119 return nil 120 } 121 122 sm := schemaMap(p.Schema) 123 124 // Get a ResourceData for this configuration. To do this, we actually 125 // generate an intermediary "diff" although that is never exposed. 126 diff, err := sm.Diff(nil, c) 127 if err != nil { 128 return err 129 } 130 131 data, err := sm.Data(nil, diff) 132 if err != nil { 133 return err 134 } 135 136 meta, err := p.ConfigureFunc(data) 137 if err != nil { 138 return err 139 } 140 141 p.meta = meta 142 return nil 143 } 144 145 // Apply implementation of terraform.ResourceProvider interface. 146 func (p *Provider) Apply( 147 info *terraform.InstanceInfo, 148 s *terraform.InstanceState, 149 d *terraform.InstanceDiff) (*terraform.InstanceState, error) { 150 r, ok := p.ResourcesMap[info.Type] 151 if !ok { 152 return nil, fmt.Errorf("unknown resource type: %s", info.Type) 153 } 154 155 return r.Apply(s, d, p.meta) 156 } 157 158 // Diff implementation of terraform.ResourceProvider interface. 159 func (p *Provider) Diff( 160 info *terraform.InstanceInfo, 161 s *terraform.InstanceState, 162 c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { 163 r, ok := p.ResourcesMap[info.Type] 164 if !ok { 165 return nil, fmt.Errorf("unknown resource type: %s", info.Type) 166 } 167 168 return r.Diff(s, c) 169 } 170 171 // Refresh implementation of terraform.ResourceProvider interface. 172 func (p *Provider) Refresh( 173 info *terraform.InstanceInfo, 174 s *terraform.InstanceState) (*terraform.InstanceState, error) { 175 r, ok := p.ResourcesMap[info.Type] 176 if !ok { 177 return nil, fmt.Errorf("unknown resource type: %s", info.Type) 178 } 179 180 return r.Refresh(s, p.meta) 181 } 182 183 // Resources implementation of terraform.ResourceProvider interface. 184 func (p *Provider) Resources() []terraform.ResourceType { 185 keys := make([]string, 0, len(p.ResourcesMap)) 186 for k, _ := range p.ResourcesMap { 187 keys = append(keys, k) 188 } 189 sort.Strings(keys) 190 191 result := make([]terraform.ResourceType, 0, len(keys)) 192 for _, k := range keys { 193 result = append(result, terraform.ResourceType{ 194 Name: k, 195 }) 196 } 197 198 return result 199 }