myxce/src/frontend/xcecli/cmd/resources/list.go

359 lines
9.8 KiB
Go

package resources
import (
"fmt"
"strings"
"xcecli/common/output"
"xcecli/common/request"
"xcecli/config"
"xcecli/models"
logger "xcecli/config"
resource_filter "xcecli/filters"
"github.com/spf13/cobra"
"go.uber.org/zap"
)
type ResourcesDistQuerier struct {
configManager *config.ConfigManager
filter *resource_filter.ResourceDistFilter
fields string
distType string
jsonOutput bool
noHeader bool
verbose bool
wideFormat bool // wide format
}
func NewResourcesDistQuerier(configManager *config.ConfigManager) *ResourcesDistQuerier {
return &ResourcesDistQuerier{
configManager: configManager,
filter: &resource_filter.ResourceDistFilter{},
}
}
func (rq *ResourcesDistQuerier) ParseCmdArgs(cmd *cobra.Command, args []string) error {
// No additional processing needed, all parameters are bound in flags
if len(args) > 0 {
rq.filter.ResName = strings.Join(args, ",")
}
// Define mutual exclusions for verbose flag
if rq.verbose {
conflicts := make([]string, 0)
if rq.wideFormat {
conflicts = append(conflicts, "--wided (-w)")
}
if len(conflicts) > 0 {
return fmt.Errorf("flag --verbose (-l) cannot be used with: %s\n\n%s",
strings.Join(conflicts, ", "), cmd.UsageString())
}
}
return nil
}
// ResourcesDefQuerier handles querying resource definition information
type ResourcesDefQuerier struct {
configManager *config.ConfigManager
filter *resource_filter.ResourceDefFilter
fields string
jsonOutput bool
noHeader bool
verbose bool
wideFormat bool // wide format
}
func NewResourcesDefQuerier(configManager *config.ConfigManager) *ResourcesDefQuerier {
return &ResourcesDefQuerier{
configManager: configManager,
filter: &resource_filter.ResourceDefFilter{},
}
}
func (rq *ResourcesDefQuerier) ParseCmdArgs(cmd *cobra.Command, args []string) error {
// No additional processing needed, all parameters are bound in flags
if len(args) > 0 {
rq.filter.ResName = strings.Join(args, ",")
}
// Define mutual exclusions for verbose flag
if rq.verbose {
conflicts := make([]string, 0)
if rq.wideFormat {
conflicts = append(conflicts, "--wided (-w)")
}
if len(conflicts) > 0 {
return fmt.Errorf("flag --verbose (-l) cannot be used with: %s\n\n%s",
strings.Join(conflicts, ", "), cmd.UsageString())
}
}
return nil
}
// NewListResourcesDefCmd creates a command for listing resource definition information
func NewListResourcesDefCmd(configManager *config.ConfigManager) *cobra.Command {
resourcesDefQuerier := NewResourcesDefQuerier(configManager)
cmd := &cobra.Command{
Use: "list",
Short: "Query the resources definition info",
Long: `Query the resources definition info.
Example:
xce resources definition list # query the definition info`,
RunE: func(cmd *cobra.Command, args []string) error {
if err := resourcesDefQuerier.ParseCmdArgs(cmd, args); err != nil {
fmt.Println(strings.ToLower(err.Error()))
return nil
}
if err := resourcesDefQuerier.RunResourcesDefList(); err != nil {
fmt.Println(strings.ToLower(err.Error()))
return nil
}
return nil
},
}
// Add command line parameters
flags := cmd.Flags()
flags.BoolVarP(&resourcesDefQuerier.verbose, "verbose", "l", false, "show resource detail")
flags.BoolVarP(&resourcesDefQuerier.wideFormat, "wided", "w", false, "output in wide format")
flags.BoolVarP(&resourcesDefQuerier.jsonOutput, "json", "", false, "output in JSON format")
flags.BoolVarP(&resourcesDefQuerier.noHeader, "noheader", "n", false, "output no header")
return cmd
}
func (rq *ResourcesDefQuerier) RunResourcesDefList() error {
// Get configuration
// Get server information
serverInfo, _ := rq.configManager.GetServerInfo()
// create API client
apiClient := request.NewAPIClient(serverInfo.URL)
apiClient.SetRootCAs(serverInfo.CACert)
// Create query parameters
params := make(map[string]string)
// Get filter string
filterStr, err := rq.filter.HandleResourceDefFilter()
if err != nil {
errMsg := request.ExtractErrorMessage(err)
return fmt.Errorf("failed to get filter: [%s]", errMsg)
} else if filterStr != "" {
params["filter"] = filterStr
}
// Field mapping
fieldsMap := models.ResourceDefFieldsMap
if rq.verbose && rq.fields == "" {
for header := range fieldsMap {
rq.fields += header + ","
}
rq.fields = strings.TrimSuffix(rq.fields, ",")
}
// Process field selection
if rq.fields != "" {
rq.fields = request.CleanFields(rq.fields)
mappedFields, err := request.CheckAndMapFields(rq.fields, fieldsMap)
if err != nil {
return err
}
params["fields"] = strings.Join(mappedFields, ",")
}
// create page printer
pagePrinter := output.NewPagePrinter(output.DataTypeResourcesDef, output.WithFields(rq.fields),
output.WithFormatJson(rq.jsonOutput), output.WithNoHeader(rq.noHeader),
output.WithVerbose(rq.verbose), output.WithWideFormat(rq.wideFormat))
// Record if the first page has been processed
isFirstPage := true
var (
resp models.ResourceDefResponse
loopCount int
pageToken string
)
// Loop to get all pages of data
for {
if loopCount > 0 && pageToken == "" {
break
}
err = apiClient.GetRequestFromAPIServer(serverInfo.Token, pageToken, serverInfo.CACert, "/xce/v1/resources/definition", &resp, params)
if err != nil {
return err
}
if len(resp.Data.Rows) == 0 {
if isFirstPage {
fmt.Println("no resource definition found")
return nil
}
}
// Process the first page
if isFirstPage {
// Start printing process
pagePrinter.StartPrinting()
// Prepare for printing, calculate column width and table header, etc.
pagePrinter.PrepareForPrinting(&resp)
isFirstPage = false
}
// Print the current page
pagePrinter.PrintPage(&resp)
// Update page token and loop counter
pageToken = resp.Data.Page_token
loopCount++
}
// Finish printing
pagePrinter.Finish()
logger.Debug("resource definition response completed", zap.Int("pages", loopCount))
return nil
}
// NewListResourcesDistCmd creates a command for listing resource distribution information
func NewListResourcesDistCmd(configManager *config.ConfigManager) *cobra.Command {
resourcesDistQuerier := NewResourcesDistQuerier(configManager)
cmd := &cobra.Command{
Use: "list",
Short: "Query the resources distribution info",
Long: `Query the resources info, support static and dynamic type.
Example:
xce resources distribution list # query the distribution info`,
RunE: func(cmd *cobra.Command, args []string) error {
if err := resourcesDistQuerier.ParseCmdArgs(cmd, args); err != nil {
fmt.Println(strings.ToLower(err.Error()))
return nil
}
if err := resourcesDistQuerier.RunResourcesDistList(); err != nil {
fmt.Println(strings.ToLower(err.Error()))
return nil
}
return nil
},
}
// Add command line parameters
flags := cmd.Flags()
flags.StringVarP(&resourcesDistQuerier.distType, "type", "t", "", "static or dynamic")
flags.BoolVarP(&resourcesDistQuerier.wideFormat, "wided", "w", false, "output in wide format")
flags.BoolVarP(&resourcesDistQuerier.jsonOutput, "json", "", false, "output in JSON format")
flags.BoolVarP(&resourcesDistQuerier.noHeader, "noheader", "n", false, "output no header")
return cmd
}
func (rq *ResourcesDistQuerier) RunResourcesDistList() error {
// Get configuration
// Get server information
serverInfo, _ := rq.configManager.GetServerInfo()
// create API client
apiClient := request.NewAPIClient(serverInfo.URL)
apiClient.SetRootCAs(serverInfo.CACert)
// Create query parameters
params := make(map[string]string)
// Get filter string
filterStr, err := rq.filter.HandleResourceDistFilter()
if rq.distType != "" {
if rq.distType != "static" && rq.distType != "dynamic" {
return fmt.Errorf("invalid type, must be 'static' or 'dynamic'")
} else {
params["type"] = rq.distType
}
}
if err != nil {
errMsg := request.ExtractErrorMessage(err)
return fmt.Errorf("failed to get filter: [%s]", errMsg)
} else if filterStr != "" {
params["filter"] = filterStr
}
// Field mapping
fieldsMap := models.ResourceDistFieldsMap
if rq.verbose && rq.fields == "" {
for header := range fieldsMap {
rq.fields += header + ","
}
rq.fields = strings.TrimSuffix(rq.fields, ",")
}
// Process field selection
if rq.fields != "" {
rq.fields = request.CleanFields(rq.fields)
mappedFields, err := request.CheckAndMapFields(rq.fields, fieldsMap)
if err != nil {
return err
}
params["fields"] = strings.Join(mappedFields, ",")
}
// create page printer
pagePrinter := output.NewPagePrinter(output.DataTypeResourcesDist, output.WithFields(rq.fields),
output.WithFormatJson(rq.jsonOutput), output.WithNoHeader(rq.noHeader),
output.WithVerbose(rq.verbose), output.WithWideFormat(rq.wideFormat))
// Record if the first page has been processed
isFirstPage := true
var (
resp models.ResourceDistResponse
loopCount int
pageToken string
)
// Loop to get all pages of data
for {
if loopCount > 0 && pageToken == "" {
break
}
err = apiClient.GetRequestFromAPIServer(serverInfo.Token, pageToken, serverInfo.CACert, "/xce/v1/resources/distribution", &resp, params)
if err != nil {
return err
}
if len(resp.Data.Rows) == 0 {
if isFirstPage {
fmt.Println("no resource found")
return nil
}
}
// Process the first page
if isFirstPage {
// Start printing process
pagePrinter.StartPrinting()
// Prepare for printing, calculate column width and table header, etc.
pagePrinter.PrepareForPrinting(&resp)
isFirstPage = false
}
// Print the current page
pagePrinter.PrintPage(&resp)
// Update page token and loop counter
pageToken = resp.Data.Page_token
loopCount++
}
// Finish printing
pagePrinter.Finish()
logger.Debug("resource dirstribution response completed", zap.Int("pages", loopCount))
return nil
}