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"
|
||||
kubernetesprovider "github.com/hashicorp/terraform/builtin/providers/kubernetes"
|
||||
libratoprovider "github.com/hashicorp/terraform/builtin/providers/librato"
|
||||
localprovider "github.com/hashicorp/terraform/builtin/providers/local"
|
||||
logentriesprovider "github.com/hashicorp/terraform/builtin/providers/logentries"
|
||||
mailgunprovider "github.com/hashicorp/terraform/builtin/providers/mailgun"
|
||||
mysqlprovider "github.com/hashicorp/terraform/builtin/providers/mysql"
|
||||
|
@ -115,6 +116,7 @@ var InternalProviders = map[string]plugin.ProviderFunc{
|
|||
"influxdb": influxdbprovider.Provider,
|
||||
"kubernetes": kubernetesprovider.Provider,
|
||||
"librato": libratoprovider.Provider,
|
||||
"local": localprovider.Provider,
|
||||
"logentries": logentriesprovider.Provider,
|
||||
"mailgun": mailgunprovider.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>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-providers-local") %>>
|
||||
<a href="/docs/providers/local/index.html">Local</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-providers-logentries") %>>
|
||||
<a href="/docs/providers/logentries/index.html">Logentries</a>
|
||||
</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