mirror of
https://github.com/kreuzwerker/terraform-provider-docker.git
synced 2025-12-18 23:06:10 -05:00
1077 lines
36 KiB
Go
1077 lines
36 KiB
Go
package provider
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
|
|
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
|
)
|
|
|
|
func resourceDockerContainer() *schema.Resource {
|
|
return &schema.Resource{
|
|
Description: "Manages the lifecycle of a Docker container.",
|
|
|
|
CreateContext: resourceDockerContainerCreate,
|
|
ReadContext: resourceDockerContainerRead,
|
|
UpdateContext: resourceDockerContainerUpdate,
|
|
DeleteContext: resourceDockerContainerDelete,
|
|
MigrateState: resourceDockerContainerMigrateState,
|
|
SchemaVersion: 2,
|
|
Importer: &schema.ResourceImporter{
|
|
StateContext: schema.ImportStatePassthroughContext,
|
|
},
|
|
StateUpgraders: []schema.StateUpgrader{
|
|
{
|
|
Version: 1,
|
|
Type: resourceDockerContainerV1().CoreConfigSchema().ImpliedType(),
|
|
Upgrade: func(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) {
|
|
// TODO do the ohter V0-to-V1 migration, unless we're okay
|
|
// with breaking for users who straggled on their docker
|
|
// provider version
|
|
|
|
return migrateContainerLabels(rawState), nil
|
|
},
|
|
},
|
|
},
|
|
|
|
Schema: map[string]*schema.Schema{
|
|
"name": {
|
|
Type: schema.TypeString,
|
|
Description: "The name of the container.",
|
|
Required: true,
|
|
ForceNew: true,
|
|
},
|
|
|
|
"rm": {
|
|
Type: schema.TypeBool,
|
|
Description: "If `true`, then the container will be automatically removed when it exits. Defaults to `false`.",
|
|
Default: false,
|
|
Optional: true,
|
|
},
|
|
|
|
"read_only": {
|
|
Type: schema.TypeBool,
|
|
Description: "If `true`, the container will be started as readonly. Defaults to `false`.",
|
|
Default: false,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
|
|
"start": {
|
|
Type: schema.TypeBool,
|
|
Description: "If `true`, then the Docker container will be started after creation. If `false`, then the container is only created. Defaults to `true`.",
|
|
Default: true,
|
|
Optional: true,
|
|
},
|
|
|
|
"wait": {
|
|
Type: schema.TypeBool,
|
|
Description: "If `true`, then the Docker container is waited for being healthy state after creation. This requires your container to have a healthcheck, otherwise this provider will error. If `false`, then the container health state is not checked. Defaults to `false`.",
|
|
Default: false,
|
|
Optional: true,
|
|
},
|
|
|
|
"wait_timeout": {
|
|
Type: schema.TypeInt,
|
|
Description: "The timeout in seconds to wait the container to be healthy after creation. Defaults to `60`.",
|
|
Default: 60,
|
|
Optional: true,
|
|
},
|
|
|
|
"attach": {
|
|
Type: schema.TypeBool,
|
|
Description: "If `true` attach to the container after its creation and waits the end of its execution. Defaults to `false`.",
|
|
Default: false,
|
|
Optional: true,
|
|
},
|
|
|
|
"logs": {
|
|
Type: schema.TypeBool,
|
|
Description: "Save the container logs (`attach` must be enabled). Defaults to `false`.",
|
|
Default: false,
|
|
Optional: true,
|
|
},
|
|
|
|
// Indicates whether the container must be running.
|
|
//
|
|
// An assumption is made that configured containers
|
|
// should be running; if not, they should not be in
|
|
// the configuration. Therefore a stopped container
|
|
// should be started. Set to false to have the
|
|
// provider leave the container alone.
|
|
//
|
|
// Actively-debugged containers are likely to be
|
|
// stopped and started manually, and Docker has
|
|
// some provisions for restarting containers that
|
|
// stop. The utility here comes from the fact that
|
|
// this will delete and re-create the container
|
|
// following the principle that the containers
|
|
// should be pristine when started.
|
|
"must_run": {
|
|
Type: schema.TypeBool,
|
|
Description: "If `true`, then the Docker container will be kept running. If `false`, then as long as the container exists, Terraform assumes it is successful. Defaults to `true`.",
|
|
Default: true,
|
|
Optional: true,
|
|
},
|
|
|
|
"exit_code": {
|
|
Type: schema.TypeInt,
|
|
Description: "The exit code of the container if its execution is done (`must_run` must be disabled).",
|
|
Computed: true,
|
|
},
|
|
|
|
"container_logs": {
|
|
Type: schema.TypeString,
|
|
Description: "The logs of the container if its execution is done (`attach` must be disabled).",
|
|
Computed: true,
|
|
},
|
|
|
|
"image": {
|
|
Type: schema.TypeString,
|
|
Description: "The ID of the image to back this container. The easiest way to get this value is to use the `image_id` attribute of the `docker_image` resource as is shown in the example.",
|
|
Required: true,
|
|
ForceNew: true,
|
|
},
|
|
|
|
"hostname": {
|
|
Type: schema.TypeString,
|
|
Description: "Hostname of the container.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Computed: true,
|
|
},
|
|
|
|
"domainname": {
|
|
Type: schema.TypeString,
|
|
Description: "Domain name of the container.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
|
|
"command": {
|
|
Type: schema.TypeList,
|
|
Description: "The command to use to start the container. For example, to run `/usr/bin/myprogram -f baz.conf` set the command to be `[\"/usr/bin/myprogram\",\"-f\",\"baz.conf\"]`.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Computed: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
},
|
|
|
|
"entrypoint": {
|
|
Type: schema.TypeList,
|
|
Description: "The command to use as the Entrypoint for the container. The Entrypoint allows you to configure a container to run as an executable. For example, to run `/usr/bin/myprogram` when starting a container, set the entrypoint to be `\"/usr/bin/myprogram\"]`.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Computed: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
},
|
|
|
|
"user": {
|
|
Type: schema.TypeString,
|
|
Description: "User used for run the first process. Format is `user` or `user:group` which user and group can be passed literraly or by name.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
DiffSuppressFunc: func(k, oldV, newV string, d *schema.ResourceData) bool {
|
|
// treat "" as a no-op, which is Docker's default value
|
|
if newV == "" {
|
|
newV = oldV
|
|
}
|
|
return oldV == newV
|
|
},
|
|
},
|
|
|
|
"dns": {
|
|
Type: schema.TypeSet,
|
|
Description: "DNS servers to use.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
Set: schema.HashString,
|
|
},
|
|
|
|
"dns_opts": {
|
|
Type: schema.TypeSet,
|
|
Description: "DNS options used by the DNS provider(s), see `resolv.conf` documentation for valid list of options.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
Set: schema.HashString,
|
|
},
|
|
|
|
"dns_search": {
|
|
Type: schema.TypeSet,
|
|
Description: "DNS search domains that are used when bare unqualified hostnames are used inside of the container.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
Set: schema.HashString,
|
|
},
|
|
|
|
"publish_all_ports": {
|
|
Type: schema.TypeBool,
|
|
Description: "Publish all ports of the container.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
|
|
"restart": {
|
|
Type: schema.TypeString,
|
|
Description: "The restart policy for the container. Must be one of 'no', 'on-failure', 'always', 'unless-stopped'. Defaults to `no`.",
|
|
Default: "no",
|
|
Optional: true,
|
|
ValidateDiagFunc: validateStringMatchesPattern(`^(no|on-failure|always|unless-stopped)$`),
|
|
},
|
|
|
|
"max_retry_count": {
|
|
Type: schema.TypeInt,
|
|
Description: "The maximum amount of times to an attempt a restart when `restart` is set to 'on-failure'.",
|
|
Optional: true,
|
|
},
|
|
"working_dir": {
|
|
Type: schema.TypeString,
|
|
Description: "The working directory for commands to run in.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
DiffSuppressFunc: func(k, oldV, newV string, d *schema.ResourceData) bool {
|
|
// treat "" as a no-op, which is Docker's default behavior
|
|
if newV == "" {
|
|
newV = oldV
|
|
}
|
|
return oldV == newV
|
|
},
|
|
},
|
|
"remove_volumes": {
|
|
Type: schema.TypeBool,
|
|
Description: "If `true`, it will remove anonymous volumes associated with the container. Defaults to `true`.",
|
|
Default: true,
|
|
Optional: true,
|
|
},
|
|
"capabilities": {
|
|
Type: schema.TypeSet,
|
|
Description: "Add or drop certrain linux capabilities.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
MaxItems: 1,
|
|
// TODO implement DiffSuppressFunc
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"add": {
|
|
Type: schema.TypeSet,
|
|
Description: "List of linux capabilities to add.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
Set: schema.HashString,
|
|
},
|
|
|
|
"drop": {
|
|
Type: schema.TypeSet,
|
|
Description: "List of linux capabilities to drop.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
Set: schema.HashString,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"security_opts": {
|
|
Type: schema.TypeSet,
|
|
Description: "List of string values to customize labels for MLS systems, such as SELinux. See https://docs.docker.com/engine/reference/run/#security-configuration.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Computed: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
Set: schema.HashString,
|
|
},
|
|
"runtime": {
|
|
Type: schema.TypeString,
|
|
Description: "Runtime to use for the container.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Computed: true,
|
|
},
|
|
"stop_signal": {
|
|
Type: schema.TypeString,
|
|
Description: "Signal to stop a container (default `SIGTERM`).",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Computed: true,
|
|
},
|
|
"stop_timeout": {
|
|
Type: schema.TypeInt,
|
|
Description: "Timeout (in seconds) to stop a container.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Computed: true,
|
|
},
|
|
"mounts": {
|
|
Type: schema.TypeSet,
|
|
Description: "Specification for mounts to be added to containers created as part of the service.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"target": {
|
|
Type: schema.TypeString,
|
|
Description: "Container path",
|
|
Required: true,
|
|
},
|
|
"source": {
|
|
Type: schema.TypeString,
|
|
Description: "Mount source (e.g. a volume name, a host path).",
|
|
Optional: true,
|
|
},
|
|
"type": {
|
|
Type: schema.TypeString,
|
|
Description: "The mount type",
|
|
Required: true,
|
|
ValidateDiagFunc: validateStringMatchesPattern(`^(bind|volume|tmpfs)$`),
|
|
},
|
|
"read_only": {
|
|
Type: schema.TypeBool,
|
|
Description: "Whether the mount should be read-only.",
|
|
Optional: true,
|
|
},
|
|
"bind_options": {
|
|
Type: schema.TypeList,
|
|
Description: "Optional configuration for the bind type.",
|
|
Optional: true,
|
|
MaxItems: 1,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"propagation": {
|
|
Type: schema.TypeString,
|
|
Description: "A propagation mode with the value.",
|
|
Optional: true,
|
|
ValidateDiagFunc: validateStringMatchesPattern(`^(private|rprivate|shared|rshared|slave|rslave)$`),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"volume_options": {
|
|
Type: schema.TypeList,
|
|
Description: "Optional configuration for the volume type.",
|
|
Optional: true,
|
|
MaxItems: 1,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"no_copy": {
|
|
Type: schema.TypeBool,
|
|
Description: "Populate volume with data from the target.",
|
|
Optional: true,
|
|
},
|
|
"labels": {
|
|
Type: schema.TypeSet,
|
|
Description: "User-defined key/value metadata.",
|
|
Optional: true,
|
|
Elem: labelSchema,
|
|
},
|
|
"driver_name": {
|
|
Type: schema.TypeString,
|
|
Description: "Name of the driver to use to create the volume.",
|
|
Optional: true,
|
|
},
|
|
"driver_options": {
|
|
Type: schema.TypeMap,
|
|
Description: "key/value map of driver specific options.",
|
|
Optional: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
},
|
|
"subpath": {
|
|
Type: schema.TypeString,
|
|
Description: "Path within the volume to mount. Requires docker server version 1.45 or higher.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"tmpfs_options": {
|
|
Type: schema.TypeList,
|
|
Description: "Optional configuration for the tmpfs type.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
MaxItems: 1,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"size_bytes": {
|
|
Type: schema.TypeInt,
|
|
Description: "The size for the tmpfs mount in bytes.",
|
|
Optional: true,
|
|
},
|
|
"mode": {
|
|
Type: schema.TypeInt,
|
|
Description: "The permission mode for the tmpfs mount in an integer.",
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"volumes": {
|
|
Type: schema.TypeSet,
|
|
Description: "Spec for mounting volumes in the container.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"from_container": {
|
|
Type: schema.TypeString,
|
|
Description: "The container where the volume is coming from.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"container_path": {
|
|
Type: schema.TypeString,
|
|
Description: "The path in the container where the volume will be mounted.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"host_path": {
|
|
Type: schema.TypeString,
|
|
Description: "The path on the host where the volume is coming from.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
ValidateDiagFunc: validateDockerContainerPath(),
|
|
},
|
|
"volume_name": {
|
|
Type: schema.TypeString,
|
|
Description: "The name of the docker volume which should be mounted.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"read_only": {
|
|
Type: schema.TypeBool,
|
|
Description: "If `true`, this volume will be readonly. Defaults to `false`.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"tmpfs": {
|
|
Type: schema.TypeMap,
|
|
Description: "A map of container directories which should be replaced by `tmpfs mounts`, and their corresponding mount options.",
|
|
Optional: true,
|
|
},
|
|
"ports": {
|
|
Type: schema.TypeList,
|
|
Description: "Publish a container's port(s) to the host.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"internal": {
|
|
Type: schema.TypeInt,
|
|
Description: "Port within the container.",
|
|
Required: true,
|
|
ForceNew: true,
|
|
},
|
|
|
|
"external": {
|
|
Type: schema.TypeInt,
|
|
Description: "Port exposed out of the container. If not given a free random port `>= 32768` will be used.",
|
|
Optional: true,
|
|
Computed: true,
|
|
ForceNew: true,
|
|
},
|
|
|
|
"ip": {
|
|
Type: schema.TypeString,
|
|
Description: "IP address/mask that can access this port. Defaults to `0.0.0.0`.",
|
|
Default: "0.0.0.0",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
StateFunc: func(val interface{}) string {
|
|
// Empty IP assignments default to 0.0.0.0
|
|
if val.(string) == "" {
|
|
return "0.0.0.0"
|
|
}
|
|
|
|
return val.(string)
|
|
},
|
|
},
|
|
|
|
"protocol": {
|
|
Type: schema.TypeString,
|
|
Description: "Protocol that can be used over this port. Defaults to `tcp`.",
|
|
Default: "tcp",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
},
|
|
},
|
|
DiffSuppressFunc: suppressIfPortsDidNotChangeForMigrationV0ToV1(),
|
|
},
|
|
|
|
"host": {
|
|
Type: schema.TypeSet,
|
|
Description: "Additional hosts to add to the container.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"ip": {
|
|
Type: schema.TypeString,
|
|
Description: "IP address this hostname should resolve to.",
|
|
Required: true,
|
|
ForceNew: true,
|
|
},
|
|
|
|
"host": {
|
|
Type: schema.TypeString,
|
|
Description: "Hostname to add",
|
|
Required: true,
|
|
ForceNew: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"ulimit": {
|
|
Type: schema.TypeSet,
|
|
Description: "Ulimit options to add.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"name": {
|
|
Type: schema.TypeString,
|
|
Description: "The name of the ulimit",
|
|
Required: true,
|
|
ForceNew: true,
|
|
},
|
|
"soft": {
|
|
Type: schema.TypeInt,
|
|
Description: "The soft limit",
|
|
Required: true,
|
|
ForceNew: true,
|
|
},
|
|
"hard": {
|
|
Type: schema.TypeInt,
|
|
Description: "The hard limit",
|
|
Required: true,
|
|
ForceNew: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"env": {
|
|
Type: schema.TypeSet,
|
|
Description: "Environment variables to set in the form of `KEY=VALUE`, e.g. `DEBUG=0`",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Computed: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
Set: schema.HashString,
|
|
},
|
|
|
|
"bridge": {
|
|
Type: schema.TypeString,
|
|
Description: "The network bridge of the container as read from its NetworkSettings.",
|
|
Computed: true,
|
|
},
|
|
|
|
"network_data": {
|
|
Type: schema.TypeList,
|
|
Description: "The data of the networks the container is connected to.",
|
|
Computed: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"network_name": {
|
|
Type: schema.TypeString,
|
|
Description: "The name of the network",
|
|
Computed: true,
|
|
},
|
|
"ip_address": {
|
|
Type: schema.TypeString,
|
|
Description: "The IP address of the container.",
|
|
Computed: true,
|
|
},
|
|
"ip_prefix_length": {
|
|
Type: schema.TypeInt,
|
|
Description: "The IP prefix length of the container.",
|
|
Computed: true,
|
|
},
|
|
"gateway": {
|
|
Type: schema.TypeString,
|
|
Description: "The network gateway of the container.",
|
|
Computed: true,
|
|
},
|
|
"global_ipv6_address": {
|
|
Type: schema.TypeString,
|
|
Description: "The IPV6 address of the container.",
|
|
Computed: true,
|
|
},
|
|
"global_ipv6_prefix_length": {
|
|
Type: schema.TypeInt,
|
|
Description: "The IPV6 prefix length address of the container.",
|
|
Computed: true,
|
|
},
|
|
"ipv6_gateway": {
|
|
Type: schema.TypeString,
|
|
Description: "The IPV6 gateway of the container.",
|
|
Computed: true,
|
|
},
|
|
"mac_address": {
|
|
Type: schema.TypeString,
|
|
Description: "The MAC address of the container.",
|
|
Computed: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"privileged": {
|
|
Type: schema.TypeBool,
|
|
Description: "If `true`, the container runs in privileged mode.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
|
|
"devices": {
|
|
Type: schema.TypeSet,
|
|
Description: "Bind devices to the container.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"host_path": {
|
|
Type: schema.TypeString,
|
|
Description: "The path on the host where the device is located.",
|
|
Required: true,
|
|
ForceNew: true,
|
|
},
|
|
"container_path": {
|
|
Type: schema.TypeString,
|
|
Description: "The path in the container where the device will be bound.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"permissions": {
|
|
Type: schema.TypeString,
|
|
Description: "The cgroup permissions given to the container to access the device. Defaults to `rwm`.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"destroy_grace_seconds": {
|
|
Type: schema.TypeInt,
|
|
Description: "If defined will attempt to stop the container before destroying. Container will be destroyed after `n` seconds or on successful stop.",
|
|
Optional: true,
|
|
},
|
|
|
|
"labels": {
|
|
Type: schema.TypeSet,
|
|
Description: "User-defined key/value metadata",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Computed: true,
|
|
Elem: labelSchema,
|
|
},
|
|
|
|
"memory": {
|
|
Type: schema.TypeInt,
|
|
Description: "The memory limit for the container in MBs.",
|
|
Optional: true,
|
|
ValidateDiagFunc: validateIntegerGeqThan(0),
|
|
},
|
|
"memory_reservation": {
|
|
Type: schema.TypeInt,
|
|
Description: "The memory-resveration for the container in MBs. Defaults to 0. Allows you to specify a soft limit smaller than `memory` which is activated when Docker detects contention or low memory on the host machine. If you use `memory-reservation`, it must be set lower than `memory` for it to take precedence. Because it is a soft limit, it doesn't guarantee that the container doesn't exceed the limit.",
|
|
Optional: true,
|
|
ValidateDiagFunc: validateIntegerGeqThan(0),
|
|
Default: 0,
|
|
},
|
|
|
|
"memory_swap": {
|
|
Type: schema.TypeInt,
|
|
Description: "The total memory limit (memory + swap) for the container in MBs. This setting may compute to `-1` after `terraform apply` if the target host doesn't support memory swap, when that is the case docker will use a soft limitation.",
|
|
Optional: true,
|
|
ValidateDiagFunc: validateIntegerGeqThan(-1),
|
|
},
|
|
|
|
"shm_size": {
|
|
Type: schema.TypeInt,
|
|
Description: "Size of `/dev/shm` in MBs.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Computed: true,
|
|
ValidateDiagFunc: validateIntegerGeqThan(0),
|
|
},
|
|
|
|
"cpu_shares": {
|
|
Type: schema.TypeInt,
|
|
Description: "CPU shares (relative weight) for the container.",
|
|
Optional: true,
|
|
ValidateDiagFunc: validateIntegerGeqThan(0),
|
|
},
|
|
|
|
"cpu_set": {
|
|
Type: schema.TypeString,
|
|
Description: "A comma-separated list or hyphen-separated range of CPUs a container can use, e.g. `0-1`.",
|
|
Optional: true,
|
|
ValidateDiagFunc: validateStringMatchesPattern(`^\d+([,-]\d+)*$`),
|
|
},
|
|
|
|
"log_driver": {
|
|
Type: schema.TypeString,
|
|
Description: "The logging driver to use for the container.",
|
|
Computed: true,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
|
|
"log_opts": {
|
|
Type: schema.TypeMap,
|
|
Description: "Key/value pairs to use as options for the logging driver.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
|
|
"network_mode": {
|
|
Type: schema.TypeString,
|
|
Description: "Network mode of the container. Defaults to `bridge`. If your host OS is any other OS, you need to set this value explicitly, e.g. `nat` when your container will be running on an Windows host. See https://docs.docker.com/engine/network/ for more information.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Default: "bridge",
|
|
},
|
|
|
|
"networks_advanced": {
|
|
Type: schema.TypeSet,
|
|
Description: "The networks the container is attached to",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"name": {
|
|
Type: schema.TypeString,
|
|
Description: "The name or id of the network to use. You can use `name` or `id` attribute from a `docker_network` resource.",
|
|
Required: true,
|
|
ForceNew: true,
|
|
},
|
|
"aliases": {
|
|
Type: schema.TypeSet,
|
|
Description: "The network aliases of the container in the specific network.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
Set: schema.HashString,
|
|
},
|
|
"ipv4_address": {
|
|
Type: schema.TypeString,
|
|
Description: "The IPV4 address of the container in the specific network.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"ipv6_address": {
|
|
Type: schema.TypeString,
|
|
Description: "The IPV6 address of the container in the specific network.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"mac_address": {
|
|
Type: schema.TypeString,
|
|
Description: "The MAC address of the container in the specific network.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"pid_mode": {
|
|
Type: schema.TypeString,
|
|
Description: "he PID (Process) Namespace mode for the container. Either `container:<name|id>` or `host`.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"userns_mode": {
|
|
Type: schema.TypeString,
|
|
Description: "Sets the usernamespace mode for the container when usernamespace remapping option is enabled.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
|
|
"upload": {
|
|
Type: schema.TypeSet,
|
|
Description: "Specifies files to upload to the container before starting it. Only one of `content` or `content_base64` can be set and at least one of them has to be set.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"content": {
|
|
Type: schema.TypeString,
|
|
Description: "Literal string value to use as the object content, which will be uploaded as UTF-8-encoded text. Conflicts with `content_base64` & `source`",
|
|
Optional: true,
|
|
// This is intentional. The container is mutated once, and never updated later.
|
|
// New configuration forces a new deployment, even with the same binaries.
|
|
ForceNew: true,
|
|
},
|
|
"content_base64": {
|
|
Type: schema.TypeString,
|
|
Description: "Base64-encoded data that will be decoded and uploaded as raw bytes for the object content. This allows safely uploading non-UTF8 binary data, but is recommended only for larger binary content such as the result of the `base64encode` interpolation function. See [here](https://github.com/terraform-providers/terraform-provider-docker/issues/48#issuecomment-374174588) for the reason. Conflicts with `content` & `source`",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
ValidateDiagFunc: validateStringIsBase64Encoded(),
|
|
},
|
|
"file": {
|
|
Type: schema.TypeString,
|
|
Description: "Path to the file in the container where is upload goes to",
|
|
Required: true,
|
|
ForceNew: true,
|
|
},
|
|
"executable": {
|
|
Type: schema.TypeBool,
|
|
Description: "If `true`, the file will be uploaded with user executable permission. Defaults to `false`.",
|
|
Default: false,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"permissions": {
|
|
Type: schema.TypeString,
|
|
Description: "The permission mode for the file in the container. Has precedence over `executable`.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
ValidateDiagFunc: validateStringMatchesPattern(`^0[0-7]{3}$`),
|
|
},
|
|
"source": {
|
|
Type: schema.TypeString,
|
|
Description: "A filename that references a file which will be uploaded as the object content. This allows for large file uploads that do not get stored in state. Conflicts with `content` & `content_base64`",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"source_hash": {
|
|
Type: schema.TypeString,
|
|
Description: "If using `source`, this will force an update if the file content has updated but the filename has not. ",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"healthcheck": {
|
|
Type: schema.TypeList,
|
|
Description: "A test to perform to check that the container is healthy",
|
|
MaxItems: 1,
|
|
Optional: true,
|
|
Computed: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"test": {
|
|
Type: schema.TypeList,
|
|
Description: "Command to run to check health. For example, to run `curl -f localhost/health` set the command to be `[\"CMD\", \"curl\", \"-f\", \"localhost/health\"]`.",
|
|
Required: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
},
|
|
"interval": {
|
|
Type: schema.TypeString,
|
|
Description: "Time between running the check (ms|s|m|h). Defaults to `0s`.",
|
|
Default: "0s",
|
|
Optional: true,
|
|
ValidateDiagFunc: validateDurationGeq0(),
|
|
},
|
|
"timeout": {
|
|
Type: schema.TypeString,
|
|
Description: "Maximum time to allow one check to run (ms|s|m|h). Defaults to `0s`.",
|
|
Default: "0s",
|
|
Optional: true,
|
|
ValidateDiagFunc: validateDurationGeq0(),
|
|
},
|
|
"start_period": {
|
|
Type: schema.TypeString,
|
|
Description: "Start period for the container to initialize before counting retries towards unstable (ms|s|m|h). Defaults to `0s`.",
|
|
Default: "0s",
|
|
Optional: true,
|
|
ValidateDiagFunc: validateDurationGeq0(),
|
|
},
|
|
"start_interval": {
|
|
Type: schema.TypeString,
|
|
Description: "Interval before the healthcheck starts (ms|s|m|h). Defaults to `0s`.",
|
|
Default: "0s",
|
|
Optional: true,
|
|
ValidateDiagFunc: validateDurationGeq0(),
|
|
},
|
|
"retries": {
|
|
Type: schema.TypeInt,
|
|
Description: "Consecutive failures needed to report unhealthy. Defaults to `0`.",
|
|
Default: 0,
|
|
Optional: true,
|
|
ValidateDiagFunc: validateIntegerGeqThan(0),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"container_read_refresh_timeout_milliseconds": {
|
|
Type: schema.TypeInt,
|
|
Description: "The total number of milliseconds to wait for the container to reach status 'running'",
|
|
Optional: true,
|
|
Default: containerReadRefreshTimeoutMillisecondsDefault,
|
|
},
|
|
|
|
"sysctls": {
|
|
Type: schema.TypeMap,
|
|
Description: "A map of kernel parameters (sysctls) to set in the container.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"ipc_mode": {
|
|
Type: schema.TypeString,
|
|
Description: "IPC sharing mode for the container. Possible values are: `none`, `private`, `shareable`, `container:<name|id>` or `host`.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Computed: true,
|
|
},
|
|
"group_add": {
|
|
Type: schema.TypeSet,
|
|
Description: "Additional groups for the container user",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
Set: schema.HashString,
|
|
},
|
|
"init": {
|
|
Type: schema.TypeBool,
|
|
Description: "Configured whether an init process should be injected for this container. If unset this will default to the `dockerd` defaults.",
|
|
Optional: true,
|
|
Computed: true,
|
|
},
|
|
"tty": {
|
|
Type: schema.TypeBool,
|
|
Description: "If `true`, allocate a pseudo-tty (`docker run -t`). Defaults to `false`.",
|
|
Default: false,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"stdin_open": {
|
|
Type: schema.TypeBool,
|
|
Description: "If `true`, keep STDIN open even if not attached (`docker run -i`). Defaults to `false`.",
|
|
Default: false,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"storage_opts": {
|
|
Type: schema.TypeMap,
|
|
Description: "Key/value pairs for the storage driver options, e.g. `size`: `120G`",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"gpus": {
|
|
Type: schema.TypeString,
|
|
Description: "GPU devices to add to the container. Currently, only the value `all` is supported. Passing any other value will result in unexpected behavior.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"cpus": {
|
|
Type: schema.TypeString,
|
|
Description: "Specify how much of the available CPU resources a container can use. e.g a value of 1.5 means the container is guaranteed at most one and a half of the CPUs. Has precedence over `cpu_period` and `cpu_quota`.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"cpu_period": {
|
|
Type: schema.TypeInt,
|
|
Description: "Specify the CPU CFS scheduler period (in microseconds), which is used alongside `cpu-quota`. Is ignored if `cpus` is set.",
|
|
Optional: true,
|
|
ValidateDiagFunc: validateIntegerGeqThan(0),
|
|
},
|
|
"cpu_quota": {
|
|
Type: schema.TypeInt,
|
|
Description: "Impose a CPU CFS quota on the container (in microseconds). The number of microseconds per `cpu-period` that the container is limited to before throttled. Is ignored if `cpus` is set.",
|
|
Optional: true,
|
|
ValidateDiagFunc: validateIntegerGeqThan(0),
|
|
},
|
|
"cgroupns_mode": {
|
|
Type: schema.TypeString,
|
|
Description: "Cgroup namespace mode to use for the container. Possible values are: `private`, `host`.",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"cgroup_parent": {
|
|
Type: schema.TypeString,
|
|
Description: "Optional parent cgroup for the container",
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func suppressIfPortsDidNotChangeForMigrationV0ToV1() schema.SchemaDiffSuppressFunc {
|
|
return func(k, old, new string, d *schema.ResourceData) bool {
|
|
if k == "ports.#" && old != new {
|
|
log.Printf("[DEBUG] suppress diff ports: old and new don't have the same length")
|
|
return false
|
|
}
|
|
portsOldRaw, portsNewRaw := d.GetChange("ports")
|
|
portsOld := portsOldRaw.([]interface{})
|
|
portsNew := portsNewRaw.([]interface{})
|
|
if len(portsOld) != len(portsNew) {
|
|
log.Printf("[DEBUG] suppress diff ports: old and new don't have the same length")
|
|
return false
|
|
}
|
|
log.Printf("[DEBUG] suppress diff ports: old and new have same length")
|
|
|
|
for _, portOld := range portsOld {
|
|
portOldMapped := portOld.(map[string]interface{})
|
|
oldInternalPort := portOldMapped["internal"]
|
|
portFound := false
|
|
for _, portNew := range portsNew {
|
|
portNewMapped := portNew.(map[string]interface{})
|
|
newInternalPort := portNewMapped["internal"]
|
|
// port is still there in new
|
|
if newInternalPort == oldInternalPort {
|
|
log.Printf("[DEBUG] suppress diff ports: comparing port '%v'", oldInternalPort)
|
|
if portNewMapped["protocol"] != portOldMapped["protocol"] {
|
|
if containsPortWithProtocol(portsNew, portOldMapped["internal"], portOldMapped["protocol"]) {
|
|
log.Printf("[DEBUG] suppress diff ports: found another port in new list with the same protocol for '%v", oldInternalPort)
|
|
continue
|
|
}
|
|
|
|
log.Printf("[DEBUG] suppress diff ports: 'protocol' changed for '%v'", oldInternalPort)
|
|
return false
|
|
}
|
|
if portNewMapped["external"] != portOldMapped["external"] {
|
|
log.Printf("[DEBUG] suppress diff ports: 'external' changed for '%v'", oldInternalPort)
|
|
return false
|
|
}
|
|
if portNewMapped["ip"] != portOldMapped["ip"] {
|
|
log.Printf("[DEBUG] suppress diff ports: 'ip' changed for '%v'", oldInternalPort)
|
|
return false
|
|
}
|
|
|
|
portFound = true
|
|
break
|
|
}
|
|
}
|
|
// port was deleted or exchanges in new
|
|
if !portFound {
|
|
log.Printf("[DEBUG] suppress diff ports: port was deleted '%v'", oldInternalPort)
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
}
|
|
|
|
func containsPortWithProtocol(ports []interface{}, searchInternalPort, searchProtocol interface{}) bool {
|
|
for _, port := range ports {
|
|
portMapped := port.(map[string]interface{})
|
|
internalPort := portMapped["internal"]
|
|
protocol := portMapped["protocol"]
|
|
if internalPort == searchInternalPort && protocol == searchProtocol {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|