diff --git a/.gitignore b/.gitignore index c0304f60..f6de6c90 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ temporal* .DS* get.sh .vscode +staging.civo.json diff --git a/README.md b/README.md index 2c804136..674d9f5c 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ Civo CLI is a tool to manage your [Civo.com](https://www.civo.com) account from - [Domains and Domain Records](#domains-and-domain-records) - [Firewalls](#firewalls) - [Networks](#networks) +- [Database Backup and Restore](./doc/DTABASE_BACKUP_RESTORE.md) - [Object Stores](#object-stores) - [Object Store Credentials](#object-store-credentials) - [Load Balancers](#load-balancers) @@ -37,7 +38,7 @@ Civo CLI is a tool to manage your [Civo.com](https://www.civo.com) account from ## Set-up -Civo CLI is built with Go and distributed as binary files, available for multiple operating systems and downloadable from https://github.com/civo/cli/releases. +Civo CLI is built with Go and distributed as binary files, available for multiple operating systems and downloadable from . ### Installing on macOS @@ -59,38 +60,44 @@ curl -sL https://civo.com/get | sh Civo CLI is available to download on windows via Chocolatey and Scoop For installing via Chocolatey you need [Chocolatey](https://chocolatey.org/install) package manager installed on your PC. -- run the following command after confirming Chocolatey on your PC + +- run the following command after confirming Chocolatey on your PC + ``` choco install civo-cli - ``` + ``` + and it will install Civo CLI on your PC. For installing via Scoop you need [Scoop](https://scoop.sh/) installed as a package manager, then: -- add the extras bucket with + +- add the extras bucket with + ``` scoop bucket add extras ``` -- install civo with + +- install civo with + ``` scoop install civo ``` You will also, of course, need a Civo account, for which you can [register here](https://www.civo.com/signup). - ### Installing on Linux For Linux Civo CLI can be installed by various methods. -* Install via the direct shell script: +- Install via the direct shell script: ```sh curl -sL https://civo.com/get | sh ``` -* Install via the brew package manager, as shown in the above instructions for MacOS. +- Install via the brew package manager, as shown in the above instructions for MacOS. -* Install via wget, specifying the [release version](https://github.com/civo/cli/releases) you want. +- Install via wget, specifying the [release version](https://github.com/civo/cli/releases) you want. ***Note that the version in the example below may not be the latest. Specify the version based on the latest available if you are using this method.*** @@ -101,8 +108,7 @@ chmod +x civo mv ./civo /usr/local/bin/ ``` -* You can also build the binary, but make sure you have go installed, - +- You can also build the binary, but make sure you have go installed, ```sh git clone https://github.com/civo/cli.git @@ -112,11 +118,11 @@ cd .. cp -r cli $HOME export PATH="$HOME/cli:$PATH" ``` + With this, we have installed the Civo CLI successfully. Check it is working by running any of the following commands. **Note:** For the first time when you are running, make sure you set your current region. Check [Region](#region) for more information. - ### Running the Civo CLI tool and getting help To use the tool, simply run `civo` with your chosen options. You can find context-sensitive help for commands and their options by invoking the `help` or `-h` command: @@ -152,6 +158,7 @@ docker run -it --rm -v $HOME/.civo.json:/.civo.json -v $HOME/.kube/config:/root/ To make usage easier, an alias is recommended. Here's an example how to set one to the same command as would be used if installed directly on the system, and using the Docker image: Ubuntu etc: + ```sh alias civo="docker run -it --rm -v $HOME/.civo.json:/.civo.json civo/cli:latest" # Maybe put the above line in ~/.bash_profile or ~/.zshrc @@ -162,6 +169,7 @@ civo k8s list ``` For Fedora users: + ```sh alias civo="docker run -it --rm -v $HOME/.civo.json:/.civo.json:Z -v $HOME/.kube/config:$HOME/.kube/config:Z civo/cli:latest" ``` @@ -340,6 +348,7 @@ $ civo size ls +----------------+-------------+------------+-----+-------+-----+------------+ ```` + #### Viewing the Default User Password For an Instance You can view the default user's password for an instance by running `civo instance password ID/hostname` @@ -367,7 +376,6 @@ $ civo instance show api-demo.test -o custom -f public_ip The above example uses `-o` and `-f` to display only the IP address in the output. - #### Setting Firewalls Instances can make use of separately-configured firewalls. By default, an instance is created with default all port open firewall rules set. If you want to secure your instances more, so you will need to configure some rules (see [Firewalls](#firewalls) for more information). Once you have configured the rules you can check it by running `civo firewall ls` @@ -553,6 +561,7 @@ $ civo kubernetes list | 5604340f-caa3-4ac1-adb7-40c863fe5639 | falling-sunset | NYC1 | 2 | 1 | ACTIVE | +--------------------------------------+----------------+--------+-------+-------+--------+ ``` + #### Listing kubernetes sizes You can list all kubernetes sizes by running `civo kubernetes size`. @@ -587,29 +596,29 @@ You can create a cluster by running `civo kubernetes create` with a cluster name -t, --network string the name of the network to use in the creation (default "default") -n, --nodes int the number of nodes to create (the master also acts as a node). (default 3) -r, --remove-applications string optional, remove default application names shown by running 'civo kubernetes applications ls' - --save save the config + --save save the config -s, --size string the size of nodes to create. (default "g4s.kube.medium") - --switch switch context to newly-created cluster + --switch switch context to newly-created cluster -v, --version string the k3s version to use on the cluster. Defaults to the latest. Example - 'civo k3s create --version 1.21.2+k3s1' (default "latest") -w, --wait a simple flag (e.g. --wait) that will cause the CLI to spin and wait for the cluster to be ACTIVE ``` -*Note* -* The '--create-firewall' will open the ports 80,443 and 6443 in the firewall if '--firewall-rules' is not used. -* The '--create-firewall' and '--existing-firewall' flags are mutually exclusive. You can't use them together. -* The '--firewall-rules' flag need to be used with '--create-firewall'. -* The '--firewall-rules' flag can accept: - * You can pass 'all' to open all ports. - * An optional end port using 'start_port-end_port' format (e.g. 8000-8100) - * An optional CIDR notation (e.g. 0.0.0.0/0) - * When no CIDR notation is provided, the port will get 0.0.0.0/0 (open to public) as default CIDR notation - * When a CIDR notation is provided without slash and number segment, it will default to /32 - * Within a rule, you can use comma separator for multiple ports to have same CIDR notation - * To separate between rules, you can use semicolon symbol and wrap everything in double quotes (see below) - So the following would all be valid: - * "80,443,6443:0.0.0.0/0;8080:1.2.3.4" (open 80,443,6443 to public and 8080 just for 1.2.3.4/32) - * "80,443,6443;6000-6500:4.4.4.4/24" (open 80,443,6443 to public and 6000 to 6500 just for 4.4.4.4/24) +*Note* +- The '--create-firewall' will open the ports 80,443 and 6443 in the firewall if '--firewall-rules' is not used. +- The '--create-firewall' and '--existing-firewall' flags are mutually exclusive. You can't use them together. +- The '--firewall-rules' flag need to be used with '--create-firewall'. +- The '--firewall-rules' flag can accept: + - You can pass 'all' to open all ports. + - An optional end port using 'start_port-end_port' format (e.g. 8000-8100) + - An optional CIDR notation (e.g. 0.0.0.0/0) + - When no CIDR notation is provided, the port will get 0.0.0.0/0 (open to public) as default CIDR notation + - When a CIDR notation is provided without slash and number segment, it will default to /32 + - Within a rule, you can use comma separator for multiple ports to have same CIDR notation + - To separate between rules, you can use semicolon symbol and wrap everything in double quotes (see below) + So the following would all be valid: + - "80,443,6443:0.0.0.0/0;8080:1.2.3.4" (open 80,443,6443 to public and 8080 just for 1.2.3.4/32) + - "80,443,6443;6000-6500:4.4.4.4/24" (open 80,443,6443 to public and 6000 to 6500 just for 4.4.4.4/24) ```sh $ civo kubernetes create my-first-cluster @@ -999,23 +1008,23 @@ To get an up-to-date list of available applications on the Marketplace, run `civ | Wordpress | 5.6.2 | management | 5GB, 10GB, 20GB | mariadb:5GB | +------------------------------+------------------+--------------+--------------------------------------------------------------------------------------------+---------------------------+ ``` + #### Show Applications details when is installed in the cluster This option will be allow you to see the post-install instruction of every app installed in the cluster ```sh -$ civo kubernetes application show Traefik apps-demo-cluster +civo kubernetes application show Traefik apps-demo-cluster ``` the first parameter is for the name of the app and the second is the name of the cluster - #### Installing Applications Onto a New Cluster To specify applications to install onto a new cluster, list them at cluster creation by specifying their `name` from the list above: ```sh -$ civo kubernetes create apps-demo-cluster --nodes=2 --applications=Redis,Linkerd +civo kubernetes create apps-demo-cluster --nodes=2 --applications=Redis,Linkerd ``` Now, if you take a look at the cluster's details, you will see the newly-installed applications listed: @@ -1053,7 +1062,7 @@ Installed marketplace applications: **Note:** Applications like `metrics-server` are installed by default on any new cluster you create. If you don't need to install the default applications, use the `--remove-applications` flag as below: ```sh -$ civo kubernetes create apps-demo-cluster --nodes=2 --applications=Redis,Linkerd --remove-applications=metrics-server +civo kubernetes create apps-demo-cluster --nodes=2 --applications=Redis,Linkerd --remove-applications=metrics-server ``` #### Installing Applications to an Existing Cluster @@ -1100,6 +1109,7 @@ Created a domain called civoclidemo.xyz with ID 418181b2-fcd2-46a2-ba7f-c843c331 You can then proceed to add DNS records to this domain. #### List Domain Names + To see your created domains, call `civo domain list`: ```sh @@ -1137,6 +1147,7 @@ Created a record www1 for civoclidemo.xyz with a TTL of 600 seconds and with a p ``` #### Listing DNS Records + You can get an overview of all records you have created for a particular domain by requesting `civo domain record list domain.name`: ```sh @@ -1147,7 +1158,9 @@ $ civo domain record list civoclidemo.xyz | 4e181dde-bde8-4744-8984-067f957a7d59 | A | www.civoclidemo.xyz | 192.168.1.1 | 1000 | 0 | +--------------------------------------+------+---------------------+-------------+------+----------+ ``` + #### Deleting a DNS Record + You can remove a particular DNS record from a domain you own by requesting `civo domain record remove record_id`. This immediately removes the associated record, so use with caution: ```sh @@ -1162,6 +1175,7 @@ The domain record called www with ID 4e181dde-bde8-4744-8984-067f957a7d59 was de You can configure custom firewall rules for your instances using the Firewall component of Civo CLI. These are freely configurable, however customers should be careful to not lock out their own access to their instances. By default, all ports are closed for custom firewalls. Firewalls can be configured with rules, and they can be made to apply to your chosen instance(s) with subsequent commands. + #### Configuring a New Firewall To create a new Firewall, use `civo firewall create new_firewall_name`: @@ -1170,7 +1184,9 @@ To create a new Firewall, use `civo firewall create new_firewall_name`: $ civo firewall create civocli_demo Created a firewall called civocli_demo with ID ab2a25d7-edd4-4ecd-95c4-58cb6bc402de ``` + You can also create a firewall without any default rules by using the flag `-r` or `--create-rules` set to `false`. In both cases, the usage is like: + ```bash civo firewall create new_firewall_name --create-rules=false @@ -1264,7 +1280,9 @@ Create a private network called cli-demo with ID 74b69006-ea59-46a0-96c4-63f5bfa ``` #### Listing Networks + To list all the networks you can run `civo network ls` + ```sh $ civo network ls +--------------------------------------+----------+--------+---------+ @@ -1285,12 +1303,12 @@ $ civo network remove 74b69006-ea59-46a0-96c4-63f5bfa290e1 Removed the network cli-demo with ID 74b69006-ea59-46a0-96c4-63f5bfa290e1 ``` - ## Object Stores #### Introduction Object stores are S3-compatible data storage structures on Civo. Through creating object stores in your account, you can manage unstructured data within the size limits of each object store and subject to your quota. + #### Listing Object Stores You can run `civo objectstore ls` to get the list of all object stores in your account. @@ -1341,7 +1359,7 @@ The Object Store (cli-demo) has been deleted #### Introduction -Access to object stores is controlled by credentials management. When a new object store is created, a default administrative set of credentials is created with it. You can create other credentials for object stores you create, and export credential information for use in applications. +Access to object stores is controlled by credentials management. When a new object store is created, a default administrative set of credentials is created with it. You can create other credentials for object stores you create, and export credential information for use in applications. #### Listing Object Store Credentials @@ -1394,7 +1412,6 @@ Warning: Are you sure you want to delete the cli-demo-fa5d-7de9b2 Object Store C The Object Store Credential (cli-demo-fa5d-7de9b2) has been deleted ``` - ## Quota All customers joining Civo will have a default quota applied to their account. The quota has nothing to do with charges or payments, but with the limits on the amount of simultaneous resources you can use. You can view the state of your quota at any time by running `civo quota show`. Here is my current quota usage at the time of writing: @@ -1490,6 +1507,7 @@ $ civo sshkeys ls #### Removing a SSH Key You can delete a SSH key by calling `remove` for it by ID: + ```sh $ civo ssh remove 531d0998-4152-410a-af20-0cccb1c7c73b Removed SSH key cli-demo with ID 531d0998-4152-410a-af20-0cccb1c7c73b @@ -1501,7 +1519,6 @@ Removed SSH key cli-demo with ID 531d0998-4152-410a-af20-0cccb1c7c73b Civo instances are built from a disk image. Currently there centos, debian and ubuntu are supported.In order to create an instance the diskimage ID is needed that can be found by running `civo diskimage ls` - #### Listing Available Disk Images ```sh @@ -1517,7 +1534,6 @@ $ civo diskimage ls +--------------------------------------+---------------+---------+-----------+--------------+ ``` - ## Volumes #### Introduction @@ -1590,11 +1606,13 @@ The volume called CLI-demo-volume with ID 59076ec8-edba-4071-80d0-e9cfcce37b12 w If a Kubernetes volume is showing with a status of `dangling` it can be deleted to release the quota and prevent further billing by running `civo volume delete --region `. ## Teams + Teams are a grouping of users, each member of a team having one or more permissions, or roles. When a user logs in, they don't have to select which team to use - only which account they want to act within. The permissions available are the total set of permissions they have across the teams in that account, combined. #### List all teams You can run `civo teams ls` to get the list of all teams + ```sh $ civo teams ls +--------------------------------------+------------------+ @@ -1612,6 +1630,7 @@ $ civo teams ls #### Create a new team To create a new team in your account, the cmd you need to run is `civo teams create ` and a new team will be created with the given name. + ```sh $ civo teams create Community Created a team called Community with team ID 475a087b-bec8-4a66-ac14-95bc09bd8d1e @@ -1620,6 +1639,7 @@ Created a team called Community with team ID 475a087b-bec8-4a66-ac14-95bc09bd8d1 #### Rename a team To rename a team, you need to run the cmd `civo teams rename ` + ```sh $ civo teams rename Community Advocacy The team with ID 475a087b-bec8-4a66-ac14-95bc09bd8d1e was renamed to Advocacy @@ -1628,19 +1648,21 @@ The team with ID 475a087b-bec8-4a66-ac14-95bc09bd8d1e was renamed to Advocacy #### Delete a team To delete a team, you need to run the cmd `civo teams delete ` + ```sh $ civo teams delete Advocacy Warning: Are you sure you want to delete the Advocacy team (y/N) ? y The team (Advocacy) has been deleted -``` - +``` ## Permissions + Each member of a team is assigned one or more permissions, or roles. The permissions available are the total set of permissions they have across the teams in that account, combined. #### List all permissions You have to run the cmd `civo permissions ls` to list down all the available permissions. + ```sh $ civo permissions ls +-------------------------+----------------------------+------------------------------------------------------------------------------------------------+ @@ -1707,11 +1729,13 @@ $ civo permissions ls ``` ## Region + As Civo grows, more regions for your instances will become available. You can run `civo region ls` to list the regions available. Block storage (Volumes) is region-specific, so if you configure an instance in one region, any volumes you wish to attach to that instance would have to be in the same region. #### List all region You can run `civo region ls` to get the list of all region + ```sh civo region ls +------+-------------+----------------+---------+ @@ -1726,10 +1750,12 @@ civo region ls #### Change region To change the region the only cmd you need run is `civo region current ` and you will see a message like this: + ```sh civo region current NYC1 ``` + The default region was set to (New York 1) NYC1 #### Use region in non-interactive mode @@ -1814,19 +1840,21 @@ compinit ``` To set the civo completion code for zsh to auto-load on start up yo can run this command. + ```bash civo completion zsh > "${fpath[1]}/_civo" ``` ## Contributing -Bug reports and pull requests are welcome on GitHub at https://github.com/civo/cli. +Bug reports and pull requests are welcome on GitHub at . ## License The code is available as open source under the terms of the [Apache License 2.0](https://opensource.org/licenses/Apache-2.0). ## Thanks to all the contributors ❤ + diff --git a/cmd/database/database.go b/cmd/database/database.go index b12764e2..89939309 100644 --- a/cmd/database/database.go +++ b/cmd/database/database.go @@ -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") } diff --git a/cmd/database/database_backup.go b/cmd/database/database_backup.go index a2ee72ef..5d3b0360 100644 --- a/cmd/database/database_backup.go +++ b/cmd/database/database_backup.go @@ -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{ @@ -32,7 +31,6 @@ 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") @@ -40,5 +38,4 @@ func init() { // 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") } diff --git a/cmd/database/database_backup_create.go b/cmd/database/database_backup_create.go index 723608ba..80362150 100644 --- a/cmd/database/database_backup_create.go +++ b/cmd/database/database_backup_create.go @@ -15,7 +15,7 @@ import ( var dbBackupCreateCmd = &cobra.Command{ Use: "create", Aliases: []string{"new", "add"}, - Example: `Scheduled: civo database backup create --name --schedule --count \n + Example: `Scheduled: civo database backup create --name --schedule \n Manual: civo database backup create --name --type manual`, Short: "Create a new database backup", Args: cobra.MinimumNArgs(1), @@ -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) @@ -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 @@ -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{ diff --git a/cmd/database/database_backup_list.go b/cmd/database/database_backup_list.go index e4ed7202..9dbd3123 100644 --- a/cmd/database/database_backup_list.go +++ b/cmd/database/database_backup_list.go @@ -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" @@ -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() + } } diff --git a/cmd/database/database_backup_update.go b/cmd/database/database_backup_update.go index b0fe60b3..46c2f0bd 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 --count ", + Example: "civo database backup update --name --schedule ", Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { utility.EnsureCurrentRegion() @@ -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) } @@ -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 } @@ -69,9 +66,8 @@ 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": @@ -79,7 +75,7 @@ var dbBackupUpdateCmd = &cobra.Command{ 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)) } }, } diff --git a/cmd/database/database_restore.go b/cmd/database/database_restore.go index 833706d8..55c501c8 100644 --- a/cmd/database/database_restore.go +++ b/cmd/database/database_restore.go @@ -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 --backup ", + Example: "civo db restore --name --backup ", Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { utility.EnsureCurrentRegion() @@ -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, } diff --git a/doc/DTABASE_BACKUP_RESTORE.md b/doc/DTABASE_BACKUP_RESTORE.md new file mode 100644 index 00000000..7cba94ac --- /dev/null +++ b/doc/DTABASE_BACKUP_RESTORE.md @@ -0,0 +1,157 @@ + +# Database Backup and Restore + +> This repository provides a solution for backing up and restoring databases. Whether you need scheduled backups for automated routine tasks or manual backups for specific events, this guide will walk you through the process. + +## Backup Types + +### Scheduled Backups + +Scheduled backups are automated processes that run at predefined intervals. They help ensure that your data is regularly backed up without manual intervention. + +To set up scheduled backups, follow the steps outlined in the Configuration section. + +* Support: PostgreSQL + +### Manual Backups + +Manual backups are initiated by a user on-demand. These are useful for creating backups before system updates, major changes, or any event that requires a snapshot of the database at a specific point in time. + +To manually create a backup, follow the steps outlined in the Usage section. + +* Support: PostgreSQL, MySQL + +### Restore Process + +The restore process allows you to recover your database from a previously created backup. + +* Support: PostgreSQL, MySQL + +# CLI Operations + +## Create MySQL and PostgreSQL database + +```bash +❯ civo database create postgres-demo --size g3.db.medium --software PostgreSQL --version 14 +Database (postgres-demo) with ID 65dd8173-f754-4c6c-b50a-7ddb6d5446c5 has been created +``` + +```bash +❯ civo database create mysql-demo --size g3.db.medium --software MySQL --version 8.0 +Database (mysql-demo) with ID 0d328d59-98c3-4f68-8025-5b1633a1c287 has been created +``` + +```bash +❯ civo database ls ++--------+---------------+--------------+-------+------------+------------------+--------------+------+--------+ +| ID | Name | Size | Nodes | Software | Software Version | Host | Port | Status | ++--------+---------------+--------------+-------+------------+------------------+--------------+------+--------+ +| 65dd81 | postgres-demo | g3.db.medium | 1 | PostgreSQL | 14 | 31.28.88.149 | 5432 | Ready | ++--------+---------------+--------------+-------+------------+------------------+--------------+------+--------+ +| 0d328d | mysql-demo | g3.db.medium | 1 | MySQL | 8.0 | 31.28.88.184 | 3306 | Ready | ++--------+---------------+--------------+-------+------------+------------------+--------------+------+--------+ +To get the credentials for a database, use `civo db credential ` +``` + +### List database backups + +```bash +❯ civo database backups ls postgres-demo +❯ civo database backups ls mysql-demo +``` + +## PostgreSQL + +### Create Scheduled Backup + +```bash +❯ civo database backups create postgres-demo --name every10minutes --schedule "*/10 * * * *" +Database backup (every10minutes) for database postgr-b697-c429d7 has been created +``` + +### Create Manual Backup + +```bash +❯ civo database backups create postgres-dem --name firstbackup --type manual +Database backup (firstbackup) for database postgres-demo has been created +``` + +### List backup + +```bash +Scheduled backup ++-------------+---------------+------------+--------------+----------------+------------------+ +| Database ID | Database Name | Software | Schedule | Backup Name | Backup | ++-------------+---------------+------------+--------------+----------------+------------------+ +| 65dd81 | postgres-demo | PostgreSQL | */10 * * * * | every10minutes | 20240131-100009F | ++-------------+---------------+------------+--------------+----------------+------------------+ +``` + +### Create Manual Backup + +```bash +❯ civo database backups create postgres-demo +``` + +### List + +```bash +❯ civo database backups ls postgres-demo +Scheduled backup ++-------------+---------------+------------+--------------+----------------+------------------+ +| Database ID | Database Name | Software | Schedule | Backup Name | Backup | ++-------------+---------------+------------+--------------+----------------+------------------+ +| 65dd81 | postgres-demo | PostgreSQL | */10 * * * * | every10minutes | 20240131-100009F | ++-------------+---------------+------------+--------------+----------------+------------------+ +Manual backups ++-------------+---------------+------------+------------------+ +| Database ID | Database Name | Software | Backup | ++-------------+---------------+------------+------------------+ +| 65dd81 | postgres-demo | PostgreSQL | 20240131-095615F | ++-------------+---------------+------------+------------------+ +``` + +### Restore from scheduled + +```bash +❯ civo database restore postgres-demo --name restorefromscheduledbackup --backup 20240131-102006F +Warning: Are you sure you want to restore db postgres-demo from 20240131-102006F backup (y/N) ? y +Restoring database postgres-demo from from backup 20240131-102006F +``` + +### Restore from manual + +```bash +❯ civo database restore postgres-demo --name restorefromscheduledbackup --backup 20240131-095615F +Warning: Are you sure you want to restore db postgres-demo from 20240131-095615F backup (y/N) ? y +Restoring database postgres-demo from from backup 20240131-095615F +``` + +## MySQL Backup + +### Create + +```bash +❯ civo database backups create mysql-demo --name firstbackup --type manual +Database backup (firstbackup) for database mysql-demo has been created +``` + +### List backup + +```bash +❯ civo database backups ls mysql-demo +Manual backups ++-------------+---------------+-----------+-------------+----------+--------+ +| Database ID | Database Name | Backup ID | Backup Name | Software | Status | ++-------------+---------------+-----------+-------------+----------+--------+ +| 0d328d | mysql-demo | ba0466 | firstbackup | MySQL | READY | ++-------------+---------------+-----------+-------------+----------+--------+ +``` + +### Restore + +```bash +❯ civo database restore mysql-demo --name restorefirstbackup --backup firstbackup +Warning: Are you sure you want to restore db mysql-demo from firstbackup backup (y/N) ? y +Restoring database mysql-demo from from backup firstbackup +``` diff --git a/go.mod b/go.mod index cf164ae3..1a79268b 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.56 + github.com/civo/civogo v0.3.58 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 3587df24..1d9c26d3 100644 --- a/go.sum +++ b/go.sum @@ -61,8 +61,8 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/civo/civogo v0.3.56 h1:t5u/OwExb2ibVmIXsUprV5m++bAqBRLO9uMcodNHZek= -github.com/civo/civogo v0.3.56/go.mod h1:54lv/FOf7gh6wE9ZwVdw4yBehk8V1CvU9aWa4v6dvW0= +github.com/civo/civogo v0.3.58 h1:FikCbwAKB5ovD8+NmSi7rzYBSpC4nUpGVpCyngEkTo4= +github.com/civo/civogo v0.3.58/go.mod h1:54lv/FOf7gh6wE9ZwVdw4yBehk8V1CvU9aWa4v6dvW0= 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=