github.com/loicalbertin/terraform@v0.6.15-0.20170626182346-8e2583055467/terraform/resource_provider.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 6 multierror "github.com/hashicorp/go-multierror" 7 "github.com/hashicorp/terraform/plugin/discovery" 8 ) 9 10 // ResourceProvider is an interface that must be implemented by any 11 // resource provider: the thing that creates and manages the resources in 12 // a Terraform configuration. 13 // 14 // Important implementation note: All returned pointers, such as 15 // *ResourceConfig, *InstanceState, *InstanceDiff, etc. must not point to 16 // shared data. Terraform is highly parallel and assumes that this data is safe 17 // to read/write in parallel so it must be unique references. Note that it is 18 // safe to return arguments as results, however. 19 type ResourceProvider interface { 20 /********************************************************************* 21 * Functions related to the provider 22 *********************************************************************/ 23 24 // Input is called to ask the provider to ask the user for input 25 // for completing the configuration if necesarry. 26 // 27 // This may or may not be called, so resource provider writers shouldn't 28 // rely on this being available to set some default values for validate 29 // later. Example of a situation where this wouldn't be called is if 30 // the user is not using a TTY. 31 Input(UIInput, *ResourceConfig) (*ResourceConfig, error) 32 33 // Validate is called once at the beginning with the raw configuration 34 // (no interpolation done) and can return a list of warnings and/or 35 // errors. 36 // 37 // This is called once with the provider configuration only. It may not 38 // be called at all if no provider configuration is given. 39 // 40 // This should not assume that any values of the configurations are valid. 41 // The primary use case of this call is to check that required keys are 42 // set. 43 Validate(*ResourceConfig) ([]string, []error) 44 45 // Configure configures the provider itself with the configuration 46 // given. This is useful for setting things like access keys. 47 // 48 // This won't be called at all if no provider configuration is given. 49 // 50 // Configure returns an error if it occurred. 51 Configure(*ResourceConfig) error 52 53 // Resources returns all the available resource types that this provider 54 // knows how to manage. 55 Resources() []ResourceType 56 57 // Stop is called when the provider should halt any in-flight actions. 58 // 59 // This can be used to make a nicer Ctrl-C experience for Terraform. 60 // Even if this isn't implemented to do anything (just returns nil), 61 // Terraform will still cleanly stop after the currently executing 62 // graph node is complete. However, this API can be used to make more 63 // efficient halts. 64 // 65 // Stop doesn't have to and shouldn't block waiting for in-flight actions 66 // to complete. It should take any action it wants and return immediately 67 // acknowledging it has received the stop request. Terraform core will 68 // automatically not make any further API calls to the provider soon 69 // after Stop is called (technically exactly once the currently executing 70 // graph nodes are complete). 71 // 72 // The error returned, if non-nil, is assumed to mean that signaling the 73 // stop somehow failed and that the user should expect potentially waiting 74 // a longer period of time. 75 Stop() error 76 77 /********************************************************************* 78 * Functions related to individual resources 79 *********************************************************************/ 80 81 // ValidateResource is called once at the beginning with the raw 82 // configuration (no interpolation done) and can return a list of warnings 83 // and/or errors. 84 // 85 // This is called once per resource. 86 // 87 // This should not assume any of the values in the resource configuration 88 // are valid since it is possible they have to be interpolated still. 89 // The primary use case of this call is to check that the required keys 90 // are set and that the general structure is correct. 91 ValidateResource(string, *ResourceConfig) ([]string, []error) 92 93 // Apply applies a diff to a specific resource and returns the new 94 // resource state along with an error. 95 // 96 // If the resource state given has an empty ID, then a new resource 97 // is expected to be created. 98 Apply( 99 *InstanceInfo, 100 *InstanceState, 101 *InstanceDiff) (*InstanceState, error) 102 103 // Diff diffs a resource versus a desired state and returns 104 // a diff. 105 Diff( 106 *InstanceInfo, 107 *InstanceState, 108 *ResourceConfig) (*InstanceDiff, error) 109 110 // Refresh refreshes a resource and updates all of its attributes 111 // with the latest information. 112 Refresh(*InstanceInfo, *InstanceState) (*InstanceState, error) 113 114 /********************************************************************* 115 * Functions related to importing 116 *********************************************************************/ 117 118 // ImportState requests that the given resource be imported. 119 // 120 // The returned InstanceState only requires ID be set. Importing 121 // will always call Refresh after the state to complete it. 122 // 123 // IMPORTANT: InstanceState doesn't have the resource type attached 124 // to it. A type must be specified on the state via the Ephemeral 125 // field on the state. 126 // 127 // This function can return multiple states. Normally, an import 128 // will map 1:1 to a physical resource. However, some resources map 129 // to multiple. For example, an AWS security group may contain many rules. 130 // Each rule is represented by a separate resource in Terraform, 131 // therefore multiple states are returned. 132 ImportState(*InstanceInfo, string) ([]*InstanceState, error) 133 134 /********************************************************************* 135 * Functions related to data resources 136 *********************************************************************/ 137 138 // ValidateDataSource is called once at the beginning with the raw 139 // configuration (no interpolation done) and can return a list of warnings 140 // and/or errors. 141 // 142 // This is called once per data source instance. 143 // 144 // This should not assume any of the values in the resource configuration 145 // are valid since it is possible they have to be interpolated still. 146 // The primary use case of this call is to check that the required keys 147 // are set and that the general structure is correct. 148 ValidateDataSource(string, *ResourceConfig) ([]string, []error) 149 150 // DataSources returns all of the available data sources that this 151 // provider implements. 152 DataSources() []DataSource 153 154 // ReadDataDiff produces a diff that represents the state that will 155 // be produced when the given data source is read using a later call 156 // to ReadDataApply. 157 ReadDataDiff(*InstanceInfo, *ResourceConfig) (*InstanceDiff, error) 158 159 // ReadDataApply initializes a data instance using the configuration 160 // in a diff produced by ReadDataDiff. 161 ReadDataApply(*InstanceInfo, *InstanceDiff) (*InstanceState, error) 162 } 163 164 // ResourceProviderError may be returned when creating a Context if the 165 // required providers cannot be satisfied. This error can then be used to 166 // format a more useful message for the user. 167 type ResourceProviderError struct { 168 Errors []error 169 } 170 171 func (e *ResourceProviderError) Error() string { 172 // use multierror to format the default output 173 return multierror.Append(nil, e.Errors...).Error() 174 } 175 176 // ResourceProviderCloser is an interface that providers that can close 177 // connections that aren't needed anymore must implement. 178 type ResourceProviderCloser interface { 179 Close() error 180 } 181 182 // ResourceType is a type of resource that a resource provider can manage. 183 type ResourceType struct { 184 Name string // Name of the resource, example "instance" (no provider prefix) 185 Importable bool // Whether this resource supports importing 186 } 187 188 // DataSource is a data source that a resource provider implements. 189 type DataSource struct { 190 Name string 191 } 192 193 // ResourceProviderResolver is an interface implemented by objects that are 194 // able to resolve a given set of resource provider version constraints 195 // into ResourceProviderFactory callbacks. 196 type ResourceProviderResolver interface { 197 // Given a constraint map, return a ResourceProviderFactory for each 198 // requested provider. If some or all of the constraints cannot be 199 // satisfied, return a non-nil slice of errors describing the problems. 200 ResolveProviders(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error) 201 } 202 203 // ResourceProviderResolverFunc wraps a callback function and turns it into 204 // a ResourceProviderResolver implementation, for convenience in situations 205 // where a function and its associated closure are sufficient as a resolver 206 // implementation. 207 type ResourceProviderResolverFunc func(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error) 208 209 // ResolveProviders implements ResourceProviderResolver by calling the 210 // wrapped function. 211 func (f ResourceProviderResolverFunc) ResolveProviders(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error) { 212 return f(reqd) 213 } 214 215 // ResourceProviderResolverFixed returns a ResourceProviderResolver that 216 // has a fixed set of provider factories provided by the caller. The returned 217 // resolver ignores version constraints entirely and just returns the given 218 // factory for each requested provider name. 219 // 220 // This function is primarily used in tests, to provide mock providers or 221 // in-process providers under test. 222 func ResourceProviderResolverFixed(factories map[string]ResourceProviderFactory) ResourceProviderResolver { 223 return ResourceProviderResolverFunc(func(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error) { 224 ret := make(map[string]ResourceProviderFactory, len(reqd)) 225 var errs []error 226 for name := range reqd { 227 if factory, exists := factories[name]; exists { 228 ret[name] = factory 229 } else { 230 errs = append(errs, fmt.Errorf("provider %q is not available", name)) 231 } 232 } 233 return ret, errs 234 }) 235 } 236 237 // ResourceProviderFactory is a function type that creates a new instance 238 // of a resource provider. 239 type ResourceProviderFactory func() (ResourceProvider, error) 240 241 // ResourceProviderFactoryFixed is a helper that creates a 242 // ResourceProviderFactory that just returns some fixed provider. 243 func ResourceProviderFactoryFixed(p ResourceProvider) ResourceProviderFactory { 244 return func() (ResourceProvider, error) { 245 return p, nil 246 } 247 } 248 249 func ProviderHasResource(p ResourceProvider, n string) bool { 250 for _, rt := range p.Resources() { 251 if rt.Name == n { 252 return true 253 } 254 } 255 256 return false 257 } 258 259 func ProviderHasDataSource(p ResourceProvider, n string) bool { 260 for _, rt := range p.DataSources() { 261 if rt.Name == n { 262 return true 263 } 264 } 265 266 return false 267 } 268 269 // resourceProviderFactories matches available plugins to the given version 270 // requirements to produce a map of compatible provider plugins if possible, 271 // or an error if the currently-available plugins are insufficient. 272 // 273 // This should be called only with configurations that have passed calls 274 // to config.Validate(), which ensures that all of the given version 275 // constraints are valid. It will panic if any invalid constraints are present. 276 func resourceProviderFactories(resolver ResourceProviderResolver, reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, error) { 277 ret, errs := resolver.ResolveProviders(reqd) 278 if errs != nil { 279 return nil, &ResourceProviderError{ 280 Errors: errs, 281 } 282 } 283 284 return ret, nil 285 }