Skip to content

Commit fe904bb

Browse files
authored
feat(flagd): Added WithGrpcDialOptionsOverride provider option (#638)
Signed-off-by: Maks Osowski <[email protected]>
1 parent 99d1a0c commit fe904bb

File tree

5 files changed

+114
-41
lines changed

5 files changed

+114
-41
lines changed

providers/flagd/README.md

+21
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,27 @@ openfeature.SetProvider(flagd.NewProvider(
144144
))
145145
```
146146

147+
### gRPC DialOptions override
148+
149+
The `GrpcDialOptionsOverride` is meant for connection of the in-process resolver to a Sync API implementation on a host/port,
150+
that might require special credentials or headers.
151+
152+
```go
153+
creds := customSync.CreateCredentials(...)
154+
155+
dialOptions := []grpc.DialOption{
156+
grpc.WithTransportCredentials(creds.TransportCredentials()),
157+
grpc.WithPerRPCCredentials(creds.PerRPCCredentials()),
158+
grpc.WithAuthority(...),
159+
}
160+
161+
openfeature.SetProvider(flagd.NewProvider(
162+
flagd.WithInProcessResolver(),
163+
flagd.WithHost("example.com/flagdSyncApi"), flagd.WithPort(443),
164+
flagd.WithGrpcDialOptionsOverride(dialOptions),
165+
))
166+
```
167+
147168
## Supported Events
148169

149170
The flagd provider emits `PROVIDER_READY`, `PROVIDER_ERROR` and `PROVIDER_CONFIGURATION_CHANGED` events.

providers/flagd/pkg/configuration.go

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/go-logr/logr"
99
"github.com/open-feature/flagd/core/pkg/sync"
1010
"github.com/open-feature/go-sdk-contrib/providers/flagd/internal/cache"
11+
"google.golang.org/grpc"
1112
)
1213

1314
type ResolverType string
@@ -58,6 +59,7 @@ type providerConfiguration struct {
5859
TLSEnabled bool
5960
CustomSyncProvider sync.ISync
6061
CustomSyncProviderUri string
62+
GrpcDialOptionsOverride []grpc.DialOption
6163

6264
log logr.Logger
6365
}

providers/flagd/pkg/provider.go

+21-9
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
process "github.com/open-feature/go-sdk-contrib/providers/flagd/pkg/service/in_process"
1414
rpcService "github.com/open-feature/go-sdk-contrib/providers/flagd/pkg/service/rpc"
1515
of "github.com/open-feature/go-sdk/openfeature"
16+
"google.golang.org/grpc"
1617
)
1718

1819
const (
@@ -78,15 +79,16 @@ func NewProvider(opts ...ProviderOption) *Provider {
7879
provider.providerConfiguration.EventStreamConnectionMaxAttempts)
7980
} else {
8081
service = process.NewInProcessService(process.Configuration{
81-
Host: provider.providerConfiguration.Host,
82-
Port: provider.providerConfiguration.Port,
83-
ProviderID: provider.providerConfiguration.ProviderID,
84-
Selector: provider.providerConfiguration.Selector,
85-
TargetUri: provider.providerConfiguration.TargetUri,
86-
TLSEnabled: provider.providerConfiguration.TLSEnabled,
87-
OfflineFlagSource: provider.providerConfiguration.OfflineFlagSourcePath,
88-
CustomSyncProvider: provider.providerConfiguration.CustomSyncProvider,
89-
CustomSyncProviderUri: provider.providerConfiguration.CustomSyncProviderUri,
82+
Host: provider.providerConfiguration.Host,
83+
Port: provider.providerConfiguration.Port,
84+
ProviderID: provider.providerConfiguration.ProviderID,
85+
Selector: provider.providerConfiguration.Selector,
86+
TargetUri: provider.providerConfiguration.TargetUri,
87+
TLSEnabled: provider.providerConfiguration.TLSEnabled,
88+
OfflineFlagSource: provider.providerConfiguration.OfflineFlagSourcePath,
89+
CustomSyncProvider: provider.providerConfiguration.CustomSyncProvider,
90+
CustomSyncProviderUri: provider.providerConfiguration.CustomSyncProviderUri,
91+
GrpcDialOptionsOverride: provider.providerConfiguration.GrpcDialOptionsOverride,
9092
})
9193
}
9294

@@ -356,3 +358,13 @@ func WithCustomSyncProviderAndUri(customSyncProvider sync.ISync, customSyncProvi
356358
p.providerConfiguration.CustomSyncProviderUri = customSyncProviderUri
357359
}
358360
}
361+
362+
// WithGrpcDialOptionsOverride provides a set of custom grps.DialOption that will fully override the gRPC dial options used by
363+
// the InProcess resolver with gRPC syncer. All the other provider options that also set dial options (e.g. WithTLS, or WithCertificatePath)
364+
// will be silently ignored.
365+
// This is only useful with inProcess resolver type
366+
func WithGrpcDialOptionsOverride(grpcDialOptionsOverride []grpc.DialOption) ProviderOption {
367+
return func(p *Provider) {
368+
p.providerConfiguration.GrpcDialOptionsOverride = grpcDialOptionsOverride
369+
}
370+
}

providers/flagd/pkg/provider_test.go

+51-17
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package flagd
22

33
import (
4+
"reflect"
45
"testing"
56

67
"github.com/open-feature/flagd/core/pkg/sync"
@@ -9,29 +10,36 @@ import (
910
process "github.com/open-feature/go-sdk-contrib/providers/flagd/pkg/service/in_process"
1011
of "github.com/open-feature/go-sdk/openfeature"
1112
"go.uber.org/mock/gomock"
13+
"google.golang.org/grpc"
14+
"google.golang.org/grpc/credentials/insecure"
1215
)
1316

1417
func TestNewProvider(t *testing.T) {
1518
customSyncProvider := process.NewDoNothingCustomSyncProvider()
19+
gRPCDialOptionOverride := []grpc.DialOption{
20+
grpc.WithTransportCredentials(insecure.NewCredentials()),
21+
grpc.WithAuthority("test-authority"),
22+
}
1623

1724
tests := []struct {
18-
name string
19-
expectedResolver ResolverType
20-
expectPort uint16
21-
expectHost string
22-
expectTargetUri string
23-
expectCacheType cache.Type
24-
expectCertPath string
25-
expectMaxRetries int
26-
expectCacheSize int
27-
expectOtelIntercept bool
28-
expectSocketPath string
29-
expectTlsEnabled bool
30-
expectProviderID string
31-
expectSelector string
32-
expectCustomSyncProvider sync.ISync
33-
expectCustomSyncProviderUri string
34-
options []ProviderOption
25+
name string
26+
expectedResolver ResolverType
27+
expectPort uint16
28+
expectHost string
29+
expectTargetUri string
30+
expectCacheType cache.Type
31+
expectCertPath string
32+
expectMaxRetries int
33+
expectCacheSize int
34+
expectOtelIntercept bool
35+
expectSocketPath string
36+
expectTlsEnabled bool
37+
expectProviderID string
38+
expectSelector string
39+
expectCustomSyncProvider sync.ISync
40+
expectCustomSyncProviderUri string
41+
expectGrpcDialOptionsOverride []grpc.DialOption
42+
options []ProviderOption
3543
}{
3644
{
3745
name: "default construction",
@@ -173,6 +181,20 @@ func TestNewProvider(t *testing.T) {
173181
WithCustomSyncProvider(customSyncProvider),
174182
},
175183
},
184+
{
185+
name: "with gRPC DialOptions override with in-process resolver",
186+
expectedResolver: inProcess,
187+
expectHost: defaultHost,
188+
expectPort: defaultInProcessPort,
189+
expectCacheType: defaultCache,
190+
expectCacheSize: defaultMaxCacheSize,
191+
expectMaxRetries: defaultMaxEventStreamRetries,
192+
expectGrpcDialOptionsOverride: gRPCDialOptionOverride,
193+
options: []ProviderOption{
194+
WithInProcessResolver(),
195+
WithGrpcDialOptionsOverride(gRPCDialOptionOverride),
196+
},
197+
},
176198
{
177199
name: "with selector and providerID with in-process resolver",
178200
expectedResolver: inProcess,
@@ -295,6 +317,18 @@ func TestNewProvider(t *testing.T) {
295317
test.expectCustomSyncProviderUri, config.CustomSyncProviderUri)
296318
}
297319

320+
if test.expectGrpcDialOptionsOverride != nil {
321+
if config.GrpcDialOptionsOverride == nil {
322+
t.Errorf("incorrent configuration GrpcDialOptionsOverride, expected %v, got nil", config.GrpcDialOptionsOverride)
323+
} else if !reflect.DeepEqual(config.GrpcDialOptionsOverride, test.expectGrpcDialOptionsOverride) {
324+
t.Errorf("incorrent configuration GrpcDialOptionsOverride, expected %v, got %v", test.expectGrpcDialOptionsOverride, config.GrpcDialOptionsOverride)
325+
}
326+
} else {
327+
if config.GrpcDialOptionsOverride != nil {
328+
t.Errorf("incorrent configuration GrpcDialOptionsOverride, expected nil, got %v", config.GrpcDialOptionsOverride)
329+
}
330+
}
331+
298332
// this line will fail linting if this provider is no longer compatible with the openfeature sdk
299333
var _ of.FeatureProvider = flagdProvider
300334
})

providers/flagd/pkg/service/in_process/service.go

+19-15
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"regexp"
88
parallel "sync"
99

10+
googlegrpc "google.golang.org/grpc"
11+
1012
"github.com/open-feature/flagd/core/pkg/evaluator"
1113
"github.com/open-feature/flagd/core/pkg/logger"
1214
"github.com/open-feature/flagd/core/pkg/model"
@@ -33,15 +35,16 @@ type InProcess struct {
3335
}
3436

3537
type Configuration struct {
36-
Host any
37-
Port any
38-
TargetUri string
39-
ProviderID string
40-
Selector string
41-
TLSEnabled bool
42-
OfflineFlagSource string
43-
CustomSyncProvider sync.ISync
44-
CustomSyncProviderUri string
38+
Host any
39+
Port any
40+
TargetUri string
41+
ProviderID string
42+
Selector string
43+
TLSEnabled bool
44+
OfflineFlagSource string
45+
CustomSyncProvider sync.ISync
46+
CustomSyncProviderUri string
47+
GrpcDialOptionsOverride []googlegrpc.DialOption
4548
}
4649

4750
func NewInProcessService(cfg Configuration) *InProcess {
@@ -301,12 +304,13 @@ func makeSyncProvider(cfg Configuration, log *logger.Logger) (sync.ISync, string
301304
log.Info("operating in in-process mode with flags sourced from " + uri)
302305

303306
return &grpc.Sync{
304-
CredentialBuilder: &credentials.CredentialBuilder{},
305-
Logger: log,
306-
Secure: cfg.TLSEnabled,
307-
ProviderID: cfg.ProviderID,
308-
Selector: cfg.Selector,
309-
URI: uri,
307+
CredentialBuilder: &credentials.CredentialBuilder{},
308+
GrpcDialOptionsOverride: cfg.GrpcDialOptionsOverride,
309+
Logger: log,
310+
Secure: cfg.TLSEnabled,
311+
ProviderID: cfg.ProviderID,
312+
Selector: cfg.Selector,
313+
URI: uri,
310314
}, uri
311315
}
312316

0 commit comments

Comments
 (0)