mirror of
https://github.com/yusing/godoxy.git
synced 2025-05-20 20:52:33 +02:00

* feat: idle sleep for proxmox LXCs * refactor: replace deprecated docker api types * chore(api): remove debug task list endpoint * refactor: move servemux to gphttp/servemux; favicon.go to v1/favicon * refactor: introduce Pool interface, move agent_pool to agent module * refactor: simplify api code * feat: introduce debug api * refactor: remove net.URL and net.CIDR types, improved unmarshal handling * chore: update Makefile for debug build tag, update README * chore: add gperr.Unwrap method * feat: relative time and duration formatting * chore: add ROOT_DIR environment variable, refactor * migration: move homepage override and icon cache to $BASE_DIR/data, add migration code * fix: nil dereference on marshalling service health * fix: wait for route deletion * chore: enhance tasks debuggability * feat: stdout access logger and MultiWriter * fix(agent): remove agent properly on verify error * fix(metrics): disk exclusion logic and added corresponding tests * chore: update schema and prettify, fix package.json and Makefile * fix: I/O buffer not being shrunk before putting back to pool * feat: enhanced error handling module * chore: deps upgrade * feat: better value formatting and handling --------- Co-authored-by: yusing <yusing@6uo.me>
129 lines
3.2 KiB
Go
129 lines
3.2 KiB
Go
package provider
|
|
|
|
import (
|
|
"context"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/yusing/go-proxy/internal/gperr"
|
|
idlewatcher "github.com/yusing/go-proxy/internal/idlewatcher/types"
|
|
"github.com/yusing/go-proxy/internal/proxmox"
|
|
"github.com/yusing/go-proxy/internal/watcher"
|
|
"github.com/yusing/go-proxy/internal/watcher/events"
|
|
)
|
|
|
|
type ProxmoxProvider struct {
|
|
*proxmox.Node
|
|
vmid int
|
|
lxcName string
|
|
running bool
|
|
}
|
|
|
|
const proxmoxStateCheckInterval = 1 * time.Second
|
|
|
|
var ErrNodeNotFound = gperr.New("node not found in pool")
|
|
|
|
func NewProxmoxProvider(nodeName string, vmid int) (idlewatcher.Provider, error) {
|
|
node, ok := proxmox.Nodes.Get(nodeName)
|
|
if !ok {
|
|
return nil, ErrNodeNotFound.Subject(nodeName).
|
|
Withf("available nodes: %s", proxmox.AvailableNodeNames())
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
|
defer cancel()
|
|
|
|
lxcName, err := node.LXCName(ctx, vmid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &ProxmoxProvider{Node: node, vmid: vmid, lxcName: lxcName}, nil
|
|
}
|
|
|
|
func (p *ProxmoxProvider) ContainerPause(ctx context.Context) error {
|
|
return p.LXCAction(ctx, p.vmid, proxmox.LXCSuspend)
|
|
}
|
|
|
|
func (p *ProxmoxProvider) ContainerUnpause(ctx context.Context) error {
|
|
return p.LXCAction(ctx, p.vmid, proxmox.LXCResume)
|
|
}
|
|
|
|
func (p *ProxmoxProvider) ContainerStart(ctx context.Context) error {
|
|
return p.LXCAction(ctx, p.vmid, proxmox.LXCStart)
|
|
}
|
|
|
|
func (p *ProxmoxProvider) ContainerStop(ctx context.Context, _ idlewatcher.Signal, _ int) error {
|
|
return p.LXCAction(ctx, p.vmid, proxmox.LXCShutdown)
|
|
}
|
|
|
|
func (p *ProxmoxProvider) ContainerKill(ctx context.Context, _ idlewatcher.Signal) error {
|
|
return p.LXCAction(ctx, p.vmid, proxmox.LXCShutdown)
|
|
}
|
|
|
|
func (p *ProxmoxProvider) ContainerStatus(ctx context.Context) (idlewatcher.ContainerStatus, error) {
|
|
status, err := p.LXCStatus(ctx, p.vmid)
|
|
if err != nil {
|
|
return idlewatcher.ContainerStatusError, err
|
|
}
|
|
switch status {
|
|
case proxmox.LXCStatusRunning:
|
|
return idlewatcher.ContainerStatusRunning, nil
|
|
case proxmox.LXCStatusStopped:
|
|
return idlewatcher.ContainerStatusStopped, nil
|
|
}
|
|
return idlewatcher.ContainerStatusError, idlewatcher.ErrUnexpectedContainerStatus.Subject(string(status))
|
|
}
|
|
|
|
func (p *ProxmoxProvider) Watch(ctx context.Context) (<-chan watcher.Event, <-chan gperr.Error) {
|
|
eventCh := make(chan watcher.Event)
|
|
errCh := make(chan gperr.Error)
|
|
|
|
go func() {
|
|
defer close(eventCh)
|
|
defer close(errCh)
|
|
|
|
var err error
|
|
p.running, err = p.LXCIsRunning(ctx, p.vmid)
|
|
if err != nil {
|
|
errCh <- gperr.Wrap(err)
|
|
return
|
|
}
|
|
|
|
ticker := time.NewTicker(proxmoxStateCheckInterval)
|
|
defer ticker.Stop()
|
|
|
|
event := watcher.Event{
|
|
Type: events.EventTypeDocker,
|
|
ActorID: strconv.Itoa(p.vmid),
|
|
ActorName: p.lxcName,
|
|
}
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-ticker.C:
|
|
status, err := p.ContainerStatus(ctx)
|
|
if err != nil {
|
|
errCh <- gperr.Wrap(err)
|
|
return
|
|
}
|
|
running := status == idlewatcher.ContainerStatusRunning
|
|
if p.running != running {
|
|
p.running = running
|
|
if running {
|
|
event.Action = events.ActionContainerStart
|
|
} else {
|
|
event.Action = events.ActionContainerStop
|
|
}
|
|
eventCh <- event
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
|
|
return eventCh, errCh
|
|
}
|
|
|
|
func (p *ProxmoxProvider) Close() {
|
|
// noop
|
|
}
|