blob: 56d025eb441dda1ecabb098871dd1e1244d4ec26 [file] [log] [blame]
sslobodr392ebd52019-01-18 12:41:49 -05001/*
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 */
sslobodr392ebd52019-01-18 12:41:49 -050016
17package afrouter
18
19import (
sslobodr392ebd52019-01-18 12:41:49 -050020 "errors"
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040021 "fmt"
Kent Hagerman03b58992019-08-29 17:21:03 -040022 "github.com/golang/protobuf/proto"
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040023 "github.com/opencord/voltha-go/common/log"
sslobodr392ebd52019-01-18 12:41:49 -050024 "google.golang.org/grpc"
25 "google.golang.org/grpc/metadata"
Kent Hagerman03b58992019-08-29 17:21:03 -040026 "io/ioutil"
sslobodr392ebd52019-01-18 12:41:49 -050027)
28
29const NoMeta = "nometa"
30
31type MethodRouter struct {
Kent Hagerman03b58992019-08-29 17:21:03 -040032 name string
33 service string
34 methodRouter map[string]map[string]Router // map of [metadata][method]
35 methodStreaming map[string]streamingDirections
36}
37
38type streamingDirections struct {
39 request bool
40 response bool
sslobodr392ebd52019-01-18 12:41:49 -050041}
42
43func newMethodRouter(config *RouterConfig) (Router, error) {
Kent Hagerman03b58992019-08-29 17:21:03 -040044 // Load the protobuf descriptor file
45 fb, err := ioutil.ReadFile(config.ProtoFile)
46 if err != nil {
47 log.Errorf("Could not open proto file '%s'", config.ProtoFile)
48 return nil, err
49 }
50 if err := proto.Unmarshal(fb, &config.protoDescriptor); err != nil {
51 log.Errorf("Could not unmarshal %s, %v", "proto.pb", err)
52 return nil, err
53 }
54
55 mr := MethodRouter{
56 name: config.Name,
57 service: config.ProtoService,
58 methodRouter: map[string]map[string]Router{
59 NoMeta: make(map[string]Router), // For routes not needing metadata (all except binding at this time)
60 },
61 methodStreaming: make(map[string]streamingDirections),
62 }
sslobodr1d1e50b2019-03-14 09:17:40 -040063 log.Debugf("Processing MethodRouter config %v", *config)
Kent Hagerman03b58992019-08-29 17:21:03 -040064
65 for _, file := range config.protoDescriptor.File {
66 if *file.Package == config.ProtoPackage {
67 for _, service := range file.Service {
68 if *service.Name == config.ProtoService {
69 for _, method := range service.Method {
70 if clientStreaming, serverStreaming := method.ClientStreaming != nil && *method.ClientStreaming, method.ServerStreaming != nil && *method.ServerStreaming; clientStreaming || serverStreaming {
71 mr.methodStreaming[*method.Name] = streamingDirections{
72 request: clientStreaming,
73 response: serverStreaming,
74 }
75 }
76 }
77 }
78 }
79 }
80 }
81
sslobodr392ebd52019-01-18 12:41:49 -050082 if len(config.Routes) == 0 {
83 return nil, errors.New(fmt.Sprintf("Router %s must have at least one route", config.Name))
84 }
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040085 for _, rtv := range config.Routes {
sslobodr1d1e50b2019-03-14 09:17:40 -040086 //log.Debugf("Processing route: %v",rtv)
sslobodr392ebd52019-01-18 12:41:49 -050087 var idx1 string
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040088 r, err := newSubRouter(config, &rtv)
sslobodr392ebd52019-01-18 12:41:49 -050089 if err != nil {
90 return nil, err
91 }
Kent Hagerman1e9061e2019-05-21 16:01:21 -040092 if rtv.Type == RouteTypeBinding {
sslobodr392ebd52019-01-18 12:41:49 -050093 idx1 = rtv.Binding.Field
Kent Hagerman1e9061e2019-05-21 16:01:21 -040094 if _, ok := mr.methodRouter[idx1]; !ok { // /First attempt on this key
95 mr.methodRouter[idx1] = make(map[string]Router)
sslobodr392ebd52019-01-18 12:41:49 -050096 }
97 } else {
98 idx1 = NoMeta
99 }
100 switch len(rtv.Methods) {
101 case 0:
102 return nil, errors.New(fmt.Sprintf("Route for router %s must have at least one method", config.Name))
103 case 1:
104 if rtv.Methods[0] == "*" {
105 return r, nil
106 } else {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400107 log.Debugf("Setting router '%s' for single method '%s'", r.Name(), rtv.Methods[0])
Kent Hagerman1e9061e2019-05-21 16:01:21 -0400108 if _, ok := mr.methodRouter[idx1][rtv.Methods[0]]; !ok {
109 mr.methodRouter[idx1][rtv.Methods[0]] = r
sslobodr392ebd52019-01-18 12:41:49 -0500110 } else {
111 err := errors.New(fmt.Sprintf("Attempt to define method %s for 2 routes: %s & %s", rtv.Methods[0],
Kent Hagerman1e9061e2019-05-21 16:01:21 -0400112 r.Name(), mr.methodRouter[idx1][rtv.Methods[0]].Name()))
sslobodr1d1e50b2019-03-14 09:17:40 -0400113 log.Error(err)
sslobodr392ebd52019-01-18 12:41:49 -0500114 return mr, err
115 }
116 }
117 default:
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400118 for _, m := range rtv.Methods {
sslobodr1d1e50b2019-03-14 09:17:40 -0400119 log.Debugf("Processing Method %s", m)
Kent Hagerman1e9061e2019-05-21 16:01:21 -0400120 if _, ok := mr.methodRouter[idx1][m]; !ok {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400121 log.Debugf("Setting router '%s' for method '%s'", r.Name(), m)
Kent Hagerman1e9061e2019-05-21 16:01:21 -0400122 mr.methodRouter[idx1][m] = r
sslobodr392ebd52019-01-18 12:41:49 -0500123 } else {
Kent Hagerman1e9061e2019-05-21 16:01:21 -0400124 err := errors.New(fmt.Sprintf("Attempt to define method %s for 2 routes: %s & %s", m, r.Name(), mr.methodRouter[idx1][m].Name()))
sslobodr1d1e50b2019-03-14 09:17:40 -0400125 log.Error(err)
sslobodr392ebd52019-01-18 12:41:49 -0500126 return mr, err
127 }
128 }
129 }
130 }
131
132 return mr, nil
133}
134
135func (mr MethodRouter) Name() string {
136 return mr.name
137}
138
139func (mr MethodRouter) Service() string {
140 return mr.service
141}
142
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400143func (mr MethodRouter) GetMetaKeyVal(serverStream grpc.ServerStream) (string, string, error) {
Kent Hagerman1e9061e2019-05-21 16:01:21 -0400144 var rtrnK = NoMeta
145 var rtrnV = ""
sslobodr392ebd52019-01-18 12:41:49 -0500146
147 // Get the metadata from the server stream
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400148 md, ok := metadata.FromIncomingContext(serverStream.Context())
sslobodr392ebd52019-01-18 12:41:49 -0500149 if !ok {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400150 return rtrnK, rtrnV, errors.New("Could not get a server stream metadata")
151 }
sslobodr392ebd52019-01-18 12:41:49 -0500152
153 // Determine if one of the method routing keys exists in the metadata
Kent Hagerman1e9061e2019-05-21 16:01:21 -0400154 for k := range mr.methodRouter {
155 if _, ok := md[k]; ok {
sslobodr392ebd52019-01-18 12:41:49 -0500156 rtrnV = md[k][0]
157 rtrnK = k
158 break
159 }
160 }
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400161 return rtrnK, rtrnV, nil
sslobodr392ebd52019-01-18 12:41:49 -0500162
163}
164
165func (mr MethodRouter) ReplyHandler(sel interface{}) error {
166 switch sl := sel.(type) {
Kent Hagerman03b58992019-08-29 17:21:03 -0400167 case *responseFrame:
Kent Hagerman1e9061e2019-05-21 16:01:21 -0400168 if r, ok := mr.methodRouter[NoMeta][sl.method]; ok {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400169 return r.ReplyHandler(sel)
170 }
171 // TODO: this case should also be an error
172 default: //TODO: This should really be a big error
Kent Hagerman03b58992019-08-29 17:21:03 -0400173 // A reply handler should only be called on the responseFrame
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400174 return nil
sslobodr392ebd52019-01-18 12:41:49 -0500175 }
176 return nil
177}
178
Scott Baker112b0d42019-08-22 08:32:26 -0700179func (mr MethodRouter) Route(sel interface{}) (*backend, *connection) {
sslobodr392ebd52019-01-18 12:41:49 -0500180 switch sl := sel.(type) {
Kent Hagerman03b58992019-08-29 17:21:03 -0400181 case *requestFrame:
Kent Hagerman1e9061e2019-05-21 16:01:21 -0400182 if r, ok := mr.methodRouter[sl.metaKey][sl.methodInfo.method]; ok {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400183 return r.Route(sel)
184 }
Kent Hagerman1e9061e2019-05-21 16:01:21 -0400185 log.Errorf("Attept to route on non-existent method '%s'", sl.methodInfo.method)
Scott Baker112b0d42019-08-22 08:32:26 -0700186 return nil, nil
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400187 default:
Scott Baker112b0d42019-08-22 08:32:26 -0700188 return nil, nil
sslobodr392ebd52019-01-18 12:41:49 -0500189 }
sslobodr392ebd52019-01-18 12:41:49 -0500190}
191
Kent Hagerman03b58992019-08-29 17:21:03 -0400192func (mr MethodRouter) IsStreaming(method string) (bool, bool) {
193 streamingDirections := mr.methodStreaming[method]
194 return streamingDirections.request, streamingDirections.response
195}
196
Kent Hagerman1e9061e2019-05-21 16:01:21 -0400197func (mr MethodRouter) BackendCluster(mthd string, metaKey string) (*cluster, error) {
198 if r, ok := mr.methodRouter[metaKey][mthd]; ok {
sslobodr392ebd52019-01-18 12:41:49 -0500199 return r.BackendCluster(mthd, metaKey)
200 }
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400201 err := errors.New(fmt.Sprintf("No backend cluster exists for method '%s' using meta key '%s'", mthd, metaKey))
sslobodr392ebd52019-01-18 12:41:49 -0500202 log.Error(err)
203 return nil, err
204}
205
Kent Hagerman1e9061e2019-05-21 16:01:21 -0400206func (mr MethodRouter) FindBackendCluster(beName string) *cluster {
207 for _, meta := range mr.methodRouter {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400208 for _, r := range meta {
209 if rtrn := r.FindBackendCluster(beName); rtrn != nil {
sslobodr392ebd52019-01-18 12:41:49 -0500210 return rtrn
211 }
212 }
213 }
214 return nil
215}