Skip to content

Commit

Permalink
dbaas: database management for mysql, pg
Browse files Browse the repository at this point in the history
  • Loading branch information
tgrondier committed Jan 9, 2025
1 parent bb74bd1 commit a7af867
Show file tree
Hide file tree
Showing 12 changed files with 441 additions and 1 deletion.
14 changes: 14 additions & 0 deletions cmd/dbaas_database.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package cmd

import (
"github.com/spf13/cobra"
)

var dbaasDatabaseCmd = &cobra.Command{
Use: "database",
Short: "Manage DBaaS databases",
}

func init() {
dbaasCmd.AddCommand(dbaasDatabaseCmd)
}
72 changes: 72 additions & 0 deletions cmd/dbaas_database_create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package cmd

import (
"fmt"
"os"

"github.com/spf13/cobra"
)

type dbaasDatabaseCreateCmd struct {
cliCommandSettings `cli-cmd:"-"`

_ bool `cli-cmd:"create"`

Name string `cli-arg:"#"`
Database string `cli-arg:"#"`

HelpPg bool `cli-usage:"show usage for flags specific to the pg type"`
Zone string `cli-short:"z" cli-usage:"Database Service zone"`

// "pg" type specific flags
PgLcCollate string `cli-usage:"Default string sort order (LC_COLLATE) for PostgreSQL database" cli-hidden:""`
PgLcCtype string `cli-usage:"Default character classification (LC_CTYPE) for PostgreSQL database" cli-hidden:""`
}

func (c *dbaasDatabaseCreateCmd) cmdAliases() []string { return nil }

func (c *dbaasDatabaseCreateCmd) cmdShort() string { return "Create DBAAS database" }

func (c *dbaasDatabaseCreateCmd) cmdLong() string {
return `This command creates a DBAAS database for the specified service.`
}

func (c *dbaasDatabaseCreateCmd) cmdPreRun(cmd *cobra.Command, args []string) error {
switch {

case cmd.Flags().Changed("help-mysql"):
cmdShowHelpFlags(cmd.Flags(), "mysql-")
os.Exit(0)
case cmd.Flags().Changed("help-pg"):
cmdShowHelpFlags(cmd.Flags(), "pg-")
os.Exit(0)
}

cmdSetZoneFlagFromDefault(cmd)
return cliCommandDefaultPreRun(c, cmd, args)
}

func (c *dbaasDatabaseCreateCmd) cmdRun(cmd *cobra.Command, args []string) error {

ctx := gContext
db, err := dbaasGetV3(ctx, c.Name, c.Zone)
if err != nil {
return err
}

switch db.Type {
case "mysql":
return c.createMysql(cmd, args)
case "pg":
return c.createPg(cmd, args)
default:
return fmt.Errorf("creating database unsupported for service of type %q", db.Type)
}

}

func init() {
cobra.CheckErr(registerCLICommand(dbaasDatabaseCmd, &dbaasDatabaseCreateCmd{
cliCommandSettings: defaultCLICmdSettings(),
}))
}
55 changes: 55 additions & 0 deletions cmd/dbaas_database_create_mysql.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package cmd

import (
"fmt"

"github.com/exoscale/cli/pkg/account"
"github.com/exoscale/cli/pkg/globalstate"
exoapi "github.com/exoscale/egoscale/v2/api"
v3 "github.com/exoscale/egoscale/v3"
"github.com/spf13/cobra"
)

