frontend: Add instance update functionality

This commit is contained in:
Tom Wiesing 2022-10-15 18:14:23 +02:00
parent ccab2883a6
commit 45af2cc95b
No known key found for this signature in database
6 changed files with 119 additions and 70 deletions

View file

@ -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)
}))

View file

@ -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))

View file

@ -78,7 +78,6 @@
<tr>
<th colspan="2">
Build
<button class="remote-action pure-button pure-button-action" data-action="rebuild" data-param="{{ .Instance.Slug }}" data-buffer="1000" data-force-reload="true">Rebuild</button>
</th>
</tr>
</thead>
@ -93,7 +92,8 @@
</tr>
<tr>
<td>
Last Rebuild
Last Rebuild <br>
<button class="remote-action pure-button pure-button-action" data-action="rebuild" data-param="{{ .Instance.Slug }}" data-buffer="1000" data-force-reload="true">Rebuild</button>
</td>
<td>
<code class="date">{{ .Info.LastRebuild.Format "2006-01-02T15:04:05Z07:00" }}</code>
@ -107,6 +107,15 @@
<code>{{ .Instance.AutoBlindUpdateEnabled }}</code>
</td>
</tr>
<tr>
<td>
Last Update <br>
<button class="remote-action pure-button pure-button-action" data-action="update" data-param="{{ .Instance.Slug }}" data-buffer="1000" data-force-reload="true">Update</button>
</td>
<td>
<code class="date">{{ .Info.LastUpdate.Format "2006-01-02T15:04:05Z07:00" }}</code>
</td>
</tr>
</tbody>
</table>
</div>

View file

@ -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 {
// perform an action if it exists!
if action, ok := socketInstanceActions[string(message.Bytes)]; ok {
info.handleInstanceAction(conn, action)
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))
}
}
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
}
}
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
str.Println("done")
}
}
stream.Println("Done")
}

View file

@ -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

View file

@ -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())
}