Skip to content

Commit

Permalink
feat!: start command flag refactor (#222)
Browse files Browse the repository at this point in the history
Corresponding OFO changes
[here](open-feature/open-feature-operator#256)
<!-- Please use this template for your pull request. -->
<!-- Please use the sections that you need and delete other sections -->

## This PR
<!-- add the description of the PR here -->

- refactors the start command flags to remove `--sync-provider`
- multiple `--uri` flags can be passed indicating the use of different
existing `sync-provider` types, all of which will work
- uses a prefix on the uri to define the `sync-provider`; `http(s)://`
will be passed to the http sync, `file://` will be passed to the file
path sync and the Kubernetes sync uses the following pattern
`core.openfeature.dev/{namespace}/{name}`, this will also allow for the
Kubernetes sync to watch multiple `FeatureFlagConfigurations` from
different namespaces.
- adds deprecation warning when the `--sync-provider` flag is passed as
an argument

`./flagd start --uri file://etc/flagd/end-to-end.json --uri
core.openfeature.dev/test/end-to-end-2`

### Related Issues
<!-- add here the GitHub issue that this PR resolves if applicable -->

open-feature/open-feature-operator#251

### Notes
<!-- any additional notes for this PR -->

### Follow-up Tasks

### How to test
<!-- if applicable, add testing instructions under this section -->

Signed-off-by: James Milligan <james@omnant.co.uk>
Signed-off-by: James Milligan <75740990+james-milligan@users.noreply.github.com>
Co-authored-by: Todd Baert <toddbaert@gmail.com>
  • Loading branch information
james-milligan and toddbaert authored Nov 30, 2022
1 parent 4b9de42 commit 14474cc
Show file tree
Hide file tree
Showing 10 changed files with 239 additions and 87 deletions.
38 changes: 20 additions & 18 deletions cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,54 +16,55 @@ const (
portFlagName = "port"
metricsPortFlagName = "metrics-port"
socketPathFlagName = "socket-path"
syncProviderFlagName = "sync-provider"
providerArgsFlagName = "sync-provider-args"
evaluatorFlagName = "evaluator"
serverCertPathFlagName = "server-cert-path"
serverKeyPathFlagName = "server-key-path"
uriFlagName = "uri"
bearerTokenFlagName = "bearer-token"
corsFlagName = "cors-origin"
syncProviderFlagName = "sync-provider"
)

func init() {
flags := startCmd.Flags()

// allows environment variables to use _ instead of -
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) // sync-provider becomes SYNC_PROVIDER
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) // sync-provider-args becomes SYNC_PROVIDER_ARGS
viper.SetEnvPrefix("FLAGD") // port becomes FLAGD_PORT
flags.Int32P(metricsPortFlagName, "m", 8014, "Port to serve metrics on")
flags.Int32P(portFlagName, "p", 8013, "Port to listen on")
flags.StringP(socketPathFlagName, "d", "", "Flagd socket path. "+
"With grpc the service will become available on this address. "+
"With http(s) the grpc-gateway proxy will use this address internally.")
flags.StringP(
syncProviderFlagName, "y", "filepath", "Set a sync provider e.g. filepath or remote",
)
flags.StringP(evaluatorFlagName, "e", "json", "Set an evaluator e.g. json")
flags.StringP(serverCertPathFlagName, "c", "", "Server side tls certificate path")
flags.StringP(serverKeyPathFlagName, "k", "", "Server side tls key path")
flags.StringToStringP(providerArgsFlagName,
"a", nil, "Sync provider arguments as key values separated by =")
flags.StringSliceP(
uriFlagName, "f", []string{}, "Set a sync provider uri to read data from this can be a filepath or url. "+
"Using multiple providers is supported where collisions between "+
"flags with the same key, the later will be used.")
uriFlagName, "f", []string{}, "Set a sync provider uri to read data from, this can be a filepath,"+
"url or FeatureFlagConfiguration. Using multiple providers is supported however if"+
"flag keys are duplicated across multiple sources it may lead to unexpected behavior ",
)
flags.StringP(
bearerTokenFlagName, "b", "", "Set a bearer token to use for remote sync")
flags.StringSliceP(corsFlagName, "C", []string{}, "CORS allowed origins, * will allow all origins")
flags.StringP(
syncProviderFlagName, "y", "", "DEPRECATED: Set a sync provider e.g. filepath or remote",
)

