Skip to content

Commit

Permalink
Updated metal-go client for sub-commands hardware
Browse files Browse the repository at this point in the history
  • Loading branch information
codinja1188 committed Nov 30, 2023
1 parent 099001c commit 12ecbf2
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 91 deletions.
12 changes: 7 additions & 5 deletions internal/hardware/hardware.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@
package hardware

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.HardwareReservationService
Service metal.HardwareReservationsApiService
Out outputs.Outputer
}

Expand All @@ -44,7 +44,7 @@ func (c *Client) NewCommand() *cobra.Command {
root.PersistentPreRun(cmd, args)
}
}
c.Service = c.Servicer.API(cmd).HardwareReservations
c.Service = *c.Servicer.MetalAPI(cmd).HardwareReservationsApi
},
}

Expand All @@ -56,9 +56,11 @@ 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
Filters() map[string]string
Includes(defaultIncludes []string) (incl []string)
Excludes(defaultExcludes []string) (excl []string)
}

func NewClient(s Servicer, out outputs.Outputer) *Client {
Expand Down
10 changes: 7 additions & 3 deletions internal/hardware/move.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
package hardware

import (
"context"
"fmt"

metal "github.com/equinix-labs/metal-go/metal/v1"
"github.com/spf13/cobra"
)

Expand All @@ -39,14 +41,16 @@ func (c *Client) Move() *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
header := []string{"ID", "Facility", "Plan", "Created"}
r, _, err := c.Service.Move(hardwareReservationID, projectID)
moveHardReserveRequest := metal.NewMoveHardwareReservationRequest()
moveHardReserveRequest.ProjectId = &projectID
r, _, err := c.Service.MoveHardwareReservation(context.Background(), hardwareReservationID).MoveHardwareReservationRequest(*moveHardReserveRequest).Execute()
if err != nil {
return fmt.Errorf("Could not move Hardware Reservation: %w", err)
return fmt.Errorf("could not move Hardware Reservation: %w", err)
}

data := make([][]string, 1)

data[0] = []string{r.ID, r.Facility.Code, r.Plan.Name, r.CreatedAt.String()}
data[0] = []string{r.GetId(), r.Facility.GetCode(), r.Plan.GetName(), r.CreatedAt.String()}

return c.Out.Output(r, header, &data)
},
Expand Down
65 changes: 31 additions & 34 deletions internal/hardware/retrieve.go
Original file line number Diff line number Diff line change
@@ -1,31 +1,14 @@
// Copyright © 2018 Jasmin Gacic <[email protected]>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package hardware

import (
"context"
"fmt"

"github.com/equinix/metal-cli/internal/outputs"
"github.com/packethost/packngo"

"github.com/spf13/cobra"

metal "github.com/equinix-labs/metal-go/metal/v1"
)

