From 39e9ff3faa2c723e1ded3e2eebbd62c5fa962d65 Mon Sep 17 00:00:00 2001 From: Anna Khmelnitsky Date: Wed, 8 Jul 2020 16:59:45 -0700 Subject: [PATCH 1/2] Support MAC address criteria in policy group --- nsxt/resource_nsxt_policy_group.go | 65 ++++++++++++++++++++++- nsxt/resource_nsxt_policy_group_test.go | 56 +++++++++++++++++-- website/docs/r/policy_group.html.markdown | 26 ++++++--- 3 files changed, 134 insertions(+), 13 deletions(-) diff --git a/nsxt/resource_nsxt_policy_group.go b/nsxt/resource_nsxt_policy_group.go index 37ef376eb..cd5d575ab 100644 --- a/nsxt/resource_nsxt_policy_group.go +++ b/nsxt/resource_nsxt_policy_group.go @@ -15,6 +15,7 @@ import ( "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/infra/domains" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" "log" + "strings" ) var conditionKeyValues = []string{ @@ -99,6 +100,22 @@ func getIPAddressExpressionSchema() *schema.Resource { } } +func getMACAddressExpressionSchema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "mac_addresses": { + Type: schema.TypeSet, + Required: true, + Description: "List of Mac Addresses", + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.IsMACAddress, + }, + }, + }, + } +} + func getPathExpressionSchema() *schema.Resource { return &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -201,6 +218,13 @@ func getCriteriaSetSchema() *schema.Resource { Elem: getPathExpressionSchema(), MaxItems: 1, }, + "macaddress_expression": { + Type: schema.TypeList, + Description: "An MAC address expression specifying MAC Address members in the Group", + Elem: getMACAddressExpressionSchema(), + Optional: true, + MaxItems: 1, + }, }, } } @@ -287,7 +311,7 @@ func validateGroupCriteriaSets(criteriaSets []interface{}) ([]criteriaMeta, erro return nil, err } memberType = mType - } else if expName == "ipaddress_expression" || expName == "path_expression" { + } else if strings.HasSuffix(expName, "_expression") { memberType = "" } else { return nil, fmt.Errorf("Unknown criteria: %v", expName) @@ -380,6 +404,25 @@ func buildGroupIPAddressData(ipaddr interface{}) (*data.StructValue, error) { return dataValue.(*data.StructValue), nil } +func buildGroupMacAddressData(ipaddr interface{}) (*data.StructValue, error) { + addrMap := ipaddr.(map[string]interface{}) + var macList []string + for _, mac := range addrMap["mac_addresses"].(*schema.Set).List() { + macList = append(macList, mac.(string)) + } + addrStruct := model.MACAddressExpression{ + MacAddresses: macList, + ResourceType: model.MACAddressExpression__TYPE_IDENTIFIER, + } + converter := bindings.NewTypeConverter() + converter.SetMode(bindings.REST) + dataValue, errors := converter.ConvertToVapi(addrStruct, model.MACAddressExpressionBindingType()) + if errors != nil { + return nil, errors[0] + } + return dataValue.(*data.StructValue), nil +} + func buildGroupMemberPathData(paths interface{}) (*data.StructValue, error) { pathMap := paths.(map[string]interface{}) var pathList []string @@ -444,6 +487,12 @@ func buildGroupExpressionDataFromType(expressionType string, datum interface{}) return nil, err } return data, nil + } else if expressionType == "macaddress_expression" { + data, err := buildGroupMacAddressData(datum) + if err != nil { + return nil, err + } + return data, nil } return nil, fmt.Errorf("Unknown expression type: %v", expressionType) } @@ -577,6 +626,20 @@ func fromGroupExpressionData(expressions []*data.StructValue) ([]map[string]inte pathList = append(pathList, pathMap) exprMap["path_expression"] = pathList parsedCriteria = append(parsedCriteria, exprMap) + } else if expStruct.ResourceType == model.MACAddressExpression__TYPE_IDENTIFIER { + log.Printf("[DEBUG] Parsing mac address expression") + macData, errors := converter.ConvertToGolang(expression, model.MACAddressExpressionBindingType()) + if len(errors) > 0 { + return nil, nil, errors[0] + } + macStruct := macData.(model.MACAddressExpression) + var addrList []map[string]interface{} + var addrMap = make(map[string]interface{}) + addrMap["mac_addresses"] = macStruct.MacAddresses + var macMap = make(map[string]interface{}) + addrList = append(addrList, addrMap) + macMap["macaddress_expression"] = addrList + parsedCriteria = append(parsedCriteria, macMap) } else if expStruct.ResourceType == model.Condition__TYPE_IDENTIFIER { log.Printf("[DEBUG] Parsing condition") condMap, err := groupConditionDataToMap(expression) diff --git a/nsxt/resource_nsxt_policy_group_test.go b/nsxt/resource_nsxt_policy_group_test.go index 3b6c8f5fa..cebb536a1 100644 --- a/nsxt/resource_nsxt_policy_group_test.go +++ b/nsxt/resource_nsxt_policy_group_test.go @@ -32,7 +32,7 @@ func TestAccResourceNsxtPolicyGroup_basicImport(t *testing.T) { }) } -func TestAccResourceNsxtPolicyGroup_singleIPAddressCriteria(t *testing.T) { +func TestAccResourceNsxtPolicyGroup_AddressCriteria(t *testing.T) { name := fmt.Sprintf("test-nsx-policy-group-ipaddrs") testResourceName := "nsxt_policy_group.test" @@ -44,7 +44,7 @@ func TestAccResourceNsxtPolicyGroup_singleIPAddressCriteria(t *testing.T) { }, Steps: []resource.TestStep{ { - Config: testAccNsxtPolicyGroupIPAddressCreateTemplate(name), + Config: testAccNsxtPolicyGroupAddressCreateTemplate(name), Check: resource.ComposeTestCheckFunc( testAccNsxtPolicyGroupExists(testResourceName, defaultDomain), resource.TestCheckResourceAttr(testResourceName, "display_name", name), @@ -52,9 +52,30 @@ func TestAccResourceNsxtPolicyGroup_singleIPAddressCriteria(t *testing.T) { resource.TestCheckResourceAttr(testResourceName, "domain", defaultDomain), resource.TestCheckResourceAttrSet(testResourceName, "path"), resource.TestCheckResourceAttrSet(testResourceName, "revision"), - resource.TestCheckNoResourceAttr(testResourceName, "conjunction"), + resource.TestCheckResourceAttr(testResourceName, "conjunction.#", "1"), resource.TestCheckResourceAttr(testResourceName, "tag.#", "2"), + resource.TestCheckResourceAttr(testResourceName, "criteria.#", "2"), + resource.TestCheckResourceAttr(testResourceName, "criteria.0.ipaddress_expression.#", "1"), + resource.TestCheckResourceAttr(testResourceName, "criteria.0.ipaddress_expression.0.ip_addresses.#", "2"), + resource.TestCheckResourceAttr(testResourceName, "criteria.1.macaddress_expression.#", "1"), + resource.TestCheckResourceAttr(testResourceName, "criteria.1.macaddress_expression.0.mac_addresses.#", "2"), + ), + }, + { + Config: testAccNsxtPolicyGroupAddressUpdateTemplate(name), + Check: resource.ComposeTestCheckFunc( + testAccNsxtPolicyGroupExists(testResourceName, defaultDomain), + resource.TestCheckResourceAttr(testResourceName, "display_name", name), + resource.TestCheckResourceAttr(testResourceName, "description", "Acceptance Test"), + resource.TestCheckResourceAttr(testResourceName, "domain", defaultDomain), + resource.TestCheckResourceAttrSet(testResourceName, "path"), + resource.TestCheckResourceAttrSet(testResourceName, "revision"), + resource.TestCheckResourceAttr(testResourceName, "conjunction.#", "0"), + resource.TestCheckResourceAttr(testResourceName, "tag.#", "0"), resource.TestCheckResourceAttr(testResourceName, "criteria.#", "1"), + resource.TestCheckResourceAttr(testResourceName, "criteria.0.ipaddress_expression.#", "1"), + resource.TestCheckResourceAttr(testResourceName, "criteria.0.ipaddress_expression.0.ip_addresses.#", "1"), + resource.TestCheckResourceAttr(testResourceName, "criteria.1.macaddress_expression.#", "0"), ), }, }, @@ -525,7 +546,7 @@ resource "nsxt_policy_group" "test" { `, name) } -func testAccNsxtPolicyGroupIPAddressCreateTemplate(name string) string { +func testAccNsxtPolicyGroupAddressCreateTemplate(name string) string { return fmt.Sprintf(` resource "nsxt_policy_group" "test" { display_name = "%s" @@ -534,7 +555,17 @@ resource "nsxt_policy_group" "test" { criteria { ipaddress_expression { ip_addresses = ["111.1.1.1", "222.2.2.2"] - } + } + } + + conjunction { + operator = "OR" + } + + criteria { + macaddress_expression { + mac_addresses = ["a2:54:00:68:b0:83", "fa:10:3e:01:49:5e"] + } } tag { @@ -550,6 +581,21 @@ resource "nsxt_policy_group" "test" { `, name) } +func testAccNsxtPolicyGroupAddressUpdateTemplate(name string) string { + return fmt.Sprintf(` +resource "nsxt_policy_group" "test" { + display_name = "%s" + description = "Acceptance Test" + + criteria { + ipaddress_expression { + ip_addresses = ["111.1.1.1"] + } + } +} +`, name) +} + func testAccNsxtGlobalPolicyGroupIPAddressCreateTemplate(name string, siteName string) string { return fmt.Sprintf(` data "nsxt_policy_site" "test" { diff --git a/website/docs/r/policy_group.html.markdown b/website/docs/r/policy_group.html.markdown index e6994659b..d44f57620 100644 --- a/website/docs/r/policy_group.html.markdown +++ b/website/docs/r/policy_group.html.markdown @@ -41,6 +41,16 @@ resource "nsxt_policy_group" "group1" { } } + conjunction { + operator = "OR" + } + + criteria { + macaddress_expression { + mac_addresses = ["b2:54:00:98:b0:83"] + } + } + extended_criteria { identity_group { distinguished_name = "cn=u1,ou=users,dc=example,dc=local" @@ -102,16 +112,18 @@ The following arguments are supported: * `nsx_id` - (Optional) The NSX ID of this resource. If set, this ID will be used to create the group resource. * `criteria` - (Optional) A repeatable block to specify criteria for members of this Group. If more than 1 criteria block is specified, it must be separated by a `conjunction`. In a `criteria` block the following membership selection expressions can be used: * `ipaddress_expression` - (Optional) An expression block to specify individual IP Addresses, ranges of IP Addresses or subnets for this Group. - * `ip_addresses` - (Required for a `ipaddress_expression`) This list can consist of a single IP address, IP address range or a subnet. Its type can be of either IPv4 or IPv6. Both IPv4 and IPv6 addresses within one expression is not allowed. + * `ip_addresses` - (Required) This list can consist of a single IP address, IP address range or a subnet. Its type can be of either IPv4 or IPv6. Both IPv4 and IPv6 addresses within one expression is not allowed. + * `macaddress_expression` - (Optional) An expression block to specify individual MAC Addresses for this Group. + * `mac_addresses` - (Required) List of MAC addresses. * `path_expression` - (Optional) An expression block to specify direct group members by policy path. - * `member_paths` - (Required for a `path_expression`) List of policy paths for direct members for this Group (such as Segments, Segment ports, Groups etc). + * `member_paths` - (Required) List of policy paths for direct members for this Group (such as Segments, Segment ports, Groups etc). * `condition` (Optional) A repeatable condition block to select this Group's members. When multiple `condition` blocks are used in a single `criteria` they form a nested expression that's implicitly ANDed together and each nested condition must used the same `member_type`. - * `key` (Required for a `condition`) Specifies the attribute to query. Must be one of: `Tag`, `ComputerName`, `OSName` or `Name`. For a `member_type` other than `VirtualMachine`, only the `Tag` key is supported. - * `member_type` (Required for a `condition`) Specifies the type of resource to query. Must be one of: `IPSet`, `LogicalPort`, `LogicalSwitch`, `Segment`, `SegmentPort` or `VirtualMachine`. - * `operator` (Required for a `condition`) Specifies the query operator to use. Must be one of: `CONTAINS`, `ENDSWITH`, `EQUALS`, `NOTEQUALS` or `STARTSWITH`. - * `value` (Required for a `condition`) User specified string value to use in the query. For `Tag` criteria, use 'scope|value' notation if you wish to specify scope in criteria. + * `key` (Required) Specifies the attribute to query. Must be one of: `Tag`, `ComputerName`, `OSName` or `Name`. For a `member_type` other than `VirtualMachine`, only the `Tag` key is supported. + * `member_type` (Required) Specifies the type of resource to query. Must be one of: `IPSet`, `LogicalPort`, `LogicalSwitch`, `Segment`, `SegmentPort` or `VirtualMachine`. + * `operator` (Required) Specifies the query operator to use. Must be one of: `CONTAINS`, `ENDSWITH`, `EQUALS`, `NOTEQUALS` or `STARTSWITH`. + * `value` (Required) User specified string value to use in the query. For `Tag` criteria, use 'scope|value' notation if you wish to specify scope in criteria. * `conjunction` (Required for multiple `criteria`) When specifying multiple `criteria`, a conjunction is used to specify if the criteria should selected using `AND` or `OR`. - * `operator` (Required for `conjunction`) The operator to use. Must be one of `AND` or `OR`. If `AND` is used, then the `criteria` block before/after must be of the same type and if using `condition` then also must use the same `member_type`. + * `operator` (Required) The operator to use. Must be one of `AND` or `OR`. If `AND` is used, then the `criteria` block before/after must be of the same type and if using `condition` then also must use the same `member_type`. * `extended_criteria` (Optional) A condition block to specify higher level context to include in this Group's members. (e.g. user AD group). This configuration is for Local Manager only. Currently only one block is supported by NSX. Note that `extended_criteria` is implicitly `AND` with `criteria`. * `identity_group` (Optional) A repeatable condition block selecting user AD groups to be included in this Group. Note that `identity_groups` are `OR` with each other. * `distinguished_name` (Required for an `identity_group`) LDAP distinguished name (DN). A valid fully qualified distinguished name should be provided here. This value is valid only if it matches to exactly 1 LDAP object on the LDAP server. From 7e53ddfdd788c6da3e3bb7cb100057f5ab8dc83d Mon Sep 17 00:00:00 2001 From: Anna Khmelnitsky Date: Mon, 13 Jul 2020 09:47:12 -0700 Subject: [PATCH 2/2] Fix typo in mac address description --- nsxt/resource_nsxt_policy_group.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nsxt/resource_nsxt_policy_group.go b/nsxt/resource_nsxt_policy_group.go index cd5d575ab..0557fea3c 100644 --- a/nsxt/resource_nsxt_policy_group.go +++ b/nsxt/resource_nsxt_policy_group.go @@ -220,7 +220,7 @@ func getCriteriaSetSchema() *schema.Resource { }, "macaddress_expression": { Type: schema.TypeList, - Description: "An MAC address expression specifying MAC Address members in the Group", + Description: "MAC address expression specifying MAC Address members in the Group", Elem: getMACAddressExpressionSchema(), Optional: true, MaxItems: 1,