Skip to content

Commit

Permalink
Merge pull request #21 from Ladicle/msg-and-desc
Browse files Browse the repository at this point in the history
Provide readable error and help messages
  • Loading branch information
Ladicle authored Mar 18, 2020
2 parents 8bfe3a1 + 40fa1d4 commit 6fe7880
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 36 deletions.
31 changes: 19 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# kubectl-bindrole

Summarize RBAC roles tied to the given subject.
Summarize RBAC roles for the specified subject (ServiceAccount, User and Group).

![screenshot](./img/screenshot.png)

Expand All @@ -11,8 +11,7 @@ Summarize RBAC roles tied to the given subject.
bindrole supports [homebrew](https://docs.brew.sh/Installation) :beer:

```
brew tap Ladicle/kubectl-bindrole
brew install kubectl-bindrole
brew install Ladicle/kubectl-bindrole/kubectl-bindrole
```

### for other devices
Expand All @@ -24,23 +23,31 @@ You can also download this repository and install it using Makefile.

```bash
$ kubectl bindrole -h # or kubectl-bindrole -h
Summarize RBAC roles tied to the given subject
Summarize RBAC roles for the specified subject

Usage:
kubectl bindrole [options] <SubjectName>

Examples:
# Summarize roles tied to the "ci-bot" ServiceAccount.
kubectl-bindrole ci-bot
kubectl bindrole ci-bot

# Summarize roles tied to the "developer" Group.
kubectl-bindrole developer -k Group
kubectl bindrole -k Group developer

Options:
-k, --subject-kind='ServiceAccount': subject kind (available: ServiceAccount, Group or User)
--version=false: version for kubectl-bindrole
SubjectKinds:
- ServiceAccount (default)
- User
- Group

Usage:
kubectl-bindrole <SubjectName> [options]
Options:
-h, --help Display this help message
-n, --namespace string Change the namespace scope for this CLI request
-k, --subject-kind string Set SubjectKind to summarize (default: ServiceAccount)
-o, --options List of all options for this command
--version Show version for this command

Use "kubectl-bindrole options" for a list of global command-line options (applies to all commands).
Use "kubectl bindrole --options" for a list of all options (applies to this command).
```

This command supports both kubectl-plugin mode and standalone mode.
71 changes: 52 additions & 19 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,22 @@ package cmd
import (
"errors"
"fmt"
"os"

// Initialize all known client auth plugins.
_ "k8s.io/client-go/plugin/pkg/client/auth"

"github.com/logrusorgru/aurora"
"github.com/spf13/cobra"
rbacv1 "k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/util/templates"

"github.com/Ladicle/kubectl-bindrole/pkg/explorer"
brcmdutil "github.com/Ladicle/kubectl-bindrole/pkg/util/cmd"
"github.com/Ladicle/kubectl-bindrole/pkg/util/printer"
"github.com/Ladicle/kubectl-bindrole/pkg/util/subject"
)
Expand All @@ -24,35 +28,44 @@ var (
command string
version string
commit string

bindroleExample = fmt.Sprintf(`%v
kubectl bindrole ci-bot
%v
kubectl bindrole -k Group developer`,
aurora.BrightBlack("# Summarize roles tied to the \"ci-bot\" ServiceAccount."),
aurora.BrightBlack("# Summarize roles tied to the \"developer\" Group."))
)

type Option struct {
SubjectKind string
SubjectName string
SubjectKind string
SubjectName string
ShowOptionFlag bool

f cmdutil.Factory
}

func NewBindroleCmd() *cobra.Command {
opt := Option{}
cmd := &cobra.Command{
Use: fmt.Sprintf("%s <SubjectName>", command),
Version: fmt.Sprintf("%v @%v", version, commit),
Use: fmt.Sprintf("bindrole [options] <%v>",
aurora.Yellow("SubjectName")),
Version: version,
DisableFlagsInUseLine: true,
Short: "Summarize RBAC roles tied to the given subject",
Long: templates.LongDesc("Summarize RBAC roles tied to the given subject"),
Example: templates.Examples(fmt.Sprintf(`# Summarize roles tied to the "ci-bot" ServiceAccount.
%s ci-bot
# Summarize roles tied to the "developer" Group.
%s developer -k Group`, command, command)),
SilenceUsage: true,
SilenceErrors: true,
Short: "Summarize RBAC roles for the specified subject",
Long: "Summarize RBAC roles for the specified subject",
Example: templates.Examples(bindroleExample),
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(opt.Validate(cmd, args))
cmdutil.CheckErr(opt.Run())
brcmdutil.CheckErr(opt.Validate(cmd, args))
brcmdutil.CheckErr(opt.Run())
},
}

templates.ActsAsRootCommand(cmd, []string{"options"})
cmd.SetVersionTemplate(brcmdutil.VersionTemplate)
cmd.SetUsageTemplate(brcmdutil.UsageTemplate)

fsets := cmd.PersistentFlags()
cfgFlags := genericclioptions.NewConfigFlags(true)
Expand All @@ -62,17 +75,31 @@ func NewBindroleCmd() *cobra.Command {

opt.f = cmdutil.NewFactory(matchVersionFlags)

cmd.Flags().StringVarP(&opt.SubjectKind, "subject-kind", "k", subject.KindSA,
fmt.Sprintf("subject kind (available: %s, %s or %s)", subject.KindSA, subject.KindGroup, subject.KindUser))
cmd.Flags().StringVarP(&opt.SubjectKind, "subject-kind", "k", subject.KindSA, "Set SubjectKind to summarize")
cmd.Flags().BoolVarP(&opt.ShowOptionFlag, "options", "o", false, "List of all options for this command")

return cmd
}

func (o *Option) Validate(cmd *cobra.Command, args []string) error {
if o.ShowOptionFlag {
cmd.SetUsageTemplate(brcmdutil.OptionTemplate)
fmt.Println(cmd.UsageString())
os.Exit(0)
}

if len(args) == 0 {
return errors.New("subject name is required")
return errors.New(fmt.Sprintf("<%v> is required argument",
aurora.Cyan("SubjectName").Bold()))
}
o.SubjectName = args[0]

switch o.SubjectKind {
case subject.KindGroup, subject.KindSA, subject.KindUser:
default:
return errors.New(fmt.Sprintf("\"%v\" is unknown SubjectKind",
aurora.Cyan(o.SubjectKind).Bold()))
}
return nil
}

Expand Down Expand Up @@ -106,14 +133,20 @@ func (o *Option) Run() error {
}

pp := printer.DefaultPrettyPrinter()
pp.PrintSubject(sub)

if sub.Kind == subject.KindSA {
sa, err := client.CoreV1().ServiceAccounts(sub.Namespace).
Get(sub.Name, metav1.GetOptions{})
if err != nil {
if apierrors.IsNotFound(err) {
return errors.New(fmt.Sprintf("ServiceAccount \"%v\" not found",
aurora.Cyan(fmt.Sprintf("%v/%v", sub.Namespace, sub.Name)).Bold()))
} else if err != nil {
return err
}
pp.PrintSubject(sub)
pp.PrintSA(sa)
} else {
pp.PrintSubject(sub)
}

pp.BlankLine()
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/mattn/go-runewidth v0.0.4 // indirect
github.com/olekukonko/tablewriter v0.0.1
github.com/spf13/cobra v0.0.5
github.com/spf13/pflag v1.0.5
k8s.io/api v0.17.4
k8s.io/apimachinery v0.17.4
k8s.io/cli-runtime v0.17.4
Expand Down
13 changes: 8 additions & 5 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package main

import (
"fmt"
"os"
"github.com/spf13/pflag"

"github.com/Ladicle/kubectl-bindrole/cmd"
cmdutil "github.com/Ladicle/kubectl-bindrole/pkg/util/cmd"
)

func init() {
flags := pflag.NewFlagSet("kubectl-bindrole", pflag.ExitOnError)
pflag.CommandLine = flags
}

func main() {
command := cmd.NewBindroleCmd()
if err := command.Execute(); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v", err)
}
cmdutil.CheckErr(command.Execute())
}
17 changes: 17 additions & 0 deletions pkg/util/cmd/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package cmd

import (
"fmt"
"os"

"github.com/logrusorgru/aurora"
)

func CheckErr(err error) {
if err == nil {
return
}
fmt.Fprintf(os.Stderr, " %v Error: %v.\n", aurora.Red(">"), err)
fmt.Fprintf(os.Stderr, " %v Run %v command for the usage.\n", aurora.Red(">"), aurora.Yellow("kubectl bindrole -h"))
os.Exit(1)
}
47 changes: 47 additions & 0 deletions pkg/util/cmd/usage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package cmd

import (
"fmt"

"github.com/logrusorgru/aurora"
)

var UsageTemplate = fmt.Sprintf(`%v:{{if .Runnable}}
kubectl {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
{{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}}
%v:
{{.NameAndAliases}}{{end}}{{if .HasExample}}
%v:
{{.Example}}{{end}}{{if .HasAvailableSubCommands}}
Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}
%v:
- ServiceAccount (default)
- User
- Group
%v:
-h, --help Display this help message
-n, --namespace string Change the namespace scope for this CLI request
-k, --subject-kind string Set SubjectKind to summarize (default: ServiceAccount)
-o, --options List of all options for this command
--version Show version for this command
Use "kubectl bindrole --options" for a list of all options (applies to this command).
`,
aurora.Cyan("Usage"),
aurora.Cyan("Aliases"),
aurora.Cyan("Examples"),
aurora.Cyan("SubjectKinds"),
aurora.Cyan("Options"))

var OptionTemplate = `The following options can be passed to this command:
{{if .HasAvailableLocalFlags}}{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}`

var VersionTemplate = fmt.Sprintf(` %v {{.Name}} version {{.Version}}
`, aurora.Yellow(">"))

0 comments on commit 6fe7880

Please sign in to comment.