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

Add interface esi settings #134

Merged
merged 22 commits into from
Mar 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
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
106 changes: 105 additions & 1 deletion junos/resource_interface_physical.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type interfacePhysicalOptions struct {
description string
v8023ad string
vlanMembers []string
esi []map[string]interface{}
}

func resourceInterfacePhysical() *schema.Resource {
Expand Down Expand Up @@ -72,6 +73,42 @@ func resourceInterfacePhysical() *schema.Resource {
Type: schema.TypeString,
Optional: true,
},
"esi": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"mode": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{"all-active", "single-active"}, false),
},
"auto_derive_lacp": {
Type: schema.TypeBool,
Optional: true,
ConflictsWith: []string{"esi.0.identifier"},
},
"df_election_type": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{"mod", "preference"}, false),
},
"identifier": {
Type: schema.TypeString,
Optional: true,
ConflictsWith: []string{"esi.0.auto_derive_lacp"},
ValidateFunc: validation.StringMatch(regexp.MustCompile(
`^([\d\w]{2}:){9}[\d\w]{2}$`), "bad format or length"),
},
"source_bmac": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.IsMACAddress,
},
},
},
},
"ether802_3ad": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -435,6 +472,9 @@ func setInterfacePhysical(d *schema.ResourceData, m interface{}, jnprSess *Netco
if d.Get("description").(string) != "" {
configSet = append(configSet, setPrefix+"description \""+d.Get("description").(string)+"\"")
}
if err := setIntEsi(setPrefix, d.Get("esi").([]interface{}), m, jnprSess); err != nil {
return err
}
if v := d.Get("name").(string); strings.HasPrefix(v, "ae") {
aggregatedCount, err := interfaceAggregatedCountSearchMax(v, "ae-1", v, m, jnprSess)
if err != nil {
Expand Down Expand Up @@ -476,6 +516,32 @@ func setInterfacePhysical(d *schema.ResourceData, m interface{}, jnprSess *Netco

return sess.configSet(configSet, jnprSess)
}
func setIntEsi(setPrefix string, esiParams []interface{},
m interface{}, jnprSess *NetconfObject) error {
sess := m.(*Session)
configSet := make([]string, 0)

for _, v := range esiParams {
m := v.(map[string]interface{})
if m["mode"].(string) != "" {
configSet = append(configSet, setPrefix+"esi "+m["mode"].(string))
}
if m["auto_derive_lacp"].(bool) {
configSet = append(configSet, setPrefix+"esi auto-derive lacp")
}
if m["df_election_type"].(string) != "" {
configSet = append(configSet, setPrefix+"esi df-election-type "+m["df_election_type"].(string))
}
if m["identifier"].(string) != "" {
configSet = append(configSet, setPrefix+"esi "+m["identifier"].(string))
}
if m["source_bmac"].(string) != "" {
configSet = append(configSet, setPrefix+"esi source-bmac "+m["source_bmac"].(string))
}
}

return sess.configSet(configSet, jnprSess)
}
func readInterfacePhysical(interFace string, m interface{}, jnprSess *NetconfObject) (interfacePhysicalOptions, error) {
sess := m.(*Session)
var confRead interfacePhysicalOptions
Expand Down Expand Up @@ -509,7 +575,10 @@ func readInterfacePhysical(interFace string, m interface{}, jnprSess *NetconfObj
}
case strings.HasPrefix(itemTrim, "description "):
confRead.description = strings.Trim(strings.TrimPrefix(itemTrim, "description "), "\"")

case strings.HasPrefix(itemTrim, "esi "):
if err := readIntEsi(&confRead, itemTrim); err != nil {
return confRead, err
}
case strings.HasPrefix(itemTrim, "ether-options 802.3ad "):
confRead.v8023ad = strings.TrimPrefix(itemTrim, "ether-options 802.3ad ")
case strings.HasPrefix(itemTrim, "gigether-options 802.3ad "):
Expand All @@ -534,6 +603,37 @@ func readInterfacePhysical(interFace string, m interface{}, jnprSess *NetconfObj

return confRead, nil
}
func readIntEsi(confRead *interfacePhysicalOptions, item string) error {
itemTrim := strings.TrimPrefix(item, "esi ")
if len(confRead.esi) == 0 {
confRead.esi = append(confRead.esi, map[string]interface{}{
"mode": "",
"auto_derive_lacp": false,
"df_election_type": "",
"identifier": "",
"source_bmac": "",
})
}
var err error
identifier, err := regexp.MatchString(`^([\d\w]{2}:){9}[\d\w]{2}`, itemTrim)
if err != nil {
return fmt.Errorf("esi_identifier regexp error: %w", err)
}
switch {
case identifier:
confRead.esi[0]["identifier"] = itemTrim
case itemTrim == "all-active" || itemTrim == "single-active":
confRead.esi[0]["mode"] = itemTrim
case strings.HasPrefix(itemTrim, "df-election-type "):
confRead.esi[0]["df_election_type"] = strings.TrimPrefix(itemTrim, "df-election-type ")
case strings.HasPrefix(itemTrim, "source-bmac "):
confRead.esi[0]["source_bmac"] = strings.TrimPrefix(itemTrim, "source-bmac ")
case itemTrim == "auto-derive lacp":
confRead.esi[0]["auto_derive_lacp"] = true
}

return nil
}
func delInterfacePhysical(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error {
sess := m.(*Session)
if err := checkInterfacePhysicalContainsUnit(d.Get("name").(string), m, jnprSess); err != nil {
Expand Down Expand Up @@ -628,6 +728,7 @@ func delInterfacePhysicalOpts(d *schema.ResourceData, m interface{}, jnprSess *N
delPrefix := "delete interfaces " + d.Get("name").(string) + " "
configSet = append(configSet,
delPrefix+"aggregated-ether-options",
delPrefix+"esi",
delPrefix+"ether-options 802.3ad",
delPrefix+"gigether-options 802.3ad",
delPrefix+"native-vlan-id",
Expand All @@ -649,6 +750,9 @@ func fillInterfacePhysicalData(d *schema.ResourceData, interfaceOpt interfacePhy
if tfErr := d.Set("ae_minimum_links", interfaceOpt.aeMinLink); tfErr != nil {
panic(tfErr)
}
if tfErr := d.Set("esi", interfaceOpt.esi); tfErr != nil {
panic(tfErr)
}
if tfErr := d.Set("description", interfaceOpt.description); tfErr != nil {
panic(tfErr)
}
Expand Down
20 changes: 20 additions & 0 deletions junos/resource_interface_physical_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ func TestAccJunosInterfacePhysical_basic(t *testing.T) {
"ae_minimum_links", "1"),
resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE",
"vlan_tagging", "true"),
resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE",
"esi.#", "1"),
resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE",
"esi.0.identifier", "00:01:11:11:11:11:11:11:11:11"),
resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE",
"esi.0.mode", "all-active"),
),
},
{
Expand All @@ -96,6 +102,12 @@ func TestAccJunosInterfacePhysical_basic(t *testing.T) {
"ae_lacp", ""),
resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE",
"ae_minimum_links", "0"),
resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE",
"esi.#", "1"),
resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE",
"esi.0.identifier", "00:11:11:11:11:11:11:11:11:11"),
resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE",
"esi.0.mode", "all-active"),
),
},
{
Expand Down Expand Up @@ -147,6 +159,10 @@ resource junos_interface_physical testacc_interfaceAE {
ae_lacp = "active"
ae_minimum_links = 1
vlan_tagging = true
esi {
identifier = "00:01:11:11:11:11:11:11:11:11"
mode = "all-active"
}
}
`)
}
Expand All @@ -161,6 +177,10 @@ resource junos_interface_physical testacc_interfaceAE {
name = junos_interface_physical.testacc_interface.ether802_3ad
description = "testacc_interfaceAE"
vlan_tagging = true
esi {
identifier = "00:11:11:11:11:11:11:11:11:11"
mode = "all-active"
}
}
`)
}
9 changes: 9 additions & 0 deletions website/docs/r/interface_physical.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,21 @@ The following arguments are supported:
* `ae_link_speed` - (Optional)(`String`) Link speed of individual interface that joins the AE.
* `ae_minimum_links` - (Optional)(`Int`) Minimum number of aggregated links (1..8).
* `description` - (Optional)(`String`) Description for interface.
* `esi` -(Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to define ESI Config parameters. See the [`esi` arguments](#esi-arguments) block.
* `ether802_3ad` - (Optional)(`String`) Name of aggregated device for add this interface to link of 802.3ad interface.
* `trunk` - (Optional)(`Bool`) Interface mode is trunk.
* `vlan_members` - (Optional)(`ListOfString`) List of vlan for membership for this interface.
* `vlan_native` - (Optional)(`Int`) Vlan for untagged frames.
* `vlan_tagging` - (Optional)(`Bool`) Add 802.1q VLAN tagging support.

---
#### esi arguments
* `mode` - (Required)(`String`) ESI Mode
* `identifier` - (Optional)(`String`) The ESI value for the interface
* `auto_derive_lacp` - (Optional)(`Bool`) Auto-derive ESI value for the interface
* `df_election_type` - (Optional)(`String`) DF Election Type
* `source_bmac` - (Optional)(`String`) Unicast Source B-MAC address per ESI for PBB-EVPN

~> **NOTE:** This resource computes the maximum number of aggregate interfaces required with the current configuration (searches lines `ether-options 802.3ad` and `ae` interfaces set) then add/remove `chassis aggregated-devices ethernet device-count` line with this maximum.

## Import
Expand Down