36b3af2e3d
PR Check / Code Quality: Format (push) Failing after 1s
PR Check / Code Quality: Lint (darwin) (push) Failing after 0s
PR Check / Code Quality: Lint (freebsd) (push) Failing after 1s
PR Check / Code Quality: Lint (windows) (push) Failing after 1s
PR Check / Code Quality: Lint (linux) (push) Failing after 1s
PR Check / Security: Vulnerability Scan (push) Failing after 0s
Update Documentation / update-docs (push) Failing after 2s
PR Check / Code Quality: Vendor (push) Failing after 1s
PR Check / Code Quality: Coverage (push) Failing after 0s
PR Check / Tests: Unit (macos-latest) (push) Has been cancelled
PR Check / Tests: Unit (ubuntu-24.04) (push) Has been cancelled
PR Check / Tests: Unit (ubuntu-24.04-arm) (push) Has been cancelled
PR Check / Tests: Unit (windows-latest) (push) Has been cancelled
83 lines
2.1 KiB
Go
83 lines
2.1 KiB
Go
package proc
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"os/exec"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/pranshuparmar/witr/pkg/model"
|
|
)
|
|
|
|
func init() { registerRuntime(lxcRuntime{}) }
|
|
|
|
type lxcRuntime struct{}
|
|
|
|
func (lxcRuntime) Name() string { return "lxc" }
|
|
func (lxcRuntime) Available() bool { return binAvailable("lxc-ls") }
|
|
|
|
// List uses `lxc-ls --fancy --format json`, which returns a flat per-container
|
|
// record with name/state/ipv4/ipv6/groups/autostart/unprivileged. Image and
|
|
// PID aren't part of the listing — PID is filled in lazily via HostPID, image
|
|
// is left empty since classic LXC doesn't track image metadata after create.
|
|
func (lxcRuntime) List() []*model.ContainerMatch {
|
|
ctx, cancel := context.WithTimeout(context.Background(), runtimeQueryTimeout)
|
|
defer cancel()
|
|
out, err := exec.CommandContext(ctx, "lxc-ls", "--fancy", "--format", "json").Output()
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return parseLXCList(out)
|
|
}
|
|
|
|
func (lxcRuntime) HostPID(id string) int {
|
|
ctx, cancel := context.WithTimeout(context.Background(), runtimeQueryTimeout)
|
|
defer cancel()
|
|
out, err := exec.CommandContext(ctx, "lxc-info", "-n", id, "-p", "-H").Output()
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
pid, _ := strconv.Atoi(strings.TrimSpace(string(out)))
|
|
return pid
|
|
}
|
|
|
|
type lxcLsEntry struct {
|
|
Name string `json:"name"`
|
|
State string `json:"state"`
|
|
Autostart string `json:"autostart"`
|
|
Groups string `json:"groups"`
|
|
IPv4 string `json:"ipv4"`
|
|
IPv6 string `json:"ipv6"`
|
|
Unprivileged string `json:"unprivileged"`
|
|
}
|
|
|
|
func parseLXCList(out []byte) []*model.ContainerMatch {
|
|
var entries []lxcLsEntry
|
|
if err := json.Unmarshal(out, &entries); err != nil {
|
|
return nil
|
|
}
|
|
var matches []*model.ContainerMatch
|
|
for _, e := range entries {
|
|
state := strings.ToLower(e.State)
|
|
networks := ""
|
|
switch {
|
|
case e.IPv4 != "" && e.IPv6 != "":
|
|
networks = e.IPv4 + ", " + e.IPv6
|
|
case e.IPv4 != "":
|
|
networks = e.IPv4
|
|
case e.IPv6 != "":
|
|
networks = e.IPv6
|
|
}
|
|
matches = append(matches, &model.ContainerMatch{
|
|
Runtime: "lxc",
|
|
ID: e.Name,
|
|
Name: e.Name,
|
|
State: state,
|
|
Status: e.State,
|
|
Networks: networks,
|
|
})
|
|
}
|
|
return matches
|
|
}
|