Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/GoCodeAlone/workflow-plugin-digitalocean
go 1.26.0

require (
github.com/GoCodeAlone/workflow v0.15.2
github.com/GoCodeAlone/workflow v0.17.0
github.com/aws/aws-sdk-go-v2 v1.41.5
github.com/aws/aws-sdk-go-v2/credentials v1.19.12
github.com/aws/aws-sdk-go-v2/service/s3 v1.97.2
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ github.com/GoCodeAlone/modular/modules/jsonschema v1.15.0 h1:xb1mI4NZkzvNKQ2F6nk
github.com/GoCodeAlone/modular/modules/jsonschema v1.15.0/go.mod h1:hhGouwAVsonmJ4Lain4jINZ9nZCoc9l9eF3BHbmR8eE=
github.com/GoCodeAlone/modular/modules/reverseproxy/v2 v2.8.0 h1:cvdLHbM/vzvygQTcAWSJsy+dAPzzwWyjzKMmTBFcFIo=
github.com/GoCodeAlone/modular/modules/reverseproxy/v2 v2.8.0/go.mod h1:/9ipMG4qM2CHQ14BfXKdVlYRJelef6M8MFI5TbZv67M=
github.com/GoCodeAlone/workflow v0.15.2 h1:3zVt22diMNiXl1Alru0nPzpwh8LGaSvcUFm2lIWjwOI=
github.com/GoCodeAlone/workflow v0.15.2/go.mod h1:MGC8lxQzA1TLRIK09mGEN5JNpRzFUcTWgqk3M0/H5FI=
github.com/GoCodeAlone/workflow v0.17.0 h1:Fp4eOdaZKNnIsBvLJT4PcxSmv+++M3X9McKjKMEMz3g=
github.com/GoCodeAlone/workflow v0.17.0/go.mod h1:MGC8lxQzA1TLRIK09mGEN5JNpRzFUcTWgqk3M0/H5FI=
github.com/GoCodeAlone/yaegi v0.17.2 h1:WK6Y6e0t1a6U7r+S2dN3CGWW1PizYD3zO0zneToZPxM=
github.com/GoCodeAlone/yaegi v0.17.2/go.mod h1:z5Pr6Wse6QJcQvpgxTxzMAevFarH0N37TG88Y9dprx0=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0 h1:rIkQfkCOVKc1OiRCNcSDD8ml5RJlZbH/Xsq7lbpynwc=
Expand Down
8 changes: 4 additions & 4 deletions internal/drivers/api_gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ func (d *APIGatewayDriver) Create(ctx context.Context, spec interfaces.ResourceS

app, _, err := d.client.Create(ctx, &godo.AppCreateRequest{Spec: appSpec})
if err != nil {
return nil, fmt.Errorf("api_gateway create %q: %w", spec.Name, err)
return nil, fmt.Errorf("api_gateway create %q: %w", spec.Name, WrapGodoError(err))
}
return apiGatewayOutput(app), nil
}

func (d *APIGatewayDriver) Read(ctx context.Context, ref interfaces.ResourceRef) (*interfaces.ResourceOutput, error) {
app, _, err := d.client.Get(ctx, ref.ProviderID)
if err != nil {
return nil, fmt.Errorf("api_gateway read %q: %w", ref.Name, err)
return nil, fmt.Errorf("api_gateway read %q: %w", ref.Name, WrapGodoError(err))
}
return apiGatewayOutput(app), nil
}
Expand All @@ -64,15 +64,15 @@ func (d *APIGatewayDriver) Update(ctx context.Context, ref interfaces.ResourceRe

app, _, err := d.client.Update(ctx, ref.ProviderID, &godo.AppUpdateRequest{Spec: appSpec})
if err != nil {
return nil, fmt.Errorf("api_gateway update %q: %w", ref.Name, err)
return nil, fmt.Errorf("api_gateway update %q: %w", ref.Name, WrapGodoError(err))
}
return apiGatewayOutput(app), nil
}

func (d *APIGatewayDriver) Delete(ctx context.Context, ref interfaces.ResourceRef) error {
_, err := d.client.Delete(ctx, ref.ProviderID)
if err != nil {
return fmt.Errorf("api_gateway delete %q: %w", ref.Name, err)
return fmt.Errorf("api_gateway delete %q: %w", ref.Name, WrapGodoError(err))
}
return nil
}
Expand Down
14 changes: 7 additions & 7 deletions internal/drivers/app_platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func (d *AppPlatformDriver) Create(ctx context.Context, spec interfaces.Resource

app, _, err := d.client.Create(ctx, req)
if err != nil {
return nil, fmt.Errorf("app platform create %q: %w", spec.Name, err)
return nil, fmt.Errorf("app platform create %q: %w", spec.Name, WrapGodoError(err))
}
return appOutput(app), nil
}
Expand All @@ -81,7 +81,7 @@ func (d *AppPlatformDriver) Read(ctx context.Context, ref interfaces.ResourceRef
}
app, _, err := d.client.Get(ctx, ref.ProviderID)
if err != nil {
return nil, fmt.Errorf("app platform read %q: %w", ref.Name, err)
return nil, fmt.Errorf("app platform read %q: %w", ref.Name, WrapGodoError(err))
}
return appOutput(app), nil
}
Expand All @@ -93,7 +93,7 @@ func (d *AppPlatformDriver) findAppByName(ctx context.Context, name string) (*in
for {
apps, resp, err := d.client.List(ctx, opts)
if err != nil {
return nil, fmt.Errorf("app platform list: %w", err)
return nil, fmt.Errorf("app platform list: %w", WrapGodoError(err))
}
for _, app := range apps {
if app.Spec != nil && app.Spec.Name == name {
Expand Down Expand Up @@ -138,15 +138,15 @@ func (d *AppPlatformDriver) Update(ctx context.Context, ref interfaces.ResourceR

app, _, err := d.client.Update(ctx, ref.ProviderID, req)
if err != nil {
return nil, fmt.Errorf("app platform update %q: %w", ref.Name, err)
return nil, fmt.Errorf("app platform update %q: %w", ref.Name, WrapGodoError(err))
}
return appOutput(app), nil
}

func (d *AppPlatformDriver) Delete(ctx context.Context, ref interfaces.ResourceRef) error {
_, err := d.client.Delete(ctx, ref.ProviderID)
if err != nil {
return fmt.Errorf("app platform delete %q: %w", ref.Name, err)
return fmt.Errorf("app platform delete %q: %w", ref.Name, WrapGodoError(err))
}
return nil
}
Expand Down Expand Up @@ -219,15 +219,15 @@ func appHealthResult(app *godo.App) *interfaces.HealthResult {
func (d *AppPlatformDriver) Scale(ctx context.Context, ref interfaces.ResourceRef, replicas int) (*interfaces.ResourceOutput, error) {
app, _, err := d.client.Get(ctx, ref.ProviderID)
if err != nil {
return nil, fmt.Errorf("app platform scale read %q: %w", ref.Name, err)
return nil, fmt.Errorf("app platform scale read %q: %w", ref.Name, WrapGodoError(err))
}
spec := app.Spec
for _, svc := range spec.Services {
svc.InstanceCount = int64(replicas)
}
updated, _, err := d.client.Update(ctx, ref.ProviderID, &godo.AppUpdateRequest{Spec: spec})
if err != nil {
return nil, fmt.Errorf("app platform scale update %q: %w", ref.Name, err)
return nil, fmt.Errorf("app platform scale update %q: %w", ref.Name, WrapGodoError(err))
}
return appOutput(updated), nil
}
Expand Down
12 changes: 6 additions & 6 deletions internal/drivers/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ func (d *CacheDriver) Create(ctx context.Context, spec interfaces.ResourceSpec)

db, _, err := d.client.Create(ctx, req)
if err != nil {
return nil, fmt.Errorf("cache create %q: %w", spec.Name, err)
return nil, fmt.Errorf("cache create %q: %w", spec.Name, WrapGodoError(err))
}
return cacheOutput(db), nil
}

func (d *CacheDriver) Read(ctx context.Context, ref interfaces.ResourceRef) (*interfaces.ResourceOutput, error) {
db, _, err := d.client.Get(ctx, ref.ProviderID)
if err != nil {
return nil, fmt.Errorf("cache read %q: %w", ref.Name, err)
return nil, fmt.Errorf("cache read %q: %w", ref.Name, WrapGodoError(err))
}
return cacheOutput(db), nil
}
Expand All @@ -71,15 +71,15 @@ func (d *CacheDriver) Update(ctx context.Context, ref interfaces.ResourceRef, sp
NumNodes: numNodes,
})
if err != nil {
return nil, fmt.Errorf("cache update %q: %w", ref.Name, err)
return nil, fmt.Errorf("cache update %q: %w", ref.Name, WrapGodoError(err))
}
return d.Read(ctx, ref)
}

func (d *CacheDriver) Delete(ctx context.Context, ref interfaces.ResourceRef) error {
_, err := d.client.Delete(ctx, ref.ProviderID)
if err != nil {
return fmt.Errorf("cache delete %q: %w", ref.Name, err)
return fmt.Errorf("cache delete %q: %w", ref.Name, WrapGodoError(err))
}
return nil
}
Expand Down Expand Up @@ -109,14 +109,14 @@ func (d *CacheDriver) HealthCheck(ctx context.Context, ref interfaces.ResourceRe
func (d *CacheDriver) Scale(ctx context.Context, ref interfaces.ResourceRef, replicas int) (*interfaces.ResourceOutput, error) {
db, _, err := d.client.Get(ctx, ref.ProviderID)
if err != nil {
return nil, fmt.Errorf("cache scale read %q: %w", ref.Name, err)
return nil, fmt.Errorf("cache scale read %q: %w", ref.Name, WrapGodoError(err))
}
_, err = d.client.Resize(ctx, ref.ProviderID, &godo.DatabaseResizeRequest{
SizeSlug: db.SizeSlug,
NumNodes: replicas,
})
if err != nil {
return nil, fmt.Errorf("cache scale %q: %w", ref.Name, err)
return nil, fmt.Errorf("cache scale %q: %w", ref.Name, WrapGodoError(err))
}
return d.Read(ctx, ref)
}
Expand Down
6 changes: 3 additions & 3 deletions internal/drivers/certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,15 @@ func (d *CertificateDriver) Create(ctx context.Context, spec interfaces.Resource

cert, _, err := d.client.Create(ctx, req)
if err != nil {
return nil, fmt.Errorf("certificate create %q: %w", spec.Name, err)
return nil, fmt.Errorf("certificate create %q: %w", spec.Name, WrapGodoError(err))
}
return certOutput(cert, spec.Name), nil
}

func (d *CertificateDriver) Read(ctx context.Context, ref interfaces.ResourceRef) (*interfaces.ResourceOutput, error) {
cert, _, err := d.client.Get(ctx, ref.ProviderID)
if err != nil {
return nil, fmt.Errorf("certificate read %q: %w", ref.Name, err)
return nil, fmt.Errorf("certificate read %q: %w", ref.Name, WrapGodoError(err))
}
return certOutput(cert, ref.Name), nil
}
Expand All @@ -73,7 +73,7 @@ func (d *CertificateDriver) Update(ctx context.Context, ref interfaces.ResourceR
func (d *CertificateDriver) Delete(ctx context.Context, ref interfaces.ResourceRef) error {
_, err := d.client.Delete(ctx, ref.ProviderID)
if err != nil {
return fmt.Errorf("certificate delete %q: %w", ref.Name, err)
return fmt.Errorf("certificate delete %q: %w", ref.Name, WrapGodoError(err))
}
return nil
}
Expand Down
12 changes: 6 additions & 6 deletions internal/drivers/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@ func (d *DatabaseDriver) Create(ctx context.Context, spec interfaces.ResourceSpe

db, _, err := d.client.Create(ctx, req)
if err != nil {
return nil, fmt.Errorf("database create %q: %w", spec.Name, err)
return nil, fmt.Errorf("database create %q: %w", spec.Name, WrapGodoError(err))
}
return dbOutput(db), nil
}

func (d *DatabaseDriver) Read(ctx context.Context, ref interfaces.ResourceRef) (*interfaces.ResourceOutput, error) {
db, _, err := d.client.Get(ctx, ref.ProviderID)
if err != nil {
return nil, fmt.Errorf("database read %q: %w", ref.Name, err)
return nil, fmt.Errorf("database read %q: %w", ref.Name, WrapGodoError(err))
}
return dbOutput(db), nil
}
Expand All @@ -72,15 +72,15 @@ func (d *DatabaseDriver) Update(ctx context.Context, ref interfaces.ResourceRef,
NumNodes: numNodes,
})
if err != nil {
return nil, fmt.Errorf("database update %q: %w", ref.Name, err)
return nil, fmt.Errorf("database update %q: %w", ref.Name, WrapGodoError(err))
}
return d.Read(ctx, ref)
}

func (d *DatabaseDriver) Delete(ctx context.Context, ref interfaces.ResourceRef) error {
_, err := d.client.Delete(ctx, ref.ProviderID)
if err != nil {
return fmt.Errorf("database delete %q: %w", ref.Name, err)
return fmt.Errorf("database delete %q: %w", ref.Name, WrapGodoError(err))
}
return nil
}
Expand Down Expand Up @@ -110,14 +110,14 @@ func (d *DatabaseDriver) HealthCheck(ctx context.Context, ref interfaces.Resourc
func (d *DatabaseDriver) Scale(ctx context.Context, ref interfaces.ResourceRef, replicas int) (*interfaces.ResourceOutput, error) {
db, _, err := d.client.Get(ctx, ref.ProviderID)
if err != nil {
return nil, fmt.Errorf("database scale read %q: %w", ref.Name, err)
return nil, fmt.Errorf("database scale read %q: %w", ref.Name, WrapGodoError(err))
}
_, err = d.client.Resize(ctx, ref.ProviderID, &godo.DatabaseResizeRequest{
SizeSlug: db.SizeSlug,
NumNodes: replicas,
})
if err != nil {
return nil, fmt.Errorf("database scale %q: %w", ref.Name, err)
return nil, fmt.Errorf("database scale %q: %w", ref.Name, WrapGodoError(err))
}
return d.Read(ctx, ref)
}
Expand Down
12 changes: 6 additions & 6 deletions internal/drivers/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (d *DNSDriver) Create(ctx context.Context, spec interfaces.ResourceSpec) (*
if err != nil {
dom, _, err = d.client.Create(ctx, &godo.DomainCreateRequest{Name: domain})
if err != nil {
return nil, fmt.Errorf("dns create domain %q: %w", domain, err)
return nil, fmt.Errorf("dns create domain %q: %w", domain, WrapGodoError(err))
}
}

Expand All @@ -63,7 +63,7 @@ func (d *DNSDriver) Read(ctx context.Context, ref interfaces.ResourceRef) (*inte
domain := ref.ProviderID
dom, _, err := d.client.Get(ctx, domain)
if err != nil {
return nil, fmt.Errorf("dns read %q: %w", ref.Name, err)
return nil, fmt.Errorf("dns read %q: %w", ref.Name, WrapGodoError(err))
}
return dnsOutput(dom, ref.Name), nil
}
Expand All @@ -79,7 +79,7 @@ func (d *DNSDriver) Update(ctx context.Context, ref interfaces.ResourceRef, spec
func (d *DNSDriver) Delete(ctx context.Context, ref interfaces.ResourceRef) error {
_, err := d.client.Delete(ctx, ref.ProviderID)
if err != nil {
return fmt.Errorf("dns delete %q: %w", ref.Name, err)
return fmt.Errorf("dns delete %q: %w", ref.Name, WrapGodoError(err))
}
return nil
}
Expand Down Expand Up @@ -112,7 +112,7 @@ func (d *DNSDriver) upsertRecords(ctx context.Context, domain string, config map

existing, _, err := d.client.Records(ctx, domain, nil)
if err != nil {
return fmt.Errorf("dns list records %q: %w", domain, err)
return fmt.Errorf("dns list records %q: %w", domain, WrapGodoError(err))
}

existingByName := make(map[string]godo.DomainRecord)
Expand Down Expand Up @@ -141,11 +141,11 @@ func (d *DNSDriver) upsertRecords(ctx context.Context, domain string, config map
key := strings.ToLower(rType) + ":" + rName
if existing, found := existingByName[key]; found {
if _, _, err := d.client.EditRecord(ctx, domain, existing.ID, editReq); err != nil {
return fmt.Errorf("dns update record %q %s/%s: %w", domain, rType, rName, err)
return fmt.Errorf("dns update record %q %s/%s: %w", domain, rType, rName, WrapGodoError(err))
}
} else {
if _, _, err := d.client.CreateRecord(ctx, domain, editReq); err != nil {
return fmt.Errorf("dns create record %q %s/%s: %w", domain, rType, rName, err)
return fmt.Errorf("dns create record %q %s/%s: %w", domain, rType, rName, WrapGodoError(err))
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions internal/drivers/droplet.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (d *DropletDriver) Create(ctx context.Context, spec interfaces.ResourceSpec

droplet, _, err := d.client.Create(ctx, req)
if err != nil {
return nil, fmt.Errorf("droplet create %q: %w", spec.Name, err)
return nil, fmt.Errorf("droplet create %q: %w", spec.Name, WrapGodoError(err))
}
return dropletOutput(droplet), nil
}
Expand All @@ -54,7 +54,7 @@ func (d *DropletDriver) Read(ctx context.Context, ref interfaces.ResourceRef) (*
id := providerIDToInt(ref.ProviderID)
droplet, _, err := d.client.Get(ctx, id)
if err != nil {
return nil, fmt.Errorf("droplet read %q: %w", ref.Name, err)
return nil, fmt.Errorf("droplet read %q: %w", ref.Name, WrapGodoError(err))
}
return dropletOutput(droplet), nil
}
Expand All @@ -67,7 +67,7 @@ func (d *DropletDriver) Delete(ctx context.Context, ref interfaces.ResourceRef)
id := providerIDToInt(ref.ProviderID)
_, err := d.client.Delete(ctx, id)
if err != nil {
return fmt.Errorf("droplet delete %q: %w", ref.Name, err)
return fmt.Errorf("droplet delete %q: %w", ref.Name, WrapGodoError(err))
}
return nil
}
Expand Down
53 changes: 53 additions & 0 deletions internal/drivers/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package drivers

import (
"fmt"
"net/http"

"github.com/GoCodeAlone/workflow/interfaces"
"github.com/digitalocean/godo"
)

// WrapGodoError inspects err for a *godo.ErrorResponse and maps its HTTP status
// code to the matching interfaces.Err* sentinel. The returned error wraps the
// sentinel so callers can use errors.Is for classification while still having
// access to the original DO API message via err.Error().
//
// If err is nil or not a *godo.ErrorResponse, it is returned unchanged.
func WrapGodoError(err error) error {
if err == nil {
return nil
}
gErr, ok := err.(*godo.ErrorResponse)
if !ok || gErr.Response == nil {
return err
}
sentinel := sentinelForStatus(gErr.Response.StatusCode)
if sentinel == nil {
return err
}
return fmt.Errorf("%w: %v", sentinel, err)
}

// sentinelForStatus maps an HTTP status code to its interfaces sentinel.
// Returns nil for codes that have no sentinel mapping (pass-through).
func sentinelForStatus(code int) error {
switch {
case code == http.StatusUnauthorized:
return interfaces.ErrUnauthorized
case code == http.StatusForbidden:
return interfaces.ErrForbidden
case code == http.StatusNotFound || code == http.StatusMethodNotAllowed:
return interfaces.ErrResourceNotFound
case code == http.StatusConflict:
return interfaces.ErrResourceAlreadyExists
case code == http.StatusBadRequest || code == http.StatusUnprocessableEntity:
return interfaces.ErrValidation
case code == http.StatusTooManyRequests:
return interfaces.ErrRateLimited
case code >= 500 && code <= 599:
return interfaces.ErrTransient
default:
return nil
}
}
Loading
Loading