diff --git a/go.mod b/go.mod index 40b1f0571..6ff167332 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.25 require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc - github.com/digitalocean/godo v1.165.1 + github.com/digitalocean/godo v1.169.0 github.com/go-logr/logr v1.4.3 github.com/google/go-cmp v0.7.0 github.com/google/uuid v1.6.0 diff --git a/go.sum b/go.sum index 4a04bb1ba..a1aeeed6b 100644 --- a/go.sum +++ b/go.sum @@ -25,8 +25,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/digitalocean/godo v1.165.1 h1:H37+W7TaGFOVH+HpMW4ZeW/hrq3AGNxg+B/K8/dZ9mQ= -github.com/digitalocean/godo v1.165.1/go.mod h1:xQsWpVCCbkDrWisHA72hPzPlnC+4W5w/McZY5ij9uvU= +github.com/digitalocean/godo v1.169.0 h1:Wp9UrtIAgpFEEuY4ifWwq8JHJh7mFKPBXnkRv2Wf0Bw= +github.com/digitalocean/godo v1.169.0/go.mod h1:xQsWpVCCbkDrWisHA72hPzPlnC+4W5w/McZY5ij9uvU= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes= diff --git a/vendor/github.com/digitalocean/godo/CHANGELOG.md b/vendor/github.com/digitalocean/godo/CHANGELOG.md index 46800438d..3c780755f 100644 --- a/vendor/github.com/digitalocean/godo/CHANGELOG.md +++ b/vendor/github.com/digitalocean/godo/CHANGELOG.md @@ -1,5 +1,25 @@ # Change Log +## [1.169.0] - 2025-11-13 + +- #928 - @do-joe - Fix GetLogsink API Response Parsing to Match Actual API Behavior + +## [1.168.0] - 2025-11-06 + +- #926 - @niket-dujari - added provision for attach and detach share +- #927 - @m3co-code - CON-12804 - add GPU related DOKS cluster plugin options +- #924 - @llDrLove - CON-12995 Add GPU node pool resources to node pool template response + +## [1.167.0] - 2025-10-18 + +- #921 - @sreeram-venkitesh - MNFS-164: Added NFS resize and snapshot APIs + +## [1.166.0] - 2025-10-13 + +- #912 - @sreeram-venkitesh - MNFS-164: Added NFS APIs +- #913 - @fyzanshaik - Add ListAssociatedResourcesForDeletion for Droplets +- #909 - @jvasilevsky - LBAAS-3995: add project ID to nat gateway + ## [1.165.1] - 2025-09-24 - #906 - @do-joe - Fix Database Logsink API Response Parsing and TLS Field Marshaling diff --git a/vendor/github.com/digitalocean/godo/databases.go b/vendor/github.com/digitalocean/godo/databases.go index b535dc482..0fe799572 100644 --- a/vendor/github.com/digitalocean/godo/databases.go +++ b/vendor/github.com/digitalocean/godo/databases.go @@ -2107,12 +2107,12 @@ func (svc *DatabasesServiceOp) GetLogsink(ctx context.Context, databaseID string return nil, nil, err } - root := new(databaseLogsinkRoot) + root := new(DatabaseLogsink) resp, err := svc.client.Do(ctx, req, root) if err != nil { return nil, resp, err } - return root.Sink, resp, nil + return root, resp, nil } // ListTopics returns all topics for a given kafka cluster diff --git a/vendor/github.com/digitalocean/godo/droplets.go b/vendor/github.com/digitalocean/godo/droplets.go index 2ddd7d6b7..61a3fb6e5 100644 --- a/vendor/github.com/digitalocean/godo/droplets.go +++ b/vendor/github.com/digitalocean/godo/droplets.go @@ -33,6 +33,7 @@ type DropletsService interface { GetBackupPolicy(context.Context, int) (*DropletBackupPolicy, *Response, error) ListBackupPolicies(context.Context, *ListOptions) (map[int]*DropletBackupPolicy, *Response, error) ListSupportedBackupPolicies(context.Context) ([]*SupportedBackupPolicy, *Response, error) + ListAssociatedResourcesForDeletion(context.Context, int) (*DropletAssociatedResources, *Response, error) } // DropletsServiceOp handles communication with the Droplet related methods of the @@ -263,6 +264,26 @@ type DropletBackupPolicyRequest struct { Hour *int `json:"hour,omitempty"` } +// DropletAssociatedResource represents a billable resource associated with a Droplet. +type DropletAssociatedResource struct { + ID string `json:"id"` + Name string `json:"name"` + Cost string `json:"cost"` +} + +// DropletAssociatedResources represents the associated billable resources that can be destroyed along with a Droplet. +type DropletAssociatedResources struct { + ReservedIPs []*DropletAssociatedResource `json:"reserved_ips"` + FloatingIPs []*DropletAssociatedResource `json:"floating_ips"` + Snapshots []*DropletAssociatedResource `json:"snapshots"` + Volumes []*DropletAssociatedResource `json:"volumes"` + VolumeSnapshots []*DropletAssociatedResource `json:"volume_snapshots"` +} + +func (a DropletAssociatedResources) String() string { + return Stringify(a) +} + func (d DropletCreateRequest) String() string { return Stringify(d) } @@ -621,6 +642,27 @@ func (s *DropletsServiceOp) Neighbors(ctx context.Context, dropletID int) ([]Dro return root.Droplets, resp, err } +// ListAssociatedResourcesForDeletion lists a Droplet's associated resources that can be destroyed along with the Droplet. +// Associated resources include reserved IPs, floating IPs, snapshots, volumes, and volume snapshots. +func (s *DropletsServiceOp) ListAssociatedResourcesForDeletion(ctx context.Context, dropletID int) (*DropletAssociatedResources, *Response, error) { + if dropletID < 1 { + return nil, nil, NewArgError("dropletID", "cannot be less than 1") + } + path := fmt.Sprintf("%s/%d/destroy_with_associated_resources", dropletBasePath, dropletID) + req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil) + if err != nil { + return nil, nil, err + } + + root := new(DropletAssociatedResources) + resp, err := s.client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + return root, resp, nil +} + func (s *DropletsServiceOp) dropletActionStatus(ctx context.Context, uri string) (string, error) { action, _, err := s.client.DropletActions.GetByURI(ctx, uri) diff --git a/vendor/github.com/digitalocean/godo/godo.go b/vendor/github.com/digitalocean/godo/godo.go index a72cfc075..eeddb24f5 100644 --- a/vendor/github.com/digitalocean/godo/godo.go +++ b/vendor/github.com/digitalocean/godo/godo.go @@ -21,7 +21,7 @@ import ( ) const ( - libraryVersion = "1.165.1" + libraryVersion = "1.169.0" defaultBaseURL = "https://api.digitalocean.com/" userAgent = "godo/" + libraryVersion mediaType = "application/json" @@ -78,6 +78,8 @@ type Client struct { Kubernetes KubernetesService LoadBalancers LoadBalancersService Monitoring MonitoringService + Nfs NfsService + NfsActions NfsActionsService OneClick OneClickService Projects ProjectsService Regions RegionsService @@ -304,6 +306,8 @@ func NewClient(httpClient *http.Client) *Client { c.Kubernetes = &KubernetesServiceOp{client: c} c.LoadBalancers = &LoadBalancersServiceOp{client: c} c.Monitoring = &MonitoringServiceOp{client: c} + c.Nfs = &NfsServiceOp{client: c} + c.NfsActions = &NfsActionsServiceOp{client: c} c.VPCNATGateways = &VPCNATGatewaysServiceOp{client: c} c.OneClick = &OneClickServiceOp{client: c} c.Projects = &ProjectsServiceOp{client: c} diff --git a/vendor/github.com/digitalocean/godo/kubernetes.go b/vendor/github.com/digitalocean/godo/kubernetes.go index 82c6038f4..f68291d58 100644 --- a/vendor/github.com/digitalocean/godo/kubernetes.go +++ b/vendor/github.com/digitalocean/godo/kubernetes.go @@ -89,6 +89,8 @@ type KubernetesClusterCreateRequest struct { RoutingAgent *KubernetesRoutingAgent `json:"routing_agent,omitempty"` AmdGpuDevicePlugin *KubernetesAmdGpuDevicePlugin `json:"amd_gpu_device_plugin,omitempty"` AmdGpuDeviceMetricsExporterPlugin *KubernetesAmdGpuDeviceMetricsExporterPlugin `json:"amd_gpu_device_metrics_exporter_plugin,omitempty"` + NvidiaGpuDevicePlugin *KubernetesNvidiaGpuDevicePlugin `json:"nvidia_gpu_device_plugin,omitempty"` + RdmaSharedDevicePlugin *KubernetesRdmaSharedDevicePlugin `json:"rdma_shared_dev_plugin,omitempty"` } // KubernetesClusterUpdateRequest represents a request to update a Kubernetes cluster. @@ -103,6 +105,8 @@ type KubernetesClusterUpdateRequest struct { RoutingAgent *KubernetesRoutingAgent `json:"routing_agent,omitempty"` AmdGpuDevicePlugin *KubernetesAmdGpuDevicePlugin `json:"amd_gpu_device_plugin,omitempty"` AmdGpuDeviceMetricsExporterPlugin *KubernetesAmdGpuDeviceMetricsExporterPlugin `json:"amd_gpu_device_metrics_exporter_plugin,omitempty"` + NvidiaGpuDevicePlugin *KubernetesNvidiaGpuDevicePlugin `json:"nvidia_gpu_device_plugin,omitempty"` + RdmaSharedDevicePlugin *KubernetesRdmaSharedDevicePlugin `json:"rdma_shared_dev_plugin,omitempty"` // Convert cluster to run highly available control plane HA *bool `json:"ha,omitempty"` @@ -238,6 +242,8 @@ type KubernetesCluster struct { RoutingAgent *KubernetesRoutingAgent `json:"routing_agent,omitempty"` AmdGpuDevicePlugin *KubernetesAmdGpuDevicePlugin `json:"amd_gpu_device_plugin,omitempty"` AmdGpuDeviceMetricsExporterPlugin *KubernetesAmdGpuDeviceMetricsExporterPlugin `json:"amd_gpu_device_metrics_exporter_plugin,omitempty"` + NvidiaGpuDevicePlugin *KubernetesNvidiaGpuDevicePlugin `json:"nvidia_gpu_device_plugin,omitempty"` + RdmaSharedDevicePlugin *KubernetesRdmaSharedDevicePlugin `json:"rdma_shared_dev_plugin,omitempty"` Status *KubernetesClusterStatus `json:"status,omitempty"` CreatedAt time.Time `json:"created_at,omitempty"` @@ -280,6 +286,13 @@ type KubernetesControlPlaneFirewall struct { AllowedAddresses []string `json:"allowed_addresses"` } +// KubernetesClusterAutoscalerConfiguration represents Kubernetes cluster autoscaler configuration. +type KubernetesClusterAutoscalerConfiguration struct { + ScaleDownUtilizationThreshold *float64 `json:"scale_down_utilization_threshold"` + ScaleDownUnneededTime *string `json:"scale_down_unneeded_time"` + Expanders []string `json:"expanders"` +} + // KubernetesRoutingAgent represents information about the routing-agent cluster plugin. type KubernetesRoutingAgent struct { Enabled *bool `json:"enabled"` @@ -296,11 +309,16 @@ type KubernetesAmdGpuDeviceMetricsExporterPlugin struct { Enabled *bool `json:"enabled"` } -// KubernetesClusterAutoscalerConfiguration represents Kubernetes cluster autoscaler configuration. -type KubernetesClusterAutoscalerConfiguration struct { - ScaleDownUtilizationThreshold *float64 `json:"scale_down_utilization_threshold"` - ScaleDownUnneededTime *string `json:"scale_down_unneeded_time"` - Expanders []string `json:"expanders"` +// KubernetesNvidiaGpuDevicePlugin represents information about the NVIDIA GPU Device Plugin cluster plugin. +// If a cluster has a node pool with an NVIDIA GPU it will be enabled by default. +type KubernetesNvidiaGpuDevicePlugin struct { + Enabled *bool `json:"enabled"` +} + +// KubernetesRdmaSharedDevicePlugin represents information about the rdma-shared-dev cluster plugin. +// If a cluster has a multi-node GPU ready slug it will be enabled by default. +type KubernetesRdmaSharedDevicePlugin struct { + Enabled *bool `json:"enabled"` } // KubernetesMaintenancePolicyDay represents the possible days of a maintenance @@ -482,6 +500,12 @@ type KubernetesNodePoolResources struct { Pods int64 `json:"pods,omitempty"` } +// KubernetesNodePoolGPUResources exposes model and GPU count of a node pool template +type KubernetesNodePoolGPUResources struct { + Model string `json:"model"` + Count int64 `json:"count"` +} + // KubernetesNode represents a Node in a node pool in a Kubernetes cluster. type KubernetesNode struct { ID string `json:"id,omitempty"` @@ -495,13 +519,14 @@ type KubernetesNode struct { // KubernetesNodeTemplate represents a template in a node pool in a Kubernetes cluster. type KubernetesNodeTemplate struct { - ClusterUUID string `json:"cluster_uuid,omitempty"` - Name string `json:"name,omitempty"` - Slug string `json:"slug,omitempty"` - Labels map[string]string `json:"labels,omitempty"` - Taints []string `json:"taints,omitempty"` - Capacity *KubernetesNodePoolResources `json:"capacity,omitempty"` - Allocatable *KubernetesNodePoolResources `json:"allocatable,omitempty"` + ClusterUUID string `json:"cluster_uuid,omitempty"` + Name string `json:"name,omitempty"` + Slug string `json:"slug,omitempty"` + Labels map[string]string `json:"labels,omitempty"` + Taints []string `json:"taints,omitempty"` + Capacity *KubernetesNodePoolResources `json:"capacity,omitempty"` + Allocatable *KubernetesNodePoolResources `json:"allocatable,omitempty"` + Gpu *KubernetesNodePoolGPUResources `json:"gpu,omitempty"` } // KubernetesNodeStatus represents the status of a particular Node in a Kubernetes cluster. diff --git a/vendor/github.com/digitalocean/godo/nfs.go b/vendor/github.com/digitalocean/godo/nfs.go new file mode 100644 index 000000000..35df62b97 --- /dev/null +++ b/vendor/github.com/digitalocean/godo/nfs.go @@ -0,0 +1,356 @@ +package godo + +import ( + "context" + "fmt" + "net/http" +) + +const nfsBasePath = "v2/nfs" + +const nfsSnapshotsBasePath = "v2/nfs/snapshots" + +// NfsShareStatus represents the status of an NFS share. +type NfsShareStatus string + +// Possible states for an NFS share. +const ( + NfsShareCreating = NfsShareStatus("CREATING") + NfsShareActive = NfsShareStatus("ACTIVE") + NfsShareFailed = NfsShareStatus("FAILED") + NfsShareDeleted = NfsShareStatus("DELETED") +) + +// NfsSnapshotStatus represents the status of an NFS snapshot. +type NfsSnapshotStatus string + +// Possible states for an NFS snapshot. +const ( + NfsSnapshotUnknown = NfsSnapshotStatus("UNKNOWN") + NfsSnapshotCreating = NfsSnapshotStatus("CREATING") + NfsSnapshotActive = NfsSnapshotStatus("ACTIVE") + NfsSnapshotFailed = NfsSnapshotStatus("FAILED") + NfsSnapshotDeleted = NfsSnapshotStatus("DELETED") +) + +type NfsService interface { + // List retrieves a list of NFS shares filtered by region + List(ctx context.Context, opts *ListOptions, region string) ([]*Nfs, *Response, error) + // Create creates a new NFS share with the provided configuration + Create(ctx context.Context, nfsCreateRequest *NfsCreateRequest) (*Nfs, *Response, error) + // Delete removes an NFS share by its ID and region + Delete(ctx context.Context, nfsShareId string, region string) (*Response, error) + // Get retrieves a specific NFS share by its ID and region + Get(ctx context.Context, nfsShareId string, region string) (*Nfs, *Response, error) + // List retrieves a list of NFS snapshots filtered by an optional share ID and region + ListSnapshots(ctx context.Context, opts *ListOptions, nfsShareId string, region string) ([]*NfsSnapshot, *Response, error) + // Get retrieves a specific NFS snapshot by its ID and region + GetSnapshot(ctx context.Context, nfsSnapshotID string, region string) (*NfsSnapshot, *Response, error) + // Delete removes an NFS snapshot by its ID and region + DeleteSnapshot(ctx context.Context, nfsSnapshotID string, region string) (*Response, error) +} + +// NfsServiceOp handles communication with the NFS related methods of the +// DigitalOcean API. +type NfsServiceOp struct { + client *Client +} + +var _ NfsService = &NfsServiceOp{} + +// Nfs represents a DigitalOcean NFS share +type Nfs struct { + // ID is the unique identifier for the NFS share + ID string `json:"id"` + // Name is the human-readable name for the NFS share + Name string `json:"name"` + // SizeGib is the size of the NFS share in gibibytes + SizeGib int `json:"size_gib"` + // Region is the datacenter region where the NFS share is located + Region string `json:"region"` + // Status represents the current state of the NFS share + Status NfsShareStatus `json:"status"` + // CreatedAt is the timestamp when the NFS share was created + CreatedAt string `json:"created_at"` + // VpcIDs is a list of VPC IDs that have access to the NFS share + VpcIDs []string `json:"vpc_ids"` +} + +type NfsSnapshot struct { + // ID is the unique identifier for the NFS snapshot + ID string `json:"id"` + // Name is the human-readable name for the NFS snapshot + Name string `json:"name"` + // SizeGib is the size of the NFS snapshot in gibibytes + SizeGib int `json:"size_gib"` + // Region is the datacenter region where the NFS snapshot is located + Region string `json:"region"` + // Status represents the current status of the NFS snapshot + Status NfsSnapshotStatus `json:"status"` + // CreatedAt is the timestamp when the NFS snapshot was created + CreatedAt string `json:"created_at"` + // ShareID is the unique identifier of the share from which this snapshot was created. + ShareID string `json:"share_id"` +} + +// NfsCreateRequest represents a request to create an NFS share. +type NfsCreateRequest struct { + Name string `json:"name"` + SizeGib int `json:"size_gib"` + Region string `json:"region"` + VpcIDs []string `json:"vpc_ids,omitempty"` +} + +// nfsRoot represents a response from the DigitalOcean API +type nfsRoot struct { + Share *Nfs `json:"share"` +} + +// nfsListRoot represents a response from the DigitalOcean API +type nfsListRoot struct { + Shares []*Nfs `json:"shares,omitempty"` + Links *Links `json:"links,omitempty"` + Meta *Meta `json:"meta"` +} + +// nfsSnapshotRoot represents a response from the DigitalOcean API +type nfsSnapshotRoot struct { + Snapshot *NfsSnapshot `json:"snapshot"` +} + +// nfsSnapshotListRoot represents a response from the DigitalOcean API +type nfsSnapshotListRoot struct { + Snapshots []*NfsSnapshot `json:"snapshots,omitempty"` + Links *Links `json:"links,omitempty"` + Meta *Meta `json:"meta"` +} + +// nfsOptions represents the query param options for NFS operations +type nfsOptions struct { + // Region is the datacenter region where the NFS share/shapshot is located + Region string `url:"region"` + // ShareID is the unique identifier of the share from which this snapshot was created. + ShareID string `url:"share_id,omitempty"` +} + +// Create creates a new NFS share. +func (s *NfsServiceOp) Create(ctx context.Context, createRequest *NfsCreateRequest) (*Nfs, *Response, error) { + if createRequest == nil { + return nil, nil, NewArgError("createRequest", "cannot be nil") + } + + if createRequest.SizeGib < 50 { + return nil, nil, NewArgError("size_gib", "it cannot be less than 50Gib") + } + + req, err := s.client.NewRequest(ctx, http.MethodPost, nfsBasePath, createRequest) + if err != nil { + return nil, nil, err + } + + root := new(nfsRoot) + resp, err := s.client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + return root.Share, resp, nil +} + +// Get retrieves an NFS share by ID and region. +func (s *NfsServiceOp) Get(ctx context.Context, nfsShareId string, region string) (*Nfs, *Response, error) { + if nfsShareId == "" { + return nil, nil, NewArgError("id", "cannot be empty") + } + if region == "" { + return nil, nil, NewArgError("region", "cannot be empty") + } + + path := fmt.Sprintf("%s/%s", nfsBasePath, nfsShareId) + + getOpts := &nfsOptions{Region: region} + path, err := addOptions(path, getOpts) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil) + if err != nil { + return nil, nil, err + } + + root := new(nfsRoot) + resp, err := s.client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + return root.Share, resp, nil +} + +// List returns a list of NFS shares. +func (s *NfsServiceOp) List(ctx context.Context, opts *ListOptions, region string) ([]*Nfs, *Response, error) { + if region == "" { + return nil, nil, NewArgError("region", "cannot be empty") + } + + path, err := addOptions(nfsBasePath, opts) + if err != nil { + return nil, nil, err + } + + listOpts := &nfsOptions{Region: region} + path, err = addOptions(path, listOpts) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil) + if err != nil { + return nil, nil, err + } + + root := new(nfsListRoot) + resp, err := s.client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + if root.Links != nil { + resp.Links = root.Links + } + if root.Meta != nil { + resp.Meta = root.Meta + } + + return root.Shares, resp, nil +} + +// Delete deletes an NFS share by ID and region. +func (s *NfsServiceOp) Delete(ctx context.Context, nfsShareId string, region string) (*Response, error) { + if nfsShareId == "" { + return nil, NewArgError("id", "cannot be empty") + } + if region == "" { + return nil, NewArgError("region", "cannot be empty") + } + + path := fmt.Sprintf("%s/%s", nfsBasePath, nfsShareId) + + deleteOpts := &nfsOptions{Region: region} + path, err := addOptions(path, deleteOpts) + if err != nil { + return nil, err + } + + req, err := s.client.NewRequest(ctx, http.MethodDelete, path, nil) + if err != nil { + return nil, err + } + + resp, err := s.client.Do(ctx, req, nil) + if err != nil { + return resp, err + } + + return resp, nil +} + +// Get retrieves an NFS snapshot by ID and region. +func (s *NfsServiceOp) GetSnapshot(ctx context.Context, nfsSnapshotID string, region string) (*NfsSnapshot, *Response, error) { + if nfsSnapshotID == "" { + return nil, nil, NewArgError("snapshotID", "cannot be empty") + } + if region == "" { + return nil, nil, NewArgError("region", "cannot be empty") + } + + path := fmt.Sprintf("%s/%s", nfsSnapshotsBasePath, nfsSnapshotID) + + getOpts := &nfsOptions{Region: region} + path, err := addOptions(path, getOpts) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil) + if err != nil { + return nil, nil, err + } + + root := new(nfsSnapshotRoot) + resp, err := s.client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + return root.Snapshot, resp, nil +} + +// List returns a list of NFS snapshots. +func (s *NfsServiceOp) ListSnapshots(ctx context.Context, opts *ListOptions, nfsShareId, region string) ([]*NfsSnapshot, *Response, error) { + if region == "" { + return nil, nil, NewArgError("region", "cannot be empty") + } + + path, err := addOptions(nfsSnapshotsBasePath, opts) + if err != nil { + return nil, nil, err + } + + listOpts := &nfsOptions{Region: region, ShareID: nfsShareId} + path, err = addOptions(path, listOpts) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil) + if err != nil { + return nil, nil, err + } + + root := new(nfsSnapshotListRoot) + resp, err := s.client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + if root.Links != nil { + resp.Links = root.Links + } + if root.Meta != nil { + resp.Meta = root.Meta + } + + return root.Snapshots, resp, nil +} + +// Delete deletes an NFS snapshot by ID and region. +func (s *NfsServiceOp) DeleteSnapshot(ctx context.Context, nfsSnapshotID string, region string) (*Response, error) { + if nfsSnapshotID == "" { + return nil, NewArgError("snapshotID", "cannot be empty") + } + if region == "" { + return nil, NewArgError("region", "cannot be empty") + } + + path := fmt.Sprintf("%s/%s", nfsSnapshotsBasePath, nfsSnapshotID) + + deleteOpts := &nfsOptions{Region: region} + path, err := addOptions(path, deleteOpts) + if err != nil { + return nil, err + } + + req, err := s.client.NewRequest(ctx, http.MethodDelete, path, nil) + if err != nil { + return nil, err + } + + resp, err := s.client.Do(ctx, req, nil) + if err != nil { + return resp, err + } + + return resp, nil +} diff --git a/vendor/github.com/digitalocean/godo/nfs_actions.go b/vendor/github.com/digitalocean/godo/nfs_actions.go new file mode 100644 index 000000000..7c68cca8e --- /dev/null +++ b/vendor/github.com/digitalocean/godo/nfs_actions.go @@ -0,0 +1,147 @@ +package godo + +import ( + "context" + "fmt" + "net/http" +) + +// NfsActionsService is an interface for interacting with the NFS actions +// endpoints of the DigitalOcean API +// See: https://docs.digitalocean.com/reference/api/api-reference/#tag/NFS-Actions +type NfsActionsService interface { + Resize(ctx context.Context, nfsShareId string, size uint64, region string) (*NfsAction, *Response, error) + Snapshot(ctx context.Context, nfsShareId string, nfsSnapshotName string, region string) (*NfsAction, *Response, error) + Attach(ctx context.Context, nfsShareId string, vpcID string, region string) (*NfsAction, *Response, error) + Detach(ctx context.Context, nfsShareId string, vpcID string, region string) (*NfsAction, *Response, error) +} + +// NfsActionsServiceOp handles communication with the NFS action related +// methods of the DigitalOcean API. +type NfsActionsServiceOp struct { + client *Client +} + +var _ NfsActionsService = &NfsActionsServiceOp{} + +// NfsAction represents an NFS action +type NfsAction struct { + ID int `json:"id"` + Status string `json:"status"` + Type string `json:"type"` + StartedAt *Timestamp `json:"started_at"` + CompletedAt *Timestamp `json:"completed_at"` + ResourceID string `json:"resource_id"` + ResourceType string `json:"resource_type"` + Region *Region `json:"region,omitempty"` + RegionSlug string `json:"region_slug,omitempty"` +} + +// nfsActionRoot represents the response wrapper for NFS actions +type nfsActionRoot struct { + Event *NfsAction `json:"action"` +} + +// NfsActionRequest represents a generic NFS action request +type NfsActionRequest struct { + Type string `json:"type"` + Region string `json:"region"` + Params interface{} `json:"params"` +} + +// NfsResizeParams represents parameters for resizing an NFS share +type NfsResizeParams struct { + SizeGib uint64 `json:"size_gib"` +} + +// NfsSnapshotParams represents parameters for creating an NFS snapshot +type NfsSnapshotParams struct { + Name string `json:"name"` +} + +// NfsAttachParams represents parameters for attaching an NFS share to a VPC +type NfsAttachParams struct { + VpcID string `json:"vpc_id"` +} + +// NfsDetachParams represents parameters for detaching an NFS share from a VPC +type NfsDetachParams struct { + VpcID string `json:"vpc_id"` +} + +// Resize an NFS share +func (s *NfsActionsServiceOp) Resize(ctx context.Context, nfsShareId string, size uint64, region string) (*NfsAction, *Response, error) { + request := &NfsActionRequest{ + Type: "resize", + Region: region, + Params: &NfsResizeParams{ + SizeGib: size, + }, + } + + return s.doAction(ctx, nfsShareId, request) +} + +// Snapshot an NFS share +func (s *NfsActionsServiceOp) Snapshot(ctx context.Context, nfsShareId, nfsSnapshotName, region string) (*NfsAction, *Response, error) { + request := &NfsActionRequest{ + Type: "snapshot", + Region: region, + Params: &NfsSnapshotParams{ + Name: nfsSnapshotName, + }, + } + + return s.doAction(ctx, nfsShareId, request) +} + +// Attach an NFS share +func (s *NfsActionsServiceOp) Attach(ctx context.Context, nfsShareId, vpcID, region string) (*NfsAction, *Response, error) { + request := &NfsActionRequest{ + Type: "attach", + Region: region, + Params: &NfsAttachParams{ + VpcID: vpcID, + }, + } + + return s.doAction(ctx, nfsShareId, request) +} + +// Detach an NFS share +func (s *NfsActionsServiceOp) Detach(ctx context.Context, nfsShareId, vpcID, region string) (*NfsAction, *Response, error) { + request := &NfsActionRequest{ + Type: "detach", + Region: region, + Params: &NfsAttachParams{ + VpcID: vpcID, + }, + } + + return s.doAction(ctx, nfsShareId, request) +} + +func (s *NfsActionsServiceOp) doAction(ctx context.Context, nfsShareId string, request *NfsActionRequest) (*NfsAction, *Response, error) { + if request == nil { + return nil, nil, NewArgError("request", "request can't be nil") + } + + path := nfsActionPath(nfsShareId) + + req, err := s.client.NewRequest(ctx, http.MethodPost, path, request) + if err != nil { + return nil, nil, err + } + + root := new(nfsActionRoot) + resp, err := s.client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + return root.Event, resp, err +} + +func nfsActionPath(nfsID string) string { + return fmt.Sprintf("v2/nfs/%v/actions", nfsID) +} diff --git a/vendor/github.com/digitalocean/godo/vpc_nat_gateways.go b/vendor/github.com/digitalocean/godo/vpc_nat_gateways.go index 55d75ce6e..8c454621b 100644 --- a/vendor/github.com/digitalocean/godo/vpc_nat_gateways.go +++ b/vendor/github.com/digitalocean/godo/vpc_nat_gateways.go @@ -30,6 +30,7 @@ type VPCNATGatewayRequest struct { UDPTimeoutSeconds uint32 `json:"udp_timeout_seconds,omitempty"` ICMPTimeoutSeconds uint32 `json:"icmp_timeout_seconds,omitempty"` TCPTimeoutSeconds uint32 `json:"tcp_timeout_seconds,omitempty"` + ProjectID string `json:"project_id,omitempty"` } // VPCNATGateway represents a DigitalOcean VPC NAT Gateway resource @@ -47,6 +48,7 @@ type VPCNATGateway struct { TCPTimeoutSeconds uint32 `json:"tcp_timeout_seconds,omitempty"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` + ProjectID string `json:"project_id,omitempty"` } // IngressVPC defines the ingress configs supported by a VPC NAT Gateway diff --git a/vendor/modules.txt b/vendor/modules.txt index 21ea44927..f1e620197 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -33,7 +33,7 @@ github.com/coreos/go-systemd/v22/journal # github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc ## explicit github.com/davecgh/go-spew/spew -# github.com/digitalocean/godo v1.165.1 +# github.com/digitalocean/godo v1.169.0 ## explicit; go 1.23.0 github.com/digitalocean/godo github.com/digitalocean/godo/metrics