Skip to content

Commit c4958d1

Browse files
committed
Code clean up with help from Claude
Signed-off-by: Zachary Nixon <nixozach@amazon.com>
1 parent f391875 commit c4958d1

5 files changed

Lines changed: 735 additions & 40 deletions

File tree

internal/infrastructure/manager.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
var (
2727
_ Manager = (*kubernetes.Infra)(nil)
2828
_ Manager = (*host.Infra)(nil)
29+
_ Manager = (*remote.Infra)(nil)
2930
)
3031

3132
// Manager provides the scaffolding for managing infrastructure.
@@ -83,7 +84,7 @@ func newManagerForCustom(ctx context.Context, cfg *config.Server, logger logging
8384
return nil, err
8485
}
8586
}
86-
return remote.NewInfra(cfg, k8sClient, errors)
87+
return remote.NewInfra(cfg, remote.DefaultInfraClientFactory(cfg, k8sClient), errors), nil
8788
default:
8889
return nil, fmt.Errorf("unsupported provider type: %s", infra.Type)
8990
}

internal/infrastructure/remote/infra.go

Lines changed: 71 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ package remote
77

88
import (
99
"context"
10-
11-
"sigs.k8s.io/controller-runtime/pkg/client"
10+
"sync"
1211

1312
egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
1413
"github.com/envoyproxy/gateway/internal/envoygateway/config"
@@ -17,8 +16,13 @@ import (
1716
"github.com/envoyproxy/gateway/internal/message"
1817
)
1918

20-
// Infra manages the creation and deletion of Kubernetes infrastructure
21-
// based on Infra IR resources.
19+
// Infra manages the creation and deletion of remotely managed proxy and rate
20+
// limit infrastructure by delegating to a remote provider over gRPC.
21+
//
22+
// The underlying InfraClient is constructed lazily on the first method call
23+
// that requires it. This avoids dialing the remote service or reading
24+
// Kubernetes secrets during process startup, where failures would crash the
25+
// pod before validation that the remote provider is actually being used.
2226
type Infra struct {
2327
// EnvoyGateway is the configuration used to startup Envoy Gateway.
2428
EnvoyGateway *egv1a1.EnvoyGateway
@@ -28,44 +32,88 @@ type Infra struct {
2832
// errors is the notifier used to send async errors to the main control loop.
2933
errors message.RunnerErrorNotifier
3034

35+
// factory builds the InfraClient on demand. It must not be nil.
36+
factory InfraClientFactory
37+
38+
mu sync.Mutex
3139
ic InfraClient
3240
}
3341

34-
// NewInfra returns a new Infra.
35-
func NewInfra(cfg *config.Server, k8sClient client.Client, errors message.RunnerErrorNotifier) (*Infra, error) {
36-
// We initialize the client here, that way if the remote connection is misconfigured, then the pod
37-
// crashes rather than silently failing when infrastructure changes happen.
38-
infraClient, err := newRemoteInfraClient(cfg, k8sClient)
39-
if err != nil {
40-
if infraClient != nil {
41-
_ = infraClient.Close()
42-
}
43-
return nil, err
44-
}
45-
return &Infra{
42+
// NewInfra returns a new Infra that will lazily build its InfraClient via the
43+
// provided factory. The factory is invoked at most once for a successful
44+
// construction; if it returns an error, the next call will retry.
45+
func NewInfra(cfg *config.Server, factory InfraClientFactory, errors message.RunnerErrorNotifier) *Infra {
46+
return new(Infra{
4647
EnvoyGateway: cfg.EnvoyGateway,
4748
logger: cfg.Logger.WithName(string(egv1a1.LogComponentInfrastructureRunner)),
4849
errors: errors,
49-
ic: infraClient,
50-
}, nil
50+
factory: factory,
51+
})
5152
}
5253

54+
// Close releases any resources held by the underlying InfraClient. It is a
55+
// no-op if the client was never constructed.
5356
func (i *Infra) Close() error {
54-
return i.ic.Close()
57+
i.mu.Lock()
58+
defer i.mu.Unlock()
59+
if i.ic == nil {
60+
return nil
61+
}
62+
err := i.ic.Close()
63+
i.ic = nil
64+
return err
5565
}
5666

67+
// CreateOrUpdateProxyInfra delegates to the underlying InfraClient.
5768
func (i *Infra) CreateOrUpdateProxyInfra(ctx context.Context, infra *ir.Infra) error {
58-
return i.ic.CreateOrUpdateProxyInfra(ctx, infra)
69+
ic, err := i.client(ctx)
70+
if err != nil {
71+
return err
72+
}
73+
return ic.CreateOrUpdateProxyInfra(ctx, infra)
5974
}
6075

76+
// DeleteProxyInfra delegates to the underlying InfraClient.
6177
func (i *Infra) DeleteProxyInfra(ctx context.Context, infra *ir.Infra) error {
62-
return i.ic.DeleteProxyInfra(ctx, infra)
78+
ic, err := i.client(ctx)
79+
if err != nil {
80+
return err
81+
}
82+
return ic.DeleteProxyInfra(ctx, infra)
6383
}
6484

85+
// CreateOrUpdateRateLimitInfra delegates to the underlying InfraClient.
6586
func (i *Infra) CreateOrUpdateRateLimitInfra(ctx context.Context) error {
66-
return i.ic.CreateOrUpdateRateLimitInfra(ctx)
87+
ic, err := i.client(ctx)
88+
if err != nil {
89+
return err
90+
}
91+
return ic.CreateOrUpdateRateLimitInfra(ctx)
6792
}
6893

94+
// DeleteRateLimitInfra delegates to the underlying InfraClient.
6995
func (i *Infra) DeleteRateLimitInfra(ctx context.Context) error {
70-
return i.ic.DeleteRateLimitInfra(ctx)
96+
ic, err := i.client(ctx)
97+
if err != nil {
98+
return err
99+
}
100+
return ic.DeleteRateLimitInfra(ctx)
101+
}
102+
103+
// client returns the cached InfraClient, building it via the factory on the
104+
// first successful call. Failed factory invocations are not cached so that
105+
// transient errors during startup of the remote service are retried on the
106+
// next request.
107+
func (i *Infra) client(ctx context.Context) (InfraClient, error) {
108+
i.mu.Lock()
109+
defer i.mu.Unlock()
110+
if i.ic != nil {
111+
return i.ic, nil
112+
}
113+
ic, err := i.factory(ctx)
114+
if err != nil {
115+
return nil, err
116+
}
117+
i.ic = ic
118+
return ic, nil
71119
}

0 commit comments

Comments
 (0)