Skip to content

Commit

Permalink
Merge pull request #388 from terraform-providers/mac_address_in_group
Browse files Browse the repository at this point in the history
Support MAC address criteria in policy group
  • Loading branch information
annakhm authored Jul 13, 2020
2 parents 4c6f7a7 + 7e53ddf commit 7ebca3b
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 13 deletions.
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: "MAC address expression specifying MAC Address members in the Group",
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

0 comments on commit 7ebca3b

Please sign in to comment.