1// Copyright 2019 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 rt 16 17import ( 18 "context" 19 "encoding/json" 20 "fmt" 21 22 "github.com/gogo/protobuf/proto" 23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 25 "k8s.io/apimachinery/pkg/runtime" 26 "k8s.io/apimachinery/pkg/watch" 27 "k8s.io/client-go/tools/cache" 28 29 "istio.io/istio/galley/pkg/config/util/pb" 30 "istio.io/istio/pkg/config/schema/resource" 31) 32 33func (p *Provider) getDynamicAdapter(r resource.Schema) *Adapter { 34 return &Adapter{ 35 extractObject: func(o interface{}) metav1.Object { 36 res, ok := o.(*unstructured.Unstructured) 37 if !ok { 38 return nil 39 } 40 return res 41 }, 42 43 extractResource: func(o interface{}) (proto.Message, error) { 44 u, ok := o.(*unstructured.Unstructured) 45 if !ok { 46 return nil, fmt.Errorf("extractResource: not unstructured: %v", o) 47 } 48 49 pr := r.MustNewProtoInstance() 50 if err := pb.UnmarshalData(pr, u.Object["spec"]); err != nil { 51 return nil, err 52 } 53 54 return pr, nil 55 }, 56 57 newInformer: func() (cache.SharedIndexInformer, error) { 58 d, err := p.GetDynamicResourceInterface(r) 59 if err != nil { 60 return nil, err 61 } 62 63 return cache.NewSharedIndexInformer( 64 &cache.ListWatch{ 65 ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { 66 return d.List(context.TODO(), options) 67 }, 68 WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { 69 options.Watch = true 70 return d.Watch(context.TODO(), options) 71 }, 72 }, 73 &unstructured.Unstructured{}, 74 p.resyncPeriod, 75 cache.Indexers{}), nil 76 }, 77 78 parseJSON: func(data []byte) (interface{}, error) { 79 u := &unstructured.Unstructured{} 80 if err := json.Unmarshal(data, u); err != nil { 81 return nil, fmt.Errorf("failed marshaling into unstructured: %v", err) 82 } 83 84 if empty(u) { 85 return nil, nil 86 } 87 88 return u, nil 89 }, 90 getStatus: func(o interface{}) interface{} { 91 u, ok := o.(*unstructured.Unstructured) 92 if !ok { 93 return nil 94 } 95 return u.Object["status"] 96 }, 97 isEqual: resourceVersionsMatch, 98 isBuiltIn: false, 99 } 100} 101 102// Check if the parsed resource is empty 103func empty(r *unstructured.Unstructured) bool { 104 if r.Object == nil || len(r.Object) == 0 { 105 return true 106 } 107 return false 108} 109