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