ce9ab6a89a
* initial commit * add support of integerts * finialise the static provider * minor refactoring * the rest * revert: the rest * add new thiongs * more tests added * add ff parsing tests to check if types are handled correctly * update tests according to recent changes * address golint issues * Update pkg/setting/setting_feature_toggles.go Co-authored-by: Dave Henderson <dave.henderson@grafana.com> * fix rebase issues * addressing review comments * add test cases for enterprise * handle enterprise cases * minor refactoring to make api a bit easier to debug * make test names a bit more precise * fix linter * add openfeature sdk to goleak ignore in testutil * Remove only boolean check in ff gen tests * add non-boolean types top the doc in default.ini and doc string in FeatureFlag type * apply remarks, add docs to sample.ini * reflect changes in feature flags in the public grafana configuration doc * fix doc formatting * apply suggestions to the doc file --------- Co-authored-by: Dave Henderson <dave.henderson@grafana.com>
103 lines
3.4 KiB
Go
103 lines
3.4 KiB
Go
package featuremgmt
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/open-feature/go-sdk/openfeature"
|
|
goffmodel "github.com/thomaspoignant/go-feature-flag/cmd/relayproxy/model"
|
|
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
)
|
|
|
|
// StaticFlagEvaluator provides methods for evaluating static feature flags
|
|
// it is only used when static provider is configured
|
|
type StaticFlagEvaluator interface {
|
|
EvalFlag(ctx context.Context, flagKey string) (goffmodel.OFREPEvaluateSuccessResponse, error)
|
|
EvalAllFlags(ctx context.Context) (goffmodel.OFREPBulkEvaluateSuccessResponse, error)
|
|
}
|
|
|
|
// CreateStaticEvaluator is a dependency for ofrep APIBuilder
|
|
func CreateStaticEvaluator(cfg *setting.Cfg) (StaticFlagEvaluator, error) {
|
|
if cfg.OpenFeature.ProviderType != setting.StaticProviderType {
|
|
return nil, fmt.Errorf("provider is not a static provider, type %s", setting.StaticProviderType)
|
|
}
|
|
|
|
staticFlags, err := setting.ReadFeatureTogglesFromInitFile(cfg.Raw.Section("feature_toggles"))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read feature flags from config: %w", err)
|
|
}
|
|
|
|
staticProvider, err := newStaticProvider(staticFlags, standardFeatureFlags)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create static provider: %w", err)
|
|
}
|
|
|
|
p, ok := staticProvider.(*inMemoryBulkProvider)
|
|
if !ok {
|
|
return nil, fmt.Errorf("static provider is not of type inMemoryBulkProvider")
|
|
}
|
|
|
|
c := openfeature.NewDefaultClient()
|
|
|
|
return &staticEvaluator{
|
|
provider: p,
|
|
client: c,
|
|
log: log.New("static-evaluator"),
|
|
}, nil
|
|
}
|
|
|
|
// staticEvaluator implements StaticFlagEvaluator for static providers
|
|
type staticEvaluator struct {
|
|
provider *inMemoryBulkProvider
|
|
client openfeature.IClient
|
|
log log.Logger
|
|
}
|
|
|
|
func (s *staticEvaluator) EvalFlag(ctx context.Context, flagKey string) (goffmodel.OFREPEvaluateSuccessResponse, error) {
|
|
result, err := s.client.BooleanValueDetails(ctx, flagKey, false, openfeature.TransactionContext(ctx))
|
|
if err != nil {
|
|
return goffmodel.OFREPEvaluateSuccessResponse{}, fmt.Errorf("failed to evaluate flag %s: %w", flagKey, err)
|
|
}
|
|
resp := goffmodel.OFREPEvaluateSuccessResponse{
|
|
Key: flagKey,
|
|
Value: result.Value,
|
|
Reason: "static provider evaluation result",
|
|
Variant: result.Variant,
|
|
Metadata: result.FlagMetadata,
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func (s *staticEvaluator) EvalAllFlags(ctx context.Context) (goffmodel.OFREPBulkEvaluateSuccessResponse, error) {
|
|
flags, err := s.provider.ListFlags()
|
|
if err != nil {
|
|
return goffmodel.OFREPBulkEvaluateSuccessResponse{}, fmt.Errorf("static provider failed to list all flags: %w", err)
|
|
}
|
|
|
|
allFlags := make([]goffmodel.OFREPFlagBulkEvaluateSuccessResponse, 0, len(flags))
|
|
for _, flagKey := range flags {
|
|
result, err := s.client.BooleanValueDetails(ctx, flagKey, false, openfeature.TransactionContext(ctx))
|
|
if err != nil {
|
|
s.log.Error("failed to evaluate flag during bulk evaluation", "flagKey", flagKey, "error", err)
|
|
continue
|
|
}
|
|
|
|
allFlags = append(allFlags, goffmodel.OFREPFlagBulkEvaluateSuccessResponse{
|
|
OFREPEvaluateSuccessResponse: goffmodel.OFREPEvaluateSuccessResponse{
|
|
Key: flagKey,
|
|
Value: result.Value,
|
|
Reason: "static provider evaluation result",
|
|
Variant: result.Variant,
|
|
Metadata: result.FlagMetadata,
|
|
},
|
|
ErrorCode: string(result.ErrorCode),
|
|
ErrorDetails: result.ErrorMessage,
|
|
})
|
|
}
|
|
|
|
return goffmodel.OFREPBulkEvaluateSuccessResponse{Flags: allFlags}, nil
|
|
}
|