package docker import ( "fmt" "regexp" "github.com/hashicorp/terraform/helper/schema" ) func resourceDockerContainer() *schema.Resource { return &schema.Resource{ Create: resourceDockerContainerCreate, Read: resourceDockerContainerRead, Update: resourceDockerContainerUpdate, Delete: resourceDockerContainerDelete, Schema: map[string]*schema.Schema{ "name": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: 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": &schema.Schema{ Type: schema.TypeBool, Default: true, Optional: true, }, // ForceNew is not true for image because we need to // sane this against Docker image IDs, as each image // can have multiple names/tags attached do it. "image": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: true, }, "hostname": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, "domainname": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, "command": &schema.Schema{ Type: schema.TypeList, Optional: true, ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, }, "entrypoint": &schema.Schema{ Type: schema.TypeList, Optional: true, ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, }, "user": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, }, "dns": &schema.Schema{ Type: schema.TypeSet, Optional: true, ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, Set: schema.HashString, }, "dns_opts": &schema.Schema{ Type: schema.TypeSet, Optional: true, ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, Set: schema.HashString, }, "dns_search": &schema.Schema{ Type: schema.TypeSet, Optional: true, ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, Set: schema.HashString, }, "publish_all_ports": &schema.Schema{ Type: schema.TypeBool, Optional: true, ForceNew: true, }, "restart": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, Default: "no", ValidateFunc: validateStringMatchesPattern(`^(no|on-failure|always|unless-stopped)$`), }, "max_retry_count": &schema.Schema{ Type: schema.TypeInt, Optional: true, ForceNew: true, }, "capabilities": &schema.Schema{ Type: schema.TypeSet, Optional: true, ForceNew: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "add": &schema.Schema{ Type: schema.TypeSet, Optional: true, ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, Set: schema.HashString, }, "drop": &schema.Schema{ Type: schema.TypeSet, Optional: true, ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, Set: schema.HashString, }, }, }, }, "volumes": &schema.Schema{ Type: schema.TypeSet, Optional: true, ForceNew: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "from_container": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, "container_path": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, "host_path": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, ValidateFunc: validateDockerContainerPath, }, "volume_name": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, "read_only": &schema.Schema{ Type: schema.TypeBool, Optional: true, ForceNew: true, }, }, }, }, "ports": &schema.Schema{ Type: schema.TypeSet, Optional: true, ForceNew: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "internal": &schema.Schema{ Type: schema.TypeInt, Required: true, ForceNew: true, }, "external": &schema.Schema{ Type: schema.TypeInt, Optional: true, ForceNew: true, }, "ip": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, "protocol": &schema.Schema{ Type: schema.TypeString, Default: "tcp", Optional: true, ForceNew: true, }, }, }, }, "host": &schema.Schema{ Type: schema.TypeSet, Optional: true, ForceNew: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "ip": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: true, }, "host": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: true, }, }, }, }, "env": &schema.Schema{ Type: schema.TypeSet, Optional: true, ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, Set: schema.HashString, }, "links": &schema.Schema{ Type: schema.TypeSet, Optional: true, ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, Set: schema.HashString, }, "ip_address": &schema.Schema{ Type: schema.TypeString, Computed: true, }, "ip_prefix_length": &schema.Schema{ Type: schema.TypeInt, Computed: true, }, "gateway": &schema.Schema{ Type: schema.TypeString, Computed: true, }, "bridge": &schema.Schema{ Type: schema.TypeString, Computed: true, }, "privileged": &schema.Schema{ Type: schema.TypeBool, Optional: true, ForceNew: true, }, "devices": &schema.Schema{ Type: schema.TypeSet, Optional: true, ForceNew: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "host_path": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: true, }, "container_path": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, "permissions": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, }, }, }, "destroy_grace_seconds": &schema.Schema{ Type: schema.TypeInt, Optional: true, }, "labels": &schema.Schema{ Type: schema.TypeMap, Optional: true, ForceNew: true, }, "memory": &schema.Schema{ Type: schema.TypeInt, Optional: true, ForceNew: true, ValidateFunc: validateIntegerGeqThan(0), }, "memory_swap": &schema.Schema{ Type: schema.TypeInt, Optional: true, ForceNew: true, ValidateFunc: validateIntegerGeqThan(-1), }, "cpu_shares": &schema.Schema{ Type: schema.TypeInt, Optional: true, ForceNew: true, ValidateFunc: validateIntegerGeqThan(0), }, "log_driver": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, Default: "json-file", ValidateFunc: validateStringMatchesPattern(`^(json-file|syslog|journald|gelf|fluentd|awslogs)$`), }, "log_opts": &schema.Schema{ Type: schema.TypeMap, Optional: true, ForceNew: true, }, "network_alias": &schema.Schema{ Type: schema.TypeSet, Optional: true, ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, Set: schema.HashString, }, "network_mode": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, "networks": &schema.Schema{ Type: schema.TypeSet, Optional: true, ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, Set: schema.HashString, }, "upload": &schema.Schema{ Type: schema.TypeSet, Optional: true, ForceNew: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "content": &schema.Schema{ Type: schema.TypeString, Required: 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, }, "file": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: true, }, }, }, }, }, } } func validateDockerContainerPath(v interface{}, k string) (ws []string, errors []error) { value := v.(string) if !regexp.MustCompile(`^[a-zA-Z]:\\|^/`).MatchString(value) { errors = append(errors, fmt.Errorf("%q must be an absolute path", k)) } return }