github.com/sl1pm4t/terraform@v0.6.4-0.20170725213156-870617d22df3/website/docs/plugins/provider.html.md (about) 1 --- 2 layout: "docs" 3 page_title: "Provider Plugins" 4 sidebar_current: "docs-plugins-provider" 5 description: |- 6 A provider in Terraform is responsible for the lifecycle of a resource: create, read, update, delete. An example of a provider is AWS, which can manage resources of type `aws_instance`, `aws_eip`, `aws_elb`, etc. 7 --- 8 9 # Provider Plugins 10 11 A provider in Terraform is responsible for the lifecycle of a resource: 12 create, read, update, delete. An example of a provider is AWS, which 13 can manage resources of type `aws_instance`, `aws_eip`, `aws_elb`, etc. 14 15 The primary reasons to care about provider plugins are: 16 17 * You want to add a new resource type to an existing provider. 18 19 * You want to write a completely new provider for managing resource 20 types in a system not yet supported. 21 22 * You want to write a completely new provider for custom, internal 23 systems such as a private inventory management system. 24 25 ~> **Advanced topic!** Plugin development is a highly advanced 26 topic in Terraform, and is not required knowledge for day-to-day usage. 27 If you don't plan on writing any plugins, we recommend not reading 28 this section of the documentation. 29 30 If you're interested in provider development, then read on. The remainder 31 of this page will assume you're familiar with 32 [plugin basics](/docs/plugins/basics.html) and that you already have 33 a basic development environment setup. 34 35 ## Provider Plugin Codebases 36 37 Provider plugins live outside of the Terraform core codebase in their own 38 source code repositories. The official set of provider plugins released by 39 HashiCorp (developed by both HashiCorp staff and community contributors) 40 all live in repositories in 41 [the `terraform-providers` organization](https://github.com/terraform-providers) 42 on GitHub, but third-party plugins can be maintained in any source code 43 repository. 44 45 When developing a provider plugin, it is recommended to use a common `GOPATH` 46 that includes both the core Terraform repository and the repositories of any 47 providers being changed. This makes it easier to use a locally-built 48 `terraform` executable and a set of locally-built provider plugins together 49 without further configuration. 50 51 For example, to download both Terraform and the `template` provider into 52 `GOPATH`: 53 54 ``` 55 $ go get github.com/hashicorp/terraform 56 $ go get github.com/terraform-providers/terraform-provider-template 57 ``` 58 59 These two packages are both "main" packages that can be built into separate 60 executables with `go install`: 61 62 ``` 63 $ go install github.com/hashicorp/terraform 64 $ go install github.com/terraform-providers/terraform-provider-template 65 ``` 66 67 After running the above commands, both Terraform core and the `template` 68 provider will both be installed in the current `GOPATH` and `$GOPATH/bin` 69 will contain both `terraform` and `terraform-provider-template` executables. 70 This `terraform` executable will find and use the `template` provider plugin 71 alongside it in the `bin` directory in preference to downloading and installing 72 an official release. 73 74 When constructing a new provider from scratch, it's recommended to follow 75 a similar repository structure as for the existing providers, with the main 76 package in the repository root and a library package in a subdirectory named 77 after the provider. For more information, see 78 [the custom providers guide](/guides/writing-custom-terraform-providers.html). 79 80 When making changes only to files within the provider repository, it is _not_ 81 necessary to re-build the main Terraform executable. Note that some packages 82 from the Terraform repository are used as library dependencies by providers, 83 such as `github.com/hashicorp/terraform/helper/schema`; it is recommended to 84 use `govendor` to create a local vendor copy of the relevant packages in the 85 provider repository, as can be seen in the repositories within the 86 `terraform-providers` GitHub organization. 87 88 ## Low-Level Interface 89 90 The interface you must implement for providers is 91 [ResourceProvider](https://github.com/hashicorp/terraform/blob/master/terraform/resource_provider.go). 92 93 This interface is extremely low level, however, and we don't recommend 94 you implement it directly. Implementing the interface directly is error 95 prone, complicated, and difficult. 96 97 Instead, we've developed some higher level libraries to help you out 98 with developing providers. These are the same libraries we use in our 99 own core providers. 100 101 ## helper/schema 102 103 The `helper/schema` library is a framework we've built to make creating 104 providers extremely easy. This is the same library we use to build most 105 of the core providers. 106 107 To give you an idea of how productive you can become with this framework: 108 we implemented the Google Cloud provider in about 6 hours of coding work. 109 This isn't a simple provider, and we did have knowledge of 110 the framework beforehand, but it goes to show how expressive the framework 111 can be. 112 113 The GoDoc for `helper/schema` can be 114 [found here](https://godoc.org/github.com/hashicorp/terraform/helper/schema). 115 This is API-level documentation but will be extremely important 116 for you going forward. 117 118 ## Provider 119 120 The first thing to do in your plugin is to create the 121 [schema.Provider](https://godoc.org/github.com/hashicorp/terraform/helper/schema#Provider) structure. 122 This structure implements the `ResourceProvider` interface. We 123 recommend creating this structure in a function to make testing easier 124 later. Example: 125 126 ```golang 127 func Provider() *schema.Provider { 128 return &schema.Provider{ 129 ... 130 } 131 } 132 ``` 133 134 Within the `schema.Provider`, you should initialize all the fields. They 135 are documented within the godoc, but a brief overview is here as well: 136 137 * `Schema` - This is the configuration schema for the provider itself. 138 You should define any API keys, etc. here. Schemas are covered below. 139 140 * `ResourcesMap` - The map of resources that this provider supports. 141 All keys are resource names and the values are the 142 [schema.Resource](https://godoc.org/github.com/hashicorp/terraform/helper/schema#Resource) structures implementing this resource. 143 144 * `ConfigureFunc` - This function callback is used to configure the 145 provider. This function should do things such as initialize any API 146 clients, validate API keys, etc. The `interface{}` return value of 147 this function is the `meta` parameter that will be passed into all 148 resource [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) 149 functions. In general, the returned value is a configuration structure 150 or a client. 151 152 As part of the unit tests, you should call `InternalValidate`. This is used 153 to verify the structure of the provider and all of the resources, and reports 154 an error if it is invalid. An example test is shown below: 155 156 ```golang 157 func TestProvider(t *testing.T) { 158 if err := Provider().(*schema.Provider).InternalValidate(); err != nil { 159 t.Fatalf("err: %s", err) 160 } 161 } 162 ``` 163 164 Having this unit test will catch a lot of beginner mistakes as you build 165 your provider. 166 167 ## Resources 168 169 Next, you'll want to create the resources that the provider can manage. 170 These resources are put into the `ResourcesMap` field of the provider 171 structure. Again, we recommend creating functions to instantiate these. 172 An example is shown below. 173 174 ```golang 175 func resourceComputeAddress() *schema.Resource { 176 return &schema.Resource { 177 ... 178 } 179 } 180 ``` 181 182 Resources are described using the 183 [schema.Resource](https://godoc.org/github.com/hashicorp/terraform/helper/schema#Resource) 184 structure. This structure has the following fields: 185 186 * `Schema` - The configuration schema for this resource. Schemas are 187 covered in more detail below. 188 189 * `Create`, `Read`, `Update`, and `Delete` - These are the callback 190 functions that implement CRUD operations for the resource. The only 191 optional field is `Update`. If your resource doesn't support update, then 192 you may keep that field nil. 193 194 * `Importer` - If this is non-nil, then this resource is 195 [importable](/docs/import/importability.html). It is recommended to 196 implement this. 197 198 The CRUD operations in more detail, along with their contracts: 199 200 * `Create` - This is called to create a new instance of the resource. 201 Terraform guarantees that an existing ID is not set on the resource 202 data. That is, you're working with a new resource. Therefore, you are 203 responsible for calling `SetId` on your `schema.ResourceData` using a 204 value suitable for your resource. This ensures whatever resource 205 state you set on `schema.ResourceData` will be persisted in local state. 206 If you neglect to `SetId`, no resource state will be persisted. 207 208 * `Read` - This is called to resync the local state with the remote state. 209 Terraform guarantees that an existing ID will be set. This ID should be 210 used to look up the resource. Any remote data should be updated into 211 the local data. **No changes to the remote resource are to be made.** 212 213 * `Update` - This is called to update properties of an existing resource. 214 Terraform guarantees that an existing ID will be set. Additionally, 215 the only changed attributes are guaranteed to be those that support 216 update, as specified by the schema. Be careful to read about partial 217 states below. 218 219 * `Delete` - This is called to delete the resource. Terraform guarantees 220 an existing ID will be set. 221 222 * `Exists` - This is called to verify a resource still exists. It is 223 called prior to `Read`, and lowers the burden of `Read` to be able 224 to assume the resource exists. If the resource is no longer present in 225 remote state, calling `SetId` with an empty string will signal its removal. 226 227 ## Schemas 228 229 Both providers and resources require a schema to be specified. The schema 230 is used to define the structure of the configuration, the types, etc. It is 231 very important to get correct. 232 233 In both provider and resource, the schema is a `map[string]*schema.Schema`. 234 The key of this map is the configuration key, and the value is a schema for 235 the value of that key. 236 237 Schemas are incredibly powerful, so this documentation page won't attempt 238 to cover the full power of them. Instead, the API docs should be referenced 239 which cover all available settings. 240 241 We recommend viewing schemas of existing or similar providers to learn 242 best practices. A good starting place is the 243 [core Terraform providers](https://github.com/hashicorp/terraform/tree/master/builtin/providers). 244 245 ## Resource Data 246 247 The parameter to provider configuration as well as all the CRUD operations 248 on a resource is a 249 [schema.ResourceData](https://godoc.org/github.com/hashicorp/terraform/helper/schema#ResourceData). 250 This structure is used to query configurations as well as to set information 251 about the resource such as its ID, connection information, and computed 252 attributes. 253 254 The API documentation covers ResourceData well, as well as the core providers 255 in Terraform. 256 257 **Partial state** deserves a special mention. Occasionally in Terraform, create or 258 update operations are not atomic; they can fail halfway through. As an example, 259 when creating an AWS security group, creating the group may succeed, 260 but creating all the initial rules may fail. In this case, it is incredibly 261 important that Terraform record the correct _partial state_ so that a 262 subsequent `terraform apply` fixes this resource. 263 264 Most of the time, partial state is not required. When it is, it must be 265 specifically enabled. An example is shown below: 266 267 ```golang 268 func resourceUpdate(d *schema.ResourceData, meta interface{}) error { 269 // Enable partial state mode 270 d.Partial(true) 271 272 if d.HasChange("tags") { 273 // If an error occurs, return with an error, 274 // we didn't finish updating 275 if err := updateTags(d, meta); err != nil { 276 return err 277 } 278 279 d.SetPartial("tags") 280 } 281 282 if d.HasChange("name") { 283 if err := updateName(d, meta); err != nil { 284 return err 285 } 286 287 d.SetPartial("name") 288 } 289 290 // We succeeded, disable partial mode 291 d.Partial(false) 292 293 return nil 294 } 295 ``` 296 297 In the example above, it is possible that setting the `tags` succeeds, 298 but setting the `name` fails. In this scenario, we want to make sure 299 that only the state of the `tags` is updated. To do this the 300 `Partial` and `SetPartial` functions are used. 301 302 `Partial` toggles partial-state mode. When disabled, all changes are merged 303 into the state upon result of the operation. When enabled, only changes 304 enabled with `SetPartial` are merged in. 305 306 `SetPartial` tells Terraform what state changes to adopt upon completion 307 of an operation. You should call `SetPartial` with every key that is safe 308 to merge into the state. The parameter to `SetPartial` is a prefix, so 309 if you have a nested structure and want to accept the whole thing, 310 you can just specify the prefix.