From 96a2f325236a1112856303e5daa697df20c988ec Mon Sep 17 00:00:00 2001 From: Braeden Sowinski Date: Tue, 13 Jun 2023 20:32:09 -0700 Subject: [PATCH] initial commit --- .env.example | 7 ++++ .gitignore | 8 ++++ README.md | 44 ++++++++++++++++++++ go.mod | 5 +++ go.sum | 2 + main.go | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 178 insertions(+) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 README.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..99403c1 --- /dev/null +++ b/.env.example @@ -0,0 +1,7 @@ +# MongoDB URI +mongoURI=mongodb://localhost:27017 +# Database name followed by a ", " to list more than one +databases=db_name_1, db_name_2, ... +# Github repository ssh link +github=git@github:Username/MongoDB_Backup_Repo.git + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..15749ba --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# Environment variables +.env + +# Archive from mongodump +archive/* + +# log files +*.log \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..8328b43 --- /dev/null +++ b/README.md @@ -0,0 +1,44 @@ +# MongoDB Backup Script +A script to automatically handle the backing up of MongoDB databases and optionally the storage of the archive to a github repository. Designed as a script to be run as a service on a server. + +
+ +### Setup + +1. Rename `.env.example` to `.env` +2. Set the parameters of your **mongoURI, database names, and optionally a gitub url/ssh link**. Ex. + ```.env + mongoURI=mongodb://localhost:27017 + databases=db_name_1, db_name_2, ... + github=git@github:Username/MongoDB_Backup_Repo.git + ``` + **Note:** If you wish to backup more than one database at a time, be sure to seperate the database names with a comma and a space as follows "`, `". + +3. Setup your service on your UNIX-based OS, for example an Ubuntu Server. + **i.** Build the project to a binary. + ```bash + $ go build + ``` + **ii.** Create a System Service file + ```bash + $ vim /lib/systemd/system/mongobackup.service + ``` + Now within the `mongobackup.service` file, write the configuration for the program. + ```service + [Unit] + Description=MongoDB Backup Service + + [Service] + Type=simple + Restart=always + RestartSec=5 + ExecStart=/path/to/binary/file + + [Install] + WantedBy=multi-user.target + ``` + **iii.** Finally start the service. + ```bash + $ service mongobackup start + ``` + diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ef7a917 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/SowinskiBraeden/mongodb-backup-script + +go 1.20 + +require github.com/joho/godotenv v1.5.1 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..d61b19e --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= diff --git a/main.go b/main.go new file mode 100644 index 0000000..274f3a6 --- /dev/null +++ b/main.go @@ -0,0 +1,112 @@ +package main + +import ( + "fmt" + "os" + "os/exec" + "log" + "path/filepath" + "time" + + "github.com/joho/godotenv" + "strings" +) + +const dtFormat string = "2006-01-02 15:04:05 Monday" + +func Handle(err error) { + if err != nil { + log.Panic(err.Error()) + } +} + +// Basic logging +func LogToFile(message string) { + f, err := os.OpenFile("databaseBackup.log", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666) + Handle(err) + defer f.Close() + + log.SetOutput(f) + log.Println(fmt.Sprintf(" | %s", message)) +} + +func UploadToGithub(archiveDir string) { + // Add archive files to stage + cmd := exec.Command("git", "add", ".") + cmd.Dir = archiveDir + _, err := cmd.Output() + Handle(err) + + now := time.Now() + + // Commit archive files + cmd = exec.Command("git", "commit", "-m", fmt.Sprintf("'%s''", now.Format(dtFormat))) + cmd.Dir = archiveDir + _, err = cmd.Output() + Handle(err) + + // Push archive files to repository + cmd = exec.Command("git", "push", "origin", "master", "--force") + cmd.Dir = archiveDir + _, err = cmd.Output() + Handle(err) + + LogToFile("Successfully uploaded archive to github repository") +} + +func main() { + // Load environment variables + godotenv.Load(".env") + var mongoURI string = os.Getenv("mongoURI") + var database_string string = os.Getenv("databases") + var github string = os.Getenv("github") + + // Ensure required variables + if mongoURI == "" || database_string == "" { + log.Panic("Missing required .env variables: mongoURI, databases") + } + + var databases []string = strings.Split(database_string, ", ") + + // Ensure archive directory exists // initialize repository if github provided + archiveDir := filepath.Join(".", "archive") + if _, err := os.Stat(archiveDir); os.IsNotExist(err) { + err := os.Mkdir(archiveDir, os.ModePerm) + Handle(err) + + if github != "" { + cmd := exec.Command("git", "init") + cmd.Dir = archiveDir + _, err := cmd.Output() + Handle(err) + + cmd = exec.Command("git", "remote", "add", "origin", github) + cmd.Dir = archiveDir + _, err = cmd.Output() + Handle(err) + } + } + + // Perform mongodump to archive databases to .gzip format + for _, db := range databases { + archivePath := filepath.Join(archiveDir, db + ".gzip") + cmd := exec.Command( + "mongodump", + "--uri=" + mongoURI, + "--authenticationDatabase=admin", + "--db=" + db, + "--archive=" + archivePath, + "--gzip", + ) + _, err := cmd.Output() + Handle(err) + + LogToFile(fmt.Sprintf("Successfully archived %s", db)) + } + + if github != "" { + UploadToGithub(archiveDir) + } + + LogToFile("------------------------ mongodb-backup-script ------------------------") // Log break for easier viewing +}