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 }