diff --git a/cmd/config.go b/cmd/config.go index 97bef2089..ff4967d9e 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -98,5 +98,6 @@ func init() { flockConfigCmd, webhookConfigCmd, msteamsConfigCmd, + execConfigCmd, ) } diff --git a/cmd/exec.go b/cmd/exec.go new file mode 100644 index 000000000..2a8d9822f --- /dev/null +++ b/cmd/exec.go @@ -0,0 +1,53 @@ +/* +Copyright 2016 Skippbox, Ltd. + +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/Sirupsen/logrus" + "github.com/bitnami-labs/kubewatch/config" + "github.com/spf13/cobra" +) + +// execConfigCmd represents the exec subcommand +var execConfigCmd = &cobra.Command{ + Use: "exec FLAG", + Short: "specific exec configuration", + Long: `specific exec configuration`, + Run: func(cmd *cobra.Command, args []string) { + conf, err := config.New() + if err != nil { + logrus.Fatal(err) + } + + execCmd, err := cmd.Flags().GetString("cmd") + if err == nil { + if len(execCmd) > 0 { + conf.Handler.Exec.Cmd = execCmd + } + } else { + logrus.Fatal(err) + } + + if err = conf.Write(); err != nil { + logrus.Fatal(err) + } + }, +} + +func init() { + execConfigCmd.Flags().StringP("cmd", "c", "", "Specify local command/shell to run") +} diff --git a/config/config.go b/config/config.go index 37afac157..e5891aef4 100644 --- a/config/config.go +++ b/config/config.go @@ -35,6 +35,7 @@ type Handler struct { Mattermost Mattermost `json:"mattermost"` Flock Flock `json:"flock"` Webhook Webhook `json:"webhook"` + Exec Exec `json:"exec"` MSTeams MSTeams `json:"msteams"` } @@ -94,6 +95,11 @@ type Webhook struct { Url string `json:"url"` } +// Exec contains exec configuration +type Exec struct { + Cmd string `json:"cmd"` +} + // MSTeams contains MSTeams configuration type MSTeams struct { WebhookURL string `json:"webhookurl"` diff --git a/examples/conf/kubewatch.conf.exec.yaml b/examples/conf/kubewatch.conf.exec.yaml new file mode 100644 index 000000000..b57a8e662 --- /dev/null +++ b/examples/conf/kubewatch.conf.exec.yaml @@ -0,0 +1,14 @@ +handler: + exec: + cmd: "echo {reason} {name}" +resource: + deployment: false + replicationcontroller: false + replicaset: false + daemonset: false + services: false + pod: false + job: false + persistentvolume: false + configmap: true + ingress: false diff --git a/pkg/client/run.go b/pkg/client/run.go index 874fe0710..65a10d858 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/exec" "github.com/bitnami-labs/kubewatch/pkg/handlers/flock" "github.com/bitnami-labs/kubewatch/pkg/handlers/hipchat" "github.com/bitnami-labs/kubewatch/pkg/handlers/mattermost" @@ -52,6 +53,8 @@ func ParseEventHandler(conf *config.Config) handlers.Handler { eventHandler = new(flock.Flock) case len(conf.Handler.Webhook.Url) > 0: eventHandler = new(webhook.Webhook) + case len(conf.Handler.Exec.Cmd) > 0: + eventHandler = new(exec.Exec) case len(conf.Handler.MSTeams.WebhookURL) > 0: eventHandler = new(msteam.MSTeams) default: diff --git a/pkg/handlers/exec/exec.go b/pkg/handlers/exec/exec.go new file mode 100644 index 000000000..e5df6a794 --- /dev/null +++ b/pkg/handlers/exec/exec.go @@ -0,0 +1,88 @@ +/* +Copyright 2016 Skippbox, Ltd. + +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 exec + +import ( + "log" + "os" + "os/exec" + "strings" + + "github.com/bitnami-labs/kubewatch/config" + "github.com/bitnami-labs/kubewatch/pkg/event" +) + +// Exec handler implements handler.Handler interface, +// Notify event to run local command/shell +type Exec struct { + Cmd string +} + +// Init prepares Exec configuration +func (s *Exec) Init(c *config.Config) error { + cmd := c.Handler.Exec.Cmd + + if cmd == "" { + cmd = os.Getenv("KW_EXEC_CMD") + } + + s.Cmd = cmd + return nil +} + +func (s *Exec) ObjectCreated(obj interface{}) { + handleEvent(s, obj, "created") +} + +func (s *Exec) ObjectDeleted(obj interface{}) { + handleEvent(s, obj, "deleted") +} + +func (s *Exec) ObjectUpdated(oldObj, newObj interface{}) { + handleEvent(s, newObj, "updated") +} + +// TestHandler tests the handler configurarion by sending test messages. +func (s *Exec) TestHandler() { + return +} + +func handleEvent(s *Exec, obj interface{}, action string) { + e := event.New(obj, action) + + var cmdAndArgs []string + cmdCli := strings.Split(s.Cmd, " ") + for _, c := range cmdCli { + c = strings.Replace(c, "{reason}", e.Reason, -1) + c = strings.Replace(c, "{name}", e.Name, -1) + + cmdAndArgs = append(cmdAndArgs, c) + } + + if err := runCmd(cmdAndArgs); err != nil { + log.Printf("Exec local command %v failed %s", cmdAndArgs, err) + } else { + log.Printf("Exec local command successfully %s", cmdAndArgs) + } +} + +func runCmd(command []string) error { + cmd := exec.Command(command[0], command[1:]...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() +} diff --git a/pkg/handlers/handler.go b/pkg/handlers/handler.go index c5b96b98e..c54883c66 100644 --- a/pkg/handlers/handler.go +++ b/pkg/handlers/handler.go @@ -18,6 +18,7 @@ package handlers import ( "github.com/bitnami-labs/kubewatch/config" + "github.com/bitnami-labs/kubewatch/pkg/handlers/exec" "github.com/bitnami-labs/kubewatch/pkg/handlers/flock" "github.com/bitnami-labs/kubewatch/pkg/handlers/hipchat" "github.com/bitnami-labs/kubewatch/pkg/handlers/mattermost" @@ -44,6 +45,7 @@ var Map = map[string]interface{}{ "mattermost": &mattermost.Mattermost{}, "flock": &flock.Flock{}, "webhook": &webhook.Webhook{}, + "exec": &exec.Exec{}, "ms-teams": &msteam.MSTeams{}, }