blob: 379bf113788481754e35f63c4a92bb1362ab2339 [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 */
16// gRPC affinity router with active/active backends
17
18package afrouter
19
20import (
21 "fmt"
22 "errors"
23 "google.golang.org/grpc"
24 "google.golang.org/grpc/metadata"
25 "github.com/opencord/voltha-go/common/log"
26)
27
28const NoMeta = "nometa"
29
30type MethodRouter struct {
31 name string
32 service string
33 mthdRt map[string]map[string]Router // map of [metadata][method]
34}
35
36func newMethodRouter(config *RouterConfig) (Router, error) {
37 mr := MethodRouter{name:config.Name,service:config.ProtoService,mthdRt:make(map[string]map[string]Router)}
38 mr.mthdRt[NoMeta] = make(map[string]Router) // For routes not needing metadata (all expcept binding at this time)
sslobodr1d1e50b2019-03-14 09:17:40 -040039 log.Debugf("Processing MethodRouter config %v", *config)
sslobodr392ebd52019-01-18 12:41:49 -050040 if len(config.Routes) == 0 {
41 return nil, errors.New(fmt.Sprintf("Router %s must have at least one route", config.Name))
42 }
sslobodr5f0b5a32019-01-24 07:45:19 -050043 for _,rtv := range config.Routes {
sslobodr1d1e50b2019-03-14 09:17:40 -040044 //log.Debugf("Processing route: %v",rtv)
sslobodr392ebd52019-01-18 12:41:49 -050045 var idx1 string
sslobodrcd37bc52019-01-24 11:47:16 -050046 r,err := newSubRouter(config, &rtv)
sslobodr392ebd52019-01-18 12:41:49 -050047 if err != nil {
48 return nil, err
49 }
50 if rtv.Type == "binding" {
51 idx1 = rtv.Binding.Field
52 if _,ok := mr.mthdRt[idx1]; ok == false { // /First attempt on this key
53 mr.mthdRt[idx1] = make(map[string]Router)
54 }
55 } else {
56 idx1 = NoMeta
57 }
58 switch len(rtv.Methods) {
59 case 0:
60 return nil, errors.New(fmt.Sprintf("Route for router %s must have at least one method", config.Name))
61 case 1:
62 if rtv.Methods[0] == "*" {
63 return r, nil
64 } else {
65 log.Debugf("Setting router '%s' for single method '%s'",r.Name(),rtv.Methods[0])
sslobodr1d1e50b2019-03-14 09:17:40 -040066 if _,ok := mr.mthdRt[idx1][rtv.Methods[0]]; ok == false {
sslobodr392ebd52019-01-18 12:41:49 -050067 mr.mthdRt[idx1][rtv.Methods[0]] = r
68 } else {
69 err := errors.New(fmt.Sprintf("Attempt to define method %s for 2 routes: %s & %s", rtv.Methods[0],
70 r.Name(), mr.mthdRt[idx1][rtv.Methods[0]].Name()))
sslobodr1d1e50b2019-03-14 09:17:40 -040071 log.Error(err)
sslobodr392ebd52019-01-18 12:41:49 -050072 return mr, err
73 }
74 }
75 default:
sslobodr5f0b5a32019-01-24 07:45:19 -050076 for _,m := range rtv.Methods {
sslobodr1d1e50b2019-03-14 09:17:40 -040077 log.Debugf("Processing Method %s", m)
sslobodr392ebd52019-01-18 12:41:49 -050078 if _,ok := mr.mthdRt[idx1][m]; ok == false {
sslobodr1d1e50b2019-03-14 09:17:40 -040079 log.Debugf("Setting router '%s' for method '%s'",r.Name(),m)
sslobodr392ebd52019-01-18 12:41:49 -050080 mr.mthdRt[idx1][m] = r
81 } else {
sslobodr1d1e50b2019-03-14 09:17:40 -040082 err := errors.New(fmt.Sprintf("Attempt to define method %s for 2 routes: %s & %s", m, r.Name(), mr.mthdRt[idx1][m].Name()))
83 log.Error(err)
sslobodr392ebd52019-01-18 12:41:49 -050084 return mr, err
85 }
86 }
87 }
88 }
89
90 return mr, nil
91}
92
93func (mr MethodRouter) Name() string {
94 return mr.name
95}
96
97func (mr MethodRouter) Service() string {
98 return mr.service
99}
100
101func (mr MethodRouter) GetMetaKeyVal(serverStream grpc.ServerStream) (string,string,error) {
102 var rtrnK string = NoMeta
103 var rtrnV string = ""
104
105 // Get the metadata from the server stream
106 md, ok := metadata.FromIncomingContext(serverStream.Context())
107 if !ok {
108 return rtrnK, rtrnV, errors.New("Could not get a server stream metadata")
109 }
110
111 // Determine if one of the method routing keys exists in the metadata
sslobodr5f0b5a32019-01-24 07:45:19 -0500112 for k,_ := range mr.mthdRt {
sslobodr392ebd52019-01-18 12:41:49 -0500113 if _,ok := md[k]; ok == true {
114 rtrnV = md[k][0]
115 rtrnK = k
116 break
117 }
118 }
119 return rtrnK,rtrnV,nil
120
121}
122
123func (mr MethodRouter) ReplyHandler(sel interface{}) error {
124 switch sl := sel.(type) {
125 case *sbFrame:
126 if r,ok := mr.mthdRt[NoMeta][sl.method]; ok == true {
127 return r.ReplyHandler(sel)
128 }
129 // TODO: this case should also be an error
130 default: //TODO: This should really be a big error
131 // A reply handler should only be called on the sbFrame
132 return nil
133 }
134 return nil
135}
136
137func (mr MethodRouter) Route(sel interface{}) *backend {
138 switch sl := sel.(type) {
139 case *nbFrame:
140 if r,ok := mr.mthdRt[sl.metaKey][sl.mthdSlice[REQ_METHOD]]; ok == true {
141 return r.Route(sel)
142 }
143 log.Errorf("Attept to route on non-existent method '%s'", sl.mthdSlice[REQ_METHOD])
144 return nil
145 default:
146 return nil
147 }
148 return nil
149}
150
151func (mr MethodRouter) BackendCluster(mthd string, metaKey string) (*backendCluster,error) {
152 if r,ok := mr.mthdRt[metaKey][mthd]; ok == true {
153 return r.BackendCluster(mthd, metaKey)
154 }
155 err := errors.New(fmt.Sprintf("No backend cluster exists for method '%s' using meta key '%s'", mthd,metaKey))
156 log.Error(err)
157 return nil, err
158}
159
160func (mr MethodRouter) FindBackendCluster(beName string) *backendCluster {
161 for _,meta := range mr.mthdRt {
162 for _,r := range meta {
163 if rtrn := r.FindBackendCluster(beName); rtrn != nil {
164 return rtrn
165 }
166 }
167 }
168 return nil
169}