mirror of https://github.com/docker/docs.git
101 lines
2.9 KiB
Go
101 lines
2.9 KiB
Go
package debug
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
|
|
"github.com/docker/libswarm"
|
|
"github.com/docker/libswarm/utils"
|
|
)
|
|
|
|
// The Debug service is an example of intercepting messages between a receiver and a sender.
|
|
// The service also exposes messages passing through it for debug purposes.
|
|
func Debug() libswarm.Sender {
|
|
dbgInstance := &debug{
|
|
service: libswarm.NewServer(),
|
|
}
|
|
|
|
sender := libswarm.NewServer()
|
|
sender.OnVerb(libswarm.Spawn, libswarm.Handler(dbgInstance.spawn))
|
|
return sender
|
|
}
|
|
|
|
// Debug service type
|
|
type debug struct {
|
|
service *libswarm.Server
|
|
out libswarm.Sender
|
|
}
|
|
|
|
// Spawn will return a new instance as the Ret channel of the message sent back
|
|
func (dbg *debug) spawn(msg *libswarm.Message) (err error) {
|
|
// By sending back a task, libswarm will run the function with the in and out arguments
|
|
// set to the services present before and after this one in the pipeline.
|
|
instance := utils.Task(func(in libswarm.Receiver, out libswarm.Sender) {
|
|
// Setup our channels
|
|
dbg.out = out
|
|
|
|
// Set up the debug interceptor
|
|
dbg.service.Catchall(libswarm.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.
|
|
libswarm.Copy(dbg.service, in)
|
|
})
|
|
|
|
// Inform the system of our new instance
|
|
msg.Ret.Send(&libswarm.Message{
|
|
Verb: libswarm.Ack,
|
|
Ret: instance,
|
|
})
|
|
|
|
return
|
|
}
|
|
|
|
// Catches all messages sent to the service
|
|
func (dbg *debug) catchall(msg *libswarm.Message) (err error) {
|
|
log.Printf("[debug] ---> Outbound Message ---> { Verb: %s, Args: %v }\n", msg.Verb, msg.Args)
|
|
|
|
// If there's no output after us then we'll just reply with an error
|
|
// informing the receiver that the verb is not implemented.
|
|
if dbg.out == nil {
|
|
return fmt.Errorf("[debug] Verb: %s is not implemented.", msg.Verb)
|
|
}
|
|
|
|
// We forward the message with a special Ret value of "libswarm.RetPipe" - this
|
|
// asks libchan to open a new pipe so that we can read replies from upstream
|
|
forwardedMsg := &libswarm.Message{
|
|
Verb: msg.Verb,
|
|
Args: msg.Args,
|
|
Att: msg.Att,
|
|
Ret: libswarm.RetPipe,
|
|
}
|
|
|
|
// Send the forwarded message
|
|
if inbound, err := dbg.out.Send(forwardedMsg); err != nil {
|
|
return fmt.Errorf("[debug] Failed to forward msg. Reason: %v\n", err)
|
|
} else if inbound == nil {
|
|
return fmt.Errorf("[debug] Inbound channel nil.\n")
|
|
} else {
|
|
for {
|
|
// Relay all messages returned until the inbound channel is empty (EOF)
|
|
var reply *libswarm.Message
|
|
if reply, err = inbound.Receive(0); err != nil {
|
|
if err == io.EOF {
|
|
// EOF is expected
|
|
err = nil
|
|
}
|
|
break
|
|
}
|
|
|
|
// Forward the message back downstream
|
|
if _, err = msg.Ret.Send(reply); err != nil {
|
|
return fmt.Errorf("[debug] Failed to forward msg. Reason: %v\n", err)
|
|
}
|
|
log.Printf("[debug] <--- Inbound Message <--- { Verb: %s, Args: %v }\n", reply.Verb, reply.Args)
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|