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.