Skip to content

Commit 9527eb0

Browse files
committed
feat: add new flagd config fields, bump versions
This PR adds configuration added to flagd since the last upgrade: - context-value (--context-value / -X): static key-value pairs for evaluation context - header-to-context mappings (--context-from-header / -H): map HTTP headers to context keys - CORS origins (--cors-origin / -C): allowed origins for the OFREP endpoint - OFREP port (--ofrep-port / -r): configurable port for the OFREP service - Bump flagd from v0.12.4 to v0.15.2 - Bump flagd-proxy from v0.7.4 to v0.9.4 No e2e tests were added since none of these impact RBAC, topology, or deployment; just added unit tests that assert the associated startup args are correctly passed. Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
1 parent 3cf6a6a commit 9527eb0

19 files changed

Lines changed: 295 additions & 18 deletions

File tree

api/core/v1beta1/featureflagsource_types.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,23 @@ type FeatureFlagSourceSpec struct {
9393
// Resources defines flagd sidecar resources. Default to operator sidecar-cpu-* and sidecar-ram-* flags.
9494
// +optional
9595
Resources corev1.ResourceRequirements `json:"resources"`
96+
97+
// ContextValues are static key-value pairs added to the flagd evaluation context
98+
// +optional
99+
ContextValues map[string]string `json:"contextValues,omitempty"`
100+
101+
// HeaderToContextMappings map HTTP header names to evaluation context keys
102+
// +optional
103+
HeaderToContextMappings map[string]string `json:"headerToContextMappings,omitempty"`
104+
105+
// CORS defines the allowed CORS origins for the flagd OFREP endpoint
106+
// +optional
107+
CORS []string `json:"cors,omitempty"`
108+
109+
// OFREPPort defines the port for the OFREP service, defaults to 8016
110+
// +optional
111+
// +kubebuilder:default:=8016
112+
OFREPPort int32 `json:"ofrepPort"`
96113
}
97114

98115
type Source struct {
@@ -224,6 +241,28 @@ func (fc *FeatureFlagSourceSpec) Merge(new *FeatureFlagSourceSpec) {
224241
fc.Resources.Limits[k] = v
225242
}
226243
}
244+
if len(new.ContextValues) != 0 {
245+
if fc.ContextValues == nil {
246+
fc.ContextValues = map[string]string{}
247+
}
248+
for k, v := range new.ContextValues {
249+
fc.ContextValues[k] = v
250+
}
251+
}
252+
if len(new.HeaderToContextMappings) != 0 {
253+
if fc.HeaderToContextMappings == nil {
254+
fc.HeaderToContextMappings = map[string]string{}
255+
}
256+
for k, v := range new.HeaderToContextMappings {
257+
fc.HeaderToContextMappings[k] = v
258+
}
259+
}
260+
if len(new.CORS) != 0 {
261+
fc.CORS = new.CORS
262+
}
263+
if new.OFREPPort != 0 {
264+
fc.OFREPPort = new.OFREPPort
265+
}
227266
}
228267

229268
func (fc *FeatureFlagSourceSpec) decorateEnvVarName(original string) string {

api/core/v1beta1/featureflagsource_types_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ func Test_FLagSourceConfiguration_Merge(t *testing.T) {
5050
v1.ResourceCPU: resource.MustParse("100m"),
5151
},
5252
},
53+
ContextValues: map[string]string{
54+
"env": "staging",
55+
},
56+
HeaderToContextMappings: map[string]string{
57+
"X-Tenant": "tenant",
58+
},
59+
CORS: []string{"http://localhost:3000"},
60+
OFREPPort: 8016,
5361
},
5462
}
5563

@@ -95,6 +103,14 @@ func Test_FLagSourceConfiguration_Merge(t *testing.T) {
95103
v1.ResourceCPU: resource.MustParse("100m"),
96104
},
97105
},
106+
ContextValues: map[string]string{
107+
"env": "staging",
108+
},
109+
HeaderToContextMappings: map[string]string{
110+
"X-Tenant": "tenant",
111+
},
112+
CORS: []string{"http://localhost:3000"},
113+
OFREPPort: 8016,
98114
},
99115
}, ff_old)
100116