func (c dbaasDatabaseCreateCmd) createMysql(cmd *cobra.Command, _ []string) error {

ctx := gContext

client, err := switchClientZoneV3(ctx, globalstate.EgoscaleV3Client, v3.ZoneName(c.Zone))
if err != nil {
return err
}

s, err := client.GetDBAASServiceMysql(ctx, c.Name)
if err != nil {
return err
}

if s.State != "running" {
return fmt.Errorf("service %q is not ready for database creation", c.Name)
}

req := v3.CreateDBAASMysqlDatabaseRequest{
DatabaseName: v3.DBAASDatabaseName(c.Database),
}

op, err := client.CreateDBAASMysqlDatabase(ctx, c.Name, req)
if err != nil {
return err
}

decorateAsyncOperation(fmt.Sprintf("Creating DBaaS database %q", c.Database), func() {
op, err = client.Wait(ctx, op, v3.OperationStateSuccess)
})
if err != nil {
return err
}

if !globalstate.Quiet {
return c.outputFunc((&dbaasServiceShowCmd{
Name: c.Name,
Zone: c.Zone,
}).showDatabaseServiceMysql(exoapi.WithEndpoint(gContext, exoapi.NewReqEndpoint(account.CurrentAccount.Environment, c.Zone))))
}

return err
}
61 changes: 61 additions & 0 deletions cmd/dbaas_database_create_pg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package cmd

import (
"fmt"

"github.com/exoscale/cli/pkg/account"
"github.com/exoscale/cli/pkg/globalstate"
exoapi "github.com/exoscale/egoscale/v2/api"
v3 "github.com/exoscale/egoscale/v3"
"github.com/spf13/cobra"
)

func (c dbaasDatabaseCreateCmd) createPg(cmd *cobra.Command, _ []string) error {
ctx := gContext

client, err := switchClientZoneV3(ctx, globalstate.EgoscaleV3Client, v3.ZoneName(c.Zone))
if err != nil {
return err
}
s, err := client.GetDBAASServicePG(ctx, c.Name)
if err != nil {
return err
}

if s.State != "running" {
return fmt.Errorf("service %q is not ready for database creation", c.Name)
}

req := v3.CreateDBAASPGDatabaseRequest{
DatabaseName: v3.DBAASDatabaseName(c.Database),
}

if c.PgLcCollate != "" {
req.LCCollate = c.PgLcCollate
}

if c.PgLcCtype != "" {
req.LCCtype = c.PgLcCtype
}

op, err := client.CreateDBAASPGDatabase(ctx, c.Name, req)
if err != nil {
return err
}

decorateAsyncOperation(fmt.Sprintf("Creating DBaaS database %q", c.Database), func() {
op, err = client.Wait(ctx, op, v3.OperationStateSuccess)
})
if err != nil {
return err
}

if !globalstate.Quiet {
return c.outputFunc((&dbaasServiceShowCmd{
Name: c.Name,
Zone: c.Zone,
}).showDatabaseServicePG(exoapi.WithEndpoint(gContext, exoapi.NewReqEndpoint(account.CurrentAccount.Environment, c.Zone))))
}

return err
}
59 changes: 59 additions & 0 deletions cmd/dbaas_database_delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package cmd

import (
"fmt"

"github.com/spf13/cobra"
)

type dbaasDatabaseDeleteCmd struct {
cliCommandSettings `cli-cmd:"-"`

_ bool `cli-cmd:"delete"`

Name string `cli-arg:"#"`
Database string `cli-arg:"#"`

Zone string `cli-short:"z" cli-usage:"Database Service zone"`

Force bool `cli-short:"f" cli-usage:"don't prompt for confirmation"`
}

func (c *dbaasDatabaseDeleteCmd) cmdAliases() []string { return nil }

func (c *dbaasDatabaseDeleteCmd) cmdShort() string { return "Delete DBAAS database" }

func (c *dbaasDatabaseDeleteCmd) cmdLong() string {
return `This command deletes a DBAAS database for the specified service.`
}

func (c *dbaasDatabaseDeleteCmd) cmdPreRun(cmd *cobra.Command, args []string) error {

cmdSetZoneFlagFromDefault(cmd)
return cliCommandDefaultPreRun(c, cmd, args)
}

func (c *dbaasDatabaseDeleteCmd) cmdRun(cmd *cobra.Command, args []string) error {

ctx := gContext
db, err := dbaasGetV3(ctx, c.Name, c.Zone)
if err != nil {
return err
}

switch db.Type {
case "mysql":
return c.deleteMysql(cmd, args)
case "pg":
return c.deletePg(cmd, args)
default:
return fmt.Errorf("creating database unsupported for service of type %q", db.Type)
}

}

