116 lines
3.2 KiB
Go
116 lines
3.2 KiB
Go
package scheduler
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/robfig/cron/v3"
|
|
"go.uber.org/zap"
|
|
|
|
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/config"
|
|
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/leaderelection"
|
|
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/service/ipcleanup"
|
|
)
|
|
|
|
// IPCleanupScheduler handles scheduled IP address cleanup for GDPR compliance
|
|
// CWE-359: IP addresses must be deleted after 90 days
|
|
type IPCleanupScheduler struct {
|
|
cron *cron.Cron
|
|
cleanupService *ipcleanup.CleanupService
|
|
leaderElection leaderelection.LeaderElection
|
|
logger *zap.Logger
|
|
enabled bool
|
|
schedulePattern string
|
|
}
|
|
|
|
// ProvideIPCleanupScheduler creates a new IPCleanupScheduler from config
|
|
func ProvideIPCleanupScheduler(
|
|
cfg *config.Config,
|
|
cleanupService *ipcleanup.CleanupService,
|
|
leaderElection leaderelection.LeaderElection,
|
|
logger *zap.Logger,
|
|
) *IPCleanupScheduler {
|
|
// IP cleanup enabled if configured (defaults to true for GDPR compliance)
|
|
enabled := cfg.Scheduler.IPCleanupEnabled
|
|
// Default: run daily at 2 AM
|
|
schedulePattern := cfg.Scheduler.IPCleanupSchedule
|
|
|
|
// Create cron with logger
|
|
cronLog := &cronLogger{logger: logger.Named("cron")}
|
|
c := cron.New(
|
|
cron.WithLogger(cronLog),
|
|
cron.WithChain(
|
|
cron.Recover(cronLog),
|
|
),
|
|
)
|
|
|
|
return &IPCleanupScheduler{
|
|
cron: c,
|
|
cleanupService: cleanupService,
|
|
leaderElection: leaderElection,
|
|
logger: logger.Named("ip-cleanup-scheduler"),
|
|
enabled: enabled,
|
|
schedulePattern: schedulePattern,
|
|
}
|
|
}
|
|
|
|
// Start starts the IP cleanup scheduler
|
|
func (s *IPCleanupScheduler) Start() error {
|
|
if !s.enabled {
|
|
s.logger.Info("IP cleanup scheduler is disabled")
|
|
return nil
|
|
}
|
|
|
|
s.logger.Info("starting IP cleanup scheduler for GDPR compliance",
|
|
zap.String("schedule", s.schedulePattern),
|
|
zap.String("retention_period", "90 days"))
|
|
|
|
// Schedule the IP cleanup job
|
|
_, err := s.cron.AddFunc(s.schedulePattern, s.cleanupIPs)
|
|
if err != nil {
|
|
s.logger.Error("failed to schedule IP cleanup job", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
// Start the cron scheduler
|
|
s.cron.Start()
|
|
|
|
s.logger.Info("IP cleanup scheduler started successfully")
|
|
return nil
|
|
}
|
|
|
|
// Stop stops the IP cleanup scheduler
|
|
func (s *IPCleanupScheduler) Stop() {
|
|
if !s.enabled {
|
|
return
|
|
}
|
|
|
|
s.logger.Info("stopping IP cleanup scheduler")
|
|
ctx := s.cron.Stop()
|
|
<-ctx.Done()
|
|
s.logger.Info("IP cleanup scheduler stopped")
|
|
}
|
|
|
|
// cleanupIPs is the cron job function that cleans up expired IP addresses
|
|
func (s *IPCleanupScheduler) cleanupIPs() {
|
|
// Only execute if this instance is the leader
|
|
if !s.leaderElection.IsLeader() {
|
|
s.logger.Debug("skipping IP cleanup - not the leader instance",
|
|
zap.String("instance_id", s.leaderElection.GetInstanceID()))
|
|
return
|
|
}
|
|
|
|
s.logger.Info("executing scheduled IP cleanup for GDPR compliance as leader instance",
|
|
zap.String("instance_id", s.leaderElection.GetInstanceID()))
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
|
|
defer cancel()
|
|
|
|
err := s.cleanupService.CleanupExpiredIPs(ctx)
|
|
if err != nil {
|
|
s.logger.Error("IP cleanup failed", zap.Error(err))
|
|
return
|
|
}
|
|
|
|
s.logger.Info("IP cleanup completed successfully")
|
|
}
|