mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Merge pull request #7561 from hashicorp/jorgemarey-f-file-content
Cleanup of #3906
This commit is contained in:
commit
6084d732ae
@ -2,12 +2,12 @@ package file
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/communicator"
|
"github.com/hashicorp/terraform/communicator"
|
||||||
"github.com/hashicorp/terraform/helper/config"
|
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
"github.com/mitchellh/go-homedir"
|
"github.com/mitchellh/go-homedir"
|
||||||
)
|
)
|
||||||
@ -26,18 +26,16 @@ func (p *ResourceProvisioner) Apply(
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the source and destination
|
// Get the source
|
||||||
sRaw := c.Config["source"]
|
src, deleteSource, err := p.getSrc(c)
|
||||||
src, ok := sRaw.(string)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("Unsupported 'source' type! Must be string.")
|
|
||||||
}
|
|
||||||
|
|
||||||
src, err = homedir.Expand(src)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if deleteSource {
|
||||||
|
defer os.Remove(src)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get destination
|
||||||
dRaw := c.Config["destination"]
|
dRaw := c.Config["destination"]
|
||||||
dst, ok := dRaw.(string)
|
dst, ok := dRaw.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -48,13 +46,55 @@ func (p *ResourceProvisioner) Apply(
|
|||||||
|
|
||||||
// Validate checks if the required arguments are configured
|
// Validate checks if the required arguments are configured
|
||||||
func (p *ResourceProvisioner) Validate(c *terraform.ResourceConfig) (ws []string, es []error) {
|
func (p *ResourceProvisioner) Validate(c *terraform.ResourceConfig) (ws []string, es []error) {
|
||||||
v := &config.Validator{
|
numDst := 0
|
||||||
Required: []string{
|
numSrc := 0
|
||||||
"source",
|
for name := range c.Raw {
|
||||||
"destination",
|
switch name {
|
||||||
},
|
case "destination":
|
||||||
|
numDst++
|
||||||
|
case "source", "content":
|
||||||
|
numSrc++
|
||||||
|
default:
|
||||||
|
es = append(es, fmt.Errorf("Unknown configuration '%s'", name))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return v.Validate(c)
|
if numSrc != 1 || numDst != 1 {
|
||||||
|
es = append(es, fmt.Errorf("Must provide one of 'content' or 'source' and 'destination' to file"))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// getSrc returns the file to use as source
|
||||||
|
func (p *ResourceProvisioner) getSrc(c *terraform.ResourceConfig) (string, bool, error) {
|
||||||
|
var src string
|
||||||
|
|
||||||
|
sRaw, ok := c.Config["source"]
|
||||||
|
if ok {
|
||||||
|
if src, ok = sRaw.(string); !ok {
|
||||||
|
return "", false, fmt.Errorf("Unsupported 'source' type! Must be string.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
content, ok := c.Config["content"]
|
||||||
|
if ok {
|
||||||
|
file, err := ioutil.TempFile("", "tf-file-content")
|
||||||
|
if err != nil {
|
||||||
|
return "", true, err
|
||||||
|
}
|
||||||
|
|
||||||
|
contentStr, ok := content.(string)
|
||||||
|
if !ok {
|
||||||
|
return "", true, fmt.Errorf("Unsupported 'content' type! Must be string.")
|
||||||
|
}
|
||||||
|
if _, err = file.WriteString(contentStr); err != nil {
|
||||||
|
return "", true, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return file.Name(), true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
expansion, err := homedir.Expand(src)
|
||||||
|
return expansion, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// copyFiles is used to copy the files from a source to a destination
|
// copyFiles is used to copy the files from a source to a destination
|
||||||
|
@ -11,7 +11,7 @@ func TestResourceProvisioner_impl(t *testing.T) {
|
|||||||
var _ terraform.ResourceProvisioner = new(ResourceProvisioner)
|
var _ terraform.ResourceProvisioner = new(ResourceProvisioner)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResourceProvider_Validate_good(t *testing.T) {
|
func TestResourceProvider_Validate_good_source(t *testing.T) {
|
||||||
c := testConfig(t, map[string]interface{}{
|
c := testConfig(t, map[string]interface{}{
|
||||||
"source": "/tmp/foo",
|
"source": "/tmp/foo",
|
||||||
"destination": "/tmp/bar",
|
"destination": "/tmp/bar",
|
||||||
@ -26,7 +26,22 @@ func TestResourceProvider_Validate_good(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResourceProvider_Validate_bad(t *testing.T) {
|
func TestResourceProvider_Validate_good_content(t *testing.T) {
|
||||||
|
c := testConfig(t, map[string]interface{}{
|
||||||
|
"content": "value to copy",
|
||||||
|
"destination": "/tmp/bar",
|
||||||
|
})
|
||||||
|
p := new(ResourceProvisioner)
|
||||||
|
warn, errs := p.Validate(c)
|
||||||
|
if len(warn) > 0 {
|
||||||
|
t.Fatalf("Warnings: %v", warn)
|
||||||
|
}
|
||||||
|
if len(errs) > 0 {
|
||||||
|
t.Fatalf("Errors: %v", errs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResourceProvider_Validate_bad_not_destination(t *testing.T) {
|
||||||
c := testConfig(t, map[string]interface{}{
|
c := testConfig(t, map[string]interface{}{
|
||||||
"source": "nope",
|
"source": "nope",
|
||||||
})
|
})
|
||||||
@ -40,6 +55,22 @@ func TestResourceProvider_Validate_bad(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestResourceProvider_Validate_bad_to_many_src(t *testing.T) {
|
||||||
|
c := testConfig(t, map[string]interface{}{
|
||||||
|
"source": "nope",
|
||||||
|
"content": "value to copy",
|
||||||
|
"destination": "/tmp/bar",
|
||||||
|
})
|
||||||
|
p := new(ResourceProvisioner)
|
||||||
|
warn, errs := p.Validate(c)
|
||||||
|
if len(warn) > 0 {
|
||||||
|
t.Fatalf("Warnings: %v", warn)
|
||||||
|
}
|
||||||
|
if len(errs) == 0 {
|
||||||
|
t.Fatalf("Should have errors")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testConfig(
|
func testConfig(
|
||||||
t *testing.T,
|
t *testing.T,
|
||||||
c map[string]interface{}) *terraform.ResourceConfig {
|
c map[string]interface{}) *terraform.ResourceConfig {
|
||||||
|
@ -24,6 +24,12 @@ resource "aws_instance" "web" {
|
|||||||
destination = "/etc/myapp.conf"
|
destination = "/etc/myapp.conf"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Copies the string in content into /tmp/file.log
|
||||||
|
provisioner "file" {
|
||||||
|
content = "ami used: ${self.ami}"
|
||||||
|
destination = "/tmp/file.log"
|
||||||
|
}
|
||||||
|
|
||||||
# Copies the configs.d folder to /etc/configs.d
|
# Copies the configs.d folder to /etc/configs.d
|
||||||
provisioner "file" {
|
provisioner "file" {
|
||||||
source = "conf/configs.d"
|
source = "conf/configs.d"
|
||||||
@ -42,8 +48,14 @@ resource "aws_instance" "web" {
|
|||||||
|
|
||||||
The following arguments are supported:
|
The following arguments are supported:
|
||||||
|
|
||||||
* `source` - (Required) This is the source file or folder. It can be specified as relative
|
* `source` - This is the source file or folder. It can be specified as relative
|
||||||
to the current working directory or as an absolute path.
|
to the current working directory or as an absolute path. This cannot be provided with `content`.
|
||||||
|
|
||||||
|
* `content` - This is the content to copy on the destination. If destination is a file,
|
||||||
|
the content will be written on that file, in case of a directory a file named
|
||||||
|
*tf-file-content* is created. It's recommended to use a file as destination. A
|
||||||
|
[`template_file`](/docs/providers/template/r/file.html) might be referenced in here, or
|
||||||
|
any interpolation syntax for that matter. This cannot be provided with `source`.
|
||||||
|
|
||||||
* `destination` - (Required) This is the destination path. It must be specified as an
|
* `destination` - (Required) This is the destination path. It must be specified as an
|
||||||
absolute path.
|
absolute path.
|
||||||
|
Loading…
Reference in New Issue
Block a user