idun/main.go

322 lines
7.6 KiB
Go

package main
import (
"bufio"
"errors"
"fmt"
"github.com/rs/zerolog/log"
"github.com/urfave/cli/v2"
"gopkg.in/yaml.v3"
buckets2 "idun/pkg/buckets"
"idun/pkg/storage"
"os"
"strings"
"time"
)
type config struct {
Jobs []struct {
Name string `yaml:"name"`
Driver string `yaml:"driver"`
Config map[string]string `yaml:"config"`
Buckets buckets2.Config `yaml:"buckets"`
} `yaml:"jobs"`
Timezone string `yaml:"timezone"`
}
func main() {
app := &cli.App{
Commands: []*cli.Command{
{
Name: "plan",
Usage: "Show all Plans of Buckets",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "job",
Value: "",
Usage: "filter for job name",
},
&cli.StringFlag{
Name: "config",
Value: "config.yml",
Usage: "path to config",
},
},
Action: func(cCtx *cli.Context) error {
configPath := cCtx.String("path")
if configPath == "" {
configPath = "config.yml"
}
config, err := readConfig(configPath)
if err != nil {
log.Fatal().Err(err).Msg("cant get config")
return err
}
loc, _ := time.LoadLocation(config.Timezone)
for _, job := range config.Jobs {
if cCtx.String("job") != "" && cCtx.String("job") != job.Name {
continue
}
buckets, err := buckets2.GenerateBuckets(time.Now().In(loc), job.Buckets, loc)
if err != nil {
log.Fatal().Err(err).Interface("job", job).Msg("cant create plan for bucket")
return err
}
fmt.Println("Plan for " + job.Name)
for _, b := range buckets {
fmt.Println(b.ToString())
}
}
return nil
},
},
{
Name: "dry-run",
Usage: "Show which file idun would delete",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "job",
Value: "",
Usage: "filter for job name",
},
&cli.StringFlag{
Name: "config",
Value: "config.yml",
Usage: "path to config",
},
},
Action: func(cCtx *cli.Context) error {
configPath := cCtx.String("path")
if configPath == "" {
configPath = "config.yml"
}
config, err := readConfig(configPath)
if err != nil {
log.Fatal().Err(err).Msg("cant get config")
return err
}
loc, _ := time.LoadLocation(config.Timezone)
for _, job := range config.Jobs {
if cCtx.String("job") != "" && cCtx.String("job") != job.Name {
continue
}
log.Debug().Str("name", job.Name).Msg("Run Job")
bucketList, err := buckets2.GenerateBuckets(time.Now().In(loc), job.Buckets, loc)
if err != nil {
log.Fatal().Err(err).Interface("job", job).Msg("cant create plan for bucket")
return err
}
jobStorage, err := getFileSystem(job.Driver, job.Config)
if err != nil {
log.Fatal().Str("driver", job.Driver).Err(err).Msg("cant get driver")
return err
}
files, err := jobStorage.ListFiles()
if err != nil {
log.Fatal().Err(err).Msg("cant get files")
return err
}
log.Debug().Int("len", len(files)).Msg("got files from jobStorage")
err = buckets2.InsertFilesInBuckets(&bucketList, files)
if err != nil {
log.Fatal().Err(err).Msg("cant insert files to buckets")
}
var allFilesToDeleted []storage.File
for _, b := range bucketList {
filesToDelete, err := b.GetFilesToDelete()
if err != nil {
log.Fatal().Err(err).Msg("cant get files to delete")
return err
}
allFilesToDeleted = append(allFilesToDeleted, filesToDelete...)
}
for _, f := range files {
name, _ := f.GetName()
toDelete := contains(allFilesToDeleted, f)
if toDelete {
fmt.Println("Delete ", name)
} else {
fmt.Println("Keep ", name)
}
}
}
return nil
},
},
{
Name: "execute",
Usage: "Show which file idun would delete",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "job",
Value: "",
Usage: "filter for job name",
},
&cli.StringFlag{
Name: "config",
Value: "config.yml",
Usage: "path to config",
},
&cli.BoolFlag{
Name: "cron",
Value: false,
Usage: "Run as cron, dont ask for yes",
},
},
Action: func(cCtx *cli.Context) error {
configPath := cCtx.String("path")
if configPath == "" {
configPath = "config.yml"
}
config, err := readConfig(configPath)
if err != nil {
log.Fatal().Err(err).Msg("cant get config")
return err
}
loc, _ := time.LoadLocation(config.Timezone)
for _, job := range config.Jobs {
if cCtx.String("job") != "" && cCtx.String("job") != job.Name {
continue
}
log.Debug().Str("name", job.Name).Msg("Run Job")
bucketList, err := buckets2.GenerateBuckets(time.Now().In(loc), job.Buckets, loc)
if err != nil {
log.Fatal().Err(err).Interface("job", job).Msg("cant create plan for bucket")
return err
}
jobStorage, err := getFileSystem(job.Driver, job.Config)
if err != nil {
log.Fatal().Str("driver", job.Driver).Err(err).Msg("cant get driver")
return err
}
files, err := jobStorage.ListFiles()
if err != nil {
log.Fatal().Err(err).Msg("cant get files")
return err
}
log.Debug().Int("len", len(files)).Msg("got files from jobStorage")
err = buckets2.InsertFilesInBuckets(&bucketList, files)
if err != nil {
log.Fatal().Err(err).Msg("cant insert files to buckets")
}
var allFilesToDeleted []storage.File
for _, b := range bucketList {
filesToDelete, err := b.GetFilesToDelete()
if err != nil {
log.Fatal().Err(err).Msg("cant get files to delete")
return err
}
allFilesToDeleted = append(allFilesToDeleted, filesToDelete...)
}
for _, f := range files {
name, _ := f.GetName()
toDelete := contains(allFilesToDeleted, f)
if toDelete {
fmt.Println("Delete ", name)
} else {
fmt.Println("Keep ", name)
}
}
cron := cCtx.Bool("cron")
if !cron {
fmt.Println("Write \"yes\" to execute")
reader := bufio.NewReader(os.Stdin)
text, _ := reader.ReadString('\n')
// convert CRLF to LF
text = strings.Replace(text, "\n", "", -1)
if text == "yes" {
err = jobStorage.Delete(allFilesToDeleted)
if err != nil {
log.Fatal().Err(err).Msg("cant delete files from storage")
return err
}
}
} else {
err = jobStorage.Delete(allFilesToDeleted)
if err != nil {
log.Fatal().Err(err).Msg("cant delete files from storage")
return err
}
}
}
return nil
},
},
},
}
if err := app.Run(os.Args); err != nil {
log.Fatal().Err(err).Msg("cant finish")
}
}
func contains(files []storage.File, file storage.File) bool {
for _, f := range files {
if f == file {
return true
}
}
return false
}
func getFileSystem(driver string, config map[string]string) (storage.Storage, error) {
switch driver {
case "sftp":
sftp := storage.SFTP{Config: config}
return sftp, nil
case "s3":
s3 := storage.S3FileSystem{Config: config}
return s3, nil
case "LocaleFileSystem":
lfs := storage.LocaleFileSystem{Config: config}
return lfs, nil
}
return nil, errors.New("driver not found")
}
func readConfig(path string) (config, error) {
file, err := os.ReadFile(path)
if err != nil {
return config{}, err
}
c := config{}
err = yaml.Unmarshal(file, &c)
if err != nil {
return config{}, err
}
return c, nil
}