events: autogenerate fieldpath filters

To ensure consistent fieldpath matching for events, we generate the
fieldpath matching using protobuf definitions. This is done through a
plugin called "fieldpath" that defines a `Field` method for each type
with the plugin enabled. Generated code handles top-level envelope
fields, as well as deferred serialization for matching any types.

In practice, this means that we can cheaply match events on `topic` and
`namespace`. If we want to match on attributes within the event, we can
use the `event` prefix to address these fields. For example, the
following will match all envelopes that have a field named
`container_id` that has the value `testing`:

```
ctr events "event.container_id==testing"
```

The above will decode the underlying event and check that particular
field. Accordingly, if only `topic` or `namespace` is used, the event
will not be decoded and only match on the envelope.

Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
Stephen J Day
2017-07-31 19:14:39 -07:00
parent bb7b41ad7b
commit c857ba2d0b
24 changed files with 1005 additions and 215 deletions

View File

@@ -1,12 +1,9 @@
package typeurl
import (
"fmt"
"path/filepath"
"reflect"
"testing"
eventsapi "github.com/containerd/containerd/api/services/events/v1"
)
type test struct {
@@ -106,41 +103,6 @@ func TestIs(t *testing.T) {
}
}
func TestMarshalEvent(t *testing.T) {
for _, testcase := range []struct {
event interface{}
url string
}{
{
event: &eventsapi.TaskStart{},
url: "types.containerd.io/containerd.services.events.v1.TaskStart",
},
{
event: &eventsapi.NamespaceUpdate{},
url: "types.containerd.io/containerd.services.events.v1.NamespaceUpdate",
},
} {
t.Run(fmt.Sprintf("%T", testcase.event), func(t *testing.T) {
a, err := MarshalAny(testcase.event)
if err != nil {
t.Fatal(err)
}
if a.TypeUrl != testcase.url {
t.Fatalf("unexpected url: %v != %v", a.TypeUrl, testcase.url)
}
v, err := UnmarshalAny(a)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(v, testcase.event) {
t.Fatalf("round trip failed %v != %v", v, testcase.event)
}
})
}
}
func TestRegisterDiffUrls(t *testing.T) {
clear()
defer func() {
@@ -151,20 +113,3 @@ func TestRegisterDiffUrls(t *testing.T) {
Register(&test{}, "test")
Register(&test{}, "test", "two")
}
func BenchmarkMarshalEvent(b *testing.B) {
ev := &eventsapi.TaskStart{}
expected, err := MarshalAny(ev)
if err != nil {
b.Fatal(err)
}
for i := 0; i < b.N; i++ {
a, err := MarshalAny(ev)
if err != nil {
b.Fatal(err)
}
if a.TypeUrl != expected.TypeUrl {
b.Fatalf("incorrect type url: %v != %v", a, expected)
}
}
}