Add Docker Hub Webhook Plugin

This commit is contained in:
DazWilkin 2016-08-06 17:09:09 -07:00
parent 49988b15a3
commit 7d9e2ca05c
9 changed files with 283 additions and 3 deletions

View File

@ -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)
* [nats_consumer](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nats_consumer)
* [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)
* [mandrill](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/webhooks/mandrill)
* [rollbar](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/webhooks/rollbar)

View File

@ -15,6 +15,7 @@ $ sudo service telegraf start
## Available webhooks
- [Dockerhub](dockerhub/)
- [Github](github/)
- [Mandrill](mandrill/)
- [Rollbar](rollbar/)

View File

@ -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

View File

@ -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
}

View File

@ -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))
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -10,6 +10,7 @@ import (
"github.com/influxdata/telegraf"
"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/mandrill"
"github.com/influxdata/telegraf/plugins/inputs/webhooks/rollbar"
@ -26,9 +27,10 @@ func init() {
type Webhooks struct {
ServiceAddress string
Github *github.GithubWebhook
Mandrill *mandrill.MandrillWebhook
Rollbar *rollbar.RollbarWebhook
Dockerhub *dockerhub.DockerhubWebhook
Github *github.GithubWebhook
Mandrill *mandrill.MandrillWebhook
Rollbar *rollbar.RollbarWebhook
}
func NewWebhooks() *Webhooks {
@ -40,6 +42,9 @@ func (wb *Webhooks) SampleConfig() string {
## Address and port to host Webhook listener on
service_address = ":1619"
[inputs.webhooks.dockerhub]
path = "/dockerhub"
[inputs.webhooks.github]
path = "/github"

View File

@ -4,6 +4,7 @@ import (
"reflect"
"testing"
"github.com/influxdata/telegraf/plugins/inputs/webhooks/dockerhub"
"github.com/influxdata/telegraf/plugins/inputs/webhooks/github"
"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())
}
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"}
expected = append(expected, wb.Github)
if !reflect.DeepEqual(wb.AvailableWebhooks(), expected) {