Skip to content

Commit 4b7a985

Browse files
committed
provider/docker: Mount named volumes in containers
This adds support for specifying named volumes for mounting in a `docker_container` resource.
1 parent 52d1e21 commit 4b7a985

4 files changed

Lines changed: 93 additions & 5 deletions

File tree

‎builtin/providers/docker/resource_docker_container.go‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,20 @@ func resourceDockerContainer() *schema.Resource {
137137
Type: schema.TypeString,
138138
Optional: true,
139139
ForceNew: true,
140+
ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
141+
value := v.(string)
142+
if !regexp.MustCompile(`^/`).MatchString(value) {
143+
es = append(es, fmt.Errorf(
144+
"%q must be an absolute path", k))
145+
}
146+
return
147+
},
148+
},
149+
150+
"volume_name": &schema.Schema{
151+
Type: schema.TypeString,
152+
Optional: true,
153+
ForceNew: true,
140154
},
141155

142156
"read_only": &schema.Schema{
@@ -383,6 +397,10 @@ func resourceDockerVolumesHash(v interface{}) int {
383397
buf.WriteString(fmt.Sprintf("%v-", v.(string)))
384398
}
385399

400+
if v, ok := m["volume_name"]; ok {
401+
buf.WriteString(fmt.Sprintf("%v-", v.(string)))
402+
}
403+
386404
if v, ok := m["read_only"]; ok {
387405
buf.WriteString(fmt.Sprintf("%v-", v.(bool)))
388406
}

‎builtin/providers/docker/resource_docker_container_funcs.go‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,10 @@ func volumeSetToDockerVolumes(volumes *schema.Set) (map[string]struct{}, []strin
353353
volume := volumeInt.(map[string]interface{})
354354
fromContainer := volume["from_container"].(string)
355355
containerPath := volume["container_path"].(string)
356-
hostPath := volume["host_path"].(string)
356+
volumeName := volume["volume_name"].(string)
357+
if len(volumeName) == 0 {
358+
volumeName = volume["host_path"].(string)
359+
}
357360
readOnly := volume["read_only"].(bool)
358361

359362
switch {
@@ -363,13 +366,13 @@ func volumeSetToDockerVolumes(volumes *schema.Set) (map[string]struct{}, []strin
363366
return retVolumeMap, retHostConfigBinds, retVolumeFromContainers, errors.New("Both a container and a path specified in a volume entry")
364367
case len(fromContainer) != 0:
365368
retVolumeFromContainers = append(retVolumeFromContainers, fromContainer)
366-
case len(hostPath) != 0:
369+
case len(volumeName) != 0:
367370
readWrite := "rw"
368371
if readOnly {
369372
readWrite = "ro"
370373
}
371374
retVolumeMap[containerPath] = struct{}{}
372-
retHostConfigBinds = append(retHostConfigBinds, hostPath+":"+containerPath+":"+readWrite)
375+
retHostConfigBinds = append(retHostConfigBinds, volumeName+":"+containerPath+":"+readWrite)
373376
default:
374377
retVolumeMap[containerPath] = struct{}{}
375378
}

‎builtin/providers/docker/resource_docker_container_test.go‎

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,48 @@ func TestAccDockerContainer_basic(t *testing.T) {
2525
})
2626
}
2727

28+
func TestAccDockerContainer_volume(t *testing.T) {
29+
var c dc.Container
30+
31+
testCheck := func(*terraform.State) error {
32+
if len(c.Mounts) != 2 {
33+
return fmt.Errorf("Incorrect number of mounts: expected 2, got %d", len(c.Mounts))
34+
}
35+
36+
for _, v := range c.Mounts {
37+
if v.Name != "testAccDockerContainerVolume_volume" {
38+
continue
39+
}
40+
41+
if v.Destination != "/tmp/volume" {
42+
return fmt.Errorf("Bad destination on mount: expected /tmp/volume, got %q", v.Destination)
43+
}
44+
45+
if v.Mode != "rw" {
46+
return fmt.Errorf("Bad mode on mount: expected rw, got %q", v.Mode)
47+
}
48+
49+
return nil
50+
}
51+
52+
return fmt.Errorf("Mount for testAccDockerContainerVolume_volume not found")
53+
}
54+
55+
resource.Test(t, resource.TestCase{
56+
PreCheck: func() { testAccPreCheck(t) },
57+
Providers: testAccProviders,
58+
Steps: []resource.TestStep{
59+
resource.TestStep{
60+
Config: testAccDockerContainerVolumeConfig,
61+
Check: resource.ComposeTestCheckFunc(
62+
testAccContainerRunning("docker_container.foo", &c),
63+
testCheck,
64+
),
65+
},
66+
},
67+
})
68+
}
69+
2870
func TestAccDockerContainer_customized(t *testing.T) {
2971
var c dc.Container
3072

@@ -145,6 +187,27 @@ resource "docker_container" "foo" {
145187
}
146188
`
147189

190+
const testAccDockerContainerVolumeConfig = `
191+
resource "docker_image" "foo" {
192+
name = "nginx:latest"
193+
}
194+
195+
resource "docker_volume" "foo" {
196+
name = "testAccDockerContainerVolume_volume"
197+
}
198+
199+
resource "docker_container" "foo" {
200+
name = "tf-test"
201+
image = "${docker_image.foo.latest}"
202+
203+
volumes {
204+
volume_name = "${docker_volume.foo.name}"
205+
container_path = "/tmp/volume"
206+
read_only = false
207+
}
208+
}
209+
`
210+
148211
const testAccDockerContainerCustomizedConfig = `
149212
resource "docker_image" "foo" {
150213
name = "nginx:latest"

‎website/source/docs/providers/docker/r/container.html.markdown‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,16 @@ the following:
107107

108108
* `from_container` - (Optional, string) The container where the volume is
109109
coming from.
110-
* `container_path` - (Optional, string) The path in the container where the
111-
volume will be mounted.
112110
* `host_path` - (Optional, string) The path on the host where the volume
113111
is coming from.
112+
* `volume_name` - (Optional, string) The name of the docker volume which
113+
should be mounted.
114+
* `container_path` - (Optional, string) The path in the container where the
115+
volume will be mounted.
114116
* `read_only` - (Optional, bool) If true, this volume will be readonly.
115117
Defaults to false.
118+
119+
One of `from_container`, `host_path` or `volume_name` must be set.
116120

117121
## Attributes Reference
118122

0 commit comments

Comments
 (0)