mirror of
https://github.com/kreuzwerker/terraform-provider-docker.git
synced 2025-12-20 22:59:42 -05:00
feat: Migrate build block to docker_image (#501)
* feat: docker_image now has all build capabilities from docker_registry_image * tests: Move all docker_registry_image build tests to docker_image. * fix: Change build.context to optional. * docs: Update docs.
This commit is contained in:
parent
a5332be18d
commit
661c6628ff
14 changed files with 623 additions and 313 deletions
|
|
@ -104,17 +104,68 @@ resource "docker_image" "zoo" {
|
||||||
<a id="nestedblock--build"></a>
|
<a id="nestedblock--build"></a>
|
||||||
### Nested Schema for `build`
|
### Nested Schema for `build`
|
||||||
|
|
||||||
|
Optional:
|
||||||
|
|
||||||
|
- `auth_config` (Block List) The configuration for the authentication (see [below for nested schema](#nestedblock--build--auth_config))
|
||||||
|
- `build_arg` (Map of String) Set build-time variables
|
||||||
|
- `build_args` (Map of String) Pairs for build-time variables in the form TODO
|
||||||
|
- `build_id` (String) BuildID is an optional identifier that can be passed together with the build request. The same identifier can be used to gracefully cancel the build with the cancel request.
|
||||||
|
- `cache_from` (List of String) Images to consider as cache sources
|
||||||
|
- `cgroup_parent` (String) Optional parent cgroup for the container
|
||||||
|
- `context` (String) Value to specify the build context. Currently, only a `PATH` context is supported. You can use the helper function '${path.cwd}/context-dir'. Please see https://docs.docker.com/build/building/context/ for more information about build contexts.
|
||||||
|
- `cpu_period` (Number) The length of a CPU period in microseconds
|
||||||
|
- `cpu_quota` (Number) Microseconds of CPU time that the container can get in a CPU period
|
||||||
|
- `cpu_set_cpus` (String) CPUs in which to allow execution (e.g., `0-3`, `0`, `1`)
|
||||||
|
- `cpu_set_mems` (String) MEMs in which to allow execution (`0-3`, `0`, `1`)
|
||||||
|
- `cpu_shares` (Number) CPU shares (relative weight)
|
||||||
|
- `dockerfile` (String) Name of the Dockerfile. Defaults to `Dockerfile`.
|
||||||
|
- `extra_hosts` (List of String) A list of hostnames/IP mappings to add to the container’s /etc/hosts file. Specified in the form ["hostname:IP"]
|
||||||
|
- `force_remove` (Boolean) Always remove intermediate containers
|
||||||
|
- `isolation` (String) Isolation represents the isolation technology of a container. The supported values are
|
||||||
|
- `label` (Map of String) Set metadata for an image
|
||||||
|
- `labels` (Map of String) User-defined key/value metadata
|
||||||
|
- `memory` (Number) Set memory limit for build
|
||||||
|
- `memory_swap` (Number) Total memory (memory + swap), -1 to enable unlimited swap
|
||||||
|
- `network_mode` (String) Set the networking mode for the RUN instructions during build
|
||||||
|
- `no_cache` (Boolean) Do not use the cache when building the image
|
||||||
|
- `path` (String, Deprecated) Context path
|
||||||
|
- `platform` (String) Set platform if server is multi-platform capable
|
||||||
|
- `pull_parent` (Boolean) Attempt to pull the image even if an older image exists locally
|
||||||
|
- `remote_context` (String) A Git repository URI or HTTP/HTTPS context URI
|
||||||
|
- `remove` (Boolean) Remove intermediate containers after a successful build. Defaults to `true`.
|
||||||
|
- `security_opt` (List of String) The security options
|
||||||
|
- `session_id` (String) Set an ID for the build session
|
||||||
|
- `shm_size` (Number) Size of /dev/shm in bytes. The size must be greater than 0
|
||||||
|
- `squash` (Boolean) If true the new layers are squashed into a new image with a single new layer
|
||||||
|
- `suppress_output` (Boolean) Suppress the build output and print image ID on success
|
||||||
|
- `tag` (List of String) Name and optionally a tag in the 'name:tag' format
|
||||||
|
- `target` (String) Set the target build stage to build
|
||||||
|
- `ulimit` (Block List) Configuration for ulimits (see [below for nested schema](#nestedblock--build--ulimit))
|
||||||
|
- `version` (String) Version of the underlying builder to use
|
||||||
|
|
||||||
|
<a id="nestedblock--build--auth_config"></a>
|
||||||
|
### Nested Schema for `build.auth_config`
|
||||||
|
|
||||||
Required:
|
Required:
|
||||||
|
|
||||||
- `path` (String) Context path
|
- `host_name` (String) hostname of the registry
|
||||||
|
|
||||||
Optional:
|
Optional:
|
||||||
|
|
||||||
- `build_arg` (Map of String) Set build-time variables
|
- `auth` (String) the auth token
|
||||||
- `dockerfile` (String) Name of the Dockerfile. Defaults to `Dockerfile`.
|
- `email` (String) the user emal
|
||||||
- `force_remove` (Boolean) Always remove intermediate containers
|
- `identity_token` (String) the identity token
|
||||||
- `label` (Map of String) Set metadata for an image
|
- `password` (String) the registry password
|
||||||
- `no_cache` (Boolean) Do not use cache when building the image
|
- `registry_token` (String) the registry token
|
||||||
- `remove` (Boolean) Remove intermediate containers after a successful build. Defaults to `true`.
|
- `server_address` (String) the server address
|
||||||
- `tag` (List of String) Name and optionally a tag in the 'name:tag' format
|
- `user_name` (String) the registry user name
|
||||||
- `target` (String) Set the target build stage to build
|
|
||||||
|
|
||||||
|
<a id="nestedblock--build--ulimit"></a>
|
||||||
|
### Nested Schema for `build.ulimit`
|
||||||
|
|
||||||
|
Required:
|
||||||
|
|
||||||
|
- `hard` (Number) soft limit
|
||||||
|
- `name` (String) type of ulimit, e.g. `nofile`
|
||||||
|
- `soft` (Number) hard limit
|
||||||
|
|
|
||||||
|
|
@ -33,10 +33,10 @@ resource "docker_registry_image" "helloworld" {
|
||||||
|
|
||||||
### Optional
|
### Optional
|
||||||
|
|
||||||
- `build` (Block List, Max: 1) Definition for building the image (see [below for nested schema](#nestedblock--build))
|
- `build` (Block List, Max: 1, Deprecated) Definition for building the image (see [below for nested schema](#nestedblock--build))
|
||||||
- `insecure_skip_verify` (Boolean) If `true`, the verification of TLS certificates of the server/registry is disabled. Defaults to `false`
|
- `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`
|
- `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`
|
||||||
- `triggers` (Map of String) A map of arbitrary strings that, when changed, will force the `docker_registry_image` resource to be replaced. This can be used to rebuild an image when contents of source code folders change or to repush a local image
|
- `triggers` (Map of String) A map of arbitrary strings that, when changed, will force the `docker_registry_image` resource to be replaced. This can be used to repush a local image
|
||||||
|
|
||||||
### Read-Only
|
### Read-Only
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -96,8 +96,9 @@ func resourceDockerImage() *schema.Resource {
|
||||||
"path": {
|
"path": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Description: "Context path",
|
Description: "Context path",
|
||||||
Required: true,
|
Optional: true,
|
||||||
ForceNew: true,
|
ForceNew: true,
|
||||||
|
Deprecated: "Use context instead. This attribute will be removed in the next major release.",
|
||||||
},
|
},
|
||||||
"dockerfile": {
|
"dockerfile": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
|
|
@ -114,27 +115,12 @@ func resourceDockerImage() *schema.Resource {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"force_remove": {
|
|
||||||
Type: schema.TypeBool,
|
|
||||||
Description: "Always remove intermediate containers",
|
|
||||||
Optional: true,
|
|
||||||
},
|
|
||||||
"remove": {
|
"remove": {
|
||||||
Type: schema.TypeBool,
|
Type: schema.TypeBool,
|
||||||
Description: "Remove intermediate containers after a successful build. Defaults to `true`.",
|
Description: "Remove intermediate containers after a successful build. Defaults to `true`.",
|
||||||
Default: true,
|
Default: true,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
},
|
},
|
||||||
"no_cache": {
|
|
||||||
Type: schema.TypeBool,
|
|
||||||
Description: "Do not use cache when building the image",
|
|
||||||
Optional: true,
|
|
||||||
},
|
|
||||||
"target": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Description: "Set the target build stage to build",
|
|
||||||
Optional: true,
|
|
||||||
},
|
|
||||||
"build_arg": {
|
"build_arg": {
|
||||||
Type: schema.TypeMap,
|
Type: schema.TypeMap,
|
||||||
Description: "Set build-time variables",
|
Description: "Set build-time variables",
|
||||||
|
|
@ -152,6 +138,270 @@ func resourceDockerImage() *schema.Resource {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"suppress_output": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Description: "Suppress the build output and print image ID on success",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"remote_context": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "A Git repository URI or HTTP/HTTPS context URI",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"no_cache": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Description: "Do not use the cache when building the image",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"force_remove": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Description: "Always remove intermediate containers",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"pull_parent": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Description: "Attempt to pull the image even if an older image exists locally",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"isolation": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "Isolation represents the isolation technology of a container. The supported values are ",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"cpu_set_cpus": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "CPUs in which to allow execution (e.g., `0-3`, `0`, `1`)",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"cpu_set_mems": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "MEMs in which to allow execution (`0-3`, `0`, `1`)",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"cpu_shares": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Description: "CPU shares (relative weight)",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"cpu_quota": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Description: "Microseconds of CPU time that the container can get in a CPU period",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"cpu_period": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Description: "The length of a CPU period in microseconds",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"memory": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Description: "Set memory limit for build",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"memory_swap": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Description: "Total memory (memory + swap), -1 to enable unlimited swap",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"cgroup_parent": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "Optional parent cgroup for the container",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"network_mode": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "Set the networking mode for the RUN instructions during build",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"shm_size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Description: "Size of /dev/shm in bytes. The size must be greater than 0",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"ulimit": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Description: "Configuration for ulimits",
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "type of ulimit, e.g. `nofile`",
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"hard": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Description: "soft limit",
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"soft": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Description: "hard limit",
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"build_args": {
|
||||||
|
Type: schema.TypeMap,
|
||||||
|
Description: "Pairs for build-time variables in the form TODO",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "The argument",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"auth_config": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Description: "The configuration for the authentication",
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"host_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "hostname of the registry",
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"user_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "the registry user name",
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "the registry password",
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "the auth token",
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "the user emal",
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"server_address": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "the server address",
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"identity_token": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "the identity token",
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"registry_token": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "the registry token",
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"context": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "Value to specify the build context. Currently, only a `PATH` context is supported. You can use the helper function '${path.cwd}/context-dir'. Please see https://docs.docker.com/build/building/context/ for more information about build contexts.",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
Type: schema.TypeMap,
|
||||||
|
Description: "User-defined key/value metadata",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "The key/value pair",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"squash": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Description: "If true the new layers are squashed into a new image with a single new layer",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"cache_from": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Description: "Images to consider as cache sources",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "The image",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"security_opt": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Description: "The security options",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "The option",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"extra_hosts": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Description: "A list of hostnames/IP mappings to add to the container’s /etc/hosts file. Specified in the form [\"hostname:IP\"]",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"target": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "Set the target build stage to build",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"session_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "Set an ID for the build session",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "Set platform if server is multi-platform capable",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "Version of the underlying builder to use",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"build_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "BuildID is an optional identifier that can be passed together with the build request. The same identifier can be used to gracefully cancel the build with the cancel request.",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -325,9 +325,8 @@ func buildDockerImage(ctx context.Context, rawBuild map[string]interface{}, imag
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
buildOptions := types.ImageBuildOptions{}
|
log.Printf("[DEBUG] Building docker image")
|
||||||
|
buildOptions := createImageBuildOptions(rawBuild)
|
||||||
buildOptions.Dockerfile = rawBuild["dockerfile"].(string)
|
|
||||||
|
|
||||||
tags := []string{imageName}
|
tags := []string{imageName}
|
||||||
for _, t := range rawBuild["tag"].([]interface{}) {
|
for _, t := range rawBuild["tag"].([]interface{}) {
|
||||||
|
|
@ -335,29 +334,26 @@ func buildDockerImage(ctx context.Context, rawBuild map[string]interface{}, imag
|
||||||
}
|
}
|
||||||
buildOptions.Tags = tags
|
buildOptions.Tags = tags
|
||||||
|
|
||||||
buildOptions.ForceRemove = rawBuild["force_remove"].(bool)
|
// Supporting both "path" and "context" for backwards compatibility
|
||||||
buildOptions.Remove = rawBuild["remove"].(bool)
|
// TODO: remove "path" in the next major release
|
||||||
buildOptions.NoCache = rawBuild["no_cache"].(bool)
|
pathAttribute := rawBuild["path"].(string)
|
||||||
buildOptions.Target = rawBuild["target"].(string)
|
contextAttribute := rawBuild["context"].(string)
|
||||||
|
if len(pathAttribute) == 0 && len(contextAttribute) == 0 {
|
||||||
buildArgs := make(map[string]*string)
|
return errors.New("one of path or context must be configured")
|
||||||
for k, v := range rawBuild["build_arg"].(map[string]interface{}) {
|
|
||||||
val := v.(string)
|
|
||||||
buildArgs[k] = &val
|
|
||||||
}
|
}
|
||||||
buildOptions.BuildArgs = buildArgs
|
|
||||||
log.Printf("[DEBUG] Build Args: %v\n", buildArgs)
|
|
||||||
|
|
||||||
labels := make(map[string]string)
|
buildContext := ""
|
||||||
for k, v := range rawBuild["label"].(map[string]interface{}) {
|
if len(pathAttribute) > 0 {
|
||||||
labels[k] = v.(string)
|
// add existingAttribute to provider create API call
|
||||||
|
buildContext = pathAttribute
|
||||||
|
} else {
|
||||||
|
// add newAttribute to provider create API call
|
||||||
|
buildContext = contextAttribute
|
||||||
}
|
}
|
||||||
buildOptions.Labels = labels
|
// End backwards compatibility, remove until here
|
||||||
log.Printf("[DEBUG] Labels: %v\n", labels)
|
|
||||||
|
|
||||||
enableBuildKitIfSupported(ctx, client, &buildOptions)
|
enableBuildKitIfSupported(ctx, client, &buildOptions)
|
||||||
|
|
||||||
buildCtx, relDockerfile, err := prepareBuildContext(rawBuild["path"].(string), buildOptions.Dockerfile)
|
buildCtx, relDockerfile, err := prepareBuildContext(buildContext, buildOptions.Dockerfile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,115 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
|
"github.com/docker/go-units"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
|
"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"
|
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
|
||||||
)
|
)
|
||||||
|
|
||||||
var contentDigestRegexp = regexp.MustCompile(`\A[A-Za-z0-9_\+\.-]+:[A-Fa-f0-9]+\z`)
|
var contentDigestRegexp = regexp.MustCompile(`\A[A-Za-z0-9_\+\.-]+:[A-Fa-f0-9]+\z`)
|
||||||
|
|
||||||
|
func TestAccDockerRegistryImageResource_mapping(t *testing.T) {
|
||||||
|
assert := func(condition bool, msg string) {
|
||||||
|
if !condition {
|
||||||
|
t.Errorf("assertion failed: wrong build parameter %s", msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dummyProvider := New("dev")()
|
||||||
|
dummyResource := dummyProvider.ResourcesMap["docker_image"]
|
||||||
|
dummyResource.CreateContext = func(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||||
|
|
||||||
|
if value, ok := d.GetOk("build"); ok {
|
||||||
|
for _, rawBuild := range value.(*schema.Set).List() {
|
||||||
|
build := rawBuild.(map[string]interface{})
|
||||||
|
// build := d.Get("build").([]interface{})[0].(map[string]interface{})
|
||||||
|
options := createImageBuildOptions(build)
|
||||||
|
|
||||||
|
assert(options.SuppressOutput == true, "SuppressOutput")
|
||||||
|
assert(options.RemoteContext == "fooRemoteContext", "RemoteContext")
|
||||||
|
assert(options.NoCache == true, "NoCache")
|
||||||
|
assert(options.Remove == true, "Remove")
|
||||||
|
assert(options.ForceRemove == true, "ForceRemove")
|
||||||
|
assert(options.PullParent == true, "PullParent")
|
||||||
|
assert(options.Isolation == container.Isolation("hyperv"), "Isolation")
|
||||||
|
assert(options.CPUSetCPUs == "fooCpuSetCpus", "CPUSetCPUs")
|
||||||
|
assert(options.CPUSetMems == "fooCpuSetMems", "CPUSetMems")
|
||||||
|
assert(options.CPUShares == int64(4), "CPUShares")
|
||||||
|
assert(options.CPUQuota == int64(5), "CPUQuota")
|
||||||
|
assert(options.CPUPeriod == int64(6), "CPUPeriod")
|
||||||
|
assert(options.Memory == int64(1), "Memory")
|
||||||
|
assert(options.MemorySwap == int64(2), "MemorySwap")
|
||||||
|
assert(options.CgroupParent == "fooCgroupParent", "CgroupParent")
|
||||||
|
assert(options.NetworkMode == "fooNetworkMode", "NetworkMode")
|
||||||
|
assert(options.ShmSize == int64(3), "ShmSize")
|
||||||
|
assert(options.Dockerfile == "fooDockerfile", "Dockerfile")
|
||||||
|
assert(len(options.Ulimits) == 1, "Ulimits")
|
||||||
|
assert(reflect.DeepEqual(*options.Ulimits[0], units.Ulimit{
|
||||||
|
Name: "foo",
|
||||||
|
Hard: int64(1),
|
||||||
|
Soft: int64(2),
|
||||||
|
}), "Ulimits")
|
||||||
|
assert(len(options.BuildArgs) == 1, "BuildArgs")
|
||||||
|
// DevSkim: ignore DS137138
|
||||||
|
assert(*options.BuildArgs["HTTP_PROXY"] == "http://10.20.30.2:1234", "BuildArgs")
|
||||||
|
assert(len(options.AuthConfigs) == 1, "AuthConfigs")
|
||||||
|
assert(reflect.DeepEqual(options.AuthConfigs["foo.host"], types.AuthConfig{
|
||||||
|
Username: "fooUserName",
|
||||||
|
Password: "fooPassword",
|
||||||
|
Auth: "fooAuth",
|
||||||
|
Email: "fooEmail",
|
||||||
|
ServerAddress: "fooServerAddress",
|
||||||
|
IdentityToken: "fooIdentityToken",
|
||||||
|
RegistryToken: "fooRegistryToken",
|
||||||
|
}), "AuthConfigs")
|
||||||
|
assert(reflect.DeepEqual(options.Labels, map[string]string{"foo": "bar"}), "Labels")
|
||||||
|
assert(options.Squash == true, "Squash")
|
||||||
|
assert(reflect.DeepEqual(options.CacheFrom, []string{"fooCacheFrom", "barCacheFrom"}), "CacheFrom")
|
||||||
|
assert(reflect.DeepEqual(options.SecurityOpt, []string{"fooSecurityOpt", "barSecurityOpt"}), "SecurityOpt")
|
||||||
|
assert(reflect.DeepEqual(options.ExtraHosts, []string{"fooExtraHost", "barExtraHost"}), "ExtraHosts")
|
||||||
|
assert(options.Target == "fooTarget", "Target")
|
||||||
|
assert(options.SessionID == "fooSessionId", "SessionID")
|
||||||
|
assert(options.Platform == "fooPlatform", "Platform")
|
||||||
|
assert(options.Version == types.BuilderVersion("1"), "Version")
|
||||||
|
assert(options.BuildID == "fooBuildId", "BuildID")
|
||||||
|
// output
|
||||||
|
d.SetId("foo")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
dummyResource.UpdateContext = func(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
dummyResource.DeleteContext = func(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
dummyResource.ReadContext = func(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||||
|
d.Set("id", "foo")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
ProviderFactories: map[string]func() (*schema.Provider, error){
|
||||||
|
"docker": func() (*schema.Provider, error) {
|
||||||
|
return dummyProvider, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
Config: loadTestConfiguration(t, RESOURCE, "docker_image", "testBuildDockerImageMappingConfig"),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttrSet("docker_image.foo", "id"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestAccDockerImage_basic(t *testing.T) {
|
func TestAccDockerImage_basic(t *testing.T) {
|
||||||
// run a Docker container which refers the Docker image to test "force_remove" option
|
// run a Docker container which refers the Docker image to test "force_remove" option
|
||||||
containerName := "test-docker-image-force-remove"
|
containerName := "test-docker-image-force-remove"
|
||||||
|
|
@ -396,6 +499,113 @@ func TestAccDockerImage_buildOutsideContext(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAccDockerImageResource_build(t *testing.T) {
|
||||||
|
name := "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,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_image", "testBuildDockerImageNoKeepConfig"), name, context),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttrSet("docker_image.foo", "image_id"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for https://github.com/kreuzwerker/terraform-provider-docker/issues/249
|
||||||
|
func TestAccDockerImageResource_whitelistDockerignore(t *testing.T) {
|
||||||
|
name := "tftest-dockerregistryimage-whitelistdockerignore:1.0"
|
||||||
|
wd, _ := os.Getwd()
|
||||||
|
context := strings.ReplaceAll((filepath.Join(wd, "..", "..", "scripts", "testing", "docker_registry_image_file_whitelist_dockerignore")), "\\", "\\\\")
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
ProviderFactories: providerFactories,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_image", "testDockerImageFilePermissions"), name, context, "Dockerfile"),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttrSet("docker_image.file_permissions", "image_id"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests for issue https://github.com/kreuzwerker/terraform-provider-docker/issues/293
|
||||||
|
// First we check if we can build the docker_registry_image resource at all
|
||||||
|
// TODO in a second step we want to check whether the file has the correct permissions
|
||||||
|
func TestAccDockerImageResource_correctFilePermissions(t *testing.T) {
|
||||||
|
name := "tftest-dockerregistryimage-filepermissions:1.0"
|
||||||
|
wd, _ := os.Getwd()
|
||||||
|
context := strings.ReplaceAll((filepath.Join(wd, "..", "..", "scripts", "testing", "docker_registry_image_file_permissions")), "\\", "\\\\")
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
ProviderFactories: providerFactories,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_image", "testDockerImageFilePermissions"), name, context, "Dockerfile"),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttrSet("docker_image.file_permissions", "image_id"),
|
||||||
|
),
|
||||||
|
// TODO another check which starts the the newly built docker image and checks the file permissions to see if they are correct
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccDockerImageResource_buildWithDockerignore(t *testing.T) {
|
||||||
|
name := "tftest-dockerregistryimage-ignore:1.0"
|
||||||
|
wd, _ := os.Getwd()
|
||||||
|
ctx := context.Background()
|
||||||
|
context := strings.ReplaceAll((filepath.Join(wd, "..", "..", "scripts", "testing", "docker_registry_image_context_dockerignore")), "\\", "\\\\")
|
||||||
|
ignoredFile := context + "/to_be_ignored"
|
||||||
|
expectedSha := ""
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
ProviderFactories: providerFactories,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_image", "testBuildDockerImageNoKeepJustCache"), "one", name, context),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttrSet("docker_image.one", "image_id"),
|
||||||
|
resource.TestCheckResourceAttrWith("docker_image.one", "image_id", func(value string) error {
|
||||||
|
expectedSha = value
|
||||||
|
return nil
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
PreConfig: func() {
|
||||||
|
// create a file that should be ignored
|
||||||
|
f, err := os.OpenFile(ignoredFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
panic("failed to create test file")
|
||||||
|
}
|
||||||
|
f.Close()
|
||||||
|
},
|
||||||
|
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_image", "testBuildDockerImageNoKeepJustCache"), "two", name, context),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttrWith("docker_image.two", "image_id", func(value string) error {
|
||||||
|
if value != expectedSha {
|
||||||
|
return fmt.Errorf("Image sha256_digest changed, expected %#v, got %#v", expectedSha, value)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CheckDestroy: func(state *terraform.State) error {
|
||||||
|
return testAccDockerImageDestroy(ctx, state)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func testAccImageCreated(resourceName string, image *types.ImageInspect) resource.TestCheckFunc {
|
func testAccImageCreated(resourceName string, image *types.ImageInspect) resource.TestCheckFunc {
|
||||||
return func(s *terraform.State) error {
|
return func(s *terraform.State) error {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ func resourceDockerRegistryImage() *schema.Resource {
|
||||||
Description: "Definition for building the image",
|
Description: "Definition for building the image",
|
||||||
Optional: true,
|
Optional: true,
|
||||||
MaxItems: 1,
|
MaxItems: 1,
|
||||||
|
Deprecated: "Use `docker_image` resource instead. This field will be removed in the next major release.",
|
||||||
Elem: &schema.Resource{
|
Elem: &schema.Resource{
|
||||||
Schema: map[string]*schema.Schema{
|
Schema: map[string]*schema.Schema{
|
||||||
"suppress_output": {
|
"suppress_output": {
|
||||||
|
|
@ -333,7 +334,7 @@ func resourceDockerRegistryImage() *schema.Resource {
|
||||||
},
|
},
|
||||||
|
|
||||||
"triggers": {
|
"triggers": {
|
||||||
Description: "A map of arbitrary strings that, when changed, will force the `docker_registry_image` resource to be replaced. This can be used to rebuild an image when contents of source code folders change or to repush a local image",
|
Description: "A map of arbitrary strings that, when changed, will force the `docker_registry_image` resource to be replaced. This can be used to repush a local image",
|
||||||
Type: schema.TypeMap,
|
Type: schema.TypeMap,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
ForceNew: true,
|
ForceNew: true,
|
||||||
|
|
|
||||||
|
|
@ -1,137 +1,17 @@
|
||||||
package provider
|
package provider
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
"github.com/docker/docker/api/types/container"
|
|
||||||
"github.com/docker/go-units"
|
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
|
"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"
|
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAccDockerRegistryImageResource_mapping(t *testing.T) {
|
|
||||||
assert := func(condition bool, msg string) {
|
|
||||||
if !condition {
|
|
||||||
t.Errorf("assertion failed: wrong build parameter %s", msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dummyProvider := New("dev")()
|
|
||||||
dummyResource := dummyProvider.ResourcesMap["docker_registry_image"]
|
|
||||||
dummyResource.CreateContext = func(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
|
||||||
build := d.Get("build").([]interface{})[0].(map[string]interface{})
|
|
||||||
options := createImageBuildOptions(build)
|
|
||||||
|
|
||||||
assert(options.SuppressOutput == true, "SuppressOutput")
|
|
||||||
assert(options.RemoteContext == "fooRemoteContext", "RemoteContext")
|
|
||||||
assert(options.NoCache == true, "NoCache")
|
|
||||||
assert(options.Remove == true, "Remove")
|
|
||||||
assert(options.ForceRemove == true, "ForceRemove")
|
|
||||||
assert(options.PullParent == true, "PullParent")
|
|
||||||
assert(options.Isolation == container.Isolation("hyperv"), "Isolation")
|
|
||||||
assert(options.CPUSetCPUs == "fooCpuSetCpus", "CPUSetCPUs")
|
|
||||||
assert(options.CPUSetMems == "fooCpuSetMems", "CPUSetMems")
|
|
||||||
assert(options.CPUShares == int64(4), "CPUShares")
|
|
||||||
assert(options.CPUQuota == int64(5), "CPUQuota")
|
|
||||||
assert(options.CPUPeriod == int64(6), "CPUPeriod")
|
|
||||||
assert(options.Memory == int64(1), "Memory")
|
|
||||||
assert(options.MemorySwap == int64(2), "MemorySwap")
|
|
||||||
assert(options.CgroupParent == "fooCgroupParent", "CgroupParent")
|
|
||||||
assert(options.NetworkMode == "fooNetworkMode", "NetworkMode")
|
|
||||||
assert(options.ShmSize == int64(3), "ShmSize")
|
|
||||||
assert(options.Dockerfile == "fooDockerfile", "Dockerfile")
|
|
||||||
assert(len(options.Ulimits) == 1, "Ulimits")
|
|
||||||
assert(reflect.DeepEqual(*options.Ulimits[0], units.Ulimit{
|
|
||||||
Name: "foo",
|
|
||||||
Hard: int64(1),
|
|
||||||
Soft: int64(2),
|
|
||||||
}), "Ulimits")
|
|
||||||
assert(len(options.BuildArgs) == 1, "BuildArgs")
|
|
||||||
// DevSkim: ignore DS137138
|
|
||||||
assert(*options.BuildArgs["HTTP_PROXY"] == "http://10.20.30.2:1234", "BuildArgs")
|
|
||||||
assert(len(options.AuthConfigs) == 1, "AuthConfigs")
|
|
||||||
assert(reflect.DeepEqual(options.AuthConfigs["foo.host"], types.AuthConfig{
|
|
||||||
Username: "fooUserName",
|
|
||||||
Password: "fooPassword",
|
|
||||||
Auth: "fooAuth",
|
|
||||||
Email: "fooEmail",
|
|
||||||
ServerAddress: "fooServerAddress",
|
|
||||||
IdentityToken: "fooIdentityToken",
|
|
||||||
RegistryToken: "fooRegistryToken",
|
|
||||||
}), "AuthConfigs")
|
|
||||||
assert(reflect.DeepEqual(options.Labels, map[string]string{"foo": "bar"}), "Labels")
|
|
||||||
assert(options.Squash == true, "Squash")
|
|
||||||
assert(reflect.DeepEqual(options.CacheFrom, []string{"fooCacheFrom", "barCacheFrom"}), "CacheFrom")
|
|
||||||
assert(reflect.DeepEqual(options.SecurityOpt, []string{"fooSecurityOpt", "barSecurityOpt"}), "SecurityOpt")
|
|
||||||
assert(reflect.DeepEqual(options.ExtraHosts, []string{"fooExtraHost", "barExtraHost"}), "ExtraHosts")
|
|
||||||
assert(options.Target == "fooTarget", "Target")
|
|
||||||
assert(options.SessionID == "fooSessionId", "SessionID")
|
|
||||||
assert(options.Platform == "fooPlatform", "Platform")
|
|
||||||
assert(options.Version == types.BuilderVersion("1"), "Version")
|
|
||||||
assert(options.BuildID == "fooBuildId", "BuildID")
|
|
||||||
// output
|
|
||||||
d.SetId("foo")
|
|
||||||
d.Set("sha256_digest", "bar")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
dummyResource.UpdateContext = func(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
dummyResource.DeleteContext = func(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
dummyResource.ReadContext = func(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
|
||||||
d.Set("sha256_digest", "bar")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
resource.Test(t, resource.TestCase{
|
|
||||||
PreCheck: func() { testAccPreCheck(t) },
|
|
||||||
ProviderFactories: map[string]func() (*schema.Provider, error){
|
|
||||||
"docker": func() (*schema.Provider, error) {
|
|
||||||
return dummyProvider, nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Steps: []resource.TestStep{
|
|
||||||
{
|
|
||||||
Config: loadTestConfiguration(t, RESOURCE, "docker_registry_image", "testBuildDockerRegistryImageMappingConfig"),
|
|
||||||
Check: resource.ComposeTestCheckFunc(
|
|
||||||
resource.TestCheckResourceAttrSet("docker_registry_image.foo", "sha256_digest"),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAccDockerRegistryImageResource_build(t *testing.T) {
|
|
||||||
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,
|
|
||||||
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"),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
CheckDestroy: testDockerRegistryImageNotInRegistry(pushOptions),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
func TestAccDockerRegistryImageResource_build_insecure_registry(t *testing.T) {
|
func TestAccDockerRegistryImageResource_build_insecure_registry(t *testing.T) {
|
||||||
pushOptions := createPushImageOptions("127.0.0.1:15001/tftest-dockerregistryimage:1.0")
|
pushOptions := createPushImageOptions("127.0.0.1:15001/tftest-dockerregistryimage:1.0")
|
||||||
wd, _ := os.Getwd()
|
wd, _ := os.Getwd()
|
||||||
|
|
@ -173,125 +53,6 @@ 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")), "\\", "\\\\")
|
|
||||||
ignoredFile := context + "/to_be_ignored"
|
|
||||||
expectedSha := ""
|
|
||||||
|
|
||||||
resource.Test(t, resource.TestCase{
|
|
||||||
PreCheck: func() { testAccPreCheck(t) },
|
|
||||||
ProviderFactories: providerFactories,
|
|
||||||
Steps: []resource.TestStep{
|
|
||||||
{
|
|
||||||
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_registry_image", "testBuildDockerRegistryImageNoKeepJustCache"), pushOptions.Registry, "one", pushOptions.Name, context),
|
|
||||||
Check: resource.ComposeTestCheckFunc(
|
|
||||||
resource.TestCheckResourceAttrSet("docker_registry_image.one", "sha256_digest"),
|
|
||||||
resource.TestCheckResourceAttrWith("docker_registry_image.one", "sha256_digest", func(value string) error {
|
|
||||||
expectedSha = value
|
|
||||||
return nil
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
PreConfig: func() {
|
|
||||||
// create a file that should be ignored
|
|
||||||
f, err := os.OpenFile(ignoredFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|
||||||
if err != nil {
|
|
||||||
panic("failed to create test file")
|
|
||||||
}
|
|
||||||
f.Close()
|
|
||||||
},
|
|
||||||
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_registry_image", "testBuildDockerRegistryImageNoKeepJustCache"), pushOptions.Registry, "two", pushOptions.Name, context),
|
|
||||||
Check: resource.ComposeTestCheckFunc(
|
|
||||||
resource.TestCheckResourceAttrWith("docker_registry_image.two", "sha256_digest", func(value string) error {
|
|
||||||
if value != expectedSha {
|
|
||||||
return fmt.Errorf("Image sha256_digest changed, expected %#v, got %#v", expectedSha, value)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
CheckDestroy: resource.ComposeTestCheckFunc(
|
|
||||||
testDockerRegistryImageNotInRegistry(pushOptions),
|
|
||||||
func(*terraform.State) error {
|
|
||||||
err := os.Remove(ignoredFile)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to remove ignored file: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tests for issue https://github.com/kreuzwerker/terraform-provider-docker/issues/293
|
|
||||||
// First we check if we can build the docker_registry_image resource at all
|
|
||||||
// TODO in a second step we want to check whether the file has the correct permissions
|
|
||||||
func TestAccDockerRegistryImageResource_correctFilePermissions(t *testing.T) {
|
|
||||||
pushOptions := createPushImageOptions("127.0.0.1:15000/tftest-dockerregistryimage-filepermissions:1.0")
|
|
||||||
wd, _ := os.Getwd()
|
|
||||||
context := strings.ReplaceAll((filepath.Join(wd, "..", "..", "scripts", "testing", "docker_registry_image_file_permissions")), "\\", "\\\\")
|
|
||||||
resource.Test(t, resource.TestCase{
|
|
||||||
PreCheck: func() { testAccPreCheck(t) },
|
|
||||||
ProviderFactories: providerFactories,
|
|
||||||
Steps: []resource.TestStep{
|
|
||||||
{
|
|
||||||
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_registry_image", "testDockerRegistryImageFilePermissions"), pushOptions.Registry, pushOptions.Name, context, "Dockerfile"),
|
|
||||||
Check: resource.ComposeTestCheckFunc(
|
|
||||||
resource.TestCheckResourceAttrSet("docker_registry_image.file_permissions", "sha256_digest"),
|
|
||||||
),
|
|
||||||
// TODO another check which starts the the newly built docker image and checks the file permissions to see if they are correct
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test for https://github.com/kreuzwerker/terraform-provider-docker/issues/249
|
|
||||||
func TestAccDockerRegistryImageResource_whitelistDockerignore(t *testing.T) {
|
|
||||||
pushOptions := createPushImageOptions("127.0.0.1:15000/tftest-dockerregistryimage-whitelistdockerignore:1.0")
|
|
||||||
wd, _ := os.Getwd()
|
|
||||||
context := strings.ReplaceAll((filepath.Join(wd, "..", "..", "scripts", "testing", "docker_registry_image_file_whitelist_dockerignore")), "\\", "\\\\")
|
|
||||||
resource.Test(t, resource.TestCase{
|
|
||||||
PreCheck: func() { testAccPreCheck(t) },
|
|
||||||
ProviderFactories: providerFactories,
|
|
||||||
Steps: []resource.TestStep{
|
|
||||||
{
|
|
||||||
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_registry_image", "testDockerRegistryImageFilePermissions"), pushOptions.Registry, pushOptions.Name, context, "Dockerfile"),
|
|
||||||
Check: resource.ComposeTestCheckFunc(
|
|
||||||
resource.TestCheckResourceAttrSet("docker_registry_image.file_permissions", "sha256_digest"),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test for https://github.com/kreuzwerker/terraform-provider-docker/issues/249
|
|
||||||
func TestAccDockerRegistryImageResource_DockerfileOutsideContext(t *testing.T) {
|
|
||||||
pushOptions := createPushImageOptions("127.0.0.1:15000/tftest-dockerregistryimage-dockerfileoutsidecontext:1.0")
|
|
||||||
wd, _ := os.Getwd()
|
|
||||||
dfPath := filepath.Join(wd, "..", "Dockerfile")
|
|
||||||
if err := ioutil.WriteFile(dfPath, []byte(testDockerFileExample), 0o644); err != nil {
|
|
||||||
t.Fatalf("failed to create a Dockerfile %s for test: %+v", dfPath, err)
|
|
||||||
}
|
|
||||||
defer os.Remove(dfPath)
|
|
||||||
context := strings.ReplaceAll((filepath.Join(wd, "..", "..", "scripts", "testing", "docker_registry_image_file_permissions")), "\\", "\\\\")
|
|
||||||
resource.Test(t, resource.TestCase{
|
|
||||||
PreCheck: func() { testAccPreCheck(t) },
|
|
||||||
ProviderFactories: providerFactories,
|
|
||||||
Steps: []resource.TestStep{
|
|
||||||
{
|
|
||||||
Config: fmt.Sprintf(loadTestConfiguration(t, RESOURCE, "docker_registry_image", "testDockerRegistryImageDockerfileOutsideContext"), pushOptions.Registry, pushOptions.Name, context),
|
|
||||||
Check: resource.ComposeTestCheckFunc(
|
|
||||||
resource.TestCheckResourceAttrSet("docker_registry_image.outside_context", "sha256_digest"),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
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) },
|
||||||
|
|
|
||||||
14
testdata/resources/docker_image/testBuildDockerImageKeepConfig.tf
vendored
Normal file
14
testdata/resources/docker_image/testBuildDockerImageKeepConfig.tf
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
provider "docker" {
|
||||||
|
alias = "private"
|
||||||
|
}
|
||||||
|
resource "docker_image" "foo" {
|
||||||
|
provider = "docker.private"
|
||||||
|
name = "%s"
|
||||||
|
|
||||||
|
build {
|
||||||
|
context = "%s"
|
||||||
|
remove = true
|
||||||
|
force_remove = true
|
||||||
|
no_cache = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
resource "docker_registry_image" "foo" {
|
resource "docker_image" "foo" {
|
||||||
name = "localhost:15000/foo:1.0"
|
name = "localhost:15000/foo:1.0"
|
||||||
insecure_skip_verify = true
|
|
||||||
build {
|
build {
|
||||||
suppress_output = true
|
suppress_output = true
|
||||||
remote_context = "fooRemoteContext"
|
remote_context = "fooRemoteContext"
|
||||||
14
testdata/resources/docker_image/testBuildDockerImageNoKeepConfig.tf
vendored
Normal file
14
testdata/resources/docker_image/testBuildDockerImageNoKeepConfig.tf
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
provider "docker" {
|
||||||
|
alias = "private"
|
||||||
|
}
|
||||||
|
resource "docker_image" "foo" {
|
||||||
|
provider = "docker.private"
|
||||||
|
name = "%s"
|
||||||
|
|
||||||
|
build {
|
||||||
|
context = "%s"
|
||||||
|
remove = true
|
||||||
|
force_remove = true
|
||||||
|
no_cache = true
|
||||||
|
}
|
||||||
|
}
|
||||||
14
testdata/resources/docker_image/testBuildDockerImageNoKeepJustCache.tf
vendored
Normal file
14
testdata/resources/docker_image/testBuildDockerImageNoKeepJustCache.tf
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
provider "docker" {
|
||||||
|
alias = "private"
|
||||||
|
}
|
||||||
|
resource "docker_image" "%s" {
|
||||||
|
provider = "docker.private"
|
||||||
|
name = "%s"
|
||||||
|
|
||||||
|
build {
|
||||||
|
context = "%s"
|
||||||
|
remove = false
|
||||||
|
force_remove = false
|
||||||
|
no_cache = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,14 +1,10 @@
|
||||||
provider "docker" {
|
provider "docker" {
|
||||||
alias = "private"
|
alias = "private"
|
||||||
registry_auth {
|
|
||||||
address = "%s"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "docker_registry_image" "file_permissions" {
|
resource "docker_image" "file_permissions" {
|
||||||
provider = "docker.private"
|
provider = "docker.private"
|
||||||
name = "%s"
|
name = "%s"
|
||||||
insecure_skip_verify = true
|
|
||||||
|
|
||||||
build {
|
build {
|
||||||
context = "%s"
|
context = "%s"
|
||||||
|
|
@ -4,16 +4,18 @@ provider "docker" {
|
||||||
address = "%s"
|
address = "%s"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resource "docker_registry_image" "foo" {
|
|
||||||
provider = "docker.private"
|
|
||||||
name = "%s"
|
|
||||||
insecure_skip_verify = true
|
|
||||||
keep_remotely = true
|
|
||||||
|
|
||||||
|
resource "docker_image" "foo_image" {
|
||||||
|
provider = "docker.private"
|
||||||
|
name = "%s"
|
||||||
build {
|
build {
|
||||||
context = "%s"
|
context = "%s"
|
||||||
remove = true
|
|
||||||
force_remove = true
|
|
||||||
no_cache = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resource "docker_registry_image" "foo" {
|
||||||
|
provider = "docker.private"
|
||||||
|
name = docker_image.foo_image.name
|
||||||
|
insecure_skip_verify = true
|
||||||
|
keep_remotely = true
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,17 @@ provider "docker" {
|
||||||
address = "%s"
|
address = "%s"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resource "docker_registry_image" "foo" {
|
|
||||||
provider = "docker.private"
|
|
||||||
name = "%s"
|
|
||||||
insecure_skip_verify = true
|
|
||||||
|
|
||||||
|
resource "docker_image" "foo_image" {
|
||||||
|
provider = "docker.private"
|
||||||
|
name = "%s"
|
||||||
build {
|
build {
|
||||||
context = "%s"
|
context = "%s"
|
||||||
remove = true
|
|
||||||
force_remove = true
|
|
||||||
no_cache = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resource "docker_registry_image" "foo" {
|
||||||
|
provider = "docker.private"
|
||||||
|
name = docker_image.foo_image.name
|
||||||
|
insecure_skip_verify = true
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue