chore/refactor tests (#201)

* chore: format test configs for datasources

* chore: outlines load test config helper and structure

* docs(contributing): add command for resouce tests

to have an example of the regex

* refactor: move container test configs into separate files

* fix: add insecure_skip_verify for image pulls

to fix the local test setup with invalid certs

* chore(ci): remove insecure registry adaption

* chore: regenerate website

* chore: update gitignore for scipts/testing dir

* fix: replace nodejs services with go versions

* fix: move testing program versions in separate files

* test: reactivate flaky test from travis

* chore: fix linter on all go files

* fix(linter): testing go servers

* chore(ci): add env for go version

* chore(ci): name workflow steps

also moves description of available docker versions in to acc dockerfile

* Revert "test: reactivate flaky test from travis"

This reverts commit b02654acc4d6b7d02c8f3ba090e6a3f248741b10.

* docs: fix provider-ssh example

* chore: use alpine als final image for tests

* refactor: move test configs from folder into testname.tf files

* refactor: image delete log is now debug and indented

* refactor: image test config into seprate files

* refactor: move network test config into seperate files

* refactor: move plugin test config into seperate files

* chore: rename registry image test file

* refactor: move registry_image test config into seperate files

* chore: format secret test configs

* refactor: inline volume test configs

* fix: remove unused volume label test function

* refactor: move service test configs into seperate files

* test: reactivate and fix service test

* chore: simplify insecure skip verify add to http client

* chore(ci): debug into service test

* chore(ci): add testacc setup

* chore: format tf config for provider test

* chore(ci): add debug output for config.json

* fix: check service auth for emptyness

* fix: remove re-read of provider auth config

because the bug occured only in CI as the meta object might be GCd

* test: pass auth to service instead of provider

* chore: reactivate all acc tests

* test: outlines service inspect json check for full spec

* test: add service inspect json checks

* test: finish service inspect json checks

* chore(service): move test helper to end to of the file

* chore: move mapEquals to test helpers

* test: add json inspect for config

* chore: add debug inspect log for plugin, secret and volume

* test: add json inspect for secret

* test: add json inspect for image

* test: add json inspect for network

* test: add json inspect for plugin

* test: add json inspect for volume

* test: inline ds plugin test configs

* test: inline network configs

* test: move ds reg image configs into separate files

* test: reactivates container upload checks

* chore: adapt issues ref from old to new xw repo

* fix: reactivate network ingress test

and provide helpers for removing the default ingress network and leaving the swamr

* docs: rerun website gen

* test: fix reg image build and keep test

* chore: add name to todo

* chore: move ds network and plugin specs to file

* chore: format provider test spec

* chore: use simpler error message for empty strings
This commit is contained in:
Manuel Vogel 2021-05-31 09:11:49 +02:00 committed by GitHub
parent 22c490336c
commit 0588c2071b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
131 changed files with 2879 additions and 2235 deletions

View file

@ -15,6 +15,7 @@ env:
GOPROXY: https://proxy.golang.org,https://gocenter.io,direct
DEBIAN_FRONTEND: noninteractive
DOCKER_CE_VERSION: "5:20.10.5~3-0~ubuntu-focal"
GO_VERSION: "1.16"
jobs:
acc-test:
@ -31,22 +32,22 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: '1.16'
- run: cat /etc/issue
- run: bash scripts/gogetcookie.sh
# locally: docker run -it ubuntu:20.04 bash (https://ubuntu.pkgs.org/20.04/docker-ce-stable-amd64/)
- run: sudo apt-get update
- run: sudo apt-get -y install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
- run: curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
- run: sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
- run: sudo apt-get update
# list available docker versions: apt-cache policy docker-ce
- run: sudo apt-get -y install docker-ce=${DOCKER_CE_VERSION}
- run: docker version
# Allow local registry to be insecure
- run: sudo sed 's/DOCKER_OPTS="/DOCKER_OPTS="--insecure-registry=127.0.0.1:15000 /g' -i /etc/default/docker
- run: sudo cat /etc/default/docker
- run: sudo service docker restart
- run: make testacc
go-version: ${{ env.GO_VERSION }}
- name: Setup cookies
run: |
cat /etc/issue
bash scripts/gogetcookie.sh
- name: Setup docker version ${{ env.DOCKER_CE_VERSION }}
run: |
sudo apt-get update
sudo apt-get -y install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get update
sudo apt-get -y install docker-ce=${DOCKER_CE_VERSION}
docker version
sudo service docker restart
- name: Run acceptance tests
run: make testacc
env:
TF_ACC_TERRAFORM_VERSION: ${{ matrix.terraform_version }}

View file

@ -13,6 +13,7 @@ on:
env:
GOPROXY: https://proxy.golang.org,https://gocenter.io,direct
GO_VERSION: "1.16"
jobs:
compile:
@ -21,7 +22,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: '1.16'
go-version: ${{ env.GO_VERSION }}
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:

View file

@ -14,6 +14,10 @@ on:
push:
tags:
- "v*"
env:
GO_VERSION: "1.16"
jobs:
goreleaser:
runs-on: ubuntu-20.04
@ -25,7 +29,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: '1.16'
go-version: ${{ env.GO_VERSION }}
- name: Import GPG key
id: import_gpg
uses: paultyng/ghaction-import-gpg@v2.1.0

View file

@ -13,6 +13,7 @@ on:
env:
GOPROXY: https://proxy.golang.org,https://gocenter.io,direct
GO_VERSION: "1.16"
jobs:
unit-test:
@ -21,10 +22,14 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: '1.16'
- run: cat /etc/issue
- run: bash scripts/gogetcookie.sh
- run: make vet
- run: make test
go-version: ${{ env.GO_VERSION }}
- name: Setup cookies
run: |
cat /etc/issue
bash scripts/gogetcookie.sh
- name: Running vet
run: make vet
- name: Running unit tests
run: make test

View file

@ -11,9 +11,8 @@ on:
- docs/**
env:
GO_VERSION: "1.16"
GOPROXY: https://proxy.golang.org,https://gocenter.io,direct
DOCKER_CE_VERSION: "5:20.10.5~3-0~ubuntu-focal"
GO_VERSION: "1.16"
jobs:
website-generation:
@ -22,7 +21,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: '1.16'
go-version: ${{ env.GO_VERSION }}
- name: Setup tools
run: make setup
- name: Generate the website
@ -48,7 +47,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: '1.16'
go-version: ${{ env.GO_VERSION }}
- run: docker version
- name: Setup tools
run: make setup

5
.gitignore vendored
View file

@ -32,14 +32,15 @@ website/vendor
!command/test-fixtures/**/.terraform/
scripts/testing/auth
scripts/testing/certs
scripts/testing/testingFile*
# build outputs
results
dist
# testing
testing
testing-mirror/registry.terraform.io/kreuzwerker/docker
/testing
/testing-mirror/registry.terraform.io/kreuzwerker/docker
# lint error outputs
markdown-link-check-*.txt

View file

@ -62,7 +62,10 @@ make test
make testacc_setup
## run a single test
TF_LOG=INFO TF_ACC=1 go test -v ./internal/provider -run ^TestAccDockerImage_data_private_config_file$ -timeout 360s
TF_LOG=INFO TF_ACC=1 go test -v ./internal/provider -timeout 60s -run ^TestAccDockerImage_data_private_config_file$
## run all test for a resource, e.g docker_container
TF_LOG=INFO TF_ACC=1 go test -v ./internal/provider -timeout 360s -run TestAccDockerContainer
## cleanup the local testing resources
make testacc_cleanup

View file

@ -18,7 +18,7 @@ setup:
&& chmod 500 .git/hooks/commit-msg
golangci-lint:
@golangci-lint run ./$(PKG_NAME)/...
@golangci-lint run ./...
test: fmtcheck
go test -i $(TEST) || exit 1

View file

@ -33,6 +33,7 @@ resource "docker_image" "ubuntu" {
### Optional
- **id** (String) The ID of this resource.
- **insecure_skip_verify** (Boolean) If `true`, the verification of TLS certificates of the server/registry is disabled. Defaults to `false`
### Read-Only

View file

@ -71,28 +71,8 @@ You can also use the `ssh` protocol to connect to the docker host on a remote ma
The configuration would look as follows:
```terraform
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "2.12.2"
}
}
}
provider "docker" {
host = "unix:///var/run/docker.sock"
}
# Pulls the image
resource "docker_image" "ubuntu" {
name = "ubuntu:latest"
}
# Create a container
resource "docker_container" "foo" {
image = docker_image.ubuntu.latest
name = "foo"
host = "ssh://user@remote-host:22"
}
```

View file

@ -33,6 +33,7 @@ resource "docker_registry_image" "helloworld" {
- **build** (Block List, Max: 1) Definition for building the image (see [below for nested schema](#nestedblock--build))
- **id** (String) The ID of this resource.
- **insecure_skip_verify** (Boolean) If `true`, the verification of TLS certificates of the server/registry is disabled. Defaults to `false`
- **keep_remotely** (Boolean) If true, then the Docker image won't be deleted on destroy operation. If this is false, it will delete the image from the docker registry on destroy operation. Defaults to `false`
### Read-Only

View file

@ -1,23 +1,3 @@
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "2.12.2"
}
}
}
provider "docker" {
host = "unix:///var/run/docker.sock"
}
# Pulls the image
resource "docker_image" "ubuntu" {
name = "ubuntu:latest"
}
# Create a container
resource "docker_container" "foo" {
image = docker_image.ubuntu.latest
name = "foo"
}
host = "ssh://user@remote-host:22"
}

View file

@ -16,7 +16,7 @@ func TestAccDockerNetworkDataSource_basic(t *testing.T) {
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccDockerNetworkDataSourceConfig,
Config: loadTestConfiguration(t, DATA_SOURCE, "docker_network", "testAccDockerNetworkDataSourceBasic"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.docker_network.bridge", "name", "bridge"),
testAccDockerNetworkDataSourceIPAMRead,
@ -44,9 +44,3 @@ func testAccDockerNetworkDataSourceIPAMRead(state *terraform.State) error {
}
return nil
}
const testAccDockerNetworkDataSourceConfig = `
data "docker_network" "bridge" {
name = "bridge"
}
`

View file

@ -23,7 +23,7 @@ func TestAccDockerPluginDataSource_basic(t *testing.T) {
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccDockerPluginDataSourceTest,
Config: loadTestConfiguration(t, DATA_SOURCE, "docker_plugin", "testAccDockerPluginDataSourceBasic"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.docker_plugin.test", "plugin_reference", "docker.io/tiborvass/sample-volume-plugin:latest"),
),
@ -31,9 +31,3 @@ func TestAccDockerPluginDataSource_basic(t *testing.T) {
},
})
}
const testAccDockerPluginDataSourceTest = `
data "docker_plugin" "test" {
alias = "tiborvass/sample-volume-plugin:latest"
}
`

View file

