provider/docker: Mount named volumes in containers
This adds support for specifying named volumes for mounting in a `docker_container` resource.
This commit is contained in:
parent
52d1e214fb
commit
4b7a98584a
|
@ -137,6 +137,20 @@ func resourceDockerContainer() *schema.Resource {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
ForceNew: true,
|
ForceNew: true,
|
||||||
|
ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
|
||||||
|
value := v.(string)
|
||||||
|
if !regexp.MustCompile(`^/`).MatchString(value) {
|
||||||
|
es = append(es, fmt.Errorf(
|
||||||
|
"%q must be an absolute path", k))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"volume_name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
"read_only": &schema.Schema{
|
"read_only": &schema.Schema{
|
||||||
|
@ -383,6 +397,10 @@ func resourceDockerVolumesHash(v interface{}) int {
|
||||||
buf.WriteString(fmt.Sprintf("%v-", v.(string)))
|
buf.WriteString(fmt.Sprintf("%v-", v.(string)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if v, ok := m["volume_name"]; ok {
|
||||||
|
buf.WriteString(fmt.Sprintf("%v-", v.(string)))
|
||||||
|
}
|
||||||
|
|
||||||
if v, ok := m["read_only"]; ok {
|
if v, ok := m["read_only"]; ok {
|
||||||
buf.WriteString(fmt.Sprintf("%v-", v.(bool)))
|
buf.WriteString(fmt.Sprintf("%v-", v.(bool)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -353,7 +353,10 @@ func volumeSetToDockerVolumes(volumes *schema.Set) (map[string]struct{}, []strin
|
||||||
volume := volumeInt.(map[string]interface{})
|
volume := volumeInt.(map[string]interface{})
|
||||||
fromContainer := volume["from_container"].(string)
|
fromContainer := volume["from_container"].(string)
|
||||||
containerPath := volume["container_path"].(string)
|
containerPath := volume["container_path"].(string)
|
||||||
hostPath := volume["host_path"].(string)
|
volumeName := volume["volume_name"].(string)
|
||||||
|
if len(volumeName) == 0 {
|
||||||
|
volumeName = volume["host_path"].(string)
|
||||||
|
}
|
||||||
readOnly := volume["read_only"].(bool)
|
readOnly := volume["read_only"].(bool)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
@ -363,13 +366,13 @@ func volumeSetToDockerVolumes(volumes *schema.Set) (map[string]struct{}, []strin
|
||||||
return retVolumeMap, retHostConfigBinds, retVolumeFromContainers, errors.New("Both a container and a path specified in a volume entry")
|
return retVolumeMap, retHostConfigBinds, retVolumeFromContainers, errors.New("Both a container and a path specified in a volume entry")
|
||||||
case len(fromContainer) != 0:
|
case len(fromContainer) != 0:
|
||||||
retVolumeFromContainers = append(retVolumeFromContainers, fromContainer)
|
retVolumeFromContainers = append(retVolumeFromContainers, fromContainer)
|
||||||
case len(hostPath) != 0:
|
case len(volumeName) != 0:
|
||||||
readWrite := "rw"
|
readWrite := "rw"
|
||||||
if readOnly {
|
if readOnly {
|
||||||
readWrite = "ro"
|
readWrite = "ro"
|
||||||
}
|
}
|
||||||
retVolumeMap[containerPath] = struct{}{}
|
retVolumeMap[containerPath] = struct{}{}
|
||||||
retHostConfigBinds = append(retHostConfigBinds, hostPath+":"+containerPath+":"+readWrite)
|
retHostConfigBinds = append(retHostConfigBinds, volumeName+":"+containerPath+":"+readWrite)
|
||||||
default:
|
default:
|
||||||
retVolumeMap[containerPath] = struct{}{}
|
retVolumeMap[containerPath] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,48 @@ func TestAccDockerContainer_basic(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAccDockerContainer_volume(t *testing.T) {
|
||||||
|
var c dc.Container
|
||||||
|
|
||||||
|
testCheck := func(*terraform.State) error {
|
||||||
|
if len(c.Mounts) != 2 {
|
||||||
|
return fmt.Errorf("Incorrect number of mounts: expected 2, got %d", len(c.Mounts))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range c.Mounts {
|
||||||
|
if v.Name != "testAccDockerContainerVolume_volume" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Destination != "/tmp/volume" {
|
||||||
|
return fmt.Errorf("Bad destination on mount: expected /tmp/volume, got %q", v.Destination)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Mode != "rw" {
|
||||||
|
return fmt.Errorf("Bad mode on mount: expected rw, got %q", v.Mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("Mount for testAccDockerContainerVolume_volume not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccDockerContainerVolumeConfig,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccContainerRunning("docker_container.foo", &c),
|
||||||
|
testCheck,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestAccDockerContainer_customized(t *testing.T) {
|
func TestAccDockerContainer_customized(t *testing.T) {
|
||||||
var c dc.Container
|
var c dc.Container
|
||||||
|
|
||||||
|
@ -145,6 +187,27 @@ resource "docker_container" "foo" {
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const testAccDockerContainerVolumeConfig = `
|
||||||
|
resource "docker_image" "foo" {
|
||||||
|
name = "nginx:latest"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "docker_volume" "foo" {
|
||||||
|
name = "testAccDockerContainerVolume_volume"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "docker_container" "foo" {
|
||||||
|
name = "tf-test"
|
||||||
|
image = "${docker_image.foo.latest}"
|
||||||
|
|
||||||
|
volumes {
|
||||||
|
volume_name = "${docker_volume.foo.name}"
|
||||||
|
container_path = "/tmp/volume"
|
||||||
|
read_only = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
const testAccDockerContainerCustomizedConfig = `
|
const testAccDockerContainerCustomizedConfig = `
|
||||||
resource "docker_image" "foo" {
|
resource "docker_image" "foo" {
|
||||||
name = "nginx:latest"
|
name = "nginx:latest"
|
||||||
|
|
|
@ -107,13 +107,17 @@ the following:
|
||||||
|
|
||||||
* `from_container` - (Optional, string) The container where the volume is
|
* `from_container` - (Optional, string) The container where the volume is
|
||||||
coming from.
|
coming from.
|
||||||
* `container_path` - (Optional, string) The path in the container where the
|
|
||||||
volume will be mounted.
|
|
||||||
* `host_path` - (Optional, string) The path on the host where the volume
|
* `host_path` - (Optional, string) The path on the host where the volume
|
||||||
is coming from.
|
is coming from.
|
||||||
|
* `volume_name` - (Optional, string) The name of the docker volume which
|
||||||
|
should be mounted.
|
||||||
|
* `container_path` - (Optional, string) The path in the container where the
|
||||||
|
volume will be mounted.
|
||||||
* `read_only` - (Optional, bool) If true, this volume will be readonly.
|
* `read_only` - (Optional, bool) If true, this volume will be readonly.
|
||||||
Defaults to false.
|
Defaults to false.
|
||||||
|
|
||||||
|
One of `from_container`, `host_path` or `volume_name` must be set.
|
||||||
|
|
||||||
## Attributes Reference
|
## Attributes Reference
|
||||||
|
|
||||||
The following attributes are exported:
|
The following attributes are exported:
|
||||||
|
|
Loading…
Reference in New Issue