diff --git a/internal/capacity/capacity.go b/internal/capacity/capacity.go index 79d9190f..0a377760 100644 --- a/internal/capacity/capacity.go +++ b/internal/capacity/capacity.go @@ -21,14 +21,14 @@ package capacity import ( + metal "github.com/equinix-labs/metal-go/metal/v1" "github.com/equinix/metal-cli/internal/outputs" - "github.com/packethost/packngo" "github.com/spf13/cobra" ) type Client struct { Servicer Servicer - Service packngo.CapacityService + Service metal.CapacityApiService Out outputs.Outputer } @@ -44,7 +44,7 @@ func (c *Client) NewCommand() *cobra.Command { root.PersistentPreRun(cmd, args) } } - c.Service = c.Servicer.API(cmd).CapacityService + c.Service = *c.Servicer.MetalAPI(cmd).CapacityApi }, } @@ -56,8 +56,7 @@ func (c *Client) NewCommand() *cobra.Command { } type Servicer interface { - API(*cobra.Command) *packngo.Client - ListOptions(defaultIncludes, defaultExcludes []string) *packngo.ListOptions + MetalAPI(*cobra.Command) *metal.APIClient Format() outputs.Format } diff --git a/internal/capacity/check.go b/internal/capacity/check.go index b793a330..847bf85f 100644 --- a/internal/capacity/check.go +++ b/internal/capacity/check.go @@ -21,11 +21,12 @@ package capacity import ( + "context" "errors" "fmt" "strconv" - "github.com/packethost/packngo" + metal "github.com/equinix-labs/metal-go/metal/v1" "github.com/spf13/cobra" ) @@ -47,16 +48,16 @@ func (c *Client) Check() *cobra.Command { metal capacity check -m sv,da -P c3.medium.x86,m3.large.x86 -q 4`, RunE: func(cmd *cobra.Command, args []string) error { - var checker func(*packngo.CapacityInput) (*packngo.CapacityInput, *packngo.Response, error) var locationField string - var locationer func(si packngo.ServerInfo) string - req := &packngo.CapacityInput{ - Servers: []packngo.ServerInfo{}, - } + var returnOut error + quantityStr := strconv.Itoa(quantity) + var serverListInput []metal.ServerInfo + req := *metal.NewCapacityInput() if metro != "" { metros = append(metros, metro) } + if facility != "" { facilities = append(facilities, facility) } @@ -71,56 +72,65 @@ func (c *Client) Check() *cobra.Command { } if len(facilities) > 0 { - checker = c.Service.Check - locationField = "Facility" - locationer = func(si packngo.ServerInfo) string { - return si.Facility - } for _, f := range facilities { for _, p := range plans { - req.Servers = append(req.Servers, packngo.ServerInfo{ - Facility: f, - Plan: p, - Quantity: quantity, - }, - ) + var serverInfoInput metal.ServerInfo + serverInfoInput.SetFacility(f) + serverInfoInput.SetPlan(p) + serverInfoInput.SetQuantity(quantityStr) + serverListInput = append(serverListInput, serverInfoInput) } } - } else if len(metros) > 0 { - checker = c.Service.CheckMetros - locationField = "Metro" - locationer = func(si packngo.ServerInfo) string { - return si.Metro + req.SetServers(serverListInput) + facilityList, _, err := c.Service.CheckCapacityForFacility(context.Background()).CapacityInput(req).Execute() + if err != nil { + return fmt.Errorf("could not check facility: %w", err) + } + locationField = "Facility" + ServerList := facilityList.GetServers() + + data := make([][]string, len(ServerList)) + for i, s := range ServerList { + data[i] = []string{ + s.GetFacility(), + s.GetPlan(), + s.GetQuantity(), + strconv.FormatBool(s.GetAvailable()), + } } + header := []string{locationField, "Plan", "Quantity", "Availability"} + returnOut = c.Out.Output(ServerList, header, &data) + } else if len(metros) > 0 { for _, m := range metros { for _, p := range plans { - req.Servers = append(req.Servers, packngo.ServerInfo{ - Metro: m, - Plan: p, - Quantity: quantity, - }, - ) + var serverInfoInput metal.ServerInfo + serverInfoInput.SetMetro(m) + serverInfoInput.SetPlan(p) + serverInfoInput.SetQuantity(quantityStr) + serverListInput = append(serverListInput, serverInfoInput) } } - } - - availability, _, err := checker(req) - if err != nil { - return fmt.Errorf("Could not check capacity: %w", err) - } + req.SetServers(serverListInput) + metroList, _, err := c.Service.CheckCapacityForMetro(context.Background()).CapacityInput(req).Execute() + if err != nil { + return fmt.Errorf("could not check capacity: %w", err) + } - data := make([][]string, len(availability.Servers)) - for i, s := range availability.Servers { - data[i] = []string{ - locationer(s), - s.Plan, - strconv.Itoa(s.Quantity), - strconv.FormatBool(s.Available), + locationField = "Metro" + ServerList := metroList.GetServers() + data := make([][]string, len(ServerList)) + for i, s := range ServerList { + data[i] = []string{ + s.GetMetro(), + s.GetPlan(), + s.GetQuantity(), + strconv.FormatBool(s.GetAvailable()), + } } + header := []string{locationField, "Plan", "Quantity", "Availability"} + returnOut = c.Out.Output(ServerList, header, &data) } - - header := []string{locationField, "Plan", "Quantity", "Availability"} - return c.Out.Output(availability, header, &data) + return returnOut }, } diff --git a/internal/capacity/retrieve.go b/internal/capacity/retrieve.go index ca1fafa5..5787dea4 100644 --- a/internal/capacity/retrieve.go +++ b/internal/capacity/retrieve.go @@ -21,10 +21,12 @@ package capacity import ( + "context" "fmt" "errors" + metal "github.com/equinix-labs/metal-go/metal/v1" "github.com/spf13/cobra" ) @@ -51,20 +53,24 @@ func (c *Client) Retrieve() *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { var err error var locationField string - lister := c.Service.List // Default to facilities + var capacitiesList *metal.CapacityList + capacitiesList, _, err = c.Service.FindCapacityForFacility(context.Background()).Execute() // Default to facilities + if err != nil { + return fmt.Errorf("could not get Capacity: %w", err) + } fs := cmd.Flags() if fs.Changed("metros") && fs.Changed("facilities") { - return errors.New("Either facilities or metros, but not both, can be set") + return errors.New("either facilities or metros, but not both, can be set") } if fs.Changed("facility") && fs.Changed("metro") { - return errors.New("Either --facility (-f) or --metro (-m), but not both, can be set") + return errors.New("either --facility (-f) or --metro (-m), but not both, can be set") } if fs.Changed("facility") && fs.Changed("metros") || fs.Changed("facilities") && fs.Changed("metro") { - return errors.New("Cannot specify both facility and metro filtering") + return errors.New("cannot specify both facility and metro filtering") } if fs.Changed("metro") && fs.Changed("metros") || fs.Changed("facility") && fs.Changed("facilities") { - return errors.New("Cannot use both --metro (-m) and --metros or --facility (-f) and --facilities") + return errors.New("cannot use both --metro (-m) and --metros or --facility (-f) and --facilities") } cmd.SilenceUsage = true @@ -72,23 +78,23 @@ func (c *Client) Retrieve() *cobra.Command { if len(facilities) > 0 { locationField = "Facility" locs = append(locs, facilities...) + } else if len(metros) > 0 || checkMetro { - lister = c.Service.ListMetros + capacitiesList, _, err = c.Service.FindCapacityForMetro(context.Background()).Execute() + if err != nil { + return fmt.Errorf("could not get Capacity: %w", err) + } locationField = "Metro" locs = append(locs, metros...) - } - capacities, _, err := lister() - if err != nil { - return fmt.Errorf("Could not get Capacity: %w", err) } header := []string{locationField, "Plan", "Level"} data := [][]string{} + capacities := capacitiesList.GetCapacity() filtered := map[string]map[string]map[string]string{} - - for locCode, capacity := range *capacities { + for locCode, capacity := range capacities { if len(locs) > 0 && !contains(locs, locCode) { continue } @@ -96,15 +102,14 @@ func (c *Client) Retrieve() *cobra.Command { if len(plans) > 0 && !contains(plans, plan) { continue } - loc := []string{locCode, plan, bm.Level} + loc := []string{locCode, plan, bm.GetLevel()} data = append(data, loc) if len(filtered[locCode]) == 0 { filtered[locCode] = map[string]map[string]string{} } - filtered[locCode][plan] = map[string]string{"levels": bm.Level} + filtered[locCode][plan] = map[string]string{"levels": bm.GetLevel()} } } - return c.Out.Output(filtered, header, &data) }, } diff --git a/test/e2e/capacity_test.go b/test/e2e/capacity_test.go new file mode 100644 index 00000000..c3a9757c --- /dev/null +++ b/test/e2e/capacity_test.go @@ -0,0 +1,205 @@ +package e2e + +import ( + "io" + "os" + "strings" + "testing" + + "github.com/equinix/metal-cli/internal/capacity" + root "github.com/equinix/metal-cli/internal/cli" + outputPkg "github.com/equinix/metal-cli/internal/outputs" + "github.com/spf13/cobra" +) + +func TestCli_Capacity(t *testing.T) { + subCommand := "capacity" + consumerToken := "" + apiURL := "" + Version := "metal" + rootClient := root.NewClient(consumerToken, apiURL, Version) + type fields struct { + MainCmd *cobra.Command + Outputer outputPkg.Outputer + } + tests := []struct { + name string + fields fields + want *cobra.Command + cmdFunc func(*testing.T, *cobra.Command) + }{ + { + name: "get", + fields: fields{ + MainCmd: capacity.NewClient(rootClient, outputPkg.Outputer(&outputPkg.Standard{})).NewCommand(), + Outputer: outputPkg.Outputer(&outputPkg.Standard{}), + }, + want: &cobra.Command{}, + cmdFunc: func(t *testing.T, c *cobra.Command) { + root := c.Root() + root.SetArgs([]string{subCommand, "get"}) + 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[:]), "n3.xlarge.x86") && + !strings.Contains(string(out[:]), "m3.large.x86") && + !strings.Contains(string(out[:]), "s3.xlarge.x86") && + !strings.Contains(string(out[:]), "sv16") && + !strings.Contains(string(out[:]), "sv16") && + !strings.Contains(string(out[:]), "dc10") { + t.Error("expected output should include n3.xlarge.x86, m3.large.x86, s3.xlarge.x86, dc10.") + } + }, + }, + { + name: "get_by_plan_1", + fields: fields{ + MainCmd: capacity.NewClient(rootClient, outputPkg.Outputer(&outputPkg.Standard{})).NewCommand(), + Outputer: outputPkg.Outputer(&outputPkg.Standard{}), + }, + want: &cobra.Command{}, + cmdFunc: func(t *testing.T, c *cobra.Command) { + root := c.Root() + root.SetArgs([]string{subCommand, "get", "-m", "-P", "c3.small.x86"}) + 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[:]), "c3.small.x86") && + !strings.Contains(string(out[:]), "mt") && + !strings.Contains(string(out[:]), "sv") && + !strings.Contains(string(out[:]), "md") && + !strings.Contains(string(out[:]), "sg") && + !strings.Contains(string(out[:]), "pa") { + t.Error("expected output should include c3.small.x86, mt, sv, md, sg, pa") + } + }, + }, + { + name: "get_by_plan_2", + fields: fields{ + MainCmd: capacity.NewClient(rootClient, outputPkg.Outputer(&outputPkg.Standard{})).NewCommand(), + Outputer: outputPkg.Outputer(&outputPkg.Standard{}), + }, + want: &cobra.Command{}, + cmdFunc: func(t *testing.T, c *cobra.Command) { + root := c.Root() + root.SetArgs([]string{subCommand, "get", "-m", "-P", "m3.large.x86"}) + 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[:]), "m3.large.x86") && + !strings.Contains(string(out[:]), "mt") && + !strings.Contains(string(out[:]), "sv") && + !strings.Contains(string(out[:]), "md") && + !strings.Contains(string(out[:]), "sg") { + t.Error("expected output should include c3.small.x86, mt, sv, md, sg") + } + }, + }, + { + name: "check_by_multi_metro", + fields: fields{ + MainCmd: capacity.NewClient(rootClient, outputPkg.Outputer(&outputPkg.Standard{})).NewCommand(), + Outputer: outputPkg.Outputer(&outputPkg.Standard{}), + }, + want: &cobra.Command{}, + cmdFunc: func(t *testing.T, c *cobra.Command) { + root := c.Root() + root.SetArgs([]string{subCommand, "check", "-m", "ny,da", "-P", "c3.medium.x86", "-q", "10"}) + 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[:]), "c3.medium.x86") && + !strings.Contains(string(out[:]), "ny") && + !strings.Contains(string(out[:]), "da") { + t.Error("expected output should include c3.medium.x86, ny, da") + } + }, + }, + { + name: "check_by_multi_plan", + fields: fields{ + MainCmd: capacity.NewClient(rootClient, outputPkg.Outputer(&outputPkg.Standard{})).NewCommand(), + Outputer: outputPkg.Outputer(&outputPkg.Standard{}), + }, + want: &cobra.Command{}, + cmdFunc: func(t *testing.T, c *cobra.Command) { + root := c.Root() + root.SetArgs([]string{subCommand, "check", "-m", "da", "-P", "c3.medium.x86,m3.large.x86", "-q", "10"}) + 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[:]), "c3.medium.x86") && + !strings.Contains(string(out[:]), "m3.large.x86") && + !strings.Contains(string(out[:]), "ny") && + !strings.Contains(string(out[:]), "da") { + t.Error("expected output should include c3.medium.x86, m3.large.x86, da") + } + }, + }, + { + name: "check_by_multi_metro_and_plan", + fields: fields{ + MainCmd: capacity.NewClient(rootClient, outputPkg.Outputer(&outputPkg.Standard{})).NewCommand(), + Outputer: outputPkg.Outputer(&outputPkg.Standard{}), + }, + want: &cobra.Command{}, + cmdFunc: func(t *testing.T, c *cobra.Command) { + root := c.Root() + root.SetArgs([]string{subCommand, "check", "-m", "ny,da", "-P", "c3.medium.x86,m3.large.x86", "-q", "10"}) + 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[:]), "c3.medium.x86") && + !strings.Contains(string(out[:]), "m3.large.x86") && + !strings.Contains(string(out[:]), "ny") && + !strings.Contains(string(out[:]), "da") { + t.Error("expected output should include c3.medium.x86, m3.large.x86, ny, da") + } + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rootCmd := rootClient.NewCommand() + rootCmd.AddCommand(tt.fields.MainCmd) + tt.cmdFunc(t, tt.fields.MainCmd) + }) + } +} diff --git a/test/e2e/os_test.go b/test/e2e/os_test.go index 8b6390d0..9fe59099 100644 --- a/test/e2e/os_test.go +++ b/test/e2e/os_test.go @@ -38,7 +38,6 @@ func TestCli_OperatingSystem(t *testing.T) { }, want: &cobra.Command{}, cmdFunc: func(t *testing.T, c *cobra.Command) { - t.Helper() root := c.Root() out := &bytes.Buffer{} root.SetArgs([]string{subCommand, "get"})