istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/config/monitor/file_snapshot.go (about) 1 // Copyright 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 15 package monitor 16 17 import ( 18 "os" 19 "path/filepath" 20 "sort" 21 22 "istio.io/istio/pilot/pkg/config/kube/crd" 23 "istio.io/istio/pkg/config" 24 "istio.io/istio/pkg/config/schema/collection" 25 "istio.io/istio/pkg/config/schema/collections" 26 ) 27 28 var supportedExtensions = map[string]bool{ 29 ".yaml": true, 30 ".yml": true, 31 } 32 33 // FileSnapshot holds a reference to a file directory that contains crd 34 // config and filter criteria for which of those configs will be parsed. 35 type FileSnapshot struct { 36 root string 37 domainSuffix string 38 configTypeFilter map[config.GroupVersionKind]bool 39 } 40 41 // NewFileSnapshot returns a snapshotter. 42 // If no types are provided in the descriptor, all Istio types will be allowed. 43 func NewFileSnapshot(root string, schemas collection.Schemas, domainSuffix string) *FileSnapshot { 44 snapshot := &FileSnapshot{ 45 root: root, 46 domainSuffix: domainSuffix, 47 configTypeFilter: make(map[config.GroupVersionKind]bool), 48 } 49 50 ss := schemas.All() 51 if len(ss) == 0 { 52 ss = collections.Pilot.All() 53 } 54 55 for _, k := range ss { 56 if _, ok := collections.Pilot.FindByGroupVersionKind(k.GroupVersionKind()); ok { 57 snapshot.configTypeFilter[k.GroupVersionKind()] = true 58 } 59 } 60 61 return snapshot 62 } 63 64 // ReadConfigFiles parses files in the root directory and returns a sorted slice of 65 // eligible model.Config. This can be used as a configFunc when creating a Monitor. 66 func (f *FileSnapshot) ReadConfigFiles() ([]*config.Config, error) { 67 var result []*config.Config 68 69 err := filepath.Walk(f.root, func(path string, info os.FileInfo, err error) error { 70 if err != nil { 71 return err 72 } else if !supportedExtensions[filepath.Ext(path)] || (info.Mode()&os.ModeType) != 0 { 73 return nil 74 } 75 data, err := os.ReadFile(path) 76 if err != nil { 77 log.Warnf("Failed to read %s: %v", path, err) 78 return err 79 } 80 configs, err := parseInputs(data, f.domainSuffix) 81 if err != nil { 82 log.Warnf("Failed to parse %s: %v", path, err) 83 return err 84 } 85 86 // Filter any unsupported types before appending to the result. 87 for _, cfg := range configs { 88 if !f.configTypeFilter[cfg.GroupVersionKind] { 89 continue 90 } 91 result = append(result, cfg) 92 } 93 return nil 94 }) 95 if err != nil { 96 log.Warnf("failure during filepath.Walk: %v", err) 97 } 98 99 // Sort by the config IDs. 100 sort.Sort(byKey(result)) 101 return result, err 102 } 103 104 // parseInputs is identical to crd.ParseInputs, except that it returns an array of config pointers. 105 func parseInputs(data []byte, domainSuffix string) ([]*config.Config, error) { 106 configs, _, err := crd.ParseInputs(string(data)) 107 108 // Convert to an array of pointers. 109 refs := make([]*config.Config, len(configs)) 110 for i := range configs { 111 refs[i] = &configs[i] 112 refs[i].Domain = domainSuffix 113 } 114 return refs, err 115 } 116 117 // byKey is an array of config objects that is capable or sorting by Namespace, GroupVersionKind, and Name. 118 type byKey []*config.Config 119 120 func (rs byKey) Len() int { 121 return len(rs) 122 } 123 124 func (rs byKey) Swap(i, j int) { 125 rs[i], rs[j] = rs[j], rs[i] 126 } 127 128 func (rs byKey) Less(i, j int) bool { 129 return compareIDs(rs[i], rs[j]) < 0 130 }