Add Docker Hub Webhook Plugin
This commit is contained in:
parent
49988b15a3
commit
7d9e2ca05c
|
@ -219,6 +219,7 @@ Telegraf can also collect metrics via the following service plugins:
|
||||||
* [kafka_consumer](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/kafka_consumer)
|
* [kafka_consumer](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/kafka_consumer)
|
||||||
* [nats_consumer](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nats_consumer)
|
* [nats_consumer](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nats_consumer)
|
||||||
* [webhooks](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/webhooks)
|
* [webhooks](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/webhooks)
|
||||||
|
* [dockerhub](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/webhooks/dockerhub)
|
||||||
* [github](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/webhooks/github)
|
* [github](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/webhooks/github)
|
||||||
* [mandrill](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/webhooks/mandrill)
|
* [mandrill](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/webhooks/mandrill)
|
||||||
* [rollbar](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/webhooks/rollbar)
|
* [rollbar](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/webhooks/rollbar)
|
||||||
|
|
|
@ -15,6 +15,7 @@ $ sudo service telegraf start
|
||||||
|
|
||||||
## Available webhooks
|
## Available webhooks
|
||||||
|
|
||||||
|
- [Dockerhub](dockerhub/)
|
||||||
- [Github](github/)
|
- [Github](github/)
|
||||||
- [Mandrill](mandrill/)
|
- [Mandrill](mandrill/)
|
||||||
- [Rollbar](rollbar/)
|
- [Rollbar](rollbar/)
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Docker Hub Webhook
|
||||||
|
|
||||||
|
Docker Hub can be configured to send events to Webhooks. The page describes the JSON format of the events:
|
||||||
|
|
||||||
|
https://docs.docker.com/docker-hub/webhooks/
|
||||||
|
|
||||||
|
Webhooks are configured by repository:
|
||||||
|
|
||||||
|
https://hub.docker.com/r/[[User]]/[Repository]]/~/settings/webhooks/
|
||||||
|
|
||||||
|
## Events
|
||||||
|
|
||||||
|
An event is generated by Docker Hub as the result of a docker push to the repository.
|
||||||
|
|
||||||
|
#### [`dockerhub_event`](https://docs.docker.com/docker-hub/webhooks/)
|
||||||
|
|
||||||
|
The measurement is called "dockerhub"
|
||||||
|
|
||||||
|
**Tags:**
|
||||||
|
|
||||||
|
* 'description' = `repository.description` string
|
||||||
|
* 'name' = `repository.name` string
|
||||||
|
* 'namespace' = `repository.namespace` string
|
||||||
|
* 'owner' = `repository.owner` string
|
||||||
|
* 'repo_name' = `repository.repo_name` string
|
||||||
|
* 'repo_url' = `repository.repo_url` string
|
||||||
|
* 'status' = `repository.status` string
|
||||||
|
|
||||||
|
* 'pusher' = `push_data.pusher` string
|
||||||
|
* 'tag' = `push_data.tag` string
|
||||||
|
|
||||||
|
**Fields:**
|
||||||
|
|
||||||
|
* 'comment_count' = `repository.comment_count` int
|
||||||
|
* 'date_created' = `repository.date_created` int64
|
||||||
|
* 'is_official' = `repository.is_official` bool
|
||||||
|
* 'is_private' = `repository.is_private` bool
|
||||||
|
* 'is_trusted' = `repository.is_trusted` bool
|
||||||
|
* 'star_count' = `repository.stat_count` int
|
||||||
|
|
||||||
|
* 'pushed_at' = `push_data.psuhed_at` int64
|
|
@ -0,0 +1,50 @@
|
||||||
|
package dockerhub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/influxdata/telegraf"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DockerhubWebhook struct {
|
||||||
|
Path string
|
||||||
|
acc telegraf.Accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dhwh *DockerhubWebhook) Register(router *mux.Router, acc telegraf.Accumulator) {
|
||||||
|
router.HandleFunc(dhwh.Path, dhwh.eventHandler).Methods("POST")
|
||||||
|
log.Printf("Started '%s' on %s\n", meas, dhwh.Path)
|
||||||
|
dhwh.acc = acc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dhwh *DockerhubWebhook) eventHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
defer r.Body.Close()
|
||||||
|
|
||||||
|
data, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e, err := NewEvent(data, &DockerhubEvent{})
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dh := e.NewMetric()
|
||||||
|
dhwh.acc.AddFields(meas, dh.Fields(), dh.Tags(), dh.Time())
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEvent(data []byte, event Event) (Event, error) {
|
||||||
|
err := json.Unmarshal(data, event)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return event, nil
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
package dockerhub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// See https://docs.docker.com/docker-hub/webhooks/
|
||||||
|
|
||||||
|
const dockerid = "somerandomuser"
|
||||||
|
const hexBytes = "0123456789abcdef"
|
||||||
|
const imagename = "testimage"
|
||||||
|
const registry = "https://registry.hub.docker.com/u/"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
}
|
||||||
|
|
||||||
|
func RandStringBytes(n int) string {
|
||||||
|
b := make([]byte, n)
|
||||||
|
for i := range b {
|
||||||
|
b[i] = hexBytes[rand.Intn(len(hexBytes))]
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEventJSONEncoded() string {
|
||||||
|
return fmt.Sprintf(`{
|
||||||
|
"callback_url": "%s",
|
||||||
|
"push_data": {
|
||||||
|
"images": [
|
||||||
|
"%s",
|
||||||
|
"%s"
|
||||||
|
],
|
||||||
|
"pushed_at": %v,
|
||||||
|
"pusher": "%s"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"comment_count": 0,
|
||||||
|
"date_created": %v,
|
||||||
|
"description": "",
|
||||||
|
"dockerfile": "",
|
||||||
|
"is_official": false,
|
||||||
|
"is_private": true,
|
||||||
|
"is_trusted": true,
|
||||||
|
"name": "testhook",
|
||||||
|
"namespace": "%s",
|
||||||
|
"owner": "%s",
|
||||||
|
"repo_name": "%s",
|
||||||
|
"repo_url": "%s",
|
||||||
|
"star_count": 0,
|
||||||
|
"status": "Active"
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
fmt.Sprintf("%s/%s/%s/%s/", registry, dockerid, imagename, RandStringBytes(64)),
|
||||||
|
RandStringBytes(64),
|
||||||
|
RandStringBytes(64),
|
||||||
|
time.Now().Unix(),
|
||||||
|
dockerid,
|
||||||
|
time.Now().Unix(),
|
||||||
|
dockerid,
|
||||||
|
dockerid,
|
||||||
|
fmt.Sprintf("%s/%s", dockerid, imagename),
|
||||||
|
fmt.Sprintf("%s/%s/%s/", registry, dockerid, imagename))
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
package dockerhub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/influxdata/telegraf"
|
||||||
|
)
|
||||||
|
|
||||||
|
const meas = "dockerhub"
|
||||||
|
|
||||||
|
type Event interface {
|
||||||
|
NewMetric() telegraf.Metric
|
||||||
|
}
|
||||||
|
|
||||||
|
type PushData struct {
|
||||||
|
Images []string `json:"images"`
|
||||||
|
PushedAt int64 `json:"pushed_at"`
|
||||||
|
Pusher string `json:"pusher"`
|
||||||
|
Tag string `json:"tag"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Repository struct {
|
||||||
|
CommentCount int `json:"comment_count"`
|
||||||
|
DateCreated int64 `json:"date_created"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Dockerfile string `json:"dockerfile"`
|
||||||
|
FullDescription string `json:"full_description"`
|
||||||
|
IsOfficial bool `json:"is__official"`
|
||||||
|
IsPrivate bool `json:"is_private"`
|
||||||
|
IsTrusted bool `json:"is_trusted"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
Owner string `json:"owner"`
|
||||||
|
RepoName string `json:"repo_name"`
|
||||||
|
RepoURL string `json:"repo_url"`
|
||||||
|
StarCount int `json:"star_count"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DockerhubEvent struct {
|
||||||
|
CallbackURL string `json:"callback_url"`
|
||||||
|
PushData PushData `json:"push_data"`
|
||||||
|
Repository Repository `json:"repository"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dhe DockerhubEvent) String() string {
|
||||||
|
return fmt.Sprintf(`{
|
||||||
|
callback_url: %v
|
||||||
|
}`,
|
||||||
|
dhe.CallbackURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dhe DockerhubEvent) NewMetric() telegraf.Metric {
|
||||||
|
tags := map[string]string{
|
||||||
|
"description": dhe.Repository.Description,
|
||||||
|
"name": dhe.Repository.Name,
|
||||||
|
"namespace": dhe.Repository.Namespace,
|
||||||
|
"owner": dhe.Repository.Owner,
|
||||||
|
"pusher": dhe.PushData.Pusher,
|
||||||
|
"repo_name": dhe.Repository.RepoName,
|
||||||
|
"repo_url": dhe.Repository.RepoURL,
|
||||||
|
"status": dhe.Repository.Status,
|
||||||
|
"tag": dhe.PushData.Tag,
|
||||||
|
}
|
||||||
|
fields := map[string]interface{}{
|
||||||
|
"comment_count": dhe.Repository.CommentCount,
|
||||||
|
"date_created": dhe.Repository.DateCreated,
|
||||||
|
"is_official": dhe.Repository.IsOfficial,
|
||||||
|
"is_private": dhe.Repository.IsPrivate,
|
||||||
|
"is_trusted": dhe.Repository.IsTrusted,
|
||||||
|
"pushed_at": dhe.PushData.PushedAt,
|
||||||
|
"star_count": dhe.Repository.StarCount,
|
||||||
|
}
|
||||||
|
metric, err := telegraf.NewMetric(meas, tags, fields, time.Unix(dhe.PushData.PushedAt, 0))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to create %v event", meas)
|
||||||
|
}
|
||||||
|
return metric
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package dockerhub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/influxdata/telegraf/testutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DockerhubWebhookRequest(event string, jsonString string, t *testing.T) {
|
||||||
|
var acc testutil.Accumulator
|
||||||
|
dhwh := &DockerhubWebhook{Path: "/dockerhub", acc: &acc}
|
||||||
|
req, _ := http.NewRequest("POST", "/dockerhub", strings.NewReader(jsonString))
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
dhwh.eventHandler(w, req)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Errorf(
|
||||||
|
"POST"+event+" returned HTTP status code %v.\nExpected %v",
|
||||||
|
w.Code,
|
||||||
|
http.StatusOK)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewEvent(t *testing.T) {
|
||||||
|
DockerhubWebhookRequest("dockerhub_event", NewEventJSONEncoded(), t)
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/influxdata/telegraf"
|
"github.com/influxdata/telegraf"
|
||||||
"github.com/influxdata/telegraf/plugins/inputs"
|
"github.com/influxdata/telegraf/plugins/inputs"
|
||||||
|
|
||||||
|
"github.com/influxdata/telegraf/plugins/inputs/webhooks/dockerhub"
|
||||||
"github.com/influxdata/telegraf/plugins/inputs/webhooks/github"
|
"github.com/influxdata/telegraf/plugins/inputs/webhooks/github"
|
||||||
"github.com/influxdata/telegraf/plugins/inputs/webhooks/mandrill"
|
"github.com/influxdata/telegraf/plugins/inputs/webhooks/mandrill"
|
||||||
"github.com/influxdata/telegraf/plugins/inputs/webhooks/rollbar"
|
"github.com/influxdata/telegraf/plugins/inputs/webhooks/rollbar"
|
||||||
|
@ -26,6 +27,7 @@ func init() {
|
||||||
type Webhooks struct {
|
type Webhooks struct {
|
||||||
ServiceAddress string
|
ServiceAddress string
|
||||||
|
|
||||||
|
Dockerhub *dockerhub.DockerhubWebhook
|
||||||
Github *github.GithubWebhook
|
Github *github.GithubWebhook
|
||||||
Mandrill *mandrill.MandrillWebhook
|
Mandrill *mandrill.MandrillWebhook
|
||||||
Rollbar *rollbar.RollbarWebhook
|
Rollbar *rollbar.RollbarWebhook
|
||||||
|
@ -40,6 +42,9 @@ func (wb *Webhooks) SampleConfig() string {
|
||||||
## Address and port to host Webhook listener on
|
## Address and port to host Webhook listener on
|
||||||
service_address = ":1619"
|
service_address = ":1619"
|
||||||
|
|
||||||
|
[inputs.webhooks.dockerhub]
|
||||||
|
path = "/dockerhub"
|
||||||
|
|
||||||
[inputs.webhooks.github]
|
[inputs.webhooks.github]
|
||||||
path = "/github"
|
path = "/github"
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/influxdata/telegraf/plugins/inputs/webhooks/dockerhub"
|
||||||
"github.com/influxdata/telegraf/plugins/inputs/webhooks/github"
|
"github.com/influxdata/telegraf/plugins/inputs/webhooks/github"
|
||||||
"github.com/influxdata/telegraf/plugins/inputs/webhooks/rollbar"
|
"github.com/influxdata/telegraf/plugins/inputs/webhooks/rollbar"
|
||||||
)
|
)
|
||||||
|
@ -15,6 +16,12 @@ func TestAvailableWebhooks(t *testing.T) {
|
||||||
t.Errorf("expected to %v.\nGot %v", expected, wb.AvailableWebhooks())
|
t.Errorf("expected to %v.\nGot %v", expected, wb.AvailableWebhooks())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wb.Dockerhub = &dockerhub.DockerhubWebhook{Path: "/dockerhub"}
|
||||||
|
expected = append(expected, wb.Dockerhub)
|
||||||
|
if !reflect.DeepEqual(wb.AvailableWebhooks(), expected) {
|
||||||
|
t.Errorf("expected to be %v.\nGot %v", expected, wb.AvailableWebhooks())
|
||||||
|
}
|
||||||
|
|
||||||
wb.Github = &github.GithubWebhook{Path: "/github"}
|
wb.Github = &github.GithubWebhook{Path: "/github"}
|
||||||
expected = append(expected, wb.Github)
|
expected = append(expected, wb.Github)
|
||||||
if !reflect.DeepEqual(wb.AvailableWebhooks(), expected) {
|
if !reflect.DeepEqual(wb.AvailableWebhooks(), expected) {
|
||||||
|
|
Loading…
Reference in New Issue