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)
|
||||
* [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)
|
||||
|
|
|
@ -15,6 +15,7 @@ $ sudo service telegraf start
|
|||
|
||||
## Available webhooks
|
||||
|
||||
- [Dockerhub](dockerhub/)
|
||||
- [Github](github/)
|
||||
- [Mandrill](mandrill/)
|
||||
- [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/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"
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue