mirror of
https://github.com/kreuzwerker/terraform-provider-docker.git
synced 2025-12-20 22:59:42 -05:00
fix(registry_image): consider .dockerignore in image build (#240)
* fix(registry_image): consider .dockerignore in image build * test: for respecting dockerignore in registry image build
This commit is contained in:
parent
0b9790e3d3
commit
b759b8f2c9
6 changed files with 110 additions and 1 deletions
|
|
@ -20,9 +20,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/cli/cli/command/image/build"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
|
"github.com/docker/docker/pkg/fileutils"
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||||
|
|
@ -245,9 +247,10 @@ func buildDockerRegistryImage(ctx context.Context, client *client.Client, buildO
|
||||||
if lastIndex := strings.LastIndexByte(buildContext, ':'); (lastIndex > -1) && (buildContext[lastIndex+1] != filepath.Separator) {
|
if lastIndex := strings.LastIndexByte(buildContext, ':'); (lastIndex > -1) && (buildContext[lastIndex+1] != filepath.Separator) {
|
||||||
buildContext = buildContext[:lastIndex]
|
buildContext = buildContext[:lastIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
dockerContextTarPath, err := buildDockerImageContextTar(buildContext)
|
dockerContextTarPath, err := buildDockerImageContextTar(buildContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to build context %v", err)
|
return fmt.Errorf("unable to build context: %v", err)
|
||||||
}
|
}
|
||||||
defer os.Remove(dockerContextTarPath)
|
defer os.Remove(dockerContextTarPath)
|
||||||
dockerBuildContext, err := os.Open(dockerContextTarPath)
|
dockerBuildContext, err := os.Open(dockerContextTarPath)
|
||||||
|
|
@ -282,6 +285,16 @@ func buildDockerImageContextTar(buildContext string) (string, error) {
|
||||||
return "", fmt.Errorf("unable to read build context - %v", err.Error())
|
return "", fmt.Errorf("unable to read build context - %v", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
excludes, err := build.ReadDockerignore(buildContext)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("unable to read .dockerignore file - %v", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
pm, err := fileutils.NewPatternMatcher(excludes)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("unable to create pattern matcher from .dockerignore exlcudes - %v", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
tw := tar.NewWriter(tmpFile)
|
tw := tar.NewWriter(tmpFile)
|
||||||
defer tw.Close()
|
defer tw.Close()
|
||||||
|
|
||||||
|
|
@ -291,6 +304,46 @@ func buildDockerImageContextTar(buildContext string) (string, error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if .dockerignore is present, ignore files from there
|
||||||
|
skip, err := pm.Matches(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// adapted from https://github.com/moby/moby/blob/v20.10.7/pkg/archive/archive.go#L851
|
||||||
|
if skip {
|
||||||
|
log.Printf("[DEBUG] Skipping file/dir from image build '%v'", file)
|
||||||
|
// If we want to skip this file and its a directory
|
||||||
|
// then we should first check to see if there's an
|
||||||
|
// excludes pattern (e.g. !dir/file) that starts with this
|
||||||
|
// dir. If so then we can't skip this dir.
|
||||||
|
|
||||||
|
// Its not a dir then so we can just return/skip.
|
||||||
|
if !info.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// No exceptions (!...) in patterns so just skip dir
|
||||||
|
if !pm.Exclusions() {
|
||||||
|
return filepath.SkipDir
|
||||||
|
}
|
||||||
|
|
||||||
|
dirSlash := file + string(filepath.Separator)
|
||||||
|
|
||||||
|
for _, pat := range pm.Patterns() {
|
||||||
|
if !pat.Exclusion() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(pat.String()+string(filepath.Separator), dirSlash) {
|
||||||
|
// found a match - so can't skip this dir
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No matching exclusion dir so just skip dir
|
||||||
|
return filepath.SkipDir
|
||||||
|
}
|
||||||
|
|
||||||
// create a new dir/file header
|
// create a new dir/file header
|
||||||
header, err := tar.FileInfoHeader(info, info.Name())
|
header, err := tar.FileInfoHeader(info, info.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,59 @@ func TestAccDockerRegistryImageResource_buildAndKeep(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAccDockerRegistryImageResource_buildWithDockerignore(t *testing.T) {
|
||||||
|
pushOptions := createPushImageOptions("127.0.0.1:15000/tftest-dockerregistryimage-ignore:1.0")
|
||||||
|
wd, _ := os.Getwd()
|
||||||
|
context := strings.ReplaceAll((filepath.Join(wd, "..", "..", "scripts", "testing", "docker_registry_image_context_dockerignore")), "\\", "\\\\")
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
ProviderFactories: providerFactories,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
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"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_registry_image", "testBuildDockerRegistryImageNoKeepConfig"), pushOptions.Registry, pushOptions.Name, context),
|
||||||
|
Check: func(*terraform.State) error {
|
||||||
|
// we will modify the ignored file
|
||||||
|
f, err := os.OpenFile(context+"/empty_to_ignore", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to open file: %w", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
_, err = f.WriteString("modify-me")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to write to file: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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: resource.ComposeTestCheckFunc(
|
||||||
|
testDockerRegistryImageNotInRegistry(pushOptions),
|
||||||
|
func(*terraform.State) error {
|
||||||
|
// the 0 specifies the file will be empty afterwards
|
||||||
|
err := os.Truncate(context+"/empty_to_ignore", 0)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to truncate the ignored file: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestAccDockerRegistryImageResource_pushMissingImage(t *testing.T) {
|
func TestAccDockerRegistryImageResource_pushMissingImage(t *testing.T) {
|
||||||
resource.Test(t, resource.TestCase{
|
resource.Test(t, resource.TestCase{
|
||||||
PreCheck: func() { testAccPreCheck(t) },
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
empty_to_ignore
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
FROM scratch
|
||||||
|
COPY empty /empty
|
||||||
Loading…
Reference in a new issue