@@ -133,6 +149,16 @@ func Test_FLagSourceConfiguration_Merge(t *testing.T) {
133149
v1.ResourceCPU: resource.MustParse("200m"),
134150
},
135151
},
152+
ContextValues: map[string]string{
153+
"env": "production",
154+
"region": "us-east-1",
155+
},
156+
HeaderToContextMappings: map[string]string{
157+
"X-Tenant": "tenant-override",
158+
"X-Region": "region",
159+
},
160+
CORS: []string{"https://app.example.com", "https://admin.example.com"},
161+
OFREPPort: 9090,
136162
},
137163
}
138164

@@ -184,6 +210,20 @@ func Test_FLagSourceConfiguration_Merge(t *testing.T) {
184210
Name: "env4",
185211
Value: "val4",
186212
})
213+
214+
// context values are merged additively, with new overriding old
215+
require.Equal(t, "production", ff_old.Spec.ContextValues["env"])
216+
require.Equal(t, "us-east-1", ff_old.Spec.ContextValues["region"])
217+
218+
// header mappings are merged additively, with new overriding old
219+
require.Equal(t, "tenant-override", ff_old.Spec.HeaderToContextMappings["X-Tenant"])
220+
require.Equal(t, "region", ff_old.Spec.HeaderToContextMappings["X-Region"])
221+
222+
// CORS is replaced entirely
223+
require.Equal(t, []string{"https://app.example.com", "https://admin.example.com"}, ff_old.Spec.CORS)
224+
225+
// OFREPPort is overridden
226+
require.Equal(t, int32(9090), ff_old.Spec.OFREPPort)
187227
}
188228

