repos / pico

pico services - prose.sh, pastes.sh, imgs.sh, feeds.sh, pgs.sh
git clone https://github.com/picosh/pico.git

pico / cmd / scripts / clean-object-store
Eric Bower · 13 Apr 24

clean.go

  1package main
  2
  3import (
  4	"log/slog"
  5	"os"
  6	"strings"
  7
  8	"github.com/picosh/pico/db"
  9	"github.com/picosh/pico/db/postgres"
 10	"github.com/picosh/pico/pgs"
 11	"github.com/picosh/pico/shared"
 12	"github.com/picosh/pico/shared/storage"
 13)
 14
 15func bail(err error) {
 16	if err != nil {
 17		panic(err)
 18	}
 19}
 20
 21type RmProject struct {
 22	user *db.User
 23	name string
 24}
 25
 26// this script will find any objects stored within Store that does not
 27// have a corresponding project inside our database.
 28func main() {
 29	// to actually commit changes, set to true
 30	writeEnv := shared.GetEnv("WRITE", "0")
 31	write := false
 32	if writeEnv == "1" {
 33		write = true
 34	}
 35	logger := slog.Default()
 36
 37	picoCfg := shared.NewConfigSite()
 38	picoCfg.Logger = logger
 39	picoCfg.DbURL = os.Getenv("DATABASE_URL")
 40	picoCfg.MinioURL = os.Getenv("MINIO_URL")
 41	picoCfg.MinioUser = os.Getenv("MINIO_ROOT_USER")
 42	picoCfg.MinioPass = os.Getenv("MINIO_ROOT_PASSWORD")
 43	picoDb := postgres.NewDB(picoCfg.DbURL, picoCfg.Logger)
 44
 45	var st storage.StorageServe
 46	var err error
 47	st, err = storage.NewStorageMinio(picoCfg.MinioURL, picoCfg.MinioUser, picoCfg.MinioPass)
 48	bail(err)
 49
 50	logger.Info("fetching all users")
 51	users, err := picoDb.FindUsers()
 52	bail(err)
 53
 54	logger.Info("fetching all buckets")
 55	buckets, err := st.ListBuckets()
 56	bail(err)
 57
 58	rmProjects := []RmProject{}
 59
 60	for _, bucketName := range buckets {
 61		// only care about pgs
 62		if !strings.HasPrefix(bucketName, "static-") {
 63			continue
 64		}
 65
 66		bucket, err := st.GetBucket(bucketName)
 67		bail(err)
 68		bucketProjects, err := st.ListObjects(bucket, "/", false)
 69		bail(err)
 70
 71		userID := strings.Replace(bucketName, "static-", "", 1)
 72		user := &db.User{
 73			ID:   userID,
 74			Name: userID,
 75		}
 76		for _, u := range users {
 77			if u.ID == userID {
 78				user = u
 79				break
 80			}
 81		}
 82		projects, err := picoDb.FindProjectsByUser(userID)
 83		bail(err)
 84		for _, bucketProject := range bucketProjects {
 85			found := false
 86			for _, project := range projects {
 87				// ignore links
 88				if project.Name != project.ProjectDir {
 89					continue
 90				}
 91				if project.Name == bucketProject.Name() {
 92					found = true
 93				}
 94			}
 95			if !found {
 96				logger.Info("marking for removal", "bucket", bucketName, "project", bucketProject.Name())
 97				rmProjects = append(rmProjects, RmProject{
 98					name: bucketProject.Name(),
 99					user: user,
100				})
101			}
102		}
103	}
104
105	session := &shared.CmdSessionLogger{
106		Log: logger,
107	}
108
109	for _, project := range rmProjects {
110		opts := &pgs.Cmd{
111			Session: session,
112			User:    project.user,
113			Store:   st,
114			Log:     logger,
115			Dbpool:  picoDb,
116			Write:   write,
117		}
118		err := opts.RmProjectAssets(project.name)
119		bail(err)
120	}
121
122	logger.Info("store projects marked for deletion", "length", len(rmProjects))
123	for _, project := range rmProjects {
124		logger.Info("removing project", "user", project.user.Name, "project", project.name)
125	}
126	if !write {
127		logger.Info("WARNING: changes not committed, need env var WRITE=1")
128	}
129}