This repository was archived by the owner on Oct 29, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Got parsing of VCAP right. And some testing.
- Loading branch information
Showing
8 changed files
with
257 additions
and
163 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/* | ||
Copyright © 2024 NAME HERE <EMAIL ADDRESS> | ||
*/ | ||
package cmd | ||
|
||
import ( | ||
"database/sql" | ||
"fmt" | ||
"os" | ||
|
||
"github.com/spf13/cobra" | ||
"gov.gsa.fac.backups/internal/logging" | ||
vcap "gov.gsa.fac.backups/internal/vcap" | ||
) | ||
|
||
func get_row_count(creds *vcap.RDSCreds, table string) int { | ||
var count int | ||
// FIXME: Not sure if `disable` is correct for RDS sslmode. | ||
connStr := fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=disable", | ||
creds.Username, | ||
creds.Password, | ||
creds.Host, | ||
creds.DB_Name) | ||
db, _ := sql.Open("postgres", connStr) | ||
defer db.Close() | ||
row := db.QueryRow(fmt.Sprintf("SELECT count(*) FROM %s", table)) | ||
if err := row.Scan(&count); err != nil { | ||
logging.Logger.Printf("BACKUPS Could not get count of %s", table) | ||
} | ||
return count | ||
} | ||
|
||
func check_results(source *vcap.RDSCreds, dest *vcap.RDSCreds, tables []string) { | ||
// FIXME: These won't exist in the VCAP_SERVICES version | ||
// of the config. We'll have to always... load both? | ||
// There needs to be a way to configure this in the remote env. | ||
for _, table := range tables { | ||
source_row_count := get_row_count(source, table) | ||
dest_row_count := get_row_count(dest, table) | ||
logging.Logger.Printf("CHECK OK %s source %d dest %d", | ||
table, source_row_count, dest_row_count) | ||
if source_row_count < dest_row_count { | ||
logging.Logger.Printf("CHECK too many rows in '%s' source (%d < %d)", | ||
table, source_row_count, dest_row_count) | ||
os.Exit(-1) | ||
} | ||
} | ||
} | ||
|
||
// checkCmd represents the check command | ||
var checkCmd = &cobra.Command{ | ||
Use: "check", | ||
Short: "Checks table counts between source and destination", | ||
Long: ` | ||
When given a source and destination, this command returns 0 when the | ||
number of rows in the source are equal to or higher than the number | ||
of rows in the destination. | ||
This is because the clone tool is used against live tables. It is likely | ||
that the source will increase between the time of the clone and the check. | ||
Expects a space-separated list of table names as arguments. | ||
`, | ||
Args: cobra.MinimumNArgs(1), | ||
Run: func(cmd *cobra.Command, args []string) { | ||
source_creds, dest_creds := vcap.GetCreds(SourceDB, DestinationDB) | ||
check_results(source_creds, dest_creds, args) | ||
|
||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(checkCmd) | ||
checkCmd.Flags().StringVarP(&SourceDB, "source-db", "", "", "source database (req)") | ||
checkCmd.Flags().StringVarP(&DestinationDB, "destination-db", "", "", "destination database (req)") | ||
checkCmd.MarkFlagRequired("source-db") | ||
checkCmd.MarkFlagRequired("destination-db") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
/* | ||
Copyright © 2024 NAME HERE <EMAIL ADDRESS> | ||
*/ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"strings" | ||
|
||
"github.com/bitfield/script" | ||
"github.com/spf13/cobra" | ||
"gov.gsa.fac.backups/internal/logging" | ||
vcap "gov.gsa.fac.backups/internal/vcap" | ||
|
||
_ "github.com/lib/pq" | ||
) | ||
|
||
// https://bitfieldconsulting.com/golang/scripting | ||
func pg_dump(creds *vcap.RDSCreds) *script.Pipe { | ||
// Compose the command as a slice | ||
cmd := []string{ | ||
"pg_dump", | ||
"--clean", | ||
"--no-password", | ||
"--if-exists", | ||
"--no-privileges", | ||
"--no-owner", | ||
"--format plain", | ||
"--dbname", | ||
fmt.Sprintf("postgres://%s:%s@%s:%s/%s", | ||
creds.Username, | ||
creds.Password, | ||
creds.Host, | ||
creds.Port, | ||
creds.DB_Name, | ||
), | ||
} | ||
// Combine the slice for printing and execution. | ||
combined := strings.Join(cmd[:], " ") | ||
// This will log the password... | ||
// logging.Logger.Printf("BACKUPS Running `%s`\n", combined) | ||
logging.Logger.Printf("BACKUPS pg_dump targeting %s", creds.DB_Name) | ||
return script.Exec(combined) | ||
} | ||
|
||
func psql(in_pipe *script.Pipe, creds *vcap.RDSCreds) *script.Pipe { | ||
cmd := []string{ | ||
"psql", | ||
"--no-password", | ||
"--dbname", | ||
fmt.Sprintf("postgres://%s:%s@%s:%s/%s", | ||
creds.Username, | ||
creds.Password, | ||
creds.Host, | ||
creds.Port, | ||
creds.DB_Name, | ||
), | ||
} | ||
combined := strings.Join(cmd[:], " ") | ||
logging.Logger.Printf("BACKUPS psql targeting %s", creds.DB_Name) | ||
return in_pipe.Exec(combined) | ||
} | ||
|
||
func clone(source *vcap.RDSCreds, dest *vcap.RDSCreds) { | ||
psql_pipe := psql(pg_dump(source), dest) | ||
psql_pipe.Wait() | ||
if err := psql_pipe.Error(); err != nil { | ||
logging.Logger.Println("BACKUPS Pipe failed") | ||
os.Exit(-1) | ||
} | ||
} | ||
|
||
// snapshotDbToDbCmd represents the snapshotDbToDb command | ||
var cloneCmd = &cobra.Command{ | ||
Use: "clone", | ||
Short: "pg_dump | psql, source to destination", | ||
Long: ` | ||
An imperfect, point-in-time snapshot. | ||
This command copies the source database to the destination | ||
database by streaming STDOUT of 'pg_dump' piped into the STNDIN | ||
of 'psql'. The former reads from the FAC production database, and | ||
writes to a snapshot clone DB. | ||
`, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
source_creds, dest_creds := vcap.GetCreds(SourceDB, DestinationDB) | ||
clone(source_creds, dest_creds) | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(cloneCmd) | ||
cloneCmd.Flags().StringVarP(&SourceDB, "source-db", "", "", "source database (req)") | ||
cloneCmd.Flags().StringVarP(&DestinationDB, "destination-db", "", "", "destination database (req)") | ||
cloneCmd.MarkFlagRequired("source-db") | ||
cloneCmd.MarkFlagRequired("destination-db") | ||
|
||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.