mirror of
https://github.com/kreuzwerker/terraform-provider-docker.git
synced 2026-01-03 05:19:34 -05:00
feat: allow use of source file instead of content / content_base64 (#240)
Closes #239 * Added a 'source' and 'source hash' which will reference a file / file hash to load into the container * Add to docs * Adding a test, cleaning up another one
This commit is contained in:
parent
5733f00a64
commit
5ad4646537
6 changed files with 198 additions and 8 deletions
|
|
@ -716,6 +716,16 @@ func resourceDockerContainer() *schema.Resource {
|
|||
ForceNew: true,
|
||||
Default: false,
|
||||
},
|
||||
"source": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"source_hash": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1473,6 +1483,16 @@ func resourceDockerContainerV1() *schema.Resource {
|
|||
ForceNew: true,
|
||||
Default: false,
|
||||
},
|
||||
"source": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"source_hash": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"sort"
|
||||
|
|
@ -385,12 +386,23 @@ func resourceDockerContainerCreate(d *schema.ResourceData, meta interface{}) err
|
|||
for _, upload := range v.(*schema.Set).List() {
|
||||
content := upload.(map[string]interface{})["content"].(string)
|
||||
contentBase64 := upload.(map[string]interface{})["content_base64"].(string)
|
||||
if content == "" && contentBase64 == "" {
|
||||
return fmt.Errorf("Error with upload content: neither 'content', nor 'content_base64' was set")
|
||||
source := upload.(map[string]interface{})["source"].(string)
|
||||
|
||||
testParams := []string{content, contentBase64, source}
|
||||
setParams := 0
|
||||
for _, v := range testParams {
|
||||
if v != "" {
|
||||
setParams++
|
||||
}
|
||||
}
|
||||
if content != "" && contentBase64 != "" {
|
||||
return fmt.Errorf("Error with upload content: only one of 'content' or 'content_base64' can be specified")
|
||||
|
||||
if setParams == 0 {
|
||||
return fmt.Errorf("error with upload content: one of 'content', 'content_base64', or 'source' must be set")
|
||||
}
|
||||
if setParams > 1 {
|
||||
return fmt.Errorf("error with upload content: only one of 'content', 'content_base64', or 'source' can be set")
|
||||
}
|
||||
|
||||
var contentToUpload string
|
||||
if content != "" {
|
||||
contentToUpload = content
|
||||
|
|
@ -399,6 +411,13 @@ func resourceDockerContainerCreate(d *schema.ResourceData, meta interface{}) err
|
|||
decoded, _ := base64.StdEncoding.DecodeString(contentBase64)
|
||||
contentToUpload = string(decoded)
|
||||
}
|
||||
if source != "" {
|
||||
sourceContent, err := ioutil.ReadFile(source)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not read file: %s", err)
|
||||
}
|
||||
contentToUpload = string(sourceContent)
|
||||
}
|
||||
file := upload.(map[string]interface{})["file"].(string)
|
||||
executable := upload.(map[string]interface{})["executable"].(bool)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"archive/tar"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
|
|
@ -658,6 +659,112 @@ func TestAccDockerContainer_upload(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccDockerContainer_uploadSource(t *testing.T) {
|
||||
var c types.ContainerJSON
|
||||
|
||||
wd, _ := os.Getwd()
|
||||
testFile := wd + "/../scripts/testing/testingFile"
|
||||
testFileContent, _ := ioutil.ReadFile(testFile)
|
||||
|
||||
testCheck := func(*terraform.State) error {
|
||||
client := testAccProvider.Meta().(*ProviderConfig).DockerClient
|
||||
|
||||
srcPath := "/terraform/test.txt"
|
||||
r, _, err := client.CopyFromContainer(context.Background(), c.ID, srcPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to download a file from container: %s", err)
|
||||
}
|
||||
|
||||
tr := tar.NewReader(r)
|
||||
if header, err := tr.Next(); err != nil {
|
||||
return fmt.Errorf("Unable to read content of tar archive: %s", err)
|
||||
} else {
|
||||
mode := strconv.FormatInt(header.Mode, 8)
|
||||
if !strings.HasSuffix(mode, "744") {
|
||||
return fmt.Errorf("File permissions are incorrect: %s", mode)
|
||||
}
|
||||
}
|
||||
|
||||
fbuf := new(bytes.Buffer)
|
||||
fbuf.ReadFrom(tr)
|
||||
content := fbuf.String()
|
||||
if content != string(testFileContent) {
|
||||
return fmt.Errorf("file content is invalid")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: fmt.Sprintf(testAccDockerContainerUploadSourceConfig, testFile),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccContainerRunning("docker_container.foo", &c),
|
||||
testCheck,
|
||||
resource.TestCheckResourceAttr("docker_container.foo", "name", "tf-test"),
|
||||
resource.TestCheckResourceAttr("docker_container.foo", "upload.#", "1"),
|
||||
// NOTE mavogel: current the terraform-plugin-sdk it's likely that
|
||||
// the acceptance testing framework shims (still using the older flatmap-style addressing)
|
||||
// are missing a conversion with the hashes.
|
||||
// See https://github.com/hashicorp/terraform-plugin-sdk/issues/196
|
||||
// resource.TestCheckResourceAttr("docker_container.foo", "upload.0.content", "foo"),
|
||||
// resource.TestCheckResourceAttr("docker_container.foo", "upload.0.content_base64", ""),
|
||||
// resource.TestCheckResourceAttr("docker_container.foo", "upload.0.executable", "true"),
|
||||
// resource.TestCheckResourceAttr("docker_container.foo", "upload.0.file", "/terraform/test.txt"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
//
|
||||
func TestAccDockerContainer_uploadSourceHash(t *testing.T) {
|
||||
var c types.ContainerJSON
|
||||
var firstRunId string
|
||||
|
||||
wd, _ := os.Getwd()
|
||||
testFile := wd + "/../scripts/testing/testingFile"
|
||||
hash, _ := ioutil.ReadFile(testFile + ".base64")
|
||||
grabFirstCheck := func(*terraform.State) error {
|
||||
firstRunId = c.ID
|
||||
return nil
|
||||
}
|
||||
testCheck := func(*terraform.State) error {
|
||||
if c.ID == firstRunId {
|
||||
return fmt.Errorf("Container should have been recreated due to changed hash")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: fmt.Sprintf(testAccDockerContainerUploadSourceHashConfig, testFile, string(hash)),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccContainerRunning("docker_container.foo", &c),
|
||||
grabFirstCheck,
|
||||
resource.TestCheckResourceAttr("docker_container.foo", "name", "tf-test"),
|
||||
resource.TestCheckResourceAttr("docker_container.foo", "upload.#", "1"),
|
||||
),
|
||||
},
|
||||
{
|
||||
Config: fmt.Sprintf(testAccDockerContainerUploadSourceHashConfig, testFile, string(hash)+"arbitrary"),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccContainerRunning("docker_container.foo", &c),
|
||||
testCheck,
|
||||
resource.TestCheckResourceAttr("docker_container.foo", "name", "tf-test"),
|
||||
resource.TestCheckResourceAttr("docker_container.foo", "upload.#", "1"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccDockerContainer_uploadAsBase64(t *testing.T) {
|
||||
var c types.ContainerJSON
|
||||
|
||||
|
|
@ -765,7 +872,7 @@ func TestAccDockerContainer_multipleUploadContentsConfig(t *testing.T) {
|
|||
}
|
||||
}
|
||||
`,
|
||||
ExpectError: regexp.MustCompile(`.*only one of 'content' or 'content_base64' can be specified.*`),
|
||||
ExpectError: regexp.MustCompile(`.*only one of 'content', 'content_base64', or 'source' can be set.*`),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
@ -794,7 +901,7 @@ func TestAccDockerContainer_noUploadContentsConfig(t *testing.T) {
|
|||
}
|
||||
}
|
||||
`,
|
||||
ExpectError: regexp.MustCompile(`.* neither 'content', nor 'content_base64' was set.*`),
|
||||
ExpectError: regexp.MustCompile(`.* one of 'content', 'content_base64', or 'source' must be set.*`),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
@ -1791,6 +1898,43 @@ resource "docker_container" "foo" {
|
|||
}
|
||||
`
|
||||
|
||||
const testAccDockerContainerUploadSourceConfig = `
|
||||
resource "docker_image" "foo" {
|
||||
name = "nginx:latest"
|
||||
keep_locally = true
|
||||
}
|
||||
|
||||
resource "docker_container" "foo" {
|
||||
name = "tf-test"
|
||||
image = "${docker_image.foo.latest}"
|
||||
|
||||
upload {
|
||||
source = "%s"
|
||||
file = "/terraform/test.txt"
|
||||
executable = true
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const testAccDockerContainerUploadSourceHashConfig = `
|
||||
resource "docker_image" "foo" {
|
||||
name = "nginx:latest"
|
||||
keep_locally = true
|
||||
}
|
||||
|
||||
resource "docker_container" "foo" {
|
||||
name = "tf-test"
|
||||
image = "${docker_image.foo.latest}"
|
||||
|
||||
upload {
|
||||
source = "%s"
|
||||
source_hash = "%s"
|
||||
file = "/terraform/test.txt"
|
||||
executable = true
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const testAccDockerContainerUploadBase64Config = `
|
||||
resource "docker_image" "foo" {
|
||||
name = "nginx:latest"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ set -e
|
|||
for p in $(docker container ls -f 'name=private_registry' -q); do docker stop $p; done
|
||||
echo "### stopped private registry ###"
|
||||
|
||||
rm -f "$(pwd)/scripts/testing/testingFile"
|
||||
rm -f "$(pwd)/scripts/testing/testingFile.base64"
|
||||
rm -f "$(pwd)"/scripts/testing/auth/htpasswd
|
||||
rm -f "$(pwd)"/scripts/testing/certs/registry_auth.*
|
||||
echo "### removed auth and certs ###"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo -n "foo" > "$(pwd)/scripts/testing/testingFile"
|
||||
echo -n `base64 $(pwd)/scripts/testing/testingFile` > "$(pwd)/scripts/testing/testingFile.base64"
|
||||
|
||||
# Create self signed certs
|
||||
mkdir -p "$(pwd)"/scripts/testing/certs
|
||||
openssl req \
|
||||
|
|
|
|||
|
|
@ -220,8 +220,10 @@ files to upload to the container before starting it. Only one of `content` or `c
|
|||
one of them hast to be set.
|
||||
Each `upload` supports the following
|
||||
|
||||
* `content` - (Optional, string, conflicts with `content_base64`) Literal string value to use as the object content, which will be uploaded as UTF-8-encoded text.
|
||||
* `content_base64` - (Optional, string, conflicts with `content`) Base64-encoded data that will be decoded and uploaded as raw bytes for the object content. This allows safely uploading non-UTF8 binary data, but is recommended only for larger binary content such as the result of the `base64encode` interpolation function. See [here](https://github.com/terraform-providers/terraform-provider-docker/issues/48#issuecomment-374174588) for the reason.
|
||||
* `content` - (Optional, string, conflicts with `content_base64` & `source`) Literal string value to use as the object content, which will be uploaded as UTF-8-encoded text.
|
||||
* `content_base64` - (Optional, string, conflicts with `content` & `source`) Base64-encoded data that will be decoded and uploaded as raw bytes for the object content. This allows safely uploading non-UTF8 binary data, but is recommended only for larger binary content such as the result of the `base64encode` interpolation function. See [here](https://github.com/terraform-providers/terraform-provider-docker/issues/48#issuecomment-374174588) for the reason.
|
||||
* `source` - (Optional, string, conflicts with `content` & `content_base64`) A filename that references a file which will be uploaded as the object content. This allows for large file uploads that do not get stored in state.
|
||||
* `source_hash` - (Optional, string) If using `source`, this will force an update if the file content has updated but the filename has not.
|
||||
* `file` - (Required, string) path to a file in the container.
|
||||
* `executable` - (Optional, bool) If true, the file will be uploaded with user
|
||||
executable permission.
|
||||
|
|
|
|||
Loading…
Reference in a new issue