Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support MAC address criteria in policy group #388

Merged
merged 2 commits into from
Jul 13, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 64 additions & 1 deletion nsxt/resource_nsxt_policy_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -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",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A MAC instead of An MAC?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, done

Elem: getMACAddressExpressionSchema(),
Optional: true,
MaxItems: 1,
},
},
}
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
Expand Down
56 changes: 51 additions & 5 deletions nsxt/resource_nsxt_policy_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -44,17 +44,38 @@ 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),
resource.TestCheckResourceAttr(testResourceName, "description", "Acceptance Test"),
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"),
),
},
},
Expand Down Expand Up @@ -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"
Expand All @@ -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 {
Expand All @@ -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" {
Expand Down
26 changes: 19 additions & 7 deletions website/docs/r/policy_group.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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.
Expand Down