blob: 7de3ea724d431ac11950b78a8974abbe541c455f [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
28type BindingRouter struct {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040029 name string
30 routerType int // TODO: This is probably not needed
sslobodr392ebd52019-01-18 12:41:49 -050031 association int
32 //routingField string
33 grpcService string
34 //protoDescriptor *pb.FileDescriptorSet
35 //methodMap map[string]byte
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040036 bkndClstr *backendCluster
37 bindings map[string]*backend
38 bindingType string
39 bindingField string
sslobodr392ebd52019-01-18 12:41:49 -050040 bindingMethod string
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040041 curBknd **backend
sslobodr392ebd52019-01-18 12:41:49 -050042}
43
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040044func (br BindingRouter) BackendCluster(s string, metaKey string) (*backendCluster, error) {
sslobodr392ebd52019-01-18 12:41:49 -050045 return br.bkndClstr, nil
46 //return nil,errors.New("Not implemented yet")
47}
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040048func (br BindingRouter) Name() string {
sslobodr392ebd52019-01-18 12:41:49 -050049 return br.name
50}
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040051func (br BindingRouter) Service() string {
sslobodr392ebd52019-01-18 12:41:49 -050052 return br.grpcService
53}
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040054func (br BindingRouter) GetMetaKeyVal(serverStream grpc.ServerStream) (string, string, error) {
sslobodr392ebd52019-01-18 12:41:49 -050055 var rtrnK string = ""
56 var rtrnV string = ""
57
58 // Get the metadata from the server stream
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040059 md, ok := metadata.FromIncomingContext(serverStream.Context())
sslobodr392ebd52019-01-18 12:41:49 -050060 if !ok {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040061 return rtrnK, rtrnV, errors.New("Could not get a server stream metadata")
62 }
sslobodr392ebd52019-01-18 12:41:49 -050063
64 // Determine if one of the method routing keys exists in the metadata
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040065 if _, ok := md[br.bindingField]; ok == true {
sslobodr392ebd52019-01-18 12:41:49 -050066 rtrnV = md[br.bindingField][0]
67 rtrnK = br.bindingField
68 }
69
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040070 return rtrnK, rtrnV, nil
sslobodr392ebd52019-01-18 12:41:49 -050071}
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040072func (br BindingRouter) FindBackendCluster(becName string) *backendCluster {
73 if becName == br.bkndClstr.name {
sslobodr360c8d72019-02-05 12:47:56 -050074 return br.bkndClstr
75 }
sslobodr392ebd52019-01-18 12:41:49 -050076 return nil
77}
78func (br BindingRouter) ReplyHandler(v interface{}) error {
79 return nil
80}
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040081func (br BindingRouter) Route(sel interface{}) *backend {
sslobodr392ebd52019-01-18 12:41:49 -050082 var err error
83 switch sl := sel.(type) {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040084 case *nbFrame:
85 if b, ok := br.bindings[sl.metaVal]; ok == true { // binding exists, just return it
86 return b
87 } else { // establish a new binding or error.
88 if sl.metaVal != "" {
89 err = errors.New(fmt.Sprintf("Attempt to route on non-existent metadata value '%s' in key '%s'",
90 sl.metaVal, sl.metaKey))
91 log.Error(err)
92 sl.err = err
93 return nil
sslobodr392ebd52019-01-18 12:41:49 -050094 }
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040095 if sl.mthdSlice[REQ_METHOD] != br.bindingMethod {
96 err = errors.New(fmt.Sprintf("Binding must occur with method %s but attempted with method %s",
97 br.bindingMethod, sl.mthdSlice[REQ_METHOD]))
98 log.Error(err)
99 sl.err = err
100 return nil
101 }
102 log.Debugf("MUST CREATE A NEW BINDING MAP ENTRY!!")
103 if len(br.bindings) < len(br.bkndClstr.backends) {
104 if *br.curBknd, err = br.bkndClstr.nextBackend(*br.curBknd, BE_SEQ_RR); err == nil {
105 // Use the name of the backend as the metaVal for this new binding
106 br.bindings[(*br.curBknd).name] = *br.curBknd
107 return *br.curBknd
108 } else {
109 log.Error(err)
110 sl.err = err
111 return nil
112 }
113 } else {
114 err = errors.New(fmt.Sprintf("Backends exhausted in attempt to bind for metakey '%s' with value '%s'",
115 sl.metaKey, sl.metaVal))
116 log.Error(err)
117 sl.err = err
118 }
119 }
120 return nil
121 default:
122 return nil
sslobodr392ebd52019-01-18 12:41:49 -0500123 }
sslobodr392ebd52019-01-18 12:41:49 -0500124}
125
sslobodrcd37bc52019-01-24 11:47:16 -0500126func newBindingRouter(rconf *RouterConfig, config *RouteConfig) (Router, error) {
sslobodr392ebd52019-01-18 12:41:49 -0500127 var rtrn_err bool = false
128 var err error = nil
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400129 log.Debugf("Creating binding router %s", config.Name)
sslobodr392ebd52019-01-18 12:41:49 -0500130 // A name must exist
131 if config.Name == "" {
132 log.Error("A router 'name' must be specified")
133 rtrn_err = true
134 }
135
136 if rconf.ProtoPackage == "" {
137 log.Error("A 'package' must be specified")
138 rtrn_err = true
139 }
140
141 if rconf.ProtoService == "" {
142 log.Error("A 'service' must be specified")
143 rtrn_err = true
144 }
145
146 //if config.RouteField == "" {
147 // log.Error("A 'routing_field' must be specified")
148 // rtrn_err = true
149 //}
150
151 // TODO: Using the specified service, the imported proto
152 // descriptor file should be scanned for all methods provided
153 // for this router to ensure that this field exists in
154 // the message(s) passed to the method. This will avoid run
155 // time failures that might not be detected for long periods
156 // of time.
157
158 // TODO The routes section is currently not being used
159 // so the router will route all methods based on the
160 // routing_field. This needs to be done.
161 var bptr *backend
162 bptr = nil
163 br := BindingRouter{
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400164 name: config.Name,
165 grpcService: rconf.ProtoService,
166 bindings: make(map[string]*backend),
sslobodr392ebd52019-01-18 12:41:49 -0500167 //methodMap:make(map[string]byte),
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400168 curBknd: &bptr,
sslobodr392ebd52019-01-18 12:41:49 -0500169 //serialNo:0,
170 }
171
172 // A binding association must exist
173 br.association = strIndex(rAssnNames, config.Binding.Association)
174 if br.association == 0 {
175 if config.Binding.Association == "" {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400176 log.Error("An binding association must be specified")
sslobodr392ebd52019-01-18 12:41:49 -0500177 } else {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400178 log.Errorf("The binding association '%s' is not valid", config.Binding.Association)
sslobodr392ebd52019-01-18 12:41:49 -0500179 }
180 rtrn_err = true
181 }
182 // A binding type must exist
183 // TODO: This is parsed but ignored and a header based type is used.
184 if config.Binding.Type != "header" {
185 log.Error("The binding type must be set to header")
186 rtrn_err = true
187 } else {
188 br.bindingType = config.Binding.Type
189 }
190 // A binding method must exist
191 if config.Binding.Method == "" {
192 log.Error("The binding method must be specified")
193 rtrn_err = true
194 } else {
195 br.bindingMethod = config.Binding.Method
196 }
197 // A binding field must exxist
198 if config.Binding.Field == "" {
199 log.Error("The binding field must be specified")
200 rtrn_err = true
201 } else {
202 br.bindingField = config.Binding.Field
203 }
204
sslobodr392ebd52019-01-18 12:41:49 -0500205 // This has already been validated bfore this function
206 // is called so just use it.
sslobodr5f0b5a32019-01-24 07:45:19 -0500207 for idx := range rTypeNames {
sslobodr392ebd52019-01-18 12:41:49 -0500208 if config.Type == rTypeNames[idx] {
209 br.routerType = idx
210 break
211 }
212 }
213
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400214 // Create the backend cluster or link to an existing one
sslobodr392ebd52019-01-18 12:41:49 -0500215 ok := true
216 if br.bkndClstr, ok = bClusters[config.backendCluster.Name]; ok == false {
sslobodrcd37bc52019-01-24 11:47:16 -0500217 if br.bkndClstr, err = newBackendCluster(config.backendCluster); err != nil {
sslobodr392ebd52019-01-18 12:41:49 -0500218 log.Errorf("Could not create a backend for router %s", config.Name)
219 rtrn_err = true
220 }
221 }
222
223 // HERE HERE HERE
224
225 if rtrn_err {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400226 return br, errors.New(fmt.Sprintf("Failed to create a new router '%s'", br.name))
sslobodr392ebd52019-01-18 12:41:49 -0500227 }
228
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400229 return br, nil
sslobodr392ebd52019-01-18 12:41:49 -0500230}