From 4e415c5a2ae0cab882b5078e4285735081a1c9aa Mon Sep 17 00:00:00 2001 From: Charles Treatman Date: Mon, 20 Mar 2023 14:41:34 -0500 Subject: [PATCH] [WIP] Adopt metal-go --- cmd/ci-clean/main.go | 77 +++++------- controllers/packetcluster_controller.go | 8 +- controllers/packetmachine_controller.go | 68 ++++++----- go.mod | 2 +- go.sum | 10 +- pkg/cloud/packet/client.go | 154 ++++++++++++++---------- test/e2e/common_test.go | 18 +-- test/e2e/go.mod | 2 +- test/e2e/go.sum | 9 +- test/e2e/suite_test.go | 22 ++-- version/version.go | 11 +- 11 files changed, 205 insertions(+), 176 deletions(-) diff --git a/cmd/ci-clean/main.go b/cmd/ci-clean/main.go index 7514b699c..e890a3632 100644 --- a/cmd/ci-clean/main.go +++ b/cmd/ci-clean/main.go @@ -17,6 +17,7 @@ limitations under the License. package main import ( + "context" "errors" "fmt" "math/rand" @@ -24,7 +25,7 @@ import ( "strings" "time" - "github.com/packethost/packngo" + metal "github.com/equinix-labs/metal-go/metal/v1" "github.com/spf13/cobra" kerrors "k8s.io/apimachinery/pkg/util/errors" @@ -55,7 +56,7 @@ func main() { return fmt.Errorf("%s: %w", ProjectIDEnvVar, ErrMissingRequiredEnvVar) } - return cleanup(metalAuthToken, metalProjectID) //nolint:wrapcheck + return cleanup(context.Background(), metalAuthToken, metalProjectID) //nolint:wrapcheck }, } @@ -64,55 +65,50 @@ func main() { } } -func cleanup(metalAuthToken, metalProjectID string) error { +func cleanup(ctx context.Context, metalAuthToken, metalProjectID string) error { metalClient := packet.NewClient(metalAuthToken) - listOpts := &packngo.ListOptions{} var errs []error - devices, _, err := metalClient.Devices.List(metalProjectID, listOpts) + devices, _, err := metalClient.DevicesApi.FindProjectDevices(ctx, metalProjectID).Execute() if err != nil { return fmt.Errorf("failed to list devices: %w", err) } - if err := deleteDevices(metalClient, devices); err != nil { + if err := deleteDevices(ctx, metalClient, *devices); err != nil { errs = append(errs, err) } - ips, _, err := metalClient.ProjectIPs.List(metalProjectID, listOpts) + ips, _, err := metalClient.IPAddressesApi.FindIPReservations(ctx, metalProjectID).Execute() if err != nil { return fmt.Errorf("failed to list ip addresses: %w", err) } - if err := deleteIPs(metalClient, ips); err != nil { + if err := deleteIPs(ctx, metalClient, *ips); err != nil { errs = append(errs, err) } - keys, _, err := metalClient.Projects.ListSSHKeys(metalProjectID, listOpts) + keys, _, err := metalClient.SSHKeysApi.FindProjectSSHKeys(ctx, metalProjectID).Execute() if err != nil { return fmt.Errorf("failed to list ssh keys: %w", err) } - if err := deleteKeys(metalClient, keys); err != nil { + if err := deleteKeys(ctx, metalClient, *keys); err != nil { errs = append(errs, err) } return kerrors.NewAggregate(errs) } -func deleteDevices(metalClient *packet.Client, devices []packngo.Device) error { +func deleteDevices(ctx context.Context, metalClient *packet.Client, devices metal.DeviceList) error { var errs []error - for _, d := range devices { - created, err := time.Parse(time.RFC3339, d.Created) - if err != nil { - errs = append(errs, fmt.Errorf("failed to parse creation time for device %q: %w", d.Hostname, err)) - continue - } - if time.Since(created) > 4*time.Hour { - fmt.Printf("Deleting device: %s\n", d.Hostname) - _, err := metalClient.Devices.Delete(d.ID, false) + for _, d := range devices.Devices { + if time.Since(d.GetCreatedAt()) > 4*time.Hour { + hostname := d.GetHostname() + fmt.Printf("Deleting device: %s\n", hostname) + _, err := metalClient.DevicesApi.DeleteDevice(ctx, d.GetId()).ForceDelete(false).Execute() if err != nil { - errs = append(errs, fmt.Errorf("failed to delete device %q: %w", d.Hostname, err)) + errs = append(errs, fmt.Errorf("failed to delete device %q: %w", hostname, err)) } } } @@ -120,23 +116,21 @@ func deleteDevices(metalClient *packet.Client, devices []packngo.Device) error { return kerrors.NewAggregate(errs) } -func deleteIPs(metalClient *packet.Client, ips []packngo.IPAddressReservation) error { +func deleteIPs(ctx context.Context, metalClient *packet.Client, ips metal.IPReservationList) error { var errs []error - for _, ip := range ips { - created, err := time.Parse(time.RFC3339, ip.Created) - if err != nil { - errs = append(errs, fmt.Errorf("failed to parse creation time for ip address %q: %w", ip.Address, err)) - continue - } - - if time.Since(created) > 4*time.Hour { + for _, reservation := range ips.IpAddresses { + // TODO: per the spec, `reservation` could be an `IPReservation` or a `VrfIpReservation` + // maybe metal-go could define and we could move the if block to function that takes + // that interface as an argument + ip := reservation.IPReservation + if ip != nil && time.Since(ip.GetCreatedAt()) > 4*time.Hour { for _, tag := range ip.Tags { if strings.HasPrefix(tag, "cluster-api-provider-packet:cluster-id:") || strings.HasPrefix(tag, "usage=cloud-provider-equinix-metal-auto") { - fmt.Printf("Deleting IP: %s\n", ip.Address) + fmt.Printf("Deleting IP: %s\n", ip.GetAddress()) - if _, err := metalClient.ProjectIPs.Remove(ip.ID); err != nil { - errs = append(errs, fmt.Errorf("failed to delete ip address %q: %w", ip.Address, err)) + if _, err := metalClient.IPAddressesApi.DeleteIPAddress(ctx, ip.GetId()).Execute(); err != nil { + errs = append(errs, fmt.Errorf("failed to delete ip address %q: %w", ip.GetAddress(), err)) } break @@ -148,20 +142,15 @@ func deleteIPs(metalClient *packet.Client, ips []packngo.IPAddressReservation) e return kerrors.NewAggregate(errs) } -func deleteKeys(metalClient *packet.Client, keys []packngo.SSHKey) error { +func deleteKeys(ctx context.Context, metalClient *packet.Client, keys metal.SSHKeyList) error { var errs []error - for _, k := range keys { - created, err := time.Parse(time.RFC3339, k.Created) - if err != nil { - errs = append(errs, fmt.Errorf("failed to parse creation time for SSH Key %q: %w", k.Label, err)) - continue - } - if time.Since(created) > 4*time.Hour { - fmt.Printf("Deleting SSH Key: %s\n", k.Label) - _, err := metalClient.SSHKeys.Delete(k.ID) + for _, k := range keys.SshKeys { + if time.Since(k.GetCreatedAt()) > 4*time.Hour { + fmt.Printf("Deleting SSH Key: %s\n", k.GetLabel()) + _, err := metalClient.SSHKeysApi.DeleteSSHKey(ctx, k.GetId()).Execute() if err != nil { - errs = append(errs, fmt.Errorf("failed to delete SSH Key %q: %w", k.Label, err)) + errs = append(errs, fmt.Errorf("failed to delete SSH Key %q: %w", k.GetLabel(), err)) } } } diff --git a/controllers/packetcluster_controller.go b/controllers/packetcluster_controller.go index 564abe0bb..3bd49f2b4 100644 --- a/controllers/packetcluster_controller.go +++ b/controllers/packetcluster_controller.go @@ -113,7 +113,7 @@ func (r *PacketClusterReconciler) reconcileNormal(ctx context.Context, clusterSc packetCluster := clusterScope.PacketCluster - ipReserv, err := r.PacketClient.GetIPByClusterIdentifier(clusterScope.Namespace(), clusterScope.Name(), packetCluster.Spec.ProjectID) + ipReserv, err := r.PacketClient.GetIPByClusterIdentifier(ctx, clusterScope.Namespace(), clusterScope.Name(), packetCluster.Spec.ProjectID) switch { case errors.Is(err, packet.ErrControlPlanEndpointNotFound): // Parse metro and facility from the cluster spec @@ -128,7 +128,7 @@ func (r *PacketClusterReconciler) reconcileNormal(ctx context.Context, clusterSc } // There is not an ElasticIP with the right tags, at this point we can create one - ip, err := r.PacketClient.CreateIP(clusterScope.Namespace(), clusterScope.Name(), packetCluster.Spec.ProjectID, facility, metro) + ip, err := r.PacketClient.CreateIP(ctx, clusterScope.Namespace(), clusterScope.Name(), packetCluster.Spec.ProjectID, facility, metro) if err != nil { log.Error(err, "error reserving an ip") return ctrl.Result{}, err @@ -143,13 +143,13 @@ func (r *PacketClusterReconciler) reconcileNormal(ctx context.Context, clusterSc default: // If there is an ElasticIP with the right tag just use it again clusterScope.PacketCluster.Spec.ControlPlaneEndpoint = clusterv1.APIEndpoint{ - Host: ipReserv.Address, + Host: ipReserv.GetAddress(), Port: 6443, } } if clusterScope.PacketCluster.Spec.VIPManager == "KUBE_VIP" { - if err := r.PacketClient.EnableProjectBGP(packetCluster.Spec.ProjectID); err != nil { + if err := r.PacketClient.EnableProjectBGP(ctx, packetCluster.Spec.ProjectID); err != nil { log.Error(err, "error enabling bgp for project") return ctrl.Result{}, err } diff --git a/controllers/packetmachine_controller.go b/controllers/packetmachine_controller.go index 39db47ad8..44642c8f7 100644 --- a/controllers/packetmachine_controller.go +++ b/controllers/packetmachine_controller.go @@ -24,7 +24,7 @@ import ( "strings" "time" - "github.com/packethost/packngo" + metal "github.com/equinix-labs/metal-go/metal/v1" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" @@ -258,26 +258,26 @@ func (r *PacketMachineReconciler) reconcile(ctx context.Context, machineScope *s providerID := machineScope.GetInstanceID() var ( - dev *packngo.Device + dev *metal.Device addrs []corev1.NodeAddress err error - controlPlaneEndpoint packngo.IPAddressReservation + controlPlaneEndpoint *metal.IPReservation + resp *http.Response ) if providerID != "" { // If we already have a providerID, then retrieve the device using the // providerID. This means that the Machine has already been created // and we successfully recorded the providerID. - dev, err = r.PacketClient.GetDevice(providerID) + dev, resp, err = r.PacketClient.GetDevice(ctx, providerID) //nolint:bodyclose // see https://github.com/timakin/bodyclose/issues/42 if err != nil { - var perr *packngo.ErrorResponse - if errors.As(err, &perr) && perr.Response != nil { - if perr.Response.StatusCode == http.StatusNotFound { + if resp != nil { + if resp.StatusCode == http.StatusNotFound { machineScope.SetFailureReason(capierrors.UpdateMachineError) machineScope.SetFailureMessage(fmt.Errorf("failed to find device: %w", err)) log.Error(err, "unable to find device") conditions.MarkFalse(machineScope.PacketMachine, infrav1.DeviceReadyCondition, infrav1.InstanceNotFoundReason, clusterv1.ConditionSeverityError, err.Error()) - } else if perr.Response.StatusCode == http.StatusForbidden { + } else if resp.StatusCode == http.StatusForbidden { machineScope.SetFailureReason(capierrors.UpdateMachineError) log.Error(err, "device failed to provision") machineScope.SetFailureMessage(fmt.Errorf("device failed to provision: %w", err)) @@ -294,6 +294,7 @@ func (r *PacketMachineReconciler) reconcile(ctx context.Context, machineScope *s // created a device by using the tags that we assign to devices // on creation. dev, err = r.PacketClient.GetDeviceByTags( + ctx, machineScope.PacketCluster.Spec.ProjectID, packet.DefaultCreateTags(machineScope.Namespace(), machineScope.Machine.Name, machineScope.Cluster.Name), ) @@ -324,6 +325,7 @@ func (r *PacketMachineReconciler) reconcile(ctx context.Context, machineScope *s // to template out the kube-vip deployment if machineScope.IsControlPlane() { controlPlaneEndpoint, _ = r.PacketClient.GetIPByClusterIdentifier( + ctx, machineScope.Cluster.Namespace, machineScope.Cluster.Name, machineScope.PacketCluster.Spec.ProjectID) @@ -331,12 +333,12 @@ func (r *PacketMachineReconciler) reconcile(ctx context.Context, machineScope *s if len(controlPlaneEndpoint.Assignments) == 0 { a := corev1.NodeAddress{ Type: corev1.NodeExternalIP, - Address: controlPlaneEndpoint.Address, + Address: controlPlaneEndpoint.GetAddress(), } addrs = append(addrs, a) } } - createDeviceReq.ControlPlaneEndpoint = controlPlaneEndpoint.Address + createDeviceReq.ControlPlaneEndpoint = controlPlaneEndpoint.GetAddress() } dev, err = r.PacketClient.NewDevice(ctx, createDeviceReq) @@ -363,11 +365,11 @@ func (r *PacketMachineReconciler) reconcile(ctx context.Context, machineScope *s } // we do not need to set this as equinixmetal:// because SetProviderID() does the formatting for us - machineScope.SetProviderID(dev.ID) - machineScope.SetInstanceStatus(infrav1.PacketResourceStatus(dev.State)) + machineScope.SetProviderID(dev.GetId()) + machineScope.SetInstanceStatus(infrav1.PacketResourceStatus(dev.GetState())) if machineScope.PacketCluster.Spec.VIPManager == "KUBE_VIP" { - if err := r.PacketClient.EnsureNodeBGPEnabled(dev.ID); err != nil { + if err := r.PacketClient.EnsureNodeBGPEnabled(ctx, dev.GetId()); err != nil { // Do not treat an error enabling bgp on machine as fatal return ctrl.Result{RequeueAfter: time.Second * 20}, fmt.Errorf("failed to enable bgp on machine %s: %w", machineScope.Name(), err) } @@ -379,7 +381,7 @@ func (r *PacketMachineReconciler) reconcile(ctx context.Context, machineScope *s // Proceed to reconcile the PacketMachine state. var result reconcile.Result - switch infrav1.PacketResourceStatus(dev.State) { + switch infrav1.PacketResourceStatus(dev.GetState()) { case infrav1.PacketResourceStatusNew, infrav1.PacketResourceStatusQueued, infrav1.PacketResourceStatusProvisioning: log.Info("Machine instance is pending", "instance-id", machineScope.GetInstanceID()) machineScope.SetNotReady() @@ -389,13 +391,15 @@ func (r *PacketMachineReconciler) reconcile(ctx context.Context, machineScope *s if machineScope.PacketCluster.Spec.VIPManager == "CPEM" { controlPlaneEndpoint, _ = r.PacketClient.GetIPByClusterIdentifier( + ctx, machineScope.Cluster.Namespace, machineScope.Cluster.Name, machineScope.PacketCluster.Spec.ProjectID) if len(controlPlaneEndpoint.Assignments) == 0 && machineScope.IsControlPlane() { - if _, _, err := r.PacketClient.DeviceIPs.Assign(dev.ID, &packngo.AddressStruct{ - Address: controlPlaneEndpoint.Address, - }); err != nil { + apiRequest := r.PacketClient.DevicesApi.CreateIPAssignment(ctx, *dev.Id).IPAssignmentInput(metal.IPAssignmentInput{ + Address: controlPlaneEndpoint.GetAddress(), + }) + if _, _, err := apiRequest.Execute(); err != nil { //nolint:bodyclose // see https://github.com/timakin/bodyclose/issues/42 log.Error(err, "err assigining elastic ip to control plane. retrying...") return ctrl.Result{RequeueAfter: time.Second * 20}, nil } @@ -408,22 +412,24 @@ func (r *PacketMachineReconciler) reconcile(ctx context.Context, machineScope *s result = ctrl.Result{} default: machineScope.SetNotReady() - log.Info("Equinix Metal device state is undefined", "state", dev.State, "device-id", machineScope.GetInstanceID()) + log.Info("Equinix Metal device state is undefined", "state", dev.GetState(), "device-id", machineScope.GetInstanceID()) machineScope.SetFailureReason(capierrors.UpdateMachineError) - machineScope.SetFailureMessage(fmt.Errorf("instance status %q is unexpected", dev.State)) //nolint:goerr113 + machineScope.SetFailureMessage(fmt.Errorf("instance status %q is unexpected", dev.GetState())) //nolint:goerr113 conditions.MarkUnknown(machineScope.PacketMachine, infrav1.DeviceReadyCondition, "", "") result = ctrl.Result{} } // If Metro or Facility has changed in the spec, verify that the facility's metro is compatible with the requested spec change. + deviceFacility := dev.Facility.Code + deviceMetro := dev.Metro.Code - if machineScope.PacketMachine.Spec.Facility != "" && machineScope.PacketMachine.Spec.Facility != dev.Facility.Code { - return ctrl.Result{}, fmt.Errorf("%w: %s != %s", ErrFacilityMatch, machineScope.PacketMachine.Spec.Facility, dev.Facility.Code) + if machineScope.PacketMachine.Spec.Facility != "" && machineScope.PacketMachine.Spec.Facility != *deviceFacility { + return ctrl.Result{}, fmt.Errorf("%w: %s != %s", ErrFacilityMatch, machineScope.PacketMachine.Spec.Facility, *deviceFacility) } - if machineScope.PacketMachine.Spec.Metro != "" && machineScope.PacketMachine.Spec.Metro != dev.Metro.Code { - return ctrl.Result{}, fmt.Errorf("%w: %s != %s", ErrMetroMatch, machineScope.PacketMachine.Spec.Facility, dev.Facility.Code) + if machineScope.PacketMachine.Spec.Metro != "" && machineScope.PacketMachine.Spec.Metro != *deviceMetro { + return ctrl.Result{}, fmt.Errorf("%w: %s != %s", ErrMetroMatch, machineScope.PacketMachine.Spec.Facility, *deviceMetro) } return result, nil @@ -436,12 +442,13 @@ func (r *PacketMachineReconciler) reconcileDelete(ctx context.Context, machineSc packetmachine := machineScope.PacketMachine providerID := machineScope.GetInstanceID() - var device *packngo.Device + var device *metal.Device if providerID == "" { // If no providerID was recorded, check to see if there are any instances // that match by tags dev, err := r.PacketClient.GetDeviceByTags( + ctx, machineScope.PacketCluster.Spec.ProjectID, packet.DefaultCreateTags(machineScope.Namespace(), machineScope.Machine.Name, machineScope.Cluster.Name), ) @@ -457,12 +464,12 @@ func (r *PacketMachineReconciler) reconcileDelete(ctx context.Context, machineSc device = dev } else { + var resp *http.Response // Otherwise, try to retrieve the device by the providerID - dev, err := r.PacketClient.GetDevice(providerID) + dev, resp, err := r.PacketClient.GetDevice(ctx, providerID) //nolint:bodyclose // see https://github.com/timakin/bodyclose/issues/42 if err != nil { - var errResp *packngo.ErrorResponse - if errors.As(err, &errResp) && errResp.Response != nil { - if errResp.Response.StatusCode == http.StatusNotFound { + if resp != nil { + if resp.StatusCode == http.StatusNotFound { // When the server does not exist we do not have anything left to do. // Probably somebody manually deleted the server from the UI or via API. log.Info("Server not found by id, nothing left to do") @@ -470,7 +477,7 @@ func (r *PacketMachineReconciler) reconcileDelete(ctx context.Context, machineSc return ctrl.Result{}, nil } - if errResp.Response.StatusCode == http.StatusForbidden { + if resp.StatusCode == http.StatusForbidden { // When a server fails to provision it will return a 403 log.Info("Server appears to have failed provisioning, nothing left to do") controllerutil.RemoveFinalizer(packetmachine, infrav1.MachineFinalizer) @@ -490,7 +497,8 @@ func (r *PacketMachineReconciler) reconcileDelete(ctx context.Context, machineSc return ctrl.Result{}, fmt.Errorf("%w: %s", ErrMissingDevice, packetmachine.Name) } - if _, err := r.PacketClient.Devices.Delete(device.ID, force); err != nil { + apiRequest := r.PacketClient.DevicesApi.DeleteDevice(ctx, device.GetId()).ForceDelete(force) + if _, err := apiRequest.Execute(); err != nil { //nolint:bodyclose // see https://github.com/timakin/bodyclose/issues/42 return ctrl.Result{}, fmt.Errorf("failed to delete the machine: %w", err) } diff --git a/go.mod b/go.mod index d1f1ea8ae..819129470 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module sigs.k8s.io/cluster-api-provider-packet go 1.19 require ( + github.com/equinix-labs/metal-go v0.7.1 github.com/onsi/gomega v1.24.1 - github.com/packethost/packngo v0.29.0 github.com/pkg/errors v0.9.1 github.com/spf13/cobra v1.6.1 github.com/spf13/pflag v1.0.5 diff --git a/go.sum b/go.sum index 9a408aec5..7e7d844c7 100644 --- a/go.sum +++ b/go.sum @@ -88,8 +88,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY= -github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= @@ -101,6 +99,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/equinix-labs/metal-go v0.7.1 h1:dcLkBhPlTn2v4VJJBDZorYLo3QUs10FxQnwKJ8IczHk= +github.com/equinix-labs/metal-go v0.7.1/go.mod h1:qVHxbntL4uTflH4+OhtM7MNawG8j3swquGh3LLLPdfw= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -189,7 +189,6 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -313,8 +312,6 @@ github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E= github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/packethost/packngo v0.29.0 h1:gRIhciVZQ/zLNrIdIdbOUyB/Tw5IgoaXyhP4bvE+D2s= -github.com/packethost/packngo v0.29.0/go.mod h1:/UHguFdPs6Lf6FOkkSEPnRY5tgS0fsVM+Zv/bvBrmt0= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -392,8 +389,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -424,7 +421,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= diff --git a/pkg/cloud/packet/client.go b/pkg/cloud/packet/client.go index 38d7c7b5b..d7476bca8 100644 --- a/pkg/cloud/packet/client.go +++ b/pkg/cloud/packet/client.go @@ -27,7 +27,7 @@ import ( "strings" "text/template" - "github.com/packethost/packngo" + metal "github.com/equinix-labs/metal-go/metal/v1" corev1 "k8s.io/api/core/v1" "k8s.io/utils/pointer" @@ -55,7 +55,7 @@ var ( ) type Client struct { - *packngo.Client + *metal.APIClient } // NewClient creates a new Client for the given Packet credentials @@ -63,9 +63,12 @@ func NewClient(packetAPIKey string) *Client { token := strings.TrimSpace(packetAPIKey) if token != "" { - metalClient := &Client{packngo.NewClientWithAuth(clientName, token, nil)} - metalClient.UserAgent = fmt.Sprintf(clientUAFormat, version.Get(), metalClient.UserAgent) - + configuration := metal.NewConfiguration() + configuration.Debug = true + configuration.AddDefaultHeader("X-Auth-Token", token) + configuration.AddDefaultHeader("X-Consumer-Token", clientName) + configuration.UserAgent = fmt.Sprintf(clientUAFormat, version.Get(), configuration.UserAgent) + metalClient := &Client{metal.NewAPIClient(configuration)} return metalClient } @@ -80,9 +83,9 @@ func GetClient() (*Client, error) { return NewClient(token), nil } -func (p *Client) GetDevice(deviceID string) (*packngo.Device, error) { - dev, _, err := p.Devices.Get(deviceID, nil) - return dev, err +func (p *Client) GetDevice(ctx context.Context, deviceID string) (*metal.Device, *http.Response, error) { + dev, resp, err := p.DevicesApi.FindDeviceById(ctx, deviceID).Execute() + return dev, resp, err } type CreateDeviceRequest struct { @@ -91,7 +94,7 @@ type CreateDeviceRequest struct { ControlPlaneEndpoint string } -func (p *Client) NewDevice(ctx context.Context, req CreateDeviceRequest) (*packngo.Device, error) { +func (p *Client) NewDevice(ctx context.Context, req CreateDeviceRequest) (*metal.Device, error) { packetMachineSpec := req.MachineScope.PacketMachine.Spec packetClusterSpec := req.MachineScope.PacketCluster.Spec if packetMachineSpec.IPXEUrl != "" { @@ -123,7 +126,7 @@ func (p *Client) NewDevice(ctx context.Context, req CreateDeviceRequest) (*packn if req.MachineScope.IsControlPlane() { // control plane machines should get the API key injected - userDataValues["apiKey"] = p.APIKey + userDataValues["apiKey"] = p.APIClient.GetConfig().DefaultHeader["X-Auth-Token"] if req.ControlPlaneEndpoint != "" { userDataValues["controlPlaneEndpoint"] = req.ControlPlaneEndpoint @@ -150,27 +153,40 @@ func (p *Client) NewDevice(ctx context.Context, req CreateDeviceRequest) (*packn facility = packetMachineSpec.Facility } - serverCreateOpts := &packngo.DeviceCreateRequest{ - Hostname: req.MachineScope.Name(), - ProjectID: packetClusterSpec.ProjectID, - Metro: metro, - BillingCycle: packetMachineSpec.BillingCycle, - Plan: packetMachineSpec.MachineType, - OS: packetMachineSpec.OS, - IPXEScriptURL: packetMachineSpec.IPXEUrl, - Tags: tags, - UserData: userData, - } + hostname := req.MachineScope.Name() + + serverCreateOpts := metal.CreateDeviceRequest{} if facility != "" { - serverCreateOpts.Facility = []string{facility} + serverCreateOpts.DeviceCreateInFacilityInput = &metal.DeviceCreateInFacilityInput{ + Hostname: &hostname, + Facility: []string{facility}, + BillingCycle: &req.MachineScope.PacketMachine.Spec.BillingCycle, + Plan: req.MachineScope.PacketMachine.Spec.MachineType, + OperatingSystem: req.MachineScope.PacketMachine.Spec.OS, + IpxeScriptUrl: &req.MachineScope.PacketMachine.Spec.IPXEUrl, + Tags: tags, + Userdata: &userData, + } + } else { + serverCreateOpts.DeviceCreateInMetroInput = &metal.DeviceCreateInMetroInput{ + Hostname: &hostname, + Metro: metro, + BillingCycle: &req.MachineScope.PacketMachine.Spec.BillingCycle, + Plan: req.MachineScope.PacketMachine.Spec.MachineType, + OperatingSystem: req.MachineScope.PacketMachine.Spec.OS, + IpxeScriptUrl: &req.MachineScope.PacketMachine.Spec.IPXEUrl, + Tags: tags, + Userdata: &userData, + } } reservationIDs := strings.Split(packetMachineSpec.HardwareReservationID, ",") // If there are no reservationIDs to process, go ahead and return early - if len(reservationIDs) == 0 { - dev, _, err := p.Devices.Create(serverCreateOpts) + if len(reservationIDs) <= 1 { + apiRequest := p.DevicesApi.CreateDevice(ctx, req.MachineScope.PacketCluster.Spec.ProjectID) + dev, _, err := apiRequest.CreateDeviceRequest(serverCreateOpts).Execute() //nolint:bodyclose // see https://github.com/timakin/bodyclose/issues/42 return dev, err } @@ -180,8 +196,10 @@ func (p *Client) NewDevice(ctx context.Context, req CreateDeviceRequest) (*packn var lastErr error for _, resID := range reservationIDs { - serverCreateOpts.HardwareReservationID = resID - dev, _, err := p.Devices.Create(serverCreateOpts) + reservationID := resID + serverCreateOpts.DeviceCreateInFacilityInput.HardwareReservationId = &reservationID + apiRequest := p.DevicesApi.CreateDevice(ctx, req.MachineScope.PacketCluster.Spec.ProjectID) + dev, _, err := apiRequest.CreateDeviceRequest(serverCreateOpts).Execute() //nolint:bodyclose // see https://github.com/timakin/bodyclose/issues/42 if err != nil { lastErr = err continue @@ -193,29 +211,29 @@ func (p *Client) NewDevice(ctx context.Context, req CreateDeviceRequest) (*packn return nil, lastErr } -func (p *Client) GetDeviceAddresses(device *packngo.Device) []corev1.NodeAddress { +func (p *Client) GetDeviceAddresses(device *metal.Device) []corev1.NodeAddress { addrs := make([]corev1.NodeAddress, 0) - for _, addr := range device.Network { + for _, addr := range device.IpAddresses { addrType := corev1.NodeInternalIP - if addr.IpAddressCommon.Public { + if addr.GetPublic() { addrType = corev1.NodeExternalIP } a := corev1.NodeAddress{ Type: addrType, - Address: addr.Address, + Address: addr.GetAddress(), } addrs = append(addrs, a) } return addrs } -func (p *Client) GetDeviceByTags(project string, tags []string) (*packngo.Device, error) { - devices, _, err := p.Devices.List(project, nil) +func (p *Client) GetDeviceByTags(ctx context.Context, project string, tags []string) (*metal.Device, error) { + devices, _, err := p.DevicesApi.FindProjectDevices(ctx, project).Execute() //nolint:bodyclose // see https://github.com/timakin/bodyclose/issues/42 if err != nil { return nil, fmt.Errorf("error retrieving devices: %w", err) } // returns the first one that matches all of the tags - for _, device := range devices { + for _, device := range devices.Devices { if ItemsInList(device.Tags, tags) { return &device, nil } @@ -225,17 +243,21 @@ func (p *Client) GetDeviceByTags(project string, tags []string) (*packngo.Device // CreateIP reserves an IP via Packet API. The request fails straight if no IP are available for the specified project. // This prevent the cluster to become ready. -func (p *Client) CreateIP(namespace, clusterName, projectID, facility, metro string) (net.IP, error) { - req := packngo.IPReservationRequest{ - Type: packngo.PublicIPv4, +func (p *Client) CreateIP(ctx context.Context, namespace, clusterName, projectID, facility, metro string) (net.IP, error) { + failOnApprovalRequired := true + req := metal.IPReservationRequestInput{ + Type: "public_ipv4", Quantity: 1, Facility: &facility, Metro: &metro, - FailOnApprovalRequired: true, + FailOnApprovalRequired: &failOnApprovalRequired, Tags: []string{generateElasticIPIdentifier(clusterName)}, } - r, resp, err := p.ProjectIPs.Request(projectID, &req) + apiRequest := p.IPAddressesApi.RequestIPReservation(ctx, projectID) + r, resp, err := apiRequest.RequestIPReservationRequest(metal.RequestIPReservationRequest{ + IPReservationRequestInput: &req, + }).Execute() //nolint:bodyclose // see https://github.com/timakin/bodyclose/issues/42 if err != nil { return nil, err } @@ -243,17 +265,18 @@ func (p *Client) CreateIP(namespace, clusterName, projectID, facility, metro str return nil, ErrElasticIPQuotaExceeded } - ip := net.ParseIP(r.Address) + rawIP := r.IPReservation.GetAddress() + ip := net.ParseIP(rawIP) if ip == nil { - return nil, fmt.Errorf("failed to parse IP: %s, %w", r.Address, ErrInvalidIP) + return nil, fmt.Errorf("failed to parse IP: %s, %w", rawIP, ErrInvalidIP) } return ip, nil } // enableBGP enable bgp on the project -func (p *Client) EnableProjectBGP(projectID string) error { +func (p *Client) EnableProjectBGP(ctx context.Context, projectID string) error { // first check if it is enabled before trying to create it - bgpConfig, _, err := p.BGPConfig.Get(projectID, &packngo.GetOptions{}) + bgpConfig, _, err := p.BGPApi.FindBgpConfigByProject(ctx, projectID).Execute() //nolint:bodyclose // see https://github.com/timakin/bodyclose/issues/42 // if we already have a config, just return // we need some extra handling logic because the API always returns 200, even if // not BGP config is in place. @@ -264,7 +287,7 @@ func (p *Client) EnableProjectBGP(projectID string) error { // - bgpConfig struct does not have Status=="disabled" if err != nil { return err - } else if bgpConfig != nil && bgpConfig.ID != "" && strings.ToLower(bgpConfig.Status) != "disabled" { + } else if bgpConfig != nil && bgpConfig.GetId() != "" && strings.ToLower(bgpConfig.GetStatus()) != "disabled" { return nil } @@ -289,23 +312,25 @@ func (p *Client) EnableProjectBGP(projectID string) error { } // we did not have a valid one, so create it - req := packngo.CreateBGPConfigRequest{ - Asn: outLocalASN, - Md5: outBGPPass, + useCase := "kubernetes-load-balancer" + apiRequest := p.BGPApi.RequestBgpConfig(ctx, projectID) + _, err = apiRequest.BgpConfigRequestInput(metal.BgpConfigRequestInput{ + Asn: int32(outLocalASN), + Md5: &outBGPPass, DeploymentType: "local", - UseCase: "kubernetes-load-balancer", - } - _, err = p.BGPConfig.Create(projectID, req) + UseCase: &useCase, + }).Execute() //nolint:bodyclose // see https://github.com/timakin/bodyclose/issues/42 return err } // ensureNodeBGPEnabled check if the node has bgp enabled, and set it if it does not -func (p *Client) EnsureNodeBGPEnabled(id string) error { +func (p *Client) EnsureNodeBGPEnabled(ctx context.Context, id string) error { // fortunately, this is idempotent, so just create - req := packngo.CreateBGPSessionRequest{ - AddressFamily: "ipv4", + addressFamily := "ipv4" + req := metal.BGPSessionInput{ + AddressFamily: &addressFamily, } - _, response, err := p.BGPSessions.Create(id, req) + _, response, err := p.DevicesApi.CreateBgpSession(ctx, id).BGPSessionInput(req).Execute() //nolint:bodyclose // see https://github.com/timakin/bodyclose/issues/42 // if we already had one, then we can ignore the error // this really should be a 409, but 422 is what is returned if response != nil && response.StatusCode == 422 && strings.Contains(fmt.Sprintf("%s", err), "already has session") { @@ -314,23 +339,26 @@ func (p *Client) EnsureNodeBGPEnabled(id string) error { return err } -func (p *Client) GetIPByClusterIdentifier(namespace, name, projectID string) (packngo.IPAddressReservation, error) { +func (p *Client) GetIPByClusterIdentifier(ctx context.Context, namespace, name, projectID string) (*metal.IPReservation, error) { var err error - var reservedIP packngo.IPAddressReservation + var ipReservation *metal.IPReservation - listOpts := &packngo.ListOptions{} - reservedIPs, _, err := p.ProjectIPs.List(projectID, listOpts) + eipIdentifier := generateElasticIPIdentifier(name) + reservedIPs, _, err := p.IPAddressesApi.FindIPReservations(ctx, projectID).Execute() //nolint:bodyclose // see https://github.com/timakin/bodyclose/issues/42 if err != nil { - return reservedIP, err + return ipReservation, err } - for _, reservedIP := range reservedIPs { - for _, v := range reservedIP.Tags { - if v == generateElasticIPIdentifier(name) { - return reservedIP, nil + for _, reservedIPWrapper := range reservedIPs.IpAddresses { + ipReservation = reservedIPWrapper.IPReservation + if ipReservation != nil { + for _, tag := range ipReservation.Tags { + if tag == eipIdentifier { + return ipReservation, nil + } } } } - return reservedIP, ErrControlPlanEndpointNotFound + return ipReservation, ErrControlPlanEndpointNotFound } func generateElasticIPIdentifier(name string) string { diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go index 14d6f66e6..269da0b36 100644 --- a/test/e2e/common_test.go +++ b/test/e2e/common_test.go @@ -29,9 +29,9 @@ import ( "github.com/blang/semver" "github.com/docker/distribution/reference" + metal "github.com/equinix-labs/metal-go/metal/v1" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "github.com/packethost/packngo" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime" @@ -216,26 +216,28 @@ func (w *wrappedClusterProxy) Dispose(ctx context.Context) { logf("Will clean up EIPs for the following clusters: %v", clusterNames) for _, clusterName := range clusterNames { - var ip packngo.IPAddressReservation + var ip *metal.IPReservation g.Eventually(func(g Gomega) { var err error - ip, err = metalClient.GetIPByClusterIdentifier("", clusterName, metalProjectID) + ip, err = metalClient.GetIPByClusterIdentifier(ctx, "", clusterName, metalProjectID) g.Expect(err).To(SatisfyAny(Not(HaveOccurred()), MatchError(packet.ErrControlPlanEndpointNotFound))) }, "5m", "10s").Should(Succeed()) - if ip.ID != "" { - if len(ip.Assignments) == 0 { - logf("Deleting EIP with ID: %s, for cluster: %s", ip.ID, clusterName) + ipID := ip.GetId() + + if ipID != "" { + if len(ip.GetAssignments()) == 0 { + logf("Deleting EIP with ID: %s, for cluster: %s", ipID, clusterName) g.Eventually(func(g Gomega) { - _, err := metalClient.ProjectIPs.Remove(ip.ID) + _, err := metalClient.IPAddressesApi.DeleteIPAddress(ctx, ipID).Execute() Expect(err).NotTo(HaveOccurred()) }, "5m", "10s").Should(Succeed()) w.clusterNames.Delete(clusterName) } else { - logf("EIP for cluster: %s with ID: %s appears to still be assigned", clusterName, ip.ID) + logf("EIP for cluster: %s with ID: %s appears to still be assigned", clusterName, ipID) } } else { logf("Failed to find EIP for cluster: %s", clusterName) diff --git a/test/e2e/go.mod b/test/e2e/go.mod index 23411e1cb..0af8e3d0a 100644 --- a/test/e2e/go.mod +++ b/test/e2e/go.mod @@ -10,9 +10,9 @@ replace ( require ( github.com/blang/semver v3.5.1+incompatible github.com/docker/distribution v2.8.2+incompatible + github.com/equinix-labs/metal-go v0.7.1 github.com/onsi/ginkgo/v2 v2.6.0 github.com/onsi/gomega v1.24.1 - github.com/packethost/packngo v0.29.0 golang.org/x/crypto v0.3.0 k8s.io/api v0.25.10 k8s.io/apimachinery v0.25.10 diff --git a/test/e2e/go.sum b/test/e2e/go.sum index 5b8885fab..6edfbe3ea 100644 --- a/test/e2e/go.sum +++ b/test/e2e/go.sum @@ -113,8 +113,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY= -github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v20.10.24+incompatible h1:Ugvxm7a8+Gz6vqQYQQ2W7GYq5EUPaAiuPgIfVyI3dYE= @@ -136,6 +134,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/equinix-labs/metal-go v0.7.1 h1:dcLkBhPlTn2v4VJJBDZorYLo3QUs10FxQnwKJ8IczHk= +github.com/equinix-labs/metal-go v0.7.1/go.mod h1:qVHxbntL4uTflH4+OhtM7MNawG8j3swquGh3LLLPdfw= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -383,8 +383,6 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/packethost/packngo v0.29.0 h1:gRIhciVZQ/zLNrIdIdbOUyB/Tw5IgoaXyhP4bvE+D2s= -github.com/packethost/packngo v0.29.0/go.mod h1:/UHguFdPs6Lf6FOkkSEPnRY5tgS0fsVM+Zv/bvBrmt0= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= @@ -484,8 +482,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= @@ -522,7 +520,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= diff --git a/test/e2e/suite_test.go b/test/e2e/suite_test.go index cd080fb45..b15bc7970 100644 --- a/test/e2e/suite_test.go +++ b/test/e2e/suite_test.go @@ -30,9 +30,9 @@ import ( "strings" "testing" + metal "github.com/equinix-labs/metal-go/metal/v1" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "github.com/packethost/packngo" "golang.org/x/crypto/ssh" "k8s.io/apimachinery/pkg/runtime" capi_e2e "sigs.k8s.io/cluster-api/test/e2e" @@ -182,7 +182,7 @@ var _ = SynchronizedAfterSuite(func() { if metalAuthToken != "" && sshKeyID != "" { By("Cleaning up the generated SSH Key") metalClient := packet.NewClient(metalAuthToken) - _, err := metalClient.SSHKeys.Delete(sshKeyID) + _, err := metalClient.SSHKeysApi.DeleteSSHKey(nil, sshKeyID).Execute() Expect(err).NotTo(HaveOccurred()) } } @@ -290,15 +290,17 @@ func generateSSHKey() (string, string) { Expect(err).NotTo(HaveOccurred()) metalClient := packet.NewClient(metalAuthToken) - res, _, err := metalClient.SSHKeys.Create( - &packngo.SSHKeyCreateRequest{ - Label: fmt.Sprintf("capp-e2e-%s", util.RandomString(6)), - Key: string(ssh.MarshalAuthorizedKey(pub)), + label := fmt.Sprintf("capp-e2e-%s", util.RandomString(6)) + key := string(ssh.MarshalAuthorizedKey(pub)) + res, _, err := metalClient.SSHKeysApi.CreateSSHKey(nil).SSHKeyCreateInput( + metal.SSHKeyCreateInput{ + Label: &label, + Key: &key, }, - ) + ).Execute() Expect(err).NotTo(HaveOccurred()) - Expect(res.ID).NotTo(BeEmpty()) - Expect(res.Label).NotTo(BeEmpty()) + Expect(res.GetId()).NotTo(BeEmpty()) + Expect(res.GetLabel()).NotTo(BeEmpty()) - return res.ID, res.Label + return res.GetId(), res.GetLabel() } diff --git a/version/version.go b/version/version.go index 952f6d2a5..7471b8b90 100644 --- a/version/version.go +++ b/version/version.go @@ -19,8 +19,9 @@ package version import ( "fmt" "runtime" + "strings" - "github.com/packethost/packngo" + metal "github.com/equinix-labs/metal-go/metal/v1" ) var ( @@ -58,7 +59,7 @@ func Get() Info { GoVersion: runtime.Version(), Compiler: runtime.Compiler, Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), - MetalSdkVersion: packngo.Version, + MetalSdkVersion: getMetalVersion(), } } @@ -66,3 +67,9 @@ func Get() Info { func (info Info) String() string { return info.GitVersion } + +func getMetalVersion() string { + metalUserAgent := metal.NewConfiguration().UserAgent + metalVersion := metalUserAgent[strings.Index(metalUserAgent, "/")+1:] + return metalVersion +}