Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b25ade5f3d | |||
| ebdcff1049 |
@ -20,7 +20,7 @@ import (
|
||||
"hakurei.app/internal"
|
||||
"hakurei.app/internal/env"
|
||||
"hakurei.app/internal/outcome"
|
||||
"hakurei.app/internal/state"
|
||||
"hakurei.app/internal/store"
|
||||
"hakurei.app/message"
|
||||
"hakurei.app/system/dbus"
|
||||
)
|
||||
@ -322,7 +322,7 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
||||
c.NewCommand("ps", "List active instances", func(args []string) error {
|
||||
var sc hst.Paths
|
||||
env.CopyPaths().Copy(&sc, new(outcome.Hsu).MustID(nil))
|
||||
printPs(os.Stdout, time.Now().UTC(), state.NewMulti(msg, sc.RunDirPath), flagShort, flagJSON)
|
||||
printPs(os.Stdout, time.Now().UTC(), store.NewMulti(msg, sc.RunDirPath), flagShort, flagJSON)
|
||||
return errSuccess
|
||||
}).Flag(&flagShort, "short", command.BoolFlag(false), "Print instance id")
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ import (
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal/env"
|
||||
"hakurei.app/internal/outcome"
|
||||
"hakurei.app/internal/state"
|
||||
"hakurei.app/internal/store"
|
||||
"hakurei.app/message"
|
||||
)
|
||||
|
||||
@ -85,8 +85,8 @@ func tryIdentifier(msg message.Msg, name string) (config *hst.Config, entry *hst
|
||||
return tryIdentifierEntries(msg, name, func() map[hst.ID]*hst.State {
|
||||
var sc hst.Paths
|
||||
env.CopyPaths().Copy(&sc, new(outcome.Hsu).MustID(nil))
|
||||
s := state.NewMulti(msg, sc.RunDirPath)
|
||||
if entries, err := state.Join(s); err != nil {
|
||||
s := store.NewMulti(msg, sc.RunDirPath)
|
||||
if entries, err := store.Join(s); err != nil {
|
||||
msg.GetLogger().Printf("cannot join store: %v", err) // not fatal
|
||||
return nil
|
||||
} else {
|
||||
|
||||
@ -14,7 +14,7 @@ import (
|
||||
"hakurei.app/internal"
|
||||
"hakurei.app/internal/env"
|
||||
"hakurei.app/internal/outcome"
|
||||
"hakurei.app/internal/state"
|
||||
"hakurei.app/internal/store"
|
||||
"hakurei.app/message"
|
||||
)
|
||||
|
||||
@ -168,9 +168,9 @@ func printShowInstance(
|
||||
}
|
||||
|
||||
// printPs writes a representation of active instances to output.
|
||||
func printPs(output io.Writer, now time.Time, s state.Store, short, flagJSON bool) {
|
||||
func printPs(output io.Writer, now time.Time, s store.Compat, short, flagJSON bool) {
|
||||
var entries map[hst.ID]*hst.State
|
||||
if e, err := state.Join(s); err != nil {
|
||||
if e, err := store.Join(s); err != nil {
|
||||
log.Fatalf("cannot join store: %v", err)
|
||||
} else {
|
||||
entries = e
|
||||
|
||||
@ -6,7 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal/state"
|
||||
"hakurei.app/internal/store"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -709,6 +709,6 @@ func TestPrintPs(t *testing.T) {
|
||||
type stubStore map[hst.ID]*hst.State
|
||||
|
||||
func (s stubStore) Join() (map[hst.ID]*hst.State, error) { return s, nil }
|
||||
func (s stubStore) Do(int, func(c state.Cursor)) (bool, error) { panic("unreachable") }
|
||||
func (s stubStore) Do(int, func(c store.Cursor)) (bool, error) { panic("unreachable") }
|
||||
func (s stubStore) List() ([]int, error) { panic("unreachable") }
|
||||
func (s stubStore) Close() error { return nil }
|
||||
|
||||
@ -15,7 +15,7 @@ import (
|
||||
"hakurei.app/container/fhs"
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal"
|
||||
"hakurei.app/internal/state"
|
||||
"hakurei.app/internal/store"
|
||||
"hakurei.app/message"
|
||||
"hakurei.app/system"
|
||||
)
|
||||
@ -34,7 +34,7 @@ type mainState struct {
|
||||
// Time is nil if no process was ever created.
|
||||
Time *time.Time
|
||||
|
||||
store state.Store
|
||||
store store.Compat
|
||||
cancel context.CancelFunc
|
||||
cmd *exec.Cmd
|
||||
cmdWait chan error
|
||||
@ -127,7 +127,7 @@ func (ms mainState) beforeExit(isFault bool) {
|
||||
}
|
||||
|
||||
if ms.uintptr&mainNeedsRevert != 0 {
|
||||
if ok, err := ms.store.Do(ms.k.state.identity.unwrap(), func(c state.Cursor) {
|
||||
if ok, err := ms.store.Do(ms.k.state.identity.unwrap(), func(c store.Cursor) {
|
||||
if ms.uintptr&mainNeedsDestroy != 0 {
|
||||
if err := c.Destroy(ms.k.state.id.unwrap()); err != nil {
|
||||
perror(err, "destroy state entry")
|
||||
@ -220,7 +220,7 @@ func (k *outcome) main(msg message.Msg) {
|
||||
ms.fatal("cannot commit system setup:", err)
|
||||
}
|
||||
ms.uintptr |= mainNeedsRevert
|
||||
ms.store = state.NewMulti(msg, k.state.sc.RunDirPath)
|
||||
ms.store = store.NewMulti(msg, k.state.sc.RunDirPath)
|
||||
|
||||
ctx, cancel := context.WithCancel(k.ctx)
|
||||
defer cancel()
|
||||
@ -281,7 +281,7 @@ func (k *outcome) main(msg message.Msg) {
|
||||
}
|
||||
|
||||
// shim accepted setup payload, create process state
|
||||
if ok, err := ms.store.Do(k.state.identity.unwrap(), func(c state.Cursor) {
|
||||
if ok, err := ms.store.Do(k.state.identity.unwrap(), func(c store.Cursor) {
|
||||
if err := c.Save(&hst.State{
|
||||
ID: k.state.id.unwrap(),
|
||||
PID: os.Getpid(),
|
||||
|
||||
@ -1,64 +0,0 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"maps"
|
||||
|
||||
"hakurei.app/hst"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrDuplicate = errors.New("store contains duplicates")
|
||||
)
|
||||
|
||||
/*
|
||||
Joiner is the interface that wraps the Join method.
|
||||
|
||||
The Join function uses Joiner if available.
|
||||
*/
|
||||
type Joiner interface {
|
||||
Join() (map[hst.ID]*hst.State, error)
|
||||
}
|
||||
|
||||
// Join returns joined state entries of all active identities.
|
||||
func Join(s Store) (map[hst.ID]*hst.State, error) {
|
||||
if j, ok := s.(Joiner); ok {
|
||||
return j.Join()
|
||||
}
|
||||
|
||||
var (
|
||||
aids []int
|
||||
entries = make(map[hst.ID]*hst.State)
|
||||
|
||||
el int
|
||||
res map[hst.ID]*hst.State
|
||||
loadErr error
|
||||
)
|
||||
|
||||
if ln, err := s.List(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
aids = ln
|
||||
}
|
||||
|
||||
for _, aid := range aids {
|
||||
if _, err := s.Do(aid, func(c Cursor) {
|
||||
res, loadErr = c.Load()
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if loadErr != nil {
|
||||
return nil, loadErr
|
||||
}
|
||||
|
||||
// save expected length
|
||||
el = len(entries) + len(res)
|
||||
maps.Copy(entries, res)
|
||||
if len(entries) != el {
|
||||
return nil, ErrDuplicate
|
||||
}
|
||||
}
|
||||
|
||||
return entries, nil
|
||||
}
|
||||
@ -1,7 +1,8 @@
|
||||
// Package state provides cross-process state tracking for hakurei container instances.
|
||||
package state
|
||||
package store
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"maps"
|
||||
"strconv"
|
||||
|
||||
"hakurei.app/container/check"
|
||||
@ -11,7 +12,7 @@ import (
|
||||
|
||||
/* this provides an implementation of Store on top of the improved state tracking to ease in the changes */
|
||||
|
||||
type Store interface {
|
||||
type Compat interface {
|
||||
// Do calls f exactly once and ensures store exclusivity until f returns.
|
||||
// Returns whether f is called and any errors during the locking process.
|
||||
// Cursor provided to f becomes invalid as soon as f returns.
|
||||
@ -59,7 +60,7 @@ func (s storeAdapter) List() ([]int, error) {
|
||||
}
|
||||
|
||||
// NewMulti returns an instance of the multi-file store.
|
||||
func NewMulti(msg message.Msg, prefix *check.Absolute) Store {
|
||||
func NewMulti(msg message.Msg, prefix *check.Absolute) Compat {
|
||||
return storeAdapter{msg, newStore(prefix.Append("state"))}
|
||||
}
|
||||
|
||||
@ -129,3 +130,57 @@ func (h *storeHandle) Len() (int, error) {
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
var (
|
||||
ErrDuplicate = errors.New("store contains duplicates")
|
||||
)
|
||||
|
||||
// Joiner is the interface that wraps the Join method.
|
||||
//
|
||||
// The Join function uses Joiner if available.
|
||||
type Joiner interface {
|
||||
Join() (map[hst.ID]*hst.State, error)
|
||||
}
|
||||
|
||||
// Join returns joined state entries of all active identities.
|
||||
func Join(s Compat) (map[hst.ID]*hst.State, error) {
|
||||
if j, ok := s.(Joiner); ok {
|
||||
return j.Join()
|
||||
}
|
||||
|
||||
var (
|
||||
aids []int
|
||||
entries = make(map[hst.ID]*hst.State)
|
||||
|
||||
el int
|
||||
res map[hst.ID]*hst.State
|
||||
loadErr error
|
||||
)
|
||||
|
||||
if ln, err := s.List(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
aids = ln
|
||||
}
|
||||
|
||||
for _, aid := range aids {
|
||||
if _, err := s.Do(aid, func(c Cursor) {
|
||||
res, loadErr = c.Load()
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if loadErr != nil {
|
||||
return nil, loadErr
|
||||
}
|
||||
|
||||
// save expected length
|
||||
el = len(entries) + len(res)
|
||||
maps.Copy(entries, res)
|
||||
if len(entries) != el {
|
||||
return nil, ErrDuplicate
|
||||
}
|
||||
}
|
||||
|
||||
return entries, nil
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package state_test
|
||||
package store_test
|
||||
|
||||
import (
|
||||
"log"
|
||||
@ -10,12 +10,12 @@ import (
|
||||
|
||||
"hakurei.app/container/check"
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal/state"
|
||||
"hakurei.app/internal/store"
|
||||
"hakurei.app/message"
|
||||
)
|
||||
|
||||
func TestMulti(t *testing.T) {
|
||||
s := state.NewMulti(message.NewMsg(log.New(log.Writer(), "multi: ", 0)), check.MustAbs(t.TempDir()))
|
||||
s := store.NewMulti(message.NewMsg(log.New(log.Writer(), "multi: ", 0)), check.MustAbs(t.TempDir()))
|
||||
|
||||
t.Run("list empty store", func(t *testing.T) {
|
||||
if identities, err := s.List(); err != nil {
|
||||
@ -43,14 +43,14 @@ func TestMulti(t *testing.T) {
|
||||
tc[i].Time = time.Now()
|
||||
}
|
||||
|
||||
do := func(identity int, f func(c state.Cursor)) {
|
||||
do := func(identity int, f func(c store.Cursor)) {
|
||||
if ok, err := s.Do(identity, f); err != nil {
|
||||
t.Fatalf("Do: ok = %v, error = %v", ok, err)
|
||||
}
|
||||
}
|
||||
|
||||
insert := func(i, identity int) {
|
||||
do(identity, func(c state.Cursor) {
|
||||
do(identity, func(c store.Cursor) {
|
||||
if err := c.Save(&tc[i]); err != nil {
|
||||
t.Fatalf("Save: error = %v", err)
|
||||
}
|
||||
@ -58,7 +58,7 @@ func TestMulti(t *testing.T) {
|
||||
}
|
||||
|
||||
check := func(i, identity int) {
|
||||
do(identity, func(c state.Cursor) {
|
||||
do(identity, func(c store.Cursor) {
|
||||
if entries, err := c.Load(); err != nil {
|
||||
t.Fatalf("Load: error = %v", err)
|
||||
} else if got, ok := entries[tc[i].ID]; !ok {
|
||||
@ -98,19 +98,19 @@ func TestMulti(t *testing.T) {
|
||||
}
|
||||
|
||||
// join store
|
||||
if entries, err := state.Join(s); err != nil {
|
||||
if entries, err := store.Join(s); err != nil {
|
||||
t.Fatalf("Join: error = %v", err)
|
||||
} else if len(entries) != 3 {
|
||||
t.Fatalf("Join(s) = %#v", entries)
|
||||
}
|
||||
|
||||
// clear identity 1
|
||||
do(1, func(c state.Cursor) {
|
||||
do(1, func(c store.Cursor) {
|
||||
if err := c.Destroy(tc[insertEntryOtherApp].ID); err != nil {
|
||||
t.Fatalf("Destroy: error = %v", err)
|
||||
}
|
||||
})
|
||||
do(1, func(c state.Cursor) {
|
||||
do(1, func(c store.Cursor) {
|
||||
if l, err := c.Len(); err != nil {
|
||||
t.Fatalf("Len: error = %v", err)
|
||||
} else if l != 0 {
|
||||
@ -1,4 +1,4 @@
|
||||
package state
|
||||
package store
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
@ -1,4 +1,4 @@
|
||||
package state
|
||||
package store
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -1,4 +1,4 @@
|
||||
package state
|
||||
package store
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
@ -1,4 +1,4 @@
|
||||
package state
|
||||
package store
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -1,4 +1,4 @@
|
||||
package state
|
||||
package store
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@ -1,4 +1,4 @@
|
||||
package state
|
||||
package store
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@ -1,4 +1,4 @@
|
||||
package state
|
||||
package store
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@ -1,4 +1,4 @@
|
||||
package state
|
||||
package store
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
Loading…
x
Reference in New Issue
Block a user