From 8bc727390ecccd968124b2fe2403c6788f4e0ad0 Mon Sep 17 00:00:00 2001 From: Adam Barreiro Date: Tue, 14 Jan 2025 09:53:08 +0100 Subject: [PATCH] Add vcd_tm_storage_class data source vcd_tm_content_library update operation (#1362) Signed-off-by: abarreiro --- .changes/v4.0.0/1339-features.md | 2 +- .changes/v4.0.0/1362-features.md | 1 + go.mod | 2 +- go.sum | 4 +- vcd/config_test.go | 12 +-- vcd/datasource_vcd_tm_content_library_item.go | 6 +- vcd/datasource_vcd_tm_storage_class.go | 94 +++++++++++++++++++ vcd/provider.go | 1 + vcd/resource_vcd_tm_content_library.go | 35 ++++--- vcd/resource_vcd_tm_content_library_item.go | 12 ++- ...source_vcd_tm_content_library_item_test.go | 4 +- vcd/resource_vcd_tm_content_library_test.go | 45 ++++++++- vcd/sample_vcd_test_config_tm.json | 2 +- vcd/tm_common_test.go | 12 +-- .../d/tm_region_storage_policy.html.markdown | 17 ++-- website/docs/d/tm_storage_class.html.markdown | 49 ++++++++++ .../docs/r/tm_content_library.html.markdown | 8 +- website/vcd.erb | 3 + 18 files changed, 247 insertions(+), 62 deletions(-) create mode 100644 .changes/v4.0.0/1362-features.md create mode 100644 vcd/datasource_vcd_tm_storage_class.go create mode 100644 website/docs/d/tm_storage_class.html.markdown diff --git a/.changes/v4.0.0/1339-features.md b/.changes/v4.0.0/1339-features.md index b95fd591e..09efb795f 100644 --- a/.changes/v4.0.0/1339-features.md +++ b/.changes/v4.0.0/1339-features.md @@ -1,3 +1,3 @@ -* **New Data Source:** `vcd_tm_region_storage_policy` to read Region Storage Policies [GH-1339, GH-1349] +* **New Data Source:** `vcd_tm_region_storage_policy` to read Region Storage Policies [GH-1339, GH-1349, GH-1362] * **New Resource:** `vcd_tm_content_library` to manage Content Libraries [GH-1339, GH-1349] * **New Data Source:** `vcd_tm_content_library` to read Content Libraries [GH-1339, GH-1349] diff --git a/.changes/v4.0.0/1362-features.md b/.changes/v4.0.0/1362-features.md new file mode 100644 index 000000000..609158318 --- /dev/null +++ b/.changes/v4.0.0/1362-features.md @@ -0,0 +1 @@ +* **New Data Source:** `vcd_tm_storage_class` to read Storage Classes in Tenant Manager [GH-1362] diff --git a/go.mod b/go.mod index 6f5076a5e..5a9c25374 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/hashicorp/go-version v1.6.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0 github.com/kr/pretty v0.3.1 - github.com/vmware/go-vcloud-director/v3 v3.0.0-alpha.13 + github.com/vmware/go-vcloud-director/v3 v3.0.0-alpha.14 ) require ( diff --git a/go.sum b/go.sum index 2eaae64cc..25c71cb0f 100644 --- a/go.sum +++ b/go.sum @@ -149,8 +149,8 @@ github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IU github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= -github.com/vmware/go-vcloud-director/v3 v3.0.0-alpha.13 h1:hX1PukXYr5n4IR61evd+hPW/iv+i5+nzUT8mWyKn034= -github.com/vmware/go-vcloud-director/v3 v3.0.0-alpha.13/go.mod h1:68KHsVns52dsq/w5JQYzauaU/+NAi1FmCxhBrFc/VoQ= +github.com/vmware/go-vcloud-director/v3 v3.0.0-alpha.14 h1:zY0f4JXNsK2z04DuoQ9VLeRw0FZq1sRCRrmSeKog/ps= +github.com/vmware/go-vcloud-director/v3 v3.0.0-alpha.14/go.mod h1:68KHsVns52dsq/w5JQYzauaU/+NAi1FmCxhBrFc/VoQ= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= diff --git a/vcd/config_test.go b/vcd/config_test.go index 2d5f5058c..c2d54178f 100644 --- a/vcd/config_test.go +++ b/vcd/config_test.go @@ -108,12 +108,12 @@ type TestConfig struct { MaxRetryTimeout int `json:"maxRetryTimeout"` } `json:"provider"` Tm struct { - Org string `json:"org"` // temporary field to make skipIfNotTm work - CreateRegion bool `json:"createRegion"` - Region string `json:"region"` - RegionStoragePolicy string `json:"regionStoragePolicy"` - Vdc string `json:"vdc"` - ContentLibrary string `json:"contentLibrary"` + Org string `json:"org"` // temporary field to make skipIfNotTm work + CreateRegion bool `json:"createRegion"` + Region string `json:"region"` + StorageClass string `json:"storageClass"` + Vdc string `json:"vdc"` + ContentLibrary string `json:"contentLibrary"` CreateNsxtManager bool `json:"createNsxtManager"` NsxtManagerUsername string `json:"nsxtManagerUsername"` diff --git a/vcd/datasource_vcd_tm_content_library_item.go b/vcd/datasource_vcd_tm_content_library_item.go index b97d6fff8..098b9506b 100644 --- a/vcd/datasource_vcd_tm_content_library_item.go +++ b/vcd/datasource_vcd_tm_content_library_item.go @@ -53,7 +53,8 @@ func datasourceVcdTmContentLibraryItem() *schema.Resource { Description: fmt.Sprintf("The ISO-8601 timestamp representing when this %s was last synced if subscribed", labelTmContentLibraryItem), }, "owner_org_id": { - Type: schema.TypeString, + Type: schema.TypeString, + // TODO: TM: This should be optional: Either Provider or Tenant can create CLs Computed: true, Description: fmt.Sprintf("The reference to the organization that the %s belongs to", labelTmContentLibraryItem), }, @@ -74,7 +75,8 @@ func datasourceVcdTmContentLibraryItem() *schema.Resource { func datasourceTmContentLibraryItemRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { vcdClient := meta.(*VCDClient) - cl, err := vcdClient.GetContentLibraryById(d.Get("content_library_id").(string)) + // TODO: TM: Tenant Context should not be nil and depend on the configured owner_org_id + cl, err := vcdClient.GetContentLibraryById(d.Get("content_library_id").(string), nil) if err != nil { return diag.Errorf("error retrieving Content Library: %s", err) } diff --git a/vcd/datasource_vcd_tm_storage_class.go b/vcd/datasource_vcd_tm_storage_class.go new file mode 100644 index 000000000..80482f2b5 --- /dev/null +++ b/vcd/datasource_vcd_tm_storage_class.go @@ -0,0 +1,94 @@ +package vcd + +import ( + "context" + "fmt" + "github.com/vmware/go-vcloud-director/v3/types/v56" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const labelTmStorageClass = "Storage Class" + +func datasourceVcdTmStorageClass() *schema.Resource { + return &schema.Resource{ + ReadContext: datasourceVcdTmStorageClassRead, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: fmt.Sprintf("%s name", labelTmStorageClass), + }, + "region_id": { + Type: schema.TypeString, + Required: true, + Description: fmt.Sprintf("The Region that this %s belongs to", labelTmStorageClass), + }, + "storage_capacity_mib": { + Type: schema.TypeInt, + Computed: true, + Description: fmt.Sprintf("The total storage capacity of the %s in mebibytes", labelTmStorageClass), + }, + "storage_consumed_mib": { + Type: schema.TypeInt, + Computed: true, + Description: fmt.Sprintf("For tenants, this represents the total storage given to all namespaces consuming from this %s in mebibytes. "+ + "For providers, this represents the total storage given to tenants from this %s in mebibytes.", labelTmStorageClass, labelTmStorageClass), + }, + "zone_ids": { + Type: schema.TypeSet, + Computed: true, + Description: fmt.Sprintf("A set with all the IDs of the zones available to the %s", labelTmStorageClass), + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func datasourceVcdTmStorageClassRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vcdClient := meta.(*VCDClient) + regionId := d.Get("region_id").(string) + region, err := vcdClient.GetRegionById(regionId) + if err != nil { + return diag.Errorf("error retrieving Region with ID '%s': %s", regionId, err) + } + + scName := d.Get("name").(string) + sc, err := region.GetStorageClassByName(scName) + if err != nil { + return diag.Errorf("error retrieving Storage Class '%s': %s", scName, err) + } + + err = setStorageClassData(d, sc.StorageClass) + if err != nil { + return diag.Errorf("error saving Storage Class data into state: %s", err) + } + + d.SetId(sc.StorageClass.ID) + return nil +} + +func setStorageClassData(d *schema.ResourceData, sc *types.StorageClass) error { + dSet(d, "name", sc.Name) + dSet(d, "storage_capacity_mib", sc.StorageCapacityMiB) + dSet(d, "storage_consumed_mib", sc.StorageConsumedMiB) + regionId := "" + if sc.Region != nil { + regionId = sc.Region.ID + } + dSet(d, "region_id", regionId) + + var zoneIds []string + if len(sc.Zones) > 0 { + zoneIds = extractIdsFromOpenApiReferences(sc.Zones) + } + err := d.Set("zone_ids", zoneIds) + if err != nil { + return err + } + + return nil +} diff --git a/vcd/provider.go b/vcd/provider.go index d158b8730..1d34465c0 100644 --- a/vcd/provider.go +++ b/vcd/provider.go @@ -177,6 +177,7 @@ var globalDataSourceMap = map[string]*schema.Resource{ "vcd_nsxt_alb_virtual_service_http_sec_rules": datasourceVcdAlbVirtualServiceSecRules(), // 3.14 "vcd_tm_org": datasourceVcdTmOrg(), // 4.0 "vcd_tm_region_storage_policy": datasourceVcdTmRegionStoragePolicy(), // 4.0 + "vcd_tm_storage_class": datasourceVcdTmStorageClass(), // 4.0 "vcd_tm_content_library": datasourceVcdTmContentLibrary(), // 4.0 "vcd_tm_supervisor": datasourceVcdTmSupervisor(), // 4.0 "vcd_tm_supervisor_zone": datasourceVcdTmSupervisorZone(), // 4.0 diff --git a/vcd/resource_vcd_tm_content_library.go b/vcd/resource_vcd_tm_content_library.go index c0cc3e56e..2a17a8b8d 100644 --- a/vcd/resource_vcd_tm_content_library.go +++ b/vcd/resource_vcd_tm_content_library.go @@ -3,8 +3,6 @@ package vcd import ( "context" "fmt" - "strings" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/vmware/go-vcloud-director/v3/govcd" @@ -24,13 +22,11 @@ func resourceVcdTmContentLibrary() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ForceNew: true, // TODO: TM: Update not supported Description: "The name of the Content Library", }, "storage_class_ids": { Type: schema.TypeSet, Required: true, - ForceNew: true, // TODO: TM: Update not supported Description: "A set of storage class IDs used by this Content Library", Elem: &schema.Schema{ Type: schema.TypeString, @@ -56,7 +52,6 @@ func resourceVcdTmContentLibrary() *schema.Resource { "description": { Type: schema.TypeString, Optional: true, - ForceNew: true, // TODO: TM: Update not supported Description: "The description of the Content Library", }, "is_shared": { @@ -76,7 +71,8 @@ func resourceVcdTmContentLibrary() *schema.Resource { "provider) or TENANT (Content Library that is scoped to a tenant organization)", }, "owner_org_id": { - Type: schema.TypeString, + Type: schema.TypeString, + // TODO: TM: This should be optional: Either Provider or Tenant can create CLs Computed: true, Description: "The reference to the Organization that the Content Library belongs to", }, @@ -84,26 +80,24 @@ func resourceVcdTmContentLibrary() *schema.Resource { Type: schema.TypeList, MaxItems: 1, Optional: true, + ForceNew: true, // Can't change subscription settings Description: "A block representing subscription settings of a Content Library", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "subscription_url": { Type: schema.TypeString, Required: true, - ForceNew: true, // TODO: TM: Update not supported Description: "Subscription url of this Content Library", }, "password": { Type: schema.TypeString, Optional: true, // Required at Runtime as cannot be Required + Computed in schema. (It is computed as password cannot be recovered) Computed: true, - ForceNew: true, // TODO: TM: Update not supported Description: "Password to use to authenticate with the publisher", }, "need_local_copy": { Type: schema.TypeBool, Optional: true, - ForceNew: true, // TODO: TM: Update not supported Description: "Whether to eagerly download content from publisher and store it locally", }, }, @@ -126,7 +120,8 @@ func resourceVcdTmContentLibraryCreate(ctx context.Context, d *schema.ResourceDa return diag.Errorf("error getting Content Library type: %s", err) } - cl, err := vcdClient.CreateContentLibrary(t) + // TODO: TM: Tenant Context should not be nil and depend on the configured owner_org_id + cl, err := vcdClient.CreateContentLibrary(t, nil) if err != nil { return diag.Errorf("error creating Content Library: %s", err) } @@ -138,7 +133,8 @@ func resourceVcdTmContentLibraryCreate(ctx context.Context, d *schema.ResourceDa func resourceVcdTmContentLibraryUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { vcdClient := meta.(*VCDClient) - rsp, err := vcdClient.GetContentLibraryById(d.Id()) + // TODO: TM: Tenant Context should not be nil and depend on the configured owner_org_id + rsp, err := vcdClient.GetContentLibraryById(d.Id(), nil) if err != nil { return diag.Errorf("error retrieving Content Library: %s", err) } @@ -164,10 +160,11 @@ func genericVcdTmContentLibraryRead(_ context.Context, d *schema.ResourceData, m var cl *govcd.ContentLibrary var err error + // TODO: TM: Tenant Context should not be nil and depend on the configured owner_org_id if d.Id() != "" { - cl, err = vcdClient.GetContentLibraryById(d.Id()) + cl, err = vcdClient.GetContentLibraryById(d.Id(), nil) } else { - cl, err = vcdClient.GetContentLibraryByName(d.Get("name").(string)) + cl, err = vcdClient.GetContentLibraryByName(d.Get("name").(string), nil) } if err != nil { if origin == "resource" && govcd.ContainsNotFound(err) { @@ -188,12 +185,14 @@ func genericVcdTmContentLibraryRead(_ context.Context, d *schema.ResourceData, m func resourceVcdTmContentLibraryDelete(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { vcdClient := meta.(*VCDClient) - cl, err := vcdClient.GetContentLibraryById(d.Id()) + // TODO: TM: Tenant Context should not be nil and depend on the configured owner_org_id + cl, err := vcdClient.GetContentLibraryById(d.Id(), nil) if err != nil { return diag.Errorf("error retrieving Content Library: %s", err) } - err = cl.Delete() + // TODO: TM: Add two new arguments "force_delete" and "delete_recursive" + err = cl.Delete(true, true) if err != nil { return diag.Errorf("error deleting Content Library: %s", err) } @@ -203,7 +202,8 @@ func resourceVcdTmContentLibraryDelete(_ context.Context, d *schema.ResourceData func resourceVcdTmContentLibraryImport(_ context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { vcdClient := meta.(*VCDClient) - rsp, err := vcdClient.GetContentLibraryByName(d.Id()) + // TODO: TM: Tenant Context should not be nil and depend on the configured owner_org_id + rsp, err := vcdClient.GetContentLibraryByName(d.Id(), nil) if err != nil { return nil, fmt.Errorf("error retrieving Content Library with name '%s': %s", d.Id(), err) } @@ -246,8 +246,7 @@ func setTmContentLibraryData(d *schema.ResourceData, cl *types.ContentLibrary) e scs := make([]string, len(cl.StorageClasses)) for i, sc := range cl.StorageClasses { - // TODO: TM: When vcd_region_storage_policy data source starts using :storageClass: UUID, we can get rid of this - scs[i] = strings.ReplaceAll(sc.ID, "storageClass", "regionStoragePolicy") + scs[i] = sc.ID } err := d.Set("storage_class_ids", scs) if err != nil { diff --git a/vcd/resource_vcd_tm_content_library_item.go b/vcd/resource_vcd_tm_content_library_item.go index 3a658da83..3962c910f 100644 --- a/vcd/resource_vcd_tm_content_library_item.go +++ b/vcd/resource_vcd_tm_content_library_item.go @@ -104,7 +104,8 @@ func resourceVcdTmContentLibraryItemCreate(ctx context.Context, d *schema.Resour vcdClient := meta.(*VCDClient) clId := d.Get("content_library_id").(string) - cl, err := vcdClient.GetContentLibraryById(clId) + // TODO: TM: Tenant Context should not be nil and depend on the configured owner_org_id + cl, err := vcdClient.GetContentLibraryById(clId, nil) if err != nil { return diag.Errorf("could not retrieve Content Library with ID '%s': %s", clId, err) } @@ -152,7 +153,8 @@ func resourceVcdTmContentLibraryItemRead(ctx context.Context, d *schema.Resource vcdClient := meta.(*VCDClient) clId := d.Get("content_library_id").(string) - cl, err := vcdClient.GetContentLibraryById(clId) + // TODO: TM: Tenant Context should not be nil and depend on the configured owner_org_id + cl, err := vcdClient.GetContentLibraryById(clId, nil) if err != nil { return diag.Errorf("could not retrieve Content Library with ID '%s': %s", clId, err) } @@ -169,7 +171,8 @@ func resourceVcdTmContentLibraryItemDelete(ctx context.Context, d *schema.Resour vcdClient := meta.(*VCDClient) clId := d.Get("content_library_id").(string) - cl, err := vcdClient.GetContentLibraryById(clId) + // TODO: TM: Tenant Context should not be nil and depend on the configured owner_org_id + cl, err := vcdClient.GetContentLibraryById(clId, nil) if err != nil { return diag.Errorf("could not retrieve Content Library with ID '%s': %s", clId, err) } @@ -190,7 +193,8 @@ func resourceVcdTmContentLibraryItemImport(_ context.Context, d *schema.Resource return nil, fmt.Errorf("ID syntax should be \"Content Library name\".\"Content Library Item name\", where '.' is a customisable import separator") } - cl, err := vcdClient.GetContentLibraryByName(id[0]) + // TODO: TM: Tenant Context should not be nil and depend on the configured owner_org_id + cl, err := vcdClient.GetContentLibraryByName(id[0], nil) if err != nil { return nil, fmt.Errorf("error getting Content Library with name '%s' for import: %s", id[0], err) } diff --git a/vcd/resource_vcd_tm_content_library_item_test.go b/vcd/resource_vcd_tm_content_library_item_test.go index b46e67165..1041216f3 100644 --- a/vcd/resource_vcd_tm_content_library_item_test.go +++ b/vcd/resource_vcd_tm_content_library_item_test.go @@ -22,7 +22,7 @@ func TestAccVcdTmContentLibraryItem(t *testing.T) { contentLibraryHcl, contentLibraryHclRef := getContentLibraryHcl(t, regionHclRef) var params = StringMap{ - "Name": t.Name() + "6", + "Name": t.Name(), "ContentLibraryRef": fmt.Sprintf("%s.id", contentLibraryHclRef), "OvaPath": "../test-resources/test_vapp_template.ova", "Tags": "tm", @@ -58,7 +58,7 @@ func TestAccVcdTmContentLibraryItem(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "is_published", "false"), resource.TestCheckResourceAttrSet(resourceName, "image_identifier"), resource.TestMatchResourceAttr(resourceName, "owner_org_id", regexp.MustCompile("urn:vcloud:org:")), - resource.TestCheckResourceAttr(resourceName, "status", ""), + resource.TestCheckResourceAttr(resourceName, "status", "READY"), resource.TestCheckResourceAttr(resourceName, "last_successful_sync", ""), resource.TestCheckResourceAttr(resourceName, "version", "1"), ), diff --git a/vcd/resource_vcd_tm_content_library_test.go b/vcd/resource_vcd_tm_content_library_test.go index 92bc4127a..f45f96d8a 100644 --- a/vcd/resource_vcd_tm_content_library_test.go +++ b/vcd/resource_vcd_tm_content_library_test.go @@ -23,7 +23,7 @@ func TestAccVcdTmContentLibrary(t *testing.T) { var params = StringMap{ "Name": t.Name(), "RegionId": fmt.Sprintf("%s.id", regionHclRef), - "RegionStoragePolicy": testConfig.Tm.RegionStoragePolicy, + "RegionStoragePolicy": testConfig.Tm.StorageClass, "Tags": "tm", } testParamsNotEmpty(t, params) @@ -39,16 +39,24 @@ func TestAccVcdTmContentLibrary(t *testing.T) { configText1 := templateFill(preRequisites+testAccVcdTmContentLibraryStep1, params) params["FuncName"] = t.Name() + "-step2" - configText2 := templateFill(preRequisites+testAccVcdTmContentLibraryStep2, params) + params["Name"] = t.Name() + "Updated" + configText2 := templateFill(preRequisites+testAccVcdTmContentLibraryStep1, params) + params["FuncName"] = t.Name() + "-step3" + configText3 := templateFill(preRequisites+testAccVcdTmContentLibraryStep3, params) debugPrintf("#[DEBUG] CONFIGURATION step1: %s\n", configText1) debugPrintf("#[DEBUG] CONFIGURATION step2: %s\n", configText2) + debugPrintf("#[DEBUG] CONFIGURATION step3: %s\n", configText3) if vcdShortTest { t.Skip(acceptanceTestsSkipped) return } resourceName := "vcd_tm_content_library.cl" + dsRegionStoragePolicy := "data.vcd_tm_region_storage_policy.sp" + dsStorageClass := "data.vcd_tm_storage_class.sc" + + cachedId := &testCachedFieldValue{} resource.Test(t, resource.TestCase{ ProviderFactories: testAccProviders, @@ -59,6 +67,23 @@ func TestAccVcdTmContentLibrary(t *testing.T) { { Config: configText1, Check: resource.ComposeTestCheckFunc( + // Region Storage Policy + resource.TestCheckResourceAttr(dsRegionStoragePolicy, "name", testConfig.Tm.StorageClass), + resource.TestCheckResourceAttrPair(dsRegionStoragePolicy, "region_id", regionHclRef, "id"), + resource.TestMatchResourceAttr(dsRegionStoragePolicy, "description", regexp.MustCompile(`.*`)), + resource.TestCheckResourceAttr(dsRegionStoragePolicy, "status", ""), + resource.TestCheckResourceAttrSet(dsRegionStoragePolicy, "storage_capacity_mb"), + resource.TestCheckResourceAttrSet(dsRegionStoragePolicy, "storage_consumed_mb"), + + // Storage Class + resource.TestCheckResourceAttr(dsStorageClass, "name", testConfig.Tm.StorageClass), + resource.TestCheckResourceAttrPair(dsStorageClass, "region_id", regionHclRef, "id"), + resource.TestCheckResourceAttrSet(dsStorageClass, "storage_capacity_mib"), + resource.TestCheckResourceAttrSet(dsStorageClass, "storage_consumed_mib"), + resource.TestMatchResourceAttr(dsStorageClass, "zone_ids.#", regexp.MustCompile("[0-9]+")), + + // Content Library + cachedId.cacheTestResourceFieldValue(resourceName, "id"), resource.TestCheckResourceAttr(resourceName, "name", t.Name()), resource.TestCheckResourceAttr(resourceName, "description", t.Name()), resource.TestCheckResourceAttr(resourceName, "storage_class_ids.#", "1"), @@ -74,6 +99,13 @@ func TestAccVcdTmContentLibrary(t *testing.T) { }, { Config: configText2, + Check: resource.ComposeTestCheckFunc( + cachedId.testCheckCachedResourceFieldValue(resourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "name", t.Name()+"Updated"), + ), + }, + { + Config: configText3, Check: resource.ComposeTestCheckFunc( resourceFieldsEqual(resourceName, "data.vcd_tm_content_library.cl_ds", nil), ), @@ -96,16 +128,21 @@ data "vcd_tm_region_storage_policy" "sp" { name = "{{.RegionStoragePolicy}}" } +data "vcd_tm_storage_class" "sc" { + region_id = {{.RegionId}} + name = "{{.RegionStoragePolicy}}" +} + resource "vcd_tm_content_library" "cl" { name = "{{.Name}}" description = "{{.Name}}" storage_class_ids = [ - data.vcd_tm_region_storage_policy.sp.id + data.vcd_tm_storage_class.sc.id ] } ` -const testAccVcdTmContentLibraryStep2 = testAccVcdTmContentLibraryStep1 + ` +const testAccVcdTmContentLibraryStep3 = testAccVcdTmContentLibraryStep1 + ` data "vcd_tm_content_library" "cl_ds" { name = vcd_tm_content_library.cl.name } diff --git a/vcd/sample_vcd_test_config_tm.json b/vcd/sample_vcd_test_config_tm.json index e70cb5963..610b9a049 100644 --- a/vcd/sample_vcd_test_config_tm.json +++ b/vcd/sample_vcd_test_config_tm.json @@ -43,7 +43,7 @@ "org": "tf-test", "createRegion": true, "region": "one-region", - "regionStoragePolicy": "vSAN Default Storage Policy", + "storageClass": "vSAN Default Storage Policy", "vdc": "one-vdc", "contentLibrary": "content-library-one", diff --git a/vcd/tm_common_test.go b/vcd/tm_common_test.go index 4fa4f5ad0..3dc7464be 100644 --- a/vcd/tm_common_test.go +++ b/vcd/tm_common_test.go @@ -127,11 +127,11 @@ func getContentLibraryHcl(t *testing.T, regionHclRef string) (string, string) { if testConfig.Tm.ContentLibrary == "" { t.Fatalf("the property tm.contentLibrary is required but it is not present in testing JSON") } - if testConfig.Tm.RegionStoragePolicy == "" { - t.Fatalf("the property tm.regionStoragePolicy is required but it is not present in testing JSON") + if testConfig.Tm.StorageClass == "" { + t.Fatalf("the property tm.storageClass is required but it is not present in testing JSON") } vcdClient := createTemporaryVCDConnection(false) - cl, err := vcdClient.GetContentLibraryByName(testConfig.Tm.ContentLibrary) + cl, err := vcdClient.GetContentLibraryByName(testConfig.Tm.ContentLibrary, nil) if err == nil { return ` data "vcd_tm_content_library" "content_library" { @@ -144,15 +144,15 @@ data "vcd_tm_content_library" "content_library" { return "", "" } return ` -data "vcd_tm_region_storage_policy" "region_storage_policy" { +data "vcd_tm_storage_class" "storage_class" { region_id = ` + regionHclRef + `.id - name = "` + testConfig.Tm.RegionStoragePolicy + `" + name = "` + testConfig.Tm.StorageClass + `" } resource "vcd_tm_content_library" "content_library" { name = "` + testConfig.Tm.ContentLibrary + `" description = "` + testConfig.Tm.ContentLibrary + `" - storage_class_ids = [data.vcd_tm_region_storage_policy.region_storage_policy.id] + storage_class_ids = [data.vcd_tm_storage_class.storage_class.id] } `, "vcd_tm_content_library.content_library" } diff --git a/website/docs/d/tm_region_storage_policy.html.markdown b/website/docs/d/tm_region_storage_policy.html.markdown index 07d27768d..c9ee5eea8 100644 --- a/website/docs/d/tm_region_storage_policy.html.markdown +++ b/website/docs/d/tm_region_storage_policy.html.markdown @@ -3,17 +3,18 @@ layout: "vcd" page_title: "VMware Cloud Foundation Tenant Manager: vcd_tm_region_storage_policy" sidebar_current: "docs-vcd-data-source-tm-region-storage-policy" description: |- - Provides a VMware Cloud Foundation Tenant Manager Region Storage Policy data source. This can be used to read Content Libraries. + Provides a VMware Cloud Foundation Tenant Manager data source to read Region Storage Policies. --- # vcd\_tm\_region\_storage\_policy -// TODO: TM: Check whether this finally changes to Region Storage Class - -Provides a VMware Cloud Foundation Tenant Manager Region Storage Policy data source. This can be used to read Region Storage Policies. +Provides a VMware Cloud Foundation Tenant Manager data source to read Region Storage Policies. This data source is exclusive to **VMware Cloud Foundation Tenant Manager**. Supported in provider *v4.0+* +-> To retrieve Storage Classes, use the [`vcd_tm_storage_class`](/providers/vmware/vcd/latest/docs/data-sources/tm_storage_class) +data source instead + ## Example Usage ```hcl @@ -26,12 +27,8 @@ data "vcd_tm_region_storage_policy" "sp" { name = "vSAN Default Storage Policy" } -resource "vcd_tm_content_library" "cl" { - name = "My Library" - description = "A simple library" - storage_policy_ids = [ - data.vcd_tm_region_storage_policy.sp.id - ] +output "policy_id" { + value = data.vcd_tm_region_storage_policy.sp.id } ``` diff --git a/website/docs/d/tm_storage_class.html.markdown b/website/docs/d/tm_storage_class.html.markdown new file mode 100644 index 000000000..b4a05089d --- /dev/null +++ b/website/docs/d/tm_storage_class.html.markdown @@ -0,0 +1,49 @@ +--- +layout: "vcd" +page_title: "VMware Cloud Foundation Tenant Manager: vcd_tm_storage_class" +sidebar_current: "docs-vcd-data-source-tm-storage-class" +description: |- + Provides a VMware Cloud Foundation Tenant Manager data source to read Storage Classes. +--- + +# vcd\_tm\_storage\_class + +Provides a VMware Cloud Foundation Tenant Manager data source to read Region Storage Classes. + +This data source is exclusive to **VMware Cloud Foundation Tenant Manager**. Supported in provider *v4.0+* + +## Example Usage + +```hcl +data "vcd_tm_region" "region" { + name = "my-region" +} + +data "vcd_tm_region_storage_class" "sc" { + region_id = data.vcd_tm_region.region.id + name = "vSAN Default Storage Class" +} + +resource "vcd_tm_content_library" "cl" { + name = "My Library" + description = "A simple library" + storage_class_ids = [ + data.vcd_tm_storage_class.sc.id + ] +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the Storage Class to read +* `region_id` - (Required) The ID of the Region where the Storage Class belongs + +## Attribute reference + +* `storage_capacity_mib` - The total storage capacity of the Storage Class in mebibytes +* `storage_consumed_mib` - For tenants, this represents the total storage given to all namespaces consuming from this + Storage Class in mebibytes. For providers, this represents the total storage given to tenants from this Storage Class + in mebibytes +* `zone_ids` - A set with all the IDs of the zones available to the Storage Class \ No newline at end of file diff --git a/website/docs/r/tm_content_library.html.markdown b/website/docs/r/tm_content_library.html.markdown index 531683b83..fba41fa64 100644 --- a/website/docs/r/tm_content_library.html.markdown +++ b/website/docs/r/tm_content_library.html.markdown @@ -19,7 +19,7 @@ data "vcd_tm_region" "region" { name = "My Region" } -data "vcd_tm_region_storage_policy" "sp" { +data "vcd_tm_storage_class" "sc" { region_id = data.vcd_tm_region.region.id name = "vSAN Default Storage Policy" } @@ -28,7 +28,7 @@ resource "vcd_tm_content_library" "cl" { name = "My Library" description = "A simple library" storage_class_ids = [ - data.vcd_tm_region_storage_policy.sp.id + data.vcd_tm_storage_class.sc.id ] } ``` @@ -42,9 +42,7 @@ resource "vcd_tm_content_library" "cl" { The following arguments are supported: * `name` - (Required) The name of the Content Library - -// TODO: TM: Check whether this finally changes to Region Storage Class: -* `storage_class_ids` - (Required) A set of [Storage Class IDs](/providers/vmware/vcd/latest/docs/data-sources/tm_region_storage_policy) used by this Content Library +* `storage_class_ids` - (Required) A set of [Storage Class IDs](/providers/vmware/vcd/latest/docs/data-sources/tm_storage_class) used by this Content Library * `auto_attach` - (Optional) Defaults to `true`. For Tenant Content Libraries this field represents whether this Content Library should be automatically attached to all current and future namespaces in the tenant organization. If a value of `false` is supplied, then this Tenant Content Library will only be attached to namespaces that explicitly request it. For Provider Content Libraries this field is not needed diff --git a/website/vcd.erb b/website/vcd.erb index 92acb3a4b..f3379e4a0 100644 --- a/website/vcd.erb +++ b/website/vcd.erb @@ -487,6 +487,9 @@ > vcd_tm_region_storage_policy + > + vcd_tm_storage_class + > vcd_tm_content_library