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.