diff --git a/builtin/providers/docker/provider.go b/builtin/providers/docker/provider.go index 799fd9bdb..b842d6b62 100644 --- a/builtin/providers/docker/provider.go +++ b/builtin/providers/docker/provider.go @@ -29,6 +29,7 @@ func Provider() terraform.ResourceProvider { "docker_container": resourceDockerContainer(), "docker_image": resourceDockerImage(), "docker_network": resourceDockerNetwork(), + "docker_volume": resourceDockerVolume(), }, ConfigureFunc: providerConfigure, diff --git a/builtin/providers/docker/resource_docker_volume.go b/builtin/providers/docker/resource_docker_volume.go new file mode 100644 index 000000000..33c22d581 --- /dev/null +++ b/builtin/providers/docker/resource_docker_volume.go @@ -0,0 +1,102 @@ +package docker + +import ( + "fmt" + + dc "github.com/fsouza/go-dockerclient" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceDockerVolume() *schema.Resource { + return &schema.Resource{ + Create: resourceDockerVolumeCreate, + Read: resourceDockerVolumeRead, + Delete: resourceDockerVolumeDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "driver": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "driver_opts": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + ForceNew: true, + }, + "mountpoint": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceDockerVolumeCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*dc.Client) + + createOpts := dc.CreateVolumeOptions{} + if v, ok := d.GetOk("name"); ok { + createOpts.Name = v.(string) + } + if v, ok := d.GetOk("driver"); ok { + createOpts.Driver = v.(string) + } + if v, ok := d.GetOk("driver_opts"); ok { + createOpts.DriverOpts = mapTypeMapValsToString(v.(map[string]interface{})) + } + + var err error + var retVolume *dc.Volume + if retVolume, err = client.CreateVolume(createOpts); err != nil { + return fmt.Errorf("Unable to create volume: %s", err) + } + if retVolume == nil { + return fmt.Errorf("Returned volume is nil") + } + + d.SetId(retVolume.Name) + d.Set("name", retVolume.Name) + d.Set("driver", retVolume.Driver) + d.Set("mountpoint", retVolume.Mountpoint) + + return nil +} + +func resourceDockerVolumeRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*dc.Client) + + var err error + var retVolume *dc.Volume + if retVolume, err = client.InspectVolume(d.Id()); err != nil && err != dc.ErrNoSuchVolume { + return fmt.Errorf("Unable to inspect volume: %s", err) + } + if retVolume == nil { + d.SetId("") + return nil + } + + d.Set("name", retVolume.Name) + d.Set("driver", retVolume.Driver) + d.Set("mountpoint", retVolume.Mountpoint) + + return nil +} + +func resourceDockerVolumeDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*dc.Client) + + if err := client.RemoveVolume(d.Id()); err != nil && err != dc.ErrNoSuchVolume { + return fmt.Errorf("Error deleting volume %s: %s", d.Id(), err) + } + + d.SetId("") + return nil +} diff --git a/builtin/providers/docker/resource_docker_volume_test.go b/builtin/providers/docker/resource_docker_volume_test.go new file mode 100644 index 000000000..38fec3c4e --- /dev/null +++ b/builtin/providers/docker/resource_docker_volume_test.go @@ -0,0 +1,67 @@ +package docker + +import ( + "fmt" + "testing" + + dc "github.com/fsouza/go-dockerclient" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccDockerVolume_basic(t *testing.T) { + var v dc.Volume + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccDockerVolumeConfig, + Check: resource.ComposeTestCheckFunc( + checkDockerVolume("docker_volume.foo", &v), + resource.TestCheckResourceAttr("docker_volume.foo", "id", "testAccDockerVolume_basic"), + resource.TestCheckResourceAttr("docker_volume.foo", "name", "testAccDockerVolume_basic"), + ), + }, + }, + }) +} + +func checkDockerVolume(n string, volume *dc.Volume) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + client := testAccProvider.Meta().(*dc.Client) + volumes, err := client.ListVolumes(dc.ListVolumesOptions{}) + if err != nil { + return err + } + + for _, v := range volumes { + if v.Name == rs.Primary.ID { + inspected, err := client.InspectVolume(v.Name) + if err != nil { + return fmt.Errorf("Volume could not be inspected: %s", err) + } + *volume = *inspected + return nil + } + } + + return fmt.Errorf("Volume not found: %s", rs.Primary.ID) + } +} + +const testAccDockerVolumeConfig = ` +resource "docker_volume" "foo" { + name = "testAccDockerVolume_basic" +} +` diff --git a/website/source/docs/providers/docker/r/volume.html.markdown b/website/source/docs/providers/docker/r/volume.html.markdown new file mode 100644 index 000000000..5b13efc02 --- /dev/null +++ b/website/source/docs/providers/docker/r/volume.html.markdown @@ -0,0 +1,38 @@ +--- +layout: "docker" +page_title: "Docker: docker_volume" +sidebar_current: "docs-docker-resource-volume" +description: |- + Creates and destroys docker volumes. +--- + +# docker\_volume + +Creates and destroys a volume in Docker. This can be used alongside +[docker\_container](/docs/providers/docker/r/container.html) +to prepare volumes that can be shared across containers. + +## Example Usage + +``` +# Creates a docker volume "shared_volume". +resource "docker_volume" "shared_volume" { + name = "shared_volume" +} + +# Reference the volume with ${docker_volume.shared_volume.name} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Optional, string) The name of the Docker volume (generated if not provided). +* `driver` - (Optional, string) Driver type for the volume (defaults to local). +* `driver_opts` - (Optional, map of strings) Options specific to the driver. + +## Attributes Reference + +The following attributes are exported in addition to the above configuration: + +* `mountpoint` (string) - The mountpoint of the volume.