Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 109 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"net/url"
"os"
"path/filepath"
"reflect"
"slices"
"sort"
"strconv"
Expand All @@ -50,6 +51,7 @@ import (
"github.com/spf13/viper"
"golang.org/x/sync/errgroup"

"github.com/pelicanplatform/pelican/docs"
"github.com/pelicanplatform/pelican/param"
"github.com/pelicanplatform/pelican/pelican_url"
"github.com/pelicanplatform/pelican/server_structs"
Expand Down Expand Up @@ -171,7 +173,8 @@ var (
"": true,
}

clientInitialized = false
clientInitialized = false
printClientConfigOnce sync.Once
)

func init() {
Expand Down Expand Up @@ -922,6 +925,99 @@ func PrintConfig() error {
return nil
}

func contains(slice []string, item string) bool {
for _, s := range slice {
if s == item {
return true
}
}
return false
}

// GetComponentConfig filters the full config and returns only the config parameters related to the given component.
// The filtering is based on whether the given component is part of the components in docs.parameters.yaml.
func GetComponentConfig(component string) (map[string]interface{}, error) {
rawConfig, err := param.UnmarshalConfig(viper.GetViper())
if err != nil {
return nil, err
}
value, hasValue := filterConfigRecursive(reflect.ValueOf(rawConfig), "", component)
if hasValue {
return (*value).(map[string]interface{}), nil
}
return nil, nil
}

// filterConfigRecursive is a helper function for GetComponentConfig.
// It recursively creates a nested config map of the parameters that relate to the given component.
func filterConfigRecursive(v reflect.Value, currentPath string, component string) (*interface{}, bool) {
if v.Kind() == reflect.Ptr {
v = v.Elem()
}

switch v.Kind() {
case reflect.Struct:
t := v.Type()
result := make(map[string]interface{})
hasField := false
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
fieldType := t.Field(i)
if !fieldType.IsExported() {
continue
}

fieldName := strings.ToLower(fieldType.Name)

var newPath string
if currentPath == "" {
newPath = fieldName
} else {
newPath = currentPath + "." + fieldName
}

fieldValue, fieldHasValue := filterConfigRecursive(field, newPath, component)
if fieldHasValue && fieldValue != nil {
result[fieldName] = *fieldValue
hasField = true
}
}
if hasField {
resultInterface := interface{}(result)
return &resultInterface, true
}
return nil, false
default:
lowerPath := strings.ToLower(currentPath)
paramDoc, exists := docs.ParsedParameters[lowerPath]
if exists && contains(paramDoc.Components, component) {
resultValue := v.Interface()
resultInterface := interface{}(resultValue)
return &resultInterface, true
}
return nil, false
}
}

// PrintClientConfig prints the client config in JSON format to stderr.
func PrintClientConfig() error {
clientConfig, err := GetComponentConfig("client")
if err != nil {
return err
}

bytes, err := json.MarshalIndent(clientConfig, "", " ")
if err != nil {
return err
}
fmt.Fprintln(os.Stderr,
"================ Pelican Client Configuration ================\n",
string(bytes),
"\n",
"============= End of Pelican Client Configuration ============")
return nil
}

func SetServerDefaults(v *viper.Viper) error {
configDir := v.GetString("ConfigDir")
v.SetConfigType("yaml")
Expand Down Expand Up @@ -1515,6 +1611,18 @@ func InitClient() error {

clientInitialized = true

var printClientConfigErr error
printClientConfigOnce.Do(func() {
if log.GetLevel() == log.DebugLevel {
printClientConfigErr = PrintClientConfig()
}
})

// Return any error encountered during PrintClientConfig
if printClientConfigErr != nil {
return printClientConfigErr
}

return nil
}

Expand Down
14 changes: 7 additions & 7 deletions launchers/launcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,6 @@ func LaunchModules(ctx context.Context, modules server_structs.ServerType) (serv

config.LogPelicanVersion()

// Print Pelican config at server start if it's in debug or info level
if log.GetLevel() >= log.InfoLevel {
if err = config.PrintConfig(); err != nil {
return
}
}

egrp.Go(func() error {
_ = config.RestartFlag
log.Debug("Will shutdown process on signal")
Expand Down Expand Up @@ -97,6 +90,13 @@ func LaunchModules(ctx context.Context, modules server_structs.ServerType) (serv
return
}

// Print Pelican config at server start if it's in debug or info level
if log.GetLevel() >= log.InfoLevel {
if err = config.PrintConfig(); err != nil {
return
}
}

// Set up necessary APIs to support Web UI, including auth and metrics
if err = web_ui.ConfigureServerWebAPI(ctx, engine, egrp); err != nil {
return
Expand Down
Loading