func (s *server) Serve() (retErr error) { start := make(chan struct{}) var listener net.Listener var spec string var err error var addr string switch s.protocol { case protocolTCP: listener, spec, err = newTCPListener(s.volumeDriverName, s.groupOrAddress, start) addr = s.groupOrAddress case protocolUnix: listener, spec, err = newUnixListener(s.volumeDriverName, s.groupOrAddress, start) addr = s.volumeDriverName default: return fmt.Errorf("unknown protocol: %d", s.protocol) } if err != nil { return err } grpcPort := s.opts.GRPCPort if grpcPort == 0 { grpcPort = DefaultGRPCPort } return protoserver.Serve( grpcPort, func(grpcServer *grpc.Server) { RegisterAPIServer(grpcServer, s.apiServer) }, protoserver.ServeOptions{ DebugPort: s.opts.GRPCDebugPort, HTTPRegisterFunc: func(ctx context.Context, mux *runtime.ServeMux, clientConn *grpc.ClientConn) error { return RegisterAPIHandler(ctx, mux, clientConn) }, HTTPAddress: addr, HTTPListener: listener, ServeMuxOptions: []runtime.ServeMuxOption{ runtime.WithForwardResponseOption( func(_ context.Context, responseWriter http.ResponseWriter, _ proto.Message) error { responseWriter.Header().Set("Content-Type", "application/vnd.docker.plugins.v1.1+json") return nil }, ), }, HTTPBeforeShutdown: func() { _ = s.cleanup() }, HTTPShutdownInitiated: func() { if spec != "" { _ = os.Remove(spec) } }, HTTPStart: start, }, ) }
func TestIntegration(t *testing.T) { if testing.Short() { t.Skip() return } go func() { if err := server.Run(); err != nil { t.Errorf("server.Run() failed with %v; want success", err) return } }() go func() { if err := Run(":8080"); err != nil { t.Errorf("gw.Run() failed with %v; want success", err) return } }() time.Sleep(100 * time.Millisecond) testEcho(t, 8080, "application/json") testEchoBody(t) testABECreate(t) testABECreateBody(t) testABEBulkCreate(t) testABELookup(t) testABELookupNotFound(t) testABEList(t) testAdditionalBindings(t) go func() { if err := Run( ":8081", runtime.WithForwardResponseOption( func(_ context.Context, w http.ResponseWriter, _ proto.Message) error { w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1.1+json") return nil }, ), ); err != nil { t.Errorf("gw.Run() failed with %v; want success", err) return } }() time.Sleep(100 * time.Millisecond) testEcho(t, 8081, "application/vnd.docker.plugins.v1.1+json") }
func (s *server) Serve() (retErr error) { var listener net.Listener var spec string var err error var addr string switch s.protocol { case protocolTCP: listener, spec, err = newTCPListener(s.driverName, s.groupOrAddress) addr = s.groupOrAddress case protocolUnix: listener, spec, err = newUnixListener(s.driverName, s.groupOrAddress) addr = s.driverName default: return fmt.Errorf("unknown protocol: %d", s.protocol) } if err != nil { return err } grpcPort := s.opts.GRPCPort if grpcPort == 0 { grpcPort = DefaultGRPCPort } grpcServer := grpc.NewServer(grpc.MaxConcurrentStreams(math.MaxUint32)) RegisterAPIServer(grpcServer, s.apiServer) s.registerFunc(grpcServer) grpcListener, err := net.Listen("tcp", fmt.Sprintf(":%d", grpcPort)) if err != nil { return err } grpcErrC := make(chan error) httpErrC := make(chan error) errCCount := 1 go func() { grpcErrC <- grpcServer.Serve(grpcListener) }() time.Sleep(1 * time.Second) ctx, cancel := context.WithCancel(context.Background()) mux := runtime.NewServeMux( runtime.WithForwardResponseOption( func(_ context.Context, responseWriter http.ResponseWriter, _ proto.Message) error { responseWriter.Header().Set("Content-Type", "application/vnd.docker.plugins.v1.1+json") return nil }, ), ) conn, err := grpc.Dial(fmt.Sprintf("0.0.0.0:%d", grpcPort), grpc.WithInsecure()) if err != nil { glog.Flush() cancel() return err } go func() { <-ctx.Done() _ = conn.Close() }() if err := RegisterAPIHandler(ctx, mux, conn); err != nil { _ = conn.Close() glog.Flush() cancel() return err } if err := s.httpRegisterFunc(ctx, mux, conn); err != nil { _ = conn.Close() glog.Flush() cancel() return err } httpServer := &http.Server{ Addr: addr, Handler: mux, } gracefulServer := &graceful.Server{ Timeout: 1 * time.Second, ShutdownInitiated: func() { glog.Flush() cancel() if spec != "" { _ = os.Remove(spec) } }, Server: httpServer, } errCCount++ go func() { httpErrC <- gracefulServer.Serve(listener) }() var errs []error grpcStopped := false for i := 0; i < errCCount; i++ { select { case grpcErr := <-grpcErrC: if grpcErr != nil { errs = append(errs, fmt.Errorf("grpc error: %s", grpcErr.Error())) } grpcStopped = true case httpErr := <-httpErrC: if httpErr != nil { errs = append(errs, fmt.Errorf("http error: %s", httpErr.Error())) } if !grpcStopped { grpcServer.Stop() _ = listener.Close() grpcStopped = true } } } if len(errs) > 0 { return fmt.Errorf("%v", errs) } return nil }