Merge #12757: local_file resource
This commit is contained in:
commit
d515c2efc4
|
@ -0,0 +1,12 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/terraform/builtin/providers/localfile"
|
||||||
|
"github.com/hashicorp/terraform/plugin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
plugin.Serve(&plugin.ServeOpts{
|
||||||
|
ProviderFunc: localfile.Provider,
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package local
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Provider() terraform.ResourceProvider {
|
||||||
|
return &schema.Provider{
|
||||||
|
Schema: map[string]*schema.Schema{},
|
||||||
|
ResourcesMap: map[string]*schema.Resource{
|
||||||
|
"local_file": resourceLocalFile(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package local
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
var testProviders = map[string]terraform.ResourceProvider{
|
||||||
|
"local": Provider(),
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProvider(t *testing.T) {
|
||||||
|
if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
package local
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/hex"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceLocalFile() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceLocalFileCreate,
|
||||||
|
Read: resourceLocalFileRead,
|
||||||
|
Delete: resourceLocalFileDelete,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"content": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"filename": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "Path to the output file",
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceLocalFileRead(d *schema.ResourceData, _ interface{}) error {
|
||||||
|
// If the output file doesn't exist, mark the resource for creation.
|
||||||
|
outputPath := d.Get("filename").(string)
|
||||||
|
if _, err := os.Stat(outputPath); os.IsNotExist(err) {
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that the content of the destination file matches the content we
|
||||||
|
// expect. Otherwise, the file might have been modified externally and we
|
||||||
|
// must reconcile.
|
||||||
|
outputContent, err := ioutil.ReadFile(outputPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
outputChecksum := sha1.Sum([]byte(outputContent))
|
||||||
|
if hex.EncodeToString(outputChecksum[:]) != d.Id() {
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceLocalFileCreate(d *schema.ResourceData, _ interface{}) error {
|
||||||
|
content := d.Get("content").(string)
|
||||||
|
destination := d.Get("filename").(string)
|
||||||
|
|
||||||
|
destinationDir := path.Dir(destination)
|
||||||
|
if _, err := os.Stat(destinationDir); err != nil {
|
||||||
|
if err := os.MkdirAll(destinationDir, 0777); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile(destination, []byte(content), 0777); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
checksum := sha1.Sum([]byte(content))
|
||||||
|
d.SetId(hex.EncodeToString(checksum[:]))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceLocalFileDelete(d *schema.ResourceData, _ interface{}) error {
|
||||||
|
os.Remove(d.Get("filename").(string))
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package local
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
r "github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLocalFile_Basic(t *testing.T) {
|
||||||
|
var cases = []struct {
|
||||||
|
path string
|
||||||
|
content string
|
||||||
|
config string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"local_file",
|
||||||
|
"This is some content",
|
||||||
|
`resource "local_file" "file" {
|
||||||
|
content = "This is some content"
|
||||||
|
filename = "local_file"
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range cases {
|
||||||
|
r.UnitTest(t, r.TestCase{
|
||||||
|
Providers: testProviders,
|
||||||
|
Steps: []r.TestStep{
|
||||||
|
{
|
||||||
|
Config: tt.config,
|
||||||
|
Check: func(s *terraform.State) error {
|
||||||
|
content, err := ioutil.ReadFile(tt.path)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("config:\n%s\n,got: %s\n", tt.config, err)
|
||||||
|
}
|
||||||
|
if string(content) != tt.content {
|
||||||
|
return fmt.Errorf("config:\n%s\ngot:\n%s\nwant:\n%s\n", tt.config, content, tt.content)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CheckDestroy: func(*terraform.State) error {
|
||||||
|
if _, err := os.Stat(tt.path); os.IsNotExist(err) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("local_file did not get destroyed")
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,6 +39,7 @@ import (
|
||||||
influxdbprovider "github.com/hashicorp/terraform/builtin/providers/influxdb"
|
influxdbprovider "github.com/hashicorp/terraform/builtin/providers/influxdb"
|
||||||
kubernetesprovider "github.com/hashicorp/terraform/builtin/providers/kubernetes"
|
kubernetesprovider "github.com/hashicorp/terraform/builtin/providers/kubernetes"
|
||||||
libratoprovider "github.com/hashicorp/terraform/builtin/providers/librato"
|
libratoprovider "github.com/hashicorp/terraform/builtin/providers/librato"
|
||||||
|
localprovider "github.com/hashicorp/terraform/builtin/providers/local"
|
||||||
logentriesprovider "github.com/hashicorp/terraform/builtin/providers/logentries"
|
logentriesprovider "github.com/hashicorp/terraform/builtin/providers/logentries"
|
||||||
mailgunprovider "github.com/hashicorp/terraform/builtin/providers/mailgun"
|
mailgunprovider "github.com/hashicorp/terraform/builtin/providers/mailgun"
|
||||||
mysqlprovider "github.com/hashicorp/terraform/builtin/providers/mysql"
|
mysqlprovider "github.com/hashicorp/terraform/builtin/providers/mysql"
|
||||||
|
@ -115,6 +116,7 @@ var InternalProviders = map[string]plugin.ProviderFunc{
|
||||||
"influxdb": influxdbprovider.Provider,
|
"influxdb": influxdbprovider.Provider,
|
||||||
"kubernetes": kubernetesprovider.Provider,
|
"kubernetes": kubernetesprovider.Provider,
|
||||||
"librato": libratoprovider.Provider,
|
"librato": libratoprovider.Provider,
|
||||||
|
"local": localprovider.Provider,
|
||||||
"logentries": logentriesprovider.Provider,
|
"logentries": logentriesprovider.Provider,
|
||||||
"mailgun": mailgunprovider.Provider,
|
"mailgun": mailgunprovider.Provider,
|
||||||
"mysql": mysqlprovider.Provider,
|
"mysql": mysqlprovider.Provider,
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
layout: "local"
|
||||||
|
page_title: "Provider: Local"
|
||||||
|
sidebar_current: "docs-local-index"
|
||||||
|
description: |-
|
||||||
|
The Local provider is used to manage local resources, such as files.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Local Provider
|
||||||
|
|
||||||
|
The Local provider is used to manage local resources, such as files.
|
||||||
|
|
||||||
|
Use the navigation to the left to read about the available resources.
|
||||||
|
|
||||||
|
~> **Note** Terraform primarily deals with remote resources which are able
|
||||||
|
to outlive a single Terraform run, and so local resources can sometimes violate
|
||||||
|
its assumptions. The resources here are best used with care, since depending
|
||||||
|
on local state can make it hard to apply the same Terraform configuration on
|
||||||
|
many different local systems where the local resources may not be universally
|
||||||
|
available. See specific notes in each resource for more information.
|
|
@ -0,0 +1,37 @@
|
||||||
|
---
|
||||||
|
layout: "local"
|
||||||
|
page_title: "Local: local_file"
|
||||||
|
sidebar_current: "docs-local-resource-file"
|
||||||
|
description: |-
|
||||||
|
Generates a local file from content.
|
||||||
|
---
|
||||||
|
|
||||||
|
# local_file
|
||||||
|
|
||||||
|
Generates a local file with the given content.
|
||||||
|
|
||||||
|
~> **Note** When working with local files, Terraform will detect the resource
|
||||||
|
as having been deleted each time a configuration is applied on a new machine
|
||||||
|
where the file is not present and will generate a diff to re-create it. This
|
||||||
|
may cause "noise" in diffs in environments where configurations are routinely
|
||||||
|
applied by many different users or within automation systems.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
resource "local_file" "foo" {
|
||||||
|
content = "foo!"
|
||||||
|
filename = "${path.module}/foo.bar"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `content` - (Required) The content of file to create.
|
||||||
|
|
||||||
|
* `filename` - (Required) The path of the file to create.
|
||||||
|
|
||||||
|
Any required parent directories will be created automatically, and any existing
|
||||||
|
file with the given name will be overwritten.
|
|
@ -304,6 +304,10 @@
|
||||||
<a href="/docs/providers/librato/index.html">Librato</a>
|
<a href="/docs/providers/librato/index.html">Librato</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-providers-local") %>>
|
||||||
|
<a href="/docs/providers/local/index.html">Local</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li<%= sidebar_current("docs-providers-logentries") %>>
|
<li<%= sidebar_current("docs-providers-logentries") %>>
|
||||||
<a href="/docs/providers/logentries/index.html">Logentries</a>
|
<a href="/docs/providers/logentries/index.html">Logentries</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
<% wrap_layout :inner do %>
|
||||||
|
<% content_for :sidebar do %>
|
||||||
|
<ul class="nav docs-sidenav">
|
||||||
|
<li<%= sidebar_current("docs-home") %>>
|
||||||
|
<a href="/docs/providers/index.html">All Providers</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-local-index") %>>
|
||||||
|
<a href="/docs/providers/local/index.html">Local Provider</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-local-resource") %>>
|
||||||
|
<a href="#">Resources</a>
|
||||||
|
<ul class="nav nav-visible">
|
||||||
|
<li<%= sidebar_current("docs-local-resource-file") %>>
|
||||||
|
<a href="/docs/providers/local/r/file.html">file</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= yield %>
|
||||||
|
<% end %>
|
Loading…
Reference in New Issue