github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/go-control-plane/pkg/cache/v3/snapshot.go (about)

     1  // Copyright 2018 Envoyproxy 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 cache
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  
    21  	"github.com/hxx258456/ccgo/go-control-plane/pkg/cache/types"
    22  	"github.com/hxx258456/ccgo/go-control-plane/pkg/resource/v3"
    23  )
    24  
    25  // Snapshot is an internally consistent snapshot of xDS resources.
    26  // Consistency is important for the convergence as different resource types
    27  // from the snapshot may be delivered to the proxy in arbitrary order.
    28  type Snapshot struct {
    29  	Resources [types.UnknownType]Resources
    30  
    31  	// VersionMap holds the current hash map of all resources in the snapshot.
    32  	// This field should remain nil until it is used, at which point should be
    33  	// instantiated by calling ConstructVersionMap().
    34  	// VersionMap is only to be used with delta xDS.
    35  	VersionMap map[string]map[string]string
    36  }
    37  
    38  // NewSnapshot creates a snapshot from response types and a version.
    39  // The resources map is keyed off the type URL of a resource, followed by the slice of resource objects.
    40  func NewSnapshot(version string, resources map[resource.Type][]types.Resource) (Snapshot, error) {
    41  	out := Snapshot{}
    42  
    43  	for typ, resource := range resources {
    44  		index := GetResponseType(typ)
    45  		if index == types.UnknownType {
    46  			return out, errors.New("unknown resource type: " + typ)
    47  		}
    48  
    49  		out.Resources[index] = NewResources(version, resource)
    50  	}
    51  
    52  	return out, nil
    53  }
    54  
    55  // NewSnapshotWithTTLs creates a snapshot of ResourceWithTTLs.
    56  // The resources map is keyed off the type URL of a resource, followed by the slice of resource objects.
    57  func NewSnapshotWithTTLs(version string, resources map[resource.Type][]types.ResourceWithTTL) (Snapshot, error) {
    58  	out := Snapshot{}
    59  
    60  	for typ, resource := range resources {
    61  		index := GetResponseType(typ)
    62  		if index == types.UnknownType {
    63  			return out, errors.New("unknown resource type: " + typ)
    64  		}
    65  
    66  		out.Resources[index] = NewResourcesWithTTL(version, resource)
    67  	}
    68  
    69  	return out, nil
    70  }
    71  
    72  // Consistent check verifies that the dependent resources are exactly listed in the
    73  // snapshot:
    74  // - all EDS resources are listed by name in CDS resources
    75  // - all RDS resources are listed by name in LDS resources
    76  //
    77  // Note that clusters and listeners are requested without name references, so
    78  // Envoy will accept the snapshot list of clusters as-is even if it does not match
    79  // all references found in xDS.
    80  func (s *Snapshot) Consistent() error {
    81  	if s == nil {
    82  		return errors.New("nil snapshot")
    83  	}
    84  	endpoints := GetResourceReferences(s.Resources[types.Cluster].Items)
    85  	if len(endpoints) != len(s.Resources[types.Endpoint].Items) {
    86  		return fmt.Errorf("mismatched endpoint reference and resource lengths: %v != %d", endpoints, len(s.Resources[types.Endpoint].Items))
    87  	}
    88  	if err := superset(endpoints, s.Resources[types.Endpoint].Items); err != nil {
    89  		return err
    90  	}
    91  
    92  	routes := GetResourceReferences(s.Resources[types.Listener].Items)
    93  	if len(routes) != len(s.Resources[types.Route].Items) {
    94  		return fmt.Errorf("mismatched route reference and resource lengths: %v != %d", routes, len(s.Resources[types.Route].Items))
    95  	}
    96  	return superset(routes, s.Resources[types.Route].Items)
    97  }
    98  
    99  // GetResources selects snapshot resources by type, returning the map of resources.
   100  func (s *Snapshot) GetResources(typeURL resource.Type) map[string]types.Resource {
   101  	resources := s.GetResourcesAndTTL(typeURL)
   102  	if resources == nil {
   103  		return nil
   104  	}
   105  
   106  	withoutTTL := make(map[string]types.Resource, len(resources))
   107  
   108  	for k, v := range resources {
   109  		withoutTTL[k] = v.Resource
   110  	}
   111  
   112  	return withoutTTL
   113  }
   114  
   115  // GetResourcesAndTTL selects snapshot resources by type, returning the map of resources and the associated TTL.
   116  func (s *Snapshot) GetResourcesAndTTL(typeURL resource.Type) map[string]types.ResourceWithTTL {
   117  	if s == nil {
   118  		return nil
   119  	}
   120  	typ := GetResponseType(typeURL)
   121  	if typ == types.UnknownType {
   122  		return nil
   123  	}
   124  	return s.Resources[typ].Items
   125  }
   126  
   127  // GetVersion returns the version for a resource type.
   128  func (s *Snapshot) GetVersion(typeURL resource.Type) string {
   129  	if s == nil {
   130  		return ""
   131  	}
   132  	typ := GetResponseType(typeURL)
   133  	if typ == types.UnknownType {
   134  		return ""
   135  	}
   136  	return s.Resources[typ].Version
   137  }
   138  
   139  // GetVersionMap will return the internal version map of the currently applied snapshot.
   140  func (s *Snapshot) GetVersionMap(typeUrl string) map[string]string {
   141  	return s.VersionMap[typeUrl]
   142  }
   143  
   144  // ConstructVersionMap will construct a version map based on the current state of a snapshot
   145  func (s *Snapshot) ConstructVersionMap() error {
   146  	if s == nil {
   147  		return fmt.Errorf("missing snapshot")
   148  	}
   149  
   150  	// The snapshot resources never change, so no need to ever rebuild.
   151  	if s.VersionMap != nil {
   152  		return nil
   153  	}
   154  
   155  	s.VersionMap = make(map[string]map[string]string)
   156  
   157  	for i, resources := range s.Resources {
   158  		typeURL, err := GetResponseTypeURL(types.ResponseType(i))
   159  		if err != nil {
   160  			return err
   161  		}
   162  		if _, ok := s.VersionMap[typeURL]; !ok {
   163  			s.VersionMap[typeURL] = make(map[string]string)
   164  		}
   165  
   166  		for _, r := range resources.Items {
   167  			// Hash our version in here and build the version map.
   168  			marshaledResource, err := MarshalResource(r.Resource)
   169  			if err != nil {
   170  				return err
   171  			}
   172  			v := HashResource(marshaledResource)
   173  			if v == "" {
   174  				return fmt.Errorf("failed to build resource version: %v", err)
   175  			}
   176  
   177  			s.VersionMap[typeURL][GetResourceName(r.Resource)] = v
   178  		}
   179  	}
   180  
   181  	return nil
   182  }