This repository has been archived by the owner on Nov 1, 2022. It is now read-only.
Better slack notifications #415
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
930c7b0
Better release slack notifications, once per release
paulbellamy e430b63
a notification format which works for currently available data
paulbellamy d7098e6
Review Feedback - naming consistency
paulbellamy d13520d
Use the flux.ReleaseStatus enum to avoid a slip-up
paulbellamy File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package notifications | ||
|
||
import ( | ||
"github.com/weaveworks/flux" | ||
"github.com/weaveworks/flux/instance" | ||
) | ||
|
||
// Release performs post-release notifications for an instance | ||
func Release(cfg instance.Config, r flux.Release, releaseError error) error { | ||
if r.Spec.Kind != flux.ReleaseKindExecute { | ||
return nil | ||
} | ||
|
||
// TODO: Use a config settings format which allows multiple notifiers to be | ||
// configured. | ||
var err error | ||
if cfg.Settings.Slack.HookURL != "" { | ||
err = slackNotifyRelease(cfg.Settings.Slack, r, releaseError) | ||
} | ||
return err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package notifications | ||
|
||
import ( | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
"time" | ||
|
||
"github.com/weaveworks/flux" | ||
"github.com/weaveworks/flux/instance" | ||
) | ||
|
||
// Generate an example release | ||
func exampleRelease(t *testing.T) flux.Release { | ||
now := time.Now().UTC() | ||
img1a1, _ := flux.ParseImageID("img1:a1") | ||
img1a2, _ := flux.ParseImageID("img1:a2") | ||
return flux.Release{ | ||
ID: flux.NewReleaseID(), | ||
CreatedAt: now.Add(-1 * time.Minute), | ||
StartedAt: now.Add(-30 * time.Second), | ||
EndedAt: now.Add(-1 * time.Second), | ||
Done: true, | ||
Priority: 100, | ||
Status: flux.ReleaseStatusFailed, | ||
Log: []string{string(flux.ReleaseStatusFailed)}, | ||
|
||
Spec: flux.ReleaseSpec{ | ||
ServiceSpecs: []flux.ServiceSpec{flux.ServiceSpec("default/helloworld")}, | ||
ImageSpec: flux.ImageSpecLatest, | ||
Kind: flux.ReleaseKindExecute, | ||
Excludes: nil, | ||
}, | ||
Result: flux.ReleaseResult{ | ||
flux.ServiceID("default/helloworld"): { | ||
Status: flux.ReleaseStatusFailed, | ||
Error: "overall-release-error", | ||
PerContainer: []flux.ContainerResult{ | ||
{ | ||
Error: "", | ||
ContainerUpdate: flux.ContainerUpdate{ | ||
Container: "container1", | ||
Current: img1a1, | ||
Target: img1a2, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func TestRelease_DryRun(t *testing.T) { | ||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
t.Error("Expected no http request to have been made") | ||
})) | ||
defer server.Close() | ||
|
||
// It should send releases to slack | ||
r := exampleRelease(t) | ||
r.Spec.Kind = flux.ReleaseKindPlan | ||
if err := Release(instance.Config{ | ||
Settings: flux.UnsafeInstanceConfig{ | ||
Slack: flux.NotifierConfig{ | ||
HookURL: server.URL, | ||
}, | ||
}, | ||
}, r, nil); err != nil { | ||
t.Fatal(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
package notifications | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
"io/ioutil" | ||
"net/http" | ||
"reflect" | ||
"strings" | ||
"text/template" | ||
"time" | ||
|
||
"github.com/pkg/errors" | ||
|
||
"github.com/weaveworks/flux" | ||
) | ||
|
||
const ( | ||
defaultReleaseTemplate = `Release {{trim (print .Spec.ImageSpec) "<>"}} to {{with .Spec.ServiceSpecs}}{{range $index, $spec := .}}{{if not (eq $index 0)}}, {{if last $index $}}and {{end}}{{end}}{{trim (print .) "<>"}}{{end}}{{end}}. {{with .Error}}{{.}}. failed{{else}}done{{end}}` | ||
) | ||
|
||
var ( | ||
httpClient = &http.Client{Timeout: 5 * time.Second} | ||
) | ||
|
||
func slackNotifyRelease(config flux.NotifierConfig, release flux.Release, releaseError error) error { | ||
if release.Spec.Kind == flux.ReleaseKindPlan { | ||
return nil | ||
} | ||
|
||
template := defaultReleaseTemplate | ||
if config.ReleaseTemplate != "" { | ||
template = config.ReleaseTemplate | ||
} | ||
|
||
errorMessage := "" | ||
if releaseError != nil { | ||
errorMessage = releaseError.Error() | ||
} | ||
text, err := instantiateTemplate("release", template, struct { | ||
flux.Release | ||
Error string | ||
}{ | ||
Release: release, | ||
Error: errorMessage, | ||
}) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return notify(config, text) | ||
} | ||
|
||
func notify(config flux.NotifierConfig, text string) error { | ||
buf := &bytes.Buffer{} | ||
if err := json.NewEncoder(buf).Encode(map[string]string{ | ||
"username": config.Username, | ||
"text": text, | ||
}); err != nil { | ||
return errors.Wrap(err, "encoding Slack POST request") | ||
} | ||
|
||
req, err := http.NewRequest("POST", config.HookURL, buf) | ||
if err != nil { | ||
return errors.Wrap(err, "constructing Slack HTTP request") | ||
} | ||
resp, err := httpClient.Do(req) | ||
if err != nil { | ||
return errors.Wrap(err, "executing HTTP POST to Slack") | ||
} | ||
if resp.StatusCode < 200 || resp.StatusCode >= 300 { | ||
body, _ := ioutil.ReadAll(io.LimitReader(resp.Body, 1024*1024)) | ||
return fmt.Errorf("%s from Slack (%s)", resp.Status, strings.TrimSpace(string(body))) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func instantiateTemplate(tmplName, tmplStr string, args interface{}) (string, error) { | ||
tmpl, err := template.New(tmplName).Funcs(template.FuncMap{ | ||
"iso8601": func(t time.Time) string { return t.Format(time.RFC3339) }, | ||
"join": strings.Join, | ||
"replace": strings.Replace, | ||
"trim": strings.Trim, | ||
"trimLeft": strings.TrimLeft, | ||
"trimPrefix": strings.TrimPrefix, | ||
"trimRight": strings.TrimRight, | ||
"trimSuffix": strings.TrimSuffix, | ||
"trimSpace": strings.TrimSpace, | ||
"last": func(i int, a interface{}) bool { return i == reflect.ValueOf(a).Len()-1 }, | ||
}).Parse(tmplStr) | ||
if err != nil { | ||
return "", err | ||
} | ||
var buf bytes.Buffer | ||
if err := tmpl.Execute(&buf, args); err != nil { | ||
return "", err | ||
} | ||
return buf.String(), nil | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
Sorry, something went wrong.