From f0d9ed3a9034b5642b9cc4af6b6d0430ded2ad5b Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Tue, 29 Mar 2022 14:07:05 +0300 Subject: [PATCH 1/7] Self-review Signed-off-by: Dainius Serplis --- .changes/v2.15.0/XXX-features.md | 5 + govcd/nsxt_distributed_firewall.go | 82 ++++++ govcd/nsxt_distributed_firewall_test.go | 274 +++++++++++++++++++++ govcd/nsxt_network_context_profile.go | 77 ++++++ govcd/nsxt_network_context_profile_test.go | 72 ++++++ govcd/openapi_endpoints.go | 7 + types/v56/constants.go | 2 + types/v56/nsxt_types.go | 98 ++++++++ 8 files changed, 617 insertions(+) create mode 100644 .changes/v2.15.0/XXX-features.md create mode 100644 govcd/nsxt_distributed_firewall.go create mode 100644 govcd/nsxt_distributed_firewall_test.go create mode 100644 govcd/nsxt_network_context_profile.go create mode 100644 govcd/nsxt_network_context_profile_test.go diff --git a/.changes/v2.15.0/XXX-features.md b/.changes/v2.15.0/XXX-features.md new file mode 100644 index 000000000..1ea535546 --- /dev/null +++ b/.changes/v2.15.0/XXX-features.md @@ -0,0 +1,5 @@ +* Add support for for Network Context Profile lookup using `GetAllNetworkContextProfiles` and + `GetNetworkContextProfilesByNameScopeAndContext` functions [GH-XXX] +* Add support for NSX-T Distributed Firewall rule management using type `DistributedFirewall` and +`GetDistributedFirewall`, `UpdateDistributedFirewall`, `DeleteAllDistributedFirewallRules`, +`DeleteAllRules` [GH-XXX] diff --git a/govcd/nsxt_distributed_firewall.go b/govcd/nsxt_distributed_firewall.go new file mode 100644 index 000000000..a612de4bd --- /dev/null +++ b/govcd/nsxt_distributed_firewall.go @@ -0,0 +1,82 @@ +package govcd + +import ( + "errors" + "fmt" + + "github.com/vmware/go-vcloud-director/v2/types/v56" +) + +// DistributedFirewall contains a types.DfwFirewallRule +type DistributedFirewall struct { + DistributedFirewallRuleContainer *types.DistributedFirewallRules + client *Client + VdcGroup *VdcGroup +} + +func (vdcGroup *VdcGroup) GetDistributedFirewall() (*DistributedFirewall, error) { + client := vdcGroup.client + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroupsDfwRules + apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint) + if err != nil { + return nil, err + } + + urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, vdcGroup.VdcGroup.Id, "default")) + if err != nil { + return nil, err + } + + returnObject := &DistributedFirewall{ + DistributedFirewallRuleContainer: &types.DistributedFirewallRules{}, + client: client, + VdcGroup: vdcGroup, + } + + err = client.OpenApiGetItem(apiVersion, urlRef, nil, returnObject.DistributedFirewallRuleContainer, nil) + if err != nil { + return nil, fmt.Errorf("error retrieving Distributed Firewall rules: %s", err) + } + + return returnObject, nil +} + +func (vdcGroup *VdcGroup) UpdateDistributedFirewall(dfwRules *types.DistributedFirewallRules) (*DistributedFirewall, error) { + client := vdcGroup.client + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroupsDfwRules + apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint) + if err != nil { + return nil, err + } + + urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, vdcGroup.VdcGroup.Id, "default")) + if err != nil { + return nil, err + } + + returnObject := &DistributedFirewall{ + DistributedFirewallRuleContainer: &types.DistributedFirewallRules{}, + client: client, + VdcGroup: vdcGroup, + } + + err = client.OpenApiPutItem(apiVersion, urlRef, nil, dfwRules, returnObject.DistributedFirewallRuleContainer, nil) + if err != nil { + return nil, fmt.Errorf("error setting Distributed Firewall rules: %s", err) + } + + return returnObject, nil +} + +func (vdcGroup *VdcGroup) DeleteAllDistributedFirewallRules() error { + _, err := vdcGroup.UpdateDistributedFirewall(&types.DistributedFirewallRules{}) + return err +} + +func (firewall *DistributedFirewall) DeleteAllRules() error { + if firewall.VdcGroup != nil && firewall.VdcGroup.VdcGroup != nil && firewall.VdcGroup.VdcGroup.Id == "" { + return errors.New("empty VDC Group ID for parent VDC Group") + } + + return firewall.VdcGroup.DeleteAllDistributedFirewallRules() +} diff --git a/govcd/nsxt_distributed_firewall_test.go b/govcd/nsxt_distributed_firewall_test.go new file mode 100644 index 000000000..9b1787bd3 --- /dev/null +++ b/govcd/nsxt_distributed_firewall_test.go @@ -0,0 +1,274 @@ +//go:build network || nsxt || functional || openapi || ALL +// +build network nsxt functional openapi ALL + +package govcd + +import ( + "fmt" + "os" + "strconv" + "strings" + "text/tabwriter" + + "github.com/vmware/go-vcloud-director/v2/types/v56" + . "gopkg.in/check.v1" +) + +// Test_NsxtDistributedFirewall creates a list of distributed firewall rules with randomized parameters +func (vcd *TestVCD) Test_NsxtDistributedFirewallRules(check *C) { + skipNoNsxtConfiguration(vcd, check) + skipOpenApiEndpointTest(vcd, check, types.OpenApiPathVersion1_0_0+types.OpenApiEndpointEdgeGateways) + + adminOrg, err := vcd.client.GetAdminOrgByName(vcd.config.VCD.Org) + check.Assert(adminOrg, NotNil) + check.Assert(err, IsNil) + + nsxtExternalNetwork, err := GetExternalNetworkV2ByName(vcd.client, vcd.config.VCD.Nsxt.ExternalNetwork) + check.Assert(nsxtExternalNetwork, NotNil) + check.Assert(err, IsNil) + + vdc, vdcGroup := test_CreateVdcGroup(check, adminOrg, vcd) + check.Assert(vdc, NotNil) + check.Assert(vdcGroup, NotNil) + + _, err = vdcGroup.ActivateDfw() + check.Assert(err, IsNil) + + // Get existing firewall rule configuration + fwRules, err := vdcGroup.GetDistributedFirewall() + check.Assert(err, IsNil) + check.Assert(fwRules.DistributedFirewallRuleContainer.Values, NotNil) + + // Create some prerequisites and generate firewall rule configurations to feed them into config + randomizedFwRuleDefs, ipSet, secGroup := createDistributedFirewallDefinitions(check, vcd, vdcGroup.VdcGroup.Id) + + // Add IP Set and to cleanup list + openApiEndpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointFirewallGroups + ipSet.NsxtFirewallGroup.ID + PrependToCleanupListOpenApi(ipSet.NsxtFirewallGroup.Name, check.TestName(), openApiEndpoint) + openApiEndpoint = types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointFirewallGroups + secGroup.NsxtFirewallGroup.ID + PrependToCleanupListOpenApi(secGroup.NsxtFirewallGroup.Name, check.TestName(), openApiEndpoint) + + fwRules.DistributedFirewallRuleContainer.Values = randomizedFwRuleDefs + + if testVerbose { + dumpDistributedFirewallRulesToScreen(randomizedFwRuleDefs) + } + + fwUpdated, err := vdcGroup.UpdateDistributedFirewall(fwRules.DistributedFirewallRuleContainer) + check.Assert(err, IsNil) + check.Assert(fwUpdated, Not(IsNil)) + + check.Assert(len(fwUpdated.DistributedFirewallRuleContainer.Values), Equals, len(randomizedFwRuleDefs)) + + // Check that all created rules are have the same attributes and order + for index := range fwUpdated.DistributedFirewallRuleContainer.Values { + check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].Name, Equals, randomizedFwRuleDefs[index].Name) + check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].Direction, Equals, randomizedFwRuleDefs[index].Direction) + check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].IpProtocol, Equals, randomizedFwRuleDefs[index].IpProtocol) + check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].Enabled, Equals, randomizedFwRuleDefs[index].Enabled) + check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].Logging, Equals, randomizedFwRuleDefs[index].Logging) + check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].Comments, Equals, randomizedFwRuleDefs[index].Comments) + + // API V 35.2 uses ActionValue field instead of deprecated `Action` + if vcd.client.Client.APIVCDMaxVersionIs(">= 35.2") { + check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].ActionValue, Equals, randomizedFwRuleDefs[index].ActionValue) + } else { + check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].Action, Equals, randomizedFwRuleDefs[index].Action) + } + + for fwGroupIndex := range fwUpdated.DistributedFirewallRuleContainer.Values[index].SourceFirewallGroups { + check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].SourceFirewallGroups[fwGroupIndex].ID, Equals, randomizedFwRuleDefs[index].SourceFirewallGroups[fwGroupIndex].ID) + } + + for fwGroupIndex := range fwUpdated.DistributedFirewallRuleContainer.Values[index].DestinationFirewallGroups { + check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].DestinationFirewallGroups[fwGroupIndex].ID, Equals, randomizedFwRuleDefs[index].DestinationFirewallGroups[fwGroupIndex].ID) + } + + // Ensure the same amount of Application Port Profiles are assigned and created + check.Assert(len(fwUpdated.DistributedFirewallRuleContainer.Values), Equals, len(randomizedFwRuleDefs)) + definedAppPortProfileIds := extractIdsFromOpenApiReferences(randomizedFwRuleDefs[index].ApplicationPortProfiles) + for _, appPortProfile := range fwUpdated.DistributedFirewallRuleContainer.Values[index].ApplicationPortProfiles { + check.Assert(contains(appPortProfile.ID, definedAppPortProfileIds), Equals, true) + } + + // Ensure the same amount of Network Context Profiles are assigned and created + definedNetContextProfileIds := extractIdsFromOpenApiReferences(randomizedFwRuleDefs[index].NetworkContextProfiles) + for _, networkContextProfile := range fwUpdated.DistributedFirewallRuleContainer.Values[index].NetworkContextProfiles { + check.Assert(contains(networkContextProfile.ID, definedNetContextProfileIds), Equals, true) + } + } + + // Cleanup + err = fwRules.DeleteAllRules() + check.Assert(err, IsNil) + // Check that rules were removed + newRules, err := vdcGroup.GetDistributedFirewall() + check.Assert(err, IsNil) + check.Assert(len(newRules.DistributedFirewallRuleContainer.Values) == 0, Equals, true) + + // Cleanup remaining setup + _, err = vdcGroup.DisableDefaultPolicy() + check.Assert(err, IsNil) + _, err = vdcGroup.DeactivateDfw() + check.Assert(err, IsNil) + err = ipSet.Delete() + check.Assert(err, IsNil) + err = secGroup.Delete() + check.Assert(err, IsNil) + err = vdcGroup.Delete() + check.Assert(err, IsNil) + err = vdc.DeleteWait(true, true) + check.Assert(err, IsNil) +} + +// createDistributedFirewallDefinitions creates some randomized firewall rule configurations to match possible configurations +func createDistributedFirewallDefinitions(check *C, vcd *TestVCD, vdcGroupId string) ([]*types.DistributedFirewallRule, *NsxtFirewallGroup, *NsxtFirewallGroup) { + // This number does not impact performance because all rules are created at once in the API + numberOfRules := 40 + + // Pre-Create Firewall Groups (IP Set and Security Group to randomly configure them) + ipSet := preCreateVdcGroupIpSet(check, vcd, vdcGroupId) + secGroup := preCreateVdcGroupSecurityGroup(check, vcd, vdcGroupId) + fwGroupIds := []string{ipSet.NsxtFirewallGroup.ID, secGroup.NsxtFirewallGroup.ID} + fwGroupRefs := convertSliceOfStringsToOpenApiReferenceIds(fwGroupIds) + appPortProfileReferences := getRandomListOfAppPortProfiles(check, vcd) + networkContextProfiles := getRandomListOfNetworkContextProfiles(check, vcd) + // _ = getRandomListOfNetworkContextProfiles(check, vcd) + + firewallRules := make([]*types.DistributedFirewallRule, numberOfRules) + for a := 0; a < numberOfRules; a++ { + + // Feed in empty value for source and destination or a firewall group + src := pickRandomOpenApiRefOrEmpty(fwGroupRefs) + var srcValue []types.OpenApiReference + dst := pickRandomOpenApiRefOrEmpty(fwGroupRefs) + var dstValue []types.OpenApiReference + if src != (types.OpenApiReference{}) { + srcValue = []types.OpenApiReference{src} + } + if dst != (types.OpenApiReference{}) { + dstValue = []types.OpenApiReference{dst} + } + + firewallRules[a] = &types.DistributedFirewallRule{ + Name: check.TestName() + strconv.Itoa(a), + Action: pickRandomString([]string{"ALLOW", "DROP"}), + Enabled: a%2 == 0, + SourceFirewallGroups: srcValue, + DestinationFirewallGroups: dstValue, + ApplicationPortProfiles: appPortProfileReferences[0:a], + IpProtocol: pickRandomString([]string{"IPV6", "IPV4", "IPV4_IPV6"}), + Logging: a%2 == 1, + Direction: pickRandomString([]string{"IN", "OUT", "IN_OUT"}), + } + + // Network Context Profile can usually work with up to one Application Profile therefore this + // needs to be explicitly preset + if a%5 == 1 { // Every fifth rule + netCtxProfile := networkContextProfiles[0:a] + networkContextProfile := make([]types.OpenApiReference, 0) + for _, netCtxProf := range netCtxProfile { + if netCtxProf.ID != "" { + networkContextProfile = append(networkContextProfile, types.OpenApiReference{ID: netCtxProf.ID}) + } + } + + firewallRules[a].NetworkContextProfiles = networkContextProfile + // firewallRules[a].ApplicationPortProfiles = appPortProfileReferences[0:1] + firewallRules[a].ApplicationPortProfiles = nil + + } + + // API V35.2 introduced new field ActionValue instead of deprecated Action + if vcd.client.Client.APIVCDMaxVersionIs(">= 35.2") { + firewallRules[a].Action = "" + firewallRules[a].ActionValue = pickRandomString([]string{"ALLOW", "DROP", "REJECT"}) + } + + // API V36.2 introduced new field Comment which is shown in UI + if vcd.client.Client.APIVCDMaxVersionIs(">= 36.2") { + firewallRules[a].Comments = "Comment Rule" + } + + } + + return firewallRules, ipSet, secGroup +} + +func preCreateVdcGroupIpSet(check *C, vcd *TestVCD, ownerId string) *NsxtFirewallGroup { + nsxtVdc := vcd.nsxtVdc + + ipSetDefinition := &types.NsxtFirewallGroup{ + Name: check.TestName() + "ipset", + Description: check.TestName() + "-Description", + Type: types.FirewallGroupTypeIpSet, + OwnerRef: &types.OpenApiReference{ID: ownerId}, + + IpAddresses: []string{ + "12.12.12.1", + "10.10.10.0/24", + "11.11.11.1-11.11.11.2", + // represents the block of IPv6 addresses from 2001:db8:0:0:0:0:0:0 to 2001:db8:0:ffff:ffff:ffff:ffff:ffff + "2001:db8::/48", + "2001:db6:0:0:0:0:0:0-2001:db6:0:ffff:ffff:ffff:ffff:ffff", + }, + } + + // Create IP Set and add to cleanup if it was created + createdIpSet, err := nsxtVdc.CreateNsxtFirewallGroup(ipSetDefinition) + check.Assert(err, IsNil) + openApiEndpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointFirewallGroups + createdIpSet.NsxtFirewallGroup.ID + AddToCleanupListOpenApi(createdIpSet.NsxtFirewallGroup.Name, check.TestName(), openApiEndpoint) + + return createdIpSet +} + +func preCreateVdcGroupSecurityGroup(check *C, vcd *TestVCD, ownerId string) *NsxtFirewallGroup { + nsxtVdc := vcd.nsxtVdc + + fwGroupDefinition := &types.NsxtFirewallGroup{ + Name: check.TestName() + "security-group", + Description: check.TestName() + "-Description", + Type: types.FirewallGroupTypeSecurityGroup, + OwnerRef: &types.OpenApiReference{ID: ownerId}, + } + + // Create firewall group and add to cleanup if it was created + createdSecGroup, err := nsxtVdc.CreateNsxtFirewallGroup(fwGroupDefinition) + check.Assert(err, IsNil) + openApiEndpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointFirewallGroups + createdSecGroup.NsxtFirewallGroup.ID + AddToCleanupListOpenApi(createdSecGroup.NsxtFirewallGroup.Name, check.TestName(), openApiEndpoint) + + return createdSecGroup +} + +func dumpDistributedFirewallRulesToScreen(rules []*types.DistributedFirewallRule) { + fmt.Println("# The following firewall rules will be created") + w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0) + fmt.Fprintln(w, "Name\tDirection\tIP Protocol\tEnabled\tAction\tLogging\tSrc Count\tDst Count\tAppPortProfile Count\tNet Context Profile Count") + + for _, rule := range rules { + fmt.Fprintf(w, "%s\t%s\t%s\t%t\t%s\t%t\t%d\t%d\t%d\t%d\n", rule.Name, rule.Direction, rule.IpProtocol, + rule.Enabled, rule.Action, rule.Logging, len(rule.SourceFirewallGroups), len(rule.DestinationFirewallGroups), len(rule.ApplicationPortProfiles), len(rule.NetworkContextProfiles)) + } + w.Flush() +} + +func getRandomListOfNetworkContextProfiles(check *C, vcd *TestVCD) []types.OpenApiReference { + networkContextProfiles, err := GetAllNetworkContextProfiles(&vcd.client.Client, nil) + check.Assert(err, IsNil) + openApiRefs := make([]types.OpenApiReference, 1) + for _, networkContextProfile := range networkContextProfiles { + if strings.Contains(networkContextProfile.Description, "ALG") { + continue + } + openApiRef := types.OpenApiReference{ + ID: networkContextProfile.ID, + Name: networkContextProfile.Name, + } + + openApiRefs = append(openApiRefs, openApiRef) + } + + return openApiRefs +} diff --git a/govcd/nsxt_network_context_profile.go b/govcd/nsxt_network_context_profile.go new file mode 100644 index 000000000..cf9b84927 --- /dev/null +++ b/govcd/nsxt_network_context_profile.go @@ -0,0 +1,77 @@ +package govcd + +import ( + "fmt" + "net/url" + + "github.com/vmware/go-vcloud-director/v2/types/v56" +) + +// GetAllNetworkContextProfiles retrieves a slice of types.NsxtNetworkContextProfile +// This function requires at least a filter value for 'context_id' which can be one of: +// * Org VDC ID - to get Network Context Profiles scoped for VDC +// * Network provider ID - to get Network Context Profiles scoped for attached NSX-T environment +// * VDC Group ID - to get Network Context Profiles scoped for attached NSX-T environment +func GetAllNetworkContextProfiles(client *Client, queryParameters url.Values) ([]*types.NsxtNetworkContextProfile, error) { + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointNetworkContextProfiles + apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint) + if err != nil { + return nil, err + } + + urlRef, err := client.OpenApiBuildEndpoint(endpoint) + if err != nil { + return nil, err + } + + typeResponses := []*types.NsxtNetworkContextProfile{} + err = client.OpenApiGetAllItems(apiVersion, urlRef, queryParameters, &typeResponses, nil) + if err != nil { + return nil, err + } + + return typeResponses, nil +} + +// GetNetworkContextProfilesByScopeAndName retrieves a single NSX-T Network Context Profile by name +// and context ID. All fields - name, scope and contextId are mandatory +// +// contextId is mandatory and can be one off: +// * Org VDC ID - to get Network Context Profiles scoped for VDC +// * Network provider ID - to get Network Context Profiles scoped for attached NSX-T environment +// * VDC Group ID - to get Network Context Profiles scoped for attached NSX-T environment +// +// scope can be one off: +// * SYSTEM +// * PROVIDER +// * TENANT +func GetNetworkContextProfilesByNameScopeAndContext(client *Client, name, scope, contextId string) (*types.NsxtNetworkContextProfile, error) { + if name == "" || contextId == "" || scope == "" { + return nil, fmt.Errorf("error - 'name', 'scope' and 'contextId' must be specified") + } + + queryParams := copyOrNewUrlValues(nil) + queryParams.Add("filter", fmt.Sprintf("name==%s", name)) + queryParams = queryParameterFilterAnd(fmt.Sprintf("_context==%s", contextId), queryParams) + queryParams = queryParameterFilterAnd(fmt.Sprintf("scope==%s", scope), queryParams) + + allProfiles, err := GetAllNetworkContextProfiles(client, queryParams) + if err != nil { + return nil, fmt.Errorf("error retrieving Network Context Profiles by name '%s', scope '%s' and context ID '%s': %s ", + name, scope, contextId, err) + } + + return returnSingleNetworkContextProfile(allProfiles) +} + +func returnSingleNetworkContextProfile(allProfiles []*types.NsxtNetworkContextProfile) (*types.NsxtNetworkContextProfile, error) { + if len(allProfiles) > 1 { + return nil, fmt.Errorf("got more than 1 NSX-T Network Context Profile %d", len(allProfiles)) + } + + if len(allProfiles) < 1 { + return nil, fmt.Errorf("%s: got 0 NSX-T Network Context Profiles", ErrorEntityNotFound) + } + + return allProfiles[0], nil +} diff --git a/govcd/nsxt_network_context_profile_test.go b/govcd/nsxt_network_context_profile_test.go new file mode 100644 index 000000000..b8bc9643a --- /dev/null +++ b/govcd/nsxt_network_context_profile_test.go @@ -0,0 +1,72 @@ +//go:build network || nsxt || functional || openapi || ALL +// +build network nsxt functional openapi ALL + +package govcd + +import ( + "net/url" + + "github.com/vmware/go-vcloud-director/v2/types/v56" + . "gopkg.in/check.v1" +) + +func (vcd *TestVCD) Test_GetAllNetworkContextProfiles(check *C) { + skipNoNsxtConfiguration(vcd, check) + skipOpenApiEndpointTest(vcd, check, types.OpenApiPathVersion1_0_0+types.OpenApiEndpointNetworkContextProfiles) + + filteredTestGetAllNetworkContextProfiles(nil, &vcd.client.Client, check) + + // Test with SYSTEM scope + queryParams := copyOrNewUrlValues(nil) + queryParams.Add("filter", "scope==SYSTEM") + filteredTestGetAllNetworkContextProfiles(queryParams, &vcd.client.Client, check) + + // Test with PROVIDER scope + queryParams = copyOrNewUrlValues(nil) + queryParams.Add("filter", "scope==PROVIDER") + filteredTestGetAllNetworkContextProfiles(queryParams, &vcd.client.Client, check) + + // Test with TENANT scope + queryParams = copyOrNewUrlValues(nil) + queryParams.Add("filter", "scope==TENANT") + filteredTestGetAllNetworkContextProfiles(queryParams, &vcd.client.Client, check) + +} + +func filteredTestGetAllNetworkContextProfiles(queryParams url.Values, client *Client, check *C) { + profiles, err := GetAllNetworkContextProfiles(client, queryParams) + check.Assert(err, IsNil) + check.Assert(profiles, NotNil) +} + +func (vcd *TestVCD) Test_GetNetworkContextProfilesByNameScopeAndContext(check *C) { + skipNoNsxtConfiguration(vcd, check) + skipOpenApiEndpointTest(vcd, check, types.OpenApiPathVersion1_0_0+types.OpenApiEndpointNetworkContextProfiles) + + // Expect error when fields are empty + profiles, err := GetNetworkContextProfilesByNameScopeAndContext(&vcd.client.Client, "", "", "") + check.Assert(err, NotNil) + check.Assert(profiles, IsNil) + + nsxtManagers, err := vcd.client.QueryNsxtManagerByName(vcd.config.VCD.Nsxt.Manager) + check.Assert(err, IsNil) + check.Assert(len(nsxtManagers), Equals, 1) + uuid, err := GetUuidFromHref(nsxtManagers[0].HREF, true) + check.Assert(err, IsNil) + nsxtManagerUrn, err := BuildUrnWithUuid("urn:vcloud:nsxtmanager:", uuid) + check.Assert(err, IsNil) + + profiles, err = GetNetworkContextProfilesByNameScopeAndContext(&vcd.client.Client, "AMQP", "SYSTEM", nsxtManagerUrn) + check.Assert(err, IsNil) + check.Assert(profiles, NotNil) + + // VCD does not have PROVIDER Network Context Profiles by default + profiles, err = GetNetworkContextProfilesByNameScopeAndContext(&vcd.client.Client, "AMQP", "PROVIDER", nsxtManagerUrn) + check.Assert(err, NotNil) + check.Assert(profiles, IsNil) + + // VCD does not have TENANT Network Context Profiles by default + profiles, err = GetNetworkContextProfilesByNameScopeAndContext(&vcd.client.Client, "AMQP", "TENANT", nsxtManagerUrn) + check.Assert(err, NotNil) + check.Assert(profiles, IsNil) +} diff --git a/govcd/openapi_endpoints.go b/govcd/openapi_endpoints.go index 1f61ab4a2..a9c5a38da 100644 --- a/govcd/openapi_endpoints.go +++ b/govcd/openapi_endpoints.go @@ -63,6 +63,8 @@ var endpointMinApiVersions = map[string]string{ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointAlbVirtualServiceSummaries: "35.0", // VCD 10.2+ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointSSLCertificateLibrary: "35.0", // VCD 10.2+ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointSSLCertificateLibraryOld: "35.0", // VCD 10.2+ and deprecated from 10.3 + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroupsDfwRules: "35.0", // VCD 10.2+ + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointNetworkContextProfiles: "35.0", // VCD 10.2+ } // elevateNsxtNatRuleApiVersion helps to elevate API version to consume newer NSX-T NAT Rule features @@ -81,6 +83,11 @@ var endpointElevatedApiVersions = map[string][]string{ "35.0", // Deprecates field BackingType in favor of BackingTypeValue "36.0", // Adds support new type of BackingTypeValue - IMPORTED_T_LOGICAL_SWITCH (backed by NSX-T segment) }, + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroupsDfwRules: { + //"35.0", // Basic minimum required version + "35.2", // Deprecates Action field in favor of ActionValue + "36.2", // Adds 3 new fields - Comments, SourceGroupsExcluded, and DestinationGroupsExcluded + }, } // checkOpenApiEndpointCompatibility checks if VCD version (to which the client is connected) is sufficient to work with diff --git a/types/v56/constants.go b/types/v56/constants.go index e8f7c710c..36138356d 100644 --- a/types/v56/constants.go +++ b/types/v56/constants.go @@ -370,6 +370,8 @@ const ( OpenApiEndpointVdcGroupsCandidateVdcs = "vdcGroups/networkingCandidateVdcs" OpenApiEndpointVdcGroupsDfwPolicies = "vdcGroups/%s/dfwPolicies" OpenApiEndpointVdcGroupsDfwDefaultPolicies = "vdcGroups/%s/dfwPolicies/default" + OpenApiEndpointVdcGroupsDfwRules = "vdcGroups/%s/dfwPolicies/%s/rules" + OpenApiEndpointNetworkContextProfiles = "networkContextProfiles" // NSX-T ALB related endpoints diff --git a/types/v56/nsxt_types.go b/types/v56/nsxt_types.go index 8b705fa93..ce28fa248 100644 --- a/types/v56/nsxt_types.go +++ b/types/v56/nsxt_types.go @@ -1106,3 +1106,101 @@ type NsxtAlbVirtualServiceApplicationProfile struct { // * L4 TLS (certificate reference is mandatory) Type string `json:"type"` } + +// DistributedFirewallRule represents a single Distributed firewall rule +type DistributedFirewallRule struct { + ID string `json:"id,omitempty"` + Name string `json:"name"` + + // Action field. Deprecated in favor of ActionValue in VCD 10.2.2+ (API V35.2) + Action string `json:"action,omitempty"` + + // Description field is not shown in UI. 'Comments' field was introduced in 10.3.2 and is shown + // in UI. + Description string `json:"description,omitempty"` + + // ApplicationPortProfiles contains a list of references to Application Port Profiles. Empty + // list means 'Any' + ApplicationPortProfiles []OpenApiReference `json:"applicationPortProfiles,omitempty"` + + // SourceFirewallGroups contains a list of references to Firewall Groups. Empty list means 'Any' + SourceFirewallGroups []OpenApiReference `json:"sourceFirewallGroups,omitempty"` + // DestinationFirewallGroups contains a list of references to Firewall Groups. Empty list means + // 'Any' + DestinationFirewallGroups []OpenApiReference `json:"destinationFirewallGroups,omitempty"` + + // Direction 'IN_OUT', 'OUT', 'IN' + Direction string `json:"direction"` + Enabled bool `json:"enabled"` + + // IpProtocol 'IPV4', 'IPV6', 'IPV4_IPV6' + IpProtocol string `json:"ipProtocol"` + + Logging bool `json:"logging"` + + // NetworkContextProfiles sets list of layer 7 network context profiles where this firewall + // rule is applicable. Null value or an empty list will be treated as 'ANY' which means rule + // applies to all applications and domains. + NetworkContextProfiles []OpenApiReference `json:"networkContextProfiles,omitempty"` + + // Version describes the current version of the entity. To prevent clients from overwriting each + // other's changes, update operations must include the version which can be obtained by issuing + // a GET operation. If the version number on an update call is missing, the operation will be + // rejected. This is only needed on update calls. + Version *DistributedFirewallRuleVersion `json:"version,omitempty"` + + // New fields starting with 35.2 + + // ActionValue replaces deprecated field Action and defines action to be applied to all the + // traffic that meets the firewall rule criteria. It determines if the rule permits or blocks + // traffic. Property is required if action is not set. Below are valid values: + // * ALLOW permits traffic to go through the firewall. + // * DROP blocks the traffic at the firewall. No response is sent back to the source. + // * REJECT blocks the traffic at the firewall. A response is sent back to the source. + ActionValue string `json:"actionValue,omitempty"` + + // New fields starting with 36.2 + + // Comments permits setting text for user entered comments on the firewall rule. Length cannot + // exceed 2048 characters. Comments are shown Din UI for 10.3.2+. + Comments string `json:"comments,omitempty"` + + // SourceGroupsExcluded reverses the list specified in SourceFirewallGroups and the rule gets + // applied on all the groups that are NOT part of the SourceFirewallGroups. If false, the rule + // applies to the all the groups including the source groups. + SourceGroupsExcluded *bool `json:"sourceGroupsExcluded,omitempty"` + + // DestinationGroupsExcluded reverses the list specified in DestinationFirewallGroups and the + // rule gets applied on all the groups that are NOT part of the DestinationFirewallGroups. If + // false, the rule applies to the all the groups in DestinationFirewallGroups. + DestinationGroupsExcluded *bool `json:"destinationGroupsExcluded,omitempty"` +} + +type DistributedFirewallRules struct { + Values []*DistributedFirewallRule `json:"values"` +} + +type DistributedFirewallRuleVersion struct { + Version int `json:"version"` +} + +type NsxtNetworkContextProfile struct { + OrgRef *OpenApiReference `json:"orgRef"` + ContextEntityID interface{} `json:"contextEntityId"` + NetworkProviderScope interface{} `json:"networkProviderScope"` + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + + // Scope of NSX-T Network Context Profile + // SYSTEM profiles are available to all tenants. They are default profiles from the backing networking provider. + // PROVIDER profiles are available to all tenants. They are defined by the provider at a system level. + // TENANT profiles are available only to the specific tenant organization. They are defined by the tenant or by a provider on behalf of a tenant. + Scope string `json:"scope"` + Attributes []NsxtNetworkContextProfileAttributes `json:"attributes"` +} +type NsxtNetworkContextProfileAttributes struct { + Type string `json:"type"` + Values []string `json:"values"` + SubAttributes interface{} `json:"subAttributes"` +} From a98f4d34e22e9ca7a565b77cd1505faefd0b248f Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Tue, 29 Mar 2022 15:22:44 +0300 Subject: [PATCH 2/7] Self-review Signed-off-by: Dainius Serplis --- .../{XXX-features.md => 452-features.md} | 6 ++--- govcd/nsxt_distributed_firewall.go | 8 +++++- govcd/nsxt_distributed_firewall_test.go | 26 +++++++++---------- govcd/nsxt_network_context_profile_test.go | 13 +++++----- 4 files changed, 28 insertions(+), 25 deletions(-) rename .changes/v2.15.0/{XXX-features.md => 452-features.md} (59%) diff --git a/.changes/v2.15.0/XXX-features.md b/.changes/v2.15.0/452-features.md similarity index 59% rename from .changes/v2.15.0/XXX-features.md rename to .changes/v2.15.0/452-features.md index 1ea535546..0e86d9749 100644 --- a/.changes/v2.15.0/XXX-features.md +++ b/.changes/v2.15.0/452-features.md @@ -1,5 +1,5 @@ * Add support for for Network Context Profile lookup using `GetAllNetworkContextProfiles` and - `GetNetworkContextProfilesByNameScopeAndContext` functions [GH-XXX] + `GetNetworkContextProfilesByNameScopeAndContext` functions [GH-452] * Add support for NSX-T Distributed Firewall rule management using type `DistributedFirewall` and -`GetDistributedFirewall`, `UpdateDistributedFirewall`, `DeleteAllDistributedFirewallRules`, -`DeleteAllRules` [GH-XXX] +`VdcGroup.GetDistributedFirewall`, `VdcGroup.UpdateDistributedFirewall`, +`VdcGroup.DeleteAllDistributedFirewallRules`, `DistributedFirewall.DeleteAllRules` [GH-452] diff --git a/govcd/nsxt_distributed_firewall.go b/govcd/nsxt_distributed_firewall.go index a612de4bd..8aa075dc9 100644 --- a/govcd/nsxt_distributed_firewall.go +++ b/govcd/nsxt_distributed_firewall.go @@ -7,13 +7,15 @@ import ( "github.com/vmware/go-vcloud-director/v2/types/v56" ) -// DistributedFirewall contains a types.DfwFirewallRule +// DistributedFirewall contains a types.DistributedFirewallRules which handles Distributed Firewall +// rules in a VDC Group type DistributedFirewall struct { DistributedFirewallRuleContainer *types.DistributedFirewallRules client *Client VdcGroup *VdcGroup } +// GetDistributedFirewall retrieves Distributed Firewall in a VDC Group which contains all rules func (vdcGroup *VdcGroup) GetDistributedFirewall() (*DistributedFirewall, error) { client := vdcGroup.client endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroupsDfwRules @@ -41,6 +43,7 @@ func (vdcGroup *VdcGroup) GetDistributedFirewall() (*DistributedFirewall, error) return returnObject, nil } +// UpdateDistributedFirewall updates Distributed Firewall in a VDC Group func (vdcGroup *VdcGroup) UpdateDistributedFirewall(dfwRules *types.DistributedFirewallRules) (*DistributedFirewall, error) { client := vdcGroup.client endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroupsDfwRules @@ -49,6 +52,7 @@ func (vdcGroup *VdcGroup) UpdateDistributedFirewall(dfwRules *types.DistributedF return nil, err } + // "default" policy is hardcoded because there is no other policy supported urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, vdcGroup.VdcGroup.Id, "default")) if err != nil { return nil, err @@ -68,11 +72,13 @@ func (vdcGroup *VdcGroup) UpdateDistributedFirewall(dfwRules *types.DistributedF return returnObject, nil } +// DeleteAllDistributedFirewallRules removes all Distributed Firewall rules func (vdcGroup *VdcGroup) DeleteAllDistributedFirewallRules() error { _, err := vdcGroup.UpdateDistributedFirewall(&types.DistributedFirewallRules{}) return err } +// DeleteAllRules removes all Distributed Firewall rules func (firewall *DistributedFirewall) DeleteAllRules() error { if firewall.VdcGroup != nil && firewall.VdcGroup.VdcGroup != nil && firewall.VdcGroup.VdcGroup.Id == "" { return errors.New("empty VDC Group ID for parent VDC Group") diff --git a/govcd/nsxt_distributed_firewall_test.go b/govcd/nsxt_distributed_firewall_test.go index 9b1787bd3..525295a65 100644 --- a/govcd/nsxt_distributed_firewall_test.go +++ b/govcd/nsxt_distributed_firewall_test.go @@ -197,7 +197,6 @@ func createDistributedFirewallDefinitions(check *C, vcd *TestVCD, vdcGroupId str func preCreateVdcGroupIpSet(check *C, vcd *TestVCD, ownerId string) *NsxtFirewallGroup { nsxtVdc := vcd.nsxtVdc - ipSetDefinition := &types.NsxtFirewallGroup{ Name: check.TestName() + "ipset", Description: check.TestName() + "-Description", @@ -225,7 +224,6 @@ func preCreateVdcGroupIpSet(check *C, vcd *TestVCD, ownerId string) *NsxtFirewal func preCreateVdcGroupSecurityGroup(check *C, vcd *TestVCD, ownerId string) *NsxtFirewallGroup { nsxtVdc := vcd.nsxtVdc - fwGroupDefinition := &types.NsxtFirewallGroup{ Name: check.TestName() + "security-group", Description: check.TestName() + "-Description", @@ -242,18 +240,6 @@ func preCreateVdcGroupSecurityGroup(check *C, vcd *TestVCD, ownerId string) *Nsx return createdSecGroup } -func dumpDistributedFirewallRulesToScreen(rules []*types.DistributedFirewallRule) { - fmt.Println("# The following firewall rules will be created") - w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0) - fmt.Fprintln(w, "Name\tDirection\tIP Protocol\tEnabled\tAction\tLogging\tSrc Count\tDst Count\tAppPortProfile Count\tNet Context Profile Count") - - for _, rule := range rules { - fmt.Fprintf(w, "%s\t%s\t%s\t%t\t%s\t%t\t%d\t%d\t%d\t%d\n", rule.Name, rule.Direction, rule.IpProtocol, - rule.Enabled, rule.Action, rule.Logging, len(rule.SourceFirewallGroups), len(rule.DestinationFirewallGroups), len(rule.ApplicationPortProfiles), len(rule.NetworkContextProfiles)) - } - w.Flush() -} - func getRandomListOfNetworkContextProfiles(check *C, vcd *TestVCD) []types.OpenApiReference { networkContextProfiles, err := GetAllNetworkContextProfiles(&vcd.client.Client, nil) check.Assert(err, IsNil) @@ -272,3 +258,15 @@ func getRandomListOfNetworkContextProfiles(check *C, vcd *TestVCD) []types.OpenA return openApiRefs } + +func dumpDistributedFirewallRulesToScreen(rules []*types.DistributedFirewallRule) { + fmt.Println("# The following firewall rules will be created") + w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0) + fmt.Fprintln(w, "Name\tDirection\tIP Protocol\tEnabled\tAction\tLogging\tSrc Count\tDst Count\tAppPortProfile Count\tNet Context Profile Count") + + for _, rule := range rules { + fmt.Fprintf(w, "%s\t%s\t%s\t%t\t%s\t%t\t%d\t%d\t%d\t%d\n", rule.Name, rule.Direction, rule.IpProtocol, + rule.Enabled, rule.Action, rule.Logging, len(rule.SourceFirewallGroups), len(rule.DestinationFirewallGroups), len(rule.ApplicationPortProfiles), len(rule.NetworkContextProfiles)) + } + w.Flush() +} diff --git a/govcd/nsxt_network_context_profile_test.go b/govcd/nsxt_network_context_profile_test.go index b8bc9643a..a1883065f 100644 --- a/govcd/nsxt_network_context_profile_test.go +++ b/govcd/nsxt_network_context_profile_test.go @@ -30,13 +30,6 @@ func (vcd *TestVCD) Test_GetAllNetworkContextProfiles(check *C) { queryParams = copyOrNewUrlValues(nil) queryParams.Add("filter", "scope==TENANT") filteredTestGetAllNetworkContextProfiles(queryParams, &vcd.client.Client, check) - -} - -func filteredTestGetAllNetworkContextProfiles(queryParams url.Values, client *Client, check *C) { - profiles, err := GetAllNetworkContextProfiles(client, queryParams) - check.Assert(err, IsNil) - check.Assert(profiles, NotNil) } func (vcd *TestVCD) Test_GetNetworkContextProfilesByNameScopeAndContext(check *C) { @@ -70,3 +63,9 @@ func (vcd *TestVCD) Test_GetNetworkContextProfilesByNameScopeAndContext(check *C check.Assert(err, NotNil) check.Assert(profiles, IsNil) } + +func filteredTestGetAllNetworkContextProfiles(queryParams url.Values, client *Client, check *C) { + profiles, err := GetAllNetworkContextProfiles(client, queryParams) + check.Assert(err, IsNil) + check.Assert(profiles, NotNil) +} From 278515b335f9dc57483e1fe1edd375afc83fd823 Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Tue, 29 Mar 2022 22:27:56 +0300 Subject: [PATCH 3/7] Test improvement Signed-off-by: Dainius Serplis --- govcd/nsxt_distributed_firewall_test.go | 58 ++++++++++++++++++------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/govcd/nsxt_distributed_firewall_test.go b/govcd/nsxt_distributed_firewall_test.go index 525295a65..0563f48f6 100644 --- a/govcd/nsxt_distributed_firewall_test.go +++ b/govcd/nsxt_distributed_firewall_test.go @@ -14,7 +14,10 @@ import ( . "gopkg.in/check.v1" ) -// Test_NsxtDistributedFirewall creates a list of distributed firewall rules with randomized parameters +// Test_NsxtDistributedFirewall creates a list of distributed firewall rules with randomized +// parameters in two modes: +// * System user +// * Org Admin user func (vcd *TestVCD) Test_NsxtDistributedFirewallRules(check *C) { skipNoNsxtConfiguration(vcd, check) skipOpenApiEndpointTest(vcd, check, types.OpenApiPathVersion1_0_0+types.OpenApiEndpointEdgeGateways) @@ -31,6 +34,36 @@ func (vcd *TestVCD) Test_NsxtDistributedFirewallRules(check *C) { check.Assert(vdc, NotNil) check.Assert(vdcGroup, NotNil) + // Run firewall tests as System user + fmt.Println("# Running Distributed Firewall tests as 'System' user") + test_NsxtDistributedFirewallRules(vcd, check, vdcGroup.VdcGroup.Id, vcd.client, vdc) + + // Prep Org admin user and run firewall tests + userName := strings.ToLower(check.TestName()) + fmt.Printf("# Running Distributed Firewall tests as Org Admin user '%s'\n", userName) + orgUserVcdClient, err := newOrgUserConnection(adminOrg, userName, "CHANGE-ME", vcd.config.Provider.Url, true) + check.Assert(err, IsNil) + orgUserOrgAdmin, err := orgUserVcdClient.GetAdminOrgById(adminOrg.AdminOrg.ID) + check.Assert(err, IsNil) + orgUserVdc, err := orgUserOrgAdmin.GetVDCById(vdc.Vdc.ID, false) + check.Assert(err, IsNil) + test_NsxtDistributedFirewallRules(vcd, check, vdcGroup.VdcGroup.Id, orgUserVcdClient, orgUserVdc) + + // Cleanup + err = vdcGroup.Delete() + check.Assert(err, IsNil) + err = vdc.DeleteWait(true, true) + check.Assert(err, IsNil) +} + +func test_NsxtDistributedFirewallRules(vcd *TestVCD, check *C, vdcGroupId string, vcdClient *VCDClient, vdc *Vdc) { + adminOrg, err := vcdClient.GetAdminOrgByName(vcd.config.VCD.Org) + check.Assert(adminOrg, NotNil) + check.Assert(err, IsNil) + + vdcGroup, err := adminOrg.GetVdcGroupById(vdcGroupId) + check.Assert(err, IsNil) + _, err = vdcGroup.ActivateDfw() check.Assert(err, IsNil) @@ -40,7 +73,7 @@ func (vcd *TestVCD) Test_NsxtDistributedFirewallRules(check *C) { check.Assert(fwRules.DistributedFirewallRuleContainer.Values, NotNil) // Create some prerequisites and generate firewall rule configurations to feed them into config - randomizedFwRuleDefs, ipSet, secGroup := createDistributedFirewallDefinitions(check, vcd, vdcGroup.VdcGroup.Id) + randomizedFwRuleDefs, ipSet, secGroup := createDistributedFirewallDefinitions(check, vcd, vdcGroup.VdcGroup.Id, vcdClient, vdc) // Add IP Set and to cleanup list openApiEndpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointFirewallGroups + ipSet.NsxtFirewallGroup.ID @@ -115,25 +148,20 @@ func (vcd *TestVCD) Test_NsxtDistributedFirewallRules(check *C) { check.Assert(err, IsNil) err = secGroup.Delete() check.Assert(err, IsNil) - err = vdcGroup.Delete() - check.Assert(err, IsNil) - err = vdc.DeleteWait(true, true) - check.Assert(err, IsNil) } // createDistributedFirewallDefinitions creates some randomized firewall rule configurations to match possible configurations -func createDistributedFirewallDefinitions(check *C, vcd *TestVCD, vdcGroupId string) ([]*types.DistributedFirewallRule, *NsxtFirewallGroup, *NsxtFirewallGroup) { +func createDistributedFirewallDefinitions(check *C, vcd *TestVCD, vdcGroupId string, vcdClient *VCDClient, vdc *Vdc) ([]*types.DistributedFirewallRule, *NsxtFirewallGroup, *NsxtFirewallGroup) { // This number does not impact performance because all rules are created at once in the API numberOfRules := 40 // Pre-Create Firewall Groups (IP Set and Security Group to randomly configure them) - ipSet := preCreateVdcGroupIpSet(check, vcd, vdcGroupId) - secGroup := preCreateVdcGroupSecurityGroup(check, vcd, vdcGroupId) + ipSet := preCreateVdcGroupIpSet(check, vcd, vdcGroupId, vdc) + secGroup := preCreateVdcGroupSecurityGroup(check, vcd, vdcGroupId, vdc) fwGroupIds := []string{ipSet.NsxtFirewallGroup.ID, secGroup.NsxtFirewallGroup.ID} fwGroupRefs := convertSliceOfStringsToOpenApiReferenceIds(fwGroupIds) appPortProfileReferences := getRandomListOfAppPortProfiles(check, vcd) - networkContextProfiles := getRandomListOfNetworkContextProfiles(check, vcd) - // _ = getRandomListOfNetworkContextProfiles(check, vcd) + networkContextProfiles := getRandomListOfNetworkContextProfiles(check, vcd, vcdClient) firewallRules := make([]*types.DistributedFirewallRule, numberOfRules) for a := 0; a < numberOfRules; a++ { @@ -195,8 +223,7 @@ func createDistributedFirewallDefinitions(check *C, vcd *TestVCD, vdcGroupId str return firewallRules, ipSet, secGroup } -func preCreateVdcGroupIpSet(check *C, vcd *TestVCD, ownerId string) *NsxtFirewallGroup { - nsxtVdc := vcd.nsxtVdc +func preCreateVdcGroupIpSet(check *C, vcd *TestVCD, ownerId string, nsxtVdc *Vdc) *NsxtFirewallGroup { ipSetDefinition := &types.NsxtFirewallGroup{ Name: check.TestName() + "ipset", Description: check.TestName() + "-Description", @@ -222,8 +249,7 @@ func preCreateVdcGroupIpSet(check *C, vcd *TestVCD, ownerId string) *NsxtFirewal return createdIpSet } -func preCreateVdcGroupSecurityGroup(check *C, vcd *TestVCD, ownerId string) *NsxtFirewallGroup { - nsxtVdc := vcd.nsxtVdc +func preCreateVdcGroupSecurityGroup(check *C, vcd *TestVCD, ownerId string, nsxtVdc *Vdc) *NsxtFirewallGroup { fwGroupDefinition := &types.NsxtFirewallGroup{ Name: check.TestName() + "security-group", Description: check.TestName() + "-Description", @@ -240,7 +266,7 @@ func preCreateVdcGroupSecurityGroup(check *C, vcd *TestVCD, ownerId string) *Nsx return createdSecGroup } -func getRandomListOfNetworkContextProfiles(check *C, vcd *TestVCD) []types.OpenApiReference { +func getRandomListOfNetworkContextProfiles(check *C, vcd *TestVCD, vdcClient *VCDClient) []types.OpenApiReference { networkContextProfiles, err := GetAllNetworkContextProfiles(&vcd.client.Client, nil) check.Assert(err, IsNil) openApiRefs := make([]types.OpenApiReference, 1) From d8498f58b471a62337f113df6949079a3067a968 Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Tue, 29 Mar 2022 22:44:18 +0300 Subject: [PATCH 4/7] Remove ineffective test for API < 35.0 Signed-off-by: Dainius Serplis --- govcd/nsxt_nat_rule_test.go | 48 ------------------------------------- 1 file changed, 48 deletions(-) diff --git a/govcd/nsxt_nat_rule_test.go b/govcd/nsxt_nat_rule_test.go index 168846365..a6691c36a 100644 --- a/govcd/nsxt_nat_rule_test.go +++ b/govcd/nsxt_nat_rule_test.go @@ -50,58 +50,10 @@ func (vcd *TestVCD) Test_NsxtNatDnat(check *C) { nsxtNatRuleChecks(natRuleDefinition, edge, check, vcd) } -func (vcd *TestVCD) Test_NsxtNatDnatInternalPort(check *C) { - skipNoNsxtConfiguration(vcd, check) - skipOpenApiEndpointTest(vcd, check, types.OpenApiPathVersion1_0_0+types.OpenApiEndpointFirewallGroups) - - if vcd.client.Client.APIVCDMaxVersionIs(">= 35.2") { - check.Skip("InternalPort field is only used in older API versions (< 35.2) and is replaced by 'DnatExternalPort' field") - } - - org, err := vcd.client.GetOrgByName(vcd.config.VCD.Org) - check.Assert(err, IsNil) - - nsxtVdc, err := org.GetVDCByName(vcd.config.VCD.Nsxt.Vdc, false) - check.Assert(err, IsNil) - - edge, err := nsxtVdc.GetNsxtEdgeGatewayByName(vcd.config.VCD.Nsxt.EdgeGateway) - check.Assert(err, IsNil) - - appPortProfiles, err := org.GetAllNsxtAppPortProfiles(nil, types.ApplicationPortProfileScopeSystem) - check.Assert(err, IsNil) - - edgeGatewayPrimaryIp := "" - if edge.EdgeGateway != nil && len(edge.EdgeGateway.EdgeGatewayUplinks) > 0 && len(edge.EdgeGateway.EdgeGatewayUplinks[0].Subnets.Values) > 0 { - edgeGatewayPrimaryIp = edge.EdgeGateway.EdgeGatewayUplinks[0].Subnets.Values[0].PrimaryIP - } - check.Assert(edgeGatewayPrimaryIp, Not(Equals), "") - - natRuleDefinition := &types.NsxtNatRule{ - Name: check.TestName() + "dnat", - Description: "description", - Enabled: true, - RuleType: types.NsxtNatRuleTypeDnat, - ExternalAddresses: edgeGatewayPrimaryIp, - InternalAddresses: "11.11.11.2", - ApplicationPortProfile: &types.OpenApiReference{ - ID: appPortProfiles[0].NsxtAppPortProfile.ID, - Name: appPortProfiles[0].NsxtAppPortProfile.Name}, - SnatDestinationAddresses: "", - Logging: true, - InternalPort: "9898", - } - - nsxtNatRuleChecks(natRuleDefinition, edge, check, vcd) -} - func (vcd *TestVCD) Test_NsxtNatDnatExternalPortPort(check *C) { skipNoNsxtConfiguration(vcd, check) skipOpenApiEndpointTest(vcd, check, types.OpenApiPathVersion1_0_0+types.OpenApiEndpointFirewallGroups) - if vcd.client.Client.APIVCDMaxVersionIs("< 35.2") { - check.Skip("DnatExternalPort field is only used in API V35.2 (previously 'InternalPort' field)") - } - org, err := vcd.client.GetOrgByName(vcd.config.VCD.Org) check.Assert(err, IsNil) From 9d75390616c411bb519be4a80565ada35360c081 Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Wed, 30 Mar 2022 14:38:02 +0300 Subject: [PATCH 5/7] Address comments Signed-off-by: Dainius Serplis --- govcd/nsxt_distributed_firewall.go | 13 +++++++++++++ govcd/nsxt_distributed_firewall_test.go | 10 ++-------- types/v56/nsxt_types.go | 4 ++-- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/govcd/nsxt_distributed_firewall.go b/govcd/nsxt_distributed_firewall.go index 8aa075dc9..890e0eec8 100644 --- a/govcd/nsxt_distributed_firewall.go +++ b/govcd/nsxt_distributed_firewall.go @@ -16,6 +16,9 @@ type DistributedFirewall struct { } // GetDistributedFirewall retrieves Distributed Firewall in a VDC Group which contains all rules +// +// Note. This function works only with `default` policy as this was the only supported when this +// functions was created func (vdcGroup *VdcGroup) GetDistributedFirewall() (*DistributedFirewall, error) { client := vdcGroup.client endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroupsDfwRules @@ -24,6 +27,7 @@ func (vdcGroup *VdcGroup) GetDistributedFirewall() (*DistributedFirewall, error) return nil, err } + // "default" policy is hardcoded because there is no other policy supported urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, vdcGroup.VdcGroup.Id, "default")) if err != nil { return nil, err @@ -44,6 +48,9 @@ func (vdcGroup *VdcGroup) GetDistributedFirewall() (*DistributedFirewall, error) } // UpdateDistributedFirewall updates Distributed Firewall in a VDC Group +// +// Note. This function works only with `default` policy as this was the only supported when this +// functions was created func (vdcGroup *VdcGroup) UpdateDistributedFirewall(dfwRules *types.DistributedFirewallRules) (*DistributedFirewall, error) { client := vdcGroup.client endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroupsDfwRules @@ -73,12 +80,18 @@ func (vdcGroup *VdcGroup) UpdateDistributedFirewall(dfwRules *types.DistributedF } // DeleteAllDistributedFirewallRules removes all Distributed Firewall rules +// +// Note. This function works only with `default` policy as this was the only supported when this +// functions was created func (vdcGroup *VdcGroup) DeleteAllDistributedFirewallRules() error { _, err := vdcGroup.UpdateDistributedFirewall(&types.DistributedFirewallRules{}) return err } // DeleteAllRules removes all Distributed Firewall rules +// +// Note. This function works only with `default` policy as this was the only supported when this +// functions was created func (firewall *DistributedFirewall) DeleteAllRules() error { if firewall.VdcGroup != nil && firewall.VdcGroup.VdcGroup != nil && firewall.VdcGroup.VdcGroup.Id == "" { return errors.New("empty VDC Group ID for parent VDC Group") diff --git a/govcd/nsxt_distributed_firewall_test.go b/govcd/nsxt_distributed_firewall_test.go index 0563f48f6..a6a93056c 100644 --- a/govcd/nsxt_distributed_firewall_test.go +++ b/govcd/nsxt_distributed_firewall_test.go @@ -75,12 +75,6 @@ func test_NsxtDistributedFirewallRules(vcd *TestVCD, check *C, vdcGroupId string // Create some prerequisites and generate firewall rule configurations to feed them into config randomizedFwRuleDefs, ipSet, secGroup := createDistributedFirewallDefinitions(check, vcd, vdcGroup.VdcGroup.Id, vcdClient, vdc) - // Add IP Set and to cleanup list - openApiEndpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointFirewallGroups + ipSet.NsxtFirewallGroup.ID - PrependToCleanupListOpenApi(ipSet.NsxtFirewallGroup.Name, check.TestName(), openApiEndpoint) - openApiEndpoint = types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointFirewallGroups + secGroup.NsxtFirewallGroup.ID - PrependToCleanupListOpenApi(secGroup.NsxtFirewallGroup.Name, check.TestName(), openApiEndpoint) - fwRules.DistributedFirewallRuleContainer.Values = randomizedFwRuleDefs if testVerbose { @@ -244,7 +238,7 @@ func preCreateVdcGroupIpSet(check *C, vcd *TestVCD, ownerId string, nsxtVdc *Vdc createdIpSet, err := nsxtVdc.CreateNsxtFirewallGroup(ipSetDefinition) check.Assert(err, IsNil) openApiEndpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointFirewallGroups + createdIpSet.NsxtFirewallGroup.ID - AddToCleanupListOpenApi(createdIpSet.NsxtFirewallGroup.Name, check.TestName(), openApiEndpoint) + PrependToCleanupListOpenApi(createdIpSet.NsxtFirewallGroup.Name, check.TestName(), openApiEndpoint) return createdIpSet } @@ -261,7 +255,7 @@ func preCreateVdcGroupSecurityGroup(check *C, vcd *TestVCD, ownerId string, nsxt createdSecGroup, err := nsxtVdc.CreateNsxtFirewallGroup(fwGroupDefinition) check.Assert(err, IsNil) openApiEndpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointFirewallGroups + createdSecGroup.NsxtFirewallGroup.ID - AddToCleanupListOpenApi(createdSecGroup.NsxtFirewallGroup.Name, check.TestName(), openApiEndpoint) + PrependToCleanupListOpenApi(createdSecGroup.NsxtFirewallGroup.Name, check.TestName(), openApiEndpoint) return createdSecGroup } diff --git a/types/v56/nsxt_types.go b/types/v56/nsxt_types.go index ce28fa248..405c0ecb0 100644 --- a/types/v56/nsxt_types.go +++ b/types/v56/nsxt_types.go @@ -1107,7 +1107,7 @@ type NsxtAlbVirtualServiceApplicationProfile struct { Type string `json:"type"` } -// DistributedFirewallRule represents a single Distributed firewall rule +// DistributedFirewallRule represents a single Distributed Firewall rule type DistributedFirewallRule struct { ID string `json:"id,omitempty"` Name string `json:"name"` @@ -1162,7 +1162,7 @@ type DistributedFirewallRule struct { // New fields starting with 36.2 // Comments permits setting text for user entered comments on the firewall rule. Length cannot - // exceed 2048 characters. Comments are shown Din UI for 10.3.2+. + // exceed 2048 characters. Comments are shown in UI for 10.3.2+. Comments string `json:"comments,omitempty"` // SourceGroupsExcluded reverses the list specified in SourceFirewallGroups and the rule gets From f79ae951471675d00be1072e9dd108b804c55bba Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Thu, 31 Mar 2022 08:14:53 +0300 Subject: [PATCH 6/7] Address comments Signed-off-by: Dainius Serplis --- govcd/nsxt_distributed_firewall.go | 2 +- govcd/nsxt_distributed_firewall_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/govcd/nsxt_distributed_firewall.go b/govcd/nsxt_distributed_firewall.go index 890e0eec8..74959486c 100644 --- a/govcd/nsxt_distributed_firewall.go +++ b/govcd/nsxt_distributed_firewall.go @@ -73,7 +73,7 @@ func (vdcGroup *VdcGroup) UpdateDistributedFirewall(dfwRules *types.DistributedF err = client.OpenApiPutItem(apiVersion, urlRef, nil, dfwRules, returnObject.DistributedFirewallRuleContainer, nil) if err != nil { - return nil, fmt.Errorf("error setting Distributed Firewall rules: %s", err) + return nil, fmt.Errorf("error updating Distributed Firewall rules: %s", err) } return returnObject, nil diff --git a/govcd/nsxt_distributed_firewall_test.go b/govcd/nsxt_distributed_firewall_test.go index a6a93056c..465fa785e 100644 --- a/govcd/nsxt_distributed_firewall_test.go +++ b/govcd/nsxt_distributed_firewall_test.go @@ -87,7 +87,7 @@ func test_NsxtDistributedFirewallRules(vcd *TestVCD, check *C, vdcGroupId string check.Assert(len(fwUpdated.DistributedFirewallRuleContainer.Values), Equals, len(randomizedFwRuleDefs)) - // Check that all created rules are have the same attributes and order + // Check that all created rules have the same attributes and order for index := range fwUpdated.DistributedFirewallRuleContainer.Values { check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].Name, Equals, randomizedFwRuleDefs[index].Name) check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].Direction, Equals, randomizedFwRuleDefs[index].Direction) From b2df07f2173b4d9ba4297c8cee50647a94def413 Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Thu, 31 Mar 2022 09:34:47 +0300 Subject: [PATCH 7/7] Change 'default' to types.DistributedFirewallPolicyDefault Signed-off-by: Dainius Serplis --- govcd/nsxt_distributed_firewall.go | 4 ++-- types/v56/constants.go | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/govcd/nsxt_distributed_firewall.go b/govcd/nsxt_distributed_firewall.go index 74959486c..731b1bed0 100644 --- a/govcd/nsxt_distributed_firewall.go +++ b/govcd/nsxt_distributed_firewall.go @@ -28,7 +28,7 @@ func (vdcGroup *VdcGroup) GetDistributedFirewall() (*DistributedFirewall, error) } // "default" policy is hardcoded because there is no other policy supported - urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, vdcGroup.VdcGroup.Id, "default")) + urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, vdcGroup.VdcGroup.Id, types.DistributedFirewallPolicyDefault)) if err != nil { return nil, err } @@ -60,7 +60,7 @@ func (vdcGroup *VdcGroup) UpdateDistributedFirewall(dfwRules *types.DistributedF } // "default" policy is hardcoded because there is no other policy supported - urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, vdcGroup.VdcGroup.Id, "default")) + urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, vdcGroup.VdcGroup.Id, types.DistributedFirewallPolicyDefault)) if err != nil { return nil, err } diff --git a/types/v56/constants.go b/types/v56/constants.go index 36138356d..3c9c87410 100644 --- a/types/v56/constants.go +++ b/types/v56/constants.go @@ -497,3 +497,8 @@ const ( MetadataDateTimeValue string = "MetadataDateTimeValue" MetadataBooleanValue string = "MetadataBooleanValue" ) + +const ( + // DistributedFirewallPolicyDefault is a constant for "default" Distributed Firewall Policy + DistributedFirewallPolicyDefault = "default" +)