From 6c1c26b6664e4e566bbb43e486aa34ff14104bf1 Mon Sep 17 00:00:00 2001 From: MegaportPhilipBrowne Date: Thu, 23 Jul 2026 04:27:59 -0700 Subject: [PATCH 1/5] ESD-1687: Expose as-override on VXC BGP connections --- go.mod | 2 +- go.sum | 4 +-- internal/commands/vxc/vxc_inputs_partner.go | 5 ++++ internal/commands/vxc/vxc_inputs_test.go | 28 ++++++++++++++++++++ internal/commands/vxc/vxc_prompts_test.go | 7 +++++ internal/commands/vxc/vxc_prompts_vrouter.go | 17 ++++++++++++ 6 files changed, 60 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 048cf461..735062db 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/fatih/color v1.19.0 github.com/jedib0t/go-pretty/v6 v6.8.3 github.com/jmespath/go-jmespath v0.4.0 - github.com/megaport/megaportgo v1.15.0 + github.com/megaport/megaportgo v1.17.0 github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d github.com/spf13/cobra v1.10.2 github.com/spf13/pflag v1.0.10 diff --git a/go.sum b/go.sum index 2d62b697..0ff0f4ab 100644 --- a/go.sum +++ b/go.sum @@ -68,8 +68,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.17 h1:78v8ZlW0bP43XfmAfPsdXcoNCelfMHsDmd/pkENfrjQ= github.com/mattn/go-runewidth v0.0.17/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/megaport/megaportgo v1.15.0 h1:e1l/0lJcr0RQ1kPdEeLuBHPGbvjgXUa1FAeFkc8K4mE= -github.com/megaport/megaportgo v1.15.0/go.mod h1:dF1MxT8/kD6FWb4/ojrklWinIUp5exn8v8xYJVUB3Zc= +github.com/megaport/megaportgo v1.17.0 h1:H1aGlUCREFf2F0LH0SIzwYUosQyuZEtynekSzai1mZE= +github.com/megaport/megaportgo v1.17.0/go.mod h1:LoNE7I/7Btg6A63ZezVaMqO5WiGYhDxLsPdPRmt1k78= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= diff --git a/internal/commands/vxc/vxc_inputs_partner.go b/internal/commands/vxc/vxc_inputs_partner.go index 2e166bbe..0458898c 100644 --- a/internal/commands/vxc/vxc_inputs_partner.go +++ b/internal/commands/vxc/vxc_inputs_partner.go @@ -676,6 +676,11 @@ func parseBGPConnections(raw interface{}, ifaceIndex int) ([]megaport.BgpConnect } else if ok { conn.PeerType = v } + if v, ok, err := boolField("asOverride"); err != nil { + return nil, err + } else if ok { + conn.AsOverride = &v + } conns = append(conns, conn) } diff --git a/internal/commands/vxc/vxc_inputs_test.go b/internal/commands/vxc/vxc_inputs_test.go index b9aa16a7..9b09a66f 100644 --- a/internal/commands/vxc/vxc_inputs_test.go +++ b/internal/commands/vxc/vxc_inputs_test.go @@ -851,6 +851,7 @@ func TestParseVRouterConfigBGP(t *testing.T) { "exportBlacklist": 202.0, "asPathPrependCount": 3.0, "peerType": "NON_CLOUD", + "asOverride": true, }, }, }, @@ -882,6 +883,31 @@ func TestParseVRouterConfigBGP(t *testing.T) { assert.Equal(t, 202, conn.ExportBlacklist) assert.Equal(t, 3, conn.AsPathPrependCount) assert.Equal(t, "NON_CLOUD", conn.PeerType) + if assert.NotNil(t, conn.AsOverride) { + assert.True(t, *conn.AsOverride) + } + }, + }, + { + name: "asOverride false sets pointer to false", + config: map[string]interface{}{ + "connectType": "VROUTER", + "interfaces": []interface{}{ + map[string]interface{}{ + "bgpConnections": []interface{}{ + map[string]interface{}{ + "peerAsn": 65000.0, + "asOverride": false, + }, + }, + }, + }, + }, + validate: func(t *testing.T, cfg *megaport.VXCOrderVrouterPartnerConfig) { + conn := cfg.Interfaces[0].BgpConnections[0] + if assert.NotNil(t, conn.AsOverride) { + assert.False(t, *conn.AsOverride) + } }, }, { @@ -906,6 +932,7 @@ func TestParseVRouterConfigBGP(t *testing.T) { assert.Nil(t, conn.LocalAsn) assert.Nil(t, conn.PermitExportTo) assert.Nil(t, conn.DenyExportTo) + assert.Nil(t, conn.AsOverride) }, }, { @@ -1064,6 +1091,7 @@ func TestParseVRouterConfigBGP(t *testing.T) { {"exportBlacklist", "nope", "exportBlacklist must be a number"}, {"asPathPrependCount", "lots", "asPathPrependCount must be a number"}, {"peerType", 123, "peerType must be a string"}, + {"asOverride", "yes", "asOverride must be a boolean"}, } for _, tc := range bgpFieldTypeErrors { tc := tc diff --git a/internal/commands/vxc/vxc_prompts_test.go b/internal/commands/vxc/vxc_prompts_test.go index dfa00a5f..b20e17c2 100644 --- a/internal/commands/vxc/vxc_prompts_test.go +++ b/internal/commands/vxc/vxc_prompts_test.go @@ -273,6 +273,7 @@ func TestPromptBGPConnections(t *testing.T) { "no", // shutdown "", // description (optional) "no", // bfdEnabled + "", // asOverride (optional) "", // exportPolicy (optional) "", // peerType (optional) "", // medIn (optional) @@ -296,6 +297,7 @@ func TestPromptBGPConnections(t *testing.T) { assert.Equal(t, "10.0.0.2", conns[0].PeerIpAddress) assert.False(t, conns[0].Shutdown) assert.False(t, conns[0].BfdEnabled) + assert.Nil(t, conns[0].AsOverride) }, }, } @@ -560,6 +562,7 @@ func TestPromptBGPOptionalConfig_WithValues(t *testing.T) { "yes", // shutdown "my bgp", // description "yes", // bfdEnabled + "yes", // asOverride "permit", // exportPolicy "NON_CLOUD", // peerType "100", // medIn @@ -579,6 +582,9 @@ func TestPromptBGPOptionalConfig_WithValues(t *testing.T) { assert.True(t, bgp.Shutdown) assert.Equal(t, "my bgp", bgp.Description) assert.True(t, bgp.BfdEnabled) + if assert.NotNil(t, bgp.AsOverride) { + assert.True(t, *bgp.AsOverride) + } assert.Equal(t, "permit", bgp.ExportPolicy) assert.Equal(t, "NON_CLOUD", bgp.PeerType) assert.Equal(t, 100, bgp.MedIn) @@ -679,6 +685,7 @@ func TestPromptVRouterConfig(t *testing.T) { "no", // shutdown "", // description "no", // BFD enabled + "", // AS override "", // export policy "", // peer type "", // MED in diff --git a/internal/commands/vxc/vxc_prompts_vrouter.go b/internal/commands/vxc/vxc_prompts_vrouter.go index d508cf28..38ced91f 100644 --- a/internal/commands/vxc/vxc_prompts_vrouter.go +++ b/internal/commands/vxc/vxc_prompts_vrouter.go @@ -360,6 +360,23 @@ func promptBGPOptionalConfig(bgp *megaport.BgpConnectionConfig, noColor bool) er } bgp.BfdEnabled = strings.ToLower(bfdEnabledStr) == "yes" + asOverrideStr, err := utils.ResourcePrompt("vxc", "Enable AS Override? (yes/no, optional): ", noColor) + if err != nil { + return err + } + if asOverrideStr != "" { + switch strings.ToLower(asOverrideStr) { + case "yes": + v := true + bgp.AsOverride = &v + case "no": + v := false + bgp.AsOverride = &v + default: + return fmt.Errorf("AS Override must be 'yes' or 'no'") + } + } + exportPolicy, err := utils.ResourcePrompt("vxc", "Enter export policy (permit/deny, optional): ", noColor) if err != nil { return err From 56c8f484dbc545bbec232c6543b73515d6f9eabf Mon Sep 17 00:00:00 2001 From: MegaportPhilipBrowne Date: Thu, 23 Jul 2026 04:31:59 -0700 Subject: [PATCH 2/5] ESD-1687: Cover interactive AS Override no and invalid-input paths --- internal/commands/vxc/vxc_prompts_test.go | 47 +++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/internal/commands/vxc/vxc_prompts_test.go b/internal/commands/vxc/vxc_prompts_test.go index b20e17c2..1b86b7c2 100644 --- a/internal/commands/vxc/vxc_prompts_test.go +++ b/internal/commands/vxc/vxc_prompts_test.go @@ -592,6 +592,53 @@ func TestPromptBGPOptionalConfig_WithValues(t *testing.T) { assert.Equal(t, 3, bgp.AsPathPrependCount) } +func TestPromptBGPOptionalConfig_AsOverrideNo(t *testing.T) { + cleanup := mockPromptsAndSecrets([]string{ + "", // localAsn (optional) + "no", // shutdown + "", // description + "no", // bfdEnabled + "no", // asOverride + "", // exportPolicy + "", // peerType + "", // medIn + "", // medOut + "", // asPathPrepend + }, []string{ + "", // password + }) + defer cleanup() + + bgp := &megaport.BgpConnectionConfig{} + err := promptBGPOptionalConfig(bgp, true) + assert.NoError(t, err) + if assert.NotNil(t, bgp.AsOverride) { + assert.False(t, *bgp.AsOverride) + } +} + +func TestPromptBGPOptionalConfig_AsOverrideInvalid(t *testing.T) { + // The prompt returns before reaching later fields, so only the prompts up + // to and including asOverride need feeding. + cleanup := mockPromptsAndSecrets([]string{ + "", // localAsn (optional) + "no", // shutdown + "", // description + "no", // bfdEnabled + "maybe", // asOverride (invalid) + }, []string{ + "", // password + }) + defer cleanup() + + bgp := &megaport.BgpConnectionConfig{} + err := promptBGPOptionalConfig(bgp, true) + if assert.Error(t, err) { + assert.Contains(t, err.Error(), "AS Override must be 'yes' or 'no'") + } + assert.Nil(t, bgp.AsOverride) +} + func TestPromptBGPExportAddresses_WithValues(t *testing.T) { cleanup := mockPrompts([]string{ "yes", // permit export to From bd6c0a595063c1f39201cbe2986b518f8b25acc3 Mon Sep 17 00:00:00 2001 From: MegaportPhilipBrowne Date: Thu, 23 Jul 2026 04:36:55 -0700 Subject: [PATCH 3/5] ESD-1687: Cover AS Override prompt read-error branch --- internal/commands/vxc/vxc_prompts_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/internal/commands/vxc/vxc_prompts_test.go b/internal/commands/vxc/vxc_prompts_test.go index 1b86b7c2..63896da2 100644 --- a/internal/commands/vxc/vxc_prompts_test.go +++ b/internal/commands/vxc/vxc_prompts_test.go @@ -639,6 +639,25 @@ func TestPromptBGPOptionalConfig_AsOverrideInvalid(t *testing.T) { assert.Nil(t, bgp.AsOverride) } +func TestPromptBGPOptionalConfig_AsOverridePromptError(t *testing.T) { + // Exhaust the prompt queue exactly at the AS Override prompt so ResourcePrompt + // errors, exercising the error-propagation branch. + cleanup := mockPromptsAndSecrets([]string{ + "", // localAsn + "no", // shutdown + "", // description + "no", // bfdEnabled + }, []string{ + "", // password + }) + defer cleanup() + + bgp := &megaport.BgpConnectionConfig{} + err := promptBGPOptionalConfig(bgp, true) + assert.Error(t, err) + assert.Nil(t, bgp.AsOverride) +} + func TestPromptBGPExportAddresses_WithValues(t *testing.T) { cleanup := mockPrompts([]string{ "yes", // permit export to From 50f3fd91f7d4449935c9d285c285b0dbe5022c03 Mon Sep 17 00:00:00 2001 From: MegaportPhilipBrowne Date: Thu, 23 Jul 2026 04:38:41 -0700 Subject: [PATCH 4/5] ESD-1687: Clarify AS Override prompt blank-for-default wording --- internal/commands/vxc/vxc_prompts_vrouter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/commands/vxc/vxc_prompts_vrouter.go b/internal/commands/vxc/vxc_prompts_vrouter.go index 38ced91f..defcbdaf 100644 --- a/internal/commands/vxc/vxc_prompts_vrouter.go +++ b/internal/commands/vxc/vxc_prompts_vrouter.go @@ -360,7 +360,7 @@ func promptBGPOptionalConfig(bgp *megaport.BgpConnectionConfig, noColor bool) er } bgp.BfdEnabled = strings.ToLower(bfdEnabledStr) == "yes" - asOverrideStr, err := utils.ResourcePrompt("vxc", "Enable AS Override? (yes/no, optional): ", noColor) + asOverrideStr, err := utils.ResourcePrompt("vxc", "Enable AS Override? (yes/no, leave blank for API default): ", noColor) if err != nil { return err } From 75b64ebd9d9038042bddb40b0567cb182ece4c55 Mon Sep 17 00:00:00 2001 From: MegaportPhilipBrowne Date: Thu, 23 Jul 2026 05:04:00 -0700 Subject: [PATCH 5/5] ESD-1687: align AS Override prompt wording with passive-mode convention --- internal/commands/vxc/vxc_prompts_vrouter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/commands/vxc/vxc_prompts_vrouter.go b/internal/commands/vxc/vxc_prompts_vrouter.go index defcbdaf..b12853c8 100644 --- a/internal/commands/vxc/vxc_prompts_vrouter.go +++ b/internal/commands/vxc/vxc_prompts_vrouter.go @@ -360,7 +360,7 @@ func promptBGPOptionalConfig(bgp *megaport.BgpConnectionConfig, noColor bool) er } bgp.BfdEnabled = strings.ToLower(bfdEnabledStr) == "yes" - asOverrideStr, err := utils.ResourcePrompt("vxc", "Enable AS Override? (yes/no, leave blank for API default): ", noColor) + asOverrideStr, err := utils.ResourcePrompt("vxc", "Enable AS Override? (yes/no, optional - press Enter for API default): ", noColor) if err != nil { return err }