website: CLI: Remove several ghost pages, update old links
- /docs/plugins/* - /docs/commands/state/addressing.html These were redundant pages.
This commit is contained in:
parent
a60120477c
commit
33d2d9abb5
|
@ -25,7 +25,7 @@ within modules are listed last.
|
|||
|
||||
For complex infrastructures, the state can contain thousands of resources.
|
||||
To filter these, provide one or more patterns to the command. Patterns are
|
||||
in [resource addressing format](/docs/commands/state/addressing.html).
|
||||
in [resource addressing format](/docs/cli/state/resource-addressing.html).
|
||||
|
||||
The command-line flags are all optional. The list of available flags are:
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ for each state file.
|
|||
|
||||
This command requires a source and destination address of the item to move.
|
||||
Addresses are
|
||||
in [resource addressing format](/docs/commands/state/addressing.html).
|
||||
in [resource addressing format](/docs/cli/state/resource-addressing.html).
|
||||
|
||||
The command-line flags are all optional. The list of available flags are:
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ of this command, backups are required.
|
|||
|
||||
This command requires one or more addresses that point to a resources in the
|
||||
state. Addresses are
|
||||
in [resource addressing format](/docs/commands/state/addressing.html).
|
||||
in [resource addressing format](/docs/cli/state/resource-addressing.html).
|
||||
|
||||
The command-line flags are all optional. The list of available flags are:
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ state file that matches the given address.
|
|||
|
||||
This command requires an address that points to a single resource in the
|
||||
state. Addresses are
|
||||
in [resource addressing format](/docs/commands/state/addressing.html).
|
||||
in [resource addressing format](/docs/cli/state/resource-addressing.html).
|
||||
|
||||
The command-line flags are all optional. The list of available flags are:
|
||||
|
||||
|
|
|
@ -20,5 +20,5 @@ Converting a resource to be importable is also relatively simple, so if
|
|||
you're interested in contributing that functionality, the Terraform team
|
||||
would be grateful.
|
||||
|
||||
To make a resource importable, please see the
|
||||
[plugin documentation on writing a resource](/docs/plugins/provider.html).
|
||||
To make a resource importable, please see
|
||||
[Extending Terraform: Resources — Import](/docs/extend/resources/import.html).
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
---
|
||||
layout: "docs"
|
||||
page_title: "Command: state resource addressing"
|
||||
sidebar_current: "docs-commands-state-address"
|
||||
description: |-
|
||||
The `terraform state` command is used for advanced state management.
|
||||
---
|
||||
|
||||
# Resource Addressing
|
||||
|
||||
The `terraform state` subcommands use
|
||||
[standard address syntax](/docs/cli/state/resource-addressing.html) to refer
|
||||
to individual resources, resource instances, and modules. This is the same
|
||||
syntax used for the `-target` option to the `apply` and `plan` commands.
|
||||
|
||||
Most state commands allow referring to individual resource instances, whole
|
||||
resources (which may have multiple instances if `count` or `for_each` is used),
|
||||
or even whole modules.
|
||||
|
||||
For more information on the syntax, see [Resource Addressing](/docs/cli/state/resource-addressing.html).
|
|
@ -1,98 +0,0 @@
|
|||
---
|
||||
layout: "extend"
|
||||
page_title: "Plugin Basics"
|
||||
sidebar_current: "docs-plugins-basics"
|
||||
description: |-
|
||||
This page documents the basics of how the plugin system in Terraform works, and how to setup a basic development environment for plugin development if you're writing a Terraform plugin.
|
||||
---
|
||||
|
||||
# Plugin Basics
|
||||
|
||||
~> **Advanced topic!** Plugin development is a highly advanced
|
||||
topic in Terraform, and is not required knowledge for day-to-day usage.
|
||||
If you don't plan on writing any plugins, this section of the documentation is
|
||||
not necessary to read. For general use of Terraform, please see
|
||||
[Intro to Terraform](/intro/index.html) or the
|
||||
[Terraform: Get Started](https://learn.hashicorp.com/collections/terraform/aws-get-started?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS)
|
||||
collection on HashiCorp Learn.
|
||||
|
||||
This page documents the basics of how the plugin system in Terraform
|
||||
works, and how to setup a basic development environment for plugin development
|
||||
if you're writing a Terraform plugin.
|
||||
|
||||
## How it Works
|
||||
|
||||
Terraform providers and provisioners are provided via plugins. Each plugin
|
||||
exposes an implementation for a specific service, such as AWS, or provisioner,
|
||||
such as bash. Plugins are executed as a separate process and communicate with
|
||||
the main Terraform binary over an RPC interface.
|
||||
|
||||
The code within the binaries must adhere to certain interfaces.
|
||||
The network communication and RPC is handled automatically by higher-level
|
||||
Terraform libraries. The exact interface to implement is documented
|
||||
in its respective documentation section.
|
||||
|
||||
## Installing Plugins
|
||||
|
||||
The [provider plugins distributed by HashiCorp](/docs/providers/index.html) are
|
||||
automatically installed by `terraform init`. Third-party plugins (both
|
||||
providers and provisioners) can be manually installed into the user plugins
|
||||
directory, located at `%APPDATA%\terraform.d\plugins` on Windows and
|
||||
`~/.terraform.d/plugins` on other systems.
|
||||
|
||||
For more information, see:
|
||||
|
||||
- [Configuring Providers](/docs/language/providers/configuration.html)
|
||||
|
||||
For developer-centric documentation, see:
|
||||
|
||||
- [How Terraform Works: Plugin Discovery](/docs/extend/how-terraform-works.html#discovery)
|
||||
|
||||
## Developing a Plugin
|
||||
|
||||
Developing a plugin is simple. The only knowledge necessary to write
|
||||
a plugin is basic command-line skills and basic knowledge of the
|
||||
[Go programming language](http://golang.org).
|
||||
|
||||
-> **Note:** A common pitfall is not properly setting up a
|
||||
<code>$GOPATH</code>. This can lead to strange errors. You can read more about
|
||||
this [here](https://golang.org/doc/code.html) to familiarize
|
||||
yourself.
|
||||
|
||||
Create a new Go project somewhere in your `$GOPATH`. If you're a
|
||||
GitHub user, we recommend creating the project in the directory
|
||||
`$GOPATH/src/github.com/USERNAME/terraform-NAME`, where `USERNAME`
|
||||
is your GitHub username and `NAME` is the name of the plugin you're
|
||||
developing. This structure is what Go expects and simplifies things down
|
||||
the road.
|
||||
|
||||
The `NAME` should either begin with `provider-` or `provisioner-`,
|
||||
depending on what kind of plugin it will be. The repository name will,
|
||||
by default, be the name of the binary produced by `go install` for
|
||||
your plugin package.
|
||||
|
||||
With the package directory made, create a `main.go` file. This project will
|
||||
be a binary so the package is "main":
|
||||
|
||||
```golang
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/plugin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
plugin.Serve(new(MyPlugin))
|
||||
}
|
||||
```
|
||||
|
||||
The name `MyPlugin` is a placeholder for the struct type that represents
|
||||
your plugin's implementation. This must implement either
|
||||
`terraform.ResourceProvider` or `terraform.ResourceProvisioner`, depending
|
||||
on the plugin type.
|
||||
|
||||
To test your plugin, the easiest method is to copy your `terraform` binary
|
||||
to `$GOPATH/bin` and ensure that this copy is the one being used for testing.
|
||||
`terraform init` will search for plugins within the same directory as the
|
||||
`terraform` binary, and `$GOPATH/bin` is the directory into which `go install`
|
||||
will place the plugin executable.
|
|
@ -1,24 +0,0 @@
|
|||
---
|
||||
layout: "extend"
|
||||
page_title: "Plugins"
|
||||
sidebar_current: "docs-plugins"
|
||||
description: |-
|
||||
Terraform is built on a plugin-based architecture. All providers and provisioners that are used in Terraform configurations are plugins, even the core types such as AWS and Heroku. Users of Terraform are able to write new plugins in order to support new functionality in Terraform.
|
||||
---
|
||||
|
||||
# Plugins
|
||||
|
||||
Terraform is built on a plugin-based architecture. All providers and
|
||||
provisioners that are used in Terraform configurations are plugins, even
|
||||
the core types such as AWS and Heroku. Users of Terraform are able to
|
||||
write new plugins in order to support new functionality in Terraform.
|
||||
|
||||
This section of the documentation gives a high-level overview of how
|
||||
to write plugins for Terraform. It does not hold your hand through the
|
||||
process, however, and expects a relatively high level of understanding
|
||||
of Go, provider semantics, Unix, etc.
|
||||
|
||||
~> **Advanced topic!** Plugin development is a highly advanced
|
||||
topic in Terraform, and is not required knowledge for day-to-day usage.
|
||||
If you don't plan on writing any plugins, we recommend not reading
|
||||
this section of the documentation.
|
|
@ -1,308 +0,0 @@
|
|||
---
|
||||
layout: "extend"
|
||||
page_title: "Provider Plugins"
|
||||
sidebar_current: "docs-plugins-provider"
|
||||
description: |-
|
||||
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.
|
||||
---
|
||||
|
||||
# Provider Plugins
|
||||
|
||||
~> **Advanced topic!** Plugin development is a highly advanced
|
||||
topic in Terraform, and is not required knowledge for day-to-day usage.
|
||||
If you don't plan on writing any plugins, this section of the documentation is
|
||||
not necessary to read. For general use of Terraform, please see
|
||||
[Intro to Terraform](/intro/index.html) or the
|
||||
[Terraform: Get Started](https://learn.hashicorp.com/collections/terraform/aws-get-started?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS)
|
||||
collection on HashiCorp Learn.
|
||||
|
||||
> **Hands-on:** Try the [Call APIs with Terraform Providers](https://learn.hashicorp.com/collections/terraform/providers?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) collection on HashiCorp Learn.
|
||||
|
||||
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.
|
||||
|
||||
The primary reasons to care about provider plugins are:
|
||||
|
||||
* You want to add a new resource type to an existing provider.
|
||||
|
||||
* You want to write a completely new provider for managing resource
|
||||
types in a system not yet supported.
|
||||
|
||||
* You want to write a completely new provider for custom, internal
|
||||
systems such as a private inventory management system.
|
||||
|
||||
If you're interested in provider development, then read on. The remainder
|
||||
of this page will assume you're familiar with
|
||||
[plugin basics](/docs/plugins/basics.html) and that you already have
|
||||
a basic development environment setup.
|
||||
|
||||
## Provider Plugin Codebases
|
||||
|
||||
Provider plugins live outside of the Terraform core codebase in their own
|
||||
source code repositories, and are typically published in a provider registry
|
||||
such as [the public Terraform Registry](https://registry.terraform.io/).
|
||||
|
||||
When developing a provider plugin, it is recommended to use a common `GOPATH`
|
||||
that includes both the core Terraform repository and the repositories of any
|
||||
providers being changed. This makes it easier to use a locally-built
|
||||
`terraform` executable and a set of locally-built provider plugins together
|
||||
without further configuration.
|
||||
|
||||
For example, to download both Terraform and the `template` provider into
|
||||
`GOPATH`:
|
||||
|
||||
```
|
||||
$ go get github.com/hashicorp/terraform
|
||||
$ go get github.com/terraform-providers/terraform-provider-template
|
||||
```
|
||||
|
||||
These two packages are both "main" packages that can be built into separate
|
||||
executables with `go install`:
|
||||
|
||||
```
|
||||
$ go install github.com/hashicorp/terraform
|
||||
$ go install github.com/terraform-providers/terraform-provider-template
|
||||
```
|
||||
|
||||
After running the above commands, both Terraform core and the `template`
|
||||
provider will both be installed in the current `GOPATH` and `$GOPATH/bin`
|
||||
will contain both `terraform` and `terraform-provider-template` executables.
|
||||
This `terraform` executable will find and use the `template` provider plugin
|
||||
alongside it in the `bin` directory in preference to downloading and installing
|
||||
an official release.
|
||||
|
||||
When constructing a new provider from scratch, it's recommended to follow
|
||||
a similar repository structure as for the existing providers, with the main
|
||||
package in the repository root and a library package in a subdirectory named
|
||||
after the provider. For more information, see the
|
||||
[Call APIs with Terraform Providers](https://learn.hashicorp.com/collections/terraform/providers?utm_source=WEBSITE/docs/extend/writing-custom-providers.htmlutm_medium=WEB_IO/docs/extend/writing-custom-providers.htmlutm_offer=ARTICLE_PAGE/docs/extend/writing-custom-providers.htmlutm_content=DOCS) collection on HashiCorp Learn.
|
||||
|
||||
When making changes only to files within the provider repository, it is _not_
|
||||
necessary to re-build the main Terraform executable. Note that some packages
|
||||
from the Terraform repository are used as library dependencies by providers,
|
||||
such as `github.com/hashicorp/terraform/helper/schema`; it is recommended to
|
||||
use `govendor` to create a local vendor copy of the relevant packages in the
|
||||
provider repository, as can be seen in the repositories within the
|
||||
`terraform-providers` GitHub organization.
|
||||
|
||||
## Low-Level Interface
|
||||
|
||||
The interface you must implement for providers is
|
||||
[ResourceProvider](https://github.com/hashicorp/terraform/blob/master/terraform/resource_provider.go).
|
||||
|
||||
This interface is extremely low level, however, and we don't recommend
|
||||
you implement it directly. Implementing the interface directly is error
|
||||
prone, complicated, and difficult.
|
||||
|
||||
Instead, we've developed some higher level libraries to help you out
|
||||
with developing providers. These are the same libraries we use in our
|
||||
own core providers.
|
||||
|
||||
## helper/schema
|
||||
|
||||
The `helper/schema` package in the plugin SDK is a framework designed to allow
|
||||
building providers at a higher level of abstraction than the raw plugin protocol
|
||||
that Terraform expects. This is the same library we've used to build most
|
||||
of the official providers.
|
||||
|
||||
For more information on `helper/schema`, see
|
||||
[the `helper/schema` package reference documentation](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-sdk/helper/schema).
|
||||
|
||||
## Provider
|
||||
|
||||
The first thing to do in your plugin is to create the
|
||||
[schema.Provider](https://godoc.org/github.com/hashicorp/terraform/helper/schema#Provider) structure.
|
||||
This structure implements the `ResourceProvider` interface. We
|
||||
recommend creating this structure in a function to make testing easier
|
||||
later. Example:
|
||||
|
||||
```golang
|
||||
func Provider() *schema.Provider {
|
||||
return &schema.Provider{
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Within the `schema.Provider`, you should initialize all the fields. They
|
||||
are documented within the godoc, but a brief overview is here as well:
|
||||
|
||||
* `Schema` - This is the configuration schema for the provider itself.
|
||||
You should define any API keys, etc. here. Schemas are covered below.
|
||||
|
||||
* `ResourcesMap` - The map of resources that this provider supports.
|
||||
All keys are resource names and the values are the
|
||||
[schema.Resource](https://godoc.org/github.com/hashicorp/terraform/helper/schema#Resource) structures implementing this resource.
|
||||
|
||||
* `ConfigureFunc` - This function callback is used to configure the
|
||||
provider. This function should do things such as initialize any API
|
||||
clients, validate API keys, etc. The `interface{}` return value of
|
||||
this function is the `meta` parameter that will be passed into all
|
||||
resource [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete)
|
||||
functions. In general, the returned value is a configuration structure
|
||||
or a client.
|
||||
|
||||
As part of the unit tests, you should call `InternalValidate`. This is used
|
||||
to verify the structure of the provider and all of the resources, and reports
|
||||
an error if it is invalid. An example test is shown below:
|
||||
|
||||
```golang
|
||||
func TestProvider(t *testing.T) {
|
||||
if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Having this unit test will catch a lot of beginner mistakes as you build
|
||||
your provider.
|
||||
|
||||
## Resources
|
||||
|
||||
Next, you'll want to create the resources that the provider can manage.
|
||||
These resources are put into the `ResourcesMap` field of the provider
|
||||
structure. Again, we recommend creating functions to instantiate these.
|
||||
An example is shown below.
|
||||
|
||||
```golang
|
||||
func resourceComputeAddress() *schema.Resource {
|
||||
return &schema.Resource {
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Resources are described using the
|
||||
[schema.Resource](https://godoc.org/github.com/hashicorp/terraform/helper/schema#Resource)
|
||||
structure. This structure has the following fields:
|
||||
|
||||
* `Schema` - The configuration schema for this resource. Schemas are
|
||||
covered in more detail below.
|
||||
|
||||
* `Create`, `Read`, `Update`, and `Delete` - These are the callback
|
||||
functions that implement CRUD operations for the resource. The only
|
||||
optional field is `Update`. If your resource doesn't support update, then
|
||||
you may keep that field nil.
|
||||
|
||||
* `Importer` - If this is non-nil, then this resource is
|
||||
[importable](/docs/cli/import/importability.html). It is recommended to
|
||||
implement this.
|
||||
|
||||
The CRUD operations in more detail, along with their contracts:
|
||||
|
||||
* `Create` - This is called to create a new instance of the resource.
|
||||
Terraform guarantees that an existing ID is not set on the resource
|
||||
data. That is, you're working with a new resource. Therefore, you are
|
||||
responsible for calling `SetId` on your `schema.ResourceData` using a
|
||||
value suitable for your resource. This ensures whatever resource
|
||||
state you set on `schema.ResourceData` will be persisted in local state.
|
||||
If you neglect to `SetId`, no resource state will be persisted.
|
||||
|
||||
* `Read` - This is called to resync the local state with the remote state.
|
||||
Terraform guarantees that an existing ID will be set. This ID should be
|
||||
used to look up the resource. Any remote data should be updated into
|
||||
the local data. **No changes to the remote resource are to be made.**
|
||||
If the resource is no longer present, calling `SetId`
|
||||
with an empty string will signal its removal.
|
||||
|
||||
* `Update` - This is called to update properties of an existing resource.
|
||||
Terraform guarantees that an existing ID will be set. Additionally,
|
||||
the only changed attributes are guaranteed to be those that support
|
||||
update, as specified by the schema. Be careful to read about partial
|
||||
states below.
|
||||
|
||||
* `Delete` - This is called to delete the resource. Terraform guarantees
|
||||
an existing ID will be set.
|
||||
|
||||
* `Exists` - This is called to verify a resource still exists. It is
|
||||
called prior to `Read`, and lowers the burden of `Read` to be able
|
||||
to assume the resource exists. `false` should be returned if
|
||||
the resources is no longer present, which has the same effect
|
||||
as calling `SetId("")` from `Read` (i.e. removal of the resource data
|
||||
from state).
|
||||
|
||||
## Schemas
|
||||
|
||||
Both providers and resources require a schema to be specified. The schema
|
||||
is used to define the structure of the configuration, the types, etc. It is
|
||||
very important to get correct.
|
||||
|
||||
In both provider and resource, the schema is a `map[string]*schema.Schema`.
|
||||
The key of this map is the configuration key, and the value is a schema for
|
||||
the value of that key.
|
||||
|
||||
Schemas are incredibly powerful, so this documentation page won't attempt
|
||||
to cover the full power of them. Instead, the API docs should be referenced
|
||||
which cover all available settings.
|
||||
|
||||
We recommend viewing schemas of existing or similar providers to learn
|
||||
best practices. A good starting place is the
|
||||
[core Terraform providers](https://github.com/terraform-providers).
|
||||
|
||||
## Resource Data
|
||||
|
||||
The parameter to provider configuration as well as all the CRUD operations
|
||||
on a resource is a
|
||||
[schema.ResourceData](https://godoc.org/github.com/hashicorp/terraform/helper/schema#ResourceData).
|
||||
This structure is used to query configurations as well as to set information
|
||||
about the resource such as its ID, connection information, and computed
|
||||
attributes.
|
||||
|
||||
The API documentation covers ResourceData well, as well as the core providers
|
||||
in Terraform.
|
||||
|
||||
**Partial state** deserves a special mention. Occasionally in Terraform, create or
|
||||
update operations are not atomic; they can fail halfway through. As an example,
|
||||
when creating an AWS security group, creating the group may succeed,
|
||||
but creating all the initial rules may fail. In this case, it is incredibly
|
||||
important that Terraform record the correct _partial state_ so that a
|
||||
subsequent `terraform apply` fixes this resource.
|
||||
|
||||
Most of the time, partial state is not required. When it is, it must be
|
||||
specifically enabled. An example is shown below:
|
||||
|
||||
```golang
|
||||
func resourceUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
// Enable partial state mode
|
||||
d.Partial(true)
|
||||
|
||||
if d.HasChange("tags") {
|
||||
// If an error occurs, return with an error,
|
||||
// we didn't finish updating
|
||||
if err := updateTags(d, meta); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.SetPartial("tags")
|
||||
}
|
||||
|
||||
if d.HasChange("name") {
|
||||
if err := updateName(d, meta); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.SetPartial("name")
|
||||
}
|
||||
|
||||
// We succeeded, disable partial mode
|
||||
d.Partial(false)
|
||||
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
In the example above, it is possible that setting the `tags` succeeds,
|
||||
but setting the `name` fails. In this scenario, we want to make sure
|
||||
that only the state of the `tags` is updated. To do this the
|
||||
`Partial` and `SetPartial` functions are used.
|
||||
|
||||
`Partial` toggles partial-state mode. When disabled, all changes are merged
|
||||
into the state upon result of the operation. When enabled, only changes
|
||||
enabled with `SetPartial` are merged in.
|
||||
|
||||
`SetPartial` tells Terraform what state changes to adopt upon completion
|
||||
of an operation. You should call `SetPartial` with every key that is safe
|
||||
to merge into the state. The parameter to `SetPartial` is a prefix, so
|
||||
if you have a nested structure and want to accept the whole thing,
|
||||
you can just specify the prefix.
|
Loading…
Reference in New Issue