Skip to content

Commit 0b70a21

Browse files
committed
support a flag configured to passthrough to env var
1 parent ec97b44 commit 0b70a21

4 files changed

Lines changed: 47 additions & 20 deletions

File tree

packages/api/internal/cfg/model.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,6 @@ type Config struct {
6666

6767
DefaultKernelVersion string `env:"DEFAULT_KERNEL_VERSION"`
6868

69-
DefaultPersistentVolumeType string `env:"DEFAULT_PERSISTENT_VOLUME_TYPE"`
70-
7169
// SandboxStorageBackend selects the sandbox storage implementation.
7270
// "redis" uses Redis directly; "populate_redis" uses in-memory with Redis shadow writes.
7371
SandboxStorageBackend string `env:"SANDBOX_STORAGE_BACKEND" envDefault:"memory"`

packages/api/internal/handlers/volume_create.go

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func (a *APIStore) PostVolumes(c *gin.Context) {
6565

6666
ctx = featureflags.AddToContext(ctx, featureflags.VolumeContext(body.Name))
6767

68-
volumeType := a.getVolumeType(ctx)
68+
volumeType := a.featureFlags.StringFlag(ctx, featureflags.DefaultPersistentVolumeType)
6969
if volumeType == "" {
7070
a.sendAPIStoreError(c, http.StatusInternalServerError, "No persistent volume type is configured")
7171
telemetry.ReportCriticalError(ctx, "default persistent volume type is not configured", nil)
@@ -165,15 +165,6 @@ func (a *APIStore) PostVolumes(c *gin.Context) {
165165
c.JSON(http.StatusCreated, result)
166166
}
167167

168-
func (a *APIStore) getVolumeType(ctx context.Context) string {
169-
volumeType := a.featureFlags.StringFlag(ctx, featureflags.DefaultPersistentVolumeType)
170-
if volumeType == "" {
171-
volumeType = a.config.DefaultPersistentVolumeType
172-
}
173-
174-
return volumeType
175-
}
176-
177168
var validVolumeNameRegex = regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)
178169

179170
func isValidVolumeName(name string) bool {

packages/shared/pkg/featureflags/client.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package featureflags
33
import (
44
"context"
55
"os"
6+
"reflect"
67
"time"
78

89
"github.com/launchdarkly/go-sdk-common/v3/ldcontext"
@@ -108,6 +109,7 @@ func (c *Client) StringFlag(ctx context.Context, flag StringFlag, contexts ...ld
108109
type typedFlag[T any] interface {
109110
Key() string
110111
Fallback() T
112+
FallbackOnZero() bool
111113
}
112114

113115
func getFlag[T any](
@@ -128,9 +130,18 @@ func getFlag[T any](
128130
logger.L().Warn(ctx, "error evaluating flag", zap.Error(err), zap.String("flag", flag.Key()))
129131
}
130132

133+
if flag.FallbackOnZero() && isZeroValue(value) {
134+
return flag.Fallback()
135+
}
136+
131137
return value
132138
}
133139

140+
// isZeroValue returns true if the value is the zero value for its type.
141+
func isZeroValue[T any](v T) bool {
142+
return reflect.ValueOf(&v).Elem().IsZero()
143+
}
144+
134145
func (c *Client) Close(ctx context.Context) error {
135146
if c.ld == nil {
136147
return nil

packages/shared/pkg/featureflags/flags.go

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package featureflags
33
import (
44
"context"
55
"fmt"
6+
"os"
67
"strings"
78

89
"github.com/launchdarkly/go-sdk-common/v3/ldcontext"
@@ -34,8 +35,9 @@ const (
3435
// All flags must be defined here: https://app.launchdarkly.com/projects/default/flags/
3536

3637
type JSONFlag struct {
37-
name string
38-
fallback ldvalue.Value
38+
name string
39+
fallback ldvalue.Value
40+
fallbackOnZero bool
3941
}
4042

4143
func (f JSONFlag) Key() string {
@@ -50,6 +52,10 @@ func (f JSONFlag) Fallback() ldvalue.Value {
5052
return f.fallback
5153
}
5254

55+
func (f JSONFlag) FallbackOnZero() bool {
56+
return f.fallbackOnZero
57+
}
58+
5359
func newJSONFlag(name string, fallback ldvalue.Value) JSONFlag {
5460
flag := JSONFlag{name: name, fallback: fallback}
5561
builder := launchDarklyOfflineStore.Flag(flag.name).ValueForAll(fallback)
@@ -88,6 +94,10 @@ func (f BoolFlag) Fallback() bool {
8894
return f.fallback
8995
}
9096

97+
func (f BoolFlag) FallbackOnZero() bool {
98+
return false
99+
}
100+
91101
func newBoolFlag(name string, fallback bool) BoolFlag {
92102
flag := BoolFlag{name: name, fallback: fallback}
93103
builder := launchDarklyOfflineStore.Flag(flag.name).VariationForAll(fallback)
@@ -122,8 +132,9 @@ var (
122132
)
123133

124134
type IntFlag struct {
125-
name string
126-
fallback int
135+
name string
136+
fallback int
137+
fallbackOnZero bool
127138
}
128139

129140
func (f IntFlag) Key() string {
@@ -138,6 +149,10 @@ func (f IntFlag) Fallback() int {
138149
return f.fallback
139150
}
140151

152+
func (f IntFlag) FallbackOnZero() bool {
153+
return f.fallbackOnZero
154+
}
155+
141156
func newIntFlag(name string, fallback int) IntFlag {
142157
flag := IntFlag{name: name, fallback: fallback}
143158
builder := launchDarklyOfflineStore.Flag(flag.name).ValueForAll(ldvalue.Int(fallback))
@@ -207,8 +222,9 @@ var (
207222
)
208223

209224
type StringFlag struct {
210-
name string
211-
fallback string
225+
name string
226+
fallback string
227+
fallbackOnEmptyString bool
212228
}
213229

214230
func (f StringFlag) Key() string {
@@ -223,6 +239,10 @@ func (f StringFlag) Fallback() string {
223239
return f.fallback
224240
}
225241

242+
func (f StringFlag) FallbackOnZero() bool {
243+
return f.fallbackOnEmptyString
244+
}
245+
226246
func newStringFlag(name string, fallback string) StringFlag {
227247
flag := StringFlag{name: name, fallback: fallback}
228248
builder := launchDarklyOfflineStore.Flag(flag.name).ValueForAll(ldvalue.String(fallback))
@@ -231,6 +251,13 @@ func newStringFlag(name string, fallback string) StringFlag {
231251
return flag
232252
}
233253

254+
func newStringFlagFallbackOnEmptyString(name string, fallback string) StringFlag {
255+
flag := newStringFlag(name, fallback)
256+
flag.fallbackOnEmptyString = true
257+
258+
return flag
259+
}
260+
234261
// This is currently not configurable via feature flags.
235262
const (
236263
DefaultKernelVersion = "vmlinux-6.1.158"
@@ -251,9 +278,9 @@ var FirecrackerVersionMap = map[string]string{
251278

252279
// BuildIoEngine Sync is used by default as there seems to be a bad interaction between Async and a lot of io operations.
253280
var (
254-
BuildFirecrackerVersion = newStringFlag("build-firecracker-version", env.GetEnv("DEFAULT_FIRECRACKER_VERSION", DefaultFirecrackerVersion))
281+
BuildFirecrackerVersion = newStringFlagFallbackOnEmptyString("build-firecracker-version", env.GetEnv("DEFAULT_FIRECRACKER_VERSION", DefaultFirecrackerVersion))
255282
BuildIoEngine = newStringFlag("build-io-engine", "Sync")
256-
DefaultPersistentVolumeType = newStringFlag("default-persistent-volume-type", "")
283+
DefaultPersistentVolumeType = newStringFlagFallbackOnEmptyString("default-persistent-volume-type", os.Getenv("DEFAULT_PERSISTENT_VOLUME_TYPE"))
257284
BuildNodeInfo = newJSONFlag("preferred-build-node", ldvalue.Null())
258285
FirecrackerVersions = newJSONFlag("firecracker-versions", ldvalue.FromJSONMarshal(FirecrackerVersionMap))
259286
)

0 commit comments

Comments
 (0)