From 46d6f9b825517f6183c4b15c787308f770d865d7 Mon Sep 17 00:00:00 2001 From: Prasad Ghangal Date: Tue, 15 Jan 2019 13:07:40 +0530 Subject: [PATCH] Add support for multiple clusters --- config.yaml | 7 +++++++ helm/botkube/values.yaml | 9 ++++++++- pkg/config/config.go | 7 +++++++ pkg/execute/executor.go | 18 ++++++++++++------ pkg/notify/slack.go | 18 +++++++++++++----- pkg/slack/slack.go | 16 +++++++++------- 6 files changed, 56 insertions(+), 19 deletions(-) diff --git a/config.yaml b/config.yaml index 532d858bb..09a913c1c 100644 --- a/config.yaml +++ b/config.yaml @@ -118,3 +118,10 @@ communications: slack: channel: 'SLACK_CHANNEL' token: 'SLACK_API_TOKEN' + +# Setting to support multiple clusters +settings: + # Cluster name to differentiate incoming messages + clustername: not-configured + # Set false to disable kubectl commands execution + allowkubectl: false diff --git a/helm/botkube/values.yaml b/helm/botkube/values.yaml index 4e174ef6c..e6686639d 100644 --- a/helm/botkube/values.yaml +++ b/helm/botkube/values.yaml @@ -6,7 +6,7 @@ replicaCount: 1 image: repository: infracloud/botkube - tag: "0.1" + tag: "0.2" pullPolicy: Always nameOverride: "" @@ -134,6 +134,13 @@ config: channel: 'SLACK_CHANNEL' token: 'SLACK_API_TOKEN' + # Setting to support multiple clusters + settings: + # Cluster name to differentiate incoming messages + clustername: not-configured + # Set false to disable kubectl commands execution + allowkubectl: false + resources: {} # We usually recommend not to specify default resources and to leave this as a conscious # choice for the user. This also increases chances charts run on environments with little diff --git a/pkg/config/config.go b/pkg/config/config.go index 1bc6a92b8..5abd8d988 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -19,6 +19,7 @@ type Config struct { Recommendations bool Communications Communications Events K8SEvents + Settings Settings } // K8SEvents contains event types @@ -44,6 +45,12 @@ type Slack struct { Token string } +// Settings for multicluster support +type Settings struct { + ClusterName string + AllowKubectl bool +} + // New returns new Config func New() (*Config, error) { c := &Config{} diff --git a/pkg/execute/executor.go b/pkg/execute/executor.go index 16ef92fb8..72489c38a 100644 --- a/pkg/execute/executor.go +++ b/pkg/execute/executor.go @@ -34,9 +34,10 @@ var validNotifierCommands = map[string]bool{ var kubectlBinary = "/usr/local/bin/kubectl" const ( - notifierStartMsg = "Brace yourselves, notifications are coming." - notifierStopMsg = "Sure! I won't send you notifications anymore." - unsupportedCmdMsg = "Command not supported. Please run '@botkube help' to see supported commands." + notifierStartMsg = "Brace yourselves, notifications are coming." + notifierStopMsg = "Sure! I won't send you notifications anymore." + 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." ) // Executor is an interface for processes to execute commands @@ -46,13 +47,15 @@ type Executor interface { // DefaultExecutor is a default implementations of Executor type DefaultExecutor struct { - Message string + Message string + AllowKubectl bool } // NewDefaultExecutor returns new Executor object -func NewDefaultExecutor(msg string) Executor { +func NewDefaultExecutor(msg string, allowkubectl bool) Executor { return &DefaultExecutor{ - Message: msg, + Message: msg, + AllowKubectl: allowkubectl, } } @@ -60,6 +63,9 @@ func NewDefaultExecutor(msg string) Executor { func (e *DefaultExecutor) Execute() string { args := strings.Split(e.Message, " ") if validKubectlCommands[args[0]] { + if !e.AllowKubectl { + return kubectlDisabledMsg + } return runKubectlCommand(args) } if validNotifierCommands[args[0]] { diff --git a/pkg/notify/slack.go b/pkg/notify/slack.go index 148a32e64..24f6674b0 100644 --- a/pkg/notify/slack.go +++ b/pkg/notify/slack.go @@ -15,8 +15,9 @@ var attachmentColor map[events.Level]string // Slack contains Token for authentication with slack and Channel name to send notification to type Slack struct { - Token string - Channel string + Token string + Channel string + ClusterName string } // NewSlack returns new Slack object @@ -35,8 +36,9 @@ func NewSlack() Notifier { } return &Slack{ - Token: c.Communications.Slack.Token, - Channel: c.Communications.Slack.Channel, + Token: c.Communications.Slack.Token, + Channel: c.Communications.Slack.Channel, + ClusterName: c.Settings.ClusterName, } } @@ -62,7 +64,7 @@ func (s *Slack) SendEvent(event events.Event) error { Short: true, }, }, - Footer: "botkube", + Footer: "BotKube", } // Add timestamp @@ -116,6 +118,12 @@ func (s *Slack) SendEvent(event events.Event) error { }) } + // Add clustername in the message + attachment.Fields = append(attachment.Fields, slack.AttachmentField{ + Title: "Cluster", + Value: s.ClusterName, + }) + attachment.Color = attachmentColor[event.Level] params.Attachments = []slack.Attachment{attachment} diff --git a/pkg/slack/slack.go b/pkg/slack/slack.go index 86ca6db24..84dc02aee 100644 --- a/pkg/slack/slack.go +++ b/pkg/slack/slack.go @@ -12,7 +12,8 @@ import ( // Bot listens for user's message, execute commands and sends back the response type Bot struct { - Token string + Token string + AllowKubectl bool } // slackMessage contains message details to execute command and send back the result @@ -32,13 +33,14 @@ func NewSlackBot() *Bot { logging.Logger.Fatal(fmt.Sprintf("Error in loading configuration. Error:%s", err.Error())) } return &Bot{ - Token: c.Communications.Slack.Token, + Token: c.Communications.Slack.Token, + AllowKubectl: c.Settings.AllowKubectl, } } // Start starts the slacknot RTM connection and listens for messages -func (s *Bot) Start() { - api := slack.New(s.Token) +func (b *Bot) Start() { + api := slack.New(b.Token) authResp, err := api.AuthTest() if err != nil { logging.Logger.Fatal(err) @@ -66,7 +68,7 @@ func (s *Bot) Start() { InMessage: msg, RTM: rtm, } - sm.HandleMessage() + sm.HandleMessage(b.AllowKubectl) case *slack.RTMError: logging.Logger.Errorf("Slack RMT error: %+v", ev.Error()) @@ -79,8 +81,8 @@ func (s *Bot) Start() { } } -func (sm *slackMessage) HandleMessage() { - e := execute.NewDefaultExecutor(sm.InMessage) +func (sm *slackMessage) HandleMessage(allowkubectl bool) { + e := execute.NewDefaultExecutor(sm.InMessage, allowkubectl) sm.OutMessage = e.Execute() sm.OutMsgLength = len(sm.OutMessage) sm.Send()