blob: e6563989cf2865bde072bb6583c0bcf7171d226c [file] [log] [blame]
Scott Bakere7144bc2019-10-01 14:16:47 -07001/*
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
17package afrouter
18
19import (
20 "errors"
21 "fmt"
22 "github.com/opencord/voltha-go/common/log"
23 "google.golang.org/grpc"
24 "google.golang.org/grpc/metadata"
25)
26
27type BindingRouter struct {
28 name string
29 association associationType
30 //routingField string
31 grpcService string
32 //protoDescriptor *pb.FileDescriptorSet
33 //methodMap map[string]byte
34 beCluster *cluster
35 bindings map[string]*backend
36 bindingType string
37 bindingField string
38 bindingMethod string
39 currentBackend **backend
40}
41
42func (br BindingRouter) IsStreaming(_ string) (bool, bool) {
43 panic("not implemented")
44}
45
46func (br BindingRouter) BackendCluster(s string, metaKey string) (*cluster, error) {
47 return br.beCluster, nil
48 //return nil,errors.New("Not implemented yet")
49}
50func (br BindingRouter) Name() string {
51 return br.name
52}
53func (br BindingRouter) Service() string {
54 return br.grpcService
55}
56func (br BindingRouter) GetMetaKeyVal(serverStream grpc.ServerStream) (string, string, error) {
57 var rtrnK = ""
58 var rtrnV = ""
59
60 // Get the metadata from the server stream
61 md, ok := metadata.FromIncomingContext(serverStream.Context())
62 if !ok {
63 return rtrnK, rtrnV, errors.New("Could not get a server stream metadata")
64 }
65
66 // Determine if one of the method routing keys exists in the metadata
Scott Baker4989fe92019-10-09 17:03:06 -070067 if _, ok := md[br.bindingField]; ok {
Scott Bakere7144bc2019-10-01 14:16:47 -070068 rtrnV = md[br.bindingField][0]
69 rtrnK = br.bindingField
70 }
71
72 return rtrnK, rtrnV, nil
73}
74func (br BindingRouter) FindBackendCluster(becName string) *cluster {
75 if becName == br.beCluster.name {
76 return br.beCluster
77 }
78 return nil
79}
80func (br BindingRouter) ReplyHandler(v interface{}) error {
81 return nil
82}
83func (br BindingRouter) Route(sel interface{}) (*backend, *connection) {
84 var err error
85 switch sl := sel.(type) {
86 case *requestFrame:
Scott Baker4989fe92019-10-09 17:03:06 -070087 if b, ok := br.bindings[sl.metaVal]; ok { // binding exists, just return it
Scott Bakere7144bc2019-10-01 14:16:47 -070088 return b, nil
89 } else { // establish a new binding or error.
90 if sl.metaVal != "" {
Scott Baker4989fe92019-10-09 17:03:06 -070091 err = fmt.Errorf("Attempt to route on non-existent metadata value '%s' in key '%s'",
92 sl.metaVal, sl.metaKey)
Scott Bakere7144bc2019-10-01 14:16:47 -070093 log.Error(err)
94 sl.err = err
95 return nil, nil
96 }
97 if sl.methodInfo.method != br.bindingMethod {
Scott Baker4989fe92019-10-09 17:03:06 -070098 err = fmt.Errorf("Binding must occur with method %s but attempted with method %s",
99 br.bindingMethod, sl.methodInfo.method)
Scott Bakere7144bc2019-10-01 14:16:47 -0700100 log.Error(err)
101 sl.err = err
102 return nil, nil
103 }
104 log.Debugf("MUST CREATE A NEW BINDING MAP ENTRY!!")
105 if *br.currentBackend, err = br.beCluster.nextBackend(*br.currentBackend, BackendSequenceRoundRobin); err == nil {
106 // Use the name of the backend as the metaVal for this new binding
107 br.bindings[(*br.currentBackend).name] = *br.currentBackend
108 return *br.currentBackend, nil
109
110 } else {
111 log.Error(err)
112 sl.err = err
113 return nil, nil
114 }
115 }
116 default:
117 return nil, nil
118 }
119}
120
121func newBindingRouter(rconf *RouterConfig, config *RouteConfig) (Router, error) {
122 var rtrn_err = false
Scott Baker4989fe92019-10-09 17:03:06 -0700123 var err error
Scott Bakere7144bc2019-10-01 14:16:47 -0700124 log.Debugf("Creating binding router %s", config.Name)
125 // A name must exist
126 if config.Name == "" {
127 log.Error("A router 'name' must be specified")
128 rtrn_err = true
129 }
130
131 if rconf.ProtoPackage == "" {
132 log.Error("A 'package' must be specified")
133 rtrn_err = true
134 }
135
136 if rconf.ProtoService == "" {
137 log.Error("A 'service' must be specified")
138 rtrn_err = true
139 }
140
141 //if config.RouteField == "" {
142 // log.Error("A 'routing_field' must be specified")
143 // rtrn_err = true
144 //}
145
146 // TODO: Using the specified service, the imported proto
147 // descriptor file should be scanned for all methods provided
148 // for this router to ensure that this field exists in
149 // the message(s) passed to the method. This will avoid run
150 // time failures that might not be detected for long periods
151 // of time.
152
153 // TODO The routes section is currently not being used
154 // so the router will route all methods based on the
155 // routing_field. This needs to be done.
156 var bptr *backend
Scott Bakere7144bc2019-10-01 14:16:47 -0700157 br := BindingRouter{
158 name: config.Name,
159 grpcService: rconf.ProtoService,
160 bindings: make(map[string]*backend),
161 //methodMap:make(map[string]byte),
162 currentBackend: &bptr,
163 }
164
165 // A binding association must exist
166 br.association = config.Binding.Association
167 if br.association == AssociationUndefined {
168 log.Error("An binding association must be specified")
169 rtrn_err = true
170 }
171 // A binding type must exist
172 // TODO: This is parsed but ignored and a header based type is used.
173 if config.Binding.Type != "header" {
174 log.Error("The binding type must be set to header")
175 rtrn_err = true
176 } else {
177 br.bindingType = config.Binding.Type
178 }
179 // A binding method must exist
180 if config.Binding.Method == "" {
181 log.Error("The binding method must be specified")
182 rtrn_err = true
183 } else {
184 br.bindingMethod = config.Binding.Method
185 }
186 // A binding field must exxist
187 if config.Binding.Field == "" {
188 log.Error("The binding field must be specified")
189 rtrn_err = true
190 } else {
191 br.bindingField = config.Binding.Field
192 }
193
194 // Create the backend cluster or link to an existing one
Scott Baker4989fe92019-10-09 17:03:06 -0700195 var ok bool
196 if br.beCluster, ok = clusters[config.backendCluster.Name]; !ok {
Scott Bakere7144bc2019-10-01 14:16:47 -0700197 if br.beCluster, err = newBackendCluster(config.backendCluster); err != nil {
198 log.Errorf("Could not create a backend for router %s", config.Name)
199 rtrn_err = true
200 }
201 }
202
203 // HERE HERE HERE
204
205 if rtrn_err {
Scott Baker4989fe92019-10-09 17:03:06 -0700206 return br, fmt.Errorf("Failed to create a new router '%s'", br.name)
Scott Bakere7144bc2019-10-01 14:16:47 -0700207 }
208
209 return br, nil
210}