func (c *Client) Retrieve() *cobra.Command {
Expand All @@ -46,7 +29,8 @@ func (c *Client) Retrieve() *cobra.Command {

header := []string{"ID", "Facility", "Metro", "Plan", "Created"}

inc := []string{}
inc := c.Servicer.Includes(nil)
exc := c.Servicer.Excludes(nil)

// only fetch extra details when rendered
switch c.Servicer.Format() {
Expand All @@ -56,44 +40,57 @@ func (c *Client) Retrieve() *cobra.Command {
inc = []string{"facility.metro"}
}

listOpt := c.Servicer.ListOptions(inc, nil)

if hardwareReservationID == "" && projectID == "" {
return fmt.Errorf("either id or project-id should be set")
}

cmd.SilenceUsage = true
if hardwareReservationID != "" {
getOpts := &packngo.GetOptions{Includes: listOpt.Includes, Excludes: listOpt.Excludes}
r, _, err := c.Service.Get(hardwareReservationID, getOpts)
r, _, err := c.Service.FindHardwareReservationById(context.Background(), hardwareReservationID).Include(inc).Exclude(exc).Execute()
if err != nil {
return fmt.Errorf("Could not get Hardware Reservation: %w", err)
return fmt.Errorf("could not get Hardware Reservation: %w", err)
}

data := make([][]string, 1)
metro := ""
if r.Facility.Metro != nil {
metro = r.Facility.Metro.Code
metro = *r.Facility.Metro.Code
}

data[0] = []string{r.ID, r.Facility.Code, metro, r.Plan.Name, r.CreatedAt.String()}
data[0] = []string{r.GetId(), r.Facility.GetCode(), metro, r.Plan.GetName(), r.CreatedAt.String()}

return c.Out.Output(r, header, &data)
}
request := c.Service.FindProjectHardwareReservations(context.Background(), projectID).Include(inc).Exclude(exc)
filters := c.Servicer.Filters()

reservations, _, err := c.Service.List(projectID, listOpt)
if err != nil {
return fmt.Errorf("Could not list Hardware Reservations: %w", err)
if filters["query"] != "" {
request = request.Query(filters["query"])
}

if filters["state"] != "" {
state, _ := metal.NewFindProjectHardwareReservationsStateParameterFromValue(filters["state"])
request = request.State(*state)
}

if filters["provisionable"] != "" {
provisionable, _ := metal.NewFindProjectHardwareReservationsProvisionableParameterFromValue(filters["provisionable"])
request = request.Provisionable(*provisionable)
}

reservationsList, err := request.ExecuteWithPagination()
if err != nil {
return fmt.Errorf("could not list Hardware Reservations: %w", err)
}
reservations := reservationsList.GetHardwareReservations()
data := make([][]string, len(reservations))

for i, r := range reservations {
metro := ""
if r.Facility.Metro != nil {
metro = r.Facility.Metro.Code
metro = r.Facility.Metro.GetCode()
}
data[i] = []string{r.ID, r.Facility.Code, metro, r.Plan.Name, r.CreatedAt.String()}
data[i] = []string{r.GetId(), r.Facility.GetCode(), metro, r.Plan.GetName(), r.CreatedAt.String()}
}

return c.Out.Output(reservations, header, &data)
Expand Down
29 changes: 4 additions & 25 deletions internal/organizations/retrieve.go
Original file line number Diff line number Diff line change
@@ -1,30 +1,9 @@
// Copyright © 2018 Jasmin Gacic <[email protected]>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package organizations

import (
"context"
"fmt"

pager "github.com/equinix/metal-cli/internal/pagination"
"github.com/spf13/cobra"
)

Expand All @@ -48,11 +27,11 @@ func (c *Client) Retrieve() *cobra.Command {
exclude := c.Servicer.Excludes(nil)

if organizationID == "" {
orgs, err := pager.GetAllOrganizations(c.Service, include, exclude)
orgsList, err := c.Service.FindOrganizations(context.Background()).Include(c.Servicer.Includes(include)).Exclude(c.Servicer.Excludes(exclude)).ExecuteWithPagination()
if err != nil {
return fmt.Errorf("Could not list Organizations: %w", err)
return fmt.Errorf("could not list Organizations: %w", err)
}

orgs := orgsList.GetOrganizations()
data := make([][]string, len(orgs))

for i, p := range orgs {
Expand All @@ -64,7 +43,7 @@ func (c *Client) Retrieve() *cobra.Command {
} else {
org, _, err := c.Service.FindOrganizationById(context.Background(), organizationID).Include(include).Exclude(exclude).Execute()
if err != nil {
return fmt.Errorf("Could not get Organization: %w", err)
return fmt.Errorf("could not get Organization: %w", err)
}

data := make([][]string, 1)
Expand Down
30 changes: 6 additions & 24 deletions internal/pagination/pager.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ func GetAllProjects(s metal.ProjectsApiService, include []string, exclude []stri
var projects []metal.Project

page := int32(1) // int32 | Page to return (optional) (default to 1)
perPage := int32(20) // int32 | Items returned per page (optional) (default to 10)
perPage := int32(20) // int32 | Items returned per page (optional) (default to 20)
for {
projectPage, _, err := s.FindProjects(context.Background()).Include(include).Exclude(exclude).Page(page).PerPage(perPage).Execute()
if err != nil {
Expand All @@ -29,7 +29,7 @@ func GetDeviceEvents(s metal.ApiFindDeviceEventsRequest) ([]metal.Event, error)
var events []metal.Event

page := int32(1) // int32 | Page to return (optional) (default to 1)
perPage := int32(20) // int32 | Items returned per page (optional) (default to 10)
perPage := int32(20) // int32 | Items returned per page (optional) (default to 20)

for {
eventsPage, _, err := s.Page(page).PerPage(perPage).Execute()
Expand All @@ -50,7 +50,7 @@ func GetProjectEvents(s metal.ApiFindProjectEventsRequest) ([]metal.Event, error
var events []metal.Event

page := int32(1) // int32 | Page to return (optional) (default to 1)
perPage := int32(20) // int32 | Items returned per page (optional) (default to 10)
perPage := int32(20) // int32 | Items returned per page (optional) (default to 20)

for {
eventsPage, _, err := s.Page(page).PerPage(perPage).Execute()
Expand All @@ -71,7 +71,7 @@ func GetOrganizationEvents(s metal.ApiFindOrganizationEventsRequest) ([]metal.Ev
var events []metal.Event

page := int32(1) // int32 | Page to return (optional) (default to 1)
perPage := int32(20) // int32 | Items returned per page (optional) (default to 10)
perPage := int32(20) // int32 | Items returned per page (optional) (default to 20)

for {
eventsPage, _, err := s.Page(page).PerPage(perPage).Execute()
Expand All @@ -92,7 +92,8 @@ func GetAllEvents(s metal.ApiFindEventsRequest) ([]metal.Event, error) {
var events []metal.Event

page := int32(1) // int32 | Page to return (optional) (default to 1)
perPage := int32(20) // int32 | Items returned per page (optional) (default to 10)
perPage := int32(20) // int32 | Items returned per page (optional) (default to 20)

for {
eventsPage, _, err := s.Page(page).PerPage(perPage).Execute()
if err != nil {
Expand All @@ -108,25 +109,6 @@ func GetAllEvents(s metal.ApiFindEventsRequest) ([]metal.Event, error) {
}
}

func GetAllOrganizations(s metal.OrganizationsApiService, include, exclude []string) ([]metal.Organization, error) {
var orgs []metal.Organization
page := int32(1) // int32 | Page to return (optional) (default to 1)
perPage := int32(56) // int32 | Items returned per page (optional) (default to 10)

for {
orgPage, _, err := s.FindOrganizations(context.Background()).Include(include).Exclude(exclude).Page(page).PerPage(perPage).Execute()
if err != nil {
return nil, err
}
orgs = append(orgs, orgPage.GetOrganizations()...)
if orgPage.Meta.GetLastPage() > orgPage.Meta.GetCurrentPage() {
page = page + 1
continue
}
return orgs, nil
}
}

func GetProjectDevices(s metal.ApiFindProjectDevicesRequest) ([]metal.Device, error) {
var devices []metal.Device

Expand Down
68 changes: 68 additions & 0 deletions test/e2e/hardwaretest/hardware_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package hardwaretest

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

root "github.com/equinix/metal-cli/internal/cli"
"github.com/equinix/metal-cli/internal/hardware"
outputPkg "github.com/equinix/metal-cli/internal/outputs"
"github.com/spf13/cobra"
)

func TestCli_Hardware(t *testing.T) {
subCommand := "hardware"
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: hardware.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[:]), "ID") &&
!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.")
}
},
},
}
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)
})
}
}

0 comments on commit 12ecbf2

Please sign in to comment.