cmd/app: initial container template command
Test / Create distribution (push) Successful in 59s
Test / Sandbox (push) Successful in 2m54s
Test / ShareFS (push) Successful in 3m59s
Test / Hakurei (push) Successful in 4m11s
Test / Sandbox (race detector) (push) Successful in 5m38s
Test / Hakurei (race detector) (push) Successful in 6m45s
Test / Flake checks (push) Successful in 1m13s
Test / Create distribution (push) Successful in 59s
Test / Sandbox (push) Successful in 2m54s
Test / ShareFS (push) Successful in 3m59s
Test / Hakurei (push) Successful in 4m11s
Test / Sandbox (race detector) (push) Successful in 5m38s
Test / Hakurei (race detector) (push) Successful in 6m45s
Test / Flake checks (push) Successful in 1m13s
This program is an experimental frontend for cmd/hakurei. This serves as a short-term replacement of the nixos module and a testing environment to implement API useful to planterette. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
+140
@@ -0,0 +1,140 @@
|
||||
// The app program is a proof-of-concept frontend for cmd/hakurei.
|
||||
//
|
||||
// This program is not covered by the compatibility promise. The command line
|
||||
// interface and configuration syntax may change at any time.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"hakurei.app/check"
|
||||
"hakurei.app/command"
|
||||
"hakurei.app/fhs"
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/message"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
log.SetPrefix("app: ")
|
||||
msg := message.New(log.Default())
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(),
|
||||
syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
|
||||
defer stop()
|
||||
|
||||
var (
|
||||
flagVerbose bool
|
||||
flagBase string
|
||||
|
||||
base, template, initial, upper, work *check.Absolute
|
||||
)
|
||||
c := command.New(os.Stderr, log.Printf, "app", func([]string) (err error) {
|
||||
msg.SwapVerbose(flagVerbose)
|
||||
flagBase = os.ExpandEnv(flagBase)
|
||||
if flagBase == "" {
|
||||
flagBase = "state"
|
||||
}
|
||||
if flagBase, err = filepath.Abs(flagBase); err != nil {
|
||||
return
|
||||
} else if base, err = check.NewAbs(flagBase); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
template = base.Append("template")
|
||||
initial = template.Append("initial")
|
||||
upper = template.Append("upper")
|
||||
work = template.Append("work")
|
||||
return
|
||||
}).Flag(
|
||||
&flagVerbose,
|
||||
"v", command.BoolFlag(false),
|
||||
"Increase log verbosity",
|
||||
).Flag(
|
||||
&flagBase,
|
||||
"d", command.StringFlag("$HAKUREI_APP_PATH"),
|
||||
"Configuration and state directory",
|
||||
)
|
||||
|
||||
{
|
||||
var (
|
||||
flagShell string
|
||||
flagHome string
|
||||
)
|
||||
c.NewCommand(
|
||||
"enter", "Enter mutable state template",
|
||||
func([]string) error {
|
||||
config := hst.Config{
|
||||
ID: "app.hakurei.mutable",
|
||||
Container: &hst.ContainerConfig{
|
||||
Hostname: "mutable",
|
||||
Filesystem: []hst.FilesystemConfigJSON{
|
||||
{FilesystemConfig: &hst.FSOverlay{
|
||||
Target: fhs.AbsRoot,
|
||||
Lower: []*check.Absolute{initial},
|
||||
Upper: upper,
|
||||
Work: work,
|
||||
}},
|
||||
{FilesystemConfig: &hst.FSEphemeral{
|
||||
Target: fhs.AbsTmp,
|
||||
Write: true,
|
||||
Perm: 0755,
|
||||
}},
|
||||
},
|
||||
Username: "chronos",
|
||||
Flags: hst.FMultiarch |
|
||||
hst.FDevel |
|
||||
hst.FUserns |
|
||||
hst.FHostNet |
|
||||
hst.FTty,
|
||||
},
|
||||
}
|
||||
|
||||
if a, err := check.NewAbs(flagShell); err != nil {
|
||||
return err
|
||||
} else {
|
||||
config.Container.Shell = a
|
||||
config.Container.Path = a
|
||||
config.Container.Args = []string{
|
||||
"-" + filepath.Base(flagShell),
|
||||
}
|
||||
}
|
||||
|
||||
if a, err := check.NewAbs(flagHome); err != nil {
|
||||
return err
|
||||
} else {
|
||||
config.Container.Home = a
|
||||
}
|
||||
|
||||
return run(ctx, msg, &config)
|
||||
},
|
||||
).Flag(
|
||||
&flagShell,
|
||||
"shell", command.StringFlag("/bin/zsh"),
|
||||
"Shell program within container",
|
||||
).Flag(
|
||||
&flagHome,
|
||||
"home", command.StringFlag("/home/chronos"),
|
||||
"Home directory within container",
|
||||
)
|
||||
}
|
||||
|
||||
c.MustParse(os.Args[1:], func(err error) {
|
||||
if w, ok := err.(interface{ Unwrap() []error }); !ok {
|
||||
log.Fatal(err)
|
||||
} else {
|
||||
errs := w.Unwrap()
|
||||
for i, e := range errs {
|
||||
if i == len(errs)-1 {
|
||||
log.Fatal(e)
|
||||
}
|
||||
log.Println(e)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"os/exec"
|
||||
"syscall"
|
||||
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/message"
|
||||
)
|
||||
|
||||
// run starts a container via cmd/hakurei and returns after it terminates.
|
||||
func run(ctx context.Context, msg message.Msg, config *hst.Config) error {
|
||||
c, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
cmd := exec.CommandContext(c, "hakurei")
|
||||
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||
cmd.Cancel = func() error {
|
||||
return cmd.Process.Signal(syscall.SIGINT)
|
||||
}
|
||||
if msg.IsVerbose() {
|
||||
cmd.Args = append(cmd.Args, "-v")
|
||||
}
|
||||
cmd.Args = append(cmd.Args, "run", "3")
|
||||
|
||||
r, w, err := os.Pipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd.ExtraFiles = append(cmd.ExtraFiles, r)
|
||||
|
||||
if err = cmd.Start(); err != nil {
|
||||
_, _ = r.Close(), w.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
if err = r.Close(); err != nil {
|
||||
_ = w.Close()
|
||||
return err
|
||||
} else if err = json.NewEncoder(w).Encode(&config); err != nil {
|
||||
_ = w.Close()
|
||||
return err
|
||||
} else if err = w.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return cmd.Wait()
|
||||
}
|
||||
Reference in New Issue
Block a user