Skip to content

Commit

Permalink
Merge pull request #363 from terraform-providers/route_redistribution
Browse files Browse the repository at this point in the history
Support route redistribution config for T0
  • Loading branch information
annakhm authored Jun 18, 2020
2 parents a90e8e3 + 84e7801 commit 648adfd
Show file tree
Hide file tree
Showing 4 changed files with 281 additions and 18 deletions.
1 change: 1 addition & 0 deletions nsxt/gateway_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func getPolicyEdgeClusterPathSchema() *schema.Schema {
Description: "The path of the edge cluster connected to this gateway",
Optional: true,
ValidateFunc: validatePolicyPath(),
Computed: true,
}
}

Expand Down
180 changes: 163 additions & 17 deletions nsxt/resource_nsxt_policy_tier0_gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,29 @@ var nsxtPolicyTier0GatewayBgpGracefulRestartModes = []string{
model.BgpGracefulRestartConfig_MODE_HELPER_ONLY,
}

var nsxtPolicyTier0GatewayRedistributionRuleTypes = []string{
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER0_STATIC,
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER0_CONNECTED,
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER0_EXTERNAL_INTERFACE,
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER0_SEGMENT,
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER0_ROUTER_LINK,
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER0_SERVICE_INTERFACE,
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER0_LOOPBACK_INTERFACE,
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER0_DNS_FORWARDER_IP,
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER0_IPSEC_LOCAL_IP,
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER0_NAT,
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER0_EVPN_TEP_IP,
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER1_NAT,
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER1_STATIC,
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER1_LB_VIP,
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER1_LB_SNAT,
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER1_DNS_FORWARDER_IP,
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER1_CONNECTED,
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER1_SERVICE_INTERFACE,
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER1_SEGMENT,
model.Tier0RouteRedistributionRule_ROUTE_REDISTRIBUTION_TYPES_TIER1_IPSEC_LOCAL_ENDPOINT,
}

var policyVRFRouteValues = []string{
model.VrfRouteTargets_ADDRESS_FAMILY_EVPN,
}
Expand Down Expand Up @@ -114,6 +137,7 @@ func resourceNsxtPolicyTier0Gateway() *schema.Resource {
"vrf_config": getPolicyVRFConfigSchema(),
"dhcp_config_path": getPolicyPathSchema(false, false, "Policy path to DHCP server or relay configuration to use for this Tier0"),
"intersite_config": getGatewayIntersiteConfigSchema(),
"redistribution_config": getRedestributionConfigSchema(),
},
}
}
Expand Down Expand Up @@ -213,6 +237,53 @@ func getPolicyBGPConfigSchema() *schema.Schema {
}
}

func getRedestributionConfigSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeList,
Description: "Route Redistribution configuration",
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"enabled": {
Type: schema.TypeBool,
Description: "Flag to enable route redistribution for BGP",
Optional: true,
Default: true,
},
"rule": {
Type: schema.TypeList,
Description: "List of routes to be aggregated",
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Description: "Rule name",
Optional: true,
},
"route_map_path": {
Type: schema.TypeString,
Description: "Route map to be associated with the redistribution rule",
Optional: true,
},
"types": {
Type: schema.TypeSet,
Description: "List of redistribution types",
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice(nsxtPolicyTier0GatewayRedistributionRuleTypes, false),
},
},
},
},
},
},
},
}
}

func getVRFRouteSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeString,
Expand Down Expand Up @@ -617,6 +688,71 @@ func resourceNsxtPolicyTier0GatewayBGPConfigSchemaToStruct(cfg interface{}, isVr
return routeStruct
}

func setLocaleServiceRedestributionConfig(d *schema.ResourceData, serviceStruct *model.LocaleServices) {
var rules []model.Tier0RouteRedistributionRule
redistributionConfigs := d.Get("redistribution_config").([]interface{})
if len(redistributionConfigs) == 0 {
return
}

redistributionConfig := redistributionConfigs[0].(map[string]interface{})
bgp := redistributionConfig["enabled"].(bool)
rulesConfig := redistributionConfig["rule"].([]interface{})

for _, ruleConfig := range rulesConfig {
data := ruleConfig.(map[string]interface{})
name := data["name"].(string)
routeMapPath := data["route_map_path"].(string)
types := data["types"].(*schema.Set).List()

rule := model.Tier0RouteRedistributionRule{
RouteRedistributionTypes: interface2StringList(types),
}

if len(name) > 0 {
rule.Name = &name
}

if len(routeMapPath) > 0 {
rule.RouteMapPath = &routeMapPath
}

rules = append(rules, rule)
}

redistributionStruct := model.Tier0RouteRedistributionConfig{
BgpEnabled: &bgp,
RedistributionRules: rules,
}

serviceStruct.RouteRedistributionConfig = &redistributionStruct
}