189229
func Test_FLagSourceConfiguration_ToEnvVars(t *testing.T) {

api/core/v1beta1/zz_generated.deepcopy.go

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

chart/open-feature-operator/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ The command removes all the Kubernetes components associated with the chart and
123123
| `sidecarConfiguration.managementPort` | Sets the value of the `XXX_MANAGEMENT_PORT` environment variable for the injected sidecar. | `8014` |
124124
| `sidecarConfiguration.socketPath` | Sets the value of the `XXX_SOCKET_PATH` environment variable for the injected sidecar. | `""` |
125125
| `sidecarConfiguration.image.repository` | Sets the image for the injected sidecar. | `ghcr.io/open-feature/flagd` |
126-
| `sidecarConfiguration.image.tag` | Sets the version tag for the injected sidecar. | `v0.12.4` |
126+
| `sidecarConfiguration.image.tag` | Sets the version tag for the injected sidecar. | `v0.15.2` |
127127
| `sidecarConfiguration.providerArgs` | Used to append arguments to the sidecar startup command. This value is a comma separated string of key values separated by '=', e.g. `key=value,key2=value2` results in the appending of `--sync-provider-args key=value --sync-provider-args key2=value2`. | `""` |
128128
| `sidecarConfiguration.envVarPrefix` | Sets the prefix for all environment variables set in the injected sidecar. | `FLAGD` |
129129
| `sidecarConfiguration.defaultSyncProvider` | Sets the value of the `XXX_SYNC_PROVIDER` environment variable for the injected sidecar container. There are 4 valid sync providers: `kubernetes`, `grpc`, `file` and `http`. | `kubernetes` |
@@ -159,7 +159,7 @@ The command removes all the Kubernetes components associated with the chart and
159159
| `flagdProxyConfiguration.port` | Sets the port to expose the sync API on. | `8015` |
160160
| `flagdProxyConfiguration.managementPort` | Sets the port to expose the management API on. | `8016` |
161161
| `flagdProxyConfiguration.image.repository` | Sets the image for the flagd-proxy deployment. | `ghcr.io/open-feature/flagd-proxy` |
162-
| `flagdProxyConfiguration.image.tag` | Sets the tag for the flagd-proxy deployment. | `v0.7.4` |
162+
| `flagdProxyConfiguration.image.tag` | Sets the tag for the flagd-proxy deployment. | `v0.9.4` |
163163
| `flagdProxyConfiguration.debugLogging` | Controls the addition of the `--debug` flag to the container startup arguments. | `false` |
164164

165165
### Flagd configuration
@@ -171,7 +171,7 @@ The command removes all the Kubernetes components associated with the chart and
171171
| `flagdConfiguration.syncPort` | Sets the port to expose the sync API on. | `8015` |
172172
| `flagdConfiguration.managementPort` | Sets the port to expose the management API on. | `8014` |
173173
| `flagdConfiguration.image.repository` | Sets the image for the flagd deployment. | `ghcr.io/open-feature/flagd` |
174-
| `flagdConfiguration.image.tag` | Sets the tag for the flagd deployment. | `v0.12.4` |
174+
| `flagdConfiguration.image.tag` | Sets the tag for the flagd deployment. | `v0.15.2` |
175175
| `flagdConfiguration.debugLogging` | Controls the addition of the `--debug` flag to the container startup arguments. | `false` |
176176

177177
### Operator resource configuration

chart/open-feature-operator/values.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ sidecarConfiguration:
3737
## @param sidecarConfiguration.image.repository Sets the image for the injected sidecar.
3838
repository: "ghcr.io/open-feature/flagd"
3939
## @param sidecarConfiguration.image.tag Sets the version tag for the injected sidecar.
40-
tag: v0.12.4
40+
tag: v0.15.2
4141
## @param sidecarConfiguration.providerArgs Used to append arguments to the sidecar startup command. This value is a comma separated string of key values separated by '=', e.g. `key=value,key2=value2` results in the appending of `--sync-provider-args key=value --sync-provider-args key2=value2`.
4242
providerArgs: ""
4343
## @param sidecarConfiguration.envVarPrefix Sets the prefix for all environment variables set in the injected sidecar.
@@ -100,7 +100,7 @@ flagdProxyConfiguration:
100100
## @param flagdProxyConfiguration.image.repository Sets the image for the flagd-proxy deployment.
101101
repository: "ghcr.io/open-feature/flagd-proxy"
102102
## @param flagdProxyConfiguration.image.tag Sets the tag for the flagd-proxy deployment.
103-
tag: v0.7.4
103+
tag: v0.9.4
104104
## @param flagdProxyConfiguration.debugLogging Controls the addition of the `--debug` flag to the container startup arguments.
105105
debugLogging: false
106106

@@ -118,7 +118,7 @@ flagdConfiguration:
118118
## @param flagdConfiguration.image.repository Sets the image for the flagd deployment.
119119
repository: "ghcr.io/open-feature/flagd"
120120
## @param flagdConfiguration.image.tag Sets the tag for the flagd deployment.
121-
tag: v0.12.4
121+
tag: v0.15.2
122122
## @param flagdConfiguration.debugLogging Controls the addition of the `--debug` flag to the container startup arguments.
123123
debugLogging: false
124124

config/crd/bases/core.openfeature.dev_featureflagsources.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,18 @@ spec:
4141
spec:
4242
description: FeatureFlagSourceSpec defines the desired state of FeatureFlagSource
4343
properties:
44+
contextValues:
45+
additionalProperties:
46+
type: string
47+
description: ContextValues are static key-value pairs added to the
48+
flagd evaluation context
49+
type: object
50+
cors:
51+
description: CORS defines the allowed CORS origins for the flagd OFREP
52+
endpoint
53+
items:
54+
type: string
55+
type: array
4456
debugLogging:
4557
description: DebugLogging defines whether to enable --debug flag of
4658
flagd sidecar. Default false (disabled).
@@ -177,6 +189,12 @@ spec:
177189
default: json
178190
description: Evaluator sets an evaluator, defaults to 'json'
179191
type: string
192+
headerToContextMappings:
193+
additionalProperties:
194+
type: string
195+
description: HeaderToContextMappings map HTTP header names to evaluation
196+
context keys
197+
type: object
180198
logFormat:
181199
default: json
182200
description: LogFormat allows for the sidecar log format to be overridden,
@@ -188,6 +206,12 @@ spec:
188206
defaults to 8014
189207
format: int32
190208
type: integer
209+
ofrepPort:
210+
default: 8016
211+
description: OFREPPort defines the port for the OFREP service, defaults
212+
to 8016
213+
format: int32
214+
type: integer
191215
otelCollectorUri:
192216
description: OtelCollectorUri defines whether to enable --otel-collector-uri
193217
flag of flagd sidecar. Default false (disabled).

docs/crds.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,20 @@ FeatureFlagSourceSpec defines the desired state of FeatureFlagSource
276276
SyncProviders define the syncProviders and associated configuration to be applied to the sidecar<br/>
277277
</td>
278278
<td>true</td>
279+
</tr><tr>
280+
<td><b>contextValues</b></td>
281+
<td>map[string]string</td>
282+
<td>
283+
ContextValues are static key-value pairs added to the flagd evaluation context<br/>
284+
</td>
285+
<td>false</td>
286+
</tr><tr>
287+
<td><b>cors</b></td>
288+
<td>[]string</td>
289+
<td>
290+
CORS defines the allowed CORS origins for the flagd OFREP endpoint<br/>
291+
</td>
292+
<td>false</td>
279293
</tr><tr>
280294
<td><b>debugLogging</b></td>
281295
<td>boolean</td>
@@ -316,6 +330,13 @@ are added at the lowest index, all values will have the EnvVarPrefix applied, de
316330
<i>Default</i>: json<br/>
317331
</td>
318332
<td>false</td>
333+
</tr><tr>
334+
<td><b>headerToContextMappings</b></td>
335+
<td>map[string]string</td>
336+
<td>
337+
HeaderToContextMappings map HTTP header names to evaluation context keys<br/>
338+
</td>
339+
<td>false</td>
319340
</tr><tr>
320341
<td><b>logFormat</b></td>
321342
<td>string</td>
@@ -335,6 +356,16 @@ are added at the lowest index, all values will have the EnvVarPrefix applied, de
335356
<i>Default</i>: 8014<br/>
336357
</td>
337358
<td>false</td>
359+
</tr><tr>
360+
<td><b>ofrepPort</b></td>
361+
<td>integer</td>
362+
<td>
363+
OFREPPort defines the port for the OFREP service, defaults to 8016<br/>
364+
<br/>
365+
<i>Format</i>: int32<br/>
366+
<i>Default</i>: 8016<br/>
367+
</td>
368+
<td>false</td>
338369
</tr><tr>
339370
<td><b>otelCollectorUri</b></td>
340371
<td>string</td>

internal/common/flagdinjector/flagdinjector.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7+
"sort"
78
"time"
89

910
"github.com/go-logr/logr"
@@ -109,6 +110,58 @@ func (fi *FlagdContainerInjector) InjectFlagd(
109110
)
110111
}
111112

