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:
Stephen J Day 2015-02-03 13:28:10 -08:00
parent 0a29b59e14
commit 080e329cb1
4 changed files with 79 additions and 38 deletions

View file

@ -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

View file

@ -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
}

View file

@ -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.

View file

@ -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