func setLocaleServiceRedestributionConfigInSchema(d *schema.ResourceData, serviceStruct *model.LocaleServices) error {
config := serviceStruct.RouteRedistributionConfig
if config == nil {
return nil
}

var redistributionConfigs []map[string]interface{}
var rules []map[string]interface{}
elem := make(map[string]interface{})
elem["enabled"] = config.BgpEnabled

for _, ruleConfig := range config.RedistributionRules {
rule := make(map[string]interface{})
rule["name"] = ruleConfig.Name
rule["route_map_path"] = ruleConfig.RouteMapPath
rule["types"] = ruleConfig.RouteRedistributionTypes
rules = append(rules, rule)
}

elem["rule"] = rules
redistributionConfigs = append(redistributionConfigs, elem)

return d.Set("redistribution_config", redistributionConfigs)
}

func initSingleTier0GatewayLocaleService(d *schema.ResourceData, children []*data.StructValue, connector *client.RestConnector) (*data.StructValue, error) {

edgeClusterPath := d.Get("edge_cluster_path").(string)
Expand All @@ -639,6 +775,8 @@ func initSingleTier0GatewayLocaleService(d *schema.ResourceData, children []*dat
}
}

setLocaleServiceRedestributionConfig(d, serviceStruct)

serviceStruct.EdgeClusterPath = &edgeClusterPath
if len(children) > 0 {
serviceStruct.Children = children
Expand Down Expand Up @@ -738,26 +876,29 @@ func policyTier0GatewayResourceToInfraStruct(d *schema.ResourceData, connector *
}

edgeClusterPath := d.Get("edge_cluster_path").(string)
// Local Manager case
if !isGlobalManager && (len(lsChildren) > 0 || edgeClusterPath != "") {
if d.Get("edge_cluster_path") == "" {
bgpMap := bgpConfig[0].(map[string]interface{})
if bgpMap["enabled"].(bool) {
// BGP requires edge cluster
// TODO: validate at plan time once multi-attribute validation is supported
return infraStruct, fmt.Errorf("A valid edge_cluster_path is required when BGP is enabled")
_, redistributionSet := d.GetOk("redistribution_config")
if !isGlobalManager {
localeServiceNeeded := (len(lsChildren) > 0 || edgeClusterPath != "" || redistributionSet)
// Local Manager
if localeServiceNeeded {
if d.Get("edge_cluster_path") == "" && (len(bgpConfig) > 0) {
bgpMap := bgpConfig[0].(map[string]interface{})
if bgpMap["enabled"].(bool) {
// BGP requires edge cluster
// TODO: validate at plan time once multi-attribute validation is supported
return infraStruct, fmt.Errorf("A valid edge_cluster_path is required when BGP is enabled")
}
}
}

var err error
dataValue, err := initSingleTier0GatewayLocaleService(d, lsChildren, connector)
if err != nil {
return infraStruct, err
var err error
dataValue, err := initSingleTier0GatewayLocaleService(d, lsChildren, connector)
if err != nil {
return infraStruct, err
}
gwChildren = append(gwChildren, dataValue)
}
gwChildren = append(gwChildren, dataValue)
}

if isGlobalManager {
} else {
// Global Manager
localeServices, err := initGatewayLocaleServices(d, connector, listPolicyTier0GatewayLocaleServices)
if err != nil {
return infraStruct, err
Expand Down Expand Up @@ -900,6 +1041,11 @@ func resourceNsxtPolicyTier0GatewayRead(d *schema.ResourceData, m interface{}) e
}
break
}

err := setLocaleServiceRedestributionConfigInSchema(d, &service)
if err != nil {
return fmt.Errorf("Failed to set redistribution config: %v", err)
}
}
}

Expand Down
103 changes: 103 additions & 0 deletions nsxt/resource_nsxt_policy_tier0_gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,56 @@ func TestAccResourceNsxtPolicyTier0Gateway_withDHCP(t *testing.T) {
})
}

func TestAccResourceNsxtPolicyTier0Gateway_redistribution(t *testing.T) {
name := "test-nsx-policy-tier0-redistribution"
testResourceName := "nsxt_policy_tier0_gateway.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccOnlyLocalManager(t); testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: func(state *terraform.State) error {
return testAccNsxtPolicyTier0CheckDestroy(state, name)
},
Steps: []resource.TestStep{
{
Config: testAccNsxtPolicyTier0CreateWithRedistribution(name),
Check: resource.ComposeTestCheckFunc(
testAccNsxtPolicyTier0Exists(testResourceName),
resource.TestCheckResourceAttr(testResourceName, "display_name", name),
resource.TestCheckResourceAttr(testResourceName, "redistribution_config.#", "1"),
resource.TestCheckResourceAttr(testResourceName, "redistribution_config.0.enabled", "false"),
resource.TestCheckResourceAttr(testResourceName, "redistribution_config.0.rule.#", "1"),
resource.TestCheckResourceAttr(testResourceName, "redistribution_config.0.rule.0.types.#", "3"),
resource.TestCheckResourceAttr(realizationResourceName, "state", "REALIZED"),
),
},
{
Config: testAccNsxtPolicyTier0UpdateWithRedistribution(name),
Check: resource.ComposeTestCheckFunc(
testAccNsxtPolicyTier0Exists(testResourceName),
resource.TestCheckResourceAttr(testResourceName, "display_name", name),
resource.TestCheckResourceAttr(testResourceName, "redistribution_config.#", "1"),
resource.TestCheckResourceAttr(testResourceName, "redistribution_config.0.enabled", "false"),
resource.TestCheckResourceAttr(testResourceName, "redistribution_config.0.rule.#", "2"),
resource.TestCheckResourceAttr(testResourceName, "redistribution_config.0.rule.0.types.#", "0"),
resource.TestCheckResourceAttr(realizationResourceName, "state", "REALIZED"),
),
},
{
Config: testAccNsxtPolicyTier0Update2WithRedistribution(name),
Check: resource.ComposeTestCheckFunc(
testAccNsxtPolicyTier0Exists(testResourceName),
resource.TestCheckResourceAttr(testResourceName, "display_name", name),
resource.TestCheckResourceAttr(testResourceName, "redistribution_config.#", "1"),
resource.TestCheckResourceAttr(testResourceName, "redistribution_config.0.enabled", "false"),
resource.TestCheckResourceAttr(testResourceName, "redistribution_config.0.rule.#", "0"),
resource.TestCheckResourceAttr(realizationResourceName, "state", "REALIZED"),
),
},
},
})
}

