forked from TrueCloudLab/distribution
Add configurable layers in manifest events
Signed-off-by: Andrew Leung <anwleung@gmail.com>
This commit is contained in:
parent
749f6afb45
commit
276fdce3d9
9 changed files with 66 additions and 18 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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`
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in a new issue