func init() {
cobra.CheckErr(registerCLICommand(dbaasDatabaseCmd, &dbaasDatabaseDeleteCmd{
cliCommandSettings: defaultCLICmdSettings(),
}))
}
64 changes: 64 additions & 0 deletions cmd/dbaas_database_delete_mysql.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package cmd

import (
"fmt"

"github.com/exoscale/cli/pkg/account"
"github.com/exoscale/cli/pkg/globalstate"
exoapi "github.com/exoscale/egoscale/v2/api"
v3 "github.com/exoscale/egoscale/v3"
"github.com/spf13/cobra"
)

func (c dbaasDatabaseDeleteCmd) deleteMysql(cmd *cobra.Command, _ []string) error {
ctx := gContext

client, err := switchClientZoneV3(ctx, globalstate.EgoscaleV3Client, v3.ZoneName(c.Zone))
if err != nil {
return err
}

s, err := client.GetDBAASServiceMysql(ctx, c.Name)
if err != nil {
return err
}

dbFound := false
for _, db := range s.Databases {
if db == v3.DBAASMysqlDatabaseName(c.Database) {
dbFound = true
break
}
}

if !dbFound {
return fmt.Errorf("database %q not found for service %q", c.Database, c.Name)
}
if !c.Force {
if !askQuestion(fmt.Sprintf(
"Are you sure you want to delete database %q", c.Database)) {
return nil
}
}

op, err := client.DeleteDBAASMysqlDatabase(ctx, c.Name, c.Database)
if err != nil {
return err
}

decorateAsyncOperation(fmt.Sprintf("Deleting DBaaS database %q", c.Database), func() {
op, err = client.Wait(ctx, op, v3.OperationStateSuccess)
})
if err != nil {
return err
}

if !globalstate.Quiet {
return c.outputFunc((&dbaasServiceShowCmd{
Name: c.Name,
Zone: c.Zone,
}).showDatabaseServiceMysql(exoapi.WithEndpoint(gContext, exoapi.NewReqEndpoint(account.CurrentAccount.Environment, c.Zone))))
}

return err
}
64 changes: 64 additions & 0 deletions cmd/dbaas_database_delete_pg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package cmd

import (
"fmt"

"github.com/exoscale/cli/pkg/account"
"github.com/exoscale/cli/pkg/globalstate"
exoapi "github.com/exoscale/egoscale/v2/api"
v3 "github.com/exoscale/egoscale/v3"
"github.com/spf13/cobra"
)

func (c dbaasDatabaseDeleteCmd) deletePg(cmd *cobra.Command, _ []string) error {
ctx := gContext

client, err := switchClientZoneV3(ctx, globalstate.EgoscaleV3Client, v3.ZoneName(c.Zone))
if err != nil {
return err
}

s, err := client.GetDBAASServicePG(ctx, c.Name)
if err != nil {
return err
}

dbFound := false
for _, db := range s.Databases {
if db == v3.DBAASDatabaseName(c.Database) {
dbFound = true
break
}
}

if !dbFound {
return fmt.Errorf("database %q not found for service %q", c.Database, c.Name)
}
if !c.Force {
if !askQuestion(fmt.Sprintf(
"Are you sure you want to delete database %q", c.Database)) {
return nil
}
}

op, err := client.DeleteDBAASPGDatabase(ctx, c.Name, c.Database)
if err != nil {
return err
}

decorateAsyncOperation(fmt.Sprintf("Deleting DBaaS database %q", c.Database), func() {
op, err = client.Wait(ctx, op, v3.OperationStateSuccess)
})
if err != nil {
return err
}

if !globalstate.Quiet {
return c.outputFunc((&dbaasServiceShowCmd{
Name: c.Name,
Zone: c.Zone,
}).showDatabaseServicePG(exoapi.WithEndpoint(gContext, exoapi.NewReqEndpoint(account.CurrentAccount.Environment, c.Zone))))
}

return err
}
Loading

0 comments on commit a7af867

Please sign in to comment.