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