func (t *attachServerSSH) globalMux(reqchan <-chan *ssh.Request) { defer trace.End(trace.Begin("attach server global request handler")) // to make sure we close the channel once var once sync.Once // ContainersReq will close this channel t.askedAndAnswered = make(chan struct{}) for req := range reqchan { var pendingFn func() var payload []byte ok := true log.Infof("received global request type %v", req.Type) switch req.Type { case msgs.ContainersReq: keys := make([]string, len(t.config.Sessions)) i := 0 for k := range t.config.Sessions { keys[i] = k i++ } msg := msgs.ContainersMsg{IDs: keys} payload = msg.Marshal() // unblock ^ (above) pendingFn = func() { once.Do(func() { close(t.askedAndAnswered) }) } default: ok = false payload = []byte("unknown global request type: " + req.Type) } log.Debugf("Returning payload: %s", string(payload)) // make sure that errors get send back if we failed if req.WantReply { log.Debugf("Sending global request reply %t back with %#v", ok, payload) if err := req.Reply(ok, payload); err != nil { log.Warnf("Failed to reply a global request back") } } // run any pending work now that a reply has been sent if pendingFn != nil { log.Debug("Invoking pending work for global mux") go pendingFn() pendingFn = nil } } }
func (t *attachServerSSH) globalMux(reqchan <-chan *ssh.Request) { defer trace.End(trace.Begin("start attach server global request handler")) for req := range reqchan { var pendingFn func() var payload []byte ok := true log.Infof("received global request type %v", req.Type) switch req.Type { case msgs.ContainersReq: keys := make([]string, len(t.config.Sessions)) i := 0 for k := range t.config.Sessions { keys[i] = k i++ } msg := msgs.ContainersMsg{IDs: keys} payload = msg.Marshal() default: ok = false payload = []byte("unknown global request type: " + req.Type) } log.Debugf("Returning payload: %s", string(payload)) // make sure that errors get send back if we failed if req.WantReply { req.Reply(ok, payload) } // run any pending work now that a reply has been sent if pendingFn != nil { log.Debug("Invoking pending work") go pendingFn() pendingFn = nil } } }
func TestAttachSshSession(t *testing.T) { log.SetLevel(log.InfoLevel) s := NewAttachServer("", -1) assert.NoError(t, s.Start()) defer s.Stop() expectedID := "foo" // This should block until the ssh server returns its container ID wg := sync.WaitGroup{} go func() { wg.Add(1) defer wg.Done() _, err := s.connServer.Get(context.Background(), expectedID, 5*time.Second) if !assert.NoError(t, err) { return } }() // Dial the attach server. This is a TCP client networkClientCon, err := net.Dial("tcp", s.l.Addr().String()) if !assert.NoError(t, err) { return } if !assert.NoError(t, serial.HandshakeServer(context.Background(), networkClientCon)) { return } containerConfig := &ssh.ServerConfig{ NoClientAuth: true, } signer, err := ssh.ParsePrivateKey(testdata.PEMBytes["dsa"]) if !assert.NoError(t, err) { return } containerConfig.AddHostKey(signer) // create the SSH server on the client. The attach server will ssh connect to this. sshConn, chans, reqs, err := ssh.NewServerConn(networkClientCon, containerConfig) if !assert.NoError(t, err) { return } defer sshConn.Close() // Service the incoming Channel channel. go func() { wg.Add(1) defer wg.Done() for req := range reqs { if req.Type == msgs.ContainersReq { msg := msgs.ContainersMsg{IDs: []string{expectedID}} req.Reply(true, msg.Marshal()) break } } }() go func() { wg.Add(1) defer wg.Done() for ch := range chans { assert.Equal(t, ch.ChannelType(), attachChannelType) _, _, _ = ch.Accept() break } }() wg.Wait() }