Skip to content

Commit

Permalink
Merge pull request #361 from civo/mysql-manual-backup-restore
Browse files Browse the repository at this point in the history
Add support for mysql backup and restore
  • Loading branch information
vishalanarase authored Feb 1, 2024
2 parents 8995e3d + 0178a30 commit 5fe8a51
Show file tree
Hide file tree
Showing 11 changed files with 350 additions and 128 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ temporal*
.DS*
get.sh
.vscode
staging.civo.json
112 changes: 70 additions & 42 deletions README.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions cmd/database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,7 @@ func init() {
dbUpdateCmd.Flags().StringVarP(&updatedName, "name", "n", "", "the new name for the database")

dbRestoreCmd.Flags().StringVarP(&backup, "backup", "b", "", "the backup name which you can restore database")
dbRestoreCmd.Flags().StringVarP(&restoreName, "name", "n", "", "name of the restore")
dbRestoreCmd.MarkFlagRequired("backup")
dbRestoreCmd.MarkFlagRequired("name")
}
3 changes: 0 additions & 3 deletions cmd/database/database_backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
)

var name, schedule, backupType string
var count int

// dbBackupCmd is the root command for the db backup subcommand
var dbBackupCmd = &cobra.Command{
Expand All @@ -32,13 +31,11 @@ func init() {
// Create cmd options
dbBackupCreateCmd.Flags().StringVarP(&name, "name", "n", "", "name of the database backup")
dbBackupCreateCmd.Flags().StringVarP(&schedule, "schedule", "s", "", "schedule of the database backup in the form of cronjob")
dbBackupCreateCmd.Flags().IntVarP(&count, "count", "c", 1, "number of backups to keep")
dbBackupCreateCmd.Flags().StringVarP(&backupType, "type", "t", "scheduled", "set the type of database backup manual/scheduled")

dbBackupCreateCmd.MarkFlagRequired("name")

// Update cmd options
dbBackupUpdateCmd.Flags().StringVarP(&name, "name", "n", "", "name of the database backup")
dbBackupUpdateCmd.Flags().StringVarP(&schedule, "schedule", "s", "", "schedule of the database backup in the form of cronjob")
dbBackupUpdateCmd.Flags().IntVarP(&count, "count", "c", 0, "number of backups to keep")
}
14 changes: 3 additions & 11 deletions cmd/database/database_backup_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
var dbBackupCreateCmd = &cobra.Command{
Use: "create",
Aliases: []string{"new", "add"},
Example: `Scheduled: civo database backup create <DATABASE-NAME/ID> --name <BACKUP_NAME> --schedule <SCHEDULE> --count <COUNT>\n
Example: `Scheduled: civo database backup create <DATABASE-NAME/ID> --name <BACKUP_NAME> --schedule <SCHEDULE>\n
Manual: civo database backup create <DATABASE-NAME/ID> --name <BACKUP_NAME> --type manual`,
Short: "Create a new database backup",
Args: cobra.MinimumNArgs(1),
Expand Down Expand Up @@ -51,11 +51,6 @@ var dbBackupCreateCmd = &cobra.Command{
client.Region = common.RegionSet
}

if count <= 0 {
utility.Error("Count must be greater than zero, you have given: %d", count)
os.Exit(1)
}

if schedule == "" {
utility.Error("Schedule must be specified")
os.Exit(1)
Expand All @@ -69,8 +64,6 @@ var dbBackupCreateCmd = &cobra.Command{

backupCreateConfig.Name = name
backupCreateConfig.Schedule = schedule
backupCreateConfig.Count = int32(count)

} else {
backupCreateConfig.Name = name
backupCreateConfig.Type = backupType
Expand All @@ -89,9 +82,8 @@ var dbBackupCreateCmd = &cobra.Command{
"database_id": bk.DatabaseID,
"database_name": bk.DatabaseName,
"software": bk.Software,
"name": bk.Scheduled.Name,
"schedule": bk.Scheduled.Schedule,
"count": fmt.Sprintf("%d", count),
"name": bk.Name,
"schedule": bk.Schedule,
})
} else {
ow = utility.NewOutputWriterWithMap(map[string]string{
Expand Down
159 changes: 102 additions & 57 deletions cmd/database/database_backup_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package database
import (
"fmt"
"os"
"strings"

"github.com/civo/civogo"
"github.com/civo/cli/common"
"github.com/civo/cli/config"
"github.com/civo/cli/utility"
Expand Down Expand Up @@ -42,70 +42,115 @@ var dbBackupListCmd = &cobra.Command{
os.Exit(1)
}

if backups.DatabaseID == "" {
return
switch db.Software {
case "PostgreSQL":
postgresScheduledBackups(backups)
postgresManualBackups(backups)
case "MySQL":
mysqlBackups(backups)
}
},
}

func postgresScheduledBackups(backups *civogo.PaginatedDatabaseBackup) {
ow := utility.NewOutputWriter()
printMsg := false
for _, bk := range backups.Items {
if !bk.IsScheduled {
continue
}
printMsg = true
ow.StartLine()
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")

if common.OutputFormat == "json" || common.OutputFormat == "custom" {
ow.AppendDataWithLabel("database_id", bk.DatabaseID, "Database ID")
}
}

switch common.OutputFormat {
case "json":
ow.WriteMultipleObjectsJSON(common.PrettySet)
case "custom":
ow.WriteCustomOutput(common.OutputFields)
default:
if printMsg {
fmt.Println("Scheduled backup")
}
ow.WriteTable()
}
}

func postgresManualBackups(backups *civogo.PaginatedDatabaseBackup) {
ow := utility.NewOutputWriter()
printMsg := false
for _, bk := range backups.Items {
if bk.IsScheduled {
continue
}
printMsg = true
ow.StartLine()
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")

odb := utility.NewOutputWriter()
ombk := utility.NewOutputWriter()
osbk := utility.NewOutputWriter()
mbk := ""
sbk := ""
isConfiguredScheduled := false
isConfiguredManual := false

odb.StartLine()
odb.AppendDataWithLabel("database_id", utility.TrimID(backups.DatabaseID), "Database ID")
odb.AppendDataWithLabel("database_name", backups.DatabaseName, "Database Name")
odb.AppendDataWithLabel("software", backups.Software, "Software")

if backups.Scheduled != nil {
isConfiguredScheduled = true
osbk.AppendDataWithLabel("name", backups.Scheduled.Name, "Backup Name")
osbk.AppendDataWithLabel("schedule", backups.Scheduled.Schedule, "Schedule")
osbk.AppendDataWithLabel("count", fmt.Sprintf("%d", backups.Scheduled.Count), "Count")

sbk = strings.TrimSuffix(strings.Join(backups.Scheduled.Backups, ","), ",")
osbk.AppendDataWithLabel("backups", sbk, "Backups")
if common.OutputFormat == "json" || common.OutputFormat == "custom" {
ow.AppendDataWithLabel("database_id", bk.DatabaseID, "Database ID")
}
}

if backups.Manual != nil {
isConfiguredManual = true
for i, m := range backups.Manual {
if i < len(backups.Manual)-1 {
mbk += m.Backup + ", "
} else {
mbk += m.Backup
}
}
ombk.AppendDataWithLabel("backups", mbk, "Backups")
switch common.OutputFormat {
case "json":
ow.WriteMultipleObjectsJSON(common.PrettySet)
case "custom":
ow.WriteCustomOutput(common.OutputFields)
default:
if printMsg {
fmt.Println("Manual backups")
}
ow.WriteTable()
}
}

func mysqlBackups(backups *civogo.PaginatedDatabaseBackup) {
ow := utility.NewOutputWriter()
printMsg := false
for _, bk := range backups.Items {
printMsg = true
ow.StartLine()
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" {
odb.AppendDataWithLabel("database_id", utility.TrimID(backups.DatabaseID), "Database ID")
odb.AppendDataWithLabel("database_name", backups.DatabaseName, "Database Name")
odb.AppendDataWithLabel("software", backups.Software, "Software")
odb.AppendDataWithLabel("schedule_backup_name", backups.Scheduled.Name, "Schedule Backup Name")
odb.AppendDataWithLabel("schedule", backups.Scheduled.Schedule, "Schedule")
odb.AppendDataWithLabel("count", fmt.Sprintf("%d", backups.Scheduled.Count), "Count")
odb.AppendDataWithLabel("scheduled_backups", sbk, "Schedule Backups")
odb.AppendDataWithLabel("manual_backups", mbk, "Manual Backups")
ow.AppendDataWithLabel("id", bk.ID, "ID")
ow.AppendDataWithLabel("database_id", bk.DatabaseID, "Database ID")
ow.AppendDataWithLabel("database_name", bk.DatabaseName, "Database Name")
}
}

switch common.OutputFormat {
case "json":
odb.WriteMultipleObjectsJSON(common.PrettySet)
case "custom":
odb.WriteCustomOutput(common.OutputFields)
default:
if isConfiguredScheduled {
fmt.Println("Scheduled Backups:")
}
osbk.WriteTable()
if isConfiguredManual {
fmt.Println("Manual Backups:")
}
ombk.WriteTable()
switch common.OutputFormat {
case "json":
ow.WriteMultipleObjectsJSON(common.PrettySet)
case "custom":
ow.WriteCustomOutput(common.OutputFields)
default:
if printMsg {
fmt.Println("Manual backups")
}
},
ow.WriteTable()
}
}
16 changes: 6 additions & 10 deletions cmd/database/database_backup_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 <DATABASE-NAME/ID> --name <NEW_BACKUP-NAME> --schedule <SCHEDULE> --count <COUNT>",
Example: "civo database backup update <DATABASE-NAME/ID> --name <NEW_BACKUP-NAME> --schedule <SCHEDULE>",
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
utility.EnsureCurrentRegion()
Expand All @@ -30,8 +30,8 @@ var dbBackupUpdateCmd = &cobra.Command{
client.Region = common.RegionSet
}

if schedule == "" && count == 0 && name == "" {
utility.Error("Schedule, name or count must be specified")
if schedule == "" && name == "" {
utility.Error("Schedule, name must be specified")
os.Exit(1)
}

Expand All @@ -48,9 +48,6 @@ var dbBackupUpdateCmd = &cobra.Command{
if schedule != "" {
backupUpdateConfig.Schedule = schedule
}
if count >= 0 {
backupUpdateConfig.Count = int32(count)
}
if name != "" {
backupUpdateConfig.Name = name
}
Expand All @@ -69,17 +66,16 @@ var dbBackupUpdateCmd = &cobra.Command{
"database_id": bk.DatabaseID,
"database_name": bk.DatabaseName,
"software": bk.Software,
"name": bk.Scheduled.Name,
"schedule": bk.Scheduled.Schedule,
"count": fmt.Sprintf("%d", count),
"backup_name": bk.Name,
"schedule": bk.Schedule,
})
switch common.OutputFormat {
case "json":
ow.WriteSingleObjectJSON(common.PrettySet)
case "custom":
ow.WriteCustomOutput(common.OutputFields)
default:
fmt.Printf("Database backup (%s) for database %s has been update\n", utility.Green(bk.Scheduled.Name), utility.Green(bk.DatabaseName))
fmt.Printf("Database backup (%s) for database %s has been update\n", utility.Green(bk.Name), utility.Green(bk.DatabaseName))
}
},
}
8 changes: 6 additions & 2 deletions cmd/database/database_restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@ import (
"github.com/spf13/cobra"
)

var backup string
var (
backup string
restoreName string
)

var dbRestoreCmd = &cobra.Command{
Use: "restore",
Aliases: []string{"reset", "restores"},
Short: "Restore a database",
Example: "civo db restore <DATABASE-NAME/ID> --backup <BACKUP-NAME>",
Example: "civo db restore <DATABASE-NAME/ID> --name <RESTORE-NAME> --backup <BACKUP-NAME>",
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
utility.EnsureCurrentRegion()
Expand All @@ -43,6 +46,7 @@ var dbRestoreCmd = &cobra.Command{
if utility.UserConfirmedRestore(db.Name, common.DefaultYes, backup) {
config := &civogo.RestoreDatabaseRequest{
Software: db.Software,
Name: restoreName,
Backup: backup,
Region: client.Region,
}
Expand Down
Loading

0 comments on commit 5fe8a51

Please sign in to comment.