feat: podman-compose stack units and root/user execution scopes
- syncup: podman first, docker only as fallback (podman wins on name clash;
existing docker units found in podman switch to podman)
- syncup: group podman-compose containers into one `kind: stack` unit per
project (project, working_dir, compose_files, compose_bin from labels);
disable existing member units ("part of stack <project>")
- generator: compose mode (podman-compose up/stop, WorkingDirectory) with
pod start/stop fallback when compose binary/dir/files are missing
- reconcile: stacks disabled with "stack not found" when neither compose
files nor pod exist
- root: scan root + rootless users listed in `users:` (podman only)
- non-root: config ~/.config/unitdore/units.yaml, own user units only
- sysuser package: runuser with XDG_RUNTIME_DIR/DBUS env, home/linger lookup
- install: warn when linger is not enabled for user units
- testdata/stack: podman-compose test stack and captured podman ps fixture
- docs: README, generated-units, man page, AGENTS, PLAN
This commit is contained in:
+25
-3
@@ -10,6 +10,17 @@ import (
|
||||
|
||||
const DefaultConfigPath = "/etc/unitdore/units.yaml"
|
||||
|
||||
// UserConfigPath returns the config path used when running as a normal user.
|
||||
func UserConfigPath(home string) string {
|
||||
return filepath.Join(home, ".config", "unitdore", "units.yaml")
|
||||
}
|
||||
|
||||
// Unit kinds.
|
||||
const (
|
||||
KindContainer = "container"
|
||||
KindStack = "stack"
|
||||
)
|
||||
|
||||
// Unit represents a single managed container unit.
|
||||
type Unit struct {
|
||||
Name string `yaml:"name"`
|
||||
@@ -23,13 +34,24 @@ type Unit struct {
|
||||
Restart bool `yaml:"restart,omitempty"` // enable Restart=on-failure
|
||||
RestartSec int `yaml:"restart_sec,omitempty"` // seconds between restarts
|
||||
RestartRetries int `yaml:"restart_retries,omitempty"` // max restart attempts (StartLimitBurst)
|
||||
|
||||
// Stack fields (kind: stack) — one unit for a whole podman-compose project.
|
||||
Kind string `yaml:"kind,omitempty"` // container (default) | stack
|
||||
Project string `yaml:"project,omitempty"` // compose project name
|
||||
WorkingDir string `yaml:"working_dir,omitempty"` // compose project directory
|
||||
ComposeFiles []string `yaml:"compose_files,omitempty"` // relative to working_dir unless absolute
|
||||
ComposeBin string `yaml:"compose_bin,omitempty"` // path to podman-compose
|
||||
}
|
||||
|
||||
// IsStack reports whether the unit manages a compose stack.
|
||||
func (u Unit) IsStack() bool { return u.Kind == KindStack }
|
||||
|
||||
// Config is the root config structure.
|
||||
type Config struct {
|
||||
Units []Unit `yaml:"units"`
|
||||
Prefix string `yaml:"prefix,omitempty"` // prepended to generated service name, e.g. "prod-"
|
||||
Suffix string `yaml:"suffix,omitempty"` // appended to generated service name, e.g. "-svc"
|
||||
Units []Unit `yaml:"units"`
|
||||
Prefix string `yaml:"prefix,omitempty"` // prepended to generated service name, e.g. "prod-"
|
||||
Suffix string `yaml:"suffix,omitempty"` // appended to generated service name, e.g. "-svc"
|
||||
Users []string `yaml:"users,omitempty"` // rootless users scanned by syncup when run as root
|
||||
}
|
||||
|
||||
// Load reads and parses the config file at path.
|
||||
|
||||
Reference in New Issue
Block a user