Add context
This commit adds and passes context around to (almost) every function. This allows cancelling (almost) every function call globally.
This commit is contained in:
parent
996ecb9f80
commit
3455f491ca
104 changed files with 836 additions and 511 deletions
|
|
@ -41,12 +41,12 @@ func (bk backup) Run(context wisski_distillery.Context) error {
|
|||
// prune old backups
|
||||
if !bk.NoPrune {
|
||||
defer logging.LogOperation(func() error {
|
||||
return dis.Exporter().PruneExports(context.IOStream)
|
||||
return dis.Exporter().PruneExports(context.Context, context.IOStream)
|
||||
}, context.IOStream, "Pruning old backups")
|
||||
}
|
||||
|
||||
// do the handling
|
||||
err := dis.Exporter().MakeExport(context.IOStream, exporter.ExportTask{
|
||||
err := dis.Exporter().MakeExport(context.Context, context.IOStream, exporter.ExportTask{
|
||||
Dest: bk.Positionals.Dest,
|
||||
StagingOnly: bk.StagingOnly,
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ var errBlindUpdateFailed = exit.Error{
|
|||
|
||||
func (bu blindUpdate) Run(context wisski_distillery.Context) error {
|
||||
// find all the instances!
|
||||
wissKIs, err := context.Environment.Instances().Load(bu.Positionals.Slug...)
|
||||
wissKIs, err := context.Environment.Instances().Load(context.Context, bu.Positionals.Slug...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -52,7 +52,7 @@ func (bu blindUpdate) Run(context wisski_distillery.Context) error {
|
|||
|
||||
// and do the actual blind_update!
|
||||
return status.StreamGroup(context.IOStream, bu.Parallel, func(instance *wisski.WissKI, str stream.IOStream) error {
|
||||
return instance.Drush().Update(str)
|
||||
return instance.Drush().Update(context.Context, str)
|
||||
}, wissKIs, status.SmartMessage(func(item *wisski.WissKI) string {
|
||||
return fmt.Sprintf("blind_update %q", item.Slug)
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ func (bs cBootstrap) Run(context wisski_distillery.Context) error {
|
|||
return errBoostrapFailedToCopyExe.WithMessageF(err)
|
||||
}
|
||||
|
||||
err = fsx.CopyFile(env, wdcliPath, exe)
|
||||
err = fsx.CopyFile(context.Context, env, wdcliPath, exe)
|
||||
if err != nil && err != fsx.ErrCopySameFile {
|
||||
return errBoostrapFailedToCopyExe.WithMessageF(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,14 +33,14 @@ func (cron) Description() wisski_distillery.Description {
|
|||
|
||||
func (cr cron) Run(context wisski_distillery.Context) error {
|
||||
// find all the instances!
|
||||
wissKIs, err := context.Environment.Instances().Load(cr.Positionals.Slug...)
|
||||
wissKIs, err := context.Environment.Instances().Load(context.Context, cr.Positionals.Slug...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// and do the actual blind_update!
|
||||
return status.StreamGroup(context.IOStream, cr.Parallel, func(instance *wisski.WissKI, io stream.IOStream) error {
|
||||
return instance.Drush().Cron(io)
|
||||
return instance.Drush().Cron(context.Context, io)
|
||||
}, wissKIs, status.SmartMessage(func(item *wisski.WissKI) string {
|
||||
return fmt.Sprintf("cron %q", item.Slug)
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -40,14 +40,14 @@ var errSettingSet = exit.Error{
|
|||
}
|
||||
|
||||
func (ds setting) Run(context wisski_distillery.Context) error {
|
||||
instance, err := context.Environment.Instances().WissKI(ds.Positionals.Slug)
|
||||
instance, err := context.Environment.Instances().WissKI(context.Context, ds.Positionals.Slug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ds.Positionals.Value == "" {
|
||||
// get the setting
|
||||
value, err := instance.Settings().Get(nil, ds.Positionals.Setting)
|
||||
value, err := instance.Settings().Get(context.Context, nil, ds.Positionals.Setting)
|
||||
if err != nil {
|
||||
return errSettingGet.Wrap(err)
|
||||
}
|
||||
|
|
@ -69,7 +69,7 @@ func (ds setting) Run(context wisski_distillery.Context) error {
|
|||
}
|
||||
|
||||
// set the serialized value!
|
||||
if err := instance.Settings().Set(nil, ds.Positionals.Setting, data); err != nil {
|
||||
if err := instance.Settings().Set(context.Context, nil, ds.Positionals.Setting, data); err != nil {
|
||||
return errSettingSet.Wrap(err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ var errPasswordsNotIdentical = exit.Error{
|
|||
}
|
||||
|
||||
func (du duser) Run(context wisski_distillery.Context) error {
|
||||
instance, err := context.Environment.Instances().WissKI(du.Positionals.Slug)
|
||||
instance, err := context.Environment.Instances().WissKI(context.Context, du.Positionals.Slug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -94,7 +94,7 @@ func (du duser) Run(context wisski_distillery.Context) error {
|
|||
}
|
||||
|
||||
func (du duser) login(context wisski_distillery.Context, instance *wisski.WissKI) error {
|
||||
link, err := instance.Users().Login(nil, du.Positionals.User)
|
||||
link, err := instance.Users().Login(context.Context, nil, du.Positionals.User)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -110,7 +110,7 @@ var errPasswordFound = exit.Error{
|
|||
func (du duser) checkCommonPassword(context wisski_distillery.Context, instance *wisski.WissKI) error {
|
||||
users := instance.Users()
|
||||
|
||||
entities, err := users.All(nil)
|
||||
entities, err := users.All(context.Context, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -121,19 +121,19 @@ func (du duser) checkCommonPassword(context wisski_distillery.Context, instance
|
|||
},
|
||||
PrefixAlign: true,
|
||||
Handler: func(user wstatus.User, index int, writer io.Writer) error {
|
||||
pv, err := users.GetPasswordValidator(string(user.Name))
|
||||
pv, err := users.GetPasswordValidator(context.Context, string(user.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer pv.Close()
|
||||
|
||||
return pv.CheckDictionary(context.Environment.Context(), writer)
|
||||
return pv.CheckDictionary(context.Context, writer)
|
||||
},
|
||||
}, entities)
|
||||
}
|
||||
|
||||
func (du duser) checkPasswordInteractive(context wisski_distillery.Context, instance *wisski.WissKI) error {
|
||||
validator, err := instance.Users().GetPasswordValidator(du.Positionals.User)
|
||||
validator, err := instance.Users().GetPasswordValidator(context.Context, du.Positionals.User)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -151,7 +151,7 @@ func (du duser) checkPasswordInteractive(context wisski_distillery.Context, inst
|
|||
break
|
||||
}
|
||||
|
||||
if validator.Check(candidate) {
|
||||
if validator.Check(context.Context, candidate) {
|
||||
context.Println("check passed")
|
||||
} else {
|
||||
context.Println("check did not pass")
|
||||
|
|
@ -180,5 +180,5 @@ func (du duser) resetPassword(context wisski_distillery.Context, instance *wissk
|
|||
return errPasswordsNotIdentical
|
||||
}
|
||||
|
||||
return instance.Users().SetPassword(nil, du.Positionals.User, passwd1)
|
||||
return instance.Users().SetPassword(context.Context, nil, du.Positionals.User, passwd1)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,12 +29,12 @@ func (info) Description() wisski_distillery.Description {
|
|||
}
|
||||
|
||||
func (i info) Run(context wisski_distillery.Context) error {
|
||||
instance, err := context.Environment.Instances().WissKI(i.Positionals.Slug)
|
||||
instance, err := context.Environment.Instances().WissKI(context.Context, i.Positionals.Slug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info, err := instance.Info().Information(false)
|
||||
info, err := instance.Info().Information(context.Context, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,20 +46,20 @@ var errNotUnlock = exit.Error{
|
|||
}
|
||||
|
||||
func (l instanceLock) Run(context wisski_distillery.Context) error {
|
||||
instance, err := context.Environment.Instances().WissKI(l.Positionals.Slug)
|
||||
instance, err := context.Environment.Instances().WissKI(context.Context, l.Positionals.Slug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if l.Unlock {
|
||||
if !instance.Locker().TryUnlock() {
|
||||
if !instance.Locker().TryUnlock(context.Context) {
|
||||
return errNotUnlock
|
||||
}
|
||||
context.Println("unlocked")
|
||||
return nil
|
||||
}
|
||||
|
||||
if !instance.Locker().TryLock() {
|
||||
if !instance.Locker().TryLock(context.Context) {
|
||||
return locker.Locked
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ func (ls) Description() wisski_distillery.Description {
|
|||
}
|
||||
|
||||
func (l ls) Run(context wisski_distillery.Context) error {
|
||||
instances, err := context.Environment.Instances().Load(l.Positionals.Slug...)
|
||||
instances, err := context.Environment.Instances().Load(context.Context, l.Positionals.Slug...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ func (mma makeMysqlAccount) Run(context wisski_distillery.Context) error {
|
|||
return errUnableToReadPassword.WithMessageF(err)
|
||||
}
|
||||
|
||||
if err := dis.SQL().CreateSuperuser(username, password, false); err != nil {
|
||||
if err := dis.SQL().CreateSuperuser(context.Context, username, password, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ func (mysql) Description() wisski_distillery.Description {
|
|||
}
|
||||
|
||||
func (ms mysql) Run(context wisski_distillery.Context) error {
|
||||
code, err := context.Environment.SQL().Shell(context.IOStream, ms.Positionals.Args...)
|
||||
code, err := context.Environment.SQL().Shell(context.Context, context.IOStream, ms.Positionals.Args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,14 +39,14 @@ var errNoPathbuilder = exit.Error{
|
|||
func (pb pathbuilders) Run(context wisski_distillery.Context) error {
|
||||
|
||||
// get the wisski
|
||||
instance, err := context.Environment.Instances().WissKI(pb.Positionals.Slug)
|
||||
instance, err := context.Environment.Instances().WissKI(context.Context, pb.Positionals.Slug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get all of the pathbuilders
|
||||
if pb.Positionals.Name == "" {
|
||||
names, err := instance.Pathbuilder().All(nil)
|
||||
names, err := instance.Pathbuilder().All(context.Context, nil)
|
||||
if err != nil {
|
||||
return errPathbuilders.WithMessageF(err)
|
||||
}
|
||||
|
|
@ -57,7 +57,7 @@ func (pb pathbuilders) Run(context wisski_distillery.Context) error {
|
|||
}
|
||||
|
||||
// get all the pathbuilders
|
||||
xml, err := instance.Pathbuilder().Get(nil, pb.Positionals.Name)
|
||||
xml, err := instance.Pathbuilder().Get(context.Context, nil, pb.Positionals.Name)
|
||||
if xml == "" {
|
||||
return errNoPathbuilder.WithMessageF(pb.Positionals.Name)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,12 +31,12 @@ var errPrefixesGeneric = exit.Error{
|
|||
}
|
||||
|
||||
func (p prefixes) Run(context wisski_distillery.Context) error {
|
||||
instance, err := context.Environment.Instances().WissKI(p.Positionals.Slug)
|
||||
instance, err := context.Environment.Instances().WissKI(context.Context, p.Positionals.Slug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
prefixes, err := instance.Prefixes().All(nil)
|
||||
prefixes, err := instance.Prefixes().All(context.Context, nil)
|
||||
if err != nil {
|
||||
return errPrefixesGeneric.Wrap(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ func (p provision) Run(context wisski_distillery.Context) error {
|
|||
|
||||
// check that it doesn't already exist
|
||||
logging.LogMessage(context.IOStream, "Provisioning new WissKI instance %s", slug)
|
||||
if exists, err := dis.Instances().Has(slug); err != nil || exists {
|
||||
if exists, err := dis.Instances().Has(context.Context, slug); err != nil || exists {
|
||||
return errProvisionAlreadyExists.WithMessageF(slug)
|
||||
}
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ func (p provision) Run(context wisski_distillery.Context) error {
|
|||
|
||||
// Store in the instances table!
|
||||
if err := logging.LogOperation(func() error {
|
||||
if err := instance.Bookkeeping().Save(); err != nil {
|
||||
if err := instance.Bookkeeping().Save(context.Context); err != nil {
|
||||
return errProvisionGeneric.WithMessageF(slug, err)
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ func (p provision) Run(context wisski_distillery.Context) error {
|
|||
domain := instance.Domain()
|
||||
for _, pc := range dis.Provisionable() {
|
||||
logging.LogMessage(context.IOStream, "Provisioning %s resources", pc.Name())
|
||||
err := pc.Provision(instance.Instance, domain)
|
||||
err := pc.Provision(context.Context, instance.Instance, domain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ func (p provision) Run(context wisski_distillery.Context) error {
|
|||
|
||||
// run the provision script
|
||||
if err := logging.LogOperation(func() error {
|
||||
if err := instance.Provisioner().Provision(context.IOStream); err != nil {
|
||||
if err := instance.Provisioner().Provision(context.Context, context.IOStream); err != nil {
|
||||
return errProvisionGeneric.WithMessageF(slug, err)
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +101,7 @@ func (p provision) Run(context wisski_distillery.Context) error {
|
|||
|
||||
// start the container!
|
||||
logging.LogMessage(context.IOStream, "Starting Container")
|
||||
if err := instance.Barrel().Stack().Up(context.IOStream); err != nil {
|
||||
if err := instance.Barrel().Stack().Up(context.Context, context.IOStream); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
10
cmd/purge.go
10
cmd/purge.go
|
|
@ -59,7 +59,7 @@ func (p purge) Run(context wisski_distillery.Context) error {
|
|||
|
||||
// load the instance (first via bookkeeping, then via defaults)
|
||||
logging.LogMessage(context.IOStream, "Checking bookkeeping table")
|
||||
instance, err := dis.Instances().WissKI(slug)
|
||||
instance, err := dis.Instances().WissKI(context.Context, slug)
|
||||
if err == instances.ErrWissKINotFound {
|
||||
context.Println("Not found in bookkeeping table, assuming defaults")
|
||||
instance, err = dis.Instances().Create(slug)
|
||||
|
|
@ -70,7 +70,7 @@ func (p purge) Run(context wisski_distillery.Context) error {
|
|||
|
||||
// remove docker stack
|
||||
logging.LogMessage(context.IOStream, "Stopping and removing docker container")
|
||||
if err := instance.Barrel().Stack().Down(context.IOStream); err != nil {
|
||||
if err := instance.Barrel().Stack().Down(context.Context, context.IOStream); err != nil {
|
||||
context.EPrintln(err)
|
||||
}
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ func (p purge) Run(context wisski_distillery.Context) error {
|
|||
domain := instance.Domain()
|
||||
for _, pc := range dis.Provisionable() {
|
||||
logging.LogMessage(context.IOStream, "Purging %s resources", pc.Name())
|
||||
err := pc.Purge(instance.Instance, domain)
|
||||
err := pc.Purge(context.Context, instance.Instance, domain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -98,13 +98,13 @@ func (p purge) Run(context wisski_distillery.Context) error {
|
|||
|
||||
// remove from bookkeeping
|
||||
logging.LogMessage(context.IOStream, "Removing instance from bookkeeping")
|
||||
if err := instance.Bookkeeping().Delete(); err != nil {
|
||||
if err := instance.Bookkeeping().Delete(context.Context); err != nil {
|
||||
context.EPrintln(err)
|
||||
}
|
||||
|
||||
// remove the filesystem
|
||||
logging.LogMessage(context.IOStream, "Remove lock data")
|
||||
if instance.Locker().TryUnlock() {
|
||||
if instance.Locker().TryUnlock(context.Context) {
|
||||
context.EPrintln("instance was not locked")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,14 +40,14 @@ func (rb rebuild) Run(context wisski_distillery.Context) error {
|
|||
dis := context.Environment
|
||||
|
||||
// find the instances
|
||||
wissKIs, err := dis.Instances().Load(rb.Positionals.Slug...)
|
||||
wissKIs, err := dis.Instances().Load(context.Context, rb.Positionals.Slug...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// and do the actual rebuild
|
||||
return status.StreamGroup(context.IOStream, rb.Parallel, func(instance *wisski.WissKI, io stream.IOStream) error {
|
||||
return instance.Barrel().Build(io, true)
|
||||
return instance.Barrel().Build(context.Context, io, true)
|
||||
}, wissKIs, status.SmartMessage(func(item *wisski.WissKI) string {
|
||||
return fmt.Sprintf("rebuild %q", item.Slug)
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ func (r reserve) Run(context wisski_distillery.Context) error {
|
|||
|
||||
// check that it doesn't already exist
|
||||
logging.LogMessage(context.IOStream, "Reserving new WissKI instance %s", slug)
|
||||
if exists, err := dis.Instances().Has(slug); err != nil || exists {
|
||||
if exists, err := dis.Instances().Has(context.Context, slug); err != nil || exists {
|
||||
return errProvisionAlreadyExists.WithMessageF(slug)
|
||||
}
|
||||
|
||||
|
|
@ -66,13 +66,13 @@ func (r reserve) Run(context wisski_distillery.Context) error {
|
|||
s := instance.Reserve().Stack()
|
||||
{
|
||||
if err := logging.LogOperation(func() error {
|
||||
return s.Install(context.IOStream, component.InstallationContext{})
|
||||
return s.Install(context.Context, context.IOStream, component.InstallationContext{})
|
||||
}, context.IOStream, "Installing docker stack"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := logging.LogOperation(func() error {
|
||||
return s.Update(context.IOStream, true)
|
||||
return s.Update(context.Context, context.IOStream, true)
|
||||
}, context.IOStream, "Updating docker stack"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
wisski_distillery "github.com/FAU-CDI/wisski-distillery"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/cli"
|
||||
"github.com/FAU-CDI/wisski-distillery/pkg/cancel"
|
||||
"github.com/tkw1536/goprogram/exit"
|
||||
)
|
||||
|
||||
|
|
@ -33,7 +34,7 @@ var errServerListen = exit.Error{
|
|||
|
||||
func (s server) Run(context wisski_distillery.Context) error {
|
||||
dis := context.Environment
|
||||
handler, err := dis.Control().Server(dis.Context(), context.IOStream)
|
||||
handler, err := dis.Control().Server(context.Context, context.IOStream)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -47,14 +48,21 @@ func (s server) Run(context wisski_distillery.Context) error {
|
|||
}
|
||||
|
||||
go func() {
|
||||
<-dis.Context().Done()
|
||||
<-context.Context.Done()
|
||||
listener.Close()
|
||||
}()
|
||||
|
||||
// and serve that listener
|
||||
err = http.Serve(listener, http.StripPrefix(s.Prefix, handler))
|
||||
if err == nil {
|
||||
return nil
|
||||
server := http.Server{
|
||||
Handler: http.StripPrefix(s.Prefix, handler),
|
||||
}
|
||||
|
||||
err, _ = cancel.WithContext(context.Context, func(start func()) error {
|
||||
start()
|
||||
return server.Serve(listener)
|
||||
}, func() {
|
||||
// gracefully shutdown server
|
||||
context.Printf("shutting down server")
|
||||
server.Shutdown(context.Context)
|
||||
})
|
||||
return errServerListen.Wrap(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,12 +38,12 @@ var errShell = exit.Error{
|
|||
}
|
||||
|
||||
func (sh shell) Run(context wisski_distillery.Context) error {
|
||||
instance, err := context.Environment.Instances().WissKI(sh.Positionals.Slug)
|
||||
instance, err := context.Environment.Instances().WissKI(context.Context, sh.Positionals.Slug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
code, err := instance.Barrel().Shell(context.IOStream, sh.Positionals.Args...)
|
||||
code, err := instance.Barrel().Shell(context.Context, context.IOStream, sh.Positionals.Args...)
|
||||
if err != nil {
|
||||
return errShell.WithMessageF(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,13 +39,13 @@ func (sn snapshot) Run(context wisski_distillery.Context) error {
|
|||
dis := context.Environment
|
||||
|
||||
// find the instance!
|
||||
instance, err := dis.Instances().WissKI(sn.Positionals.Slug)
|
||||
instance, err := dis.Instances().WissKI(context.Context, sn.Positionals.Slug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// do a snapshot of it!
|
||||
err = dis.Exporter().MakeExport(context.IOStream, exporter.ExportTask{
|
||||
err = dis.Exporter().MakeExport(context.Context, context.IOStream, exporter.ExportTask{
|
||||
Dest: sn.Positionals.Dest,
|
||||
StagingOnly: sn.StagingOnly,
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ var errSSHListen = exit.Error{
|
|||
|
||||
func (s ssh) Run(context wisski_distillery.Context) error {
|
||||
dis := context.Environment
|
||||
server, err := dis.SSH().Server(dis.Context(), s.PrivateKeyPath, context.IOStream)
|
||||
server, err := dis.SSH().Server(context.Context, s.PrivateKeyPath, context.IOStream)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -45,7 +45,7 @@ func (s ssh) Run(context wisski_distillery.Context) error {
|
|||
}
|
||||
|
||||
go func() {
|
||||
<-dis.Context().Done()
|
||||
<-context.Context.Done()
|
||||
listener.Close()
|
||||
}()
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ func (cStatus) Description() wisski_distillery.Description {
|
|||
}
|
||||
|
||||
func (s cStatus) Run(context wisski_distillery.Context) error {
|
||||
status, _, err := context.Environment.Info().Status(true)
|
||||
status, _, err := context.Environment.Info().Status(context.Context, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ func (sp systempause) start(context wisski_distillery.Context, dis *dis.Distille
|
|||
|
||||
Handler: func(item component.Installable, index int, writer io.Writer) error {
|
||||
io := stream.NewIOStream(writer, writer, stream.Null, 0)
|
||||
return item.Stack(context.Environment.Environment).Up(io)
|
||||
return item.Stack(context.Environment.Environment).Up(context.Context, io)
|
||||
},
|
||||
}, dis.Installable()); err != nil {
|
||||
return err
|
||||
|
|
@ -74,7 +74,7 @@ func (sp systempause) start(context wisski_distillery.Context, dis *dis.Distille
|
|||
logging.LogMessage(context.IOStream, "Starting Up WissKIs")
|
||||
|
||||
// find the instances
|
||||
wissKIs, err := dis.Instances().All()
|
||||
wissKIs, err := dis.Instances().All(context.Context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -88,7 +88,7 @@ func (sp systempause) start(context wisski_distillery.Context, dis *dis.Distille
|
|||
|
||||
Handler: func(item *wisski.WissKI, index int, writer io.Writer) error {
|
||||
io := stream.NewIOStream(writer, writer, stream.Null, 0)
|
||||
return item.Barrel().Stack().Up(io)
|
||||
return item.Barrel().Stack().Up(context.Context, io)
|
||||
},
|
||||
}, wissKIs); err != nil {
|
||||
return err
|
||||
|
|
@ -101,7 +101,7 @@ func (sp systempause) stop(context wisski_distillery.Context, dis *dis.Distiller
|
|||
logging.LogMessage(context.IOStream, "Shutting Down WissKIs")
|
||||
|
||||
// find the instances
|
||||
wissKIs, err := dis.Instances().All()
|
||||
wissKIs, err := dis.Instances().All(context.Context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -115,7 +115,7 @@ func (sp systempause) stop(context wisski_distillery.Context, dis *dis.Distiller
|
|||
|
||||
Handler: func(item *wisski.WissKI, index int, writer io.Writer) error {
|
||||
io := stream.NewIOStream(writer, writer, stream.Null, 0)
|
||||
return item.Barrel().Stack().Down(io)
|
||||
return item.Barrel().Stack().Down(context.Context, io)
|
||||
},
|
||||
}, wissKIs); err != nil {
|
||||
return err
|
||||
|
|
@ -132,7 +132,7 @@ func (sp systempause) stop(context wisski_distillery.Context, dis *dis.Distiller
|
|||
|
||||
Handler: func(item component.Installable, index int, writer io.Writer) error {
|
||||
io := stream.NewIOStream(writer, writer, stream.Null, 0)
|
||||
return item.Stack(context.Environment.Environment).Down(io)
|
||||
return item.Stack(context.Environment.Environment).Down(context.Context, io)
|
||||
},
|
||||
}, dis.Installable()); err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -135,11 +135,11 @@ func (si systemupdate) Run(context wisski_distillery.Context) error {
|
|||
io := stream.NewIOStream(writer, writer, stream.Null, 0)
|
||||
stack := item.Stack(context.Environment.Environment)
|
||||
|
||||
if err := stack.Install(io, item.Context(ctx)); err != nil {
|
||||
if err := stack.Install(context.Context, io, item.Context(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := stack.Update(io, true); err != nil {
|
||||
if err := stack.Update(context.Context, io, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -154,7 +154,7 @@ func (si systemupdate) Run(context wisski_distillery.Context) error {
|
|||
updated[item.ID()] = struct{}{}
|
||||
}()
|
||||
|
||||
return ud.Update(io)
|
||||
return ud.Update(context.Context, io)
|
||||
},
|
||||
}, dis.Installable())
|
||||
}, context.IOStream, "Performing Stack Updates"); err != nil {
|
||||
|
|
@ -170,7 +170,7 @@ func (si systemupdate) Run(context wisski_distillery.Context) error {
|
|||
context.Println("Already updated")
|
||||
return nil
|
||||
}
|
||||
return item.Update(context.IOStream)
|
||||
return item.Update(context.Context, context.IOStream)
|
||||
}, context.IOStream, "Updating Component: %s", name); err != nil {
|
||||
return errBootstrapComponent.WithMessageF(name, err)
|
||||
}
|
||||
|
|
@ -194,9 +194,9 @@ var errMustExecFailed = exit.Error{
|
|||
func (si systemupdate) mustExec(context wisski_distillery.Context, workdir string, exe string, argv ...string) error {
|
||||
dis := context.Environment
|
||||
if workdir == "" {
|
||||
workdir = context.Environment.Config.DeployRoot
|
||||
workdir = dis.Config.DeployRoot
|
||||
}
|
||||
code := dis.Still.Environment.Exec(context.IOStream, workdir, exe, argv...)
|
||||
code := dis.Still.Environment.Exec(context.Context, context.IOStream, workdir, exe, argv...)
|
||||
if code != 0 {
|
||||
err := errMustExecFailed.WithMessageF(code)
|
||||
err.ExitCode = exit.ExitCode(code)
|
||||
|
|
|
|||
|
|
@ -37,14 +37,14 @@ var errPrefixUpdateFailed = exit.Error{
|
|||
func (upc updateprefixconfig) Run(context wisski_distillery.Context) error {
|
||||
dis := context.Environment
|
||||
|
||||
wissKIs, err := dis.Instances().All()
|
||||
wissKIs, err := dis.Instances().All(context.Context)
|
||||
if err != nil {
|
||||
return errPrefixUpdateFailed.Wrap(err)
|
||||
}
|
||||
|
||||
return status.StreamGroup(context.IOStream, upc.Parallel, func(instance *wisski.WissKI, io stream.IOStream) error {
|
||||
io.Println("reading prefixes")
|
||||
err := instance.Prefixes().Update()
|
||||
err := instance.Prefixes().Update(context.Context)
|
||||
if err != nil {
|
||||
return errPrefixUpdateFailed.Wrap(err)
|
||||
}
|
||||
|
|
|
|||
10
go.mod
10
go.mod
|
|
@ -12,12 +12,12 @@ require (
|
|||
github.com/gorilla/mux v1.8.0
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/tkw1536/goprogram v0.1.1
|
||||
github.com/tkw1536/goprogram v0.2.0
|
||||
golang.org/x/crypto v0.3.0
|
||||
golang.org/x/exp v0.0.0-20221004215720-b9f4876ce741
|
||||
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0
|
||||
gorm.io/driver/mysql v1.3.6
|
||||
gorm.io/gorm v1.23.10
|
||||
golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9
|
||||
golang.org/x/sync v0.1.0
|
||||
gorm.io/driver/mysql v1.4.4
|
||||
gorm.io/gorm v1.24.2
|
||||
)
|
||||
|
||||
require (
|
||||
|
|
|
|||
10
go.sum
10
go.sum
|
|
@ -31,15 +31,21 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/tkw1536/goprogram v0.1.1 h1:gamK9OuRqoX2yQlA/nkgfVHHZWd/u2uUj6vJMYrYa70=
|
||||
github.com/tkw1536/goprogram v0.1.1/go.mod h1:Jqs0sTMzhrAGCX3JQrlEwQ0WRWQACCvuQQkaBDp65pE=
|
||||
github.com/tkw1536/goprogram v0.2.0 h1:qoa5Izgq5gfVggkAcOtCwpjz4oZv1KgDEJ8BHIK/djQ=
|
||||
github.com/tkw1536/goprogram v0.2.0/go.mod h1:Jqs0sTMzhrAGCX3JQrlEwQ0WRWQACCvuQQkaBDp65pE=
|
||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/exp v0.0.0-20221004215720-b9f4876ce741 h1:fGZugkZk2UgYBxtpKmvub51Yno1LJDeEsRp2xGD+0gY=
|
||||
golang.org/x/exp v0.0.0-20221004215720-b9f4876ce741/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||
golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9 h1:yZNXmy+j/JpX19vZkVktWqAo7Gny4PBWYYK3zskGpx4=
|
||||
golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0 h1:cu5kTvlzcw1Q5S9f5ip1/cpiB4nXvw1XYzFPGgzLUOY=
|
||||
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
@ -59,6 +65,10 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gorm.io/driver/mysql v1.3.6 h1:BhX1Y/RyALb+T9bZ3t07wLnPZBukt+IRkMn8UZSNbGM=
|
||||
gorm.io/driver/mysql v1.3.6/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c=
|
||||
gorm.io/driver/mysql v1.4.4 h1:MX0K9Qvy0Na4o7qSC/YI7XxqUw5KDw01umqgID+svdQ=
|
||||
gorm.io/driver/mysql v1.4.4/go.mod h1:BCg8cKI+R0j/rZRQxeKis/forqRwRSYOR8OM3Wo6hOM=
|
||||
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||
gorm.io/gorm v1.23.10 h1:4Ne9ZbzID9GUxRkllxN4WjJKpsHx8YbKvekVdgyWh24=
|
||||
gorm.io/gorm v1.23.10/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
||||
gorm.io/gorm v1.24.2 h1:9wR6CFD+G8nOusLdvkZelOEhpJVwwHzpQOUM+REd6U0=
|
||||
gorm.io/gorm v1.24.2/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package component
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"path/filepath"
|
||||
|
||||
|
|
@ -45,7 +46,7 @@ type StagingContext interface {
|
|||
// Passing the empty path creates the destination as a directory.
|
||||
//
|
||||
// It then allows op to fill the file.
|
||||
AddDirectory(path string, op func() error) error
|
||||
AddDirectory(path string, op func(context.Context) error) error
|
||||
|
||||
// CopyFile copies a file from src to dst.
|
||||
CopyFile(dst, src string) error
|
||||
|
|
@ -61,12 +62,13 @@ type StagingContext interface {
|
|||
// The op function must not retain file.
|
||||
// The underlying file does not need to be closed.
|
||||
// AddFile will not return before op has returned.
|
||||
AddFile(path string, op func(file io.Writer) error) error
|
||||
AddFile(path string, op func(ctx context.Context, file io.Writer) error) error
|
||||
}
|
||||
|
||||
// NewStagingContext returns a new [StagingContext]
|
||||
func NewStagingContext(env environment.Environment, io stream.IOStream, path string, manifest chan<- string) StagingContext {
|
||||
func NewStagingContext(ctx context.Context, env environment.Environment, io stream.IOStream, path string, manifest chan<- string) StagingContext {
|
||||
return &stagingContext{
|
||||
ctx: ctx,
|
||||
env: env,
|
||||
io: io,
|
||||
path: path,
|
||||
|
|
@ -76,6 +78,7 @@ func NewStagingContext(env environment.Environment, io stream.IOStream, path str
|
|||
|
||||
// stagingContext implements [components.StagingContext]
|
||||
type stagingContext struct {
|
||||
ctx context.Context
|
||||
env environment.Environment // environment
|
||||
io stream.IOStream // context the files are sent to
|
||||
path string // path to send files to
|
||||
|
|
@ -110,7 +113,12 @@ func (bc *stagingContext) resolve(path string) (dest string, err error) {
|
|||
return filepath.Join(bc.path, path), nil
|
||||
}
|
||||
|
||||
func (sc *stagingContext) AddDirectory(path string, op func() error) error {
|
||||
func (sc *stagingContext) AddDirectory(path string, op func(context.Context) error) error {
|
||||
// check if we are already done
|
||||
if err, ok := sc.ctxdone(); ok {
|
||||
return err
|
||||
}
|
||||
|
||||
// resolve the path!
|
||||
dst, err := sc.resolve(path)
|
||||
if err != nil {
|
||||
|
|
@ -126,30 +134,43 @@ func (sc *stagingContext) AddDirectory(path string, op func() error) error {
|
|||
sc.sendPath(path)
|
||||
|
||||
// and run the files!
|
||||
return op()
|
||||
return op(sc.ctx)
|
||||
}
|
||||
|
||||
func (sc *stagingContext) CopyFile(dst, src string) error {
|
||||
if err, ok := sc.ctxdone(); ok {
|
||||
return err
|
||||
}
|
||||
|
||||
dstPath, err := sc.resolve(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sc.sendPath(dst)
|
||||
return fsx.CopyFile(sc.env, dstPath, src)
|
||||
return fsx.CopyFile(sc.ctx, sc.env, dstPath, src)
|
||||
}
|
||||
|
||||
func (sc *stagingContext) CopyDirectory(dst, src string) error {
|
||||
if err, ok := sc.ctxdone(); ok {
|
||||
return err
|
||||
}
|
||||
|
||||
dstPath, err := sc.resolve(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return fsx.CopyDirectory(sc.env, dstPath, src, func(dst, src string) {
|
||||
return fsx.CopyDirectory(sc.ctx, sc.env, dstPath, src, func(dst, src string) {
|
||||
sc.sendPath(dst)
|
||||
})
|
||||
}
|
||||
|
||||
func (sc *stagingContext) AddFile(path string, op func(file io.Writer) error) error {
|
||||
func (sc *stagingContext) AddFile(path string, op func(ctx context.Context, file io.Writer) error) error {
|
||||
// check if we're already done
|
||||
if err, ok := sc.ctxdone(); ok {
|
||||
return err
|
||||
}
|
||||
|
||||
// resolve the path!
|
||||
dst, err := sc.resolve(path)
|
||||
if err != nil {
|
||||
|
|
@ -167,5 +188,11 @@ func (sc *stagingContext) AddFile(path string, op func(file io.Writer) error) er
|
|||
sc.sendPath(path)
|
||||
|
||||
// and do whatever they wanted to do
|
||||
return op(file)
|
||||
return op(sc.ctx, file)
|
||||
}
|
||||
|
||||
func (sc *stagingContext) ctxdone() (err error, done bool) {
|
||||
err = sc.ctx.Err()
|
||||
done = (err != nil)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,10 +26,10 @@ type Home struct {
|
|||
|
||||
func (*Home) Routes() []string { return []string{"/"} }
|
||||
|
||||
func (home *Home) Handler(route string, context context.Context, io stream.IOStream) (http.Handler, error) {
|
||||
home.updateRedirect(context, io)
|
||||
home.updateInstances(context, io)
|
||||
home.updateRender(context, io)
|
||||
func (home *Home) Handler(ctx context.Context, route string, io stream.IOStream) (http.Handler, error) {
|
||||
home.updateRedirect(ctx, io)
|
||||
home.updateInstances(ctx, io)
|
||||
home.updateRender(ctx, io)
|
||||
return home, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,14 +19,27 @@ func (home *Home) updateInstances(ctx context.Context, io stream.IOStream) {
|
|||
for t := range timex.TickContext(ctx, home.RefreshInterval) {
|
||||
io.Printf("[%s]: reloading instance list\n", t.Format(time.Stamp))
|
||||
|
||||
names, _ := home.instanceMap()
|
||||
home.instanceNames.Set(names)
|
||||
err := (func() error {
|
||||
ctx, cancel := context.WithTimeout(ctx, home.RefreshInterval)
|
||||
defer cancel()
|
||||
|
||||
names, err := home.instanceMap(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
home.instanceNames.Set(names)
|
||||
return nil
|
||||
})()
|
||||
if err != nil {
|
||||
io.EPrintf("error reloading instances: ", err.Error())
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (home *Home) instanceMap() (map[string]struct{}, error) {
|
||||
wissKIs, err := home.Instances.All()
|
||||
func (home *Home) instanceMap(ctx context.Context) (map[string]struct{}, error) {
|
||||
wissKIs, err := home.Instances.All(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -41,10 +54,23 @@ func (home *Home) instanceMap() (map[string]struct{}, error) {
|
|||
func (home *Home) updateRender(ctx context.Context, io stream.IOStream) {
|
||||
go func() {
|
||||
for t := range timex.TickContext(ctx, home.RefreshInterval) {
|
||||
io.Printf("[%s]: reloading home render\n", t.Format(time.Stamp))
|
||||
io.Printf("[%s]: reloading home render list\n", t.Format(time.Stamp))
|
||||
|
||||
bytes, _ := home.homeRender()
|
||||
home.homeBytes.Set(bytes)
|
||||
err := (func() error {
|
||||
ctx, cancel := context.WithTimeout(ctx, home.RefreshInterval)
|
||||
defer cancel()
|
||||
|
||||
bytes, err := home.homeRender(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
home.homeBytes.Set(bytes)
|
||||
return nil
|
||||
})()
|
||||
if err != nil {
|
||||
io.EPrintf("error reloading instances: ", err.Error())
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
|
@ -53,7 +79,7 @@ func (home *Home) updateRender(ctx context.Context, io stream.IOStream) {
|
|||
var homeHTMLStr string
|
||||
var homeTemplate = static.AssetsHomeHome.MustParseShared("home.html", homeHTMLStr)
|
||||
|
||||
func (home *Home) homeRender() ([]byte, error) {
|
||||
func (home *Home) homeRender(ctx context.Context) ([]byte, error) {
|
||||
var context HomeContext
|
||||
|
||||
// setup a couple of static things
|
||||
|
|
@ -61,7 +87,7 @@ func (home *Home) homeRender() ([]byte, error) {
|
|||
context.SelfRedirect = home.Config.SelfRedirect.String()
|
||||
|
||||
// find all the WissKIs
|
||||
wissKIs, err := home.Instances.All()
|
||||
wissKIs, err := home.Instances.All(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -73,7 +99,7 @@ func (home *Home) homeRender() ([]byte, error) {
|
|||
i := i
|
||||
wissKI := instance
|
||||
eg.Go(func() (err error) {
|
||||
context.Instances[i], err = wissKI.Info().Information(false)
|
||||
context.Instances[i], err = wissKI.Info().Information(ctx, false)
|
||||
return
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,13 +16,27 @@ func (home *Home) updateRedirect(ctx context.Context, io stream.IOStream) {
|
|||
for t := range timex.TickContext(ctx, home.RefreshInterval) {
|
||||
io.Printf("[%s]: reloading overrides\n", t.Format(time.Stamp))
|
||||
|
||||
redirect, _ := home.loadRedirect()
|
||||
home.redirect.Set(&redirect)
|
||||
err := (func() error {
|
||||
ctx, cancel := context.WithTimeout(ctx, home.RefreshInterval)
|
||||
defer cancel()
|
||||
|
||||
redirect, err := home.loadRedirect(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
home.redirect.Set(&redirect)
|
||||
return nil
|
||||
})()
|
||||
if err != nil {
|
||||
io.EPrintf("error reloading overrides: ", err.Error())
|
||||
}
|
||||
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (home *Home) loadRedirect() (redirect Redirect, err error) {
|
||||
func (home *Home) loadRedirect(ctx context.Context) (redirect Redirect, err error) {
|
||||
if redirect.Overrides == nil {
|
||||
redirect.Overrides = make(map[string]string)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ func (info *Info) ingredients(r *http.Request) (cp ingredientsContext, err error
|
|||
cp.Time = time.Now().UTC()
|
||||
|
||||
// find the instance itself!
|
||||
instance, err := info.Instances.WissKI(mux.Vars(r)["slug"])
|
||||
instance, err := info.Instances.WissKI(r.Context(), mux.Vars(r)["slug"])
|
||||
if err == instances.ErrWissKINotFound {
|
||||
return cp, httpx.ErrNotFound
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package info
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
|
|
@ -25,18 +26,18 @@ type indexContext struct {
|
|||
}
|
||||
|
||||
func (info *Info) index(r *http.Request) (idx indexContext, err error) {
|
||||
idx.Distillery, idx.Instances, err = info.Status(true)
|
||||
idx.Distillery, idx.Instances, err = info.Status(r.Context(), true)
|
||||
return
|
||||
}
|
||||
|
||||
// Status produces a new observation of the distillery, and a new information of all instances
|
||||
// The information on all instances is passed the given quick flag.
|
||||
func (info *Info) Status(QuickInformation bool) (target status.Distillery, information []status.WissKI, err error) {
|
||||
func (info *Info) Status(ctx context.Context, QuickInformation bool) (target status.Distillery, information []status.WissKI, err error) {
|
||||
var group errgroup.Group
|
||||
|
||||
group.Go(func() error {
|
||||
// list all the instances
|
||||
all, err := info.Instances.All()
|
||||
all, err := info.Instances.All(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -50,7 +51,7 @@ func (info *Info) Status(QuickInformation bool) (target status.Distillery, infor
|
|||
|
||||
// store the info for this group!
|
||||
group.Go(func() (err error) {
|
||||
information[i], err = instance.Info().Information(true)
|
||||
information[i], err = instance.Info().Information(ctx, true)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
|
@ -59,7 +60,9 @@ func (info *Info) Status(QuickInformation bool) (target status.Distillery, infor
|
|||
})
|
||||
|
||||
// gather all the observations
|
||||
var flags component.FetcherFlags
|
||||
flags := component.FetcherFlags{
|
||||
Context: ctx,
|
||||
}
|
||||
for _, o := range info.Fetchers {
|
||||
o := o
|
||||
group.Go(func() error {
|
||||
|
|
|
|||
|
|
@ -28,11 +28,11 @@ type Info struct {
|
|||
|
||||
func (*Info) Routes() []string { return []string{"/dis/"} }
|
||||
|
||||
func (info *Info) Handler(route string, context context.Context, io stream.IOStream) (handler http.Handler, err error) {
|
||||
func (info *Info) Handler(ctx context.Context, route string, io stream.IOStream) (handler http.Handler, err error) {
|
||||
router := mux.NewRouter()
|
||||
{
|
||||
socket := &httpx.WebSocket{
|
||||
Context: context,
|
||||
Context: ctx,
|
||||
Fallback: router,
|
||||
Handler: info.serveSocket,
|
||||
}
|
||||
|
|
@ -82,12 +82,12 @@ func (info *Info) Handler(route string, context context.Context, io stream.IOStr
|
|||
}
|
||||
|
||||
// get the instance
|
||||
instance, err := info.Instances.WissKI(r.PostFormValue("slug"))
|
||||
instance, err := info.Instances.WissKI(r.Context(), r.PostFormValue("slug"))
|
||||
if err != nil {
|
||||
return "", httpx.ErrNotFound
|
||||
}
|
||||
|
||||
target, err := instance.Users().Login(nil, r.PostFormValue("user"))
|
||||
target, err := instance.Users().Login(r.Context(), nil, r.PostFormValue("user"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ type instanceContext struct {
|
|||
|
||||
func (info *Info) instance(r *http.Request) (is instanceContext, err error) {
|
||||
// find the instance itself!
|
||||
instance, err := info.Instances.WissKI(mux.Vars(r)["slug"])
|
||||
instance, err := info.Instances.WissKI(r.Context(), mux.Vars(r)["slug"])
|
||||
if err == instances.ErrWissKINotFound {
|
||||
return is, httpx.ErrNotFound
|
||||
}
|
||||
|
|
@ -39,7 +39,7 @@ func (info *Info) instance(r *http.Request) (is instanceContext, err error) {
|
|||
is.Instance = instance.Instance
|
||||
|
||||
// get some more info about the wisski
|
||||
is.Info, err = instance.Info().Information(false)
|
||||
is.Info, err = instance.Info().Information(r.Context(), false)
|
||||
if err != nil {
|
||||
return is, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package info
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
|
|
@ -14,14 +15,15 @@ import (
|
|||
type InstanceAction struct {
|
||||
NumParams int
|
||||
|
||||
HandleInteractive func(info *Info, instance *wisski.WissKI, str stream.IOStream, params ...string) error
|
||||
HandleResult func(info *Info, instance *wisski.WissKI, params ...string) (value any, err error)
|
||||
HandleInteractive func(ctx context.Context, info *Info, instance *wisski.WissKI, str stream.IOStream, params ...string) error
|
||||
HandleResult func(ctx context.Context, info *Info, instance *wisski.WissKI, params ...string) (value any, err error)
|
||||
}
|
||||
|
||||
var socketInstanceActions = map[string]InstanceAction{
|
||||
"snapshot": {
|
||||
HandleInteractive: func(info *Info, instance *wisski.WissKI, str stream.IOStream, params ...string) error {
|
||||
HandleInteractive: func(ctx context.Context, info *Info, instance *wisski.WissKI, str stream.IOStream, params ...string) error {
|
||||
return info.Exporter.MakeExport(
|
||||
ctx,
|
||||
str,
|
||||
exporter.ExportTask{
|
||||
Dest: "",
|
||||
|
|
@ -33,18 +35,18 @@ var socketInstanceActions = map[string]InstanceAction{
|
|||
},
|
||||
},
|
||||
"rebuild": {
|
||||
HandleInteractive: func(_ *Info, instance *wisski.WissKI, str stream.IOStream, params ...string) error {
|
||||
return instance.Barrel().Build(str, true)
|
||||
HandleInteractive: func(ctx context.Context, _ *Info, instance *wisski.WissKI, str stream.IOStream, params ...string) error {
|
||||
return instance.Barrel().Build(ctx, str, true)
|
||||
},
|
||||
},
|
||||
"update": {
|
||||
HandleInteractive: func(_ *Info, instance *wisski.WissKI, str stream.IOStream, params ...string) error {
|
||||
return instance.Drush().Update(str)
|
||||
HandleInteractive: func(ctx context.Context, _ *Info, instance *wisski.WissKI, str stream.IOStream, params ...string) error {
|
||||
return instance.Drush().Update(ctx, str)
|
||||
},
|
||||
},
|
||||
"cron": {
|
||||
HandleInteractive: func(_ *Info, instance *wisski.WissKI, str stream.IOStream, params ...string) error {
|
||||
return instance.Drush().Cron(str)
|
||||
HandleInteractive: func(ctx context.Context, _ *Info, instance *wisski.WissKI, str stream.IOStream, params ...string) error {
|
||||
return instance.Drush().Cron(ctx, str)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -75,7 +77,7 @@ func (info *Info) handleInstanceAction(conn httpx.WebSocketConnection, action In
|
|||
}
|
||||
|
||||
// resolve the instance
|
||||
instance, err := info.Instances.WissKI(string(slug.Bytes))
|
||||
instance, err := info.Instances.WissKI(conn.Context(), string(slug.Bytes))
|
||||
if err != nil {
|
||||
<-conn.WriteText("Instance not found")
|
||||
return
|
||||
|
|
@ -110,7 +112,7 @@ func (info *Info) handleInstanceAction(conn httpx.WebSocketConnection, action In
|
|||
|
||||
// handle the interactive action
|
||||
if action.HandleInteractive != nil {
|
||||
err := action.HandleInteractive(info, instance, str, params...)
|
||||
err := action.HandleInteractive(conn.Context(), info, instance, str, params...)
|
||||
if err != nil {
|
||||
str.EPrintln(err)
|
||||
return
|
||||
|
|
@ -120,7 +122,7 @@ func (info *Info) handleInstanceAction(conn httpx.WebSocketConnection, action In
|
|||
|
||||
// handle the result computation
|
||||
if action.HandleResult != nil {
|
||||
result, err := action.HandleResult(info, instance, params...)
|
||||
result, err := action.HandleResult(conn.Context(), info, instance, params...)
|
||||
if err != nil {
|
||||
str.Println("false")
|
||||
return
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import (
|
|||
// The server may spawn background tasks, but these should be terminated once context closes.
|
||||
//
|
||||
// Logging messages are directed to io.
|
||||
func (control *Control) Server(context context.Context, io stream.IOStream) (*http.ServeMux, error) {
|
||||
func (control *Control) Server(ctx context.Context, io stream.IOStream) (*http.ServeMux, error) {
|
||||
// create a new mux
|
||||
mux := http.NewServeMux()
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ func (control *Control) Server(context context.Context, io stream.IOStream) (*ht
|
|||
for _, s := range control.Servables {
|
||||
for _, route := range s.Routes() {
|
||||
io.Printf("mounting %s\n", route)
|
||||
handler, err := s.Handler(route, context, io)
|
||||
handler, err := s.Handler(ctx, route, io)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func (*Static) Routes() []string { return []string{"/static/"} }
|
|||
//go:embed dist
|
||||
var staticFS embed.FS
|
||||
|
||||
func (static *Static) Handler(route string, context context.Context, io stream.IOStream) (http.Handler, error) {
|
||||
func (static *Static) Handler(ctx context.Context, route string, io stream.IOStream) (http.Handler, error) {
|
||||
// take the filesystem
|
||||
fs, err := fs.Sub(staticFS, "dist")
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package exporter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
|
|
@ -49,7 +50,7 @@ type BackupDescription struct {
|
|||
}
|
||||
|
||||
// New create a new Backup
|
||||
func (exporter *Exporter) NewBackup(io stream.IOStream, description BackupDescription) (backup Backup) {
|
||||
func (exporter *Exporter) NewBackup(ctx context.Context, io stream.IOStream, description BackupDescription) (backup Backup) {
|
||||
backup.Description = description
|
||||
|
||||
// catch anything critical that happened during the snapshot
|
||||
|
|
@ -60,7 +61,7 @@ func (exporter *Exporter) NewBackup(io stream.IOStream, description BackupDescri
|
|||
// do the create keeping track of time!
|
||||
logging.LogOperation(func() error {
|
||||
backup.StartTime = time.Now().UTC()
|
||||
backup.run(io, exporter)
|
||||
backup.run(ctx, io, exporter)
|
||||
backup.EndTime = time.Now().UTC()
|
||||
|
||||
return nil
|
||||
|
|
@ -69,7 +70,7 @@ func (exporter *Exporter) NewBackup(io stream.IOStream, description BackupDescri
|
|||
return
|
||||
}
|
||||
|
||||
func (backup *Backup) run(ios stream.IOStream, exporter *Exporter) {
|
||||
func (backup *Backup) run(ctx context.Context, ios stream.IOStream, exporter *Exporter) {
|
||||
// create a manifest
|
||||
manifest, done := backup.handleManifest(backup.Description.Dest)
|
||||
defer done()
|
||||
|
|
@ -93,6 +94,7 @@ func (backup *Backup) run(ios stream.IOStream, exporter *Exporter) {
|
|||
Handler: func(bc component.Backupable, index int, writer io.Writer) error {
|
||||
return bc.Backup(
|
||||
component.NewStagingContext(
|
||||
ctx,
|
||||
exporter.Environment,
|
||||
stream.NewIOStream(writer, writer, nil, 0),
|
||||
filepath.Join(backup.Description.Dest, bc.BackupName()),
|
||||
|
|
@ -124,7 +126,7 @@ func (backup *Backup) run(ios stream.IOStream, exporter *Exporter) {
|
|||
}
|
||||
|
||||
// list all instances
|
||||
wissKIs, err := exporter.Instances.All()
|
||||
wissKIs, err := exporter.Instances.All(ctx)
|
||||
if err != nil {
|
||||
backup.InstanceListErr = err
|
||||
return nil
|
||||
|
|
@ -147,7 +149,7 @@ func (backup *Backup) run(ios stream.IOStream, exporter *Exporter) {
|
|||
|
||||
manifest <- dir
|
||||
|
||||
return exporter.NewSnapshot(instance, stream.NewIOStream(writer, writer, nil, 0), SnapshotDescription{
|
||||
return exporter.NewSnapshot(ctx, instance, stream.NewIOStream(writer, writer, nil, 0), SnapshotDescription{
|
||||
Dest: dir,
|
||||
})
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package exporter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
|
|
@ -19,8 +20,8 @@ func (Bookkeeping) SnapshotNeedsRunning() bool { return false }
|
|||
func (Bookkeeping) SnapshotName() string { return "bookkeeping.txt" }
|
||||
|
||||
// Snapshot creates a snapshot of this instance
|
||||
func (*Bookkeeping) Snapshot(wisski models.Instance, context component.StagingContext) error {
|
||||
return context.AddFile(".", func(file io.Writer) error {
|
||||
func (*Bookkeeping) Snapshot(wisski models.Instance, scontext component.StagingContext) error {
|
||||
return scontext.AddFile(".", func(ctx context.Context, file io.Writer) error {
|
||||
_, err := fmt.Fprintf(file, "%#v\n", wisski)
|
||||
return err
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package exporter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||
|
|
@ -15,13 +16,13 @@ func (*Config) BackupName() string {
|
|||
return "config"
|
||||
}
|
||||
|
||||
func (control *Config) Backup(context component.StagingContext) error {
|
||||
func (control *Config) Backup(scontext component.StagingContext) error {
|
||||
files := control.backupFiles()
|
||||
|
||||
return context.AddDirectory("", func() error {
|
||||
return scontext.AddDirectory("", func(ctx context.Context) error {
|
||||
for _, src := range files {
|
||||
name := filepath.Base(src)
|
||||
if err := context.CopyFile(name, src); err != nil {
|
||||
if err := scontext.CopyFile(name, src); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package exporter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||
|
|
@ -17,15 +18,15 @@ func (Pathbuilders) SnapshotNeedsRunning() bool { return true }
|
|||
|
||||
func (Pathbuilders) SnapshotName() string { return "pathbuilders" }
|
||||
|
||||
func (pbs *Pathbuilders) Snapshot(wisski models.Instance, context component.StagingContext) error {
|
||||
return context.AddDirectory(".", func() error {
|
||||
builders, err := pbs.Instances.Instance(wisski).Pathbuilder().GetAll(nil)
|
||||
func (pbs *Pathbuilders) Snapshot(wisski models.Instance, scontext component.StagingContext) error {
|
||||
return scontext.AddDirectory(".", func(ctx context.Context) error {
|
||||
builders, err := pbs.Instances.Instance(ctx, wisski).Pathbuilder().GetAll(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for name, bytes := range builders {
|
||||
if err := context.AddFile(name+".xml", func(file io.Writer) error {
|
||||
if err := scontext.AddFile(name+".xml", func(ctx context.Context, file io.Writer) error {
|
||||
_, err := file.Write([]byte(bytes))
|
||||
return err
|
||||
}); err != nil {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package exporter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"path/filepath"
|
||||
|
||||
|
|
@ -42,7 +43,7 @@ type export interface {
|
|||
|
||||
// MakeExport performs an export task as described by flags.
|
||||
// Output is directed to the provided io.
|
||||
func (exporter *Exporter) MakeExport(io stream.IOStream, task ExportTask) (err error) {
|
||||
func (exporter *Exporter) MakeExport(ctx context.Context, io stream.IOStream, task ExportTask) (err error) {
|
||||
// extract parameters
|
||||
Title := "Backup"
|
||||
Slug := ""
|
||||
|
|
@ -95,11 +96,11 @@ func (exporter *Exporter) MakeExport(io stream.IOStream, task ExportTask) (err e
|
|||
var sl export
|
||||
if task.Instance == nil {
|
||||
task.BackupDescription.Dest = stagingDir
|
||||
backup := exporter.NewBackup(io, task.BackupDescription)
|
||||
backup := exporter.NewBackup(ctx, io, task.BackupDescription)
|
||||
sl = &backup
|
||||
} else {
|
||||
task.SnapshotDescription.Dest = stagingDir
|
||||
snapshot := exporter.NewSnapshot(task.Instance, io, task.SnapshotDescription)
|
||||
snapshot := exporter.NewSnapshot(ctx, task.Instance, io, task.SnapshotDescription)
|
||||
sl = &snapshot
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +132,7 @@ func (exporter *Exporter) MakeExport(io stream.IOStream, task ExportTask) (err e
|
|||
// write out the log entry
|
||||
entry.Path = stagingDir
|
||||
entry.Packed = false
|
||||
exporter.ExporterLogger.Add(entry)
|
||||
exporter.ExporterLogger.Add(ctx, entry)
|
||||
|
||||
io.Printf("Wrote %s\n", stagingDir)
|
||||
return nil
|
||||
|
|
@ -159,7 +160,7 @@ func (exporter *Exporter) MakeExport(io stream.IOStream, task ExportTask) (err e
|
|||
logging.LogMessage(io, "Writing Log Entry")
|
||||
entry.Path = archivePath
|
||||
entry.Packed = true
|
||||
exporter.ExporterLogger.Add(entry)
|
||||
exporter.ExporterLogger.Add(ctx, entry)
|
||||
|
||||
// and we're done!
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package logger
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/sql"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||
|
|
@ -19,8 +21,8 @@ type Logger struct {
|
|||
// For retrieves (and prunes) the ExportLog.
|
||||
// Slug determines if entries for Backups (empty slug)
|
||||
// or a specific Instance (non-empty slug) are returned.
|
||||
func (log *Logger) For(slug string) (exports []models.Export, err error) {
|
||||
exports, err = log.Log()
|
||||
func (log *Logger) For(ctx context.Context, slug string) (exports []models.Export, err error) {
|
||||
exports, err = log.Log(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -31,9 +33,9 @@ func (log *Logger) For(slug string) (exports []models.Export, err error) {
|
|||
}
|
||||
|
||||
// Log retrieves (and prunes) all entries in the snapshot log.
|
||||
func (log *Logger) Log() ([]models.Export, error) {
|
||||
func (log *Logger) Log(ctx context.Context) ([]models.Export, error) {
|
||||
// query the table!
|
||||
table, err := log.SQL.QueryTable(false, models.ExportTable)
|
||||
table, err := log.SQL.QueryTable(ctx, false, models.ExportTable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -63,9 +65,9 @@ func (log *Logger) Log() ([]models.Export, error) {
|
|||
}
|
||||
|
||||
// AddToExportLog adds the provided export to the log.
|
||||
func (log *Logger) Add(export models.Export) error {
|
||||
func (log *Logger) Add(ctx context.Context, export models.Export) error {
|
||||
// find the table
|
||||
table, err := log.SQL.QueryTable(false, models.ExportTable)
|
||||
table, err := log.SQL.QueryTable(ctx, false, models.ExportTable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -79,7 +81,7 @@ func (log *Logger) Add(export models.Export) error {
|
|||
}
|
||||
|
||||
// Fetch writes the SnapshotLog into the given observation
|
||||
func (logger *Logger) Fetch(flags component.FetcherFlags, target *status.Distillery) (err error) {
|
||||
target.Backups, err = logger.For("")
|
||||
func (logger *Logger) Fetch(ctx context.Context, flags component.FetcherFlags, target *status.Distillery) (err error) {
|
||||
target.Backups, err = logger.For(ctx, "")
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package exporter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
|
|
@ -14,7 +15,7 @@ func (exporter *Exporter) ShouldPrune(modtime time.Time) bool {
|
|||
}
|
||||
|
||||
// Prune prunes all old exports
|
||||
func (exporter *Exporter) PruneExports(io stream.IOStream) error {
|
||||
func (exporter *Exporter) PruneExports(ctx context.Context, io stream.IOStream) error {
|
||||
sPath := exporter.ArchivePath()
|
||||
|
||||
// list all the files
|
||||
|
|
@ -50,6 +51,6 @@ func (exporter *Exporter) PruneExports(io stream.IOStream) error {
|
|||
}
|
||||
|
||||
// prune the snapshot log!
|
||||
_, err = exporter.ExporterLogger.Log()
|
||||
_, err = exporter.ExporterLogger.Log(ctx)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package exporter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
|
|
@ -44,10 +45,10 @@ type Snapshot struct {
|
|||
}
|
||||
|
||||
// Snapshot creates a new snapshot of this instance into dest
|
||||
func (snapshots *Exporter) NewSnapshot(instance *wisski.WissKI, io stream.IOStream, desc SnapshotDescription) (snapshot Snapshot) {
|
||||
func (snapshots *Exporter) NewSnapshot(ctx context.Context, instance *wisski.WissKI, io stream.IOStream, desc SnapshotDescription) (snapshot Snapshot) {
|
||||
|
||||
logging.LogMessage(io, "Locking instance")
|
||||
if !instance.Locker().TryLock() {
|
||||
if !instance.Locker().TryLock(ctx) {
|
||||
err := locker.Locked
|
||||
io.EPrintln(err)
|
||||
logging.LogMessage(io, "Aborting snapshot creation")
|
||||
|
|
@ -58,7 +59,7 @@ func (snapshots *Exporter) NewSnapshot(instance *wisski.WissKI, io stream.IOStre
|
|||
}
|
||||
defer func() {
|
||||
logging.LogMessage(io, "Unlocking instance")
|
||||
instance.Locker().Unlock()
|
||||
instance.Locker().Unlock(ctx)
|
||||
}()
|
||||
|
||||
// setup the snapshot
|
||||
|
|
@ -74,8 +75,8 @@ func (snapshots *Exporter) NewSnapshot(instance *wisski.WissKI, io stream.IOStre
|
|||
logging.LogOperation(func() error {
|
||||
snapshot.StartTime = time.Now().UTC()
|
||||
|
||||
snapshot.ErrWhitebox = snapshot.makeParts(io, snapshots, instance, false)
|
||||
snapshot.ErrBlackbox = snapshot.makeParts(io, snapshots, instance, true)
|
||||
snapshot.ErrWhitebox = snapshot.makeParts(ctx, io, snapshots, instance, false)
|
||||
snapshot.ErrBlackbox = snapshot.makeParts(ctx, io, snapshots, instance, true)
|
||||
|
||||
snapshot.EndTime = time.Now().UTC()
|
||||
return nil
|
||||
|
|
@ -85,16 +86,16 @@ func (snapshots *Exporter) NewSnapshot(instance *wisski.WissKI, io stream.IOStre
|
|||
return
|
||||
}
|
||||
|
||||
func (snapshot *Snapshot) makeParts(ios stream.IOStream, snapshots *Exporter, instance *wisski.WissKI, needsRunning bool) map[string]error {
|
||||
func (snapshot *Snapshot) makeParts(ctx context.Context, ios stream.IOStream, snapshots *Exporter, instance *wisski.WissKI, needsRunning bool) map[string]error {
|
||||
if !needsRunning && !snapshot.Description.Keepalive {
|
||||
stack := instance.Barrel().Stack()
|
||||
|
||||
logging.LogMessage(ios, "Stopping instance")
|
||||
snapshot.ErrStop = stack.Down(ios)
|
||||
snapshot.ErrStop = stack.Down(ctx, ios)
|
||||
|
||||
defer func() {
|
||||
logging.LogMessage(ios, "Starting instance")
|
||||
snapshot.ErrStart = stack.Up(ios)
|
||||
snapshot.ErrStart = stack.Up(ctx, ios)
|
||||
}()
|
||||
}
|
||||
// handle writing the manifest!
|
||||
|
|
@ -123,6 +124,7 @@ func (snapshot *Snapshot) makeParts(ios stream.IOStream, snapshots *Exporter, in
|
|||
return sc.Snapshot(
|
||||
instance.Instance,
|
||||
component.NewStagingContext(
|
||||
ctx,
|
||||
snapshots.Environment,
|
||||
stream.NewIOStream(writer, writer, nil, 0),
|
||||
filepath.Join(snapshot.Description.Dest, sc.SnapshotName()),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
package component
|
||||
|
||||
import "github.com/FAU-CDI/wisski-distillery/internal/status"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/status"
|
||||
)
|
||||
|
||||
type DistilleryFetcher interface {
|
||||
Component
|
||||
|
|
@ -11,4 +15,6 @@ type DistilleryFetcher interface {
|
|||
}
|
||||
|
||||
// FetcherFlags describes options for a DistilleryFetcher
|
||||
type FetcherFlags struct{}
|
||||
type FetcherFlags struct {
|
||||
Context context.Context
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package component
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/pkg/environment"
|
||||
"github.com/tkw1536/goprogram/stream"
|
||||
)
|
||||
|
|
@ -40,5 +42,5 @@ type Updatable interface {
|
|||
// It may send output to the provided stream.
|
||||
//
|
||||
// Updating should be idempotent, meaning running it multiple times must not break the existing system.
|
||||
Update(stream stream.IOStream) error
|
||||
Update(ctx context.Context, stream stream.IOStream) error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package instances
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"path/filepath"
|
||||
|
||||
|
|
@ -42,13 +43,13 @@ func (instances *Instances) use(wisski *wisski.WissKI) {
|
|||
|
||||
// WissKI returns the WissKI with the provided slug, if it exists.
|
||||
// It the WissKI does not exist, returns ErrWissKINotFound.
|
||||
func (instances *Instances) WissKI(slug string) (wissKI *wisski.WissKI, err error) {
|
||||
func (instances *Instances) WissKI(ctx context.Context, slug string) (wissKI *wisski.WissKI, err error) {
|
||||
sql := instances.SQL
|
||||
if err := sql.WaitQueryTable(); err != nil {
|
||||
if err := sql.WaitQueryTable(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
table, err := sql.QueryTable(false, models.InstanceTable)
|
||||
table, err := sql.QueryTable(ctx, false, models.InstanceTable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -72,8 +73,8 @@ func (instances *Instances) WissKI(slug string) (wissKI *wisski.WissKI, err erro
|
|||
|
||||
// Instance is a convenience function to return an instance based on a model slug.
|
||||
// When the instance does not exist, returns nil.
|
||||
func (instances *Instances) Instance(instance models.Instance) *wisski.WissKI {
|
||||
wissKI, err := instances.WissKI(instance.Slug)
|
||||
func (instances *Instances) Instance(ctx context.Context, instance models.Instance) *wisski.WissKI {
|
||||
wissKI, err := instances.WissKI(ctx, instance.Slug)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -82,13 +83,13 @@ func (instances *Instances) Instance(instance models.Instance) *wisski.WissKI {
|
|||
|
||||
// Has checks if a WissKI with the provided slug exists inside the database.
|
||||
// It does not perform any checks on the WissKI itself.
|
||||
func (instances *Instances) Has(slug string) (ok bool, err error) {
|
||||
func (instances *Instances) Has(ctx context.Context, slug string) (ok bool, err error) {
|
||||
sql := instances.SQL
|
||||
if err := sql.WaitQueryTable(); err != nil {
|
||||
if err := sql.WaitQueryTable(ctx); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
table, err := sql.QueryTable(false, models.InstanceTable)
|
||||
table, err := sql.QueryTable(ctx, false, models.InstanceTable)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
|
@ -103,37 +104,37 @@ func (instances *Instances) Has(slug string) (ok bool, err error) {
|
|||
// All returns all instances of the WissKI Distillery in consistent order.
|
||||
//
|
||||
// There is no guarantee that this order remains identical between different api releases; however subsequent invocations are guaranteed to return the same order.
|
||||
func (instances *Instances) All() ([]*wisski.WissKI, error) {
|
||||
return instances.find(true, func(table *gorm.DB) *gorm.DB {
|
||||
func (instances *Instances) All(ctx context.Context) ([]*wisski.WissKI, error) {
|
||||
return instances.find(ctx, true, func(table *gorm.DB) *gorm.DB {
|
||||
return table
|
||||
})
|
||||
}
|
||||
|
||||
// WissKIs returns the WissKI instances with the provides slugs.
|
||||
// If a slug does not exist, it is omitted from the result.
|
||||
func (instances *Instances) WissKIs(slugs ...string) ([]*wisski.WissKI, error) {
|
||||
return instances.find(true, func(table *gorm.DB) *gorm.DB {
|
||||
func (instances *Instances) WissKIs(ctx context.Context, slugs ...string) ([]*wisski.WissKI, error) {
|
||||
return instances.find(ctx, true, func(table *gorm.DB) *gorm.DB {
|
||||
return table.Where("slug IN ?", slugs)
|
||||
})
|
||||
}
|
||||
|
||||
// Load is like All, except that when no slugs are provided, it calls All.
|
||||
func (instances *Instances) Load(slugs ...string) ([]*wisski.WissKI, error) {
|
||||
func (instances *Instances) Load(ctx context.Context, slugs ...string) ([]*wisski.WissKI, error) {
|
||||
if len(slugs) == 0 {
|
||||
return instances.All()
|
||||
return instances.All(ctx)
|
||||
}
|
||||
return instances.WissKIs(slugs...)
|
||||
return instances.WissKIs(ctx, slugs...)
|
||||
}
|
||||
|
||||
// find finds instances based on the provided query
|
||||
func (instances *Instances) find(order bool, query func(table *gorm.DB) *gorm.DB) (results []*wisski.WissKI, err error) {
|
||||
func (instances *Instances) find(ctx context.Context, order bool, query func(table *gorm.DB) *gorm.DB) (results []*wisski.WissKI, err error) {
|
||||
sql := instances.SQL
|
||||
if err := sql.WaitQueryTable(); err != nil {
|
||||
if err := sql.WaitQueryTable(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// open the bookkeeping table
|
||||
table, err := sql.QueryTable(false, models.InstanceTable)
|
||||
table, err := sql.QueryTable(ctx, false, models.InstanceTable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package instances
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/pkg/unpack"
|
||||
|
|
@ -19,7 +20,7 @@ var errBootstrapFailedRuntime = exit.Error{
|
|||
var runtimeResources embed.FS
|
||||
|
||||
// Update installs or updates runtime components needed by this component.
|
||||
func (instances *Instances) Update(stream stream.IOStream) error {
|
||||
func (instances *Instances) Update(ctx context.Context, stream stream.IOStream) error {
|
||||
err := unpack.InstallDir(instances.Still.Environment, instances.Config.RuntimeDir(), "runtime", runtimeResources, func(dst, src string) {
|
||||
stream.Printf("[copy] %s\n", dst)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,14 +1,18 @@
|
|||
package meta
|
||||
|
||||
import "github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||
)
|
||||
|
||||
// Provision provisions new meta storage for this instance.
|
||||
// NOTE(twiesing): This is a no-op, because we implement Purge.
|
||||
func (meta *Meta) Provision(instance models.Instance, domain string) error {
|
||||
func (meta *Meta) Provision(ctx context.Context, instance models.Instance, domain string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Purge purges the storage for the given instance.
|
||||
func (meta *Meta) Purge(instance models.Instance, domain string) error {
|
||||
return meta.Storage(instance.Slug).Purge()
|
||||
func (meta *Meta) Purge(ctx context.Context, instance models.Instance, domain string) error {
|
||||
return meta.Storage(instance.Slug).Purge(ctx)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package meta
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
|
|
@ -24,8 +25,8 @@ type Storage struct {
|
|||
|
||||
// Get retrieves metadata with the provided key and deserializes the first one into target.
|
||||
// If no metadatum exists, returns [ErrMetadatumNotSet].
|
||||
func (s Storage) Get(key Key, target any) error {
|
||||
table, err := s.sql.QueryTable(true, models.MetadataTable)
|
||||
func (s Storage) Get(ctx context.Context, key Key, target any) error {
|
||||
table, err := s.sql.QueryTable(ctx, true, models.MetadataTable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -53,8 +54,8 @@ func (s Storage) Get(key Key, target any) error {
|
|||
// The function is intended to return a target for deserialization.
|
||||
//
|
||||
// When no metadatum exists, targets is not called, and nil error is returned.
|
||||
func (s Storage) GetAll(key Key, target func(index, total int) any) error {
|
||||
table, err := s.sql.QueryTable(true, models.MetadataTable)
|
||||
func (s Storage) GetAll(ctx context.Context, key Key, target func(index, total int) any) error {
|
||||
table, err := s.sql.QueryTable(ctx, true, models.MetadataTable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -80,8 +81,8 @@ func (s Storage) GetAll(key Key, target func(index, total int) any) error {
|
|||
}
|
||||
|
||||
// Delete deletes all metadata with the provided key.
|
||||
func (s Storage) Delete(key Key) error {
|
||||
table, err := s.sql.QueryTable(true, models.MetadataTable)
|
||||
func (s Storage) Delete(ctx context.Context, key Key) error {
|
||||
table, err := s.sql.QueryTable(ctx, true, models.MetadataTable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -96,8 +97,8 @@ func (s Storage) Delete(key Key) error {
|
|||
|
||||
// Set serializes value and stores it with the provided key.
|
||||
// Any other metadata with the same key is deleted.
|
||||
func (s Storage) Set(key Key, value any) error {
|
||||
table, err := s.sql.QueryTable(true, models.MetadataTable)
|
||||
func (s Storage) Set(ctx context.Context, key Key, value any) error {
|
||||
table, err := s.sql.QueryTable(ctx, true, models.MetadataTable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -131,8 +132,8 @@ func (s Storage) Set(key Key, value any) error {
|
|||
|
||||
// Set serializes values and stores them with the provided key.
|
||||
// Any other metadata with the same key is deleted.
|
||||
func (s Storage) SetAll(key Key, values ...any) error {
|
||||
table, err := s.sql.QueryTable(true, models.MetadataTable)
|
||||
func (s Storage) SetAll(ctx context.Context, key Key, values ...any) error {
|
||||
table, err := s.sql.QueryTable(ctx, true, models.MetadataTable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -165,8 +166,8 @@ func (s Storage) SetAll(key Key, values ...any) error {
|
|||
}
|
||||
|
||||
// Purge removes all metadata, regardless of key.
|
||||
func (s Storage) Purge() error {
|
||||
table, err := s.sql.QueryTable(true, models.MetadataTable)
|
||||
func (s Storage) Purge(ctx context.Context) error {
|
||||
table, err := s.sql.QueryTable(ctx, true, models.MetadataTable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -181,22 +182,22 @@ func (s Storage) Purge() error {
|
|||
// TypedKey represents a convenience wrapper for a given with a given value.
|
||||
type TypedKey[Value any] Key
|
||||
|
||||
func (f TypedKey[Value]) Get(s *Storage) (value Value, err error) {
|
||||
err = s.Get(Key(f), &value)
|
||||
func (f TypedKey[Value]) Get(ctx context.Context, s *Storage) (value Value, err error) {
|
||||
err = s.Get(ctx, Key(f), &value)
|
||||
return
|
||||
}
|
||||
|
||||
func (f TypedKey[Value]) GetOrSet(s *Storage, dflt Value) (value Value, err error) {
|
||||
value, err = f.Get(s)
|
||||
func (f TypedKey[Value]) GetOrSet(ctx context.Context, s *Storage, dflt Value) (value Value, err error) {
|
||||
value, err = f.Get(ctx, s)
|
||||
if err == ErrMetadatumNotSet {
|
||||
value = dflt
|
||||
err = f.Set(s, value)
|
||||
err = f.Set(ctx, s, value)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (f TypedKey[Value]) GetAll(m *Storage) (values []Value, err error) {
|
||||
err = m.GetAll(Key(f), func(index, total int) any {
|
||||
func (f TypedKey[Value]) GetAll(ctx context.Context, m *Storage) (values []Value, err error) {
|
||||
err = m.GetAll(ctx, Key(f), func(index, total int) any {
|
||||
if values == nil {
|
||||
values = make([]Value, total)
|
||||
}
|
||||
|
|
@ -205,14 +206,14 @@ func (f TypedKey[Value]) GetAll(m *Storage) (values []Value, err error) {
|
|||
return values, err
|
||||
}
|
||||
|
||||
func (f TypedKey[Value]) Set(m *Storage, value Value) error {
|
||||
return m.Set(Key(f), value)
|
||||
func (f TypedKey[Value]) Set(ctx context.Context, m *Storage, value Value) error {
|
||||
return m.Set(ctx, Key(f), value)
|
||||
}
|
||||
|
||||
func (f TypedKey[Value]) SetAll(m *Storage, values ...Value) error {
|
||||
return m.SetAll(Key(f), collection.AsAny(values)...)
|
||||
func (f TypedKey[Value]) SetAll(ctx context.Context, m *Storage, values ...Value) error {
|
||||
return m.SetAll(ctx, Key(f), collection.AsAny(values)...)
|
||||
}
|
||||
|
||||
func (f TypedKey[Value]) Delete(m *Storage) error {
|
||||
return m.Delete(Key(f))
|
||||
func (f TypedKey[Value]) Delete(ctx context.Context, m *Storage) error {
|
||||
return m.Delete(ctx, Key(f))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package component
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||
)
|
||||
|
||||
|
|
@ -10,9 +12,9 @@ type Provisionable interface {
|
|||
|
||||
// Provision provisions resources specific to the provided instance.
|
||||
// Domain holds the full (unique) domain name of the given instance.
|
||||
Provision(instance models.Instance, domain string) error
|
||||
Provision(ctx context.Context, instance models.Instance, domain string) error
|
||||
|
||||
// Purge purges resources specific to the provided instance.
|
||||
// Domain holds the full (unique) domain name of the given instance.
|
||||
Purge(instance models.Instance, domain string) error
|
||||
Purge(ctx context.Context, instance models.Instance, domain string) error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,20 +9,34 @@ import (
|
|||
)
|
||||
|
||||
// updatePrefixes starts updating prefixes
|
||||
func (resolver *Resolver) updatePrefixes(io stream.IOStream, ctx context.Context) {
|
||||
func (resolver *Resolver) updatePrefixes(ctx context.Context, io stream.IOStream) {
|
||||
go func() {
|
||||
for t := range timex.TickContext(ctx, resolver.RefreshInterval) {
|
||||
io.Printf("[%s]: reloading prefixes\n", t.Format(time.Stamp))
|
||||
prefixes, _ := resolver.AllPrefixes()
|
||||
resolver.prefixes.Set(prefixes)
|
||||
|
||||
err := (func() (err error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, resolver.RefreshInterval)
|
||||
defer cancel()
|
||||
|
||||
prefixes, err := resolver.AllPrefixes(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resolver.prefixes.Set(prefixes)
|
||||
return nil
|
||||
})()
|
||||
if err != nil {
|
||||
io.EPrintf("error reloading prefixes: ", err.Error())
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// AllPrefixes returns a list of all prefixes from the server.
|
||||
// Prefixes may be cached on the server
|
||||
func (resolver *Resolver) AllPrefixes() (map[string]string, error) {
|
||||
instances, err := resolver.Instances.All()
|
||||
func (resolver *Resolver) AllPrefixes(ctx context.Context) (map[string]string, error) {
|
||||
instances, err := resolver.Instances.All(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -37,7 +51,7 @@ func (resolver *Resolver) AllPrefixes() (map[string]string, error) {
|
|||
|
||||
// failed to fetch prefixes for this particular instance
|
||||
// => skip it!
|
||||
prefixes, err := instance.Prefixes().AllCached()
|
||||
prefixes, err := instance.Prefixes().AllCached(ctx)
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ type Resolver struct {
|
|||
|
||||
func (resolver *Resolver) Routes() []string { return []string{"/go/", "/wisski/get/"} }
|
||||
|
||||
func (resolver *Resolver) Handler(route string, context context.Context, io stream.IOStream) (http.Handler, error) {
|
||||
func (resolver *Resolver) Handler(ctx context.Context, route string, io stream.IOStream) (http.Handler, error) {
|
||||
var err error
|
||||
return resolver.handler.Get(func() (p wdresolve.ResolveHandler) {
|
||||
p.TrustXForwardedProto = true
|
||||
|
|
@ -51,7 +51,7 @@ func (resolver *Resolver) Handler(route string, context context.Context, io stre
|
|||
}
|
||||
|
||||
// start updating prefixes
|
||||
resolver.updatePrefixes(io, context)
|
||||
resolver.updatePrefixes(ctx, io)
|
||||
|
||||
// resolve the prefixes
|
||||
p.Resolver = resolvers.InOrder{
|
||||
|
|
|
|||
|
|
@ -15,5 +15,5 @@ type Servable interface {
|
|||
Routes() []string
|
||||
|
||||
// Handler returns the handler for the requested route
|
||||
Handler(route string, context context.Context, io stream.IOStream) (http.Handler, error)
|
||||
Handler(ctx context.Context, route string, io stream.IOStream) (http.Handler, error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package solr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
|
@ -15,8 +14,7 @@ type Solr struct {
|
|||
|
||||
BaseURL string // upstream solr url
|
||||
|
||||
PollContext context.Context // context to abort polling with
|
||||
PollInterval time.Duration // duration to wait for during wait
|
||||
PollInterval time.Duration // duration to wait for during wait
|
||||
}
|
||||
|
||||
func (s *Solr) Path() string {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package sql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
|
|
@ -14,10 +15,10 @@ func (*SQL) BackupName() string {
|
|||
}
|
||||
|
||||
// Backup makes a backup of all SQL databases into the path dest.
|
||||
func (sql *SQL) Backup(context component.StagingContext) error {
|
||||
return context.AddFile("", func(file io.Writer) error {
|
||||
io := context.IO().Streams(file, nil, nil, 0).NonInteractive()
|
||||
code, err := sql.Stack(sql.Environment).Exec(io, "sql", "mysqldump", "--all-databases")
|
||||
func (sql *SQL) Backup(scontext component.StagingContext) error {
|
||||
return scontext.AddFile("", func(ctx context.Context, file io.Writer) error {
|
||||
io := scontext.IO().Streams(file, nil, nil, 0).NonInteractive()
|
||||
code, err := sql.Stack(sql.Environment).Exec(ctx, io, "sql", "mysqldump", "--all-databases")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,20 +40,12 @@ func (sql *SQL) Exec(query string, args ...interface{}) error {
|
|||
}
|
||||
}
|
||||
|
||||
// WaitExec waits for the query interface to be able to connect to the database
|
||||
func (sql *SQL) WaitExec() error {
|
||||
return timex.TickUntilFunc(func(time.Time) bool {
|
||||
err := sql.Exec("select 1;")
|
||||
return err == nil
|
||||
}, sql.PollContext, sql.PollInterval)
|
||||
}
|
||||
|
||||
//
|
||||
// ========== connection via gorm ==========
|
||||
//
|
||||
|
||||
// QueryTable returns a gorm.DB to connect to the provided distillery database table
|
||||
func (sql *SQL) QueryTable(silent bool, table string) (*gorm.DB, error) {
|
||||
func (sql *SQL) QueryTable(ctx context.Context, silent bool, table string) (*gorm.DB, error) {
|
||||
conn, err := sql.connect(sql.Config.DistilleryDatabase)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -79,7 +71,7 @@ func (sql *SQL) QueryTable(silent bool, table string) (*gorm.DB, error) {
|
|||
}
|
||||
|
||||
// set the table
|
||||
db = db.Table(table)
|
||||
db = db.WithContext(ctx).Table(table)
|
||||
|
||||
// check that nothing went wrong
|
||||
if db.Error != nil {
|
||||
|
|
@ -89,12 +81,12 @@ func (sql *SQL) QueryTable(silent bool, table string) (*gorm.DB, error) {
|
|||
}
|
||||
|
||||
// WaitQueryTable waits for a connection to succeed via QueryTable
|
||||
func (sql *SQL) WaitQueryTable() error {
|
||||
func (sql *SQL) WaitQueryTable(ctx context.Context) error {
|
||||
// TODO: Establish a convention on when to wait for this!
|
||||
return timex.TickUntilFunc(func(time.Time) bool {
|
||||
_, err := sql.QueryTable(true, models.InstanceTable)
|
||||
_, err := sql.QueryTable(ctx, true, models.InstanceTable)
|
||||
return err == nil
|
||||
}, sql.PollContext, sql.PollInterval)
|
||||
}, ctx, sql.PollInterval)
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package sql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||
|
|
@ -12,15 +13,15 @@ var errProvisionInvalidDatabaseParams = errors.New("Provision: Invalid parameter
|
|||
var errProvisionInvalidGrant = errors.New("Provision: Grant failed")
|
||||
|
||||
// Provision provisions sql-specific resource for the given instance
|
||||
func (sql *SQL) Provision(instance models.Instance, domain string) error {
|
||||
return sql.CreateDatabase(instance.SqlDatabase, instance.SqlUsername, instance.SqlPassword)
|
||||
func (sql *SQL) Provision(ctx context.Context, instance models.Instance, domain string) error {
|
||||
return sql.CreateDatabase(ctx, instance.SqlDatabase, instance.SqlUsername, instance.SqlPassword)
|
||||
}
|
||||
|
||||
// Purge purges sql-specific resources for the given instance
|
||||
func (sql *SQL) Purge(instance models.Instance, domain string) error {
|
||||
func (sql *SQL) Purge(ctx context.Context, instance models.Instance, domain string) error {
|
||||
return errorx.First(
|
||||
sql.PurgeDatabase(instance.SqlDatabase),
|
||||
sql.PurgeUser(instance.SqlUsername),
|
||||
sql.PurgeUser(ctx, instance.SqlUsername),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -28,7 +29,7 @@ func (sql *SQL) Purge(instance models.Instance, domain string) error {
|
|||
// It then generates a new user, with the name 'user' and the password 'password', that is then granted access to this database.
|
||||
//
|
||||
// Provision internally waits for the database to become available.
|
||||
func (sql *SQL) CreateDatabase(name, user, password string) error {
|
||||
func (sql *SQL) CreateDatabase(ctx context.Context, name, user, password string) error {
|
||||
|
||||
// NOTE(twiesing): We shouldn't use string concat to build sql queries.
|
||||
// But the driver doesn't support using query params for this particular query.
|
||||
|
|
@ -43,14 +44,14 @@ func (sql *SQL) CreateDatabase(name, user, password string) error {
|
|||
// Queries of the form "CREATE USER 'test'@'%' IDENTIFIED BY 'test'; FLUSH PRIVILEGES;" return error 1064 when using driver, but are fine with the shell.
|
||||
// This should be fixed eventually, but I have no idea how.
|
||||
|
||||
if err := sql.unsafeWaitShell(); err != nil {
|
||||
if err := sql.unsafeWaitShell(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query := "CREATE DATABASE `" + name + "`;" +
|
||||
"CREATE USER '" + user + "'@'%' IDENTIFIED BY '" + password + "';" +
|
||||
"GRANT ALL PRIVILEGES ON `" + name + "`.* TO `" + user + "`@`%`; FLUSH PRIVILEGES;"
|
||||
if !sql.unsafeQueryShell(query) {
|
||||
if !sql.unsafeQueryShell(ctx, query) {
|
||||
return errProvisionInvalidGrant
|
||||
}
|
||||
|
||||
|
|
@ -63,7 +64,7 @@ var errCreateSuperuserGrant = errors.New("CreateSuperUser: Grant failed")
|
|||
// It then grants this user superuser status in the database.
|
||||
//
|
||||
// CreateSuperuser internally waits for the database to become available.
|
||||
func (sql *SQL) CreateSuperuser(user, password string, allowExisting bool) error {
|
||||
func (sql *SQL) CreateSuperuser(ctx context.Context, user, password string, allowExisting bool) error {
|
||||
// NOTE(twiesing): This function unsafely uses the shell directly to create a superuser.
|
||||
// This is for two reasons:
|
||||
// (1) this is used during bootstraping
|
||||
|
|
@ -74,7 +75,7 @@ func (sql *SQL) CreateSuperuser(user, password string, allowExisting bool) error
|
|||
return errProvisionInvalidDatabaseParams
|
||||
}
|
||||
|
||||
if err := sql.unsafeWaitShell(); err != nil {
|
||||
if err := sql.unsafeWaitShell(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -85,7 +86,7 @@ func (sql *SQL) CreateSuperuser(user, password string, allowExisting bool) error
|
|||
|
||||
query := "CREATE USER " + IfNotExists + " '" + user + "'@'%' IDENTIFIED BY '" + password + "';" +
|
||||
"GRANT ALL PRIVILEGES ON *.* TO '" + user + "'@'%' WITH GRANT OPTION; FLUSH PRIVILEGES;"
|
||||
if !sql.unsafeQueryShell(query) {
|
||||
if !sql.unsafeQueryShell(ctx, query) {
|
||||
return errCreateSuperuserGrant
|
||||
}
|
||||
|
||||
|
|
@ -95,14 +96,14 @@ func (sql *SQL) CreateSuperuser(user, password string, allowExisting bool) error
|
|||
var errPurgeUser = errors.New("PurgeUser: Failed to drop user")
|
||||
|
||||
// SQLPurgeUser deletes the specified user from the database
|
||||
func (sql *SQL) PurgeUser(user string) error {
|
||||
func (sql *SQL) PurgeUser(ctx context.Context, user string) error {
|
||||
if !sqle.IsSafeDatabaseSingleQuote(user) {
|
||||
return errPurgeUser
|
||||
}
|
||||
|
||||
query := "DROP USER IF EXISTS '" + user + "'@'%';" +
|
||||
"FLUSH PRIVILEGES;"
|
||||
if !sql.unsafeQueryShell(query) {
|
||||
if !sql.unsafeQueryShell(ctx, query) {
|
||||
return errPurgeUser
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package sql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||
|
|
@ -12,19 +13,19 @@ func (*SQL) SnapshotNeedsRunning() bool { return false }
|
|||
|
||||
func (*SQL) SnapshotName() string { return "sql" }
|
||||
|
||||
func (sql *SQL) Snapshot(wisski models.Instance, context component.StagingContext) error {
|
||||
return context.AddDirectory(".", func() error {
|
||||
return context.AddFile(wisski.SqlDatabase+".sql", func(file io.Writer) error {
|
||||
return sql.SnapshotDB(context.IO(), file, wisski.SqlDatabase)
|
||||
func (sql *SQL) Snapshot(wisski models.Instance, scontext component.StagingContext) error {
|
||||
return scontext.AddDirectory(".", func(ctx context.Context) error {
|
||||
return scontext.AddFile(wisski.SqlDatabase+".sql", func(ctx context.Context, file io.Writer) error {
|
||||
return sql.SnapshotDB(ctx, scontext.IO(), file, wisski.SqlDatabase)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// SnapshotDB makes a backup of the sql database into dest.
|
||||
func (sql *SQL) SnapshotDB(io stream.IOStream, dest io.Writer, database string) error {
|
||||
func (sql *SQL) SnapshotDB(ctx context.Context, io stream.IOStream, dest io.Writer, database string) error {
|
||||
io = io.Streams(dest, nil, nil, 0).NonInteractive()
|
||||
|
||||
code, err := sql.Stack(sql.Environment).Exec(io, "sql", "mysqldump", "--databases", database)
|
||||
code, err := sql.Stack(sql.Environment).Exec(ctx, io, "sql", "mysqldump", "--databases", database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package sql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
|
@ -16,8 +15,7 @@ type SQL struct {
|
|||
|
||||
ServerURL string // upstream server url
|
||||
|
||||
PollContext context.Context // context to abort polling with
|
||||
PollInterval time.Duration // duration to wait for during wait
|
||||
PollInterval time.Duration // duration to wait for during wait
|
||||
|
||||
lazyNetwork lazy.Lazy[string]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package sql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
|
@ -16,22 +17,22 @@ import (
|
|||
// Shell runs a mysql shell with the provided databases.
|
||||
//
|
||||
// NOTE(twiesing): This command should not be used to connect to the database or execute queries except in known situations.
|
||||
func (sql *SQL) Shell(io stream.IOStream, argv ...string) (int, error) {
|
||||
return sql.Stack(sql.Environment).Exec(io, "sql", "mysql", argv...)
|
||||
func (sql *SQL) Shell(ctx context.Context, io stream.IOStream, argv ...string) (int, error) {
|
||||
return sql.Stack(sql.Environment).Exec(ctx, io, "sql", "mysql", argv...)
|
||||
}
|
||||
|
||||
// unsafeWaitShell waits for a connection via the database shell to succeed
|
||||
func (sql *SQL) unsafeWaitShell() error {
|
||||
func (sql *SQL) unsafeWaitShell(ctx context.Context) error {
|
||||
n := stream.FromNil()
|
||||
return timex.TickUntilFunc(func(time.Time) bool {
|
||||
code, err := sql.Shell(n, "-e", "select 1;")
|
||||
code, err := sql.Shell(ctx, n, "-e", "select 1;")
|
||||
return err == nil && code == 0
|
||||
}, sql.PollContext, sql.PollInterval)
|
||||
}, ctx, sql.PollInterval)
|
||||
}
|
||||
|
||||
// unsafeQuery shell executes a raw database query.
|
||||
func (sql *SQL) unsafeQueryShell(query string) bool {
|
||||
code, err := sql.Shell(stream.FromNil(), "-e", query)
|
||||
func (sql *SQL) unsafeQueryShell(ctx context.Context, query string) bool {
|
||||
code, err := sql.Shell(ctx, stream.FromNil(), "-e", query)
|
||||
return err == nil && code == 0
|
||||
}
|
||||
|
||||
|
|
@ -43,18 +44,18 @@ var errSQLUnableToMigrate = exit.Error{
|
|||
}
|
||||
|
||||
// Update initializes or updates the SQL database.
|
||||
func (sql *SQL) Update(io stream.IOStream) error {
|
||||
func (sql *SQL) Update(ctx context.Context, io stream.IOStream) error {
|
||||
|
||||
// unsafely create the admin user!
|
||||
{
|
||||
if err := sql.unsafeWaitShell(); err != nil {
|
||||
if err := sql.unsafeWaitShell(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
logging.LogMessage(io, "Creating administrative user")
|
||||
{
|
||||
username := sql.Config.MysqlAdminUser
|
||||
password := sql.Config.MysqlAdminPassword
|
||||
if err := sql.CreateSuperuser(username, password, true); err != nil {
|
||||
if err := sql.CreateSuperuser(ctx, username, password, true); err != nil {
|
||||
return errSQLUnableToCreateUser
|
||||
}
|
||||
}
|
||||
|
|
@ -74,7 +75,7 @@ func (sql *SQL) Update(io stream.IOStream) error {
|
|||
|
||||
// wait for the database to come up
|
||||
logging.LogMessage(io, "Waiting for database update to be complete")
|
||||
sql.WaitQueryTable()
|
||||
sql.WaitQueryTable(ctx)
|
||||
|
||||
tables := []struct {
|
||||
name string
|
||||
|
|
@ -107,7 +108,7 @@ func (sql *SQL) Update(io stream.IOStream) error {
|
|||
return logging.LogOperation(func() error {
|
||||
for _, table := range tables {
|
||||
logging.LogMessage(io, "migrating %q table", table.name)
|
||||
db, err := sql.QueryTable(false, table.table)
|
||||
db, err := sql.QueryTable(ctx, false, table.table)
|
||||
if err != nil {
|
||||
return errSQLUnableToMigrate.WithMessageF(table.name, "unable to access table")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ func (ssh2 *SSH2) handleAuth(ctx ssh.Context, key ssh.PublicKey) bool {
|
|||
|
||||
// grab permissions for each instance
|
||||
{
|
||||
instances, err := ssh2.Instances.All()
|
||||
instances, err := ssh2.Instances.All(ctx)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package component
|
|||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
|
||||
|
|
@ -33,9 +34,9 @@ var errStackUpdateBuild = errors.New("Stack.Update: Build returned non-zero exit
|
|||
// This does not have a direct 'docker compose' shell equivalent.
|
||||
//
|
||||
// See also Up.
|
||||
func (ds Stack) Update(io stream.IOStream, start bool) error {
|
||||
func (ds Stack) Update(ctx context.Context, io stream.IOStream, start bool) error {
|
||||
{
|
||||
code, err := ds.compose(io, "pull")
|
||||
code, err := ds.compose(ctx, io, "pull")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -45,7 +46,7 @@ func (ds Stack) Update(io stream.IOStream, start bool) error {
|
|||
}
|
||||
|
||||
{
|
||||
code, err := ds.compose(io, "build", "--pull")
|
||||
code, err := ds.compose(ctx, io, "build", "--pull")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -54,7 +55,7 @@ func (ds Stack) Update(io stream.IOStream, start bool) error {
|
|||
}
|
||||
}
|
||||
if start {
|
||||
return ds.Up(io)
|
||||
return ds.Up(ctx, io)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -63,8 +64,8 @@ var errStackUp = errors.New("Stack.Up: Up returned non-zero exit code")
|
|||
|
||||
// Up creates and starts the containers in this Stack.
|
||||
// It is equivalent to 'docker compose up --remove-orphans --detach' on the shell.
|
||||
func (ds Stack) Up(io stream.IOStream) error {
|
||||
code, err := ds.compose(io, "up", "--remove-orphans", "--detach")
|
||||
func (ds Stack) Up(ctx context.Context, io stream.IOStream) error {
|
||||
code, err := ds.compose(ctx, io, "up", "--remove-orphans", "--detach")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -78,7 +79,7 @@ func (ds Stack) Up(io stream.IOStream) error {
|
|||
// It is equivalent to 'docker compose exec $service $executable $args...'.
|
||||
//
|
||||
// It returns the exit code of the process.
|
||||
func (ds Stack) Exec(io stream.IOStream, service, executable string, args ...string) (int, error) {
|
||||
func (ds Stack) Exec(ctx context.Context, io stream.IOStream, service, executable string, args ...string) (int, error) {
|
||||
compose := []string{"exec"}
|
||||
if io.StdinIsATerminal() {
|
||||
compose = append(compose, "-ti")
|
||||
|
|
@ -86,14 +87,14 @@ func (ds Stack) Exec(io stream.IOStream, service, executable string, args ...str
|
|||
compose = append(compose, service)
|
||||
compose = append(compose, executable)
|
||||
compose = append(compose, args...)
|
||||
return ds.compose(io, compose...)
|
||||
return ds.compose(ctx, io, compose...)
|
||||
}
|
||||
|
||||
// Run runs a command in a running container with the given executable.
|
||||
// It is equivalent to 'docker compose run [--rm] $service $executable $args...'.
|
||||
//
|
||||
// It returns the exit code of the process.
|
||||
func (ds Stack) Run(io stream.IOStream, autoRemove bool, service, command string, args ...string) (int, error) {
|
||||
func (ds Stack) Run(ctx context.Context, io stream.IOStream, autoRemove bool, service, command string, args ...string) (int, error) {
|
||||
compose := []string{"run"}
|
||||
if autoRemove {
|
||||
compose = append(compose, "--rm")
|
||||
|
|
@ -104,7 +105,7 @@ func (ds Stack) Run(io stream.IOStream, autoRemove bool, service, command string
|
|||
compose = append(compose, service, command)
|
||||
compose = append(compose, args...)
|
||||
|
||||
code, err := ds.compose(io, compose...)
|
||||
code, err := ds.compose(ctx, io, compose...)
|
||||
if err != nil {
|
||||
return environment.ExecCommandError, nil
|
||||
}
|
||||
|
|
@ -115,8 +116,8 @@ var errStackRestart = errors.New("Stack.Restart: Restart returned non-zero exit
|
|||
|
||||
// Restart restarts all containers in this Stack.
|
||||
// It is equivalent to 'docker compose restart' on the shell.
|
||||
func (ds Stack) Restart(io stream.IOStream) error {
|
||||
code, err := ds.compose(io, "restart")
|
||||
func (ds Stack) Restart(ctx context.Context, io stream.IOStream) error {
|
||||
code, err := ds.compose(ctx, io, "restart")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -129,12 +130,12 @@ func (ds Stack) Restart(io stream.IOStream) error {
|
|||
var errStackPs = errors.New("Stack.Ps: Down returned non-zero exit code")
|
||||
|
||||
// Ps returns the ids of the containers currently running
|
||||
func (ds Stack) Ps(io stream.IOStream) ([]string, error) {
|
||||
func (ds Stack) Ps(ctx context.Context, io stream.IOStream) ([]string, error) {
|
||||
// create a buffer
|
||||
var buffer bytes.Buffer
|
||||
|
||||
// read the ids from the command!
|
||||
code, err := ds.compose(io.Streams(&buffer, nil, nil, 0), "ps", "-q")
|
||||
code, err := ds.compose(ctx, io.Streams(&buffer, nil, nil, 0), "ps", "-q")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -162,8 +163,8 @@ var errStackDown = errors.New("Stack.Down: Down returned non-zero exit code")
|
|||
|
||||
// Down stops and removes all containers in this Stack.
|
||||
// It is equivalent to 'docker compose down -v' on the shell.
|
||||
func (ds Stack) Down(io stream.IOStream) error {
|
||||
code, err := ds.compose(io, "down", "-v")
|
||||
func (ds Stack) Down(ctx context.Context, io stream.IOStream) error {
|
||||
code, err := ds.compose(ctx, io, "down", "-v")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -177,7 +178,7 @@ func (ds Stack) Down(io stream.IOStream) error {
|
|||
//
|
||||
// NOTE(twiesing): Check if this can be replaced by an internal call to libcompose.
|
||||
// But probably not.
|
||||
func (ds Stack) compose(io stream.IOStream, args ...string) (int, error) {
|
||||
func (ds Stack) compose(ctx context.Context, io stream.IOStream, args ...string) (int, error) {
|
||||
if ds.DockerExecutable == "" {
|
||||
var err error
|
||||
ds.DockerExecutable, err = ds.Env.LookPathAbs("docker")
|
||||
|
|
@ -185,7 +186,7 @@ func (ds Stack) compose(io stream.IOStream, args ...string) (int, error) {
|
|||
return environment.ExecCommandError, err
|
||||
}
|
||||
}
|
||||
return ds.Env.Exec(io, ds.Dir, ds.DockerExecutable, append([]string{"compose"}, args...)...), nil
|
||||
return ds.Env.Exec(ctx, io, ds.Dir, ds.DockerExecutable, append([]string{"compose"}, args...)...), nil
|
||||
}
|
||||
|
||||
// StackWithResources represents a Stack that can be automatically installed from a set of resources.
|
||||
|
|
@ -218,7 +219,7 @@ type InstallationContext map[string]string
|
|||
//
|
||||
// Installation is non-interactive, but will provide debugging output onto io.
|
||||
// InstallationContext
|
||||
func (is StackWithResources) Install(io stream.IOStream, context InstallationContext) error {
|
||||
func (is StackWithResources) Install(ctx context.Context, io stream.IOStream, context InstallationContext) error {
|
||||
env := is.Stack.Env
|
||||
if is.ContextPath != "" {
|
||||
// setup the base files
|
||||
|
|
@ -277,7 +278,7 @@ func (is StackWithResources) Install(io stream.IOStream, context InstallationCon
|
|||
|
||||
// copy over file from context
|
||||
io.Printf("[copy] %s (from %s)\n", dst, src)
|
||||
if err := fsx.CopyFile(env, dst, src); err != nil {
|
||||
if err := fsx.CopyFile(ctx, env, dst, src); err != nil {
|
||||
return errors.Wrapf(err, "Unable to copy file %s", src)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package triplestore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
|
|
@ -10,19 +11,17 @@ import (
|
|||
func (ts *Triplestore) BackupName() string { return "triplestore" }
|
||||
|
||||
// Backup makes a backup of all Triplestore repositories databases into the path dest.
|
||||
func (ts *Triplestore) Backup(context component.StagingContext) error {
|
||||
func (ts *Triplestore) Backup(scontext component.StagingContext) error {
|
||||
return scontext.AddDirectory("", func(ctx context.Context) error {
|
||||
// list all the directories
|
||||
repos, err := ts.listRepositories(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// list all the directories
|
||||
repos, err := ts.listRepositories()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// then backup each file separatly
|
||||
return context.AddDirectory("", func() error {
|
||||
for _, repo := range repos {
|
||||
if err := context.AddFile(repo.ID+".nq", func(file io.Writer) error {
|
||||
_, err := ts.SnapshotDB(file, repo.ID)
|
||||
if err := scontext.AddFile(repo.ID+".nq", func(ctx context.Context, file io.Writer) error {
|
||||
_, err := ts.SnapshotDB(ctx, file, repo.ID)
|
||||
return err
|
||||
}); err != nil {
|
||||
return err
|
||||
|
|
@ -32,8 +31,8 @@ func (ts *Triplestore) Backup(context component.StagingContext) error {
|
|||
})
|
||||
}
|
||||
|
||||
func (ts Triplestore) listRepositories() (repos []Repository, err error) {
|
||||
res, err := ts.OpenRaw("GET", "/rest/repositories", nil, "", "application/json")
|
||||
func (ts Triplestore) listRepositories(ctx context.Context) (repos []Repository, err error) {
|
||||
res, err := ts.OpenRaw(ctx, "GET", "/rest/repositories", nil, "", "application/json")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package triplestore
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
|
|
@ -30,7 +31,7 @@ type TriplestoreUserAppSettings struct {
|
|||
//
|
||||
// When bodyName is non-empty, expect body to be a byte slice representing a multipart/form-data upload with the given name.
|
||||
// When bodyName is empty, simply marshal body as application/json
|
||||
func (ts Triplestore) OpenRaw(method, url string, body interface{}, bodyName string, accept string) (*http.Response, error) {
|
||||
func (ts Triplestore) OpenRaw(ctx context.Context, method, url string, body interface{}, bodyName string, accept string) (*http.Response, error) {
|
||||
var reader io.Reader
|
||||
|
||||
var contentType string
|
||||
|
|
@ -66,7 +67,7 @@ func (ts Triplestore) OpenRaw(method, url string, body interface{}, bodyName str
|
|||
DisableKeepAlives: true,
|
||||
},
|
||||
}
|
||||
req, err := http.NewRequest(method, ts.BaseURL+url, reader)
|
||||
req, err := http.NewRequestWithContext(ctx, method, ts.BaseURL+url, reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -86,23 +87,23 @@ func (ts Triplestore) OpenRaw(method, url string, body interface{}, bodyName str
|
|||
|
||||
// Wait waits for the connection to the Triplestore to succeed.
|
||||
// This is achieved using a polling strategy.
|
||||
func (ts Triplestore) Wait() error {
|
||||
func (ts Triplestore) Wait(ctx context.Context) error {
|
||||
n := stream.FromNil()
|
||||
return timex.TickUntilFunc(func(time.Time) bool {
|
||||
res, err := ts.OpenRaw("GET", "/rest/repositories", nil, "", "")
|
||||
res, err := ts.OpenRaw(ctx, "GET", "/rest/repositories", nil, "", "")
|
||||
n.EPrintf("[Triplestore.Wait]: %s\n", err)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer res.Body.Close()
|
||||
return true
|
||||
}, ts.PollContext, ts.PollInterval)
|
||||
}, ctx, ts.PollInterval)
|
||||
}
|
||||
|
||||
// PurgeUser deletes the specified user from the triplestore.
|
||||
// When the user does not exist, returns no error.
|
||||
func (ts Triplestore) PurgeUser(user string) error {
|
||||
res, err := ts.OpenRaw("DELETE", "/rest/security/users/"+user, nil, "", "")
|
||||
func (ts Triplestore) PurgeUser(ctx context.Context, user string) error {
|
||||
res, err := ts.OpenRaw(ctx, "DELETE", "/rest/security/users/"+user, nil, "", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -114,8 +115,8 @@ func (ts Triplestore) PurgeUser(user string) error {
|
|||
|
||||
// PurgeRepo deletes the specified repo from the triplestore.
|
||||
// When the repo does not exist, returns no error.
|
||||
func (ts Triplestore) PurgeRepo(repo string) error {
|
||||
res, err := ts.OpenRaw("DELETE", "/rest/repositories/"+repo, nil, "", "")
|
||||
func (ts Triplestore) PurgeRepo(ctx context.Context, repo string) error {
|
||||
res, err := ts.OpenRaw(ctx, "DELETE", "/rest/repositories/"+repo, nil, "", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package triplestore
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
_ "embed"
|
||||
|
|
@ -20,19 +21,19 @@ var errTripleStoreFailedRepository = exit.Error{
|
|||
//go:embed create-repo.ttl
|
||||
var createRepoTTL []byte
|
||||
|
||||
func (ts *Triplestore) Provision(instance models.Instance, domain string) error {
|
||||
return ts.CreateRepository(instance.GraphDBRepository, domain, instance.GraphDBUsername, instance.GraphDBPassword)
|
||||
func (ts *Triplestore) Provision(ctx context.Context, instance models.Instance, domain string) error {
|
||||
return ts.CreateRepository(ctx, instance.GraphDBRepository, domain, instance.GraphDBUsername, instance.GraphDBPassword)
|
||||
}
|
||||
|
||||
func (ts *Triplestore) Purge(instance models.Instance, domain string) error {
|
||||
func (ts *Triplestore) Purge(ctx context.Context, instance models.Instance, domain string) error {
|
||||
return errorx.First(
|
||||
ts.PurgeRepo(instance.GraphDBRepository),
|
||||
ts.PurgeUser(instance.GraphDBUsername),
|
||||
ts.PurgeRepo(ctx, instance.GraphDBRepository),
|
||||
ts.PurgeUser(ctx, instance.GraphDBUsername),
|
||||
)
|
||||
}
|
||||
|
||||
func (ts *Triplestore) CreateRepository(name, domain, user, password string) error {
|
||||
if err := ts.Wait(); err != nil {
|
||||
func (ts *Triplestore) CreateRepository(ctx context.Context, name, domain, user, password string) error {
|
||||
if err := ts.Wait(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +49,7 @@ func (ts *Triplestore) CreateRepository(name, domain, user, password string) err
|
|||
|
||||
// do the create!
|
||||
{
|
||||
res, err := ts.OpenRaw("POST", "/rest/repositories", createRepo.Bytes(), "config", "")
|
||||
res, err := ts.OpenRaw(ctx, "POST", "/rest/repositories", createRepo.Bytes(), "config", "")
|
||||
if err != nil {
|
||||
return errTripleStoreFailedRepository.WithMessageF(err)
|
||||
}
|
||||
|
|
@ -60,7 +61,7 @@ func (ts *Triplestore) CreateRepository(name, domain, user, password string) err
|
|||
|
||||
// create the user and grant them access
|
||||
{
|
||||
res, err := ts.OpenRaw("POST", "/rest/security/users/"+user, TriplestoreUserPayload{
|
||||
res, err := ts.OpenRaw(ctx, "POST", "/rest/security/users/"+user, TriplestoreUserPayload{
|
||||
Password: password,
|
||||
AppSettings: TriplestoreUserAppSettings{
|
||||
DefaultInference: true,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package triplestore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
|
|
@ -13,10 +14,10 @@ func (Triplestore) SnapshotNeedsRunning() bool { return false }
|
|||
|
||||
func (Triplestore) SnapshotName() string { return "triplestore" }
|
||||
|
||||
func (ts *Triplestore) Snapshot(wisski models.Instance, context component.StagingContext) error {
|
||||
return context.AddDirectory(".", func() error {
|
||||
return context.AddFile(wisski.GraphDBRepository+".nq", func(file io.Writer) error {
|
||||
_, err := ts.SnapshotDB(file, wisski.GraphDBRepository)
|
||||
func (ts *Triplestore) Snapshot(wisski models.Instance, scontext component.StagingContext) error {
|
||||
return scontext.AddDirectory(".", func(ctx context.Context) error {
|
||||
return scontext.AddFile(wisski.GraphDBRepository+".nq", func(ctx context.Context, file io.Writer) error {
|
||||
_, err := ts.SnapshotDB(ctx, file, wisski.GraphDBRepository)
|
||||
return err
|
||||
})
|
||||
})
|
||||
|
|
@ -25,8 +26,8 @@ func (ts *Triplestore) Snapshot(wisski models.Instance, context component.Stagin
|
|||
var errTSBackupWrongStatusCode = errors.New("Triplestore.Backup: Wrong status code")
|
||||
|
||||
// SnapshotDB snapshots the provided repository into dst
|
||||
func (ts Triplestore) SnapshotDB(dst io.Writer, repo string) (int64, error) {
|
||||
res, err := ts.OpenRaw("GET", "/repositories/"+repo+"/statements?infer=false", nil, "", "application/n-quads")
|
||||
func (ts Triplestore) SnapshotDB(ctx context.Context, dst io.Writer, repo string) (int64, error) {
|
||||
res, err := ts.OpenRaw(ctx, "GET", "/repositories/"+repo+"/statements?infer=false", nil, "", "application/n-quads")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package triplestore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
|
@ -15,8 +14,7 @@ type Triplestore struct {
|
|||
|
||||
BaseURL string // upstream server url
|
||||
|
||||
PollContext context.Context // context to abort polling with
|
||||
PollInterval time.Duration // duration to wait for during wait
|
||||
PollInterval time.Duration // duration to wait for during wait
|
||||
}
|
||||
|
||||
func (ts *Triplestore) Path() string {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package triplestore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
|
|
@ -11,15 +12,15 @@ import (
|
|||
|
||||
var errTriplestoreFailedSecurity = errors.New("failed to enable triplestore security: request did not succeed with HTTP 200 OK")
|
||||
|
||||
func (ts Triplestore) Update(io stream.IOStream) error {
|
||||
func (ts Triplestore) Update(ctx context.Context, io stream.IOStream) error {
|
||||
logging.LogMessage(io, "Waiting for Triplestore")
|
||||
if err := ts.Wait(); err != nil {
|
||||
if err := ts.Wait(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logging.LogMessage(io, "Resetting admin user password")
|
||||
{
|
||||
res, err := ts.OpenRaw("PUT", "/rest/security/users/"+ts.Config.TriplestoreAdminUser, TriplestoreUserPayload{
|
||||
res, err := ts.OpenRaw(ctx, "PUT", "/rest/security/users/"+ts.Config.TriplestoreAdminUser, TriplestoreUserPayload{
|
||||
Password: ts.Config.TriplestoreAdminPassword,
|
||||
AppSettings: TriplestoreUserAppSettings{
|
||||
DefaultInference: true,
|
||||
|
|
@ -51,7 +52,7 @@ func (ts Triplestore) Update(io stream.IOStream) error {
|
|||
|
||||
logging.LogMessage(io, "Enabling Triplestore security")
|
||||
{
|
||||
res, err := ts.OpenRaw("POST", "/rest/security", true, "", "")
|
||||
res, err := ts.OpenRaw(ctx, "POST", "/rest/security", true, "", "")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to enable triplestore security: %s", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
package dis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
|
@ -32,8 +32,8 @@ type Distillery struct {
|
|||
// core holds the core of the distillery
|
||||
component.Still
|
||||
|
||||
// internal context for the distillery
|
||||
context context.Context
|
||||
// Where interactive progress is displayed
|
||||
Progress io.Writer
|
||||
|
||||
// Upstream holds information to connect to the various running
|
||||
// distillery components.
|
||||
|
|
@ -54,11 +54,6 @@ type Upstream struct {
|
|||
Solr string
|
||||
}
|
||||
|
||||
// Context returns a new Context belonging to this distillery
|
||||
func (dis *Distillery) Context() context.Context {
|
||||
return dis.context
|
||||
}
|
||||
|
||||
//
|
||||
// PUBLIC COMPONENT GETTERS
|
||||
//
|
||||
|
|
@ -110,17 +105,14 @@ func (dis *Distillery) allComponents() []initFunc {
|
|||
|
||||
manual(func(ts *triplestore.Triplestore) {
|
||||
ts.BaseURL = "http://" + dis.Upstream.Triplestore
|
||||
ts.PollContext = dis.Context()
|
||||
ts.PollInterval = time.Second
|
||||
}),
|
||||
manual(func(sql *sql.SQL) {
|
||||
sql.ServerURL = dis.Upstream.SQL
|
||||
sql.PollContext = dis.Context()
|
||||
sql.PollInterval = time.Second
|
||||
}),
|
||||
manual(func(s *solr.Solr) {
|
||||
s.BaseURL = dis.Upstream.Solr
|
||||
s.PollContext = dis.Context()
|
||||
s.PollInterval = time.Second
|
||||
}),
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ var errOpenConfig = exit.Error{
|
|||
// NewDistillery creates a new distillery from the provided flags
|
||||
func NewDistillery(params cli.Params, flags cli.Flags, req cli.Requirements) (dis *Distillery, err error) {
|
||||
dis = &Distillery{
|
||||
context: params.Context,
|
||||
Still: component.Still{
|
||||
Environment: new(environment.Native),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,18 +1,22 @@
|
|||
// Package phpx provides functionalities for interacting with PHP code
|
||||
package phpx
|
||||
|
||||
import "github.com/tkw1536/goprogram/stream"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tkw1536/goprogram/stream"
|
||||
)
|
||||
|
||||
// Executor represents anything that can spawn
|
||||
type Executor interface {
|
||||
// Spawn spawns a new (independent) process executing code.
|
||||
// It should return only once the execution terminates.
|
||||
Spawn(str stream.IOStream, code string) error
|
||||
Spawn(ctx context.Context, str stream.IOStream, code string) error
|
||||
}
|
||||
|
||||
// SpawnFunc implements Executor
|
||||
type SpawnFunc func(str stream.IOStream, code string) error
|
||||
type SpawnFunc func(ctx context.Context, str stream.IOStream, code string) error
|
||||
|
||||
func (sf SpawnFunc) Spawn(str stream.IOStream, code string) error {
|
||||
return sf(str, code)
|
||||
func (sf SpawnFunc) Spawn(ctx context.Context, str stream.IOStream, code string) error {
|
||||
return sf(ctx, str, code)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
|
||||
_ "embed"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/pkg/cancel"
|
||||
"github.com/FAU-CDI/wisski-distillery/pkg/lazy"
|
||||
"github.com/tkw1536/goprogram/lib/collection"
|
||||
"github.com/tkw1536/goprogram/lib/nobufio"
|
||||
|
|
@ -21,6 +22,9 @@ import (
|
|||
//
|
||||
// A server, once used, should be closed using the [Close] method.
|
||||
type Server struct {
|
||||
// Context to use for the server
|
||||
Context context.Context
|
||||
|
||||
// Executor is the executor used by this server.
|
||||
// It may not be modified concurrently with other processes.
|
||||
Executor Executor
|
||||
|
|
@ -35,8 +39,8 @@ type Server struct {
|
|||
|
||||
m sync.Mutex // prevents concurrent access on any of the methods
|
||||
|
||||
c context.Context // closed when server is finished
|
||||
|
||||
cancel context.CancelFunc
|
||||
c context.Context // closed when server is finished
|
||||
}
|
||||
|
||||
func (server *Server) prepare() error {
|
||||
|
|
@ -57,7 +61,8 @@ func (server *Server) prepare() error {
|
|||
}
|
||||
|
||||
// create a context to close the server
|
||||
context, cancel := context.WithCancel(context.Background())
|
||||
context, cancel := context.WithCancel(server.Context)
|
||||
server.cancel = cancel
|
||||
|
||||
// start the shell process, which will close everything once done
|
||||
go func() {
|
||||
|
|
@ -67,12 +72,12 @@ func (server *Server) prepare() error {
|
|||
or.Close()
|
||||
ow.Close()
|
||||
|
||||
cancel()
|
||||
server.cancel()
|
||||
}()
|
||||
|
||||
// start the server
|
||||
io := stream.NewIOStream(ow, nil, ir, 0)
|
||||
err := server.Executor.Spawn(io, serverPHP)
|
||||
err := server.Executor.Spawn(server.c, io, serverPHP)
|
||||
server.err.Set(ServerError{errClosed, err})
|
||||
}()
|
||||
|
||||
|
|
@ -91,7 +96,7 @@ func (server *Server) prepare() error {
|
|||
// as such any functions defined will remain in server memory.
|
||||
//
|
||||
// When an exception is thrown by the PHP Code, error is not nil, and dest remains unchanged.
|
||||
func (server *Server) MarshalEval(value any, code string) error {
|
||||
func (server *Server) MarshalEval(ctx context.Context, value any, code string) error {
|
||||
if err := server.prepare(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -111,8 +116,11 @@ func (server *Server) MarshalEval(value any, code string) error {
|
|||
// find a delimiter for the code, and then send
|
||||
io.WriteString(server.in, input)
|
||||
|
||||
// read the next line (as a response)
|
||||
data, err := nobufio.ReadLine(server.out)
|
||||
data, err, _ := cancel.WithContext2(ctx, func(start func()) (string, error) {
|
||||
return nobufio.ReadLine(server.out)
|
||||
}, func() {
|
||||
server.cancel()
|
||||
})
|
||||
if err != nil {
|
||||
return ServerError{Message: errReceive, Err: err}
|
||||
}
|
||||
|
|
@ -139,8 +147,8 @@ func (server *Server) MarshalEval(value any, code string) error {
|
|||
}
|
||||
|
||||
// Eval is like [MarshalEval], but returns the value as an any
|
||||
func (server *Server) Eval(code string) (value any, err error) {
|
||||
err = server.MarshalEval(&value, code)
|
||||
func (server *Server) Eval(ctx context.Context, code string) (value any, err error) {
|
||||
err = server.MarshalEval(ctx, &value, code)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -148,7 +156,7 @@ func (server *Server) Eval(code string) (value any, err error) {
|
|||
// Arguments are sent to php using json Marshal, and are 'json_decode'd on the php side.
|
||||
//
|
||||
// Return values are received as in [MarshalEval].
|
||||
func (server *Server) MarshalCall(value any, function string, args ...any) error {
|
||||
func (server *Server) MarshalCall(ctx context.Context, value any, function string, args ...any) error {
|
||||
// name of function to call
|
||||
name := MarshalString(function)
|
||||
|
||||
|
|
@ -172,12 +180,12 @@ func (server *Server) MarshalCall(value any, function string, args ...any) error
|
|||
}
|
||||
|
||||
// and evaluate the code
|
||||
return server.MarshalEval(value, code)
|
||||
return server.MarshalEval(ctx, value, code)
|
||||
}
|
||||
|
||||
// Call is like [MarshalCall] but returns the return value of the function as an any
|
||||
func (server *Server) Call(function string, args ...any) (value any, err error) {
|
||||
err = server.MarshalCall(&value, function, args...)
|
||||
func (server *Server) Call(ctx context.Context, function string, args ...any) (value any, err error) {
|
||||
err = server.MarshalCall(ctx, &value, function, args...)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package barrel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||
|
|
@ -15,40 +16,40 @@ import (
|
|||
// Build builds or rebuilds the barel connected to this instance.
|
||||
//
|
||||
// It also logs the current time into the metadata belonging to this instance.
|
||||
func (barrel *Barrel) Build(stream stream.IOStream, start bool) error {
|
||||
if !barrel.Locker.TryLock() {
|
||||
func (barrel *Barrel) Build(ctx context.Context, stream stream.IOStream, start bool) error {
|
||||
if !barrel.Locker.TryLock(ctx) {
|
||||
err := locker.Locked
|
||||
return err
|
||||
}
|
||||
defer barrel.Locker.Unlock()
|
||||
defer barrel.Locker.Unlock(ctx)
|
||||
|
||||
stack := barrel.Stack()
|
||||
|
||||
var context component.InstallationContext
|
||||
|
||||
{
|
||||
err := stack.Install(stream, context)
|
||||
err := stack.Install(ctx, stream, context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
err := stack.Update(stream, start)
|
||||
err := stack.Update(ctx, stream, start)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// store the current last rebuild
|
||||
return barrel.setLastRebuild()
|
||||
return barrel.setLastRebuild(ctx)
|
||||
}
|
||||
|
||||
// TODO: Move this to time.Time
|
||||
var lastRebuild = mstore.For[int64]("lastRebuild")
|
||||
|
||||
func (barrel Barrel) LastRebuild() (t time.Time, err error) {
|
||||
epoch, err := lastRebuild.Get(barrel.MStore)
|
||||
func (barrel Barrel) LastRebuild(ctx context.Context) (t time.Time, err error) {
|
||||
epoch, err := lastRebuild.Get(ctx, barrel.MStore)
|
||||
if err == meta.ErrMetadatumNotSet {
|
||||
return t, nil
|
||||
}
|
||||
|
|
@ -60,8 +61,8 @@ func (barrel Barrel) LastRebuild() (t time.Time, err error) {
|
|||
return time.Unix(epoch, 0), nil
|
||||
}
|
||||
|
||||
func (barrel *Barrel) setLastRebuild() error {
|
||||
return lastRebuild.Set(barrel.MStore, time.Now().Unix())
|
||||
func (barrel *Barrel) setLastRebuild(ctx context.Context) error {
|
||||
return lastRebuild.Set(ctx, barrel.MStore, time.Now().Unix())
|
||||
}
|
||||
|
||||
type LastRebuildFetcher struct {
|
||||
|
|
@ -70,7 +71,7 @@ type LastRebuildFetcher struct {
|
|||
Barrel *Barrel
|
||||
}
|
||||
|
||||
func (lbr *LastRebuildFetcher) Fetch(flags ingredient.FetcherFlags, info *status.WissKI) (err error) {
|
||||
info.LastRebuild, _ = lbr.Barrel.LastRebuild()
|
||||
func (lbr *LastRebuildFetcher) Fetch(ctx context.Context, flags ingredient.FetcherFlags, info *status.WissKI) (err error) {
|
||||
info.LastRebuild, _ = lbr.Barrel.LastRebuild(ctx)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package drush
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/phpx"
|
||||
|
|
@ -15,8 +16,8 @@ var errCronFailed = exit.Error{
|
|||
ExitCode: exit.ExitGeneric,
|
||||
}
|
||||
|
||||
func (drush *Drush) Cron(io stream.IOStream) error {
|
||||
code, err := drush.Barrel.Shell(io, "/runtime/cron.sh")
|
||||
func (drush *Drush) Cron(ctx context.Context, io stream.IOStream) error {
|
||||
code, err := drush.Barrel.Shell(ctx, io, "/runtime/cron.sh")
|
||||
if err != nil {
|
||||
io.EPrintln(err)
|
||||
}
|
||||
|
|
@ -29,9 +30,9 @@ func (drush *Drush) Cron(io stream.IOStream) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (drush *Drush) LastCron(server *phpx.Server) (t time.Time, err error) {
|
||||
func (drush *Drush) LastCron(ctx context.Context, server *phpx.Server) (t time.Time, err error) {
|
||||
var timestamp int64
|
||||
err = drush.PHP.EvalCode(server, ×tamp, `$val = \Drupal::state()->get('system.cron_last'); return $val; `)
|
||||
err = drush.PHP.EvalCode(ctx, server, ×tamp, `$val = \Drupal::state()->get('system.cron_last'); return $val; `)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -49,6 +50,6 @@ func (lbr *LastCronFetcher) Fetch(flags ingredient.FetcherFlags, info *status.Wi
|
|||
return
|
||||
}
|
||||
|
||||
info.LastRebuild, _ = lbr.Drush.LastCron(flags.Server)
|
||||
info.LastRebuild, _ = lbr.Drush.LastCron(flags.Context, flags.Server)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package drush
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/meta"
|
||||
|
|
@ -18,8 +19,8 @@ var errBlindUpdateFailed = exit.Error{
|
|||
}
|
||||
|
||||
// Update performs a blind drush update
|
||||
func (drush *Drush) Update(io stream.IOStream) error {
|
||||
code, err := drush.Barrel.Shell(io, "/runtime/blind_update.sh")
|
||||
func (drush *Drush) Update(ctx context.Context, io stream.IOStream) error {
|
||||
code, err := drush.Barrel.Shell(ctx, io, "/runtime/blind_update.sh")
|
||||
if err != nil {
|
||||
return errBlindUpdateFailed.WithMessageF(drush.Slug, environment.ExecCommandError)
|
||||
}
|
||||
|
|
@ -27,13 +28,13 @@ func (drush *Drush) Update(io stream.IOStream) error {
|
|||
return errBlindUpdateFailed.WithMessageF(drush.Slug, code)
|
||||
}
|
||||
|
||||
return drush.setLastUpdate()
|
||||
return drush.setLastUpdate(ctx)
|
||||
}
|
||||
|
||||
const lastUpdate = mstore.For[int64]("lastUpdate")
|
||||
|
||||
func (drush *Drush) LastUpdate() (t time.Time, err error) {
|
||||
epoch, err := lastUpdate.Get(drush.MStore)
|
||||
func (drush *Drush) LastUpdate(ctx context.Context) (t time.Time, err error) {
|
||||
epoch, err := lastUpdate.Get(ctx, drush.MStore)
|
||||
if err == meta.ErrMetadatumNotSet {
|
||||
return t, nil
|
||||
}
|
||||
|
|
@ -45,8 +46,8 @@ func (drush *Drush) LastUpdate() (t time.Time, err error) {
|
|||
return time.Unix(epoch, 0), nil
|
||||
}
|
||||
|
||||
func (drush *Drush) setLastUpdate() error {
|
||||
return lastUpdate.Set(drush.MStore, time.Now().Unix())
|
||||
func (drush *Drush) setLastUpdate(ctx context.Context) error {
|
||||
return lastUpdate.Set(ctx, drush.MStore, time.Now().Unix())
|
||||
}
|
||||
|
||||
type LastUpdateFetcher struct {
|
||||
|
|
@ -56,6 +57,6 @@ type LastUpdateFetcher struct {
|
|||
}
|
||||
|
||||
func (lbr *LastUpdateFetcher) Fetch(flags ingredient.FetcherFlags, info *status.WissKI) (err error) {
|
||||
info.LastUpdate, err = lbr.Drush.LastUpdate()
|
||||
info.LastUpdate, err = lbr.Drush.LastUpdate(flags.Context)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package provisioner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
|
|
@ -19,10 +20,10 @@ type Provisioner struct {
|
|||
}
|
||||
|
||||
// Provision provisions an instance, assuming that the required databases already exist.
|
||||
func (provision *Provisioner) Provision(io stream.IOStream) error {
|
||||
func (provision *Provisioner) Provision(ctx context.Context, io stream.IOStream) error {
|
||||
|
||||
// build the container
|
||||
if err := provision.Barrel.Build(io, false); err != nil {
|
||||
if err := provision.Barrel.Build(ctx, io, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +54,7 @@ func (provision *Provisioner) Provision(io stream.IOStream) error {
|
|||
// TODO: Move the provision script into the control plane!
|
||||
provisionScript := "sudo PATH=$PATH -u www-data /bin/bash /provision_container.sh " + strings.Join(provisionParams, " ")
|
||||
|
||||
code, err := provision.Barrel.Stack().Run(io, true, "barrel", "/bin/bash", "-c", provisionScript)
|
||||
code, err := provision.Barrel.Stack().Run(ctx, io, true, "barrel", "/bin/bash", "-c", provisionScript)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
package barrel
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/status"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/wisski/ingredient"
|
||||
"github.com/tkw1536/goprogram/stream"
|
||||
)
|
||||
|
||||
// Running checks if this WissKI is currently running.
|
||||
func (barrel *Barrel) Running() (bool, error) {
|
||||
ps, err := barrel.Stack().Ps(stream.FromNil())
|
||||
func (barrel *Barrel) Running(ctx context.Context) (bool, error) {
|
||||
ps, err := barrel.Stack().Ps(ctx, stream.FromNil())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
|
@ -22,6 +24,6 @@ type RunningFetcher struct {
|
|||
}
|
||||
|
||||
func (rf *RunningFetcher) Fetch(flags ingredient.FetcherFlags, info *status.WissKI) (err error) {
|
||||
info.Running, err = rf.Barrel.Running()
|
||||
info.Running, err = rf.Barrel.Running(flags.Context)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
package barrel
|
||||
|
||||
import "github.com/tkw1536/goprogram/stream"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tkw1536/goprogram/stream"
|
||||
)
|
||||
|
||||
// Shell executes a shell command inside the instance.
|
||||
func (barrel *Barrel) Shell(io stream.IOStream, argv ...string) (int, error) {
|
||||
return barrel.Stack().Exec(io, "barrel", "/bin/sh", append([]string{"/user_shell.sh"}, argv...)...)
|
||||
func (barrel *Barrel) Shell(ctx context.Context, io stream.IOStream, argv ...string) (int, error) {
|
||||
return barrel.Stack().Exec(ctx, io, "barrel", "/bin/sh", append([]string{"/user_shell.sh"}, argv...)...)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package bookkeeping
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/wisski/ingredient"
|
||||
)
|
||||
|
|
@ -11,8 +13,8 @@ type Bookkeeping struct {
|
|||
}
|
||||
|
||||
// Save saves this instance in the bookkeeping table
|
||||
func (bk *Bookkeeping) Save() error {
|
||||
sdb, err := bk.Malt.SQL.QueryTable(false, models.InstanceTable)
|
||||
func (bk *Bookkeeping) Save(ctx context.Context) error {
|
||||
sdb, err := bk.Malt.SQL.QueryTable(ctx, false, models.InstanceTable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -27,8 +29,8 @@ func (bk *Bookkeeping) Save() error {
|
|||
}
|
||||
|
||||
// Delete deletes this instance from the bookkeeping table
|
||||
func (bk *Bookkeeping) Delete() error {
|
||||
sdb, err := bk.Malt.SQL.QueryTable(false, models.InstanceTable)
|
||||
func (bk *Bookkeeping) Delete(ctx context.Context) error {
|
||||
sdb, err := bk.Malt.SQL.QueryTable(ctx, false, models.InstanceTable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package ingredient
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/phpx"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/status"
|
||||
)
|
||||
|
|
@ -15,6 +17,7 @@ type WissKIFetcher interface {
|
|||
|
||||
// FetcherFlags describes options for a WissKIFetcher
|
||||
type FetcherFlags struct {
|
||||
Quick bool
|
||||
Server *phpx.Server
|
||||
Context context.Context
|
||||
Quick bool
|
||||
Server *phpx.Server
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package info
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/status"
|
||||
|
|
@ -21,10 +22,11 @@ type Info struct {
|
|||
|
||||
// Information fetches information about this WissKI.
|
||||
// TODO: Rework this to be able to determine what kind of information is available.
|
||||
func (wisski *Info) Information(quick bool) (info status.WissKI, err error) {
|
||||
func (wisski *Info) Information(ctx context.Context, quick bool) (info status.WissKI, err error) {
|
||||
// setup flags
|
||||
flags := ingredient.FetcherFlags{
|
||||
Quick: quick,
|
||||
Quick: quick,
|
||||
Context: ctx,
|
||||
}
|
||||
|
||||
// potentially setup a new server
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ func (lbr *SnapshotsFetcher) Fetch(flags ingredient.FetcherFlags, info *status.W
|
|||
return
|
||||
}
|
||||
|
||||
info.Snapshots, _ = lbr.Snapshots()
|
||||
info.Snapshots, _ = lbr.Snapshots(flags.Context)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package locker
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/wisski/ingredient"
|
||||
"github.com/tkw1536/goprogram/exit"
|
||||
|
|
@ -17,8 +19,8 @@ var Locked = exit.Error{
|
|||
}
|
||||
|
||||
// TryLock attemps to lock this WissKI and returns if it suceeded
|
||||
func (lock *Locker) TryLock() bool {
|
||||
table, err := lock.Malt.SQL.QueryTable(true, models.LockTable)
|
||||
func (lock *Locker) TryLock(ctx context.Context) bool {
|
||||
table, err := lock.Malt.SQL.QueryTable(ctx, true, models.LockTable)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
|
@ -29,8 +31,8 @@ func (lock *Locker) TryLock() bool {
|
|||
|
||||
// TryUnlock attempts to unlock this WissKI and reports if it succeeded.
|
||||
// An unlock can only
|
||||
func (lock *Locker) TryUnlock() bool {
|
||||
table, err := lock.Malt.SQL.QueryTable(true, models.LockTable)
|
||||
func (lock *Locker) TryUnlock(ctx context.Context) bool {
|
||||
table, err := lock.Malt.SQL.QueryTable(ctx, true, models.LockTable)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
|
@ -39,6 +41,6 @@ func (lock *Locker) TryUnlock() bool {
|
|||
}
|
||||
|
||||
// Unlock unlocks this WissKI, ignoring any error.
|
||||
func (lock *Locker) Unlock() {
|
||||
lock.TryUnlock()
|
||||
func (lock *Locker) Unlock(ctx context.Context) {
|
||||
lock.TryUnlock(ctx)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
package locker
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/status"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/wisski/ingredient"
|
||||
)
|
||||
|
||||
// Locked checks if this WissKI is currently locked.
|
||||
func (lock *Locker) Locked() (locked bool) {
|
||||
table, err := lock.SQL.QueryTable(true, models.LockTable)
|
||||
// If an error occurs, the instance is considered not locked.
|
||||
func (lock *Locker) Locked(ctx context.Context) (locked bool) {
|
||||
table, err := lock.SQL.QueryTable(ctx, true, models.LockTable)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
|
@ -19,6 +22,6 @@ func (lock *Locker) Locked() (locked bool) {
|
|||
}
|
||||
|
||||
func (locker *Locker) Fetch(flags ingredient.FetcherFlags, info *status.WissKI) (err error) {
|
||||
info.Locked = locker.Locked()
|
||||
info.Locked = locker.Locked(flags.Context)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package mstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/meta"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/wisski/ingredient"
|
||||
)
|
||||
|
|
@ -14,26 +16,26 @@ type MStore struct {
|
|||
// For is a Store for the provided value
|
||||
type For[Value any] meta.TypedKey[Value]
|
||||
|
||||
func (f For[Value]) Get(m *MStore) (value Value, err error) {
|
||||
return meta.TypedKey[Value](f).Get(m.Storage)
|
||||
func (f For[Value]) Get(ctx context.Context, m *MStore) (value Value, err error) {
|
||||
return meta.TypedKey[Value](f).Get(ctx, m.Storage)
|
||||
}
|
||||
|
||||
func (f For[Value]) GetAll(m *MStore) (values []Value, err error) {
|
||||
return meta.TypedKey[Value](f).GetAll(m.Storage)
|
||||
func (f For[Value]) GetAll(ctx context.Context, m *MStore) (values []Value, err error) {
|
||||
return meta.TypedKey[Value](f).GetAll(ctx, m.Storage)
|
||||
}
|
||||
|
||||
func (f For[Value]) GetOrSet(m *MStore, dflt Value) (value Value, err error) {
|
||||
return meta.TypedKey[Value](f).GetOrSet(m.Storage, dflt)
|
||||
func (f For[Value]) GetOrSet(ctx context.Context, m *MStore, dflt Value) (value Value, err error) {
|
||||
return meta.TypedKey[Value](f).GetOrSet(ctx, m.Storage, dflt)
|
||||
}
|
||||
|
||||
func (f For[Value]) Set(m *MStore, value Value) error {
|
||||
return meta.TypedKey[Value](f).Set(m.Storage, value)
|
||||
func (f For[Value]) Set(ctx context.Context, m *MStore, value Value) error {
|
||||
return meta.TypedKey[Value](f).Set(ctx, m.Storage, value)
|
||||
}
|
||||
|
||||
func (f For[Value]) SetAll(m *MStore, values ...Value) error {
|
||||
return meta.TypedKey[Value](f).SetAll(m.Storage, values...)
|
||||
func (f For[Value]) SetAll(ctx context.Context, m *MStore, values ...Value) error {
|
||||
return meta.TypedKey[Value](f).SetAll(ctx, m.Storage, values...)
|
||||
}
|
||||
|
||||
func (f For[Value]) Delete(m *MStore) error {
|
||||
return m.Storage.Delete(meta.Key(f))
|
||||
func (f For[Value]) Delete(ctx context.Context, m *MStore) error {
|
||||
return m.Storage.Delete(ctx, meta.Key(f))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package extras
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/phpx"
|
||||
|
|
@ -22,8 +23,8 @@ var pathbuilderPHP string
|
|||
// All returns the ids of all pathbuilders in consistent order.
|
||||
//
|
||||
// server is the server to fetch the pathbuilders from, any may be nil.
|
||||
func (pathbuilder *Pathbuilder) All(server *phpx.Server) (ids []string, err error) {
|
||||
err = pathbuilder.PHP.ExecScript(server, &ids, pathbuilderPHP, "all_list")
|
||||
func (pathbuilder *Pathbuilder) All(ctx context.Context, server *phpx.Server) (ids []string, err error) {
|
||||
err = pathbuilder.PHP.ExecScript(ctx, server, &ids, pathbuilderPHP, "all_list")
|
||||
slices.Sort(ids)
|
||||
return
|
||||
}
|
||||
|
|
@ -32,16 +33,16 @@ func (pathbuilder *Pathbuilder) All(server *phpx.Server) (ids []string, err erro
|
|||
// If it does not exist, it returns the empty string and nil error.
|
||||
//
|
||||
// server is the server to fetch the pathbuilders from, any may be nil.
|
||||
func (pathbuilder *Pathbuilder) Get(server *phpx.Server, id string) (xml string, err error) {
|
||||
err = pathbuilder.PHP.ExecScript(server, &xml, pathbuilderPHP, "one_xml", id)
|
||||
func (pathbuilder *Pathbuilder) Get(ctx context.Context, server *phpx.Server, id string) (xml string, err error) {
|
||||
err = pathbuilder.PHP.ExecScript(ctx, server, &xml, pathbuilderPHP, "one_xml", id)
|
||||
return
|
||||
}
|
||||
|
||||
// GetAll returns all pathbuilders serialized as xml
|
||||
//
|
||||
// server is the server to fetch the pathbuilders from, any may be nil.
|
||||
func (pathbuilder *Pathbuilder) GetAll(server *phpx.Server) (pathbuilders map[string]string, err error) {
|
||||
err = pathbuilder.PHP.ExecScript(server, &pathbuilders, pathbuilderPHP, "all_xml")
|
||||
func (pathbuilder *Pathbuilder) GetAll(ctx context.Context, server *phpx.Server) (pathbuilders map[string]string, err error) {
|
||||
err = pathbuilder.PHP.ExecScript(ctx, server, &pathbuilders, pathbuilderPHP, "all_xml")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -50,6 +51,6 @@ func (pathbuilder *Pathbuilder) Fetch(flags ingredient.FetcherFlags, info *statu
|
|||
return
|
||||
}
|
||||
|
||||
info.Pathbuilders, _ = pathbuilder.GetAll(flags.Server)
|
||||
info.Pathbuilders, _ = pathbuilder.GetAll(flags.Context, flags.Server)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package extras
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
|
|
@ -37,8 +38,8 @@ var listURIPrefixesPHP string
|
|||
//
|
||||
// server is an optional server to fetch prefixes from.
|
||||
// server may be nil.
|
||||
func (prefixes *Prefixes) All(server *phpx.Server) ([]string, error) {
|
||||
uris, err := prefixes.database(server)
|
||||
func (prefixes *Prefixes) All(ctx context.Context, server *phpx.Server) ([]string, error) {
|
||||
uris, err := prefixes.database(ctx, server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -51,9 +52,9 @@ func (prefixes *Prefixes) All(server *phpx.Server) ([]string, error) {
|
|||
return append(uris, uris2...), nil
|
||||
}
|
||||
|
||||
func (wisski *Prefixes) database(server *phpx.Server) (prefixes []string, err error) {
|
||||
func (wisski *Prefixes) database(ctx context.Context, server *phpx.Server) (prefixes []string, err error) {
|
||||
// get all the ugly prefixes
|
||||
err = wisski.PHP.ExecScript(server, &prefixes, listURIPrefixesPHP, "list_prefixes")
|
||||
err = wisski.PHP.ExecScript(ctx, server, &prefixes, listURIPrefixesPHP, "list_prefixes")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -143,28 +144,28 @@ func (wisski *Prefixes) filePrefixes() (prefixes []string, err error) {
|
|||
var prefix = mstore.For[string]("prefix")
|
||||
|
||||
// Prefixes returns the cached prefixes from the given instance
|
||||
func (wisski *Prefixes) AllCached() (results []string, err error) {
|
||||
return prefix.GetAll(wisski.MStore)
|
||||
func (wisski *Prefixes) AllCached(ctx context.Context) (results []string, err error) {
|
||||
return prefix.GetAll(ctx, wisski.MStore)
|
||||
}
|
||||
|
||||
// Update updates the cached prefixes of this instance
|
||||
func (wisski *Prefixes) Update() error {
|
||||
prefixes, err := wisski.All(nil)
|
||||
func (wisski *Prefixes) Update(ctx context.Context) error {
|
||||
prefixes, err := wisski.All(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return prefix.SetAll(wisski.MStore, prefixes...)
|
||||
return prefix.SetAll(ctx, wisski.MStore, prefixes...)
|
||||
}
|
||||
|
||||
func (prefixes *Prefixes) Fetch(flags ingredient.FetcherFlags, info *status.WissKI) (err error) {
|
||||
info.NoPrefixes = prefixes.NoPrefix()
|
||||
if flags.Quick {
|
||||
// quick mode: grab only the cached prefixes
|
||||
info.Prefixes, _ = prefixes.AllCached()
|
||||
info.Prefixes, _ = prefixes.AllCached(flags.Context)
|
||||
} else {
|
||||
// slow mode: grab the fresh prefixes from the server
|
||||
// TODO: Do we want to update them while we are at it?
|
||||
info.Prefixes, _ = prefixes.All(flags.Server)
|
||||
info.Prefixes, _ = prefixes.All(flags.Context, flags.Server)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package extras
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/phpx"
|
||||
|
|
@ -17,11 +18,11 @@ type Settings struct {
|
|||
//go:embed settings.php
|
||||
var settingsPHP string
|
||||
|
||||
func (settings *Settings) Get(server *phpx.Server, key string) (value any, err error) {
|
||||
err = settings.PHP.ExecScript(server, &value, settingsPHP, "get_setting", key)
|
||||
func (settings *Settings) Get(ctx context.Context, server *phpx.Server, key string) (value any, err error) {
|
||||
err = settings.PHP.ExecScript(ctx, server, &value, settingsPHP, "get_setting", key)
|
||||
return
|
||||
}
|
||||
|
||||
func (settings *Settings) Set(server *phpx.Server, key string, value any) error {
|
||||
return settings.PHP.ExecScript(server, nil, settingsPHP, "set_setting", key, value)
|
||||
func (settings *Settings) Set(ctx context.Context, server *phpx.Server, key string, value any) error {
|
||||
return settings.PHP.ExecScript(ctx, server, nil, settingsPHP, "set_setting", key, value)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package extras
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"log"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/phpx"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/status"
|
||||
|
|
@ -20,11 +20,8 @@ type Stats struct {
|
|||
var statsPHP string
|
||||
|
||||
// Get fetches all statistics from the server
|
||||
func (stats *Stats) Get(server *phpx.Server) (data status.Statistics, err error) {
|
||||
err = stats.PHP.ExecScript(server, &data, statsPHP, "export_statistics")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
func (stats *Stats) Get(ctx context.Context, server *phpx.Server) (data status.Statistics, err error) {
|
||||
err = stats.PHP.ExecScript(ctx, server, &data, statsPHP, "export_statistics")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -33,6 +30,6 @@ func (stats *Stats) Fetch(flags ingredient.FetcherFlags, info *status.WissKI) (e
|
|||
return
|
||||
}
|
||||
|
||||
info.Statistics, _ = stats.Get(flags.Server)
|
||||
info.Statistics, _ = stats.Get(flags.Context, flags.Server)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package php
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/phpx"
|
||||
|
|
@ -28,7 +29,7 @@ type PHP struct {
|
|||
// It's arguments are encoded as json using [json.Marshal] and decoded within php.
|
||||
//
|
||||
// The return value of the function is again marshaled with json and returned to the caller.
|
||||
func (php *PHP) ExecScript(server *phpx.Server, value any, code string, entrypoint string, args ...any) (err error) {
|
||||
func (php *PHP) ExecScript(ctx context.Context, server *phpx.Server, value any, code string, entrypoint string, args ...any) (err error) {
|
||||
if server == nil {
|
||||
server = php.NewServer()
|
||||
if err != nil {
|
||||
|
|
@ -38,15 +39,15 @@ func (php *PHP) ExecScript(server *phpx.Server, value any, code string, entrypoi
|
|||
}
|
||||
|
||||
if code != "" {
|
||||
if err := server.MarshalEval(nil, strings.TrimPrefix(code, "<?php")); err != nil {
|
||||
if err := server.MarshalEval(ctx, nil, strings.TrimPrefix(code, "<?php")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return server.MarshalCall(value, entrypoint, args...)
|
||||
return server.MarshalCall(ctx, value, entrypoint, args...)
|
||||
}
|
||||
|
||||
func (php *PHP) EvalCode(server *phpx.Server, value any, code string) (err error) {
|
||||
func (php *PHP) EvalCode(ctx context.Context, server *phpx.Server, value any, code string) (err error) {
|
||||
if server == nil {
|
||||
server = php.NewServer()
|
||||
if err != nil {
|
||||
|
|
@ -55,5 +56,5 @@ func (php *PHP) EvalCode(server *phpx.Server, value any, code string) (err error
|
|||
defer server.Close()
|
||||
}
|
||||
|
||||
return server.MarshalEval(value, code)
|
||||
return server.MarshalEval(ctx, value, code)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package php
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/phpx"
|
||||
|
|
@ -14,11 +15,12 @@ import (
|
|||
// See [PHPServer].
|
||||
func (php *PHP) NewServer() *phpx.Server {
|
||||
return &phpx.Server{
|
||||
Context: context.Background(),
|
||||
Executor: phpx.SpawnFunc(php.spawn),
|
||||
}
|
||||
}
|
||||
|
||||
func (php *PHP) spawn(str stream.IOStream, code string) error {
|
||||
_, err := php.Barrel.Shell(str, "-c", shellescape.QuoteCommand([]string{"drush", "php:eval", code}))
|
||||
func (php *PHP) spawn(ctx context.Context, str stream.IOStream, code string) error {
|
||||
_, err := php.Barrel.Shell(ctx, str, "-c", shellescape.QuoteCommand([]string{"drush", "php:eval", code}))
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,11 +15,11 @@ import (
|
|||
|
||||
var errGetValidator = errors.New("GetPasswordValidator: Unknown Error")
|
||||
|
||||
func (u *Users) GetPasswordValidator(username string) (pv PasswordValidator, err error) {
|
||||
func (u *Users) GetPasswordValidator(ctx context.Context, username string) (pv PasswordValidator, err error) {
|
||||
server := u.PHP.NewServer()
|
||||
|
||||
var hash string
|
||||
err = u.PHP.ExecScript(server, &hash, usersPHP, "get_password_hash", username)
|
||||
err = u.PHP.ExecScript(ctx, server, &hash, usersPHP, "get_password_hash", username)
|
||||
if err != nil {
|
||||
server.Close()
|
||||
return pv, err
|
||||
|
|
@ -46,9 +46,9 @@ func (pv PasswordValidator) Close() error {
|
|||
return pv.server.Close()
|
||||
}
|
||||
|
||||
func (pv PasswordValidator) Check(password string) bool {
|
||||
func (pv PasswordValidator) Check(ctx context.Context, password string) bool {
|
||||
var result phpx.Boolean
|
||||
err := pv.server.MarshalCall(&result, "check_password_hash", password, string(pv.hash))
|
||||
err := pv.server.MarshalCall(ctx, &result, "check_password_hash", password, string(pv.hash))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
|
@ -65,10 +65,10 @@ func (cpe CommonPasswordError) Error() string {
|
|||
return fmt.Sprintf("%q from %q", cpe.Password.Password, cpe.Password.Source)
|
||||
}
|
||||
|
||||
func (pv PasswordValidator) CheckDictionary(context context.Context, writer io.Writer) error {
|
||||
func (pv PasswordValidator) CheckDictionary(ctx context.Context, writer io.Writer) error {
|
||||
var counter int
|
||||
|
||||
if pv.Check(pv.username) {
|
||||
if pv.Check(ctx, pv.username) {
|
||||
if writer != nil {
|
||||
counter++
|
||||
fmt.Fprintln(writer, counter)
|
||||
|
|
@ -76,10 +76,10 @@ func (pv PasswordValidator) CheckDictionary(context context.Context, writer io.W
|
|||
return errPasswordUsername
|
||||
}
|
||||
for candidate := range CommonPasswords() {
|
||||
if context.Err() != nil {
|
||||
if ctx.Err() != nil {
|
||||
continue
|
||||
}
|
||||
result := pv.Check(candidate.Password)
|
||||
result := pv.Check(ctx, candidate.Password)
|
||||
if writer != nil {
|
||||
counter++
|
||||
fmt.Fprintln(writer, counter)
|
||||
|
|
@ -90,7 +90,7 @@ func (pv PasswordValidator) CheckDictionary(context context.Context, writer io.W
|
|||
}
|
||||
}
|
||||
|
||||
return context.Err()
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
//go:embed passwords
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package users
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"errors"
|
||||
"net/url"
|
||||
|
|
@ -21,19 +22,19 @@ type Users struct {
|
|||
var usersPHP string
|
||||
|
||||
// All returns all known usernames
|
||||
func (u *Users) All(server *phpx.Server) (users []status.User, err error) {
|
||||
err = u.PHP.ExecScript(server, &users, usersPHP, "list_users")
|
||||
func (u *Users) All(ctx context.Context, server *phpx.Server) (users []status.User, err error) {
|
||||
err = u.PHP.ExecScript(ctx, server, &users, usersPHP, "list_users")
|
||||
return
|
||||
}
|
||||
|
||||
var errLoginUnknownError = errors.New("Login: Unknown Error")
|
||||
|
||||
// Login generates a login link for the user with the given username
|
||||
func (u *Users) Login(server *phpx.Server, username string) (dest *url.URL, err error) {
|
||||
func (u *Users) Login(ctx context.Context, server *phpx.Server, username string) (dest *url.URL, err error) {
|
||||
|
||||
// generate a (relative) link
|
||||
var path string
|
||||
err = u.PHP.ExecScript(server, &path, usersPHP, "get_login_link", username)
|
||||
err = u.PHP.ExecScript(ctx, server, &path, usersPHP, "get_login_link", username)
|
||||
|
||||
// if something went wrong, return
|
||||
if err != nil {
|
||||
|
|
@ -57,9 +58,9 @@ func (u *Users) Login(server *phpx.Server, username string) (dest *url.URL, err
|
|||
var errSetPassword = errors.New("SetPassword: Unknown Error")
|
||||
|
||||
// SetPassword sets the password for a given user
|
||||
func (u *Users) SetPassword(server *phpx.Server, username, password string) error {
|
||||
func (u *Users) SetPassword(ctx context.Context, server *phpx.Server, username, password string) error {
|
||||
var ok bool
|
||||
err := u.PHP.ExecScript(server, &ok, usersPHP, "set_user_password", username, password)
|
||||
err := u.PHP.ExecScript(ctx, server, &ok, usersPHP, "set_user_password", username, password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -74,6 +75,6 @@ func (u *Users) Fetch(flags ingredient.FetcherFlags, info *status.WissKI) (err e
|
|||
return
|
||||
}
|
||||
|
||||
info.Users, _ = u.All(flags.Server)
|
||||
info.Users, _ = u.All(flags.Context, flags.Server)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
package liquid
|
||||
|
||||
import "github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||
)
|
||||
|
||||
// Snapshots returns the list of snapshots of this WissKI
|
||||
// NOTE(twiesing): Not entirely sure where this should go.
|
||||
// It's not that this is
|
||||
func (liquid *Liquid) Snapshots() (snapshots []models.Export, err error) {
|
||||
return liquid.Malt.ExporterLog.For(liquid.Slug)
|
||||
func (liquid *Liquid) Snapshots(ctx context.Context) (snapshots []models.Export, err error) {
|
||||
return liquid.Malt.ExporterLog.For(ctx, liquid.Slug)
|
||||
}
|
||||
|
|
|
|||
56
pkg/cancel/context.go
Normal file
56
pkg/cancel/context.go
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
package cancel
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// WithContext executes f and returns the returns the return value and nil.
|
||||
//
|
||||
// If the context is closed before f returns, invokes cancel and returns f(), ctx.Err().
|
||||
//
|
||||
// In general, WithContext always waits for f() to return even if cancel was called.
|
||||
// As a special case if a closed context is passed, f is not invoked.
|
||||
//
|
||||
// allowcancel must be called by f exactly once, as soon as the cancel function may be invoked.
|
||||
func WithContext[T any](ctx context.Context, f func(allowcancel func()) T, cancel func()) (t T, err error) {
|
||||
t, _, err = WithContext2(ctx, func(start func()) (T, struct{}) {
|
||||
return f(start), struct{}{}
|
||||
}, cancel)
|
||||
return
|
||||
}
|
||||
|
||||
// WithContext2 is exactly like WithContext, but takes a function returning two parameters.
|
||||
func WithContext2[T1, T2 any](ctx context.Context, f func(start func()) (T1, T2), cancel func()) (t1 T1, t2 T2, err error) {
|
||||
// context is already closed, don't even try invoking it.
|
||||
if err := ctx.Err(); err != nil {
|
||||
return t1, t2, err
|
||||
}
|
||||
|
||||
cancelable := make(chan struct{}, 1)
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
defer close(cancelable)
|
||||
|
||||
t1, t2 = f(func() {
|
||||
cancelable <- struct{}{}
|
||||
})
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
// the function has exited regularly
|
||||
// nothing to be done
|
||||
case <-ctx.Done():
|
||||
|
||||
// context was cancelled
|
||||
<-cancelable
|
||||
cancel()
|
||||
|
||||
// still wait for it to be done!
|
||||
<-done
|
||||
err = ctx.Err()
|
||||
}
|
||||
return
|
||||
}
|
||||
57
pkg/cancel/copy.go
Normal file
57
pkg/cancel/copy.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package cancel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
type SetDeadline interface {
|
||||
SetDeadline(t time.Time)
|
||||
}
|
||||
|
||||
type SetReadDeadline interface {
|
||||
SetReadDeadline(t time.Time) error
|
||||
}
|
||||
|
||||
type SetWriteDeadline interface {
|
||||
SetWriteDeadline(t time.Time) error
|
||||
}
|
||||
|
||||
// Copy reads from src, and copies to dst.
|
||||
//
|
||||
// If the context is closed before src is closed, attempts to close the underlying reader and writer.
|
||||
func Copy(ctx context.Context, dst io.Writer, src io.Reader) (written int64, err error) {
|
||||
|
||||
// if the context has a deadline, the propanate that deadline to the underyling file.
|
||||
// this might cause the read call to not block.
|
||||
if deadline, ok := ctx.Deadline(); ok {
|
||||
var zero time.Time
|
||||
|
||||
if file, ok := src.(SetReadDeadline); ok {
|
||||
file.SetReadDeadline(deadline)
|
||||
defer file.SetReadDeadline(zero)
|
||||
} else if file, ok := src.(SetDeadline); ok {
|
||||
file.SetDeadline(deadline)
|
||||
defer file.SetDeadline(zero)
|
||||
}
|
||||
|
||||
if file, ok := dst.(SetWriteDeadline); ok {
|
||||
file.SetWriteDeadline(deadline)
|
||||
defer file.SetWriteDeadline(zero)
|
||||
} else if file, ok := dst.(SetDeadline); ok {
|
||||
file.SetDeadline(deadline)
|
||||
defer file.SetDeadline(zero)
|
||||
}
|
||||
}
|
||||
|
||||
written, err, _ = WithContext2(ctx, func(start func()) (int64, error) {
|
||||
start()
|
||||
return io.Copy(dst, src)
|
||||
}, func() {
|
||||
if closer, ok := src.(io.Closer); ok {
|
||||
closer.Close()
|
||||
}
|
||||
})
|
||||
return written, err
|
||||
}
|
||||
|
|
@ -45,7 +45,7 @@ type Environment interface {
|
|||
DialContext(context context.Context, network, address string) (net.Conn, error)
|
||||
|
||||
Executable() (string, error)
|
||||
Exec(io stream.IOStream, workdir string, exe string, argv ...string) int
|
||||
Exec(ctx context.Context, io stream.IOStream, workdir string, exe string, argv ...string) int
|
||||
LookPathAbs(name string) (string, error)
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue