github.com/vmware/go-vcloud-director/v2@v2.24.0/govcd/nsxt_firewall_test.go (about)

     1  //go:build network || nsxt || functional || openapi || ALL
     2  
     3  package govcd
     4  
     5  import (
     6  	"crypto/rand"
     7  	"fmt"
     8  	"github.com/vmware/go-vcloud-director/v2/util"
     9  	"math/big"
    10  	"os"
    11  	"strconv"
    12  	"text/tabwriter"
    13  
    14  	"github.com/vmware/go-vcloud-director/v2/types/v56"
    15  	. "gopkg.in/check.v1"
    16  )
    17  
    18  // Test_NsxtFirewall creates 20 firewall rules with randomized parameters
    19  func (vcd *TestVCD) Test_NsxtFirewall(check *C) {
    20  	skipNoNsxtConfiguration(vcd, check)
    21  	skipOpenApiEndpointTest(vcd, check, types.OpenApiPathVersion1_0_0+types.OpenApiEndpointFirewallGroups)
    22  
    23  	org, err := vcd.client.GetOrgByName(vcd.config.VCD.Org)
    24  	check.Assert(err, IsNil)
    25  	nsxtVdc, err := org.GetVDCByName(vcd.config.VCD.Nsxt.Vdc, false)
    26  	check.Assert(err, IsNil)
    27  	edge, err := nsxtVdc.GetNsxtEdgeGatewayByName(vcd.config.VCD.Nsxt.EdgeGateway)
    28  	check.Assert(err, IsNil)
    29  
    30  	// Get existing firewall rule configuration
    31  	fwRules, err := edge.GetNsxtFirewall()
    32  	check.Assert(err, IsNil)
    33  
    34  	existingDefaultRuleCount := len(fwRules.NsxtFirewallRuleContainer.DefaultRules)
    35  	existingSystemRuleCount := len(fwRules.NsxtFirewallRuleContainer.SystemRules)
    36  
    37  	// Create some prerequisites and generate firewall rule configurations to feed them into config
    38  	randomizedFwRuleDefs := createFirewallDefinitions(check, vcd)
    39  	fwRules.NsxtFirewallRuleContainer.UserDefinedRules = randomizedFwRuleDefs
    40  
    41  	if testVerbose {
    42  		dumpFirewallRulesToScreen(randomizedFwRuleDefs)
    43  	}
    44  
    45  	fwCreated, err := edge.UpdateNsxtFirewall(fwRules.NsxtFirewallRuleContainer)
    46  	check.Assert(err, IsNil)
    47  
    48  	openApiEndpoint := types.OpenApiPathVersion1_0_0 + fmt.Sprintf(types.OpenApiEndpointNsxtFirewallRules, edge.EdgeGateway.ID)
    49  	PrependToCleanupList(openApiEndpoint, "OpenApiEntityFirewall", edge.EdgeGateway.Name, check.TestName())
    50  
    51  	check.Assert(fwCreated, Not(IsNil))
    52  	check.Assert(len(fwCreated.NsxtFirewallRuleContainer.UserDefinedRules), Equals, len(randomizedFwRuleDefs))
    53  
    54  	// Check that all created rules are have the same attributes and order
    55  	for index := range fwCreated.NsxtFirewallRuleContainer.UserDefinedRules {
    56  		check.Assert(fwCreated.NsxtFirewallRuleContainer.UserDefinedRules[index].Name, Equals, randomizedFwRuleDefs[index].Name)
    57  		check.Assert(fwCreated.NsxtFirewallRuleContainer.UserDefinedRules[index].Direction, Equals, randomizedFwRuleDefs[index].Direction)
    58  		check.Assert(fwCreated.NsxtFirewallRuleContainer.UserDefinedRules[index].IpProtocol, Equals, randomizedFwRuleDefs[index].IpProtocol)
    59  		check.Assert(fwCreated.NsxtFirewallRuleContainer.UserDefinedRules[index].Enabled, Equals, randomizedFwRuleDefs[index].Enabled)
    60  		check.Assert(fwCreated.NsxtFirewallRuleContainer.UserDefinedRules[index].Action, Equals, randomizedFwRuleDefs[index].Action)
    61  		if vcd.client.Client.IsSysAdmin {
    62  			// Only system administrator can handle logging
    63  			check.Assert(fwCreated.NsxtFirewallRuleContainer.UserDefinedRules[index].Logging, Equals, randomizedFwRuleDefs[index].Logging)
    64  		}
    65  
    66  		for fwGroupIndex := range fwCreated.NsxtFirewallRuleContainer.UserDefinedRules[index].SourceFirewallGroups {
    67  			check.Assert(fwCreated.NsxtFirewallRuleContainer.UserDefinedRules[index].SourceFirewallGroups[fwGroupIndex].ID, Equals, randomizedFwRuleDefs[index].SourceFirewallGroups[fwGroupIndex].ID)
    68  		}
    69  
    70  		for fwGroupIndex := range fwCreated.NsxtFirewallRuleContainer.UserDefinedRules[index].DestinationFirewallGroups {
    71  			check.Assert(fwCreated.NsxtFirewallRuleContainer.UserDefinedRules[index].DestinationFirewallGroups[fwGroupIndex].ID, Equals, randomizedFwRuleDefs[index].DestinationFirewallGroups[fwGroupIndex].ID)
    72  		}
    73  
    74  		// Ensure the same amount of Application Port Profiles are assigned and created
    75  		check.Assert(len(fwCreated.NsxtFirewallRuleContainer.UserDefinedRules), Equals, len(randomizedFwRuleDefs))
    76  		definedAppPortProfileIds := extractIdsFromOpenApiReferences(randomizedFwRuleDefs[index].ApplicationPortProfiles)
    77  		for _, appPortProfile := range fwCreated.NsxtFirewallRuleContainer.UserDefinedRules[index].ApplicationPortProfiles {
    78  			check.Assert(contains(appPortProfile.ID, definedAppPortProfileIds), Equals, true)
    79  		}
    80  	}
    81  
    82  	// Delete a single rule by ID and check for two things:
    83  	// * Rule with deleted ID should not be found in list post deletion
    84  	// * There should be one less rule in the list
    85  	deleteRuleId := fwCreated.NsxtFirewallRuleContainer.UserDefinedRules[3].ID
    86  	err = fwCreated.DeleteRuleById(deleteRuleId)
    87  	check.Assert(err, IsNil)
    88  
    89  	allRulesPostDeletion, err := edge.GetNsxtFirewall()
    90  	check.Assert(err, IsNil)
    91  
    92  	check.Assert(len(allRulesPostDeletion.NsxtFirewallRuleContainer.UserDefinedRules), Equals, len(fwCreated.NsxtFirewallRuleContainer.UserDefinedRules)-1)
    93  	for _, rule := range allRulesPostDeletion.NsxtFirewallRuleContainer.UserDefinedRules {
    94  		check.Assert(rule.ID, Not(Equals), deleteRuleId)
    95  	}
    96  
    97  	err = fwRules.DeleteAllRules()
    98  	check.Assert(err, IsNil)
    99  
   100  	// Ensure no firewall rules left in user space post deletion, but the same amount of default and system rules still exist
   101  	postDeleteCheck, err := edge.GetNsxtFirewall()
   102  	check.Assert(err, IsNil)
   103  	check.Assert(len(postDeleteCheck.NsxtFirewallRuleContainer.UserDefinedRules), Equals, 0)
   104  	check.Assert(len(postDeleteCheck.NsxtFirewallRuleContainer.DefaultRules), Equals, existingDefaultRuleCount)
   105  	check.Assert(len(postDeleteCheck.NsxtFirewallRuleContainer.SystemRules), Equals, existingSystemRuleCount)
   106  
   107  }
   108  
   109  // createFirewallDefinitions creates some randomized firewall rule configurations to match possible configurations
   110  func createFirewallDefinitions(check *C, vcd *TestVCD) []*types.NsxtFirewallRule {
   111  	// This number does not impact performance because all rules are created at once in the API
   112  	numberOfRules := 20
   113  
   114  	// Pre-Create Firewall Groups (IP Set and Security Group to randomly configure them)
   115  	ipSet := preCreateIpSet(check, vcd)
   116  	secGroup := preCreateSecurityGroup(check, vcd)
   117  	fwGroupIds := []string{ipSet.NsxtFirewallGroup.ID, secGroup.NsxtFirewallGroup.ID}
   118  	fwGroupRefs := convertSliceOfStringsToOpenApiReferenceIds(fwGroupIds)
   119  	appPortProfileReferences := getRandomListOfAppPortProfiles(check, vcd)
   120  
   121  	firewallRules := make([]*types.NsxtFirewallRule, numberOfRules)
   122  	for a := 0; a < numberOfRules; a++ {
   123  
   124  		// Feed in empty value for source and destination or a firewall group
   125  		src := pickRandomOpenApiRefOrEmpty(fwGroupRefs)
   126  		var srcValue []types.OpenApiReference
   127  		dst := pickRandomOpenApiRefOrEmpty(fwGroupRefs)
   128  		var dstValue []types.OpenApiReference
   129  		if src != (types.OpenApiReference{}) {
   130  			srcValue = []types.OpenApiReference{src}
   131  		}
   132  		if dst != (types.OpenApiReference{}) {
   133  			dstValue = []types.OpenApiReference{dst}
   134  		}
   135  
   136  		firewallRules[a] = &types.NsxtFirewallRule{
   137  			Name:                      check.TestName() + strconv.Itoa(a),
   138  			Action:                    pickRandomString([]string{"ALLOW", "DROP"}),
   139  			Enabled:                   a%2 == 0,
   140  			SourceFirewallGroups:      srcValue,
   141  			DestinationFirewallGroups: dstValue,
   142  			ApplicationPortProfiles:   appPortProfileReferences[0:a],
   143  			IpProtocol:                pickRandomString([]string{"IPV6", "IPV4", "IPV4_IPV6"}),
   144  			Logging:                   a%2 == 1,
   145  			Direction:                 pickRandomString([]string{"IN", "OUT", "IN_OUT"}),
   146  		}
   147  	}
   148  
   149  	return firewallRules
   150  }
   151  
   152  func pickRandomString(in []string) string {
   153  	randomIndex, _ := rand.Int(rand.Reader, big.NewInt(int64(len(in))))
   154  	return in[randomIndex.Uint64()]
   155  }
   156  
   157  // pickRandomOpenApiRefOrEmpty picks a random OpenAPI entity or an empty one
   158  func pickRandomOpenApiRefOrEmpty(in []types.OpenApiReference) types.OpenApiReference {
   159  	// Random value can be up to len+1 (len+1 is the special case when it should return an empty reference)
   160  	randomIndex, _ := rand.Int(rand.Reader, big.NewInt(int64(len(in)+1)))
   161  	if randomIndex.Uint64() == uint64(len(in)) {
   162  		return types.OpenApiReference{}
   163  	}
   164  	return in[randomIndex.Uint64()]
   165  }
   166  
   167  func preCreateIpSet(check *C, vcd *TestVCD) *NsxtFirewallGroup {
   168  	nsxtVdc := vcd.nsxtVdc
   169  	edge, err := nsxtVdc.GetNsxtEdgeGatewayByName(vcd.config.VCD.Nsxt.EdgeGateway)
   170  	check.Assert(err, IsNil)
   171  
   172  	ipSetDefinition := &types.NsxtFirewallGroup{
   173  		Name:           check.TestName() + "ipset",
   174  		Description:    check.TestName() + "-Description",
   175  		Type:           types.FirewallGroupTypeIpSet,
   176  		EdgeGatewayRef: &types.OpenApiReference{ID: edge.EdgeGateway.ID},
   177  
   178  		IpAddresses: []string{
   179  			"12.12.12.1",
   180  			"10.10.10.0/24",
   181  			"11.11.11.1-11.11.11.2",
   182  			// represents the block of IPv6 addresses from 2001:db8:0:0:0:0:0:0 to 2001:db8:0:ffff:ffff:ffff:ffff:ffff
   183  			"2001:db8::/48",
   184  			"2001:db6:0:0:0:0:0:0-2001:db6:0:ffff:ffff:ffff:ffff:ffff",
   185  		},
   186  	}
   187  
   188  	// Create IP Set and add to cleanup if it was created
   189  	createdIpSet, err := nsxtVdc.CreateNsxtFirewallGroup(ipSetDefinition)
   190  	check.Assert(err, IsNil)
   191  	openApiEndpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointFirewallGroups + createdIpSet.NsxtFirewallGroup.ID
   192  	AddToCleanupListOpenApi(createdIpSet.NsxtFirewallGroup.Name, check.TestName(), openApiEndpoint)
   193  
   194  	return createdIpSet
   195  }
   196  
   197  func preCreateSecurityGroup(check *C, vcd *TestVCD) *NsxtFirewallGroup {
   198  	nsxtVdc := vcd.nsxtVdc
   199  	edge, err := nsxtVdc.GetNsxtEdgeGatewayByName(vcd.config.VCD.Nsxt.EdgeGateway)
   200  	check.Assert(err, IsNil)
   201  
   202  	fwGroupDefinition := &types.NsxtFirewallGroup{
   203  		Name:           check.TestName() + "security-group",
   204  		Description:    check.TestName() + "-Description",
   205  		Type:           types.FirewallGroupTypeSecurityGroup,
   206  		EdgeGatewayRef: &types.OpenApiReference{ID: edge.EdgeGateway.ID},
   207  	}
   208  
   209  	// Create firewall group and add to cleanup if it was created
   210  	createdSecGroup, err := nsxtVdc.CreateNsxtFirewallGroup(fwGroupDefinition)
   211  	check.Assert(err, IsNil)
   212  	openApiEndpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointFirewallGroups + createdSecGroup.NsxtFirewallGroup.ID
   213  	AddToCleanupListOpenApi(check.TestName()+"sec-group", check.TestName(), openApiEndpoint)
   214  
   215  	return createdSecGroup
   216  }
   217  
   218  func getRandomListOfAppPortProfiles(check *C, vcd *TestVCD) []types.OpenApiReference {
   219  	org, err := vcd.client.GetOrgByName(vcd.config.VCD.Org)
   220  	check.Assert(err, IsNil)
   221  
   222  	appProfileSlice, err := org.GetAllNsxtAppPortProfiles(nil, types.ApplicationPortProfileScopeSystem)
   223  	check.Assert(err, IsNil)
   224  
   225  	openApiRefs := make([]types.OpenApiReference, len(appProfileSlice))
   226  	for index, appPortProfile := range appProfileSlice {
   227  		openApiRefs[index].ID = appPortProfile.NsxtAppPortProfile.ID
   228  		openApiRefs[index].Name = appPortProfile.NsxtAppPortProfile.Name
   229  	}
   230  
   231  	return openApiRefs
   232  }
   233  
   234  func dumpFirewallRulesToScreen(rules []*types.NsxtFirewallRule) {
   235  	fmt.Println("# The following firewall rules will be created")
   236  	w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)
   237  	fmt.Fprintln(w, "Name\tDirection\tIP Protocol\tEnabled\tAction\tLogging\tSrc Count\tDst Count\tAppPortProfile Count")
   238  
   239  	for _, rule := range rules {
   240  		fmt.Fprintf(w, "%s\t%s\t%s\t%t\t%s\t%t\t%d\t%d\t%d\n", rule.Name, rule.Direction, rule.IpProtocol,
   241  			rule.Enabled, rule.Action, rule.Logging, len(rule.SourceFirewallGroups), len(rule.DestinationFirewallGroups), len(rule.ApplicationPortProfiles))
   242  	}
   243  	err := w.Flush()
   244  	if err != nil {
   245  		util.Logger.Printf("Error while dumping Firewall rules to screen: %s", err)
   246  	}
   247  }