2021-03-18 03:30:54 -04:00
package provider
2016-01-15 12:33:17 -05:00
import (
2018-07-03 11:30:53 -04:00
"context"
2021-05-31 03:11:49 -04:00
"encoding/json"
2019-11-23 08:42:05 -05:00
"log"
"time"
2018-07-03 11:30:53 -04:00
"github.com/docker/docker/api/types/volume"
2021-03-18 03:30:54 -04:00
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
2016-01-15 12:33:17 -05:00
)
2021-04-19 09:33:13 -04:00
const (
volumeReadRefreshTimeout = 30 * time . Second
volumeReadRefreshWaitBeforeRefreshes = 5 * time . Second
volumeReadRefreshDelay = 2 * time . Second
)
2016-01-15 12:33:17 -05:00
func resourceDockerVolume ( ) * schema . Resource {
return & schema . Resource {
2021-05-21 08:30:56 -04:00
Description : "Creates and destroys a volume in Docker. This can be used alongside [docker_container](container.md) to prepare volumes that can be shared across containers." ,
2021-03-18 03:30:54 -04:00
CreateContext : resourceDockerVolumeCreate ,
ReadContext : resourceDockerVolumeRead ,
DeleteContext : resourceDockerVolumeDelete ,
2019-11-23 08:42:05 -05:00
Importer : & schema . ResourceImporter {
2021-03-18 03:30:54 -04:00
StateContext : schema . ImportStatePassthroughContext ,
2019-11-23 08:42:05 -05:00
} ,
2016-01-15 12:33:17 -05:00
2019-11-14 07:58:53 -05:00
Schema : map [ string ] * schema . Schema {
"name" : {
2021-05-21 08:30:56 -04:00
Type : schema . TypeString ,
Description : "The name of the Docker volume (will be generated if not provided)." ,
Optional : true ,
Computed : true ,
ForceNew : true ,
2019-11-14 07:58:53 -05:00
} ,
"labels" : {
2021-05-21 08:30:56 -04:00
Type : schema . TypeSet ,
Description : "User-defined key/value metadata" ,
Optional : true ,
ForceNew : true ,
Elem : labelSchema ,
2019-11-14 07:58:53 -05:00
} ,
"driver" : {
2021-05-21 08:30:56 -04:00
Type : schema . TypeString ,
Description : "Driver type for the volume. Defaults to `local`." ,
Optional : true ,
Computed : true ,
ForceNew : true ,
2019-11-14 07:58:53 -05:00
} ,
"driver_opts" : {
2021-05-21 08:30:56 -04:00
Type : schema . TypeMap ,
Description : "Options specific to the driver." ,
Optional : true ,
ForceNew : true ,
2019-11-14 07:58:53 -05:00
} ,
"mountpoint" : {
2021-05-21 08:30:56 -04:00
Type : schema . TypeString ,
Description : "The mountpoint of the volume." ,
Computed : true ,
2019-11-14 07:58:53 -05:00
} ,
} ,
SchemaVersion : 1 ,
StateUpgraders : [ ] schema . StateUpgrader {
{
Version : 0 ,
Type : resourceDockerVolumeV0 ( ) . CoreConfigSchema ( ) . ImpliedType ( ) ,
2021-03-18 03:30:54 -04:00
Upgrade : func ( ctx context . Context , rawState map [ string ] interface { } , meta interface { } ) ( map [ string ] interface { } , error ) {
2019-11-14 17:44:58 -05:00
return replaceLabelsMapFieldWithSetField ( rawState ) , nil
2019-11-14 07:58:53 -05:00
} ,
} ,
} ,
}
}
2021-03-18 03:30:54 -04:00
func resourceDockerVolumeCreate ( ctx context . Context , d * schema . ResourceData , meta interface { } ) diag . Diagnostics {
2017-11-21 04:14:07 -05:00
client := meta . ( * ProviderConfig ) . DockerClient
2018-07-03 11:30:53 -04:00
2025-04-17 13:22:08 -04:00
createOpts := volume . CreateOptions { }
2016-01-15 12:33:17 -05:00
if v , ok := d . GetOk ( "name" ) ; ok {
createOpts . Name = v . ( string )
}
2018-10-18 06:39:58 -04:00
if v , ok := d . GetOk ( "labels" ) ; ok {
2019-11-14 07:58:53 -05:00
createOpts . Labels = labelSetToMap ( v . ( * schema . Set ) )
2018-10-18 06:39:58 -04:00
}
2016-01-15 12:33:17 -05:00
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
2025-04-17 13:22:08 -04:00
var retVolume volume . Volume
2018-07-03 11:30:53 -04:00
retVolume , err = client . VolumeCreate ( ctx , createOpts )
if err != nil {
2021-03-18 03:30:54 -04:00
return diag . Errorf ( "Unable to create volume: %s" , err )
2016-01-15 12:33:17 -05:00
}
d . SetId ( retVolume . Name )
2021-03-18 03:30:54 -04:00
return resourceDockerVolumeRead ( ctx , d , meta )
2016-01-15 12:33:17 -05:00
}
2021-03-18 03:30:54 -04:00
func resourceDockerVolumeRead ( ctx context . Context , d * schema . ResourceData , meta interface { } ) diag . Diagnostics {
2017-11-21 04:14:07 -05:00
client := meta . ( * ProviderConfig ) . DockerClient
2016-01-15 12:33:17 -05:00
2021-05-31 03:11:49 -04:00
volume , err := client . VolumeInspect ( ctx , d . Id ( ) )
2018-07-03 11:30:53 -04:00
if err != nil {
2021-03-18 03:30:54 -04:00
return diag . Errorf ( "Unable to inspect volume: %s" , err )
2016-01-15 12:33:17 -05:00
}
2021-05-31 03:11:49 -04:00
jsonObj , _ := json . MarshalIndent ( volume , "" , "\t" )
log . Printf ( "[DEBUG] Docker volume inspect from readFunc: %s" , jsonObj )
d . Set ( "name" , volume . Name )
d . Set ( "labels" , mapToLabelSet ( volume . Labels ) )
d . Set ( "driver" , volume . Driver )
d . Set ( "driver_opts" , volume . Options )
d . Set ( "mountpoint" , volume . Mountpoint )
2016-01-15 12:33:17 -05:00
return nil
}
2021-03-18 03:30:54 -04:00
func resourceDockerVolumeDelete ( ctx context . Context , d * schema . ResourceData , meta interface { } ) diag . Diagnostics {
2021-04-19 09:33:13 -04:00
log . Printf ( "[INFO] Waiting for volume: '%s' to get removed: max '%v seconds'" , d . Id ( ) , volumeReadRefreshTimeout )
2018-07-03 11:30:53 -04:00
stateConf := & resource . StateChangeConf {
Pending : [ ] string { "in_use" } ,
Target : [ ] string { "removed" } ,
Refresh : resourceDockerVolumeRemoveRefreshFunc ( d . Id ( ) , meta ) ,
2021-04-19 09:33:13 -04:00
Timeout : volumeReadRefreshTimeout ,
MinTimeout : volumeReadRefreshWaitBeforeRefreshes ,
Delay : volumeReadRefreshDelay ,
2018-07-03 11:30:53 -04:00
}
2016-01-15 12:33:17 -05:00
2018-07-03 11:30:53 -04:00
// Wait, catching any errors
2021-03-18 03:30:54 -04:00
_ , err := stateConf . WaitForStateContext ( ctx )
2018-07-03 11:30:53 -04:00
if err != nil {
2021-03-18 03:30:54 -04:00
return diag . FromErr ( err )
2016-01-15 12:33:17 -05:00
}
d . SetId ( "" )
return nil
}
2018-07-03 11:30:53 -04:00
func resourceDockerVolumeRemoveRefreshFunc (
volumeID string , meta interface { } ) resource . StateRefreshFunc {
return func ( ) ( interface { } , string , error ) {
client := meta . ( * ProviderConfig ) . DockerClient
forceDelete := true
if err := client . VolumeRemove ( context . Background ( ) , volumeID , forceDelete ) ; err != nil {
2021-06-22 09:11:32 -04:00
if containsIgnorableErrorMessage ( err . Error ( ) , "volume is in use" ) {
2018-07-03 11:30:53 -04:00
log . Printf ( "[INFO] Volume with id '%v' is still in use" , volumeID )
return volumeID , "in_use" , nil
}
log . Printf ( "[INFO] Removing volume with id '%v' caused an error: %v" , volumeID , err )
return nil , "" , err
}
log . Printf ( "[INFO] Removing volume with id '%v' got removed" , volumeID )
return volumeID , "removed" , nil
}
}