212 lines
5.3 KiB
Go
212 lines
5.3 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
|
|
"gitea.ceperka.net/rosti/incus-sentinel/http_notifier"
|
|
"gitea.ceperka.net/rosti/incus-sentinel/incus"
|
|
"gitea.ceperka.net/rosti/incus-sentinel/scheduler"
|
|
"github.com/urfave/cli/v3"
|
|
)
|
|
|
|
func main() {
|
|
cmd := &cli.Command{
|
|
Name: "incus-sentinel",
|
|
Usage: "Keeps an eye on sync and backups of Incus instances",
|
|
Commands: []*cli.Command{
|
|
{
|
|
Name: "list",
|
|
Usage: "List all instances with their sync and backup settings",
|
|
Flags: []cli.Flag{},
|
|
Action: func(c context.Context, cmd *cli.Command) error {
|
|
i := incus.NewIncusDriver()
|
|
insts, err := i.GetInstances("")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, inst := range insts {
|
|
s := inst.Sentinel()
|
|
if s.Backup || s.Sync {
|
|
fmt.Printf("%s\n", inst.Name)
|
|
fmt.Printf(" Backup: %t (%s)\n", s.Backup, s.BackupSchedule)
|
|
fmt.Printf(" Sync: %t (%s)\n", s.Sync, s.SyncSchedule)
|
|
if s.Sync {
|
|
fmt.Printf(" Sync Target: %s (pool: %s, suffix: %s)\n", s.SyncTargetRemote, s.SyncTargetPool, s.SyncTargetInstanceSuffix)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
},
|
|
},
|
|
{
|
|
Name: "list-volumes",
|
|
Usage: "List all volumes with their sync and backup settings",
|
|
Flags: []cli.Flag{},
|
|
Action: func(c context.Context, cmd *cli.Command) error {
|
|
i := incus.NewIncusDriver()
|
|
vols, err := i.GetVolumes("")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, vol := range vols {
|
|
s := vol.Sentinel()
|
|
if s.Backup || s.Sync {
|
|
fmt.Printf("%s/%s/%s\n", vol.Project, vol.Pool, vol.Name)
|
|
fmt.Printf(" Backup: %t (%s, %s)\n", s.Backup, s.BackupMode, s.BackupSchedule)
|
|
fmt.Printf(" Sync: %t (%s)\n", s.Sync, s.SyncSchedule)
|
|
if s.Sync {
|
|
fmt.Printf(" Sync Target: %s (pool: %s, suffix: %s)\n", s.SyncTargetRemote, s.SyncTargetPool, s.SyncTargetVolumeSuffix)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
},
|
|
},
|
|
{
|
|
Name: "sync",
|
|
Usage: "Syncs all instances where sync is enabled",
|
|
Flags: []cli.Flag{},
|
|
Action: func(c context.Context, cmd *cli.Command) error {
|
|
i := incus.NewIncusDriver()
|
|
insts, err := i.GetInstances("")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, inst := range insts {
|
|
s := inst.Sentinel()
|
|
if s.Sync {
|
|
fmt.Println(".. syncing", inst.Name)
|
|
err := i.Sync(inst.Project, inst.Name, fmt.Sprintf("%s%s", inst.Name, s.SyncTargetInstanceSuffix), s.SyncTargetRemote, s.SyncTargetPool)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
},
|
|
},
|
|
{
|
|
Name: "sync-volumes",
|
|
Usage: "Syncs all volumes where sync is enabled",
|
|
Flags: []cli.Flag{},
|
|
Action: func(c context.Context, cmd *cli.Command) error {
|
|
i := incus.NewIncusDriver()
|
|
vols, err := i.GetVolumes("")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, vol := range vols {
|
|
s := vol.Sentinel()
|
|
if s.Sync {
|
|
fmt.Printf(".. syncing %s/%s/%s\n", vol.Project, vol.Pool, vol.Name)
|
|
|
|
targetPool := vol.Pool
|
|
if s.SyncTargetPool != "" {
|
|
targetPool = s.SyncTargetPool
|
|
}
|
|
|
|
err := i.SyncVolume(vol.Project, vol.Pool, vol.Name, s.SyncTargetRemote, targetPool, fmt.Sprintf("%s%s", vol.Name, s.SyncTargetVolumeSuffix))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
},
|
|
},
|
|
{
|
|
Name: "backup",
|
|
Usage: "Backs up all instances where backup is enabled",
|
|
Flags: []cli.Flag{},
|
|
Action: func(c context.Context, cmd *cli.Command) error {
|
|
i := incus.NewIncusDriver()
|
|
insts, err := i.GetInstances("")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, inst := range insts {
|
|
s := inst.Sentinel()
|
|
if s.Backup {
|
|
fmt.Println(".. backing up", inst.Name)
|
|
err := i.Backup(inst.Project, inst.Name, []string{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
},
|
|
},
|
|
{
|
|
Name: "backup-volumes",
|
|
Usage: "Backs up all volumes where backup is enabled",
|
|
Flags: []cli.Flag{},
|
|
Action: func(c context.Context, cmd *cli.Command) error {
|
|
i := incus.NewIncusDriver()
|
|
vols, err := i.GetVolumes("")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, vol := range vols {
|
|
s := vol.Sentinel()
|
|
if s.Backup {
|
|
fmt.Printf(".. backing up %s/%s/%s\n", vol.Project, vol.Pool, vol.Name)
|
|
|
|
if s.BackupMode == "dir" {
|
|
err := i.BackupVolumeDir(vol.Project, vol.Pool, vol.Name, []string{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else if s.BackupMode == "native" {
|
|
err := i.BackupVolumeNative(vol.Project, vol.Pool, vol.Name, []string{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
return fmt.Errorf("invalid backup mode: %s", s.BackupMode)
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return nil
|
|
},
|
|
},
|
|
{
|
|
Name: "run",
|
|
Usage: "Runs the sentinel that syncs and backs up instances based on their configuration",
|
|
Flags: []cli.Flag{},
|
|
Action: func(c context.Context, cmd *cli.Command) error {
|
|
i := incus.NewIncusDriver()
|
|
n := http_notifier.NewNotifier()
|
|
|
|
s := scheduler.NewScheduler(i, n)
|
|
err := s.Run()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
if err := cmd.Run(context.Background(), os.Args); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|