...

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

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

     1  package view
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"slices"
     8  
     9  	"github.com/shurcooL/graphql"
    10  
    11  	"edge-infra.dev/pkg/edge/api/client"
    12  	"edge-infra.dev/pkg/edge/api/graph/model"
    13  	"edge-infra.dev/pkg/edge/edgeadmin/commands/operatorintervention/edgeextension"
    14  	"edge-infra.dev/pkg/edge/edgecli"
    15  	"edge-infra.dev/pkg/edge/edgecli/flagutil"
    16  	"edge-infra.dev/pkg/lib/cli/command"
    17  	"edge-infra.dev/pkg/lib/cli/rags"
    18  )
    19  
    20  const (
    21  	longHelpStr = `
    22  	This command returns a readable JSON-formatted summary of all role mappings and their allowed commands from the database.
    23  	
    24  	$ edgeadmin operatorintervention view summary
    25  
    26  	By default this command will return a summary of all roles on the database, but you can also specify just a subset of roles
    27  	using any number of optional --role flags.
    28  
    29  	$ edgeadmin operatorintervention view summary --role role1 --role role2 --role role3
    30  	`
    31  )
    32  
    33  type RoleConfiguration struct {
    34  	Role       string
    35  	Privileges []model.Rule
    36  }
    37  
    38  func NewSummary(cfg *edgecli.Config) *command.Command {
    39  	var (
    40  		edge  = &edgeextension.Ext{Cfg: cfg}
    41  		roles []string
    42  	)
    43  
    44  	return &command.Command{
    45  		ShortUsage: "edgeadmin operatorintervention view summary [--role <role>]",
    46  		ShortHelp:  "view the summary of the full operator intervention rules configuration",
    47  		LongHelp:   longHelpStr,
    48  		Flags: []*rags.Rag{
    49  			{
    50  				Name:  flagutil.RoleFlag,
    51  				Usage: "(optional) filter results by edge role name",
    52  				Value: &rags.StringSet{
    53  					Var: &roles,
    54  				},
    55  			},
    56  		},
    57  
    58  		Extensions: []command.Extension{
    59  			edge,
    60  		},
    61  
    62  		Exec: func(ctx context.Context, _ []string) error {
    63  			roleMappings, rules, err := retrieveRolesAndRules(ctx, edge.Client, roles)
    64  			if err != nil {
    65  				return err
    66  			}
    67  
    68  			roleConfigs := assembleRoleConfigurations(roleMappings, rules)
    69  			output, err := json.MarshalIndent(roleConfigs, "", "  ")
    70  			if err != nil {
    71  				return err
    72  			}
    73  
    74  			fmt.Println(string(output))
    75  
    76  			return nil
    77  		},
    78  	}
    79  }
    80  
    81  // Query graphql for all OIRoleMappings and OIRules.
    82  // Takes in optional list of roles as a filter for OIRoleMappings.
    83  func retrieveRolesAndRules(ctx context.Context, bffClient *client.EdgeClient, roles []string) ([]model.OiRoleMapping, []model.Rule, error) {
    84  	var query struct {
    85  		OiRoleMappings []model.OiRoleMapping `graphql:"operatorInterventionRoleMappings(roles: $roles)"`
    86  		Rules          []model.Rule          `graphql:"operatorInterventionRules"`
    87  	}
    88  
    89  	graphqlRoles := []graphql.String{}
    90  	for _, role := range roles {
    91  		graphqlRoles = append(graphqlRoles, graphql.String(role))
    92  	}
    93  	variables := map[string]any{
    94  		"roles": graphqlRoles,
    95  	}
    96  
    97  	err := bffClient.Query(ctx, &query, variables)
    98  	if err != nil {
    99  		return nil, nil, fmt.Errorf("error calling Edge API: %w", err)
   100  	}
   101  	return query.OiRoleMappings, query.Rules, nil
   102  }
   103  
   104  // Add all rule configurations for each role
   105  func assembleRoleConfigurations(roleMappings []model.OiRoleMapping, rules []model.Rule) []RoleConfiguration {
   106  	var roleConfigs []RoleConfiguration
   107  	for _, roleMapping := range roleMappings {
   108  		// Add all rules matching a role's privileges
   109  		roleConfig := assembleRulesForRole(roleMapping, rules)
   110  		roleConfigs = append(roleConfigs, roleConfig)
   111  	}
   112  	return roleConfigs
   113  }
   114  
   115  // Add all rules matching a role's privileges
   116  func assembleRulesForRole(roleMapping model.OiRoleMapping, rules []model.Rule) RoleConfiguration {
   117  	roleConfig := RoleConfiguration{Role: roleMapping.Role.String()}
   118  	for _, priv := range roleMapping.Privileges {
   119  		rule := model.Rule{Privilege: priv}
   120  		// If there are any rules for a role's privilege, add that rule to roleConfig
   121  		if slices.ContainsFunc(rules, func(r model.Rule) bool {
   122  			rule.Commands = r.Commands
   123  			return *r.Privilege == *priv
   124  		}) {
   125  			roleConfig.Privileges = append(roleConfig.Privileges, rule)
   126  		}
   127  	}
   128  	return roleConfig
   129  }
   130  

View as plain text