diff --git a/internal/storage/resource_storage_volume.go b/internal/storage/resource_storage_volume.go index c2a3a2a3..19bc1979 100644 --- a/internal/storage/resource_storage_volume.go +++ b/internal/storage/resource_storage_volume.go @@ -3,6 +3,7 @@ package storage import ( "context" "fmt" + "strings" lxd "github.com/canonical/lxd/client" "github.com/canonical/lxd/shared/api" @@ -349,7 +350,14 @@ func (r StorageVolumeResource) SyncState(ctx context.Context, tfState *tfsdk.Sta } // Extract user defined config and merge it with current config state. - stateConfig := common.StripConfig(vol.Config, m.Config, m.ComputedKeys()) + inheritedPoolVolumeKeys, err := m.InheritedStoragePoolVolumeKeys(server, poolName) + if err != nil { + respDiags.AddError(fmt.Sprintf("Failed to retrieve storage pool config %q", volName), err.Error()) + return respDiags + } + + combinedComputedKeys := append(inheritedPoolVolumeKeys, m.ComputedKeys()...) + stateConfig := common.StripConfig(vol.Config, m.Config, combinedComputedKeys) config, diags := common.ToConfigMapType(ctx, stateConfig, m.Config) respDiags.Append(diags...) @@ -381,3 +389,22 @@ func (_ StorageVolumeModel) ComputedKeys() []string { "volatile.", } } + +func (_ StorageVolumeModel) InheritedStoragePoolVolumeKeys(server lxd.InstanceServer, poolName string) ([]string, error) { + pool, _, err := server.GetStoragePool(poolName) + if err != nil { + return nil, err + } + + volumePrefix := "volume." + inheritedKeys := make([]string, 0) + + for key := range pool.Config { + if strings.HasPrefix(key, volumePrefix) { + inheritedKey := strings.TrimPrefix(key, volumePrefix) + inheritedKeys = append(inheritedKeys, inheritedKey) + } + } + + return inheritedKeys, nil +} diff --git a/internal/storage/resource_storage_volume_test.go b/internal/storage/resource_storage_volume_test.go index 00627745..45396cfc 100644 --- a/internal/storage/resource_storage_volume_test.go +++ b/internal/storage/resource_storage_volume_test.go @@ -172,6 +172,35 @@ func TestAccStorageVolume_importProject(t *testing.T) { }) } +func TestAccStorageVolume_inheritedStoragePoolKeys(t *testing.T) { + poolName := acctest.GenerateName(2, "-") + volumeName := acctest.GenerateName(2, "-") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccStorageVolume_inheritedStoragePoolVolumeKeys(poolName, volumeName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("lxd_storage_pool.pool1", "name", poolName), + resource.TestCheckResourceAttr("lxd_storage_pool.pool1", "driver", "zfs"), + resource.TestCheckResourceAttr("lxd_storage_pool.pool1", "config.volume.zfs.remove_snapshots", "true"), + resource.TestCheckResourceAttr("lxd_storage_pool.pool1", "config.volume.zfs.use_refquota", "true"), + resource.TestCheckResourceAttr("lxd_volume.volume1", "name", volumeName), + resource.TestCheckResourceAttr("lxd_volume.volume1", "pool", poolName), + resource.TestCheckResourceAttr("lxd_volume.volume1", "type", "custom"), + resource.TestCheckResourceAttr("lxd_volume.volume1", "content_type", "block"), + + // Ensure computed keys are not tracked. + resource.TestCheckNoResourceAttr("lxd_volume.volume1", "config.zfs.remove_snapshots"), + resource.TestCheckNoResourceAttr("lxd_volume.volume1", "config.zfs.use_refquota"), + ), + }, + }, + }) +} + func testAccStorageVolume_basic(poolName, volumeName string) string { return fmt.Sprintf(` resource "lxd_storage_pool" "pool1" { @@ -257,3 +286,25 @@ resource "lxd_volume" "volume1" { } `, poolName, volumeName) } + +func testAccStorageVolume_inheritedStoragePoolVolumeKeys(poolName, volumeName string) string { + return fmt.Sprintf(` +resource "lxd_storage_pool" "pool1" { + name = "%s" + driver = "zfs" + config = { + "volume.zfs.remove_snapshots" = true + "volume.zfs.use_refquota" = true + } +} + +resource "lxd_volume" "volume1" { + name = "%s" + pool = lxd_storage_pool.pool1.name + content_type = "block" + config = { + "size" = "1GiB" + } +} + `, poolName, volumeName) +}