Skip to content

Commit

Permalink
website: documentation for the "external" provider
Browse files Browse the repository at this point in the history
  • Loading branch information
apparentlymart committed Sep 11, 2016
1 parent a64bfaf commit f5d9e7f
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 0 deletions.
1 change: 1 addition & 0 deletions website/source/assets/stylesheets/_docs.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ body.layout-dme,
body.layout-dnsimple,
body.layout-docker,
body.layout-dyn,
body.layout-external,
body.layout-github,
body.layout-grafana,
body.layout-fastly,
Expand Down
111 changes: 111 additions & 0 deletions website/source/docs/providers/external/data_source.html.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
layout: "external"
page_title: "External Data Source"
sidebar_current: "docs-external-data-source"
description: |-
Executes an external program that implements a data source.
---

# External Data Source

The `external` data source allows an external program implementing a specific
protocol (defined below) to act as a data source, exposing arbitrary
data for use elsewhere in the Terraform configuration.

~> **Warning** This mechanism is provided as an "escape hatch" for exceptional
situations where a first-class Terraform provider is not more appropriate.
Its capabilities are limited in comparison to a true data source, and
implementing a data source via an external program is likely to hurt the
portability of your Terraform configuration by creating dependencies on
external programs and libraries that may not be available (or may need to
be used differently) on different operating systems.

## Example Usage

```
data "external" "example" {
program = ["python", "${path.module}/example-data-source.py"]
query = {
# arbitrary map from strings to strings, passed
# to the external program as the data query.
id = "abc123"
}
}
```

## External Program Protocol

The external program described by the `program` attribute must implement a
specific protocol for interacting with Terraform, as follows.

The program must read all of the data passed to it on `stdin`, and parse
it as a JSON object. The JSON object contains the contents of the `query`
argument and its values will always be strings.

The program must then produce a valid JSON object on `stdout`, which will
be used to populate the `result` attribute exported to the rest of the
Terraform configuration. This JSON object must again have all of its
values as strings. On successful completion it must exit with status zero.

If the program encounters an error and is unable to produce a result, it
must print a human-readable error message (ideally a single line) to `stderr`
and exit with a non-zero status. Any data on `stdout` is ignored if the
program returns a non-zero status.

All environment variables visible to the Terraform process are passed through
to the child program.

Terraform expects a data source to have *no observable side-effects*, and will
re-run the program each time the state is refreshed.

## Argument Reference

The following arguments are supported:

* `program` - (Required) A list of strings, whose first element is the program
to run and whose subsequent elements are optional command line arguments
to the program. Terraform does not execute the program through a shell, so
it is not necessary to escape shell metacharacters nor add quotes around
arguments containing spaces.

* `query` - (Optional) A map of string values to pass to the external program
as the query arguments. If not supplied, the program will recieve an empty
object as its input.

## Attributes Reference

The following attributes are exported:

* `result` - A map of string values returned from the external program.

## Processing JSON in shell scripts

Since the external data source protocol uses JSON, it is recommended to use
the utility [`jq`](https://stedolan.github.io/jq/) to translate to and from
JSON in a robust way when implementing a data source in a shell scripting
language.

The following example shows some input/output boilerplate code for a
data source implemented in bash:

```
#!/bin/bash
# Exit if any of the intermediate steps fail
set -e
# Extract "foo" and "baz" arguments from the input into
# FOO and BAZ shell variables.
# jq will ensure that the values are properly quoted
# and escaped for consumption by the shell.
eval "$(jq -r '@sh "FOO=\(.foo) BAZ=\(.baz)"')"
# Placeholder for whatever data-fetching logic your script implements
FOOBAZ="$FOO BAZ"
# Safely produce a JSON object containing the result value.
# jq will ensure that the value is properly quoted
# and escaped to produce a valid JSON string.
jq -n --arg foobaz "$FOOBAZ" '{"foobaz":$foobaz}'
```
23 changes: 23 additions & 0 deletions website/source/docs/providers/external/index.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
layout: "external"
page_title: "Provider: External"
sidebar_current: "docs-external-index"
description: |-
The external provider allows external scripts to be integrated with Terraform.
---

# External Provider

`external` is a special provider that exists to provide an interface
between Terraform and external programs.

Using this provider it is possible to write separate programs that can
participate in the Terraform workflow by implementing a specific protocol.

This provider is intended to be used for simple situations where you wish
to integrate Terraform with a system for which a first-class provider
doesn't exist. It is not as powerful as a first-class Terraform provider,
so users of this interface should carefully consider the implications
described on each of the child documentation pages (available from the
navigation bar) for each type of object this provider supports.

4 changes: 4 additions & 0 deletions website/source/layouts/docs.erb
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@
<a href="/docs/providers/dyn/index.html">Dyn</a>
</li>

<li<%= sidebar_current("docs-providers-external") %>>
<a href="/docs/providers/external/index.html">External</a>
</li>

<li<%= sidebar_current("docs-providers-github") %>>
<a href="/docs/providers/github/index.html">GitHub</a>
</li>
Expand Down
25 changes: 25 additions & 0 deletions website/source/layouts/external.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<% wrap_layout :inner do %>
<% content_for :sidebar do %>
<div class="docs-sidebar hidden-print affix-top" role="complementary">
<ul class="nav docs-sidenav">
<li<%#= sidebar_current("docs-home") %>>
<a href="/docs/providers/index.html">&laquo; Documentation Home</a>
</li>

<li<%= sidebar_current("docs-external-index") %>>
<a href="/docs/providers/external/index.html">External Provider</a>
<ul class="nav nav-visible">
<li<%= sidebar_current("docs-external-data-source") %>>
<a href="/docs/providers/external/data_source.html">Data Source</a>
</li>
<li<%= sidebar_current("docs-external-resource") %>>
<a href="/docs/providers/external/resource.html">Resource</a>
</li>
</ul>
</li>
</ul>
</div>
<% end %>

<%= yield %>
<% end %>

0 comments on commit f5d9e7f

Please sign in to comment.