diff --git a/cmd/blind_update.go b/cmd/blind_update.go
index c48a5fe..62e7695 100644
--- a/cmd/blind_update.go
+++ b/cmd/blind_update.go
@@ -6,7 +6,6 @@ import (
wisski_distillery "github.com/FAU-CDI/wisski-distillery"
"github.com/FAU-CDI/wisski-distillery/internal/component/instances"
"github.com/FAU-CDI/wisski-distillery/internal/core"
- "github.com/FAU-CDI/wisski-distillery/pkg/environment"
"github.com/tkw1536/goprogram/exit"
"github.com/tkw1536/goprogram/lib/collection"
"github.com/tkw1536/goprogram/status"
@@ -52,15 +51,8 @@ func (bu blindUpdate) Run(context wisski_distillery.Context) error {
}
// and do the actual blind_update!
- return status.StreamGroup(context.IOStream, bu.Parallel, func(instance instances.WissKI, io stream.IOStream) error {
- code, err := instance.Shell(io, "/runtime/blind_update.sh")
- if err != nil {
- return errBlindUpdateFailed.WithMessageF(instance.Slug, environment.ExecCommandError)
- }
- if code != 0 {
- return errBlindUpdateFailed.WithMessageF(instance.Slug, code)
- }
- return nil
+ return status.StreamGroup(context.IOStream, bu.Parallel, func(instance instances.WissKI, str stream.IOStream) error {
+ return instance.BlindUpdate(str)
}, wissKIs, status.SmartMessage(func(item instances.WissKI) string {
return fmt.Sprintf("blind_update %q", item.Slug)
}))
diff --git a/cmd/info.go b/cmd/info.go
index 6df1d7c..6084165 100644
--- a/cmd/info.go
+++ b/cmd/info.go
@@ -60,6 +60,7 @@ func (i info) Run(context wisski_distillery.Context) error {
context.Printf("Running: %v\n", info.Running)
context.Printf("Locked: %v\n", info.Locked)
context.Printf("Last Rebuild: %v\n", info.LastRebuild.String())
+ context.Printf("Last Update: %v\n", info.LastUpdate.String())
context.Printf("Skip Prefixes: %v\n", info.NoPrefixes)
context.Printf("Prefixes: (count %d)\n", len(info.Prefixes))
diff --git a/internal/component/info/html/instance.html b/internal/component/info/html/instance.html
index 4fce2ca..e2bd884 100644
--- a/internal/component/info/html/instance.html
+++ b/internal/component/info/html/instance.html
@@ -78,7 +78,6 @@
|
Build
-
|
@@ -93,7 +92,8 @@
- Last Rebuild
+ Last Rebuild
+
|
{{ .Info.LastRebuild.Format "2006-01-02T15:04:05Z07:00" }}
@@ -107,6 +107,15 @@
{{ .Instance.AutoBlindUpdateEnabled }}
|
+
+
+ Last Update
+
+ |
+
+ {{ .Info.LastUpdate.Format "2006-01-02T15:04:05Z07:00" }}
+ |
+
diff --git a/internal/component/info/socket.go b/internal/component/info/socket.go
index 9b04897..a1912fe 100644
--- a/internal/component/info/socket.go
+++ b/internal/component/info/socket.go
@@ -1,12 +1,35 @@
package info
import (
+ "github.com/FAU-CDI/wisski-distillery/internal/component/instances"
"github.com/FAU-CDI/wisski-distillery/internal/component/snapshots"
"github.com/FAU-CDI/wisski-distillery/pkg/httpx"
"github.com/tkw1536/goprogram/status"
"github.com/tkw1536/goprogram/stream"
)
+type instanceActionFunc = func(info *Info, instance instances.WissKI, str stream.IOStream) error
+
+var socketInstanceActions = map[string]instanceActionFunc{
+ "snapshot": func(info *Info, instance instances.WissKI, str stream.IOStream) error {
+ return info.SnapshotManager.MakeExport(
+ str,
+ snapshots.ExportTask{
+ Dest: "",
+ Instance: &instance,
+
+ StagingOnly: false,
+ },
+ )
+ },
+ "rebuild": func(_ *Info, instance instances.WissKI, str stream.IOStream) error {
+ return instance.Build(str, true)
+ },
+ "update": func(_ *Info, instance instances.WissKI, str stream.IOStream) error {
+ return instance.BlindUpdate(str)
+ },
+}
+
func (info *Info) serveSocket(conn httpx.WebSocketConnection) {
// read the next message to act on
message, ok := <-conn.Read()
@@ -14,77 +37,47 @@ func (info *Info) serveSocket(conn httpx.WebSocketConnection) {
return
}
- switch string(message.Bytes) {
- case "snapshot":
- slug, ok := <-conn.Read()
- if !ok {
- return
- }
- info.serverSocketSnapshot(string(slug.Bytes), info.socketWriter(conn))
- case "rebuild":
- slug, ok := <-conn.Read()
- if !ok {
- return
- }
- info.serverSocketRebuild(string(slug.Bytes), info.socketWriter(conn))
+ // perform an action if it exists!
+ if action, ok := socketInstanceActions[string(message.Bytes)]; ok {
+ info.handleInstanceAction(conn, action)
+ return
}
}
-func (*Info) socketWriter(conn httpx.WebSocketConnection) *status.LineBuffer {
- return &status.LineBuffer{
+func (info *Info) handleInstanceAction(conn httpx.WebSocketConnection, action instanceActionFunc) {
+
+ // read the slug
+ slug, ok := <-conn.Read()
+ if !ok {
+ conn.WriteText("Error reading slug")
+ return
+ }
+
+ // resolve the instance
+ instance, err := info.Instances.WissKI(string(slug.Bytes))
+ if err != nil {
+ conn.WriteText("Instance not found")
+ return
+ }
+
+ // build a stream
+ writer := &status.LineBuffer{
Line: func(line string) {
<-conn.WriteText(line)
},
FlushLineOnClose: true,
}
-}
+ defer writer.Close()
-func (info *Info) serverSocketSnapshot(slug string, writer *status.LineBuffer) {
- stream := stream.NewIOStream(writer, writer, nil, 0)
-
- // get the wisski
- wissKI, err := info.Instances.WissKI(slug)
- if err != nil {
- stream.EPrintln(err)
- return
- }
+ str := stream.NewIOStream(writer, writer, nil, 0)
+ // and perform the action
{
- err := info.SnapshotManager.MakeExport(
- stream,
- snapshots.ExportTask{
- Dest: "",
- Instance: &wissKI,
-
- StagingOnly: false,
- },
- )
+ err := action(info, instance, str)
if err != nil {
- stream.EPrintln(err)
+ str.EPrintln(err)
return
}
+ str.Println("done")
}
- stream.Println("Done")
-
-}
-
-func (info *Info) serverSocketRebuild(slug string, writer *status.LineBuffer) {
- stream := stream.NewIOStream(writer, writer, nil, 0)
-
- // get the wisski
- wissKI, err := info.Instances.WissKI(slug)
- if err != nil {
- stream.EPrintln(err)
- return
- }
-
- {
- err := wissKI.Build(stream, true)
- if err != nil {
- stream.EPrintln(err)
- return
- }
- }
- stream.Println("Done")
-
}
diff --git a/internal/component/instances/wisski_status.go b/internal/component/instances/wisski_status.go
index 19a2521..5fa7886 100644
--- a/internal/component/instances/wisski_status.go
+++ b/internal/component/instances/wisski_status.go
@@ -21,6 +21,7 @@ type WissKIInfo struct {
// Information about the running instance
Running bool
LastRebuild time.Time
+ LastUpdate time.Time
// List of backups made
Snapshots []models.Export
@@ -63,6 +64,10 @@ func (wisski *WissKI) Info(quick bool) (info WissKIInfo, err error) {
info.LastRebuild, _ = wisski.LastRebuild()
return nil
})
+ group.Go(func() (err error) {
+ info.LastUpdate, _ = wisski.LastUpdate()
+ return nil
+ })
group.Go(func() error {
info.Pathbuilders, _ = wisski.AllPathbuilders()
return nil
diff --git a/internal/component/instances/wisski_update.go b/internal/component/instances/wisski_update.go
new file mode 100644
index 0000000..cc8c15f
--- /dev/null
+++ b/internal/component/instances/wisski_update.go
@@ -0,0 +1,49 @@
+package instances
+
+import (
+ "time"
+
+ "github.com/FAU-CDI/wisski-distillery/pkg/environment"
+ "github.com/tkw1536/goprogram/exit"
+ "github.com/tkw1536/goprogram/stream"
+)
+
+var errBlindUpdateFailed = exit.Error{
+ Message: "Failed to run blind update script for instance %q: exited with code %s",
+ ExitCode: exit.ExitGeneric,
+}
+
+// BlinUpdate performs a blind update of the given instance
+func (wisski *WissKI) BlindUpdate(io stream.IOStream) error {
+ code, err := wisski.Shell(io, "/runtime/blind_update.sh")
+ if err != nil {
+ return errBlindUpdateFailed.WithMessageF(wisski.Slug, environment.ExecCommandError)
+ }
+ if code != 0 {
+ return errBlindUpdateFailed.WithMessageF(wisski.Slug, code)
+ }
+
+ return wisski.setLastUpdate()
+}
+
+const KeyLastUpdate MetaKey = "lastUpdate"
+
+func (wisski *WissKI) LastUpdate() (t time.Time, err error) {
+ var epoch int64
+
+ // read the epoch!
+ err = wisski.Metadata().Get(KeyLastUpdate, &epoch)
+ if err == ErrMetadatumNotSet {
+ return t, nil
+ }
+ if err != nil {
+ return t, err
+ }
+
+ // and turn it into time!
+ return time.Unix(epoch, 0), nil
+}
+
+func (wisski *WissKI) setLastUpdate() error {
+ return wisski.Metadata().Set(KeyLastUpdate, time.Now().Unix())
+}