blob: 2c1ca4f2dcb6743b38c2b34672849e4a15a417e6 [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"
22 "github.com/opencord/voltha-go/common/log"
sslobodr392ebd52019-01-18 12:41:49 -050023 "google.golang.org/grpc"
24 "google.golang.org/grpc/metadata"
sslobodr392ebd52019-01-18 12:41:49 -050025)
26
27const NoMeta = "nometa"
28
29type MethodRouter struct {
Kent Hagerman1e9061e2019-05-21 16:01:21 -040030 name string
31 service string
32 methodRouter map[string]map[string]Router // map of [metadata][method]
sslobodr392ebd52019-01-18 12:41:49 -050033}
34
35func newMethodRouter(config *RouterConfig) (Router, error) {
Kent Hagerman1e9061e2019-05-21 16:01:21 -040036 mr := MethodRouter{name: config.Name, service: config.ProtoService, methodRouter: make(map[string]map[string]Router)}
37 mr.methodRouter[NoMeta] = make(map[string]Router) // For routes not needing metadata (all expcept binding at this time)
sslobodr1d1e50b2019-03-14 09:17:40 -040038 log.Debugf("Processing MethodRouter config %v", *config)
sslobodr392ebd52019-01-18 12:41:49 -050039 if len(config.Routes) == 0 {
40 return nil, errors.New(fmt.Sprintf("Router %s must have at least one route", config.Name))
41 }
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040042 for _, rtv := range config.Routes {
sslobodr1d1e50b2019-03-14 09:17:40 -040043 //log.Debugf("Processing route: %v",rtv)
sslobodr392ebd52019-01-18 12:41:49 -050044 var idx1 string
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040045 r, err := newSubRouter(config, &rtv)
sslobodr392ebd52019-01-18 12:41:49 -050046 if err != nil {
47 return nil, err
48 }
Kent Hagerman1e9061e2019-05-21 16:01:21 -040049 if rtv.Type == RouteTypeBinding {
sslobodr392ebd52019-01-18 12:41:49 -050050 idx1 = rtv.Binding.Field
Kent Hagerman1e9061e2019-05-21 16:01:21 -040051 if _, ok := mr.methodRouter[idx1]; !ok { // /First attempt on this key
52 mr.methodRouter[idx1] = make(map[string]Router)
sslobodr392ebd52019-01-18 12:41:49 -050053 }
54 } else {
55 idx1 = NoMeta
56 }
57 switch len(rtv.Methods) {
58 case 0:
59 return nil, errors.New(fmt.Sprintf("Route for router %s must have at least one method", config.Name))
60 case 1:
61 if rtv.Methods[0] == "*" {
62 return r, nil
63 } else {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040064 log.Debugf("Setting router '%s' for single method '%s'", r.Name(), rtv.Methods[0])
Kent Hagerman1e9061e2019-05-21 16:01:21 -040065 if _, ok := mr.methodRouter[idx1][rtv.Methods[0]]; !ok {
66 mr.methodRouter[idx1][rtv.Methods[0]] = r
sslobodr392ebd52019-01-18 12:41:49 -050067 } else {
68 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 -040069 r.Name(), mr.methodRouter[idx1][rtv.Methods[0]].Name()))
sslobodr1d1e50b2019-03-14 09:17:40 -040070 log.Error(err)
sslobodr392ebd52019-01-18 12:41:49 -050071 return mr, err
72 }
73 }
74 default:
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040075 for _, m := range rtv.Methods {
sslobodr1d1e50b2019-03-14 09:17:40 -040076 log.Debugf("Processing Method %s", m)
Kent Hagerman1e9061e2019-05-21 16:01:21 -040077 if _, ok := mr.methodRouter[idx1][m]; !ok {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040078 log.Debugf("Setting router '%s' for method '%s'", r.Name(), m)
Kent Hagerman1e9061e2019-05-21 16:01:21 -040079 mr.methodRouter[idx1][m] = r
sslobodr392ebd52019-01-18 12:41:49 -050080 } else {
Kent Hagerman1e9061e2019-05-21 16:01:21 -040081 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 -040082 log.Error(err)
sslobodr392ebd52019-01-18 12:41:49 -050083 return mr, err
84 }
85 }
86 }
87 }
88
89 return mr, nil
90}
91
92func (mr MethodRouter) Name() string {
93 return mr.name
94}
95
96func (mr MethodRouter) Service() string {
97 return mr.service
98}
99
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400100func (mr MethodRouter) GetMetaKeyVal(serverStream grpc.ServerStream) (string, string, error) {
Kent Hagerman1e9061e2019-05-21 16:01:21 -0400101 var rtrnK = NoMeta
102 var rtrnV = ""
sslobodr392ebd52019-01-18 12:41:49 -0500103
104 // Get the metadata from the server stream
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400105 md, ok := metadata.FromIncomingContext(serverStream.Context())
sslobodr392ebd52019-01-18 12:41:49 -0500106 if !ok {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400107 return rtrnK, rtrnV, errors.New("Could not get a server stream metadata")
108 }
sslobodr392ebd52019-01-18 12:41:49 -0500109
110 // Determine if one of the method routing keys exists in the metadata
Kent Hagerman1e9061e2019-05-21 16:01:21 -0400111 for k := range mr.methodRouter {
112 if _, ok := md[k]; ok {
sslobodr392ebd52019-01-18 12:41:49 -0500113 rtrnV = md[k][0]
114 rtrnK = k
115 break
116 }
117 }
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400118 return rtrnK, rtrnV, nil
sslobodr392ebd52019-01-18 12:41:49 -0500119
120}
121
122func (mr MethodRouter) ReplyHandler(sel interface{}) error {
123 switch sl := sel.(type) {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400124 case *sbFrame:
Kent Hagerman1e9061e2019-05-21 16:01:21 -0400125 if r, ok := mr.methodRouter[NoMeta][sl.method]; ok {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400126 return r.ReplyHandler(sel)
127 }
128 // TODO: this case should also be an error
129 default: //TODO: This should really be a big error
130 // A reply handler should only be called on the sbFrame
131 return nil
sslobodr392ebd52019-01-18 12:41:49 -0500132 }
133 return nil
134}
135
136func (mr MethodRouter) Route(sel interface{}) *backend {
137 switch sl := sel.(type) {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400138 case *nbFrame:
Kent Hagerman1e9061e2019-05-21 16:01:21 -0400139 if r, ok := mr.methodRouter[sl.metaKey][sl.methodInfo.method]; ok {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400140 return r.Route(sel)
141 }
Kent Hagerman1e9061e2019-05-21 16:01:21 -0400142 log.Errorf("Attept to route on non-existent method '%s'", sl.methodInfo.method)
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400143 return nil
144 default:
145 return nil
sslobodr392ebd52019-01-18 12:41:49 -0500146 }
sslobodr392ebd52019-01-18 12:41:49 -0500147}
148
Kent Hagerman1e9061e2019-05-21 16:01:21 -0400149func (mr MethodRouter) BackendCluster(mthd string, metaKey string) (*cluster, error) {
150 if r, ok := mr.methodRouter[metaKey][mthd]; ok {
sslobodr392ebd52019-01-18 12:41:49 -0500151 return r.BackendCluster(mthd, metaKey)
152 }
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400153 err := errors.New(fmt.Sprintf("No backend cluster exists for method '%s' using meta key '%s'", mthd, metaKey))
sslobodr392ebd52019-01-18 12:41:49 -0500154 log.Error(err)
155 return nil, err
156}
157
Kent Hagerman1e9061e2019-05-21 16:01:21 -0400158func (mr MethodRouter) FindBackendCluster(beName string) *cluster {
159 for _, meta := range mr.methodRouter {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400160 for _, r := range meta {
161 if rtrn := r.FindBackendCluster(beName); rtrn != nil {
sslobodr392ebd52019-01-18 12:41:49 -0500162 return rtrn
163 }
164 }
165 }
166 return nil
167}