Files
godoxy-yusing/internal/types/idlewatcher.go

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", "SIGKILL", "SIGQUIT", "SIGHUP", "INT", "TERM", "KILL", "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
}