Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add info subcommand to CLI #17566

Merged
merged 7 commits into from
Jun 7, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,16 @@ bin/cli.sh item mark --unset name
where it is expected that either `--set` or `--unset` are specified.
This is preferred over the alternative of two separate commands with `setMark` and `unsetMark` as the operations.

## User input validation

User inputs should be validated by the CLI command as much as possible as opposed to the resulting invocation.

## Output conventions and java invocation

A majority of commands result in invoking a java class with arguments to execute the expected operation and possibly return some output.
The output returned from the java invocation should tend towards being plain or machine parseable, such as a JSON formatted string,
rather than terminal friendly or human readable format.
When appropriate, the CLI command will default to formatting this output to be terminal friendly, with an option to output in a machine parseable format such as JSON.
When appropriate, the CLI command will default to formatting this output to be terminal friendly, with an option to output in a machine parseable format.

## References

Expand Down
69 changes: 69 additions & 0 deletions cli/src/alluxio.org/cli/cmd/info/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
* (the "License"). You may not use this work except in compliance with the License, which is
* available at www.apache.org/licenses/LICENSE-2.0
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied, as more fully set forth in the License.
*
* See the NOTICE file distributed with this work for information regarding copyright ownership.
*/

package info

import (
"strings"

"github.com/spf13/cobra"

"alluxio.org/cli/env"
)

var Cache = &CacheCommand{
BaseJavaCommand: &env.BaseJavaCommand{
CommandName: "cache",
JavaClassName: "alluxio.cli.fsadmin.FileSystemAdminShell",
Parameters: []string{"report", "capacity"},
},
}

type CacheCommand struct {
*env.BaseJavaCommand

liveWorkers bool
lostWorkers bool
workersList []string // list of worker hostnames or ip addresses
}

func (c *CacheCommand) Base() *env.BaseJavaCommand {
return c.BaseJavaCommand
}

func (c *CacheCommand) ToCommand() *cobra.Command {
cmd := c.Base().InitRunJavaClassCmd(&cobra.Command{
Use: Cache.CommandName,
Short: "Reports worker capacity information",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return c.Run(nil)
},
})
cmd.Flags().BoolVar(&c.liveWorkers, "live", false, "Only show live workers for capacity report")
cmd.Flags().BoolVar(&c.lostWorkers, "lost", false, "Only show lost workers for capacity report")
cmd.Flags().StringSliceVar(&c.workersList, "workers", nil, "Only show specified workers for capacity report, labeled by hostname or IP address")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StringSliceVar supports using --workers multiple times to specify multiple workers, maybe it should be named --worker (singular) then so the command can read bin/cli.sh info cache --worker <hostname1> --worker <hostname2> ... (similar to bin/cli.sh conf log --target <target1> --target <target2>...). wdyt?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

worker it is

cmd.MarkFlagsMutuallyExclusive("live", "lost", "workers")
return cmd
}

func (c *CacheCommand) Run(_ []string) error {
// TODO: output all in a serializable format and filter/trim as specified by flags
var args []string
if c.liveWorkers {
args = append(args, "-live")
} else if c.lostWorkers {
args = append(args, "-lost")
} else if len(c.workersList) > 0 {
args = append(args, "-workers", strings.Join(c.workersList, ","))
}
return c.Base().Run(args)
}
147 changes: 147 additions & 0 deletions cli/src/alluxio.org/cli/cmd/info/collect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
* (the "License"). You may not use this work except in compliance with the License, which is
* available at www.apache.org/licenses/LICENSE-2.0
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied, as more fully set forth in the License.
*
* See the NOTICE file distributed with this work for information regarding copyright ownership.
*/

package info

import (
"fmt"
"strconv"
"strings"
"time"

"github.com/palantir/stacktrace"
"github.com/spf13/cobra"

"alluxio.org/cli/env"
)

var Collect = &CollectCommand{
BaseJavaCommand: &env.BaseJavaCommand{
CommandName: "collect",
JavaClassName: "alluxio.cli.bundler.CollectInfo",
},
}

type CollectCommand struct {
*env.BaseJavaCommand

additionalLogs []string
endTime string
excludeLogs []string
excludeWorkerMetrics bool
includeLogs []string
local bool
maxThreads int
startTime string
}

func (c *CollectCommand) Base() *env.BaseJavaCommand {
return c.BaseJavaCommand
}

const dateFormat = "2006-01-02T15:04:05"

