Skip to content

Commit

Permalink
Updated metal-go client for sub-commands ips
Browse files Browse the repository at this point in the history
  • Loading branch information
codinja1188 committed Sep 25, 2023
1 parent a264ffd commit 7fe2a75
Show file tree
Hide file tree
Showing 12 changed files with 291 additions and 40 deletions.
2 changes: 1 addition & 1 deletion internal/capacity/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func (c *Client) Check() *cobra.Command {
data[i] = []string{
s.GetMetro(),
s.GetPlan(),
s.GetQuantity(),
string(s.GetQuantity()),
strconv.FormatBool(s.GetAvailable()),
}
}
Expand Down
9 changes: 6 additions & 3 deletions internal/ips/assign.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@
package ips

import (
"context"
"fmt"
"strconv"

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

Expand All @@ -44,14 +45,16 @@ func (c *Client) Assign() *cobra.Command {

RunE: func(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
assignment, _, err := c.DeviceService.Assign(deviceID, &packngo.AddressStruct{Address: address})
IPAssignmentInput := metal.NewIPAssignmentInput(address)

assignment, _, err := c.DeviceService.CreateIPAssignment(context.Background(), deviceID).IPAssignmentInput(*IPAssignmentInput).Execute()
if err != nil {
return fmt.Errorf("Could not assign Device IP address: %w", err)
}

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

data[0] = []string{assignment.ID, assignment.Address, strconv.FormatBool(assignment.Public), assignment.Created}
data[0] = []string{assignment.GetId(), assignment.GetAddress(), strconv.FormatBool(assignment.GetPublic()), assignment.CreatedAt.String()}
header := []string{"ID", "Address", "Public", "Created"}

return c.Out.Output(assignment, header, &data)
Expand Down
7 changes: 5 additions & 2 deletions internal/ips/available.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@
package ips

import (
"context"
"fmt"
"strconv"

"github.com/packethost/packngo"
"github.com/spf13/cobra"
)

Expand All @@ -41,10 +42,12 @@ func (c *Client) Available() *cobra.Command {

RunE: func(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
result, _, err := c.ProjectService.AvailableAddresses(reservationID, &packngo.AvailableRequest{CIDR: cidr})
Cidr := strconv.Itoa(cidr)
resultList, _, err := c.IPService.FindIPAvailabilities(context.Background(), reservationID).Cidr(Cidr).Execute()

Check failure on line 46 in internal/ips/available.go

View workflow job for this annotation

GitHub Actions / lint

cannot use Cidr (variable of type string) as v1.FindIPAvailabilitiesCidrParameter value in argument to c.IPService.FindIPAvailabilities(context.Background(), reservationID).Cidr (typecheck)
if err != nil {
return fmt.Errorf("Could not get available IP addresses: %w", err)
}
result := resultList.GetAvailable()
data := make([][]string, len(result))
for i, r := range result {
data[i] = []string{r}
Expand Down
17 changes: 8 additions & 9 deletions internal/ips/ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@
package ips

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
ProjectService packngo.ProjectIPService
DeviceService packngo.DeviceIPService
Out outputs.Outputer
Servicer Servicer
IPService metal.IPAddressesApiService
DeviceService metal.DevicesApiService
Out outputs.Outputer
}

func (c *Client) NewCommand() *cobra.Command {
Expand All @@ -46,8 +46,8 @@ func (c *Client) NewCommand() *cobra.Command {
root.PersistentPreRun(cmd, args)
}
}
c.ProjectService = c.Servicer.API(cmd).ProjectIPs
c.DeviceService = c.Servicer.API(cmd).DeviceIPs
c.IPService = *c.Servicer.MetalAPI(cmd).IPAddressesApi
c.DeviceService = *c.Servicer.MetalAPI(cmd).DevicesApi
},
}

Expand All @@ -63,8 +63,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
}

func NewClient(s Servicer, out outputs.Outputer) *Client {
Expand Down
3 changes: 2 additions & 1 deletion internal/ips/remove.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
package ips

import (
"context"
"fmt"

"github.com/spf13/cobra"
Expand All @@ -38,7 +39,7 @@ func (c *Client) Remove() *cobra.Command {

RunE: func(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
_, err := c.ProjectService.Remove(reservationID)
_, err := c.IPService.DeleteIPAddress(context.Background(), reservationID).Execute()
if err != nil {
return fmt.Errorf("Could not remove IP address Reservation: %w", err)
}
Expand Down
23 changes: 16 additions & 7 deletions internal/ips/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@
package ips

import (
"context"
"fmt"
"strconv"

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

Expand All @@ -49,22 +50,30 @@ func (c *Client) Request() *cobra.Command {

RunE: func(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
req := &packngo.IPReservationRequest{
Type: packngo.IPReservationType(ttype),
Quantity: quantity,
Facility: &facility,

req := &metal.IPReservationRequestInput{
Metro: &metro,
Tags: tags,
Quantity: int32(quantity),
Type: ttype,
Facility: &facility,
}

requestIPReservationRequest := &metal.RequestIPReservationRequest{
IPReservationRequestInput: req,
}

reservation, _, err := c.ProjectService.Request(projectID, req)
reservation, _, err := c.IPService.RequestIPReservation(context.Background(), projectID).RequestIPReservationRequest(*requestIPReservationRequest).Execute()
if err != nil {
return fmt.Errorf("Could not request IP addresses: %w", err)
}

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

data[0] = []string{reservation.ID, reservation.Address, strconv.FormatBool(reservation.Public), reservation.Created}
data[0] = []string{reservation.IPReservation.GetId(),
reservation.IPReservation.GetAddress(),
strconv.FormatBool(reservation.IPReservation.GetPublic()),
reservation.IPReservation.CreatedAt.String()}
header := []string{"ID", "Address", "Public", "Created"}

return c.Out.Output(reservation, header, &data)
Expand Down
40 changes: 24 additions & 16 deletions internal/ips/retrieve.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
package ips

import (
"context"
"fmt"
"strconv"

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

Expand Down Expand Up @@ -59,57 +61,63 @@ func (c *Client) Retrieve() *cobra.Command {
}

cmd.SilenceUsage = true
listOpts := c.Servicer.ListOptions(nil, nil)
inc := []string{}
exc := []string{}
types := []string{}

if assignmentID != "" {
ip, _, err := c.ProjectService.Get(assignmentID, listOpts)
ip, _, err := c.IPService.FindIPAddressById(context.Background(), assignmentID).Include(inc).Exclude(exc).Execute()
if err != nil {
return fmt.Errorf("Could not get Device IP address: %w", err)
}

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

data[0] = []string{ip.ID, ip.Address, strconv.FormatBool(ip.Public), ip.Created}
data[0] = []string{ip.IPAssignment.GetId(), ip.IPAssignment.GetAddress(), strconv.FormatBool(ip.IPAssignment.GetPublic()), ip.IPAssignment.CreatedAt.String()}
header := []string{"ID", "Address", "Public", "Created"}

return c.Out.Output(ip, header, &data)
} else if reservationID != "" {
ip, _, err := c.ProjectService.Get(reservationID, listOpts)
ip, _, err := c.IPService.FindIPAddressById(context.Background(), reservationID).Include(inc).Exclude(exc).Execute()
if err != nil {
return fmt.Errorf("Could not get Reservation IP address: %w", err)
}

data := make([][]string, 1)
code := ""
metro := ""
if ip.Facility != nil {
code = ip.Facility.Code
if ip.IPReservation.Facility != nil {
code = ip.IPReservation.Facility.GetCode()
}
if ip.Metro != nil {
metro = ip.Metro.Code

if ip.IPReservation.Metro != nil {
metro = ip.IPReservation.Metro.GetCode()
}
data[0] = []string{ip.ID, ip.Address, metro, code, strconv.FormatBool(ip.Public), ip.Created}

data[0] = []string{ip.IPReservation.GetId(), ip.IPReservation.GetAddress(), metro, code, strconv.FormatBool(ip.IPReservation.GetPublic()), ip.IPReservation.CreatedAt.String()}
header := []string{"ID", "Address", "Metro", "Facility", "Public", "Created"}

return c.Out.Output(ip, header, &data)
}

ips, _, err := c.ProjectService.List(projectID, listOpts)
ips, err := pager.GetAllIPReservations(c.IPService, projectID, inc, exc, types)
// ipsList, _, err := c.IPService.FindIPReservations(context.Background(), projectID).Types(types).Include(inc).Exclude(exc).Execute()
if err != nil {
return fmt.Errorf("Could not list Project IP addresses: %w", err)
}

// ips := ipsList.GetIpAddresses()
data := make([][]string, len(ips))

for i, ip := range ips {
code := ""
metro := ""
if ip.Facility != nil {
code = ip.Facility.Code
if ip.IPReservation.Facility != nil {
code = ip.IPReservation.Facility.GetCode()
}
if ip.Metro != nil {
metro = ip.Metro.Code
if ip.IPReservation.Metro != nil {
metro = ip.IPReservation.Metro.GetCode()
}
data[i] = []string{ip.ID, ip.Address, metro, code, strconv.FormatBool(ip.Public), ip.Created}
data[i] = []string{ip.IPReservation.GetId(), ip.IPReservation.GetAddress(), metro, code, strconv.FormatBool(ip.IPReservation.GetPublic()), ip.IPReservation.CreatedAt.String()}
}
header := []string{"ID", "Address", "Metro", "Facility", "Public", "Created"}

Expand Down
3 changes: 2 additions & 1 deletion internal/ips/unassign.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
package ips

import (
"context"
"fmt"

"github.com/spf13/cobra"
Expand All @@ -38,7 +39,7 @@ func (c *Client) Unassign() *cobra.Command {

RunE: func(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
_, err := c.DeviceService.Unassign(assignmentID)
_, err := c.IPService.DeleteIPAddress(context.Background(), assignmentID).Execute()
if err != nil {
return fmt.Errorf("Could not unassign IP address: %w", err)
}
Expand Down
20 changes: 20 additions & 0 deletions internal/pagination/pager.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,23 @@ func GetProjectDevices(s metal.ApiFindProjectDevicesRequest) ([]metal.Device, er
return devices, nil
}
}

func GetAllIPReservations(s metal.IPAddressesApiService, projectId string, inc, exc, types []string) ([]metal.IPReservationListIpAddressesInner, error) {
var ipReservations []metal.IPReservationListIpAddressesInner
page := int32(1) // int32 | Page to return (optional) (default to 1)
perPage := int32(20) // int32 | Items returned per page (optional) (default to 10)

for {
ipReservationsPage, _, err := s.FindIPReservations(context.Background(), projectId).Types(types).Include(inc).Exclude(exc).PerPage(perPage).Execute()

Check failure on line 155 in internal/pagination/pager.go

View workflow job for this annotation

GitHub Actions / test

cannot use types (variable of type []string) as type []v1.FindIPReservationsTypesParameterInner in argument to s.FindIPReservations(context.Background(), projectId).Types

Check failure on line 155 in internal/pagination/pager.go

View workflow job for this annotation

GitHub Actions / lint

cannot use types (variable of type []string) as type []v1.FindIPReservationsTypesParameterInner in argument to s.FindIPReservations(context.Background(), projectId).Types (typecheck)

Check failure on line 155 in internal/pagination/pager.go

View workflow job for this annotation

GitHub Actions / lint

cannot use types (variable of type []string) as type []v1.FindIPReservationsTypesParameterInner in argument to s.FindIPReservations(context.Background(), projectId).Types) (typecheck)

Check failure on line 155 in internal/pagination/pager.go

View workflow job for this annotation

GitHub Actions / lint

cannot use types (variable of type []string) as type []v1.FindIPReservationsTypesParameterInner in argument to s.FindIPReservations(context.Background(), projectId).Types) (typecheck)

Check failure on line 155 in internal/pagination/pager.go

View workflow job for this annotation

GitHub Actions / lint

cannot use types (variable of type []string) as type []v1.FindIPReservationsTypesParameterInner in argument to s.FindIPReservations(context.Background(), projectId).Types) (typecheck)

Check failure on line 155 in internal/pagination/pager.go

View workflow job for this annotation

GitHub Actions / docs (1.19)

cannot use types (variable of type []string) as type []v1.FindIPReservationsTypesParameterInner in argument to s.FindIPReservations(context.Background(), projectId).Types
if err != nil {
return nil, err
}

ipReservations = append(ipReservations, ipReservationsPage.GetIpAddresses()...)
if ipReservationsPage.Meta.GetLastPage() > ipReservationsPage.Meta.GetCurrentPage() {
page = page + 1
continue
}
return ipReservations, nil
}
}
87 changes: 87 additions & 0 deletions test/e2e/ipstest/ips_get_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package ipstest

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

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

func TestCli_Ips_Get(t *testing.T) {
var projectId, ipsId string
var err error
subCommand := "ip"
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_virtual_network",
fields: fields{
MainCmd: ips.NewClient(rootClient, outputPkg.Outputer(&outputPkg.Standard{})).NewCommand(),
Outputer: outputPkg.Outputer(&outputPkg.Standard{}),
},
want: &cobra.Command{},
cmdFunc: func(t *testing.T, c *cobra.Command) {
if true {
t.Skip("Skipping this test because someCondition is true")
}
root := c.Root()
projectId, err = helper.CreateTestProject("metal-cli-ips-get-pro")
if err != nil {
t.Error(err)
}
ipsId, err = helper.CreateTestIps(projectId, 5, "public_ipv4")
if len(projectId) != 0 && len(ipsId) != 0 {
root.SetArgs([]string{subCommand, "get", "-p", projectId})
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[:]), ipsId) &&
!strings.Contains(string(out[:]), "da") {
t.Error("expected output should include " + ipsId + " da strings in the out string")
}

err = helper.CleanTestIps(ipsId)
if err != nil {
t.Error(err)
}
err = helper.CleanTestProject(projectId)
if err != nil {
t.Error(err)
}
}
},
},
}

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)
})
}
}
Loading

0 comments on commit 7fe2a75

Please sign in to comment.