From aba62396d4b9c859cb44386c3eeacdca87b8639e Mon Sep 17 00:00:00 2001 From: Daniel Weinshenker Date: Thu, 7 Dec 2023 17:31:46 -0800 Subject: [PATCH] Database Users: Update settings independent of other user settings --- .../database/resource_database_user.go | 12 +++++- .../database/resource_database_user_test.go | 41 ++++++++++++++++++- go.mod | 2 +- go.sum | 6 +-- .../github.com/digitalocean/godo/CHANGELOG.md | 10 +++++ .../github.com/digitalocean/godo/apps.gen.go | 24 +++++++++-- vendor/github.com/digitalocean/godo/apps.go | 2 + .../digitalocean/godo/apps_accessors.go | 24 +++++++++++ .../github.com/digitalocean/godo/databases.go | 22 +++++++++- vendor/github.com/digitalocean/godo/godo.go | 2 +- vendor/modules.txt | 2 +- 11 files changed, 133 insertions(+), 14 deletions(-) diff --git a/digitalocean/database/resource_database_user.go b/digitalocean/database/resource_database_user.go index 0e26e417f..9e4a9277e 100644 --- a/digitalocean/database/resource_database_user.go +++ b/digitalocean/database/resource_database_user.go @@ -88,13 +88,11 @@ func userACLSchema() *schema.Resource { "topic": { Type: schema.TypeString, Required: true, - ForceNew: true, ValidateFunc: validation.NoZeroValues, }, "permission": { Type: schema.TypeString, Required: true, - ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ "admin", "consume", @@ -211,6 +209,16 @@ func resourceDigitalOceanDatabaseUserUpdate(ctx context.Context, d *schema.Resou return diag.Errorf("Error updating mysql_auth_plugin for DatabaseUser: %s", err) } } + if d.HasChange("settings") { + updateReq := &godo.DatabaseUpdateUserRequest{} + if v, ok := d.GetOk("settings"); ok { + updateReq.Settings = expandUserSettings(v.([]interface{})) + } + _, _, err := client.Databases.UpdateUser(context.Background(), d.Get("cluster_id").(string), d.Get("name").(string), updateReq) + if err != nil { + return diag.Errorf("Error updating settings for DatabaseUser: %s", err) + } + } return resourceDigitalOceanDatabaseUserRead(ctx, d, meta) } diff --git a/digitalocean/database/resource_database_user_test.go b/digitalocean/database/resource_database_user_test.go index c9d5f210a..1a036379e 100644 --- a/digitalocean/database/resource_database_user_test.go +++ b/digitalocean/database/resource_database_user_test.go @@ -181,7 +181,6 @@ func TestAccDigitalOceanDatabaseUser_KafkaACLs(t *testing.T) { var databaseUser godo.DatabaseUser databaseClusterName := acceptance.RandomTestName() databaseUserName := acceptance.RandomTestName() - resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.TestAccPreCheck(t) }, ProviderFactories: acceptance.TestAccProviderFactories, @@ -224,6 +223,25 @@ func TestAccDigitalOceanDatabaseUser_KafkaACLs(t *testing.T) { "digitalocean_database_user.foobar_user", "settings.0.acl.3.permission", "consume"), ), }, + { + Config: fmt.Sprintf(testAccCheckDigitalOceanDatabaseUserConfigKafkaACLUpdate, databaseClusterName, databaseUserName), + Check: resource.ComposeTestCheckFunc( + testAccCheckDigitalOceanDatabaseUserExists("digitalocean_database_user.foobar_user", &databaseUser), + testAccCheckDigitalOceanDatabaseUserAttributes(&databaseUser, databaseUserName), + resource.TestCheckResourceAttr( + "digitalocean_database_user.foobar_user", "name", databaseUserName), + resource.TestCheckResourceAttrSet( + "digitalocean_database_user.foobar_user", "role"), + resource.TestCheckResourceAttrSet( + "digitalocean_database_user.foobar_user", "password"), + resource.TestCheckResourceAttrSet( + "digitalocean_database_user.foobar_user", "settings.0.acl.0.id"), + resource.TestCheckResourceAttr( + "digitalocean_database_user.foobar_user", "settings.0.acl.0.topic", "topic-1"), + resource.TestCheckResourceAttr( + "digitalocean_database_user.foobar_user", "settings.0.acl.0.permission", "produceconsume"), + ), + }, }, }) } @@ -445,6 +463,27 @@ resource "digitalocean_database_user" "foobar_user" { } }` +const testAccCheckDigitalOceanDatabaseUserConfigKafkaACLUpdate = ` +resource "digitalocean_database_cluster" "foobar" { + name = "%s" + engine = "kafka" + version = "3.5" + size = "db-s-2vcpu-2gb" + region = "nyc1" + node_count = 3 +} + +resource "digitalocean_database_user" "foobar_user" { + cluster_id = digitalocean_database_cluster.foobar.id + name = "%s" + settings { + acl { + topic = "topic-1" + permission = "produceconsume" + } + } +}` + const testAccCheckDigitalOceanDatabaseUserConfigMySQLAuthUpdate = ` resource "digitalocean_database_cluster" "foobar" { name = "%s" diff --git a/go.mod b/go.mod index 78d3df249..f1024540a 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.105.1 + github.com/digitalocean/godo v1.107.0 github.com/hashicorp/awspolicyequivalence v1.5.0 github.com/hashicorp/go-uuid v1.0.3 github.com/hashicorp/go-version v1.6.0 diff --git a/go.sum b/go.sum index b110d08e2..fc39c080a 100644 --- a/go.sum +++ b/go.sum @@ -25,10 +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.105.0 h1:bUfWVsyQCYZ7OQLK+p2EBFYWD5BoOgpyq/PMSQHEeMg= -github.com/digitalocean/godo v1.105.0/go.mod h1:R6EmmWI8CT1+fCtjWY9UCB+L5uufuZH13wk3YhxycCs= -github.com/digitalocean/godo v1.105.1 h1:3FjFDurw7po27Y0uHhdR+EvwNil06KCeu1Nx/0jZbmI= -github.com/digitalocean/godo v1.105.1/go.mod h1:R6EmmWI8CT1+fCtjWY9UCB+L5uufuZH13wk3YhxycCs= +github.com/digitalocean/godo v1.107.0 h1:P72IbmGFQvKOvyjVLyT59bmHxilA4E5hWi40rF4zNQc= +github.com/digitalocean/godo v1.107.0/go.mod h1:R6EmmWI8CT1+fCtjWY9UCB+L5uufuZH13wk3YhxycCs= 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 08458e75f..8177eb196 100644 --- a/vendor/github.com/digitalocean/godo/CHANGELOG.md +++ b/vendor/github.com/digitalocean/godo/CHANGELOG.md @@ -1,5 +1,15 @@ # Change Log +## [v1.107.0] - 2023-12-07 + +- #658 - @markusthoemmes - APPS-8033 Add the RUN_RESTARTED log type +- #656 - @dweinshenker - Enhancement: add database user update +- #657 - @markusthoemmes - apps: Add registry_credentials field, GHCR registry type and the egress spec + +## [v1.106.0] - 2023-11-14 + +- #654 - @dweinshenker - Remove unclean_leader_election_enable for topic configuration + ## [v1.105.1] - 2023-11-07 - #652 - @andrewsomething - Retry on HTTP/2 internal errors. diff --git a/vendor/github.com/digitalocean/godo/apps.gen.go b/vendor/github.com/digitalocean/godo/apps.gen.go index 8b01dbb7b..7ec24c334 100644 --- a/vendor/github.com/digitalocean/godo/apps.gen.go +++ b/vendor/github.com/digitalocean/godo/apps.gen.go @@ -244,6 +244,20 @@ const ( AppDomainSpecType_Alias AppDomainSpecType = "ALIAS" ) +// AppEgressSpec Specification for app egress configurations. +type AppEgressSpec struct { + Type AppEgressSpecType `json:"type,omitempty"` +} + +// AppEgressSpecType the model 'AppEgressSpecType' +type AppEgressSpecType string + +// List of AppEgressSpecType +const ( + APPEGRESSSPECTYPE_Autoassign AppEgressSpecType = "AUTOASSIGN" + APPEGRESSSPECTYPE_DedicatedIp AppEgressSpecType = "DEDICATED_IP" +) + // AppFunctionsSpec struct for AppFunctionsSpec type AppFunctionsSpec struct { // The name. Must be unique across all components within the same app. @@ -495,6 +509,7 @@ type AppSpec struct { // 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"` } @@ -1012,8 +1027,10 @@ type ImageSourceSpec struct { // The repository tag. Defaults to `latest` if not provided and no digest is provided. Cannot be specified if digest is provided. Tag string `json:"tag,omitempty"` // The image digest. Cannot be specified if tag is provided. - Digest string `json:"digest,omitempty"` - DeployOnPush *ImageSourceSpecDeployOnPush `json:"deploy_on_push,omitempty"` + Digest string `json:"digest,omitempty"` + // The credentials to be able to pull the image. The value will be encrypted on first submission. On following submissions, the encrypted value should be used. - \"$username:$access_token\" for registries of type `DOCKER_HUB`. - \"$username:$access_token\" for registries of type `GHCR`. + RegistryCredentials string `json:"registry_credentials,omitempty"` + DeployOnPush *ImageSourceSpecDeployOnPush `json:"deploy_on_push,omitempty"` } // ImageSourceSpecDeployOnPush struct for ImageSourceSpecDeployOnPush @@ -1022,7 +1039,7 @@ type ImageSourceSpecDeployOnPush struct { Enabled bool `json:"enabled,omitempty"` } -// ImageSourceSpecRegistryType - DOCR: The DigitalOcean container registry type. - DOCKER_HUB: The DockerHub container registry type. +// ImageSourceSpecRegistryType - DOCR: The DigitalOcean container registry type. - DOCKER_HUB: The DockerHub container registry type. - GHCR: The GitHub container registry type. type ImageSourceSpecRegistryType string // List of ImageSourceSpecRegistryType @@ -1030,6 +1047,7 @@ const ( ImageSourceSpecRegistryType_Unspecified ImageSourceSpecRegistryType = "UNSPECIFIED" ImageSourceSpecRegistryType_DOCR ImageSourceSpecRegistryType = "DOCR" ImageSourceSpecRegistryType_DockerHub ImageSourceSpecRegistryType = "DOCKER_HUB" + ImageSourceSpecRegistryType_Ghcr ImageSourceSpecRegistryType = "GHCR" ) // AppInstanceSize struct for AppInstanceSize diff --git a/vendor/github.com/digitalocean/godo/apps.go b/vendor/github.com/digitalocean/godo/apps.go index 422b48acc..880ce0921 100644 --- a/vendor/github.com/digitalocean/godo/apps.go +++ b/vendor/github.com/digitalocean/godo/apps.go @@ -21,6 +21,8 @@ const ( AppLogTypeDeploy AppLogType = "DEPLOY" // AppLogTypeRun represents run logs. AppLogTypeRun AppLogType = "RUN" + // AppLogTypeRunRestarted represents logs of crashed/restarted instances during runtime. + AppLogTypeRunRestarted AppLogType = "RUN_RESTARTED" ) // AppsService is an interface for interfacing with the App Platform endpoints diff --git a/vendor/github.com/digitalocean/godo/apps_accessors.go b/vendor/github.com/digitalocean/godo/apps_accessors.go index 486c75973..059d64731 100644 --- a/vendor/github.com/digitalocean/godo/apps_accessors.go +++ b/vendor/github.com/digitalocean/godo/apps_accessors.go @@ -757,6 +757,14 @@ func (a *AppDomainValidation) GetTXTValue() string { return a.TXTValue } +// GetType returns the Type field. +func (a *AppEgressSpec) GetType() AppEgressSpecType { + if a == nil { + return "" + } + return a.Type +} + // GetAlerts returns the Alerts field. func (a *AppFunctionsSpec) GetAlerts() []*AppAlertSpec { if a == nil { @@ -1733,6 +1741,14 @@ func (a *AppSpec) GetDomains() []*AppDomainSpec { return a.Domains } +// GetEgress returns the Egress field. +func (a *AppSpec) GetEgress() *AppEgressSpec { + if a == nil { + return nil + } + return a.Egress +} + // GetEnvs returns the Envs field. func (a *AppSpec) GetEnvs() []*AppVariableDefinition { if a == nil { @@ -3189,6 +3205,14 @@ func (i *ImageSourceSpec) GetRegistry() string { return i.Registry } +// GetRegistryCredentials returns the RegistryCredentials field. +func (i *ImageSourceSpec) GetRegistryCredentials() string { + if i == nil { + return "" + } + return i.RegistryCredentials +} + // GetRegistryType returns the RegistryType field. func (i *ImageSourceSpec) GetRegistryType() ImageSourceSpecRegistryType { if i == nil { diff --git a/vendor/github.com/digitalocean/godo/databases.go b/vendor/github.com/digitalocean/godo/databases.go index 4b3749978..54d80e99b 100644 --- a/vendor/github.com/digitalocean/godo/databases.go +++ b/vendor/github.com/digitalocean/godo/databases.go @@ -118,6 +118,7 @@ type DatabasesService interface { GetUser(context.Context, string, string) (*DatabaseUser, *Response, error) ListUsers(context.Context, string, *ListOptions) ([]DatabaseUser, *Response, error) CreateUser(context.Context, string, *DatabaseCreateUserRequest) (*DatabaseUser, *Response, error) + UpdateUser(context.Context, string, string, *DatabaseUpdateUserRequest) (*DatabaseUser, *Response, error) DeleteUser(context.Context, string, string) (*Response, error) ResetUserAuth(context.Context, string, string, *DatabaseResetUserAuthRequest) (*DatabaseUser, *Response, error) ListDBs(context.Context, string, *ListOptions) ([]DatabaseDB, *Response, error) @@ -347,7 +348,6 @@ type TopicConfig struct { SegmentIndexBytes *uint64 `json:"segment_index_bytes,omitempty"` SegmentJitterMS *uint64 `json:"segment_jitter_ms,omitempty"` SegmentMS *uint64 `json:"segment_ms,omitempty"` - UncleanLeaderElectionEnable *bool `json:"unclean_leader_election_enable,omitempty"` } // DatabaseCreateTopicRequest is used to create a new topic within a kafka cluster @@ -413,6 +413,11 @@ type DatabaseCreateUserRequest struct { Settings *DatabaseUserSettings `json:"settings,omitempty"` } +// DatabaseUpdateUserRequest is used to update an existing database user +type DatabaseUpdateUserRequest struct { + Settings *DatabaseUserSettings `json:"settings,omitempty"` +} + // DatabaseResetUserAuthRequest is used to reset a users DB auth type DatabaseResetUserAuthRequest struct { MySQLSettings *DatabaseMySQLUserSettings `json:"mysql_settings,omitempty"` @@ -871,6 +876,21 @@ func (svc *DatabasesServiceOp) CreateUser(ctx context.Context, databaseID string return root.User, resp, nil } +// UpdateUser will update an existing database user +func (svc *DatabasesServiceOp) UpdateUser(ctx context.Context, databaseID, userID string, updateUser *DatabaseUpdateUserRequest) (*DatabaseUser, *Response, error) { + path := fmt.Sprintf(databaseUserPath, databaseID, userID) + req, err := svc.client.NewRequest(ctx, http.MethodPut, path, updateUser) + if err != nil { + return nil, nil, err + } + root := new(databaseUserRoot) + resp, err := svc.client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + return root.User, resp, nil +} + // ResetUserAuth will reset user authentication func (svc *DatabasesServiceOp) ResetUserAuth(ctx context.Context, databaseID, userID string, resetAuth *DatabaseResetUserAuthRequest) (*DatabaseUser, *Response, error) { path := fmt.Sprintf(databaseResetUserAuthPath, databaseID, userID) diff --git a/vendor/github.com/digitalocean/godo/godo.go b/vendor/github.com/digitalocean/godo/godo.go index ee0ff2bec..e73738976 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.105.1" + libraryVersion = "1.107.0" defaultBaseURL = "https://api.digitalocean.com/" userAgent = "godo/" + libraryVersion mediaType = "application/json" diff --git a/vendor/modules.txt b/vendor/modules.txt index fd2555e09..ee96b6914 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.105.1 +# github.com/digitalocean/godo v1.107.0 ## explicit; go 1.20 github.com/digitalocean/godo github.com/digitalocean/godo/metrics