diff --git a/cmd/basecamp.go b/cmd/basecamp.go new file mode 100644 index 000000000..050ecf9f8 --- /dev/null +++ b/cmd/basecamp.go @@ -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") +} diff --git a/cmd/config.go b/cmd/config.go index e286de581..661cc3efa 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -120,5 +120,6 @@ func init() { webhookConfigCmd, msteamsConfigCmd, smtpConfigCmd, + basecampConfigCmd, ) } diff --git a/cmd/root.go b/cmd/root.go index 607860c01..59b83b753 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -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: @@ -46,6 +46,7 @@ supported webhooks: - mattermost - flock - webhook + - basecamp `, Run: func(cmd *cobra.Command, args []string) { diff --git a/config/config.go b/config/config.go index f0ab26e1a..6ee7ded77 100644 --- a/config/config.go +++ b/config/config.go @@ -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 @@ -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{} diff --git a/config/sample.go b/config/sample.go index d42876d5b..c2a71bb0f 100644 --- a/config/sample.go +++ b/config/sample.go @@ -54,6 +54,8 @@ handler: requireTLS: false # SMTP hello field (optional) hello: "" + basecamp: + url: "" # Resources to watch. resource: deployment: false diff --git a/docs/design.md b/docs/design.md index 4d9caf753..effcb468c 100644 --- a/docs/design.md +++ b/docs/design.md @@ -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. diff --git a/examples/conf/kubewatch.conf.basecamp.yaml b/examples/conf/kubewatch.conf.basecamp.yaml new file mode 100644 index 000000000..d07678ac0 --- /dev/null +++ b/examples/conf/kubewatch.conf.basecamp.yaml @@ -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 diff --git a/pkg/client/run.go b/pkg/client/run.go index 03cd25bc9..b01014e93 100644 --- a/pkg/client/run.go +++ b/pkg/client/run.go @@ -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" @@ -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) } diff --git a/pkg/handlers/basecamp/basecamp.go b/pkg/handlers/basecamp/basecamp.go new file mode 100644 index 000000000..b657cfd78 --- /dev/null +++ b/pkg/handlers/basecamp/basecamp.go @@ -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 +} diff --git a/pkg/handlers/basecamp/basecamp_test.go b/pkg/handlers/basecamp/basecamp_test.go new file mode 100644 index 000000000..355d637aa --- /dev/null +++ b/pkg/handlers/basecamp/basecamp_test.go @@ -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) + } + } +} diff --git a/pkg/handlers/handler.go b/pkg/handlers/handler.go index 2ef71f0ee..42f346609 100644 --- a/pkg/handlers/handler.go +++ b/pkg/handlers/handler.go @@ -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" @@ -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,