1// Copyright 2018 Istio Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package routing
16
17import (
18	tpb "istio.io/api/mixer/adapter/model/v1beta1"
19	descriptor "istio.io/api/policy/v1beta1"
20	"istio.io/istio/mixer/pkg/adapter"
21	"istio.io/istio/mixer/pkg/attribute"
22	"istio.io/istio/mixer/pkg/lang/compiled"
23	"istio.io/istio/mixer/pkg/template"
24	"istio.io/pkg/log"
25)
26
27// Table is the main routing table. It is used to find the set of handlers that should be invoked, along with the
28// instance builders and match conditions.
29type Table struct {
30
31	// id of this table. This is based on the config snapshot id. IDs are unique within the life-span of a Mixer instance.
32	id int64
33
34	// namespaceTables grouped by variety.
35	// Note that CHECK_WITH_OUTPUT templates are placed into CHECK variety group.
36	entries map[tpb.TemplateVariety]*varietyTable
37
38	debugInfo *tableDebugInfo
39}
40
41// varietyTable contains destination sets for a given template variety. It contains a mapping from namespaces
42// to a flattened list of destinations. It also contains the defaultSet, which gets returned if no namespace-specific
43// destination entry is found.
44type varietyTable struct {
45	// destinations grouped by namespace. These contain destinations from the default namespace as well.
46	entries map[string]*NamespaceTable
47
48	// destinations for default namespace
49	defaultSet *NamespaceTable
50}
51
52// NamespaceTable contains a list of destinations and directives that should be targeted for a given namespace.
53type NamespaceTable struct {
54	entries    []*Destination
55	directives []*DirectiveGroup
56}
57
58var emptyDestinations = &NamespaceTable{}
59
60// Destination contains a target handler, and instances to send, grouped by the conditional match that applies to them.
61type Destination struct {
62	// id of the entry. IDs are reused every time a table is recreated. Used for debugging.
63	id uint32
64
65	// Handler to invoke
66	Handler adapter.Handler
67
68	// HandlerName is the name of the handler. Used for monitoring/logging purposes.
69	HandlerName string
70
71	// AdapterName is the name of the adapter. Used for monitoring/logging purposes.
72	AdapterName string
73
74	// Template of the handler.
75	Template *TemplateInfo
76
77	// InstanceGroups that should be (conditionally) applied to the handler.
78	InstanceGroups []*InstanceGroup
79
80	// Maximum number of instances that can be created from this entry.
81	maxInstances int
82
83	// FriendlyName is the friendly name of this configured handler entry. Used for monitoring/logging purposes.
84	FriendlyName string
85}
86
87// DirectiveGroup is a group of route directive expressions with a condition.
88// Directive expressions reference destination action names.
89// Note that InstanceGroup organizes by handlers, rather than rules, which necessitates
90// a different grouping for directives.
91type DirectiveGroup struct {
92	Condition  compiled.Expression
93	Operations []*HeaderOperation
94}
95
96// HeaderOperationType is an enumeration for the route directive header operation template type.
97type HeaderOperationType int
98
99// Request and response header operation types.
100const (
101	RequestHeaderOperation HeaderOperationType = iota
102	ResponseHeaderOperation
103)
104
105// HeaderOperation is an intermediate form of a rule header operation.
106type HeaderOperation struct {
107	Type        HeaderOperationType
108	HeaderName  string
109	HeaderValue compiled.Expression
110	Operation   descriptor.Rule_HeaderOperationTemplate_Operation
111}
112
113// NamedBuilder holds a builder function and the short name of the associated instance.
114type NamedBuilder struct {
115	InstanceShortName string
116	Builder           template.InstanceBuilderFn
117
118	// ActionName is the action name in the rule, used to reference the output of the handler applied to the instance
119	ActionName string
120}
121
122// TemplateInfo is the common data that is needed from a template
123type TemplateInfo struct {
124	Name             string
125	Variety          tpb.TemplateVariety
126	DispatchReport   template.DispatchReportFn
127	DispatchCheck    template.DispatchCheckFn
128	DispatchQuota    template.DispatchQuotaFn
129	DispatchGenAttrs template.DispatchGenerateAttributesFn
130}
131
132func buildTemplateInfo(info *template.Info) *TemplateInfo {
133	return &TemplateInfo{
134		Name:             info.Name,
135		Variety:          info.Variety,
136		DispatchReport:   info.DispatchReport,
137		DispatchCheck:    info.DispatchCheck,
138		DispatchQuota:    info.DispatchQuota,
139		DispatchGenAttrs: info.DispatchGenAttrs,
140	}
141}
142
143// InstanceGroup is a set of instances that needs to be sent to a handler, grouped by a condition expression.
144type InstanceGroup struct {
145	// id of the InstanceGroup. IDs are reused every time a table is recreated. Used for debugging.
146	id uint32
147
148	// Condition for applying this instance group.
149	Condition compiled.Expression
150
151	// Builders for the instances in this group for each instance that should be applied.
152	Builders []NamedBuilder
153
154	// Mappers for attribute-generating adapters that map output attributes into the main attribute set.
155	Mappers []template.OutputMapperFn
156}
157
158var emptyTable = &Table{id: -1}
159
160// Empty returns an empty routing table.
161func Empty() *Table {
162	return emptyTable
163}
164
165// ID of the table. Based on the Config Snapshot id.
166func (t *Table) ID() int64 {
167	return t.id
168}
169
170// GetDestinations returns the set of destinations (handlers) for the given template variety and for the given namespace.
171// CHECK_WITH_OUTPUT variety destinations are grouped together with CHECK variety destinations.
172func (t *Table) GetDestinations(variety tpb.TemplateVariety, namespace string) *NamespaceTable {
173	destinations, ok := t.entries[variety]
174	if !ok {
175		log.Debugf("No destinations found for variety: table='%d', variety='%d'", t.id, variety)
176
177		return emptyDestinations
178	}
179
180	destinationSet := destinations.entries[namespace]
181	if destinationSet == nil {
182		log.Debugf("no rules for namespace, using defaults: table='%d', variety='%d', ns='%s'", t.id, variety, namespace)
183		destinationSet = destinations.defaultSet
184	}
185
186	return destinationSet
187}
188
189// Count returns the number of entries contained.
190func (d *NamespaceTable) Count() int {
191	return len(d.entries)
192}
193
194// Entries in the table.
195func (d *NamespaceTable) Entries() []*Destination {
196	return d.entries
197}
198
199// Directives in the table
200func (d *NamespaceTable) Directives() []*DirectiveGroup {
201	return d.directives
202}
203
204// MaxInstances returns the maximum number of instances that can be built from this Destination.
205func (d *Destination) MaxInstances() int {
206	return d.maxInstances
207}
208
209// used during building to recalculate maxInstances, after a modification.
210func (d *Destination) recalculateMaxInstances() {
211	c := 0
212	for _, input := range d.InstanceGroups {
213		c += len(input.Builders)
214	}
215
216	d.maxInstances = c
217}
218
219// Matches returns true, if the instances from this input set should be used for the given attribute bag.
220func (i *InstanceGroup) Matches(bag attribute.Bag) bool {
221	if i.Condition == nil {
222		return true
223	}
224
225	matches, err := i.Condition.EvaluateBoolean(bag)
226	if err != nil {
227		log.Warnf("input set condition evaluation error: id='%d', error='%v'", i.id, err)
228		return false
229	}
230
231	return matches
232}
233