Skip to content
This repository has been archived by the owner on Apr 8, 2022. It is now read-only.

Add support for basecamp campfire messages (simple chatbot) #241

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions cmd/basecamp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
Copyright 2018 Bitnami

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cmd

import (
"github.com/bitnami-labs/kubewatch/config"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

// basecampConfigCmd represents the basecamp subcommand
var basecampConfigCmd = &cobra.Command{
Use: "basecamp",
Short: "specific basecamp configuration",
Long: `specific basecamp configuration`,
Run: func(cmd *cobra.Command, args []string) {
conf, err := config.New()
if err != nil {
logrus.Fatal(err)
}

url, err := cmd.Flags().GetString("url")
if err == nil {
if len(url) > 0 {
conf.Handler.BaseCamp.Url = url
}
} else {
logrus.Fatal(err)
}

if err = conf.Write(); err != nil {
logrus.Fatal(err)
}
},
}

func init() {
basecampConfigCmd.Flags().StringP("url", "u", "", "Specify BaseCamp url")
}
1 change: 1 addition & 0 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,5 +120,6 @@ func init() {
webhookConfigCmd,
msteamsConfigCmd,
smtpConfigCmd,
basecampConfigCmd,
)
}
3 changes: 2 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ var RootCmd = &cobra.Command{
Kubewatch: A watcher for Kubernetes

kubewatch is a Kubernetes watcher that could publishes notification
to Slack/hipchat/mattermost/flock channels. It watches the cluster
to Slack/hipchat/mattermost/flock/BaseCamp channels. It watches the cluster
for resource changes and notifies them through webhooks.

supported webhooks:
Expand All @@ -46,6 +46,7 @@ supported webhooks:
- mattermost
- flock
- webhook
- basecamp
`,

Run: func(cmd *cobra.Command, args []string) {
Expand Down
7 changes: 7 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type Handler struct {
Webhook Webhook `json:"webhook"`
MSTeams MSTeams `json:"msteams"`
SMTP SMTP `json:"smtp"`
BaseCamp BaseCamp `json:"basecamp"`
}

// Resource contains resource configuration
Expand Down Expand Up @@ -156,6 +157,12 @@ type SMTPAuth struct {
Secret string `json:"secret" yaml:"secret,omitempty"`
}

// BaseCamp contains BaseCamp configuration
type BaseCamp struct {
// BaseCamp url.
Url string `json:"url"`
}

// New creates new config object
func New() (*Config, error) {
c := &Config{}
Expand Down
2 changes: 2 additions & 0 deletions config/sample.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ handler:
requireTLS: false
# SMTP hello field (optional)
hello: ""
basecamp:
url: ""
# Resources to watch.
resource:
deployment: false
Expand Down
1 change: 1 addition & 0 deletions docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ With each event get from k8s and matched filtering from configuration, it is pas
- `MS Teams`: which send notification to MS Team incoming webhook based on information from config
- `Slack`: which send notification to Slack channel based on information from config
- `Smtp`: which sends notifications to email recipients using a SMTP server obtained from config
- `BaseCamp`: which sends notifications to a campfire room using a basecamp url obtained from config

More handlers will be added in future.

Expand Down
13 changes: 13 additions & 0 deletions examples/conf/kubewatch.conf.basecamp.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
handler:
basecamp:
url: "https://3.basecamp.com/ID_A/integrations/ID_B/buckets/ID_C/chats/ID_D/lines"
resource:
deployment: true
replicationcontroller: false
replicaset: false
daemonset: false
services: false
pod: false
job: false
persistentvolume: false
ingress: false
3 changes: 3 additions & 0 deletions pkg/client/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/bitnami-labs/kubewatch/config"
"github.com/bitnami-labs/kubewatch/pkg/controller"
"github.com/bitnami-labs/kubewatch/pkg/handlers"
"github.com/bitnami-labs/kubewatch/pkg/handlers/basecamp"
"github.com/bitnami-labs/kubewatch/pkg/handlers/flock"
"github.com/bitnami-labs/kubewatch/pkg/handlers/hipchat"
"github.com/bitnami-labs/kubewatch/pkg/handlers/mattermost"
Expand Down Expand Up @@ -57,6 +58,8 @@ func ParseEventHandler(conf *config.Config) handlers.Handler {
eventHandler = new(msteam.MSTeams)
case len(conf.Handler.SMTP.Smarthost) > 0 || len(conf.Handler.SMTP.To) > 0:
eventHandler = new(smtp.SMTP)
case len(conf.Handler.BaseCamp.Url) > 0:
eventHandler = new(basecamp.BaseCamp)
default:
eventHandler = new(handlers.Default)
}
Expand Down
108 changes: 108 additions & 0 deletions pkg/handlers/basecamp/basecamp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
Copyright 2018 Bitnami

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package basecamp

import (
"fmt"
"log"
"os"
"strings"

"net/http"
"net/url"
"time"

"github.com/bitnami-labs/kubewatch/config"
"github.com/bitnami-labs/kubewatch/pkg/event"
)

var basecampErrMsg = `
%s

You need to set BaseCamp url
using "--url/-u" or using environment variables:

export KW_BASECAMP_URL=basecamp_url

Command line flags will override environment variables

`

// BaseCamp handler implements handler.Handler interface,
// Notify event to BaseCamp campfire
type BaseCamp struct {
Url string
}

// EventMeta contains the metadata about the occurred event
type EventMeta struct {
Kind string `json:"kind"`
Name string `json:"name"`
Namespace string `json:"namespace"`
Reason string `json:"reason"`
}

// Init prepares BaseCamp configuration
func (m *BaseCamp) Init(c *config.Config) error {
url := c.Handler.BaseCamp.Url

if url == "" {
url = os.Getenv("KW_BASECAMP_URL")
}

m.Url = url

return checkMissingBaseCampVars(m)
}

// Handle handles an event.
func (m *BaseCamp) Handle(e event.Event) {
err := postMessage(m.Url, e.Message())
if err != nil {
log.Printf("%s\n", err)
return
}

log.Printf("Message successfully sent to %s at %s ", m.Url, time.Now())
}

func checkMissingBaseCampVars(s *BaseCamp) error {
if s.Url == "" {
return fmt.Errorf(basecampErrMsg, "Missing BaseCamp url")
}

return nil
}

func postMessage(basecampURL string, basecampMessage string) error {
data := url.Values{}
data.Set("content", basecampMessage)

req, err := http.NewRequest("POST", basecampURL, strings.NewReader(data.Encode()))
if err != nil {
return err
}
req.Header.Add("content-type", "application/x-www-form-urlencoded")

client := &http.Client{}
_, err = client.Do(req)
if err != nil {
return err
}

return nil
}
46 changes: 46 additions & 0 deletions pkg/handlers/basecamp/basecamp_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
Copyright 2018 Bitnami

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package basecamp

import (
"fmt"
"reflect"
"testing"

"github.com/bitnami-labs/kubewatch/config"
)

func TestBaseCampInit(t *testing.T) {
s := &BaseCamp{}
expectedError := fmt.Errorf(basecampErrMsg, "Missing BaseCamp url")

var Tests = []struct {
basecamp config.BaseCamp
err error
}{
{config.BaseCamp{Url: "foo"}, nil},
{config.BaseCamp{}, expectedError},
}

for _, tt := range Tests {
c := &config.Config{}
c.Handler.BaseCamp = tt.basecamp
if err := s.Init(c); !reflect.DeepEqual(err, tt.err) {
t.Fatalf("Init(): %v", err)
}
}
}
2 changes: 2 additions & 0 deletions pkg/handlers/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package handlers
import (
"github.com/bitnami-labs/kubewatch/config"
"github.com/bitnami-labs/kubewatch/pkg/event"
"github.com/bitnami-labs/kubewatch/pkg/handlers/basecamp"
"github.com/bitnami-labs/kubewatch/pkg/handlers/flock"
"github.com/bitnami-labs/kubewatch/pkg/handlers/hipchat"
"github.com/bitnami-labs/kubewatch/pkg/handlers/mattermost"
Expand All @@ -45,6 +46,7 @@ var Map = map[string]interface{}{
"webhook": &webhook.Webhook{},
"ms-teams": &msteam.MSTeams{},
"smtp": &smtp.SMTP{},
"basecamp": &basecamp.BaseCamp{},
}

// Default handler implements Handler interface,
Expand Down