forked from TrueCloudLab/distribution
Merge pull request #2501 from xiaonancc77/master
Added ignore event types into notifications
This commit is contained in:
commit
607ae5d128
7 changed files with 84 additions and 20 deletions
|
@ -561,6 +561,13 @@ type Endpoint struct {
|
||||||
Threshold int `yaml:"threshold"` // circuit breaker threshold before backing off on failure
|
Threshold int `yaml:"threshold"` // circuit breaker threshold before backing off on failure
|
||||||
Backoff time.Duration `yaml:"backoff"` // backoff duration
|
Backoff time.Duration `yaml:"backoff"` // backoff duration
|
||||||
IgnoredMediaTypes []string `yaml:"ignoredmediatypes"` // target media types to ignore
|
IgnoredMediaTypes []string `yaml:"ignoredmediatypes"` // target media types to ignore
|
||||||
|
Ignore Ignore `yaml:"ignore"` // ignore event types
|
||||||
|
}
|
||||||
|
|
||||||
|
//Ignore configures mediaTypes and actions of the event, that it won't be propagated
|
||||||
|
type Ignore struct {
|
||||||
|
MediaTypes []string `yaml:"mediatypes"` // target media types to ignore
|
||||||
|
Actions []string `yaml:"actions"` // ignore action types
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reporting defines error reporting methods.
|
// Reporting defines error reporting methods.
|
||||||
|
|
|
@ -63,6 +63,10 @@ var configStruct = Configuration{
|
||||||
"Authorization": []string{"Bearer <example>"},
|
"Authorization": []string{"Bearer <example>"},
|
||||||
},
|
},
|
||||||
IgnoredMediaTypes: []string{"application/octet-stream"},
|
IgnoredMediaTypes: []string{"application/octet-stream"},
|
||||||
|
Ignore: Ignore{
|
||||||
|
MediaTypes: []string{"application/octet-stream"},
|
||||||
|
Actions: []string{"pull"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -148,6 +152,11 @@ notifications:
|
||||||
Authorization: [Bearer <example>]
|
Authorization: [Bearer <example>]
|
||||||
ignoredmediatypes:
|
ignoredmediatypes:
|
||||||
- application/octet-stream
|
- application/octet-stream
|
||||||
|
ignore:
|
||||||
|
mediatypes:
|
||||||
|
- application/octet-stream
|
||||||
|
actions:
|
||||||
|
- pull
|
||||||
reporting:
|
reporting:
|
||||||
bugsnag:
|
bugsnag:
|
||||||
apikey: BugsnagApiKey
|
apikey: BugsnagApiKey
|
||||||
|
@ -176,6 +185,11 @@ notifications:
|
||||||
Authorization: [Bearer <example>]
|
Authorization: [Bearer <example>]
|
||||||
ignoredmediatypes:
|
ignoredmediatypes:
|
||||||
- application/octet-stream
|
- application/octet-stream
|
||||||
|
ignore:
|
||||||
|
mediatypes:
|
||||||
|
- application/octet-stream
|
||||||
|
actions:
|
||||||
|
- pull
|
||||||
http:
|
http:
|
||||||
headers:
|
headers:
|
||||||
X-Content-Type-Options: [nosniff]
|
X-Content-Type-Options: [nosniff]
|
||||||
|
|
|
@ -236,6 +236,11 @@ notifications:
|
||||||
backoff: 1s
|
backoff: 1s
|
||||||
ignoredmediatypes:
|
ignoredmediatypes:
|
||||||
- application/octet-stream
|
- application/octet-stream
|
||||||
|
ignore:
|
||||||
|
mediatypes:
|
||||||
|
- application/octet-stream
|
||||||
|
actions:
|
||||||
|
- pull
|
||||||
redis:
|
redis:
|
||||||
addr: localhost:6379
|
addr: localhost:6379
|
||||||
password: asecret
|
password: asecret
|
||||||
|
@ -858,6 +863,11 @@ notifications:
|
||||||
backoff: 1s
|
backoff: 1s
|
||||||
ignoredmediatypes:
|
ignoredmediatypes:
|
||||||
- application/octet-stream
|
- application/octet-stream
|
||||||
|
ignore:
|
||||||
|
mediatypes:
|
||||||
|
- application/octet-stream
|
||||||
|
actions:
|
||||||
|
- pull
|
||||||
```
|
```
|
||||||
|
|
||||||
The notifications option is **optional** and currently may contain a single
|
The notifications option is **optional** and currently may contain a single
|
||||||
|
@ -878,6 +888,14 @@ accept event notifications.
|
||||||
| `threshold` | yes | An integer specifying how long to wait before backing off a failure. |
|
| `threshold` | yes | An integer specifying how long to wait before backing off a failure. |
|
||||||
| `backoff` | yes | How long the system backs off before retrying after a failure. A positive integer and an optional suffix indicating the unit of time, which may be `ns`, `us`, `ms`, `s`, `m`, or `h`. If you omit the unit of time, `ns` is used. |
|
| `backoff` | yes | How long the system backs off before retrying after a failure. A positive integer and an optional suffix indicating the unit of time, which may be `ns`, `us`, `ms`, `s`, `m`, or `h`. If you omit the unit of time, `ns` is used. |
|
||||||
| `ignoredmediatypes`|no| A list of target media types to ignore. Events with these target media types are not published to the endpoint. |
|
| `ignoredmediatypes`|no| A list of target media types to ignore. Events with these target media types are not published to the endpoint. |
|
||||||
|
| `ignore` |no| Events with these mediatypes or actions are not published to the endpoint. |
|
||||||
|
|
||||||
|
#### `ignore`
|
||||||
|
| Parameter | Required | Description |
|
||||||
|
|-----------|----------|-------------------------------------------------------|
|
||||||
|
| `mediatypes`|no| A list of target media types to ignore. Events with these target media types are not published to the endpoint. |
|
||||||
|
| `actions` |no| A list of actions to ignore. Events with these actions are not published to the endpoint. |
|
||||||
|
|
||||||
|
|
||||||
## `redis`
|
## `redis`
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package notifications
|
package notifications
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/docker/distribution/configuration"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -14,6 +15,7 @@ type EndpointConfig struct {
|
||||||
Backoff time.Duration
|
Backoff time.Duration
|
||||||
IgnoredMediaTypes []string
|
IgnoredMediaTypes []string
|
||||||
Transport *http.Transport `json:"-"`
|
Transport *http.Transport `json:"-"`
|
||||||
|
Ignore configuration.Ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaults set any zero-valued fields to a reasonable default.
|
// defaults set any zero-valued fields to a reasonable default.
|
||||||
|
@ -63,7 +65,8 @@ func NewEndpoint(name, url string, config EndpointConfig) *Endpoint {
|
||||||
endpoint.Transport, endpoint.metrics.httpStatusListener())
|
endpoint.Transport, endpoint.metrics.httpStatusListener())
|
||||||
endpoint.Sink = newRetryingSink(endpoint.Sink, endpoint.Threshold, endpoint.Backoff)
|
endpoint.Sink = newRetryingSink(endpoint.Sink, endpoint.Threshold, endpoint.Backoff)
|
||||||
endpoint.Sink = newEventQueue(endpoint.Sink, endpoint.metrics.eventQueueListener())
|
endpoint.Sink = newEventQueue(endpoint.Sink, endpoint.metrics.eventQueueListener())
|
||||||
endpoint.Sink = newIgnoredMediaTypesSink(endpoint.Sink, config.IgnoredMediaTypes)
|
mediaTypes := append(config.Ignore.MediaTypes, config.IgnoredMediaTypes...)
|
||||||
|
endpoint.Sink = newIgnoredSink(endpoint.Sink, mediaTypes, config.Ignore.Actions)
|
||||||
|
|
||||||
register(&endpoint)
|
register(&endpoint)
|
||||||
return &endpoint
|
return &endpoint
|
||||||
|
|
|
@ -210,14 +210,15 @@ func (eq *eventQueue) next() []Event {
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignoredMediaTypesSink discards events with ignored target media types and
|
// ignoredSink discards events with ignored target media types and actions.
|
||||||
// passes the rest along.
|
// passes the rest along.
|
||||||
type ignoredMediaTypesSink struct {
|
type ignoredSink struct {
|
||||||
Sink
|
Sink
|
||||||
ignored map[string]bool
|
ignoreMediaTypes map[string]bool
|
||||||
|
ignoreActions map[string]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newIgnoredMediaTypesSink(sink Sink, ignored []string) Sink {
|
func newIgnoredSink(sink Sink, ignored []string, ignoreActions []string) Sink {
|
||||||
if len(ignored) == 0 {
|
if len(ignored) == 0 {
|
||||||
return sink
|
return sink
|
||||||
}
|
}
|
||||||
|
@ -227,25 +228,41 @@ func newIgnoredMediaTypesSink(sink Sink, ignored []string) Sink {
|
||||||
ignoredMap[mediaType] = true
|
ignoredMap[mediaType] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ignoredMediaTypesSink{
|
ignoredActionsMap := make(map[string]bool)
|
||||||
Sink: sink,
|
for _, action := range ignoreActions {
|
||||||
ignored: ignoredMap,
|
ignoredActionsMap[action] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ignoredSink{
|
||||||
|
Sink: sink,
|
||||||
|
ignoreMediaTypes: ignoredMap,
|
||||||
|
ignoreActions: ignoredActionsMap,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write discards events with ignored target media types and passes the rest
|
// Write discards events with ignored target media types and passes the rest
|
||||||
// along.
|
// along.
|
||||||
func (imts *ignoredMediaTypesSink) Write(events ...Event) error {
|
func (imts *ignoredSink) Write(events ...Event) error {
|
||||||
var kept []Event
|
var kept []Event
|
||||||
for _, e := range events {
|
for _, e := range events {
|
||||||
if !imts.ignored[e.Target.MediaType] {
|
if !imts.ignoreMediaTypes[e.Target.MediaType] {
|
||||||
kept = append(kept, e)
|
kept = append(kept, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(kept) == 0 {
|
if len(kept) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return imts.Sink.Write(kept...)
|
|
||||||
|
var results []Event
|
||||||
|
for _, e := range kept {
|
||||||
|
if !imts.ignoreActions[e.Action] {
|
||||||
|
results = append(results, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(results) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return imts.Sink.Write(results...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// retryingSink retries the write until success or an ErrSinkClosed is
|
// retryingSink retries the write until success or an ErrSinkClosed is
|
||||||
|
|
|
@ -113,25 +113,29 @@ func TestEventQueue(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIgnoredMediaTypesSink(t *testing.T) {
|
func TestIgnoredSink(t *testing.T) {
|
||||||
blob := createTestEvent("push", "library/test", "blob")
|
blob := createTestEvent("push", "library/test", "blob")
|
||||||
manifest := createTestEvent("push", "library/test", "manifest")
|
manifest := createTestEvent("pull", "library/test", "manifest")
|
||||||
|
|
||||||
type testcase struct {
|
type testcase struct {
|
||||||
ignored []string
|
ignoreMediaTypes []string
|
||||||
expected []Event
|
ignoreActions []string
|
||||||
|
expected []Event
|
||||||
}
|
}
|
||||||
|
|
||||||
cases := []testcase{
|
cases := []testcase{
|
||||||
{nil, []Event{blob, manifest}},
|
{nil, nil, []Event{blob, manifest}},
|
||||||
{[]string{"other"}, []Event{blob, manifest}},
|
{[]string{"other"}, []string{"other"}, []Event{blob, manifest}},
|
||||||
{[]string{"blob"}, []Event{manifest}},
|
{[]string{"blob"}, []string{"other"}, []Event{manifest}},
|
||||||
{[]string{"blob", "manifest"}, nil},
|
{[]string{"blob", "manifest"}, []string{"other"}, nil},
|
||||||
|
{[]string{"other"}, []string{"push"}, []Event{manifest}},
|
||||||
|
{[]string{"other"}, []string{"pull"}, []Event{blob}},
|
||||||
|
{[]string{"other"}, []string{"pull", "push"}, nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
ts := &testSink{}
|
ts := &testSink{}
|
||||||
s := newIgnoredMediaTypesSink(ts, c.ignored)
|
s := newIgnoredSink(ts, c.ignoreMediaTypes, c.ignoreActions)
|
||||||
|
|
||||||
if err := s.Write(blob, manifest); err != nil {
|
if err := s.Write(blob, manifest); err != nil {
|
||||||
t.Fatalf("error writing event: %v", err)
|
t.Fatalf("error writing event: %v", err)
|
||||||
|
|
|
@ -450,6 +450,7 @@ func (app *App) configureEvents(configuration *configuration.Configuration) {
|
||||||
Backoff: endpoint.Backoff,
|
Backoff: endpoint.Backoff,
|
||||||
Headers: endpoint.Headers,
|
Headers: endpoint.Headers,
|
||||||
IgnoredMediaTypes: endpoint.IgnoredMediaTypes,
|
IgnoredMediaTypes: endpoint.IgnoredMediaTypes,
|
||||||
|
Ignore: endpoint.Ignore,
|
||||||
})
|
})
|
||||||
|
|
||||||
sinks = append(sinks, endpoint)
|
sinks = append(sinks, endpoint)
|
||||||
|
|
Loading…
Reference in a new issue