func New( listenNetwork, listenAddr string, containerGraceTime time.Duration, backend garden.Backend, logger lager.Logger, ) *GardenServer { s := &GardenServer{ logger: logger.Session("garden-server"), listenNetwork: listenNetwork, listenAddr: listenAddr, containerGraceTime: containerGraceTime, backend: backend, stopping: make(chan bool), handling: new(sync.WaitGroup), conns: make(map[net.Conn]net.Conn), streamer: streamer.New(time.Minute), destroys: make(map[string]struct{}), destroysL: new(sync.Mutex), } handlers := map[string]http.Handler{ routes.Ping: http.HandlerFunc(s.handlePing), routes.Capacity: http.HandlerFunc(s.handleCapacity), routes.Create: http.HandlerFunc(s.handleCreate), routes.Destroy: http.HandlerFunc(s.handleDestroy), routes.List: http.HandlerFunc(s.handleList), routes.Stop: http.HandlerFunc(s.handleStop), routes.StreamIn: http.HandlerFunc(s.handleStreamIn), routes.StreamOut: http.HandlerFunc(s.handleStreamOut), routes.CurrentBandwidthLimits: http.HandlerFunc(s.handleCurrentBandwidthLimits), routes.CurrentCPULimits: http.HandlerFunc(s.handleCurrentCPULimits), routes.CurrentDiskLimits: http.HandlerFunc(s.handleCurrentDiskLimits), routes.CurrentMemoryLimits: http.HandlerFunc(s.handleCurrentMemoryLimits), routes.NetIn: http.HandlerFunc(s.handleNetIn), routes.NetOut: http.HandlerFunc(s.handleNetOut), routes.Info: http.HandlerFunc(s.handleInfo), routes.BulkInfo: http.HandlerFunc(s.handleBulkInfo), routes.BulkMetrics: http.HandlerFunc(s.handleBulkMetrics), routes.Run: http.HandlerFunc(s.handleRun), routes.Stdout: streamer.HandlerFunc(s.streamer.ServeStdout), routes.Stderr: streamer.HandlerFunc(s.streamer.ServeStderr), routes.Attach: http.HandlerFunc(s.handleAttach), routes.Metrics: http.HandlerFunc(s.handleMetrics), routes.Properties: http.HandlerFunc(s.handleProperties), routes.Property: http.HandlerFunc(s.handleProperty), routes.SetProperty: http.HandlerFunc(s.handleSetProperty), routes.RemoveProperty: http.HandlerFunc(s.handleRemoveProperty), routes.SetGraceTime: http.HandlerFunc(s.handleSetGraceTime), } mux, err := rata.NewRouter(routes.Routes, handlers) if err != nil { logger.Fatal("failed-to-initialize-rata", err) } conLogger := logger.Session("connection") s.server = &http.Server{ Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { mux.ServeHTTP(w, r) }), ConnState: func(conn net.Conn, state http.ConnState) { switch state { case http.StateNew: conLogger.Debug("open", lager.Data{"local_addr": conn.LocalAddr(), "remote_addr": conn.RemoteAddr()}) s.handling.Add(1) case http.StateActive: s.mu.Lock() delete(s.conns, conn) s.mu.Unlock() case http.StateIdle: select { case <-s.stopping: conn.Close() default: s.mu.Lock() s.conns[conn] = conn s.mu.Unlock() } case http.StateHijacked, http.StateClosed: s.mu.Lock() delete(s.conns, conn) s.mu.Unlock() conLogger.Debug("closed", lager.Data{"local_addr": conn.LocalAddr(), "remote_addr": conn.RemoteAddr()}) s.handling.Done() } }, } return s }
var _ = Describe("Streamer", func() { const testString = "x" var ( graceTime time.Duration str *streamer.Streamer stdoutChan chan []byte stderrChan chan []byte testByteSlice []byte channelBufferSize int ) JustBeforeEach(func() { str = streamer.New(graceTime) stdoutChan = make(chan []byte, channelBufferSize) stderrChan = make(chan []byte, channelBufferSize) }) BeforeEach(func() { graceTime = 50 * time.Millisecond channelBufferSize = 1 testByteSlice = []byte(testString) }) It("should stream standard output until it is stopped", func() { sid := str.Stream(stdoutChan, stderrChan) w := &syncBuffer{ Buffer: new(bytes.Buffer),