1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package cache
17
18 import (
19 "errors"
20 "fmt"
21 "time"
22
23 "github.com/datawire/ambassador/v2/pkg/envoy-control-plane/cache/types"
24 )
25
26
27 type Resources struct {
28
29 Version string
30
31
32 Items map[string]types.ResourceWithTtl
33 }
34
35
36 func IndexResourcesByName(items []types.ResourceWithTtl) map[string]types.ResourceWithTtl {
37 indexed := make(map[string]types.ResourceWithTtl)
38 for _, item := range items {
39 indexed[GetResourceName(item.Resource)] = item
40 }
41 return indexed
42 }
43
44
45 func NewResources(version string, items []types.Resource) Resources {
46 itemsWithTtl := []types.ResourceWithTtl{}
47 for _, item := range items {
48 itemsWithTtl = append(itemsWithTtl, types.ResourceWithTtl{Resource: item})
49 }
50 return NewResourcesWithTtl(version, itemsWithTtl)
51 }
52
53
54 func NewResourcesWithTtl(version string, items []types.ResourceWithTtl) Resources {
55 return Resources{
56 Version: version,
57 Items: IndexResourcesByName(items),
58 }
59 }
60
61
62
63
64 type Snapshot struct {
65 Resources [types.UnknownType]Resources
66 }
67
68
69 func NewSnapshot(version string,
70 endpoints []types.Resource,
71 clusters []types.Resource,
72 routes []types.Resource,
73 listeners []types.Resource,
74 runtimes []types.Resource,
75 secrets []types.Resource) Snapshot {
76 return NewSnapshotWithResources(version, SnapshotResources{
77 Endpoints: endpoints,
78 Clusters: clusters,
79 Routes: routes,
80 Listeners: listeners,
81 Runtimes: runtimes,
82 Secrets: secrets,
83 })
84 }
85
86
87 type SnapshotResources struct {
88 Endpoints []types.Resource
89 Clusters []types.Resource
90 Routes []types.Resource
91 Listeners []types.Resource
92 Runtimes []types.Resource
93 Secrets []types.Resource
94 ExtensionConfigs []types.Resource
95 }
96
97
98 func NewSnapshotWithResources(version string, resources SnapshotResources) Snapshot {
99 out := Snapshot{}
100 out.Resources[types.Endpoint] = NewResources(version, resources.Endpoints)
101 out.Resources[types.Cluster] = NewResources(version, resources.Clusters)
102 out.Resources[types.Route] = NewResources(version, resources.Routes)
103 out.Resources[types.Listener] = NewResources(version, resources.Listeners)
104 out.Resources[types.Runtime] = NewResources(version, resources.Runtimes)
105 out.Resources[types.Secret] = NewResources(version, resources.Secrets)
106 out.Resources[types.ExtensionConfig] = NewResources(version, resources.ExtensionConfigs)
107 return out
108 }
109
110 type ResourceWithTtl struct {
111 Resources []types.Resource
112 Ttl *time.Duration
113 }
114
115 func NewSnapshotWithTtls(version string,
116 endpoints []types.ResourceWithTtl,
117 clusters []types.ResourceWithTtl,
118 routes []types.ResourceWithTtl,
119 listeners []types.ResourceWithTtl,
120 runtimes []types.ResourceWithTtl,
121 secrets []types.ResourceWithTtl) Snapshot {
122 out := Snapshot{}
123 out.Resources[types.Endpoint] = NewResourcesWithTtl(version, endpoints)
124 out.Resources[types.Cluster] = NewResourcesWithTtl(version, clusters)
125 out.Resources[types.Route] = NewResourcesWithTtl(version, routes)
126 out.Resources[types.Listener] = NewResourcesWithTtl(version, listeners)
127 out.Resources[types.Runtime] = NewResourcesWithTtl(version, runtimes)
128 out.Resources[types.Secret] = NewResourcesWithTtl(version, secrets)
129 return out
130 }
131
132
133
134
135
136
137
138
139
140 func (s *Snapshot) Consistent() error {
141 if s == nil {
142 return errors.New("nil snapshot")
143 }
144 endpoints := GetResourceReferences(s.Resources[types.Cluster].Items)
145 if len(endpoints) != len(s.Resources[types.Endpoint].Items) {
146 return fmt.Errorf("mismatched endpoint reference and resource lengths: %v != %d", endpoints, len(s.Resources[types.Endpoint].Items))
147 }
148 if err := superset(endpoints, s.Resources[types.Endpoint].Items); err != nil {
149 return err
150 }
151
152 routes := GetResourceReferences(s.Resources[types.Listener].Items)
153 if len(routes) != len(s.Resources[types.Route].Items) {
154 return fmt.Errorf("mismatched route reference and resource lengths: %v != %d", routes, len(s.Resources[types.Route].Items))
155 }
156 return superset(routes, s.Resources[types.Route].Items)
157 }
158
159
160 func (s *Snapshot) GetResources(typeURL string) map[string]types.Resource {
161 resources := s.GetResourcesAndTtl(typeURL)
162 if resources == nil {
163 return nil
164 }
165
166 withoutTtl := make(map[string]types.Resource, len(resources))
167
168 for k, v := range resources {
169 withoutTtl[k] = v.Resource
170 }
171
172 return withoutTtl
173 }
174
175
176 func (s *Snapshot) GetResourcesAndTtl(typeURL string) map[string]types.ResourceWithTtl {
177 if s == nil {
178 return nil
179 }
180 typ := GetResponseType(typeURL)
181 if typ == types.UnknownType {
182 return nil
183 }
184 return s.Resources[typ].Items
185 }
186
187
188 func (s *Snapshot) GetVersion(typeURL string) string {
189 if s == nil {
190 return ""
191 }
192 typ := GetResponseType(typeURL)
193 if typ == types.UnknownType {
194 return ""
195 }
196 return s.Resources[typ].Version
197 }
198
View as plain text