forked from TrueCloudLab/distribution
Separate request data from actor in Event
To clarify the role of actor, the request data that initiates an event has been separated. The ActorRecord is pared down to just the username. This eliminates confusion about where event related data should be added. Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
parent
0a29b59e14
commit
080e329cb1
4 changed files with 79 additions and 38 deletions
|
@ -337,12 +337,10 @@ func (app *App) eventBridge(ctx *Context, r *http.Request) notifications.Listene
|
|||
// addition of user and google context type.
|
||||
actor := notifications.ActorRecord{
|
||||
Name: "--todo--",
|
||||
Addr: r.RemoteAddr,
|
||||
Host: r.Host,
|
||||
RequestID: ctx.RequestID,
|
||||
}
|
||||
request := notifications.NewRequestRecord(ctx.RequestID, r)
|
||||
|
||||
return notifications.NewBridge(ctx.urlBuilder, app.events.source, actor, app.events.sink)
|
||||
return notifications.NewBridge(ctx.urlBuilder, app.events.source, actor, request, app.events.sink)
|
||||
}
|
||||
|
||||
// apiBase implements a simple yes-man for doing overall checks against the
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package notifications
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/manifest"
|
||||
|
@ -14,6 +15,7 @@ type bridge struct {
|
|||
ub URLBuilder
|
||||
actor ActorRecord
|
||||
source SourceRecord
|
||||
request RequestRecord
|
||||
sink Sink
|
||||
}
|
||||
|
||||
|
@ -28,15 +30,29 @@ type URLBuilder interface {
|
|||
// NewBridge returns a notification listener that writes records to sink,
|
||||
// using the actor and source. Any urls populated in the events created by
|
||||
// this bridge will be created using the URLBuilder.
|
||||
func NewBridge(ub URLBuilder, source SourceRecord, actor ActorRecord, sink Sink) Listener {
|
||||
// TODO(stevvooe): Update this to simply take a context.Context object.
|
||||
func NewBridge(ub URLBuilder, source SourceRecord, actor ActorRecord, request RequestRecord, sink Sink) Listener {
|
||||
return &bridge{
|
||||
ub: ub,
|
||||
actor: actor,
|
||||
source: source,
|
||||
request: request,
|
||||
sink: sink,
|
||||
}
|
||||
}
|
||||
|
||||
// NewRequestRecord builds a RequestRecord for use in NewBridge from an
|
||||
// http.Request, associating it with a request id.
|
||||
func NewRequestRecord(id string, r *http.Request) RequestRecord {
|
||||
return RequestRecord{
|
||||
ID: id,
|
||||
Addr: r.RemoteAddr,
|
||||
Host: r.Host,
|
||||
Method: r.Method,
|
||||
UserAgent: r.UserAgent(),
|
||||
}
|
||||
}
|
||||
|
||||
func (b *bridge) ManifestPushed(repo storage.Repository, sm *manifest.SignedManifest) error {
|
||||
return b.createManifestEventAndWrite(EventActionPush, repo, sm)
|
||||
}
|
||||
|
@ -125,6 +141,7 @@ func (b *bridge) createEvent(action string) *Event {
|
|||
event := createEvent(action)
|
||||
event.Source = b.source
|
||||
event.Actor = b.actor
|
||||
event.Request = b.request
|
||||
|
||||
return event
|
||||
}
|
||||
|
|
|
@ -67,6 +67,9 @@ type Event struct {
|
|||
URL string `json:"url,omitempty"`
|
||||
} `json:"target,omitempty"`
|
||||
|
||||
// Request covers the request that generated the event.
|
||||
Request RequestRecord `json:"request,omitempty"`
|
||||
|
||||
// Actor specifies the agent that initiated the event. For most
|
||||
// situations, this could be from the authorizaton context of the request.
|
||||
Actor ActorRecord `json:"actor,omitempty"`
|
||||
|
@ -86,18 +89,6 @@ type ActorRecord struct {
|
|||
// request context that generated the event.
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// Addr contains the ip or hostname and possibly port of the client
|
||||
// connection that initiated the event.
|
||||
Addr string `json:"addr,omitempty"`
|
||||
|
||||
// Host is the externally accessible host name of the registry instance,
|
||||
// as specified by the http host header on incoming requests.
|
||||
Host string `json:"host,omitempty"`
|
||||
|
||||
// RequestID uniquely identifies the registry request that generated the
|
||||
// event.
|
||||
RequestID string `json:"requestID,omitempty"`
|
||||
|
||||
// TODO(stevvooe): Look into setting a session cookie to get this
|
||||
// without docker daemon.
|
||||
// SessionID
|
||||
|
@ -107,6 +98,27 @@ type ActorRecord struct {
|
|||
// Command
|
||||
}
|
||||
|
||||
// RequestRecord covers the request that generated the event.
|
||||
type RequestRecord struct {
|
||||
// ID uniquely identifies the request that initiated the event.
|
||||
ID string `json:"id"`
|
||||
|
||||
// Addr contains the ip or hostname and possibly port of the client
|
||||
// connection that initiated the event. This is the RemoteAddr from
|
||||
// the standard http request.
|
||||
Addr string `json:"addr,omitempty"`
|
||||
|
||||
// Host is the externally accessible host name of the registry instance,
|
||||
// as specified by the http host header on incoming requests.
|
||||
Host string `json:"host,omitempty"`
|
||||
|
||||
// Method has the request method that generated the event.
|
||||
Method string `json:"method"`
|
||||
|
||||
// UserAgent contains the user agent header of the request.
|
||||
UserAgent string `json:"useragent"`
|
||||
}
|
||||
|
||||
// SourceRecord identifies the registry node that generated the event. Put
|
||||
// differently, while the actor "initiates" the event, the source "generates"
|
||||
// it.
|
||||
|
|
|
@ -25,11 +25,15 @@ func TestEventEnvelopeJSONFormat(t *testing.T) {
|
|||
"tag": "latest",
|
||||
"url": "http://example.com/v2/library/test/manifests/latest"
|
||||
},
|
||||
"actor": {
|
||||
"name": "test-actor",
|
||||
"request": {
|
||||
"id": "asdfasdf",
|
||||
"addr": "client.local",
|
||||
"host": "registrycluster.local",
|
||||
"requestID": "asdfasdf"
|
||||
"method": "PUT",
|
||||
"useragent": "test/0.1"
|
||||
},
|
||||
"actor": {
|
||||
"name": "test-actor"
|
||||
},
|
||||
"source": {
|
||||
"addr": "hostname.local:port"
|
||||
|
@ -45,11 +49,15 @@ func TestEventEnvelopeJSONFormat(t *testing.T) {
|
|||
"digest": "tarsum.v2+sha256:0123456789abcdef1",
|
||||
"url": "http://example.com/v2/library/test/manifests/latest"
|
||||
},
|
||||
"actor": {
|
||||
"name": "test-actor",
|
||||
"request": {
|
||||
"id": "asdfasdf",
|
||||
"addr": "client.local",
|
||||
"host": "registrycluster.local",
|
||||
"requestID": "asdfasdf"
|
||||
"method": "PUT",
|
||||
"useragent": "test/0.1"
|
||||
},
|
||||
"actor": {
|
||||
"name": "test-actor"
|
||||
},
|
||||
"source": {
|
||||
"addr": "hostname.local:port"
|
||||
|
@ -65,11 +73,15 @@ func TestEventEnvelopeJSONFormat(t *testing.T) {
|
|||
"digest": "tarsum.v2+sha256:0123456789abcdef2",
|
||||
"url": "http://example.com/v2/library/test/manifests/latest"
|
||||
},
|
||||
"actor": {
|
||||
"name": "test-actor",
|
||||
"request": {
|
||||
"id": "asdfasdf",
|
||||
"addr": "client.local",
|
||||
"host": "registrycluster.local",
|
||||
"requestID": "asdfasdf"
|
||||
"method": "PUT",
|
||||
"useragent": "test/0.1"
|
||||
},
|
||||
"actor": {
|
||||
"name": "test-actor"
|
||||
},
|
||||
"source": {
|
||||
"addr": "hostname.local:port"
|
||||
|
@ -87,10 +99,12 @@ func TestEventEnvelopeJSONFormat(t *testing.T) {
|
|||
var prototype Event
|
||||
prototype.Action = "push"
|
||||
prototype.Timestamp = tm
|
||||
prototype.Actor.Addr = "client.local"
|
||||
prototype.Actor.Name = "test-actor"
|
||||
prototype.Actor.RequestID = "asdfasdf"
|
||||
prototype.Actor.Host = "registrycluster.local"
|
||||
prototype.Request.ID = "asdfasdf"
|
||||
prototype.Request.Addr = "client.local"
|
||||
prototype.Request.Host = "registrycluster.local"
|
||||
prototype.Request.Method = "PUT"
|
||||
prototype.Request.UserAgent = "test/0.1"
|
||||
prototype.Source.Addr = "hostname.local:port"
|
||||
|
||||
var manifestPush Event
|
||||
|
|
Loading…
Reference in a new issue