github.com/Mirantis/virtlet@v1.5.2-0.20191204181327-1659b8a48e9b/pkg/manager/grpc.go (about)

     1  /*
     2  Copyright 2018 Mirantis
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package manager
    18  
    19  import (
    20  	"net"
    21  	"os"
    22  	"strings"
    23  	"syscall"
    24  
    25  	"github.com/ghodss/yaml"
    26  	"github.com/golang/glog"
    27  	"golang.org/x/net/context"
    28  	"google.golang.org/grpc"
    29  	kubeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
    30  )
    31  
    32  const (
    33  	criErrorLogLevel   = 2
    34  	criRequestLogLevel = 3
    35  	criNoisyLogLevel   = 4
    36  	criListLogLevel    = 5
    37  )
    38  
    39  // Server wraps a gRPC server and provides listener setup and request
    40  // logging.
    41  type Server struct {
    42  	server *grpc.Server
    43  }
    44  
    45  // NewServer creates a new Server.
    46  func NewServer() *Server {
    47  	return &Server{
    48  		server: grpc.NewServer(grpc.UnaryInterceptor(func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
    49  			return intercept(ctx, req, info, handler)
    50  		})),
    51  	}
    52  }
    53  
    54  // Serve set up a listener on unix socket, than it passes that listener to
    55  // main loop of grpc server which handles CRI calls.
    56  func (s *Server) Serve(addr string) error {
    57  	if err := syscall.Unlink(addr); err != nil && !os.IsNotExist(err) {
    58  		return err
    59  	}
    60  	ln, err := net.Listen("unix", addr)
    61  	if err != nil {
    62  		return err
    63  	}
    64  	defer ln.Close()
    65  	return s.server.Serve(ln)
    66  }
    67  
    68  // Stop halts the manager.
    69  func (s *Server) Stop() {
    70  	s.server.Stop()
    71  }
    72  
    73  // Register registers CRI Runtime and Image services
    74  func (s *Server) Register(runtimeService kubeapi.RuntimeServiceServer, imageService kubeapi.ImageServiceServer) {
    75  	kubeapi.RegisterRuntimeServiceServer(s.server, runtimeService)
    76  	kubeapi.RegisterImageServiceServer(s.server, imageService)
    77  }
    78  
    79  func logLevelForMethod(fullMethod string) glog.Level {
    80  	idx := strings.LastIndex(fullMethod, "/")
    81  	if idx < 0 {
    82  		return criNoisyLogLevel
    83  	}
    84  	methodName := fullMethod[idx+1:]
    85  	switch {
    86  	case strings.Contains(methodName, "Status"):
    87  		return criNoisyLogLevel
    88  	case strings.Contains(methodName, "Version"):
    89  		return criNoisyLogLevel
    90  	case strings.Contains(methodName, "List"):
    91  		return criListLogLevel
    92  	case methodName == "ImageFsInfo":
    93  		return criListLogLevel
    94  	default:
    95  		return criRequestLogLevel
    96  	}
    97  }
    98  
    99  func dump(v interface{}) string {
   100  	out, err := yaml.Marshal(v)
   101  	if err != nil {
   102  		return "<marshalling error>"
   103  	}
   104  	return string(out)
   105  }
   106  
   107  func intercept(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
   108  	logLevel := logLevelForMethod(info.FullMethod)
   109  	if glog.V(logLevel) {
   110  		glog.Infof("ENTER: %s():\n%s", info.FullMethod, dump(req))
   111  	}
   112  	resp, err := handler(ctx, req)
   113  	switch {
   114  	case err != nil && !bool(glog.V(criErrorLogLevel)):
   115  		// do nothing
   116  	case err != nil:
   117  		glog.Errorf("FAIL: %s(): %v", info.FullMethod, err)
   118  	case bool(glog.V(logLevel)):
   119  		glog.Infof("LEAVE: %s()\n%s", info.FullMethod, dump(resp))
   120  	}
   121  	return resp, err
   122  }