feat: Implementation of docker_tag resource. (#418)

* feat: Basic implementation of docker_tag resource.

* feat: Adding new AccDockerTag tests to ci pipeline.

* fix: Update failing tests.

* docs: Update tags documentation.

* fix: Fix docker_tags test.

* fix: docker_tag tests now download platform specific images.

* fix: also pull correct busybox image for dockert_tag test.
This commit is contained in:
Martin 2022-07-28 14:03:16 +02:00 committed by GitHub
parent cf3f8d6457
commit 777e292b7f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 198 additions and 1 deletions

View file

@ -38,6 +38,7 @@ jobs:
- "TestAccDockerSecret"
- "TestAccDockerService"
- "TestAccDockerVolume"
- "TestAccDockerTag"
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3

28
docs/resources/tag.md Normal file
View file

@ -0,0 +1,28 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "docker_tag Resource - terraform-provider-docker"
subcategory: ""
description: |-
Creates a docker tag. It has the exact same functionality as the docker tag command. Deleting the resource will neither delete the source nor target images. The source image must exist on the machine running the docker daemon.
---
# docker_tag (Resource)
Creates a docker tag. It has the exact same functionality as the `docker tag` command. Deleting the resource will neither delete the source nor target images. The source image must exist on the machine running the docker daemon.
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `source_image` (String) Name of the source image.
- `target_image` (String) Name of the target image.
### Read-Only
- `id` (String) The ID of this resource.
- `source_image_id` (String) ImageID of the source image in the format of `sha256:<<ID>>`

View file

@ -32,7 +32,7 @@ func TestAccDockerImageDataSource_withSpecificTag(t *testing.T) {
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", "busybox@sha256:8c40df61d40166f5791f44b3d90b77b4c7f59ed39a992fd9046886d3126ffa68"),
resource.TestCheckResourceAttr("data.docker_image.foo", "repo_digest", "busybox@sha256:a3170d3672568b2c6626710db3573f3d92ee31eed933c24f3d7ea978178e21b8"),
),
},
},

View file

@ -137,6 +137,7 @@ func New(version string) func() *schema.Provider {
"docker_secret": resourceDockerSecret(),
"docker_service": resourceDockerService(),
"docker_plugin": resourceDockerPlugin(),
"docker_tag": resourceDockerTag(),
},
DataSourcesMap: map[string]*schema.Resource{

View file

@ -0,0 +1,32 @@
package provider
import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
func resourceDockerTag() *schema.Resource {
return &schema.Resource{
Description: "Creates a docker tag. It has the exact same functionality as the `docker tag` command. Deleting the resource will neither delete the source nor target images. The source image must exist on the machine running the docker daemon.",
CreateContext: resourceDockerTagCreate,
DeleteContext: resourceDockerTagDelete,
ReadContext: resourceDockerTagRead,
Schema: map[string]*schema.Schema{
"source_image": {
Type: schema.TypeString,
Description: "Name of the source image.",
Required: true,
ForceNew: true,
},
"source_image_id": {
Type: schema.TypeString,
Description: "ImageID of the source image in the format of `sha256:<<ID>>`",
Computed: true,
},
"target_image": {
Type: schema.TypeString,
Description: "Name of the target image.",
Required: true,
ForceNew: true,
},
},
}
}

View file

@ -0,0 +1,44 @@
package provider
import (
"context"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func resourceDockerTagCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*ProviderConfig).DockerClient
sourceImage := d.Get("source_image").(string)
targetImage := d.Get("target_image").(string)
err := client.ImageTag(ctx, sourceImage, targetImage)
if err != nil {
return diag.Errorf("failed to create docker tag: %s", err)
}
imageInspect, _, err := client.ImageInspectWithRaw(ctx, sourceImage)
if err != nil {
return diag.Errorf("failed to ImageInspectWithRaw: %s", err)
}
d.Set("source_image_id", imageInspect.ID)
d.SetId(sourceImage + "." + targetImage)
return nil
}
func resourceDockerTagDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
// We do not delete any of the source and target images
return nil
}
func resourceDockerTagRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*ProviderConfig).DockerClient
sourceImage := d.Get("source_image").(string)
targetImage := d.Get("target_image").(string)
imageInspect, _, err := client.ImageInspectWithRaw(ctx, sourceImage)
if err != nil {
return diag.Errorf("failed to ImageInspectWithRaw: %s", err)
}
d.Set("source_image_id", imageInspect.ID)
d.SetId(sourceImage + "." + targetImage)
return nil
}

View file

@ -0,0 +1,80 @@
package provider
import (
"fmt"
"os/exec"
"regexp"
"testing"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)
// Things to test:
// * what happens when source_image is not available locally
// * wrong source_image/target_image names
// * update of source_image name
// * update of target_image name
func TestAccDockerTag_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_tag", "testAccDockerTag"), "nginx:1.17.6@sha256:36b77d8bb27ffca25c7f6f53cadd059aca2747d46fb6ef34064e31727325784e", "nginx:new_tag"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("docker_tag.foobar", "source_image_id", "sha256:f7bb5701a33c0e572ed06ca554edca1bee96cbbc1f76f3b01c985de7e19d0657"),
),
},
},
})
}
func TestAccDockerTag_no_local_image(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_tag", "testAccDockerTag"), "nginx:not_existent_on_machine", "nginx:new_tag"),
ExpectError: regexp.MustCompile(`Error response from daemon: No such image: nginx:not_existent_on_machine`),
},
},
})
}
func TestAccDockerTag_wrong_names(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_tag", "testAccDockerTag"), "foobar//nginx:not_existent_on_machine", "nginx:new_tag"),
ExpectError: regexp.MustCompile(`failed to create docker tag: Error parsing reference: "foobar//nginx:not_existent_on_machine"`),
},
},
})
}
func TestAccDockerTag_source_image_changed(t *testing.T) {
if err := exec.Command("docker", "pull", "busybox:1.35.0@sha256:8cde9b8065696b65d7b7ffaefbab0262d47a5a9852bfd849799559d296d2e0cd").Run(); err != nil {
t.Fatal(err)
}
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_tag", "testAccDockerTag"), "nginx:1.17.6@sha256:36b77d8bb27ffca25c7f6f53cadd059aca2747d46fb6ef34064e31727325784e", "nginx:new_tag"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("docker_tag.foobar", "source_image_id", "sha256:f7bb5701a33c0e572ed06ca554edca1bee96cbbc1f76f3b01c985de7e19d0657"),
),
},
{
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_tag", "testAccDockerTag"), "busybox:1.35.0@sha256:8cde9b8065696b65d7b7ffaefbab0262d47a5a9852bfd849799559d296d2e0cd", "nginx:new_tag"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("docker_tag.foobar", "source_image_id", "sha256:d8c0f97fc6a6ac400e43342e67d06222b27cecdb076cbf8a87f3a2a25effe81c"),
),
},
},
})
}

View file

@ -0,0 +1,11 @@
resource "docker_image" "foo" {
name = "nginx:1.17.6@sha256:36b77d8bb27ffca25c7f6f53cadd059aca2747d46fb6ef34064e31727325784e"
}
resource "docker_tag" "foobar" {
source_image = "%s"
target_image = "%s"
depends_on = [
docker_image.foo
]
}