Add configurable layers in manifest events

Signed-off-by: Andrew Leung <anwleung@gmail.com>
This commit is contained in:
Andrew Leung 2018-06-27 08:47:40 -07:00
parent 749f6afb45
commit 276fdce3d9
9 changed files with 66 additions and 18 deletions

View file

@ -29,6 +29,8 @@ redis:
readtimeout: 10ms readtimeout: 10ms
writetimeout: 10ms writetimeout: 10ms
notifications: notifications:
events:
manifestlayers: true
endpoints: endpoints:
- name: local-8082 - name: local-8082
url: http://localhost:5003/callback url: http://localhost:5003/callback

View file

@ -47,6 +47,8 @@ redis:
readtimeout: 10ms readtimeout: 10ms
writetimeout: 10ms writetimeout: 10ms
notifications: notifications:
events:
manifestlayers: true
endpoints: endpoints:
- name: local-5003 - name: local-5003
url: http://localhost:5003/callback url: http://localhost:5003/callback

View file

@ -544,6 +544,8 @@ func (auth Auth) MarshalYAML() (interface{}, error) {
// Notifications configures multiple http endpoints. // Notifications configures multiple http endpoints.
type Notifications struct { type Notifications struct {
// EventConfig is the configuration for the event format that is sent to each Endpoint.
EventConfig Events `yaml:"events,omitempty"`
// Endpoints is a list of http configurations for endpoints that // Endpoints is a list of http configurations for endpoints that
// respond to webhook notifications. In the future, we may allow other // respond to webhook notifications. In the future, we may allow other
// kinds of endpoints, such as external queues. // kinds of endpoints, such as external queues.
@ -564,6 +566,11 @@ type Endpoint struct {
Ignore Ignore `yaml:"ignore"` // ignore event types Ignore Ignore `yaml:"ignore"` // ignore event types
} }
// Events configures notification events.
type Events struct {
ManifestLayers bool `yaml:"manifestlayers"` // include layer data in manifest events
}
//Ignore configures mediaTypes and actions of the event, that it won't be propagated //Ignore configures mediaTypes and actions of the event, that it won't be propagated
type Ignore struct { type Ignore struct {
MediaTypes []string `yaml:"mediatypes"` // target media types to ignore MediaTypes []string `yaml:"mediatypes"` // target media types to ignore

View file

@ -226,6 +226,8 @@ http:
http2: http2:
disabled: false disabled: false
notifications: notifications:
events:
manifestlayers: true
endpoints: endpoints:
- name: alistener - name: alistener
disabled: false disabled: false
@ -853,6 +855,8 @@ settings for the registry.
```none ```none
notifications: notifications:
events:
manifestlayers: true
endpoints: endpoints:
- name: alistener - name: alistener
disabled: false disabled: false
@ -896,6 +900,13 @@ accept event notifications.
| `mediatypes`|no| A list of target media types to ignore. Events with these target media types are not published to the endpoint. | | `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. | | `actions` |no| A list of actions to ignore. Events with these actions are not published to the endpoint. |
### `events`
The `events` structure configures the information provided in event notifications.
| Parameter | Required | Description |
|-----------|----------|-------------------------------------------------------|
| `manifestlayers` | no | If `true`, include layer information in manifest events. |
## `redis` ## `redis`

View file

@ -71,7 +71,7 @@ type Manifest struct {
Layers []distribution.Descriptor `json:"layers"` Layers []distribution.Descriptor `json:"layers"`
} }
// References returnes the descriptors of this manifests references. // References returns the descriptors of this manifests references.
func (m Manifest) References() []distribution.Descriptor { func (m Manifest) References() []distribution.Descriptor {
references := make([]distribution.Descriptor, 0, 1+len(m.Layers)) references := make([]distribution.Descriptor, 0, 1+len(m.Layers))
references = append(references, m.Config) references = append(references, m.Config)

View file

@ -12,11 +12,12 @@ import (
) )
type bridge struct { type bridge struct {
ub URLBuilder ub URLBuilder
actor ActorRecord manfiestLayers bool
source SourceRecord actor ActorRecord
request RequestRecord source SourceRecord
sink Sink request RequestRecord
sink Sink
} }
var _ Listener = &bridge{} var _ Listener = &bridge{}
@ -31,13 +32,14 @@ type URLBuilder interface {
// using the actor and source. Any urls populated in the events created by // using the actor and source. Any urls populated in the events created by
// this bridge will be created using the URLBuilder. // this bridge will be created using the URLBuilder.
// TODO(stevvooe): Update this to simply take a context.Context object. // TODO(stevvooe): Update this to simply take a context.Context object.
func NewBridge(ub URLBuilder, source SourceRecord, actor ActorRecord, request RequestRecord, sink Sink) Listener { func NewBridge(ub URLBuilder, source SourceRecord, actor ActorRecord, request RequestRecord, sink Sink, manifestLayers bool) Listener {
return &bridge{ return &bridge{
ub: ub, ub: ub,
actor: actor, manfiestLayers: manifestLayers,
source: source, actor: actor,
request: request, source: source,
sink: sink, request: request,
sink: sink,
} }
} }
@ -135,7 +137,7 @@ func (b *bridge) createManifestEvent(action string, repo reference.Named, sm dis
} }
// Ensure we have the canonical manifest descriptor here // Ensure we have the canonical manifest descriptor here
_, desc, err := distribution.UnmarshalManifest(mt, p) manifest, desc, err := distribution.UnmarshalManifest(mt, p)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -144,6 +146,9 @@ func (b *bridge) createManifestEvent(action string, repo reference.Named, sm dis
event.Target.Length = desc.Size event.Target.Length = desc.Size
event.Target.Size = desc.Size event.Target.Size = desc.Size
event.Target.Digest = desc.Digest event.Target.Digest = desc.Digest
if b.manfiestLayers {
event.Target.Layers = append(event.Target.Layers, manifest.References()...)
}
ref, err := reference.WithDigest(repo, event.Target.Digest) ref, err := reference.WithDigest(repo, event.Target.Digest)
if err != nil { if err != nil {

View file

@ -26,9 +26,18 @@ var (
Name: "test", Name: "test",
} }
request = RequestRecord{} request = RequestRecord{}
m = schema1.Manifest{ layers = []schema1.FSLayer{
Name: repo, {
Tag: "latest", BlobSum: "asdf",
},
{
BlobSum: "qwer",
},
}
m = schema1.Manifest{
Name: repo,
Tag: "latest",
FSLayers: layers,
} }
sm *schema1.SignedManifest sm *schema1.SignedManifest
@ -120,7 +129,7 @@ func createTestEnv(t *testing.T, fn testSinkFn) Listener {
payload = sm.Canonical payload = sm.Canonical
dgst = digest.FromBytes(payload) dgst = digest.FromBytes(payload)
return NewBridge(ub, source, actor, request, fn) return NewBridge(ub, source, actor, request, fn, true)
} }
func checkDeleted(t *testing.T, action string, events ...Event) { func checkDeleted(t *testing.T, action string, events ...Event) {
@ -170,6 +179,15 @@ func checkCommonManifest(t *testing.T, action string, events ...Event) {
if event.Target.URL != u { if event.Target.URL != u {
t.Fatalf("incorrect url passed: \n%q != \n%q", event.Target.URL, u) t.Fatalf("incorrect url passed: \n%q != \n%q", event.Target.URL, u)
} }
if len(event.Target.Layers) != len(layers) {
t.Fatalf("unexpected number of layers %v != %v", len(event.Target.Layers), len(layers))
}
for i, layer := range event.Target.Layers {
if layer.Digest != layers[i].BlobSum {
t.Fatalf("unexpected layer: %q != %q", layer.Digest, layers[i].BlobSum)
}
}
} }
func checkCommon(t *testing.T, events ...Event) { func checkCommon(t *testing.T, events ...Event) {

View file

@ -71,6 +71,9 @@ type Event struct {
// Tag provides the tag // Tag provides the tag
Tag string `json:"tag,omitempty"` Tag string `json:"tag,omitempty"`
// Layers provides the layers descriptors.
Layers []distribution.Descriptor `json:"layers,omitempty"`
} `json:"target,omitempty"` } `json:"target,omitempty"`
// Request covers the request that generated the event. // Request covers the request that generated the event.

View file

@ -869,7 +869,7 @@ func (app *App) eventBridge(ctx *Context, r *http.Request) notifications.Listene
} }
request := notifications.NewRequestRecord(dcontext.GetRequestID(ctx), r) request := notifications.NewRequestRecord(dcontext.GetRequestID(ctx), r)
return notifications.NewBridge(ctx.urlBuilder, app.events.source, actor, request, app.events.sink) return notifications.NewBridge(ctx.urlBuilder, app.events.source, actor, request, app.events.sink, app.Config.Notifications.EventConfig.ManifestLayers)
} }
// nameRequired returns true if the route requires a name. // nameRequired returns true if the route requires a name.