From 36b5cd18e8dfd2bfeda884347a632391852297db Mon Sep 17 00:00:00 2001 From: CrazyMax Date: Wed, 7 Dec 2022 11:42:49 +0100 Subject: [PATCH 1/2] store: use constants for directory names Signed-off-by: CrazyMax --- store/store.go | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/store/store.go b/store/store.go index 1ca650fc852..8796c7afbab 100644 --- a/store/store.go +++ b/store/store.go @@ -12,11 +12,16 @@ import ( "github.com/pkg/errors" ) +const ( + instanceDir = "instances" + defaultsDir = "defaults" +) + func New(root string) (*Store, error) { - if err := os.MkdirAll(filepath.Join(root, "instances"), 0700); err != nil { + if err := os.MkdirAll(filepath.Join(root, instanceDir), 0700); err != nil { return nil, err } - if err := os.MkdirAll(filepath.Join(root, "defaults"), 0700); err != nil { + if err := os.MkdirAll(filepath.Join(root, defaultsDir), 0700); err != nil { return nil, err } return &Store{root: root}, nil @@ -43,7 +48,7 @@ type Txn struct { } func (t *Txn) List() ([]*NodeGroup, error) { - pp := filepath.Join(t.s.root, "instances") + pp := filepath.Join(t.s.root, instanceDir) fis, err := os.ReadDir(pp) if err != nil { return nil, err @@ -73,7 +78,7 @@ func (t *Txn) NodeGroupByName(name string) (*NodeGroup, error) { if err != nil { return nil, err } - dt, err := os.ReadFile(filepath.Join(t.s.root, "instances", name)) + dt, err := os.ReadFile(filepath.Join(t.s.root, instanceDir, name)) if err != nil { return nil, err } @@ -93,7 +98,7 @@ func (t *Txn) Save(ng *NodeGroup) error { if err != nil { return err } - return ioutils.AtomicWriteFile(filepath.Join(t.s.root, "instances", name), dt, 0600) + return ioutils.AtomicWriteFile(filepath.Join(t.s.root, instanceDir, name), dt, 0600) } func (t *Txn) Remove(name string) error { @@ -101,7 +106,7 @@ func (t *Txn) Remove(name string) error { if err != nil { return err } - return os.RemoveAll(filepath.Join(t.s.root, "instances", name)) + return os.RemoveAll(filepath.Join(t.s.root, instanceDir, name)) } func (t *Txn) SetCurrent(key, name string, global, def bool) error { @@ -121,11 +126,11 @@ func (t *Txn) SetCurrent(key, name string, global, def bool) error { h := toHash(key) if def { - if err := ioutils.AtomicWriteFile(filepath.Join(t.s.root, "defaults", h), []byte(name), 0600); err != nil { + if err := ioutils.AtomicWriteFile(filepath.Join(t.s.root, defaultsDir, h), []byte(name), 0600); err != nil { return err } } else { - os.RemoveAll(filepath.Join(t.s.root, "defaults", h)) // ignore error + os.RemoveAll(filepath.Join(t.s.root, defaultsDir, h)) // ignore error } return nil } @@ -173,7 +178,7 @@ func (t *Txn) Current(key string) (*NodeGroup, error) { h := toHash(key) - dt, err = os.ReadFile(filepath.Join(t.s.root, "defaults", h)) + dt, err = os.ReadFile(filepath.Join(t.s.root, defaultsDir, h)) if err != nil { if os.IsNotExist(err) { t.reset(key) From 8c472771418cc676e69fd7744396b7b9a07b7849 Mon Sep 17 00:00:00 2001 From: CrazyMax Date: Wed, 7 Dec 2022 11:44:33 +0100 Subject: [PATCH 2/2] store: set nodegroup last activity Signed-off-by: CrazyMax --- commands/bake.go | 3 +++ commands/build.go | 14 ++++++++++++++ commands/inspect.go | 3 +++ store/nodegroup.go | 4 +++- store/store.go | 37 ++++++++++++++++++++++++++++++++++++ store/store_test.go | 1 + store/storeutil/storeutil.go | 9 ++++++--- 7 files changed, 67 insertions(+), 4 deletions(-) diff --git a/commands/bake.go b/commands/bake.go index 4c7ffc4f892..e36d36b943b 100644 --- a/commands/bake.go +++ b/commands/bake.go @@ -111,6 +111,9 @@ func runBake(dockerCli command.Cli, targets []string, in bakeOptions) (err error if err != nil { return err } + if err = updateLastActivity(dockerCli, b.NodeGroup); err != nil { + return errors.Wrapf(err, "failed to update builder last activity time") + } nodes, err = b.LoadNodes(ctx, false) if err != nil { return err diff --git a/commands/build.go b/commands/build.go index 3114a0000ae..e8e3c231085 100644 --- a/commands/build.go +++ b/commands/build.go @@ -18,6 +18,8 @@ import ( "github.com/docker/buildx/build" "github.com/docker/buildx/builder" "github.com/docker/buildx/monitor" + "github.com/docker/buildx/store" + "github.com/docker/buildx/store/storeutil" "github.com/docker/buildx/util/buildflags" "github.com/docker/buildx/util/confutil" "github.com/docker/buildx/util/dockerutil" @@ -261,6 +263,9 @@ func runBuild(dockerCli command.Cli, in buildOptions) (err error) { if err != nil { return err } + if err = updateLastActivity(dockerCli, b.NodeGroup); err != nil { + return errors.Wrapf(err, "failed to update builder last activity time") + } nodes, err := b.LoadNodes(ctx, false) if err != nil { return err @@ -730,3 +735,12 @@ func isExperimental() bool { } return false } + +func updateLastActivity(dockerCli command.Cli, ng *store.NodeGroup) error { + txn, release, err := storeutil.GetStore(dockerCli) + if err != nil { + return err + } + defer release() + return txn.UpdateLastActivity(ng) +} diff --git a/commands/inspect.go b/commands/inspect.go index 8cf2ce6892f..fc4530b70d2 100644 --- a/commands/inspect.go +++ b/commands/inspect.go @@ -50,6 +50,9 @@ func runInspect(dockerCli command.Cli, in inspectOptions) error { w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0) fmt.Fprintf(w, "Name:\t%s\n", b.Name) fmt.Fprintf(w, "Driver:\t%s\n", b.Driver) + if !b.NodeGroup.LastActivity.IsZero() { + fmt.Fprintf(w, "Last Activity:\t%v\n", b.NodeGroup.LastActivity) + } if err != nil { fmt.Fprintf(w, "Error:\t%s\n", err.Error()) diff --git a/store/nodegroup.go b/store/nodegroup.go index cbfcf225ed8..823470dd43e 100644 --- a/store/nodegroup.go +++ b/store/nodegroup.go @@ -2,6 +2,7 @@ package store import ( "fmt" + "time" "github.com/containerd/containerd/platforms" "github.com/docker/buildx/util/confutil" @@ -18,7 +19,8 @@ type NodeGroup struct { Dynamic bool // skip the following fields from being saved in the store - DockerContext bool `json:"-"` + DockerContext bool `json:"-"` + LastActivity time.Time `json:"-"` } type Node struct { diff --git a/store/store.go b/store/store.go index 8796c7afbab..72d1811edf9 100644 --- a/store/store.go +++ b/store/store.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "sort" + "time" "github.com/docker/docker/pkg/ioutils" "github.com/gofrs/flock" @@ -15,6 +16,7 @@ import ( const ( instanceDir = "instances" defaultsDir = "defaults" + activityDir = "activity" ) func New(root string) (*Store, error) { @@ -24,6 +26,9 @@ func New(root string) (*Store, error) { if err := os.MkdirAll(filepath.Join(root, defaultsDir), 0700); err != nil { return nil, err } + if err := os.MkdirAll(filepath.Join(root, activityDir), 0700); err != nil { + return nil, err + } return &Store{root: root}, nil } @@ -86,6 +91,9 @@ func (t *Txn) NodeGroupByName(name string) (*NodeGroup, error) { if err := json.Unmarshal(dt, &ng); err != nil { return nil, err } + if ng.LastActivity, err = t.GetLastActivity(&ng); err != nil { + return nil, err + } return &ng, nil } @@ -94,6 +102,9 @@ func (t *Txn) Save(ng *NodeGroup) error { if err != nil { return err } + if err := t.UpdateLastActivity(ng); err != nil { + return err + } dt, err := json.Marshal(ng) if err != nil { return err @@ -106,6 +117,9 @@ func (t *Txn) Remove(name string) error { if err != nil { return err } + if err := t.RemoveLastActivity(name); err != nil { + return err + } return os.RemoveAll(filepath.Join(t.s.root, instanceDir, name)) } @@ -135,6 +149,29 @@ func (t *Txn) SetCurrent(key, name string, global, def bool) error { return nil } +func (t *Txn) UpdateLastActivity(ng *NodeGroup) error { + return ioutils.AtomicWriteFile(filepath.Join(t.s.root, activityDir, ng.Name), []byte(time.Now().UTC().Format(time.RFC3339)), 0600) +} + +func (t *Txn) GetLastActivity(ng *NodeGroup) (la time.Time, _ error) { + dt, err := os.ReadFile(filepath.Join(t.s.root, activityDir, ng.Name)) + if err != nil { + if os.IsNotExist(errors.Cause(err)) { + return la, nil + } + return la, err + } + return time.Parse(time.RFC3339, string(dt)) +} + +func (t *Txn) RemoveLastActivity(name string) error { + name, err := ValidateName(name) + if err != nil { + return err + } + return os.RemoveAll(filepath.Join(t.s.root, activityDir, name)) +} + func (t *Txn) reset(key string) error { dt, err := json.Marshal(current{Key: key}) if err != nil { diff --git a/store/store_test.go b/store/store_test.go index 5586db3ef0d..f116ba14287 100644 --- a/store/store_test.go +++ b/store/store_test.go @@ -92,6 +92,7 @@ func TestNodeManagement(t *testing.T) { require.NoError(t, err) require.Equal(t, "mybuild", ng.Name) require.Equal(t, "mydriver", ng.Driver) + require.True(t, !ng.LastActivity.IsZero()) _, err = txn.NodeGroupByName("mybuild2") require.Error(t, err) diff --git a/store/storeutil/storeutil.go b/store/storeutil/storeutil.go index 04eae317c57..e6c06828d0e 100644 --- a/store/storeutil/storeutil.go +++ b/store/storeutil/storeutil.go @@ -85,7 +85,7 @@ func GetNodeGroup(txn *store.Txn, dockerCli command.Cli, name string) (*store.No } for _, l := range list { if l.Name == name { - return &store.NodeGroup{ + ng = &store.NodeGroup{ Name: name, Nodes: []store.Node{ { @@ -93,8 +93,11 @@ func GetNodeGroup(txn *store.Txn, dockerCli command.Cli, name string) (*store.No Endpoint: name, }, }, - DockerContext: true, - }, nil + } + if ng.LastActivity, err = txn.GetLastActivity(ng); err != nil { + return nil, err + } + return ng, nil } }