blob: fa5c521f78088919acc2535fe6b3953086652e96 [file] [log] [blame]
khenaidoobf6e7bb2018-08-14 22:27:29 -04001/*
2 * Copyright 2018-present Open Networking Foundation
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 */
Stephane Barbarie7dfae952018-08-13 11:43:17 -040016package grpc
17
18import (
Stephane Barbarie7dfae952018-08-13 11:43:17 -040019 "context"
20 "google.golang.org/grpc"
Scott Bakeree6a0872019-10-29 15:59:52 -070021 "google.golang.org/grpc/codes"
Stephane Barbarie7dfae952018-08-13 11:43:17 -040022 "google.golang.org/grpc/credentials"
Scott Bakeree6a0872019-10-29 15:59:52 -070023 "google.golang.org/grpc/status"
khenaidoobf6e7bb2018-08-14 22:27:29 -040024 "net"
Stephane Barbarie7dfae952018-08-13 11:43:17 -040025)
26
27/*
28To add a GRPC server to your existing component simply follow these steps:
29
301. Create a server instance by passing the host and port where it should run and optionally add certificate information
31
32 e.g.
33 s.server = server.NewGrpcServer(s.config.GrpcHost, s.config.GrpcPort, nil, false)
34
352. Create a function that will register your service with the GRPC server
36
37 e.g.
38 f := func(gs *grpc.Server) {
39 voltha.RegisterVolthaReadOnlyServiceServer(
40 gs,
41 core.NewReadOnlyServiceHandler(s.root),
42 )
43 }
44
453. Add the service to the server
46
47 e.g.
48 s.server.AddService(f)
49
504. Start the server
51
52 s.server.Start(ctx)
khenaidoobf6e7bb2018-08-14 22:27:29 -040053*/
Stephane Barbarie7dfae952018-08-13 11:43:17 -040054
Scott Bakeree6a0872019-10-29 15:59:52 -070055// Interface allows probes to be attached to server
56// A probe must support the IsReady() method
57type ReadyProbe interface {
58 IsReady() bool
59}
60
Stephane Barbarie7dfae952018-08-13 11:43:17 -040061type GrpcServer struct {
62 gs *grpc.Server
63 address string
Stephane Barbarie7dfae952018-08-13 11:43:17 -040064 secure bool
65 services []func(*grpc.Server)
Scott Bakeree6a0872019-10-29 15:59:52 -070066 probe ReadyProbe // optional
Stephane Barbarie7dfae952018-08-13 11:43:17 -040067
68 *GrpcSecurity
69}
70
71/*
72Instantiate a GRPC server data structure
73*/
74func NewGrpcServer(
75 address string,
Stephane Barbarie7dfae952018-08-13 11:43:17 -040076 certs *GrpcSecurity,
77 secure bool,
Scott Bakeree6a0872019-10-29 15:59:52 -070078 probe ReadyProbe,
Stephane Barbarie7dfae952018-08-13 11:43:17 -040079) *GrpcServer {
80 server := &GrpcServer{
81 address: address,
Stephane Barbarie7dfae952018-08-13 11:43:17 -040082 secure: secure,
83 GrpcSecurity: certs,
Scott Bakeree6a0872019-10-29 15:59:52 -070084 probe: probe,
Stephane Barbarie7dfae952018-08-13 11:43:17 -040085 }
86 return server
87}
88
89/*
90Start prepares the GRPC server and starts servicing requests
91*/
92func (s *GrpcServer) Start(ctx context.Context) {
khenaidoo5aadea02018-11-07 14:30:11 -050093
Neha Sharmad1387da2020-05-07 20:07:28 +000094 lis, err := net.Listen("tcp", s.address)
Stephane Barbarie7dfae952018-08-13 11:43:17 -040095 if err != nil {
Scott Baker432f9be2020-03-26 11:56:30 -070096 logger.Fatalf("failed to listen: %v", err)
Stephane Barbarie7dfae952018-08-13 11:43:17 -040097 }
98
99 if s.secure && s.GrpcSecurity != nil {
100 creds, err := credentials.NewServerTLSFromFile(s.CertFile, s.KeyFile)
101 if err != nil {
Scott Baker432f9be2020-03-26 11:56:30 -0700102 logger.Fatalf("could not load TLS keys: %s", err)
Stephane Barbarie7dfae952018-08-13 11:43:17 -0400103 }
Scott Bakeree6a0872019-10-29 15:59:52 -0700104 s.gs = grpc.NewServer(grpc.Creds(creds),
105 withServerUnaryInterceptor(s))
Stephane Barbarie7dfae952018-08-13 11:43:17 -0400106
107 } else {
Scott Baker432f9be2020-03-26 11:56:30 -0700108 logger.Info("starting-insecure-grpc-server")
Scott Bakeree6a0872019-10-29 15:59:52 -0700109 s.gs = grpc.NewServer(withServerUnaryInterceptor(s))
Stephane Barbarie7dfae952018-08-13 11:43:17 -0400110 }
111
112 // Register all required services
113 for _, service := range s.services {
114 service(s.gs)
115 }
116
117 if err := s.gs.Serve(lis); err != nil {
Scott Baker432f9be2020-03-26 11:56:30 -0700118 logger.Fatalf("failed to serve: %v\n", err)
Stephane Barbarie7dfae952018-08-13 11:43:17 -0400119 }
120}
121
Scott Bakeree6a0872019-10-29 15:59:52 -0700122func withServerUnaryInterceptor(s *GrpcServer) grpc.ServerOption {
123 return grpc.UnaryInterceptor(mkServerInterceptor(s))
124}
125
126// Make a serverInterceptor for the given GrpcServer
127// This interceptor will check whether there is an attached probe,
128// and if that probe indicates NotReady, then an UNAVAILABLE
129// response will be returned.
130func mkServerInterceptor(s *GrpcServer) func(ctx context.Context,
131 req interface{},
132 info *grpc.UnaryServerInfo,
133 handler grpc.UnaryHandler) (interface{}, error) {
134
135 return func(ctx context.Context,
136 req interface{},
137 info *grpc.UnaryServerInfo,
138 handler grpc.UnaryHandler) (interface{}, error) {
139
140 if (s.probe != nil) && (!s.probe.IsReady()) {
Scott Baker432f9be2020-03-26 11:56:30 -0700141 logger.Warnf("Grpc request received while not ready %v", req)
Scott Bakeree6a0872019-10-29 15:59:52 -0700142 return nil, status.Error(codes.Unavailable, "system is not ready")
143 }
144
145 // Calls the handler
146 h, err := handler(ctx, req)
147
148 return h, err
149 }
150}
151
Stephane Barbarie7dfae952018-08-13 11:43:17 -0400152/*
153Stop servicing GRPC requests
154*/
155func (s *GrpcServer) Stop() {
David K. Bainbridgeb4a9ab02019-09-20 15:12:16 -0700156 if s.gs != nil {
157 s.gs.Stop()
158 }
Stephane Barbarie7dfae952018-08-13 11:43:17 -0400159}
160
161/*
162AddService appends a generic service request function
163*/
164func (s *GrpcServer) AddService(
165 registerFunction func(*grpc.Server),
166) {
167 s.services = append(s.services, registerFunction)
168}