Files
godoxy-yusing/internal/types/idlewatcher.go
yusing 978dd886c0 refactor(proxmox): change VMID type from int to uint64 across Proxmox provider
Updates VMID parameter and field types from int to uint64 throughout the Proxmox provider implementation,
including API request structures, provider structs, client methods, and LXC-related functions.
Also updates string conversion calls from strconv.Itoa to strconv.FormatUint.
2026-02-10 16:53:07 +08:00

157 lines
4.5 KiB
Go

package types
import (
"errors"
"net/url"
"strconv"
"strings"
"time"
gperr "github.com/yusing/goutils/errs"
)
type (
IdlewatcherProviderConfig struct {
Proxmox *ProxmoxConfig `json:"proxmox,omitempty"`
Docker *DockerConfig `json:"docker,omitempty"`
} // @name IdlewatcherProviderConfig
IdlewatcherConfigBase struct {
// 0: no idle watcher.
// Positive: idle watcher with idle timeout.
// Negative: idle watcher as a dependency.
IdleTimeout time.Duration `json:"idle_timeout"`
WakeTimeout time.Duration `json:"wake_timeout"`
StopTimeout time.Duration `json:"stop_timeout"`
StopMethod ContainerStopMethod `json:"stop_method"`
StopSignal ContainerSignal `json:"stop_signal,omitempty"`
} // @name IdlewatcherConfigBase
IdlewatcherConfig struct {
IdlewatcherProviderConfig
IdlewatcherConfigBase
StartEndpoint string `json:"start_endpoint,omitempty"` // Optional path that must be hit to start container
DependsOn []string `json:"depends_on,omitempty"`
NoLoadingPage bool `json:"no_loading_page,omitempty"`
valErr error
} // @name IdlewatcherConfig
ContainerStopMethod string // @name ContainerStopMethod
ContainerSignal string // @name ContainerSignal
DockerConfig struct {
DockerCfg DockerProviderConfig `json:"docker_cfg" validate:"required"`
ContainerID string `json:"container_id" validate:"required"`
ContainerName string `json:"container_name" validate:"required"`
} // @name IdlewatcherDockerConfig
ProxmoxConfig struct {
Node string `json:"node" validate:"required"`
VMID uint64 `json:"vmid" validate:"required"`
} // @name IdlewatcherProxmoxNodeConfig
)
const (
ContainerWakeTimeoutDefault = 30 * time.Second
ContainerStopTimeoutDefault = 1 * time.Minute
ContainerStopMethodPause ContainerStopMethod = "pause"
ContainerStopMethodStop ContainerStopMethod = "stop"
ContainerStopMethodKill ContainerStopMethod = "kill"
)
var (
ErrMissingProviderConfig = errors.New("missing idlewatcher provider config")
ErrInvalidStopMethod = errors.New("invalid stop method")
ErrInvalidStopSignal = errors.New("invalid stop signal")
ErrEmptyStartEndpoint = errors.New("start endpoint must not be empty if defined")
)
func (c *IdlewatcherConfig) Key() string {
if c.Docker != nil {
return c.Docker.ContainerID
}
return c.Proxmox.Node + ":" + strconv.FormatUint(c.Proxmox.VMID, 10)
}
func (c *IdlewatcherConfig) ContainerName() string {
if c.Docker != nil {
return c.Docker.ContainerName
}
return "lxc-" + strconv.FormatUint(c.Proxmox.VMID, 10)
}
func (c *IdlewatcherConfig) Validate() error {
if c.IdleTimeout == 0 { // zero idle timeout means no idle watcher
c.valErr = nil
return nil
}
var errs gperr.Builder
errs.AddRange(
c.validateProvider(),
c.validateTimeouts(),
c.validateStopMethod(),
c.validateStopSignal(),
c.validateStartEndpoint(),
)
c.valErr = errs.Error()
return c.valErr
}
func (c *IdlewatcherConfig) ValErr() error {
return c.valErr
}
func (c *IdlewatcherConfig) validateProvider() error {
if c.Docker == nil && c.Proxmox == nil {
return ErrMissingProviderConfig
}
return nil
}
func (c *IdlewatcherConfig) validateTimeouts() error { //nolint:unparam
if c.WakeTimeout == 0 {
c.WakeTimeout = ContainerWakeTimeoutDefault
}
if c.StopTimeout == 0 {
c.StopTimeout = ContainerStopTimeoutDefault
}
return nil
}
func (c *IdlewatcherConfig) validateStopMethod() error {
switch c.StopMethod {
case "":
c.StopMethod = ContainerStopMethodStop
return nil
case ContainerStopMethodPause, ContainerStopMethodStop, ContainerStopMethodKill:
return nil
default:
return gperr.PrependSubject(ErrInvalidStopMethod, string(c.StopMethod))
}
}
func (c *IdlewatcherConfig) validateStopSignal() error {
switch c.StopSignal {
case "", "SIGINT", "SIGTERM", "SIGQUIT", "SIGHUP", "INT", "TERM", "QUIT", "HUP":
return nil
default:
return gperr.PrependSubject(ErrInvalidStopSignal, string(c.StopSignal))
}
}
func (c *IdlewatcherConfig) validateStartEndpoint() error {
if c.StartEndpoint == "" {
return nil
}
// checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195
// emulate browser and strip the '#' suffix prior to validation. see issue-#237
if i := strings.Index(c.StartEndpoint, "#"); i > -1 {
c.StartEndpoint = c.StartEndpoint[:i]
}
if len(c.StartEndpoint) == 0 {
return ErrEmptyStartEndpoint
}
_, err := url.ParseRequestURI(c.StartEndpoint)
return err
}