...

Source file src/edge-infra.dev/pkg/edge/edgeadmin/commands/operatorintervention/add/add.go

Documentation: edge-infra.dev/pkg/edge/edgeadmin/commands/operatorintervention/add

     1  package add
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"edge-infra.dev/pkg/edge/api/graph/model"
     9  	"edge-infra.dev/pkg/edge/edgeadmin/commands/operatorintervention/edgeextension"
    10  	"edge-infra.dev/pkg/edge/edgeadmin/commands/operatorintervention/format"
    11  	"edge-infra.dev/pkg/edge/edgecli"
    12  	"edge-infra.dev/pkg/edge/edgecli/constructors"
    13  	"edge-infra.dev/pkg/lib/cli/command"
    14  	"edge-infra.dev/pkg/lib/cli/rags"
    15  )
    16  
    17  type SubCommand interface {
    18  	// Returns the short usage string for a subcommand
    19  	ShortUsageString() string
    20  	// Returns the short help string for a subcommand
    21  	ShortHelpString() string
    22  	// Returns the long help string for a subcommand
    23  	LongHelpString() string
    24  	// Returns list of associated flags for a subcommand
    25  	Flags() []*rags.Rag
    26  	// Gets all values from supported flags for a subcommand and
    27  	// creates a GraphQL variables map from them
    28  	Variables() map[string]interface{}
    29  	// Return the mutation struct for a subcommand's graphQL mutation
    30  	Mutation() OperatorInterventionMutation
    31  	// Return the input type used to generate a relevant error display string
    32  	ResponseType() string
    33  }
    34  
    35  type OperatorInterventionMutation interface {
    36  	Errors() []*model.OperatorInterventionErrorResponse
    37  }
    38  
    39  func NewCmd(cfg *edgecli.Config) *command.Command {
    40  	return &command.Command{
    41  		ShortUsage: "edgeadmin operatorintervention add",
    42  		ShortHelp:  "subcommands to add operator intervention configurations",
    43  
    44  		Commands: []*command.Command{
    45  			newSubcommand(&Command{}, cfg),
    46  			newSubcommand(&Privilege{}, cfg),
    47  			newSubcommand(&RoleMapping{}, cfg),
    48  			newSubcommand(&Rule{}, cfg),
    49  		},
    50  	}
    51  }
    52  
    53  // There is a lot of repeated boilerplate between different Add subcommands, so an
    54  // interface is passed in to cut down on duplication and to have a fixed Add subcommand
    55  // structure
    56  func newSubcommand(subcommand SubCommand, cfg *edgecli.Config) *command.Command {
    57  	var (
    58  		// Extension that validates connection flags and builds
    59  		// a BFF client on initialization
    60  		edge = &edgeextension.Ext{Cfg: cfg}
    61  	)
    62  
    63  	var cmd *command.Command
    64  	cmd = &command.Command{
    65  		ShortUsage: subcommand.ShortUsageString(),
    66  		ShortHelp:  subcommand.ShortHelpString(),
    67  		LongHelp:   subcommand.LongHelpString(),
    68  		Flags:      subcommand.Flags(),
    69  
    70  		Extensions: []command.Extension{
    71  			edge,
    72  		},
    73  
    74  		Exec: func(ctx context.Context, _ []string) error {
    75  			if err := validateRequiredFlags(cmd.Rags); err != nil {
    76  				return err
    77  			}
    78  			registrar, err := constructors.BuildRegistrar(cmd.Rags)
    79  			if err != nil {
    80  				return err
    81  			}
    82  			mutation := subcommand.Mutation()
    83  			if err := registrar.GetBFFClient().Mutate(ctx, mutation, subcommand.Variables()); err != nil {
    84  				return err
    85  			}
    86  			return handleResponse(subcommand.ResponseType(), mutation.Errors())
    87  		},
    88  	}
    89  	return cmd
    90  }
    91  
    92  // Current implementation of flagutil.ValidateRequiredFlags() does not validate list
    93  // flags so custom implementation is needed. This function checks only for string and
    94  // string collection flags
    95  func validateRequiredFlags(rags *rags.RagSet) (err error) {
    96  	for _, rag := range rags.Rags() {
    97  		if rag.Required {
    98  			val := rag.Value.String()
    99  			if val == "" {
   100  				err = errors.Join(err, fmt.Errorf("Flag '%s' is required", rag.Name))
   101  			}
   102  		}
   103  	}
   104  	return err
   105  }
   106  
   107  func handleResponse(inputType string, errs []*model.OperatorInterventionErrorResponse) error {
   108  	fmt.Println(format.GenerateApplyOutput(inputType, errs))
   109  	if len(errs) != 0 {
   110  		// Return empty error to guarantee binary non-zero exit code.
   111  		// Error details have already been printed, so return an empty
   112  		// error. This does unfortunately print an extra blank line on
   113  		// the output
   114  		return fmt.Errorf("")
   115  	}
   116  	return nil
   117  }
   118  
   119  const (
   120  	longHelpSingleFlagFormatString = `
   121  	This adds new %[1]ss to the operator intervention configuration database. To add a %[1]s, run the following:
   122  	
   123  	$ edgeadmin operatorintervention add %[1]s --%[1]s example
   124  	
   125  	If the %[1]s is valid, it will then be added to the database. For a %[1]s to be considered valid, it must
   126  	contain at least one character and must not have any whitespace. The database query is best-effort and no errors
   127  	are expected to be returned as long as all %[1]ss are valid inputs.
   128  	
   129  	Multiple %[1]ss can be added at once by using the --%[1]s flag multiple times:
   130  	
   131  	$ edgeadmin operatorintervention add %[1]s --%[1]s example1 --%[1]s example2 --%[1]s example3
   132  	`
   133  	longHelpTwoFlagsFormatStr = `
   134  	This adds new %[1]ss to the operator intervention configuration database. To add a %[1]s, run the following:
   135  	
   136  	$ edgeadmin operatorintervention add %[1]s --%[2]s example --%[3]s  val1
   137  	
   138  	If the %[1]s is valid, it will then be added to the database. For a %[1]s to be considered valid, it must
   139  	contain ONLY one valid %[2]s and at least one %[3]s  (all of which must be valid). The database query is 
   140  	all-or-nothing, so a response with potential errors is expected. This may be because of an incomplete payload,
   141  	or because one or more input values were not found in the database.
   142  	
   143  	Multiple %[3]ss can be added to the same %[1]s by using the --%[3]s  flag multiple times:
   144  	
   145  	$ edgeadmin operatorintervention add %[1]s --%[2]s example --%[3]s  val1 --%[3]s  val2 --%[3]s  val3
   146  	`
   147  )
   148  

View as plain text