github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/admin/commands/common/set_config.go (about)

     1  package common
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/onflow/flow-go/admin"
     8  	"github.com/onflow/flow-go/admin/commands"
     9  	"github.com/onflow/flow-go/module/updatable_configs"
    10  )
    11  
    12  var _ commands.AdminCommand = (*SetConfigCommand)(nil)
    13  
    14  // SetConfigCommand is an admin command which enables setting any config field which
    15  // has registered as dynamically updatable with the config Manager.
    16  type SetConfigCommand struct {
    17  	configs *updatable_configs.Manager
    18  }
    19  
    20  func NewSetConfigCommand(configs *updatable_configs.Manager) *SetConfigCommand {
    21  	return &SetConfigCommand{
    22  		configs: configs,
    23  	}
    24  }
    25  
    26  // validatedSetConfigData represents a set-config admin request which has passed basic validation.
    27  // It contains the config field to update, and the config value.
    28  type validatedSetConfigData struct {
    29  	field updatable_configs.Field
    30  	value any
    31  }
    32  
    33  func (s *SetConfigCommand) Handler(_ context.Context, req *admin.CommandRequest) (interface{}, error) {
    34  	validatedReq := req.ValidatorData.(validatedSetConfigData)
    35  
    36  	oldValue := validatedReq.field.Get()
    37  
    38  	err := validatedReq.field.Set(validatedReq.value)
    39  	if err != nil {
    40  		if updatable_configs.IsValidationError(err) {
    41  			return nil, fmt.Errorf("config update failed due to invalid input: %w", err)
    42  		}
    43  		return nil, fmt.Errorf("unexpected error setting config field %s: %w", validatedReq.field.Name, err)
    44  	}
    45  
    46  	res := map[string]any{
    47  		"oldValue": oldValue,
    48  		"newValue": validatedReq.value,
    49  	}
    50  
    51  	return res, nil
    52  }
    53  
    54  // Validator validates the request.
    55  // Returns admin.InvalidAdminReqError for invalid/malformed requests.
    56  func (s *SetConfigCommand) Validator(req *admin.CommandRequest) error {
    57  	mval, ok := req.Data.(map[string]any)
    58  	if !ok {
    59  		return admin.NewInvalidAdminReqFormatError("expected map[string]any")
    60  	}
    61  
    62  	if len(mval) != 1 {
    63  		return admin.NewInvalidAdminReqErrorf("data field must have 1 entry, got %d", len(mval))
    64  	}
    65  
    66  	var (
    67  		configName  string
    68  		configValue any
    69  	)
    70  	// select the single name/value pair from the map
    71  	for k, v := range mval {
    72  		configName = k
    73  		configValue = v
    74  		break
    75  	}
    76  
    77  	field, ok := s.configs.GetField(configName)
    78  	if !ok {
    79  		return admin.NewInvalidAdminReqErrorf("unknown config field: %s", configName)
    80  	}
    81  
    82  	// we have found a corresponding updatable config field, set it in the ValidatorData
    83  	// field - we will attempt to apply the change in Handler
    84  	req.ValidatorData = validatedSetConfigData{
    85  		field: field,
    86  		value: configValue,
    87  	}
    88  	return nil
    89  }