From 84e7801399b7d1db641ed24c450b64547ba6fbbd Mon Sep 17 00:00:00 2001 From: Anna Khmelnitsky Date: Wed, 17 Jun 2020 18:52:40 -0700 Subject: [PATCH] Support roue redistribution config for T0 This is for local manager only. Global Manager support will follow. --- nsxt/gateway_common.go | 1 + nsxt/resource_nsxt_policy_tier0_gateway.go | 180 ++++++++++++++++-- ...resource_nsxt_policy_tier0_gateway_test.go | 103 ++++++++++ .../docs/r/policy_tier0_gateway.html.markdown | 15 +- 4 files changed, 281 insertions(+), 18 deletions(-) diff --git a/nsxt/gateway_common.go b/nsxt/gateway_common.go index 83ccf68e5..70a2b1b6f 100644 --- a/nsxt/gateway_common.go +++ b/nsxt/gateway_common.go @@ -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, } } diff --git a/nsxt/resource_nsxt_policy_tier0_gateway.go b/nsxt/resource_nsxt_policy_tier0_gateway.go index 4c419bd74..0936218e6 100644 --- a/nsxt/resource_nsxt_policy_tier0_gateway.go +++ b/nsxt/resource_nsxt_policy_tier0_gateway.go @@ -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, } @@ -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(), }, } } @@ -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, @@ -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) @@ -639,6 +775,8 @@ func initSingleTier0GatewayLocaleService(d *schema.ResourceData, children []*dat } } + setLocaleServiceRedestributionConfig(d, serviceStruct) + serviceStruct.EdgeClusterPath = &edgeClusterPath if len(children) > 0 { serviceStruct.Children = children @@ -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 @@ -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) + } } } diff --git a/nsxt/resource_nsxt_policy_tier0_gateway_test.go b/nsxt/resource_nsxt_policy_tier0_gateway_test.go index 9ef7a02b9..3f3ae7bce 100644 --- a/nsxt/resource_nsxt_policy_tier0_gateway_test.go +++ b/nsxt/resource_nsxt_policy_tier0_gateway_test.go @@ -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) @@ -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) +} diff --git a/website/docs/r/policy_tier0_gateway.html.markdown b/website/docs/r/policy_tier0_gateway.html.markdown index 050520299..2b299025c 100644 --- a/website/docs/r/policy_tier0_gateway.html.markdown +++ b/website/docs/r/policy_tier0_gateway.html.markdown @@ -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" @@ -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