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

Added '@Botkube commands list' to show all the supported kubectl cmds #328

Merged
merged 9 commits into from
Sep 2, 2020
34 changes: 34 additions & 0 deletions pkg/execute/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ var (
validFilterCommand = map[string]bool{
"filters": true,
}
validInfoCommand = map[string]bool{
"commands": true,
}
validDebugCommands = map[string]bool{
"exec": true,
"logs": true,
Expand Down Expand Up @@ -146,6 +149,14 @@ const (
FilterDisable FiltersAction = "disable"
)

// infoAction for options in Info commands
type infoAction string

// Info command options
const (
infoList infoAction = "list"
)

func (action FiltersAction) String() string {
return string(action)
}
Expand Down Expand Up @@ -210,6 +221,12 @@ func (e *DefaultExecutor) Execute() string {
if validFilterCommand[args[0]] {
return e.runFilterCommand(args, e.ClusterName, e.IsAuthChannel)
}

//Check if info command
if validInfoCommand[args[0]] {
return e.runInfoCommand(args, e.IsAuthChannel)
}

if e.IsAuthChannel {
return printDefaultMsg(e.Platform)
}
Expand Down Expand Up @@ -360,6 +377,23 @@ func (e *DefaultExecutor) runFilterCommand(args []string, clusterName string, is
return printDefaultMsg(e.Platform)
}

//runInfoCommand to list allowed commands
func (e *DefaultExecutor) runInfoCommand(args []string, isAuthChannel bool) string {
if isAuthChannel == false {
return ""
}
if len(args) < 2 && args[1] != string(infoList) {
return IncompleteCmdMsg
}
return makeCommandInfoList()
}

func makeCommandInfoList() string {
allowedVerbs := utils.GetStringInYamlFormat("allowed verbs:", utils.AllowedKubectlVerbMap)
allowedResources := utils.GetStringInYamlFormat("allowed resources:", utils.AllowedKubectlResourceMap)
return allowedVerbs + allowedResources
}

// Use tabwriter to display string in tabular form
// https://golang.org/pkg/text/tabwriter
func makeFiltersList() string {
Expand Down
14 changes: 14 additions & 0 deletions pkg/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
package utils

import (
"bytes"
"fmt"
"os"
"regexp"
"strconv"
Expand Down Expand Up @@ -477,3 +479,15 @@ func GetClusterNameFromKubectlCmd(cmd string) string {
}
return s
}

//GetStringInYamlFormat get the formated commands list
func GetStringInYamlFormat(header string, commands map[string]bool) string {
var b bytes.Buffer
fmt.Fprintln(&b, header)
for k, v := range commands {
if v {
fmt.Fprintf(&b, " - %s\n", k)
}
}
return b.String()
}
13 changes: 13 additions & 0 deletions pkg/utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package utils

import (
"fmt"
"testing"
)

Expand Down Expand Up @@ -49,3 +50,15 @@ func TestGetClusterNameFromKubectlCmd(t *testing.T) {
}
}
}

func TestGetStringInYamlFormat(t *testing.T) {
var header = "allowed verbs"
var commands = map[string]bool{
"api-versions": true,
}
expected := fmt.Sprintf(header + "\n - api-versions\n")
got := GetStringInYamlFormat(header, commands)
if got != expected {
t.Errorf("expected: %v, got: %v", expected, got)
}
}
26 changes: 25 additions & 1 deletion test/e2e/command/botkube.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,29 @@ func (c *context) testBotkubeCommand(t *testing.T) {
"ImageTagChecker true Checks and adds recommendation if 'latest' image tag is used for container image.\n" +
"IngressValidator true Checks if services and tls secrets used in ingress specs are available.\n",
},
"BotKube commands list": {
command: "commands list",
expected: "allowed verbs:\n" +
" - api-resources\n" +
" - describe\n" +
" - diff\n" +
" - explain\n" +
" - get\n" +
" - logs\n" +
" - api-versions\n" +
" - cluster-info\n" +
" - top\n" +
" - auth\n" +
"allowed resources:\n" +
" - nodes\n" +
" - deployments\n" +
" - pods\n" +
" - namespaces\n" +
" - daemonsets\n" +
" - statefulsets\n" +
" - storageclasses\n",
},
}

for name, test := range tests {
t.Run(name, func(t *testing.T) {
if c.TestEnv.Config.Communications.Slack.Enabled {
Expand All @@ -80,6 +101,9 @@ func (c *context) testBotkubeCommand(t *testing.T) {
case "filters list":
fl := compareFilters(strings.Split(test.expected, "\n"), strings.Split(strings.Trim(m.Text, "```"), "\n"))
assert.Equal(t, fl, true)
case "commands list":
cl := compareFilters(strings.Split(test.expected, "\n"), strings.Split(strings.Trim(m.Text, "```"), "\n"))
assert.Equal(t, cl, true)
default:
assert.Equal(t, test.expected, m.Text)
}
Expand Down
3 changes: 2 additions & 1 deletion test/resource_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,8 @@ settings:
# method which are allowed
verbs: ["api-resources", "api-versions", "cluster-info", "describe", "diff", "explain", "get", "logs", "top", "auth"]
# resource configuration which is allowed
resources: ["deployments", "pods" , "namespaces", "daemonsets", "statefulsets", "storageclasses", "serviceaccounts"]
resources: ["deployments", "pods" , "namespaces", "daemonsets", "statefulsets", "storageclasses", "nodes"]

# set Namespace to execute botkube kubectl commands by default
defaultNamespace: default
# Set true to enable commands execution from configured channel only
Expand Down