From 2f963e8897e659d9c535166c3b93720b8d8d975a Mon Sep 17 00:00:00 2001 From: Kobi Samoray Date: Tue, 21 Nov 2023 11:51:53 +0200 Subject: [PATCH] Implement DFW settings Exclusion list Signed-off-by: Kobi Samoray --- api/api_list.yaml | 17 +- .../firewall/security/policy_exclude_list.go | 118 +++++++++++++ nsxt/provider.go | 1 + ...sxt_policy_firewall_exclude_list_member.go | 144 ++++++++++++++++ ...olicy_firewall_exclude_list_member_test.go | 155 ++++++++++++++++++ ...firewall_exclude_list_member.html.markdown | 65 ++++++++ 6 files changed, 499 insertions(+), 1 deletion(-) create mode 100644 api/infra/settings/firewall/security/policy_exclude_list.go create mode 100644 nsxt/resource_nsxt_policy_firewall_exclude_list_member.go create mode 100644 nsxt/resource_nsxt_policy_firewall_exclude_list_member_test.go create mode 100644 website/docs/r/policy_firewall_exclude_list_member.html.markdown diff --git a/api/api_list.yaml b/api/api_list.yaml index 5d6c6cdea..4c0608aad 100644 --- a/api/api_list.yaml +++ b/api/api_list.yaml @@ -897,4 +897,19 @@ - Delete - Patch - Update - - List \ No newline at end of file + - List +- api_packages: + - client: github.com/vmware/vsphere-automation-sdk-go/services/nsxt/infra/settings/firewall/security + model: github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model + type: Local + - client: github.com/vmware/vsphere-automation-sdk-go/services/nsxt-gm/global_infra/settings/firewall/security + model: github.com/vmware/vsphere-automation-sdk-go/services/nsxt-gm/model + type: Global + model_name: PolicyExcludeList + obj_name: PolicyExcludeList + client_name: ExcludeListClient + supported_method: + - New + - Get + - Patch + - Update diff --git a/api/infra/settings/firewall/security/policy_exclude_list.go b/api/infra/settings/firewall/security/policy_exclude_list.go new file mode 100644 index 000000000..0f27fae93 --- /dev/null +++ b/api/infra/settings/firewall/security/policy_exclude_list.go @@ -0,0 +1,118 @@ +//nolint:revive +package security + +// The following file has been autogenerated. Please avoid any changes! +import ( + "errors" + + vapiProtocolClient_ "github.com/vmware/vsphere-automation-sdk-go/runtime/protocol/client" + client1 "github.com/vmware/vsphere-automation-sdk-go/services/nsxt-gm/global_infra/settings/firewall/security" + model1 "github.com/vmware/vsphere-automation-sdk-go/services/nsxt-gm/model" + client0 "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/infra/settings/firewall/security" + model0 "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + + utl "github.com/vmware/terraform-provider-nsxt/api/utl" +) + +type PolicyExcludeListClientContext utl.ClientContext + +func NewExcludeListClient(sessionContext utl.SessionContext, connector vapiProtocolClient_.Connector) *PolicyExcludeListClientContext { + var client interface{} + + switch sessionContext.ClientType { + + case utl.Local: + client = client0.NewExcludeListClient(connector) + + case utl.Global: + client = client1.NewExcludeListClient(connector) + + default: + return nil + } + return &PolicyExcludeListClientContext{Client: client, ClientType: sessionContext.ClientType, ProjectID: sessionContext.ProjectID} +} + +func (c PolicyExcludeListClientContext) Get() (model0.PolicyExcludeList, error) { + var obj model0.PolicyExcludeList + var err error + + switch c.ClientType { + + case utl.Local: + client := c.Client.(client0.ExcludeListClient) + obj, err = client.Get() + if err != nil { + return obj, err + } + + case utl.Global: + client := c.Client.(client1.ExcludeListClient) + gmObj, err1 := client.Get() + if err1 != nil { + return obj, err1 + } + var rawObj interface{} + rawObj, err = utl.ConvertModelBindingType(gmObj, model1.PolicyExcludeListBindingType(), model0.PolicyExcludeListBindingType()) + obj = rawObj.(model0.PolicyExcludeList) + + default: + return obj, errors.New("invalid infrastructure for model") + } + return obj, err +} + +func (c PolicyExcludeListClientContext) Patch(policyExcludeListParam model0.PolicyExcludeList) error { + var err error + + switch c.ClientType { + + case utl.Local: + client := c.Client.(client0.ExcludeListClient) + err = client.Patch(policyExcludeListParam) + + case utl.Global: + client := c.Client.(client1.ExcludeListClient) + gmObj, err1 := utl.ConvertModelBindingType(policyExcludeListParam, model0.PolicyExcludeListBindingType(), model1.PolicyExcludeListBindingType()) + if err1 != nil { + return err1 + } + err = client.Patch(gmObj.(model1.PolicyExcludeList)) + + default: + err = errors.New("invalid infrastructure for model") + } + return err +} + +func (c PolicyExcludeListClientContext) Update(policyExcludeListParam model0.PolicyExcludeList) (model0.PolicyExcludeList, error) { + var err error + var obj model0.PolicyExcludeList + + switch c.ClientType { + + case utl.Local: + client := c.Client.(client0.ExcludeListClient) + obj, err = client.Update(policyExcludeListParam) + + case utl.Global: + client := c.Client.(client1.ExcludeListClient) + gmObj, err := utl.ConvertModelBindingType(policyExcludeListParam, model0.PolicyExcludeListBindingType(), model1.PolicyExcludeListBindingType()) + if err != nil { + return obj, err + } + gmObj, err = client.Update(gmObj.(model1.PolicyExcludeList)) + if err != nil { + return obj, err + } + obj1, err1 := utl.ConvertModelBindingType(gmObj, model1.PolicyExcludeListBindingType(), model0.PolicyExcludeListBindingType()) + if err1 != nil { + return obj, err1 + } + obj = obj1.(model0.PolicyExcludeList) + + default: + err = errors.New("invalid infrastructure for model") + } + return obj, err +} diff --git a/nsxt/provider.go b/nsxt/provider.go index 255af54c1..57057e068 100644 --- a/nsxt/provider.go +++ b/nsxt/provider.go @@ -441,6 +441,7 @@ func Provider() *schema.Provider { "nsxt_policy_lb_http_application_profile": resourceNsxtPolicyLBHttpApplicationProfile(), "nsxt_policy_security_policy_rule": resourceNsxtPolicySecurityPolicyRule(), "nsxt_policy_parent_security_policy": resourceNsxtPolicyParentSecurityPolicy(), + "nsxt_policy_firewall_exclude_list_member": resourceNsxtPolicyFirewallExcludeListMember(), }, ConfigureFunc: providerConfigure, diff --git a/nsxt/resource_nsxt_policy_firewall_exclude_list_member.go b/nsxt/resource_nsxt_policy_firewall_exclude_list_member.go new file mode 100644 index 000000000..fc2f9ec8e --- /dev/null +++ b/nsxt/resource_nsxt_policy_firewall_exclude_list_member.go @@ -0,0 +1,144 @@ +/* Copyright © 2023 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: MPL-2.0 */ + +package nsxt + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + utl "github.com/vmware/terraform-provider-nsxt/api/utl" + "github.com/vmware/vsphere-automation-sdk-go/lib/vapi/std/errors" + "github.com/vmware/vsphere-automation-sdk-go/runtime/protocol/client" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" + + "github.com/vmware/terraform-provider-nsxt/api/infra/settings/firewall/security" +) + +func resourceNsxtPolicyFirewallExcludeListMember() *schema.Resource { + return &schema.Resource{ + Create: resourceNsxtPolicyFirewallExcludeListMemberCreate, + Read: resourceNsxtPolicyFirewallExcludeListMemberRead, + Delete: resourceNsxtPolicyFirewallExcludeListMemberDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "member": { + Type: schema.TypeString, + Description: "ExcludeList member", + Required: true, + ForceNew: true, + ValidateFunc: validatePolicyPath(), + }, + }, + } +} + +func memberInList(member string, members []string) int { + for i, mem := range members { + if mem == member { + return i + } + } + return -1 +} + +func resourceNsxtPolicyFirewallExcludeListMemberExists(sessionContext utl.SessionContext, id string, connector client.Connector) (bool, error) { + + client := security.NewExcludeListClient(sessionContext, connector) + obj, err := client.Get() + if isNotFoundError(err) { + return false, nil + } else if err != nil { + return false, err + } + if 0 <= memberInList(id, obj.Members) { + return true, nil + } + + return false, nil +} + +func resourceNsxtPolicyFirewallExcludeListMemberCreate(d *schema.ResourceData, m interface{}) error { + connector := getPolicyConnector(m) + member := d.Get("member").(string) + + doUpdate := func() error { + var obj model.PolicyExcludeList + + client := security.NewExcludeListClient(getSessionContext(d, m), connector) + obj, err := client.Get() + if isNotFoundError(err) { + obj = model.PolicyExcludeList{ + Members: []string{member}, + } + } else if err != nil { + return err + } + if 0 <= memberInList(member, obj.Members) { + return errors.AlreadyExists{} + } + obj.Members = append(obj.Members, member) + _, err = client.Update(obj) + if err != nil { + return err + } + + d.SetId(member) + + return nil + } + commonProviderConfig := getCommonProviderConfig(m) + err := retryUponPreconditionFailed(doUpdate, commonProviderConfig.MaxRetries) + if err != nil { + return handleCreateError("PolicyFirewallExcludeListMember", member, err) + } + + return resourceNsxtPolicyFirewallExcludeListMemberRead(d, m) +} + +func resourceNsxtPolicyFirewallExcludeListMemberRead(d *schema.ResourceData, m interface{}) error { + connector := getPolicyConnector(m) + member := d.Id() + + client := security.NewExcludeListClient(getSessionContext(d, m), connector) + obj, err := client.Get() + if err != nil { + return handleReadError(d, "PolicyFirewallExcludeListMember", member, err) + } + if 0 > memberInList(member, obj.Members) { + return errors.NotFound{} + } + d.Set("member", member) + return nil +} + +func resourceNsxtPolicyFirewallExcludeListMemberDelete(d *schema.ResourceData, m interface{}) error { + connector := getPolicyConnector(m) + member := d.Get("member").(string) + + doUpdate := func() error { + var obj model.PolicyExcludeList + + client := security.NewExcludeListClient(getSessionContext(d, m), connector) + obj, err := client.Get() + if isNotFoundError(err) { + return nil + } else if err != nil { + return err + } + i := memberInList(member, obj.Members) + if i < 0 { + return errors.NotFound{} + } + + obj.Members = append(obj.Members[:i], obj.Members[i+1:]...) + _, err = client.Update(obj) + return err + } + commonProviderConfig := getCommonProviderConfig(m) + err := retryUponPreconditionFailed(doUpdate, commonProviderConfig.MaxRetries) + if err != nil { + return handleDeleteError("PolicyFirewallExcludeListMember", member, err) + } + return nil +} diff --git a/nsxt/resource_nsxt_policy_firewall_exclude_list_member_test.go b/nsxt/resource_nsxt_policy_firewall_exclude_list_member_test.go new file mode 100644 index 000000000..762256755 --- /dev/null +++ b/nsxt/resource_nsxt_policy_firewall_exclude_list_member_test.go @@ -0,0 +1,155 @@ +/* Copyright © 2023 VMware, Inc. All Rights Reserved. + SPDX-License-Identifier: MPL-2.0 */ + +package nsxt + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func getGroupPrefix() string { + groupPrefix := "/infra/domains/default/groups/" + if testAccIsGlobalManager() { + groupPrefix = "/global-infra/domains/default/groups/" + } + return groupPrefix +} + +func TestAccResourceNsxtPolicyFirewallExcludeListMember_basic(t *testing.T) { + testResourcePfx := "nsxt_policy_firewall_exclude_list_member." + names := []string{getAccTestResourceName(), getAccTestResourceName(), getAccTestResourceName(), getAccTestResourceName()} + groupPrefix := getGroupPrefix() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: func(state *terraform.State) error { + for _, name := range names { + err := testAccNsxtPolicyFirewallExcludeListMemberCheckDestroy(state, groupPrefix+name) + if err != nil { + return err + } + } + return nil + }, + Steps: []resource.TestStep{ + { + // Add resource + Config: testAccNsxtPolicyFirewallExcludeListMemberTemplate(names[0]), + Check: resource.ComposeTestCheckFunc( + testAccNsxtPolicyFirewallExcludeListMemberExists(names[0], testResourcePfx+names[0]), + resource.TestCheckResourceAttr(testResourcePfx+names[0], "member", groupPrefix+names[0]), + ), + }, + { + // Additional resource + Config: testAccNsxtPolicyFirewallExcludeListMemberTemplate(names[1]), + Check: resource.ComposeTestCheckFunc( + testAccNsxtPolicyFirewallExcludeListMemberExists(names[1], testResourcePfx+names[1]), + resource.TestCheckResourceAttr(testResourcePfx+names[1], "member", groupPrefix+names[1]), + ), + }, + { + // Two more concurrently + Config: testAccNsxtPolicyFirewallExcludeListMemberTemplate(names[2]) + testAccNsxtPolicyFirewallExcludeListMemberTemplate(names[3]), + Check: resource.ComposeTestCheckFunc( + testAccNsxtPolicyFirewallExcludeListMemberExists(names[2], testResourcePfx+names[2]), + testAccNsxtPolicyFirewallExcludeListMemberExists(names[3], testResourcePfx+names[3]), + resource.TestCheckResourceAttr(testResourcePfx+names[2], "member", groupPrefix+names[2]), + resource.TestCheckResourceAttr(testResourcePfx+names[3], "member", groupPrefix+names[3]), + ), + }, + }, + }) +} + +func TestAccResourceNsxtPolicyFirewallExcludeListMember_importBasic(t *testing.T) { + name := getAccTestResourceName() + testResourceName := "nsxt_policy_firewall_exclude_list_member." + name + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: func(state *terraform.State) error { + return testAccNsxtPolicyFirewallExcludeListMemberCheckDestroy(state, getGroupPrefix()+name) + }, + Steps: []resource.TestStep{ + { + Config: testAccNsxtPolicyFirewallExcludeListMemberTemplate(name), + }, + { + ResourceName: testResourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccNsxtPolicyFirewallExcludeListMemberExists(displayName string, resourceName string) resource.TestCheckFunc { + return func(state *terraform.State) error { + + connector := getPolicyConnector(testAccProvider.Meta().(nsxtClients)) + + rs, ok := state.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("policy FirewallExcludeListMember resource %s not found in resources", resourceName) + } + + resourceID := rs.Primary.ID + if resourceID == "" { + return fmt.Errorf("policy FirewallExcludeListMember resource ID not set in resources") + } + + exists, err := resourceNsxtPolicyFirewallExcludeListMemberExists(testAccGetSessionContext(), resourceID, connector) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("policy FirewallExcludeListMember %s does not exist", resourceID) + } + + return nil + } +} + +func testAccNsxtPolicyFirewallExcludeListMemberCheckDestroy(state *terraform.State, member string) error { + connector := getPolicyConnector(testAccProvider.Meta().(nsxtClients)) + for _, rs := range state.RootModule().Resources { + + if rs.Type != "nsxt_policy_firewall_exclude_list_member" { + continue + } + + exists, err := resourceNsxtPolicyFirewallExcludeListMemberExists(testAccGetSessionContext(), member, connector) + if err == nil { + return err + } + + if exists { + return fmt.Errorf("policy FirewallExcludeListMember %s still exists", member) + } + } + return nil +} + +func testAccNsxtPolicyFirewallExcludeListMemberTemplate(name string) string { + return fmt.Sprintf(` +resource "nsxt_policy_group" "%s" { + nsx_id = "%s" + display_name = "%s" + description = "Acceptance Test" +} +resource "nsxt_policy_firewall_exclude_list_member" "%s" { + member = nsxt_policy_group.%s.path +} +`, name, name, name, name, name) +} diff --git a/website/docs/r/policy_firewall_exclude_list_member.html.markdown b/website/docs/r/policy_firewall_exclude_list_member.html.markdown new file mode 100644 index 000000000..9b5371d1c --- /dev/null +++ b/website/docs/r/policy_firewall_exclude_list_member.html.markdown @@ -0,0 +1,65 @@ +--- +subcategory: "Firewall" +layout: "nsxt" +page_title: "NSXT: nsxt_policy_firewall_exclude_list_member" +description: A resource to configure a member within the firewall exclude list. +--- + +# nsxt_policy_firewall_exclude_list_member + +This resource provides a method for the management of a firewall exclude list members. + +This resource is applicable to NSX Global Manager, NSX Policy Manager and VMC. + +## Example Usage + +```hcl +resource "nsxt_policy_group" "testgroup" { + display_name = "Terraform created test group" + description = "Group for testing purposes" +} + +resource "nsxt_policy_firewall_exclude_list_member" "excludetestgroup" { + member = nsxt_policy_group.testgroup.path +} +``` + +## Example Usage - Multi-Tenancy + +```hcl +data "nsxt_policy_project" "demoproj" { + display_name = "demoproj" +} + +resource "nsxt_policy_group" "testgroup" { + context { + project_id = data.nsxt_policy_project.demoproj.id + } + display_name = "Terraform created test group" + description = "Group for testing purposes" +} + +resource "nsxt_policy_firewall_exclude_list_member" "excludetestgroup" { + context { + project_id = data.nsxt_policy_project.demoproj.id + } + member = nsxt_policy_group.testgroup.path +} +``` + +## Argument Reference + +The following arguments are supported: + +* `member` - Exclusion list member policy path + +## Importing + +An existing exclude list member can be [imported][docs-import] into this resource, via the following command: + +[docs-import]: https://www.terraform.io/cli/import + +``` +terraform import nsxt_policy_firewall_exclude_list_member.test POLICY_PATH +``` +The above command imports the exclude list member named `test` with policy path `POLICY_PATH`.