mirror of
https://github.com/MengMengCode/CLICD.git
synced 2026-08-05 05:36:07 +08:00
138 lines
3.8 KiB
Go
138 lines
3.8 KiB
Go
package lxc
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"clicd/internal/config"
|
|
)
|
|
|
|
// IsExpired checks if a container has passed its expiration date
|
|
func IsExpired(c config.Container) bool {
|
|
return isContainerExpired(c, time.Now())
|
|
}
|
|
|
|
// StopExpiredContainers stops running containers whose expiration date has passed.
|
|
func (m *Manager) StopExpiredContainers(now time.Time) {
|
|
for _, container := range config.AppConfig.Containers {
|
|
if container.IsKVM() || !isContainerExpired(container, now) {
|
|
continue
|
|
}
|
|
|
|
status, err := m.GetContainerStatus(container.LxcName())
|
|
if err != nil {
|
|
status = container.Status
|
|
}
|
|
if status != "running" {
|
|
continue
|
|
}
|
|
|
|
fmt.Printf("Container %s (ID=%d) expired at %s, stopping...\n", container.Name, container.ID, container.ExpiresAt)
|
|
if err := m.StopContainer(container.ID); err != nil {
|
|
fmt.Printf("Warning: failed to stop expired container %s: %v\n", container.Name, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// StartExpiryScanner runs a background loop that tracks traffic & stops expired/over-traffic containers every 30 seconds
|
|
func (m *Manager) StartExpiryScanner() {
|
|
go func() {
|
|
for {
|
|
time.Sleep(30 * time.Second)
|
|
now := time.Now()
|
|
m.AccumulateTraffic() // track network traffic deltas
|
|
m.StopExpiredContainers(now)
|
|
m.StopTrafficExceededContainers(now)
|
|
}
|
|
}()
|
|
}
|
|
|
|
// StopTrafficExceededContainers stops running containers that have exceeded their monthly traffic limit
|
|
func (m *Manager) StopTrafficExceededContainers(now time.Time) {
|
|
currentMonth := now.Format("2006-01")
|
|
saved := false
|
|
for i := range config.AppConfig.Containers {
|
|
c := &config.AppConfig.Containers[i]
|
|
if c.IsKVM() || c.Status != "running" {
|
|
continue
|
|
}
|
|
|
|
// Reset traffic if new month
|
|
if c.TrafficResetDate != currentMonth {
|
|
c.TrafficUsedRX = 0
|
|
c.TrafficUsedTX = 0
|
|
c.TrafficResetDate = currentMonth
|
|
saved = true
|
|
continue
|
|
}
|
|
|
|
// Check traffic limits
|
|
if isTrafficExceeded(*c) {
|
|
fmt.Printf("Container %s (ID=%d) exceeded traffic limit, stopping...\n", c.Name, c.ID)
|
|
if err := m.StopContainer(c.ID); err != nil {
|
|
fmt.Printf("Warning: failed to stop traffic-exceeded container %s: %v\n", c.Name, err)
|
|
}
|
|
}
|
|
}
|
|
if saved {
|
|
config.SaveConfig()
|
|
}
|
|
}
|
|
|
|
func isTrafficExceeded(c config.Container) bool {
|
|
if c.TrafficMode == "in_out" {
|
|
inLimit := int64(c.TrafficInGB) * 1073741824
|
|
outLimit := int64(c.TrafficOutGB) * 1073741824
|
|
if inLimit > 0 && c.TrafficUsedRX >= inLimit {
|
|
return true
|
|
}
|
|
if outLimit > 0 && c.TrafficUsedTX >= outLimit {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
totalLimit := int64(c.MonthlyTrafficGB) * 1073741824
|
|
return totalLimit > 0 && (c.TrafficUsedRX+c.TrafficUsedTX) >= totalLimit
|
|
}
|
|
|
|
// ResetTraffic resets traffic counters for a container
|
|
func (m *Manager) ResetTraffic(id int) error {
|
|
c := config.FindContainer(id)
|
|
if c == nil {
|
|
return fmt.Errorf("container not found: %d", id)
|
|
}
|
|
c.TrafficUsedRX = 0
|
|
c.TrafficUsedTX = 0
|
|
c.TrafficResetDate = time.Now().Format("2006-01")
|
|
config.SaveConfig()
|
|
return nil
|
|
}
|
|
|
|
// IsTrafficExceeded checks if a container has exceeded its traffic limit
|
|
func IsTrafficExceeded(c config.Container) bool {
|
|
return isTrafficExceeded(c)
|
|
}
|
|
|
|
func isContainerExpired(container config.Container, now time.Time) bool {
|
|
expiresAt, ok := ParseExpiration(container.ExpiresAt)
|
|
return ok && !now.Before(expiresAt)
|
|
}
|
|
|
|
// ParseExpiration parses an expiration string. A YYYY-MM-DD value expires at the
|
|
// end of that local day, while RFC3339 values are treated as exact timestamps.
|
|
func ParseExpiration(value string) (time.Time, bool) {
|
|
if value == "" {
|
|
return time.Time{}, false
|
|
}
|
|
|
|
if parsed, err := time.Parse(time.RFC3339, value); err == nil {
|
|
return parsed, true
|
|
}
|
|
|
|
if parsed, err := time.ParseInLocation("2006-01-02", value, time.Local); err == nil {
|
|
return parsed.Add(24 * time.Hour), true
|
|
}
|
|
|
|
return time.Time{}, false
|
|
}
|