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  }