func TestAccResourceNsxtPolicyTier0Gateway_withEdgeCluster(t *testing.T) {
name := fmt.Sprintf("test-nsx-policy-tier0-ec")
updateName := fmt.Sprintf("%s-update", name)
Expand Down Expand Up @@ -698,3 +748,56 @@ resource "nsxt_policy_tier0_gateway_interface" "parent-loopback" {
subnets = ["4.4.4.12/24"]
}`
}

func testAccNsxtPolicyTier0CreateWithRedistribution(name string) string {
return fmt.Sprintf(`
resource "nsxt_policy_tier0_gateway" "test" {
display_name = "%s"
redistribution_config {
enabled = false
rule {
name = "test-rule-1"
types = ["TIER0_SEGMENT", "TIER0_EVPN_TEP_IP", "TIER1_CONNECTED"]
}
}
}
data "nsxt_policy_realization_info" "realization_info" {
path = nsxt_policy_tier0_gateway.test.path
}`, name)
}

func testAccNsxtPolicyTier0UpdateWithRedistribution(name string) string {
return fmt.Sprintf(`
resource "nsxt_policy_tier0_gateway" "test" {
display_name = "%s"
redistribution_config {
enabled = false
rule {
name = "test-rule-1"
}
rule {
name = "test-rule-3"
types = ["TIER1_CONNECTED"]
}
}
}
data "nsxt_policy_realization_info" "realization_info" {
path = nsxt_policy_tier0_gateway.test.path
}`, name)
}

func testAccNsxtPolicyTier0Update2WithRedistribution(name string) string {
return fmt.Sprintf(`
resource "nsxt_policy_tier0_gateway" "test" {
display_name = "%s"
redistribution_config {
enabled = false
}
}
data "nsxt_policy_realization_info" "realization_info" {
path = nsxt_policy_tier0_gateway.test.path
}`, name)
}
15 changes: 14 additions & 1 deletion website/docs/r/policy_tier0_gateway.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ resource "nsxt_policy_tier0_gateway" "tier0_gw" {
}
}
redistribution_config {
enabled = true
rule {
name = "rule1"
types = ["TIER0_STATIC", "TIER0_CONNECTED", "TIER1_CONNECTED"]
}
}
tag {
scope = "color"
tag = "blue"
Expand Down Expand Up @@ -132,7 +140,12 @@ The following arguments are supported:
* `transit_subnet` - (Optional) IPv4 subnet for inter-site transit segment connecting service routers across sites for stretched gateway. For IPv6 link local subnet is auto configured.
* `primary_site_path` - (Optional) Primary egress site for gateway.
* `fallback_site_paths` - (Optional) Fallback sites to be used as new primary site on current primary site failure.

* `redistribution_config` - (Optional) Route redistribution properties. This setting is for local manager only.
* `enabled` - (Optional) Enable route redistribution for BGP
* `rule` - (Optional) List of redistribution rules.
* `name` - (Optional) Rule name.
* `route_map_path` - (Optional) Route map to be associated with the redistribution rule.
* `types` - (Optional) List of redistribution types, possible values are: `TIER0_STATIC`, `TIER0_CONNECTED`, `TIER0_EXTERNAL_INTERFACE`, `TIER0_SEGMENT`, `TIER0_ROUTER_LINK`, `TIER0_SERVICE_INTERFACE`, `TIER0_LOOPBACK_INTERFACE`, `TIER0_DNS_FORWARDER_IP`, `TIER0_IPSEC_LOCAL_IP`, `TIER0_NAT`, `TIER0_EVPN_TEP_IP`, `TIER1_NAT`, `TIER1_STATIC`, `TIER1_LB_VIP`, `TIER1_LB_SNAT`, `TIER1_DNS_FORWARDER_IP`, `TIER1_CONNECTED`, `TIER1_SERVICE_INTERFACE`, `TIER1_SEGMENT`, `TIER1_IPSEC_LOCAL_ENDPOINT`.

## Attributes Reference

Expand Down

0 comments on commit 648adfd

Please sign in to comment.