Skip to content

Commit

Permalink
databases: update connection pool (#1557)
Browse files Browse the repository at this point in the history
* db: add update pool command

* db: fix cmd, add basic tests

* db: fix conn pool cmds test

* db: add integration tests
  • Loading branch information
bentranter authored Jul 24, 2024
1 parent 8c01513 commit e508b13
Show file tree
Hide file tree
Showing 5 changed files with 441 additions and 2 deletions.
73 changes: 71 additions & 2 deletions commands/databases.go
Original file line number Diff line number Diff line change
Expand Up @@ -1107,6 +1107,19 @@ We recommend starting with a pool size of about half your available connections
"The name of the specific database within the database cluster", requiredOpt())
cmdDatabasePoolCreate.Example = `The following example creates a connection pool named ` + "`" + `example-pool` + "`" + ` for a database cluster with the ID ` + "`" + `ca9f591d-f38h-5555-a0ef-1c02d1d1e35` + "`" + `. The command uses the ` + "`" + `--size` + "`" + ` flag to set the pool size to 10 and sets the user to the database's default user: doctl databases pool create ca9f591d-f38h-5555-a0ef-1c02d1d1e35 example-pool --size 10`

cmdDatabasePoolUpdate := CmdBuilder(cmd, RunDatabasePoolUpdate,
"update <database-cluster-id> <pool-name>", "Update a connection pool for a database", `Updates the specified connection pool for the specified database cluster.`+getPoolDetails, Writer,
aliasOpt("u"),
)
AddStringFlag(cmdDatabasePoolUpdate, doctl.ArgDatabasePoolMode, "",
"transaction", "The pool mode for the connection pool, such as `session`, `transaction`, and `statement`")
AddIntFlag(cmdDatabasePoolUpdate, doctl.ArgSizeSlug, "", 0, "pool size")
AddStringFlag(cmdDatabasePoolUpdate, doctl.ArgDatabasePoolDBName, "", "",
"The name of the specific database within the database cluster")
AddStringFlag(cmdDatabasePoolUpdate, doctl.ArgDatabasePoolUserName, "", "",
"The username for the database user")
cmdDatabasePoolUpdate.Example = `The following example updates a connection pool named ` + "`" + `example-pool` + "`" + ` for a database cluster with the ID ` + "`" + `ca9f591d-f38h-5555-a0ef-1c02d1d1e35` + "`" + `. The command uses the ` + "`" + `--size` + "`" + ` flag to set the pool size to 10 and sets the user to the database's default user: doctl databases pool update ca9f591d-f38h-5555-a0ef-1c02d1d1e35 example-pool --size 10`

cmdDatabasePoolDelete := CmdBuilder(cmd, RunDatabasePoolDelete,
"delete <database-cluster-id> <pool-name>", "Delete a connection pool for a database", `Deletes the specified connection pool for the specified database cluster.`+getPoolDetails, Writer,
aliasOpt("rm"))
Expand Down Expand Up @@ -1202,6 +1215,62 @@ func buildDatabaseCreatePoolRequestFromArgs(c *CmdConfig) (*godo.DatabaseCreateP
return req, nil
}

// RunDatabasePoolUpdate updates a database pool.
func RunDatabasePoolUpdate(c *CmdConfig) error {
if len(c.Args) < 2 {
return doctl.NewMissingArgsErr(c.NS)
}

databaseID := c.Args[0]
poolName := c.Args[1]

pool, err := c.Databases().GetPool(databaseID, poolName)
if err != nil {
return err
}

req := &godo.DatabaseUpdatePoolRequest{}
size, err := c.Doit.GetInt(c.NS, doctl.ArgDatabasePoolSize)
if err != nil {
return err
}
if size != 0 {
req.Size = size
} else {
req.Size = pool.Size
}

db, err := c.Doit.GetString(c.NS, doctl.ArgDatabasePoolDBName)
if err != nil {
return err
}
if db != "" {
req.Database = db
} else {
req.Database = pool.Database
}

mode, err := c.Doit.GetString(c.NS, doctl.ArgDatabasePoolMode)
if err != nil {
return err
}
if mode != "" {
req.Mode = mode
} else {
req.Mode = pool.Mode
}

user, err := c.Doit.GetString(c.NS, doctl.ArgDatabasePoolUserName)
if err != nil {
return err
}
if user != "" {
req.User = user
}

return c.Databases().UpdatePool(databaseID, poolName, req)
}

