blob: 5e11fa6214ee402c888c340b9c023b4c3113919c [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 (
sslobodr392ebd52019-01-18 12:41:49 -050021 "errors"
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040022 "fmt"
23 "github.com/opencord/voltha-go/common/log"
sslobodr392ebd52019-01-18 12:41:49 -050024 "google.golang.org/grpc"
25 "google.golang.org/grpc/metadata"
sslobodr392ebd52019-01-18 12:41:49 -050026)
27
28const NoMeta = "nometa"
29
30type MethodRouter struct {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040031 name string
sslobodr392ebd52019-01-18 12:41:49 -050032 service string
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040033 mthdRt map[string]map[string]Router // map of [metadata][method]
sslobodr392ebd52019-01-18 12:41:49 -050034}
35
36func newMethodRouter(config *RouterConfig) (Router, error) {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040037 mr := MethodRouter{name: config.Name, service: config.ProtoService, mthdRt: make(map[string]map[string]Router)}
sslobodr392ebd52019-01-18 12:41:49 -050038 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 }
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040043 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
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040046 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
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040052 if _, ok := mr.mthdRt[idx1]; ok == false { // /First attempt on this key
sslobodr392ebd52019-01-18 12:41:49 -050053 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 {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040065 log.Debugf("Setting router '%s' for single method '%s'", r.Name(), rtv.Methods[0])
66 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:
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040076 for _, m := range rtv.Methods {
sslobodr1d1e50b2019-03-14 09:17:40 -040077 log.Debugf("Processing Method %s", m)
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040078 if _, ok := mr.mthdRt[idx1][m]; ok == false {
79 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
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400101func (mr MethodRouter) GetMetaKeyVal(serverStream grpc.ServerStream) (string, string, error) {
sslobodr392ebd52019-01-18 12:41:49 -0500102 var rtrnK string = NoMeta
103 var rtrnV string = ""
104
105 // Get the metadata from the server stream
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400106 md, ok := metadata.FromIncomingContext(serverStream.Context())
sslobodr392ebd52019-01-18 12:41:49 -0500107 if !ok {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400108 return rtrnK, rtrnV, errors.New("Could not get a server stream metadata")
109 }
sslobodr392ebd52019-01-18 12:41:49 -0500110
111 // Determine if one of the method routing keys exists in the metadata
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400112 for k, _ := range mr.mthdRt {
113 if _, ok := md[k]; ok == true {
sslobodr392ebd52019-01-18 12:41:49 -0500114 rtrnV = md[k][0]
115 rtrnK = k
116 break
117 }
118 }
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400119 return rtrnK, rtrnV, nil
sslobodr392ebd52019-01-18 12:41:49 -0500120
121}
122
123func (mr MethodRouter) ReplyHandler(sel interface{}) error {
124 switch sl := sel.(type) {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400125 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
sslobodr392ebd52019-01-18 12:41:49 -0500133 }
134 return nil
135}
136
137func (mr MethodRouter) Route(sel interface{}) *backend {
138 switch sl := sel.(type) {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400139 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
sslobodr392ebd52019-01-18 12:41:49 -0500147 }
sslobodr392ebd52019-01-18 12:41:49 -0500148}
149
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400150func (mr MethodRouter) BackendCluster(mthd string, metaKey string) (*backendCluster, error) {
151 if r, ok := mr.mthdRt[metaKey][mthd]; ok == true {
sslobodr392ebd52019-01-18 12:41:49 -0500152 return r.BackendCluster(mthd, metaKey)
153 }
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400154 err := errors.New(fmt.Sprintf("No backend cluster exists for method '%s' using meta key '%s'", mthd, metaKey))
sslobodr392ebd52019-01-18 12:41:49 -0500155 log.Error(err)
156 return nil, err
157}
158
159func (mr MethodRouter) FindBackendCluster(beName string) *backendCluster {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400160 for _, meta := range mr.mthdRt {
161 for _, r := range meta {
162 if rtrn := r.FindBackendCluster(beName); rtrn != nil {
sslobodr392ebd52019-01-18 12:41:49 -0500163 return rtrn
164 }
165 }
166 }
167 return nil
168}