blob: a87481b26d417102d0fd3d5c26580428854fffd5 [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
28type BindingRouter struct {
29 name string
30 routerType int // TODO: This is probably not needed
31 association int
32 //routingField string
33 grpcService string
34 //protoDescriptor *pb.FileDescriptorSet
35 //methodMap map[string]byte
36 bkndClstr *backendCluster
37 bindings map[string]*backend
38 bindingType string
39 bindingField string
40 bindingMethod string
41 curBknd **backend
42}
43
44func (br BindingRouter) BackendCluster(s string, metaKey string) (*backendCluster,error) {
45 return br.bkndClstr, nil
46 //return nil,errors.New("Not implemented yet")
47}
48func (br BindingRouter) Name() (string) {
49 return br.name
50}
51func (br BindingRouter) Service() (string) {
52 return br.grpcService
53}
54func (br BindingRouter) GetMetaKeyVal(serverStream grpc.ServerStream) (string,string,error) {
55 var rtrnK string = ""
56 var rtrnV string = ""
57
58 // Get the metadata from the server stream
59 md, ok := metadata.FromIncomingContext(serverStream.Context())
60 if !ok {
61 return rtrnK, rtrnV, errors.New("Could not get a server stream metadata")
62 }
63
64 // Determine if one of the method routing keys exists in the metadata
65 if _,ok := md[br.bindingField]; ok == true {
66 rtrnV = md[br.bindingField][0]
67 rtrnK = br.bindingField
68 }
69
70 return rtrnK,rtrnV,nil
71}
72func (br BindingRouter) FindBackendCluster(string) (*backendCluster) {
73 return nil
74}
75func (br BindingRouter) ReplyHandler(v interface{}) error {
76 return nil
77}
78func (br BindingRouter) Route(sel interface{}) (*backend) {
79 var err error
80 switch sl := sel.(type) {
81 case *nbFrame:
82 if b, ok := br.bindings[sl.metaVal]; ok == true { // binding exists, just return it
83 return b
84 } else { // establish a new binding or error.
85 if sl.metaVal != "" {
86 err = errors.New(fmt.Sprintf("Attempt to route on non-existent metadata value '%s' in key '%s'",
87 sl.metaVal, sl.metaKey))
88 log.Error(err)
89 sl.err = err
90 return nil
91 }
92 if sl.mthdSlice[REQ_METHOD] != br.bindingMethod {
93 err = errors.New(fmt.Sprintf("Binding must occur with method %s but attempted with method %s",
94 br.bindingMethod, sl.mthdSlice[REQ_METHOD]))
95 log.Error(err)
96 sl.err = err
97 return nil
98 }
99 log.Debugf("MUST CREATE A NEW BINDING MAP ENTRY!!")
100 if len(br.bindings) < len(br.bkndClstr.backends) {
101 if *br.curBknd, err = br.bkndClstr.nextBackend(*br.curBknd,BE_SEQ_RR); err == nil {
102 // Use the name of the backend as the metaVal for this new binding
103 br.bindings[(*br.curBknd).name] = *br.curBknd
104 return *br.curBknd
105 } else {
106 log.Error(err)
107 sl.err = err
108 return nil
109 }
110 } else {
111 err = errors.New(fmt.Sprintf("Backends exhausted in attempt to bind for metakey '%s' with value '%s'",
112 sl.metaKey, sl.metaVal))
113 log.Error(err)
114 sl.err = err
115 }
116 }
117 return nil
118 default:
119 return nil
120 }
121 return nil
122}
123
sslobodrcd37bc52019-01-24 11:47:16 -0500124func newBindingRouter(rconf *RouterConfig, config *RouteConfig) (Router, error) {
sslobodr392ebd52019-01-18 12:41:49 -0500125 var rtrn_err bool = false
126 var err error = nil
127 log.Debugf("Creating binding router %s",config.Name)
128 // A name must exist
129 if config.Name == "" {
130 log.Error("A router 'name' must be specified")
131 rtrn_err = true
132 }
133
134 if rconf.ProtoPackage == "" {
135 log.Error("A 'package' must be specified")
136 rtrn_err = true
137 }
138
139 if rconf.ProtoService == "" {
140 log.Error("A 'service' must be specified")
141 rtrn_err = true
142 }
143
144 //if config.RouteField == "" {
145 // log.Error("A 'routing_field' must be specified")
146 // rtrn_err = true
147 //}
148
149 // TODO: Using the specified service, the imported proto
150 // descriptor file should be scanned for all methods provided
151 // for this router to ensure that this field exists in
152 // the message(s) passed to the method. This will avoid run
153 // time failures that might not be detected for long periods
154 // of time.
155
156 // TODO The routes section is currently not being used
157 // so the router will route all methods based on the
158 // routing_field. This needs to be done.
159 var bptr *backend
160 bptr = nil
161 br := BindingRouter{
162 name:config.Name,
163 grpcService:rconf.ProtoService,
164 bindings:make(map[string]*backend),
165 //methodMap:make(map[string]byte),
166 curBknd:&bptr,
167 //serialNo:0,
168 }
169
170 // A binding association must exist
171 br.association = strIndex(rAssnNames, config.Binding.Association)
172 if br.association == 0 {
173 if config.Binding.Association == "" {
174 log.Error("An binding association must be specified")
175 } else {
176 log.Errorf("The binding association '%s' is not valid", config.Binding.Association)
177 }
178 rtrn_err = true
179 }
180 // A binding type must exist
181 // TODO: This is parsed but ignored and a header based type is used.
182 if config.Binding.Type != "header" {
183 log.Error("The binding type must be set to header")
184 rtrn_err = true
185 } else {
186 br.bindingType = config.Binding.Type
187 }
188 // A binding method must exist
189 if config.Binding.Method == "" {
190 log.Error("The binding method must be specified")
191 rtrn_err = true
192 } else {
193 br.bindingMethod = config.Binding.Method
194 }
195 // A binding field must exxist
196 if config.Binding.Field == "" {
197 log.Error("The binding field must be specified")
198 rtrn_err = true
199 } else {
200 br.bindingField = config.Binding.Field
201 }
202
203
204 // This has already been validated bfore this function
205 // is called so just use it.
sslobodr5f0b5a32019-01-24 07:45:19 -0500206 for idx := range rTypeNames {
sslobodr392ebd52019-01-18 12:41:49 -0500207 if config.Type == rTypeNames[idx] {
208 br.routerType = idx
209 break
210 }
211 }
212
213 // Create the backend cluster or link to an existing one
214 ok := true
215 if br.bkndClstr, ok = bClusters[config.backendCluster.Name]; ok == false {
sslobodrcd37bc52019-01-24 11:47:16 -0500216 if br.bkndClstr, err = newBackendCluster(config.backendCluster); err != nil {
sslobodr392ebd52019-01-18 12:41:49 -0500217 log.Errorf("Could not create a backend for router %s", config.Name)
218 rtrn_err = true
219 }
220 }
221
222 // HERE HERE HERE
223
224 if rtrn_err {
225 return br,errors.New(fmt.Sprintf("Failed to create a new router '%s'",br.name))
226 }
227
228
229 return br,nil
230}