Compare commits
1 Commits
d0460cea09
...
a43a156abf
Author | SHA1 | Date |
---|---|---|
Malachi Soord | a43a156abf |
30
Makefile
30
Makefile
|
@ -21,6 +21,9 @@ build-arm64:
|
||||||
build-armhf:
|
build-armhf:
|
||||||
GOOS=linux GOARCH=arm RELEASE=prod make build
|
GOOS=linux GOARCH=arm RELEASE=prod make build
|
||||||
|
|
||||||
|
build-amd64:
|
||||||
|
GOOS=linux GOARCH=amd64 RELEASE=prod make build
|
||||||
|
|
||||||
build:
|
build:
|
||||||
@echo "Building ${GOOS}-${GOARCH}"
|
@echo "Building ${GOOS}-${GOARCH}"
|
||||||
GOOS=${GOOS} GOARCH=${GOARCH} go build \
|
GOOS=${GOOS} GOARCH=${GOARCH} go build \
|
||||||
|
@ -40,26 +43,19 @@ test:
|
||||||
test-with-coverage:
|
test-with-coverage:
|
||||||
go test -tags=unit -timeout=600s -v ./... -coverprofile=coverage.out
|
go test -tags=unit -timeout=600s -v ./... -coverprofile=coverage.out
|
||||||
|
|
||||||
install:
|
install-cloud: build-cloud
|
||||||
sudo systemctl stop edgeboxctl
|
systemctl stop edgeboxctl
|
||||||
|
cp ./bin/edgeboxctl /usr/local/bin/edgeboxctl
|
||||||
|
cp ./edgeboxctl/edgeboxctl.service /lib/systemd/system/edgeboxctl.service
|
||||||
|
systemctl daemon-reload
|
||||||
|
@echo "Edgeboxctl installed successfully"
|
||||||
|
@echo "To start edgeboxctl run: systemctl start edgeboxctl"
|
||||||
|
|
||||||
|
install-prod: build-prod
|
||||||
|
-sudo systemctl stop edgeboxctl
|
||||||
sudo rm -rf /usr/local/bin/edgeboxctl /lib/systemd/system/edgeboxctl.service
|
sudo rm -rf /usr/local/bin/edgeboxctl /lib/systemd/system/edgeboxctl.service
|
||||||
sudo cp ./bin/edgeboxctl /usr/local/bin/edgeboxctl
|
sudo cp ./bin/edgeboxctl /usr/local/bin/edgeboxctl
|
||||||
sudo cp ./edgeboxctl.service /lib/systemd/system/edgeboxctl.service
|
sudo cp ./edgeboxctl.service /lib/systemd/system/edgeboxctl.service
|
||||||
sudo systemctl daemon-reload
|
sudo systemctl daemon-reload
|
||||||
@echo "Edgeboxctl installed successfully"
|
@echo "Edgeboxctl installed successfully"
|
||||||
@echo "To start edgeboxctl run: systemctl start edgeboxctl"
|
@echo "To start edgeboxctl run: systemctl start edgeboxctl"
|
||||||
|
|
||||||
install-prod: build-prod install
|
|
||||||
install-cloud: build-cloud install
|
|
||||||
install-arm64: build-arm64 install
|
|
||||||
install-armhf: build-armhf install
|
|
||||||
|
|
||||||
start:
|
|
||||||
systemctl start edgeboxctl
|
|
||||||
|
|
||||||
stop:
|
|
||||||
systemctl stop edgeboxctl
|
|
||||||
|
|
||||||
log: start
|
|
||||||
journalctl -fu edgeboxctl
|
|
||||||
|
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
package backups
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "fmt"
|
|
||||||
// "os"
|
|
||||||
// "path/filepath"
|
|
||||||
// "strings"
|
|
||||||
|
|
||||||
// "github.com/edgebox-iot/edgeboxctl/internal/diagnostics"
|
|
||||||
// "github.com/edgebox-iot/edgeboxctl/internal/utils"
|
|
||||||
// "github.com/shirou/gopsutil/disk"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// Repository : Struct representing the backup repository of a device in the system
|
|
||||||
type Repository struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
FileCount int64 `json:"file_count"`
|
|
||||||
Size string `json:"size"`
|
|
||||||
Snapshots []Snapshot `json:"snapshots"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
// UsageStat UsageStat `json:"usage_stat"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Snapshot : Struct representing a single snapshot in the backup repository
|
|
||||||
type Snapshot struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
time string `json:"time"`
|
|
||||||
}
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
|
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
|
|
||||||
"github.com/edgebox-iot/edgeboxctl/internal/system"
|
|
||||||
"github.com/edgebox-iot/edgeboxctl/internal/utils"
|
"github.com/edgebox-iot/edgeboxctl/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -98,7 +97,7 @@ func GetEdgeApp(ID string) MaybeEdgeApp {
|
||||||
Status: GetEdgeAppStatus(ID),
|
Status: GetEdgeAppStatus(ID),
|
||||||
Services: GetEdgeAppServices(ID),
|
Services: GetEdgeAppServices(ID),
|
||||||
InternetAccessible: edgeAppInternetAccessible,
|
InternetAccessible: edgeAppInternetAccessible,
|
||||||
NetworkURL: ID + system.GetHostname() + ".local",
|
NetworkURL: ID + ".edgebox.local",
|
||||||
InternetURL: edgeAppInternetURL,
|
InternetURL: edgeAppInternetURL,
|
||||||
},
|
},
|
||||||
Valid: true,
|
Valid: true,
|
||||||
|
@ -297,36 +296,6 @@ func StopEdgeApp(ID string) EdgeAppStatus {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StopAllEdgeApps: Stops all EdgeApps and returns a count of how many were stopped
|
|
||||||
func StopAllEdgeApps() int {
|
|
||||||
edgeApps := GetEdgeApps()
|
|
||||||
appCount := 0
|
|
||||||
for _, edgeApp := range edgeApps {
|
|
||||||
StopEdgeApp(edgeApp.ID)
|
|
||||||
appCount++
|
|
||||||
}
|
|
||||||
|
|
||||||
return appCount
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartAllEdgeApps: Starts all EdgeApps and returns a count of how many were started
|
|
||||||
func StartAllEdgeApps() int {
|
|
||||||
edgeApps := GetEdgeApps()
|
|
||||||
appCount := 0
|
|
||||||
for _, edgeApp := range edgeApps {
|
|
||||||
RunEdgeApp(edgeApp.ID)
|
|
||||||
appCount++
|
|
||||||
}
|
|
||||||
|
|
||||||
return appCount
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func RestartEdgeAppsService() {
|
|
||||||
buildFrameworkContainers()
|
|
||||||
}
|
|
||||||
|
|
||||||
// EnableOnline : Write environment file and rebuild the necessary containers. Rebuilds containers in project (in case of change only)
|
// EnableOnline : Write environment file and rebuild the necessary containers. Rebuilds containers in project (in case of change only)
|
||||||
func EnableOnline(ID string, InternetURL string) MaybeEdgeApp {
|
func EnableOnline(ID string, InternetURL string) MaybeEdgeApp {
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"io"
|
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"bufio"
|
"bufio"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -131,22 +130,6 @@ func GetServiceStatus(serviceID string) string {
|
||||||
return utils.Exec(wsPath, "systemctl", cmdargs)
|
return utils.Exec(wsPath, "systemctl", cmdargs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateBackupsPasswordFile(password string) {
|
|
||||||
// Create a password file for backups
|
|
||||||
backupPasswordFile := utils.GetPath(utils.BackupPasswordFileLocation)
|
|
||||||
backupPasswordFileDir := filepath.Dir(backupPasswordFile)
|
|
||||||
|
|
||||||
if _, err := os.Stat(backupPasswordFileDir); os.IsNotExist(err) {
|
|
||||||
os.MkdirAll(backupPasswordFileDir, 0755)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the password to the file, overriting an existing file
|
|
||||||
err := ioutil.WriteFile(backupPasswordFile, []byte(password), 0644)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateTunnel: Creates a tunnel via cloudflared, needs to be authenticated first
|
// CreateTunnel: Creates a tunnel via cloudflared, needs to be authenticated first
|
||||||
func CreateTunnel(configDestination string) {
|
func CreateTunnel(configDestination string) {
|
||||||
fmt.Println("Creating Tunnel for Edgebox.")
|
fmt.Println("Creating Tunnel for Edgebox.")
|
||||||
|
@ -303,78 +286,3 @@ func RemoveTunnelService() {
|
||||||
utils.Exec(wsPath, "rm", cmdargs)
|
utils.Exec(wsPath, "rm", cmdargs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func CopyDir(src string, dest string) error {
|
|
||||||
srcInfo, err := os.Stat(src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !srcInfo.IsDir() {
|
|
||||||
return fmt.Errorf("%s is not a directory", src)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = os.MkdirAll(dest, srcInfo.Mode())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
items, err := ioutil.ReadDir(src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, item := range items {
|
|
||||||
srcPath := filepath.Join(src, item.Name())
|
|
||||||
destPath := filepath.Join(dest, item.Name())
|
|
||||||
|
|
||||||
if item.IsDir() {
|
|
||||||
err = CopyDir(srcPath, destPath)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("error copying directory %s to %s: %s\n", srcPath, destPath, err.Error())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = CopyFile(srcPath, destPath)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("error copying file %s to %s: %s\n", srcPath, destPath, err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func CopyFile(src string, dest string) error {
|
|
||||||
srcFile, err := os.Open(src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer srcFile.Close()
|
|
||||||
|
|
||||||
destFile, err := os.Create(dest)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer destFile.Close()
|
|
||||||
|
|
||||||
_, err = io.Copy(destFile, srcFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = destFile.Sync()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
srcInfo, err := os.Stat(src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = os.Chmod(dest, srcInfo.Mode())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -66,14 +66,6 @@ type taskEnablePublicDashboardArgs struct {
|
||||||
InternetURL string `json:"internet_url"`
|
InternetURL string `json:"internet_url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type taskSetupBackupsArgs struct {
|
|
||||||
Service string `json:"service"`
|
|
||||||
AccessKeyID string `json:"access_key_id"`
|
|
||||||
SecretAccessKey string `json:"secret_access_key"`
|
|
||||||
RepositoryName string `json:"repository_name"`
|
|
||||||
RepositoryPassword string `json:"repository_password"`
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const STATUS_CREATED int = 0
|
const STATUS_CREATED int = 0
|
||||||
const STATUS_EXECUTING int = 1
|
const STATUS_EXECUTING int = 1
|
||||||
|
@ -132,7 +124,6 @@ func ExecuteTask(task Task) Task {
|
||||||
|
|
||||||
formatedDatetime := utils.GetSQLiteFormattedDateTime(time.Now())
|
formatedDatetime := utils.GetSQLiteFormattedDateTime(time.Now())
|
||||||
|
|
||||||
fmt.Println("Changing task status to executing: " + task.Task)
|
|
||||||
_, err = statement.Exec(STATUS_EXECUTING, formatedDatetime, strconv.Itoa(task.ID)) // Execute SQL Statement
|
_, err = statement.Exec(STATUS_EXECUTING, formatedDatetime, strconv.Itoa(task.ID)) // Execute SQL Statement
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err.Error())
|
log.Fatal(err.Error())
|
||||||
|
@ -144,44 +135,6 @@ func ExecuteTask(task Task) Task {
|
||||||
log.Println("Task: " + task.Task)
|
log.Println("Task: " + task.Task)
|
||||||
log.Println("Args: " + task.Args.String)
|
log.Println("Args: " + task.Args.String)
|
||||||
switch task.Task {
|
switch task.Task {
|
||||||
case "setup_backups":
|
|
||||||
|
|
||||||
log.Println("Setting up Backups Destination...")
|
|
||||||
var args taskSetupBackupsArgs
|
|
||||||
err := json.Unmarshal([]byte(task.Args.String), &args)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Error reading arguments of setup_backups task.")
|
|
||||||
} else {
|
|
||||||
taskResult := taskSetupBackups(args)
|
|
||||||
taskResultBool := true
|
|
||||||
// Check if returned taskResult string contains "error"
|
|
||||||
if strings.Contains(taskResult, "error") {
|
|
||||||
taskResultBool = false
|
|
||||||
}
|
|
||||||
task.Result = sql.NullString{String: taskResult, Valid: taskResultBool}
|
|
||||||
}
|
|
||||||
|
|
||||||
case "start_backup":
|
|
||||||
|
|
||||||
log.Println("Backing up Edgebox...")
|
|
||||||
taskResult := taskBackup()
|
|
||||||
taskResultBool := true
|
|
||||||
// Check if returned taskResult string contains "error"
|
|
||||||
if strings.Contains(taskResult, "error") {
|
|
||||||
taskResultBool = false
|
|
||||||
}
|
|
||||||
task.Result = sql.NullString{String: taskResult, Valid: taskResultBool}
|
|
||||||
|
|
||||||
case "restore_backup":
|
|
||||||
log.Println("Attempting to Restore Last Backup to Edgebox")
|
|
||||||
taskResult := taskRestoreBackup()
|
|
||||||
taskResultBool := true
|
|
||||||
// Check if returned taskResult string contains "error"
|
|
||||||
if strings.Contains(taskResult, "error") {
|
|
||||||
taskResultBool = false
|
|
||||||
}
|
|
||||||
task.Result = sql.NullString{String: taskResult, Valid: taskResultBool}
|
|
||||||
|
|
||||||
case "setup_tunnel":
|
case "setup_tunnel":
|
||||||
|
|
||||||
log.Println("Setting up Cloudflare Tunnel...")
|
log.Println("Setting up Cloudflare Tunnel...")
|
||||||
|
@ -319,13 +272,11 @@ func ExecuteTask(task Task) Task {
|
||||||
formatedDatetime = utils.GetSQLiteFormattedDateTime(time.Now())
|
formatedDatetime = utils.GetSQLiteFormattedDateTime(time.Now())
|
||||||
|
|
||||||
if task.Result.Valid {
|
if task.Result.Valid {
|
||||||
fmt.Println("Task Result: " + task.Result.String)
|
|
||||||
_, err = statement.Exec(STATUS_FINISHED, task.Result.String, formatedDatetime, strconv.Itoa(task.ID)) // Execute SQL Statement with result info
|
_, err = statement.Exec(STATUS_FINISHED, task.Result.String, formatedDatetime, strconv.Itoa(task.ID)) // Execute SQL Statement with result info
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err.Error())
|
log.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Error executing task with result: " + task.Result.String)
|
|
||||||
_, err = statement.Exec(STATUS_ERROR, "Error", formatedDatetime, strconv.Itoa(task.ID)) // Execute SQL Statement with Error info
|
_, err = statement.Exec(STATUS_ERROR, "Error", formatedDatetime, strconv.Itoa(task.ID)) // Execute SQL Statement with Error info
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err.Error())
|
log.Fatal(err.Error())
|
||||||
|
@ -387,31 +338,6 @@ func ExecuteSchedules(tick int) {
|
||||||
if tick%30 == 0 {
|
if tick%30 == 0 {
|
||||||
// Executing every 30 ticks
|
// Executing every 30 ticks
|
||||||
log.Println(taskGetEdgeApps())
|
log.Println(taskGetEdgeApps())
|
||||||
// RESET SOME VARIABLES HERE IF NEEDED, SINCE SYSTEM IS UNBLOCKED
|
|
||||||
utils.WriteOption("BACKUP_IS_WORKING", "0")
|
|
||||||
|
|
||||||
// Check is Last Backup time (in unix time) is older than 1 h
|
|
||||||
lastBackup := utils.ReadOption("BACKUP_LAST_RUN")
|
|
||||||
if lastBackup != "" {
|
|
||||||
lastBackupTime, err := strconv.ParseInt(lastBackup, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Error parsing last backup time: " + err.Error())
|
|
||||||
} else {
|
|
||||||
secondsSinceLastBackup := time.Now().Unix() - lastBackupTime
|
|
||||||
if secondsSinceLastBackup > 3600 {
|
|
||||||
// If last backup is older than 1 hour, set BACKUP_IS_WORKING to 0
|
|
||||||
log.Println("Last backup was older than 1 hour, performing auto backup...")
|
|
||||||
log.Println(taskAutoBackup())
|
|
||||||
} else {
|
|
||||||
|
|
||||||
log.Println("Last backup is " + fmt.Sprint(secondsSinceLastBackup) + " seconds old (less than 1 hour ago), skipping auto backup...")
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.Println("Last backup time not found, skipping performing auto backup...")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if tick%60 == 0 {
|
if tick%60 == 0 {
|
||||||
|
@ -419,308 +345,10 @@ func ExecuteSchedules(tick int) {
|
||||||
log.Println("System IP is: " + ip)
|
log.Println("System IP is: " + ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tick%3600 == 0 {
|
|
||||||
// Executing every 3600 ticks (1 hour)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just add a schedule here if you need a custom one (every "tick hour", every "tick day", etc...)
|
// Just add a schedule here if you need a custom one (every "tick hour", every "tick day", etc...)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func taskSetupBackups(args taskSetupBackupsArgs) string {
|
|
||||||
fmt.Println("Executing taskSetupBackups" + args.Service)
|
|
||||||
// ...
|
|
||||||
service_url := ""
|
|
||||||
key_id_name := "AWS_ACCESS_KEY_ID"
|
|
||||||
key_secret_name := "AWS_SECRET_ACCESS_KEY"
|
|
||||||
repo_location := "/home/system/components/apps/"
|
|
||||||
service_found := false
|
|
||||||
|
|
||||||
switch args.Service {
|
|
||||||
case "s3":
|
|
||||||
service_url = "s3.amazonaws.com/"
|
|
||||||
service_found = true
|
|
||||||
case "b2":
|
|
||||||
service_url = ""
|
|
||||||
key_id_name = "B2_ACCOUNT_ID"
|
|
||||||
key_secret_name = "B2_ACCOUNT_KEY"
|
|
||||||
service_found = true
|
|
||||||
case "wasabi":
|
|
||||||
service_found = true
|
|
||||||
service_url = "s3.wasabisys.com/"
|
|
||||||
}
|
|
||||||
|
|
||||||
if !service_found {
|
|
||||||
fmt.Println("Service not found")
|
|
||||||
return "{\"status\": \"error\", \"message\": \"Service not found\"}"
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Creating env vars for authentication with backup service")
|
|
||||||
os.Setenv(key_id_name, args.AccessKeyID)
|
|
||||||
os.Setenv(key_secret_name, args.SecretAccessKey)
|
|
||||||
|
|
||||||
fmt.Println("Creating restic password file")
|
|
||||||
|
|
||||||
system.CreateBackupsPasswordFile(args.RepositoryPassword)
|
|
||||||
|
|
||||||
fmt.Println("Initializing restic repository")
|
|
||||||
utils.WriteOption("BACKUP_IS_WORKING", "1")
|
|
||||||
|
|
||||||
cmdArgs := []string{"-r", args.Service + ":" + service_url + args.RepositoryName + ":" + repo_location, "init", "--password-file", utils.GetPath(utils.BackupPasswordFileLocation), "--verbose=3"}
|
|
||||||
|
|
||||||
result := utils.ExecAndStream(repo_location, "restic", cmdArgs)
|
|
||||||
|
|
||||||
utils.WriteOption("BACKUP_IS_WORKING", "0")
|
|
||||||
|
|
||||||
// Write backup settings to table
|
|
||||||
utils.WriteOption("BACKUP_SERVICE", args.Service)
|
|
||||||
utils.WriteOption("BACKUP_SERVICE_URL", service_url)
|
|
||||||
utils.WriteOption("BACKUP_REPOSITORY_NAME", args.RepositoryName)
|
|
||||||
utils.WriteOption("BACKUP_REPOSITORY_PASSWORD", args.RepositoryPassword)
|
|
||||||
utils.WriteOption("BACKUP_REPOSITORY_ACCESS_KEY_ID", args.AccessKeyID)
|
|
||||||
utils.WriteOption("BACKUP_REPOSITORY_SECRET_ACCESS_KEY", args.SecretAccessKey)
|
|
||||||
utils.WriteOption("BACKUP_REPOSITORY_LOCATION", repo_location)
|
|
||||||
|
|
||||||
// See if result contains the substring "Fatal:"
|
|
||||||
if strings.Contains(result, "Fatal:") {
|
|
||||||
fmt.Println("Error initializing restic repository")
|
|
||||||
|
|
||||||
utils.WriteOption("BACKUP_STATUS", "error")
|
|
||||||
utils.WriteOption("BACKUP_ERROR_MESSAGE", result)
|
|
||||||
|
|
||||||
return "{\"status\": \"error\", \"message\": \"" + result + "\"}"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save options to database
|
|
||||||
utils.WriteOption("BACKUP_STATUS", "initiated")
|
|
||||||
|
|
||||||
// Populate Stats right away
|
|
||||||
taskGetBackupStatus()
|
|
||||||
|
|
||||||
return "{\"status\": \"ok\"}"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func taskRemoveBackups() string {
|
|
||||||
|
|
||||||
fmt.Println("Executing taskRemoveBackups")
|
|
||||||
|
|
||||||
// ... This deletes the restic repository
|
|
||||||
// cmdArgs := []string{"-r", "s3:https://s3.amazonaws.com/edgebox-backups:/home/system/components/apps/", "forget", "latest", "--password-file", utils.GetPath(utils.BackupPasswordFileLocation), "--verbose=3"}
|
|
||||||
|
|
||||||
utils.WriteOption("BACKUP_STATUS", "")
|
|
||||||
utils.WriteOption("BACKUP_IS_WORKING", "0")
|
|
||||||
|
|
||||||
return "{\"status\": \"ok\"}"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func taskBackup() string {
|
|
||||||
fmt.Println("Executing taskBackup")
|
|
||||||
|
|
||||||
// Load Backup Options
|
|
||||||
backup_service := utils.ReadOption("BACKUP_SERVICE")
|
|
||||||
backup_service_url := utils.ReadOption("BACKUP_SERVICE_URL")
|
|
||||||
backup_repository_name := utils.ReadOption("BACKUP_REPOSITORY_NAME")
|
|
||||||
// backup_repository_password := utils.ReadOption("BACKUP_REPOSITORY_PASSWORD")
|
|
||||||
backup_repository_access_key_id := utils.ReadOption("BACKUP_REPOSITORY_ACCESS_KEY_ID")
|
|
||||||
backup_repository_secret_access_key := utils.ReadOption("BACKUP_REPOSITORY_SECRET_ACCESS_KEY")
|
|
||||||
backup_repository_location := utils.ReadOption("BACKUP_REPOSITORY_LOCATION")
|
|
||||||
|
|
||||||
key_id_name := "AWS_ACCESS_KEY_ID"
|
|
||||||
key_secret_name := "AWS_SECRET_ACCESS_KEY"
|
|
||||||
service_found := false
|
|
||||||
|
|
||||||
switch backup_service {
|
|
||||||
case "s3":
|
|
||||||
service_found = true
|
|
||||||
case "b2":
|
|
||||||
key_id_name = "B2_ACCOUNT_ID"
|
|
||||||
key_secret_name = "B2_ACCOUNT_KEY"
|
|
||||||
service_found = true
|
|
||||||
case "wasabi":
|
|
||||||
service_found = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if !service_found {
|
|
||||||
fmt.Println("Service not found")
|
|
||||||
return "{\"status\": \"error\", \"message\": \"Backup Service not found\"}"
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Creating env vars for authentication with backup service")
|
|
||||||
fmt.Println(key_id_name)
|
|
||||||
os.Setenv(key_id_name, backup_repository_access_key_id)
|
|
||||||
fmt.Println(key_secret_name)
|
|
||||||
os.Setenv(key_secret_name, backup_repository_secret_access_key)
|
|
||||||
|
|
||||||
|
|
||||||
utils.WriteOption("BACKUP_IS_WORKING", "1")
|
|
||||||
|
|
||||||
// ... This backs up the restic repository
|
|
||||||
cmdArgs := []string{"-r", backup_service + ":" + backup_service_url + backup_repository_name + ":" + backup_repository_location, "backup", backup_repository_location, "--password-file", utils.GetPath(utils.BackupPasswordFileLocation), "--verbose=3"}
|
|
||||||
result := utils.ExecAndStream(backup_repository_location, "restic", cmdArgs)
|
|
||||||
|
|
||||||
utils.WriteOption("BACKUP_IS_WORKING", "0")
|
|
||||||
// Write as Unix timestamp
|
|
||||||
utils.WriteOption("BACKUP_LAST_RUN", strconv.FormatInt(time.Now().Unix(), 10))
|
|
||||||
|
|
||||||
// See if result contains the substring "Fatal:"
|
|
||||||
if strings.Contains(result, "Fatal:") {
|
|
||||||
fmt.Println("Error backing up")
|
|
||||||
utils.WriteOption("BACKUP_STATUS", "error")
|
|
||||||
utils.WriteOption("BACKUP_ERROR_MESSAGE", result)
|
|
||||||
return "{\"status\": \"error\", \"message\": \"" + result + "\"}"
|
|
||||||
}
|
|
||||||
|
|
||||||
utils.WriteOption("BACKUP_STATUS", "working")
|
|
||||||
taskGetBackupStatus()
|
|
||||||
return "{\"status\": \"ok\"}"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func taskRestoreBackup() string {
|
|
||||||
fmt.Println("Executing taskRestoreBackup")
|
|
||||||
|
|
||||||
// Load Backup Options
|
|
||||||
backup_service := utils.ReadOption("BACKUP_SERVICE")
|
|
||||||
backup_service_url := utils.ReadOption("BACKUP_SERVICE_URL")
|
|
||||||
backup_repository_name := utils.ReadOption("BACKUP_REPOSITORY_NAME")
|
|
||||||
// backup_repository_password := utils.ReadOption("BACKUP_REPOSITORY_PASSWORD")
|
|
||||||
backup_repository_access_key_id := utils.ReadOption("BACKUP_REPOSITORY_ACCESS_KEY_ID")
|
|
||||||
backup_repository_secret_access_key := utils.ReadOption("BACKUP_REPOSITORY_SECRET_ACCESS_KEY")
|
|
||||||
backup_repository_location := utils.ReadOption("BACKUP_REPOSITORY_LOCATION")
|
|
||||||
|
|
||||||
key_id_name := "AWS_ACCESS_KEY_ID"
|
|
||||||
key_secret_name := "AWS_SECRET_ACCESS_KEY"
|
|
||||||
service_found := false
|
|
||||||
|
|
||||||
switch backup_service {
|
|
||||||
case "s3":
|
|
||||||
service_found = true
|
|
||||||
case "b2":
|
|
||||||
key_id_name = "B2_ACCOUNT_ID"
|
|
||||||
key_secret_name = "B2_ACCOUNT_KEY"
|
|
||||||
service_found = true
|
|
||||||
case "wasabi":
|
|
||||||
service_found = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if !service_found {
|
|
||||||
fmt.Println("Service not found")
|
|
||||||
return "{\"status\": \"error\", \"message\": \"Backup Service not found\"}"
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Creating env vars for authentication with backup service")
|
|
||||||
fmt.Println(key_id_name)
|
|
||||||
os.Setenv(key_id_name, backup_repository_access_key_id)
|
|
||||||
fmt.Println(key_secret_name)
|
|
||||||
os.Setenv(key_secret_name, backup_repository_secret_access_key)
|
|
||||||
|
|
||||||
|
|
||||||
utils.WriteOption("BACKUP_IS_WORKING", "1")
|
|
||||||
|
|
||||||
fmt.Println("Stopping All EdgeApps")
|
|
||||||
// Stop All EdgeApps
|
|
||||||
edgeapps.StopAllEdgeApps()
|
|
||||||
|
|
||||||
// Copy all files in /home/system/components/apps/ to a backup folder
|
|
||||||
fmt.Println("Copying all files in /home/system/components/apps/ to a backup folder")
|
|
||||||
os.MkdirAll(utils.GetPath(utils.EdgeAppsBackupPath + "temp/"), 0777)
|
|
||||||
system.CopyDir(utils.GetPath(utils.EdgeAppsPath), utils.GetPath(utils.EdgeAppsBackupPath + "temp/"))
|
|
||||||
|
|
||||||
fmt.Println("Removing all files in /home/system/components/apps/")
|
|
||||||
os.RemoveAll(utils.GetPath(utils.EdgeAppsPath))
|
|
||||||
|
|
||||||
// Create directory /home/system/components/apps/
|
|
||||||
fmt.Println("Creating directory /home/system/components/apps/")
|
|
||||||
os.MkdirAll(utils.GetPath(utils.EdgeAppsPath), 0777)
|
|
||||||
|
|
||||||
// ... This restores up the restic repository
|
|
||||||
cmdArgs := []string{"-r", backup_service + ":" + backup_service_url + backup_repository_name + ":" + backup_repository_location, "restore", "latest", "--target", "/", "--path", backup_repository_location, "--password-file", utils.GetPath(utils.BackupPasswordFileLocation), "--verbose=3"}
|
|
||||||
result := utils.ExecAndStream(backup_repository_location, "restic", cmdArgs)
|
|
||||||
|
|
||||||
taskGetBackupStatus()
|
|
||||||
|
|
||||||
edgeapps.RestartEdgeAppsService()
|
|
||||||
|
|
||||||
utils.WriteOption("BACKUP_IS_WORKING", "0")
|
|
||||||
|
|
||||||
// See if result contains the substring "Fatal:"
|
|
||||||
if strings.Contains(result, "Fatal:") {
|
|
||||||
// Copy all files from backup folder to /home/system/components/apps/
|
|
||||||
os.MkdirAll(utils.GetPath(utils.EdgeAppsPath), 0777)
|
|
||||||
system.CopyDir(utils.GetPath(utils.EdgeAppsBackupPath + "temp/"), utils.GetPath(utils.EdgeAppsPath))
|
|
||||||
|
|
||||||
fmt.Println("Error restoring backup: ")
|
|
||||||
utils.WriteOption("BACKUP_STATUS", "error")
|
|
||||||
utils.WriteOption("BACKUP_ERROR_MESSAGE", result)
|
|
||||||
return "{\"status\": \"error\", \"message\": \"" + result + "\"}"
|
|
||||||
}
|
|
||||||
|
|
||||||
utils.WriteOption("BACKUP_STATUS", "working")
|
|
||||||
taskGetBackupStatus()
|
|
||||||
return "{\"status\": \"ok\"}"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func taskAutoBackup() string {
|
|
||||||
fmt.Println("Executing taskAutoBackup")
|
|
||||||
|
|
||||||
// Get Backup Status
|
|
||||||
backup_status := utils.ReadOption("BACKUP_STATUS")
|
|
||||||
// We only backup is the status is "working"
|
|
||||||
if backup_status == "working" {
|
|
||||||
return taskBackup()
|
|
||||||
} else {
|
|
||||||
fmt.Println("Backup status is not working... skipping")
|
|
||||||
return "{\"status\": \"skipped\"}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func taskGetBackupStatus() string {
|
|
||||||
fmt.Println("Executing taskGetBackupStatus")
|
|
||||||
|
|
||||||
// Load Backup Options
|
|
||||||
backup_service := utils.ReadOption("BACKUP_SERVICE")
|
|
||||||
backup_service_url := utils.ReadOption("BACKUP_SERVICE_URL")
|
|
||||||
backup_repository_name := utils.ReadOption("BACKUP_REPOSITORY_NAME")
|
|
||||||
// backup_repository_password := utils.ReadOption("BACKUP_REPOSITORY_PASSWORD")
|
|
||||||
backup_repository_access_key_id := utils.ReadOption("BACKUP_REPOSITORY_ACCESS_KEY_ID")
|
|
||||||
backup_repository_secret_access_key := utils.ReadOption("BACKUP_REPOSITORY_SECRET_ACCESS_KEY")
|
|
||||||
backup_repository_location := utils.ReadOption("BACKUP_REPOSITORY_LOCATION")
|
|
||||||
|
|
||||||
key_id_name := "AWS_ACCESS_KEY_ID"
|
|
||||||
key_secret_name := "AWS_SECRET_ACCESS_KEY"
|
|
||||||
service_found := false
|
|
||||||
|
|
||||||
switch backup_service {
|
|
||||||
case "s3":
|
|
||||||
service_found = true
|
|
||||||
case "b2":
|
|
||||||
key_id_name = "B2_ACCOUNT_ID"
|
|
||||||
key_secret_name = "B2_ACCOUNT_KEY"
|
|
||||||
service_found = true
|
|
||||||
case "wasabi":
|
|
||||||
service_found = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if !service_found {
|
|
||||||
fmt.Println("Service not found")
|
|
||||||
return "{\"status\": \"error\", \"message\": \"Backup Service not found\"}"
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Creating env vars for authentication with backup service")
|
|
||||||
os.Setenv(key_id_name, backup_repository_access_key_id)
|
|
||||||
os.Setenv(key_secret_name, backup_repository_secret_access_key)
|
|
||||||
|
|
||||||
// ... This gets the restic repository status
|
|
||||||
cmdArgs := []string{"-r", backup_service + ":" + backup_service_url + backup_repository_name + ":" + backup_repository_location, "stats", "--password-file", utils.GetPath(utils.BackupPasswordFileLocation), "--verbose=3"}
|
|
||||||
utils.WriteOption("BACKUP_STATS", utils.ExecAndStream(backup_repository_location, "restic", cmdArgs))
|
|
||||||
|
|
||||||
return "{\"status\": \"ok\"}"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func taskSetupTunnel(args taskSetupTunnelArgs) string {
|
func taskSetupTunnel(args taskSetupTunnelArgs) string {
|
||||||
fmt.Println("Executing taskSetupTunnel")
|
fmt.Println("Executing taskSetupTunnel")
|
||||||
wsPath := utils.GetPath(utils.WsPath)
|
wsPath := utils.GetPath(utils.WsPath)
|
||||||
|
|
|
@ -16,7 +16,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExecAndStream : Runs a terminal command, but streams progress instead of outputting. Ideal for long lived process that need to be logged.
|
// ExecAndStream : Runs a terminal command, but streams progress instead of outputting. Ideal for long lived process that need to be logged.
|
||||||
func ExecAndStream(path string, command string, args []string) string {
|
func ExecAndStream(path string, command string, args []string) {
|
||||||
|
|
||||||
cmd := exec.Command(command, args...)
|
cmd := exec.Command(command, args...)
|
||||||
|
|
||||||
|
@ -27,17 +27,13 @@ func ExecAndStream(path string, command string, args []string) string {
|
||||||
|
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
|
|
||||||
outStr, errStr := string(stdoutBuf.Bytes()), string(stderrBuf.Bytes())
|
|
||||||
|
|
||||||
returnVal := outStr
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("cmd.Run() failed with %s\n", err)
|
fmt.Printf("cmd.Run() failed with %s\n", err)
|
||||||
returnVal = errStr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
outStr, errStr := string(stdoutBuf.Bytes()), string(stderrBuf.Bytes())
|
||||||
fmt.Printf("\nout:\n%s\nerr:\n%s\n", outStr, errStr)
|
fmt.Printf("\nout:\n%s\nerr:\n%s\n", outStr, errStr)
|
||||||
|
|
||||||
return returnVal
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec : Runs a terminal Command, catches and logs errors, returns the result.
|
// Exec : Runs a terminal Command, catches and logs errors, returns the result.
|
||||||
|
@ -104,12 +100,10 @@ func GetSQLiteFormattedDateTime(t time.Time) string {
|
||||||
return formatedDatetime
|
return formatedDatetime
|
||||||
}
|
}
|
||||||
|
|
||||||
const BackupPasswordFileLocation string = "backupPasswordFileLocation"
|
|
||||||
const CloudEnvFileLocation string = "cloudEnvFileLocation"
|
const CloudEnvFileLocation string = "cloudEnvFileLocation"
|
||||||
const ApiEnvFileLocation string = "apiEnvFileLocation"
|
const ApiEnvFileLocation string = "apiEnvFileLocation"
|
||||||
const ApiPath string = "apiPath"
|
const ApiPath string = "apiPath"
|
||||||
const EdgeAppsPath string = "edgeAppsPath"
|
const EdgeAppsPath string = "edgeAppsPath"
|
||||||
const EdgeAppsBackupPath string = "edgeAppsBackupPath"
|
|
||||||
const WsPath string = "wsPath"
|
const WsPath string = "wsPath"
|
||||||
|
|
||||||
// GetPath : Returns either the hardcoded path, or a overwritten value via .env file at project root. Register paths here for seamless working code between dev and prod environments ;)
|
// GetPath : Returns either the hardcoded path, or a overwritten value via .env file at project root. Register paths here for seamless working code between dev and prod environments ;)
|
||||||
|
@ -157,13 +151,6 @@ func GetPath(pathKey string) string {
|
||||||
targetPath = "/home/system/components/apps/"
|
targetPath = "/home/system/components/apps/"
|
||||||
}
|
}
|
||||||
|
|
||||||
case EdgeAppsBackupPath:
|
|
||||||
if env["EDGEAPPS_BACKUP_PATH"] != "" {
|
|
||||||
targetPath = env["EDGEAPPS_BACKUP_PATH"]
|
|
||||||
} else {
|
|
||||||
targetPath = "/home/system/components/backups/"
|
|
||||||
}
|
|
||||||
|
|
||||||
case WsPath:
|
case WsPath:
|
||||||
|
|
||||||
if env["WS_PATH"] != "" {
|
if env["WS_PATH"] != "" {
|
||||||
|
@ -172,14 +159,6 @@ func GetPath(pathKey string) string {
|
||||||
targetPath = "/home/system/components/ws/"
|
targetPath = "/home/system/components/ws/"
|
||||||
}
|
}
|
||||||
|
|
||||||
case BackupPasswordFileLocation:
|
|
||||||
|
|
||||||
if env["BACKUP_PASSWORD_FILE_LOCATION"] != "" {
|
|
||||||
targetPath = env["BACKUP_PASSWORD_FILE_LOCATION"]
|
|
||||||
} else {
|
|
||||||
targetPath = "/home/system/components/backups/pw.txt"
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
log.Printf("path_key %s nonexistant in GetPath().\n", pathKey)
|
log.Printf("path_key %s nonexistant in GetPath().\n", pathKey)
|
||||||
|
@ -228,7 +207,7 @@ func ReadOption(optionKey string) string {
|
||||||
err = db.QueryRow("SELECT value FROM option WHERE name = ?", optionKey).Scan(&optionValue)
|
err = db.QueryRow("SELECT value FROM option WHERE name = ?", optionKey).Scan(&optionValue)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err.Error())
|
log.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
db.Close()
|
db.Close()
|
||||||
|
|
Loading…
Reference in New Issue