Skip to content

Commit 4ceaadf

Browse files
committed
Initial import
0 parents  commit 4ceaadf

10 files changed

+351
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
vendor
2+
.idea
3+
config.yml

Gopkg.lock

+15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Gopkg.toml example
2+
#
3+
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
4+
# for detailed Gopkg.toml documentation.
5+
#
6+
# required = ["github.com/user/thing/cmd/thing"]
7+
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
8+
#
9+
# [[constraint]]
10+
# name = "github.com/user/project"
11+
# version = "1.0.0"
12+
#
13+
# [[constraint]]
14+
# name = "github.com/user/project2"
15+
# branch = "dev"
16+
# source = "github.com/myfork/project2"
17+
#
18+
# [[override]]
19+
# name = "github.com/x/y"
20+
# version = "2.4.0"
21+
#
22+
# [prune]
23+
# non-go = false
24+
# go-tests = true
25+
# unused-packages = true
26+
27+
28+
[prune]
29+
go-tests = true
30+
unused-packages = true
31+
32+
[[constraint]]
33+
name = "gopkg.in/yaml.v2"
34+
version = "2.2.1"

icinga_host.go

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package main
2+
3+
import "flag"
4+
5+
type icingaHostCmd struct {
6+
SimpleCFGLocation *string
7+
icHostname *string
8+
icHostV4 *string
9+
icHostV6 *string
10+
icHostState *string
11+
icHostNotfnType *string
12+
icHostCheckOutput *string
13+
icHostNotfnUser *string
14+
icHostNotfnComment *string
15+
icURL *string
16+
}
17+
18+
func (this *icingaHostCmd) Init(flagSet *flag.FlagSet) {
19+
this.SimpleCFGLocation = flagSet.String("cfg", "/etc/sendmsg.yml", "Path to sendmsg config")
20+
this.icHostname = flagSet.String("l", "", "Hostname")
21+
this.icHostV4 = flagSet.String("4", "", "Host address (v4)")
22+
this.icHostV6 = flagSet.String("6", "", "Host address (v6)")
23+
this.icHostState = flagSet.String("s", "", "Host state")
24+
this.icHostNotfnType = flagSet.String("t", "", "Notification type")
25+
this.icHostCheckOutput = flagSet.String("o", "", "Check output")
26+
this.icHostNotfnUser = flagSet.String("b", "", "Manual host notification user")
27+
this.icHostNotfnComment = flagSet.String("c", "", "Manual host notification comment")
28+
this.icHostNotfnComment = flagSet.String("i", "", "URL of Webinterface")}
29+
30+
func (this *icingaHostCmd) Parse() Message {
31+
var msg Message
32+
33+
// TODO
34+
35+
return msg
36+
}

listarg.go

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package main
2+
3+
import (
4+
"strings"
5+
"bytes"
6+
)
7+
8+
type fieldList []Field
9+
10+
type FieldArgParseError struct {
11+
err string
12+
}
13+
14+
func (e *FieldArgParseError) Error() string {
15+
return e.err
16+
}
17+
18+
func (s *fieldList) String() string{
19+
var buffer bytes.Buffer
20+
for _, item := range *s {
21+
buffer.WriteString("Element Title: ")
22+
buffer.WriteString(item.Header)
23+
buffer.WriteString(", Text: ")
24+
buffer.WriteString(item.Text)
25+
buffer.WriteString(", Short?: ")
26+
if item.Short {
27+
buffer.WriteString("yes\n")
28+
} else {
29+
buffer.WriteString("no\n")
30+
}
31+
}
32+
return buffer.String()
33+
}
34+
35+
func (s *fieldList) Set(val string) error {
36+
arr := strings.Split(val, ",")
37+
for _, elem := range arr {
38+
values := strings.Split(elem, ":")
39+
if len(values) != 3 {
40+
return &FieldArgParseError{"Split produced unexpected number of parts (delimiter ':')"}
41+
}
42+
var field Field
43+
field.Text = values[1]
44+
field.Header = values[0]
45+
field.Short = values[2] == "yes"
46+
*s = append(*s, field)
47+
}
48+
return nil
49+
}

sendmsg.go

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"io/ioutil"
6+
"fmt"
7+
"os"
8+
"gopkg.in/yaml.v2"
9+
)
10+
11+
func main() {
12+
// 'Simple' frontend - that is specifying each field manually
13+
simpleCommand := flag.NewFlagSet("simple", flag.ExitOnError)
14+
simpleFrontendCmd := simpleCmdData{}
15+
simpleFrontendCmd.Init(simpleCommand)
16+
17+
// 'Icinga2' frontend - use this as a drop-in replacement for mails
18+
icingaHostCommand := flag.NewFlagSet("icingaHost", flag.ExitOnError)
19+
icingaHostCmd := icingaHostCmd{}
20+
icingaHostCmd.Init(icingaHostCommand)
21+
22+
if len(os.Args) < 2 {
23+
fmt.Print("Please use one of [simple, icingaHost]")
24+
return
25+
}
26+
27+
var cfglocation *string
28+
switch os.Args[1] {
29+
case "simple":
30+
simpleCommand.Parse(os.Args[2:])
31+
cfglocation = simpleFrontendCmd.SimpleCFGLocation
32+
break
33+
case "icingaHost":
34+
simpleCommand.Parse(os.Args[2:])
35+
cfglocation = icingaHostCmd.SimpleCFGLocation
36+
break
37+
default:
38+
flag.PrintDefaults()
39+
return
40+
}
41+
42+
cfg := Config{}
43+
if contents, err := ioutil.ReadFile(*cfglocation); err == nil {
44+
err = yaml.UnmarshalStrict(contents, &cfg)
45+
if err != nil {
46+
fmt.Println("ERROR: Couldn't parse the configuration file!", err)
47+
os.Exit(-1)
48+
}
49+
} else {
50+
fmt.Println("ERROR: Couldn't read the configuration file!", err)
51+
os.Exit(-1)
52+
}
53+
54+
var msg Message
55+
if simpleCommand.Parsed() {
56+
msg = simpleFrontendCmd.Parse()
57+
}
58+
if icingaHostCommand.Parsed() {
59+
msg = icingaHostCmd.Parse()
60+
}
61+
62+
if msg.Body == "" || msg.Body_title == "" {
63+
fmt.Println("ERROR: Either title or body are missing. Aborting now!")
64+
return
65+
}
66+
67+
switch cfg.Backend {
68+
case "slack":
69+
send_with_slack(msg, cfg, "simple", "")
70+
}
71+
}

