func cmdDaemon(c *cli.Context) { app := beam.NewServer() app.OnLog(beam.Handler(func(msg *beam.Message) error { log.Printf("%s\n", strings.Join(msg.Args, " ")) return nil })) app.OnError(beam.Handler(func(msg *beam.Message) error { Fatalf("Fatal: %v", strings.Join(msg.Args[:1], "")) return nil })) back := backends.New() if len(c.Args()) == 0 { names, err := back.Ls() if err != nil { Fatalf("ls: %v", err) } fmt.Println(strings.Join(names, "\n")) return } var previousInstanceR beam.Receiver // FIXME: refactor into a Pipeline for idx, backendArg := range c.Args() { bName, bArgs, err := parseCmd(backendArg) if err != nil { Fatalf("parse: %v", err) } _, backend, err := back.Attach(bName) if err != nil { Fatalf("%s: %v\n", bName, err) } instance, err := backend.Spawn(bArgs...) if err != nil { Fatalf("spawn %s: %v\n", bName, err) } instanceR, instanceW, err := instance.Attach("") if err != nil { Fatalf("attach: %v", err) } go func(r beam.Receiver, w beam.Sender, idx int) { if r != nil { beam.Copy(w, r) } w.Close() }(previousInstanceR, instanceW, idx) if err := instance.Start(); err != nil { Fatalf("start: %v", err) } previousInstanceR = instanceR } _, err := beam.Copy(app, previousInstanceR) if err != nil { Fatalf("copy: %v", err) } }
func (a *aggregator) attach(ctx *beam.Message) error { if ctx.Args[0] != "" { // TODO: implement this? return fmt.Errorf("attaching to a child is not implemented") } if _, err := ctx.Ret.Send(&beam.Message{Verb: beam.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) beam.Copy(ctx.Ret, r) log.Printf("finished output from %#v\n", b) copies.Done() }() } copies.Wait() return nil }
func (c *Conn) Send(msg *beam.Message) (beam.Receiver, error) { if msg.Att != nil { return nil, fmt.Errorf("file attachment not yet implemented in unix transport") } parts := []string{fmt.Sprintf("%d", msg.Verb)} parts = append(parts, msg.Args...) b := []byte(data.EncodeList(parts)) // Setup nested streams var ( fd *os.File ret beam.Receiver err error ) // Caller requested a return pipe if beam.RetPipe.Equals(msg.Ret) { local, remote, err := sendablePair() if err != nil { return nil, err } fd = remote ret = &Conn{local} // Caller specified its own return channel } else if msg.Ret != nil { // The specified return channel is a unix conn: engaging cheat mode! if retConn, ok := msg.Ret.(*Conn); ok { fd, err = retConn.UnixConn.File() if err != nil { return nil, fmt.Errorf("error passing return channel: %v", err) } // Close duplicate fd retConn.UnixConn.Close() // The specified return channel is an unknown type: proxy messages. } else { local, remote, err := sendablePair() if err != nil { return nil, fmt.Errorf("error passing return channel: %v", err) } fd = remote // FIXME: do we need a reference no all these background tasks? go func() { // Copy messages from the remote return channel to the local return channel. // When the remote return channel is closed, also close the local return channel. localConn := &Conn{local} beam.Copy(msg.Ret, localConn) msg.Ret.Close() localConn.Close() }() } } if err := c.UnixConn.Send(b, fd); err != nil { return nil, err } return ret, nil }
func Simulator() beam.Sender { s := beam.NewServer() s.OnSpawn(beam.Handler(func(ctx *beam.Message) error { containers := ctx.Args instance := beam.Task(func(in beam.Receiver, out beam.Sender) { beam.Obj(out).Log("[simulator] starting\n") s := beam.NewServer() s.OnLs(beam.Handler(func(msg *beam.Message) error { beam.Obj(out).Log("[simulator] generating fake list of objects...\n") beam.Obj(msg.Ret).Set(containers...) return nil })) beam.Copy(s, in) }) ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: instance}) return nil })) return s }
func cmdDaemon(c *cli.Context) { app := beam.NewServer() app.OnLog(beam.Handler(func(msg *beam.Message) error { utils.Debugf("%s", strings.Join(msg.Args, " ")) return nil })) app.OnError(beam.Handler(func(msg *beam.Message) error { Fatalf("Fatal: %v", strings.Join(msg.Args[:1], "")) return nil })) backend := beam.Object{backends.Forward()} dockerHost := os.Getenv("DOCKER_HOST") if dockerHost == "" { dockerHost = "unix:///var/run/docker.sock" } instance, err := backend.Spawn(dockerHost) if err != nil { Fatalf("spawn: %v\n", err) } instanceR, instanceW, err := instance.Attach("") if err != nil { Fatalf("attach: %v", err) } defer instanceW.Close() go beam.Copy(app, instanceR) if err := instance.Start(); err != nil { Fatalf("start: %v", err) } err = doCmd(instance, c.Args()) if err != nil { Fatalf("%v", err) } }
// Spawn will return a new instance as the Ret channel of the message sent back func (dbg *debug) spawn(msg *beam.Message) (err error) { // By sending back a task, beam will run the function with the in and out arguments // set to the services present before and after this one in the pipeline. instance := beam.Task(func(in beam.Receiver, out beam.Sender) { // Setup our channels dbg.in = in dbg.out = out // Set up the debug interceptor dbg.service.Catchall(beam.Handler(dbg.catchall)) // Copy everything from the receiver to our service. By copying like this in the task // we can use the catchall handler instead of handling the message here. beam.Copy(dbg.service, in) }) // Inform the system of our new instance msg.Ret.Send(&beam.Message{ Verb: beam.Ack, Ret: instance, }) return }