style(frontend): gofmt the apiserver and xcecli sources
Formatting only (gofmt -w on the 29 non-vendored, non-generated files gofmt -l reported); swag-generated apiserver/docs/docs.go left as is. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b57ce6d6a9
commit
3615c7c0fb
29 changed files with 1280 additions and 1285 deletions
|
|
@ -1,50 +1,50 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
"xcecli/common/request"
|
||||
"xcecli/config"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// NewListCmd create the list command
|
||||
func NewListCmd(configManager *config.ConfigManager) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "list",
|
||||
GroupID: "api",
|
||||
Short: "List the API Servers",
|
||||
Long: "List all the configured API Servers and the default API Server",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return runList(configManager)
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func runList(cm *config.ConfigManager) error {
|
||||
cfg, err := cm.GetConfig()
|
||||
if err != nil {
|
||||
errMsg := request.ExtractErrorMessage(err)
|
||||
return fmt.Errorf("failed to get the config: [%s]", errMsg)
|
||||
}
|
||||
|
||||
// use tabwriter to format the output
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
|
||||
fmt.Fprintln(w, "Default\tVersion\tURL")
|
||||
|
||||
for _, server := range cfg.APIServerInfo {
|
||||
isDefault := " "
|
||||
if server.Token == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "%s\t%s\n",
|
||||
isDefault,
|
||||
server.URL)
|
||||
}
|
||||
|
||||
return w.Flush()
|
||||
}
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
"xcecli/common/request"
|
||||
"xcecli/config"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// NewListCmd create the list command
|
||||
func NewListCmd(configManager *config.ConfigManager) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "list",
|
||||
GroupID: "api",
|
||||
Short: "List the API Servers",
|
||||
Long: "List all the configured API Servers and the default API Server",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return runList(configManager)
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func runList(cm *config.ConfigManager) error {
|
||||
cfg, err := cm.GetConfig()
|
||||
if err != nil {
|
||||
errMsg := request.ExtractErrorMessage(err)
|
||||
return fmt.Errorf("failed to get the config: [%s]", errMsg)
|
||||
}
|
||||
|
||||
// use tabwriter to format the output
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
|
||||
fmt.Fprintln(w, "Default\tVersion\tURL")
|
||||
|
||||
for _, server := range cfg.APIServerInfo {
|
||||
isDefault := " "
|
||||
if server.Token == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "%s\t%s\n",
|
||||
isDefault,
|
||||
server.URL)
|
||||
}
|
||||
|
||||
return w.Flush()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,38 +1,38 @@
|
|||
package jobs
|
||||
|
||||
import (
|
||||
"xcecli/config"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// NewJobsCmd creates a jobs query command
|
||||
func NewJobsCmd(configManager *config.ConfigManager) *cobra.Command {
|
||||
|
||||
// Create the parent jobs command
|
||||
cmd := &cobra.Command{
|
||||
Use: "jobs",
|
||||
GroupID: "query",
|
||||
Short: "Manage jobs",
|
||||
Long: `Manage jobs in the system.
|
||||
Use 'xce jobs list' to query jobs information.
|
||||
Use 'xce jobs <action>' to submit/kill/stop/resume/checkpoint/restart jobs.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// Display help when no subcommand is specified
|
||||
cmd.Help()
|
||||
},
|
||||
}
|
||||
cmd.AddCommand(NewListJobsCmd(configManager))
|
||||
// Add submit command to jobs command
|
||||
cmd.AddCommand(NewSubmitJobsCmd(configManager))
|
||||
// Add job control sub-commands to jobs command
|
||||
cmd.AddCommand(NewKillJobsCmd(configManager))
|
||||
cmd.AddCommand(NewStopJobsCmd(configManager))
|
||||
cmd.AddCommand(NewResumeJobsCmd(configManager))
|
||||
cmd.AddCommand(NewCheckPointJobsCmd(configManager))
|
||||
cmd.AddCommand(NewRestartJobsCmd(configManager))
|
||||
// Add peek command to view job output
|
||||
cmd.AddCommand(NewPeekJobsCmd(configManager))
|
||||
|
||||
return cmd
|
||||
}
|
||||
package jobs
|
||||
|
||||
import (
|
||||
"xcecli/config"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// NewJobsCmd creates a jobs query command
|
||||
func NewJobsCmd(configManager *config.ConfigManager) *cobra.Command {
|
||||
|
||||
// Create the parent jobs command
|
||||
cmd := &cobra.Command{
|
||||
Use: "jobs",
|
||||
GroupID: "query",
|
||||
Short: "Manage jobs",
|
||||
Long: `Manage jobs in the system.
|
||||
Use 'xce jobs list' to query jobs information.
|
||||
Use 'xce jobs <action>' to submit/kill/stop/resume/checkpoint/restart jobs.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// Display help when no subcommand is specified
|
||||
cmd.Help()
|
||||
},
|
||||
}
|
||||
cmd.AddCommand(NewListJobsCmd(configManager))
|
||||
// Add submit command to jobs command
|
||||
cmd.AddCommand(NewSubmitJobsCmd(configManager))
|
||||
// Add job control sub-commands to jobs command
|
||||
cmd.AddCommand(NewKillJobsCmd(configManager))
|
||||
cmd.AddCommand(NewStopJobsCmd(configManager))
|
||||
cmd.AddCommand(NewResumeJobsCmd(configManager))
|
||||
cmd.AddCommand(NewCheckPointJobsCmd(configManager))
|
||||
cmd.AddCommand(NewRestartJobsCmd(configManager))
|
||||
// Add peek command to view job output
|
||||
cmd.AddCommand(NewPeekJobsCmd(configManager))
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,111 +1,111 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2025 xce
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"xcecli/config"
|
||||
logger "xcecli/config"
|
||||
cmd "xcecli/router"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// GitCommit and BuildTime are injected at link time via
|
||||
// `-ldflags "-X main.GitCommit=... -X main.BuildTime=..."` (see
|
||||
// src/tools/go_build). The
|
||||
// "unknown" defaults matter: a bare `go build`/`go run` that bypasses that
|
||||
// ldflags injection must still report "unknown" rather than an empty
|
||||
// string, matching this feature's unknown-fallback requirement (see
|
||||
// xce_version_field() in src/lib/utils.c for the equivalent C-side
|
||||
// convention).
|
||||
//
|
||||
// DirtyFingerprint is injected the same way (`-X main.DirtyFingerprint=...`,
|
||||
// see src/tools/go_build task 4.1) but its default is a deliberately EMPTY
|
||||
// string, not "unknown" -- matching dirty_fingerprint's convention
|
||||
// everywhere else in the dirty-content-fingerprint feature (empty means
|
||||
// "no fingerprint available", distinct from GitCommit/BuildTime's
|
||||
// "unknown" sentinel for "not injected at all").
|
||||
var (
|
||||
GitCommit = "unknown"
|
||||
BuildTime = "unknown"
|
||||
DirtyFingerprint = ""
|
||||
)
|
||||
|
||||
// composeVersionDisplay applies the dirty-content-fingerprint feature's
|
||||
// strip-and-append rule to gitCommit: if dirtyFingerprint is non-empty, a
|
||||
// trailing "-dirty" suffix on gitCommit is stripped (an anchored suffix
|
||||
// check via strings.TrimSuffix, not a blind substring replace) and
|
||||
// "-<dirtyFingerprint>" is appended in its place; otherwise gitCommit is
|
||||
// returned exactly as-is (already correctly showing "-dirty" or not, per
|
||||
// the original build-time-versioning feature). Mirrors
|
||||
// xce_compose_version_ex() in src/lib/utils.c (task 3.1) and apiserver's
|
||||
// own composeVersionDisplay (task 4.4), the equivalent implementations
|
||||
// already approved for the other version-displaying components.
|
||||
//
|
||||
// xcecli has no startup log to protect (already established as out of
|
||||
// scope by the original build-time-versioning feature, see that feature's
|
||||
// own task 4.5 commit fb09afe), so this result feeds the ONLY consumption
|
||||
// point below: the version string passed into router.Execute(cm, version),
|
||||
// which sets rootCmd.Version for Cobra's native --version/-v handling.
|
||||
func composeVersionDisplay(gitCommit, dirtyFingerprint string) string {
|
||||
if dirtyFingerprint == "" {
|
||||
return gitCommit
|
||||
}
|
||||
return strings.TrimSuffix(gitCommit, "-dirty") + "-" + dirtyFingerprint
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// init logger
|
||||
if err := logger.InitLogger(); err != nil {
|
||||
fmt.Println(strings.ToLower(err.Error()))
|
||||
os.Exit(1)
|
||||
}
|
||||
logger.Info("********** Initialize Logger on client side done!")
|
||||
|
||||
// initialize the config manager
|
||||
configManager, err := config.NewConfigManager()
|
||||
if err != nil {
|
||||
fmt.Println("failed to initialize the config manager", zap.Error(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// ensure the config manager is initialized correctly
|
||||
if configManager == nil {
|
||||
fmt.Println("failed to initialize the config manager")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// execute the command
|
||||
version := fmt.Sprintf("%s built %s", composeVersionDisplay(GitCommit, DirtyFingerprint), BuildTime)
|
||||
if err := cmd.Execute(configManager, version); err != nil {
|
||||
fmt.Println(strings.ToLower(err.Error()))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2025 xce
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"xcecli/config"
|
||||
logger "xcecli/config"
|
||||
cmd "xcecli/router"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// GitCommit and BuildTime are injected at link time via
|
||||
// `-ldflags "-X main.GitCommit=... -X main.BuildTime=..."` (see
|
||||
// src/tools/go_build). The
|
||||
// "unknown" defaults matter: a bare `go build`/`go run` that bypasses that
|
||||
// ldflags injection must still report "unknown" rather than an empty
|
||||
// string, matching this feature's unknown-fallback requirement (see
|
||||
// xce_version_field() in src/lib/utils.c for the equivalent C-side
|
||||
// convention).
|
||||
//
|
||||
// DirtyFingerprint is injected the same way (`-X main.DirtyFingerprint=...`,
|
||||
// see src/tools/go_build task 4.1) but its default is a deliberately EMPTY
|
||||
// string, not "unknown" -- matching dirty_fingerprint's convention
|
||||
// everywhere else in the dirty-content-fingerprint feature (empty means
|
||||
// "no fingerprint available", distinct from GitCommit/BuildTime's
|
||||
// "unknown" sentinel for "not injected at all").
|
||||
var (
|
||||
GitCommit = "unknown"
|
||||
BuildTime = "unknown"
|
||||
DirtyFingerprint = ""
|
||||
)
|
||||
|
||||
// composeVersionDisplay applies the dirty-content-fingerprint feature's
|
||||
// strip-and-append rule to gitCommit: if dirtyFingerprint is non-empty, a
|
||||
// trailing "-dirty" suffix on gitCommit is stripped (an anchored suffix
|
||||
// check via strings.TrimSuffix, not a blind substring replace) and
|
||||
// "-<dirtyFingerprint>" is appended in its place; otherwise gitCommit is
|
||||
// returned exactly as-is (already correctly showing "-dirty" or not, per
|
||||
// the original build-time-versioning feature). Mirrors
|
||||
// xce_compose_version_ex() in src/lib/utils.c (task 3.1) and apiserver's
|
||||
// own composeVersionDisplay (task 4.4), the equivalent implementations
|
||||
// already approved for the other version-displaying components.
|
||||
//
|
||||
// xcecli has no startup log to protect (already established as out of
|
||||
// scope by the original build-time-versioning feature, see that feature's
|
||||
// own task 4.5 commit fb09afe), so this result feeds the ONLY consumption
|
||||
// point below: the version string passed into router.Execute(cm, version),
|
||||
// which sets rootCmd.Version for Cobra's native --version/-v handling.
|
||||
func composeVersionDisplay(gitCommit, dirtyFingerprint string) string {
|
||||
if dirtyFingerprint == "" {
|
||||
return gitCommit
|
||||
}
|
||||
return strings.TrimSuffix(gitCommit, "-dirty") + "-" + dirtyFingerprint
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// init logger
|
||||
if err := logger.InitLogger(); err != nil {
|
||||
fmt.Println(strings.ToLower(err.Error()))
|
||||
os.Exit(1)
|
||||
}
|
||||
logger.Info("********** Initialize Logger on client side done!")
|
||||
|
||||
// initialize the config manager
|
||||
configManager, err := config.NewConfigManager()
|
||||
if err != nil {
|
||||
fmt.Println("failed to initialize the config manager", zap.Error(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// ensure the config manager is initialized correctly
|
||||
if configManager == nil {
|
||||
fmt.Println("failed to initialize the config manager")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// execute the command
|
||||
version := fmt.Sprintf("%s built %s", composeVersionDisplay(GitCommit, DirtyFingerprint), BuildTime)
|
||||
if err := cmd.Execute(configManager, version); err != nil {
|
||||
fmt.Println(strings.ToLower(err.Error()))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ Use 'xce resources definition list' to query resources definition information.`,
|
|||
distributionCmd := &cobra.Command{
|
||||
Use: "distribution",
|
||||
Short: "Manage resource distribution",
|
||||
Long: `Manage resource distribution information.
|
||||
Long: `Manage resource distribution information.
|
||||
Use 'xce resources distribution list' to query resources distribution information.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// Display help when no subcommand is specified
|
||||
|
|
@ -39,7 +39,7 @@ Use 'xce resources distribution list' to query resources distribution informatio
|
|||
definitionCmd := &cobra.Command{
|
||||
Use: "definition",
|
||||
Short: "Manage resource definition",
|
||||
Long: `Manage resource definition information.
|
||||
Long: `Manage resource definition information.
|
||||
Use 'xce resources definition list' to query resources definition information.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// Display help when no subcommand is specified
|
||||
|
|
|
|||
|
|
@ -1,45 +1,45 @@
|
|||
package output
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
"xcecli/models"
|
||||
)
|
||||
|
||||
type Output struct {
|
||||
fields string
|
||||
formatJson bool
|
||||
noheader bool
|
||||
verbose bool
|
||||
wideFormat bool
|
||||
jobStatusFilter []string
|
||||
}
|
||||
|
||||
func NewOutput(fields string, formatJson bool, noheader bool) *Output {
|
||||
return &Output{fields: fields, formatJson: formatJson, noheader: noheader}
|
||||
}
|
||||
|
||||
func (o *Output) SetVerbose(verbose bool) {
|
||||
o.verbose = verbose
|
||||
}
|
||||
|
||||
func (o *Output) SetNoHeader(noheader bool) {
|
||||
o.noheader = noheader
|
||||
}
|
||||
|
||||
func (o *Output) SetWideFormat(wideFormat bool) {
|
||||
o.wideFormat = wideFormat
|
||||
}
|
||||
|
||||
func (o *Output) ClusterPrintData(cluster *models.ClusterInfo) {
|
||||
printClustersVerboseOutput(cluster)
|
||||
}
|
||||
|
||||
func printClustersVerboseOutput(clusters *models.ClusterInfo) {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
|
||||
defer w.Flush()
|
||||
fmt.Fprintf(w, "XCE Standard Cluster\t%s\t%s\n", clusters.Version, "Jul 08 2025")
|
||||
fmt.Fprintf(w, "My cluster name: <%s>\n", clusters.ClusterName)
|
||||
fmt.Fprintf(w, "The cluster status: <%s>\n", clusters.Status)
|
||||
}
|
||||
package output
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
"xcecli/models"
|
||||
)
|
||||
|
||||
type Output struct {
|
||||
fields string
|
||||
formatJson bool
|
||||
noheader bool
|
||||
verbose bool
|
||||
wideFormat bool
|
||||
jobStatusFilter []string
|
||||
}
|
||||
|
||||
func NewOutput(fields string, formatJson bool, noheader bool) *Output {
|
||||
return &Output{fields: fields, formatJson: formatJson, noheader: noheader}
|
||||
}
|
||||
|
||||
func (o *Output) SetVerbose(verbose bool) {
|
||||
o.verbose = verbose
|
||||
}
|
||||
|
||||
func (o *Output) SetNoHeader(noheader bool) {
|
||||
o.noheader = noheader
|
||||
}
|
||||
|
||||
func (o *Output) SetWideFormat(wideFormat bool) {
|
||||
o.wideFormat = wideFormat
|
||||
}
|
||||
|
||||
func (o *Output) ClusterPrintData(cluster *models.ClusterInfo) {
|
||||
printClustersVerboseOutput(cluster)
|
||||
}
|
||||
|
||||
func printClustersVerboseOutput(clusters *models.ClusterInfo) {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
|
||||
defer w.Flush()
|
||||
fmt.Fprintf(w, "XCE Standard Cluster\t%s\t%s\n", clusters.Version, "Jul 08 2025")
|
||||
fmt.Fprintf(w, "My cluster name: <%s>\n", clusters.ClusterName)
|
||||
fmt.Fprintf(w, "The cluster status: <%s>\n", clusters.Status)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,189 +1,189 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
Log *zap.Logger
|
||||
)
|
||||
|
||||
const (
|
||||
defaultLoggerConfigFile = "logger.yaml"
|
||||
defaultLoggerOutputFile = "xcecli_out.log"
|
||||
)
|
||||
|
||||
type LoggerConfig struct {
|
||||
Logging struct {
|
||||
Level string `yaml:"level"`
|
||||
Encoding string `yaml:"encoding"`
|
||||
OutputPath string `yaml:"outputPath"`
|
||||
File struct {
|
||||
MaxSize int `yaml:"maxSize"`
|
||||
MaxBackups int `yaml:"maxBackups"`
|
||||
MaxAge int `yaml:"maxAge"`
|
||||
Compress bool `yaml:"compress"`
|
||||
} `yaml:"file"`
|
||||
EncoderConfig struct {
|
||||
MessageKey string `yaml:"messageKey"`
|
||||
LevelKey string `yaml:"levelKey"`
|
||||
TimeKey string `yaml:"timeKey"`
|
||||
NameKey string `yaml:"nameKey"`
|
||||
CallerKey string `yaml:"callerKey"`
|
||||
FunctionKey string `yaml:"functionKey"`
|
||||
StacktraceKey string `yaml:"stacktraceKey"`
|
||||
EncodeTime string `yaml:"timeEncoder"`
|
||||
EncodeLevel string `yaml:"levelEncoder"`
|
||||
} `yaml:"encoderConfig"`
|
||||
} `yaml:"logging"`
|
||||
}
|
||||
|
||||
func InitLogger() error {
|
||||
var err error
|
||||
err = loadLoggerConfig()
|
||||
return err
|
||||
}
|
||||
|
||||
func loadLoggerConfig() error {
|
||||
usr, err := user.Current()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get the user info: [%v]", err)
|
||||
}
|
||||
// read logger configuration file
|
||||
configPath := filepath.Join(usr.HomeDir, ".xce")
|
||||
|
||||
var loggerConfig LoggerConfig
|
||||
v := viper.New()
|
||||
|
||||
v.SetDefault("logging.level", "info") // debug, info, warn, error, fatal
|
||||
v.SetDefault("logging.encoding", "console") // console, json
|
||||
v.SetDefault("logging.outputPath", defaultLoggerOutputFile) // xcecli_out.log
|
||||
v.SetDefault("logging.file.maxSize", 100) // 100MB
|
||||
v.SetDefault("logging.file.maxBackups", 10) // 10
|
||||
v.SetDefault("logging.file.maxAge", 14) // 14 days
|
||||
v.SetDefault("logging.file.compress", true) // true
|
||||
v.SetDefault("logging.encoderConfig.messageKey", "message") // message
|
||||
v.SetDefault("logging.encoderConfig.levelKey", "level") // level
|
||||
v.SetDefault("logging.encoderConfig.timeKey", "timestamp") // timestamp
|
||||
v.SetDefault("logging.encoderConfig.nameKey", "logger") // logger
|
||||
v.SetDefault("logging.encoderConfig.callerKey", "caller") // caller
|
||||
v.SetDefault("logging.encoderConfig.functionKey", "func") // func
|
||||
v.SetDefault("logging.encoderConfig.stacktraceKey", "stacktrace") // stacktrace
|
||||
v.SetDefault("logging.encoderConfig.timeEncoder", "ISO8601") // ISO8601
|
||||
v.SetDefault("logging.encoderConfig.levelEncoder", "capital") // capital
|
||||
v.SetConfigName(defaultLoggerConfigFile)
|
||||
v.SetConfigType("yaml")
|
||||
v.AddConfigPath(configPath)
|
||||
// yamlContent := `# log level: debug, info, warn, error, fatal
|
||||
// # debug: detailed log
|
||||
// # info: normal log
|
||||
// # warn: warning log
|
||||
// # error: error log
|
||||
// # fatal: fatal log` + v.GetString("logging.level")
|
||||
|
||||
err = v.ReadInConfig()
|
||||
if err != nil {
|
||||
os.MkdirAll(configPath, 0755)
|
||||
|
||||
if err = v.WriteConfigAs(filepath.Join(configPath, "logger.yaml")); err != nil {
|
||||
fmt.Printf("failed to write default logger configuration file: [%v]", err)
|
||||
}
|
||||
}
|
||||
err = v.Unmarshal(&loggerConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to decode into struct: [%v]", err)
|
||||
}
|
||||
// Handle both formats for OutputPath
|
||||
if !filepath.IsAbs(loggerConfig.Logging.OutputPath) {
|
||||
if loggerConfig.Logging.OutputPath == "" {
|
||||
loggerConfig.Logging.OutputPath = defaultLoggerOutputFile
|
||||
}
|
||||
// If OutputPath is relative, prepend the logs directory
|
||||
loggerConfig.Logging.OutputPath = filepath.Join(configPath, "logs", loggerConfig.Logging.OutputPath)
|
||||
}
|
||||
logDir := filepath.Dir(loggerConfig.Logging.OutputPath) // Extract the directory
|
||||
// Create the directory if it does not exist
|
||||
if err = os.MkdirAll(logDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create client logs directory: %w", err)
|
||||
}
|
||||
Log, err = createLogger(loggerConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create client logger: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func createLogger(loggerConfig LoggerConfig) (*zap.Logger, error) {
|
||||
configLevel, err := zapcore.ParseLevel(loggerConfig.Logging.Level)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// create log file and set the permission
|
||||
file, err := os.OpenFile(loggerConfig.Logging.OutputPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
file.Close()
|
||||
|
||||
// configure lumberjack for log rotation
|
||||
logWriter := &lumberjack.Logger{
|
||||
Filename: loggerConfig.Logging.OutputPath,
|
||||
MaxSize: loggerConfig.Logging.File.MaxSize,
|
||||
MaxBackups: loggerConfig.Logging.File.MaxBackups,
|
||||
MaxAge: loggerConfig.Logging.File.MaxAge,
|
||||
Compress: loggerConfig.Logging.File.Compress,
|
||||
}
|
||||
|
||||
// Create cores for different log levels
|
||||
core := zapcore.NewCore(
|
||||
zapcore.NewConsoleEncoder(zapcore.EncoderConfig{
|
||||
MessageKey: loggerConfig.Logging.EncoderConfig.MessageKey,
|
||||
LevelKey: loggerConfig.Logging.EncoderConfig.LevelKey,
|
||||
TimeKey: loggerConfig.Logging.EncoderConfig.TimeKey,
|
||||
NameKey: loggerConfig.Logging.EncoderConfig.NameKey,
|
||||
CallerKey: loggerConfig.Logging.EncoderConfig.CallerKey,
|
||||
StacktraceKey: "", // disable stacktrace
|
||||
EncodeTime: zapcore.ISO8601TimeEncoder,
|
||||
EncodeLevel: zapcore.CapitalLevelEncoder,
|
||||
EncodeCaller: zapcore.ShortCallerEncoder,
|
||||
ConsoleSeparator: " ",
|
||||
}),
|
||||
zapcore.AddSync(logWriter),
|
||||
configLevel,
|
||||
)
|
||||
logger := zap.New(core,
|
||||
zap.AddCaller(), // caller info
|
||||
zap.AddStacktrace(zap.ErrorLevel), // show error stacktrace
|
||||
zap.AddCallerSkip(1), // skip one layer of caller
|
||||
)
|
||||
return logger, nil
|
||||
|
||||
}
|
||||
|
||||
func Info(msg string, fields ...zap.Field) {
|
||||
Log.WithOptions(zap.WithCaller(false)).Info(msg, fields...)
|
||||
}
|
||||
func Error(msg string, fields ...zap.Field) {
|
||||
Log.WithOptions(zap.WithCaller(false)).Error(msg, fields...)
|
||||
}
|
||||
|
||||
func Warn(msg string, fields ...zap.Field) {
|
||||
Log.WithOptions(zap.WithCaller(false)).Warn(msg, fields...)
|
||||
}
|
||||
|
||||
func Debug(msg string, fields ...zap.Field) {
|
||||
Log.WithOptions(zap.WithCaller(true)).Debug(msg, fields...)
|
||||
}
|
||||
|
||||
func Fatal(msg string, fields ...zap.Field) {
|
||||
Log.WithOptions(zap.WithCaller(false)).Fatal(msg, fields...)
|
||||
}
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
Log *zap.Logger
|
||||
)
|
||||
|
||||
const (
|
||||
defaultLoggerConfigFile = "logger.yaml"
|
||||
defaultLoggerOutputFile = "xcecli_out.log"
|
||||
)
|
||||
|
||||
type LoggerConfig struct {
|
||||
Logging struct {
|
||||
Level string `yaml:"level"`
|
||||
Encoding string `yaml:"encoding"`
|
||||
OutputPath string `yaml:"outputPath"`
|
||||
File struct {
|
||||
MaxSize int `yaml:"maxSize"`
|
||||
MaxBackups int `yaml:"maxBackups"`
|
||||
MaxAge int `yaml:"maxAge"`
|
||||
Compress bool `yaml:"compress"`
|
||||
} `yaml:"file"`
|
||||
EncoderConfig struct {
|
||||
MessageKey string `yaml:"messageKey"`
|
||||
LevelKey string `yaml:"levelKey"`
|
||||
TimeKey string `yaml:"timeKey"`
|
||||
NameKey string `yaml:"nameKey"`
|
||||
CallerKey string `yaml:"callerKey"`
|
||||
FunctionKey string `yaml:"functionKey"`
|
||||
StacktraceKey string `yaml:"stacktraceKey"`
|
||||
EncodeTime string `yaml:"timeEncoder"`
|
||||
EncodeLevel string `yaml:"levelEncoder"`
|
||||
} `yaml:"encoderConfig"`
|
||||
} `yaml:"logging"`
|
||||
}
|
||||
|
||||
func InitLogger() error {
|
||||
var err error
|
||||
err = loadLoggerConfig()
|
||||
return err
|
||||
}
|
||||
|
||||
func loadLoggerConfig() error {
|
||||
usr, err := user.Current()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get the user info: [%v]", err)
|
||||
}
|
||||
// read logger configuration file
|
||||
configPath := filepath.Join(usr.HomeDir, ".xce")
|
||||
|
||||
var loggerConfig LoggerConfig
|
||||
v := viper.New()
|
||||
|
||||
v.SetDefault("logging.level", "info") // debug, info, warn, error, fatal
|
||||
v.SetDefault("logging.encoding", "console") // console, json
|
||||
v.SetDefault("logging.outputPath", defaultLoggerOutputFile) // xcecli_out.log
|
||||
v.SetDefault("logging.file.maxSize", 100) // 100MB
|
||||
v.SetDefault("logging.file.maxBackups", 10) // 10
|
||||
v.SetDefault("logging.file.maxAge", 14) // 14 days
|
||||
v.SetDefault("logging.file.compress", true) // true
|
||||
v.SetDefault("logging.encoderConfig.messageKey", "message") // message
|
||||
v.SetDefault("logging.encoderConfig.levelKey", "level") // level
|
||||
v.SetDefault("logging.encoderConfig.timeKey", "timestamp") // timestamp
|
||||
v.SetDefault("logging.encoderConfig.nameKey", "logger") // logger
|
||||
v.SetDefault("logging.encoderConfig.callerKey", "caller") // caller
|
||||
v.SetDefault("logging.encoderConfig.functionKey", "func") // func
|
||||
v.SetDefault("logging.encoderConfig.stacktraceKey", "stacktrace") // stacktrace
|
||||
v.SetDefault("logging.encoderConfig.timeEncoder", "ISO8601") // ISO8601
|
||||
v.SetDefault("logging.encoderConfig.levelEncoder", "capital") // capital
|
||||
v.SetConfigName(defaultLoggerConfigFile)
|
||||
v.SetConfigType("yaml")
|
||||
v.AddConfigPath(configPath)
|
||||
// yamlContent := `# log level: debug, info, warn, error, fatal
|
||||
// # debug: detailed log
|
||||
// # info: normal log
|
||||
// # warn: warning log
|
||||
// # error: error log
|
||||
// # fatal: fatal log` + v.GetString("logging.level")
|
||||
|
||||
err = v.ReadInConfig()
|
||||
if err != nil {
|
||||
os.MkdirAll(configPath, 0755)
|
||||
|
||||
if err = v.WriteConfigAs(filepath.Join(configPath, "logger.yaml")); err != nil {
|
||||
fmt.Printf("failed to write default logger configuration file: [%v]", err)
|
||||
}
|
||||
}
|
||||
err = v.Unmarshal(&loggerConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to decode into struct: [%v]", err)
|
||||
}
|
||||
// Handle both formats for OutputPath
|
||||
if !filepath.IsAbs(loggerConfig.Logging.OutputPath) {
|
||||
if loggerConfig.Logging.OutputPath == "" {
|
||||
loggerConfig.Logging.OutputPath = defaultLoggerOutputFile
|
||||
}
|
||||
// If OutputPath is relative, prepend the logs directory
|
||||
loggerConfig.Logging.OutputPath = filepath.Join(configPath, "logs", loggerConfig.Logging.OutputPath)
|
||||
}
|
||||
logDir := filepath.Dir(loggerConfig.Logging.OutputPath) // Extract the directory
|
||||
// Create the directory if it does not exist
|
||||
if err = os.MkdirAll(logDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create client logs directory: %w", err)
|
||||
}
|
||||
Log, err = createLogger(loggerConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create client logger: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func createLogger(loggerConfig LoggerConfig) (*zap.Logger, error) {
|
||||
configLevel, err := zapcore.ParseLevel(loggerConfig.Logging.Level)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// create log file and set the permission
|
||||
file, err := os.OpenFile(loggerConfig.Logging.OutputPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
file.Close()
|
||||
|
||||
// configure lumberjack for log rotation
|
||||
logWriter := &lumberjack.Logger{
|
||||
Filename: loggerConfig.Logging.OutputPath,
|
||||
MaxSize: loggerConfig.Logging.File.MaxSize,
|
||||
MaxBackups: loggerConfig.Logging.File.MaxBackups,
|
||||
MaxAge: loggerConfig.Logging.File.MaxAge,
|
||||
Compress: loggerConfig.Logging.File.Compress,
|
||||
}
|
||||
|
||||
// Create cores for different log levels
|
||||
core := zapcore.NewCore(
|
||||
zapcore.NewConsoleEncoder(zapcore.EncoderConfig{
|
||||
MessageKey: loggerConfig.Logging.EncoderConfig.MessageKey,
|
||||
LevelKey: loggerConfig.Logging.EncoderConfig.LevelKey,
|
||||
TimeKey: loggerConfig.Logging.EncoderConfig.TimeKey,
|
||||
NameKey: loggerConfig.Logging.EncoderConfig.NameKey,
|
||||
CallerKey: loggerConfig.Logging.EncoderConfig.CallerKey,
|
||||
StacktraceKey: "", // disable stacktrace
|
||||
EncodeTime: zapcore.ISO8601TimeEncoder,
|
||||
EncodeLevel: zapcore.CapitalLevelEncoder,
|
||||
EncodeCaller: zapcore.ShortCallerEncoder,
|
||||
ConsoleSeparator: " ",
|
||||
}),
|
||||
zapcore.AddSync(logWriter),
|
||||
configLevel,
|
||||
)
|
||||
logger := zap.New(core,
|
||||
zap.AddCaller(), // caller info
|
||||
zap.AddStacktrace(zap.ErrorLevel), // show error stacktrace
|
||||
zap.AddCallerSkip(1), // skip one layer of caller
|
||||
)
|
||||
return logger, nil
|
||||
|
||||
}
|
||||
|
||||
func Info(msg string, fields ...zap.Field) {
|
||||
Log.WithOptions(zap.WithCaller(false)).Info(msg, fields...)
|
||||
}
|
||||
func Error(msg string, fields ...zap.Field) {
|
||||
Log.WithOptions(zap.WithCaller(false)).Error(msg, fields...)
|
||||
}
|
||||
|
||||
func Warn(msg string, fields ...zap.Field) {
|
||||
Log.WithOptions(zap.WithCaller(false)).Warn(msg, fields...)
|
||||
}
|
||||
|
||||
func Debug(msg string, fields ...zap.Field) {
|
||||
Log.WithOptions(zap.WithCaller(true)).Debug(msg, fields...)
|
||||
}
|
||||
|
||||
func Fatal(msg string, fields ...zap.Field) {
|
||||
Log.WithOptions(zap.WithCaller(false)).Fatal(msg, fields...)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,92 +1,92 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/xeipuuv/gojsonschema"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// validate the specified yaml file format whether is correct
|
||||
// return the content of the yaml file if the format is correct
|
||||
// return error if the format is incorrect
|
||||
func ValidateYamlFormat(yamlFilePath string) ([]byte, error) {
|
||||
// find the file path
|
||||
yamlFilePath, err := filepath.Abs(yamlFilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// get scheme file path, suppose schema file is in the same directory as yaml file
|
||||
yamlFileRootPath := filepath.Dir(yamlFilePath)
|
||||
realFileName := filepath.Base(yamlFilePath)
|
||||
preRealFileName := realFileName[:len(realFileName)-5] + "_schema.json"
|
||||
schemaFilePath := filepath.Join(yamlFileRootPath, "schema", preRealFileName)
|
||||
// checking if the schema file exists
|
||||
if _, err := os.Stat(schemaFilePath); os.IsNotExist(err) {
|
||||
err = fmt.Errorf("schema file %s does not exist ", schemaFilePath)
|
||||
return nil, err
|
||||
}
|
||||
data, err := ValidateYAML(yamlFilePath, schemaFilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// ValidateYAML validates the YAML content against the provided JSON schema
|
||||
func ValidateYAML(yamlPath, schemaPath string) ([]byte, error) {
|
||||
// schemaLoader is a absolute file path
|
||||
schemaLoader := gojsonschema.NewReferenceLoader("file:///" + filepath.ToSlash(schemaPath))
|
||||
// get yaml file content by reading the file
|
||||
data, err := os.ReadFile(yamlPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// get the yaml file into object
|
||||
var raw interface{}
|
||||
err = yaml.Unmarshal(data, &raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// transform into map[string]interface{}
|
||||
yamlContent := convertYAML(raw)
|
||||
|
||||
// create documentLoader
|
||||
documentLoader := gojsonschema.NewGoLoader(yamlContent)
|
||||
result, err := gojsonschema.Validate(schemaLoader, documentLoader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !result.Valid() {
|
||||
var errorMessages string
|
||||
for _, desc := range result.Errors() {
|
||||
errorMessages += fmt.Sprintf("- %s\n", desc)
|
||||
}
|
||||
err = errors.New(errorMessages)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// return the yaml content
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// convertYAML recursively converts map[interface{}]interface{} to map[string]interface{}
|
||||
func convertYAML(i interface{}) interface{} {
|
||||
switch x := i.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
m2 := make(map[string]interface{})
|
||||
for k, v := range x {
|
||||
m2[fmt.Sprintf("%v", k)] = convertYAML(v)
|
||||
}
|
||||
return m2
|
||||
case []interface{}:
|
||||
for idx, v := range x {
|
||||
x[idx] = convertYAML(v)
|
||||
}
|
||||
}
|
||||
return i
|
||||
}
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/xeipuuv/gojsonschema"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// validate the specified yaml file format whether is correct
|
||||
// return the content of the yaml file if the format is correct
|
||||
// return error if the format is incorrect
|
||||
func ValidateYamlFormat(yamlFilePath string) ([]byte, error) {
|
||||
// find the file path
|
||||
yamlFilePath, err := filepath.Abs(yamlFilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// get scheme file path, suppose schema file is in the same directory as yaml file
|
||||
yamlFileRootPath := filepath.Dir(yamlFilePath)
|
||||
realFileName := filepath.Base(yamlFilePath)
|
||||
preRealFileName := realFileName[:len(realFileName)-5] + "_schema.json"
|
||||
schemaFilePath := filepath.Join(yamlFileRootPath, "schema", preRealFileName)
|
||||
// checking if the schema file exists
|
||||
if _, err := os.Stat(schemaFilePath); os.IsNotExist(err) {
|
||||
err = fmt.Errorf("schema file %s does not exist ", schemaFilePath)
|
||||
return nil, err
|
||||
}
|
||||
data, err := ValidateYAML(yamlFilePath, schemaFilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// ValidateYAML validates the YAML content against the provided JSON schema
|
||||
func ValidateYAML(yamlPath, schemaPath string) ([]byte, error) {
|
||||
// schemaLoader is a absolute file path
|
||||
schemaLoader := gojsonschema.NewReferenceLoader("file:///" + filepath.ToSlash(schemaPath))
|
||||
// get yaml file content by reading the file
|
||||
data, err := os.ReadFile(yamlPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// get the yaml file into object
|
||||
var raw interface{}
|
||||
err = yaml.Unmarshal(data, &raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// transform into map[string]interface{}
|
||||
yamlContent := convertYAML(raw)
|
||||
|
||||
// create documentLoader
|
||||
documentLoader := gojsonschema.NewGoLoader(yamlContent)
|
||||
result, err := gojsonschema.Validate(schemaLoader, documentLoader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !result.Valid() {
|
||||
var errorMessages string
|
||||
for _, desc := range result.Errors() {
|
||||
errorMessages += fmt.Sprintf("- %s\n", desc)
|
||||
}
|
||||
err = errors.New(errorMessages)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// return the yaml content
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// convertYAML recursively converts map[interface{}]interface{} to map[string]interface{}
|
||||
func convertYAML(i interface{}) interface{} {
|
||||
switch x := i.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
m2 := make(map[string]interface{})
|
||||
for k, v := range x {
|
||||
m2[fmt.Sprintf("%v", k)] = convertYAML(v)
|
||||
}
|
||||
return m2
|
||||
case []interface{}:
|
||||
for idx, v := range x {
|
||||
x[idx] = convertYAML(v)
|
||||
}
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,22 @@
|
|||
package models
|
||||
|
||||
type ClusterResponse struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data struct {
|
||||
Count int `json:"count"`
|
||||
Rows []ClusterInfo `json:"rows"`
|
||||
Page_token string `json:"page_token"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type ClusterInfo struct {
|
||||
ClusterName string `json:"cluster_name"`
|
||||
Version string `json:"version"`
|
||||
Status string `json:"status"`
|
||||
ControllerName string `json:"controller_name"`
|
||||
Resources interface{} `json:"resources"`
|
||||
HostTypes interface{} `json:"host_types"`
|
||||
HostModels interface{} `json:"host_models"`
|
||||
ClusterAdmins interface{} `json:"cluster_admins"`
|
||||
}
|
||||
package models
|
||||
|
||||
type ClusterResponse struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data struct {
|
||||
Count int `json:"count"`
|
||||
Rows []ClusterInfo `json:"rows"`
|
||||
Page_token string `json:"page_token"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type ClusterInfo struct {
|
||||
ClusterName string `json:"cluster_name"`
|
||||
Version string `json:"version"`
|
||||
Status string `json:"status"`
|
||||
ControllerName string `json:"controller_name"`
|
||||
Resources interface{} `json:"resources"`
|
||||
HostTypes interface{} `json:"host_types"`
|
||||
HostModels interface{} `json:"host_models"`
|
||||
ClusterAdmins interface{} `json:"cluster_admins"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,172 +1,172 @@
|
|||
package models
|
||||
|
||||
const (
|
||||
HEADER_HOST_NAME = "HOST_NAME"
|
||||
HEADER_HOST_STATUS = "STATUS"
|
||||
HEADER_HOST_NCPUS = "NCPUS"
|
||||
HEADER_HOST_MAX_SLOT = "MAX_SLOT"
|
||||
HEADER_HOST_NUM_RUN = "NUM_RUN"
|
||||
HEADER_HOST_NUM_SSUSP = "NUM_SSUSP"
|
||||
HEADER_HOST_NUM_USUSP = "NUM_USUSP"
|
||||
HEADER_HOST_HOST_TYPE = "HOST_TYPE"
|
||||
// host details info
|
||||
HEADER_HOST_CPUF = "CPUF"
|
||||
HEADER_HOST_JLU = "JL/U"
|
||||
HEADER_HOST_MAX = "MAX"
|
||||
HEADER_HOST_NJOBS = "NJOBS"
|
||||
HEADER_HOST_RUN = "RUN"
|
||||
HEADER_HOST_SSUSP = "SSUSP"
|
||||
HEADER_HOST_USUSP = "USUSP"
|
||||
HEADER_HOST_RSV = "RSV"
|
||||
HEADER_HOST_DISPT_WINDOW = "DISPATCH_WINDOW"
|
||||
// second line
|
||||
HEADER_HOST_R15S = "r15s"
|
||||
HEADER_HOST_R1M = "r1m"
|
||||
HEADER_HOST_R15M = "r15m"
|
||||
HEADER_HOST_UT = "ut"
|
||||
HEADER_HOST_PG = "pg"
|
||||
HEADER_HOST_IO = "io"
|
||||
HEADER_HOST_LS = "ls"
|
||||
HEADER_HOST_IT = "it"
|
||||
HEADER_HOST_TMP = "tmp"
|
||||
HEADER_HOST_SWP = "swp"
|
||||
HEADER_HOST_MEM = "mem"
|
||||
HEADER_HOST_SLOTS = "slots"
|
||||
)
|
||||
|
||||
var HostDetailHeaders = []string{
|
||||
HEADER_HOST_STATUS,
|
||||
HEADER_HOST_CPUF,
|
||||
HEADER_HOST_JLU,
|
||||
HEADER_HOST_MAX,
|
||||
HEADER_HOST_NJOBS,
|
||||
HEADER_HOST_RUN,
|
||||
HEADER_HOST_SSUSP,
|
||||
HEADER_HOST_USUSP,
|
||||
HEADER_HOST_RSV,
|
||||
HEADER_HOST_DISPT_WINDOW,
|
||||
}
|
||||
|
||||
var HostLoadSchedulingHeaders = []string{
|
||||
HEADER_HOST_R15S,
|
||||
HEADER_HOST_R1M,
|
||||
HEADER_HOST_R15M,
|
||||
HEADER_HOST_UT,
|
||||
HEADER_HOST_PG,
|
||||
HEADER_HOST_IO,
|
||||
HEADER_HOST_LS,
|
||||
HEADER_HOST_IT,
|
||||
HEADER_HOST_TMP,
|
||||
HEADER_HOST_SWP,
|
||||
HEADER_HOST_MEM,
|
||||
HEADER_HOST_SLOTS,
|
||||
}
|
||||
|
||||
// HostsResponse define the data structure in the host query response
|
||||
type HostsResponse struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data struct {
|
||||
Count int `json:"count"`
|
||||
Rows []XCEHost `json:"rows"`
|
||||
Page_token string `json:"page_token"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// Host define the data structure in the host info\
|
||||
type XCEHost struct {
|
||||
HostID int64 `json:"host_id"`
|
||||
HostName string `json:"host_name"`
|
||||
HostStatus string `json:"host_status"`
|
||||
HostModel string `json:"host_model"`
|
||||
HostType string `json:"host_type"`
|
||||
HostGroup string `json:"host_group"`
|
||||
Flag int `json:"flag"`
|
||||
CPUFactor float64 `json:"cpu_factor"`
|
||||
DisptWindow interface{} `json:"dispt_window"`
|
||||
NumCPUs int `json:"num_cpus"`
|
||||
MaxSlot int `json:"max_slot"`
|
||||
MaxMem int `json:"max_mem"`
|
||||
MaxSwap int `json:"max_swap"`
|
||||
MaxTmp int `json:"max_tmp"`
|
||||
NumDisk int `json:"num_disk"`
|
||||
NumRun int `json:"num_run"`
|
||||
NumSSusp int `json:"num_ssusp"`
|
||||
NumUSusp int `json:"num_ususp"`
|
||||
NumDone int `json:"num_done"`
|
||||
AffTopo interface{} `json:"aff_topo"` // JSONB
|
||||
GPUTopo interface{} `json:"gpu_topo"` // JSONB
|
||||
SchedStop SchedStop `json:"sched_stop"` // JSONB
|
||||
RealLoad interface{} `json:"real_load"`
|
||||
|
||||
// ResourceValues carries this host's live per-resource wire values
|
||||
// (r15s/r1m/r15m/ut/pg/io/ls/it/tmp/swp/mem/slots, among others), the
|
||||
// same set the C scheduler's own "info worker" REPL command shows --
|
||||
// populated by the apiserver from the worker's own resval pushes.
|
||||
ResourceValues []ResourceDistributionInfo `json:"resource_values"`
|
||||
}
|
||||
|
||||
// ResourceDistributionInfo mirrors apiserver/models.ResourceDistributionInfo's
|
||||
// JSON shape -- one resource's current value for one host/worker.
|
||||
type ResourceDistributionInfo struct {
|
||||
ResourceName string `json:"res_name"`
|
||||
IsDynamic bool `json:"is_dynamic"`
|
||||
ValueType int `json:"value_type"`
|
||||
BooleanValue bool `json:"boolean_value"`
|
||||
StringValue string `json:"string_value"`
|
||||
NumericValue float64 `json:"numeric_value"`
|
||||
Location string `json:"location"`
|
||||
}
|
||||
|
||||
var HostFieldsMap = map[string]string{
|
||||
HEADER_HOST_NAME: "host_name",
|
||||
HEADER_HOST_STATUS: "host_status",
|
||||
HEADER_HOST_NCPUS: "num_cores",
|
||||
HEADER_HOST_MAX_SLOT: "max_slot",
|
||||
HEADER_HOST_NUM_RUN: "num_run",
|
||||
HEADER_HOST_NUM_SSUSP: "num_ssusp",
|
||||
HEADER_HOST_NUM_USUSP: "num_ususp",
|
||||
HEADER_HOST_HOST_TYPE: "host_type",
|
||||
}
|
||||
|
||||
type SchedStop struct {
|
||||
Ls string `json:"ls"` // Load Sharing
|
||||
Pg string `json:"pg"` // Page
|
||||
R1m string `json:"r1m"` // Recent 1 minute
|
||||
Tmp string `json:"tmp"` // Temporary
|
||||
}
|
||||
|
||||
type HostControlRequest struct {
|
||||
ControlAction string `json:"action" binding:"required"` //control action
|
||||
Hostname []string `json:"host_name" binding:"required"` //host name
|
||||
Comment string `json:"comment"` //comment
|
||||
}
|
||||
|
||||
type HostControlResponse struct {
|
||||
Data struct {
|
||||
Accepted []*HostControlResponseItem `json:"accepted"`
|
||||
Failed []*HostControlResponseItem `json:"failed"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type HostControlResponseItem struct {
|
||||
HostName string `json:"host_name"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
||||
func (h *XCEHost) UnmarshalJSON(data []byte) error {
|
||||
type Alias XCEHost
|
||||
var a Alias
|
||||
if err := UnmarshalOrderMapRow(data, &a); err != nil {
|
||||
return err
|
||||
}
|
||||
*h = XCEHost(a)
|
||||
return nil
|
||||
}
|
||||
|
||||
type ResReqSelectRequest struct {
|
||||
Select string `json:"select"`
|
||||
Order string `json:"order,omitempty"`
|
||||
Limit int `json:"limit,omitempty"`
|
||||
PageToken string `json:"page_token,omitempty"`
|
||||
}
|
||||
package models
|
||||
|
||||
const (
|
||||
HEADER_HOST_NAME = "HOST_NAME"
|
||||
HEADER_HOST_STATUS = "STATUS"
|
||||
HEADER_HOST_NCPUS = "NCPUS"
|
||||
HEADER_HOST_MAX_SLOT = "MAX_SLOT"
|
||||
HEADER_HOST_NUM_RUN = "NUM_RUN"
|
||||
HEADER_HOST_NUM_SSUSP = "NUM_SSUSP"
|
||||
HEADER_HOST_NUM_USUSP = "NUM_USUSP"
|
||||
HEADER_HOST_HOST_TYPE = "HOST_TYPE"
|
||||
// host details info
|
||||
HEADER_HOST_CPUF = "CPUF"
|
||||
HEADER_HOST_JLU = "JL/U"
|
||||
HEADER_HOST_MAX = "MAX"
|
||||
HEADER_HOST_NJOBS = "NJOBS"
|
||||
HEADER_HOST_RUN = "RUN"
|
||||
HEADER_HOST_SSUSP = "SSUSP"
|
||||
HEADER_HOST_USUSP = "USUSP"
|
||||
HEADER_HOST_RSV = "RSV"
|
||||
HEADER_HOST_DISPT_WINDOW = "DISPATCH_WINDOW"
|
||||
// second line
|
||||
HEADER_HOST_R15S = "r15s"
|
||||
HEADER_HOST_R1M = "r1m"
|
||||
HEADER_HOST_R15M = "r15m"
|
||||
HEADER_HOST_UT = "ut"
|
||||
HEADER_HOST_PG = "pg"
|
||||
HEADER_HOST_IO = "io"
|
||||
HEADER_HOST_LS = "ls"
|
||||
HEADER_HOST_IT = "it"
|
||||
HEADER_HOST_TMP = "tmp"
|
||||
HEADER_HOST_SWP = "swp"
|
||||
HEADER_HOST_MEM = "mem"
|
||||
HEADER_HOST_SLOTS = "slots"
|
||||
)
|
||||
|
||||
var HostDetailHeaders = []string{
|
||||
HEADER_HOST_STATUS,
|
||||
HEADER_HOST_CPUF,
|
||||
HEADER_HOST_JLU,
|
||||
HEADER_HOST_MAX,
|
||||
HEADER_HOST_NJOBS,
|
||||
HEADER_HOST_RUN,
|
||||
HEADER_HOST_SSUSP,
|
||||
HEADER_HOST_USUSP,
|
||||
HEADER_HOST_RSV,
|
||||
HEADER_HOST_DISPT_WINDOW,
|
||||
}
|
||||
|
||||
var HostLoadSchedulingHeaders = []string{
|
||||
HEADER_HOST_R15S,
|
||||
HEADER_HOST_R1M,
|
||||
HEADER_HOST_R15M,
|
||||
HEADER_HOST_UT,
|
||||
HEADER_HOST_PG,
|
||||
HEADER_HOST_IO,
|
||||
HEADER_HOST_LS,
|
||||
HEADER_HOST_IT,
|
||||
HEADER_HOST_TMP,
|
||||
HEADER_HOST_SWP,
|
||||
HEADER_HOST_MEM,
|
||||
HEADER_HOST_SLOTS,
|
||||
}
|
||||
|
||||
// HostsResponse define the data structure in the host query response
|
||||
type HostsResponse struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data struct {
|
||||
Count int `json:"count"`
|
||||
Rows []XCEHost `json:"rows"`
|
||||
Page_token string `json:"page_token"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// Host define the data structure in the host info\
|
||||
type XCEHost struct {
|
||||
HostID int64 `json:"host_id"`
|
||||
HostName string `json:"host_name"`
|
||||
HostStatus string `json:"host_status"`
|
||||
HostModel string `json:"host_model"`
|
||||
HostType string `json:"host_type"`
|
||||
HostGroup string `json:"host_group"`
|
||||
Flag int `json:"flag"`
|
||||
CPUFactor float64 `json:"cpu_factor"`
|
||||
DisptWindow interface{} `json:"dispt_window"`
|
||||
NumCPUs int `json:"num_cpus"`
|
||||
MaxSlot int `json:"max_slot"`
|
||||
MaxMem int `json:"max_mem"`
|
||||
MaxSwap int `json:"max_swap"`
|
||||
MaxTmp int `json:"max_tmp"`
|
||||
NumDisk int `json:"num_disk"`
|
||||
NumRun int `json:"num_run"`
|
||||
NumSSusp int `json:"num_ssusp"`
|
||||
NumUSusp int `json:"num_ususp"`
|
||||
NumDone int `json:"num_done"`
|
||||
AffTopo interface{} `json:"aff_topo"` // JSONB
|
||||
GPUTopo interface{} `json:"gpu_topo"` // JSONB
|
||||
SchedStop SchedStop `json:"sched_stop"` // JSONB
|
||||
RealLoad interface{} `json:"real_load"`
|
||||
|
||||
// ResourceValues carries this host's live per-resource wire values
|
||||
// (r15s/r1m/r15m/ut/pg/io/ls/it/tmp/swp/mem/slots, among others), the
|
||||
// same set the C scheduler's own "info worker" REPL command shows --
|
||||
// populated by the apiserver from the worker's own resval pushes.
|
||||
ResourceValues []ResourceDistributionInfo `json:"resource_values"`
|
||||
}
|
||||
|
||||
// ResourceDistributionInfo mirrors apiserver/models.ResourceDistributionInfo's
|
||||
// JSON shape -- one resource's current value for one host/worker.
|
||||
type ResourceDistributionInfo struct {
|
||||
ResourceName string `json:"res_name"`
|
||||
IsDynamic bool `json:"is_dynamic"`
|
||||
ValueType int `json:"value_type"`
|
||||
BooleanValue bool `json:"boolean_value"`
|
||||
StringValue string `json:"string_value"`
|
||||
NumericValue float64 `json:"numeric_value"`
|
||||
Location string `json:"location"`
|
||||
}
|
||||
|
||||
var HostFieldsMap = map[string]string{
|
||||
HEADER_HOST_NAME: "host_name",
|
||||
HEADER_HOST_STATUS: "host_status",
|
||||
HEADER_HOST_NCPUS: "num_cores",
|
||||
HEADER_HOST_MAX_SLOT: "max_slot",
|
||||
HEADER_HOST_NUM_RUN: "num_run",
|
||||
HEADER_HOST_NUM_SSUSP: "num_ssusp",
|
||||
HEADER_HOST_NUM_USUSP: "num_ususp",
|
||||
HEADER_HOST_HOST_TYPE: "host_type",
|
||||
}
|
||||
|
||||
type SchedStop struct {
|
||||
Ls string `json:"ls"` // Load Sharing
|
||||
Pg string `json:"pg"` // Page
|
||||
R1m string `json:"r1m"` // Recent 1 minute
|
||||
Tmp string `json:"tmp"` // Temporary
|
||||
}
|
||||
|
||||
type HostControlRequest struct {
|
||||
ControlAction string `json:"action" binding:"required"` //control action
|
||||
Hostname []string `json:"host_name" binding:"required"` //host name
|
||||
Comment string `json:"comment"` //comment
|
||||
}
|
||||
|
||||
type HostControlResponse struct {
|
||||
Data struct {
|
||||
Accepted []*HostControlResponseItem `json:"accepted"`
|
||||
Failed []*HostControlResponseItem `json:"failed"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type HostControlResponseItem struct {
|
||||
HostName string `json:"host_name"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
||||
func (h *XCEHost) UnmarshalJSON(data []byte) error {
|
||||
type Alias XCEHost
|
||||
var a Alias
|
||||
if err := UnmarshalOrderMapRow(data, &a); err != nil {
|
||||
return err
|
||||
}
|
||||
*h = XCEHost(a)
|
||||
return nil
|
||||
}
|
||||
|
||||
type ResReqSelectRequest struct {
|
||||
Select string `json:"select"`
|
||||
Order string `json:"order,omitempty"`
|
||||
Limit int `json:"limit,omitempty"`
|
||||
PageToken string `json:"page_token,omitempty"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,8 +60,6 @@ var JobLoadSchedulingHeaders = []string{
|
|||
HEADER_JOB_MEM,
|
||||
}
|
||||
|
||||
|
||||
|
||||
// for array jobs
|
||||
const (
|
||||
HEADER_ARRAY_JOB_JOBID = "JOBID"
|
||||
|
|
@ -93,96 +91,96 @@ type Jsonb struct {
|
|||
|
||||
// Job define the data structure in the job info
|
||||
type QueryJob struct {
|
||||
JobID int64 `json:"job_id"`
|
||||
SubmitUser string `json:"submit_user"`
|
||||
JobStatus string `json:"job_status"`
|
||||
JobName string `json:"job_name"`
|
||||
Command string `json:"command"`
|
||||
QueueName string `json:"queue_name"`
|
||||
ProjectName string `json:"project_name"`
|
||||
UserGroup string `json:"user_group"`
|
||||
LicenseProject string `json:"license_project"`
|
||||
JobDescription string `json:"job_description"`
|
||||
Resreq string `json:"resreq"`
|
||||
RsvID string `json:"rsv_id"`
|
||||
SLA string `json:"sla"`
|
||||
MaxNumProcessors int `json:"maxnum_processors"`
|
||||
NumProcessors int `json:"num_processors"`
|
||||
AskedHosts string `json:"asked_hosts"`
|
||||
BeginTime string `json:"begin_time"`
|
||||
TermTime string `json:"term_time"`
|
||||
UserPriority int `json:"user_priority"`
|
||||
DependCond string `json:"depend_cond"`
|
||||
SubmitTime int64 `json:"submit_time"`
|
||||
ReserveTime int64 `json:"reserve_time"`
|
||||
StartTime int64 `json:"start_time"`
|
||||
EndTime int64 `json:"end_time"`
|
||||
JobRusage string `json:"job_rusage"`
|
||||
MaxMem float64 `json:"max_mem"`
|
||||
AvgMem float64 `json:"avg_mem"`
|
||||
UsedMem float64 `json:"used_mem"`
|
||||
CPUTime int `json:"cpu_time"`
|
||||
PeakCPUTime int `json:"peak_cpu_time"`
|
||||
PeakCPUDuration float64 `json:"peak_cpu_duration"`
|
||||
MemEfficiency float64 `json:"mem_efficiency"` // Memory efficiency in percentage
|
||||
AvgCPUEfficiency float64 `json:"avg_cpu_efficiency"` // Average CPU efficiency in percentage
|
||||
PeakCPUEfficiency float64 `json:"peak_cpu_efficiency"` // Peak CPU efficiency in percentage
|
||||
NumHosts int `json:"num_hosts"` // Number of hosts used by the job
|
||||
FirstHost string `json:"first_host"` // First host where the job ran
|
||||
AllocSlot string `json:"alloc_slots"` // Allocated slot information
|
||||
Duration int `json:"duration"`
|
||||
Umask int `json:"umask"`
|
||||
CWD string `json:"cwd"`
|
||||
SubmitHomeDir string `json:"submit_home_dir"`
|
||||
FromHost string `json:"from_host"`
|
||||
ExecHosts ExecHosts `json:"exec_hosts"`
|
||||
JobID int64 `json:"job_id"`
|
||||
SubmitUser string `json:"submit_user"`
|
||||
JobStatus string `json:"job_status"`
|
||||
JobName string `json:"job_name"`
|
||||
Command string `json:"command"`
|
||||
QueueName string `json:"queue_name"`
|
||||
ProjectName string `json:"project_name"`
|
||||
UserGroup string `json:"user_group"`
|
||||
LicenseProject string `json:"license_project"`
|
||||
JobDescription string `json:"job_description"`
|
||||
Resreq string `json:"resreq"`
|
||||
RsvID string `json:"rsv_id"`
|
||||
SLA string `json:"sla"`
|
||||
MaxNumProcessors int `json:"maxnum_processors"`
|
||||
NumProcessors int `json:"num_processors"`
|
||||
AskedHosts string `json:"asked_hosts"`
|
||||
BeginTime string `json:"begin_time"`
|
||||
TermTime string `json:"term_time"`
|
||||
UserPriority int `json:"user_priority"`
|
||||
DependCond string `json:"depend_cond"`
|
||||
SubmitTime int64 `json:"submit_time"`
|
||||
ReserveTime int64 `json:"reserve_time"`
|
||||
StartTime int64 `json:"start_time"`
|
||||
EndTime int64 `json:"end_time"`
|
||||
JobRusage string `json:"job_rusage"`
|
||||
MaxMem float64 `json:"max_mem"`
|
||||
AvgMem float64 `json:"avg_mem"`
|
||||
UsedMem float64 `json:"used_mem"`
|
||||
CPUTime int `json:"cpu_time"`
|
||||
PeakCPUTime int `json:"peak_cpu_time"`
|
||||
PeakCPUDuration float64 `json:"peak_cpu_duration"`
|
||||
MemEfficiency float64 `json:"mem_efficiency"` // Memory efficiency in percentage
|
||||
AvgCPUEfficiency float64 `json:"avg_cpu_efficiency"` // Average CPU efficiency in percentage
|
||||
PeakCPUEfficiency float64 `json:"peak_cpu_efficiency"` // Peak CPU efficiency in percentage
|
||||
NumHosts int `json:"num_hosts"` // Number of hosts used by the job
|
||||
FirstHost string `json:"first_host"` // First host where the job ran
|
||||
AllocSlot string `json:"alloc_slots"` // Allocated slot information
|
||||
Duration int `json:"duration"`
|
||||
Umask int `json:"umask"`
|
||||
CWD string `json:"cwd"`
|
||||
SubmitHomeDir string `json:"submit_home_dir"`
|
||||
FromHost string `json:"from_host"`
|
||||
ExecHosts ExecHosts `json:"exec_hosts"`
|
||||
ExitStatus ExitStatusValue `json:"exit_status"`
|
||||
ExecUID int `json:"exec_uid"`
|
||||
ExecHome string `json:"exec_home"`
|
||||
ExecCWD string `json:"exec_cwd"`
|
||||
ExecUserName string `json:"exec_user_name"`
|
||||
JobPriority int `json:"job_priority"`
|
||||
ChargedSAAP string `json:"charged_SAAP"`
|
||||
PreExecCmd string `json:"pre_exec_cmd"`
|
||||
PostExecCmd string `json:"post_exec_cmd"`
|
||||
RequeueErrorValues string `json:"requeue_error_values"`
|
||||
NumLicenses int `json:"num_licenses"`
|
||||
LicenseNames []string `json:"license_names"`
|
||||
RunTime int `json:"run_time"`
|
||||
RunTimeEstimation int `json:"run_time_estimation"`
|
||||
MigThreshold int `json:"mig_threshold"`
|
||||
ChkpntPeriod int `json:"chkpnt_period"`
|
||||
ChkpntDir string `json:"chkpnt_dir"`
|
||||
OutDir string `json:"out_dir"`
|
||||
InFile string `json:"in_file"`
|
||||
OutFile string `json:"out_file"`
|
||||
ErrFile string `json:"err_file"`
|
||||
MailUser string `json:"mail_user"`
|
||||
LoginShell string `json:"login_shell"`
|
||||
ExceptList string `json:"except_list"`
|
||||
RLimits64 []int64 `json:"rlimits64"`
|
||||
SubEnvVars string `json:"sub_env_vars"`
|
||||
PendingReason string `json:"pending_reason"`
|
||||
JobStartInfo string `json:"job_start_info"`
|
||||
JobExecInfo string `json:"job_exec_info"`
|
||||
CoreLimit float64 `json:"core_limit"`
|
||||
CPULimit string `json:"cpu_limit"`
|
||||
RunLimit string `json:"run_limit"`
|
||||
FileLimit float64 `json:"file_limit"`
|
||||
DataLimit float64 `json:"data_limit"`
|
||||
StackLimit float64 `json:"stack_limit"`
|
||||
MemLimit float64 `json:"mem_limit"`
|
||||
SwapLimit float64 `json:"swap_limit"`
|
||||
ProcessLimit float64 `json:"process_limit"`
|
||||
ThreadLimit float64 `json:"thread_limit"`
|
||||
NumFiles int `json:"num_files"`
|
||||
ArrayIdx int `json:"array_idx"` //
|
||||
UniqueJobID int64 `json:"unique_job_id"` //
|
||||
ExtendData JobExtendData `json:"extend_data"`
|
||||
InteractiveJobURL string `json:"interactive_job_url"`
|
||||
PGIDs IntSlice `json:"pgids"`
|
||||
PID IntSlice `json:"pids"`
|
||||
LaunchType string `json:"launch_type"`
|
||||
ExecUID int `json:"exec_uid"`
|
||||
ExecHome string `json:"exec_home"`
|
||||
ExecCWD string `json:"exec_cwd"`
|
||||
ExecUserName string `json:"exec_user_name"`
|
||||
JobPriority int `json:"job_priority"`
|
||||
ChargedSAAP string `json:"charged_SAAP"`
|
||||
PreExecCmd string `json:"pre_exec_cmd"`
|
||||
PostExecCmd string `json:"post_exec_cmd"`
|
||||
RequeueErrorValues string `json:"requeue_error_values"`
|
||||
NumLicenses int `json:"num_licenses"`
|
||||
LicenseNames []string `json:"license_names"`
|
||||
RunTime int `json:"run_time"`
|
||||
RunTimeEstimation int `json:"run_time_estimation"`
|
||||
MigThreshold int `json:"mig_threshold"`
|
||||
ChkpntPeriod int `json:"chkpnt_period"`
|
||||
ChkpntDir string `json:"chkpnt_dir"`
|
||||
OutDir string `json:"out_dir"`
|
||||
InFile string `json:"in_file"`
|
||||
OutFile string `json:"out_file"`
|
||||
ErrFile string `json:"err_file"`
|
||||
MailUser string `json:"mail_user"`
|
||||
LoginShell string `json:"login_shell"`
|
||||
ExceptList string `json:"except_list"`
|
||||
RLimits64 []int64 `json:"rlimits64"`
|
||||
SubEnvVars string `json:"sub_env_vars"`
|
||||
PendingReason string `json:"pending_reason"`
|
||||
JobStartInfo string `json:"job_start_info"`
|
||||
JobExecInfo string `json:"job_exec_info"`
|
||||
CoreLimit float64 `json:"core_limit"`
|
||||
CPULimit string `json:"cpu_limit"`
|
||||
RunLimit string `json:"run_limit"`
|
||||
FileLimit float64 `json:"file_limit"`
|
||||
DataLimit float64 `json:"data_limit"`
|
||||
StackLimit float64 `json:"stack_limit"`
|
||||
MemLimit float64 `json:"mem_limit"`
|
||||
SwapLimit float64 `json:"swap_limit"`
|
||||
ProcessLimit float64 `json:"process_limit"`
|
||||
ThreadLimit float64 `json:"thread_limit"`
|
||||
NumFiles int `json:"num_files"`
|
||||
ArrayIdx int `json:"array_idx"` //
|
||||
UniqueJobID int64 `json:"unique_job_id"` //
|
||||
ExtendData JobExtendData `json:"extend_data"`
|
||||
InteractiveJobURL string `json:"interactive_job_url"`
|
||||
PGIDs IntSlice `json:"pgids"`
|
||||
PID IntSlice `json:"pids"`
|
||||
LaunchType string `json:"launch_type"`
|
||||
}
|
||||
|
||||
var JobFieldsMap = map[string]string{
|
||||
|
|
|
|||
|
|
@ -1,124 +1,124 @@
|
|||
package models
|
||||
|
||||
const (
|
||||
HEADER_QUEUE_NAME = "QUEUE_NAME"
|
||||
HEADER_QUEUE_PRIORITY = "PRIORITY"
|
||||
HEADER_QUEUE_STATUS = "QUEUE_STATUS"
|
||||
HEADER_QUEUE_NUM_PEND = "NUM_PEND"
|
||||
HEADER_QUEUE_NUM_RUN = "NUM_RUN"
|
||||
HEADER_QUEUE_NUM_SSUSP = "NUM_SSUSP"
|
||||
HEADER_QUEUE_NUM_USUSP = "NUM_USUSP"
|
||||
HEADER_QUEUE_NUM_DONE = "NUM_DONE"
|
||||
// queue detail info
|
||||
HEADER_QUEUE_PRIO = "PRIO"
|
||||
HEADER_QUEUE_NICE = "NICE"
|
||||
HEADER_QUEUE_MAX = "MAX"
|
||||
HEADER_QUEUE_JLU = "JL/U"
|
||||
HEADER_QUEUE_JLP = "JL/P"
|
||||
HEADER_QUEUE_JLH = "JL/H"
|
||||
HEADER_QUEUE_NJOBS = "NJOBS"
|
||||
HEADER_QUEUE_PEND = "PEND"
|
||||
HEADER_QUEUE_RUN = "RUN"
|
||||
HEADER_QUEUE_SSUSP = "SSUSP"
|
||||
HEADER_QUEUE_USUSP = "USUSP"
|
||||
HEADER_QUEUE_RSV = "RSV"
|
||||
// second line
|
||||
HEADER_QUEUE_R15S = "r15s"
|
||||
HEADER_QUEUE_R1M = "r1m"
|
||||
HEADER_QUEUE_R15M = "r15m"
|
||||
HEADER_QUEUE_UT = "ut"
|
||||
HEADER_QUEUE_PG = "pg"
|
||||
HEADER_QUEUE_IO = "io"
|
||||
HEADER_QUEUE_LS = "ls"
|
||||
HEADER_QUEUE_IT = "it"
|
||||
HEADER_QUEUE_TMP = "tmp"
|
||||
HEADER_QUEUE_SWP = "swp"
|
||||
HEADER_QUEUE_MEM = "mem"
|
||||
)
|
||||
|
||||
var QueueDetailHeaders = []string{
|
||||
HEADER_QUEUE_PRIO,
|
||||
HEADER_QUEUE_NICE,
|
||||
HEADER_QUEUE_STATUS,
|
||||
HEADER_QUEUE_MAX,
|
||||
HEADER_QUEUE_JLU,
|
||||
HEADER_QUEUE_JLP,
|
||||
HEADER_QUEUE_JLH,
|
||||
HEADER_QUEUE_NJOBS,
|
||||
HEADER_QUEUE_PEND,
|
||||
HEADER_QUEUE_RUN,
|
||||
HEADER_QUEUE_SSUSP,
|
||||
HEADER_QUEUE_USUSP,
|
||||
HEADER_QUEUE_RSV,
|
||||
}
|
||||
|
||||
var QueueLoadSchedulingHeaders = []string{
|
||||
HEADER_QUEUE_R15S,
|
||||
HEADER_QUEUE_R1M,
|
||||
HEADER_QUEUE_R15M,
|
||||
HEADER_QUEUE_UT,
|
||||
HEADER_QUEUE_PG,
|
||||
HEADER_QUEUE_IO,
|
||||
HEADER_QUEUE_LS,
|
||||
HEADER_QUEUE_IT,
|
||||
HEADER_QUEUE_TMP,
|
||||
HEADER_QUEUE_SWP,
|
||||
HEADER_QUEUE_MEM,
|
||||
}
|
||||
|
||||
// QueuesResponse define the data structure in the queue query response
|
||||
type QueuesResponse struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data struct {
|
||||
Count int `json:"count"`
|
||||
Rows []DBQueueInfo `json:"rows"`
|
||||
Page_token string `json:"page_token"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
var QueueFieldsMap = map[string]string{
|
||||
HEADER_QUEUE_NAME: "queue_name",
|
||||
HEADER_QUEUE_PRIORITY: "priority",
|
||||
HEADER_QUEUE_STATUS: "queue_status",
|
||||
HEADER_QUEUE_NUM_PEND: "num_pend",
|
||||
HEADER_QUEUE_NUM_RUN: "num_run",
|
||||
HEADER_QUEUE_NUM_SSUSP: "num_ssusp",
|
||||
HEADER_QUEUE_NUM_USUSP: "num_ususp",
|
||||
HEADER_QUEUE_NUM_DONE: "num_done",
|
||||
}
|
||||
|
||||
// DBQueueInfo define the data structure in the queue info
|
||||
type DBQueueInfo struct {
|
||||
QueueName string `json:"queue_name"`
|
||||
QueueStatus string `json:"queue_status"`
|
||||
Priority int `json:"priority"`
|
||||
Description string `json:"description"`
|
||||
NumPend int `json:"num_pend"`
|
||||
NumRun int `json:"num_run"`
|
||||
NumSSusp int `json:"num_ssusp"`
|
||||
NumUSusp int `json:"num_ususp"`
|
||||
NumDone int `json:"num_done"`
|
||||
FSInfo map[string]interface{} `json:"fs_info"` // JSONB
|
||||
}
|
||||
|
||||
type QueueControlRequest struct {
|
||||
ControlAction string `json:"action" binding:"required"` //control action
|
||||
QueueName []string `json:"queue_name" binding:"required"` //queue name
|
||||
Comment string `json:"comment"` //comment
|
||||
}
|
||||
|
||||
type QueueControlResponse struct {
|
||||
Data struct {
|
||||
Accepted []*QueueControlResponseItem `json:"accepted"`
|
||||
Failed []*QueueControlResponseItem `json:"failed"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type QueueControlResponseItem struct {
|
||||
QueueName string `json:"queue_name"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
package models
|
||||
|
||||
const (
|
||||
HEADER_QUEUE_NAME = "QUEUE_NAME"
|
||||
HEADER_QUEUE_PRIORITY = "PRIORITY"
|
||||
HEADER_QUEUE_STATUS = "QUEUE_STATUS"
|
||||
HEADER_QUEUE_NUM_PEND = "NUM_PEND"
|
||||
HEADER_QUEUE_NUM_RUN = "NUM_RUN"
|
||||
HEADER_QUEUE_NUM_SSUSP = "NUM_SSUSP"
|
||||
HEADER_QUEUE_NUM_USUSP = "NUM_USUSP"
|
||||
HEADER_QUEUE_NUM_DONE = "NUM_DONE"
|
||||
// queue detail info
|
||||
HEADER_QUEUE_PRIO = "PRIO"
|
||||
HEADER_QUEUE_NICE = "NICE"
|
||||
HEADER_QUEUE_MAX = "MAX"
|
||||
HEADER_QUEUE_JLU = "JL/U"
|
||||
HEADER_QUEUE_JLP = "JL/P"
|
||||
HEADER_QUEUE_JLH = "JL/H"
|
||||
HEADER_QUEUE_NJOBS = "NJOBS"
|
||||
HEADER_QUEUE_PEND = "PEND"
|
||||
HEADER_QUEUE_RUN = "RUN"
|
||||
HEADER_QUEUE_SSUSP = "SSUSP"
|
||||
HEADER_QUEUE_USUSP = "USUSP"
|
||||
HEADER_QUEUE_RSV = "RSV"
|
||||
// second line
|
||||
HEADER_QUEUE_R15S = "r15s"
|
||||
HEADER_QUEUE_R1M = "r1m"
|
||||
HEADER_QUEUE_R15M = "r15m"
|
||||
HEADER_QUEUE_UT = "ut"
|
||||
HEADER_QUEUE_PG = "pg"
|
||||
HEADER_QUEUE_IO = "io"
|
||||
HEADER_QUEUE_LS = "ls"
|
||||
HEADER_QUEUE_IT = "it"
|
||||
HEADER_QUEUE_TMP = "tmp"
|
||||
HEADER_QUEUE_SWP = "swp"
|
||||
HEADER_QUEUE_MEM = "mem"
|
||||
)
|
||||
|
||||
var QueueDetailHeaders = []string{
|
||||
HEADER_QUEUE_PRIO,
|
||||
HEADER_QUEUE_NICE,
|
||||
HEADER_QUEUE_STATUS,
|
||||
HEADER_QUEUE_MAX,
|
||||
HEADER_QUEUE_JLU,
|
||||
HEADER_QUEUE_JLP,
|
||||
HEADER_QUEUE_JLH,
|
||||
HEADER_QUEUE_NJOBS,
|
||||
HEADER_QUEUE_PEND,
|
||||
HEADER_QUEUE_RUN,
|
||||
HEADER_QUEUE_SSUSP,
|
||||
HEADER_QUEUE_USUSP,
|
||||
HEADER_QUEUE_RSV,
|
||||
}
|
||||
|
||||
var QueueLoadSchedulingHeaders = []string{
|
||||
HEADER_QUEUE_R15S,
|
||||
HEADER_QUEUE_R1M,
|
||||
HEADER_QUEUE_R15M,
|
||||
HEADER_QUEUE_UT,
|
||||
HEADER_QUEUE_PG,
|
||||
HEADER_QUEUE_IO,
|
||||
HEADER_QUEUE_LS,
|
||||
HEADER_QUEUE_IT,
|
||||
HEADER_QUEUE_TMP,
|
||||
HEADER_QUEUE_SWP,
|
||||
HEADER_QUEUE_MEM,
|
||||
}
|
||||
|
||||
// QueuesResponse define the data structure in the queue query response
|
||||
type QueuesResponse struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data struct {
|
||||
Count int `json:"count"`
|
||||
Rows []DBQueueInfo `json:"rows"`
|
||||
Page_token string `json:"page_token"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
var QueueFieldsMap = map[string]string{
|
||||
HEADER_QUEUE_NAME: "queue_name",
|
||||
HEADER_QUEUE_PRIORITY: "priority",
|
||||
HEADER_QUEUE_STATUS: "queue_status",
|
||||
HEADER_QUEUE_NUM_PEND: "num_pend",
|
||||
HEADER_QUEUE_NUM_RUN: "num_run",
|
||||
HEADER_QUEUE_NUM_SSUSP: "num_ssusp",
|
||||
HEADER_QUEUE_NUM_USUSP: "num_ususp",
|
||||
HEADER_QUEUE_NUM_DONE: "num_done",
|
||||
}
|
||||
|
||||
// DBQueueInfo define the data structure in the queue info
|
||||
type DBQueueInfo struct {
|
||||
QueueName string `json:"queue_name"`
|
||||
QueueStatus string `json:"queue_status"`
|
||||
Priority int `json:"priority"`
|
||||
Description string `json:"description"`
|
||||
NumPend int `json:"num_pend"`
|
||||
NumRun int `json:"num_run"`
|
||||
NumSSusp int `json:"num_ssusp"`
|
||||
NumUSusp int `json:"num_ususp"`
|
||||
NumDone int `json:"num_done"`
|
||||
FSInfo map[string]interface{} `json:"fs_info"` // JSONB
|
||||
}
|
||||
|
||||
type QueueControlRequest struct {
|
||||
ControlAction string `json:"action" binding:"required"` //control action
|
||||
QueueName []string `json:"queue_name" binding:"required"` //queue name
|
||||
Comment string `json:"comment"` //comment
|
||||
}
|
||||
|
||||
type QueueControlResponse struct {
|
||||
Data struct {
|
||||
Accepted []*QueueControlResponseItem `json:"accepted"`
|
||||
Failed []*QueueControlResponseItem `json:"failed"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type QueueControlResponseItem struct {
|
||||
QueueName string `json:"queue_name"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
||||
func (q *DBQueueInfo) UnmarshalJSON(data []byte) error {
|
||||
type Alias DBQueueInfo
|
||||
|
|
|
|||
|
|
@ -1,117 +1,117 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
apiserver "xcecli/cmd/auth"
|
||||
"xcecli/cmd/clusters"
|
||||
"xcecli/cmd/hosts"
|
||||
"xcecli/cmd/jobs"
|
||||
"xcecli/cmd/permissions"
|
||||
"xcecli/cmd/queues"
|
||||
"xcecli/cmd/resources"
|
||||
"xcecli/cmd/roles"
|
||||
"xcecli/cmd/users"
|
||||
"xcecli/common/request"
|
||||
"xcecli/config"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
rootCmd = &cobra.Command{
|
||||
Use: "xce",
|
||||
Short: "XCE CLI tool for the API Server operations",
|
||||
}
|
||||
configManager *config.ConfigManager
|
||||
)
|
||||
|
||||
// execute the root command
|
||||
func Execute(cm *config.ConfigManager, version string) error {
|
||||
if cm == nil {
|
||||
return fmt.Errorf("the config manager is not initialized")
|
||||
}
|
||||
configManager = cm
|
||||
rootCmd.Version = version
|
||||
rootCmd.CompletionOptions.DisableDefaultCmd = true
|
||||
rootCmd.SilenceErrors = true
|
||||
rootCmd.SilenceUsage = true
|
||||
|
||||
// initialize the subcommands
|
||||
initCommands()
|
||||
|
||||
return rootCmd.Execute()
|
||||
}
|
||||
|
||||
// withAuth wraps a command with authentication check
|
||||
// This function creates a middleware that checks authentication before executing any command
|
||||
func withAuth(cmd *cobra.Command) *cobra.Command {
|
||||
// Store original handlers
|
||||
originalRunE := cmd.RunE
|
||||
originalRun := cmd.Run
|
||||
|
||||
// Create new RunE that checks authentication first
|
||||
cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
// Check authentication before executing the command
|
||||
_, err := configManager.IsAuthenticated()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Execute the original command logic
|
||||
if originalRunE != nil {
|
||||
return originalRunE(cmd, args)
|
||||
}
|
||||
if originalRun != nil {
|
||||
originalRun(cmd, args)
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// addCommandWithAuth adds a command and all its subcommands with authentication check
|
||||
func addCommandWithAuth(parent *cobra.Command, cmd *cobra.Command) {
|
||||
// Apply auth check to the command itself
|
||||
withAuth(cmd)
|
||||
|
||||
// Apply auth check to all subcommands recursively
|
||||
for _, subCmd := range cmd.Commands() {
|
||||
withAuth(subCmd)
|
||||
}
|
||||
|
||||
parent.AddCommand(cmd)
|
||||
}
|
||||
|
||||
// initialize all the subcommands
|
||||
func initCommands() {
|
||||
cobra.EnableCommandSorting = false
|
||||
rootCmd.AddGroup(
|
||||
&cobra.Group{
|
||||
ID: "api",
|
||||
Title: "API Server Operations",
|
||||
},
|
||||
&cobra.Group{
|
||||
ID: "query",
|
||||
Title: "Query Operations",
|
||||
},
|
||||
)
|
||||
|
||||
// Add authentication commands (no auth required)
|
||||
rootCmd.AddCommand(apiserver.NewLogonCmd(configManager))
|
||||
rootCmd.AddCommand(apiserver.NewLogoutCmd(configManager))
|
||||
|
||||
// Add commands that require authentication
|
||||
// These commands will automatically check authentication before execution
|
||||
addCommandWithAuth(rootCmd, apiserver.NewListCmd(configManager))
|
||||
addCommandWithAuth(rootCmd, permissions.NewPermsCmd(configManager))
|
||||
addCommandWithAuth(rootCmd, roles.NewRolesCmd(configManager))
|
||||
addCommandWithAuth(rootCmd, users.NewUsersCmd(configManager))
|
||||
addCommandWithAuth(rootCmd, jobs.NewJobsCmd(configManager))
|
||||
addCommandWithAuth(rootCmd, hosts.NewHostsCmd(configManager))
|
||||
addCommandWithAuth(rootCmd, queues.NewQueuesCmd(configManager))
|
||||
addCommandWithAuth(rootCmd, clusters.NewClustersCmd(configManager))
|
||||
addCommandWithAuth(rootCmd, resources.NewResourcesCmd(configManager))
|
||||
rootCmd.SetFlagErrorFunc(request.FlagErrorHandler)
|
||||
}
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
apiserver "xcecli/cmd/auth"
|
||||
"xcecli/cmd/clusters"
|
||||
"xcecli/cmd/hosts"
|
||||
"xcecli/cmd/jobs"
|
||||
"xcecli/cmd/permissions"
|
||||
"xcecli/cmd/queues"
|
||||
"xcecli/cmd/resources"
|
||||
"xcecli/cmd/roles"
|
||||
"xcecli/cmd/users"
|
||||
"xcecli/common/request"
|
||||
"xcecli/config"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
rootCmd = &cobra.Command{
|
||||
Use: "xce",
|
||||
Short: "XCE CLI tool for the API Server operations",
|
||||
}
|
||||
configManager *config.ConfigManager
|
||||
)
|
||||
|
||||
// execute the root command
|
||||
func Execute(cm *config.ConfigManager, version string) error {
|
||||
if cm == nil {
|
||||
return fmt.Errorf("the config manager is not initialized")
|
||||
}
|
||||
configManager = cm
|
||||
rootCmd.Version = version
|
||||
rootCmd.CompletionOptions.DisableDefaultCmd = true
|
||||
rootCmd.SilenceErrors = true
|
||||
rootCmd.SilenceUsage = true
|
||||
|
||||
// initialize the subcommands
|
||||
initCommands()
|
||||
|
||||
return rootCmd.Execute()
|
||||
}
|
||||
|
||||
// withAuth wraps a command with authentication check
|
||||
// This function creates a middleware that checks authentication before executing any command
|
||||
func withAuth(cmd *cobra.Command) *cobra.Command {
|
||||
// Store original handlers
|
||||
originalRunE := cmd.RunE
|
||||
originalRun := cmd.Run
|
||||
|
||||
// Create new RunE that checks authentication first
|
||||
cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
// Check authentication before executing the command
|
||||
_, err := configManager.IsAuthenticated()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Execute the original command logic
|
||||
if originalRunE != nil {
|
||||
return originalRunE(cmd, args)
|
||||
}
|
||||
if originalRun != nil {
|
||||
originalRun(cmd, args)
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// addCommandWithAuth adds a command and all its subcommands with authentication check
|
||||
func addCommandWithAuth(parent *cobra.Command, cmd *cobra.Command) {
|
||||
// Apply auth check to the command itself
|
||||
withAuth(cmd)
|
||||
|
||||
// Apply auth check to all subcommands recursively
|
||||
for _, subCmd := range cmd.Commands() {
|
||||
withAuth(subCmd)
|
||||
}
|
||||
|
||||
parent.AddCommand(cmd)
|
||||
}
|
||||
|
||||
// initialize all the subcommands
|
||||
func initCommands() {
|
||||
cobra.EnableCommandSorting = false
|
||||
rootCmd.AddGroup(
|
||||
&cobra.Group{
|
||||
ID: "api",
|
||||
Title: "API Server Operations",
|
||||
},
|
||||
&cobra.Group{
|
||||
ID: "query",
|
||||
Title: "Query Operations",
|
||||
},
|
||||
)
|
||||
|
||||
// Add authentication commands (no auth required)
|
||||
rootCmd.AddCommand(apiserver.NewLogonCmd(configManager))
|
||||
rootCmd.AddCommand(apiserver.NewLogoutCmd(configManager))
|
||||
|
||||
// Add commands that require authentication
|
||||
// These commands will automatically check authentication before execution
|
||||
addCommandWithAuth(rootCmd, apiserver.NewListCmd(configManager))
|
||||
addCommandWithAuth(rootCmd, permissions.NewPermsCmd(configManager))
|
||||
addCommandWithAuth(rootCmd, roles.NewRolesCmd(configManager))
|
||||
addCommandWithAuth(rootCmd, users.NewUsersCmd(configManager))
|
||||
addCommandWithAuth(rootCmd, jobs.NewJobsCmd(configManager))
|
||||
addCommandWithAuth(rootCmd, hosts.NewHostsCmd(configManager))
|
||||
addCommandWithAuth(rootCmd, queues.NewQueuesCmd(configManager))
|
||||
addCommandWithAuth(rootCmd, clusters.NewClustersCmd(configManager))
|
||||
addCommandWithAuth(rootCmd, resources.NewResourcesCmd(configManager))
|
||||
rootCmd.SetFlagErrorFunc(request.FlagErrorHandler)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue