2018-08-27 22:21:45 +02:00
|
|
|
package job
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/zrepl/zrepl/config"
|
|
|
|
"github.com/zrepl/zrepl/daemon/connecter"
|
|
|
|
"github.com/zrepl/zrepl/daemon/filters"
|
2018-08-30 11:52:05 +02:00
|
|
|
"github.com/zrepl/zrepl/daemon/pruner"
|
2018-08-27 22:21:45 +02:00
|
|
|
"github.com/zrepl/zrepl/endpoint"
|
|
|
|
"github.com/zrepl/zrepl/replication"
|
|
|
|
"sync"
|
2018-08-31 16:26:11 +02:00
|
|
|
"github.com/zrepl/zrepl/daemon/logging"
|
2018-09-04 23:46:02 +02:00
|
|
|
"github.com/zrepl/zrepl/daemon/snapper"
|
2018-08-27 22:21:45 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
type Push struct {
|
|
|
|
name string
|
2018-08-31 21:51:44 +02:00
|
|
|
clientFactory *connecter.ClientFactory
|
2018-08-27 22:21:45 +02:00
|
|
|
fsfilter endpoint.FSFilter
|
|
|
|
|
2018-08-30 17:40:45 +02:00
|
|
|
prunerFactory *pruner.PrunerFactory
|
2018-08-29 19:00:45 +02:00
|
|
|
|
2018-09-04 23:46:02 +02:00
|
|
|
snapper *snapper.Snapper
|
|
|
|
|
2018-08-27 22:21:45 +02:00
|
|
|
mtx sync.Mutex
|
|
|
|
replication *replication.Replication
|
|
|
|
}
|
|
|
|
|
2018-08-31 21:50:59 +02:00
|
|
|
func PushFromConfig(g *config.Global, in *config.PushJob) (j *Push, err error) {
|
2018-08-27 22:21:45 +02:00
|
|
|
|
|
|
|
j = &Push{}
|
|
|
|
j.name = in.Name
|
|
|
|
|
2018-09-04 23:44:45 +02:00
|
|
|
j.clientFactory, err = connecter.FromConfig(g, in.Connect)
|
2018-08-31 21:51:44 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "cannot build client")
|
|
|
|
}
|
2018-08-27 22:21:45 +02:00
|
|
|
|
2018-09-04 23:46:02 +02:00
|
|
|
fsf, err := filters.DatasetMapFilterFromConfig(in.Filesystems)
|
|
|
|
if err != nil {
|
2018-08-27 22:21:45 +02:00
|
|
|
return nil, errors.Wrap(err, "cannnot build filesystem filter")
|
|
|
|
}
|
2018-09-04 23:46:02 +02:00
|
|
|
j.fsfilter = fsf
|
2018-08-27 22:21:45 +02:00
|
|
|
|
2018-08-30 17:40:45 +02:00
|
|
|
j.prunerFactory, err = pruner.NewPrunerFactory(in.Pruning)
|
2018-08-30 11:52:05 +02:00
|
|
|
if err != nil {
|
2018-08-30 17:40:45 +02:00
|
|
|
return nil, err
|
2018-08-30 11:52:05 +02:00
|
|
|
}
|
|
|
|
|
2018-09-04 23:46:02 +02:00
|
|
|
if j.snapper, err = snapper.FromConfig(g, fsf, &in.Snapshotting); err != nil {
|
|
|
|
return nil, errors.Wrap(err, "cannot build snapper")
|
|
|
|
}
|
|
|
|
|
2018-08-27 22:21:45 +02:00
|
|
|
return j, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (j *Push) Name() string { return j.name }
|
|
|
|
|
|
|
|
func (j *Push) Status() interface{} {
|
2018-08-29 19:18:54 +02:00
|
|
|
rep := func() *replication.Replication {
|
|
|
|
j.mtx.Lock()
|
|
|
|
defer j.mtx.Unlock()
|
|
|
|
if j.replication == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return j.replication
|
|
|
|
}()
|
|
|
|
if rep == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return rep.Report()
|
2018-08-27 22:21:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (j *Push) Run(ctx context.Context) {
|
|
|
|
log := GetLogger(ctx)
|
|
|
|
|
|
|
|
defer log.Info("job exiting")
|
|
|
|
|
2018-09-04 23:46:02 +02:00
|
|
|
snapshotsTaken := make(chan struct{})
|
|
|
|
{
|
|
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
|
|
defer cancel()
|
|
|
|
ctx = logging.WithSubsystemLoggers(ctx, log)
|
|
|
|
go j.snapper.Run(ctx, snapshotsTaken)
|
|
|
|
}
|
|
|
|
|
2018-08-27 22:21:45 +02:00
|
|
|
invocationCount := 0
|
|
|
|
outer:
|
|
|
|
for {
|
2018-08-31 16:26:11 +02:00
|
|
|
log.Info("wait for wakeups")
|
2018-08-27 22:21:45 +02:00
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
log.WithError(ctx.Err()).Info("context")
|
|
|
|
break outer
|
2018-09-04 23:46:02 +02:00
|
|
|
|
2018-08-27 22:21:45 +02:00
|
|
|
case <-WaitWakeup(ctx):
|
2018-09-04 23:46:02 +02:00
|
|
|
case <-snapshotsTaken:
|
2018-08-27 22:21:45 +02:00
|
|
|
}
|
2018-09-04 23:46:02 +02:00
|
|
|
invocationCount++
|
|
|
|
invLog := log.WithField("invocation", invocationCount)
|
|
|
|
j.do(WithLogger(ctx, invLog))
|
2018-08-27 22:21:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (j *Push) do(ctx context.Context) {
|
|
|
|
|
|
|
|
log := GetLogger(ctx)
|
2018-08-31 16:26:11 +02:00
|
|
|
ctx = logging.WithSubsystemLoggers(ctx, log)
|
2018-08-27 22:21:45 +02:00
|
|
|
|
2018-08-31 21:51:44 +02:00
|
|
|
client, err := j.clientFactory.NewClient()
|
2018-08-27 22:21:45 +02:00
|
|
|
if err != nil {
|
2018-08-31 21:51:44 +02:00
|
|
|
log.WithError(err).Error("factory cannot instantiate streamrpc client")
|
2018-08-27 22:21:45 +02:00
|
|
|
}
|
2018-08-31 16:26:11 +02:00
|
|
|
defer client.Close(ctx)
|
2018-08-27 22:21:45 +02:00
|
|
|
|
2018-09-06 04:49:26 +02:00
|
|
|
sender := endpoint.NewSender(j.fsfilter)
|
2018-08-27 22:21:45 +02:00
|
|
|
receiver := endpoint.NewRemote(client)
|
|
|
|
|
|
|
|
j.mtx.Lock()
|
2018-08-29 19:18:54 +02:00
|
|
|
j.replication = replication.NewReplication()
|
2018-08-27 22:21:45 +02:00
|
|
|
j.mtx.Unlock()
|
|
|
|
|
2018-08-31 16:26:11 +02:00
|
|
|
log.Info("start replication")
|
2018-08-29 19:18:54 +02:00
|
|
|
j.replication.Drive(ctx, sender, receiver)
|
2018-08-29 19:00:45 +02:00
|
|
|
|
2018-08-31 16:26:11 +02:00
|
|
|
log.Info("start pruning sender")
|
2018-09-03 22:19:56 +02:00
|
|
|
senderPruner := j.prunerFactory.BuildSenderPruner(ctx, sender, sender)
|
2018-08-30 17:40:45 +02:00
|
|
|
senderPruner.Prune()
|
2018-08-29 19:00:45 +02:00
|
|
|
|
2018-08-31 16:26:11 +02:00
|
|
|
log.Info("start pruning receiver")
|
2018-09-03 22:19:56 +02:00
|
|
|
receiverPruner := j.prunerFactory.BuildReceiverPruner(ctx, receiver, sender)
|
2018-08-30 17:40:45 +02:00
|
|
|
receiverPruner.Prune()
|
2018-08-29 19:00:45 +02:00
|
|
|
|
2018-08-27 22:21:45 +02:00
|
|
|
}
|