sendmsg.yml

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
backend: slack
2+
webhook: https://hooks.slack.com/services/something/secret/changeme

simple.go

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package main
2+
3+
import "flag"
4+
5+
type simpleCmdData struct {
6+
SimpleCFGLocation *string
7+
head *string
8+
title *string
9+
title_url *string
10+
body *string
11+
color *string
12+
fields fieldList
13+
}
14+
15+
func (this *simpleCmdData) Init(flagSet *flag.FlagSet) {
16+
this.SimpleCFGLocation = flagSet.String("cfg", "/etc/sendmsg.yml", "Path to sendmsg config")
17+
this.head = flagSet.String("head", "", "The header of the message to send (required)")
18+
this.title = flagSet.String("title", "", "The title of the message to send (required)")
19+
this.title_url = flagSet.String("title_url", "", "The url of the title of the message to send")
20+
this.body = flagSet.String("body", "", "The body of the message to send")
21+
this.color = flagSet.String("color", "", "The color of the message to send")
22+
flagSet.Var(&this.fields, "fields", "A comma seperated list of fields (name:text) to be added")
23+
}
24+
25+
func (this *simpleCmdData) Parse() Message {
26+
var msg Message
27+
msg.Body = *this.body
28+
msg.Head = *this.head
29+
msg.Color = *this.color
30+
msg.Body_title = *this.title
31+
msg.Body_link = *this.title_url
32+
msg.Fields = this.fields
33+
return msg
34+
}

slack.go

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package main
2+
3+
import (
4+
"net/http"
5+
"bytes"
6+
"encoding/json"
7+
"fmt"
8+
"io/ioutil"
9+
)
10+
11+
type SlackField struct {
12+
Text string `json:"value,omitempty"`
13+
Title string `json:"title,omitempty"`
14+
Short bool `json:"short,omitempty"`
15+
}
16+
17+
type SlackAttachments struct {
18+
Color string `json:"color,omitempty"`
19+
Text string `json:"text,omitempty"`
20+
Title string `json:"title,omitempty"`
21+
TitleLink string `json:"title_link,omitempty"`
22+
Fields []SlackField `json:"fields,omitempty"`
23+
Footer string `json:"footer,omitempty"`
24+
FooterIcon string `json:"footer_icon,omitempty"`
25+
Head string `json:"author_name,omitempty"`
26+
}
27+
28+
type SlackMessage struct {
29+
Text string `json:"text,omitempty"`
30+
Attachments []SlackAttachments `json:"attachments,omitempty"`
31+
}
32+
33+
func send_with_slack(msg Message, cfg Config, frontend string, frontendIcon string) {
34+
var body SlackMessage
35+
var attachement SlackAttachments
36+
attachement.Head = msg.Head
37+
attachement.Text = msg.Body
38+
if msg.Color != "" {
39+
attachement.Color = msg.Color
40+
}
41+
if msg.Body_title != "" {
42+
attachement.Title = msg.Body_title
43+
}
44+
if msg.Body_link != "" {
45+
attachement.TitleLink = msg.Body_link
46+
}
47+
var fields []SlackField
48+
for _, value := range msg.Fields {
49+
var field SlackField
50+
field.Title = value.Header
51+
field.Text = value.Text
52+
field.Short = value.Short
53+
fields = append(fields, field)
54+
}
55+
attachement.Fields = fields
56+
attachement.Footer = frontend + " (sendmsg)"
57+
if frontendIcon != "" {
58+
attachement.FooterIcon = frontendIcon
59+
}
60+
body.Attachments = []SlackAttachments{attachement}
61+
62+
jsonBody, err := json.Marshal(body)
63+
if err != nil {
64+
fmt.Errorf("Coudln't masrshal message for JSON transport: ", err)
65+
return
66+
}
67+
resp, err := http.Post(cfg.Webhook, "application/reader", bytes.NewBuffer(jsonBody))
68+
if err != nil {
69+
fmt.Errorf("Coudln't POST message to webhook: ", err)
70+
return
71+
}
72+
defer resp.Body.Close()
73+
74+
bodyBytes, err := ioutil.ReadAll(resp.Body)
75+
if err != nil {
76+
fmt.Errorf("Couldn't read body", err)
77+
}
78+
bodyString := string(bodyBytes)
79+
fmt.Print(bodyString)
80+
81+
if bodyString != "ok" {
82+
fmt.Errorf("Slack didn't like what we sent, error: ", bodyString)
83+
}
84+
}

types.go

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package main
2+
3+
type Field struct {
4+
Text string
5+
Header string
6+
Short bool
7+
}
8+
9+
type Message struct {
10+
Head string
11+
Body_title string
12+
Body_link string
13+
Body string
14+
Color string
15+
Fields []Field
16+
}
17+
18+
type Config struct {
19+
Backend string `yaml:"backend"`
20+
Webhook string `yaml:"webhook"`
21+
}
22+
23+
type CmdData struct {}

0 commit comments

Comments
 (0)