@ -9,8 +9,6 @@ import (
"io/ioutil"
"net/http"
"net/url"
"os"
"strconv"
"strings"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@ -35,6 +33,13 @@ func dataSourceDockerRegistryImage() *schema.Resource {
Description: "The content digest of the image, as stored in the registry.",
Computed: true,
},
"insecure_skip_verify": {
Type: schema.TypeBool,
Description: "If `true`, the verification of TLS certificates of the server/registry is disabled. Defaults to `false`",
Optional: true,
Default: false,
},
},
}
}
@ -70,9 +75,10 @@ func dataSourceDockerRegistryImageRead(ctx context.Context, d *schema.ResourceDa
password = auth.Password
}
digest, err := getImageDigest(pullOpts.Registry, pullOpts.Repository, pullOpts.Tag, username, password, false)
insecureSkipVerify := d.Get("insecure_skip_verify").(bool)
digest, err := getImageDigest(pullOpts.Registry, pullOpts.Repository, pullOpts.Tag, username, password, insecureSkipVerify, false)
if err != nil {
digest, err = getImageDigest(pullOpts.Registry, pullOpts.Repository, pullOpts.Tag, username, password, true)
digest, err = getImageDigest(pullOpts.Registry, pullOpts.Repository, pullOpts.Tag, username, password, insecureSkipVerify, true)
if err != nil {
return diag.Errorf("Got error when attempting to fetch image version from registry: %s", err)
}
@ -84,22 +90,10 @@ func dataSourceDockerRegistryImageRead(ctx context.Context, d *schema.ResourceDa
return nil
}
func getImageDigest(registry, image, tag, username, password string, fallback bool) (string, error) {
func getImageDigest(registry, image, tag, username, password string, insecureSkipVerify, fallback bool) (string, error) {
client := http.DefaultClient
// Allow insecure registries only for ACC tests
// cuz we don't have a valid certs for this case
if env, okEnv := os.LookupEnv("TF_ACC"); okEnv {
if i, errConv := strconv.Atoi(env); errConv == nil && i >= 1 {
// DevSkim: ignore DS440000
cfg := &tls.Config{
InsecureSkipVerify: true,
}
client.Transport = &http.Transport{
TLSClientConfig: cfg,
}
}
}
// DevSkim: ignore DS440000
client.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: insecureSkipVerify}}
req, err := http.NewRequest("GET", "https://"+registry+"/v2/"+image+"/manifests/"+tag, nil)
if err != nil {

View file

@ -21,7 +21,7 @@ func TestAccDockerRegistryImage_basic(t *testing.T) {
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccDockerImageDataSourceConfig,
Config: loadTestConfiguration(t, DATA_SOURCE, "docker_registry_image", "testAccDockerImageDataSourceConfig"),
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr("data.docker_registry_image.foo", "sha256_digest", registryDigestRegexp),
),
@ -36,7 +36,7 @@ func TestAccDockerRegistryImage_private(t *testing.T) {
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccDockerImageDataSourcePrivateConfig,
Config: loadTestConfiguration(t, DATA_SOURCE, "docker_registry_image", "testAccDockerImageDataSourcePrivateConfig"),
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr("data.docker_registry_image.bar", "sha256_digest", registryDigestRegexp),
),
@ -54,7 +54,7 @@ func TestAccDockerRegistryImage_auth(t *testing.T) {
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(testAccDockerImageDataSourceAuthConfig, registry, image),
Config: fmt.Sprintf(loadTestConfiguration(t, DATA_SOURCE, "docker_registry_image", "testAccDockerImageDataSourceAuthConfig"), registry, image),
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr("data.docker_registry_image.foobar", "sha256_digest", registryDigestRegexp),
),
@ -66,31 +66,6 @@ func TestAccDockerRegistryImage_auth(t *testing.T) {
})
}
const testAccDockerImageDataSourceConfig = `
data "docker_registry_image" "foo" {
name = "alpine:latest"
}
`
const testAccDockerImageDataSourcePrivateConfig = `
data "docker_registry_image" "bar" {
name = "gcr.io:443/google_containers/pause:0.8.0"
}
`
const testAccDockerImageDataSourceAuthConfig = `
provider "docker" {
alias = "private"
registry_auth {
address = "%s"
}
}
data "docker_registry_image" "foobar" {
provider = "docker.private"
name = "%s"
}
`
func TestGetDigestFromResponse(t *testing.T) {
headerContent := "sha256:2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"
respWithHeaders := &http.Response{

View file

@ -87,7 +87,8 @@ provider "docker" {
}
}
data "docker_registry_image" "foobar" {
provider = "docker.private"
name = "localhost:15000/helloworld:1.0"
provider = "docker.private"
name = "localhost:15000/helloworld:1.0"
insecure_skip_verify = true
}
`

View file

@ -3,6 +3,7 @@ package provider
import (
"context"
"encoding/base64"
"encoding/json"
"log"
"github.com/docker/docker/api/types/swarm"
@ -68,6 +69,10 @@ func resourceDockerConfigRead(ctx context.Context, d *schema.ResourceData, meta
d.SetId("")
return nil
}
jsonObj, _ := json.MarshalIndent(config, "", "\t")
log.Printf("[DEBUG] Docker config inspect from readFunc: %s", jsonObj)
d.SetId(config.ID)
d.Set("name", config.Spec.Name)
d.Set("data", base64.StdEncoding.EncodeToString(config.Spec.Data))

View file

@ -2,15 +2,35 @@ package provider
import (
"context"
"errors"
"fmt"
"testing"
"github.com/docker/docker/api/types/swarm"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)
func TestAccDockerConfig_basic(t *testing.T) {
ctx := context.Background()
var c swarm.Config
testCheckConfigInspect := func(*terraform.State) error {
if c.Spec.Name == "" {
return errors.New("Config Spec.Name is empty")
}
if len(c.Spec.Data) == 0 {
return errors.New("Config Spec.Data is empty")
}
if len(c.Spec.Labels) != 0 {
return fmt.Errorf("Config Spec.Labels is wrong: %v", c.Spec.Labels)
}
return nil
}
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
@ -28,6 +48,8 @@ func TestAccDockerConfig_basic(t *testing.T) {
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("docker_config.foo", "name", "foo-config"),
resource.TestCheckResourceAttr("docker_config.foo", "data", "Ymxhc2RzYmxhYmxhMTI0ZHNkd2VzZA=="),
testAccServiceConfigCreated("docker_config.foo", &c),
testCheckConfigInspect,
),
},
{
@ -55,7 +77,7 @@ func TestAccDockerConfig_basicUpdatable(t *testing.T) {
data = "Ymxhc2RzYmxhYmxhMTI0ZHNkd2VzZA=="
lifecycle {
ignore_changes = ["name"]
ignore_changes = ["name"]
create_before_destroy = true
}
}
@ -71,7 +93,7 @@ func TestAccDockerConfig_basicUpdatable(t *testing.T) {
data = "U3VuIDI1IE1hciAyMDE4IDE0OjQ2OjE5IENFU1QK"
lifecycle {
ignore_changes = ["name"]
ignore_changes = ["name"]
create_before_destroy = true
}
}
@ -109,3 +131,29 @@ func testCheckDockerConfigDestroy(ctx context.Context, s *terraform.State) error
}
return nil
}
func testAccServiceConfigCreated(resourceName string, config *swarm.Config) resource.TestCheckFunc {
return func(s *terraform.State) error {
ctx := context.Background()
rs, ok := s.RootModule().Resources[resourceName]
if !ok {
return fmt.Errorf("Resource with name '%s' not found in state", resourceName)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}
client := testAccProvider.Meta().(*ProviderConfig).DockerClient
inspectedConfig, _, err := client.ConfigInspectWithRaw(ctx, rs.Primary.ID)
if err != nil {
return fmt.Errorf("Config with ID '%s': %w", rs.Primary.ID, err)
}
// we set the value to the pointer to be able to use the value
// outside of the function
*config = inspectedConfig
return nil
}
}

File diff suppressed because it is too large Load diff

View file

@ -63,6 +63,7 @@ func resourceDockerImageRead(ctx context.Context, d *schema.ResourceData, meta i
return nil
}
// TODO mavogel: remove the appended name from the ID
d.SetId(foundImage.ID + d.Get("name").(string))
d.Set("latest", foundImage.ID)
return nil
@ -100,6 +101,9 @@ func searchLocalImages(ctx context.Context, client *client.Client, data Data, im
return nil
}
jsonObj, _ := json.MarshalIndent(imageInspect, "", "\t")
log.Printf("[DEBUG] Docker image inspect from readFunc: %s", jsonObj)
if apiImage, ok := data.DockerImages[imageInspect.ID]; ok {
log.Printf("[DEBUG] found local image via imageName: %v", imageName)
return apiImage
@ -132,7 +136,8 @@ func removeImage(ctx context.Context, d *schema.ResourceData, client *client.Cli
if err != nil {
return err
}
log.Printf("[INFO] Deleted image items: %v", imageDeleteResponseItems)
indentedImageDeleteResponseItems, _ := json.MarshalIndent(imageDeleteResponseItems, "", "\t")
log.Printf("[DEBUG] Deleted image items: \n%s", indentedImageDeleteResponseItems)
}
return nil

View file

@ -11,19 +11,18 @@ import (
"strings"
"testing"
"github.com/docker/docker/api/types"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)
var contentDigestRegexp = regexp.MustCompile(`\A[A-Za-z0-9_\+\.-]+:[A-Fa-f0-9]+\z`)
const testForceRemoveDockerImageName = "alpine:3.11.5"
func TestAccDockerImage_basic(t *testing.T) {
// run a Docker container which refers the Docker image to test "force_remove" option
containerName := "test-docker-image-force-remove"
ctx := context.Background()
if err := exec.Command("docker", "run", "--rm", "-d", "--name", containerName, testForceRemoveDockerImageName, "tail", "-f", "/dev/null").Run(); err != nil {
if err := exec.Command("docker", "run", "--rm", "-d", "--name", containerName, "alpine:3.11.5", "tail", "-f", "/dev/null").Run(); err != nil {
t.Fatal(err)
}
defer func() {
@ -39,13 +38,13 @@ func TestAccDockerImage_basic(t *testing.T) {
},
Steps: []resource.TestStep{
{
Config: testAccDockerImageConfig,
Config: loadTestConfiguration(t, RESOURCE, "docker_image", "testAccDockerImageConfig"),
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr("docker_image.foo", "latest", contentDigestRegexp),
),
},
{
Config: testAccForceRemoveDockerImage,
Config: loadTestConfiguration(t, RESOURCE, "docker_image", "testAccForceRemoveDockerImage"),
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr("docker_image.test", "latest", contentDigestRegexp),
),
@ -56,6 +55,22 @@ func TestAccDockerImage_basic(t *testing.T) {
func TestAccDockerImage_private(t *testing.T) {
ctx := context.Background()
var i types.ImageInspect
testCheckImageInspect := func(*terraform.State) error {
if len(i.RepoTags) != 1 ||
i.RepoTags[0] != "gcr.io:443/google_containers/pause:0.8.0" {
return fmt.Errorf("Image RepoTags is wrong: %v", i.RepoTags)
}
if len(i.RepoDigests) != 1 ||
i.RepoDigests[0] != "gcr.io:443/google_containers/pause@sha256:bbeaef1d40778579b7b86543fe03e1ec041428a50d21f7a7b25630e357ec9247" {
return fmt.Errorf("Image RepoDigests is wrong: %v", i.RepoDigests)
}
return nil
}
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
@ -64,9 +79,11 @@ func TestAccDockerImage_private(t *testing.T) {
},
Steps: []resource.TestStep{
{
Config: testAddDockerPrivateImageConfig,
Config: loadTestConfiguration(t, RESOURCE, "docker_image", "testAddDockerPrivateImageConfig"),
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr("docker_image.foobar", "latest", contentDigestRegexp),
testAccImageCreated("docker_image.foobar", &i),
testCheckImageInspect,
),
},
},
@ -94,7 +111,7 @@ func TestAccDockerImage_destroy(t *testing.T) {
},
Steps: []resource.TestStep{
{
Config: testAccDockerImageKeepLocallyConfig,
Config: loadTestConfiguration(t, RESOURCE, "docker_image", "testAccDockerImageKeepLocallyConfig"),
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr("docker_image.foobarzoo", "latest", contentDigestRegexp),
),
@ -110,7 +127,7 @@ func TestAccDockerImage_data(t *testing.T) {
PreventPostDestroyRefresh: true,
Steps: []resource.TestStep{
{
Config: testAccDockerImageFromDataConfig,
Config: loadTestConfiguration(t, RESOURCE, "docker_image", "testAccDockerImageFromDataConfig"),
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr("docker_image.foobarbaz", "latest", contentDigestRegexp),
),
@ -126,7 +143,7 @@ func TestAccDockerImage_data_pull_trigger(t *testing.T) {
PreventPostDestroyRefresh: true,
Steps: []resource.TestStep{
{
Config: testAccDockerImageFromDataConfigWithPullTrigger,
Config: loadTestConfiguration(t, RESOURCE, "docker_image", "testAccDockerImageFromDataConfigWithPullTrigger"),
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr("docker_image.foobarbazoo", "latest", contentDigestRegexp),
),
@ -146,7 +163,7 @@ func TestAccDockerImage_data_private(t *testing.T) {
PreventPostDestroyRefresh: true,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(testAccDockerImageFromDataPrivateConfig, registry, image),
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_image", "testAccDockerImageFromDataPrivateConfig"), registry, image),
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr("docker_image.foo_private", "latest", contentDigestRegexp),
),
@ -171,7 +188,7 @@ func TestAccDockerImage_data_private_config_file(t *testing.T) {
PreventPostDestroyRefresh: true,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(testAccDockerImageFromDataPrivateConfigFile, registry, dockerConfig, image),
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_image", "testAccDockerImageFromDataPrivateConfigFile"), registry, dockerConfig, image),
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr("docker_image.foo_private", "latest", contentDigestRegexp),
),
@ -196,7 +213,7 @@ func TestAccDockerImage_data_private_config_file_content(t *testing.T) {
PreventPostDestroyRefresh: true,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(testAccDockerImageFromDataPrivateConfigFileContent, registry, dockerConfig, image),
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_image", "testAccDockerImageFromDataPrivateConfigFileContent"), registry, dockerConfig, image),
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr("docker_image.foo_private", "latest", contentDigestRegexp),
),
@ -218,7 +235,7 @@ func TestAccDockerImage_sha265(t *testing.T) {
},
Steps: []resource.TestStep{
{
Config: testAddDockerImageWithSHA256RepoDigest,
Config: loadTestConfiguration(t, RESOURCE, "docker_image", "testAddDockerImageWithSHA256RepoDigest"),
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr("docker_image.foobar", "latest", contentDigestRegexp),
),
@ -252,7 +269,7 @@ func TestAccDockerImage_tag_sha265(t *testing.T) {
},
Steps: []resource.TestStep{
{
Config: testDockerImageWithTagAndSHA256RepoDigest,
Config: loadTestConfiguration(t, RESOURCE, "docker_image", "testAccDockerImageWithTagAndSHA256RepoDigest"),
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr("docker_image.nginx", "latest", contentDigestRegexp),
),
@ -277,7 +294,7 @@ func TestAccDockerImage_build(t *testing.T) {
},
Steps: []resource.TestStep{
{
Config: testCreateDockerImage,
Config: loadTestConfiguration(t, RESOURCE, "docker_image", "testCreateDockerImage"),
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr("docker_image.test", "name", contentDigestRegexp),
),
@ -286,123 +303,6 @@ func TestAccDockerImage_build(t *testing.T) {
})
}
const testAccDockerImageConfig = `
resource "docker_image" "foo" {
name = "alpine:3.1"
}
`
const testAccForceRemoveDockerImage = `
resource "docker_image" "test" {
name = "` + testForceRemoveDockerImageName + `"
force_remove = true
}
`
const testAddDockerPrivateImageConfig = `
resource "docker_image" "foobar" {
name = "gcr.io:443/google_containers/pause:0.8.0"
}
`
const testAccDockerImageKeepLocallyConfig = `
resource "docker_image" "foobarzoo" {
name = "crux:3.1"
keep_locally = true
}
`
const testAccDockerImageFromDataConfig = `
data "docker_registry_image" "foobarbaz" {
name = "alpine:3.1"
}
resource "docker_image" "foobarbaz" {
name = data.docker_registry_image.foobarbaz.name
pull_triggers = [data.docker_registry_image.foobarbaz.sha256_digest]
}
`
const testAccDockerImageFromDataConfigWithPullTrigger = `
data "docker_registry_image" "foobarbazoo" {
name = "alpine:3.1"
}
resource "docker_image" "foobarbazoo" {
name = data.docker_registry_image.foobarbazoo.name
pull_trigger = data.docker_registry_image.foobarbazoo.sha256_digest
}
`
const testAccDockerImageFromDataPrivateConfig = `
provider "docker" {
alias = "private"
registry_auth {
address = "%s"
}
}
data "docker_registry_image" "foo_private" {
provider = "docker.private"
name = "%s"
}
resource "docker_image" "foo_private" {
provider = "docker.private"
name = data.docker_registry_image.foo_private.name
keep_locally = true
pull_triggers = [data.docker_registry_image.foo_private.sha256_digest]
}
`
const testAccDockerImageFromDataPrivateConfigFile = `
provider "docker" {
alias = "private"
registry_auth {
address = "%s"
config_file = "%s"
}
}
resource "docker_image" "foo_private" {
provider = "docker.private"
name = "%s"
}
`
const testAccDockerImageFromDataPrivateConfigFileContent = `
provider "docker" {
alias = "private"
registry_auth {
address = "%s"
config_file_content = file("%s")
}
}
resource "docker_image" "foo_private" {
provider = "docker.private"
name = "%s"
}
`
const testAddDockerImageWithSHA256RepoDigest = `
resource "docker_image" "foobar" {
name = "stocard/gotthard@sha256:ed752380c07940c651b46c97ca2101034b3be112f4d86198900aa6141f37fe7b"
}
`
const testCreateDockerImage = `
resource "docker_image" "test" {
name = "ubuntu:11"
build {
path = "."
dockerfile = "Dockerfile"
force_remove = true
build_arg = {
test_arg = "kenobi"
}
label = {
test_label1 = "han"
test_label2 = "solo"
}
}
}
`
const testDockerFileExample = `
FROM python:3-stretch
@ -415,8 +315,34 @@ RUN echo ${test_arg} > test_arg.txt
RUN apt-get update -qq
`
const testDockerImageWithTagAndSHA256RepoDigest = `
resource "docker_image" "nginx" {
name = "nginx:1.18.0-alpine@sha256:0c56c40f232f41c1b8341c3cc055c8b528cb6decefd7f7c8506e2d30bb9678b6"
func testAccImageCreated(resourceName string, image *types.ImageInspect) resource.TestCheckFunc {
return func(s *terraform.State) error {
ctx := context.Background()
rs, ok := s.RootModule().Resources[resourceName]
if !ok {
return fmt.Errorf("Resource with name '%s' not found in state", resourceName)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}
name := rs.Primary.Attributes["name"]
// TODO mavogel: it's because we set the ID in the format:
// d.SetId(foundImage.ID + d.Get("name").(string))
// so we need to strip away the name
strippedID := strings.Replace(rs.Primary.ID, name, "", -1)
client := testAccProvider.Meta().(*ProviderConfig).DockerClient
inspectedImage, _, err := client.ImageInspectWithRaw(ctx, strippedID)
if err != nil {
return fmt.Errorf("Image with ID '%s': %w", strippedID, err)
}
// we set the value to the pointer to be able to use the value
// outside of the function
*image = inspectedImage
return nil
}
}
`

View file

@ -73,7 +73,7 @@ func resourceDockerNetworkCreate(ctx context.Context, d *schema.ResourceData, me
}
d.SetId(retNetwork.ID)
// d.Set("check_duplicate") TODO
// d.Set("check_duplicate") TODO mavogel
return resourceDockerNetworkRead(ctx, d, meta)
}

View file

@ -7,7 +7,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
// TODO 2: seems like we can replace the set hash generation with plain lists -> #219
// TODO 2: seems like we can replace the set hash generation with plain lists -> #74 (import resources)
func flattenIpamConfigSpec(in []network.IPAMConfig) *schema.Set { // []interface{} {
out := make([]interface{}, len(in))
for i, v := range in {

View file

@ -19,7 +19,7 @@ func TestAccDockerNetwork_basic(t *testing.T) {
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccDockerNetworkConfig,
Config: loadTestConfiguration(t, RESOURCE, "docker_network", "testAccDockerNetworkConfig"),
Check: resource.ComposeTestCheckFunc(
testAccNetwork(resourceName, &n),
),
@ -33,7 +33,93 @@ func TestAccDockerNetwork_basic(t *testing.T) {
})
}
// TODO mavogel: add full network config test in #219
func TestAccDockerNetwork_full(t *testing.T) {
var n types.NetworkResource
resourceName := "docker_network.foo"
testCheckNetworkInspect := func(*terraform.State) error {
if n.Scope == "" || n.Scope != "local" {
return fmt.Errorf("Network Scope is wrong: %v", n.Scope)
}
if n.Driver == "" || n.Driver != "bridge" {
return fmt.Errorf("Network Driver is wrong: %v", n.Driver)
}
if n.EnableIPv6 != false {
return fmt.Errorf("Network EnableIPv6 is wrong: %v", n.EnableIPv6)
}
if n.IPAM.Driver == "" ||
n.IPAM.Options != nil ||
len(n.IPAM.Config) != 1 ||
n.IPAM.Config[0].Gateway != "" ||
n.IPAM.Config[0].IPRange != "" ||
n.IPAM.Config[0].AuxAddress != nil ||
n.IPAM.Config[0].Subnet != "10.0.1.0/24" ||
n.IPAM.Driver != "default" {
return fmt.Errorf("Network IPAM is wrong: %v", n.IPAM)
}
if n.Internal != true {
return fmt.Errorf("Network Internal is wrong: %v", n.Internal)
}
if n.Attachable != false {
return fmt.Errorf("Network Attachable is wrong: %v", n.Attachable)
}
if n.Ingress != false {
return fmt.Errorf("Network Ingress is wrong: %v", n.Ingress)
}
if n.ConfigFrom.Network != "" {
return fmt.Errorf("Network ConfigFrom is wrong: %v", n.ConfigFrom)
}
if n.ConfigOnly != false {
return fmt.Errorf("Network ConfigOnly is wrong: %v", n.ConfigOnly)
}
if n.Containers == nil || len(n.Containers) != 0 {
return fmt.Errorf("Network Containers is wrong: %v", n.Containers)
}
if n.Options == nil || len(n.Options) != 0 {
return fmt.Errorf("Network Options is wrong: %v", n.Options)
}
if n.Labels == nil ||
len(n.Labels) != 2 ||
!mapEquals("com.docker.compose.network", "foo", n.Labels) ||
!mapEquals("com.docker.compose.project", "test", n.Labels) {
return fmt.Errorf("Network Labels is wrong: %v", n.Labels)
}
return nil
}
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: loadTestConfiguration(t, RESOURCE, "docker_network", "testAccDockerNetworkConfigFull"),
Check: resource.ComposeTestCheckFunc(
testAccNetwork(resourceName, &n),
testCheckNetworkInspect,
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}
// TODO mavogel: add full network config test in #74 (import resources)
func testAccNetwork(n string, network *types.NetworkResource) resource.TestCheckFunc {
return func(s *terraform.State) error {
@ -68,12 +154,6 @@ func testAccNetwork(n string, network *types.NetworkResource) resource.TestCheck
}
}
const testAccDockerNetworkConfig = `
resource "docker_network" "foo" {
name = "bar"
}
`
func TestAccDockerNetwork_internal(t *testing.T) {
var n types.NetworkResource
resourceName := "docker_network.foo"
@ -83,7 +163,7 @@ func TestAccDockerNetwork_internal(t *testing.T) {
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccDockerNetworkInternalConfig,
Config: loadTestConfiguration(t, RESOURCE, "docker_network", "testAccDockerNetworkInternalConfig"),
Check: resource.ComposeTestCheckFunc(
testAccNetwork(resourceName, &n),
testAccNetworkInternal(&n, true),
@ -107,13 +187,6 @@ func testAccNetworkInternal(network *types.NetworkResource, internal bool) resou
}
}
const testAccDockerNetworkInternalConfig = `
resource "docker_network" "foo" {
name = "bar"
internal = true
}
`
func TestAccDockerNetwork_attachable(t *testing.T) {
var n types.NetworkResource
resourceName := "docker_network.foo"
@ -123,7 +196,7 @@ func TestAccDockerNetwork_attachable(t *testing.T) {
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccDockerNetworkAttachableConfig,
Config: loadTestConfiguration(t, RESOURCE, "docker_network", "testAccDockerNetworkAttachableConfig"),
Check: resource.ComposeTestCheckFunc(
testAccNetwork(resourceName, &n),
testAccNetworkAttachable(&n, true),
@ -147,46 +220,74 @@ func testAccNetworkAttachable(network *types.NetworkResource, attachable bool) r
}
}
const testAccDockerNetworkAttachableConfig = `
resource "docker_network" "foo" {
name = "bar"
attachable = true
}
`
func TestAccDockerNetwork_ingress(t *testing.T) {
ctx := context.Background()
var n types.NetworkResource
//func TestAccDockerNetwork_ingress(t *testing.T) {
// var n types.NetworkResource
//
// resource.Test(t, resource.TestCase{
// PreCheck: func() { testAccPreCheck(t) },
// ProviderFactories: providerFactories,
// Steps: []resource.TestStep{
// resource.TestStep{
// Config: testAccDockerNetworkIngressConfig,
// Check: resource.ComposeTestCheckFunc(
// testAccNetwork("docker_network.foo", &n),
// testAccNetworkIngress(&n, true),
// ),
// },
// },
// })
//}
//
//func testAccNetworkIngress(network *types.NetworkResource, internal bool) resource.TestCheckFunc {
// return func(s *terraform.State) error {
// if network.Internal != internal {
// return fmt.Errorf("Bad value for attribute 'ingress': %t", network.Ingress)
// }
// return nil
// }
//}
//
//const testAccDockerNetworkIngressConfig = `
//resource "docker_network" "foo" {
// name = "bar"
// ingress = true
//}
//`
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
// as we join the swarm an ingress network is created by default
// As only one can exist, we remove it for the test
removeSwarmIngressNetwork(ctx, t)
},
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: loadTestConfiguration(t, RESOURCE, "docker_network", "testAccDockerNetworkIngressConfig"),
Check: resource.ComposeTestCheckFunc(
testAccNetwork("docker_network.foo", &n),
testAccNetworkIngress(&n, true),
),
},
},
CheckDestroy: func(state *terraform.State) error {
// we leave the swarm because in the next testAccPreCheck
// the node will join the swarm again
// and so recreate the default swarm ingress network
return nodeLeaveSwarm(ctx, t)
},
})
}
func removeSwarmIngressNetwork(ctx context.Context, t *testing.T) {
client := testAccProvider.Meta().(*ProviderConfig).DockerClient
networks, err := client.NetworkList(ctx, types.NetworkListOptions{})
if err != nil {
t.Errorf("failed to list swarm networks: %v", err)
}
var ingressNetworkID string
for _, network := range networks {
if network.Ingress {
ingressNetworkID = network.ID
break
}
}
err = client.NetworkRemove(ctx, ingressNetworkID)
if err != nil {
t.Errorf("failed to remove swarm ingress network '%s': %v", ingressNetworkID, err)
}
}
func nodeLeaveSwarm(ctx context.Context, t *testing.T) error {
client := testAccProvider.Meta().(*ProviderConfig).DockerClient
force := true
err := client.SwarmLeave(ctx, force)
if err != nil {
t.Errorf("node failed to leave the swarm: %v", err)
}
return nil
}
func testAccNetworkIngress(network *types.NetworkResource, ingress bool) resource.TestCheckFunc {
return func(s *terraform.State) error {
if network.Ingress != ingress {
return fmt.Errorf("Bad value for attribute 'ingress': %t", network.Ingress)
}
return nil
}
}
func TestAccDockerNetwork_ipv4(t *testing.T) {
var n types.NetworkResource
@ -197,7 +298,7 @@ func TestAccDockerNetwork_ipv4(t *testing.T) {
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccDockerNetworkIPv4Config,
Config: loadTestConfiguration(t, RESOURCE, "docker_network", "testAccDockerNetworkIPv4Config"),
Check: resource.ComposeTestCheckFunc(
testAccNetwork(resourceName, &n),
testAccNetworkIPv4(&n, true),
@ -224,17 +325,8 @@ func testAccNetworkIPv4(network *types.NetworkResource, internal bool) resource.
}
}
const testAccDockerNetworkIPv4Config = `
resource "docker_network" "foo" {
name = "bar"
ipam_config {
subnet = "10.0.1.0/24"
}
}
`
func TestAccDockerNetwork_ipv6(t *testing.T) {
t.Skip("mavogel: need to fix ipv6 network state")
t.Skip("TODO mavogel: need to fix ipv6 network state")
var n types.NetworkResource
resourceName := "docker_network.foo"
@ -243,14 +335,14 @@ func TestAccDockerNetwork_ipv6(t *testing.T) {
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccDockerNetworkIPv6Config,
Config: loadTestConfiguration(t, RESOURCE, "docker_network", "testAccDockerNetworkIPv6Config"),
Check: resource.ComposeTestCheckFunc(
testAccNetwork(resourceName, &n),
testAccNetworkIPv6(&n, true),
),
},
// TODO mavogel: ipam config goes from 2->1
// probably suppress diff -> #219
// probably suppress diff -> #74 (import resources)
{
ResourceName: resourceName,
ImportState: true,
@ -275,20 +367,6 @@ func testAccNetworkIPv6(network *types.NetworkResource, internal bool) resource.
}
}
const testAccDockerNetworkIPv6Config = `
resource "docker_network" "foo" {
name = "bar"
ipv6 = true
ipam_config {
subnet = "fd00::1/64"
}
# TODO mavogel: Would work but BC - 219
# ipam_config {
# subnet = "10.0.1.0/24"
# }
}
`
func TestAccDockerNetwork_labels(t *testing.T) {
var n types.NetworkResource
resourceName := "docker_network.foo"
@ -298,7 +376,7 @@ func TestAccDockerNetwork_labels(t *testing.T) {
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccDockerNetworkLabelsConfig,
Config: loadTestConfiguration(t, RESOURCE, "docker_network", "testAccDockerNetworkLabelsConfig"),
Check: resource.ComposeTestCheckFunc(
testAccNetwork(resourceName, &n),
testCheckLabelMap(resourceName, "labels",
@ -317,26 +395,3 @@ func TestAccDockerNetwork_labels(t *testing.T) {
},
})
}
func testAccNetworkLabel(network *types.NetworkResource, name string, value string) resource.TestCheckFunc { //nolint:deadcode,unused
return func(s *terraform.State) error {
if network.Labels[name] != value {
return fmt.Errorf("Bad value for label '%s': %s", name, network.Labels[name])
}
return nil
}
}
const testAccDockerNetworkLabelsConfig = `
resource "docker_network" "foo" {
name = "test_foo"
labels {
label = "com.docker.compose.network"
value = "foo"
}
labels {
label = "com.docker.compose.project"
value = "test"
}
}
`

View file

@ -2,6 +2,7 @@ package provider
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"log"
@ -23,7 +24,7 @@ func resourceDockerPluginCreate(d *schema.ResourceData, meta interface{}) error
RemoteRef: pluginName,
AcceptAllPermissions: d.Get("grant_all_permissions").(bool),
Disabled: !d.Get("enabled").(bool),
// TODO support other settings
// TODO suzuki-shunsuke: support other settings
Args: getDockerPluginEnv(d.Get("env")),
}
if v, ok := d.GetOk("grant_permissions"); ok {
@ -56,6 +57,10 @@ func resourceDockerPluginRead(d *schema.ResourceData, meta interface{}) error {
d.SetId("")
return nil
}
jsonObj, _ := json.MarshalIndent(plugin, "", "\t")
log.Printf("[DEBUG] Docker plugin inspect from readFunc: %s", jsonObj)
setDockerPlugin(d, plugin)
return nil
}
@ -161,7 +166,7 @@ func setDockerPlugin(d *schema.ResourceData, plugin *types.Plugin) {
d.Set("alias", plugin.Name)
d.Set("name", plugin.PluginReference)
d.Set("enabled", plugin.Enabled)
// TODO support other settings
// TODO suzuki-shunsuke support other settings
// https://docs.docker.com/engine/reference/commandline/plugin_set/#extended-description
// source of mounts .Settings.Mounts
// path of devices .Settings.Devices

View file

@ -1,12 +1,15 @@
package provider
import (
"context"
"fmt"
"reflect"
"testing"
"github.com/docker/docker/api/types"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)
func Test_getDockerPluginEnv(t *testing.T) {
@ -234,7 +237,7 @@ func TestAccDockerPlugin_basic(t *testing.T) {
Steps: []resource.TestStep{
{
ResourceName: resourceName,
Config: testAccDockerPluginMinimum,
Config: loadTestConfiguration(t, RESOURCE, "docker_plugin", "testAccDockerPluginMinimum"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", "docker.io/tiborvass/sample-volume-plugin:latest"),
resource.TestCheckResourceAttr(resourceName, "plugin_reference", "docker.io/tiborvass/sample-volume-plugin:latest"),
@ -244,7 +247,7 @@ func TestAccDockerPlugin_basic(t *testing.T) {
},
{
ResourceName: resourceName,
Config: testAccDockerPluginAlias,
Config: loadTestConfiguration(t, RESOURCE, "docker_plugin", "testAccDockerPluginAlias"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", "docker.io/tiborvass/sample-volume-plugin:latest"),
resource.TestCheckResourceAttr(resourceName, "plugin_reference", "docker.io/tiborvass/sample-volume-plugin:latest"),
@ -254,7 +257,7 @@ func TestAccDockerPlugin_basic(t *testing.T) {
},
{
ResourceName: resourceName,
Config: testAccDockerPluginDisableWhenSet,
Config: loadTestConfiguration(t, RESOURCE, "docker_plugin", "testAccDockerPluginDisableWhenSet"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", "docker.io/tiborvass/sample-volume-plugin:latest"),
resource.TestCheckResourceAttr(resourceName, "plugin_reference", "docker.io/tiborvass/sample-volume-plugin:latest"),
@ -267,7 +270,7 @@ func TestAccDockerPlugin_basic(t *testing.T) {
},
{
ResourceName: resourceName,
Config: testAccDockerPluginDisabled,
Config: loadTestConfiguration(t, RESOURCE, "docker_plugin", "testAccDockerPluginDisabled"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", "docker.io/tiborvass/sample-volume-plugin:latest"),
resource.TestCheckResourceAttr(resourceName, "plugin_reference", "docker.io/tiborvass/sample-volume-plugin:latest"),
@ -287,6 +290,51 @@ func TestAccDockerPlugin_basic(t *testing.T) {
})
}
func TestAccDockerPlugin_full(t *testing.T) {
const resourceName = "docker_plugin.test"
var p types.Plugin
testCheckPluginInspect := func(*terraform.State) error {
if p.Enabled != false {
return fmt.Errorf("Plugin Enabled is wrong: %v", p.Enabled)
}
return nil
}
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
ResourceName: resourceName,
Config: loadTestConfiguration(t, RESOURCE, "docker_plugin", "testAccDockerPluginFull"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", "docker.io/tiborvass/sample-volume-plugin:latest"),
resource.TestCheckResourceAttr(resourceName, "plugin_reference", "docker.io/tiborvass/sample-volume-plugin:latest"),
resource.TestCheckResourceAttr(resourceName, "alias", "sample:latest"),
resource.TestCheckResourceAttr(resourceName, "enabled", "false"),
resource.TestCheckResourceAttr(resourceName, "force_destroy", "true"),
resource.TestCheckResourceAttr(resourceName, "enable_timeout", "60"),
resource.TestCheckResourceAttr(resourceName, "force_disable", "true"),
resource.TestCheckResourceAttr(resourceName, "env.#", "1"),
resource.TestCheckResourceAttr(resourceName, "env.0", "DEBUG=1"),
resource.TestCheckResourceAttr(resourceName, "grant_permissions.#", "1"),
resource.TestCheckResourceAttr(resourceName, "grant_permissions.0.name", "network"),
resource.TestCheckResourceAttr(resourceName, "grant_permissions.0.value.#", "1"),
resource.TestCheckResourceAttr(resourceName, "grant_permissions.0.value.0", "host"),
testAccPluginCreated(resourceName, &p),
testCheckPluginInspect,
),
},
{
ResourceName: resourceName,
ImportState: true,
},
},
})
}
func TestAccDockerPlugin_grantAllPermissions(t *testing.T) {
const resourceName = "docker_plugin.test"
resource.Test(t, resource.TestCase{
@ -295,7 +343,7 @@ func TestAccDockerPlugin_grantAllPermissions(t *testing.T) {
Steps: []resource.TestStep{
{
ResourceName: resourceName,
Config: testAccDockerPluginGrantAllPermissions,
Config: loadTestConfiguration(t, RESOURCE, "docker_plugin", "testAccDockerPluginGrantAllPermissions"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", "docker.io/vieux/sshfs:latest"),
resource.TestCheckResourceAttr(resourceName, "plugin_reference", "docker.io/vieux/sshfs:latest"),
@ -319,7 +367,7 @@ func TestAccDockerPlugin_grantPermissions(t *testing.T) {
Steps: []resource.TestStep{
{
ResourceName: resourceName,
Config: testAccDockerPluginGrantPermissions,
Config: loadTestConfiguration(t, RESOURCE, "docker_plugin", "testAccDockerPluginGrantPermissions"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "name", "docker.io/vieux/sshfs:latest"),
resource.TestCheckResourceAttr(resourceName, "plugin_reference", "docker.io/vieux/sshfs:latest"),
@ -334,81 +382,28 @@ func TestAccDockerPlugin_grantPermissions(t *testing.T) {
})
}
const testAccDockerPluginMinimum = `
resource "docker_plugin" "test" {
name = "docker.io/tiborvass/sample-volume-plugin:latest"
force_destroy = true
}`
func testAccPluginCreated(resourceName string, plugin *types.Plugin) resource.TestCheckFunc {
return func(s *terraform.State) error {
ctx := context.Background()
rs, ok := s.RootModule().Resources[resourceName]
if !ok {
return fmt.Errorf("Resource with name '%s' not found in state", resourceName)
}
const testAccDockerPluginAlias = `
resource "docker_plugin" "test" {
name = "docker.io/tiborvass/sample-volume-plugin:latest"
alias = "sample:latest"
force_destroy = true
}`
if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}
const testAccDockerPluginDisableWhenSet = `
resource "docker_plugin" "test" {
name = "docker.io/tiborvass/sample-volume-plugin:latest"
alias = "sample:latest"
grant_all_permissions = true
force_destroy = true
enable_timeout = 60
env = [
"DEBUG=1"
]
}`
client := testAccProvider.Meta().(*ProviderConfig).DockerClient
inspectedPlugin, _, err := client.PluginInspectWithRaw(ctx, rs.Primary.ID)
if err != nil {
return fmt.Errorf("Plugin with ID '%s': %w", rs.Primary.ID, err)
}
const testAccDockerPluginDisabled = `
resource "docker_plugin" "test" {
name = "docker.io/tiborvass/sample-volume-plugin:latest"
alias = "sample:latest"
enabled = false
grant_all_permissions = true
force_destroy = true
force_disable = true
enable_timeout = 60
env = [
"DEBUG=1"
]
}`
// we set the value to the pointer to be able to use the value
// outside of the function
plugin = inspectedPlugin
return nil
// To install this plugin, it is required to grant required permissions.
const testAccDockerPluginGrantAllPermissions = `
resource "docker_plugin" "test" {
name = "docker.io/vieux/sshfs:latest"
grant_all_permissions = true
force_destroy = true
}`
// To install this plugin, it is required to grant required permissions.
const testAccDockerPluginGrantPermissions = `
resource "docker_plugin" "test" {
name = "vieux/sshfs"
force_destroy = true
grant_permissions {
name = "network"
value = [
"host"
]
}
grant_permissions {
name = "mount"
value = [
"",
"/var/lib/docker/plugins/"
]
}
grant_permissions {
name = "device"
value = [
"/dev/fuse"
]
}
grant_permissions {
name = "capabilities"
value = [
"CAP_SYS_ADMIN"
]
}
}`
}
}

View file

@ -30,6 +30,13 @@ func resourceDockerRegistryImage() *schema.Resource {
Optional: true,
},
"insecure_skip_verify": {
Type: schema.TypeBool,
Description: "If `true`, the verification of TLS certificates of the server/registry is disabled. Defaults to `false`",
Optional: true,
Default: false,
},
"build": {
Type: schema.TypeList,
Description: "Definition for building the image",

View file

@ -17,7 +17,6 @@ import (
"net/url"
"os"
"path/filepath"
"strconv"
"strings"
"time"
@ -50,7 +49,8 @@ func resourceDockerRegistryImageCreate(ctx context.Context, d *schema.ResourceDa
return diag.Errorf("Error pushing docker image: %s", err)
}
digest, err := getImageDigestWithFallback(pushOpts, username, password)
insecureSkipVerify := d.Get("insecure_skip_verify").(bool)
digest, err := getImageDigestWithFallback(pushOpts, username, password, insecureSkipVerify)
if err != nil {
return diag.Errorf("Unable to create image, image not found: %s", err)
}
@ -64,7 +64,9 @@ func resourceDockerRegistryImageRead(ctx context.Context, d *schema.ResourceData
name := d.Get("name").(string)
pushOpts := createPushImageOptions(name)
username, password := getDockerRegistryImageRegistryUserNameAndPassword(pushOpts, providerConfig)
digest, err := getImageDigestWithFallback(pushOpts, username, password)
insecureSkipVerify := d.Get("insecure_skip_verify").(bool)
digest, err := getImageDigestWithFallback(pushOpts, username, password, insecureSkipVerify)
if err != nil {
log.Printf("Got error getting registry image digest: %s", err)
d.SetId("")
@ -83,9 +85,9 @@ func resourceDockerRegistryImageDelete(ctx context.Context, d *schema.ResourceDa
pushOpts := createPushImageOptions(name)
username, password := getDockerRegistryImageRegistryUserNameAndPassword(pushOpts, providerConfig)
digest := d.Get("sha256_digest").(string)
err := deleteDockerRegistryImage(pushOpts, digest, username, password, false)
err := deleteDockerRegistryImage(pushOpts, digest, username, password, true, false)
if err != nil {
err = deleteDockerRegistryImage(pushOpts, pushOpts.Tag, username, password, true)
err = deleteDockerRegistryImage(pushOpts, pushOpts.Tag, username, password, true, true)
if err != nil {
return diag.Errorf("Got error getting registry image digest: %s", err)
}
@ -406,22 +408,11 @@ func getDockerRegistryImageRegistryUserNameAndPassword(
return username, password
}
func deleteDockerRegistryImage(pushOpts internalPushImageOptions, sha256Digest, username, password string, fallback bool) error {
func deleteDockerRegistryImage(pushOpts internalPushImageOptions, sha256Digest, username, password string, insecureSkipVerify, fallback bool) error {
client := http.DefaultClient
// Allow insecure registries only for ACC tests
// cuz we don't have a valid certs for this case
if env, okEnv := os.LookupEnv("TF_ACC"); okEnv {
if i, errConv := strconv.Atoi(env); errConv == nil && i >= 1 {
// DevSkim: ignore DS440000
cfg := &tls.Config{
InsecureSkipVerify: true,
}
client.Transport = &http.Transport{
TLSClientConfig: cfg,
}
}
}
// DevSkim: ignore DS440000
client.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: insecureSkipVerify}}
req, err := http.NewRequest("DELETE", pushOpts.NormalizedRegistry+"/v2/"+pushOpts.Repository+"/manifests/"+sha256Digest, nil)
if err != nil {
@ -511,10 +502,10 @@ func deleteDockerRegistryImage(pushOpts internalPushImageOptions, sha256Digest,
}
}
func getImageDigestWithFallback(opts internalPushImageOptions, username, password string) (string, error) {
digest, err := getImageDigest(opts.Registry, opts.Repository, opts.Tag, username, password, false)
func getImageDigestWithFallback(opts internalPushImageOptions, username, password string, insecureSkipVerify bool) (string, error) {
digest, err := getImageDigest(opts.Registry, opts.Repository, opts.Tag, username, password, insecureSkipVerify, false)
if err != nil {
digest, err = getImageDigest(opts.Registry, opts.Repository, opts.Tag, username, password, true)
digest, err = getImageDigest(opts.Registry, opts.Repository, opts.Tag, username, password, insecureSkipVerify, true)
if err != nil {
return "", fmt.Errorf("unable to get digest: %s", err)
}

View file

@ -104,7 +104,7 @@ func TestAccDockerRegistryImageResource_mapping(t *testing.T) {
},
Steps: []resource.TestStep{
{
Config: testBuildDockerRegistryImageMappingConfig,
Config: loadTestConfiguration(t, RESOURCE, "docker_registry_image", "testBuildDockerRegistryImageMappingConfig"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("docker_registry_image.foo", "sha256_digest"),
),
@ -120,35 +120,37 @@ func TestAccDockerRegistryImageResource_build(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
CheckDestroy: testDockerRegistryImageNotInRegistry(pushOptions),
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(testBuildDockerRegistryImageNoKeepConfig, pushOptions.Registry, pushOptions.Name, context),
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_registry_image", "testBuildDockerRegistryImageNoKeepConfig"), pushOptions.Registry, pushOptions.Name, context),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("docker_registry_image.foo", "sha256_digest"),
),
},
},
CheckDestroy: testDockerRegistryImageNotInRegistry(pushOptions),
})
}
func TestAccDockerRegistryImageResource_buildAndKeep(t *testing.T) {
t.Skip("mavogel: need to check")
pushOptions := createPushImageOptions("127.0.0.1:15000/tftest-dockerregistryimage:1.0")
wd, _ := os.Getwd()
context := strings.ReplaceAll(filepath.Join(wd, "..", "..", "scripts", "testing", "docker_registry_image_context"), "\\", "\\\\")
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
CheckDestroy: testDockerRegistryImageInRegistry(pushOptions, true),
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(testBuildDockerRegistryImageKeepConfig, pushOptions.Registry, pushOptions.Name, context),
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_registry_image", "testBuildDockerRegistryImageKeepConfig"), pushOptions.Registry, pushOptions.Name, context),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("docker_registry_image.foo", "sha256_digest"),
),
},
},
// as the providerConfig obtained from testAccProvider.Meta().(*ProviderConfig)
// is empty after the test the credetials are passed here manually
CheckDestroy: testDockerRegistryImageInRegistry("testuser", "testpwd", pushOptions, true),
})
}
@ -158,7 +160,7 @@ func TestAccDockerRegistryImageResource_pushMissingImage(t *testing.T) {
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testDockerRegistryImagePushMissingConfig,
Config: loadTestConfiguration(t, RESOURCE, "docker_registry_image", "testDockerRegistryImagePushMissingConfig"),
ExpectError: regexp.MustCompile("An image does not exist locally"),
},
},
@ -169,7 +171,7 @@ func testDockerRegistryImageNotInRegistry(pushOpts internalPushImageOptions) res
return func(s *terraform.State) error {
providerConfig := testAccProvider.Meta().(*ProviderConfig)
username, password := getDockerRegistryImageRegistryUserNameAndPassword(pushOpts, providerConfig)
digest, _ := getImageDigestWithFallback(pushOpts, username, password)
digest, _ := getImageDigestWithFallback(pushOpts, username, password, true)
if digest != "" {
return fmt.Errorf("image found")
}
@ -177,132 +179,18 @@ func testDockerRegistryImageNotInRegistry(pushOpts internalPushImageOptions) res
}
}
// TODO mavogel
//nolint:unused
func testDockerRegistryImageInRegistry(pushOpts internalPushImageOptions, cleanup bool) resource.TestCheckFunc {
func testDockerRegistryImageInRegistry(username, password string, pushOpts internalPushImageOptions, cleanup bool) resource.TestCheckFunc {
return func(s *terraform.State) error {
providerConfig := testAccProvider.Meta().(*ProviderConfig)
username, password := getDockerRegistryImageRegistryUserNameAndPassword(pushOpts, providerConfig)
digest, err := getImageDigestWithFallback(pushOpts, username, password)
digest, err := getImageDigestWithFallback(pushOpts, username, password, true)
if err != nil || len(digest) < 1 {
return fmt.Errorf("image not found")
return fmt.Errorf("image '%s' with credentials('%s' - '%s') not found: %w", pushOpts.Name, username, password, err)
}
if cleanup {
err := deleteDockerRegistryImage(pushOpts, digest, username, password, false)
err := deleteDockerRegistryImage(pushOpts, digest, username, password, true, false)
if err != nil {
return fmt.Errorf("Unable to remove test image. %s", err)
return fmt.Errorf("Unable to remove test image '%s': %w", pushOpts.Name, err)
}
}
return nil
}
}
const testBuildDockerRegistryImageMappingConfig = `
resource "docker_registry_image" "foo" {
name = "localhost:15000/foo:1.0"
build {
suppress_output = true
remote_context = "fooRemoteContext"
no_cache = true
remove = true
force_remove = true
pull_parent = true
isolation = "hyperv"
cpu_set_cpus = "fooCpuSetCpus"
cpu_set_mems = "fooCpuSetMems"
cpu_shares = 4
cpu_quota = 5
cpu_period = 6
memory = 1
memory_swap = 2
cgroup_parent = "fooCgroupParent"
network_mode = "fooNetworkMode"
shm_size = 3
dockerfile = "fooDockerfile"
ulimit {
name = "foo"
hard = 1
soft = 2
}
auth_config {
host_name = "foo.host"
user_name = "fooUserName"
password = "fooPassword"
auth = "fooAuth"
email = "fooEmail"
server_address = "fooServerAddress"
identity_token = "fooIdentityToken"
registry_token = "fooRegistryToken"
}
build_args = {
"HTTP_PROXY" = "http://10.20.30.2:1234"
}
context = "context"
labels = {
foo = "bar"
}
squash = true
cache_from = ["fooCacheFrom", "barCacheFrom"]
security_opt = ["fooSecurityOpt", "barSecurityOpt"]
extra_hosts = ["fooExtraHost", "barExtraHost"]
target = "fooTarget"
session_id = "fooSessionId"
platform = "fooPlatform"
version = "1"
build_id = "fooBuildId"
}
}
`
const testBuildDockerRegistryImageNoKeepConfig = `
provider "docker" {
alias = "private"
registry_auth {
address = "%s"
}
}
resource "docker_registry_image" "foo" {
provider = "docker.private"
name = "%s"
build {
context = "%s"
remove = true
force_remove = true
no_cache = true
}
}
`
const testBuildDockerRegistryImageKeepConfig = `
provider "docker" {
alias = "private"
registry_auth {
address = "%s"
}
}
resource "docker_registry_image" "foo" {
provider = "docker.private"
name = "%s"
keep_remotely = true
build {
context = "%s"
remove = true
force_remove = true
no_cache = true
}
}
`
const testDockerRegistryImagePushMissingConfig = `
provider "docker" {
alias = "private"
registry_auth {
address = "127.0.0.1:15000"
}
}
resource "docker_registry_image" "foo" {
provider = "docker.private"
name = "127.0.0.1:15000/nonexistent:1.0"
}
`

View file

@ -3,6 +3,7 @@ package provider
import (
"context"
"encoding/base64"
"encoding/json"
"log"
"github.com/docker/docker/api/types/swarm"
@ -120,6 +121,10 @@ func resourceDockerSecretRead(ctx context.Context, d *schema.ResourceData, meta
d.SetId("")
return nil
}
jsonObj, _ := json.MarshalIndent(secret, "", "\t")
log.Printf("[DEBUG] Docker secret inspect from readFunc: %s", jsonObj)
d.SetId(secret.ID)
d.Set("name", secret.Spec.Name)
// Note mavogel: secret data is not exposed via the API

View file

@ -5,12 +5,27 @@ import (
"fmt"
"testing"
"github.com/docker/docker/api/types/swarm"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)
func TestAccDockerSecret_basic(t *testing.T) {
ctx := context.Background()
var s swarm.Secret
testCheckSecretInspect := func(*terraform.State) error {
if s.Spec.Name == "" {
return fmt.Errorf("Secret Spec.Name is wrong: %v", s.Spec.Name)
}
if len(s.Spec.Labels) != 1 || !mapEquals("foo", "bar", s.Spec.Labels) {
return fmt.Errorf("Secret Spec.Labels is wrong: %v", s.Spec.Labels)
}
return nil
}
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
@ -23,11 +38,18 @@ func TestAccDockerSecret_basic(t *testing.T) {
resource "docker_secret" "foo" {
name = "foo-secret"
data = "Ymxhc2RzYmxhYmxhMTI0ZHNkd2VzZA=="
labels {
label = "foo"
value = "bar"
}
}
`,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("docker_secret.foo", "name", "foo-secret"),
resource.TestCheckResourceAttr("docker_secret.foo", "data", "Ymxhc2RzYmxhYmxhMTI0ZHNkd2VzZA=="),
testAccServiceSecretCreated("docker_secret.foo", &s),
testCheckSecretInspect,
),
},
},
@ -50,7 +72,7 @@ func TestAccDockerSecret_basicUpdatable(t *testing.T) {
data = "Ymxhc2RzYmxhYmxhMTI0ZHNkd2VzZA=="
lifecycle {
ignore_changes = ["name"]
ignore_changes = ["name"]
create_before_destroy = true
}
}
@ -66,7 +88,7 @@ func TestAccDockerSecret_basicUpdatable(t *testing.T) {
data = "U3VuIDI1IE1hciAyMDE4IDE0OjUzOjIxIENFU1QK"
lifecycle {
ignore_changes = ["name"]
ignore_changes = ["name"]
create_before_destroy = true
}
}
@ -134,3 +156,29 @@ func testCheckDockerSecretDestroy(ctx context.Context, s *terraform.State) error
}
return nil
}
func testAccServiceSecretCreated(resourceName string, secret *swarm.Secret) resource.TestCheckFunc {
return func(s *terraform.State) error {
ctx := context.Background()
rs, ok := s.RootModule().Resources[resourceName]
if !ok {
return fmt.Errorf("Resource with name '%s' not found in state", resourceName)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}
client := testAccProvider.Meta().(*ProviderConfig).DockerClient
inspectedSecret, _, err := client.SecretInspectWithRaw(ctx, rs.Primary.ID)
if err != nil {
return fmt.Errorf("Secret with ID '%s': %w", rs.Primary.ID, err)
}
// we set the value to the pointer to be able to use the value
// outside of the function
*secret = inspectedSecret
return nil
}
}

View file

@ -612,19 +612,14 @@ func fromRegistryAuth(image string, authConfigs map[string]types.AuthConfig) typ
// retrieveAndMarshalAuth retrieves and marshals the service registry auth
func retrieveAndMarshalAuth(d *schema.ResourceData, meta interface{}, stageType string) []byte {
var auth types.AuthConfig
if v, ok := d.GetOk("auth"); ok {
auth = authToServiceAuth(v.([]interface{}))
// when a service is updated/set for the first time the auth is set but empty
// this is why we need this additional check
if rawAuth, ok := d.GetOk("auth"); ok && len(rawAuth.([]interface{})) != 0 {
log.Printf("[DEBUG] Getting configs from service auth '%v'", rawAuth)
auth = authToServiceAuth(rawAuth.([]interface{}))
} else {
authConfigs := meta.(*ProviderConfig).AuthConfigs.Configs
if len(authConfigs) == 0 {
log.Printf("[DEBUG] AuthConfigs empty on %s. Wait 3s and try again", stageType)
// sometimes the dockerconfig is read succesfully from disk but the
// call to create/update the service is faster. So we delay to prevent the
// passing of an empty auth configuration in this case
<-time.After(3 * time.Second)
authConfigs = meta.(*ProviderConfig).AuthConfigs.Configs
}
log.Printf("[DEBUG] Getting configs from '%v'", authConfigs)
log.Printf("[DEBUG] Getting configs from provider auth '%v'", authConfigs)
auth = fromRegistryAuth(d.Get("task_spec.0.container_spec.0.image").(string), authConfigs)
}

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,7 @@ package provider
import (
"context"
"encoding/json"
"log"
"strings"
"time"
@ -110,19 +111,20 @@ func resourceDockerVolumeCreate(ctx context.Context, d *schema.ResourceData, met
func resourceDockerVolumeRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*ProviderConfig).DockerClient
var err error
var retVolume types.Volume
retVolume, err = client.VolumeInspect(ctx, d.Id())
volume, err := client.VolumeInspect(ctx, d.Id())
if err != nil {
return diag.Errorf("Unable to inspect volume: %s", err)
}
d.Set("name", retVolume.Name)
d.Set("labels", mapToLabelSet(retVolume.Labels))
d.Set("driver", retVolume.Driver)
d.Set("driver_opts", retVolume.Options)
d.Set("mountpoint", retVolume.Mountpoint)
jsonObj, _ := json.MarshalIndent(volume, "", "\t")
log.Printf("[DEBUG] Docker volume inspect from readFunc: %s", jsonObj)
d.Set("name", volume.Name)
d.Set("labels", mapToLabelSet(volume.Labels))
d.Set("driver", volume.Driver)
d.Set("driver_opts", volume.Options)
d.Set("mountpoint", volume.Mountpoint)
return nil
}

View file

@ -18,9 +18,13 @@ func TestAccDockerVolume_basic(t *testing.T) {
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccDockerVolumeConfig,
Config: `
resource "docker_volume" "foo" {
name = "testAccDockerVolume_basic"
}
`,
Check: resource.ComposeTestCheckFunc(
checkDockerVolume("docker_volume.foo", &v),
checkDockerVolumeCreated("docker_volume.foo", &v),
resource.TestCheckResourceAttr("docker_volume.foo", "id", "testAccDockerVolume_basic"),
resource.TestCheckResourceAttr("docker_volume.foo", "name", "testAccDockerVolume_basic"),
),
@ -34,7 +38,96 @@ func TestAccDockerVolume_basic(t *testing.T) {
})
}
func checkDockerVolume(n string, volume *types.Volume) resource.TestCheckFunc {
func TestAccDockerVolume_full(t *testing.T) {
var v types.Volume
testCheckVolumeInspect := func(*terraform.State) error {
if v.Driver != "local" {
return fmt.Errorf("Volume Driver is wrong: %v", v.Driver)
}
if v.Labels == nil ||
!mapEquals("com.docker.compose.project", "test", v.Labels) ||
!mapEquals("com.docker.compose.volume", "foo", v.Labels) {
return fmt.Errorf("Volume Labels is wrong: %v", v.Labels)
}
if v.Options == nil ||
!mapEquals("device", "/dev/sda2", v.Options) ||
!mapEquals("type", "btrfs", v.Options) {
return fmt.Errorf("Volume Options is wrong: %v", v.Options)
}
if v.Scope != "local" {
return fmt.Errorf("Volume Scope is wrong: %v", v.Scope)
}
return nil
}
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: loadTestConfiguration(t, RESOURCE, "docker_volume", "testAccDockerVolumeFull"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("docker_volume.foo", "id", "testAccDockerVolume_full"),
resource.TestCheckResourceAttr("docker_volume.foo", "name", "testAccDockerVolume_full"),
checkDockerVolumeCreated("docker_volume.foo", &v),
testCheckVolumeInspect,
),
},
{
ResourceName: "docker_volume.foo",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func TestAccDockerVolume_labels(t *testing.T) {
var v types.Volume
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: `
resource "docker_volume" "foo" {
name = "test_foo"
labels {
label = "com.docker.compose.project"
value = "test"
}
labels {
label = "com.docker.compose.volume"
value = "foo"
}
}
`,
Check: resource.ComposeTestCheckFunc(
checkDockerVolumeCreated("docker_volume.foo", &v),
testCheckLabelMap("docker_volume.foo", "labels",
map[string]string{
"com.docker.compose.project": "test",
"com.docker.compose.volume": "foo",
},
),
),
},
{
ResourceName: "docker_volume.foo",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func checkDockerVolumeCreated(n string, volume *types.Volume) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
@ -57,60 +150,3 @@ func checkDockerVolume(n string, volume *types.Volume) resource.TestCheckFunc {
return nil
}
}
const testAccDockerVolumeConfig = `
resource "docker_volume" "foo" {
name = "testAccDockerVolume_basic"
}
`
func TestAccDockerVolume_labels(t *testing.T) {
var v types.Volume
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccDockerVolumeLabelsConfig,
Check: resource.ComposeTestCheckFunc(
checkDockerVolume("docker_volume.foo", &v),
testCheckLabelMap("docker_volume.foo", "labels",
map[string]string{
"com.docker.compose.project": "test",
"com.docker.compose.volume": "foo",
},
),
),
},
{
ResourceName: "docker_volume.foo",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func testAccVolumeLabel(volume *types.Volume, name string, value string) resource.TestCheckFunc { //nolint:deadcode,unused
return func(s *terraform.State) error {
if volume.Labels[name] != value {
return fmt.Errorf("Bad value for label '%s': %s", name, volume.Labels[name])
}
return nil
}
}
const testAccDockerVolumeLabelsConfig = `
resource "docker_volume" "foo" {
name = "test_foo"
labels {
label = "com.docker.compose.project"
value = "test"
}
labels {
label = "com.docker.compose.volume"
value = "foo"
}
}
`

View file

@ -0,0 +1,71 @@
package provider
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
)
// resourceType the type of the resource
type resourceType int
const (
RESOURCE resourceType = iota // a resource
DATA_SOURCE // a data-source
)
// String converts the the resourceType into
// the name of the directory the test configuartions
// are int
func (r resourceType) String() string {
return [...]string{
"resources",
"data-sources",
}[r]
}
const (
TEST_CONFIG_BASE_DIR = "testdata"
)
// loadTestConfiguration loads the configuration for the test for the type of the
// resource, the resource itself, like 'docker_container' and the name of the test,
// like 'testAccDockerContainerPrivateImage'
//
// As a convention the test configurations are in
// 'testdata/<resourceType>/<resourceName>/<testName>.tf', e.g.
// 'testdata/resources/docker_container/testAccDockerContainerPrivateImage.tf'
//
func loadTestConfiguration(t *testing.T, resourceType resourceType, resourceName, testName string) string {
wd, err := os.Getwd()
if err != nil {
t.Errorf("failed to get current working directory: %w", err)
}
testConfig := strings.ReplaceAll(filepath.Join(wd, "..", "..", TEST_CONFIG_BASE_DIR, resourceType.String(), resourceName, fmt.Sprintf("%s.tf", testName)), "\\", "\\\\")
testConfigContent, err := ioutil.ReadFile(testConfig)
if err != nil {
t.Errorf("failed to read test configuration at '%s': %w", testConfig, err)
}
return string(testConfigContent)
}
// mapEquals returns true if the expectedValue is found under the given key in
// the map. Otherwise returns false, as well when the map ist nil
func mapEquals(key, expectedValue string, m map[string]string) bool {
if m == nil {
return false
}
extractedValue, ok := m[key]
if ok && extractedValue == expectedValue {
return true
}
return false
}

View file

@ -18,14 +18,13 @@ RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH"
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
# Install docker
# see listed docker versions: 'apt-cache policy docker-ce'
RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - && \
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" && \
apt-get update
apt-get update \
apt-cache policy docker-ce
RUN apt-get -y install docker-ce=${DOCKER_CE_VERSION}
RUN sed 's/DOCKER_OPTS="/DOCKER_OPTS="--insecure-registry=127.0.0.1:15000 /g' -i /etc/default/docker && \
cat /etc/default/docker
# Install terraform
RUN curl -fsSL https://apt.releases.hashicorp.com/gpg | apt-key add - && \
apt-add-repository "deb [arch=$(dpkg --print-architecture)] https://apt.releases.hashicorp.com $(lsb_release -cs) main" && \

View file

@ -35,7 +35,7 @@ sleep 5
docker login -u testuser -p testpwd 127.0.0.1:15000
# Build private images
for i in $(seq 1 3); do
docker build -t tftest-service --build-arg JS_FILE_PATH=server_v${i}.js "$(pwd)"/scripts/testing -f "$(pwd)"/scripts/testing/Dockerfile
docker build -t tftest-service --build-arg MAIN_FILE_PATH=v${i}/main.go "$(pwd)"/scripts/testing -f "$(pwd)"/scripts/testing/Dockerfile
docker tag tftest-service 127.0.0.1:15000/tftest-service:v${i}
docker push 127.0.0.1:15000/tftest-service:v${i}
docker tag tftest-service 127.0.0.1:15000/tftest-service

View file

@ -1,11 +1,20 @@
FROM node:6.12.3-slim
FROM golang:1.16-alpine as builder
ARG MAIN_FILE_PATH
ARG JS_FILE_PATH
RUN echo "appuser:x:65534:65534:Appuser:/:" > /etc/passwd
WORKDIR /build
COPY $MAIN_FILE_PATH main.go
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -o server main.go
COPY configs.json .
COPY secrets.json .
COPY $JS_FILE_PATH server.js
FROM alpine
CMD [ "node", "server.js" ]
RUN apk add --no-cache curl
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /etc/passwd /etc/passwd
COPY configs.json /configs.json
COPY secrets.json /secrets.json
COPY --from=builder /build/server /server
USER appuser
ENTRYPOINT ["/server"]
EXPOSE 8080

View file

@ -1,17 +0,0 @@
var http = require('http');
var configs = require('./configs')
var secrets = require('./secrets')
var handleRequest = function(request, response) {
console.log('Received request for URL: ' + request.url);
if(request.url === '/health') {
response.writeHead(200);
response.end('ok');
} else {
response.writeHead(200);
response.end(configs.prefix + ' - Hello World!');
}
};
var www = http.createServer(handleRequest);
www.listen(8080);

View file

@ -1,20 +0,0 @@
var http = require('http');
var configs = require('./configs')
var secrets = require('./secrets')
var handleRequest = function(request, response) {
console.log('Received request for URL: ' + request.url);
if(request.url === '/health') {
response.writeHead(200);
response.end('ok');
} else if(request.url === '/newroute') {
response.writeHead(200);
response.end('new Route!');
} else {
response.writeHead(200);
response.end(configs.prefix + ' - Hello World!');
}
};
var www = http.createServer(handleRequest);
www.listen(8080);

View file

@ -1,11 +0,0 @@
var http = require('http');
var configs = require('./configs')
var secrets = require('./secrets')
var handleRequest = function (request, response) {
console.log('Received request for URL: ' + request.url);
response.writeHead(200);
response.end(configs.prefix + ' - Hello World!');
};
var www = http.createServer(handleRequest);
www.listen(8085); // changed here on purpose

View file

@ -0,0 +1,45 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
)
const listenAddr = ":8080"
type config struct {
Prefix string `json:"prefix"`
}
func main() {
configsContent, err := ioutil.ReadFile("configs.json")
if err != nil {
log.Fatalf("cannot open 'configs.json': %s", err)
}
var configs config
err = json.Unmarshal(configsContent, &configs)
if err != nil {
log.Fatalf("cannot unmarshal 'configs.json': %s", err)
}
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, err = w.Write([]byte(fmt.Sprintf("%s - Hello World!", configs.Prefix)))
if err != nil {
log.Fatalln("failed to write for path '/'")
}
})
err = http.ListenAndServe(listenAddr, nil)
if err != nil {
log.Fatalf("failed to listen and server on port '%s'", listenAddr)
}
}

View file

@ -0,0 +1,53 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
)
const listenAddr = ":8080"
type config struct {
Prefix string `json:"prefix"`
}
func main() {
configsContent, err := ioutil.ReadFile("configs.json")
if err != nil {
log.Fatalf("cannot open 'configs.json': %s", err)
}
var configs config
err = json.Unmarshal(configsContent, &configs)
if err != nil {
log.Fatalf("cannot unmarshal 'configs.json': %s", err)
}
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, err = w.Write([]byte(fmt.Sprintf("%s - Hello World!", configs.Prefix)))
if err != nil {
log.Fatalln("failed to write for path '/'")
}
})
http.HandleFunc("/newroute", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, err = w.Write([]byte("new Route!"))
if err != nil {
log.Fatalln("failed to write for path '/newroute'")
}
})
err = http.ListenAndServe(listenAddr, nil)
if err != nil {
log.Fatalf("failed to listen and server on port '%s'", listenAddr)
}
}

View file

@ -0,0 +1,45 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
)
const listenAddr = ":8085" // changed here on purpose
type config struct {
Prefix string `json:"prefix"`
}
func main() {
configsContent, err := ioutil.ReadFile("configs.json")
if err != nil {
log.Fatalf("cannot open 'configs.json': %s", err)
}
var configs config
err = json.Unmarshal(configsContent, &configs)
if err != nil {
log.Fatalf("cannot unmarshal 'configs.json': %s", err)
}
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, err = w.Write([]byte(fmt.Sprintf("%s - Hello World!", configs.Prefix)))
if err != nil {
log.Fatalln("failed to write for path '/'")
}
})
err = http.ListenAndServe(listenAddr, nil)
if err != nil {
log.Fatalf("failed to listen and server on port '%s'", listenAddr)
}
}

View file

@ -0,0 +1,3 @@
data "docker_network" "bridge" {
name = "bridge"
}

View file

@ -0,0 +1,3 @@
data "docker_plugin" "test" {
alias = "tiborvass/sample-volume-plugin:latest"
}

View file

@ -0,0 +1,11 @@
provider "docker" {
alias = "private"
registry_auth {
address = "%s"
}
}
data "docker_registry_image" "foobar" {
provider = "docker.private"
name = "%s"
insecure_skip_verify = true
}

View file

@ -0,0 +1,3 @@
data "docker_registry_image" "foo" {
name = "alpine:latest"
}

View file

@ -0,0 +1,3 @@
data "docker_registry_image" "bar" {
name = "gcr.io:443/google_containers/pause:0.8.0"
}

View file

@ -0,0 +1,28 @@
resource "docker_image" "foo" {
name = "nginx:latest"
keep_locally = true
}
resource "docker_network" "test_network_1" {
name = "tftest-1"
}
resource "docker_network" "test_network_2" {
name = "tftest-2"
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
network_mode = docker_network.test_network_1.name
networks = [docker_network.test_network_2.name]
network_alias = ["tftest-container"]
}
resource "docker_container" "bar" {
name = "tf-test-bar"
image = docker_image.foo.latest
network_mode = "bridge"
networks = [docker_network.test_network_2.name]
network_alias = ["tftest-container-foo"]
}

View file

@ -0,0 +1,11 @@
resource "docker_image" "foo" {
name = "busybox:latest"
keep_locally = true
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
command = ["/bin/sh", "-c", "for i in $(seq 1 15); do sleep 1; done"]
attach = true
must_run = false
}

View file

@ -0,0 +1,8 @@
resource "docker_image" "foo" {
name = "nginx:latest"
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
}

View file

@ -0,0 +1,83 @@
resource "docker_image" "foo" {
name = "nginx:latest"
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
entrypoint = ["/bin/bash", "-c", "cat /proc/kmsg"]
user = "root:root"
restart = "on-failure"
destroy_grace_seconds = 10
max_retry_count = 5
memory = 512
shm_size = 128
memory_swap = 2048
cpu_shares = 32
cpu_set = "0-1"
capabilities {
add = ["ALL"]
drop = ["SYS_ADMIN"]
}
security_opts = ["apparmor=unconfined", "label=disable"]
dns = ["8.8.8.8"]
dns_opts = ["rotate"]
dns_search = ["example.com"]
labels {
label = "env"
value = "prod"
}
labels {
label = "role"
value = "test"
}
labels {
label = "maintainer"
value = "NGINX Docker Maintainers <docker-maint@nginx.com>"
}
log_driver = "json-file"
log_opts = {
max-size = "10m"
max-file = 20
}
network_mode = "bridge"
networks_advanced {
name = docker_network.test_network.name
aliases = ["tftest"]
}
host {
host = "testhost"
ip = "10.0.1.0"
}
host {
host = "testhost2"
ip = "10.0.2.0"
}
ulimit {
name = "nproc"
hard = 1024
soft = 512
}
ulimit {
name = "nofile"
hard = 262144
soft = 200000
}
pid_mode = "host"
userns_mode = "testuser:231072:65536"
ipc_mode = "private"
working_dir = "/tmp"
}
resource "docker_network" "test_network" {
name = "test"
}

View file

@ -0,0 +1,14 @@
resource "docker_image" "foo" {
name = "nginx:latest"
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
devices {
host_path = "/dev/zero"
container_path = "/dev/zero_test"
permissions = "rwm"
}
}

View file

@ -0,0 +1,11 @@
resource "docker_image" "foo" {
name = "busybox:latest"
keep_locally = true
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
command = ["/bin/sh", "-c", "exit 123"]
attach = true
must_run = false
}

View file

@ -0,0 +1,12 @@
resource "docker_image" "foo" {
name = "nginx:latest"
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
group_add = [
100
]
}

View file

@ -0,0 +1,14 @@
resource "docker_image" "foo" {
name = "nginx:latest"
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
group_add = [
1,
2,
3,
]
}

View file

@ -0,0 +1,12 @@
resource "docker_image" "foo" {
name = "nginx:latest"
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
group_add = [
"users"
]
}

View file

@ -0,0 +1,17 @@
resource "docker_image" "foo" {
name = "nginx:latest"
keep_locally = true
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
healthcheck {
test = ["CMD", "/bin/true"]
interval = "30s"
timeout = "5s"
start_period = "15s"
retries = 10
}
}

View file

@ -0,0 +1,9 @@
resource "docker_image" "fooinit" {
name = "nginx:latest"
}
resource "docker_container" "fooinit" {
name = "tf-test"
image = docker_image.fooinit.latest
init = true
}

View file

@ -0,0 +1,13 @@
resource "docker_image" "foo" {
name = "nginx:latest"
keep_locally = true
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
ports {
internal = 80
}
}

View file

@ -0,0 +1,13 @@
resource "docker_image" "foo" {
name = "busybox:latest"
keep_locally = true
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
command = ["/bin/sh", "-c", "for i in $(seq 1 10); do echo \"$i\"; done"]
attach = true
logs = true
must_run = false
}

View file

@ -0,0 +1,23 @@
resource "docker_image" "foo_mounts" {
name = "nginx:latest"
}
resource "docker_volume" "foo_mounts" {
name = "testAccDockerContainerMounts_volume"
}
resource "docker_container" "foo_mounts" {
name = "tf-test"
image = docker_image.foo_mounts.latest
mounts {
target = "/mount/test"
source = docker_volume.foo_mounts.name
type = "volume"
read_only = true
}
mounts {
target = "/mount/tmpfs"
type = "tmpfs"
}
}

View file

@ -0,0 +1,17 @@
resource "docker_image" "foo" {
name = "nginx:latest"
keep_locally = true
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
ports {
internal = 80
}
ports {
internal = 81
}
}

View file

@ -0,0 +1,19 @@
resource "docker_image" "foo" {
name = "nginx:latest"
keep_locally = true
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
ports {
internal = 80
external = 32787
}
ports {
internal = 81
external = 32788
}
}

View file

@ -0,0 +1,25 @@
resource "docker_network" "test" {
name = "tf-test"
ipv6 = true
ipam_config {
subnet = "10.0.1.0/24"
}
ipam_config {
subnet = "fd00::1/64"
}
}
resource "docker_image" "foo" {
name = "nginx:latest"
keep_locally = true
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
networks_advanced {
name = docker_network.test.name
ipv4_address = "10.0.1.123"
ipv6_address = "fd00:0:0:0::123"
}
}

View file

@ -0,0 +1,18 @@
resource "docker_network" "test" {
name = "tf-test"
ipam_config {
subnet = "10.0.1.0/24"
}
}
resource "docker_image" "foo" {
name = "nginx:latest"
keep_locally = true
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
networks_advanced {
name = docker_network.test.name
ipv4_address = "10.0.1.123"
}
}

View file

@ -0,0 +1,20 @@
resource "docker_network" "test" {
name = "tf-test"
ipv6 = true
ipam_config {
subnet = "fd00::1/64"
gateway = "fd00:0:0:0::f"
}
}
resource "docker_image" "foo" {
name = "nginx:latest"
keep_locally = true
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
networks_advanced {
name = docker_network.test.name
ipv6_address = "fd00:0:0:0::123"
}
}

View file

@ -0,0 +1,11 @@
resource "docker_image" "foo" {
name = "nginx:latest"
keep_locally = true
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
start = false
must_run = false
}

View file

@ -0,0 +1,14 @@
resource "docker_image" "foo" {
name = "nginx:latest"
keep_locally = true
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
ports {
internal = 80
external = 32787
}
}

View file

@ -0,0 +1,19 @@
provider "docker" {
alias = "private"
registry_auth {
address = "%s"
config_file = "%s"
}
}
resource "docker_image" "foo" {
provider = "docker.private"
name = "%s"
keep_locally = true
}
resource "docker_container" "foo" {
provider = "docker.private"
name = "tf-test"
image = docker_image.foo.latest
}

View file

@ -0,0 +1,10 @@
resource "docker_image" "foo" {
name = "busybox:latest"
keep_locally = true
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
command = ["/bin/sleep", "15"]
read_only = true
}

View file

@ -0,0 +1,10 @@
resource "docker_image" "foo" {
name = "busybox:latest"
keep_locally = true
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
command = ["/bin/sleep", "15"]
rm = true
}

View file

@ -0,0 +1,9 @@
resource "docker_image" "foo" {
name = "nginx:latest"
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
stdin_open = true
}

View file

@ -0,0 +1,12 @@
resource "docker_image" "foo" {
name = "nginx:latest"
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
sysctls = {
"net.ipv4.ip_forward" = "1"
}
}

View file

@ -0,0 +1,9 @@
resource "docker_image" "foo" {
name = "nginx:latest"
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
tty = true
}

View file

@ -0,0 +1,12 @@
resource "docker_image" "foo" {
name = "nginx:latest"
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
tmpfs = {
"/mount/tmpfs" = "rw,noexec,nosuid"
}
}

View file

@ -0,0 +1,15 @@
resource "docker_image" "foo" {
name = "nginx:latest"
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
restart = "on-failure"
max_retry_count = 5
cpu_shares = 32
cpu_set = "0-1"
memory = 512
memory_swap = 2048
}

View file

@ -0,0 +1,20 @@
resource "docker_image" "foo" {
name = "nginx:latest"
keep_locally = true
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
upload {
content_base64 = base64encode("894fc3f56edf2d3a4c5fb5cb71df910f958a2ed8")
file = "/terraform/test1.txt"
executable = true
}
upload {
content = "foobar"
file = "/terraform/test2.txt"
}
}

View file

@ -0,0 +1,15 @@
resource "docker_image" "foo" {
name = "nginx:latest"
keep_locally = true
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
upload {
content = "foo"
file = "/terraform/test.txt"
executable = true
}
}

View file

@ -0,0 +1,15 @@
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
}
}

View file

@ -0,0 +1,16 @@
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
}
}

View file

@ -0,0 +1,18 @@
resource "docker_image" "foo" {
name = "nginx:latest"
}
resource "docker_volume" "foo" {
name = "testAccDockerContainerVolume_volume"
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
volumes {
volume_name = docker_volume.foo.name
container_path = "/tmp/volume"
read_only = false
}
}

View file

@ -0,0 +1,20 @@
resource "docker_network" "tftest" {
name = "tftest-contnw"
}
resource "docker_network" "tftest_2" {
name = "tftest-contnw-2"
}
resource "docker_image" "foo" {
name = "nginx:latest"
}
resource "docker_container" "foo" {
name = "tf-test"
image = docker_image.foo.latest
networks = [
docker_network.tftest.name,
docker_network.tftest_2.name
]
}

View file

@ -0,0 +1,3 @@
resource "docker_image" "foo" {
name = "alpine:3.1"
}

View file

@ -0,0 +1,7 @@
data "docker_registry_image" "foobarbaz" {
name = "alpine:3.1"
}
resource "docker_image" "foobarbaz" {
name = data.docker_registry_image.foobarbaz.name
pull_triggers = [data.docker_registry_image.foobarbaz.sha256_digest]
}

View file

@ -0,0 +1,7 @@
data "docker_registry_image" "foobarbazoo" {
name = "alpine:3.1"
}
resource "docker_image" "foobarbazoo" {
name = data.docker_registry_image.foobarbazoo.name
pull_trigger = data.docker_registry_image.foobarbazoo.sha256_digest
}

View file

@ -0,0 +1,17 @@
provider "docker" {
alias = "private"
registry_auth {
address = "%s"
}
}
data "docker_registry_image" "foo_private" {
provider = "docker.private"
name = "%s"
insecure_skip_verify = true
}
resource "docker_image" "foo_private" {
provider = "docker.private"
name = data.docker_registry_image.foo_private.name
keep_locally = true
pull_triggers = [data.docker_registry_image.foo_private.sha256_digest]
}

View file

@ -0,0 +1,11 @@
provider "docker" {
alias = "private"
registry_auth {
address = "%s"
config_file = "%s"
}
}
resource "docker_image" "foo_private" {
provider = "docker.private"
name = "%s"
}

View file

@ -0,0 +1,11 @@
provider "docker" {
alias = "private"
registry_auth {
address = "%s"
config_file_content = file("%s")
}
}
resource "docker_image" "foo_private" {
provider = "docker.private"
name = "%s"
}

View file

@ -0,0 +1,4 @@
resource "docker_image" "foobarzoo" {
name = "crux:3.1"
keep_locally = true
}

View file

@ -0,0 +1,3 @@
resource "docker_image" "nginx" {
name = "nginx:1.18.0-alpine@sha256:0c56c40f232f41c1b8341c3cc055c8b528cb6decefd7f7c8506e2d30bb9678b6"
}

View file

@ -0,0 +1,4 @@
resource "docker_image" "test" {
name = "alpine:3.11.5"
force_remove = true
}

View file

@ -0,0 +1,3 @@
resource "docker_image" "foobar" {
name = "stocard/gotthard@sha256:ed752380c07940c651b46c97ca2101034b3be112f4d86198900aa6141f37fe7b"
}

View file

@ -0,0 +1,3 @@
resource "docker_image" "foobar" {
name = "gcr.io:443/google_containers/pause:0.8.0"
}

View file

@ -0,0 +1,15 @@
resource "docker_image" "test" {
name = "ubuntu:11"
build {
path = "."
dockerfile = "Dockerfile"
force_remove = true
build_arg = {
test_arg = "kenobi"
}
label = {
test_label1 = "han"
test_label2 = "solo"
}
}
}

View file

@ -0,0 +1,4 @@
resource "docker_network" "foo" {
name = "bar"
attachable = true
}

View file

@ -0,0 +1,3 @@
resource "docker_network" "foo" {
name = "bar"
}

Some files were not shown because too many files have changed in this diff Show more