From 66a738f8d3a067a26bdfc0af2b7abe299f86e34e Mon Sep 17 00:00:00 2001 From: Todd Campbell Date: Mon, 11 May 2020 16:02:46 -0700 Subject: [PATCH] Removed withAnnotations flags and its code to create description field Added descriptionTemplate and descriptionLimit flags to allow customizing the description field Signed-off-by: Todd Campbell --- CHANGELOG.md | 8 ++ README.md | 19 +++-- event.withAnnotations.json | 128 ---------------------------- event.withAnnotations.resolved.json | 128 ---------------------------- main.go | 74 ++++++++-------- main_test.go | 35 ++------ test.all.events.sh | 3 +- 7 files changed, 67 insertions(+), 328 deletions(-) delete mode 100644 event.withAnnotations.json delete mode 100644 event.withAnnotations.resolved.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 64e64a1..68e693e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ Versioning](http://semver.org/spec/v2.0.0.html). ## Unreleased +## [0.4.0] - 2020-05-11 + +### Removed +- withAnnotations flags and its code to create description field + +### Added +- descriptionTemplate and descriptionLimit flags to allow customizing the description field + ## [0.3.2] - 2020-05-01 ### Added diff --git a/README.md b/README.md index 288cb84..f081be7 100644 --- a/README.md +++ b/README.md @@ -46,15 +46,16 @@ Available Commands: version Print the version number of this plugin Flags: - -a, --auth string The OpsGenie V2 API authentication token, use default from OPSGENIE_AUTHTOKEN env var - -h, --help help for sensu-opsgenie-handler - -l, --messageLimit int The maximum length of the message field (default 100) - -i, --includeEventInNote Include the event JSON in the payload sent to OpsGenie - -m, --messageTemplate string The template for the message to be sent (default "{{.Entity.Name}}/{{.Check.Name}}") - -s, --sensuDashboard string The OpsGenie Handler will use it to create a source Sensu Dashboard URL. Use OPSGENIE_SENSU_DASHBOARD. Example: http://sensu-dashboard.example.local/c/~/n (default "disabled") - -t, --team string The OpsGenie V2 API Team, use default from OPSGENIE_TEAM env var - -u, --url string The OpsGenie V2 API URL, use default from OPSGENIE_APIURL env var (default "https://api.opsgenie.com") - -w, --withAnnotations string The OpsGenie Handler will parse check and entity annotations with these values. Use OPSGENIE_ANNOTATIONS env var with commas, like: documentation,playbook (default "documentation,playbook") + -a, --auth string The OpsGenie V2 API authentication token, use default from OPSGENIE_AUTHTOKEN env var + -h, --help help for sensu-opsgenie-handler + -i, --includeEventInNote Include the event JSON in the payload sent to OpsGenie + -m, --messageTemplate string The template for the message to be sent (default "{{.Entity.Name}}/{{.Check.Name}}") + -l, --messageLimit int The maximum length of the message field (default 100) + -d, --descriptionTemplate string The template for the description to be sent (default "{{.Check.Output}}") + -L, --descriptionLimit int The maximum length of the description field (default 100) + -s, --sensuDashboard string The OpsGenie Handler will use it to create a source Sensu Dashboard URL. Use OPSGENIE_SENSU_DASHBOARD. Example: http://sensu-dashboard.example.local/c/~/n (default "disabled") + -t, --team string The OpsGenie V2 API Team, use default from OPSGENIE_TEAM env var + -u, --url string The OpsGenie V2 API URL, use default from OPSGENIE_APIURL env var (default "https://api.opsgenie.com") Use "sensu-opsgenie-handler [command] --help" for more information about a command. diff --git a/event.withAnnotations.json b/event.withAnnotations.json deleted file mode 100644 index e9e888c..0000000 --- a/event.withAnnotations.json +++ /dev/null @@ -1,128 +0,0 @@ -{ - "timestamp": 1522100915, - "entity": { - "entity_class": "agent", - "system": { - "hostname": "webserver01", - "os": "linux", - "platform": "centos", - "platform_family": "rhel", - "platform_version": "7.4.1708", - "network": { - "interfaces": [ - { - "name": "lo", - "addresses": [ - "127.0.0.1/8", - "::1/128" - ] - }, - { - "name": "enp0s3", - "mac": "08:00:27:11:ad:d2", - "addresses": [ - "10.0.2.15/24", - "fe80::26a5:54ec:cf0d:9704/64" - ] - }, - { - "name": "enp0s8", - "mac": "08:00:27:bc:be:60", - "addresses": [ - "172.28.128.3/24", - "fe80::a00:27ff:febc:be60/64" - ] - } - ] - }, - "arch": "amd64" - }, - "subscriptions": [ - "testing", - "entity:webserver01" - ], - "last_seen": 1542667635, - "deregister": false, - "deregistration": {}, - "user": "agent", - "redact": [ - "password", - "passwd", - "pass", - "api_key", - "api_token", - "access_key", - "secret_key", - "private_key", - "secret" - ], - "metadata": { - "name": "webserver01", - "namespace": "default", - "labels": null, - "annotations": { - "documentation": "http://golang.org", - "playbook": "https://docs.sensu.io/sensu-go/latest" - } - } - }, - "check": { - "check_hooks": null, - "duration": 1.903135228, - "executed": 1522100915, - "high_flap_threshold": 0, - "history": [ - { - "executed": 1522100315 - }, - { - "executed": 1522100915 - } - ], - "command": "http_check.sh http://localhost:80", - "handlers": [ - "slack" - ], - "high_flap_threshold": 0, - "interval": 20, - "low_flap_threshold": 0, - "publish": true, - "runtime_assets": [], - "subscriptions": [ - "testing" - ], - "proxy_entity_name": "", - "check_hooks": null, - "stdin": false, - "ttl": 0, - "timeout": 0, - "duration": 0.010849143, - "executed": 1542667666, - "history": [ - { - "status": 1, - "executed": 1542667666 - } - ], - "issued": 1542667666, - "output": "example output", - "state": "failing", - "status": 1, - "total_state_change": 0, - "last_ok": 0, - "occurrences": 1, - "occurrences_watermark": 1, - "output_metric_format": "", - "output_metric_handlers": [], - "env_vars": null, - "metadata": { - "name": "check-nginx", - "namespace": "default", - "labels": null, - "annotations": { - "documentation": "https://google.com", - "playbook": "https://play.golang.org/" - } - } - } -} diff --git a/event.withAnnotations.resolved.json b/event.withAnnotations.resolved.json deleted file mode 100644 index c14a9f1..0000000 --- a/event.withAnnotations.resolved.json +++ /dev/null @@ -1,128 +0,0 @@ -{ - "timestamp": 1522100915, - "entity": { - "entity_class": "agent", - "system": { - "hostname": "webserver01", - "os": "linux", - "platform": "centos", - "platform_family": "rhel", - "platform_version": "7.4.1708", - "network": { - "interfaces": [ - { - "name": "lo", - "addresses": [ - "127.0.0.1/8", - "::1/128" - ] - }, - { - "name": "enp0s3", - "mac": "08:00:27:11:ad:d2", - "addresses": [ - "10.0.2.15/24", - "fe80::26a5:54ec:cf0d:9704/64" - ] - }, - { - "name": "enp0s8", - "mac": "08:00:27:bc:be:60", - "addresses": [ - "172.28.128.3/24", - "fe80::a00:27ff:febc:be60/64" - ] - } - ] - }, - "arch": "amd64" - }, - "subscriptions": [ - "testing", - "entity:webserver01" - ], - "last_seen": 1542667635, - "deregister": false, - "deregistration": {}, - "user": "agent", - "redact": [ - "password", - "passwd", - "pass", - "api_key", - "api_token", - "access_key", - "secret_key", - "private_key", - "secret" - ], - "metadata": { - "name": "webserver01", - "namespace": "default", - "labels": null, - "annotations": { - "documentation": "http://golang.org", - "playbook": "https://docs.sensu.io/sensu-go/latest" - } - } - }, - "check": { - "check_hooks": null, - "duration": 1.803135228, - "executed": 1522101015, - "high_flap_threshold": 0, - "history": [ - { - "executed": 1522100315 - }, - { - "executed": 1522100915 - } - ], - "command": "http_check.sh http://localhost:80", - "handlers": [ - "slack" - ], - "high_flap_threshold": 0, - "interval": 20, - "low_flap_threshold": 0, - "publish": true, - "runtime_assets": [], - "subscriptions": [ - "testing" - ], - "proxy_entity_name": "", - "check_hooks": null, - "stdin": false, - "ttl": 0, - "timeout": 0, - "duration": 0.010849143, - "executed": 1542667666, - "history": [ - { - "status": 1, - "executed": 1542667666 - } - ], - "issued": 1542667666, - "output": "example output", - "state": "failing", - "status": 0, - "total_state_change": 0, - "last_ok": 0, - "occurrences": 1, - "occurrences_watermark": 1, - "output_metric_format": "", - "output_metric_handlers": [], - "env_vars": null, - "metadata": { - "name": "check-nginx", - "namespace": "default", - "labels": null, - "annotations": { - "documentation": "https://google.com", - "playbook": "https://play.golang.org/" - } - } - } -} diff --git a/main.go b/main.go index cb37ba1..133cf4a 100644 --- a/main.go +++ b/main.go @@ -21,14 +21,16 @@ const ( // Config represents the handler plugin config. type Config struct { sensu.PluginConfig - APIURL string - AuthToken string - Team string - Annotations string - SensuDashboard string - MessageTemplate string - MessageLimit int - IncludeEventInNote bool + APIURL string + AuthToken string + Team string + Annotations string + SensuDashboard string + MessageTemplate string + MessageLimit int + DescriptionTemplate string + DescriptionLimit int + IncludeEventInNote bool } var ( @@ -104,6 +106,24 @@ var ( Usage: "The maximum length of the message field", Value: &plugin.MessageLimit, }, + { + Path: "descriptionTemplate", + Env: "OPSGENIE_DESCRIPTION_TEMPLATE", + Argument: "descriptionTemplate", + Shorthand: "d", + Default: "{{.Check.Output}}", + Usage: "The template for the description to be sent", + Value: &plugin.DescriptionTemplate, + }, + { + Path: "descriptionLimit", + Env: "OPSGENIE_DESCRIPTION_LIMIT", + Argument: "descriptionLimit", + Shorthand: "L", + Default: 100, + Usage: "The maximum length of the description field", + Value: &plugin.DescriptionLimit, + }, { Path: "includeEventInNote", Env: "", @@ -145,6 +165,15 @@ func parseEventKeyTags(event *types.Event) (title string, alias string, tags []s return trim(title, plugin.MessageLimit), alias, tags } +// parseDescription func returns string with custom template string to use in description +func parseDescription(event *types.Event) (description string) { + description, err := templates.EvalTemplate("description", plugin.DescriptionTemplate, event) + if err != nil { + return "" + } + return trim(description, plugin.DescriptionLimit) +} + // eventPriority func read priority in the event and return alerts.PX // check.Annotations override Entity.Annotations func eventPriority(event *types.Event) alertsv2.Priority { @@ -206,31 +235,6 @@ func stringInSlice(a string, list []string) bool { return false } -// parseAnnotations func try to find a predeterminated keys -func parseAnnotations(event *types.Event) string { - var output string - tags := strings.Split(plugin.Annotations, ",") - if event.Check.Annotations != nil { - for key, value := range event.Check.Annotations { - if stringInSlice(key, tags) { - output += fmt.Sprintf("%s: %s \n", key, value) - } - } - } - if event.Entity.Annotations != nil { - for key, value := range event.Entity.Annotations { - if stringInSlice(key, tags) { - output += fmt.Sprintf("%s: %s \n", key, value) - } - } - } - if plugin.SensuDashboard != "disabled" { - output += fmt.Sprintf("source: %s/%s/events/%s/%s \n", plugin.SensuDashboard, event.Entity.Namespace, event.Entity.Name, event.Check.Name) - } - output += fmt.Sprintf("check output: %s", event.Check.Output) - return output -} - func executeHandler(event *types.Event) error { // starting client instance cli := new(ogcli.OpsGenieClient) @@ -255,7 +259,7 @@ func executeHandler(event *types.Event) error { func createIncident(alertCli *ogcli.OpsGenieAlertV2Client, event *types.Event) error { var ( note string - err error + err error ) if plugin.IncludeEventInNote { note, err = getNote(event) @@ -272,7 +276,7 @@ func createIncident(alertCli *ogcli.OpsGenieAlertV2Client, event *types.Event) e request := alerts.CreateAlertRequest{ Message: title, Alias: alias, - Description: parseAnnotations(event), + Description: parseDescription(event), Teams: teams, Entity: event.Entity.Name, Source: source, diff --git a/main_test.go b/main_test.go index 3be374c..591908a 100644 --- a/main_test.go +++ b/main_test.go @@ -32,32 +32,15 @@ func TestParseEventKeyTags(t *testing.T) { assert.Contains(t, tags, "foo") } -func TestParseAnnotations(t *testing.T) { - event := v2.Event{ - Entity: &v2.Entity{ - ObjectMeta: v2.ObjectMeta{ - Name: "test", - Namespace: "default", - Annotations: map[string]string{ - "documentation": "no-docs", - }, - }, - }, - Check: &v2.Check{ - ObjectMeta: v2.ObjectMeta{ - Name: "test-check", - Annotations: map[string]string{ - "playbook": "no-playbook", - }, - }, - Output: "test output", - }, - } - plugin.Annotations = "documentation,playbook" - description := parseAnnotations(&event) - assert.Contains(t, description, "documentation") - assert.Contains(t, description, "playbook") - +func TestParseDescription(t *testing.T) { + event := types.FixtureEvent("foo", "bar") + event.Check.Output = "Check OK" + _, err := json.Marshal(event) + assert.NoError(t, err) + plugin.DescriptionTemplate = "{{.Check.Output}}" + plugin.DescriptionLimit = 100 + description := parseDescription(event) + assert.Contains(t, description, "Check OK") } func TestEventPriority(t *testing.T) { diff --git a/test.all.events.sh b/test.all.events.sh index c11beaa..8abcf24 100644 --- a/test.all.events.sh +++ b/test.all.events.sh @@ -1,7 +1,6 @@ #!/usr/bin/env bash list="event -event.withAnnotations event_with_opsgenie_priority.check event_with_opsgenie_priority" @@ -27,4 +26,4 @@ do cat ${event}.json | ./sensu-opsgenie-handler sleep 5 cat ${event}.resolved.json | ./sensu-opsgenie-handler -done \ No newline at end of file +done