113+
// set --context-value flags for static context values
114+
if len(flagSourceConfig.ContextValues) > 0 {
115+
// sort keys for deterministic arg order
116+
keys := make([]string, 0, len(flagSourceConfig.ContextValues))
117+
for k := range flagSourceConfig.ContextValues {
118+
keys = append(keys, k)
119+
}
120+
sort.Strings(keys)
121+
for _, k := range keys {
122+
flagdContainer.Args = append(
123+
flagdContainer.Args,
124+
"--context-value",
125+
fmt.Sprintf("%s=%s", k, flagSourceConfig.ContextValues[k]),
126+
)
127+
}
128+
}
129+
130+
// set --context-from-header flags for header-to-context mappings
131+
if len(flagSourceConfig.HeaderToContextMappings) > 0 {
132+
// sort keys for deterministic arg order
133+
keys := make([]string, 0, len(flagSourceConfig.HeaderToContextMappings))
134+
for k := range flagSourceConfig.HeaderToContextMappings {
135+
keys = append(keys, k)
136+
}
137+
sort.Strings(keys)
138+
for _, k := range keys {
139+
flagdContainer.Args = append(
140+
flagdContainer.Args,
141+
"--context-from-header",
142+
fmt.Sprintf("%s=%s", k, flagSourceConfig.HeaderToContextMappings[k]),
143+
)
144+
}
145+
}
146+
147+
// set --cors-origin flags for CORS allowed origins
148+
for _, origin := range flagSourceConfig.CORS {
149+
flagdContainer.Args = append(
150+
flagdContainer.Args,
151+
"--cors-origin",
152+
origin,
153+
)
154+
}
155+
156+
// set --ofrep-port flag if non-default
157+
if flagSourceConfig.OFREPPort != 0 {
158+
flagdContainer.Args = append(
159+
flagdContainer.Args,
160+
"--ofrep-port",
161+
fmt.Sprintf("%d", flagSourceConfig.OFREPPort),
162+
)
163+
}
164+
112165
if len(flagSourceConfig.Resources.Requests) != 0 {
113166
flagdContainer.Resources.Requests = flagSourceConfig.Resources.Requests
114167
}

0 commit comments

Comments
 (0)