1// Copyright 2017 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 validate
16
17import (
18	"github.com/gogo/protobuf/proto"
19
20	"istio.io/istio/mixer/adapter/metadata"
21	"istio.io/istio/mixer/pkg/adapter"
22	"istio.io/istio/mixer/pkg/config/store"
23	runtimeConfig "istio.io/istio/mixer/pkg/runtime/config"
24	"istio.io/istio/mixer/pkg/template"
25	generatedTmplRepo "istio.io/istio/mixer/template"
26	"istio.io/pkg/log"
27)
28
29// validator provides the default structural validation
30type validator struct {
31	kinds  map[string]proto.Message
32	config *runtimeConfig.Ephemeral
33}
34
35// NewValidator creates a default validator which validates the structure through registered
36// kinds and optionally referential integrity and expressions if stateful verification is enabled.
37func NewValidator(adapters map[string]*adapter.Info, templates map[string]*template.Info, stateful bool) store.BackendValidator {
38	out := &validator{
39		kinds: runtimeConfig.KindMap(adapters, templates),
40	}
41	if stateful {
42		out.config = runtimeConfig.NewEphemeral(templates, adapters)
43	}
44	return out
45}
46
47// NewDefaultValidator creates a validator using compiled templates and adapter descriptors.
48// It does not depend on actual handler/builder interfaces from the compiled-in adapters.
49func NewDefaultValidator(stateful bool) store.BackendValidator {
50	info := generatedTmplRepo.SupportedTmplInfo
51	templates := make(map[string]*template.Info, len(info))
52	for k := range info {
53		t := info[k]
54		templates[k] = &t
55	}
56	adapters := metadata.InfoMap()
57	return NewValidator(adapters, templates, stateful)
58}
59
60func (v *validator) Validate(bev *store.BackendEvent) error {
61	_, ok := v.kinds[bev.Key.Kind]
62	if !ok {
63		// Pass unrecognized kinds -- they should be validated by somewhere else.
64		log.Debugf("unrecognized kind %s is requested to validate", bev.Key.Kind)
65		return nil
66	}
67
68	ev, err := store.ConvertValue(*bev, v.kinds)
69	if err != nil {
70		return err
71	}
72
73	// optional deep validation
74	if v.config != nil {
75		v.config.ApplyEvent([]*store.Event{&ev})
76		if _, err = v.config.BuildSnapshot(); err != nil {
77			return err
78		}
79	}
80
81	return nil
82}
83
84func (v *validator) SupportsKind(kind string) bool {
85	_, exists := v.kinds[kind]
86	return exists
87}
88