This repository has been archived by the owner on Apr 7, 2020. It is now read-only.
forked from istio/istio
/
template.go
267 lines (235 loc) · 10.1 KB
/
template.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
// Copyright 2016 Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package template
import (
"context"
"fmt"
"net"
"github.com/gogo/protobuf/proto"
adptTmpl "istio.io/api/mixer/adapter/model/v1beta1"
pb "istio.io/api/policy/v1beta1"
"istio.io/istio/mixer/pkg/adapter"
"istio.io/istio/mixer/pkg/attribute"
"istio.io/istio/mixer/pkg/lang/ast"
"istio.io/istio/mixer/pkg/lang/compiled"
"istio.io/istio/mixer/pkg/runtime/lang"
)
type (
// Repository defines all the helper functions to access the generated template specific types and fields.
Repository interface {
GetTemplateInfo(template string) (Info, bool)
SupportsTemplate(hndlrBuilder adapter.HandlerBuilder, tmpl string) (bool, string)
}
// TypeEvalFn evaluates an expression and returns the ValueType for the expression.
TypeEvalFn func(string) (pb.ValueType, error)
// InferTypeFn does Type inference from the Instance.params proto message.
InferTypeFn func(proto.Message, TypeEvalFn) (proto.Message, error)
// SetTypeFn dispatches the inferred types to handlers
SetTypeFn func(types map[string]proto.Message, builder adapter.HandlerBuilder)
// BuilderSupportsTemplateFn check if the handlerBuilder supports template.
BuilderSupportsTemplateFn func(hndlrBuilder adapter.HandlerBuilder) bool
// HandlerSupportsTemplateFn check if the handler supports template.
HandlerSupportsTemplateFn func(hndlr adapter.Handler) bool
// DispatchCheckFn dispatches the instance to the handler.
// It may also produce output attributes in the output bag with the given prefix.
DispatchCheckFn func(ctx context.Context, handler adapter.Handler, instance interface{},
out *attribute.MutableBag, outPrefix string) (cr adapter.CheckResult, err error)
// DispatchReportFn dispatches the instances to the handler.
DispatchReportFn func(ctx context.Context, handler adapter.Handler, instances []interface{}) error
// DispatchQuotaFn dispatches the instance to the handler.
DispatchQuotaFn func(ctx context.Context, handler adapter.Handler, instance interface{}, args adapter.QuotaArgs) (adapter.QuotaResult, error)
// DispatchGenerateAttributesFn dispatches the instance object to the attribute generating handler.
DispatchGenerateAttributesFn func(ctx context.Context, handler adapter.Handler, instance interface{},
attrs attribute.Bag, mapper OutputMapperFn) (*attribute.MutableBag, error)
// InstanceBuilderFn builds and returns an instance, based on the attributes supplied.
// Typically, InstanceBuilderFn closes over an auto-generated "builder" struct which contains compiled
// expressions and sub-builders for the instance:
//
// // An InstanceBuilderFn implementation:
// func(attrs attribute.Bag) (interface{}, error) {
// // myInstanceBuilder is an instance of a builder struct that this function closes over (see below).
// return myInstanceBuilder.build(bag)
// }
//
// // myInstanceBuilder is an auto-generated struct for building instances. They get instantiated
// // based on instance parameters (see CreateInstanceBuilderFn documentation):
// type myInstanceBuilder struct {
//
// // field1Builder builds the value of the field field1 of the instance.
// field1Builder compiled.Expression
// ...
// }
//
// func (b *myInstanceBuilder) build(attrs attribute.Bag) (*myInstance, error) {
// ...
// instance := &myInstance{}
//
// // Build the value of field1
// if instance1.field1, err = b.field1Builder.EvaluateString(bag); err != nil {
// return nil, err
// }
// ...
// return instance, nil
//
InstanceBuilderFn func(attrs attribute.Bag) (interface{}, error)
// CreateInstanceBuilderFn returns a function that can build instances, based on the instanceParam:
//
// // A CreateInstanceBuilderFn implementation:
// func(instanceName string, instanceParam interface{}, builder *compiled.ExpressionBuilder) (InstanceBuilderFn, error) {
// // Call an auto-generated function to create a builder struct.
// builder, err := newMyInstanceBuilder(instanceName, instanceParam, builder)
// if err != nil {
// return nil, err
// }
//
// // return an InstanceBuilderfn
// func(attrs attribute.Bag) (interface{}, error) {
// // myInstanceBuilder is an instance of a builder struct that this function closes over (see below).
// return myInstanceBuilder.build(bag)
// }
// }
//
// // Auto-generated method for creating a new builder struct
// func newMyInstanceBuilder(instanceName string, instanceParam interface{}, exprBuilder *compiled.ExpressionBuilder) (*myInstanceBuilder, error) {
// myInstanceParam := instanceParam.(*myInstanceParam)
// builder := &myInstanceBuilder{}
//
// builder.field1Builder, err = exprBuilder.Compile(myInstanceParam.field1Expression)
// if err != nil {
// return nil, err
// }
// }
CreateInstanceBuilderFn func(instanceName string, instanceParam proto.Message, builder lang.Compiler) (InstanceBuilderFn, error)
// CreateOutputExpressionsFn builds and returns a map of attribute names to the expression for calculating them.
//
// // A CreateOutputExpressionsFn implementation:
// func(instanceParam interface{}, finder ast.AttributeDescriptorFinder, builder *compiled.ExpressionBuilder) (map[string]compiled.Expression, error) {
//
// // Convert the generic instanceParam to its specialized type.
// param := instanceParam.(*myInstanceParam)
//
// // Create a mapping of expressions back to the attribute names.
// expressions := make(map[string]compiled.Expression, len(param.AttributeBindings))
// for attrName, outExpr := range param.AttributeBindings {
// // compile an expression and put it in expressions.
// }
//
// return expressions, nil
// }
//
CreateOutputExpressionsFn func(
instanceParam proto.Message,
finder ast.AttributeDescriptorFinder,
expb lang.Compiler) (map[string]compiled.Expression, error)
// OutputMapperFn maps the results of an APA output bag, with "$out"s, by processing it through
// AttributeBindings.
//
// MapperFn: func(attrs attribute.Bag) (*attribute.MutableBag, error) {...}
//
// ProcessGenerateAttributes2Fn(..., attrs attribute.Bag) (*attribute.MutableBag, error) [
// // use instance to call into the handler and get back a bag with "$out" values in it.
// outBag := ...
//
// // Call an OutputMapperFn to map "$out.<name>" parameters to actual attribute values
// resultBag := MapperFn(outBag)
// return resultBag, nil
// }
OutputMapperFn func(attrs attribute.Bag) (*attribute.MutableBag, error)
// Info contains all the information related a template like
// Default instance params, type inference method etc.
Info struct {
Name string
Impl string
Variety adptTmpl.TemplateVariety
BldrInterfaceName string
HndlrInterfaceName string
CtrCfg proto.Message
InferType InferTypeFn
SetType SetTypeFn
BuilderSupportsTemplate BuilderSupportsTemplateFn
HandlerSupportsTemplate HandlerSupportsTemplateFn
AttributeManifests []*pb.AttributeManifest
DispatchReport DispatchReportFn
DispatchCheck DispatchCheckFn
DispatchQuota DispatchQuotaFn
DispatchGenAttrs DispatchGenerateAttributesFn
CreateInstanceBuilder CreateInstanceBuilderFn
CreateOutputExpressions CreateOutputExpressionsFn
}
// templateRepo implements Repository
repo struct {
info map[string]Info
allSupportedTmpls []string
tmplToBuilderNames map[string]string
}
)
func (t repo) GetTemplateInfo(template string) (Info, bool) {
if v, ok := t.info[template]; ok {
return v, true
}
return Info{}, false
}
// NewRepository returns an implementation of Repository
func NewRepository(templateInfos map[string]Info) Repository {
if templateInfos == nil {
return repo{
info: make(map[string]Info),
allSupportedTmpls: make([]string, 0),
tmplToBuilderNames: make(map[string]string),
}
}
allSupportedTmpls := make([]string, len(templateInfos))
tmplToBuilderNames := make(map[string]string)
for t, v := range templateInfos {
allSupportedTmpls = append(allSupportedTmpls, t)
tmplToBuilderNames[t] = v.BldrInterfaceName
}
return repo{info: templateInfos, tmplToBuilderNames: tmplToBuilderNames, allSupportedTmpls: allSupportedTmpls}
}
func (t repo) SupportsTemplate(hndlrBuilder adapter.HandlerBuilder, tmpl string) (bool, string) {
i, ok := t.GetTemplateInfo(tmpl)
if !ok {
return false, fmt.Sprintf("Supported template %v is not one of the allowed supported templates %v", tmpl, t.allSupportedTmpls)
}
if b := i.BuilderSupportsTemplate(hndlrBuilder); !b {
return false, fmt.Sprintf("HandlerBuilder does not implement interface %s. "+
"Therefore, it cannot support template %v", t.tmplToBuilderNames[tmpl], tmpl)
}
return true, ""
}
// NewOutputMapperFn creates and returns a function that creates new attributes, based on the supplied expression set.
func NewOutputMapperFn(expressions map[string]compiled.Expression) OutputMapperFn {
return func(attrs attribute.Bag) (*attribute.MutableBag, error) {
var val interface{}
var err error
resultBag := attribute.GetMutableBag(nil)
for attrName, expr := range expressions {
if val, err = expr.Evaluate(attrs); err != nil {
return nil, err
}
switch v := val.(type) {
case net.IP:
// conversion to []byte necessary based on current IP_ADDRESS handling within Mixer
if v4 := v.To4(); v4 != nil {
resultBag.Set(attrName, []byte(v4))
continue
}
resultBag.Set(attrName, []byte(v.To16()))
default:
resultBag.Set(attrName, val)
}
}
return resultBag, nil
}
}