func (c *CollectCommand) ToCommand() *cobra.Command {
cmd := c.Base().InitRunJavaClassCmd(&cobra.Command{
Use: fmt.Sprintf("%v [command] [outputPath]", Collect.CommandName),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current command currently looks like bin/cli.sh info collect {all | collectAlluxioInfo. | collectConfig | collectEnv | collectJvmInfo | collectLog | collectMetrics} /path/to/output. Here are some suggestions for improvements:
Trim commands to become bin/cli.sh info collect {all | cluster | conf | env | jvm | log | metrics }. Turn the output path into a flag like -o, --output-path, make the default value pwd or make flag mandatory.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree that avoid using arguments in general. adding a required --output-path

Short: "Collects information such as logs, config, metrics, and more from the running Alluxio cluster and bundle into a single tarball",
Long: `Collects information such as logs, config, metrics, and more from the running Alluxio cluster and bundle into a single tarball
[command] must be one of the following values:
all: runs all the commands below.
collectAlluxioInfo: runs a set of Alluxio commands to collect information about the Alluxio cluster.
collectConfig: collects the configuration files under ${ALLUXIO_HOME}/config/.
collectEnv: runs a set of linux commands to collect information about the cluster.
collectJvmInfo: collects jstack from the JVMs.
collectLog: collects the log files under ${ALLUXIO_HOME}/logs/.
collectMetrics: collects Alluxio system metrics.

[outputPath] the directory you want the collected tarball to be in

WARNING: This command MAY bundle credentials. To understand the risks refer to the docs here.
https://docs.alluxio.io/os/user/edge/en/operation/Troubleshooting.html#collect-alluxio-cluster-information
`,
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
return c.Run(args)
},
})
cmd.Flags().StringSliceVar(&c.additionalLogs, "additional-logs", nil, "additional file name prefixes from ${ALLUXIO_HOME}/logs to include in the tarball, inclusive of the default log files")
cmd.Flags().StringVar(&c.endTime, "end-time", "", "logs that do not contain entries before this time will be ignored, format must be like "+dateFormat)
cmd.Flags().StringSliceVar(&c.excludeLogs, "exclude-logs", nil, "file name prefixes from ${ALLUXIO_HOME}/logs to exclude; this is evaluated after adding files from --additional-logs")
cmd.Flags().BoolVar(&c.excludeWorkerMetrics, "exclude-worker-metrics", false, "true to skip worker metrics collection")
cmd.Flags().StringSliceVar(&c.includeLogs, "include-logs", nil, "file name prefixes from ${ALLUXIO_HOME}/logs to include in the tarball, ignoring the default log files; cannot be used with --exclude-logs or --additional-logs")
cmd.Flags().BoolVar(&c.local, "local", false, "true to only collect information from the local machine")
cmd.Flags().IntVar(&c.maxThreads, "max-threads", 1, "parallelism of the command; use a smaller value to limit network I/O when transferring tarballs")
cmd.Flags().StringVar(&c.startTime, "start-time", "", "logs that do not contain entries after this time will be ignored, format must be like "+dateFormat)
return cmd
}

func (c *CollectCommand) Run(args []string) error {
commands := map[string]struct{}{
"all": {},
"collectAlluxioInfo": {},
"collectConfig": {},
"collectEnv": {},
"collectJvmInfo": {},
"collectLog": {},
"collectMetrics": {},
}
if _, ok := commands[args[0]]; !ok {
var cmds []string
for c := range commands {
cmds = append(cmds, c)
}
return stacktrace.NewError("first argument must be one of %v", strings.Join(cmds, ", "))
}

var javaArgs []string
if c.additionalLogs != nil {
if c.includeLogs != nil {
return stacktrace.NewError("cannot set both --include-logs and --additional-logs")
}
javaArgs = append(javaArgs, "--additional-logs", strings.Join(c.additionalLogs, ","))
}
if c.endTime != "" {
if _, err := time.Parse(dateFormat, c.endTime); err != nil {
return stacktrace.Propagate(err, "could not parse end time %v", c.endTime)
}
javaArgs = append(javaArgs, "--end-time", c.endTime)
}
if c.excludeLogs != nil {
if c.includeLogs != nil {
return stacktrace.NewError("cannot set both --include-logs and --exclude-logs")
}
javaArgs = append(javaArgs, "--exclude-logs", strings.Join(c.excludeLogs, ","))
}
if c.excludeWorkerMetrics {
javaArgs = append(javaArgs, "--exclude-worker-metrics")
}
if c.includeLogs != nil {
// already checked exclusivity with --additional-logs and --exclude-logs
javaArgs = append(javaArgs, "--include-logs", strings.Join(c.includeLogs, ","))
}
if c.local {
javaArgs = append(javaArgs, "--local")
}
if c.maxThreads > 1 {
javaArgs = append(javaArgs, "--max-threads", strconv.Itoa(c.maxThreads))
}
if c.startTime != "" {
if _, err := time.Parse(dateFormat, c.startTime); err != nil {
return stacktrace.Propagate(err, "could not parse start time %v", c.startTime)
}
javaArgs = append(javaArgs, "--start-time", c.startTime)
}

javaArgs = append(javaArgs, args...)

return c.Base().Run(javaArgs)
}
27 changes: 27 additions & 0 deletions cli/src/alluxio.org/cli/cmd/info/info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
* (the "License"). You may not use this work except in compliance with the License, which is
* available at www.apache.org/licenses/LICENSE-2.0
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied, as more fully set forth in the License.
*
* See the NOTICE file distributed with this work for information regarding copyright ownership.
*/

