From 5386f31c16b8ec7ddc492f3aa62345b7a7b864a1 Mon Sep 17 00:00:00 2001 From: cdoria Date: Fri, 6 Dec 2024 09:17:18 -0500 Subject: [PATCH] Update FaultSet Datasource Filter --- docs/data-sources/fault_set.md | 38 +++-- .../powerflex_fault_set/data-source.tf | 23 +-- powerflex/helper/fault_set_helper.go | 6 + powerflex/models/fault_set.go | 14 +- powerflex/provider/fault_set_datasource.go | 140 +++++------------- .../provider/fault_set_datasource_test.go | 121 ++++++++++----- 6 files changed, 178 insertions(+), 164 deletions(-) diff --git a/docs/data-sources/fault_set.md b/docs/data-sources/fault_set.md index c5596936..ed65e381 100644 --- a/docs/data-sources/fault_set.md +++ b/docs/data-sources/fault_set.md @@ -49,21 +49,26 @@ limitations under the License. # commands to run this tf file : terraform init && terraform apply --auto-approve # Get all fault set details present on the cluster -data "powerflex_fault_set" "example1" { +data "powerflex_fault_set" "all" { } -# Get fault set details using fault set IDs -data "powerflex_fault_set" "example2" { - fault_set_ids = ["FaultSet_ID1", "FaultSet_ID2"] +output "fault_set_result_all" { + value = data.powerflex_fault_set.all.fault_set_details } -# Get fault set details using fault set names -data "powerflex_fault_set" "example3" { - fault_set_names = ["FaultSet_Name1", "FaultSet_Name2"] +// If multiple filter fields are provided then it will show the intersection of all of those fields. +// If there is no intersection between the filters then an empty datasource will be returned +// For more information about how we do our datasource filtering check out our guides: https://dell.github.io/terraform-docs/docs/storage/platforms/powerflex/product_guide/examples/ +data "powerflex_fault_set" "filtered" { + filter { + # protection_domain_id = ["protection_domain_id", "protection_domain_id2"] + # name = ["name", "name2"] + # id = ["id", "id2"] + } } -output "fault_set_result" { - value = data.powerflex_fault_set.example1.fault_set_details +output "fault_set_result_filtered" { + value = data.powerflex_fault_set.filtered.fault_set_details } ``` @@ -74,13 +79,22 @@ After the successful execution of above said block, we can see the output by exe ### Optional -- `fault_set_ids` (Set of String) List of fault set IDs -- `fault_set_names` (Set of String) List of fault set names +- `filter` (Block, Optional) (see [below for nested schema](#nestedblock--filter)) ### Read-Only - `fault_set_details` (Attributes Set) Fault set details (see [below for nested schema](#nestedatt--fault_set_details)) -- `id` (String) Placeholder attribute. +- `id` (String) Placeholder for fault set datasource attribute. + + +### Nested Schema for `filter` + +Optional: + +- `id` (Set of String) List of id +- `name` (Set of String) List of name +- `protection_domain_id` (Set of String) List of protection_domain_id + ### Nested Schema for `fault_set_details` diff --git a/examples/data-sources/powerflex_fault_set/data-source.tf b/examples/data-sources/powerflex_fault_set/data-source.tf index 047b1ae3..1712478f 100644 --- a/examples/data-sources/powerflex_fault_set/data-source.tf +++ b/examples/data-sources/powerflex_fault_set/data-source.tf @@ -18,19 +18,24 @@ limitations under the License. # commands to run this tf file : terraform init && terraform apply --auto-approve # Get all fault set details present on the cluster -data "powerflex_fault_set" "example1" { +data "powerflex_fault_set" "all" { } -# Get fault set details using fault set IDs -data "powerflex_fault_set" "example2" { - fault_set_ids = ["FaultSet_ID1", "FaultSet_ID2"] +output "fault_set_result_all" { + value = data.powerflex_fault_set.all.fault_set_details } -# Get fault set details using fault set names -data "powerflex_fault_set" "example3" { - fault_set_names = ["FaultSet_Name1", "FaultSet_Name2"] +// If multiple filter fields are provided then it will show the intersection of all of those fields. +// If there is no intersection between the filters then an empty datasource will be returned +// For more information about how we do our datasource filtering check out our guides: https://dell.github.io/terraform-docs/docs/storage/platforms/powerflex/product_guide/examples/ +data "powerflex_fault_set" "filtered" { + filter { + # protection_domain_id = ["protection_domain_id", "protection_domain_id2"] + # name = ["name", "name2"] + # id = ["id", "id2"] + } } -output "fault_set_result" { - value = data.powerflex_fault_set.example1.fault_set_details +output "fault_set_result_filtered" { + value = data.powerflex_fault_set.filtered.fault_set_details } diff --git a/powerflex/helper/fault_set_helper.go b/powerflex/helper/fault_set_helper.go index f416b5e3..f60ca6d3 100644 --- a/powerflex/helper/fault_set_helper.go +++ b/powerflex/helper/fault_set_helper.go @@ -20,6 +20,7 @@ package helper import ( "terraform-provider-powerflex/powerflex/models" + "github.com/dell/goscaleio" scaleiotypes "github.com/dell/goscaleio/types/v1" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -33,6 +34,11 @@ func UpdateFaultSetState(faultset *scaleiotypes.FaultSet, plan models.FaultSetRe return state } +// GetAllFaultSets returns all the fault sets +func GetAllFaultSets(system *goscaleio.System) ([]scaleiotypes.FaultSet, error) { + return system.GetAllFaultSets() +} + // GetAllFaultSetState returns the state for fault set data source func GetAllFaultSetState(faultSet scaleiotypes.FaultSet, sdsDetails []models.SdsDataModel) (response models.FaultSet) { response = models.FaultSet{ diff --git a/powerflex/models/fault_set.go b/powerflex/models/fault_set.go index ab36964f..a83d6483 100644 --- a/powerflex/models/fault_set.go +++ b/powerflex/models/fault_set.go @@ -30,10 +30,16 @@ type FaultSetResourceModel struct { // FaultSetDataSourceModel maps the struct to FaultSet data source schema type FaultSetDataSourceModel struct { - FaultSetIDs types.Set `tfsdk:"fault_set_ids"` - FaultSetNames types.Set `tfsdk:"fault_set_names"` - FaultSetDetails []FaultSet `tfsdk:"fault_set_details"` - ID types.String `tfsdk:"id"` + FaultSetFilter *FaultSetFilter `tfsdk:"filter"` + FaultSetDetails []FaultSet `tfsdk:"fault_set_details"` + ID types.String `tfsdk:"id"` +} + +// FaultSetFilter defines the filter for fault set +type FaultSetFilter struct { + ProtectionDomainID []types.String `tfsdk:"protection_domain_id"` + Name []types.String `tfsdk:"name"` + ID []types.String `tfsdk:"id"` } // FaultSet maps the struct to FaultSet schema diff --git a/powerflex/provider/fault_set_datasource.go b/powerflex/provider/fault_set_datasource.go index 80c85974..809c381a 100644 --- a/powerflex/provider/fault_set_datasource.go +++ b/powerflex/provider/fault_set_datasource.go @@ -25,12 +25,8 @@ import ( "github.com/dell/goscaleio" scaleiotypes "github.com/dell/goscaleio/types/v1" - "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" - "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -105,92 +101,50 @@ func (d *faultSetDataSource) Read(ctx context.Context, req datasource.ReadReques return } - // Fetch Fault set details if IDs are provided - if !state.FaultSetIDs.IsNull() { - faultSetIDs := make([]string, 0) - diags.Append(state.FaultSetIDs.ElementsAs(ctx, &faultSetIDs, true)...) - - for _, faultSetID := range faultSetIDs { - faultSet, err := d.system.GetFaultSetByID(faultSetID) - if err != nil { - resp.Diagnostics.AddError( - fmt.Sprintf("Error in getting fault set details using id %v", faultSetID), err.Error(), - ) - return - } - sdsDetails, err := d.GetSdsDetails(faultSet.ID) - if err != nil { - resp.Diagnostics.AddError( - fmt.Sprintf("Error in getting SDS details connected to fault set details using id %v", faultSet.ID), err.Error(), - ) - return - } + // Fetch Fault set details for all the fault sets + faultSets, err = helper.GetAllFaultSets(d.system) + if err != nil { + resp.Diagnostics.AddError( + "Error in getting Fault Set details", err.Error(), + ) + return + } - var sdsStateModels []models.SdsDataModel - for index := range sdsDetails { - sdsState := getSdsState(&sdsDetails[index]) - sdsStateModels = append(sdsStateModels, sdsState) - } - faultSetsModel = append(faultSetsModel, helper.GetAllFaultSetState(*faultSet, sdsStateModels)) + // Filter if any are set + if state.FaultSetFilter != nil { + filtered, err := helper.GetDataSourceByValue(*state.FaultSetFilter, faultSets) + if err != nil { + resp.Diagnostics.AddError( + fmt.Sprintf("Error in filtering fault sets: %v please validate the filter", state.FaultSetFilter), err.Error(), + ) + return } - } else if !state.FaultSetNames.IsNull() { - // Fetch Fault set details if names are provided - faultSetNames := make([]string, 0) - diags.Append(state.FaultSetNames.ElementsAs(ctx, &faultSetNames, true)...) - - for _, faultSetName := range faultSetNames { - faultSet, err := d.system.GetFaultSetByName(faultSetName) - if err != nil { - resp.Diagnostics.AddError( - fmt.Sprintf("Error in getting fault set details using name %v", faultSetName), err.Error(), - ) - return - } - sdsDetails, err := d.GetSdsDetails(faultSet.ID) - if err != nil { - resp.Diagnostics.AddError( - fmt.Sprintf("Error in getting SDS details connected to fault set details using id %v", faultSet.ID), err.Error(), - ) - return - } - - var sdsStateModels []models.SdsDataModel - for index := range sdsDetails { - sdsState := getSdsState(&sdsDetails[index]) - sdsStateModels = append(sdsStateModels, sdsState) - } - faultSetsModel = append(faultSetsModel, helper.GetAllFaultSetState(*faultSet, sdsStateModels)) + filteredvFaultSets := []scaleiotypes.FaultSet{} + for _, val := range filtered { + filteredvFaultSets = append(filteredvFaultSets, val.(scaleiotypes.FaultSet)) } - } else { - // Fetch Fault set details for all the fault sets - faultSets, err = d.system.GetAllFaultSets() + faultSets = filteredvFaultSets + } + + for _, faultSet := range faultSets { + sdsDetails, err := d.GetSdsDetails(faultSet.ID) if err != nil { resp.Diagnostics.AddError( - "Error in getting Fault Set details", err.Error(), + fmt.Sprintf("Error in getting SDS details connected to fault set details using id %v", faultSet.ID), err.Error(), ) return } - for _, faultSet := range faultSets { - sdsDetails, err := d.GetSdsDetails(faultSet.ID) - if err != nil { - resp.Diagnostics.AddError( - fmt.Sprintf("Error in getting SDS details connected to fault set details using id %v", faultSet.ID), err.Error(), - ) - return - } - - var sdsStateModels []models.SdsDataModel - for index := range sdsDetails { - sdsState := getSdsState(&sdsDetails[index]) - sdsStateModels = append(sdsStateModels, sdsState) - } - faultSetsModel = append(faultSetsModel, helper.GetAllFaultSetState(faultSet, sdsStateModels)) + var sdsStateModels []models.SdsDataModel + for index := range sdsDetails { + sdsState := getSdsState(&sdsDetails[index]) + sdsStateModels = append(sdsStateModels, sdsState) } + faultSetsModel = append(faultSetsModel, helper.GetAllFaultSetState(faultSet, sdsStateModels)) } state.FaultSetDetails = faultSetsModel - state.ID = types.StringValue("placeholder") + state.ID = types.StringValue("fault-set-datasource-id") diags = resp.State.Set(ctx, state) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -204,33 +158,10 @@ var FaultSetDataSourceSchema schema.Schema = schema.Schema{ MarkdownDescription: "This datasource is used to query the existing fault set from the PowerFlex array. The information fetched from this datasource can be used for getting the details / for further processing in resource block.", Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ - Description: "Placeholder attribute.", - MarkdownDescription: "Placeholder attribute.", + Description: "Placeholder for fault set datasource attribute.", + MarkdownDescription: "Placeholder for fault set datasource attribute.", Computed: true, }, - "fault_set_ids": schema.SetAttribute{ - Description: "List of fault set IDs", - MarkdownDescription: "List of fault set IDs", - Optional: true, - ElementType: types.StringType, - Validators: []validator.Set{ - setvalidator.ConflictsWith( - path.MatchRoot("fault_set_names"), - ), - setvalidator.SizeAtLeast(1), - setvalidator.ValueStringsAre(stringvalidator.LengthAtLeast(1)), - }, - }, - "fault_set_names": schema.SetAttribute{ - Description: "List of fault set names", - MarkdownDescription: "List of fault set names", - Optional: true, - ElementType: types.StringType, - Validators: []validator.Set{ - setvalidator.SizeAtLeast(1), - setvalidator.ValueStringsAre(stringvalidator.LengthAtLeast(1)), - }, - }, "fault_set_details": schema.SetNestedAttribute{ Description: "Fault set details", MarkdownDescription: "Fault set details", @@ -501,6 +432,11 @@ var FaultSetDataSourceSchema schema.Schema = schema.Schema{ }, }, }, + Blocks: map[string]schema.Block{ + "filter": schema.SingleNestedBlock{ + Attributes: helper.GenerateSchemaAttributes(helper.TypeToMap(models.FaultSetFilter{})), + }, + }, } // FaultSetLinksSchema specifies the schema for fault set links diff --git a/powerflex/provider/fault_set_datasource_test.go b/powerflex/provider/fault_set_datasource_test.go index 2955f632..fe8e00d3 100644 --- a/powerflex/provider/fault_set_datasource_test.go +++ b/powerflex/provider/fault_set_datasource_test.go @@ -18,70 +18,117 @@ limitations under the License. package provider import ( + "fmt" + "os" "regexp" + "terraform-provider-powerflex/powerflex/helper" "testing" + . "github.com/bytedance/mockey" "github.com/hashicorp/terraform-plugin-testing/helper/resource" ) -var FaultSetDataSourceConfig1 = ` -data "powerflex_fault_set" "example" { -} -` - -// To-Do: Remove hard-coded values once fault set resource gets merged -var FaultSetDataSourceConfig2 = ` -data "powerflex_fault_set" "example" { - fault_set_ids = ["` + FaultSetID + `"] -} -` - -var FaultSetDataSourceConfig3 = ` -data "powerflex_fault_set" "example" { - fault_set_names = ["terraform_fault_set"] -} -` - -var FaultSetDataSourceConfig4 = ` -data "powerflex_fault_set" "example" { - fault_set_ids = ["invalid"] -} -` - -var FaultSetDataSourceConfig5 = ` -data "powerflex_fault_set" "example" { - fault_set_names = ["invalid"] +// AT +func TestAccDatasourceAcceptanceFaultSet(t *testing.T) { + if os.Getenv("TF_ACC") != "1" { + t.Skip("Dont run with units tests, this is an Accpetance test") + } + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: ProviderConfigForTesting + FaultSetDataSourceAll, + Check: resource.ComposeAggregateTestCheckFunc(), + }, + }, + }) } -` +// UT func TestAccDatasourceFaultSet(t *testing.T) { + if os.Getenv("TF_ACC") == "1" { + t.Skip("Dont run with acceptance tests, this is an Unit test") + } resource.Test(t, resource.TestCase{ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: ProviderConfigForTesting + FaultSetDataSourceConfig1, + Config: ProviderConfigForTesting + FaultSetDataSourceAll, Check: resource.ComposeAggregateTestCheckFunc(), }, + // Single Filter { - Config: ProviderConfigForTesting + FaultSetDataSourceConfig2, + Config: ProviderConfigForTesting + FaultSetDataSourceSingle, Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("data.powerflex_fault_set.example", "fault_set_details.0.id", FaultSetID), + resource.TestCheckResourceAttr("data.powerflex_fault_set.filter-single", "fault_set_details.0.protection_domain_id", "898f009900000000"), ), }, + // Multi Filter { - Config: ProviderConfigForTesting + FaultSetDataSourceConfig3, + Config: ProviderConfigForTesting + FaultSetDataSourceMultiple, Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("data.powerflex_fault_set.example", "fault_set_details.0.name", "terraform_fault_set"), + resource.TestCheckResourceAttr("data.powerflex_fault_set.filter-multiple", "fault_set_details.0.protection_domain_id", "898f009900000000"), + resource.TestCheckResourceAttr("data.powerflex_fault_set.filter-multiple", "fault_set_details.0.name", "fs1"), + resource.TestCheckResourceAttr("data.powerflex_fault_set.filter-multiple", "fault_set_details.1.protection_domain_id", "898f27a900000001"), + resource.TestCheckResourceAttr("data.powerflex_fault_set.filter-multiple", "fault_set_details.1.name", "terraform_fault_set"), ), }, + // Read System error + { + PreConfig: func() { + if FunctionMocker != nil { + FunctionMocker.UnPatch() + } + FunctionMocker = Mock(helper.GetFirstSystem).Return(nil, fmt.Errorf("Mock error")).Build() + }, + Config: ProviderConfigForTesting + FaultSetDataSourceAll, + ExpectError: regexp.MustCompile(`.*Unable to Read Powerflex System*.`), + }, + // Read Fault Set error { - Config: ProviderConfigForTesting + FaultSetDataSourceConfig4, - ExpectError: regexp.MustCompile(`.*Error in getting fault set details using id.*`), + PreConfig: func() { + if FunctionMocker != nil { + FunctionMocker.UnPatch() + } + FunctionMocker = Mock(helper.GetAllFaultSets, OptGeneric).Return(nil, fmt.Errorf("Mock error")).Build() + }, + Config: ProviderConfigForTesting + FaultSetDataSourceAll, + ExpectError: regexp.MustCompile(`.*Error in getting Fault Set details*.`), }, + // Filter error { - Config: ProviderConfigForTesting + FaultSetDataSourceConfig5, - ExpectError: regexp.MustCompile(`.*Error in getting fault set details using name.*`), + PreConfig: func() { + if FunctionMocker != nil { + FunctionMocker.UnPatch() + } + FunctionMocker = Mock(helper.GetDataSourceByValue).Return(nil, fmt.Errorf("Mock error")).Build() + }, + Config: ProviderConfigForTesting + FaultSetDataSourceMultiple, + ExpectError: regexp.MustCompile(`.*Error in filtering fault sets*.`), }, }, }) } + +var FaultSetDataSourceAll = ` +data "powerflex_fault_set" "all" { + +} +` + +var FaultSetDataSourceSingle = ` +data "powerflex_fault_set" "filter-single" { + filter { + protection_domain_id = ["898f009900000000"] + } +} +` + +var FaultSetDataSourceMultiple = ` +data "powerflex_fault_set" "filter-multiple" { + filter { + protection_domain_id = ["898f009900000000", "898f27a900000001"] + name = ["fs1", "terraform_fault_set"] + } +} +`