From deaa2cd2c252d6eafc70fc5814e4aee95c590fbe Mon Sep 17 00:00:00 2001 From: GitHub Terraform Date: Mon, 12 Feb 2024 23:07:41 -0800 Subject: [PATCH] feat: Added support to Policy Access Redirection rule resource --- CHANGELOG.md | 16 +- docs/guides/release-notes.md | 18 +- docs/resources/zpa_policy_redirection_rule.md | 106 ++++++++ .../zpa_policy_access_timeout_rule/README.md | 22 ++ .../zpa_policy_redirection_rule/README.md | 22 ++ examples/zpa_policy_redirection_rule/main.tf | 36 +++ examples/zpa_policy_type/datasource.tf | 34 ++- go.mod | 2 +- go.sum | 4 +- zpa/data_source_zpa_policy_type.go | 1 + zpa/provider.go | 1 + ...urce_zpa_policy_access_redirection_rule.go | 251 ++++++++++++++++++ 12 files changed, 496 insertions(+), 17 deletions(-) create mode 100644 docs/resources/zpa_policy_redirection_rule.md create mode 100644 examples/zpa_policy_access_timeout_rule/README.md create mode 100644 examples/zpa_policy_redirection_rule/README.md create mode 100644 examples/zpa_policy_redirection_rule/main.tf create mode 100644 zpa/resource_zpa_policy_access_redirection_rule.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 87517ea4..bf87a67d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,22 @@ # Changelog -## 3.1.0 (January, 17 2023) +## 3.10.0 (February, 13 2024) ### Notes -- Release date: **(January, 17 2023)** +- Release date: **(February, 13 2024)** +- Supported Terraform version: **v1.x** + +### Enhacements + +- [PR #418](https://github.com/zscaler/terraform-provider-zpa/pull/418) - ✨ Added support for ZPA Policy Access Redirection Rule + - **NOTE** This feature is in limited availability. Contact Zscaler Support to enable this feature for your organization. + +## 3.1.0 (January, 17 2024) + +### Notes + +- Release date: **(January, 17 2024)** - Supported Terraform version: **v1.x** ### Enhacements diff --git a/docs/guides/release-notes.md b/docs/guides/release-notes.md index 0cfb703c..043be6a6 100644 --- a/docs/guides/release-notes.md +++ b/docs/guides/release-notes.md @@ -12,15 +12,27 @@ Track all ZPA Terraform provider's releases. New resources, features, and bug fi --- -``Last updated: v3.1.0`` +``Last updated: v3.10.0`` --- -## 3.1.0 (January, 17 2023) - Unreleased +## 3.10.0 (February, 13 2024) ### Notes -- Release date: **(January, 17 2023)** +- Release date: **(February, 13 2024)** +- Supported Terraform version: **v1.x** + +### Enhacements + +- [PR #418](https://github.com/zscaler/terraform-provider-zpa/pull/418) - ✨ Added support for ZPA Policy Access Redirection Rule + - **NOTE** This feature is in limited availability. Contact Zscaler Support to enable this feature for your organization. + +## 3.1.0 (January, 17 2024) + +### Notes + +- Release date: **(January, 17 2024)** - Supported Terraform version: **v1.x** ### Enhacements diff --git a/docs/resources/zpa_policy_redirection_rule.md b/docs/resources/zpa_policy_redirection_rule.md new file mode 100644 index 00000000..ccaa2b8c --- /dev/null +++ b/docs/resources/zpa_policy_redirection_rule.md @@ -0,0 +1,106 @@ +--- +subcategory: "Policy Set Controller" +layout: "zscaler" +page_title: "ZPA: zpa_policy_redirection_rule" +description: |- + Creates and manages ZPA Policy Access Redirection Rule. +--- + +# Resource: zpa_policy_redirection_rule + +The **zpa_policy_redirection_rule** resource creates and manages policy access redirection rule in the Zscaler Private Access cloud. + + ⚠️ **WARNING:**: The attribute ``rule_order`` is now deprecated in favor of the new resource [``policy_access_rule_reorder``](zpa_policy_access_rule_reorder.md) + +## Example Usage + +```hcl +# Get Redirection Access Policy ID +data "zpa_policy_type" "this" { + policy_type = "REDIRECTION_POLICY" +} + +# Get Service Edge Group ID +data "zpa_service_edge_group" "this" { + name = "Example" +} + +#Create Policy Access Rule +resource "zpa_policy_redirection_rule" "this" { + name = "Example" + description = "Example" + action = "REDIRECT_ALWAYS" + operator = "AND" + policy_set_id = data.zpa_policy_type.this.id + + conditions { + negated = false + operator = "OR" + operands { + object_type = "CLIENT_TYPE" + lhs = "id" + rhs = "zpn_client_type_branch_connector" + } + operands { + object_type = "CLIENT_TYPE" + lhs = "id" + rhs = "zpn_client_type_edge_connector" + } + } + service_edge_groups { + id = [ data.zpa_service_edge_group.this.id ] + } +} +``` + +### Required + +* `name` - (Required) This is the name of the policy rule. +* `policy_set_id` - (Required) Use [zpa_policy_type](https://registry.terraform.io/providers/zscaler/zpa/latest/docs/data-sources/zpa_policy_type) data source to retrieve the necessary policy Set ID ``policy_set_id`` + +## Attributes Reference + +* `action` (Optional) This is for providing the rule action. Supported values: ``REDIRECT_DEFAULT``, ``REDIRECT_PREFERRED``, and ``REDIRECT_ALWAYS`` +* `description` (Optional) This is the description of the access policy rule. +* `operator` (Optional) Supported values: ``AND``, ``OR`` +* `rule_order` - (Deprecated) + + ⚠️ **WARNING:**: The attribute ``rule_order`` is now deprecated in favor of the new resource [``policy_access_rule_reorder``](zpa_policy_access_rule_reorder.md) + +* `conditions` - (Optional) + * `negated` - (Optional) Supported values: ``true`` or ``false`` + * `operator` (Optional) Supported values: ``AND``, and ``OR`` + + * `operands` (Optional) - Operands block must be repeated if multiple per `object_type` conditions are to be added to the rule. + * `name` (Optional) + * `lhs` (Optional) LHS must always carry the string value ``id`` or the attribute ID of the resource being associated with the rule. + * `rhs` (Optional) RHS is either the ID attribute of a resource or fixed string value. Refer to the chart below for further details. + * `idp_id` (Optional) + * `object_type` (Optional) This is for specifying the policy critiera. Supported values: `CLIENT_TYPE` + * `CLIENT_TYPE` (Optional) - The below options are the only ones supported in an access policy rule. + * `zpn_client_type_machine_tunnel` + * `zpn_client_type_edge_connector` + * `zpn_client_type_zapp` + * `zpn_client_type_branch_connector` + +* `service_edge_groups` + * `id` - (Optional) The ID of an service edge group resource + +## Import + +Zscaler offers a dedicated tool called Zscaler-Terraformer to allow the automated import of ZPA configurations into Terraform-compliant HashiCorp Configuration Language. +[Visit](https://github.com/zscaler/zscaler-terraformer) + +Policy access rule can be imported by using `` as the import ID. + +For example: + +```shell +terraform import zpa_policy_redirection_rule.example +``` + +## LHS and RHS Values + +| Object Type | LHS| RHS +|----------|-----------|---------- +| [CLIENT_TYPE](https://registry.terraform.io/providers/zscaler/zpa/latest/docs/data-sources/zpa_access_policy_client_types) | ``"id"`` | ``zpn_client_type_machine_tunnel``, ``zpn_client_type_edge_connector``, ``zpn_client_type_zapp``, ``zpn_client_type_branch_connector`` | diff --git a/examples/zpa_policy_access_timeout_rule/README.md b/examples/zpa_policy_access_timeout_rule/README.md new file mode 100644 index 00000000..754a1df2 --- /dev/null +++ b/examples/zpa_policy_access_timeout_rule/README.md @@ -0,0 +1,22 @@ +# Create Policy Timeout Rule + +This example will show you how to create a policy timeout rule. +This example codifies [this API](https://help.zscaler.com/zpa/api-reference#/policy-set-controller). + +To run, configure your ZPA provider as described [Here](https://github.com/zscaler/terraform-provider-zpa/blob/master/docs/index.md) + +## Run the example + +From inside of this directory: + +```bash +terraform init +terraform plan -out theplan +terraform apply theplan +``` + +## Destroy 💥 + +```bash +terraform destroy +``` diff --git a/examples/zpa_policy_redirection_rule/README.md b/examples/zpa_policy_redirection_rule/README.md new file mode 100644 index 00000000..0a030e25 --- /dev/null +++ b/examples/zpa_policy_redirection_rule/README.md @@ -0,0 +1,22 @@ +# Create Policy Redirection Rule + +This example will show you how to create a policy redirection rule to allow you to set criteria for preferring ZPA Private Service Edges over ZPA Public Service Edges +This example codifies [this API](https://help.zscaler.com/zpa/about-redirection-policy). + +To run, configure your ZPA provider as described [Here](https://github.com/zscaler/terraform-provider-zpa/blob/master/docs/index.md) + +## Run the example + +From inside of this directory: + +```bash +terraform init +terraform plan -out theplan +terraform apply theplan +``` + +## Destroy 💥 + +```bash +terraform destroy +``` diff --git a/examples/zpa_policy_redirection_rule/main.tf b/examples/zpa_policy_redirection_rule/main.tf new file mode 100644 index 00000000..59849529 --- /dev/null +++ b/examples/zpa_policy_redirection_rule/main.tf @@ -0,0 +1,36 @@ +data "zpa_policy_type" "this" { + policy_type = "REDIRECTION_POLICY" +} + + +data "zpa_service_edge_group" "this" { + name = "Example" +} + +resource "zpa_policy_redirection_rule" "this" { + name = "Example" + description = "Example" + action = "REDIRECT_ALWAYS" + operator = "AND" + policy_set_id = data.zpa_policy_type.this.id + + conditions { + negated = false + operator = "OR" + operands { + object_type = "CLIENT_TYPE" + lhs = "id" + rhs = "zpn_client_type_branch_connector" + } + operands { + object_type = "CLIENT_TYPE" + lhs = "id" + rhs = "zpn_client_type_edge_connector" + } + } + service_edge_groups { + id = [ data.zpa_service_edge_group.this.id ] + } +} + +// ZPA Private Service Edge groups must be empty when the Private Service Edge Selection Method is Default. \ No newline at end of file diff --git a/examples/zpa_policy_type/datasource.tf b/examples/zpa_policy_type/datasource.tf index 8152c776..5cf51bfb 100644 --- a/examples/zpa_policy_type/datasource.tf +++ b/examples/zpa_policy_type/datasource.tf @@ -3,14 +3,9 @@ data "zpa_policy_type" "access_policy" { policy_type = "ACCESS_POLICY" } -// Get information for "TIMEOUT_POLICY" ID -data "zpa_policy_type" "timeout_policy" { - policy_type = "TIMEOUT_POLICY" -} - -// Get information for "REAUTH_POLICY" ID -data "zpa_policy_type" "reauth_policy" { - policy_type = "REAUTH_POLICY" +// Get information for "CAPABILITIES_POLICY" ID +data "zpa_policy_type" "capabilities_policy" { + policy_type = "CAPABILITIES_POLICY" } // Get information for "CLIENT_FORWARDING_POLICY" ID @@ -18,6 +13,11 @@ data "zpa_policy_type" "client_forwarding_policy" { policy_type = "CLIENT_FORWARDING_POLICY" } +// Get information for "CREDENTIAL_POLICY" ID +data "zpa_policy_type" "credential_policy" { + policy_type = "CREDENTIAL_POLICY" +} + // Get information for "INSPECTION_POLICY" ID data "zpa_policy_type" "inspection_policy" { policy_type = "INSPECTION_POLICY" @@ -26,4 +26,20 @@ data "zpa_policy_type" "inspection_policy" { // Get information for "INSPECTION_POLICY" ID data "zpa_policy_type" "inspection_policy" { policy_type = "ISOLATION_POLICY" -} \ No newline at end of file +} + + +// Get information for "REAUTH_POLICY" ID +data "zpa_policy_type" "reauth_policy" { + policy_type = "REAUTH_POLICY" +} + +// Get information for "TIMEOUT_POLICY" ID +data "zpa_policy_type" "timeout_policy" { + policy_type = "TIMEOUT_POLICY" +} + +data "zpa_policy_type" "inspection_policy" { + policy_type = "REDIRECTION_POLICY" +} + diff --git a/go.mod b/go.mod index 22f8b60f..621fd657 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/hashicorp/terraform-plugin-docs v0.18.0 github.com/hashicorp/terraform-plugin-sdk v1.17.2 github.com/hashicorp/terraform-plugin-sdk/v2 v2.32.0 - github.com/zscaler/zscaler-sdk-go/v2 v2.3.8 + github.com/zscaler/zscaler-sdk-go/v2 v2.3.9 ) require ( diff --git a/go.sum b/go.sum index 3fd025ab..813e5e43 100644 --- a/go.sum +++ b/go.sum @@ -412,8 +412,8 @@ github.com/zclconf/go-cty v1.14.2 h1:kTG7lqmBou0Zkx35r6HJHUQTvaRPr5bIAf3AoHS0izI github.com/zclconf/go-cty v1.14.2/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= github.com/zclconf/go-cty-yaml v1.0.2/go.mod h1:IP3Ylp0wQpYm50IHK8OZWKMu6sPJIUgKa8XhiVHura0= -github.com/zscaler/zscaler-sdk-go/v2 v2.3.8 h1:ajdAHp0SSbY5BahC2EfQo/812v2QwpKaDjsnwtYSbAM= -github.com/zscaler/zscaler-sdk-go/v2 v2.3.8/go.mod h1:v8TLsPbVlQ3kAvGs8sIWsuhSAVggLbowiyDzaGYPWKg= +github.com/zscaler/zscaler-sdk-go/v2 v2.3.9 h1:7EcMIOKJqHABJonOdQEE/i4zjmGnZtxvr4O5woPJy9w= +github.com/zscaler/zscaler-sdk-go/v2 v2.3.9/go.mod h1:v8TLsPbVlQ3kAvGs8sIWsuhSAVggLbowiyDzaGYPWKg= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= diff --git a/zpa/data_source_zpa_policy_type.go b/zpa/data_source_zpa_policy_type.go index 26dfa089..76031977 100644 --- a/zpa/data_source_zpa_policy_type.go +++ b/zpa/data_source_zpa_policy_type.go @@ -62,6 +62,7 @@ func dataSourcePolicyType() *schema.Resource { "CLIENT_FORWARDING_POLICY", "BYPASS_POLICY", "ISOLATION_POLICY", "INSPECTION_POLICY", "SIEM_POLICY", "CREDENTIAL_POLICY", "CAPABILITIES_POLICY", + "REDIRECTION_POLICY", }, false), }, "rules": { diff --git a/zpa/provider.go b/zpa/provider.go index 62f7022f..deb29314 100644 --- a/zpa/provider.go +++ b/zpa/provider.go @@ -73,6 +73,7 @@ func ZPAProvider() *schema.Provider { "zpa_policy_timeout_rule": resourcePolicyTimeoutRule(), "zpa_policy_forwarding_rule": resourcePolicyForwardingRule(), "zpa_policy_isolation_rule": resourcePolicyIsolationRule(), + "zpa_policy_redirection_rule": resourcePolicyRedictionRule(), "zpa_provisioning_key": resourceProvisioningKey(), "zpa_service_edge_group": resourceServiceEdgeGroup(), "zpa_lss_config_controller": resourceLSSConfigController(), diff --git a/zpa/resource_zpa_policy_access_redirection_rule.go b/zpa/resource_zpa_policy_access_redirection_rule.go new file mode 100644 index 00000000..a098231d --- /dev/null +++ b/zpa/resource_zpa_policy_access_redirection_rule.go @@ -0,0 +1,251 @@ +package zpa + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + client "github.com/zscaler/zscaler-sdk-go/v2/zpa" + "github.com/zscaler/zscaler-sdk-go/v2/zpa/services/policysetcontroller" +) + +func resourcePolicyRedictionRule() *schema.Resource { + return &schema.Resource{ + Create: resourcePolicyRedictionRuleCreate, + Read: resourcePolicyRedictionRuleRead, + Update: resourcePolicyRedictionRuleUpdate, + Delete: resourcePolicyRedictionRuleDelete, + Importer: &schema.ResourceImporter{ + StateContext: importPolicyStateContextFunc([]string{"REDIRECTION_POLICY"}), + }, + + Schema: MergeSchema( + CommonPolicySchema(), + map[string]*schema.Schema{ + "action": { + Type: schema.TypeString, + Optional: true, + Description: " This is for providing the rule action.", + ValidateFunc: validation.StringInSlice([]string{ + "REDIRECT_DEFAULT", + "REDIRECT_PREFERRED", + "REDIRECT_ALWAYS", + }, false), + }, + "conditions": GetPolicyConditionsSchema([]string{ + "CLIENT_TYPE", + }), + "service_edge_groups": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Description: "List of the service edge group IDs.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + ), + } +} + +// validatePolicyRedirectionRuleAction validates the "action" attribute against "service_edge_groups" requirements. +func validatePolicyRedirectionRuleAction(d *schema.ResourceData) error { + action := d.Get("action").(string) + serviceEdgeGroups := d.Get("service_edge_groups").(*schema.Set).List() + + switch action { + case "REDIRECT_PREFERRED", "REDIRECT_ALWAYS": + if len(serviceEdgeGroups) == 0 { + return fmt.Errorf("one or more ZPA Private Service Edge groups must be selected when the Private Service Edge Selection Method is %s", action) + } + case "REDIRECT_DEFAULT": + if len(serviceEdgeGroups) > 0 { + return fmt.Errorf("zpa Private Service Edge groups must be empty when the Private Service Edge Selection Method is REDIRECT_DEFAULT") + } + } + + return nil +} + +func resourcePolicyRedictionRuleCreate(d *schema.ResourceData, m interface{}) error { + // Validate the "action" and "service_edge_groups" attributes + if err := validatePolicyRedirectionRuleAction(d); err != nil { + return err + } + + zClient := m.(*Client) + service := m.(*Client).policysetcontroller.WithMicroTenant(GetString(d.Get("microtenant_id"))) + + req, err := expandCreatePolicyRedirectionRule(d) + if err != nil { + return err + } + log.Printf("[INFO] Creating zpa policy redirection rule with request\n%+v\n", req) + if err := ValidateConditions(req.Conditions, zClient, req.MicroTenantID); err == nil { + policysetcontroller, _, err := service.Create(req) + if err != nil { + return err + } + d.SetId(policysetcontroller.ID) + + return resourcePolicyRedictionRuleRead(d, m) + } else { + return fmt.Errorf("couldn't validate the zpa policy redirection (%s) operands, please make sure you are using valid inputs for APP type, LHS & RHS", req.Name) + } +} + +func resourcePolicyRedictionRuleRead(d *schema.ResourceData, m interface{}) error { + service := m.(*Client).policysetcontroller.WithMicroTenant(GetString(d.Get("microtenant_id"))) + + globalPolicySet, _, err := service.GetByPolicyType("REDIRECTION_POLICY") + if err != nil { + return err + } + log.Printf("[INFO] Getting Policy Set Rule: globalPolicySet:%s id: %s\n", globalPolicySet.ID, d.Id()) + resp, _, err := service.GetPolicyRule(globalPolicySet.ID, d.Id()) + if err != nil { + if obj, ok := err.(*client.ErrorResponse); ok && obj.IsObjectNotFound() { + log.Printf("[WARN] Removing policy rule %s from state because it no longer exists in ZPA", d.Id()) + d.SetId("") + return nil + } + + return err + } + + log.Printf("[INFO] Got Policy Set Redirection Rule:\n%+v\n", resp) + d.SetId(resp.ID) + _ = d.Set("name", resp.Name) + _ = d.Set("description", resp.Description) + _ = d.Set("action", resp.Action) + _ = d.Set("operator", resp.Operator) + _ = d.Set("policy_set_id", resp.PolicySetID) + _ = d.Set("policy_type", resp.PolicyType) + _ = d.Set("conditions", flattenPolicyConditions(resp.Conditions)) + _ = d.Set("service_edge_groups", flattenPolicyRuleServiceEdgeGroups(resp.ServiceEdgeGroups)) + return nil +} + +func resourcePolicyRedictionRuleUpdate(d *schema.ResourceData, m interface{}) error { + + // Validate the "action" and "service_edge_groups" attributes + if err := validatePolicyRedirectionRuleAction(d); err != nil { + return err + } + + zClient := m.(*Client) + service := m.(*Client).policysetcontroller.WithMicroTenant(GetString(d.Get("microtenant_id"))) + globalPolicySet, _, err := service.GetByPolicyType("REDIRECTION_POLICY") + if err != nil { + return err + } + ruleID := d.Id() + log.Printf("[INFO] Updating policy redirection rule ID: %v\n", ruleID) + req, err := expandCreatePolicyRedirectionRule(d) + if err != nil { + return err + } + if err := ValidateConditions(req.Conditions, zClient, req.MicroTenantID); err == nil { + if _, _, err := service.GetPolicyRule(globalPolicySet.ID, ruleID); err != nil { + if respErr, ok := err.(*client.ErrorResponse); ok && respErr.IsObjectNotFound() { + d.SetId("") + return nil + } + } + + if _, err := service.Update(globalPolicySet.ID, ruleID, req); err != nil { + return err + } + + return resourcePolicyRedictionRuleRead(d, m) + } else { + return fmt.Errorf("couldn't validate the zpa policy redirection (%s) operands, please make sure you are using valid inputs for APP type, LHS & RHS", req.Name) + } +} + +func resourcePolicyRedictionRuleDelete(d *schema.ResourceData, m interface{}) error { + service := m.(*Client).policysetcontroller.WithMicroTenant(GetString(d.Get("microtenant_id"))) + globalPolicySet, _, err := service.GetByPolicyType("REDIRECTION_POLICY") + if err != nil { + return err + } + + log.Printf("[INFO] Deleting policy redirection rule with id %v\n", d.Id()) + + if _, err := service.Delete(globalPolicySet.ID, d.Id()); err != nil { + return err + } + + return nil +} + +func expandCreatePolicyRedirectionRule(d *schema.ResourceData) (*policysetcontroller.PolicyRule, error) { + policySetID, ok := d.Get("policy_set_id").(string) + if !ok { + return nil, fmt.Errorf("policy_set_id is not set") + } + log.Printf("[INFO] action_id:%v\n", d.Get("action_id")) + conditions, err := ExpandPolicyConditions(d) + if err != nil { + return nil, err + } + return &policysetcontroller.PolicyRule{ + ID: d.Get("id").(string), + Name: d.Get("name").(string), + Description: d.Get("description").(string), + Action: d.Get("action").(string), + ActionID: d.Get("action_id").(string), + CustomMsg: d.Get("custom_msg").(string), + Operator: d.Get("operator").(string), + PolicySetID: policySetID, + PolicyType: d.Get("policy_type").(string), + Priority: d.Get("priority").(string), + MicroTenantID: GetString(d.Get("microtenant_id")), + Conditions: conditions, + ServiceEdgeGroups: expandPolicysetControllerServiceEdgeGroups(d), + }, nil +} + +func expandPolicysetControllerServiceEdgeGroups(d *schema.ResourceData) []policysetcontroller.ServiceEdgeGroups { + serviceEdgeGroupsInterface, ok := d.GetOk("service_edge_groups") + if ok { + edgeGroup := serviceEdgeGroupsInterface.(*schema.Set) + log.Printf("[INFO] service edge groups data: %+v\n", edgeGroup) + var edgeGroups []policysetcontroller.ServiceEdgeGroups + for _, edgeGroup := range edgeGroup.List() { + edgeGroup, _ := edgeGroup.(map[string]interface{}) + if edgeGroup != nil { + for _, id := range edgeGroup["id"].(*schema.Set).List() { + edgeGroups = append(edgeGroups, policysetcontroller.ServiceEdgeGroups{ + ID: id.(string), + }) + } + } + } + return edgeGroups + } + + return []policysetcontroller.ServiceEdgeGroups{} +} + +func flattenPolicyRuleServiceEdgeGroups(serviceEdgeGroup []policysetcontroller.ServiceEdgeGroups) []interface{} { + result := make([]interface{}, 1) + mapIds := make(map[string]interface{}) + ids := make([]string, len(serviceEdgeGroup)) + for i, serviceEdgeGroup := range serviceEdgeGroup { + ids[i] = serviceEdgeGroup.ID + } + mapIds["id"] = ids + result[0] = mapIds + return result +}