_ = viper.BindPFlag(portFlagName, flags.Lookup(portFlagName))
_ = viper.BindPFlag(metricsPortFlagName, flags.Lookup(metricsPortFlagName))
_ = viper.BindPFlag(socketPathFlagName, flags.Lookup(socketPathFlagName))
_ = viper.BindPFlag(syncProviderFlagName, flags.Lookup(syncProviderFlagName))
_ = viper.BindPFlag(providerArgsFlagName, flags.Lookup(providerArgsFlagName))
_ = viper.BindPFlag(evaluatorFlagName, flags.Lookup(evaluatorFlagName))
_ = viper.BindPFlag(serverCertPathFlagName, flags.Lookup(serverCertPathFlagName))
_ = viper.BindPFlag(serverKeyPathFlagName, flags.Lookup(serverKeyPathFlagName))
_ = viper.BindPFlag(uriFlagName, flags.Lookup(uriFlagName))
_ = viper.BindPFlag(bearerTokenFlagName, flags.Lookup(bearerTokenFlagName))
_ = viper.BindPFlag(corsFlagName, flags.Lookup(corsFlagName))
_ = viper.BindPFlag(syncProviderFlagName, flags.Lookup(syncProviderFlagName))
}

// startCmd represents the start command
Expand All @@ -87,22 +88,23 @@ var startCmd = &cobra.Command{
logger := logger.NewLogger(l)
rtLogger := logger.WithFields(zap.String("component", "start"))

if viper.GetString(syncProviderFlagName) != "" {
rtLogger.Warn("DEPRECATED: The --sync-provider flag has been deprecated. " +
"Docs: https://github.com/open-feature/flagd/blob/main/docs/configuration.md")
}

// Build Runtime -----------------------------------------------------------
rt, err := runtime.FromConfig(logger, runtime.Config{
ServicePort: viper.GetInt32(portFlagName),
MetricsPort: viper.GetInt32(metricsPortFlagName),
ServiceSocketPath: viper.GetString(socketPathFlagName),
ServiceCertPath: viper.GetString(serverCertPathFlagName),
ServiceKeyPath: viper.GetString(serverKeyPathFlagName),

SyncProvider: viper.GetString(syncProviderFlagName),
ProviderArgs: viper.GetStringMapString(providerArgsFlagName),
SyncURI: viper.GetStringSlice(uriFlagName),
SyncBearerToken: viper.GetString(bearerTokenFlagName),

Evaluator: viper.GetString(evaluatorFlagName),

CORS: viper.GetStringSlice(corsFlagName),
ProviderArgs: viper.GetStringMapString(providerArgsFlagName),
SyncURI: viper.GetStringSlice(uriFlagName),
SyncBearerToken: viper.GetString(bearerTokenFlagName),
Evaluator: viper.GetString(evaluatorFlagName),
CORS: viper.GetStringSlice(corsFlagName),
})
if err != nil {
rtLogger.Fatal(err.Error())
Expand Down
19 changes: 14 additions & 5 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,26 @@ Supported flags are as follows (result of running `./flagd start --help`):
-k, --server-key-path string Server side tls key path
-a, --sync-provider-args Sync provider arguments as key values separated by =
-d, --socket-path string Set the flagd socket path.
-y, --sync-provider string Set a sync provider e.g. filepath or remote (default "filepath")
-f, --uri strings Set a sync provider uri to read data from this can be a filepath or url. Using multiple providers is supported where collisions between flags with the same key, the later will be used.
-C, --cors-origin strings Set a CORS allow origin header, setting "*" will allow all origins (by default CORS headers are not set)
```

Environment variable keys are uppercased, prefixed with `FLAGD_` and all `-` are replaced with `_`. For example,
`sync-provider` in environment variable form is `FLAGD_SYNC_PROVIDER`.
`sync-provider-args` in environment variable form is `FLAGD_SYNC_PROVIDER_ARGS`.

Config file expects the keys to have the exact naming as the flags.

### URI patterns

Any URI passed to flagd via the `--uri` flag must follow one of the 3 following patterns to ensure that it is passed to the correct implementation:

| Sync | Pattern | Example |
| ----------- | ----------- | ----------- |
| Kubernetes | `core.openfeature.dev/namespace/name` | `core.openfeature.dev/default/my-crd` |
| Filepath | `file:path/to/my/flag` | `file:etc/flagd/my-flags.json` |
| Remote | `http(s)://flag-source-url` | `https://my-flags.com/flags` |



### Customising sync providers

Expand All @@ -37,12 +47,11 @@ The Kubernetes provider allows flagD to connect to a Kubernetes cluster and eval
To use an existing FeatureFlagConfiguration custom resource, start flagD with the following command:

```shell
flagd start --sync-provider=kubernetes --sync-provider-args=featureflagconfiguration=my-example --sync-provider-args=namespace=default
flagd start --uri core.openfeature.dev/default.my_example
```

An additional optional flag `refreshtime` can be applied to shorten the cache refresh when using the Kubernetes provider ( The default is 5s ). As an example:

```shell
flagd start --sync-provider=kubernetes --sync-provider-args=featureflagconfiguration=my-example --sync-provider-args=namespace=default
--sync-provider-args=refreshtime=1s
flagd start --uri core.openfeature.dev/default.my_example --sync-provider-args=refreshtime=1s
```
63 changes: 39 additions & 24 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ require (
github.com/deepmap/oapi-codegen v1.11.0
github.com/diegoholiveira/jsonlogic/v3 v3.2.6
github.com/dimiro1/banner v1.1.0
github.com/fsnotify/fsnotify v1.5.4
github.com/fsnotify/fsnotify v1.6.0
github.com/go-chi/chi/v5 v5.0.7
github.com/golang/mock v1.6.0
github.com/mattn/go-colorable v0.1.12
github.com/open-feature/open-feature-operator v0.0.10-0.20220826061622-a6421d66936a
github.com/open-feature/schemas v0.0.0-20220809125333-185e3bd77775
github.com/prometheus/client_golang v1.13.0
github.com/open-feature/open-feature-operator v0.2.20
github.com/open-feature/schemas v0.0.0-20221123004631-302d0fa1f813
github.com/prometheus/client_golang v1.14.0
github.com/robfig/cron v1.2.0
github.com/rs/cors v1.8.2
github.com/rs/xid v1.4.0
Expand All @@ -23,29 +23,40 @@ require (
github.com/xeipuuv/gojsonschema v1.2.0
github.com/zeebo/xxh3 v1.0.2
go.buf.build/open-feature/flagd-connect/open-feature/flagd v1.1.4
go.uber.org/zap v1.21.0
golang.org/x/net v0.0.0-20221002022538-bcab6841153b
go.uber.org/zap v1.23.0
golang.org/x/net v0.2.0
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0
google.golang.org/grpc v1.49.0
google.golang.org/grpc v1.50.1
google.golang.org/protobuf v1.28.1
k8s.io/api v0.25.2
k8s.io/apimachinery v0.25.2
k8s.io/client-go v0.25.2
sigs.k8s.io/controller-runtime v0.13.0
k8s.io/api v0.25.4
k8s.io/apimachinery v0.25.4
k8s.io/client-go v0.25.4
sigs.k8s.io/controller-runtime v0.13.1
)

require (
cloud.google.com/go/compute v1.12.1 // indirect
cloud.google.com/go/compute/metadata v0.2.1 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.28 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.21 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/common-nighthawk/go-figure v0.0.0-20200609044655-c4b36f998cf2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
github.com/emicklei/go-restful/v3 v3.10.1 // indirect
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/zapr v1.2.3 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.4.3 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/gnostic v0.6.9 // indirect
github.com/google/go-cmp v0.5.9 // indirect
Expand All @@ -60,7 +71,7 @@ require (
github.com/magiconair/properties v1.8.6 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
Expand All @@ -71,7 +82,7 @@ require (
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
github.com/spf13/afero v1.8.2 // indirect
Expand All @@ -81,23 +92,27 @@ require (
github.com/subosito/gotenv v1.4.1 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 // indirect
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20220919170432-7a66f970e087 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
golang.org/x/crypto v0.3.0 // indirect
golang.org/x/oauth2 v0.2.0 // indirect
golang.org/x/sys v0.2.0 // indirect
golang.org/x/term v0.2.0 // indirect
golang.org/x/text v0.4.0 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/time v0.2.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220930163606-c98284e70a91 // indirect
google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.25.4 // indirect
k8s.io/component-base v0.25.4 // indirect
k8s.io/klog/v2 v2.80.1 // indirect
k8s.io/kube-openapi v0.0.0-20220928191237-829ce0c27909 // indirect
k8s.io/utils v0.0.0-20220922133306-665eaaec4324 // indirect
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
k8s.io/kube-openapi v0.0.0-20221123214604-86e75ddd809a // indirect
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)
Loading

0 comments on commit 14474cc

Please sign in to comment.