#289 registry notifications webhook

feature/registry_notifications
Karolis Rusenas 2018-10-12 21:45:12 +01:00
parent 9c0d3476f9
commit 11ca37f2ad
3 changed files with 136 additions and 1 deletions

View File

@ -114,5 +114,4 @@ func (s *TriggerServer) dockerHubHandler(resp http.ResponseWriter, req *http.Req
resp.WriteHeader(http.StatusOK)
newDockerhubWebhooksCounter.With(prometheus.Labels{"image": event.Repository.Name}).Inc()
return
}

View File

@ -106,6 +106,11 @@ func (s *TriggerServer) registerRoutes(mux *mux.Router) {
mux.HandleFunc("/v1/webhooks/azure", s.azureHandler).Methods("POST", "OPTIONS")
// Docker registry notifications, used by Docker, Gitlab, Harbor
// https://docs.docker.com/registry/notifications/
//https://docs.gitlab.com/ee/administration/container_registry.html#configure-container-registry-notifications
mux.HandleFunc("/v1/webhooks/registry", s.registryNotificationHandler).Methods("POST", "OPTIONS")
mux.Handle("/metrics", promhttp.Handler())
}

View File

@ -0,0 +1,131 @@
package http
import (
"encoding/json"
"fmt"
"net/http"
"time"
"github.com/keel-hq/keel/types"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
)
var newRegistryNotificationWebhooksCounter = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "registry_notification_requests_total",
Help: "How many /v1/webhooks/registry requests processed, partitioned by image.",
},
[]string{"image"},
)
func init() {
prometheus.MustRegister(newRegistryNotificationWebhooksCounter)
}
// {
// "events": [
// {
// "id": "d83e8796-7ba5-46ad-b239-d88473e21b2b",
// "timestamp": "2018-10-11T13:53:21.859222576Z",
// "action": "push",
// "target": {
// "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
// "size": 2206,
// "digest": "sha256:4afff550708506c5b8b7384ad10d401a02b29ed587cb2730cb02753095b5178d",
// "length": 2206,
// "repository": "shinebayar-g/a",
// "url": "https://registry.git.erxes.io/v2/shinebayar-g/a/manifests/sha256:4afff550708506c5b8b7384ad10d401a02b29ed587cb2730cb02753095b5178d",
// "tag": "0.01"
// },
// "request": {
// "id": "18690582-6d1a-4e08-8825-251a0adc58ce",
// "addr": "46.101.177.27",
// "host": "registry.git.erxes.io",
// "method": "PUT",
// "useragent": "docker/18.06.1-ce go/go1.10.3 git-commit/e68fc7a kernel/4.4.0-135-generic os/linux arch/amd64 UpstreamClient(Docker-Client/18.06.1-ce \\(linux\\))"
// },
// "actor": {
// "name": "shinebayar-g"
// },
// "source": {
// "addr": "git.erxes.io:5000",
// "instanceID": "bde27723-d67e-4775-a9bd-55f771a2f895"
// }
// }
// ]
// }
type registryNotification struct {
Events []struct {
ID string `json:"id"`
Timestamp time.Time `json:"timestamp"`
Action string `json:"action"`
Target struct {
MediaType string `json:"mediaType"`
Size int `json:"size"`
Digest string `json:"digest"`
Length int `json:"length"`
Repository string `json:"repository"`
URL string `json:"url"`
Tag string `json:"tag"`
} `json:"target"`
Request struct {
ID string `json:"id"`
Addr string `json:"addr"`
Host string `json:"host"`
Method string `json:"method"`
Useragent string `json:"useragent"`
} `json:"request"`
Actor struct {
Name string `json:"name"`
} `json:"actor"`
Source struct {
Addr string `json:"addr"`
InstanceID string `json:"instanceID"`
} `json:"source"`
} `json:"events"`
}
func (s *TriggerServer) registryNotificationHandler(resp http.ResponseWriter, req *http.Request) {
rn := registryNotification{}
if err := json.NewDecoder(req.Body).Decode(&rn); err != nil {
log.WithFields(log.Fields{
"error": err,
}).Error("trigger.dockerHubHandler: failed to decode request")
resp.WriteHeader(http.StatusBadRequest)
return
}
for _, e := range rn.Events {
if e.Action != "push" {
// ignoring non-push events
resp.WriteHeader(200)
return
}
if e.Target.Tag == "" {
resp.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(resp, "tag cannot be empty")
return
}
dockerURL := e.Request.Host + "/" + e.Target.Repository
event := types.Event{}
event.Repository.Name = dockerURL
event.CreatedAt = time.Now()
event.TriggerName = "registry-notification"
event.Repository.Tag = e.Target.Tag
event.Repository.Digest = e.Target.Digest
s.trigger(event)
newRegistryNotificationWebhooksCounter.With(prometheus.Labels{"image": event.Repository.Name}).Inc()
}
}