From 9a7a1f5860a84e01525adcd1f51b0a52ba2d89d9 Mon Sep 17 00:00:00 2001 From: Vishal Anarase Date: Mon, 18 Mar 2024 14:37:34 +0530 Subject: [PATCH] Add support to get and delete database backup Signed-off-by: Vishal Anarase --- cmd/database/database_backup.go | 2 + cmd/database/database_backup_create.go | 10 ++- cmd/database/database_backup_delete.go | 108 +++++++++++++++++++++++++ cmd/database/database_backup_list.go | 20 +++-- cmd/database/database_backup_show.go | 70 ++++++++++++++++ cmd/database/database_backup_update.go | 2 +- cmd/database/database_delete.go | 17 ++-- cmd/database/database_restore.go | 15 ++-- go.mod | 2 +- go.sum | 4 +- 10 files changed, 222 insertions(+), 28 deletions(-) create mode 100644 cmd/database/database_backup_delete.go create mode 100644 cmd/database/database_backup_show.go diff --git a/cmd/database/database_backup.go b/cmd/database/database_backup.go index 5d3b0360..2ea5bdfb 100644 --- a/cmd/database/database_backup.go +++ b/cmd/database/database_backup.go @@ -27,6 +27,8 @@ func init() { dbBackupCmd.AddCommand(dbBackupCreateCmd) dbBackupCmd.AddCommand(dbBackupListCmd) dbBackupCmd.AddCommand(dbBackupUpdateCmd) + dbBackupCmd.AddCommand(dbBackupShowCmd) + dbBackupCmd.AddCommand(dbBackupDeleteCmd) // Create cmd options dbBackupCreateCmd.Flags().StringVarP(&name, "name", "n", "", "name of the database backup") diff --git a/cmd/database/database_backup_create.go b/cmd/database/database_backup_create.go index 80362150..3c8f4ee6 100644 --- a/cmd/database/database_backup_create.go +++ b/cmd/database/database_backup_create.go @@ -15,8 +15,8 @@ import ( var dbBackupCreateCmd = &cobra.Command{ Use: "create", Aliases: []string{"new", "add"}, - Example: `Scheduled: civo database backup create --name --schedule \n - Manual: civo database backup create --name --type manual`, + Example: ` Scheduled: civo database backup create --name --schedule + Manual: civo database backup create --name --type manual`, Short: "Create a new database backup", Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { @@ -39,6 +39,11 @@ var dbBackupCreateCmd = &cobra.Command{ os.Exit(1) } + if name == "" { + utility.Error("Name must be specified") + os.Exit(1) + } + db, err := client.FindDatabase(args[0]) if err != nil { utility.Error("Database %s", err) @@ -91,6 +96,7 @@ var dbBackupCreateCmd = &cobra.Command{ "database_name": bk.DatabaseName, "software": bk.Software, "name": name, + "id": bk.ID, }) } diff --git a/cmd/database/database_backup_delete.go b/cmd/database/database_backup_delete.go new file mode 100644 index 00000000..a6dfc6ab --- /dev/null +++ b/cmd/database/database_backup_delete.go @@ -0,0 +1,108 @@ +package database + +import ( + "errors" + "fmt" + "strings" + + pluralize "github.com/alejandrojnm/go-pluralize" + "github.com/civo/civogo" + "github.com/civo/cli/common" + "github.com/civo/cli/config" + "github.com/civo/cli/utility" + + "os" + + "github.com/spf13/cobra" +) + +var backupList []utility.ObjecteList +var dbBackupDeleteCmd = &cobra.Command{ + Use: "delete", + Aliases: []string{"rm", "remove", "destroy"}, + Short: "Delete a manual database backup", + Example: "civo database backup delete ", + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + utility.EnsureCurrentRegion() + + client, err := config.CivoAPIClient() + if err != nil { + utility.Error("Creating the connection to Civo's API failed with %s", err) + os.Exit(1) + } + + if common.RegionSet != "" { + client.Region = common.RegionSet + } + + if len(args) == 2 { + bk, err := client.FindDatabaseBackup(args[0], args[1]) + if err != nil { + if errors.Is(err, civogo.ZeroMatchesError) { + utility.Error("sorry there is no %s Database in your account", utility.Red(args[0])) + os.Exit(1) + } + if errors.Is(err, civogo.MultipleMatchesError) { + utility.Error("sorry we found more than one database with that name in your account") + os.Exit(1) + } + } + backupList = append(backupList, utility.ObjecteList{ID: bk.ID, Name: bk.Name}) + } else { + for idx, v := range args { + if idx == 0 { + continue + } + bk, err := client.FindDatabaseBackup(args[0], v) + if err == nil { + backupList = append(backupList, utility.ObjecteList{ID: bk.ID, Name: bk.Name}) + } + } + } + + dbNameList := []string{} + for _, v := range backupList { + dbNameList = append(dbNameList, v.Name) + } + + if utility.UserConfirmedDeletion(pluralize.Pluralize(len(backupList), "Database Backup"), common.DefaultYes, strings.Join(dbNameList, ", ")) { + + for _, v := range backupList { + db, err := client.FindDatabaseBackup(args[0], v.ID) + if err != nil { + utility.Error("%s", err) + os.Exit(1) + } + _, err = client.DeleteDatabaseBackup(args[0], db.ID) + if err != nil { + utility.Error("Error deleting the Database backup: %s", err) + os.Exit(1) + } + } + + ow := utility.NewOutputWriter() + + for _, v := range backupList { + ow.StartLine() + ow.AppendDataWithLabel("id", v.ID, "ID") + ow.AppendDataWithLabel("backup", v.Name, "Backup") + } + + switch common.OutputFormat { + case "json": + if len(backupList) == 1 { + ow.WriteSingleObjectJSON(common.PrettySet) + } else { + ow.WriteMultipleObjectsJSON(common.PrettySet) + } + case "custom": + ow.WriteCustomOutput(common.OutputFields) + default: + fmt.Printf("The %s (%s) has been deleted\n", pluralize.Pluralize(len(backupList), "database backup"), utility.Green(strings.Join(dbNameList, ", "))) + } + } else { + fmt.Println("Operation aborted") + } + }, +} diff --git a/cmd/database/database_backup_list.go b/cmd/database/database_backup_list.go index 9dbd3123..db2bf7f0 100644 --- a/cmd/database/database_backup_list.go +++ b/cmd/database/database_backup_list.go @@ -61,14 +61,14 @@ func postgresScheduledBackups(backups *civogo.PaginatedDatabaseBackup) { } printMsg = true ow.StartLine() + ow.AppendDataWithLabel("name", bk.Name, "Name") + ow.AppendDataWithLabel("schedule", bk.Schedule, "Schedule") + ow.AppendDataWithLabel("database_id", utility.TrimID(bk.DatabaseID), "Database ID") ow.AppendDataWithLabel("database_name", bk.DatabaseName, "Database Name") ow.AppendDataWithLabel("software", bk.Software, "Software") - ow.AppendDataWithLabel("schedule", bk.Schedule, "Schedule") - ow.AppendDataWithLabel("backup_name", bk.Name, "Backup Name") - - ow.AppendDataWithLabel("backup", bk.Backup, "Backup") + ow.AppendDataWithLabel("status", bk.Status, "Status") if common.OutputFormat == "json" || common.OutputFormat == "custom" { ow.AppendDataWithLabel("database_id", bk.DatabaseID, "Database ID") @@ -97,13 +97,17 @@ func postgresManualBackups(backups *civogo.PaginatedDatabaseBackup) { } printMsg = true ow.StartLine() + ow.AppendDataWithLabel("id", utility.TrimID(bk.ID), "ID") + ow.AppendDataWithLabel("name", bk.Name, "Name") + ow.AppendDataWithLabel("database_id", utility.TrimID(bk.DatabaseID), "Database ID") ow.AppendDataWithLabel("database_name", bk.DatabaseName, "Database Name") ow.AppendDataWithLabel("software", bk.Software, "Software") - ow.AppendDataWithLabel("backup", bk.Backup, "Backup") + ow.AppendDataWithLabel("status", bk.Status, "Status") if common.OutputFormat == "json" || common.OutputFormat == "custom" { + ow.AppendDataWithLabel("id", bk.ID, "ID") ow.AppendDataWithLabel("database_id", bk.DatabaseID, "Database ID") } } @@ -127,18 +131,18 @@ func mysqlBackups(backups *civogo.PaginatedDatabaseBackup) { for _, bk := range backups.Items { printMsg = true ow.StartLine() + ow.AppendDataWithLabel("id", utility.TrimID(bk.ID), "ID") + ow.AppendDataWithLabel("name", bk.Name, "Name") + ow.AppendDataWithLabel("database_id", utility.TrimID(bk.DatabaseID), "Database ID") ow.AppendDataWithLabel("database_name", bk.DatabaseName, "Database Name") - ow.AppendDataWithLabel("backup_id", utility.TrimID(bk.ID), "Backup ID") - ow.AppendDataWithLabel("backup_name", bk.Name, "Backup Name") ow.AppendDataWithLabel("software", bk.Software, "Software") ow.AppendDataWithLabel("status", bk.Status, "Status") if common.OutputFormat == "json" || common.OutputFormat == "custom" { ow.AppendDataWithLabel("id", bk.ID, "ID") ow.AppendDataWithLabel("database_id", bk.DatabaseID, "Database ID") - ow.AppendDataWithLabel("database_name", bk.DatabaseName, "Database Name") } } diff --git a/cmd/database/database_backup_show.go b/cmd/database/database_backup_show.go new file mode 100644 index 00000000..a7697f2a --- /dev/null +++ b/cmd/database/database_backup_show.go @@ -0,0 +1,70 @@ +package database + +import ( + "os" + + "github.com/civo/cli/common" + "github.com/civo/cli/config" + "github.com/civo/cli/utility" + "github.com/spf13/cobra" +) + +var dbBackupShowCmd = &cobra.Command{ + Use: "show", + Example: `civo database backup show `, + Aliases: []string{"get", "inspect"}, + Args: cobra.MinimumNArgs(2), + Short: "Show details of a database backup", + Run: func(cmd *cobra.Command, args []string) { + utility.EnsureCurrentRegion() + + client, err := config.CivoAPIClient() + if common.RegionSet != "" { + client.Region = common.RegionSet + } + if err != nil { + utility.Error("Creating the connection to Civo's API failed with %s", err) + os.Exit(1) + } + + if common.RegionSet != "" { + client.Region = common.RegionSet + } + + bk, err := client.GetDatabaseBackup(args[0], args[1]) + if err != nil { + utility.Error("Database backup %s", err) + os.Exit(1) + } + + ow := utility.NewOutputWriter() + + ow.StartLine() + + if !bk.IsScheduled { + ow.AppendDataWithLabel("id", utility.TrimID(bk.ID), "ID") + } + ow.AppendDataWithLabel("name", bk.Name, "Name") + ow.AppendDataWithLabel("schedule", bk.Schedule, "Schedule") + + ow.AppendDataWithLabel("database_id", utility.TrimID(bk.DatabaseID), "Database ID") + ow.AppendDataWithLabel("database_name", bk.DatabaseName, "Database Name") + + ow.AppendDataWithLabel("software", bk.Software, "Software") + ow.AppendDataWithLabel("status", bk.Status, "Status") + + if common.OutputFormat == "json" || common.OutputFormat == "custom" { + ow.AppendDataWithLabel("id", bk.ID, "ID") + ow.AppendDataWithLabel("database_id", bk.DatabaseID, "Database ID") + } + + switch common.OutputFormat { + case "json": + ow.WriteMultipleObjectsJSON(common.PrettySet) + case "custom": + ow.WriteCustomOutput(common.OutputFields) + default: + ow.WriteKeyValues() + } + }, +} diff --git a/cmd/database/database_backup_update.go b/cmd/database/database_backup_update.go index 46c2f0bd..e3d0abf1 100644 --- a/cmd/database/database_backup_update.go +++ b/cmd/database/database_backup_update.go @@ -15,7 +15,7 @@ var dbBackupUpdateCmd = &cobra.Command{ Use: "update", Aliases: []string{"modify", "change"}, Short: "Update a scheduled database backup", - Example: "civo database backup update --name --schedule ", + Example: "civo database backup update --name --schedule ", Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { utility.EnsureCurrentRegion() diff --git a/cmd/database/database_delete.go b/cmd/database/database_delete.go index 63565bb7..1ea1e66b 100644 --- a/cmd/database/database_delete.go +++ b/cmd/database/database_delete.go @@ -16,7 +16,6 @@ import ( "github.com/spf13/cobra" ) -var databaseList []utility.ObjecteList var dbDeleteCmd = &cobra.Command{ Use: "delete", Aliases: []string{"rm", "remove", "destroy"}, @@ -48,24 +47,24 @@ var dbDeleteCmd = &cobra.Command{ os.Exit(1) } } - databaseList = append(databaseList, utility.ObjecteList{ID: db.ID, Name: db.Name}) + backupList = append(backupList, utility.ObjecteList{ID: db.ID, Name: db.Name}) } else { for _, v := range args { db, err := client.FindDatabase(v) if err == nil { - databaseList = append(databaseList, utility.ObjecteList{ID: db.ID, Name: db.Name}) + backupList = append(backupList, utility.ObjecteList{ID: db.ID, Name: db.Name}) } } } dbNameList := []string{} - for _, v := range databaseList { + for _, v := range backupList { dbNameList = append(dbNameList, v.Name) } - if utility.UserConfirmedDeletion(pluralize.Pluralize(len(databaseList), "Database"), common.DefaultYes, strings.Join(dbNameList, ", ")) { + if utility.UserConfirmedDeletion(pluralize.Pluralize(len(backupList), "Database"), common.DefaultYes, strings.Join(dbNameList, ", ")) { - for _, v := range databaseList { + for _, v := range backupList { db, err := client.FindDatabase(v.ID) if err != nil { utility.Error("%s", err) @@ -80,7 +79,7 @@ var dbDeleteCmd = &cobra.Command{ ow := utility.NewOutputWriter() - for _, v := range databaseList { + for _, v := range backupList { ow.StartLine() ow.AppendDataWithLabel("id", v.ID, "ID") ow.AppendDataWithLabel("database", v.Name, "Database") @@ -88,7 +87,7 @@ var dbDeleteCmd = &cobra.Command{ switch common.OutputFormat { case "json": - if len(databaseList) == 1 { + if len(backupList) == 1 { ow.WriteSingleObjectJSON(common.PrettySet) } else { ow.WriteMultipleObjectsJSON(common.PrettySet) @@ -96,7 +95,7 @@ var dbDeleteCmd = &cobra.Command{ case "custom": ow.WriteCustomOutput(common.OutputFields) default: - fmt.Printf("The %s (%s) has been deleted\n", pluralize.Pluralize(len(databaseList), "database"), utility.Green(strings.Join(dbNameList, ", "))) + fmt.Printf("The %s (%s) has been deleted\n", pluralize.Pluralize(len(backupList), "database"), utility.Green(strings.Join(dbNameList, ", "))) } } else { fmt.Println("Operation aborted") diff --git a/cmd/database/database_restore.go b/cmd/database/database_restore.go index 55c501c8..0f10f228 100644 --- a/cmd/database/database_restore.go +++ b/cmd/database/database_restore.go @@ -43,16 +43,21 @@ var dbRestoreCmd = &cobra.Command{ os.Exit(1) } + bk, err := client.GetDatabaseBackup(args[0], backup) + if err != nil { + utility.Error("Database backup %s", err) + os.Exit(1) + } + if utility.UserConfirmedRestore(db.Name, common.DefaultYes, backup) { config := &civogo.RestoreDatabaseRequest{ - Software: db.Software, - Name: restoreName, - Backup: backup, - Region: client.Region, + Name: restoreName, + Backup: bk.Name, + Region: client.Region, } _, err = client.RestoreDatabase(db.ID, config) if err != nil { - utility.Error("%s", err) + utility.Error("Failed to restore %s", err) os.Exit(1) } ow := utility.NewOutputWriter() diff --git a/go.mod b/go.mod index 3345340f..a68ccd5c 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect github.com/briandowns/spinner v1.11.1 github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c // indirect - github.com/civo/civogo v0.3.63 + github.com/civo/civogo v0.3.64 github.com/dsnet/compress v0.0.1 // indirect github.com/fatih/color v1.13.0 // indirect github.com/google/go-github v17.0.0+incompatible // indirect diff --git a/go.sum b/go.sum index f28825d1..92f4443c 100644 --- a/go.sum +++ b/go.sum @@ -54,8 +54,8 @@ github.com/briandowns/spinner v1.11.1/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c h1:aprLqMn7gSPT+vdDSl+/E6NLEuArwD/J7IWd8bJt5lQ= github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c/go.mod h1:Ie6SubJv/NTO9Q0UBH0QCl3Ve50lu9hjbi5YJUw03TE= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/civo/civogo v0.3.63 h1:C8ExiFCmZKQJXths1ShxlZOjUXDiUXTY6XoSlLNy8ws= -github.com/civo/civogo v0.3.63/go.mod h1:S/iYmGvQOraxdRtcXeq/2mVX01/ia2qfpQUp2SsTLKA= +github.com/civo/civogo v0.3.64 h1:dpkWSAa8ZoJfTriajrnKG9ASObUIPats3KtWHyzyUSc= +github.com/civo/civogo v0.3.64/go.mod h1:S/iYmGvQOraxdRtcXeq/2mVX01/ia2qfpQUp2SsTLKA= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=