Skip to content

Commit

Permalink
feat: Updated metal-go client for sub-commands ips (#291)
Browse files Browse the repository at this point in the history
Breakout from #270

What this PR does / why we need it:

This PR replaces packngo with metal-go for all interactions with the
Equinix Metal API specifically for ports sub commands

DISCUSSION POINTS:

META parameter is missing in IPAddressList
https://github.com/vasubabu/metal-go/blob/main/docs/IPReservationList.md
  • Loading branch information
codinja1188 authored Sep 29, 2023
1 parent a264ffd commit ccfb9bd
Show file tree
Hide file tree
Showing 14 changed files with 295 additions and 43 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/equinix/metal-cli
go 1.19

require (
github.com/equinix-labs/metal-go v0.22.2
github.com/equinix-labs/metal-go v0.23.1
github.com/manifoldco/promptui v0.9.0
github.com/olekukonko/tablewriter v0.0.5
github.com/packethost/packngo v0.30.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/equinix-labs/metal-go v0.22.2 h1:3uVx1tMUb+P9MXcQzmoh5sRM40+Efdtc7yWwlKOh/ms=
github.com/equinix-labs/metal-go v0.22.2/go.mod h1:SmxCklxW+KjmBLVMdEXgtFO5gD5/b4N0VxcNgUYbOH4=
github.com/equinix-labs/metal-go v0.23.1 h1:u6rdCKW7ZN/ydxS63+cbPMjHk8wYiVPYJsb8LB1sXZM=
github.com/equinix-labs/metal-go v0.23.1/go.mod h1:SmxCklxW+KjmBLVMdEXgtFO5gD5/b4N0VxcNgUYbOH4=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
Expand Down
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
8 changes: 6 additions & 2 deletions internal/ips/available.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +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 @@ -41,10 +43,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 := metal.FindIPAvailabilitiesCidrParameter(strconv.Itoa(cidr))
resultList, _, err := c.IPService.FindIPAvailabilities(context.Background(), reservationID).Cidr(Cidr).Execute()
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,12 @@
package ips

import (
"context"
"fmt"
"strconv"

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

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

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

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)
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 []string, exc []string, types []metal.FindIPReservationsTypesParameterInner) ([]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()
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
}
}
Loading

0 comments on commit ccfb9bd

Please sign in to comment.