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

     1  //go:build network || nsxt || functional || openapi || ALL
     2  
     3  package govcd
     4  
     5  import (
     6  	"fmt"
     7  	"os"
     8  	"strconv"
     9  	"strings"
    10  	"text/tabwriter"
    11  
    12  	"github.com/vmware/go-vcloud-director/v2/util"
    13  
    14  	"github.com/vmware/go-vcloud-director/v2/types/v56"
    15  	. "gopkg.in/check.v1"
    16  )
    17  
    18  // Test_NsxtDistributedFirewall creates a list of distributed firewall rules with randomized
    19  // parameters in two modes:
    20  // * System user
    21  // * Org Admin user
    22  func (vcd *TestVCD) Test_NsxtDistributedFirewallRules(check *C) {
    23  	skipNoNsxtConfiguration(vcd, check)
    24  	skipOpenApiEndpointTest(vcd, check, types.OpenApiPathVersion1_0_0+types.OpenApiEndpointEdgeGateways)
    25  	vcd.skipIfNotSysAdmin(check)
    26  
    27  	adminOrg, err := vcd.client.GetAdminOrgByName(vcd.config.VCD.Org)
    28  	check.Assert(adminOrg, NotNil)
    29  	check.Assert(err, IsNil)
    30  
    31  	nsxtExternalNetwork, err := GetExternalNetworkV2ByName(vcd.client, vcd.config.VCD.Nsxt.ExternalNetwork)
    32  	check.Assert(err, IsNil)
    33  	check.Assert(nsxtExternalNetwork, NotNil)
    34  
    35  	vdc, vdcGroup := test_CreateVdcGroup(check, adminOrg, vcd)
    36  	check.Assert(vdc, NotNil)
    37  	check.Assert(vdcGroup, NotNil)
    38  
    39  	// Run firewall tests as System user
    40  	fmt.Println("# Running Distributed Firewall tests as 'System' user")
    41  	test_NsxtDistributedFirewallRules(vcd, check, vdcGroup.VdcGroup.Id, vcd.client, vdc)
    42  
    43  	// Prep Org admin user and run firewall tests
    44  	userName := strings.ToLower(check.TestName())
    45  	fmt.Printf("# Running Distributed Firewall tests as Org Admin user '%s'\n", userName)
    46  	orgUserVcdClient, _, err := newOrgUserConnection(adminOrg, userName, "CHANGE-ME", vcd.config.Provider.Url, true)
    47  	check.Assert(err, IsNil)
    48  	orgUserOrgAdmin, err := orgUserVcdClient.GetAdminOrgById(adminOrg.AdminOrg.ID)
    49  	check.Assert(err, IsNil)
    50  	orgUserVdc, err := orgUserOrgAdmin.GetVDCById(vdc.Vdc.ID, false)
    51  	check.Assert(err, IsNil)
    52  	test_NsxtDistributedFirewallRules(vcd, check, vdcGroup.VdcGroup.Id, orgUserVcdClient, orgUserVdc)
    53  
    54  	// Cleanup
    55  	err = vdcGroup.Delete()
    56  	check.Assert(err, IsNil)
    57  	err = vdc.DeleteWait(true, true)
    58  	check.Assert(err, IsNil)
    59  }
    60  
    61  func test_NsxtDistributedFirewallRules(vcd *TestVCD, check *C, vdcGroupId string, vcdClient *VCDClient, vdc *Vdc) {
    62  	adminOrg, err := vcdClient.GetAdminOrgByName(vcd.config.VCD.Org)
    63  	check.Assert(adminOrg, NotNil)
    64  	check.Assert(err, IsNil)
    65  
    66  	vdcGroup, err := adminOrg.GetVdcGroupById(vdcGroupId)
    67  	check.Assert(err, IsNil)
    68  
    69  	_, err = vdcGroup.ActivateDfw()
    70  	check.Assert(err, IsNil)
    71  
    72  	// Get existing firewall rule configuration
    73  	fwRules, err := vdcGroup.GetDistributedFirewall()
    74  	check.Assert(err, IsNil)
    75  	check.Assert(fwRules.DistributedFirewallRuleContainer.Values, NotNil)
    76  
    77  	// Create some prerequisites and generate firewall rule configurations to feed them into config
    78  	randomizedFwRuleDefs, ipSet, secGroup := createDistributedFirewallDefinitions(check, vcd, vdcGroup.VdcGroup.Id, vcdClient, vdc)
    79  
    80  	fwRules.DistributedFirewallRuleContainer.Values = randomizedFwRuleDefs
    81  
    82  	if testVerbose {
    83  		dumpDistributedFirewallRulesToScreen(randomizedFwRuleDefs)
    84  	}
    85  
    86  	fwUpdated, err := vdcGroup.UpdateDistributedFirewall(fwRules.DistributedFirewallRuleContainer)
    87  	check.Assert(err, IsNil)
    88  	check.Assert(fwUpdated, Not(IsNil))
    89  
    90  	check.Assert(len(fwUpdated.DistributedFirewallRuleContainer.Values), Equals, len(randomizedFwRuleDefs))
    91  
    92  	// Check that all created rules have the same attributes and order
    93  	for index := range fwUpdated.DistributedFirewallRuleContainer.Values {
    94  		check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].Name, Equals, randomizedFwRuleDefs[index].Name)
    95  		check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].Direction, Equals, randomizedFwRuleDefs[index].Direction)
    96  		check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].IpProtocol, Equals, randomizedFwRuleDefs[index].IpProtocol)
    97  		check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].Enabled, Equals, randomizedFwRuleDefs[index].Enabled)
    98  		check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].Logging, Equals, randomizedFwRuleDefs[index].Logging)
    99  		check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].Comments, Equals, randomizedFwRuleDefs[index].Comments)
   100  		check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].ActionValue, Equals, randomizedFwRuleDefs[index].ActionValue)
   101  
   102  		for fwGroupIndex := range fwUpdated.DistributedFirewallRuleContainer.Values[index].SourceFirewallGroups {
   103  			check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].SourceFirewallGroups[fwGroupIndex].ID, Equals, randomizedFwRuleDefs[index].SourceFirewallGroups[fwGroupIndex].ID)
   104  		}
   105  
   106  		for fwGroupIndex := range fwUpdated.DistributedFirewallRuleContainer.Values[index].DestinationFirewallGroups {
   107  			check.Assert(fwUpdated.DistributedFirewallRuleContainer.Values[index].DestinationFirewallGroups[fwGroupIndex].ID, Equals, randomizedFwRuleDefs[index].DestinationFirewallGroups[fwGroupIndex].ID)
   108  		}
   109  
   110  		// Ensure the same amount of Application Port Profiles are assigned and created
   111  		check.Assert(len(fwUpdated.DistributedFirewallRuleContainer.Values), Equals, len(randomizedFwRuleDefs))
   112  		definedAppPortProfileIds := extractIdsFromOpenApiReferences(randomizedFwRuleDefs[index].ApplicationPortProfiles)
   113  		for _, appPortProfile := range fwUpdated.DistributedFirewallRuleContainer.Values[index].ApplicationPortProfiles {
   114  			check.Assert(contains(appPortProfile.ID, definedAppPortProfileIds), Equals, true)
   115  		}
   116  
   117  		// Ensure the same amount of Network Context Profiles are assigned and created
   118  		definedNetContextProfileIds := extractIdsFromOpenApiReferences(randomizedFwRuleDefs[index].NetworkContextProfiles)
   119  		for _, networkContextProfile := range fwUpdated.DistributedFirewallRuleContainer.Values[index].NetworkContextProfiles {
   120  			check.Assert(contains(networkContextProfile.ID, definedNetContextProfileIds), Equals, true)
   121  		}
   122  	}
   123  
   124  	// Cleanup
   125  	err = fwRules.DeleteAllRules()
   126  	check.Assert(err, IsNil)
   127  	// Check that rules were removed
   128  	newRules, err := vdcGroup.GetDistributedFirewall()
   129  	check.Assert(err, IsNil)
   130  	check.Assert(len(newRules.DistributedFirewallRuleContainer.Values) == 0, Equals, true)
   131  
   132  	// Cleanup remaining setup
   133  	_, err = vdcGroup.DisableDefaultPolicy()
   134  	check.Assert(err, IsNil)
   135  	_, err = vdcGroup.DeactivateDfw()
   136  	check.Assert(err, IsNil)
   137  	err = ipSet.Delete()
   138  	check.Assert(err, IsNil)
   139  	err = secGroup.Delete()
   140  	check.Assert(err, IsNil)
   141  }
   142  
   143  // createDistributedFirewallDefinitions creates some randomized firewall rule configurations to match possible configurations
   144  func createDistributedFirewallDefinitions(check *C, vcd *TestVCD, vdcGroupId string, vcdClient *VCDClient, vdc *Vdc) ([]*types.DistributedFirewallRule, *NsxtFirewallGroup, *NsxtFirewallGroup) {
   145  	// This number does not impact performance because all rules are created at once in the API
   146  	numberOfRules := 40
   147  
   148  	// Pre-Create Firewall Groups (IP Set and Security Group to randomly configure them)
   149  	ipSet := preCreateVdcGroupIpSet(check, vcd, vdcGroupId, vdc)
   150  	secGroup := preCreateVdcGroupSecurityGroup(check, vcd, vdcGroupId, vdc)
   151  	fwGroupIds := []string{ipSet.NsxtFirewallGroup.ID, secGroup.NsxtFirewallGroup.ID}
   152  	fwGroupRefs := convertSliceOfStringsToOpenApiReferenceIds(fwGroupIds)
   153  	appPortProfileReferences := getRandomListOfAppPortProfiles(check, vcd)
   154  	networkContextProfiles := getRandomListOfNetworkContextProfiles(check, vcd, vcdClient)
   155  
   156  	firewallRules := make([]*types.DistributedFirewallRule, numberOfRules)
   157  	for a := 0; a < numberOfRules; a++ {
   158  
   159  		// Feed in empty value for source and destination or a firewall group
   160  		src := pickRandomOpenApiRefOrEmpty(fwGroupRefs)
   161  		var srcValue []types.OpenApiReference
   162  		dst := pickRandomOpenApiRefOrEmpty(fwGroupRefs)
   163  		var dstValue []types.OpenApiReference
   164  		if src != (types.OpenApiReference{}) {
   165  			srcValue = []types.OpenApiReference{src}
   166  		}
   167  		if dst != (types.OpenApiReference{}) {
   168  			dstValue = []types.OpenApiReference{dst}
   169  		}
   170  
   171  		firewallRules[a] = &types.DistributedFirewallRule{
   172  			Name:                      check.TestName() + strconv.Itoa(a),
   173  			ActionValue:               pickRandomString([]string{"ALLOW", "DROP", "REJECT"}),
   174  			Enabled:                   a%2 == 0,
   175  			SourceFirewallGroups:      srcValue,
   176  			DestinationFirewallGroups: dstValue,
   177  			ApplicationPortProfiles:   appPortProfileReferences[0:a],
   178  			IpProtocol:                pickRandomString([]string{"IPV6", "IPV4", "IPV4_IPV6"}),
   179  			Logging:                   a%2 == 1,
   180  			Direction:                 pickRandomString([]string{"IN", "OUT", "IN_OUT"}),
   181  		}
   182  
   183  		// Network Context Profile can usually work with up to one Application Profile therefore this
   184  		// needs to be explicitly preset
   185  		if a%5 == 1 { // Every fifth rule
   186  			netCtxProfile := networkContextProfiles[0:a]
   187  			networkContextProfile := make([]types.OpenApiReference, 0)
   188  			for _, netCtxProf := range netCtxProfile {
   189  				if netCtxProf.ID != "" {
   190  					networkContextProfile = append(networkContextProfile, types.OpenApiReference{ID: netCtxProf.ID, Name: netCtxProf.Name})
   191  				}
   192  			}
   193  
   194  			firewallRules[a].NetworkContextProfiles = networkContextProfile
   195  			// firewallRules[a].ApplicationPortProfiles = appPortProfileReferences[0:1]
   196  			firewallRules[a].ApplicationPortProfiles = nil
   197  
   198  		}
   199  
   200  		// API V36.2 introduced new field Comment which is shown in UI
   201  		if vcd.client.Client.APIVCDMaxVersionIs(">= 36.2") {
   202  			firewallRules[a].Comments = "Comment Rule"
   203  		}
   204  
   205  	}
   206  
   207  	return firewallRules, ipSet, secGroup
   208  }
   209  
   210  func preCreateVdcGroupIpSet(check *C, vcd *TestVCD, ownerId string, nsxtVdc *Vdc) *NsxtFirewallGroup {
   211  	ipSetDefinition := &types.NsxtFirewallGroup{
   212  		Name:        check.TestName() + "ipset",
   213  		Description: check.TestName() + "-Description",
   214  		Type:        types.FirewallGroupTypeIpSet,
   215  		OwnerRef:    &types.OpenApiReference{ID: ownerId},
   216  
   217  		IpAddresses: []string{
   218  			"12.12.12.1",
   219  			"10.10.10.0/24",
   220  			"11.11.11.1-11.11.11.2",
   221  			// represents the block of IPv6 addresses from 2001:db8:0:0:0:0:0:0 to 2001:db8:0:ffff:ffff:ffff:ffff:ffff
   222  			"2001:db8::/48",
   223  			"2001:db6:0:0:0:0:0:0-2001:db6:0:ffff:ffff:ffff:ffff:ffff",
   224  		},
   225  	}
   226  
   227  	// Create IP Set and add to cleanup if it was created
   228  	createdIpSet, err := nsxtVdc.CreateNsxtFirewallGroup(ipSetDefinition)
   229  	check.Assert(err, IsNil)
   230  	openApiEndpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointFirewallGroups + createdIpSet.NsxtFirewallGroup.ID
   231  	PrependToCleanupListOpenApi(createdIpSet.NsxtFirewallGroup.Name, check.TestName(), openApiEndpoint)
   232  
   233  	return createdIpSet
   234  }
   235  
   236  func preCreateVdcGroupSecurityGroup(check *C, vcd *TestVCD, ownerId string, nsxtVdc *Vdc) *NsxtFirewallGroup {
   237  	fwGroupDefinition := &types.NsxtFirewallGroup{
   238  		Name:        check.TestName() + "security-group",
   239  		Description: check.TestName() + "-Description",
   240  		Type:        types.FirewallGroupTypeSecurityGroup,
   241  		OwnerRef:    &types.OpenApiReference{ID: ownerId},
   242  	}
   243  
   244  	// Create firewall group and add to cleanup if it was created
   245  	createdSecGroup, err := nsxtVdc.CreateNsxtFirewallGroup(fwGroupDefinition)
   246  	check.Assert(err, IsNil)
   247  	openApiEndpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointFirewallGroups + createdSecGroup.NsxtFirewallGroup.ID
   248  	PrependToCleanupListOpenApi(createdSecGroup.NsxtFirewallGroup.Name, check.TestName(), openApiEndpoint)
   249  
   250  	return createdSecGroup
   251  }
   252  
   253  func getRandomListOfNetworkContextProfiles(check *C, vcd *TestVCD, vdcClient *VCDClient) []types.OpenApiReference {
   254  	networkContextProfiles, err := GetAllNetworkContextProfiles(&vcd.client.Client, nil)
   255  	check.Assert(err, IsNil)
   256  	openApiRefs := make([]types.OpenApiReference, 1)
   257  	for _, networkContextProfile := range networkContextProfiles {
   258  		// Skipping network context profile which has hardcoded destinations and throws error when used in firewall rules with specified destinations
   259  		if strings.Contains(networkContextProfile.Description, "ALG") || strings.Contains(networkContextProfile.Description, "includes the URL categories") {
   260  			continue
   261  		}
   262  		openApiRef := types.OpenApiReference{
   263  			ID:   networkContextProfile.ID,
   264  			Name: networkContextProfile.Name,
   265  		}
   266  
   267  		openApiRefs = append(openApiRefs, openApiRef)
   268  	}
   269  
   270  	return openApiRefs
   271  }
   272  
   273  func dumpDistributedFirewallRulesToScreen(rules []*types.DistributedFirewallRule) {
   274  	fmt.Println("# The following firewall rules will be created")
   275  	w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)
   276  	fmt.Fprintln(w, "Name\tDirection\tIP Protocol\tEnabled\tAction\tLogging\tSrc Count\tDst Count\tAppPortProfile Count\tNet Context Profile Count")
   277  
   278  	for _, rule := range rules {
   279  		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,
   280  			rule.Enabled, rule.Action, rule.Logging, len(rule.SourceFirewallGroups), len(rule.DestinationFirewallGroups), len(rule.ApplicationPortProfiles), len(rule.NetworkContextProfiles))
   281  	}
   282  	err := w.Flush()
   283  	if err != nil {
   284  		util.Logger.Printf("Error while dumping Distributed Firewall rules to screen: %s", err)
   285  	}
   286  }
   287  
   288  // Test_NsxtDistributedFirewallRule tests the capability of managing Firewall Rules one by one using
   289  // `DistributedFirewallRule` type.
   290  func (vcd *TestVCD) Test_NsxtDistributedFirewallRule(check *C) {
   291  	if vcd.skipAdminTests {
   292  		check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName()))
   293  	}
   294  	skipNoNsxtConfiguration(vcd, check)
   295  	skipOpenApiEndpointTest(vcd, check, types.OpenApiPathVersion1_0_0+types.OpenApiEndpointEdgeGateways)
   296  
   297  	adminOrg, err := vcd.client.GetAdminOrgByName(vcd.config.VCD.Org)
   298  	check.Assert(adminOrg, NotNil)
   299  	check.Assert(err, IsNil)
   300  
   301  	nsxtExternalNetwork, err := GetExternalNetworkV2ByName(vcd.client, vcd.config.VCD.Nsxt.ExternalNetwork)
   302  	check.Assert(nsxtExternalNetwork, NotNil)
   303  	check.Assert(err, IsNil)
   304  
   305  	vdc, vdcGroup := test_CreateVdcGroup(check, adminOrg, vcd)
   306  	check.Assert(vdc, NotNil)
   307  	check.Assert(vdcGroup, NotNil)
   308  
   309  	defer func() {
   310  		// Cleanup
   311  		err = vdcGroup.Delete()
   312  		check.Assert(err, IsNil)
   313  		err = vdc.DeleteWait(true, true)
   314  		check.Assert(err, IsNil)
   315  	}()
   316  
   317  	fmt.Println("# Running Distributed Firewall tests for single Rule")
   318  	test_NsxtDistributedFirewallRule(vcd, check, vdcGroup.VdcGroup.Id, vcd.client, vdc)
   319  }
   320  
   321  func test_NsxtDistributedFirewallRule(vcd *TestVCD, check *C, vdcGroupId string, vcdClient *VCDClient, vdc *Vdc) {
   322  	adminOrg, err := vcdClient.GetAdminOrgByName(vcd.config.VCD.Org)
   323  	check.Assert(adminOrg, NotNil)
   324  	check.Assert(err, IsNil)
   325  
   326  	vdcGroup, err := adminOrg.GetVdcGroupById(vdcGroupId)
   327  	check.Assert(err, IsNil)
   328  
   329  	_, err = vdcGroup.ActivateDfw()
   330  	check.Assert(err, IsNil)
   331  
   332  	// Prep firewall rule sample to operate with
   333  	randomizedFwRuleDefs, ipSet, secGroup := createDistributedFirewallDefinitions(check, vcd, vdcGroup.VdcGroup.Id, vcdClient, vdc)
   334  	// defer cleanup function in case something goes wrong
   335  	defer func() {
   336  		dfw, err := vdcGroup.GetDistributedFirewall()
   337  		check.Assert(err, IsNil)
   338  		err = dfw.DeleteAllRules()
   339  		check.Assert(err, IsNil)
   340  		_, err = vdcGroup.DisableDefaultPolicy()
   341  		check.Assert(err, IsNil)
   342  		err = ipSet.Delete()
   343  		check.Assert(err, IsNil)
   344  		err = secGroup.Delete()
   345  		check.Assert(err, IsNil)
   346  	}()
   347  
   348  	randomizedFwRuleSubSet := randomizedFwRuleDefs[0:5] // taking only first 5 rules to limit time of testing
   349  
   350  	// removing default firewall rule which is created by VCD when vdcGroup.ActivateDfw() is executed
   351  	err = vdcGroup.DeleteAllDistributedFirewallRules()
   352  	check.Assert(err, IsNil)
   353  
   354  	// Adding firewal rules one by one and checking that each of them is
   355  	testDistributedFirewallRuleSequence(vcd, check, randomizedFwRuleSubSet, vdcGroup, false)
   356  	testDistributedFirewallRuleSequence(vcd, check, randomizedFwRuleSubSet, vdcGroup, true)
   357  }
   358  
   359  // testDistributedFirewallRuleSequence tests the following:
   360  // * create firewall rules one one by one
   361  // * check that the order of firewall rules is the same as requested (or exactly reverse if
   362  // reverseOrder=true)
   363  // * check that all IDs of created firewall rules persisted during further updates (means that no
   364  // firewall rules were recreated during addition of new ones)
   365  func testDistributedFirewallRuleSequence(vcd *TestVCD, check *C, randomizedFwRuleSubSet []*types.DistributedFirewallRule, vdcGroup *VdcGroup, reverseOrder bool) {
   366  	createdIdsFound := make(map[string]bool)
   367  	fmt.Printf("# Creating '%d' rules one by one (reverseOrder: %t)\n", len(randomizedFwRuleSubSet), reverseOrder)
   368  	previousRuleId := ""
   369  	for _, rule := range randomizedFwRuleSubSet {
   370  		if testVerbose {
   371  			fmt.Printf("%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,
   372  				rule.Enabled, rule.Action, rule.Logging, len(rule.SourceFirewallGroups), len(rule.DestinationFirewallGroups), len(rule.ApplicationPortProfiles), len(rule.NetworkContextProfiles))
   373  		}
   374  
   375  		completeDfw, singleCreatedFwRule, err := vdcGroup.CreateDistributedFirewallRule(previousRuleId, rule)
   376  		check.Assert(err, IsNil)
   377  		check.Assert(completeDfw, NotNil)
   378  		check.Assert(singleCreatedFwRule, NotNil)
   379  		createdIdsFound[singleCreatedFwRule.Rule.ID] = false
   380  
   381  		// caching ID to use as previous rule in case
   382  		if reverseOrder {
   383  			previousRuleId = singleCreatedFwRule.Rule.ID
   384  		}
   385  	}
   386  	fmt.Printf("# Done creating '%d' rules one by one (reverseOrder: %t)\n", len(randomizedFwRuleSubSet), reverseOrder)
   387  
   388  	// Retrieve all firewall rules and check that order matches
   389  	allRules, err := vdcGroup.GetDistributedFirewall()
   390  	check.Assert(err, IsNil)
   391  	check.Assert(len(allRules.DistributedFirewallRuleContainer.Values), Equals, len(randomizedFwRuleSubSet))
   392  
   393  	// check that rule order is exactly as expected (either reverse of randomizedFwRuleSubSet or exactly the same based on reverseOrder parameter)
   394  	if reverseOrder {
   395  		for ruleIndex, rule := range allRules.DistributedFirewallRuleContainer.Values {
   396  			reverseRuleIndex := len(randomizedFwRuleSubSet) - ruleIndex - 1
   397  			check.Assert(rule.Name, Equals, randomizedFwRuleSubSet[reverseRuleIndex].Name)
   398  			createdIdsFound[rule.ID] = true
   399  		}
   400  	} else {
   401  		for ruleIndex, rule := range allRules.DistributedFirewallRuleContainer.Values {
   402  			check.Assert(rule.Name, Equals, randomizedFwRuleSubSet[ruleIndex].Name)
   403  			createdIdsFound[rule.ID] = true
   404  		}
   405  	}
   406  
   407  	// Check that all created IDs are in the final output (none of the firewall rules were recreated)
   408  	for _, value := range createdIdsFound {
   409  		check.Assert(value, Equals, true)
   410  	}
   411  
   412  	// Perform Update
   413  	ruleById, err := vdcGroup.GetDistributedFirewallRuleById(allRules.DistributedFirewallRuleContainer.Values[0].ID)
   414  	check.Assert(err, IsNil)
   415  
   416  	updatedRuleName := check.TestName() + "-updated"
   417  	ruleById.Rule.Name = updatedRuleName
   418  	updatedRule, err := ruleById.Update(ruleById.Rule)
   419  	check.Assert(err, IsNil)
   420  	check.Assert(updatedRule.Rule.Name, Equals, updatedRuleName)
   421  
   422  	// Delete
   423  	err = updatedRule.Delete()
   424  	check.Assert(err, IsNil)
   425  
   426  	notFoundById, err := vdcGroup.GetDistributedFirewallRuleById(updatedRule.Rule.ID)
   427  	check.Assert(err, NotNil)
   428  	check.Assert(notFoundById, IsNil)
   429  
   430  	// Clean up created firewall rules for next phase
   431  	err = vdcGroup.DeleteAllDistributedFirewallRules()
   432  	check.Assert(err, IsNil)
   433  }