From 62ea84750c1d14c1b0b0d41062ffcbf66f633221 Mon Sep 17 00:00:00 2001 From: Siddharth Kulshrestha Date: Fri, 25 Feb 2022 00:21:29 +0530 Subject: [PATCH 1/4] Added singular and plural datasources for service groups --- client/v3/v3_service.go | 8 +- client/v3/v3_structs.go | 2 +- nutanix/data_source_nutanix_service_group.go | 130 +++++++++++ nutanix/data_source_nutanix_service_groups.go | 216 ++++++++++++++++++ nutanix/provider.go | 2 + 5 files changed, 353 insertions(+), 5 deletions(-) create mode 100644 nutanix/data_source_nutanix_service_group.go create mode 100644 nutanix/data_source_nutanix_service_groups.go diff --git a/client/v3/v3_service.go b/client/v3/v3_service.go index 672819b72..3ce589c7b 100644 --- a/client/v3/v3_service.go +++ b/client/v3/v3_service.go @@ -109,7 +109,7 @@ type Service interface { UpdateRecoveryPlan(uuid string, body *RecoveryPlanInput) (*RecoveryPlanResponse, error) DeleteRecoveryPlan(uuid string) (*DeleteResponse, error) GetServiceGroup(uuid string) (*ServiceGroupResponse, error) - ListServiceGroups(getEntitiesRequest *DSMetadata) (*ServiceGroupListResponse, error) + listServiceGroups(getEntitiesRequest *DSMetadata) (*ServiceGroupListResponse, error) ListAllServiceGroups(filter string) (*ServiceGroupListResponse, error) CreateServiceGroup(request *ServiceGroupInput) (*Reference, error) UpdateServiceGroup(uuid string, body *ServiceGroupInput) error @@ -2262,7 +2262,7 @@ func (op Operations) DeleteServiceGroup(uuid string) error { func (op Operations) ListAllServiceGroups(filter string) (*ServiceGroupListResponse, error) { entities := make([]*ServiceGroupListEntry, 0) - resp, err := op.ListServiceGroups(&DSMetadata{ + resp, err := op.listServiceGroups(&DSMetadata{ Filter: &filter, Kind: utils.StringPtr("service_group"), Length: utils.Int64Ptr(itemsPerPage), @@ -2277,7 +2277,7 @@ func (op Operations) ListAllServiceGroups(filter string) (*ServiceGroupListRespo if totalEntities > itemsPerPage { for hasNext(&remaining) { - resp, err = op.ListServiceGroups(&DSMetadata{ + resp, err = op.listServiceGroups(&DSMetadata{ Filter: &filter, Kind: utils.StringPtr("service_group"), Length: utils.Int64Ptr(itemsPerPage), @@ -2300,7 +2300,7 @@ func (op Operations) ListAllServiceGroups(filter string) (*ServiceGroupListRespo return resp, nil } -func (op Operations) ListServiceGroups(getEntitiesRequest *DSMetadata) (*ServiceGroupListResponse, error) { +func (op Operations) listServiceGroups(getEntitiesRequest *DSMetadata) (*ServiceGroupListResponse, error) { ctx := context.TODO() path := "/service_groups/list" diff --git a/client/v3/v3_structs.go b/client/v3/v3_structs.go index 567609e77..ac50521af 100644 --- a/client/v3/v3_structs.go +++ b/client/v3/v3_structs.go @@ -2539,7 +2539,7 @@ type ServiceListEntry struct { type ServiceGroupListEntry struct { UUID *string `json:"uuid,omitempty"` ServiceGroup *ServiceGroupInput `json:"service_group,omitempty"` - AssociatedPoliciesList []*Reference `json:"associated_policies_list,omitempty"` + AssociatedPoliciesList []*ReferenceValues `json:"associated_policies_list,omitempty"` } type ServiceGroupInput struct { diff --git a/nutanix/data_source_nutanix_service_group.go b/nutanix/data_source_nutanix_service_group.go new file mode 100644 index 000000000..954cabf1f --- /dev/null +++ b/nutanix/data_source_nutanix_service_group.go @@ -0,0 +1,130 @@ +package nutanix + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-nutanix/utils" +) + +// dataSourceNutanixServiceGroup returns schema for datasource nutanix service group +// /v3/service_groups/{uuid} +// https://www.nutanix.dev/api_references/prism-central-v3/#/b3A6MjU1ODc2OTk-get-a-existing-service-group +func dataSourceNutanixServiceGroup() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceNutanixServiceGroupRead, + Schema: map[string]*schema.Schema{ + "uuid": { + Type: schema.TypeString, + Required: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "service_list": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "protocol": { + Type: schema.TypeString, + Computed: true, + }, + "icmp_type_code_list": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "tcp_port_range_list": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "end_port": { + Type: schema.TypeInt, + Computed: true, + }, + "start_port": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + "udp_port_range_list": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "end_port": { + Type: schema.TypeInt, + Computed: true, + }, + "start_port": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + "is_system_defined": { + Type: schema.TypeBool, + Description: "specifying whether it is a system defined service group", + Computed: true, + }, + }, + } +} + +func dataSourceNutanixServiceGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*Client).API + + if uuid, uuidOk := d.GetOk("uuid"); uuidOk { + svGroup, reqErr := conn.V3.GetServiceGroup(uuid.(string)) + + if reqErr != nil { + return diag.Errorf("error reading user with error %s", reqErr) + } + + if err := d.Set("name", utils.StringValue(svGroup.ServiceGroup.Name)); err != nil { + return diag.FromErr(err) + } + + if err := d.Set("description", utils.StringValue(svGroup.ServiceGroup.Description)); err != nil { + return diag.FromErr(err) + } + + if err := d.Set("is_system_defined", utils.BoolValue(svGroup.ServiceGroup.SystemDefined)); err != nil { + return diag.FromErr(err) + } + + if err := d.Set("service_list", flattenServiceEntry(svGroup.ServiceGroup)); err != nil { + return diag.FromErr(err) + } + + d.SetId(uuid.(string)) + } else { + return diag.Errorf("please provide `uuid`") + } + return nil +} diff --git a/nutanix/data_source_nutanix_service_groups.go b/nutanix/data_source_nutanix_service_groups.go new file mode 100644 index 000000000..c363c2725 --- /dev/null +++ b/nutanix/data_source_nutanix_service_groups.go @@ -0,0 +1,216 @@ +package nutanix + +import ( + "context" + + "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" + v3 "github.com/terraform-providers/terraform-provider-nutanix/client/v3" + "github.com/terraform-providers/terraform-provider-nutanix/utils" +) + +// dataSourceNutanixServiceGroups returns schema for datasource nutanix service groups +// https://www.nutanix.dev/api_references/prism-central-v3/#/b3A6MjU1ODc2OTg-list-the-service-groups +// v3/service_groups/list +func dataSourceNutanixServiceGroups() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceNutanixServiceGroupsRead, + Schema: map[string]*schema.Schema{ + "metadata": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "filter": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "kind": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "sort_order": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "offset": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "length": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "sort_attribute": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + }, + }, + }, + "entities": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "uuid": { + Type: schema.TypeString, + Computed: true, + }, + "service_group": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "service_list": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "protocol": { + Type: schema.TypeString, + Computed: true, + }, + "icmp_type_code_list": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "tcp_port_range_list": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "end_port": { + Type: schema.TypeInt, + Computed: true, + }, + "start_port": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + "udp_port_range_list": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "end_port": { + Type: schema.TypeInt, + Computed: true, + }, + "start_port": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + "is_system_defined": { + Type: schema.TypeBool, + Description: "specifying whether it is a system defined service group", + Computed: true, + }, + }, + }, + }, + "associated_policies_list": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "kind": { + Type: schema.TypeString, + Computed: true, + }, + "uuid": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func flattenServiceGroups(entries []*v3.ServiceGroupListEntry) interface{} { + entities := make([]map[string]interface{}, len(entries)) + for i, entry := range entries { + entities[i] = map[string]interface{}{ + "uuid": utils.StringValue(entry.UUID), + "service_group": []map[string]interface{}{ + { + "name": utils.StringValue(entry.ServiceGroup.Name), + "description": utils.StringValue(entry.ServiceGroup.Description), + "is_system_defined": utils.BoolValue(entry.ServiceGroup.SystemDefined), + "service_list": flattenServiceEntry(entry.ServiceGroup), + }, + }, + "associated_policies_list": flattenReferenceList(entry.AssociatedPoliciesList), + } + } + return entities +} + +func dataSourceNutanixServiceGroupsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*Client).API + + req := &v3.DSMetadata{} + + metadata, filtersOk := d.GetOk("metadata") + if filtersOk { + req = buildDataSourceListMetadata(metadata.(*schema.Set)) + } + + resp, err := conn.V3.ListAllServiceGroups(utils.StringValue(req.Filter)) + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set("entities", flattenServiceGroups(resp.Entities)); err != nil { + return diag.FromErr(err) + } + + d.SetId(resource.UniqueId()) + return nil +} diff --git a/nutanix/provider.go b/nutanix/provider.go index d66fa6ae8..8c99416cb 100644 --- a/nutanix/provider.go +++ b/nutanix/provider.go @@ -118,6 +118,8 @@ func Provider() *schema.Provider { "nutanix_recovery_plans": dataSourceNutanixRecoveryPlans(), "nutanix_address_groups": dataSourceNutanixAddressGroups(), "nutanix_address_group": dataSourceNutanixAddressGroup(), + "nutanix_service_group": dataSourceNutanixServiceGroup(), + "nutanix_service_groups": dataSourceNutanixServiceGroups(), }, ResourcesMap: map[string]*schema.Resource{ "nutanix_virtual_machine": resourceNutanixVirtualMachine(), From b2b0e8510aee65a2bdc4ca6f5241a7af65270084 Mon Sep 17 00:00:00 2001 From: Siddharth Kulshrestha Date: Fri, 25 Feb 2022 10:33:30 +0530 Subject: [PATCH 2/4] Added tests for datasource service groups. --- .../data_source_nutanix_service_group_test.go | 52 +++++++++++++++++++ ...data_source_nutanix_service_groups_test.go | 50 ++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 nutanix/data_source_nutanix_service_group_test.go create mode 100644 nutanix/data_source_nutanix_service_groups_test.go diff --git a/nutanix/data_source_nutanix_service_group_test.go b/nutanix/data_source_nutanix_service_group_test.go new file mode 100644 index 000000000..680d7bc18 --- /dev/null +++ b/nutanix/data_source_nutanix_service_group_test.go @@ -0,0 +1,52 @@ +package nutanix + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccNutanixServiceGroupDataSource_basic(t *testing.T) { + name := acctest.RandomWithPrefix("nutanix_service_gr") + description := "this is nutanix service group" + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccServiceGroupDataSourceConfig(name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.nutanix_service_group.service_group", "name", name), + resource.TestCheckResourceAttr("data.nutanix_service_group.service_group", "description", description), + resource.TestCheckResourceAttr("data.nutanix_service_group.service_group", "service_list.#", "1"), + resource.TestCheckResourceAttr("data.nutanix_service_group.service_group", "service_list.0.protocol", "TCP"), + ), + }, + }, + }) +} + +func testAccServiceGroupDataSourceConfig(name, description string) string { + return fmt.Sprintf(` + resource "nutanix_service_group" "test" { + name = "%[1]s" + description = "%[2]s" + + service_list { + protocol = "TCP" + tcp_port_range_list { + start_port = 22 + end_port = 22 + } + tcp_port_range_list { + start_port = 2222 + end_port = 2222 + } + } + + data "nutanix_service_group" "service_group" { + uuid = "${nutanix_address_group.test_address.id}" + }`, name, description) +} diff --git a/nutanix/data_source_nutanix_service_groups_test.go b/nutanix/data_source_nutanix_service_groups_test.go new file mode 100644 index 000000000..c9ff10bb3 --- /dev/null +++ b/nutanix/data_source_nutanix_service_groups_test.go @@ -0,0 +1,50 @@ +package nutanix + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccNutanixServiceGroupsDataSource_basic(t *testing.T) { + name := acctest.RandomWithPrefix("nutanix_service_gr") + description := "this is nutanix service group" + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccServiceGroupsDataSourceConfig(name, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.nutanix_service_groups.service_groups", "entities.0.service_group.name"), + resource.TestCheckResourceAttrSet("data.nutanix_service_groups.service_groups", "entities.0.service_group.description"), + resource.TestCheckResourceAttrSet("data.nutanix_service_groups.service_groups", "entities.0.uuid"), + ), + }, + }, + }) +} + +func testAccServiceGroupsDataSourceConfig(name, description string) string { + return fmt.Sprintf(` + resource "nutanix_service_group" "test" { + name = "%[1]s" + description = "%[2]s" + + service_list { + protocol = "TCP" + tcp_port_range_list { + start_port = 22 + end_port = 22 + } + tcp_port_range_list { + start_port = 2222 + end_port = 2222 + } + } + + data "nutanix_service_groups" "service_groups" {} + }`, name, description) +} From 544f26af37e563e35e708227d49bc478b7f5df91 Mon Sep 17 00:00:00 2001 From: Siddharth Kulshrestha Date: Sat, 26 Feb 2022 11:54:23 +0530 Subject: [PATCH 3/4] Fix --- .../data_source_nutanix_service_group_test.go | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/nutanix/data_source_nutanix_service_group_test.go b/nutanix/data_source_nutanix_service_group_test.go index 680d7bc18..c4f532b5a 100644 --- a/nutanix/data_source_nutanix_service_group_test.go +++ b/nutanix/data_source_nutanix_service_group_test.go @@ -30,23 +30,26 @@ func TestAccNutanixServiceGroupDataSource_basic(t *testing.T) { func testAccServiceGroupDataSourceConfig(name, description string) string { return fmt.Sprintf(` - resource "nutanix_service_group" "test" { - name = "%[1]s" - description = "%[2]s" + resource "nutanix_service_group" "test" { + name = "%[1]s" + description = "%[2]s" - service_list { - protocol = "TCP" - tcp_port_range_list { - start_port = 22 - end_port = 22 - } - tcp_port_range_list { - start_port = 2222 - end_port = 2222 - } - } - - data "nutanix_service_group" "service_group" { - uuid = "${nutanix_address_group.test_address.id}" - }`, name, description) + service_list { + protocol = "TCP" + tcp_port_range_list { + start_port = 22 + end_port = 22 + } + + tcp_port_range_list { + start_port = 2222 + end_port = 2222 + } + } + } + data "nutanix_service_group" "service_group" { + uuid = "${nutanix_service_group.test.id}" + } + + `, name, description) } From 2a2c6d0a6ae1bb151e81bcd5c378bb4489955829 Mon Sep 17 00:00:00 2001 From: Siddharth Kulshrestha Date: Sat, 26 Feb 2022 14:37:49 +0530 Subject: [PATCH 4/4] Fix --- ...data_source_nutanix_service_groups_test.go | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/nutanix/data_source_nutanix_service_groups_test.go b/nutanix/data_source_nutanix_service_groups_test.go index c9ff10bb3..283211362 100644 --- a/nutanix/data_source_nutanix_service_groups_test.go +++ b/nutanix/data_source_nutanix_service_groups_test.go @@ -18,8 +18,8 @@ func TestAccNutanixServiceGroupsDataSource_basic(t *testing.T) { { Config: testAccServiceGroupsDataSourceConfig(name, description), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.nutanix_service_groups.service_groups", "entities.0.service_group.name"), - resource.TestCheckResourceAttrSet("data.nutanix_service_groups.service_groups", "entities.0.service_group.description"), + resource.TestCheckResourceAttrSet("data.nutanix_service_groups.service_groups", "entities.0.service_group.0.name"), + resource.TestCheckResourceAttrSet("data.nutanix_service_groups.service_groups", "entities.0.service_group.0.description"), resource.TestCheckResourceAttrSet("data.nutanix_service_groups.service_groups", "entities.0.uuid"), ), }, @@ -30,21 +30,22 @@ func TestAccNutanixServiceGroupsDataSource_basic(t *testing.T) { func testAccServiceGroupsDataSourceConfig(name, description string) string { return fmt.Sprintf(` resource "nutanix_service_group" "test" { - name = "%[1]s" - description = "%[2]s" + name = "%[1]s" + description = "%[2]s" - service_list { - protocol = "TCP" - tcp_port_range_list { - start_port = 22 - end_port = 22 - } - tcp_port_range_list { - start_port = 2222 - end_port = 2222 - } + service_list { + protocol = "TCP" + tcp_port_range_list { + start_port = 22 + end_port = 22 + } + tcp_port_range_list { + start_port = 2222 + end_port = 2222 + } + } } data "nutanix_service_groups" "service_groups" {} - }`, name, description) + `, name, description) }