Skip to content

Commit 6240ad4

Browse files
authored
Merge pull request #2893 from PelicanPlatform/copilot/add-runtime-config-annotations
Add runtime-configurable annotations for parameters
2 parents 5f15e67 + ac76b68 commit 6240ad4

File tree

4 files changed

+470
-9
lines changed

4 files changed

+470
-9
lines changed

docs/parameters.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ description: |+
6868
type: bool
6969
default: false
7070
components: ["cache", "director", "origin", "registry"]
71+
runtime_configurable: false
7172
---
7273
name: IssuerKey
7374
description: |+
@@ -200,6 +201,7 @@ default: none
200201
client_default: warn
201202
server_default: info
202203
components: ["*"]
204+
runtime_configurable: true
203205
---
204206
name: Logging.LogLocation
205207
description: |+

generate/param_generator.go

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ type TemplateData struct {
4949

5050
var requiredKeys = [3]string{"description", "default", "type"}
5151
var deprecatedMap = make(map[string][]string)
52+
var runtimeConfigurableMap = make(map[string]bool)
5253

5354
func GenParamEnum() {
5455
/*
@@ -153,7 +154,15 @@ func GenParamEnum() {
153154
deprecatedMap[entry["name"].(string)] = replacedBySlice
154155
}
155156

157+
// Handle runtime_configurable field
156158
rawName := entry["name"].(string)
159+
if runtimeConfigurable, ok := entry["runtime_configurable"].(bool); ok {
160+
runtimeConfigurableMap[rawName] = runtimeConfigurable
161+
} else {
162+
// Default to false if not specified
163+
runtimeConfigurableMap[rawName] = false
164+
}
165+
157166
name := strings.ReplaceAll(rawName, ".", "_")
158167
pType := entry["type"].(string)
159168
switch pType {
@@ -192,15 +201,16 @@ func GenParamEnum() {
192201

193202
// Generate the code based on the template
194203
err = packageTemplate.Execute(f, struct {
195-
StringMap map[string]string
196-
StringSliceMap map[string]string
197-
IntMap map[string]string
198-
BoolMap map[string]string
199-
DurationMap map[string]string
200-
ObjectMap map[string]string
201-
DeprecatedMap map[string][]string
202-
AllParamNames []string
203-
}{StringMap: stringParamMap, StringSliceMap: stringSliceParamMap, IntMap: intParamMap, BoolMap: boolParamMap, DurationMap: durationParamMap, ObjectMap: objectParamMap, DeprecatedMap: deprecatedMap, AllParamNames: allParamNames})
204+
StringMap map[string]string
205+
StringSliceMap map[string]string
206+
IntMap map[string]string
207+
BoolMap map[string]string
208+
DurationMap map[string]string
209+
ObjectMap map[string]string
210+
DeprecatedMap map[string][]string
211+
RuntimeConfigurableMap map[string]bool
212+
AllParamNames []string
213+
}{StringMap: stringParamMap, StringSliceMap: stringSliceParamMap, IntMap: intParamMap, BoolMap: boolParamMap, DurationMap: durationParamMap, ObjectMap: objectParamMap, DeprecatedMap: deprecatedMap, RuntimeConfigurableMap: runtimeConfigurableMap, AllParamNames: allParamNames})
204214

205215
if err != nil {
206216
panic(err)
@@ -476,6 +486,27 @@ func GetDeprecated() map[string][]string {
476486
}
477487
}
478488
489+
// runtimeConfigurableMap is a map of parameter names to their runtime configurability status.
490+
// It is generated from docs/parameters.yaml and indicates whether a parameter can be reloaded
491+
// at runtime without requiring a server restart.
492+
var runtimeConfigurableMap = map[string]bool{
493+
{{- range $key, $value := .RuntimeConfigurableMap}}
494+
"{{$key}}": {{$value}},
495+
{{- end}}
496+
}
497+
498+
func GetRuntimeConfigurable() map[string]bool {
499+
return runtimeConfigurableMap
500+
}
501+
502+
// IsRuntimeConfigurable returns whether the given parameter name can be reloaded at runtime
503+
func IsRuntimeConfigurable(paramName string) bool {
504+
if val, ok := runtimeConfigurableMap[paramName]; ok {
505+
return val
506+
}
507+
return false
508+
}
509+
479510
func (sP StringParam) GetString() string {
480511
config := getOrCreateConfig()
481512
switch sP.name {
@@ -495,6 +526,10 @@ func (sP StringParam) IsSet() bool {
495526
return viper.IsSet(sP.name)
496527
}
497528
529+
func (sP StringParam) IsRuntimeConfigurable() bool {
530+
return IsRuntimeConfigurable(sP.name)
531+
}
532+
498533
func (slP StringSliceParam) GetStringSlice() []string {
499534
config := getOrCreateConfig()
500535
switch slP.name {
@@ -514,6 +549,10 @@ func (slP StringSliceParam) IsSet() bool {
514549
return viper.IsSet(slP.name)
515550
}
516551
552+
func (slP StringSliceParam) IsRuntimeConfigurable() bool {
553+
return IsRuntimeConfigurable(slP.name)
554+
}
555+
517556
func (iP IntParam) GetInt() int {
518557
config := getOrCreateConfig()
519558
switch iP.name {
@@ -533,6 +572,10 @@ func (iP IntParam) IsSet() bool {
533572
return viper.IsSet(iP.name)
534573
}
535574
575+
func (iP IntParam) IsRuntimeConfigurable() bool {
576+
return IsRuntimeConfigurable(iP.name)
577+
}
578+
536579
func (bP BoolParam) GetBool() bool {
537580
config := getOrCreateConfig()
538581
switch bP.name {
@@ -552,6 +595,10 @@ func (bP BoolParam) IsSet() bool {
552595
return viper.IsSet(bP.name)
553596
}
554597
598+
func (bP BoolParam) IsRuntimeConfigurable() bool {
599+
return IsRuntimeConfigurable(bP.name)
600+
}
601+
555602
func (dP DurationParam) GetDuration() time.Duration {
556603
config := getOrCreateConfig()
557604
switch dP.name {
@@ -571,6 +618,10 @@ func (dP DurationParam) IsSet() bool {
571618
return viper.IsSet(dP.name)
572619
}
573620
621+
func (dP DurationParam) IsRuntimeConfigurable() bool {
622+
return IsRuntimeConfigurable(dP.name)
623+
}
624+
574625
func (oP ObjectParam) Unmarshal(rawVal any) error {
575626
return viper.UnmarshalKey(oP.name, rawVal)
576627
}
@@ -583,6 +634,10 @@ func (oP ObjectParam) IsSet() bool {
583634
return viper.IsSet(oP.name)
584635
}
585636
637+
func (oP ObjectParam) IsRuntimeConfigurable() bool {
638+
return IsRuntimeConfigurable(oP.name)
639+
}
640+
586641
// allParameterNames is the list of all config keys generated from
587642
// docs/parameters.yaml. It is primarily used to bind environment variables so
588643
// that env-only overrides are included in viper.AllSettings().

param/param_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,3 +227,39 @@ func TestAccessorFunctionsWithNoConfig(t *testing.T) {
227227
require.NotNil(t, config)
228228
assert.Equal(t, 7000, config.Cache.Port)
229229
}
230+
231+
func TestIsRuntimeConfigurable(t *testing.T) {
232+
// Test the package-level function with a parameter that has runtime_configurable: true
233+
assert.True(t, IsRuntimeConfigurable("Logging.Level"), "Logging.Level should be runtime configurable")
234+
235+
// Test with a parameter that has runtime_configurable: false
236+
assert.False(t, IsRuntimeConfigurable("TLSSkipVerify"), "TLSSkipVerify should not be runtime configurable")
237+
238+
// Test with a parameter that doesn't specify runtime_configurable (should default to false)
239+
assert.False(t, IsRuntimeConfigurable("Cache.Port"), "Cache.Port should default to not runtime configurable")
240+
241+
// Test with a non-existent parameter
242+
assert.False(t, IsRuntimeConfigurable("NonExistent.Parameter"), "Non-existent parameter should return false")
243+
}
244+
245+
func TestParamIsRuntimeConfigurable(t *testing.T) {
246+
// Test the method on different param types
247+
assert.True(t, Logging_Level.IsRuntimeConfigurable(), "Logging.Level should be runtime configurable")
248+
assert.False(t, TLSSkipVerify.IsRuntimeConfigurable(), "TLSSkipVerify should not be runtime configurable")
249+
assert.False(t, Cache_Port.IsRuntimeConfigurable(), "Cache.Port should not be runtime configurable")
250+
}
251+
252+
func TestGetRuntimeConfigurable(t *testing.T) {
253+
// Test that GetRuntimeConfigurable returns a valid map
254+
runtimeConfigMap := GetRuntimeConfigurable()
255+
require.NotNil(t, runtimeConfigMap, "GetRuntimeConfigurable should return a non-nil map")
256+
257+
// Verify specific entries
258+
loggingLevel, exists := runtimeConfigMap["Logging.Level"]
259+
assert.True(t, exists, "Logging.Level should exist in the map")
260+
assert.True(t, loggingLevel, "Logging.Level should be true in the map")
261+
262+
tlsSkipVerify, exists := runtimeConfigMap["TLSSkipVerify"]
263+
assert.True(t, exists, "TLSSkipVerify should exist in the map")
264+
assert.False(t, tlsSkipVerify, "TLSSkipVerify should be false in the map")
265+
}

0 commit comments

Comments
 (0)