mirror of
https://github.com/valitydev/botkube.git
synced 2024-11-06 16:35:22 +00:00
Issue #37: Added multi-cluster support for displaying cluster specific information.
Issue #16: Added cluster-name in kubectl, notifier and ping messages from botkube.
This commit is contained in:
parent
aa72ab38a9
commit
e82a1d7f97
@ -125,5 +125,3 @@ settings:
|
|||||||
clustername: not-configured
|
clustername: not-configured
|
||||||
# Set false to disable kubectl commands execution
|
# Set false to disable kubectl commands execution
|
||||||
allowkubectl: false
|
allowkubectl: false
|
||||||
# Set true only respond to channel in config
|
|
||||||
checkchannel: false
|
|
51
design/multi-cluster.md
Normal file
51
design/multi-cluster.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# Multi-cluster Support
|
||||||
|
|
||||||
|
#### Assumptions
|
||||||
|
`@botkube` commands refer to all the commands in the slack bot which currently supports:
|
||||||
|
- kubectl
|
||||||
|
- notifier
|
||||||
|
- ping
|
||||||
|
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
Add Multi-cluster support for Botkube, where a single bot can monitor multiple clusters and respond to `@botkube` commands with cluster specific results.
|
||||||
|
|
||||||
|
### Motivation
|
||||||
|
Currently in multi-cluster scenario, a Slack bot authenticates all the clusters with a same authentication token. Thus running `@botkube` command returns response from all the configured clusters, irrespective of the slack channel or group. For `@botkube` command execution, we need a particular cluster specific output.
|
||||||
|
|
||||||
|
### Design
|
||||||
|
|
||||||
|
This design approach adds a flag `--cluster-name` to all `@botkube` commands. Use of that flag is optional in a cluster specific channel.
|
||||||
|
|
||||||
|
Botkube `Notifier` commands are restricted to a dedicated channel for a cluster only and `--cluster-name` flag is ignored.
|
||||||
|
|
||||||
|
Botkube `ping` command with the `--cluster-name` flag returns `pong` response from the cluster specified in the flag, else you get response from all the clusters. `Ping` command without --cluster-name flag can be used to list all the configured clusters in the slack bot and identify you cluster's name among them.
|
||||||
|
|
||||||
|
For `kubectl` commands in a dedicated channel to a cluster, if `--cluster-name` flag is used, it responds with the output for the cluster specified in flag, else it checks if the channel in the request matches the `config.Communications.Slack.Channel` and responds if true else ignores.
|
||||||
|
|
||||||
|
For `kubectl` commands in a group, Direct message or channel not dedicated to any cluster, the `--cluster-name` flag is mandatory. The executor checks if the `--cluster-name` flag is present in the request. If yes, it gets the cluster's name from the flag and compares with `c.Settings.ClusterName` from the config file, if it matches then it responds with the required output to the slack bot and if it doesn't match, it ignores the request. And if the `--cluster-name` flag is absent for kubectl commands, it responds to the slack bot saying 'Please specify the cluster-name'.
|
||||||
|
|
||||||
|
For example -
|
||||||
|
```sh
|
||||||
|
@Botkube get pods --cluster-name={CLUSTER_NAME}
|
||||||
|
```
|
||||||
|
where,
|
||||||
|
`CLUSTER_NAME` is the name of the cluster you want to query.
|
||||||
|
|
||||||
|
To get the list of all clusters configured in the slack, you can run the following command in slack.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
@Botkube ping
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Workflow
|
||||||
|
|
||||||
|
![Multi_Cluster_Design](workflow.png)
|
||||||
|
|
||||||
|
|
||||||
|
### Drawbacks
|
||||||
|
The `--cluster-name` flag is mandated for kubectl and notifier commands resulting additional overhead.
|
||||||
|
|
||||||
|
### Alternatives
|
||||||
|
We can add channel specific authentication token or completely dedicate a channel to a particular cluster which requires changes in the slack code.
|
||||||
|
|
BIN
design/workflow.png
Normal file
BIN
design/workflow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 78 KiB |
@ -140,8 +140,6 @@ config:
|
|||||||
clustername: not-configured
|
clustername: not-configured
|
||||||
# Set false to disable kubectl commands execution
|
# Set false to disable kubectl commands execution
|
||||||
allowkubectl: false
|
allowkubectl: false
|
||||||
# Set true only respond to channel in config
|
|
||||||
checkchannel: false
|
|
||||||
|
|
||||||
resources: {}
|
resources: {}
|
||||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||||
|
@ -49,7 +49,6 @@ type Slack struct {
|
|||||||
type Settings struct {
|
type Settings struct {
|
||||||
ClusterName string
|
ClusterName string
|
||||||
AllowKubectl bool
|
AllowKubectl bool
|
||||||
CheckChannel bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns new Config
|
// New returns new Config
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -20,13 +21,13 @@ import (
|
|||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
var startTime time.Time
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
controllerStartMsg = "...and now my watch begins! :crossed_swords:"
|
controllerStartMsg = "...and now my watch begins for cluster '%s'! :crossed_swords:"
|
||||||
controllerStopMsg = "my watch has ended!"
|
controllerStopMsg = "my watch has ended for cluster '%s'!"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var startTime time.Time
|
||||||
|
|
||||||
func findNamespace(ns string) string {
|
func findNamespace(ns string) string {
|
||||||
if ns == "all" {
|
if ns == "all" {
|
||||||
return apiV1.NamespaceAll
|
return apiV1.NamespaceAll
|
||||||
@ -39,7 +40,7 @@ func findNamespace(ns string) string {
|
|||||||
|
|
||||||
// RegisterInformers creates new informer controllers to watch k8s resources
|
// RegisterInformers creates new informer controllers to watch k8s resources
|
||||||
func RegisterInformers(c *config.Config) {
|
func RegisterInformers(c *config.Config) {
|
||||||
sendMessage(controllerStartMsg)
|
sendMessage(fmt.Sprintf(controllerStartMsg, c.Settings.ClusterName))
|
||||||
startTime = time.Now().Local()
|
startTime = time.Now().Local()
|
||||||
|
|
||||||
// Get resync period
|
// Get resync period
|
||||||
@ -127,7 +128,7 @@ func RegisterInformers(c *config.Config) {
|
|||||||
signal.Notify(sigterm, syscall.SIGTERM)
|
signal.Notify(sigterm, syscall.SIGTERM)
|
||||||
signal.Notify(sigterm, syscall.SIGINT)
|
signal.Notify(sigterm, syscall.SIGINT)
|
||||||
<-sigterm
|
<-sigterm
|
||||||
sendMessage(controllerStopMsg)
|
sendMessage(fmt.Sprintf(controllerStopMsg, c.Settings.ClusterName))
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerEventHandlers(resourceType string, events []string) (handlerFns cache.ResourceEventHandlerFuncs) {
|
func registerEventHandlers(resourceType string, events []string) (handlerFns cache.ResourceEventHandlerFuncs) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package execute
|
package execute
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -25,19 +26,23 @@ var validKubectlCommands = map[string]bool{
|
|||||||
"auth": true,
|
"auth": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
var validNotifierCommands = map[string]bool{
|
var validNotifierCommand = map[string]bool{
|
||||||
"notifier": true,
|
"notifier": true,
|
||||||
"help": true,
|
}
|
||||||
"ping": true,
|
var validPingCommand = map[string]bool{
|
||||||
|
"ping": true,
|
||||||
|
}
|
||||||
|
var validHelpCommand = map[string]bool{
|
||||||
|
"help": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
var kubectlBinary = "/usr/local/bin/kubectl"
|
var kubectlBinary = "/usr/local/bin/kubectl"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
notifierStartMsg = "Brace yourselves, notifications are coming."
|
notifierStartMsg = "Brace yourselves, notifications are coming from cluster '%s'."
|
||||||
notifierStopMsg = "Sure! I won't send you notifications anymore."
|
notifierStopMsg = "Sure! I won't send you notifications from cluster '%s' anymore."
|
||||||
unsupportedCmdMsg = "Command not supported. Please run '@BotKube help' to see supported commands."
|
unsupportedCmdMsg = "Command not supported. Please run '@BotKube help' to see supported commands."
|
||||||
kubectlDisabledMsg = "Sorry, the admin hasn't given me the permission to execute kubectl command."
|
kubectlDisabledMsg = "Sorry, the admin hasn't given me the permission to execute kubectl command on cluster '%s'."
|
||||||
)
|
)
|
||||||
|
|
||||||
// Executor is an interface for processes to execute commands
|
// Executor is an interface for processes to execute commands
|
||||||
@ -47,15 +52,52 @@ type Executor interface {
|
|||||||
|
|
||||||
// DefaultExecutor is a default implementations of Executor
|
// DefaultExecutor is a default implementations of Executor
|
||||||
type DefaultExecutor struct {
|
type DefaultExecutor struct {
|
||||||
Message string
|
Message string
|
||||||
AllowKubectl bool
|
AllowKubectl bool
|
||||||
|
ClusterName string
|
||||||
|
ChannelName string
|
||||||
|
IsAuthChannel bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotifierAction creates custom type for notifier actions
|
||||||
|
type NotifierAction string
|
||||||
|
|
||||||
|
// Defines constants for notifier actions
|
||||||
|
const (
|
||||||
|
Start NotifierAction = "start"
|
||||||
|
Stop NotifierAction = "stop"
|
||||||
|
Status NotifierAction = "status"
|
||||||
|
ShowConfig NotifierAction = "showconfig"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (action NotifierAction) String() string {
|
||||||
|
return string(action)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommandFlags creates custom type for flags in botkube
|
||||||
|
type CommandFlags string
|
||||||
|
|
||||||
|
// Defines botkube flags
|
||||||
|
const (
|
||||||
|
ClusterFlag CommandFlags = "--cluster-name"
|
||||||
|
FollowFlag CommandFlags = "--follow"
|
||||||
|
AbbrFollowFlag CommandFlags = "-f"
|
||||||
|
WatchFlag CommandFlags = "--watch"
|
||||||
|
AbbrWatchFlag CommandFlags = "-w"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (flag CommandFlags) String() string {
|
||||||
|
return string(flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDefaultExecutor returns new Executor object
|
// NewDefaultExecutor returns new Executor object
|
||||||
func NewDefaultExecutor(msg string, allowkubectl bool) Executor {
|
func NewDefaultExecutor(msg string, allowkubectl bool, clusterName, channelName string, isAuthChannel bool) Executor {
|
||||||
return &DefaultExecutor{
|
return &DefaultExecutor{
|
||||||
Message: msg,
|
Message: msg,
|
||||||
AllowKubectl: allowkubectl,
|
AllowKubectl: allowkubectl,
|
||||||
|
ClusterName: clusterName,
|
||||||
|
ChannelName: channelName,
|
||||||
|
IsAuthChannel: isAuthChannel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,112 +106,172 @@ func (e *DefaultExecutor) Execute() string {
|
|||||||
args := strings.Split(e.Message, " ")
|
args := strings.Split(e.Message, " ")
|
||||||
if validKubectlCommands[args[0]] {
|
if validKubectlCommands[args[0]] {
|
||||||
if !e.AllowKubectl {
|
if !e.AllowKubectl {
|
||||||
return kubectlDisabledMsg
|
return fmt.Sprintf(kubectlDisabledMsg, e.ClusterName)
|
||||||
}
|
}
|
||||||
return runKubectlCommand(args)
|
return runKubectlCommand(args, e.ClusterName, e.IsAuthChannel)
|
||||||
}
|
}
|
||||||
if validNotifierCommands[args[0]] {
|
if validNotifierCommand[args[0]] {
|
||||||
return runNotifierCommand(args)
|
return runNotifierCommand(args, e.ClusterName, e.IsAuthChannel)
|
||||||
|
}
|
||||||
|
if validPingCommand[args[0]] {
|
||||||
|
return runPingCommand(args, e.ClusterName)
|
||||||
|
}
|
||||||
|
if validHelpCommand[args[0]] {
|
||||||
|
return printHelp(e.ChannelName)
|
||||||
}
|
}
|
||||||
return unsupportedCmdMsg
|
return unsupportedCmdMsg
|
||||||
}
|
}
|
||||||
|
|
||||||
func printHelp() string {
|
func printHelp(channelName string) string {
|
||||||
allowedKubectl := ""
|
kubecltCmdKeys := make([]string, 0, len(validKubectlCommands))
|
||||||
for k := range validKubectlCommands {
|
for cmd := range validKubectlCommands {
|
||||||
allowedKubectl = allowedKubectl + k + ", "
|
kubecltCmdKeys = append(kubecltCmdKeys, cmd)
|
||||||
}
|
}
|
||||||
helpMsg := "BotKube executes kubectl commands on k8s cluster and returns output.\n" +
|
allowedKubectl := strings.Join(kubecltCmdKeys, ", ")
|
||||||
"Usages:\n" +
|
helpMsg := `
|
||||||
" @BotKube <kubectl command without `kubectl` prefix>\n" +
|
BotKube Help
|
||||||
"e.g:\n" +
|
|
||||||
" @BotKube get pods\n" +
|
|
||||||
" @BotKube logs podname -n namespace\n" +
|
|
||||||
"Allowed kubectl commands:\n" +
|
|
||||||
" " + allowedKubectl + "\n\n" +
|
|
||||||
"Commands to manage notifier:\n" +
|
|
||||||
"notifier stop Stop sending k8s event notifications to Slack (started by default)\n" +
|
|
||||||
"notifier start Start sending k8s event notifications to Slack\n" +
|
|
||||||
"notifier status Show running status of event notifier\n" +
|
|
||||||
"notifier showconfig Show BotKube configuration for event notifier\n\n" +
|
|
||||||
"Other Commands:\n" +
|
|
||||||
"help Show help\n" +
|
|
||||||
"ping Check connection health\n"
|
|
||||||
return helpMsg
|
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
@BotKube <kubectl command without kubectl prefix> [--cluster-name <cluster_name>]
|
||||||
|
@BotKube notifier [stop|start|status|showconfig]
|
||||||
|
@BotKube ping [--cluster-name <cluster-name>]
|
||||||
|
|
||||||
|
Description:
|
||||||
|
|
||||||
|
Kubectl commands:
|
||||||
|
- Executes kubectl commands on k8s cluster and returns output.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
@BotKube get pods
|
||||||
|
@BotKube logs podname -n namespace
|
||||||
|
@BotKube get deployment --cluster-name cluster_name
|
||||||
|
|
||||||
|
Allowed kubectl commands:
|
||||||
|
%s
|
||||||
|
|
||||||
|
Cluster Status:
|
||||||
|
- List all available Kubernetes Clusters and check connection health.
|
||||||
|
- If flag specified, gives response from the specified cluster.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
@BotKube ping
|
||||||
|
@BotKube ping --cluster-name mycluster
|
||||||
|
|
||||||
|
Notifier commands:
|
||||||
|
- Commands to manage notifier (Runs only on configured channel %s).
|
||||||
|
|
||||||
|
Example:
|
||||||
|
@BotKube notifier stop Stop sending k8s event notifications to Slack
|
||||||
|
@BotKube notifier start Start sending k8s event notifications to Slack
|
||||||
|
@BotKube notifier status Show running status of event notifier
|
||||||
|
@BotKube notifier showconfig Show BotKube configuration for event notifier
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--cluster-name Get cluster specific response
|
||||||
|
`
|
||||||
|
return fmt.Sprintf(helpMsg, allowedKubectl, channelName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func printDefaultMsg() string {
|
func printDefaultMsg() string {
|
||||||
return unsupportedCmdMsg
|
return unsupportedCmdMsg
|
||||||
}
|
}
|
||||||
|
|
||||||
func runKubectlCommand(args []string) string {
|
func runKubectlCommand(args []string, clusterName string, isAuthChannel bool) string {
|
||||||
// Use 'default' as a default namespace
|
// Use 'default' as a default namespace
|
||||||
args = append([]string{"-n", "default"}, args...)
|
args = append([]string{"-n", "default"}, args...)
|
||||||
|
|
||||||
// Remove unnecessary flags
|
// Remove unnecessary flags
|
||||||
finalArgs := []string{}
|
finalArgs := []string{}
|
||||||
for _, a := range args {
|
checkFlag := false
|
||||||
if a == "-f" || strings.HasPrefix(a, "--follow") {
|
for _, arg := range args {
|
||||||
|
if checkFlag {
|
||||||
|
if arg != clusterName {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
checkFlag = false
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if a == "-w" || strings.HasPrefix(a, "--watch") {
|
if arg == AbbrFollowFlag.String() || strings.HasPrefix(arg, FollowFlag.String()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
finalArgs = append(finalArgs, a)
|
if arg == AbbrWatchFlag.String() || strings.HasPrefix(arg, WatchFlag.String()) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(arg, ClusterFlag.String()) {
|
||||||
|
if arg == ClusterFlag.String() {
|
||||||
|
checkFlag = true
|
||||||
|
} else if strings.SplitAfterN(arg, ClusterFlag.String()+"=", 2)[1] != clusterName {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
isAuthChannel = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
finalArgs = append(finalArgs, arg)
|
||||||
|
}
|
||||||
|
if isAuthChannel == false {
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.Command(kubectlBinary, finalArgs...)
|
cmd := exec.Command(kubectlBinary, finalArgs...)
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logger.Error("Error in executing kubectl command: ", err)
|
log.Logger.Error("Error in executing kubectl command: ", err)
|
||||||
return string(out) + err.Error()
|
return fmt.Sprintf("Cluster: %s\n%s", clusterName, string(out)+err.Error())
|
||||||
}
|
}
|
||||||
return string(out)
|
return fmt.Sprintf("Cluster: %s\n%s", clusterName, string(out))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Have a seperate cli which runs bot commands
|
// TODO: Have a seperate cli which runs bot commands
|
||||||
func runNotifierCommand(args []string) string {
|
func runNotifierCommand(args []string, clusterName string, isAuthChannel bool) string {
|
||||||
switch len(args) {
|
if isAuthChannel == false {
|
||||||
case 1:
|
return ""
|
||||||
if strings.ToLower(args[0]) == "help" {
|
}
|
||||||
return printHelp()
|
switch args[1] {
|
||||||
|
case Start.String():
|
||||||
|
config.Notify = true
|
||||||
|
log.Logger.Info("Notifier enabled")
|
||||||
|
return fmt.Sprintf(notifierStartMsg, clusterName)
|
||||||
|
case Stop.String():
|
||||||
|
config.Notify = false
|
||||||
|
log.Logger.Info("Notifier disabled")
|
||||||
|
return fmt.Sprintf(notifierStopMsg, clusterName)
|
||||||
|
case Status.String():
|
||||||
|
if config.Notify == false {
|
||||||
|
return fmt.Sprintf("Notifications are off for cluster '%s'", clusterName)
|
||||||
}
|
}
|
||||||
if strings.ToLower(args[0]) == "ping" {
|
return fmt.Sprintf("Notifications are on for cluster '%s'", clusterName)
|
||||||
return "pong"
|
case ShowConfig.String():
|
||||||
}
|
out, err := showControllerConfig()
|
||||||
case 2:
|
if err != nil {
|
||||||
if args[0] != "notifier" {
|
log.Logger.Error("Error in executing showconfig command: ", err)
|
||||||
return printDefaultMsg()
|
return "Error in getting configuration!"
|
||||||
}
|
|
||||||
if args[1] == "start" {
|
|
||||||
config.Notify = true
|
|
||||||
log.Logger.Info("Notifier enabled")
|
|
||||||
return notifierStartMsg
|
|
||||||
}
|
|
||||||
if args[1] == "stop" {
|
|
||||||
config.Notify = false
|
|
||||||
log.Logger.Info("Notifier disabled")
|
|
||||||
return notifierStopMsg
|
|
||||||
}
|
|
||||||
if args[1] == "status" {
|
|
||||||
if config.Notify == false {
|
|
||||||
return "stopped"
|
|
||||||
}
|
|
||||||
return "running"
|
|
||||||
}
|
|
||||||
if args[1] == "showconfig" {
|
|
||||||
out, err := showControllerConfig()
|
|
||||||
if err != nil {
|
|
||||||
log.Logger.Error("Error in executing showconfig command: ", err)
|
|
||||||
return "Error in getting configuration!"
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
}
|
||||||
|
return fmt.Sprintf("Showing config for cluster '%s'\n\n%s", clusterName, out)
|
||||||
}
|
}
|
||||||
return printDefaultMsg()
|
return printDefaultMsg()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func runPingCommand(args []string, clusterName string) string {
|
||||||
|
checkFlag := false
|
||||||
|
for _, arg := range args {
|
||||||
|
if checkFlag {
|
||||||
|
if arg != clusterName {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
checkFlag = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(arg, ClusterFlag.String()) {
|
||||||
|
if arg == ClusterFlag.String() {
|
||||||
|
checkFlag = true
|
||||||
|
} else if strings.SplitAfterN(arg, ClusterFlag.String()+"=", 2)[1] != clusterName {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("pong from cluster '%s'", clusterName)
|
||||||
|
}
|
||||||
|
|
||||||
func showControllerConfig() (string, error) {
|
func showControllerConfig() (string, error) {
|
||||||
configPath := os.Getenv("CONFIG_PATH")
|
configPath := os.Getenv("CONFIG_PATH")
|
||||||
configFile := filepath.Join(configPath, config.ConfigFileName)
|
configFile := filepath.Join(configPath, config.ConfigFileName)
|
||||||
|
@ -14,14 +14,15 @@ import (
|
|||||||
type Bot struct {
|
type Bot struct {
|
||||||
Token string
|
Token string
|
||||||
AllowKubectl bool
|
AllowKubectl bool
|
||||||
|
ClusterName string
|
||||||
ChannelName string
|
ChannelName string
|
||||||
CheckChannel bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// slackMessage contains message details to execute command and send back the result
|
// slackMessage contains message details to execute command and send back the result
|
||||||
type slackMessage struct {
|
type slackMessage struct {
|
||||||
ChannelID string
|
ChannelID string
|
||||||
BotID string
|
BotID string
|
||||||
|
MessageType string
|
||||||
InMessage string
|
InMessage string
|
||||||
OutMessage string
|
OutMessage string
|
||||||
OutMsgLength int
|
OutMsgLength int
|
||||||
@ -37,8 +38,8 @@ func NewSlackBot() *Bot {
|
|||||||
return &Bot{
|
return &Bot{
|
||||||
Token: c.Communications.Slack.Token,
|
Token: c.Communications.Slack.Token,
|
||||||
AllowKubectl: c.Settings.AllowKubectl,
|
AllowKubectl: c.Settings.AllowKubectl,
|
||||||
|
ClusterName: c.Settings.ClusterName,
|
||||||
ChannelName: c.Communications.Slack.Channel,
|
ChannelName: c.Communications.Slack.Channel,
|
||||||
CheckChannel: c.Settings.CheckChannel,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,6 +56,7 @@ func (b *Bot) Start() {
|
|||||||
go rtm.ManageConnection()
|
go rtm.ManageConnection()
|
||||||
|
|
||||||
for msg := range rtm.IncomingEvents {
|
for msg := range rtm.IncomingEvents {
|
||||||
|
isAuthChannel := false
|
||||||
switch ev := msg.Data.(type) {
|
switch ev := msg.Data.(type) {
|
||||||
case *slack.ConnectedEvent:
|
case *slack.ConnectedEvent:
|
||||||
logging.Logger.Debug("Connection Info: ", ev.Info)
|
logging.Logger.Debug("Connection Info: ", ev.Info)
|
||||||
@ -73,10 +75,9 @@ func (b *Bot) Start() {
|
|||||||
if !strings.HasPrefix(ev.Text, "<@"+botID+"> ") {
|
if !strings.HasPrefix(ev.Text, "<@"+botID+"> ") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// if config.settings.checkChannel is true
|
|
||||||
// Serve only if current channel is in config
|
// Serve only if current channel is in config
|
||||||
if b.CheckChannel && (b.ChannelName != info.Name) {
|
if b.ChannelName == info.Name {
|
||||||
continue
|
isAuthChannel = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,7 +96,7 @@ func (b *Bot) Start() {
|
|||||||
InMessage: inMessage,
|
InMessage: inMessage,
|
||||||
RTM: rtm,
|
RTM: rtm,
|
||||||
}
|
}
|
||||||
sm.HandleMessage(b.AllowKubectl)
|
sm.HandleMessage(b.AllowKubectl, b.ClusterName, b.ChannelName, isAuthChannel)
|
||||||
|
|
||||||
case *slack.RTMError:
|
case *slack.RTMError:
|
||||||
logging.Logger.Errorf("Slack RMT error: %+v", ev.Error())
|
logging.Logger.Errorf("Slack RMT error: %+v", ev.Error())
|
||||||
@ -108,8 +109,8 @@ func (b *Bot) Start() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *slackMessage) HandleMessage(allowkubectl bool) {
|
func (sm *slackMessage) HandleMessage(allowkubectl bool, clusterName, channelName string, isAuthChannel bool) {
|
||||||
e := execute.NewDefaultExecutor(sm.InMessage, allowkubectl)
|
e := execute.NewDefaultExecutor(sm.InMessage, allowkubectl, clusterName, channelName, isAuthChannel)
|
||||||
sm.OutMessage = e.Execute()
|
sm.OutMessage = e.Execute()
|
||||||
sm.OutMsgLength = len(sm.OutMessage)
|
sm.OutMsgLength = len(sm.OutMessage)
|
||||||
sm.Send()
|
sm.Send()
|
||||||
@ -141,7 +142,11 @@ func (sm slackMessage) Send() {
|
|||||||
logging.Logger.Error("Error in uploading file:", err)
|
logging.Logger.Error("Error in uploading file:", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
} else if sm.OutMsgLength == 0 {
|
||||||
|
logging.Logger.Info("Invalid request. Dumping the response")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
params := slack.PostMessageParameters{
|
params := slack.PostMessageParameters{
|
||||||
AsUser: true,
|
AsUser: true,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user