Skip to content

Commit

Permalink
Migrate metal ports subcommand cli to metal-go from packngo
Browse files Browse the repository at this point in the history
Signed-off-by: Ayush Rangwala <[email protected]>
  • Loading branch information
aayushrangwala committed Oct 17, 2023
1 parent de1378f commit ebaebc0
Show file tree
Hide file tree
Showing 8 changed files with 474 additions and 33 deletions.
30 changes: 13 additions & 17 deletions internal/ports/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ import (
func (c *Client) Convert() *cobra.Command {
var portID string
var bonded, layer2, bulk, force, ipv4, ipv6 bool
// retrievePortCmd represents the retrievePort command
retrievePortCmd := &cobra.Command{
convertPortCmd := &cobra.Command{
Use: `convert -i <port_UUID> [--bonded] [--bulk] --layer2 [--force] [--public-ipv4] [--public-ipv6]`,
Aliases: []string{},
Short: "Converts a list of ports or the details of the specified port.",
Expand Down Expand Up @@ -87,7 +86,10 @@ func (c *Client) Convert() *cobra.Command {
return nil, nil, nil
}
}
return c.PortService.ConvertLayer2(context.Background(), portID).Execute()

return c.PortService.ConvertLayer2(context.Background(), portID).
PortAssignInput(*metal.NewPortAssignInput()).
Execute()
}
convToL3 := func(portID string) (*metal.Port, *http.Response, error) {
log.Printf("Converting port %s to layer-3 with addresses %v", portID, addrs)
Expand All @@ -105,8 +107,6 @@ func (c *Client) Convert() *cobra.Command {

port, _, err := c.PortService.FindPortById(context.Background(), portID).
Include(c.Servicer.Includes(nil)).
// TODO: uncomment this when metal api supports it
// Exclude(c.Servicer.Excludes(nil)).
Execute()
if err != nil {
return fmt.Errorf("Could not get Port: %w", err)
Expand All @@ -121,31 +121,27 @@ func (c *Client) Convert() *cobra.Command {
},
}

retrievePortCmd.Flags().StringVarP(&portID, "port-id", "i", "", "The UUID of a port.")
retrievePortCmd.Flags().BoolVarP(&bonded, "bonded", "b", false, "Convert to layer-2 bonded.")
retrievePortCmd.Flags().BoolVarP(&bulk, "bulk", "", false, "Affect both ports in a bond.")
retrievePortCmd.Flags().BoolVarP(&layer2, "layer2", "2", false, "Convert to layer-2 unbonded.")
retrievePortCmd.Flags().BoolVarP(&force, "force", "f", false, "Force conversion to layer-2 bonded.")
retrievePortCmd.Flags().BoolVarP(&ipv4, "public-ipv4", "4", false, "Convert to layer-2 bonded with public IPv4.")
retrievePortCmd.Flags().BoolVarP(&ipv6, "public-ipv6", "6", false, "Convert to layer-2 bonded with public IPv6.")
convertPortCmd.Flags().StringVarP(&portID, "port-id", "i", "", "The UUID of a port.")
convertPortCmd.Flags().BoolVarP(&bonded, "bonded", "b", false, "Convert to layer-2 bonded.")
convertPortCmd.Flags().BoolVarP(&bulk, "bulk", "", false, "Affect both ports in a bond.")
convertPortCmd.Flags().BoolVarP(&layer2, "layer2", "2", false, "Convert to layer-2 unbonded.")
convertPortCmd.Flags().BoolVarP(&force, "force", "f", false, "Force conversion to layer-2 bonded.")
convertPortCmd.Flags().BoolVarP(&ipv4, "public-ipv4", "4", false, "Convert to layer-2 bonded with public IPv4.")
convertPortCmd.Flags().BoolVarP(&ipv6, "public-ipv6", "6", false, "Convert to layer-2 bonded with public IPv6.")

return retrievePortCmd
return convertPortCmd
}

func portBondingHandler(cmd *cobra.Command, c *Client, portId string) error {
if cmd.Flag("bonded").Changed {
_, _, err := c.PortService.BondPort(context.Background(), portId).
Include(c.Servicer.Includes(nil)).
// TODO: uncomment this when metal api supports it
// Exclude(c.Servicer.Excludes(nil)).
Execute()
return err
}

_, _, err := c.PortService.DisbondPort(context.Background(), portId).
Include(c.Servicer.Includes(nil)).
// TODO: uncomment this when metal api supports it
// Exclude(c.Servicer.Excludes(nil)).
Execute()
return err
}
1 change: 0 additions & 1 deletion internal/ports/port.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ type Servicer interface {
MetalAPI(*cobra.Command) *metal.APIClient
Filters() map[string]string
Includes(defaultIncludes []string) (incl []string)
Excludes(defaultExcludes []string) (excl []string)
}

func NewClient(s Servicer, out outputs.Outputer) *Client {
Expand Down
4 changes: 1 addition & 3 deletions internal/ports/retrieve.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ func (c *Client) Retrieve() *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
port, _, err := c.PortService.FindPortById(context.Background(), portID).
Include(c.Servicer.Excludes(nil)).
// TODO: uncomment this when metal api supports it
// Exclude(c.Servicer.Excludes(nil)).
Include(c.Servicer.Includes(nil)).
Execute()
if err != nil {
return fmt.Errorf("Could not get Port: %w", err)
Expand Down
2 changes: 0 additions & 2 deletions internal/ports/vlans.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,6 @@ func (c *Client) Vlans() *cobra.Command {
batch, _, err := c.PortService.CreatePortVlanAssignmentBatch(context.Background(), portID).
PortVlanAssignmentBatchCreateInput(*req).
Include(c.Servicer.Includes([]string{"port"})).
// TODO: uncomment this when metal api supports it
// Exclude(c.Servicer.Excludes(nil)).
Execute()
if err != nil {
return fmt.Errorf("Could not update port VLAN assignments: %w", err)
Expand Down
120 changes: 120 additions & 0 deletions test/e2e/ports/convert/convert_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package convert

Check failure on line 1 in test/e2e/ports/convert/convert_test.go

View workflow job for this annotation

GitHub Actions / lint

: # github.com/equinix/metal-cli/test/e2e/ports/convert [github.com/equinix/metal-cli/test/e2e/ports/convert.test]

import (
"io"
"os"
"strconv"
"strings"
"testing"

root "github.com/equinix/metal-cli/internal/cli"
outputPkg "github.com/equinix/metal-cli/internal/outputs"
"github.com/equinix/metal-cli/internal/ports"
"github.com/equinix/metal-cli/test/helper"

"github.com/spf13/cobra"
)

func TestPorts_Convert(t *testing.T) {
var projectId, deviceId *string
subCommand := "port"
consumerToken := ""
apiURL := ""
Version := "devel"
rootClient := root.NewClient(consumerToken, apiURL, Version)
tests := []struct {
name string
cmd *cobra.Command
want *cobra.Command
cmdFunc func(*testing.T, *cobra.Command)
}{
{
name: "convert port",
cmd: ports.NewClient(rootClient, outputPkg.Outputer(&outputPkg.Standard{})).NewCommand(),
want: &cobra.Command{},
cmdFunc: func(t *testing.T, c *cobra.Command) {
root := c.Root()
projId, err := helper.CreateTestProject("metal-cli-test-ports-project")
if err != nil {
t.Error(err)
}
projectId = &projId

devId, err := helper.CreateTestDevice(*projectId, "metal-cli-test-ports-device")
if err != nil {
t.Error(err)
}
deviceId = &devId

device, err := helper.GetDeviceById(*deviceId)
if len(device.NetworkPorts) < 3 {
t.Errorf("All 3 ports doesnot exist for the created device: %s", device.GetId())
}
port := device.GetNetworkPorts()[2]

active, err := helper.IsDeviceStateActive(*deviceId)
if err == nil && active {
root.SetArgs([]string{subCommand, "convert", "-i", port.GetId(), "--layer2", "--bonded", "--force"})

rescueStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
if err := root.Execute(); err != nil {
t.Error(err)
}
w.Close()
out, _ := io.ReadAll(r)
os.Stdout = rescueStdout

if !strings.Contains(string(out[:]), port.GetId()) {
t.Errorf("cmd output should contain ID of the port: %s", port.GetId())
}

if !strings.Contains(string(out[:]), port.GetName()) {
t.Errorf("cmd output should contain name of the port: %s", port.GetName())
}

if !strings.Contains(string(out[:]), string(port.GetType())) {
t.Errorf("cmd output should contain type of the port: %s", string(port.GetType()))
}

if !strings.Contains(string(out[:]), strconv.FormatBool(port.Data.GetBonded())) {
t.Errorf("cmd output should contain if port is bonded: %s", strconv.FormatBool(port.Data.GetBonded()))
}

if err := helper.DeletePort(port.GetId()); err != nil {

Check failure on line 85 in test/e2e/ports/convert/convert_test.go

View workflow job for this annotation

GitHub Actions / lint

undefined: helper.DeletePort
t.Error(err)
}
if err := helper.DeleteVLAN(port.GetId()); err != nil {

Check failure on line 88 in test/e2e/ports/convert/convert_test.go

View workflow job for this annotation

GitHub Actions / lint

undefined: helper.DeleteVLAN (typecheck)
t.Error(err)
}
if err := helper.CleanupProjectAndDevice(deviceId, projectId); err != nil {
t.Error(err)
}
}
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
rootCmd := rootClient.NewCommand()
rootCmd.AddCommand(tt.cmd)
tt.cmdFunc(t, tt.cmd)
})
}
}

func cleanup(t *testing.T, deviceId, projectId *string) {
resp, err := helper.IsDeviceStateActive(*deviceId)
if err == nil && resp == true {
err = helper.CleanTestDevice(*deviceId)
if err != nil {
t.Error(err)
}
err = helper.CleanTestProject(*projectId)
if err != nil {
t.Error(err)
}
}
}
102 changes: 102 additions & 0 deletions test/e2e/ports/retrieve/retrieve_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package retrieve

import (
"io"
"os"
"strconv"
"strings"
"testing"

root "github.com/equinix/metal-cli/internal/cli"
outputPkg "github.com/equinix/metal-cli/internal/outputs"
"github.com/equinix/metal-cli/internal/ports"
"github.com/equinix/metal-cli/test/helper"

"github.com/spf13/cobra"
)

func TestPorts_Retrieve(t *testing.T) {
var projectId, deviceId *string
subCommand := "port"
consumerToken := ""
apiURL := ""
Version := "devel"
rootClient := root.NewClient(consumerToken, apiURL, Version)
tests := []struct {
name string
cmd *cobra.Command
want *cobra.Command
cmdFunc func(*testing.T, *cobra.Command)
}{
{
name: "retrieve port",
cmd: ports.NewClient(rootClient, outputPkg.Outputer(&outputPkg.Standard{})).NewCommand(),
want: &cobra.Command{},
cmdFunc: func(t *testing.T, c *cobra.Command) {
root := c.Root()
projId, err := helper.CreateTestProject("metal-cli-test-ports-project")
if err != nil {
t.Error(err)
}
projectId = &projId

devId, err := helper.CreateTestDevice(*projectId, "metal-cli-test-ports-device")
if err != nil {
t.Error(err)
}
deviceId = &devId

device, err := helper.GetDeviceById(*deviceId)

Check failure on line 49 in test/e2e/ports/retrieve/retrieve_test.go

View workflow job for this annotation

GitHub Actions / lint

ineffectual assignment to err (ineffassign)

if len(device.NetworkPorts) == 0 {
t.Errorf("ports doesnot exist for the created device: %s", device.GetId())
}

port := device.GetNetworkPorts()[0]
root.SetArgs([]string{subCommand, "get", "-i", port.GetId()})

rescueStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
if err := root.Execute(); err != nil {
t.Error(err)
}
w.Close()
out, _ := io.ReadAll(r)
os.Stdout = rescueStdout

if !strings.Contains(string(out[:]), port.GetId()) {
t.Errorf("cmd output should contain ID of the port: %s", port.GetId())
}

if !strings.Contains(string(out[:]), port.GetName()) {
t.Errorf("cmd output should contain name of the port: %s", port.GetName())
}

if !strings.Contains(string(out[:]), string(port.GetType())) {
t.Errorf("cmd output should contain type of the port: %s", string(port.GetType()))
}

if !strings.Contains(string(out[:]), port.Data.GetMac()) {
t.Errorf("cmd output should contain MAC address of the port: %s", port.Data.GetMac())
}

if !strings.Contains(string(out[:]), strconv.FormatBool(port.Data.GetBonded())) {
t.Errorf("cmd output should contain if port is bonded: %s", strconv.FormatBool(port.Data.GetBonded()))
}

if err := helper.CleanupProjectAndDevice(deviceId, projectId); err != nil {
t.Error(err)
}
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
rootCmd := rootClient.NewCommand()
rootCmd.AddCommand(tt.cmd)
tt.cmdFunc(t, tt.cmd)
})
}
}
Loading

0 comments on commit ebaebc0

Please sign in to comment.