mirror of
https://github.com/mainflux/mainflux.git
synced 2025-04-24 13:48:49 +08:00
MF-1268 - CLI improvements (#1274)
* Prefix error messages in CLI with a bold "error: ". Signed-off-by: Joao Matos <joao@tritao.eu> * Remove duplicated "Usage: " from groups command help. Signed-off-by: Joao Matos <joao@tritao.eu> * Add a raw output mode for CLI and use it on logCreated. Signed-off-by: Joao Matos <joao@tritao.eu> * Add CLI global flag for user auth token. Signed-off-by: Joao Matos <joao@tritao.eu> * Add CLI config flag and parsing logic. Signed-off-by: Joao Matos <joao@tritao.eu> * Refactor CLI users commands outside array structure. Signed-off-by: Joao Matos <joao@tritao.eu> * Refactor CLI certificates commands using flags. Signed-off-by: Joao Matos <joao@tritao.eu> * Refactor CLI things create command using flags. Signed-off-by: Joao Matos <joao@tritao.eu> Co-authored-by: Drasko DRASKOVIC <drasko.draskovic@gmail.com>
This commit is contained in:
parent
46c675cd5f
commit
3273c30d8b
49
cli/certs.go
49
cli/certs.go
@ -1,54 +1,57 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var cmdCerts = []cobra.Command{
|
||||
cobra.Command{
|
||||
// NewCertsCmd returns certificate command.
|
||||
func NewCertsCmd() *cobra.Command {
|
||||
var keySize uint16
|
||||
var keyType string
|
||||
var ttl uint32
|
||||
|
||||
issueCmd := cobra.Command{
|
||||
Use: "issue",
|
||||
Short: "issue <thing_id> <keybits> <keytype> <hoursvalid> <user_auth_token>",
|
||||
Short: "issue <thing_id> [--keysize=2048] [--keytype=rsa] [--ttl=8760]",
|
||||
Long: `Issues new certificate for a thing`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 5 {
|
||||
if len(args) != 1 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
|
||||
thingID := args[0]
|
||||
keyBits, err := strconv.Atoi(args[1])
|
||||
if err != nil {
|
||||
logError(errors.New("invalid format for keybits"))
|
||||
return
|
||||
}
|
||||
valid := strconv.FormatUint(uint64(ttl), 10)
|
||||
token := getUserAuthToken()
|
||||
|
||||
keyType := args[2]
|
||||
valid := args[3]
|
||||
token := args[4]
|
||||
|
||||
c, err := sdk.IssueCert(thingID, keyBits, keyType, valid, token)
|
||||
c, err := sdk.IssueCert(thingID, int(keySize), keyType, valid, token)
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
logJSON(c)
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
issueCmd.Flags().Uint16Var(&keySize, "keysize", 2048, "certificate key strength in bits: 2048, 4096 (RSA) or 224, 256, 384, 512 (EC)")
|
||||
issueCmd.Flags().StringVar(&keyType, "keytype", "rsa", "certificate key type: RSA or EC")
|
||||
issueCmd.Flags().Uint32Var(&ttl, "ttl", 8760, "certificate time to live in hours")
|
||||
|
||||
// NewCertsCmd returns certificate command.
|
||||
func NewCertsCmd() *cobra.Command {
|
||||
cmd := cobra.Command{
|
||||
Use: "cert",
|
||||
Short: "Certificate management",
|
||||
Long: `Certificate management: create certificates for things"`,
|
||||
Use: "certs",
|
||||
Short: "Certificates management",
|
||||
Long: `Certificates management: create certificates for things"`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
logUsage("cert issue <thing_id> <keybits> <keytype> <hoursvalid> <user_auth_token>")
|
||||
logUsage("certs [issue]")
|
||||
},
|
||||
}
|
||||
|
||||
cmdCerts := []cobra.Command{
|
||||
issueCmd,
|
||||
}
|
||||
|
||||
for i := range cmdCerts {
|
||||
cmd.AddCommand(&cmdCerts[i])
|
||||
}
|
||||
|
81
cli/config.go
Normal file
81
cli/config.go
Normal file
@ -0,0 +1,81 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
"github.com/pelletier/go-toml"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
AuthToken string `toml:"auth_token"`
|
||||
}
|
||||
|
||||
// save - store config in a file
|
||||
func save(c Config, file string) error {
|
||||
b, err := toml.Marshal(c)
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("failed to read config file: %s", err))
|
||||
}
|
||||
if err := ioutil.WriteFile(file, b, 0644); err != nil {
|
||||
return errors.New(fmt.Sprintf("failed to write config TOML: %s", err))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// read - retrieve config from a file
|
||||
func read(file string) (Config, error) {
|
||||
data, err := ioutil.ReadFile(file)
|
||||
c := Config{}
|
||||
if err != nil {
|
||||
return c, errors.New(fmt.Sprintf("failed to read config file: %s", err))
|
||||
}
|
||||
|
||||
if err := toml.Unmarshal(data, &c); err != nil {
|
||||
return Config{}, errors.New(fmt.Sprintf("failed to unmarshal config TOML: %s", err))
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func getConfigPath() (string, error) {
|
||||
// Check if a config path passed by user exists.
|
||||
if ConfigPath != "" {
|
||||
if _, err := os.Stat(ConfigPath); os.IsNotExist(err) {
|
||||
errConfigNotFound := errors.Wrap(errors.New("config file was not found"), err)
|
||||
logError(errConfigNotFound)
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
// If not, then read it from the user config directory.
|
||||
if ConfigPath == "" {
|
||||
userConfigDir, _ := os.UserConfigDir()
|
||||
ConfigPath = path.Join(userConfigDir, "mainflux", "cli.toml")
|
||||
}
|
||||
|
||||
if _, err := os.Stat(ConfigPath); os.IsNotExist(err) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return ConfigPath, nil
|
||||
}
|
||||
|
||||
func ParseConfig() {
|
||||
path, err := getConfigPath()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
config, err := read(path)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if UserAuthToken == "" {
|
||||
UserAuthToken = config.AuthToken
|
||||
}
|
||||
}
|
@ -172,7 +172,7 @@ func NewGroupsCmd() *cobra.Command {
|
||||
Short: "Groups management",
|
||||
Long: `Groups management: create groups and assigns user to groups"`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
logUsage("Usage: Groups [create | get | delete | assign | unassign | members | membership]")
|
||||
logUsage("groups [create | get | delete | assign | unassign | members | membership]")
|
||||
},
|
||||
}
|
||||
for i := range cmdGroups {
|
||||
|
@ -13,10 +13,10 @@ import (
|
||||
var cmdThings = []cobra.Command{
|
||||
cobra.Command{
|
||||
Use: "create",
|
||||
Short: "create <JSON_thing> <user_auth_token>",
|
||||
Short: "create <JSON_thing>",
|
||||
Long: `Create new thing, generate his UUID and store it`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
if len(args) != 1 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
@ -27,7 +27,8 @@ var cmdThings = []cobra.Command{
|
||||
return
|
||||
}
|
||||
|
||||
id, err := sdk.CreateThing(thing, args[1])
|
||||
token := getUserAuthToken()
|
||||
id, err := sdk.CreateThing(thing, token)
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
|
37
cli/users.go
37
cli/users.go
@ -10,8 +10,9 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var cmdUsers = []cobra.Command{
|
||||
cobra.Command{
|
||||
// NewUsersCmd returns users command.
|
||||
func NewUsersCmd() *cobra.Command {
|
||||
createCmd := cobra.Command{
|
||||
Use: "create",
|
||||
Short: "create <username> <password>",
|
||||
Long: `Creates new user`,
|
||||
@ -33,8 +34,9 @@ var cmdUsers = []cobra.Command{
|
||||
|
||||
logCreated(id)
|
||||
},
|
||||
},
|
||||
cobra.Command{
|
||||
}
|
||||
|
||||
getCmd := cobra.Command{
|
||||
Use: "get",
|
||||
Short: "get <user_auth_token>",
|
||||
Long: `Returns user object`,
|
||||
@ -52,8 +54,9 @@ var cmdUsers = []cobra.Command{
|
||||
|
||||
logJSON(u)
|
||||
},
|
||||
},
|
||||
cobra.Command{
|
||||
}
|
||||
|
||||
tokenCmd := cobra.Command{
|
||||
Use: "token",
|
||||
Short: "token <username> <password>",
|
||||
Long: `Creates new token`,
|
||||
@ -74,9 +77,11 @@ var cmdUsers = []cobra.Command{
|
||||
}
|
||||
|
||||
logCreated(token)
|
||||
|
||||
},
|
||||
},
|
||||
cobra.Command{
|
||||
}
|
||||
|
||||
updateCmd := cobra.Command{
|
||||
Use: "update",
|
||||
Short: "update <JSON_string> <user_auth_token>",
|
||||
Long: `Update user metadata`,
|
||||
@ -99,8 +104,9 @@ var cmdUsers = []cobra.Command{
|
||||
|
||||
logOK()
|
||||
},
|
||||
},
|
||||
cobra.Command{
|
||||
}
|
||||
|
||||
passwordCmd := cobra.Command{
|
||||
Use: "password",
|
||||
Short: "password <old_password> <password> <user_auth_token>",
|
||||
Long: `Update user password`,
|
||||
@ -117,20 +123,21 @@ var cmdUsers = []cobra.Command{
|
||||
|
||||
logOK()
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewUsersCmd returns users command.
|
||||
func NewUsersCmd() *cobra.Command {
|
||||
cmd := cobra.Command{
|
||||
Use: "users",
|
||||
Short: "Users management",
|
||||
Long: `Users management: create accounts and tokens"`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
logUsage("Usage: users [create | get | update | token | password]")
|
||||
logUsage("users [create | get | update | token | password]")
|
||||
},
|
||||
}
|
||||
|
||||
cmdUsers := []cobra.Command{
|
||||
createCmd, getCmd, tokenCmd, updateCmd, passwordCmd,
|
||||
}
|
||||
|
||||
for i := range cmdUsers {
|
||||
cmd.AddCommand(&cmdUsers[i])
|
||||
}
|
||||
|
26
cli/utils.go
26
cli/utils.go
@ -6,6 +6,7 @@ package cli
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/fatih/color"
|
||||
prettyjson "github.com/hokaccha/go-prettyjson"
|
||||
@ -18,6 +19,12 @@ var (
|
||||
Offset uint = 0
|
||||
// Name query parameter
|
||||
Name string = ""
|
||||
// UserAuthToken user auth token parameter
|
||||
UserAuthToken string = ""
|
||||
// ConfigPath config path parameter
|
||||
ConfigPath string = ""
|
||||
// RawOutput raw output mode
|
||||
RawOutput bool = false
|
||||
)
|
||||
|
||||
func logJSON(iList ...interface{}) {
|
||||
@ -43,7 +50,10 @@ func logUsage(u string) {
|
||||
}
|
||||
|
||||
func logError(err error) {
|
||||
fmt.Printf("\n%s\n\n", color.RedString(err.Error()))
|
||||
boldRed := color.New(color.FgRed, color.Bold)
|
||||
boldRed.Print("\nerror: ")
|
||||
|
||||
fmt.Printf("%s\n\n", color.RedString(err.Error()))
|
||||
}
|
||||
|
||||
func logOK() {
|
||||
@ -51,5 +61,17 @@ func logOK() {
|
||||
}
|
||||
|
||||
func logCreated(e string) {
|
||||
fmt.Printf(color.BlueString("\ncreated: %s\n\n"), e)
|
||||
if RawOutput {
|
||||
fmt.Println(e)
|
||||
} else {
|
||||
fmt.Printf(color.BlueString("\ncreated: %s\n\n"), e)
|
||||
}
|
||||
}
|
||||
|
||||
func getUserAuthToken() string {
|
||||
if UserAuthToken == "" {
|
||||
log.Fatal("user auth token not valid, please pass using --user-auth-token flag or config file")
|
||||
}
|
||||
|
||||
return UserAuthToken
|
||||
}
|
||||
|
@ -32,6 +32,8 @@ func main() {
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "mainflux-cli",
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
cli.ParseConfig()
|
||||
|
||||
sdkConf.MsgContentType = sdk.ContentType(msgContentType)
|
||||
s := sdk.NewSDK(sdkConf)
|
||||
cli.SetSDK(s)
|
||||
@ -117,6 +119,27 @@ func main() {
|
||||
"Do not check for TLS cert",
|
||||
)
|
||||
|
||||
rootCmd.PersistentFlags().StringVar(
|
||||
&cli.UserAuthToken,
|
||||
"user-auth-token",
|
||||
"",
|
||||
"Mainflux user auth token",
|
||||
)
|
||||
|
||||
rootCmd.PersistentFlags().StringVar(
|
||||
&cli.ConfigPath,
|
||||
"config",
|
||||
"",
|
||||
"Mainflux config path",
|
||||
)
|
||||
|
||||
rootCmd.PersistentFlags().BoolVar(
|
||||
&cli.RawOutput,
|
||||
"raw",
|
||||
false,
|
||||
"Enables raw output mode for easier parsing of output",
|
||||
)
|
||||
|
||||
// Client and Channels Flags
|
||||
rootCmd.PersistentFlags().UintVarP(
|
||||
&cli.Limit,
|
||||
|
Loading…
x
Reference in New Issue
Block a user