Files
Olares/cli/cmd/ctl/user/list.go

183 lines
4.9 KiB
Go

package user
import (
"context"
"encoding/json"
"fmt"
iamv1alpha2 "github.com/beclab/api/iam/v1alpha2"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/util/sets"
"log"
"slices"
"sort"
"strings"
)
var sortFuncs = map[string]func(users []iamv1alpha2.User, i, j int) bool{
"name": func(users []iamv1alpha2.User, i, j int) bool {
return strings.Compare(users[i].Name, users[j].Name) == -1
},
"role": func(users []iamv1alpha2.User, i, j int) bool {
return strings.Compare(users[i].Annotations[annotationKeyRole], users[j].Annotations[annotationKeyRole]) == -1
},
"create-time": func(users []iamv1alpha2.User, i, j int) bool {
return users[i].CreationTimestamp.Before(&users[j].CreationTimestamp)
},
"memory": func(users []iamv1alpha2.User, i, j int) bool {
iMemoryStr, ok := users[i].Annotations[annotationKeyMemoryLimit]
if !ok || iMemoryStr == "" {
return false
}
jMemoryStr, ok := users[j].Annotations[annotationKeyMemoryLimit]
if !ok || jMemoryStr == "" {
return true
}
iMemory, err := resource.ParseQuantity(iMemoryStr)
if err != nil {
fmt.Printf("Warning: invalid memory limit '%s' is set on user '%s'\n", iMemoryStr, users[i].Name)
return false
}
jMemory, err := resource.ParseQuantity(jMemoryStr)
if err != nil {
fmt.Printf("Warning: invalid memory limit '%s' is set on user '%s'\n", jMemoryStr, users[j].Name)
return true
}
return iMemory.Cmp(jMemory) == -1
},
"cpu": func(users []iamv1alpha2.User, i, j int) bool {
iCPUStr, ok := users[i].Annotations[annotationKeyCPULimit]
if !ok || iCPUStr == "" {
return false
}
jCPUStr, ok := users[j].Annotations[annotationKeyCPULimit]
if !ok || jCPUStr == "" {
return true
}
iCPU, err := resource.ParseQuantity(iCPUStr)
if err != nil {
fmt.Printf("Warning: invalid cpu limit '%s' is set on user '%s'", iCPUStr, users[i].Name)
return false
}
jCPU, err := resource.ParseQuantity(jCPUStr)
if err != nil {
fmt.Printf("Warning: invalid cpu limit '%s' is set on user '%s'", jCPUStr, users[j].Name)
return true
}
return iCPU.Cmp(jCPU) == -1
},
}
var sortAliases = map[string]sets.Set[string]{
"name": sets.New[string]("n", "N", "Name"),
"role": sets.New[string]("r", "R", "Role"),
"create-time": sets.New[string]("creation", "created", "created-at", "createdat", "createtime"),
"cpu": sets.New[string]("c", "C", "CPU"),
"memory": sets.New[string]("m", "M", "Memory"),
}
func getSortFunc(sortBy string) func(users []iamv1alpha2.User, i, j int) bool {
if f, ok := sortFuncs[sortBy]; ok {
return f
}
for origin, sortAlias := range sortAliases {
if sortAlias.Has(sortBy) {
return sortFuncs[origin]
}
}
return nil
}
type listUsersOptions struct {
kubeConfig string
output string
noHeaders bool
sortBys []string
reverse bool
}
func NewCmdListUsers() *cobra.Command {
o := &listUsersOptions{}
cmd := &cobra.Command{
Use: "list",
Aliases: []string{"ls", "l"},
Short: "list all users",
Run: func(cmd *cobra.Command, args []string) {
if err := o.Validate(); err != nil {
log.Fatal(err)
}
if err := o.Run(); err != nil {
log.Fatal(err)
}
},
}
o.AddFlags(cmd)
return cmd
}
func (o *listUsersOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().StringVar(&o.kubeConfig, "kubeconfig", "", "path to kubeconfig file")
cmd.Flags().StringVarP(&o.output, "output", "o", "table", "output format (table, json)")
cmd.Flags().BoolVar(&o.noHeaders, "no-headers", false, "disable headers")
cmd.Flags().StringSliceVar(&o.sortBys, "sort", []string{}, "sort output order by (name, role, create-time, memory, cpu)")
cmd.Flags().BoolVarP(&o.reverse, "reverse", "r", false, "reverse order")
}
func (o *listUsersOptions) Validate() error {
for _, sortBy := range o.sortBys {
f := getSortFunc(sortBy)
if f == nil {
return fmt.Errorf("unknown sort option: %s", sortBy)
}
}
return nil
}
func (o *listUsersOptions) Run() error {
ctx := context.Background()
userClient, err := newUserClientFromKubeConfig(o.kubeConfig)
if err != nil {
return err
}
var userList iamv1alpha2.UserList
err = userClient.List(ctx, &userList)
if err != nil {
return fmt.Errorf("failed to list users: %w", err)
}
for _, sortBy := range o.sortBys {
sort.SliceStable(userList.Items, func(i, j int) bool {
f := getSortFunc(sortBy)
if f == nil {
log.Fatalf("unkown sort option: %s", sortBy)
}
return f(userList.Items, i, j)
})
}
if o.reverse {
slices.Reverse(userList.Items)
}
users := make([]userInfo, 0, len(userList.Items))
for _, user := range userList.Items {
users = append(users, convertUserObjectToUserInfo(user))
}
if o.output == "json" {
jsonOutput, _ := json.MarshalIndent(users, "", " ")
fmt.Println(string(jsonOutput))
} else {
if !o.noHeaders {
printUserTableHeaders()
}
for _, user := range users {
printUserTableRow(user)
}
}
return nil
}