mirror of
https://github.com/kreuzwerker/terraform-provider-docker.git
synced 2025-12-18 23:06:10 -05:00
fix/service image name (#212)
* fix(service): remove image name suppress function * feat: add docker image data-source * docs(service): add example for iamge datasource usage * fix: image repo digest with tag determination * fix: always return a repoDigest * fix(image): deprecation notice for latest attribute * fix(ci): explicitly go get tfplugindocs * fix(ci): remove gocenter.io proxy
This commit is contained in:
parent
7f4c14d1f5
commit
4d40b84443
40 changed files with 650 additions and 243 deletions
2
.github/workflows/acc-test.yaml
vendored
2
.github/workflows/acc-test.yaml
vendored
|
|
@ -12,7 +12,7 @@ on:
|
|||
- '.github/workflows/**'
|
||||
|
||||
env:
|
||||
GOPROXY: https://proxy.golang.org,https://gocenter.io,direct
|
||||
GOPROXY: https://proxy.golang.org,direct
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
DOCKER_CE_VERSION: "5:20.10.5~3-0~ubuntu-focal"
|
||||
GO_VERSION: "1.16"
|
||||
|
|
|
|||
2
.github/workflows/compile.yaml
vendored
2
.github/workflows/compile.yaml
vendored
|
|
@ -12,7 +12,7 @@ on:
|
|||
- '.github/workflows/**'
|
||||
|
||||
env:
|
||||
GOPROXY: https://proxy.golang.org,https://gocenter.io,direct
|
||||
GOPROXY: https://proxy.golang.org,direct
|
||||
GO_VERSION: "1.16"
|
||||
|
||||
jobs:
|
||||
|
|
|
|||
2
.github/workflows/unit-test.yaml
vendored
2
.github/workflows/unit-test.yaml
vendored
|
|
@ -12,7 +12,7 @@ on:
|
|||
- '.github/workflows/**'
|
||||
|
||||
env:
|
||||
GOPROXY: https://proxy.golang.org,https://gocenter.io,direct
|
||||
GOPROXY: https://proxy.golang.org,direct
|
||||
GO_VERSION: "1.16"
|
||||
|
||||
jobs:
|
||||
|
|
|
|||
4
.github/workflows/website-lint.yaml
vendored
4
.github/workflows/website-lint.yaml
vendored
|
|
@ -11,7 +11,7 @@ on:
|
|||
- docs/**
|
||||
|
||||
env:
|
||||
GOPROXY: https://proxy.golang.org,https://gocenter.io,direct
|
||||
GOPROXY: https://proxy.golang.org,direct
|
||||
GO_VERSION: "1.16"
|
||||
|
||||
jobs:
|
||||
|
|
@ -24,6 +24,8 @@ jobs:
|
|||
go-version: ${{ env.GO_VERSION }}
|
||||
- name: Setup tools
|
||||
run: make setup
|
||||
- name: Explicitly get tfplugindocs
|
||||
run: go get github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs
|
||||
- name: Generate the website
|
||||
run: make website-generation
|
||||
- name: Verify Changed files
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ build: fmtcheck
|
|||
go install
|
||||
|
||||
setup:
|
||||
go mod download
|
||||
cd tools && GO111MODULE=on go install github.com/client9/misspell/cmd/misspell
|
||||
cd tools && GO111MODULE=on go install github.com/katbyte/terrafmt
|
||||
cd tools && GO111MODULE=on go install github.com/golangci/golangci-lint/cmd/golangci-lint
|
||||
|
|
@ -76,7 +75,7 @@ website-lint:
|
|||
echo "Unexpected mispelling found in website files."; \
|
||||
echo "To automatically fix the misspelling, run 'make website-lint-fix' and commit the changes."; \
|
||||
exit 1)
|
||||
@docker run -v $(PWD):/markdown 06kellyjac/markdownlint-cli docs/ || (echo; \
|
||||
@docker run --rm -v $(PWD):/markdown 06kellyjac/markdownlint-cli docs/ || (echo; \
|
||||
echo "Unexpected issues found in website Markdown files."; \
|
||||
echo "To apply any automatic fixes, run 'make website-lint-fix' and commit the changes."; \
|
||||
exit 1)
|
||||
|
|
@ -89,7 +88,7 @@ website-lint:
|
|||
website-lint-fix:
|
||||
@echo "==> Applying automatic website linter fixes..."
|
||||
@misspell -w -source=text docs/
|
||||
@docker run -v $(PWD):/markdown 06kellyjac/markdownlint-cli --fix docs/
|
||||
@docker run --rm -v $(PWD):/markdown 06kellyjac/markdownlint-cli --fix docs/
|
||||
@terrafmt fmt ./docs --pattern '*.md'
|
||||
|
||||
.PHONY: build test testacc vet fmt fmtcheck errcheck test-compile website-link-check website-lint website-lint-fix
|
||||
|
|
|
|||
33
README.md
33
README.md
|
|
@ -25,7 +25,7 @@ terraform {
|
|||
# since new versions are released frequently
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
version = "2.12.1"
|
||||
version = "2.12.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -42,9 +42,38 @@ resource "docker_image" "nginx" {
|
|||
}
|
||||
|
||||
# Create a docker container resource
|
||||
# -> same as 'docker run --name nginx -d nginx:latest'
|
||||
# -> same as 'docker run --name nginx -p8080:80 -d nginx:latest'
|
||||
resource "docker_container" "nginx" {
|
||||
name = "nginx"
|
||||
image = docker_image.nginx.latest
|
||||
|
||||
ports {
|
||||
external = 8080
|
||||
internal = 80
|
||||
}
|
||||
}
|
||||
|
||||
# Or create a service resource
|
||||
# -> same as 'docker service create -d -p 8081:80 --name nginx-service --replicas 2 nginx:latest'
|
||||
resource "docker_service" "nginx_service" {
|
||||
name = "nginx-service"
|
||||
task_spec {
|
||||
container_spec {
|
||||
image = docker_image.nginx.repo_digest
|
||||
}
|
||||
}
|
||||
|
||||
mode {
|
||||
replicated {
|
||||
replicas = 2
|
||||
}
|
||||
}
|
||||
|
||||
endpoint_spec {
|
||||
ports {
|
||||
published_port = 8081
|
||||
target_port = 80
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
|||
52
docs/data-sources/image.md
Normal file
52
docs/data-sources/image.md
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
||||
page_title: "docker_image Data Source - terraform-provider-docker"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
docker_image provides details about a specific Docker Image which need to be presend on the Docker Host
|
||||
---
|
||||
|
||||
# docker_image (Data Source)
|
||||
|
||||
`docker_image` provides details about a specific Docker Image which need to be presend on the Docker Host
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
# uses the 'latest' tag
|
||||
data "docker_image" "latest" {
|
||||
name = "nginx"
|
||||
}
|
||||
|
||||
# uses a specific tag
|
||||
data "docker_image" "specific" {
|
||||
name = "nginx:1.17.6"
|
||||
}
|
||||
|
||||
# use the image digest
|
||||
data "docker_image" "digest" {
|
||||
name = "nginx@sha256:36b74457bccb56fbf8b05f79c85569501b721d4db813b684391d63e02287c0b2"
|
||||
}
|
||||
|
||||
# uses the tag and the image digest
|
||||
data "docker_image" "tag_and_digest" {
|
||||
name = "nginx:1.19.1@sha256:36b74457bccb56fbf8b05f79c85569501b721d4db813b684391d63e02287c0b2"
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
## Schema
|
||||
|
||||
### Required
|
||||
|
||||
- **name** (String) The name of the Docker image, including any tags or SHA256 repo digests.
|
||||
|
||||
### Optional
|
||||
|
||||
- **id** (String) The ID of this resource.
|
||||
|
||||
### Read-Only
|
||||
|
||||
- **repo_digest** (String) The image sha256 digest in the form of `repo[:tag]@sha256:<hash>`. It may be empty in the edge case where the local image was pulled from a repo, tagged locally, and then referred to in the data source by that local name/tag.
|
||||
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ resource "docker_image" "ubuntu" {
|
|||
|
||||
### Dynamic updates
|
||||
|
||||
To be able to update an update dynamically when the `sha256` sum changes,
|
||||
To be able to update an image dynamically when the `sha256` sum changes,
|
||||
you need to use it in combination with `docker_registry_image` as follows:
|
||||
|
||||
```terraform
|
||||
|
|
@ -43,8 +43,8 @@ resource "docker_image" "ubuntu" {
|
|||
|
||||
### Build
|
||||
|
||||
You can also use the resource to build and image.
|
||||
In thid case the image "zoo" and "zoo:develop" are built.
|
||||
You can also use the resource to build an image.
|
||||
In this case the image "zoo" and "zoo:develop" are built.
|
||||
|
||||
```terraform
|
||||
resource "docker_image" "zoo" {
|
||||
|
|
@ -80,8 +80,9 @@ resource "docker_image" "zoo" {
|
|||
|
||||
### Read-Only
|
||||
|
||||
- **latest** (String) The ID of the image.
|
||||
- **latest** (String, Deprecated) The ID of the image in the form of `sha256:<hash>` image digest. Do not confuse it with the default `latest` tag.
|
||||
- **output** (String, Deprecated)
|
||||
- **repo_digest** (String) The image sha256 digest in the form of `repo[:tag]@sha256:<hash>`.
|
||||
|
||||
<a id="nestedblock--build"></a>
|
||||
### Nested Schema for `build`
|
||||
|
|
@ -99,4 +100,4 @@ Optional:
|
|||
- **no_cache** (Boolean) Do not use cache when building the image
|
||||
- **remove** (Boolean) Remove intermediate containers after a successful build. Defaults to `true`.
|
||||
- **tag** (List of String) Name and optionally a tag in the 'name:tag' format
|
||||
- **target** (String) Set the target build stage to build
|
||||
- **target** (String) Set the target build stage to build
|
||||
|
|
|
|||
|
|
@ -48,6 +48,33 @@ The following command is the equivalent:
|
|||
docker service create -d -p 8080 --name foo-service repo.mycompany.com:8080/foo-service:v1
|
||||
```
|
||||
|
||||
### Basic with Datasource
|
||||
|
||||
Alternatively, if the image is already present on the Docker Host and not managed
|
||||
by `terraform`, you can also use the `docker_image` datasource:
|
||||
|
||||
```terraform
|
||||
data "docker_image" "foo" {
|
||||
name = "repo.mycompany.com:8080/foo-service:v1"
|
||||
}
|
||||
|
||||
resource "docker_service" "foo" {
|
||||
name = "foo-service"
|
||||
|
||||
task_spec {
|
||||
container_spec {
|
||||
image = data.docker_image.foo.repo_digest
|
||||
}
|
||||
}
|
||||
|
||||
endpoint_spec {
|
||||
ports {
|
||||
target_port = "8080"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Advanced
|
||||
|
||||
The following configuration shows the full capabilities of a Docker Service,
|
||||
|
|
@ -307,7 +334,7 @@ Optional:
|
|||
|
||||
Required:
|
||||
|
||||
- **image** (String) The image name to use for the containers of the service
|
||||
- **image** (String) The image name to use for the containers of the service, like `nginx:1.17.6`. Also use the data-source or resource of `docker_image` with the `repo_digest` or `docker_registry_image` with the `name` attribute for this, as shown in the examples.
|
||||
|
||||
Optional:
|
||||
|
||||
|
|
|
|||
19
examples/data-sources/docker_image/data-source.tf
Normal file
19
examples/data-sources/docker_image/data-source.tf
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# uses the 'latest' tag
|
||||
data "docker_image" "latest" {
|
||||
name = "nginx"
|
||||
}
|
||||
|
||||
# uses a specific tag
|
||||
data "docker_image" "specific" {
|
||||
name = "nginx:1.17.6"
|
||||
}
|
||||
|
||||
# use the image digest
|
||||
data "docker_image" "digest" {
|
||||
name = "nginx@sha256:36b74457bccb56fbf8b05f79c85569501b721d4db813b684391d63e02287c0b2"
|
||||
}
|
||||
|
||||
# uses the tag and the image digest
|
||||
data "docker_image" "tag_and_digest" {
|
||||
name = "nginx:1.19.1@sha256:36b74457bccb56fbf8b05f79c85569501b721d4db813b684391d63e02287c0b2"
|
||||
}
|
||||
19
examples/resources/docker_service/resource-basic-image-ds.tf
Normal file
19
examples/resources/docker_service/resource-basic-image-ds.tf
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
data "docker_image" "foo" {
|
||||
name = "repo.mycompany.com:8080/foo-service:v1"
|
||||
}
|
||||
|
||||
resource "docker_service" "foo" {
|
||||
name = "foo-service"
|
||||
|
||||
task_spec {
|
||||
container_spec {
|
||||
image = data.docker_image.foo.repo_digest
|
||||
}
|
||||
}
|
||||
|
||||
endpoint_spec {
|
||||
ports {
|
||||
target_port = "8080"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
resource "docker_service" "foo" {
|
||||
name = "foo-service"
|
||||
|
||||
|
|
@ -12,4 +13,4 @@ resource "docker_service" "foo" {
|
|||
target_port = "8080"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
101
internal/provider/data_source_docker_image.go
Normal file
101
internal/provider/data_source_docker_image.go
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
)
|
||||
|
||||
func dataSourceDockerImage() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Description: "`docker_image` provides details about a specific Docker Image which need to be presend on the Docker Host",
|
||||
|
||||
ReadContext: dataSourceDockerImageRead,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Description: "The name of the Docker image, including any tags or SHA256 repo digests.",
|
||||
Required: true,
|
||||
},
|
||||
"repo_digest": {
|
||||
Type: schema.TypeString,
|
||||
Description: "The image sha256 digest in the form of `repo[:tag]@sha256:<hash>`. It may be empty in the edge case where the local image was pulled from a repo, tagged locally, and then referred to in the data source by that local name/tag.",
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func dataSourceDockerImageRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
client := meta.(*ProviderConfig).DockerClient
|
||||
|
||||
var data Data
|
||||
if err := fetchLocalImages(ctx, &data, client); err != nil {
|
||||
return diag.Errorf("Error reading docker image list: %s", err)
|
||||
}
|
||||
for id := range data.DockerImages {
|
||||
log.Printf("[DEBUG] local images data: %v", id)
|
||||
}
|
||||
|
||||
imageName := d.Get("name").(string)
|
||||
|
||||
foundImage := searchLocalImages(ctx, client, data, imageName)
|
||||
if foundImage == nil {
|
||||
return diag.Errorf("did not find docker image '%s'", imageName)
|
||||
}
|
||||
|
||||
repoDigest := determineRepoDigest(imageName, foundImage)
|
||||
|
||||
d.SetId(foundImage.ID)
|
||||
d.Set("name", imageName)
|
||||
d.Set("repo_digest", repoDigest)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// determineRepoDigest determines the repo digest for a local image name.
|
||||
// It will always return a digest and if none was found it returns an empty string.
|
||||
// See https://github.com/kreuzwerker/terraform-provider-docker/pull/212#discussion_r646025706 for details
|
||||
func determineRepoDigest(imageName string, imageToQuery *types.ImageSummary) string {
|
||||
// the edge case where the local image was pulled from a repo, tagged locally,
|
||||
// and then referred to in the data source by that local name/tag...
|
||||
if len(imageToQuery.RepoDigests) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
// the standard case when there is only one digest
|
||||
if len(imageToQuery.RepoDigests) == 1 {
|
||||
return imageToQuery.RepoDigests[0]
|
||||
}
|
||||
|
||||
// the special case when the same image is in multiple registries
|
||||
// we first need to strip a possible tag because the digest do not contain it
|
||||
imageNameWithoutTag := imageName
|
||||
tagColonIndex := strings.Index(imageName, ":")
|
||||
// we have a tag
|
||||
if tagColonIndex != -1 {
|
||||
imageNameWithoutTag = imageName[:tagColonIndex]
|
||||
}
|
||||
|
||||
for _, repoDigest := range imageToQuery.RepoDigests {
|
||||
// we look explicitly at the beginning of the digest
|
||||
// as the image name is e.g. nginx:1.19.1 or 127.0.0.1/nginx:1.19.1 and the digests are
|
||||
// "RepoDigests": [
|
||||
// "127.0.0.1:15000/nginx@sha256:a5a1e8e5148de5ebc9697b64e4edb2296b5aac1f05def82efdc00ccb7b457171",
|
||||
// "nginx@sha256:36b74457bccb56fbf8b05f79c85569501b721d4db813b684391d63e02287c0b2"
|
||||
// ],
|
||||
if strings.HasPrefix(repoDigest, imageNameWithoutTag) {
|
||||
return repoDigest
|
||||
}
|
||||
}
|
||||
|
||||
// another edge case where the image was pulled from somewhere, pushed somewhere else,
|
||||
// but the tag being referenced in the data is that local-only tag
|
||||
log.Printf("[WARN] could not determine repo digest for image name '%s' and repo digests: %v. Will fall back to '%s'", imageName, imageToQuery.RepoDigests, imageToQuery.RepoDigests[0])
|
||||
return imageToQuery.RepoDigests[0]
|
||||
}
|
||||
203
internal/provider/data_source_docker_image_test.go
Normal file
203
internal/provider/data_source_docker_image_test.go
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
|
||||
)
|
||||
|
||||
var imageRepoDigestRegexp = regexp.MustCompile(`^.*@sha256:[A-Fa-f0-9]+$`)
|
||||
var imageNameWithTagAndDigestRegexp = regexp.MustCompile(`^.*:.*@sha256:[A-Fa-f0-9]+$`)
|
||||
|
||||
func TestAccDockerImageDataSource_withSpecificTag(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
imageName := "nginx:1.17.6"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
pullImageForTest(t, imageName)
|
||||
},
|
||||
ProviderFactories: providerFactories,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: loadTestConfiguration(t, DATA_SOURCE, "docker_image", "testAccDockerImageDataSourceWithSpecificTag"),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("data.docker_image.foo", "name", imageName),
|
||||
resource.TestCheckResourceAttr("data.docker_image.foo", "repo_digest", "nginx@sha256:b2d89d0a210398b4d1120b3e3a7672c16a4ba09c2c4a0395f18b9f7999b768f2"),
|
||||
),
|
||||
},
|
||||
},
|
||||
CheckDestroy: func(state *terraform.State) error {
|
||||
return removeImageForTest(ctx, state, imageName)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccDockerImageDataSource_withDefaultTag(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
imageName := "nginx"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
pullImageForTest(t, imageName)
|
||||
},
|
||||
ProviderFactories: providerFactories,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: loadTestConfiguration(t, DATA_SOURCE, "docker_image", "testAccDockerImageDataSourceWithDefaultTag"),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("data.docker_image.foo", "name", imageName),
|
||||
resource.TestMatchResourceAttr("data.docker_image.foo", "repo_digest", imageRepoDigestRegexp),
|
||||
),
|
||||
},
|
||||
},
|
||||
CheckDestroy: func(state *terraform.State) error {
|
||||
return removeImageForTest(ctx, state, imageName)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccDockerImageDataSource_withSha256Digest(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
imageName := "nginx@sha256:36b74457bccb56fbf8b05f79c85569501b721d4db813b684391d63e02287c0b2"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
pullImageForTest(t, imageName)
|
||||
},
|
||||
ProviderFactories: providerFactories,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: loadTestConfiguration(t, DATA_SOURCE, "docker_image", "testAccDockerImageDataSourceWithSha256Digest"),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("data.docker_image.foo", "name", imageName),
|
||||
resource.TestMatchResourceAttr("data.docker_image.foo", "repo_digest", imageRepoDigestRegexp),
|
||||
),
|
||||
},
|
||||
},
|
||||
CheckDestroy: func(state *terraform.State) error {
|
||||
return removeImageForTest(ctx, state, imageName)
|
||||
},
|
||||
})
|
||||
}
|
||||
func TestAccDockerImageDataSource_withTagAndSha256Digest(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
imageName := "nginx:1.19.1@sha256:36b74457bccb56fbf8b05f79c85569501b721d4db813b684391d63e02287c0b2"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
pullImageForTest(t, imageName)
|
||||
},
|
||||
ProviderFactories: providerFactories,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: loadTestConfiguration(t, DATA_SOURCE, "docker_image", "testAccDockerImageDataSourceWithTagAndSha256Digest"),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("data.docker_image.foo", "name", imageName),
|
||||
resource.TestMatchResourceAttr("data.docker_image.foo", "repo_digest", imageRepoDigestRegexp),
|
||||
),
|
||||
},
|
||||
},
|
||||
CheckDestroy: func(state *terraform.State) error {
|
||||
return removeImageForTest(ctx, state, imageName)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccDockerImageDataSource_withNonExistentImage(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
ProviderFactories: providerFactories,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: `
|
||||
data "docker_image" "foo" {
|
||||
name = "image-does-not-exist"
|
||||
}
|
||||
`,
|
||||
ExpectError: regexp.MustCompile(`.*did not find docker image.*`),
|
||||
},
|
||||
{
|
||||
Config: `
|
||||
data "docker_image" "foo" {
|
||||
name = "nginx:tag-does-not-exist"
|
||||
}
|
||||
`,
|
||||
ExpectError: regexp.MustCompile(`.*did not find docker image.*`),
|
||||
},
|
||||
{
|
||||
Config: `
|
||||
data "docker_image" "foo" {
|
||||
name = "nginx@shaDoesNotExist"
|
||||
}
|
||||
`,
|
||||
ExpectError: regexp.MustCompile(`.*did not find docker image.*`),
|
||||
},
|
||||
{
|
||||
Config: `
|
||||
data "docker_image" "foo" {
|
||||
name = "nginx:1.19.1@shaDoesNotExist"
|
||||
}
|
||||
`,
|
||||
ExpectError: regexp.MustCompile(`.*did not find docker image.*`),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Helpers
|
||||
func pullImageForTest(t *testing.T, imageName string) {
|
||||
cmd := exec.Command("docker", "pull", imageName)
|
||||
if err := cmd.Run(); err != nil {
|
||||
t.Fatalf("Failed to pull image '%s': %s", imageName, err)
|
||||
}
|
||||
}
|
||||
|
||||
func removeImageForTest(ctx context.Context, s *terraform.State, imageName string) error {
|
||||
client := testAccProvider.Meta().(*ProviderConfig).DockerClient
|
||||
|
||||
// for images with tag and digest like e.g.
|
||||
// 'nginx:1.19.1@sha256:36b74457bccb56fbf8b05f79c85569501b721d4db813b684391d63e02287c0b2'
|
||||
// no image is found. This is why we strip the tag to remain with
|
||||
// 'nginx@sha256:36b74457bccb56fbf8b05f79c85569501b721d4db813b684391d63e02287c0b2'
|
||||
if imageNameWithTagAndDigestRegexp.MatchString(imageName) {
|
||||
tagStartIndex := strings.Index(imageName, ":")
|
||||
digestStartIndex := strings.Index(imageName, "@")
|
||||
imageName = imageName[:tagStartIndex] + imageName[digestStartIndex:]
|
||||
}
|
||||
|
||||
filters := filters.NewArgs()
|
||||
filters.Add("reference", imageName)
|
||||
images, err := client.ImageList(ctx, types.ImageListOptions{
|
||||
Filters: filters,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(images) == 0 {
|
||||
return fmt.Errorf("did not find any image with name '%s' to delete", imageName)
|
||||
}
|
||||
|
||||
for _, image := range images {
|
||||
_, err := client.ImageRemove(ctx, image.ID, types.ImageRemoveOptions{
|
||||
Force: true,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to remove image with ID '%s'", image.ID)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -134,6 +134,7 @@ func New(version string) func() *schema.Provider {
|
|||
"docker_registry_image": dataSourceDockerRegistryImage(),
|
||||
"docker_network": dataSourceDockerNetwork(),
|
||||
"docker_plugin": dataSourceDockerPlugin(),
|
||||
"docker_image": dataSourceDockerImage(),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -120,7 +120,6 @@ func resourceDockerContainer() *schema.Resource {
|
|||
Description: "The ID of the image to back this container. The easiest way to get this value is to use the `docker_image` resource as is shown in the example.",
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
// DiffSuppressFunc: suppressIfSHAwasAdded(), // TODO mvogel
|
||||
},
|
||||
|
||||
"hostname": {
|
||||
|
|
|
|||
|
|
@ -734,7 +734,6 @@ func resourceDockerContainerReadRefreshFunc(ctx context.Context,
|
|||
if container.State.Running ||
|
||||
!container.State.Running && !d.Get("must_run").(bool) {
|
||||
log.Printf("[DEBUG] Container %s is running: %v", containerID, container.State.Running)
|
||||
// break
|
||||
return container, "running", nil
|
||||
}
|
||||
|
||||
|
|
@ -753,6 +752,18 @@ func resourceDockerContainerReadRefreshFunc(ctx context.Context,
|
|||
return container, "pending", errContainerExitedImmediately
|
||||
}
|
||||
|
||||
// TODO mavogel wait until all properties are exposed from the API
|
||||
// dns = []
|
||||
// dns_opts = []
|
||||
// dns_search = []
|
||||
// group_add = []
|
||||
// id = "9e6d9e987923e2c3a99f17e8781c7ce3515558df0e45f8ab06f6adb2dda0de50"
|
||||
// links = []
|
||||
// log_opts = {}
|
||||
// name = "nginx"
|
||||
// sysctls = {}
|
||||
// tmpfs = {}
|
||||
|
||||
return container, "running", nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,7 +90,6 @@ func resourceDockerContainerV1() *schema.Resource {
|
|||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
// DiffSuppressFunc: suppressIfSHAwasAdded(), // TODO mvogel
|
||||
},
|
||||
|
||||
"hostname": {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,14 @@ func resourceDockerImage() *schema.Resource {
|
|||
|
||||
"latest": {
|
||||
Type: schema.TypeString,
|
||||
Description: "The ID of the image.",
|
||||
Description: "The ID of the image in the form of `sha256:<hash>` image digest. Do not confuse it with the default `latest` tag.",
|
||||
Computed: true,
|
||||
Deprecated: "Use repo_digest instead",
|
||||
},
|
||||
|
||||
"repo_digest": {
|
||||
Type: schema.TypeString,
|
||||
Description: "The image sha256 digest in the form of `repo[:tag]@sha256:<hash>`.",
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -63,9 +63,12 @@ func resourceDockerImageRead(ctx context.Context, d *schema.ResourceData, meta i
|
|||
return nil
|
||||
}
|
||||
|
||||
repoDigest := determineRepoDigest(imageName, foundImage)
|
||||
|
||||
// TODO mavogel: remove the appended name from the ID
|
||||
d.SetId(foundImage.ID + d.Get("name").(string))
|
||||
d.Set("latest", foundImage.ID)
|
||||
d.Set("repo_digest", repoDigest)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -86,6 +89,7 @@ func resourceDockerImageUpdate(ctx context.Context, d *schema.ResourceData, meta
|
|||
|
||||
func resourceDockerImageDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
client := meta.(*ProviderConfig).DockerClient
|
||||
// TODO mavogel: add retries. see e.g. service updateFailsAndRollbackConvergeConfig test
|
||||
err := removeImage(ctx, d, client)
|
||||
if err != nil {
|
||||
return diag.Errorf("Unable to remove Docker image: %s", err)
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ func TestAccDockerImage_private(t *testing.T) {
|
|||
Config: loadTestConfiguration(t, RESOURCE, "docker_image", "testAddDockerPrivateImageConfig"),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_image.foobar", "latest", contentDigestRegexp),
|
||||
resource.TestMatchResourceAttr("docker_image.foobar", "repo_digest", imageRepoDigestRegexp),
|
||||
testAccImageCreated("docker_image.foobar", &i),
|
||||
testCheckImageInspect,
|
||||
),
|
||||
|
|
@ -114,6 +115,7 @@ func TestAccDockerImage_destroy(t *testing.T) {
|
|||
Config: loadTestConfiguration(t, RESOURCE, "docker_image", "testAccDockerImageKeepLocallyConfig"),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_image.foobarzoo", "latest", contentDigestRegexp),
|
||||
resource.TestMatchResourceAttr("docker_image.foobarzoo", "repo_digest", imageRepoDigestRegexp),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
|
@ -130,6 +132,7 @@ func TestAccDockerImage_data(t *testing.T) {
|
|||
Config: loadTestConfiguration(t, RESOURCE, "docker_image", "testAccDockerImageFromDataConfig"),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_image.foobarbaz", "latest", contentDigestRegexp),
|
||||
resource.TestMatchResourceAttr("docker_image.foobarbaz", "repo_digest", imageRepoDigestRegexp),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
|
@ -146,6 +149,7 @@ func TestAccDockerImage_data_pull_trigger(t *testing.T) {
|
|||
Config: loadTestConfiguration(t, RESOURCE, "docker_image", "testAccDockerImageFromDataConfigWithPullTrigger"),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_image.foobarbazoo", "latest", contentDigestRegexp),
|
||||
resource.TestMatchResourceAttr("docker_image.foobarbazoo", "repo_digest", imageRepoDigestRegexp),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
|
@ -166,6 +170,7 @@ func TestAccDockerImage_data_private(t *testing.T) {
|
|||
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_image", "testAccDockerImageFromDataPrivateConfig"), registry, image),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_image.foo_private", "latest", contentDigestRegexp),
|
||||
resource.TestMatchResourceAttr("docker_image.foo_private", "repo_digest", imageRepoDigestRegexp),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
|
@ -191,6 +196,7 @@ func TestAccDockerImage_data_private_config_file(t *testing.T) {
|
|||
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_image", "testAccDockerImageFromDataPrivateConfigFile"), registry, dockerConfig, image),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_image.foo_private", "latest", contentDigestRegexp),
|
||||
resource.TestMatchResourceAttr("docker_image.foo_private", "repo_digest", imageRepoDigestRegexp),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
|
@ -216,6 +222,7 @@ func TestAccDockerImage_data_private_config_file_content(t *testing.T) {
|
|||
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_image", "testAccDockerImageFromDataPrivateConfigFileContent"), registry, dockerConfig, image),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_image.foo_private", "latest", contentDigestRegexp),
|
||||
resource.TestMatchResourceAttr("docker_image.foo_private", "repo_digest", imageRepoDigestRegexp),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
|
@ -238,6 +245,7 @@ func TestAccDockerImage_sha265(t *testing.T) {
|
|||
Config: loadTestConfiguration(t, RESOURCE, "docker_image", "testAddDockerImageWithSHA256RepoDigest"),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_image.foobar", "latest", contentDigestRegexp),
|
||||
resource.TestMatchResourceAttr("docker_image.foobar", "repo_digest", imageRepoDigestRegexp),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
|
@ -272,6 +280,7 @@ func TestAccDockerImage_tag_sha265(t *testing.T) {
|
|||
Config: loadTestConfiguration(t, RESOURCE, "docker_image", "testAccDockerImageWithTagAndSHA256RepoDigest"),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_image.nginx", "latest", contentDigestRegexp),
|
||||
resource.TestMatchResourceAttr("docker_image.nginx", "repo_digest", imageRepoDigestRegexp),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
)
|
||||
|
||||
|
|
@ -83,10 +79,9 @@ func resourceDockerService() *schema.Resource {
|
|||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"image": {
|
||||
Type: schema.TypeString,
|
||||
Description: "The image name to use for the containers of the service",
|
||||
Required: true,
|
||||
DiffSuppressFunc: suppressIfSHAwasAdded(),
|
||||
Type: schema.TypeString,
|
||||
Description: "The image name to use for the containers of the service, like `nginx:1.17.6`. Also use the data-source or resource of `docker_image` with the `repo_digest` or `docker_registry_image` with the `name` attribute for this, as shown in the examples.",
|
||||
Required: true,
|
||||
},
|
||||
"labels": {
|
||||
Type: schema.TypeSet,
|
||||
|
|
@ -944,96 +939,3 @@ func resourceDockerService() *schema.Resource {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
func suppressIfSHAwasAdded() schema.SchemaDiffSuppressFunc {
|
||||
return func(k, old, new string, d *schema.ResourceData) bool {
|
||||
// the initial case when the service is created
|
||||
if old == "" && new != "" {
|
||||
return false
|
||||
}
|
||||
|
||||
oldURL, oldImage, oldTag, oldDigest, oldErr := splitImageName(old)
|
||||
if oldErr != nil {
|
||||
log.Printf("[DEBUG] invalid old image name: %s\n", oldErr.Error())
|
||||
return false
|
||||
}
|
||||
log.Printf("[DEBUG] old image parse: %s, %s, %s, %s\n", oldURL, oldImage, oldTag, oldDigest)
|
||||
|
||||
newURL, newImage, newTag, newDigest, newErr := splitImageName(new)
|
||||
if newErr != nil {
|
||||
log.Printf("[DEBUG] invalid new image name: %s\n", newErr.Error())
|
||||
return false
|
||||
}
|
||||
log.Printf("[DEBUG] new image parse: %s, %s, %s, %s\n", newURL, newImage, newTag, newDigest)
|
||||
|
||||
if oldURL != newURL || oldImage != newImage {
|
||||
return false
|
||||
}
|
||||
|
||||
// special case with latest
|
||||
if oldTag == "latest" && (newTag == "" || newTag == "latest") {
|
||||
if oldDigest != "" && newDigest == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// https://success.docker.com/article/images-tagging-vs-digests
|
||||
// we always pull if the tag changes, also in the empty and 'latest' case
|
||||
if (oldTag == "latest" || newTag == "") || (oldTag == "" && newTag == "latest") {
|
||||
return false
|
||||
}
|
||||
|
||||
if oldTag != newTag {
|
||||
return false
|
||||
}
|
||||
|
||||
// tags are the same and so should be its digests
|
||||
if oldDigest == newDigest || (oldDigest == "" && newDigest != "") || (oldDigest != "" && newDigest == "") {
|
||||
return true
|
||||
}
|
||||
|
||||
// we only update if the digests are given and different
|
||||
if oldDigest != newDigest {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// spitImageName splits an image with name 127.0.0.1:15000/tftest-service:v1@sha256:24..
|
||||
// into its parts. Handles edge cases like no tag and no digest
|
||||
func splitImageName(imageNameToSplit string) (url, image, tag, digest string, err error) {
|
||||
urlToRestSplit := strings.Split(imageNameToSplit, "/")
|
||||
if len(urlToRestSplit) != 2 {
|
||||
return "", "", "", "", fmt.Errorf("image name is not valid: %s", imageNameToSplit)
|
||||
}
|
||||
url = urlToRestSplit[0]
|
||||
imageNameToRestSplit := strings.Split(urlToRestSplit[1], ":")
|
||||
// we only have an image name without tag and sha256
|
||||
if len(imageNameToRestSplit) == 1 {
|
||||
image = imageNameToRestSplit[0]
|
||||
return url, image, "", "", nil
|
||||
}
|
||||
// has tag and sha256
|
||||
if len(imageNameToRestSplit) == 3 {
|
||||
image = imageNameToRestSplit[0]
|
||||
tag = strings.Replace(imageNameToRestSplit[1], "@sha256", "", 1)
|
||||
digest = imageNameToRestSplit[2]
|
||||
return url, image, tag, digest, nil
|
||||
}
|
||||
// can be either with tag or sha256, which implies 'latest' tag
|
||||
if len(imageNameToRestSplit) == 2 {
|
||||
image = imageNameToRestSplit[0]
|
||||
if strings.Contains(imageNameToRestSplit[1], "sha256") {
|
||||
digest = imageNameToRestSplit[1]
|
||||
return url, image, "", digest, nil
|
||||
}
|
||||
tag = strings.Replace(imageNameToRestSplit[1], "@sha256", "", 1)
|
||||
return url, image, tag, "", nil
|
||||
}
|
||||
|
||||
return "", "", "", "", fmt.Errorf("image name is not valid: %s", imageNameToSplit)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,10 +99,9 @@ func resourceDockerServiceV1() *schema.Resource {
|
|||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"image": {
|
||||
Type: schema.TypeString,
|
||||
Description: "The image name to use for the containers of the service",
|
||||
Required: true,
|
||||
DiffSuppressFunc: suppressIfSHAwasAdded(),
|
||||
Type: schema.TypeString,
|
||||
Description: "The image name to use for the containers of the service",
|
||||
Required: true,
|
||||
},
|
||||
"labels": {
|
||||
Type: schema.TypeSet,
|
||||
|
|
@ -1021,10 +1020,9 @@ func resourceDockerServiceV0() *schema.Resource {
|
|||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"image": {
|
||||
Type: schema.TypeString,
|
||||
Description: "The image name to use for the containers of the service",
|
||||
Required: true,
|
||||
DiffSuppressFunc: suppressIfSHAwasAdded(),
|
||||
Type: schema.TypeString,
|
||||
Description: "The image name to use for the containers of the service",
|
||||
Required: true,
|
||||
},
|
||||
"labels": {
|
||||
Type: schema.TypeMap,
|
||||
|
|
|
|||
|
|
@ -277,79 +277,6 @@ func checkAttribute(t *testing.T, name, actual, expected string) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDockerImageNameSuppress(t *testing.T) {
|
||||
suppressFunc := suppressIfSHAwasAdded()
|
||||
old := ""
|
||||
new := "alpine3.1"
|
||||
suppress := suppressFunc("k", old, new, nil)
|
||||
if suppress {
|
||||
t.Fatalf("Expected no suppress for \n\told '%s' \n\tnew '%s'", old, new)
|
||||
}
|
||||
|
||||
old = "127.0.0.1:15000/tftest-service:v1"
|
||||
new = "127.0.0.1:15000/tftest-service:v1@sha256:74d04f400723d9770187ee284255d1eb556f3d51700792fb2bfd6ab13da50981"
|
||||
suppress = suppressFunc("k", old, new, nil)
|
||||
if !suppress {
|
||||
t.Fatalf("Expected suppress for \n\told '%s' \n\tnew '%s'", old, new)
|
||||
}
|
||||
|
||||
old = "127.0.0.1:15000/tftest-service:latest@sha256:74d04f400723d9770187ee284255d1eb556f3d51700792fb2bfd6ab13da50981"
|
||||
new = "127.0.0.1:15000/tftest-service"
|
||||
suppress = suppressFunc("k", old, new, nil)
|
||||
if !suppress {
|
||||
t.Fatalf("Expected suppress for \n\told '%s' \n\tnew '%s'", old, new)
|
||||
}
|
||||
|
||||
old = "127.0.0.1:15000/tftest-service:latest"
|
||||
new = "127.0.0.1:15000/tftest-service:latest@sha256:74d04f400723d9770187ee284255d1eb556f3d51700792fb2bfd6ab13da50981"
|
||||
suppress = suppressFunc("k", old, new, nil)
|
||||
if suppress {
|
||||
t.Fatalf("Expected no suppress for \n\told '%s' \n\tnew '%s'", old, new)
|
||||
}
|
||||
|
||||
old = "127.0.0.1:15000/tftest-service"
|
||||
new = "127.0.0.1:15000/tftest-service:latest@sha256:74d04f400723d9770187ee284255d1eb556f3d51700792fb2bfd6ab13da50981"
|
||||
suppress = suppressFunc("k", old, new, nil)
|
||||
if suppress {
|
||||
t.Fatalf("Expected no suppress for \n\told '%s' \n\tnew '%s'", old, new)
|
||||
}
|
||||
|
||||
old = "127.0.0.1:15000/tftest-service:v1"
|
||||
new = "127.0.0.1:15000/tftest-service:v2@sha256:ed8e15d68bb13e3a04abddc295f87d2a8b7d849d5ff91f00dbdd66dc10fd8aac"
|
||||
suppress = suppressFunc("k", old, new, nil)
|
||||
if suppress {
|
||||
t.Fatalf("Expected no suppress for image tag update from \n\told '%s' \n\tnew '%s'", old, new)
|
||||
}
|
||||
|
||||
old = "127.0.0.1:15000/tftest-service:v1@sha256:74d04f400723d9770187ee284255d1eb556f3d51700792fb2bfd6ab13da50981"
|
||||
new = "127.0.0.1:15000/tftest-service:v2@sha256:74d04f400723d9770187ee284255d1eb556f3d51700792fb2bfd6ab13da50981"
|
||||
suppress = suppressFunc("k", old, new, nil)
|
||||
if suppress {
|
||||
t.Fatalf("Expected no suppress for image tag update from \n\told '%s' \n\tnew '%s'", old, new)
|
||||
}
|
||||
|
||||
old = "127.0.0.1:15000/tftest-service:latest@sha256:74d04f400723d9770187ee284255d1eb556f3d51700792fb2bfd6ab13da50981"
|
||||
new = "127.0.0.1:15000/tftest-service:latest@sha256:c9d1055182f0607632b7d859d2f220126fb1c0d10aedc4451817840b30c1af86"
|
||||
suppress = suppressFunc("k", old, new, nil)
|
||||
if suppress {
|
||||
t.Fatalf("Expected no suppress for image digest update from \n\told '%s' \n\tnew '%s'", old, new)
|
||||
}
|
||||
|
||||
old = "127.0.0.1:15000/tftest-service:v3@sha256:74d04f400723d9770187ee284255d1eb556f3d51700792fb2bfd6ab13da50981"
|
||||
new = "127.0.0.1:15000/tftest-service:latest@sha256:c9d1055182f0607632b7d859d2f220126fb1c0d10aedc4451817840b30c1af86"
|
||||
suppress = suppressFunc("k", old, new, nil)
|
||||
if suppress {
|
||||
t.Fatalf("Expected no suppress for image tag but no digest update from \n\told '%s' \n\tnew '%s'", old, new)
|
||||
}
|
||||
|
||||
old = "127.0.0.1:15000/tftest-service@sha256:74d04f400723d9770187ee284255d1eb556f3d51700792fb2bfd6ab13da50981"
|
||||
new = "127.0.0.1:15000/tftest-service@sha256:c9d1055182f0607632b7d859d2f220126fb1c0d10aedc4451817840b30c1af86"
|
||||
suppress = suppressFunc("k", old, new, nil)
|
||||
if suppress {
|
||||
t.Fatalf("Expected no suppress for image tag but no digest update from \n\told '%s' \n\tnew '%s'", old, new)
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
// ----------- ACCEPTANCE TESTS -----------
|
||||
// ----------------------------------------
|
||||
|
|
@ -367,7 +294,7 @@ func TestAccDockerService_minimalSpec(t *testing.T) {
|
|||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "id", serviceIDRegex),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "name", "tftest-service-basic"),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`127.0.0.1:15000/tftest-service:v1@sha256.*`)),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`sha256.*`)),
|
||||
),
|
||||
},
|
||||
{
|
||||
|
|
@ -639,7 +566,7 @@ func TestAccDockerService_fullSpec(t *testing.T) {
|
|||
resource.TestMatchResourceAttr("docker_service.foo", "id", serviceIDRegex),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "name", "tftest-service-basic"),
|
||||
testCheckLabelMap("docker_service.foo", "labels", map[string]string{"servicelabel": "true"}),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`127.0.0.1:15000/tftest-service:v1.*`)),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`sha256.*`)),
|
||||
testCheckLabelMap("docker_service.foo", "task_spec.0.container_spec.0.labels", map[string]string{"foo": "bar"}),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.command.0", "ls"),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.args.0", "-las"),
|
||||
|
|
@ -740,7 +667,7 @@ func TestAccDockerService_partialReplicationConfig(t *testing.T) {
|
|||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "id", serviceIDRegex),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "name", "tftest-service-basic"),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`127.0.0.1:15000/tftest-service:v1@sha256.*`)),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`sha256.*`)),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "mode.0.replicated.0.replicas", "1"),
|
||||
),
|
||||
},
|
||||
|
|
@ -749,7 +676,7 @@ func TestAccDockerService_partialReplicationConfig(t *testing.T) {
|
|||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "id", serviceIDRegex),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "name", "tftest-service-basic"),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`127.0.0.1:15000/tftest-service:v1@sha256.*`)),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`sha256.*`)),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "mode.0.replicated.0.replicas", "1"),
|
||||
),
|
||||
},
|
||||
|
|
@ -758,7 +685,7 @@ func TestAccDockerService_partialReplicationConfig(t *testing.T) {
|
|||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "id", serviceIDRegex),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "name", "tftest-service-basic"),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`127.0.0.1:15000/tftest-service:v1@sha256.*`)),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`sha256.*`)),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "mode.0.replicated.0.replicas", "2"),
|
||||
),
|
||||
},
|
||||
|
|
@ -785,7 +712,7 @@ func TestAccDockerService_globalReplicationMode(t *testing.T) {
|
|||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "id", serviceIDRegex),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "name", "tftest-service-basic"),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`127.0.0.1:15000/tftest-service:v1@sha256.*`)),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`sha256.*`)),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "mode.0.global", "true"),
|
||||
),
|
||||
},
|
||||
|
|
@ -850,7 +777,7 @@ func TestAccDockerService_privateImageConverge(t *testing.T) {
|
|||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "id", serviceIDRegex),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "name", "tftest-service-foo"),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`127.0.0.1:15000/tftest-service:v1@sha256.*`)),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`sha256.*`)),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
|
@ -903,7 +830,7 @@ func TestAccDockerService_convergeAndStopGracefully(t *testing.T) {
|
|||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "id", serviceIDRegex),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "name", "tftest-service-basic-converge"),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`127.0.0.1:15000/tftest-service:v1.*`)),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`sha256.*`)),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "mode.0.replicated.0.replicas", "2"),
|
||||
testValueHigherEqualThan("docker_service.foo", "endpoint_spec.0.ports.0.target_port", 8080),
|
||||
testValueHigherEqualThan("docker_service.foo", "endpoint_spec.0.ports.0.published_port", 30000),
|
||||
|
|
@ -930,7 +857,7 @@ func TestAccDockerService_updateFailsAndRollbackConverge(t *testing.T) {
|
|||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "id", serviceIDRegex),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "name", "tftest-service-updateFailsAndRollbackConverge"),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`127.0.0.1:15000/tftest-service:v1.*`)),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`sha256.*`)),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "mode.0.replicated.0.replicas", "2"),
|
||||
),
|
||||
},
|
||||
|
|
@ -940,7 +867,7 @@ func TestAccDockerService_updateFailsAndRollbackConverge(t *testing.T) {
|
|||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "id", serviceIDRegex),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "name", "tftest-service-updateFailsAndRollbackConverge"),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`127.0.0.1:15000/tftest-service:v1.*`)),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`sha256.*`)),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "mode.0.replicated.0.replicas", "2"),
|
||||
),
|
||||
},
|
||||
|
|
@ -1078,7 +1005,15 @@ func TestAccDockerService_updateMultiplePropertiesConverge(t *testing.T) {
|
|||
portsSpec3 := portsSpec2
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
// Note mavogel: we download all images upfront and use a data_source then
|
||||
// becausee the test is only flaky in CI. See
|
||||
// https://github.com/kreuzwerker/terraform-provider-docker/runs/2732063570
|
||||
pullImageForTest(t, image)
|
||||
pullImageForTest(t, image2)
|
||||
pullImageForTest(t, image3)
|
||||
},
|
||||
ProviderFactories: providerFactories,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
|
|
@ -1086,7 +1021,7 @@ func TestAccDockerService_updateMultiplePropertiesConverge(t *testing.T) {
|
|||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "id", serviceIDRegex),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "name", "tftest-fnf-service-up-crihiadr"),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`127.0.0.1:15000/tftest-service:v1@sha256.*`)),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`sha256.*`)),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "mode.0.replicated.0.replicas", strconv.Itoa(replicas)),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "update_config.0.parallelism", "2"),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "update_config.0.delay", "3s"),
|
||||
|
|
@ -1132,7 +1067,7 @@ func TestAccDockerService_updateMultiplePropertiesConverge(t *testing.T) {
|
|||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "id", serviceIDRegex),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "name", "tftest-fnf-service-up-crihiadr"),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`127.0.0.1:15000/tftest-service:v2.*`)),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`sha256.*`)),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "mode.0.replicated.0.replicas", strconv.Itoa(replicas2)),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "update_config.0.parallelism", "2"),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "update_config.0.delay", "3s"),
|
||||
|
|
@ -1180,7 +1115,7 @@ func TestAccDockerService_updateMultiplePropertiesConverge(t *testing.T) {
|
|||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "id", serviceIDRegex),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "name", "tftest-fnf-service-up-crihiadr"),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`127.0.0.1:15000/tftest-service:v2.*`)),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`sha256.*`)),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "mode.0.replicated.0.replicas", strconv.Itoa(replicas3)),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "update_config.0.parallelism", "2"),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "update_config.0.delay", "3s"),
|
||||
|
|
@ -1233,6 +1168,10 @@ func TestAccDockerService_updateMultiplePropertiesConverge(t *testing.T) {
|
|||
const updateMultiplePropertiesConfigConverge = `
|
||||
provider "docker" {
|
||||
alias = "private"
|
||||
|
||||
registry_auth {
|
||||
address = "127.0.0.1:15000"
|
||||
}
|
||||
}
|
||||
|
||||
resource "docker_volume" "foo" {
|
||||
|
|
@ -1262,19 +1201,24 @@ const updateMultiplePropertiesConfigConverge = `
|
|||
create_before_destroy = true
|
||||
}
|
||||
}
|
||||
|
||||
data "docker_image" "tftest_image" {
|
||||
name = "%s"
|
||||
}
|
||||
|
||||
resource "docker_service" "foo" {
|
||||
provider = "docker.private"
|
||||
name = "tftest-fnf-service-up-crihiadr"
|
||||
|
||||
auth {
|
||||
server_address = "127.0.0.1:15000"
|
||||
username = "testuser"
|
||||
password = "testpwd"
|
||||
server_address = "127.0.0.1:15000"
|
||||
username = "testuser"
|
||||
password = "testpwd"
|
||||
}
|
||||
|
||||
task_spec {
|
||||
container_spec {
|
||||
image = "%s"
|
||||
image = data.docker_image.tftest_image.repo_digest
|
||||
|
||||
%s
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,13 @@ The following command is the equivalent:
|
|||
|
||||
{{codefile "shell" "examples/resources/docker_service/resource-basic-create.sh" }}
|
||||
|
||||
### Basic with Datasource
|
||||
|
||||
Alternatively, if the image is already present on the Docker Host and not managed
|
||||
by `terraform`, you can also use the `docker_image` datasource:
|
||||
|
||||
{{tffile "examples/resources/docker_service/resource-basic-image-ds.tf"}}
|
||||
|
||||
### Advanced
|
||||
|
||||
The following configuration shows the full capabilities of a Docker Service,
|
||||
|
|
|
|||
3
testdata/data-sources/docker_image/testAccDockerImageDataSourceWithDefaultTag.tf
vendored
Normal file
3
testdata/data-sources/docker_image/testAccDockerImageDataSourceWithDefaultTag.tf
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
data "docker_image" "foo" {
|
||||
name = "nginx"
|
||||
}
|
||||
3
testdata/data-sources/docker_image/testAccDockerImageDataSourceWithSha256Digest.tf
vendored
Normal file
3
testdata/data-sources/docker_image/testAccDockerImageDataSourceWithSha256Digest.tf
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
data "docker_image" "foo" {
|
||||
name = "nginx@sha256:36b74457bccb56fbf8b05f79c85569501b721d4db813b684391d63e02287c0b2"
|
||||
}
|
||||
3
testdata/data-sources/docker_image/testAccDockerImageDataSourceWithSpecificTag.tf
vendored
Normal file
3
testdata/data-sources/docker_image/testAccDockerImageDataSourceWithSpecificTag.tf
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
data "docker_image" "foo" {
|
||||
name = "nginx:1.17.6"
|
||||
}
|
||||
3
testdata/data-sources/docker_image/testAccDockerImageDataSourceWithTagAndSha256Digest.tf
vendored
Normal file
3
testdata/data-sources/docker_image/testAccDockerImageDataSourceWithTagAndSha256Digest.tf
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
data "docker_image" "foo" {
|
||||
name = "nginx:1.19.1@sha256:36b74457bccb56fbf8b05f79c85569501b721d4db813b684391d63e02287c0b2"
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
provider "docker" {
|
||||
alias = "private"
|
||||
registry_auth {
|
||||
address = "%s"
|
||||
}
|
||||
alias = "private"
|
||||
registry_auth {
|
||||
address = "%s"
|
||||
}
|
||||
}
|
||||
data "docker_registry_image" "foobar" {
|
||||
provider = "docker.private"
|
||||
name = "%s"
|
||||
insecure_skip_verify = true
|
||||
provider = "docker.private"
|
||||
name = "%s"
|
||||
insecure_skip_verify = true
|
||||
}
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
resource "docker_plugin" "test" {
|
||||
name = "docker.io/tiborvass/sample-volume-plugin:latest"
|
||||
alias = "sample:latest"
|
||||
enabled = false
|
||||
force_destroy = true
|
||||
force_disable = true
|
||||
enable_timeout = 60
|
||||
name = "docker.io/tiborvass/sample-volume-plugin:latest"
|
||||
alias = "sample:latest"
|
||||
enabled = false
|
||||
force_destroy = true
|
||||
force_disable = true
|
||||
enable_timeout = 60
|
||||
env = [
|
||||
"DEBUG=1"
|
||||
]
|
||||
|
|
|
|||
|
|
@ -4,11 +4,16 @@ provider "docker" {
|
|||
}
|
||||
}
|
||||
|
||||
resource "docker_image" "tftest_image" {
|
||||
name = "127.0.0.1:15000/tftest-service:v1"
|
||||
keep_locally = false
|
||||
}
|
||||
|
||||
resource "docker_service" "foo" {
|
||||
name = "tftest-service-basic-converge"
|
||||
task_spec {
|
||||
container_spec {
|
||||
image = "127.0.0.1:15000/tftest-service:v1"
|
||||
image = docker_image.tftest_image.repo_digest
|
||||
stop_grace_period = "10s"
|
||||
healthcheck {
|
||||
test = ["CMD", "curl", "-f", "localhost:8080/health"]
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@ provider "docker" {
|
|||
}
|
||||
}
|
||||
|
||||
resource "docker_image" "tftest_image" {
|
||||
name = "127.0.0.1:15000/tftest-service:v1"
|
||||
keep_locally = false
|
||||
}
|
||||
|
||||
resource "docker_volume" "test_volume" {
|
||||
name = "tftest-volume"
|
||||
}
|
||||
|
|
@ -33,7 +38,7 @@ resource "docker_service" "foo" {
|
|||
|
||||
task_spec {
|
||||
container_spec {
|
||||
image = "127.0.0.1:15000/tftest-service:v1"
|
||||
image = docker_image.tftest_image.repo_digest
|
||||
|
||||
labels {
|
||||
label = "foo"
|
||||
|
|
|
|||
|
|
@ -4,11 +4,16 @@ provider "docker" {
|
|||
}
|
||||
}
|
||||
|
||||
resource "docker_image" "tftest_image" {
|
||||
name = "127.0.0.1:15000/tftest-service:v1"
|
||||
keep_locally = false
|
||||
}
|
||||
|
||||
resource "docker_service" "foo" {
|
||||
name = "tftest-service-basic"
|
||||
task_spec {
|
||||
container_spec {
|
||||
image = "127.0.0.1:15000/tftest-service:v1"
|
||||
image = docker_image.tftest_image.repo_digest
|
||||
stop_grace_period = "10s"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ resource "docker_service" "foo" {
|
|||
name = "tftest-service-basic"
|
||||
task_spec {
|
||||
container_spec {
|
||||
image = "127.0.0.1:15000/tftest-service:v1"
|
||||
image = "127.0.0.1:15000/tftest-service:v1@sha256:2ca4c7a50df3515ea96106caab374759879830f6e4d6b400cee064e2e8db08c0"
|
||||
stop_grace_period = "10s"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,17 @@ provider "docker" {
|
|||
}
|
||||
}
|
||||
|
||||
resource "docker_image" "tftest_image" {
|
||||
name = "127.0.0.1:15000/tftest-service:v1"
|
||||
keep_locally = false
|
||||
force_remove = true
|
||||
}
|
||||
|
||||
resource "docker_service" "foo" {
|
||||
name = "tftest-service-basic"
|
||||
task_spec {
|
||||
container_spec {
|
||||
image = "127.0.0.1:15000/tftest-service:v1"
|
||||
image = docker_image.tftest_image.repo_digest
|
||||
stop_grace_period = "10s"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,17 @@ provider "docker" {
|
|||
}
|
||||
}
|
||||
|
||||
resource "docker_image" "tftest_image" {
|
||||
name = "127.0.0.1:15000/tftest-service:v1"
|
||||
keep_locally = false
|
||||
force_remove = true
|
||||
}
|
||||
|
||||
resource "docker_service" "foo" {
|
||||
name = "tftest-service-basic"
|
||||
task_spec {
|
||||
container_spec {
|
||||
image = "127.0.0.1:15000/tftest-service:v1"
|
||||
image = docker_image.tftest_image.repo_digest
|
||||
stop_grace_period = "10s"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,17 @@ provider "docker" {
|
|||
}
|
||||
}
|
||||
|
||||
resource "docker_image" "tftest_image" {
|
||||
name = "127.0.0.1:15000/tftest-service:v1"
|
||||
keep_locally = false
|
||||
force_remove = true
|
||||
}
|
||||
|
||||
resource "docker_service" "foo" {
|
||||
name = "tftest-service-basic"
|
||||
task_spec {
|
||||
container_spec {
|
||||
image = "127.0.0.1:15000/tftest-service:v1"
|
||||
image = docker_image.tftest_image.repo_digest
|
||||
stop_grace_period = "10s"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,29 @@
|
|||
provider "docker" {
|
||||
alias = "private"
|
||||
registry_auth {
|
||||
address = "%s"
|
||||
}
|
||||
}
|
||||
|
||||
data "docker_registry_image" "tftest_image" {
|
||||
provider = "docker.private"
|
||||
name = "%s"
|
||||
insecure_skip_verify = true
|
||||
}
|
||||
resource "docker_image" "tftest_image" {
|
||||
provider = "docker.private"
|
||||
name = data.docker_registry_image.tftest_image.name
|
||||
keep_locally = false
|
||||
force_remove = true
|
||||
pull_triggers = [data.docker_registry_image.tftest_image.sha256_digest]
|
||||
}
|
||||
|
||||
resource "docker_service" "foo" {
|
||||
name = "tftest-service-foo"
|
||||
provider = "docker.private"
|
||||
name = "tftest-service-foo"
|
||||
task_spec {
|
||||
container_spec {
|
||||
image = "%s"
|
||||
image = docker_image.tftest_image.repo_digest
|
||||
stop_grace_period = "10s"
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,12 +5,25 @@ provider "docker" {
|
|||
}
|
||||
}
|
||||
|
||||
data "docker_registry_image" "tftest_image" {
|
||||
provider = "docker.private"
|
||||
name = "%s"
|
||||
insecure_skip_verify = true
|
||||
}
|
||||
resource "docker_image" "tftest_image" {
|
||||
provider = "docker.private"
|
||||
name = data.docker_registry_image.tftest_image.name
|
||||
keep_locally = false
|
||||
force_remove = true
|
||||
pull_triggers = [data.docker_registry_image.tftest_image.sha256_digest]
|
||||
}
|
||||
|
||||
resource "docker_service" "foo" {
|
||||
provider = "docker.private"
|
||||
name = "tftest-service-updateFailsAndRollbackConverge"
|
||||
task_spec {
|
||||
container_spec {
|
||||
image = "%s"
|
||||
image = docker_image.tftest_image.repo_digest
|
||||
stop_grace_period = "10s"
|
||||
|
||||
healthcheck {
|
||||
|
|
|
|||
Loading…
Reference in a new issue