// RunDatabasePoolDelete deletes a database pool
func RunDatabasePoolDelete(c *CmdConfig) error {
if len(c.Args) < 2 {
Expand Down Expand Up @@ -1992,7 +2061,7 @@ This command requires the ID of a database cluster, which you can retrieve by ca
databaseFirewallRulesTxt := `A comma-separated list of firewall rules, in ` + "`" + `type:value` + "`" + ` format.`

databaseFirewallUpdateDetails := `
Replace the firewall rules for a specified database. This command requires the ` + "`" + `--rule` + "`" + ` flag.
Replace the firewall rules for a specified database. This command requires the ` + "`" + `--rule` + "`" + ` flag.
You can configure multiple rules for the firewall by passing additional arguments in a comma-separated list with the ` + "`" + `--rule` + "`" + ` flag. Each rule passed using the ` + "`" + `--rule` + "`" + ` flag must be in a ` + "`" + `<type>:<value>` + "`" + ` format where:
` + "`" + `type` + "`" + ` is the type of resource that the firewall rule allows to access the database cluster. Possible values are: ` + "`" + `droplet` + "`" + `, ` + "`" + `k8s` + "`" + `, ` + "`" + `ip_addr` + "`" + `, ` + "`" + `tag` + "`" + `, ` + "`" + `app` + "`" + `
Expand All @@ -2001,7 +2070,7 @@ You can configure multiple rules for the firewall by passing additional argument

databaseFirewallAddDetails :=
`
Appends a single rule to the existing firewall rules of the specified database.
Appends a single rule to the existing firewall rules of the specified database.
This command requires the ` + "`" + `--rule` + "`" + ` flag specifying the resource or resources allowed to access the database cluster. The rule passed to the ` + "`" + `--rule` + "`" + ` flag must be in a <type>:<value> format where:
- ` + "`" + `type` + "`" + ` is the type of resource that the firewall rule allows to access the database cluster. Possible values are: ` + "`" + `droplet` + "`" + `, ` + "`" + `k8s", ` + "`" + `ip_addr` + "`" + `, ` + "`" + `tag` + "`" + `, ` + "`" + `app` + "`" + `
Expand Down
50 changes: 50 additions & 0 deletions commands/databases_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ func TestDatabasePoolCommand(t *testing.T) {
"list",
"get",
"create",
"update",
"delete",
)
}
Expand Down Expand Up @@ -1170,6 +1171,55 @@ func TestDatabasePoolCreate_InboundUser(t *testing.T) {
})
}

func TestDatabasePoolUpdate(t *testing.T) {
pool := *(testDBPool.DatabasePool)
pool.Connection = nil

r := &godo.DatabaseUpdatePoolRequest{
User: pool.User,
Mode: pool.Mode,
Size: pool.Size,
Database: pool.Database,
}

// Successful call
withTestClient(t, func(config *CmdConfig, tm *tcMocks) {
tm.databases.EXPECT().GetPool(testDBCluster.ID, pool.Name).Return(&do.DatabasePool{DatabasePool: &pool}, nil)
tm.databases.EXPECT().UpdatePool(testDBCluster.ID, pool.Name, r).Return(nil)

config.Args = append(config.Args, testDBCluster.ID, testDBPool.Name)
config.Doit.Set(config.NS, doctl.ArgDatabasePoolMode, testDBPool.Mode)
config.Doit.Set(config.NS, doctl.ArgDatabasePoolSize, testDBPool.Size)
config.Doit.Set(config.NS, doctl.ArgDatabasePoolDBName, testDBPool.Database)
config.Doit.Set(config.NS, doctl.ArgDatabasePoolUserName, testDBPool.User)

err := RunDatabasePoolUpdate(config)
assert.NoError(t, err)
})

// Error
withTestClient(t, func(config *CmdConfig, tm *tcMocks) {
tm.databases.EXPECT().GetPool(testDBCluster.ID, pool.Name).Return(&do.DatabasePool{
DatabasePool: &godo.DatabasePool{
User: pool.User,
Name: pool.Name,
Mode: pool.Mode,
Size: pool.Size,
Database: pool.Database,
},
}, nil)
tm.databases.EXPECT().UpdatePool(
testDBCluster.ID,
pool.Name,
gomock.AssignableToTypeOf(&godo.DatabaseUpdatePoolRequest{}),
).Return(errTest)

config.Args = append(config.Args, testDBCluster.ID, testDBPool.Name)
err := RunDatabasePoolUpdate(config)
assert.EqualError(t, err, "error")
})
}

func TestDatabasesPoolDelete(t *testing.T) {
// Successful
withTestClient(t, func(config *CmdConfig, tm *tcMocks) {
Expand Down
6 changes: 6 additions & 0 deletions do/databases.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ type DatabasesService interface {
ListPools(string) (DatabasePools, error)
CreatePool(string, *godo.DatabaseCreatePoolRequest) (*DatabasePool, error)
GetPool(string, string) (*DatabasePool, error)
UpdatePool(string, string, *godo.DatabaseUpdatePoolRequest) error
DeletePool(string, string) error

GetReplica(string, string) (*DatabaseReplica, error)
Expand Down Expand Up @@ -492,6 +493,11 @@ func (ds *databasesService) GetPool(databaseID, poolName string) (*DatabasePool,
return &DatabasePool{DatabasePool: p}, nil
}

func (ds *databasesService) UpdatePool(databaseID, poolName string, req *godo.DatabaseUpdatePoolRequest) error {
_, err := ds.client.Databases.UpdatePool(context.TODO(), databaseID, poolName, req)
return err
}

func (ds *databasesService) DeletePool(databaseID, poolName string) error {
_, err := ds.client.Databases.DeletePool(context.TODO(), databaseID, poolName)

Expand Down
14 changes: 14 additions & 0 deletions do/mocks/DatabasesService.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit e508b13

Please sign in to comment.