diff --git a/digitalocean/droplet/datasource_droplet.go b/digitalocean/droplet/datasource_droplet.go index 3023b07ab..1391932c6 100644 --- a/digitalocean/droplet/datasource_droplet.go +++ b/digitalocean/droplet/datasource_droplet.go @@ -24,6 +24,12 @@ func DataSourceDigitalOceanDroplet() *schema.Resource { recordSchema["id"].Optional = true recordSchema["name"].ExactlyOneOf = []string{"id", "tag", "name"} recordSchema["name"].Optional = true + recordSchema["gpu"] = &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + ConflictsWith: []string{"tag"}, + } recordSchema["tag"] = &schema.Schema{ Type: schema.TypeString, @@ -64,7 +70,13 @@ func dataSourceDigitalOceanDropletRead(ctx context.Context, d *schema.ResourceDa foundDroplet = *droplet } else if v, ok := d.GetOk("name"); ok { - dropletList, err := getDigitalOceanDroplets(meta, nil) + gpus := d.Get("gpu").(bool) + extra := make(map[string]interface{}) + if gpus { + extra["gpus"] = true + } + + dropletList, err := getDigitalOceanDroplets(meta, extra) if err != nil { return diag.FromErr(err) } diff --git a/digitalocean/droplet/datasource_droplet_test.go b/digitalocean/droplet/datasource_droplet_test.go index 6c6779cb3..d929134cf 100644 --- a/digitalocean/droplet/datasource_droplet_test.go +++ b/digitalocean/droplet/datasource_droplet_test.go @@ -3,12 +3,14 @@ package droplet_test import ( "context" "fmt" + "os" "strconv" "testing" "github.com/digitalocean/godo" "github.com/digitalocean/terraform-provider-digitalocean/digitalocean/acceptance" "github.com/digitalocean/terraform-provider-digitalocean/digitalocean/config" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) @@ -52,6 +54,52 @@ data "digitalocean_droplet" "foobar" { }) } +func TestAccDataSourceDigitalOceanDroplet_GPUByName(t *testing.T) { + runGPU := os.Getenv(runGPUEnvVar) + if runGPU == "" { + t.Skip("'DO_RUN_GPU_TESTS' env var not set; Skipping tests that requires a GPU Droplet") + } + + keyName := acceptance.RandomTestName() + publicKeyMaterial, _, err := acctest.RandSSHKeyPair("digitalocean@ssh-acceptance-test") + if err != nil { + t.Fatalf("Cannot generate test SSH key pair: %s", err) + } + + var droplet godo.Droplet + name := acceptance.RandomTestName() + resourceConfig := testAccCheckDataSourceDigitalOceanDropletConfig_gpuByName(keyName, publicKeyMaterial, name) + dataSourceConfig := ` +data "digitalocean_droplet" "foobar" { + name = digitalocean_droplet.foo.name + gpu = true +}` + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.TestAccPreCheck(t) }, + ProviderFactories: acceptance.TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: resourceConfig, + }, + { + Config: resourceConfig + dataSourceConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckDataSourceDigitalOceanDropletExists("data.digitalocean_droplet.foobar", &droplet), + resource.TestCheckResourceAttr( + "data.digitalocean_droplet.foobar", "name", name), + resource.TestCheckResourceAttr( + "data.digitalocean_droplet.foobar", "image", gpuImage), + resource.TestCheckResourceAttr( + "data.digitalocean_droplet.foobar", "region", "tor1"), + resource.TestCheckResourceAttrSet("data.digitalocean_droplet.foobar", "urn"), + resource.TestCheckResourceAttrSet("data.digitalocean_droplet.foobar", "created_at"), + ), + }, + }, + }) +} + func TestAccDataSourceDigitalOceanDroplet_BasicById(t *testing.T) { var droplet godo.Droplet name := acceptance.RandomTestName() @@ -173,6 +221,22 @@ resource "digitalocean_droplet" "foo" { }`, acceptance.RandomTestName(), name, defaultSize, defaultImage) } +func testAccCheckDataSourceDigitalOceanDropletConfig_gpuByName(keyName, key, name string) string { + return fmt.Sprintf(` +resource "digitalocean_ssh_key" "foobar" { + name = "%s" + public_key = "%s" +} + +resource "digitalocean_droplet" "foo" { + name = "%s" + size = "%s" + image = "%s" + region = "tor1" + ssh_keys = [digitalocean_ssh_key.foobar.id] +}`, keyName, key, name, gpuSize, gpuImage) +} + func testAccCheckDataSourceDigitalOceanDropletConfig_basicById(name string) string { return fmt.Sprintf(` resource "digitalocean_droplet" "foo" { diff --git a/digitalocean/droplet/datasource_droplets.go b/digitalocean/droplet/datasource_droplets.go index 152e5448e..386b7d3e7 100644 --- a/digitalocean/droplet/datasource_droplets.go +++ b/digitalocean/droplet/datasource_droplets.go @@ -11,6 +11,13 @@ func DataSourceDigitalOceanDroplets() *schema.Resource { ResultAttributeName: "droplets", GetRecords: getDigitalOceanDroplets, FlattenRecord: flattenDigitalOceanDroplet, + ExtraQuerySchema: map[string]*schema.Schema{ + "gpus": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + }, } return datalist.NewResource(dataListConfig) diff --git a/digitalocean/droplet/datasource_droplets_test.go b/digitalocean/droplet/datasource_droplets_test.go index efba5f196..2041c4dfe 100644 --- a/digitalocean/droplet/datasource_droplets_test.go +++ b/digitalocean/droplet/datasource_droplets_test.go @@ -2,9 +2,11 @@ package droplet_test import ( "fmt" + "os" "testing" "github.com/digitalocean/terraform-provider-digitalocean/digitalocean/acceptance" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -57,3 +59,67 @@ data "digitalocean_droplets" "result" { }, }) } + +func TestAccDataSourceDigitalOceanDroplets_GPUDroplet(t *testing.T) { + runGPU := os.Getenv(runGPUEnvVar) + if runGPU == "" { + t.Skip("'DO_RUN_GPU_TESTS' env var not set; Skipping tests that requires a GPU Droplet") + } + + keyName := acceptance.RandomTestName() + publicKeyMaterial, _, err := acctest.RandSSHKeyPair("digitalocean@ssh-acceptance-test") + if err != nil { + t.Fatalf("Cannot generate test SSH key pair: %s", err) + } + + name1 := acceptance.RandomTestName("gpu") + name2 := acceptance.RandomTestName("regular") + + resourcesConfig := fmt.Sprintf(` +resource "digitalocean_ssh_key" "foobar" { + name = "%s" + public_key = "%s" +} + +resource "digitalocean_droplet" "gpu" { + name = "%s" + size = "%s" + image = "%s" + region = "nyc2" + ssh_keys = [digitalocean_ssh_key.foobar.id] +} + +resource "digitalocean_droplet" "regular" { + name = "%s" + size = "%s" + image = "%s" + region = "nyc2" +} +`, keyName, publicKeyMaterial, name1, gpuSize, gpuImage, name2, defaultSize, defaultImage) + + datasourceConfig := ` +data "digitalocean_droplets" "result" { + gpus = true +} +` + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.TestAccPreCheck(t) }, + ProviderFactories: acceptance.TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: resourcesConfig, + }, + { + Config: resourcesConfig + datasourceConfig, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.digitalocean_droplets.result", "droplets.#", "1"), + resource.TestCheckResourceAttr("data.digitalocean_droplets.result", "droplets.0.name", name1), + resource.TestCheckResourceAttrPair("data.digitalocean_droplets.result", "droplets.0.id", "digitalocean_droplet.gpu", "id"), + ), + }, + { + Config: resourcesConfig, + }, + }, + }) +} diff --git a/digitalocean/droplet/droplets.go b/digitalocean/droplet/droplets.go index cabe98616..b9252f221 100644 --- a/digitalocean/droplet/droplets.go +++ b/digitalocean/droplet/droplets.go @@ -118,6 +118,8 @@ func dropletSchema() map[string]*schema.Schema { func getDigitalOceanDroplets(meta interface{}, extra map[string]interface{}) ([]interface{}, error) { client := meta.(*config.CombinedConfig).GodoClient() + gpus, _ := extra["gpus"].(bool) + opts := &godo.ListOptions{ Page: 1, PerPage: 200, @@ -126,7 +128,16 @@ func getDigitalOceanDroplets(meta interface{}, extra map[string]interface{}) ([] var dropletList []interface{} for { - droplets, resp, err := client.Droplets.List(context.Background(), opts) + var ( + droplets []godo.Droplet + resp *godo.Response + err error + ) + if gpus { + droplets, resp, err = client.Droplets.ListWithGPUs(context.Background(), opts) + } else { + droplets, resp, err = client.Droplets.List(context.Background(), opts) + } if err != nil { return nil, fmt.Errorf("Error retrieving droplets: %s", err) diff --git a/digitalocean/droplet/resource_droplet_test.go b/digitalocean/droplet/resource_droplet_test.go index b55e3a355..17910531a 100644 --- a/digitalocean/droplet/resource_droplet_test.go +++ b/digitalocean/droplet/resource_droplet_test.go @@ -18,6 +18,10 @@ import ( const ( defaultSize = "s-1vcpu-1gb" defaultImage = "ubuntu-22-04-x64" + + gpuSize = "gpu-h100x1-80gb" + gpuImage = "gpu-h100x1-base" + runGPUEnvVar = "DO_RUN_GPU_TESTS" ) func TestAccDigitalOceanDroplet_Basic(t *testing.T) { diff --git a/docs/data-sources/droplet.md b/docs/data-sources/droplet.md index 88fcffa06..5db784655 100644 --- a/docs/data-sources/droplet.md +++ b/docs/data-sources/droplet.md @@ -51,6 +51,10 @@ One of the following arguments must be provided: * `name` - (Optional) The name of the Droplet. * `tag` - (Optional) A tag applied to the Droplet. +To include GPU Droplets when searching by name, use: + +* `gpu` - (Optional) A boolean value specifying whether or not to search GPU Droplets + ## Attributes Reference The following attributes are exported: diff --git a/docs/data-sources/droplets.md b/docs/data-sources/droplets.md index 5e6bcff09..2d233ae54 100644 --- a/docs/data-sources/droplets.md +++ b/docs/data-sources/droplets.md @@ -11,6 +11,9 @@ If no filters are specified, all Droplets will be returned. This data source is useful if the Droplets in question are not managed by Terraform or you need to utilize any of the Droplets' data. +By default, only non-GPU Droplets are returned. To list only GPU Droplets, set +the `gpus` attribute to `true`. + Note: You can use the [`digitalocean_droplet`](droplet) data source to obtain metadata about a single Droplet if you already know the `id`, unique `name`, or unique `tag` to retrieve. @@ -50,6 +53,8 @@ data "digitalocean_droplets" "small-with-backups" { ## Argument Reference +* `gpus` - (Optional) A boolean value specifying whether or not to list GPU Droplets + * `filter` - (Optional) Filter the results. The `filter` block is documented below. diff --git a/go.mod b/go.mod index cef6e2feb..a45200125 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/digitalocean/terraform-provider-digitalocean require ( github.com/aws/aws-sdk-go v1.42.18 - github.com/digitalocean/godo v1.126.1-0.20241004175533-dfe74ef3d8bb + github.com/digitalocean/godo v1.128.1-0.20241025145008-2654a9d1e887 github.com/hashicorp/awspolicyequivalence v1.5.0 github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 github.com/hashicorp/go-uuid v1.0.3 diff --git a/go.sum b/go.sum index 07b7e1430..ce527179e 100644 --- a/go.sum +++ b/go.sum @@ -25,8 +25,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/digitalocean/godo v1.126.1-0.20241004175533-dfe74ef3d8bb h1:D6/pJ6+5wMkpwaF2HMJqvhlPlxWdlbpKx6bOpy8sbBg= -github.com/digitalocean/godo v1.126.1-0.20241004175533-dfe74ef3d8bb/go.mod h1:PU8JB6I1XYkQIdHFop8lLAY9ojp6M0XcU0TWaQSxbrc= +github.com/digitalocean/godo v1.128.1-0.20241025145008-2654a9d1e887 h1:kdXNbMfHEDbQilcqllKkNrJ85ftyJSvSDpsQvzrhHbg= +github.com/digitalocean/godo v1.128.1-0.20241025145008-2654a9d1e887/go.mod h1:PU8JB6I1XYkQIdHFop8lLAY9ojp6M0XcU0TWaQSxbrc= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= diff --git a/vendor/github.com/digitalocean/godo/CHANGELOG.md b/vendor/github.com/digitalocean/godo/CHANGELOG.md index 371272169..667255b2a 100644 --- a/vendor/github.com/digitalocean/godo/CHANGELOG.md +++ b/vendor/github.com/digitalocean/godo/CHANGELOG.md @@ -1,5 +1,20 @@ # Change Log +## [v1.128.0] - 2024-10-24 + +- #746 - @blesswinsamuel - Add archive field to AppSpec to archive/restore apps +- #745 - @asaha2 - Add load balancer monitoring endpoints +- #744 - @asaha2 - Adjust delete dangerous +- #743 - @asaha2 - Introduce droplet autoscale godo methods +- #740 - @blesswinsamuel - Add maintenance field to AppSpec to enable/disable maintenance mode +- #739 - @markusthoemmes - Add protocol to AppSpec and pending to detect responses + +## [v1.127.0] - 2024-10-18 + +- #737 - @loosla - [databases]: change Opensearch ism_history_max_docs type to int64 to … +- #735 - @loosla - [databases]: add a missing field to Opensearch advanced configuration +- #729 - @loosla - [databases]: add support for Opensearch advanced configuration + ## [v1.126.0] - 2024-09-25 - #732 - @gottwald - DOKS: add custom CIDR fields diff --git a/vendor/github.com/digitalocean/godo/apps.gen.go b/vendor/github.com/digitalocean/godo/apps.gen.go index 229705402..0232ae943 100644 --- a/vendor/github.com/digitalocean/godo/apps.gen.go +++ b/vendor/github.com/digitalocean/godo/apps.gen.go @@ -462,6 +462,15 @@ type AppLogDestinationSpecPapertrail struct { Endpoint string `json:"endpoint"` } +// AppMaintenanceSpec struct for AppMaintenanceSpec +type AppMaintenanceSpec struct { + // Indicates whether maintenance mode should be enabled for the app. + Enabled bool `json:"enabled,omitempty"` + // Indicates whether the app should be archived. Setting this to true implies that enabled is set to true. + // Note that this feature is currently in closed beta. + Archive bool `json:"archive,omitempty"` +} + // AppRouteSpec struct for AppRouteSpec type AppRouteSpec struct { // (Deprecated) An HTTP path prefix. Paths must start with / and must be unique across all components within an app. @@ -495,7 +504,8 @@ type AppServiceSpec struct { InstanceCount int64 `json:"instance_count,omitempty"` Autoscaling *AppAutoscalingSpec `json:"autoscaling,omitempty"` // The internal port on which this service's run command will listen. Default: 8080 If there is not an environment variable with the name `PORT`, one will be automatically added with its value set to the value of this field. - HTTPPort int64 `json:"http_port,omitempty"` + HTTPPort int64 `json:"http_port,omitempty"` + Protocol ServingProtocol `json:"protocol,omitempty"` // (Deprecated) A list of HTTP routes that should be routed to this component. Routes []*AppRouteSpec `json:"routes,omitempty"` HealthCheck *AppServiceSpecHealthCheck `json:"health_check,omitempty"` @@ -559,10 +569,11 @@ type AppSpec struct { // A list of environment variables made available to all components in the app. Envs []*AppVariableDefinition `json:"envs,omitempty"` // A list of alerts which apply to the app. - Alerts []*AppAlertSpec `json:"alerts,omitempty"` - Ingress *AppIngressSpec `json:"ingress,omitempty"` - Egress *AppEgressSpec `json:"egress,omitempty"` - Features []string `json:"features,omitempty"` + Alerts []*AppAlertSpec `json:"alerts,omitempty"` + Ingress *AppIngressSpec `json:"ingress,omitempty"` + Egress *AppEgressSpec `json:"egress,omitempty"` + Features []string `json:"features,omitempty"` + Maintenance *AppMaintenanceSpec `json:"maintenance,omitempty"` } // AppStaticSiteSpec struct for AppStaticSiteSpec @@ -917,6 +928,8 @@ type DetectResponse struct { TemplateFound bool `json:"template_found,omitempty"` TemplateValid bool `json:"template_valid,omitempty"` TemplateError string `json:"template_error,omitempty"` + // Whether or not the underlying detection is still pending. If true, the request can be retried as-is until this field is false and the response contains the detection result. + Pending bool `json:"pending,omitempty"` } // DetectResponseComponent struct for DetectResponseComponent @@ -1252,6 +1265,15 @@ type ResetDatabasePasswordResponse struct { Deployment *Deployment `json:"deployment,omitempty"` } +// ServingProtocol - HTTP: The app is serving the HTTP protocol. Default. - HTTP2: The app is serving the HTTP/2 protocol. Currently, this needs to be implemented in the service by serving HTTP/2 with prior knowledge. +type ServingProtocol string + +// List of ServingProtocol +const ( + SERVINGPROTOCOL_HTTP ServingProtocol = "HTTP" + SERVINGPROTOCOL_HTTP2 ServingProtocol = "HTTP2" +) + // AppStringMatch struct for AppStringMatch type AppStringMatch struct { // Exact string match. Only 1 of `exact`, `prefix`, or `regex` must be set. diff --git a/vendor/github.com/digitalocean/godo/apps_accessors.go b/vendor/github.com/digitalocean/godo/apps_accessors.go index 05c5ac4b1..02e7c4b15 100644 --- a/vendor/github.com/digitalocean/godo/apps_accessors.go +++ b/vendor/github.com/digitalocean/godo/apps_accessors.go @@ -1421,6 +1421,22 @@ func (a *AppLogDestinationSpecPapertrail) GetEndpoint() string { return a.Endpoint } +// GetArchive returns the Archive field. +func (a *AppMaintenanceSpec) GetArchive() bool { + if a == nil { + return false + } + return a.Archive +} + +// GetEnabled returns the Enabled field. +func (a *AppMaintenanceSpec) GetEnabled() bool { + if a == nil { + return false + } + return a.Enabled +} + // GetAppID returns the AppID field. func (a *AppProposeRequest) GetAppID() string { if a == nil { @@ -1757,6 +1773,14 @@ func (a *AppServiceSpec) GetName() string { return a.Name } +// GetProtocol returns the Protocol field. +func (a *AppServiceSpec) GetProtocol() ServingProtocol { + if a == nil { + return "" + } + return a.Protocol +} + // GetRoutes returns the Routes field. func (a *AppServiceSpec) GetRoutes() []*AppRouteSpec { if a == nil { @@ -1941,6 +1965,14 @@ func (a *AppSpec) GetJobs() []*AppJobSpec { return a.Jobs } +// GetMaintenance returns the Maintenance field. +func (a *AppSpec) GetMaintenance() *AppMaintenanceSpec { + if a == nil { + return nil + } + return a.Maintenance +} + // GetName returns the Name field. func (a *AppSpec) GetName() string { if a == nil { @@ -3093,6 +3125,14 @@ func (d *DetectResponse) GetComponents() []*DetectResponseComponent { return d.Components } +// GetPending returns the Pending field. +func (d *DetectResponse) GetPending() bool { + if d == nil { + return false + } + return d.Pending +} + // GetTemplate returns the Template field. func (d *DetectResponse) GetTemplate() *DeployTemplate { if d == nil { diff --git a/vendor/github.com/digitalocean/godo/droplet_autoscale.go b/vendor/github.com/digitalocean/godo/droplet_autoscale.go new file mode 100644 index 000000000..4ef9dff81 --- /dev/null +++ b/vendor/github.com/digitalocean/godo/droplet_autoscale.go @@ -0,0 +1,258 @@ +package godo + +import ( + "context" + "fmt" + "net/http" + "time" +) + +const ( + dropletAutoscaleBasePath = "/v2/droplets/autoscale" +) + +// DropletAutoscaleService defines an interface for managing droplet autoscale pools through DigitalOcean API +type DropletAutoscaleService interface { + Create(context.Context, *DropletAutoscalePoolRequest) (*DropletAutoscalePool, *Response, error) + Get(context.Context, string) (*DropletAutoscalePool, *Response, error) + List(context.Context, *ListOptions) ([]*DropletAutoscalePool, *Response, error) + ListMembers(context.Context, string, *ListOptions) ([]*DropletAutoscaleResource, *Response, error) + ListHistory(context.Context, string, *ListOptions) ([]*DropletAutoscaleHistoryEvent, *Response, error) + Update(context.Context, string, *DropletAutoscalePoolRequest) (*DropletAutoscalePool, *Response, error) + Delete(context.Context, string) (*Response, error) + DeleteDangerous(context.Context, string) (*Response, error) +} + +// DropletAutoscalePool represents a DigitalOcean droplet autoscale pool +type DropletAutoscalePool struct { + ID string `json:"id"` + Name string `json:"name"` + Config *DropletAutoscaleConfiguration `json:"config"` + DropletTemplate *DropletAutoscaleResourceTemplate `json:"droplet_template"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + CurrentUtilization *DropletAutoscaleResourceUtilization `json:"current_utilization,omitempty"` + Status string `json:"status"` +} + +// DropletAutoscaleConfiguration represents a DigitalOcean droplet autoscale pool configuration +type DropletAutoscaleConfiguration struct { + MinInstances uint64 `json:"min_instances,omitempty"` + MaxInstances uint64 `json:"max_instances,omitempty"` + TargetCPUUtilization float64 `json:"target_cpu_utilization,omitempty"` + TargetMemoryUtilization float64 `json:"target_memory_utilization,omitempty"` + CooldownMinutes uint32 `json:"cooldown_minutes,omitempty"` + TargetNumberInstances uint64 `json:"target_number_instances,omitempty"` +} + +// DropletAutoscaleResourceTemplate represents a DigitalOcean droplet autoscale pool resource template +type DropletAutoscaleResourceTemplate struct { + Size string `json:"size"` + Region string `json:"region"` + Image string `json:"image"` + Tags []string `json:"tags"` + SSHKeys []string `json:"ssh_keys"` + VpcUUID string `json:"vpc_uuid"` + WithDropletAgent bool `json:"with_droplet_agent"` + ProjectID string `json:"project_id"` + IPV6 bool `json:"ipv6"` + UserData string `json:"user_data"` +} + +// DropletAutoscaleResourceUtilization represents a DigitalOcean droplet autoscale pool resource utilization +type DropletAutoscaleResourceUtilization struct { + Memory float64 `json:"memory,omitempty"` + CPU float64 `json:"cpu,omitempty"` +} + +// DropletAutoscaleResource represents a DigitalOcean droplet autoscale pool resource +type DropletAutoscaleResource struct { + DropletID uint64 `json:"droplet_id"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + HealthStatus string `json:"health_status"` + UnhealthyReason string `json:"unhealthy_reason,omitempty"` + Status string `json:"status"` + CurrentUtilization *DropletAutoscaleResourceUtilization `json:"current_utilization,omitempty"` +} + +// DropletAutoscaleHistoryEvent represents a DigitalOcean droplet autoscale pool history event +type DropletAutoscaleHistoryEvent struct { + HistoryEventID string `json:"history_event_id"` + CurrentInstanceCount uint64 `json:"current_instance_count"` + DesiredInstanceCount uint64 `json:"desired_instance_count"` + Reason string `json:"reason"` + Status string `json:"status"` + ErrorReason string `json:"error_reason,omitempty"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +// DropletAutoscalePoolRequest represents a DigitalOcean droplet autoscale pool create/update request +type DropletAutoscalePoolRequest struct { + Name string `json:"name"` + Config *DropletAutoscaleConfiguration `json:"config"` + DropletTemplate *DropletAutoscaleResourceTemplate `json:"droplet_template"` +} + +type dropletAutoscalePoolRoot struct { + AutoscalePool *DropletAutoscalePool `json:"autoscale_pool"` +} + +type dropletAutoscalePoolsRoot struct { + AutoscalePools []*DropletAutoscalePool `json:"autoscale_pools"` + Links *Links `json:"links"` + Meta *Meta `json:"meta"` +} + +type dropletAutoscaleMembersRoot struct { + Droplets []*DropletAutoscaleResource `json:"droplets"` + Links *Links `json:"links"` + Meta *Meta `json:"meta"` +} + +type dropletAutoscaleHistoryEventsRoot struct { + History []*DropletAutoscaleHistoryEvent `json:"history"` + Links *Links `json:"links"` + Meta *Meta `json:"meta"` +} + +// DropletAutoscaleServiceOp handles communication with droplet autoscale-related methods of the DigitalOcean API +type DropletAutoscaleServiceOp struct { + client *Client +} + +var _ DropletAutoscaleService = &DropletAutoscaleServiceOp{} + +// Create a new droplet autoscale pool +func (d *DropletAutoscaleServiceOp) Create(ctx context.Context, createReq *DropletAutoscalePoolRequest) (*DropletAutoscalePool, *Response, error) { + req, err := d.client.NewRequest(ctx, http.MethodPost, dropletAutoscaleBasePath, createReq) + if err != nil { + return nil, nil, err + } + root := new(dropletAutoscalePoolRoot) + resp, err := d.client.Do(ctx, req, root) + if err != nil { + return nil, nil, err + } + return root.AutoscalePool, resp, nil +} + +// Get an existing droplet autoscale pool +func (d *DropletAutoscaleServiceOp) Get(ctx context.Context, id string) (*DropletAutoscalePool, *Response, error) { + req, err := d.client.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s/%s", dropletAutoscaleBasePath, id), nil) + if err != nil { + return nil, nil, err + } + root := new(dropletAutoscalePoolRoot) + resp, err := d.client.Do(ctx, req, root) + if err != nil { + return nil, nil, err + } + return root.AutoscalePool, resp, err +} + +// List all existing droplet autoscale pools +func (d *DropletAutoscaleServiceOp) List(ctx context.Context, opts *ListOptions) ([]*DropletAutoscalePool, *Response, error) { + path, err := addOptions(dropletAutoscaleBasePath, opts) + if err != nil { + return nil, nil, err + } + req, err := d.client.NewRequest(ctx, http.MethodGet, path, nil) + if err != nil { + return nil, nil, err + } + root := new(dropletAutoscalePoolsRoot) + resp, err := d.client.Do(ctx, req, root) + if err != nil { + return nil, nil, err + } + if root.Links != nil { + resp.Links = root.Links + } + if root.Meta != nil { + resp.Meta = root.Meta + } + return root.AutoscalePools, resp, err +} + +// ListMembers all members for an existing droplet autoscale pool +func (d *DropletAutoscaleServiceOp) ListMembers(ctx context.Context, id string, opts *ListOptions) ([]*DropletAutoscaleResource, *Response, error) { + path, err := addOptions(fmt.Sprintf("%s/%s/members", dropletAutoscaleBasePath, id), opts) + if err != nil { + return nil, nil, err + } + req, err := d.client.NewRequest(ctx, http.MethodGet, path, nil) + if err != nil { + return nil, nil, err + } + root := new(dropletAutoscaleMembersRoot) + resp, err := d.client.Do(ctx, req, root) + if err != nil { + return nil, nil, err + } + if root.Links != nil { + resp.Links = root.Links + } + if root.Meta != nil { + resp.Meta = root.Meta + } + return root.Droplets, resp, err +} + +// ListHistory all history events for an existing droplet autoscale pool +func (d *DropletAutoscaleServiceOp) ListHistory(ctx context.Context, id string, opts *ListOptions) ([]*DropletAutoscaleHistoryEvent, *Response, error) { + path, err := addOptions(fmt.Sprintf("%s/%s/history", dropletAutoscaleBasePath, id), opts) + if err != nil { + return nil, nil, err + } + req, err := d.client.NewRequest(ctx, http.MethodGet, path, nil) + if err != nil { + return nil, nil, err + } + root := new(dropletAutoscaleHistoryEventsRoot) + resp, err := d.client.Do(ctx, req, root) + if err != nil { + return nil, nil, err + } + if root.Links != nil { + resp.Links = root.Links + } + if root.Meta != nil { + resp.Meta = root.Meta + } + return root.History, resp, err +} + +// Update an existing autoscale pool +func (d *DropletAutoscaleServiceOp) Update(ctx context.Context, id string, updateReq *DropletAutoscalePoolRequest) (*DropletAutoscalePool, *Response, error) { + req, err := d.client.NewRequest(ctx, http.MethodPut, fmt.Sprintf("%s/%s", dropletAutoscaleBasePath, id), updateReq) + if err != nil { + return nil, nil, err + } + root := new(dropletAutoscalePoolRoot) + resp, err := d.client.Do(ctx, req, root) + if err != nil { + return nil, nil, err + } + return root.AutoscalePool, resp, nil +} + +// Delete an existing autoscale pool +func (d *DropletAutoscaleServiceOp) Delete(ctx context.Context, id string) (*Response, error) { + req, err := d.client.NewRequest(ctx, http.MethodDelete, fmt.Sprintf("%s/%s", dropletAutoscaleBasePath, id), nil) + if err != nil { + return nil, err + } + return d.client.Do(ctx, req, nil) +} + +// DeleteDangerous deletes an existing autoscale pool with all underlying resources +func (d *DropletAutoscaleServiceOp) DeleteDangerous(ctx context.Context, id string) (*Response, error) { + req, err := d.client.NewRequest(ctx, http.MethodDelete, fmt.Sprintf("%s/%s/dangerous", dropletAutoscaleBasePath, id), nil) + req.Header.Set("X-Dangerous", "true") + if err != nil { + return nil, err + } + return d.client.Do(ctx, req, nil) +} diff --git a/vendor/github.com/digitalocean/godo/droplets.go b/vendor/github.com/digitalocean/godo/droplets.go index 5f1986364..1ed09ec8c 100644 --- a/vendor/github.com/digitalocean/godo/droplets.go +++ b/vendor/github.com/digitalocean/godo/droplets.go @@ -17,6 +17,7 @@ var errNoNetworks = errors.New("no networks have been defined") // See: https://docs.digitalocean.com/reference/api/api-reference/#tag/Droplets type DropletsService interface { List(context.Context, *ListOptions) ([]Droplet, *Response, error) + ListWithGPUs(context.Context, *ListOptions) ([]Droplet, *Response, error) ListByName(context.Context, string, *ListOptions) ([]Droplet, *Response, error) ListByTag(context.Context, string, *ListOptions) ([]Droplet, *Response, error) Get(context.Context, int) (*Droplet, *Response, error) @@ -321,6 +322,17 @@ func (s *DropletsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Dropl return s.list(ctx, path) } +// ListWithGPUs lists all Droplets with GPUs. +func (s *DropletsServiceOp) ListWithGPUs(ctx context.Context, opt *ListOptions) ([]Droplet, *Response, error) { + path := fmt.Sprintf("%s?type=gpus", dropletBasePath) + path, err := addOptions(path, opt) + if err != nil { + return nil, nil, err + } + + return s.list(ctx, path) +} + // ListByName lists all Droplets filtered by name returning only exact matches. // It is case-insensitive func (s *DropletsServiceOp) ListByName(ctx context.Context, name string, opt *ListOptions) ([]Droplet, *Response, error) { diff --git a/vendor/github.com/digitalocean/godo/godo.go b/vendor/github.com/digitalocean/godo/godo.go index 3702ac1f7..edf0f6d46 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.126.0" + libraryVersion = "1.128.0" defaultBaseURL = "https://api.digitalocean.com/" userAgent = "godo/" + libraryVersion mediaType = "application/json" @@ -65,6 +65,7 @@ type Client struct { Domains DomainsService Droplets DropletsService DropletActions DropletActionsService + DropletAutoscale DropletAutoscaleService Firewalls FirewallsService FloatingIPs FloatingIPsService FloatingIPActions FloatingIPActionsService @@ -275,6 +276,7 @@ func NewClient(httpClient *http.Client) *Client { c.Domains = &DomainsServiceOp{client: c} c.Droplets = &DropletsServiceOp{client: c} c.DropletActions = &DropletActionsServiceOp{client: c} + c.DropletAutoscale = &DropletAutoscaleServiceOp{client: c} c.Firewalls = &FirewallsServiceOp{client: c} c.FloatingIPs = &FloatingIPsServiceOp{client: c} c.FloatingIPActions = &FloatingIPActionsServiceOp{client: c} diff --git a/vendor/github.com/digitalocean/godo/monitoring.go b/vendor/github.com/digitalocean/godo/monitoring.go index 937bb8d91..00feb2565 100644 --- a/vendor/github.com/digitalocean/godo/monitoring.go +++ b/vendor/github.com/digitalocean/godo/monitoring.go @@ -10,9 +10,10 @@ import ( ) const ( - monitoringBasePath = "v2/monitoring" - alertPolicyBasePath = monitoringBasePath + "/alerts" - dropletMetricsBasePath = monitoringBasePath + "/metrics/droplet" + monitoringBasePath = "v2/monitoring" + alertPolicyBasePath = monitoringBasePath + "/alerts" + dropletMetricsBasePath = monitoringBasePath + "/metrics/droplet" + loadBalancerMetricsBasePath = monitoringBasePath + "/metrics/load_balancer" DropletCPUUtilizationPercent = "v1/insights/droplet/cpu" DropletMemoryUtilizationPercent = "v1/insights/droplet/memory_utilization_percent" @@ -67,6 +68,34 @@ type MonitoringService interface { GetDropletCachedMemory(context.Context, *DropletMetricsRequest) (*MetricsResponse, *Response, error) GetDropletFreeMemory(context.Context, *DropletMetricsRequest) (*MetricsResponse, *Response, error) GetDropletTotalMemory(context.Context, *DropletMetricsRequest) (*MetricsResponse, *Response, error) + + GetLoadBalancerFrontendHttpRequestsPerSecond(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerFrontendConnectionsCurrent(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerFrontendConnectionsLimit(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerFrontendCpuUtilization(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerFrontendNetworkThroughputHttp(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerFrontendNetworkThroughputUdp(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerFrontendNetworkThroughputTcp(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerFrontendNlbTcpNetworkThroughput(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerFrontendNlbUdpNetworkThroughput(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerFrontendFirewallDroppedBytes(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerFrontendFirewallDroppedPackets(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerFrontendHttpResponses(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerFrontendTlsConnectionsCurrent(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerFrontendTlsConnectionsLimit(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerFrontendTlsConnectionsExceedingRateLimit(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerDropletsHttpSessionDurationAvg(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerDropletsHttpSessionDuration50P(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerDropletsHttpSessionDuration95P(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerDropletsHttpResponseTimeAvg(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerDropletsHttpResponseTime50P(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerDropletsHttpResponseTime95P(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerDropletsHttpResponseTime99P(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerDropletsQueueSize(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerDropletsHttpResponses(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerDropletsConnections(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerDropletsHealthChecks(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) + GetLoadBalancerDropletsDowntime(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) } // MonitoringServiceOp handles communication with monitoring related methods of the @@ -163,6 +192,13 @@ type DropletBandwidthMetricsRequest struct { Direction string } +// LoadBalancerMetricsRequest holds the information needed to retrieve Load Balancer various metrics. +type LoadBalancerMetricsRequest struct { + LoadBalancerID string + Start time.Time + End time.Time +} + // MetricsResponse holds a Metrics query response. type MetricsResponse struct { Status string `json:"status"` @@ -372,3 +408,157 @@ func (s *MonitoringServiceOp) getDropletMetrics(ctx context.Context, path string return root, resp, err } + +// GetLoadBalancerFrontendHttpRequestsPerSecond retrieves frontend HTTP requests per second for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerFrontendHttpRequestsPerSecond(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/frontend_http_requests_per_second", args) +} + +// GetLoadBalancerFrontendConnectionsCurrent retrieves frontend total current active connections for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerFrontendConnectionsCurrent(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/frontend_connections_current", args) +} + +// GetLoadBalancerFrontendConnectionsLimit retrieves frontend max connections limit for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerFrontendConnectionsLimit(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/frontend_connections_limit", args) +} + +// GetLoadBalancerFrontendCpuUtilization retrieves frontend average percentage cpu utilization for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerFrontendCpuUtilization(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/frontend_cpu_utilization", args) +} + +// GetLoadBalancerFrontendNetworkThroughputHttp retrieves frontend HTTP throughput for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerFrontendNetworkThroughputHttp(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/frontend_network_throughput_http", args) +} + +// GetLoadBalancerFrontendNetworkThroughputUdp retrieves frontend UDP throughput for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerFrontendNetworkThroughputUdp(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/frontend_network_throughput_udp", args) +} + +// GetLoadBalancerFrontendNetworkThroughputTcp retrieves frontend TCP throughput for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerFrontendNetworkThroughputTcp(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/frontend_network_throughput_tcp", args) +} + +// GetLoadBalancerFrontendNlbTcpNetworkThroughput retrieves frontend TCP throughput for a given network load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerFrontendNlbTcpNetworkThroughput(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/frontend_nlb_tcp_network_throughput", args) +} + +// GetLoadBalancerFrontendNlbUdpNetworkThroughput retrieves frontend UDP throughput for a given network load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerFrontendNlbUdpNetworkThroughput(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/frontend_nlb_udp_network_throughput", args) +} + +// GetLoadBalancerFrontendFirewallDroppedBytes retrieves firewall dropped bytes for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerFrontendFirewallDroppedBytes(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/frontend_firewall_dropped_bytes", args) +} + +// GetLoadBalancerFrontendFirewallDroppedPackets retrieves firewall dropped packets for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerFrontendFirewallDroppedPackets(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/frontend_firewall_dropped_packets", args) +} + +// GetLoadBalancerFrontendHttpResponses retrieves frontend HTTP rate of response code for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerFrontendHttpResponses(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/frontend_http_responses", args) +} + +// GetLoadBalancerFrontendTlsConnectionsCurrent retrieves frontend current TLS connections rate for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerFrontendTlsConnectionsCurrent(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/frontend_tls_connections_current", args) +} + +// GetLoadBalancerFrontendTlsConnectionsLimit retrieves frontend max TLS connections limit for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerFrontendTlsConnectionsLimit(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/frontend_tls_connections_limit", args) +} + +// GetLoadBalancerFrontendTlsConnectionsExceedingRateLimit retrieves frontend closed TLS connections for exceeded rate limit for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerFrontendTlsConnectionsExceedingRateLimit(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/frontend_tls_connections_exceeding_rate_limit", args) +} + +// GetLoadBalancerDropletsHttpSessionDurationAvg retrieves droplet average HTTP session duration for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerDropletsHttpSessionDurationAvg(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/droplets_http_session_duration_avg", args) +} + +// GetLoadBalancerDropletsHttpSessionDuration50P retrieves droplet 50th percentile HTTP session duration for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerDropletsHttpSessionDuration50P(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/droplets_http_session_duration_50p", args) +} + +// GetLoadBalancerDropletsHttpSessionDuration95P retrieves droplet 95th percentile HTTP session duration for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerDropletsHttpSessionDuration95P(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/droplets_http_session_duration_95p", args) +} + +// GetLoadBalancerDropletsHttpResponseTimeAvg retrieves droplet average HTTP response time for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerDropletsHttpResponseTimeAvg(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/droplets_http_response_time_avg", args) +} + +// GetLoadBalancerDropletsHttpResponseTime50P retrieves droplet 50th percentile HTTP response time for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerDropletsHttpResponseTime50P(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/droplets_http_response_time_50p", args) +} + +// GetLoadBalancerDropletsHttpResponseTime95P retrieves droplet 95th percentile HTTP response time for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerDropletsHttpResponseTime95P(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/droplets_http_response_time_95p", args) +} + +// GetLoadBalancerDropletsHttpResponseTime99P retrieves droplet 99th percentile HTTP response time for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerDropletsHttpResponseTime99P(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/droplets_http_response_time_99p", args) +} + +// GetLoadBalancerDropletsQueueSize retrieves droplet queue size for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerDropletsQueueSize(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/droplets_queue_size", args) +} + +// GetLoadBalancerDropletsHttpResponses retrieves droplet HTTP rate of response code for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerDropletsHttpResponses(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/droplets_http_responses", args) +} + +// GetLoadBalancerDropletsConnections retrieves droplet active connections for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerDropletsConnections(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/droplets_connections", args) +} + +// GetLoadBalancerDropletsHealthChecks retrieves droplet health check status for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerDropletsHealthChecks(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/droplets_health_checks", args) +} + +// GetLoadBalancerDropletsDowntime retrieves droplet downtime status for a given load balancer. +func (s *MonitoringServiceOp) GetLoadBalancerDropletsDowntime(ctx context.Context, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + return s.getLoadBalancerMetrics(ctx, "/droplets_downtime", args) +} + +func (s *MonitoringServiceOp) getLoadBalancerMetrics(ctx context.Context, path string, args *LoadBalancerMetricsRequest) (*MetricsResponse, *Response, error) { + fullPath := loadBalancerMetricsBasePath + path + req, err := s.client.NewRequest(ctx, http.MethodGet, fullPath, nil) + if err != nil { + return nil, nil, err + } + + q := req.URL.Query() + q.Add("lb_id", args.LoadBalancerID) + q.Add("start", fmt.Sprintf("%d", args.Start.Unix())) + q.Add("end", fmt.Sprintf("%d", args.End.Unix())) + req.URL.RawQuery = q.Encode() + + root := new(MetricsResponse) + resp, err := s.client.Do(ctx, req, root) + + return root, resp, err +} diff --git a/vendor/github.com/digitalocean/godo/sizes.go b/vendor/github.com/digitalocean/godo/sizes.go index a3cb74523..72d5321c9 100644 --- a/vendor/github.com/digitalocean/godo/sizes.go +++ b/vendor/github.com/digitalocean/godo/sizes.go @@ -22,16 +22,44 @@ var _ SizesService = &SizesServiceOp{} // Size represents a DigitalOcean Size type Size struct { - Slug string `json:"slug,omitempty"` - Memory int `json:"memory,omitempty"` - Vcpus int `json:"vcpus,omitempty"` - Disk int `json:"disk,omitempty"` - PriceMonthly float64 `json:"price_monthly,omitempty"` - PriceHourly float64 `json:"price_hourly,omitempty"` - Regions []string `json:"regions,omitempty"` - Available bool `json:"available,omitempty"` - Transfer float64 `json:"transfer,omitempty"` - Description string `json:"description,omitempty"` + Slug string `json:"slug,omitempty"` + Memory int `json:"memory,omitempty"` + Vcpus int `json:"vcpus,omitempty"` + Disk int `json:"disk,omitempty"` + PriceMonthly float64 `json:"price_monthly,omitempty"` + PriceHourly float64 `json:"price_hourly,omitempty"` + Regions []string `json:"regions,omitempty"` + Available bool `json:"available,omitempty"` + Transfer float64 `json:"transfer,omitempty"` + Description string `json:"description,omitempty"` + GPUInfo *GPUInfo `json:"gpu_info,omitempty"` + DiskInfo []DiskInfo `json:"disk_info,omitempty"` +} + +// DiskInfo containing information about the disks available to Droplets created +// with this size. +type DiskInfo struct { + Type string `json:"type,omitempty"` + Size *DiskSize `json:"size,omitempty"` +} + +// DiskSize provides information about the size of a disk. +type DiskSize struct { + Amount int `json:"amount,omitempty"` + Unit string `json:"unit,omitempty"` +} + +// GPUInfo provides information about the GPU available to Droplets created with this size. +type GPUInfo struct { + Count int `json:"count,omitempty"` + VRAM *VRAM `json:"vram,omitempty"` + Model string `json:"model,omitempty"` +} + +// VRAM provides information about the amount of VRAM available to the GPU. +type VRAM struct { + Amount int `json:"amount,omitempty"` + Unit string `json:"unit,omitempty"` } func (s Size) String() string { diff --git a/vendor/modules.txt b/vendor/modules.txt index 4be2307e9..04b805a87 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -58,7 +58,7 @@ github.com/aws/aws-sdk-go/service/sts/stsiface # github.com/davecgh/go-spew v1.1.1 ## explicit github.com/davecgh/go-spew/spew -# github.com/digitalocean/godo v1.126.1-0.20241004175533-dfe74ef3d8bb +# github.com/digitalocean/godo v1.128.1-0.20241025145008-2654a9d1e887 ## explicit; go 1.22 github.com/digitalocean/godo github.com/digitalocean/godo/metrics