From e6743b04e3e5a673a293f53ad1ddabbb8caec7f4 Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Thu, 8 Aug 2024 16:15:11 -0400 Subject: [PATCH] feat: handle VRF Gateways in "metal gateway list" (#479) Adds `metal gateway list` support for VRF Gateways. **Why is this needed?** ``` $ metal gateway get panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0xad902e] goroutine 1 [running]: github.com/equinix/metal-cli/internal/gateway.(*Client).Retrieve.func1(0xc00021c308?, {0x12e08e0?, 0x0?, 0x0?}) /home/runner/work/metal-cli/metal-cli/internal/gateway/retrieve.go:70 +0x56e github.com/spf13/cobra.(*Command).execute(0xc00021c308, {0x12e08e0, 0x0, 0x0}) /home/runner/go/pkg/mod/github.com/spf13/cobra@v1.8.0/command.go:983 +0xaca github.com/spf13/cobra.(*Command).ExecuteC(0xc000134608) /home/runner/go/pkg/mod/github.com/spf13/cobra@v1.8.0/command.go:1115 +0x3ff github.com/spf13/cobra.(*Command).Execute(0xc0000061c0?) /home/runner/go/pkg/mod/github.com/spf13/cobra@v1.8.0/command.go:1039 +0x13 main.main() /home/runner/work/metal-cli/metal-cli/cmd/metal/main.go:32 +0x1b ``` Signed-off-by: Marques Johansson --- internal/gateway/retrieve.go | 105 +++++++++++++++++++++++++++++++---- 1 file changed, 93 insertions(+), 12 deletions(-) diff --git a/internal/gateway/retrieve.go b/internal/gateway/retrieve.go index 6a9a0bdf..033d6530 100644 --- a/internal/gateway/retrieve.go +++ b/internal/gateway/retrieve.go @@ -24,12 +24,78 @@ import ( "context" "fmt" "strconv" + "time" metal "github.com/equinix/equinix-sdk-go/services/metalv1" "github.com/spf13/cobra" ) +type ipreservationIsh interface { + GetAddress() string + GetCidr() int32 +} + +var ( + _ ipreservationIsh = (*metal.VrfIpReservation)(nil) + _ ipreservationIsh = (*metal.IPReservation)(nil) +) + +type gatewayIsh interface { + GetId() string + GetCreatedAt() time.Time + GetState() metal.MetalGatewayState + GetVirtualNetwork() metal.VirtualNetwork + GetIpReservation() ipreservationIsh + GetVrfName() string +} + +var ( + _ gatewayIsh = (*metalGatewayWrapper)(nil) + _ gatewayIsh = (*vrfMetalGatewayWrapper)(nil) +) + +type metalGatewayWrapper struct { + *metal.MetalGateway +} + +func (m metalGatewayWrapper) GetIpReservation() ipreservationIsh { + if m.MetalGateway.IpReservation == nil { + return nil + } + return m.MetalGateway.IpReservation +} + +func (m metalGatewayWrapper) GetVrfName() string { + return "" +} + +type vrfMetalGatewayWrapper struct { + *metal.VrfMetalGateway +} + +func newGatewayish(gwaysInner metal.MetalGatewayListMetalGatewaysInner) gatewayIsh { + if gwaysInner.MetalGateway != nil { + return metalGatewayWrapper{gwaysInner.MetalGateway} + } + if gwaysInner.VrfMetalGateway != nil { + return vrfMetalGatewayWrapper{gwaysInner.VrfMetalGateway} + } + return nil // Return nil if neither type is present +} + +func (v vrfMetalGatewayWrapper) GetIpReservation() ipreservationIsh { + if v.VrfMetalGateway.IpReservation == nil { + return nil + } + return v.VrfMetalGateway.IpReservation +} + +func (v vrfMetalGatewayWrapper) GetVrfName() string { + vrf := v.GetVrf() + return vrf.GetName() +} + func (c *Client) Retrieve() *cobra.Command { var projectID string @@ -45,7 +111,7 @@ func (c *Client) Retrieve() *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { cmd.SilenceUsage = true - includes := []string{"virtual_network", "ip_reservation"} + includes := []string{"virtual_network", "ip_reservation", "vrf"} gwayList, _, err := c.Service. FindMetalGatewaysByProject(context.Background(), projectID). @@ -58,26 +124,41 @@ func (c *Client) Retrieve() *cobra.Command { gways := gwayList.GetMetalGateways() - data := make([][]string, len(gways)) - metalGways := make([]*metal.MetalGateway, len(gways)) + data := make([][]string, 0, len(gways)) + var gateways []gatewayIsh - for i, n := range gways { - gway := n.MetalGateway - metalGways = append(metalGways, gway) + for _, gwaysInner := range gways { + gway := newGatewayish(gwaysInner) + if gway == nil { + continue + } - address := "" + gateways = append(gateways, gway) - ipReservation := gway.IpReservation + address := "" + ipReservation := gway.GetIpReservation() if ipReservation != nil { address = ipReservation.GetAddress() + "/" + strconv.Itoa(int(ipReservation.GetCidr())) } - data[i] = []string{gway.GetId(), gway.VirtualNetwork.GetMetroCode(), strconv.Itoa(int(gway.VirtualNetwork.GetVxlan())), - address, string(gway.GetState()), gway.GetCreatedAt().String()} + vnet := gway.GetVirtualNetwork() + metroCode := vnet.GetMetroCode() + vxlan := strconv.Itoa(int(vnet.GetVxlan())) + + data = append(data, []string{ + gway.GetId(), + metroCode, + vxlan, + address, + string(gway.GetState()), + gway.GetCreatedAt().String(), + gway.GetVrfName(), + }) } - header := []string{"ID", "Metro", "VXLAN", "Addresses", "State", "Created"} - return c.Out.Output(metalGways, header, &data) + header := []string{"ID", "Metro", "VXLAN", "Addresses", "State", "Created", "VRF"} + + return c.Out.Output(gateways, header, &data) }, }