docs/backends/aggregate.go

116 lines
2.2 KiB
Go

package backends
import (
"github.com/docker/libswarm"
"github.com/flynn/go-shlex"
"fmt"
"log"
"sync"
)
func Aggregate() libswarm.Sender {
backend := libswarm.NewServer()
backend.OnSpawn(func(cmd ...string) (libswarm.Sender, error) {
allBackends := New()
instance := libswarm.NewServer()
a, err := newAggregator(allBackends, instance, cmd)
if err != nil {
return nil, err
}
instance.OnAttach(a.attach)
instance.OnStart(a.start)
instance.OnLs(a.ls)
return instance, nil
})
return backend
}
type aggregator struct {
backends []*libswarm.Client
server *libswarm.Server
}
func newAggregator(allBackends *libswarm.Client, server *libswarm.Server, args []string) (*aggregator, error) {
a := &aggregator{server: server}
for _, argString := range args {
args, err := shlex.Split(argString)
if err != nil {
return nil, err
}
if len(args) == 0 {
return nil, fmt.Errorf("empty backend string")
}
log.Printf("aggregator: spawning %s(%#v)\n", args[0], args[1:])
_, b, err := allBackends.Attach(args[0])
if err != nil {
return nil, err
}
i, err := b.Spawn(args[1:]...)
if err != nil {
return nil, err
}
a.backends = append(a.backends, i)
}
return a, nil
}
func (a *aggregator) attach(name string, ret libswarm.Sender) error {
if name != "" {
// TODO: implement this?
return fmt.Errorf("attaching to a child is not implemented")
}
if _, err := ret.Send(&libswarm.Message{Verb: libswarm.Ack, Ret: a.server}); err != nil {
return err
}
var copies sync.WaitGroup
for _, b := range a.backends {
r, _, err := b.Attach("")
if err != nil {
return err
}
copies.Add(1)
go func() {
log.Printf("copying output from %#v\n", b)
libswarm.Copy(ret, r)
log.Printf("finished output from %#v\n", b)
copies.Done()
}()
}
copies.Wait()
return nil
}
func (a *aggregator) start() error {
for _, b := range a.backends {
err := b.Start()
if err != nil {
return err
}
}
return nil
}
func (a *aggregator) ls() ([]string, error) {
var children []string
for _, b := range a.backends {
bChildren, err := b.Ls()
if err != nil {
return nil, err
}
children = append(children, bChildren...)
}
return children, nil
}