github.com/loicalbertin/terraform@v0.6.15-0.20170626182346-8e2583055467/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 ## Low-Level Interface 36 37 The interface you must implement for providers is 38 [ResourceProvider](https://github.com/hashicorp/terraform/blob/master/terraform/resource_provider.go). 39 40 This interface is extremely low level, however, and we don't recommend 41 you implement it directly. Implementing the interface directly is error 42 prone, complicated, and difficult. 43 44 Instead, we've developed some higher level libraries to help you out 45 with developing providers. These are the same libraries we use in our 46 own core providers. 47 48 ## helper/schema 49 50 The `helper/schema` library is a framework we've built to make creating 51 providers extremely easy. This is the same library we use to build most 52 of the core providers. 53 54 To give you an idea of how productive you can become with this framework: 55 we implemented the Google Cloud provider in about 6 hours of coding work. 56 This isn't a simple provider, and we did have knowledge of 57 the framework beforehand, but it goes to show how expressive the framework 58 can be. 59 60 The GoDoc for `helper/schema` can be 61 [found here](https://godoc.org/github.com/hashicorp/terraform/helper/schema). 62 This is API-level documentation but will be extremely important 63 for you going forward. 64 65 ## Provider 66 67 The first thing to do in your plugin is to create the 68 [schema.Provider](https://godoc.org/github.com/hashicorp/terraform/helper/schema#Provider) structure. 69 This structure implements the `ResourceProvider` interface. We 70 recommend creating this structure in a function to make testing easier 71 later. Example: 72 73 ```golang 74 func Provider() *schema.Provider { 75 return &schema.Provider{ 76 ... 77 } 78 } 79 ``` 80 81 Within the `schema.Provider`, you should initialize all the fields. They 82 are documented within the godoc, but a brief overview is here as well: 83 84 * `Schema` - This is the configuration schema for the provider itself. 85 You should define any API keys, etc. here. Schemas are covered below. 86 87 * `ResourcesMap` - The map of resources that this provider supports. 88 All keys are resource names and the values are the 89 [schema.Resource](https://godoc.org/github.com/hashicorp/terraform/helper/schema#Resource) structures implementing this resource. 90 91 * `ConfigureFunc` - This function callback is used to configure the 92 provider. This function should do things such as initialize any API 93 clients, validate API keys, etc. The `interface{}` return value of 94 this function is the `meta` parameter that will be passed into all 95 resource [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) 96 functions. In general, the returned value is a configuration structure 97 or a client. 98 99 As part of the unit tests, you should call `InternalValidate`. This is used 100 to verify the structure of the provider and all of the resources, and reports 101 an error if it is invalid. An example test is shown below: 102 103 ```golang 104 func TestProvider(t *testing.T) { 105 if err := Provider().(*schema.Provider).InternalValidate(); err != nil { 106 t.Fatalf("err: %s", err) 107 } 108 } 109 ``` 110 111 Having this unit test will catch a lot of beginner mistakes as you build 112 your provider. 113 114 ## Resources 115 116 Next, you'll want to create the resources that the provider can manage. 117 These resources are put into the `ResourcesMap` field of the provider 118 structure. Again, we recommend creating functions to instantiate these. 119 An example is shown below. 120 121 ```golang 122 func resourceComputeAddress() *schema.Resource { 123 return &schema.Resource { 124 ... 125 } 126 } 127 ``` 128 129 Resources are described using the 130 [schema.Resource](https://godoc.org/github.com/hashicorp/terraform/helper/schema#Resource) 131 structure. This structure has the following fields: 132 133 * `Schema` - The configuration schema for this resource. Schemas are 134 covered in more detail below. 135 136 * `Create`, `Read`, `Update`, and `Delete` - These are the callback 137 functions that implement CRUD operations for the resource. The only 138 optional field is `Update`. If your resource doesn't support update, then 139 you may keep that field nil. 140 141 * `Importer` - If this is non-nil, then this resource is 142 [importable](/docs/import/importability.html). It is recommended to 143 implement this. 144 145 The CRUD operations in more detail, along with their contracts: 146 147 * `Create` - This is called to create a new instance of the resource. 148 Terraform guarantees that an existing ID is not set on the resource 149 data. That is, you're working with a new resource. Therefore, you are 150 responsible for calling `SetId` on your `schema.ResourceData` using a 151 value suitable for your resource. This ensures whatever resource 152 state you set on `schema.ResourceData` will be persisted in local state. 153 If you neglect to `SetId`, no resource state will be persisted. 154 155 * `Read` - This is called to resync the local state with the remote state. 156 Terraform guarantees that an existing ID will be set. This ID should be 157 used to look up the resource. Any remote data should be updated into 158 the local data. **No changes to the remote resource are to be made.** 159 160 * `Update` - This is called to update properties of an existing resource. 161 Terraform guarantees that an existing ID will be set. Additionally, 162 the only changed attributes are guaranteed to be those that support 163 update, as specified by the schema. Be careful to read about partial 164 states below. 165 166 * `Delete` - This is called to delete the resource. Terraform guarantees 167 an existing ID will be set. 168 169 * `Exists` - This is called to verify a resource still exists. It is 170 called prior to `Read`, and lowers the burden of `Read` to be able 171 to assume the resource exists. If the resource is no longer present in 172 remote state, calling `SetId` with an empty string will signal its removal. 173 174 ## Schemas 175 176 Both providers and resources require a schema to be specified. The schema 177 is used to define the structure of the configuration, the types, etc. It is 178 very important to get correct. 179 180 In both provider and resource, the schema is a `map[string]*schema.Schema`. 181 The key of this map is the configuration key, and the value is a schema for 182 the value of that key. 183 184 Schemas are incredibly powerful, so this documentation page won't attempt 185 to cover the full power of them. Instead, the API docs should be referenced 186 which cover all available settings. 187 188 We recommend viewing schemas of existing or similar providers to learn 189 best practices. A good starting place is the 190 [core Terraform providers](https://github.com/hashicorp/terraform/tree/master/builtin/providers). 191 192 ## Resource Data 193 194 The parameter to provider configuration as well as all the CRUD operations 195 on a resource is a 196 [schema.ResourceData](https://godoc.org/github.com/hashicorp/terraform/helper/schema#ResourceData). 197 This structure is used to query configurations as well as to set information 198 about the resource such as its ID, connection information, and computed 199 attributes. 200 201 The API documentation covers ResourceData well, as well as the core providers 202 in Terraform. 203 204 **Partial state** deserves a special mention. Occasionally in Terraform, create or 205 update operations are not atomic; they can fail halfway through. As an example, 206 when creating an AWS security group, creating the group may succeed, 207 but creating all the initial rules may fail. In this case, it is incredibly 208 important that Terraform record the correct _partial state_ so that a 209 subsequent `terraform apply` fixes this resource. 210 211 Most of the time, partial state is not required. When it is, it must be 212 specifically enabled. An example is shown below: 213 214 ```golang 215 func resourceUpdate(d *schema.ResourceData, meta interface{}) error { 216 // Enable partial state mode 217 d.Partial(true) 218 219 if d.HasChange("tags") { 220 // If an error occurs, return with an error, 221 // we didn't finish updating 222 if err := updateTags(d, meta); err != nil { 223 return err 224 } 225 226 d.SetPartial("tags") 227 } 228 229 if d.HasChange("name") { 230 if err := updateName(d, meta); err != nil { 231 return err 232 } 233 234 d.SetPartial("name") 235 } 236 237 // We succeeded, disable partial mode 238 d.Partial(false) 239 240 return nil 241 } 242 ``` 243 244 In the example above, it is possible that setting the `tags` succeeds, 245 but setting the `name` fails. In this scenario, we want to make sure 246 that only the state of the `tags` is updated. To do this the 247 `Partial` and `SetPartial` functions are used. 248 249 `Partial` toggles partial-state mode. When disabled, all changes are merged 250 into the state upon result of the operation. When enabled, only changes 251 enabled with `SetPartial` are merged in. 252 253 `SetPartial` tells Terraform what state changes to adopt upon completion 254 of an operation. You should call `SetPartial` with every key that is safe 255 to merge into the state. The parameter to `SetPartial` is a prefix, so 256 if you have a nested structure and want to accept the whole thing, 257 you can just specify the prefix.