diff --git a/cmd/botkube/main.go b/cmd/botkube/main.go index ed2338d39f..dbd789d861 100644 --- a/cmd/botkube/main.go +++ b/cmd/botkube/main.go @@ -19,23 +19,32 @@ const ( func main() { log.Logger.Info("Starting controller") - Config, err := config.New() + conf, err := config.New() if err != nil { log.Logger.Fatal(fmt.Sprintf("Error in loading configuration. Error:%s", err.Error())) } - if Config.Communications.Slack.Enabled { + // List notifiers + var notifiers []notify.Notifier + if conf.Communications.Slack.Enabled { log.Logger.Info("Starting slack bot") - sb := bot.NewSlackBot() + sb := bot.NewSlackBot(conf) go sb.Start() } - if Config.Communications.Mattermost.Enabled { + if conf.Communications.Mattermost.Enabled { log.Logger.Info("Starting mattermost bot") - mb := bot.NewMattermostBot() + mb := bot.NewMattermostBot(conf) go mb.Start() } + if conf.Communications.Teams.Enabled { + log.Logger.Info("Starting MS Teams bot") + tb := bot.NewTeamsBot(conf) + notifiers = append(notifiers, tb) + go tb.Start() + } + // Prometheus metrics metricsPort, exists := os.LookupEnv("METRICS_PORT") if !exists { @@ -43,29 +52,27 @@ func main() { } go metrics.ServeMetrics(metricsPort) - // List notifiers - var notifiers []notify.Notifier - if Config.Communications.Slack.Enabled { - notifiers = append(notifiers, notify.NewSlack(Config)) + if conf.Communications.Slack.Enabled { + notifiers = append(notifiers, notify.NewSlack(conf)) } - if Config.Communications.Mattermost.Enabled { - if notifier, err := notify.NewMattermost(Config); err == nil { + if conf.Communications.Mattermost.Enabled { + if notifier, err := notify.NewMattermost(conf); err == nil { notifiers = append(notifiers, notifier) } } - if Config.Communications.ElasticSearch.Enabled { - notifiers = append(notifiers, notify.NewElasticSearch(Config)) + if conf.Communications.ElasticSearch.Enabled { + notifiers = append(notifiers, notify.NewElasticSearch(conf)) } - if Config.Communications.Webhook.Enabled { - notifiers = append(notifiers, notify.NewWebhook(Config)) + if conf.Communications.Webhook.Enabled { + notifiers = append(notifiers, notify.NewWebhook(conf)) } - if Config.Settings.UpgradeNotifier { + if conf.Settings.UpgradeNotifier { log.Logger.Info("Starting upgrade notifier") - go controller.UpgradeNotifier(Config, notifiers) + go controller.UpgradeNotifier(conf, notifiers) } // Init KubeClient, InformerMap and start controller utils.InitKubeClient() utils.InitInformerMap() - controller.RegisterInformers(Config, notifiers) + controller.RegisterInformers(conf, notifiers) } diff --git a/comm_config.yaml b/comm_config.yaml index bc0a619f99..8559557215 100644 --- a/comm_config.yaml +++ b/comm_config.yaml @@ -15,6 +15,13 @@ communications: team: 'MATTERMOST_TEAM' # Mattermost Team to configure with BotKube channel: 'MATTERMOST_CHANNEL' # Mattermost Channel for receiving BotKube alerts notiftype: short # Change notification type short/long you want to receive. notiftype is optional and Default notification type is short (if not specified) + + # Settings for MS Teams + teams: + enabled: false + appID: 'TEAMS_APP_ID' + appPassword: 'TEAMS_APP_PASSWORD' + notiftype: short # Settings for ELS elasticsearch: diff --git a/go.mod b/go.mod index 6f18c04950..f2712950c3 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/gorilla/websocket v1.4.1 // indirect github.com/hashicorp/golang-lru v0.5.3 // indirect github.com/imdario/mergo v0.3.7 // indirect + github.com/infracloudio/msbotbuilder-go v0.1.1-0.20200128183632-9d11322f671e github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect github.com/lib/pq v1.2.0 // indirect github.com/mattermost/gorp v2.0.0+incompatible // indirect @@ -30,6 +31,7 @@ require ( github.com/onsi/ginkgo v1.10.2 // indirect github.com/pborman/uuid v1.2.0 // indirect github.com/pelletier/go-toml v1.5.0 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.2.1 github.com/sirupsen/logrus v1.4.2 github.com/stretchr/testify v1.4.0 @@ -44,11 +46,11 @@ require ( gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect - gopkg.in/yaml.v2 v2.2.4 + gopkg.in/yaml.v2 v2.2.8 k8s.io/api v0.17.0 k8s.io/apimachinery v0.17.0 k8s.io/client-go v0.17.0 k8s.io/kubectl v0.17.0 ) -go 1.13 +go 1.12 diff --git a/go.sum b/go.sum index f8357dd1d9..10ca1787a1 100644 --- a/go.sum +++ b/go.sum @@ -50,6 +50,7 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0 h1:w3NnFcKR5241cfmQU5ZZAsf0xcpId6mWOupTvJlUX2U= @@ -168,6 +169,9 @@ github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/infracloudio/msbotbuilder-go v0.1.0 h1:52h4uhEev67TTv4n4HNlo9rxr1/LiHShwYTtNBu5r5U= +github.com/infracloudio/msbotbuilder-go v0.1.1-0.20200128183632-9d11322f671e h1:rr89i/xWiD/l+MtGXF+LRz2K/wQ/SV1FabVPrEmHr3s= +github.com/infracloudio/msbotbuilder-go v0.1.1-0.20200128183632-9d11322f671e/go.mod h1:zTFZH9V4x9YQMXrBw2CNsI6hO6blIQ8jHNvdnjbAqZM= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -194,6 +198,8 @@ github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= +github.com/lestrrat-go/jwx v0.9.0 h1:Fnd0EWzTm0kFrBPzE/PEPp9nzllES5buMkksPMjEKpM= +github.com/lestrrat-go/jwx v0.9.0/go.mod h1:iEoxlYfZjvoGpuWwxUz+eR5e6KTJGsaRcy/YNA/UnBk= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= @@ -253,6 +259,9 @@ github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -422,6 +431,8 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/bot/mattermost.go b/pkg/bot/mattermost.go index 7f4cb92e46..9116a22aa1 100644 --- a/pkg/bot/mattermost.go +++ b/pkg/bot/mattermost.go @@ -52,12 +52,7 @@ type mattermostMessage struct { } // NewMattermostBot returns new Bot object -func NewMattermostBot() Bot { - c, err := config.New() - if err != nil { - logging.Logger.Fatalf("Error in loading configuration. Error: %s", err.Error()) - } - +func NewMattermostBot(c *config.Config) Bot { return &MMBot{ ServerURL: c.Communications.Mattermost.URL, Token: c.Communications.Mattermost.Token, @@ -133,7 +128,7 @@ func (mm *mattermostMessage) handleMessage(b MMBot) { // Trim the @BotKube prefix if exists mm.Request = strings.TrimPrefix(post.Message, "@"+BotName+" ") - e := execute.NewDefaultExecutor(mm.Request, b.AllowKubectl, b.RestrictAccess, b.ClusterName, b.ChannelName, mm.IsAuthChannel) + e := execute.NewDefaultExecutor(mm.Request, b.AllowKubectl, b.RestrictAccess, b.ClusterName, mm.IsAuthChannel) mm.Response = e.Execute() mm.sendMessage() } diff --git a/pkg/bot/slack.go b/pkg/bot/slack.go index 16c01d8903..3c6be8c70d 100644 --- a/pkg/bot/slack.go +++ b/pkg/bot/slack.go @@ -1,7 +1,6 @@ package bot import ( - "fmt" "strings" "github.com/infracloudio/botkube/pkg/config" @@ -33,11 +32,7 @@ type slackMessage struct { } // NewSlackBot returns new Bot object -func NewSlackBot() Bot { - c, err := config.New() - if err != nil { - logging.Logger.Fatal(fmt.Sprintf("Error in loading configuration. Error:%s", err.Error())) - } +func NewSlackBot(c *config.Config) Bot { return &SlackBot{ Token: c.Communications.Slack.Token, AllowKubectl: c.Settings.AllowKubectl, @@ -139,7 +134,7 @@ func (sm *slackMessage) HandleMessage(b *SlackBot) { return } - e := execute.NewDefaultExecutor(sm.Request, b.AllowKubectl, b.RestrictAccess, b.ClusterName, b.ChannelName, sm.IsAuthChannel) + e := execute.NewDefaultExecutor(sm.Request, b.AllowKubectl, b.RestrictAccess, b.ClusterName, sm.IsAuthChannel) sm.Response = e.Execute() sm.Send() } diff --git a/pkg/bot/teams.go b/pkg/bot/teams.go new file mode 100644 index 0000000000..a9750713e3 --- /dev/null +++ b/pkg/bot/teams.go @@ -0,0 +1,148 @@ +package bot + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "strings" + + "github.com/infracloudio/botkube/pkg/config" + "github.com/infracloudio/botkube/pkg/events" + "github.com/infracloudio/botkube/pkg/execute" + "github.com/infracloudio/botkube/pkg/logging" + "github.com/infracloudio/msbotbuilder-go/core" + coreActivity "github.com/infracloudio/msbotbuilder-go/core/activity" + "github.com/infracloudio/msbotbuilder-go/schema" +) + +const ( + defaultMsgPath = "/api/messages" + defaultPort = "3978" +) + +// Teams contains credentials to start Teams backend server +type Teams struct { + AppID string + AppPassword string + MessagePath string + Port string + AllowKubectl bool + RestrictAccess bool + ClusterName string + NotifType config.NotifType + Adapter core.Adapter + + ConversationRef schema.ConversationReference +} + +// NewTeamsBot returns Teams instance +func NewTeamsBot(c *config.Config) *Teams { + logging.Logger.Infof("Config:: %+v", c.Communications.Teams) + return &Teams{ + AppID: c.Communications.Teams.AppID, + AppPassword: c.Communications.Teams.AppPassword, + NotifType: c.Communications.Teams.NotifType, + MessagePath: defaultMsgPath, + Port: defaultPort, + AllowKubectl: c.Settings.AllowKubectl, + RestrictAccess: c.Settings.RestrictAccess, + ClusterName: c.Settings.ClusterName, + } +} + +// Start MS Teams server to serve messages from Teams client +func (t *Teams) Start() { + var err error + setting := core.AdapterSetting{ + AppID: t.AppID, + AppPassword: t.AppPassword, + } + t.Adapter, err = core.NewBotAdapter(setting) + if err != nil { + logging.Logger.Errorf("Failed Start teams bot. %+v", err) + return + } + http.HandleFunc(t.MessagePath, t.processActivity) + logging.Logger.Infof("Started MS Teams server on port %s", defaultPort) + logging.Logger.Errorf("Error in MS Teams server. %v", http.ListenAndServe(fmt.Sprintf(":%s", t.Port), nil)) +} + +func (t *Teams) processActivity(w http.ResponseWriter, req *http.Request) { + ctx := context.Background() + activity, err := t.Adapter.ParseRequest(ctx, req) + if err != nil { + logging.Logger.Errorf("Failed to parse Teams request. %s", err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + err = t.Adapter.ProcessActivity(ctx, activity, coreActivity.HandlerFuncs{ + OnMessageFunc: func(turn *coreActivity.TurnContext) (schema.Activity, error) { + actjson, _ := json.MarshalIndent(turn.Activity, "", " ") + logging.Logger.Debugf("Received activity: %s", actjson) + return turn.SendActivity(coreActivity.MsgOptionText(t.processMessage(turn.Activity))) + }, + }) + if err != nil { + logging.Logger.Errorf("Failed to process request. %s", err.Error()) + } +} + +func (t *Teams) processMessage(activity schema.Activity) string { + // Trim @BotKube prefix + msg := strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(activity.Text), "BotKube")) + + // Parse "set default channel" command and set conversation reference + if msg == "set default channel" { + t.ConversationRef = coreActivity.GetCoversationReference(activity) + // Remove messageID from the ChannelID + if ID, ok := activity.ChannelData["teamsChannelId"]; ok { + t.ConversationRef.ChannelID = ID.(string) + t.ConversationRef.Conversation.ID = ID.(string) + } + return "Okay. I'll send notifications to this channel" + } + + // Multicluster is not supported for Teams + e := execute.NewDefaultExecutor(msg, t.AllowKubectl, t.RestrictAccess, t.ClusterName, true) + return fmt.Sprintf("```%s\n%s```", t.ClusterName, e.Execute()) +} + +func (t *Teams) SendEvent(event events.Event) error { + card := formatTeamsMessage(event, t.NotifType) + if err := t.sendProactiveMessage(card); err != nil { + logging.Logger.Errorf("Failed to send notification. %s", err.Error()) + } + logging.Logger.Debugf("Event successfully sent to MS Teams >> %+v", event) + return nil +} + +// SendMessage sends message to MsTeams +func (t *Teams) SendMessage(msg string) error { + err := t.Adapter.ProactiveMessage(context.TODO(), t.ConversationRef, coreActivity.HandlerFuncs{ + OnMessageFunc: func(turn *coreActivity.TurnContext) (schema.Activity, error) { + return turn.SendActivity(coreActivity.MsgOptionText(msg)) + }, + }) + if err != nil { + return err + } + logging.Logger.Debug("Message successfully sent to MS Teams") + return nil +} + +func (t *Teams) sendProactiveMessage(card map[string]interface{}) error { + err := t.Adapter.ProactiveMessage(context.TODO(), t.ConversationRef, coreActivity.HandlerFuncs{ + OnMessageFunc: func(turn *coreActivity.TurnContext) (schema.Activity, error) { + attachments := []schema.Attachment{ + { + ContentType: "application/vnd.microsoft.card.adaptive", + Content: card, + }, + } + return turn.SendActivity(coreActivity.MsgOptionAttachments(attachments)) + }, + }) + return err +} diff --git a/pkg/bot/teams_notif.go b/pkg/bot/teams_notif.go new file mode 100644 index 0000000000..499d057ec2 --- /dev/null +++ b/pkg/bot/teams_notif.go @@ -0,0 +1,151 @@ +package bot + +import ( + "strings" + + "github.com/infracloudio/botkube/pkg/config" + "github.com/infracloudio/botkube/pkg/events" + "github.com/infracloudio/botkube/pkg/notify" +) + +const ( + // Constants for sending messageCards + messageType = "MessageCard" + schemaContext = "http://schema.org/extensions" +) + +var themeColor = map[events.Level]string{ + events.Info: "good", + events.Warn: "warning", + events.Debug: "good", + events.Error: "attention", + events.Critical: "attention", +} + +type Fact map[string]interface{} + +func formatTeamsMessage(event events.Event, notifType config.NotifType) map[string]interface{} { + switch notifType { + case config.LongNotify: + return teamsLongNotification(event) + + case config.ShortNotify: + fallthrough + + default: + return teamsShortNotification(event) + } + return nil +} + +func teamsShortNotification(event events.Event) map[string]interface{} { + return map[string]interface{}{ + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.0", + "body": []map[string]interface{}{ + { + "type": "TextBlock", + "text": event.Title, + "size": "Large", + "color": themeColor[event.Level], + "wrap": true, + }, + { + "type": "TextBlock", + "text": strings.ReplaceAll(notify.FormatShortMessage(event), "```", ""), + "wrap": true, + }, + }, + } +} + +func teamsLongNotification(event events.Event) map[string]interface{} { + card := map[string]interface{}{ + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.0", + } + + sectionFacts := []Fact{} + + if event.Cluster != "" { + sectionFacts = append(sectionFacts, Fact{ + "title": "Cluster", + "value": event.Cluster, + }) + } + + sectionFacts = append(sectionFacts, Fact{ + "title": "Name", + "value": event.Name, + }) + + if event.Namespace != "" { + sectionFacts = append(sectionFacts, Fact{ + "title": "Namespace", + "value": event.Namespace, + }) + } + + if event.Reason != "" { + sectionFacts = append(sectionFacts, Fact{ + "title": "Reason", + "value": event.Reason, + }) + } + + if len(event.Messages) > 0 { + message := "" + for _, m := range event.Messages { + message = message + m + "\n" + } + sectionFacts = append(sectionFacts, Fact{ + "title": "Message", + "value": message, + }) + } + + if event.Action != "" { + sectionFacts = append(sectionFacts, Fact{ + "title": "Action", + "value": event.Action, + }) + } + + if len(event.Recommendations) > 0 { + rec := "" + for _, r := range event.Recommendations { + rec = rec + r + "\n" + } + sectionFacts = append(sectionFacts, Fact{ + "title": "Recommendations", + "value": rec, + }) + } + + if len(event.Warnings) > 0 { + warn := "" + for _, w := range event.Warnings { + warn = warn + w + "\n" + } + sectionFacts = append(sectionFacts, Fact{ + "title": "Warnings", + "value": warn, + }) + } + + card["body"] = []map[string]interface{}{ + { + "type": "TextBlock", + "text": event.Title, + "size": "Large", + "color": themeColor[event.Level], + }, + { + "type": "FactSet", + "facts": sectionFacts, + }, + } + return card +} diff --git a/pkg/config/config.go b/pkg/config/config.go index 6b02bb46a3..dbd7589716 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -82,9 +82,10 @@ type Namespaces struct { // Communications channels to send events to type Communications struct { Slack Slack - ElasticSearch ElasticSearch Mattermost Mattermost Webhook Webhook + Teams Teams + ElasticSearch ElasticSearch } // Slack configuration to authentication and send notifications @@ -122,6 +123,16 @@ type Mattermost struct { NotifType NotifType `yaml:",omitempty"` } +// Teams creds for authentication with MS Teams +type Teams struct { + Enabled bool + AppID string `yaml:"appID,omitempty"` + AppPassword string `yaml:"appPassword,omitempty"` + Team string + Channel string + NotifType NotifType `yaml:",omitempty"` +} + // Webhook configuration to send notifications type Webhook struct { Enabled bool diff --git a/pkg/execute/executor.go b/pkg/execute/executor.go index 35f9ce01fe..07682bbf46 100644 --- a/pkg/execute/executor.go +++ b/pkg/execute/executor.go @@ -71,7 +71,6 @@ type DefaultExecutor struct { AllowKubectl bool RestrictAccess bool ClusterName string - ChannelName string IsAuthChannel bool } @@ -126,13 +125,12 @@ func (action FiltersAction) String() string { } // NewDefaultExecutor returns new Executor object -func NewDefaultExecutor(msg string, allowkubectl bool, restrictAccess bool, clusterName, channelName string, isAuthChannel bool) Executor { +func NewDefaultExecutor(msg string, allowkubectl bool, restrictAccess bool, clusterName string, isAuthChannel bool) Executor { return &DefaultExecutor{ Message: msg, AllowKubectl: allowkubectl, RestrictAccess: restrictAccess, ClusterName: clusterName, - ChannelName: channelName, IsAuthChannel: isAuthChannel, } } diff --git a/pkg/notify/mattermost.go b/pkg/notify/mattermost.go index dcac82831c..1620e122e3 100644 --- a/pkg/notify/mattermost.go +++ b/pkg/notify/mattermost.go @@ -200,7 +200,7 @@ func mmLongNotification(event events.Event) []*model.SlackAttachmentField { func mmShortNotification(event events.Event) []*model.SlackAttachmentField { return []*model.SlackAttachmentField{ { - Value: formatShortMessage(event), + Value: FormatShortMessage(event), }, } } diff --git a/pkg/notify/slack.go b/pkg/notify/slack.go index d5a1cabb74..c5ed49b9cc 100644 --- a/pkg/notify/slack.go +++ b/pkg/notify/slack.go @@ -203,14 +203,14 @@ func slackShortNotification(event events.Event) slack.Attachment { Title: event.Title, Fields: []slack.AttachmentField{ { - Value: formatShortMessage(event), + Value: FormatShortMessage(event), }, }, Footer: "BotKube", } } -func formatShortMessage(event events.Event) (msg string) { +func FormatShortMessage(event events.Event) (msg string) { additionalMsg := "" if len(event.Messages) > 0 { for _, m := range event.Messages { diff --git a/pkg/notify/webhook.go b/pkg/notify/webhook.go index 30ce8a3360..44593bbceb 100644 --- a/pkg/notify/webhook.go +++ b/pkg/notify/webhook.go @@ -73,7 +73,7 @@ func (w *Webhook) SendEvent(event events.Event) (err error) { Error: event.Error, Messages: event.Messages, }, - EventSummary: formatShortMessage(event), + EventSummary: FormatShortMessage(event), TimeStamp: event.TimeStamp, Recommendations: event.Recommendations, Warnings: event.Warnings,