Skip to content

Commit f22e9c9

Browse files
authored
Endpoint Discovery (#484)
* internal/ini: Update INI parser's error message. * aws/crr: Support for Endpoint Discovery Caching * aws: Add aws.Config option for enabling endpoint discovery * aws/external: Add configuration resolver for configuring endpoint discovery * private/model/api: Code Generation for Endpoint Discovery * aws/external: Add code generation tool for generating provider assertions
1 parent dac592f commit f22e9c9

File tree

102 files changed

+4643
-32
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+4643
-32
lines changed

Makefile

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ all: generate unit
2626
###################
2727
# Code Generation #
2828
###################
29-
generate: cleanup-models gen-test gen-endpoints gen-services gen-tools
29+
generate: cleanup-models gen-test gen-endpoints gen-services gen-external-asserts gen-tools
3030

31-
gen-test: gen-protocol-test
32-
#gen-test: gen-protocol-test gen-codegen-test
31+
gen-test: gen-protocol-test gen-codegen-test
3332

3433
#gen-codegen-test:
3534
# @echo "Generating SDK API tests"
@@ -47,6 +46,14 @@ gen-endpoints:
4746
@echo "Generating SDK endpoints"
4847
go generate ./models/endpoints
4948

49+
gen-codegen-test:
50+
@echo "Generating SDK API tests"
51+
go generate ./private/model/api/codegentest/service
52+
53+
gen-external-asserts:
54+
@echo "Generating SDK external package implementor assertions"
55+
go generate ./aws/external
56+
5057
gen-tools:
5158
go generate -tags sdktool ./internal/awstesting/cmd/op_crawler/
5259

aws/config.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,12 @@ type Config struct {
7979
// for testing that do not support the modeled host prefix pattern.
8080
DisableEndpointHostPrefix bool
8181

82+
// EnableEndpointDiscovery will allow for endpoint discovery on operations that
83+
// have the definition in its model. By default, endpoint discovery is off.
84+
EnableEndpointDiscovery bool
85+
8286
// ConfigSources are the sources that were used to construct the Config.
83-
// Allows for additional configuration can be loaded by clients.
87+
// Allows for additional configuration to be loaded by clients.
8488
ConfigSources []interface{}
8589
}
8690

aws/crr/cache.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package crr
2+
3+
import (
4+
"sync"
5+
"sync/atomic"
6+
)
7+
8+
// EndpointCache is an LRU cache that holds a series of endpoints
9+
// based on some key. The datastructure makes use of a read write
10+
// mutex to enable asynchronous use.
11+
type EndpointCache struct {
12+
endpoints sync.Map
13+
endpointLimit int64
14+
// size is used to count the number elements in the cache.
15+
// The atomic package is used to ensure this size is accurate when
16+
// using multiple goroutines.
17+
size int64
18+
}
19+
20+
// NewEndpointCache will return a newly initialized cache with a limit
21+
// of endpointLimit entries.
22+
func NewEndpointCache(endpointLimit int64) *EndpointCache {
23+
return &EndpointCache{
24+
endpointLimit: endpointLimit,
25+
endpoints: sync.Map{},
26+
}
27+
}
28+
29+
// get is a concurrent safe get operation that will retrieve an endpoint
30+
// based on endpointKey. A boolean will also be returned to illustrate whether
31+
// or not the endpoint had been found.
32+
func (c *EndpointCache) get(endpointKey string) (Endpoint, bool) {
33+
endpoint, ok := c.endpoints.Load(endpointKey)
34+
if !ok {
35+
return Endpoint{}, false
36+
}
37+
38+
c.endpoints.Store(endpointKey, endpoint)
39+
return endpoint.(Endpoint), true
40+
}
41+
42+
// Has returns if the enpoint cache contains a valid entry for the endpoint key
43+
// provided.
44+
func (c *EndpointCache) Has(endpointKey string) bool {
45+
endpoint, ok := c.get(endpointKey)
46+
_, found := endpoint.GetValidAddress()
47+
48+
return ok && found
49+
}
50+
51+
// Get will retrieve a weighted address based off of the endpoint key. If an endpoint
52+
// should be retrieved, due to not existing or the current endpoint has expired
53+
// the Discoverer object that was passed in will attempt to discover a new endpoint
54+
// and add that to the cache.
55+
func (c *EndpointCache) Get(d Discoverer, endpointKey string, required bool) (WeightedAddress, error) {
56+
var err error
57+
endpoint, ok := c.get(endpointKey)
58+
weighted, found := endpoint.GetValidAddress()
59+
shouldGet := !ok || !found
60+
61+
if required && shouldGet {
62+
if endpoint, err = c.discover(d, endpointKey); err != nil {
63+
return WeightedAddress{}, err
64+
}
65+
66+
weighted, _ = endpoint.GetValidAddress()
67+
} else if shouldGet {
68+
go c.discover(d, endpointKey)
69+
}
70+
71+
return weighted, nil
72+
}
73+
74+
// Add is a concurrent safe operation that will allow new endpoints to be added
75+
// to the cache. If the cache is full, the number of endpoints equal endpointLimit,
76+
// then this will remove the oldest entry before adding the new endpoint.
77+
func (c *EndpointCache) Add(endpoint Endpoint) {
78+
// de-dups multiple adds of an endpoint with a pre-existing key
79+
if iface, ok := c.endpoints.Load(endpoint.Key); ok {
80+
e := iface.(Endpoint)
81+
if e.Len() > 0 {
82+
return
83+
}
84+
}
85+
c.endpoints.Store(endpoint.Key, endpoint)
86+
87+
size := atomic.AddInt64(&c.size, 1)
88+
if size > 0 && size > c.endpointLimit {
89+
c.deleteRandomKey()
90+
}
91+
}
92+
93+
// deleteRandomKey will delete a random key from the cache. If
94+
// no key was deleted false will be returned.
95+
func (c *EndpointCache) deleteRandomKey() bool {
96+
atomic.AddInt64(&c.size, -1)
97+
found := false
98+
99+
c.endpoints.Range(func(key, value interface{}) bool {
100+
found = true
101+
c.endpoints.Delete(key)
102+
103+
return false
104+
})
105+
106+
return found
107+
}
108+
109+
// discover will get and store and endpoint using the Discoverer.
110+
func (c *EndpointCache) discover(d Discoverer, endpointKey string) (Endpoint, error) {
111+
endpoint, err := d.Discover()
112+
if err != nil {
113+
return Endpoint{}, err
114+
}
115+
116+
endpoint.Key = endpointKey
117+
c.Add(endpoint)
118+
119+
return endpoint, nil
120+
}

0 commit comments

Comments
 (0)