package info

import (
"alluxio.org/cli/env"
)

var Service = &env.Service{
Name: "info",
Description: "Retrieve and/or display info about the running Alluxio cluster",
Commands: []env.Command{
Cache,
Collect,
Master,
Report,
},
}
50 changes: 50 additions & 0 deletions cli/src/alluxio.org/cli/cmd/info/master.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
* (the "License"). You may not use this work except in compliance with the License, which is
* available at www.apache.org/licenses/LICENSE-2.0
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied, as more fully set forth in the License.
*
* See the NOTICE file distributed with this work for information regarding copyright ownership.
*/

package info

import (
"github.com/spf13/cobra"

"alluxio.org/cli/env"
)

var Master = &MasterCommand{
BaseJavaCommand: &env.BaseJavaCommand{
CommandName: "master",
JavaClassName: "alluxio.cli.fs.FileSystemShell",
Parameters: []string{"masterInfo"},
},
}

type MasterCommand struct {
*env.BaseJavaCommand
}

func (c *MasterCommand) Base() *env.BaseJavaCommand {
return c.BaseJavaCommand
}

func (c *MasterCommand) ToCommand() *cobra.Command {
cmd := c.Base().InitRunJavaClassCmd(&cobra.Command{
Use: Master.CommandName,
Short: "Prints information regarding master fault tolerance such as leader address and list of master addresses",
RunE: func(cmd *cobra.Command, args []string) error {
return c.Run(nil)
},
})
return cmd
}

func (c *MasterCommand) Run(_ []string) error {
// TODO: output in a serializable format
return c.Base().Run(nil)
}
81 changes: 81 additions & 0 deletions cli/src/alluxio.org/cli/cmd/info/report.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
* (the "License"). You may not use this work except in compliance with the License, which is
* available at www.apache.org/licenses/LICENSE-2.0
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied, as more fully set forth in the License.
*
* See the NOTICE file distributed with this work for information regarding copyright ownership.
*/

package info

import (
"fmt"
"strings"

"github.com/palantir/stacktrace"
"github.com/spf13/cobra"

"alluxio.org/cli/env"
)

var Report = &ReportCommand{
BaseJavaCommand: &env.BaseJavaCommand{
CommandName: "report",
JavaClassName: "alluxio.cli.fsadmin.FileSystemAdminShell",
Parameters: []string{"report"},
},
}

type ReportCommand struct {
*env.BaseJavaCommand
}

func (c *ReportCommand) Base() *env.BaseJavaCommand {
return c.BaseJavaCommand
}

func (c *ReportCommand) ToCommand() *cobra.Command {
cmd := c.Base().InitRunJavaClassCmd(&cobra.Command{
Use: fmt.Sprintf("%v [arg]", Report.CommandName),
Short: "Reports Alluxio running cluster information",
Long: `Reports Alluxio running cluster information
[arg] can be one of the following values:
jobservice: job service metrics information
metrics: metrics information
summary: cluster summary
ufs: under storage system information

Defaults to summary if no arg is provided
`,
Args: cobra.RangeArgs(0, 1),
RunE: func(cmd *cobra.Command, args []string) error {
return c.Run(args)
},
})
return cmd
}

func (c *ReportCommand) Run(args []string) error {
reportArg := "summary"
if len(args) == 1 {
options := map[string]struct{}{
"jobservice": {},
"metrics": {},
"summary": {},
"ufs": {},
}
if _, ok := options[args[0]]; !ok {
var cmds []string
for c := range options {
cmds = append(cmds, c)
}
return stacktrace.NewError("first argument must be one of %v", strings.Join(cmds, ", "))
}
reportArg = args[0]
}
// TODO: output all in a serializable format and filter/trim as specified by flags
return c.Base().Run([]string{reportArg})
}
Loading