From 333f74d0f812c89d7aa27f8071e7946208d010b0 Mon Sep 17 00:00:00 2001 From: Aaron Lehmann Date: Tue, 24 Jan 2017 18:13:32 -0800 Subject: [PATCH 1/7] Add watch API This is the first part of an external store API. Watch returns a stream of new, updated, or removed objects matching the given selectors. Signed-off-by: Aaron Lehmann --- api/gen.go | 2 +- api/store.pb.go | 3989 +++++++++++++++++++++++++++++++ api/store.proto | 114 + api/types.pb.go | 7 + manager/manager.go | 6 + manager/state/watch.go | 253 +- manager/storeapi/server.go | 17 + manager/storeapi/server_test.go | 118 + manager/storeapi/watch.go | 676 ++++++ manager/storeapi/watch_test.go | 161 ++ 10 files changed, 5335 insertions(+), 8 deletions(-) create mode 100644 api/store.pb.go create mode 100644 api/store.proto create mode 100644 manager/storeapi/server.go create mode 100644 manager/storeapi/server_test.go create mode 100644 manager/storeapi/watch.go create mode 100644 manager/storeapi/watch_test.go diff --git a/api/gen.go b/api/gen.go index 5657931bae..00a8d5d9e2 100644 --- a/api/gen.go +++ b/api/gen.go @@ -1,3 +1,3 @@ package api -//go:generate protoc -I.:../protobuf:../vendor:../vendor/github.com/gogo/protobuf --gogoswarm_out=plugins=grpc+deepcopy+storeobject+raftproxy+authenticatedwrapper,import_path=github.com/docker/swarmkit/api,Mgogoproto/gogo.proto=github.com/gogo/protobuf/gogoproto,Mgoogle/protobuf/descriptor.proto=github.com/gogo/protobuf/protoc-gen-gogo/descriptor,Mplugin/plugin.proto=github.com/docker/swarmkit/protobuf/plugin,Mgoogle/protobuf/duration.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/any.proto=github.com/gogo/protobuf/types:. types.proto specs.proto objects.proto control.proto dispatcher.proto ca.proto snapshot.proto raft.proto health.proto resource.proto logbroker.proto +//go:generate protoc -I.:../protobuf:../vendor:../vendor/github.com/gogo/protobuf --gogoswarm_out=plugins=grpc+deepcopy+storeobject+raftproxy+authenticatedwrapper,import_path=github.com/docker/swarmkit/api,Mgogoproto/gogo.proto=github.com/gogo/protobuf/gogoproto,Mgoogle/protobuf/descriptor.proto=github.com/gogo/protobuf/protoc-gen-gogo/descriptor,Mplugin/plugin.proto=github.com/docker/swarmkit/protobuf/plugin,Mgoogle/protobuf/duration.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/any.proto=github.com/gogo/protobuf/types:. types.proto specs.proto objects.proto control.proto dispatcher.proto ca.proto snapshot.proto raft.proto health.proto resource.proto logbroker.proto store.proto diff --git a/api/store.pb.go b/api/store.pb.go new file mode 100644 index 0000000000..8660ca6b55 --- /dev/null +++ b/api/store.pb.go @@ -0,0 +1,3989 @@ +// Code generated by protoc-gen-gogo. +// source: store.proto +// DO NOT EDIT! + +package api + +import proto "github.com/gogo/protobuf/proto" +import fmt "fmt" +import math "math" +import _ "github.com/gogo/protobuf/gogoproto" +import _ "github.com/docker/swarmkit/protobuf/plugin" + +import github_com_docker_swarmkit_api_deepcopy "github.com/docker/swarmkit/api/deepcopy" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +import raftselector "github.com/docker/swarmkit/manager/raftselector" +import codes "google.golang.org/grpc/codes" +import metadata "google.golang.org/grpc/metadata" +import transport "google.golang.org/grpc/transport" +import rafttime "time" + +import strings "strings" +import reflect "reflect" + +import io "io" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +type Object struct { + // Types that are valid to be assigned to Object: + // *Object_Node + // *Object_Service + // *Object_Network + // *Object_Task + // *Object_Cluster + // *Object_Secret + // *Object_Resource + // *Object_Extension + Object isObject_Object `protobuf_oneof:"Object"` +} + +func (m *Object) Reset() { *m = Object{} } +func (*Object) ProtoMessage() {} +func (*Object) Descriptor() ([]byte, []int) { return fileDescriptorStore, []int{0} } + +type isObject_Object interface { + isObject_Object() + MarshalTo([]byte) (int, error) + Size() int +} + +type Object_Node struct { + Node *Node `protobuf:"bytes,1,opt,name=node,oneof"` +} +type Object_Service struct { + Service *Service `protobuf:"bytes,2,opt,name=service,oneof"` +} +type Object_Network struct { + Network *Network `protobuf:"bytes,3,opt,name=network,oneof"` +} +type Object_Task struct { + Task *Task `protobuf:"bytes,4,opt,name=task,oneof"` +} +type Object_Cluster struct { + Cluster *Cluster `protobuf:"bytes,5,opt,name=cluster,oneof"` +} +type Object_Secret struct { + Secret *Secret `protobuf:"bytes,6,opt,name=secret,oneof"` +} +type Object_Resource struct { + Resource *Resource `protobuf:"bytes,7,opt,name=resource,oneof"` +} +type Object_Extension struct { + Extension *Extension `protobuf:"bytes,8,opt,name=extension,oneof"` +} + +func (*Object_Node) isObject_Object() {} +func (*Object_Service) isObject_Object() {} +func (*Object_Network) isObject_Object() {} +func (*Object_Task) isObject_Object() {} +func (*Object_Cluster) isObject_Object() {} +func (*Object_Secret) isObject_Object() {} +func (*Object_Resource) isObject_Object() {} +func (*Object_Extension) isObject_Object() {} + +func (m *Object) GetObject() isObject_Object { + if m != nil { + return m.Object + } + return nil +} + +func (m *Object) GetNode() *Node { + if x, ok := m.GetObject().(*Object_Node); ok { + return x.Node + } + return nil +} + +func (m *Object) GetService() *Service { + if x, ok := m.GetObject().(*Object_Service); ok { + return x.Service + } + return nil +} + +func (m *Object) GetNetwork() *Network { + if x, ok := m.GetObject().(*Object_Network); ok { + return x.Network + } + return nil +} + +func (m *Object) GetTask() *Task { + if x, ok := m.GetObject().(*Object_Task); ok { + return x.Task + } + return nil +} + +func (m *Object) GetCluster() *Cluster { + if x, ok := m.GetObject().(*Object_Cluster); ok { + return x.Cluster + } + return nil +} + +func (m *Object) GetSecret() *Secret { + if x, ok := m.GetObject().(*Object_Secret); ok { + return x.Secret + } + return nil +} + +func (m *Object) GetResource() *Resource { + if x, ok := m.GetObject().(*Object_Resource); ok { + return x.Resource + } + return nil +} + +func (m *Object) GetExtension() *Extension { + if x, ok := m.GetObject().(*Object_Extension); ok { + return x.Extension + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*Object) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _Object_OneofMarshaler, _Object_OneofUnmarshaler, _Object_OneofSizer, []interface{}{ + (*Object_Node)(nil), + (*Object_Service)(nil), + (*Object_Network)(nil), + (*Object_Task)(nil), + (*Object_Cluster)(nil), + (*Object_Secret)(nil), + (*Object_Resource)(nil), + (*Object_Extension)(nil), + } +} + +func _Object_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*Object) + // Object + switch x := m.Object.(type) { + case *Object_Node: + _ = b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Node); err != nil { + return err + } + case *Object_Service: + _ = b.EncodeVarint(2<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Service); err != nil { + return err + } + case *Object_Network: + _ = b.EncodeVarint(3<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Network); err != nil { + return err + } + case *Object_Task: + _ = b.EncodeVarint(4<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Task); err != nil { + return err + } + case *Object_Cluster: + _ = b.EncodeVarint(5<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Cluster); err != nil { + return err + } + case *Object_Secret: + _ = b.EncodeVarint(6<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Secret); err != nil { + return err + } + case *Object_Resource: + _ = b.EncodeVarint(7<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Resource); err != nil { + return err + } + case *Object_Extension: + _ = b.EncodeVarint(8<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Extension); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("Object.Object has unexpected type %T", x) + } + return nil +} + +func _Object_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*Object) + switch tag { + case 1: // Object.node + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Node) + err := b.DecodeMessage(msg) + m.Object = &Object_Node{msg} + return true, err + case 2: // Object.service + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Service) + err := b.DecodeMessage(msg) + m.Object = &Object_Service{msg} + return true, err + case 3: // Object.network + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Network) + err := b.DecodeMessage(msg) + m.Object = &Object_Network{msg} + return true, err + case 4: // Object.task + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Task) + err := b.DecodeMessage(msg) + m.Object = &Object_Task{msg} + return true, err + case 5: // Object.cluster + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Cluster) + err := b.DecodeMessage(msg) + m.Object = &Object_Cluster{msg} + return true, err + case 6: // Object.secret + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Secret) + err := b.DecodeMessage(msg) + m.Object = &Object_Secret{msg} + return true, err + case 7: // Object.resource + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Resource) + err := b.DecodeMessage(msg) + m.Object = &Object_Resource{msg} + return true, err + case 8: // Object.extension + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Extension) + err := b.DecodeMessage(msg) + m.Object = &Object_Extension{msg} + return true, err + default: + return false, nil + } +} + +func _Object_OneofSizer(msg proto.Message) (n int) { + m := msg.(*Object) + // Object + switch x := m.Object.(type) { + case *Object_Node: + s := proto.Size(x.Node) + n += proto.SizeVarint(1<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *Object_Service: + s := proto.Size(x.Service) + n += proto.SizeVarint(2<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *Object_Network: + s := proto.Size(x.Network) + n += proto.SizeVarint(3<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *Object_Task: + s := proto.Size(x.Task) + n += proto.SizeVarint(4<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *Object_Cluster: + s := proto.Size(x.Cluster) + n += proto.SizeVarint(5<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *Object_Secret: + s := proto.Size(x.Secret) + n += proto.SizeVarint(6<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *Object_Resource: + s := proto.Size(x.Resource) + n += proto.SizeVarint(7<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *Object_Extension: + s := proto.Size(x.Extension) + n += proto.SizeVarint(8<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +// FIXME(aaronl): These messages should ideally be embedded in SelectBy, but +// protoc generates bad code for that. +type SelectBySlot struct { + ServiceID string `protobuf:"bytes,1,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` + Slot uint64 `protobuf:"varint,2,opt,name=slot,proto3" json:"slot,omitempty"` +} + +func (m *SelectBySlot) Reset() { *m = SelectBySlot{} } +func (*SelectBySlot) ProtoMessage() {} +func (*SelectBySlot) Descriptor() ([]byte, []int) { return fileDescriptorStore, []int{1} } + +type SelectByCustom struct { + Kind string `protobuf:"bytes,1,opt,name=kind,proto3" json:"kind,omitempty"` + Index string `protobuf:"bytes,2,opt,name=index,proto3" json:"index,omitempty"` + Value string `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *SelectByCustom) Reset() { *m = SelectByCustom{} } +func (*SelectByCustom) ProtoMessage() {} +func (*SelectByCustom) Descriptor() ([]byte, []int) { return fileDescriptorStore, []int{2} } + +type SelectBy struct { + // TODO(aaronl): Are all of these things we want to expose in + // the API? Exposing them may commit us to maintaining those + // internal indices going forward. + // + // Types that are valid to be assigned to By: + // *SelectBy_ID + // *SelectBy_IDPrefix + // *SelectBy_Name + // *SelectBy_NamePrefix + // *SelectBy_Custom + // *SelectBy_CustomPrefix + // *SelectBy_ServiceID + // *SelectBy_NodeID + // *SelectBy_Slot + // *SelectBy_DesiredState + // *SelectBy_Role + // *SelectBy_Membership + // *SelectBy_ReferencedNetworkID + // *SelectBy_ReferencedSecretID + // *SelectBy_Kind + By isSelectBy_By `protobuf_oneof:"By"` +} + +func (m *SelectBy) Reset() { *m = SelectBy{} } +func (*SelectBy) ProtoMessage() {} +func (*SelectBy) Descriptor() ([]byte, []int) { return fileDescriptorStore, []int{3} } + +type isSelectBy_By interface { + isSelectBy_By() + MarshalTo([]byte) (int, error) + Size() int +} + +type SelectBy_ID struct { + ID string `protobuf:"bytes,1,opt,name=id,proto3,oneof"` +} +type SelectBy_IDPrefix struct { + IDPrefix string `protobuf:"bytes,2,opt,name=id_prefix,json=idPrefix,proto3,oneof"` +} +type SelectBy_Name struct { + Name string `protobuf:"bytes,3,opt,name=name,proto3,oneof"` +} +type SelectBy_NamePrefix struct { + NamePrefix string `protobuf:"bytes,4,opt,name=name_prefix,json=namePrefix,proto3,oneof"` +} +type SelectBy_Custom struct { + Custom *SelectByCustom `protobuf:"bytes,5,opt,name=custom,oneof"` +} +type SelectBy_CustomPrefix struct { + CustomPrefix *SelectByCustom `protobuf:"bytes,6,opt,name=custom_prefix,json=customPrefix,oneof"` +} +type SelectBy_ServiceID struct { + ServiceID string `protobuf:"bytes,7,opt,name=service_id,json=serviceId,proto3,oneof"` +} +type SelectBy_NodeID struct { + NodeID string `protobuf:"bytes,8,opt,name=node_id,json=nodeId,proto3,oneof"` +} +type SelectBy_Slot struct { + Slot *SelectBySlot `protobuf:"bytes,9,opt,name=slot,oneof"` +} +type SelectBy_DesiredState struct { + DesiredState TaskState `protobuf:"varint,10,opt,name=desired_state,json=desiredState,proto3,enum=docker.swarmkit.v1.TaskState,oneof"` +} +type SelectBy_Role struct { + Role NodeRole `protobuf:"varint,11,opt,name=role,proto3,enum=docker.swarmkit.v1.NodeRole,oneof"` +} +type SelectBy_Membership struct { + Membership NodeSpec_Membership `protobuf:"varint,12,opt,name=membership,proto3,enum=docker.swarmkit.v1.NodeSpec_Membership,oneof"` +} +type SelectBy_ReferencedNetworkID struct { + ReferencedNetworkID string `protobuf:"bytes,13,opt,name=referenced_network_id,json=referencedNetworkId,proto3,oneof"` +} +type SelectBy_ReferencedSecretID struct { + ReferencedSecretID string `protobuf:"bytes,14,opt,name=referenced_secret_id,json=referencedSecretId,proto3,oneof"` +} +type SelectBy_Kind struct { + Kind string `protobuf:"bytes,15,opt,name=kind,proto3,oneof"` +} + +func (*SelectBy_ID) isSelectBy_By() {} +func (*SelectBy_IDPrefix) isSelectBy_By() {} +func (*SelectBy_Name) isSelectBy_By() {} +func (*SelectBy_NamePrefix) isSelectBy_By() {} +func (*SelectBy_Custom) isSelectBy_By() {} +func (*SelectBy_CustomPrefix) isSelectBy_By() {} +func (*SelectBy_ServiceID) isSelectBy_By() {} +func (*SelectBy_NodeID) isSelectBy_By() {} +func (*SelectBy_Slot) isSelectBy_By() {} +func (*SelectBy_DesiredState) isSelectBy_By() {} +func (*SelectBy_Role) isSelectBy_By() {} +func (*SelectBy_Membership) isSelectBy_By() {} +func (*SelectBy_ReferencedNetworkID) isSelectBy_By() {} +func (*SelectBy_ReferencedSecretID) isSelectBy_By() {} +func (*SelectBy_Kind) isSelectBy_By() {} + +func (m *SelectBy) GetBy() isSelectBy_By { + if m != nil { + return m.By + } + return nil +} + +func (m *SelectBy) GetID() string { + if x, ok := m.GetBy().(*SelectBy_ID); ok { + return x.ID + } + return "" +} + +func (m *SelectBy) GetIDPrefix() string { + if x, ok := m.GetBy().(*SelectBy_IDPrefix); ok { + return x.IDPrefix + } + return "" +} + +func (m *SelectBy) GetName() string { + if x, ok := m.GetBy().(*SelectBy_Name); ok { + return x.Name + } + return "" +} + +func (m *SelectBy) GetNamePrefix() string { + if x, ok := m.GetBy().(*SelectBy_NamePrefix); ok { + return x.NamePrefix + } + return "" +} + +func (m *SelectBy) GetCustom() *SelectByCustom { + if x, ok := m.GetBy().(*SelectBy_Custom); ok { + return x.Custom + } + return nil +} + +func (m *SelectBy) GetCustomPrefix() *SelectByCustom { + if x, ok := m.GetBy().(*SelectBy_CustomPrefix); ok { + return x.CustomPrefix + } + return nil +} + +func (m *SelectBy) GetServiceID() string { + if x, ok := m.GetBy().(*SelectBy_ServiceID); ok { + return x.ServiceID + } + return "" +} + +func (m *SelectBy) GetNodeID() string { + if x, ok := m.GetBy().(*SelectBy_NodeID); ok { + return x.NodeID + } + return "" +} + +func (m *SelectBy) GetSlot() *SelectBySlot { + if x, ok := m.GetBy().(*SelectBy_Slot); ok { + return x.Slot + } + return nil +} + +func (m *SelectBy) GetDesiredState() TaskState { + if x, ok := m.GetBy().(*SelectBy_DesiredState); ok { + return x.DesiredState + } + return TaskStateNew +} + +func (m *SelectBy) GetRole() NodeRole { + if x, ok := m.GetBy().(*SelectBy_Role); ok { + return x.Role + } + return NodeRoleWorker +} + +func (m *SelectBy) GetMembership() NodeSpec_Membership { + if x, ok := m.GetBy().(*SelectBy_Membership); ok { + return x.Membership + } + return NodeMembershipPending +} + +func (m *SelectBy) GetReferencedNetworkID() string { + if x, ok := m.GetBy().(*SelectBy_ReferencedNetworkID); ok { + return x.ReferencedNetworkID + } + return "" +} + +func (m *SelectBy) GetReferencedSecretID() string { + if x, ok := m.GetBy().(*SelectBy_ReferencedSecretID); ok { + return x.ReferencedSecretID + } + return "" +} + +func (m *SelectBy) GetKind() string { + if x, ok := m.GetBy().(*SelectBy_Kind); ok { + return x.Kind + } + return "" +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*SelectBy) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _SelectBy_OneofMarshaler, _SelectBy_OneofUnmarshaler, _SelectBy_OneofSizer, []interface{}{ + (*SelectBy_ID)(nil), + (*SelectBy_IDPrefix)(nil), + (*SelectBy_Name)(nil), + (*SelectBy_NamePrefix)(nil), + (*SelectBy_Custom)(nil), + (*SelectBy_CustomPrefix)(nil), + (*SelectBy_ServiceID)(nil), + (*SelectBy_NodeID)(nil), + (*SelectBy_Slot)(nil), + (*SelectBy_DesiredState)(nil), + (*SelectBy_Role)(nil), + (*SelectBy_Membership)(nil), + (*SelectBy_ReferencedNetworkID)(nil), + (*SelectBy_ReferencedSecretID)(nil), + (*SelectBy_Kind)(nil), + } +} + +func _SelectBy_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*SelectBy) + // By + switch x := m.By.(type) { + case *SelectBy_ID: + _ = b.EncodeVarint(1<<3 | proto.WireBytes) + _ = b.EncodeStringBytes(x.ID) + case *SelectBy_IDPrefix: + _ = b.EncodeVarint(2<<3 | proto.WireBytes) + _ = b.EncodeStringBytes(x.IDPrefix) + case *SelectBy_Name: + _ = b.EncodeVarint(3<<3 | proto.WireBytes) + _ = b.EncodeStringBytes(x.Name) + case *SelectBy_NamePrefix: + _ = b.EncodeVarint(4<<3 | proto.WireBytes) + _ = b.EncodeStringBytes(x.NamePrefix) + case *SelectBy_Custom: + _ = b.EncodeVarint(5<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Custom); err != nil { + return err + } + case *SelectBy_CustomPrefix: + _ = b.EncodeVarint(6<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.CustomPrefix); err != nil { + return err + } + case *SelectBy_ServiceID: + _ = b.EncodeVarint(7<<3 | proto.WireBytes) + _ = b.EncodeStringBytes(x.ServiceID) + case *SelectBy_NodeID: + _ = b.EncodeVarint(8<<3 | proto.WireBytes) + _ = b.EncodeStringBytes(x.NodeID) + case *SelectBy_Slot: + _ = b.EncodeVarint(9<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Slot); err != nil { + return err + } + case *SelectBy_DesiredState: + _ = b.EncodeVarint(10<<3 | proto.WireVarint) + _ = b.EncodeVarint(uint64(x.DesiredState)) + case *SelectBy_Role: + _ = b.EncodeVarint(11<<3 | proto.WireVarint) + _ = b.EncodeVarint(uint64(x.Role)) + case *SelectBy_Membership: + _ = b.EncodeVarint(12<<3 | proto.WireVarint) + _ = b.EncodeVarint(uint64(x.Membership)) + case *SelectBy_ReferencedNetworkID: + _ = b.EncodeVarint(13<<3 | proto.WireBytes) + _ = b.EncodeStringBytes(x.ReferencedNetworkID) + case *SelectBy_ReferencedSecretID: + _ = b.EncodeVarint(14<<3 | proto.WireBytes) + _ = b.EncodeStringBytes(x.ReferencedSecretID) + case *SelectBy_Kind: + _ = b.EncodeVarint(15<<3 | proto.WireBytes) + _ = b.EncodeStringBytes(x.Kind) + case nil: + default: + return fmt.Errorf("SelectBy.By has unexpected type %T", x) + } + return nil +} + +func _SelectBy_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*SelectBy) + switch tag { + case 1: // By.id + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.By = &SelectBy_ID{x} + return true, err + case 2: // By.id_prefix + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.By = &SelectBy_IDPrefix{x} + return true, err + case 3: // By.name + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.By = &SelectBy_Name{x} + return true, err + case 4: // By.name_prefix + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.By = &SelectBy_NamePrefix{x} + return true, err + case 5: // By.custom + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(SelectByCustom) + err := b.DecodeMessage(msg) + m.By = &SelectBy_Custom{msg} + return true, err + case 6: // By.custom_prefix + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(SelectByCustom) + err := b.DecodeMessage(msg) + m.By = &SelectBy_CustomPrefix{msg} + return true, err + case 7: // By.service_id + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.By = &SelectBy_ServiceID{x} + return true, err + case 8: // By.node_id + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.By = &SelectBy_NodeID{x} + return true, err + case 9: // By.slot + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(SelectBySlot) + err := b.DecodeMessage(msg) + m.By = &SelectBy_Slot{msg} + return true, err + case 10: // By.desired_state + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.By = &SelectBy_DesiredState{TaskState(x)} + return true, err + case 11: // By.role + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.By = &SelectBy_Role{NodeRole(x)} + return true, err + case 12: // By.membership + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.By = &SelectBy_Membership{NodeSpec_Membership(x)} + return true, err + case 13: // By.referenced_network_id + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.By = &SelectBy_ReferencedNetworkID{x} + return true, err + case 14: // By.referenced_secret_id + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.By = &SelectBy_ReferencedSecretID{x} + return true, err + case 15: // By.kind + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.By = &SelectBy_Kind{x} + return true, err + default: + return false, nil + } +} + +func _SelectBy_OneofSizer(msg proto.Message) (n int) { + m := msg.(*SelectBy) + // By + switch x := m.By.(type) { + case *SelectBy_ID: + n += proto.SizeVarint(1<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(len(x.ID))) + n += len(x.ID) + case *SelectBy_IDPrefix: + n += proto.SizeVarint(2<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(len(x.IDPrefix))) + n += len(x.IDPrefix) + case *SelectBy_Name: + n += proto.SizeVarint(3<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(len(x.Name))) + n += len(x.Name) + case *SelectBy_NamePrefix: + n += proto.SizeVarint(4<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(len(x.NamePrefix))) + n += len(x.NamePrefix) + case *SelectBy_Custom: + s := proto.Size(x.Custom) + n += proto.SizeVarint(5<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *SelectBy_CustomPrefix: + s := proto.Size(x.CustomPrefix) + n += proto.SizeVarint(6<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *SelectBy_ServiceID: + n += proto.SizeVarint(7<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(len(x.ServiceID))) + n += len(x.ServiceID) + case *SelectBy_NodeID: + n += proto.SizeVarint(8<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(len(x.NodeID))) + n += len(x.NodeID) + case *SelectBy_Slot: + s := proto.Size(x.Slot) + n += proto.SizeVarint(9<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *SelectBy_DesiredState: + n += proto.SizeVarint(10<<3 | proto.WireVarint) + n += proto.SizeVarint(uint64(x.DesiredState)) + case *SelectBy_Role: + n += proto.SizeVarint(11<<3 | proto.WireVarint) + n += proto.SizeVarint(uint64(x.Role)) + case *SelectBy_Membership: + n += proto.SizeVarint(12<<3 | proto.WireVarint) + n += proto.SizeVarint(uint64(x.Membership)) + case *SelectBy_ReferencedNetworkID: + n += proto.SizeVarint(13<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(len(x.ReferencedNetworkID))) + n += len(x.ReferencedNetworkID) + case *SelectBy_ReferencedSecretID: + n += proto.SizeVarint(14<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(len(x.ReferencedSecretID))) + n += len(x.ReferencedSecretID) + case *SelectBy_Kind: + n += proto.SizeVarint(15<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(len(x.Kind))) + n += len(x.Kind) + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +type WatchRequest struct { + // Multiple entries are combined using OR logic - i.e. if an event + // matches all of the selectors specified in any single watch entry, + // the event will be sent to the client. + Entries []*WatchRequest_WatchEntry `protobuf:"bytes,1,rep,name=entries" json:"entries,omitempty"` +} + +func (m *WatchRequest) Reset() { *m = WatchRequest{} } +func (*WatchRequest) ProtoMessage() {} +func (*WatchRequest) Descriptor() ([]byte, []int) { return fileDescriptorStore, []int{4} } + +type WatchRequest_WatchEntry struct { + // Kind can contain a builtin type such as "node", "secret", etc. or + // the kind specified by a custom-defined object. + Kind string `protobuf:"bytes,1,opt,name=kind,proto3" json:"kind,omitempty"` + // Action (create/update/delete) + Action StoreActionKind `protobuf:"varint,2,opt,name=action,proto3,enum=docker.swarmkit.v1.StoreActionKind" json:"action,omitempty"` + // Filters are combined using AND logic - an event must match + // all of them to pass the filter. + Filters []*SelectBy `protobuf:"bytes,3,rep,name=filters" json:"filters,omitempty"` +} + +func (m *WatchRequest_WatchEntry) Reset() { *m = WatchRequest_WatchEntry{} } +func (*WatchRequest_WatchEntry) ProtoMessage() {} +func (*WatchRequest_WatchEntry) Descriptor() ([]byte, []int) { return fileDescriptorStore, []int{4, 0} } + +// WatchMessage is the type of the stream that's returned to the client by +// Watch. Note that the first item of this stream will always be a WatchMessage +// with a nil Object, to signal that the stream has started. +type WatchMessage struct { + // Action (create/update/delete) + // Note that WatchMessage does not expose "commit" events that mark + // transaction boundaries. + Action StoreActionKind `protobuf:"varint,1,opt,name=action,proto3,enum=docker.swarmkit.v1.StoreActionKind" json:"action,omitempty"` + // Matched object + Object *Object `protobuf:"bytes,2,opt,name=object" json:"object,omitempty"` +} + +func (m *WatchMessage) Reset() { *m = WatchMessage{} } +func (*WatchMessage) ProtoMessage() {} +func (*WatchMessage) Descriptor() ([]byte, []int) { return fileDescriptorStore, []int{5} } + +func init() { + proto.RegisterType((*Object)(nil), "docker.swarmkit.v1.Object") + proto.RegisterType((*SelectBySlot)(nil), "docker.swarmkit.v1.SelectBySlot") + proto.RegisterType((*SelectByCustom)(nil), "docker.swarmkit.v1.SelectByCustom") + proto.RegisterType((*SelectBy)(nil), "docker.swarmkit.v1.SelectBy") + proto.RegisterType((*WatchRequest)(nil), "docker.swarmkit.v1.WatchRequest") + proto.RegisterType((*WatchRequest_WatchEntry)(nil), "docker.swarmkit.v1.WatchRequest.WatchEntry") + proto.RegisterType((*WatchMessage)(nil), "docker.swarmkit.v1.WatchMessage") +} + +type authenticatedWrapperStoreServer struct { + local StoreServer + authorize func(context.Context, []string) error +} + +func NewAuthenticatedWrapperStoreServer(local StoreServer, authorize func(context.Context, []string) error) StoreServer { + return &authenticatedWrapperStoreServer{ + local: local, + authorize: authorize, + } +} + +func (p *authenticatedWrapperStoreServer) Watch(r *WatchRequest, stream Store_WatchServer) error { + + if err := p.authorize(stream.Context(), []string{"swarm-manager"}); err != nil { + return err + } + return p.local.Watch(r, stream) +} + +func (m *Object) Copy() *Object { + if m == nil { + return nil + } + o := &Object{} + o.CopyFrom(m) + return o +} + +func (m *Object) CopyFrom(src interface{}) { + + o := src.(*Object) + *m = *o + if o.Object != nil { + switch o.Object.(type) { + case *Object_Node: + v := Object_Node{ + Node: &Node{}, + } + github_com_docker_swarmkit_api_deepcopy.Copy(v.Node, o.GetNode()) + m.Object = &v + case *Object_Service: + v := Object_Service{ + Service: &Service{}, + } + github_com_docker_swarmkit_api_deepcopy.Copy(v.Service, o.GetService()) + m.Object = &v + case *Object_Network: + v := Object_Network{ + Network: &Network{}, + } + github_com_docker_swarmkit_api_deepcopy.Copy(v.Network, o.GetNetwork()) + m.Object = &v + case *Object_Task: + v := Object_Task{ + Task: &Task{}, + } + github_com_docker_swarmkit_api_deepcopy.Copy(v.Task, o.GetTask()) + m.Object = &v + case *Object_Cluster: + v := Object_Cluster{ + Cluster: &Cluster{}, + } + github_com_docker_swarmkit_api_deepcopy.Copy(v.Cluster, o.GetCluster()) + m.Object = &v + case *Object_Secret: + v := Object_Secret{ + Secret: &Secret{}, + } + github_com_docker_swarmkit_api_deepcopy.Copy(v.Secret, o.GetSecret()) + m.Object = &v + case *Object_Resource: + v := Object_Resource{ + Resource: &Resource{}, + } + github_com_docker_swarmkit_api_deepcopy.Copy(v.Resource, o.GetResource()) + m.Object = &v + case *Object_Extension: + v := Object_Extension{ + Extension: &Extension{}, + } + github_com_docker_swarmkit_api_deepcopy.Copy(v.Extension, o.GetExtension()) + m.Object = &v + } + } + +} + +func (m *SelectBySlot) Copy() *SelectBySlot { + if m == nil { + return nil + } + o := &SelectBySlot{} + o.CopyFrom(m) + return o +} + +func (m *SelectBySlot) CopyFrom(src interface{}) { + + o := src.(*SelectBySlot) + *m = *o +} + +func (m *SelectByCustom) Copy() *SelectByCustom { + if m == nil { + return nil + } + o := &SelectByCustom{} + o.CopyFrom(m) + return o +} + +func (m *SelectByCustom) CopyFrom(src interface{}) { + + o := src.(*SelectByCustom) + *m = *o +} + +func (m *SelectBy) Copy() *SelectBy { + if m == nil { + return nil + } + o := &SelectBy{} + o.CopyFrom(m) + return o +} + +func (m *SelectBy) CopyFrom(src interface{}) { + + o := src.(*SelectBy) + *m = *o + if o.By != nil { + switch o.By.(type) { + case *SelectBy_ID: + v := SelectBy_ID{ + ID: o.GetID(), + } + m.By = &v + case *SelectBy_IDPrefix: + v := SelectBy_IDPrefix{ + IDPrefix: o.GetIDPrefix(), + } + m.By = &v + case *SelectBy_Name: + v := SelectBy_Name{ + Name: o.GetName(), + } + m.By = &v + case *SelectBy_NamePrefix: + v := SelectBy_NamePrefix{ + NamePrefix: o.GetNamePrefix(), + } + m.By = &v + case *SelectBy_Custom: + v := SelectBy_Custom{ + Custom: &SelectByCustom{}, + } + github_com_docker_swarmkit_api_deepcopy.Copy(v.Custom, o.GetCustom()) + m.By = &v + case *SelectBy_CustomPrefix: + v := SelectBy_CustomPrefix{ + CustomPrefix: &SelectByCustom{}, + } + github_com_docker_swarmkit_api_deepcopy.Copy(v.CustomPrefix, o.GetCustomPrefix()) + m.By = &v + case *SelectBy_ServiceID: + v := SelectBy_ServiceID{ + ServiceID: o.GetServiceID(), + } + m.By = &v + case *SelectBy_NodeID: + v := SelectBy_NodeID{ + NodeID: o.GetNodeID(), + } + m.By = &v + case *SelectBy_Slot: + v := SelectBy_Slot{ + Slot: &SelectBySlot{}, + } + github_com_docker_swarmkit_api_deepcopy.Copy(v.Slot, o.GetSlot()) + m.By = &v + case *SelectBy_DesiredState: + v := SelectBy_DesiredState{ + DesiredState: o.GetDesiredState(), + } + m.By = &v + case *SelectBy_Role: + v := SelectBy_Role{ + Role: o.GetRole(), + } + m.By = &v + case *SelectBy_Membership: + v := SelectBy_Membership{ + Membership: o.GetMembership(), + } + m.By = &v + case *SelectBy_ReferencedNetworkID: + v := SelectBy_ReferencedNetworkID{ + ReferencedNetworkID: o.GetReferencedNetworkID(), + } + m.By = &v + case *SelectBy_ReferencedSecretID: + v := SelectBy_ReferencedSecretID{ + ReferencedSecretID: o.GetReferencedSecretID(), + } + m.By = &v + case *SelectBy_Kind: + v := SelectBy_Kind{ + Kind: o.GetKind(), + } + m.By = &v + } + } + +} + +func (m *WatchRequest) Copy() *WatchRequest { + if m == nil { + return nil + } + o := &WatchRequest{} + o.CopyFrom(m) + return o +} + +func (m *WatchRequest) CopyFrom(src interface{}) { + + o := src.(*WatchRequest) + *m = *o + if o.Entries != nil { + m.Entries = make([]*WatchRequest_WatchEntry, len(o.Entries)) + for i := range m.Entries { + m.Entries[i] = &WatchRequest_WatchEntry{} + github_com_docker_swarmkit_api_deepcopy.Copy(m.Entries[i], o.Entries[i]) + } + } + +} + +func (m *WatchRequest_WatchEntry) Copy() *WatchRequest_WatchEntry { + if m == nil { + return nil + } + o := &WatchRequest_WatchEntry{} + o.CopyFrom(m) + return o +} + +func (m *WatchRequest_WatchEntry) CopyFrom(src interface{}) { + + o := src.(*WatchRequest_WatchEntry) + *m = *o + if o.Filters != nil { + m.Filters = make([]*SelectBy, len(o.Filters)) + for i := range m.Filters { + m.Filters[i] = &SelectBy{} + github_com_docker_swarmkit_api_deepcopy.Copy(m.Filters[i], o.Filters[i]) + } + } + +} + +func (m *WatchMessage) Copy() *WatchMessage { + if m == nil { + return nil + } + o := &WatchMessage{} + o.CopyFrom(m) + return o +} + +func (m *WatchMessage) CopyFrom(src interface{}) { + + o := src.(*WatchMessage) + *m = *o + if o.Object != nil { + m.Object = &Object{} + github_com_docker_swarmkit_api_deepcopy.Copy(m.Object, o.Object) + } +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for Store service + +type StoreClient interface { + // Watch starts a stream that returns any changes to objects that match + // the specified selectors. When the stream begins, it immediately sends + // an empty message back to the client. It is important to wait for + // this message before taking any actions that depend on an established + // stream of changes for consistency. + Watch(ctx context.Context, in *WatchRequest, opts ...grpc.CallOption) (Store_WatchClient, error) +} + +type storeClient struct { + cc *grpc.ClientConn +} + +func NewStoreClient(cc *grpc.ClientConn) StoreClient { + return &storeClient{cc} +} + +func (c *storeClient) Watch(ctx context.Context, in *WatchRequest, opts ...grpc.CallOption) (Store_WatchClient, error) { + stream, err := grpc.NewClientStream(ctx, &_Store_serviceDesc.Streams[0], c.cc, "/docker.swarmkit.v1.Store/Watch", opts...) + if err != nil { + return nil, err + } + x := &storeWatchClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type Store_WatchClient interface { + Recv() (*WatchMessage, error) + grpc.ClientStream +} + +type storeWatchClient struct { + grpc.ClientStream +} + +func (x *storeWatchClient) Recv() (*WatchMessage, error) { + m := new(WatchMessage) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// Server API for Store service + +type StoreServer interface { + // Watch starts a stream that returns any changes to objects that match + // the specified selectors. When the stream begins, it immediately sends + // an empty message back to the client. It is important to wait for + // this message before taking any actions that depend on an established + // stream of changes for consistency. + Watch(*WatchRequest, Store_WatchServer) error +} + +func RegisterStoreServer(s *grpc.Server, srv StoreServer) { + s.RegisterService(&_Store_serviceDesc, srv) +} + +func _Store_Watch_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(WatchRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(StoreServer).Watch(m, &storeWatchServer{stream}) +} + +type Store_WatchServer interface { + Send(*WatchMessage) error + grpc.ServerStream +} + +type storeWatchServer struct { + grpc.ServerStream +} + +func (x *storeWatchServer) Send(m *WatchMessage) error { + return x.ServerStream.SendMsg(m) +} + +var _Store_serviceDesc = grpc.ServiceDesc{ + ServiceName: "docker.swarmkit.v1.Store", + HandlerType: (*StoreServer)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "Watch", + Handler: _Store_Watch_Handler, + ServerStreams: true, + }, + }, + Metadata: "store.proto", +} + +func (m *Object) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Object) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Object != nil { + nn1, err := m.Object.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += nn1 + } + return i, nil +} + +func (m *Object_Node) MarshalTo(dAtA []byte) (int, error) { + i := 0 + if m.Node != nil { + dAtA[i] = 0xa + i++ + i = encodeVarintStore(dAtA, i, uint64(m.Node.Size())) + n2, err := m.Node.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n2 + } + return i, nil +} +func (m *Object_Service) MarshalTo(dAtA []byte) (int, error) { + i := 0 + if m.Service != nil { + dAtA[i] = 0x12 + i++ + i = encodeVarintStore(dAtA, i, uint64(m.Service.Size())) + n3, err := m.Service.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n3 + } + return i, nil +} +func (m *Object_Network) MarshalTo(dAtA []byte) (int, error) { + i := 0 + if m.Network != nil { + dAtA[i] = 0x1a + i++ + i = encodeVarintStore(dAtA, i, uint64(m.Network.Size())) + n4, err := m.Network.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n4 + } + return i, nil +} +func (m *Object_Task) MarshalTo(dAtA []byte) (int, error) { + i := 0 + if m.Task != nil { + dAtA[i] = 0x22 + i++ + i = encodeVarintStore(dAtA, i, uint64(m.Task.Size())) + n5, err := m.Task.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n5 + } + return i, nil +} +func (m *Object_Cluster) MarshalTo(dAtA []byte) (int, error) { + i := 0 + if m.Cluster != nil { + dAtA[i] = 0x2a + i++ + i = encodeVarintStore(dAtA, i, uint64(m.Cluster.Size())) + n6, err := m.Cluster.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n6 + } + return i, nil +} +func (m *Object_Secret) MarshalTo(dAtA []byte) (int, error) { + i := 0 + if m.Secret != nil { + dAtA[i] = 0x32 + i++ + i = encodeVarintStore(dAtA, i, uint64(m.Secret.Size())) + n7, err := m.Secret.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n7 + } + return i, nil +} +func (m *Object_Resource) MarshalTo(dAtA []byte) (int, error) { + i := 0 + if m.Resource != nil { + dAtA[i] = 0x3a + i++ + i = encodeVarintStore(dAtA, i, uint64(m.Resource.Size())) + n8, err := m.Resource.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n8 + } + return i, nil +} +func (m *Object_Extension) MarshalTo(dAtA []byte) (int, error) { + i := 0 + if m.Extension != nil { + dAtA[i] = 0x42 + i++ + i = encodeVarintStore(dAtA, i, uint64(m.Extension.Size())) + n9, err := m.Extension.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n9 + } + return i, nil +} +func (m *SelectBySlot) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SelectBySlot) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.ServiceID) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintStore(dAtA, i, uint64(len(m.ServiceID))) + i += copy(dAtA[i:], m.ServiceID) + } + if m.Slot != 0 { + dAtA[i] = 0x10 + i++ + i = encodeVarintStore(dAtA, i, uint64(m.Slot)) + } + return i, nil +} + +func (m *SelectByCustom) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SelectByCustom) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Kind) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintStore(dAtA, i, uint64(len(m.Kind))) + i += copy(dAtA[i:], m.Kind) + } + if len(m.Index) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintStore(dAtA, i, uint64(len(m.Index))) + i += copy(dAtA[i:], m.Index) + } + if len(m.Value) > 0 { + dAtA[i] = 0x1a + i++ + i = encodeVarintStore(dAtA, i, uint64(len(m.Value))) + i += copy(dAtA[i:], m.Value) + } + return i, nil +} + +func (m *SelectBy) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SelectBy) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.By != nil { + nn10, err := m.By.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += nn10 + } + return i, nil +} + +func (m *SelectBy_ID) MarshalTo(dAtA []byte) (int, error) { + i := 0 + dAtA[i] = 0xa + i++ + i = encodeVarintStore(dAtA, i, uint64(len(m.ID))) + i += copy(dAtA[i:], m.ID) + return i, nil +} +func (m *SelectBy_IDPrefix) MarshalTo(dAtA []byte) (int, error) { + i := 0 + dAtA[i] = 0x12 + i++ + i = encodeVarintStore(dAtA, i, uint64(len(m.IDPrefix))) + i += copy(dAtA[i:], m.IDPrefix) + return i, nil +} +func (m *SelectBy_Name) MarshalTo(dAtA []byte) (int, error) { + i := 0 + dAtA[i] = 0x1a + i++ + i = encodeVarintStore(dAtA, i, uint64(len(m.Name))) + i += copy(dAtA[i:], m.Name) + return i, nil +} +func (m *SelectBy_NamePrefix) MarshalTo(dAtA []byte) (int, error) { + i := 0 + dAtA[i] = 0x22 + i++ + i = encodeVarintStore(dAtA, i, uint64(len(m.NamePrefix))) + i += copy(dAtA[i:], m.NamePrefix) + return i, nil +} +func (m *SelectBy_Custom) MarshalTo(dAtA []byte) (int, error) { + i := 0 + if m.Custom != nil { + dAtA[i] = 0x2a + i++ + i = encodeVarintStore(dAtA, i, uint64(m.Custom.Size())) + n11, err := m.Custom.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n11 + } + return i, nil +} +func (m *SelectBy_CustomPrefix) MarshalTo(dAtA []byte) (int, error) { + i := 0 + if m.CustomPrefix != nil { + dAtA[i] = 0x32 + i++ + i = encodeVarintStore(dAtA, i, uint64(m.CustomPrefix.Size())) + n12, err := m.CustomPrefix.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n12 + } + return i, nil +} +func (m *SelectBy_ServiceID) MarshalTo(dAtA []byte) (int, error) { + i := 0 + dAtA[i] = 0x3a + i++ + i = encodeVarintStore(dAtA, i, uint64(len(m.ServiceID))) + i += copy(dAtA[i:], m.ServiceID) + return i, nil +} +func (m *SelectBy_NodeID) MarshalTo(dAtA []byte) (int, error) { + i := 0 + dAtA[i] = 0x42 + i++ + i = encodeVarintStore(dAtA, i, uint64(len(m.NodeID))) + i += copy(dAtA[i:], m.NodeID) + return i, nil +} +func (m *SelectBy_Slot) MarshalTo(dAtA []byte) (int, error) { + i := 0 + if m.Slot != nil { + dAtA[i] = 0x4a + i++ + i = encodeVarintStore(dAtA, i, uint64(m.Slot.Size())) + n13, err := m.Slot.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n13 + } + return i, nil +} +func (m *SelectBy_DesiredState) MarshalTo(dAtA []byte) (int, error) { + i := 0 + dAtA[i] = 0x50 + i++ + i = encodeVarintStore(dAtA, i, uint64(m.DesiredState)) + return i, nil +} +func (m *SelectBy_Role) MarshalTo(dAtA []byte) (int, error) { + i := 0 + dAtA[i] = 0x58 + i++ + i = encodeVarintStore(dAtA, i, uint64(m.Role)) + return i, nil +} +func (m *SelectBy_Membership) MarshalTo(dAtA []byte) (int, error) { + i := 0 + dAtA[i] = 0x60 + i++ + i = encodeVarintStore(dAtA, i, uint64(m.Membership)) + return i, nil +} +func (m *SelectBy_ReferencedNetworkID) MarshalTo(dAtA []byte) (int, error) { + i := 0 + dAtA[i] = 0x6a + i++ + i = encodeVarintStore(dAtA, i, uint64(len(m.ReferencedNetworkID))) + i += copy(dAtA[i:], m.ReferencedNetworkID) + return i, nil +} +func (m *SelectBy_ReferencedSecretID) MarshalTo(dAtA []byte) (int, error) { + i := 0 + dAtA[i] = 0x72 + i++ + i = encodeVarintStore(dAtA, i, uint64(len(m.ReferencedSecretID))) + i += copy(dAtA[i:], m.ReferencedSecretID) + return i, nil +} +func (m *SelectBy_Kind) MarshalTo(dAtA []byte) (int, error) { + i := 0 + dAtA[i] = 0x7a + i++ + i = encodeVarintStore(dAtA, i, uint64(len(m.Kind))) + i += copy(dAtA[i:], m.Kind) + return i, nil +} +func (m *WatchRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *WatchRequest) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Entries) > 0 { + for _, msg := range m.Entries { + dAtA[i] = 0xa + i++ + i = encodeVarintStore(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n + } + } + return i, nil +} + +func (m *WatchRequest_WatchEntry) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *WatchRequest_WatchEntry) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Kind) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintStore(dAtA, i, uint64(len(m.Kind))) + i += copy(dAtA[i:], m.Kind) + } + if m.Action != 0 { + dAtA[i] = 0x10 + i++ + i = encodeVarintStore(dAtA, i, uint64(m.Action)) + } + if len(m.Filters) > 0 { + for _, msg := range m.Filters { + dAtA[i] = 0x1a + i++ + i = encodeVarintStore(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n + } + } + return i, nil +} + +func (m *WatchMessage) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *WatchMessage) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Action != 0 { + dAtA[i] = 0x8 + i++ + i = encodeVarintStore(dAtA, i, uint64(m.Action)) + } + if m.Object != nil { + dAtA[i] = 0x12 + i++ + i = encodeVarintStore(dAtA, i, uint64(m.Object.Size())) + n14, err := m.Object.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n14 + } + return i, nil +} + +func encodeFixed64Store(dAtA []byte, offset int, v uint64) int { + dAtA[offset] = uint8(v) + dAtA[offset+1] = uint8(v >> 8) + dAtA[offset+2] = uint8(v >> 16) + dAtA[offset+3] = uint8(v >> 24) + dAtA[offset+4] = uint8(v >> 32) + dAtA[offset+5] = uint8(v >> 40) + dAtA[offset+6] = uint8(v >> 48) + dAtA[offset+7] = uint8(v >> 56) + return offset + 8 +} +func encodeFixed32Store(dAtA []byte, offset int, v uint32) int { + dAtA[offset] = uint8(v) + dAtA[offset+1] = uint8(v >> 8) + dAtA[offset+2] = uint8(v >> 16) + dAtA[offset+3] = uint8(v >> 24) + return offset + 4 +} +func encodeVarintStore(dAtA []byte, offset int, v uint64) int { + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return offset + 1 +} + +type raftProxyStoreServer struct { + local StoreServer + connSelector raftselector.ConnProvider + localCtxMods, remoteCtxMods []func(context.Context) (context.Context, error) +} + +func NewRaftProxyStoreServer(local StoreServer, connSelector raftselector.ConnProvider, localCtxMod, remoteCtxMod func(context.Context) (context.Context, error)) StoreServer { + redirectChecker := func(ctx context.Context) (context.Context, error) { + s, ok := transport.StreamFromContext(ctx) + if !ok { + return ctx, grpc.Errorf(codes.InvalidArgument, "remote addr is not found in context") + } + addr := s.ServerTransport().RemoteAddr().String() + md, ok := metadata.FromContext(ctx) + if ok && len(md["redirect"]) != 0 { + return ctx, grpc.Errorf(codes.ResourceExhausted, "more than one redirect to leader from: %s", md["redirect"]) + } + if !ok { + md = metadata.New(map[string]string{}) + } + md["redirect"] = append(md["redirect"], addr) + return metadata.NewContext(ctx, md), nil + } + remoteMods := []func(context.Context) (context.Context, error){redirectChecker} + remoteMods = append(remoteMods, remoteCtxMod) + + var localMods []func(context.Context) (context.Context, error) + if localCtxMod != nil { + localMods = []func(context.Context) (context.Context, error){localCtxMod} + } + + return &raftProxyStoreServer{ + local: local, + connSelector: connSelector, + localCtxMods: localMods, + remoteCtxMods: remoteMods, + } +} +func (p *raftProxyStoreServer) runCtxMods(ctx context.Context, ctxMods []func(context.Context) (context.Context, error)) (context.Context, error) { + var err error + for _, mod := range ctxMods { + ctx, err = mod(ctx) + if err != nil { + return ctx, err + } + } + return ctx, nil +} +func (p *raftProxyStoreServer) pollNewLeaderConn(ctx context.Context) (*grpc.ClientConn, error) { + ticker := rafttime.NewTicker(500 * rafttime.Millisecond) + defer ticker.Stop() + for { + select { + case <-ticker.C: + conn, err := p.connSelector.LeaderConn(ctx) + if err != nil { + return nil, err + } + + client := NewHealthClient(conn) + + resp, err := client.Check(ctx, &HealthCheckRequest{Service: "Raft"}) + if err != nil || resp.Status != HealthCheckResponse_SERVING { + continue + } + return conn, nil + case <-ctx.Done(): + return nil, ctx.Err() + } + } +} + +type Store_WatchServerWrapper struct { + Store_WatchServer + ctx context.Context +} + +func (s Store_WatchServerWrapper) Context() context.Context { + return s.ctx +} + +func (p *raftProxyStoreServer) Watch(r *WatchRequest, stream Store_WatchServer) error { + ctx := stream.Context() + conn, err := p.connSelector.LeaderConn(ctx) + if err != nil { + if err == raftselector.ErrIsLeader { + ctx, err = p.runCtxMods(ctx, p.localCtxMods) + if err != nil { + return err + } + streamWrapper := Store_WatchServerWrapper{ + Store_WatchServer: stream, + ctx: ctx, + } + return p.local.Watch(r, streamWrapper) + } + return err + } + ctx, err = p.runCtxMods(ctx, p.remoteCtxMods) + if err != nil { + return err + } + clientStream, err := NewStoreClient(conn).Watch(ctx, r) + + if err != nil { + return err + } + + for { + msg, err := clientStream.Recv() + if err == io.EOF { + break + } + if err != nil { + return err + } + if err := stream.Send(msg); err != nil { + return err + } + } + return nil +} + +func (m *Object) Size() (n int) { + var l int + _ = l + if m.Object != nil { + n += m.Object.Size() + } + return n +} + +func (m *Object_Node) Size() (n int) { + var l int + _ = l + if m.Node != nil { + l = m.Node.Size() + n += 1 + l + sovStore(uint64(l)) + } + return n +} +func (m *Object_Service) Size() (n int) { + var l int + _ = l + if m.Service != nil { + l = m.Service.Size() + n += 1 + l + sovStore(uint64(l)) + } + return n +} +func (m *Object_Network) Size() (n int) { + var l int + _ = l + if m.Network != nil { + l = m.Network.Size() + n += 1 + l + sovStore(uint64(l)) + } + return n +} +func (m *Object_Task) Size() (n int) { + var l int + _ = l + if m.Task != nil { + l = m.Task.Size() + n += 1 + l + sovStore(uint64(l)) + } + return n +} +func (m *Object_Cluster) Size() (n int) { + var l int + _ = l + if m.Cluster != nil { + l = m.Cluster.Size() + n += 1 + l + sovStore(uint64(l)) + } + return n +} +func (m *Object_Secret) Size() (n int) { + var l int + _ = l + if m.Secret != nil { + l = m.Secret.Size() + n += 1 + l + sovStore(uint64(l)) + } + return n +} +func (m *Object_Resource) Size() (n int) { + var l int + _ = l + if m.Resource != nil { + l = m.Resource.Size() + n += 1 + l + sovStore(uint64(l)) + } + return n +} +func (m *Object_Extension) Size() (n int) { + var l int + _ = l + if m.Extension != nil { + l = m.Extension.Size() + n += 1 + l + sovStore(uint64(l)) + } + return n +} +func (m *SelectBySlot) Size() (n int) { + var l int + _ = l + l = len(m.ServiceID) + if l > 0 { + n += 1 + l + sovStore(uint64(l)) + } + if m.Slot != 0 { + n += 1 + sovStore(uint64(m.Slot)) + } + return n +} + +func (m *SelectByCustom) Size() (n int) { + var l int + _ = l + l = len(m.Kind) + if l > 0 { + n += 1 + l + sovStore(uint64(l)) + } + l = len(m.Index) + if l > 0 { + n += 1 + l + sovStore(uint64(l)) + } + l = len(m.Value) + if l > 0 { + n += 1 + l + sovStore(uint64(l)) + } + return n +} + +func (m *SelectBy) Size() (n int) { + var l int + _ = l + if m.By != nil { + n += m.By.Size() + } + return n +} + +func (m *SelectBy_ID) Size() (n int) { + var l int + _ = l + l = len(m.ID) + n += 1 + l + sovStore(uint64(l)) + return n +} +func (m *SelectBy_IDPrefix) Size() (n int) { + var l int + _ = l + l = len(m.IDPrefix) + n += 1 + l + sovStore(uint64(l)) + return n +} +func (m *SelectBy_Name) Size() (n int) { + var l int + _ = l + l = len(m.Name) + n += 1 + l + sovStore(uint64(l)) + return n +} +func (m *SelectBy_NamePrefix) Size() (n int) { + var l int + _ = l + l = len(m.NamePrefix) + n += 1 + l + sovStore(uint64(l)) + return n +} +func (m *SelectBy_Custom) Size() (n int) { + var l int + _ = l + if m.Custom != nil { + l = m.Custom.Size() + n += 1 + l + sovStore(uint64(l)) + } + return n +} +func (m *SelectBy_CustomPrefix) Size() (n int) { + var l int + _ = l + if m.CustomPrefix != nil { + l = m.CustomPrefix.Size() + n += 1 + l + sovStore(uint64(l)) + } + return n +} +func (m *SelectBy_ServiceID) Size() (n int) { + var l int + _ = l + l = len(m.ServiceID) + n += 1 + l + sovStore(uint64(l)) + return n +} +func (m *SelectBy_NodeID) Size() (n int) { + var l int + _ = l + l = len(m.NodeID) + n += 1 + l + sovStore(uint64(l)) + return n +} +func (m *SelectBy_Slot) Size() (n int) { + var l int + _ = l + if m.Slot != nil { + l = m.Slot.Size() + n += 1 + l + sovStore(uint64(l)) + } + return n +} +func (m *SelectBy_DesiredState) Size() (n int) { + var l int + _ = l + n += 1 + sovStore(uint64(m.DesiredState)) + return n +} +func (m *SelectBy_Role) Size() (n int) { + var l int + _ = l + n += 1 + sovStore(uint64(m.Role)) + return n +} +func (m *SelectBy_Membership) Size() (n int) { + var l int + _ = l + n += 1 + sovStore(uint64(m.Membership)) + return n +} +func (m *SelectBy_ReferencedNetworkID) Size() (n int) { + var l int + _ = l + l = len(m.ReferencedNetworkID) + n += 1 + l + sovStore(uint64(l)) + return n +} +func (m *SelectBy_ReferencedSecretID) Size() (n int) { + var l int + _ = l + l = len(m.ReferencedSecretID) + n += 1 + l + sovStore(uint64(l)) + return n +} +func (m *SelectBy_Kind) Size() (n int) { + var l int + _ = l + l = len(m.Kind) + n += 1 + l + sovStore(uint64(l)) + return n +} +func (m *WatchRequest) Size() (n int) { + var l int + _ = l + if len(m.Entries) > 0 { + for _, e := range m.Entries { + l = e.Size() + n += 1 + l + sovStore(uint64(l)) + } + } + return n +} + +func (m *WatchRequest_WatchEntry) Size() (n int) { + var l int + _ = l + l = len(m.Kind) + if l > 0 { + n += 1 + l + sovStore(uint64(l)) + } + if m.Action != 0 { + n += 1 + sovStore(uint64(m.Action)) + } + if len(m.Filters) > 0 { + for _, e := range m.Filters { + l = e.Size() + n += 1 + l + sovStore(uint64(l)) + } + } + return n +} + +func (m *WatchMessage) Size() (n int) { + var l int + _ = l + if m.Action != 0 { + n += 1 + sovStore(uint64(m.Action)) + } + if m.Object != nil { + l = m.Object.Size() + n += 1 + l + sovStore(uint64(l)) + } + return n +} + +func sovStore(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} +func sozStore(x uint64) (n int) { + return sovStore(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (this *Object) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Object{`, + `Object:` + fmt.Sprintf("%v", this.Object) + `,`, + `}`, + }, "") + return s +} +func (this *Object_Node) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Object_Node{`, + `Node:` + strings.Replace(fmt.Sprintf("%v", this.Node), "Node", "Node", 1) + `,`, + `}`, + }, "") + return s +} +func (this *Object_Service) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Object_Service{`, + `Service:` + strings.Replace(fmt.Sprintf("%v", this.Service), "Service", "Service", 1) + `,`, + `}`, + }, "") + return s +} +func (this *Object_Network) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Object_Network{`, + `Network:` + strings.Replace(fmt.Sprintf("%v", this.Network), "Network", "Network", 1) + `,`, + `}`, + }, "") + return s +} +func (this *Object_Task) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Object_Task{`, + `Task:` + strings.Replace(fmt.Sprintf("%v", this.Task), "Task", "Task", 1) + `,`, + `}`, + }, "") + return s +} +func (this *Object_Cluster) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Object_Cluster{`, + `Cluster:` + strings.Replace(fmt.Sprintf("%v", this.Cluster), "Cluster", "Cluster", 1) + `,`, + `}`, + }, "") + return s +} +func (this *Object_Secret) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Object_Secret{`, + `Secret:` + strings.Replace(fmt.Sprintf("%v", this.Secret), "Secret", "Secret", 1) + `,`, + `}`, + }, "") + return s +} +func (this *Object_Resource) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Object_Resource{`, + `Resource:` + strings.Replace(fmt.Sprintf("%v", this.Resource), "Resource", "Resource", 1) + `,`, + `}`, + }, "") + return s +} +func (this *Object_Extension) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Object_Extension{`, + `Extension:` + strings.Replace(fmt.Sprintf("%v", this.Extension), "Extension", "Extension", 1) + `,`, + `}`, + }, "") + return s +} +func (this *SelectBySlot) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&SelectBySlot{`, + `ServiceID:` + fmt.Sprintf("%v", this.ServiceID) + `,`, + `Slot:` + fmt.Sprintf("%v", this.Slot) + `,`, + `}`, + }, "") + return s +} +func (this *SelectByCustom) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&SelectByCustom{`, + `Kind:` + fmt.Sprintf("%v", this.Kind) + `,`, + `Index:` + fmt.Sprintf("%v", this.Index) + `,`, + `Value:` + fmt.Sprintf("%v", this.Value) + `,`, + `}`, + }, "") + return s +} +func (this *SelectBy) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&SelectBy{`, + `By:` + fmt.Sprintf("%v", this.By) + `,`, + `}`, + }, "") + return s +} +func (this *SelectBy_ID) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&SelectBy_ID{`, + `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + `}`, + }, "") + return s +} +func (this *SelectBy_IDPrefix) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&SelectBy_IDPrefix{`, + `IDPrefix:` + fmt.Sprintf("%v", this.IDPrefix) + `,`, + `}`, + }, "") + return s +} +func (this *SelectBy_Name) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&SelectBy_Name{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `}`, + }, "") + return s +} +func (this *SelectBy_NamePrefix) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&SelectBy_NamePrefix{`, + `NamePrefix:` + fmt.Sprintf("%v", this.NamePrefix) + `,`, + `}`, + }, "") + return s +} +func (this *SelectBy_Custom) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&SelectBy_Custom{`, + `Custom:` + strings.Replace(fmt.Sprintf("%v", this.Custom), "SelectByCustom", "SelectByCustom", 1) + `,`, + `}`, + }, "") + return s +} +func (this *SelectBy_CustomPrefix) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&SelectBy_CustomPrefix{`, + `CustomPrefix:` + strings.Replace(fmt.Sprintf("%v", this.CustomPrefix), "SelectByCustom", "SelectByCustom", 1) + `,`, + `}`, + }, "") + return s +} +func (this *SelectBy_ServiceID) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&SelectBy_ServiceID{`, + `ServiceID:` + fmt.Sprintf("%v", this.ServiceID) + `,`, + `}`, + }, "") + return s +} +func (this *SelectBy_NodeID) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&SelectBy_NodeID{`, + `NodeID:` + fmt.Sprintf("%v", this.NodeID) + `,`, + `}`, + }, "") + return s +} +func (this *SelectBy_Slot) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&SelectBy_Slot{`, + `Slot:` + strings.Replace(fmt.Sprintf("%v", this.Slot), "SelectBySlot", "SelectBySlot", 1) + `,`, + `}`, + }, "") + return s +} +func (this *SelectBy_DesiredState) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&SelectBy_DesiredState{`, + `DesiredState:` + fmt.Sprintf("%v", this.DesiredState) + `,`, + `}`, + }, "") + return s +} +func (this *SelectBy_Role) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&SelectBy_Role{`, + `Role:` + fmt.Sprintf("%v", this.Role) + `,`, + `}`, + }, "") + return s +} +func (this *SelectBy_Membership) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&SelectBy_Membership{`, + `Membership:` + fmt.Sprintf("%v", this.Membership) + `,`, + `}`, + }, "") + return s +} +func (this *SelectBy_ReferencedNetworkID) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&SelectBy_ReferencedNetworkID{`, + `ReferencedNetworkID:` + fmt.Sprintf("%v", this.ReferencedNetworkID) + `,`, + `}`, + }, "") + return s +} +func (this *SelectBy_ReferencedSecretID) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&SelectBy_ReferencedSecretID{`, + `ReferencedSecretID:` + fmt.Sprintf("%v", this.ReferencedSecretID) + `,`, + `}`, + }, "") + return s +} +func (this *SelectBy_Kind) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&SelectBy_Kind{`, + `Kind:` + fmt.Sprintf("%v", this.Kind) + `,`, + `}`, + }, "") + return s +} +func (this *WatchRequest) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&WatchRequest{`, + `Entries:` + strings.Replace(fmt.Sprintf("%v", this.Entries), "WatchRequest_WatchEntry", "WatchRequest_WatchEntry", 1) + `,`, + `}`, + }, "") + return s +} +func (this *WatchRequest_WatchEntry) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&WatchRequest_WatchEntry{`, + `Kind:` + fmt.Sprintf("%v", this.Kind) + `,`, + `Action:` + fmt.Sprintf("%v", this.Action) + `,`, + `Filters:` + strings.Replace(fmt.Sprintf("%v", this.Filters), "SelectBy", "SelectBy", 1) + `,`, + `}`, + }, "") + return s +} +func (this *WatchMessage) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&WatchMessage{`, + `Action:` + fmt.Sprintf("%v", this.Action) + `,`, + `Object:` + strings.Replace(fmt.Sprintf("%v", this.Object), "Object", "Object", 1) + `,`, + `}`, + }, "") + return s +} +func valueToStringStore(v interface{}) string { + rv := reflect.ValueOf(v) + if rv.IsNil() { + return "nil" + } + pv := reflect.Indirect(rv).Interface() + return fmt.Sprintf("*%v", pv) +} +func (m *Object) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Object: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Object: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Node", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &Node{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Object = &Object_Node{v} + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Service", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &Service{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Object = &Object_Service{v} + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Network", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &Network{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Object = &Object_Network{v} + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Task", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &Task{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Object = &Object_Task{v} + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Cluster", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &Cluster{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Object = &Object_Cluster{v} + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Secret", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &Secret{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Object = &Object_Secret{v} + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Resource", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &Resource{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Object = &Object_Resource{v} + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Extension", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &Extension{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Object = &Object_Extension{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipStore(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthStore + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SelectBySlot) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SelectBySlot: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SelectBySlot: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ServiceID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ServiceID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Slot", wireType) + } + m.Slot = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Slot |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipStore(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthStore + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SelectByCustom) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SelectByCustom: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SelectByCustom: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Kind", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Kind = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Index = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipStore(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthStore + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SelectBy) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SelectBy: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SelectBy: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.By = &SelectBy_ID{string(dAtA[iNdEx:postIndex])} + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IDPrefix", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.By = &SelectBy_IDPrefix{string(dAtA[iNdEx:postIndex])} + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.By = &SelectBy_Name{string(dAtA[iNdEx:postIndex])} + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NamePrefix", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.By = &SelectBy_NamePrefix{string(dAtA[iNdEx:postIndex])} + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Custom", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &SelectByCustom{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.By = &SelectBy_Custom{v} + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CustomPrefix", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &SelectByCustom{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.By = &SelectBy_CustomPrefix{v} + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ServiceID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.By = &SelectBy_ServiceID{string(dAtA[iNdEx:postIndex])} + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NodeID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.By = &SelectBy_NodeID{string(dAtA[iNdEx:postIndex])} + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Slot", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &SelectBySlot{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.By = &SelectBy_Slot{v} + iNdEx = postIndex + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DesiredState", wireType) + } + var v TaskState + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (TaskState(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.By = &SelectBy_DesiredState{v} + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Role", wireType) + } + var v NodeRole + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (NodeRole(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.By = &SelectBy_Role{v} + case 12: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Membership", wireType) + } + var v NodeSpec_Membership + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (NodeSpec_Membership(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.By = &SelectBy_Membership{v} + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReferencedNetworkID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.By = &SelectBy_ReferencedNetworkID{string(dAtA[iNdEx:postIndex])} + iNdEx = postIndex + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReferencedSecretID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.By = &SelectBy_ReferencedSecretID{string(dAtA[iNdEx:postIndex])} + iNdEx = postIndex + case 15: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Kind", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.By = &SelectBy_Kind{string(dAtA[iNdEx:postIndex])} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipStore(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthStore + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *WatchRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: WatchRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: WatchRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Entries", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Entries = append(m.Entries, &WatchRequest_WatchEntry{}) + if err := m.Entries[len(m.Entries)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipStore(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthStore + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *WatchRequest_WatchEntry) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: WatchEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: WatchEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Kind", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Kind = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Action", wireType) + } + m.Action = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Action |= (StoreActionKind(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Filters", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Filters = append(m.Filters, &SelectBy{}) + if err := m.Filters[len(m.Filters)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipStore(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthStore + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *WatchMessage) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: WatchMessage: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: WatchMessage: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Action", wireType) + } + m.Action = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Action |= (StoreActionKind(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Object", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Object == nil { + m.Object = &Object{} + } + if err := m.Object.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipStore(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthStore + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipStore(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowStore + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowStore + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + return iNdEx, nil + case 1: + iNdEx += 8 + return iNdEx, nil + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowStore + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + iNdEx += length + if length < 0 { + return 0, ErrInvalidLengthStore + } + return iNdEx, nil + case 3: + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowStore + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + innerWire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + innerWireType := int(innerWire & 0x7) + if innerWireType == 4 { + break + } + next, err := skipStore(dAtA[start:]) + if err != nil { + return 0, err + } + iNdEx = start + next + } + return iNdEx, nil + case 4: + return iNdEx, nil + case 5: + iNdEx += 4 + return iNdEx, nil + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + } + panic("unreachable") +} + +var ( + ErrInvalidLengthStore = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowStore = fmt.Errorf("proto: integer overflow") +) + +func init() { proto.RegisterFile("store.proto", fileDescriptorStore) } + +var fileDescriptorStore = []byte{ + // 913 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x94, 0x95, 0xcd, 0x6e, 0x23, 0x45, + 0x10, 0xc7, 0x3d, 0x8e, 0x33, 0xb6, 0xcb, 0xf6, 0xae, 0xd4, 0xc9, 0xc2, 0xc8, 0x04, 0xdb, 0x18, + 0x21, 0x22, 0x2d, 0x78, 0xc1, 0xa0, 0x45, 0xe2, 0xe3, 0x80, 0x37, 0x91, 0x6c, 0x50, 0x96, 0xa8, + 0x8d, 0xc4, 0x31, 0x9a, 0xcc, 0x54, 0xbc, 0x83, 0xc7, 0x33, 0xa6, 0xbb, 0x9d, 0xdd, 0x9c, 0xe0, + 0x25, 0x90, 0x38, 0xf1, 0x08, 0x3c, 0xc7, 0x8a, 0x03, 0xe2, 0xc8, 0xc9, 0x62, 0xe7, 0x0e, 0xcf, + 0x80, 0xba, 0xba, 0x27, 0x0e, 0xec, 0x78, 0xd1, 0x9e, 0xa6, 0xbb, 0xe6, 0xf7, 0xaf, 0xae, 0xae, + 0xea, 0xae, 0x86, 0x86, 0x54, 0xa9, 0xc0, 0xc1, 0x52, 0xa4, 0x2a, 0x65, 0x2c, 0x4c, 0x83, 0x39, + 0x8a, 0x81, 0x7c, 0xec, 0x8b, 0xc5, 0x3c, 0x52, 0x83, 0xcb, 0xf7, 0xdb, 0x0d, 0xb9, 0xc4, 0x40, + 0x1a, 0xa0, 0xdd, 0x4a, 0xcf, 0xbf, 0xc5, 0x40, 0xe5, 0x53, 0x10, 0xfe, 0x85, 0xb2, 0xe3, 0x86, + 0xba, 0x5a, 0x62, 0xfe, 0x63, 0x7f, 0x96, 0xce, 0x52, 0x1a, 0xde, 0xd3, 0x23, 0x6b, 0xdd, 0x5b, + 0xc6, 0xab, 0x59, 0x94, 0xdc, 0x33, 0x1f, 0x63, 0xec, 0xff, 0xb6, 0x03, 0xee, 0x57, 0xe4, 0x95, + 0x0d, 0xa0, 0x92, 0xa4, 0x21, 0x7a, 0x4e, 0xcf, 0x39, 0x6c, 0x0c, 0xbd, 0xc1, 0xf3, 0xd1, 0x0c, + 0x1e, 0xa6, 0x21, 0x8e, 0x4b, 0x9c, 0x38, 0xf6, 0x11, 0x54, 0x25, 0x8a, 0xcb, 0x28, 0x40, 0xaf, + 0x4c, 0x92, 0xd7, 0x8a, 0x24, 0x53, 0x83, 0x8c, 0x4b, 0x3c, 0xa7, 0xb5, 0x30, 0x41, 0xf5, 0x38, + 0x15, 0x73, 0x6f, 0x67, 0xbb, 0xf0, 0xa1, 0x41, 0xb4, 0xd0, 0xd2, 0x3a, 0x42, 0xe5, 0xcb, 0xb9, + 0x57, 0xd9, 0x1e, 0xe1, 0xd7, 0xbe, 0xd4, 0x12, 0xe2, 0xf4, 0x42, 0x41, 0xbc, 0x92, 0x0a, 0x85, + 0xb7, 0xbb, 0x7d, 0xa1, 0x07, 0x06, 0xd1, 0x0b, 0x59, 0x9a, 0x7d, 0x08, 0xae, 0xc4, 0x40, 0xa0, + 0xf2, 0x5c, 0xd2, 0xb5, 0x8b, 0x77, 0xa6, 0x89, 0x71, 0x89, 0x5b, 0x96, 0x7d, 0x0c, 0x35, 0x81, + 0x32, 0x5d, 0x89, 0x00, 0xbd, 0x2a, 0xe9, 0x0e, 0x8a, 0x74, 0xdc, 0x32, 0xe3, 0x12, 0xbf, 0xe6, + 0xd9, 0x67, 0x50, 0xc7, 0x27, 0x0a, 0x13, 0x19, 0xa5, 0x89, 0x57, 0x23, 0xf1, 0xeb, 0x45, 0xe2, + 0xe3, 0x1c, 0x1a, 0x97, 0xf8, 0x46, 0x31, 0xaa, 0xe5, 0x55, 0xec, 0x9f, 0x42, 0x73, 0x8a, 0x31, + 0x06, 0x6a, 0x74, 0x35, 0x8d, 0x53, 0xc5, 0xde, 0x01, 0xb0, 0x79, 0x3f, 0x8b, 0x42, 0xaa, 0x6d, + 0x7d, 0xd4, 0xca, 0xd6, 0xdd, 0xba, 0x2d, 0xcc, 0xe4, 0x88, 0xd7, 0x2d, 0x30, 0x09, 0x19, 0x83, + 0x8a, 0x8c, 0x53, 0x45, 0x05, 0xad, 0x70, 0x1a, 0xf7, 0x4f, 0xe1, 0x56, 0xee, 0xf1, 0xc1, 0x4a, + 0xaa, 0x74, 0xa1, 0xa9, 0x79, 0x94, 0x58, 0x6f, 0x9c, 0xc6, 0x6c, 0x1f, 0x76, 0xa3, 0x24, 0xc4, + 0x27, 0x24, 0xad, 0x73, 0x33, 0xd1, 0xd6, 0x4b, 0x3f, 0x5e, 0x21, 0x15, 0xba, 0xce, 0xcd, 0xa4, + 0xff, 0xb3, 0x0b, 0xb5, 0xdc, 0x25, 0xf3, 0xa0, 0x7c, 0x1d, 0x98, 0x9b, 0xad, 0xbb, 0xe5, 0xc9, + 0xd1, 0xb8, 0xc4, 0xcb, 0x51, 0xc8, 0xee, 0x42, 0x3d, 0x0a, 0xcf, 0x96, 0x02, 0x2f, 0x22, 0xeb, + 0x76, 0xd4, 0xcc, 0xd6, 0xdd, 0xda, 0xe4, 0xe8, 0x94, 0x6c, 0x3a, 0x81, 0x51, 0x68, 0xc6, 0x6c, + 0x1f, 0x2a, 0x89, 0xbf, 0xb0, 0x0b, 0xd1, 0x19, 0xf5, 0x17, 0xc8, 0xde, 0x80, 0x86, 0xfe, 0xe6, + 0x4e, 0x2a, 0xf6, 0x27, 0x68, 0xa3, 0x15, 0x7e, 0x0a, 0x6e, 0x40, 0xdb, 0xb2, 0x67, 0xa4, 0x5f, + 0x5c, 0xeb, 0x9b, 0x09, 0xd0, 0x35, 0x37, 0x1a, 0x36, 0x81, 0x96, 0x19, 0xe5, 0x4b, 0xb8, 0x2f, + 0xe1, 0xa4, 0x69, 0xa4, 0x36, 0x90, 0xc1, 0xbf, 0x2a, 0x55, 0x2d, 0xa8, 0x94, 0xae, 0xf9, 0xa6, + 0x56, 0x6f, 0x41, 0x55, 0xdf, 0x43, 0x0d, 0xd7, 0x08, 0x86, 0x6c, 0xdd, 0x75, 0xf5, 0x15, 0x25, + 0xd2, 0xd5, 0x3f, 0x27, 0x21, 0xbb, 0x6f, 0x4b, 0x5a, 0xa7, 0xc0, 0x7a, 0x2f, 0x0a, 0x4c, 0x1f, + 0x18, 0x9d, 0x3a, 0xcd, 0xb3, 0x23, 0x68, 0x85, 0x28, 0x23, 0x81, 0xe1, 0x99, 0x54, 0xbe, 0x42, + 0x0f, 0x7a, 0xce, 0xe1, 0xad, 0xe2, 0x53, 0xa9, 0x6f, 0xdd, 0x54, 0x43, 0x7a, 0x53, 0x56, 0x45, + 0x73, 0x36, 0x84, 0x8a, 0x48, 0x63, 0xf4, 0x1a, 0x24, 0x3e, 0xd8, 0xd6, 0x54, 0x78, 0x1a, 0x53, + 0x63, 0xd1, 0x2c, 0x9b, 0x00, 0x2c, 0x70, 0x71, 0x8e, 0x42, 0x3e, 0x8a, 0x96, 0x5e, 0x93, 0x94, + 0x6f, 0x6f, 0x53, 0x4e, 0x97, 0x18, 0x0c, 0x4e, 0xae, 0x71, 0x5d, 0xdc, 0x8d, 0x98, 0x9d, 0xc0, + 0x1d, 0x81, 0x17, 0x28, 0x30, 0x09, 0x30, 0x3c, 0xb3, 0x7d, 0x44, 0x67, 0xac, 0x45, 0x19, 0x7b, + 0x35, 0x5b, 0x77, 0xf7, 0xf8, 0x35, 0x60, 0x5b, 0x0e, 0xa5, 0x6f, 0x4f, 0x3c, 0x67, 0x0e, 0xd9, + 0x17, 0xb0, 0x7f, 0xc3, 0x9d, 0xb9, 0xf6, 0xda, 0xdb, 0x2d, 0xf2, 0xf6, 0x4a, 0xb6, 0xee, 0xb2, + 0x8d, 0x37, 0xd3, 0x1f, 0xc8, 0x19, 0x13, 0xff, 0xb5, 0xea, 0x0b, 0x63, 0x2e, 0xd1, 0xed, 0xfc, + 0xc0, 0xea, 0xd9, 0xa8, 0x02, 0xe5, 0xd1, 0x55, 0xff, 0x2f, 0x07, 0x9a, 0xdf, 0xf8, 0x2a, 0x78, + 0xc4, 0xf1, 0xbb, 0x15, 0x4a, 0xc5, 0x8e, 0xa1, 0x8a, 0x89, 0x12, 0x11, 0x4a, 0xcf, 0xe9, 0xed, + 0x1c, 0x36, 0x86, 0x77, 0x8b, 0xf2, 0x71, 0x53, 0x62, 0x26, 0xc7, 0x89, 0x12, 0x57, 0x3c, 0xd7, + 0xb6, 0x7f, 0x74, 0x00, 0x36, 0xf6, 0xc2, 0x7b, 0xfc, 0x09, 0xb8, 0x7e, 0xa0, 0x74, 0x17, 0x2a, + 0x53, 0xe2, 0xdf, 0x2c, 0x3c, 0x30, 0xfa, 0xd5, 0xfa, 0x9c, 0xb0, 0x2f, 0xa3, 0x24, 0xe4, 0x56, + 0xc2, 0xee, 0x43, 0xf5, 0x22, 0x8a, 0x15, 0x0a, 0xe9, 0xed, 0x50, 0x98, 0x07, 0x2f, 0x3a, 0x6e, + 0x3c, 0x87, 0xfb, 0xdf, 0xdb, 0xed, 0x9e, 0xa0, 0x94, 0xfe, 0x0c, 0x6f, 0x04, 0xe1, 0xbc, 0x7c, + 0x10, 0x43, 0x70, 0xcd, 0x3b, 0x69, 0x9f, 0xa5, 0xc2, 0xe6, 0x6d, 0xba, 0x25, 0xb7, 0xe4, 0x70, + 0x01, 0xbb, 0xe4, 0x8e, 0x85, 0xb0, 0x4b, 0x91, 0xb0, 0xde, 0xff, 0x25, 0xb8, 0xbd, 0x9d, 0xb0, + 0xdb, 0xe8, 0xdf, 0xf9, 0xf5, 0x97, 0xbf, 0x7f, 0x2a, 0xdf, 0x86, 0x16, 0x11, 0xef, 0x2e, 0xfc, + 0xc4, 0x9f, 0xa1, 0x78, 0xcf, 0x19, 0x79, 0x4f, 0x9f, 0x75, 0x4a, 0x7f, 0x3c, 0xeb, 0x94, 0x7e, + 0xc8, 0x3a, 0xce, 0xd3, 0xac, 0xe3, 0xfc, 0x9e, 0x75, 0x9c, 0x3f, 0xb3, 0x8e, 0x73, 0xee, 0xd2, + 0xb3, 0xfc, 0xc1, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xd7, 0xef, 0x30, 0x33, 0x19, 0x08, 0x00, + 0x00, +} diff --git a/api/store.proto b/api/store.proto new file mode 100644 index 0000000000..c820b7382b --- /dev/null +++ b/api/store.proto @@ -0,0 +1,114 @@ +syntax = "proto3"; + +package docker.swarmkit.v1; + +import "specs.proto"; +import "objects.proto"; +import "raft.proto"; +import "types.proto"; +import "gogoproto/gogo.proto"; +import "plugin/plugin.proto"; + +message Object { + oneof Object { + Node node = 1; + Service service = 2; + Network network = 3; + Task task = 4; + Cluster cluster = 5; + Secret secret = 6; + Resource resource = 7; + Extension extension = 8; + } +} + +// FIXME(aaronl): These messages should ideally be embedded in SelectBy, but +// protoc generates bad code for that. +message SelectBySlot { + string service_id = 1 [(gogoproto.customname) = "ServiceID"]; + uint64 slot = 2; +} + +message SelectByCustom { + string kind = 1; + string index = 2; + string value = 3; +} + +message SelectBy { + // TODO(aaronl): Are all of these things we want to expose in + // the API? Exposing them may commit us to maintaining those + // internal indices going forward. + oneof By { + // supported by all object types + string id = 1 [(gogoproto.customname) = "ID"]; // not applicable for FindObjects - use GetObject instead + string id_prefix = 2 [(gogoproto.customname) = "IDPrefix"]; + string name = 3; + string name_prefix = 4; + SelectByCustom custom = 5; + SelectByCustom custom_prefix = 6; + + // supported by tasks only + string service_id = 7 [(gogoproto.customname) = "ServiceID"]; + string node_id = 8 [(gogoproto.customname) = "NodeID"]; + SelectBySlot slot = 9; + TaskState desired_state = 10; + + // supported by nodes only + NodeRole role = 11; + NodeSpec.Membership membership = 12; + + // supported by: service, task + string referenced_network_id = 13 [(gogoproto.customname) = "ReferencedNetworkID"]; + string referenced_secret_id = 14 [(gogoproto.customname) = "ReferencedSecretID"]; + + // supported by: resource + string kind = 15; + } +} + + +// Store defines the RPC methods for interacting with the data store. +service Store { + // Watch starts a stream that returns any changes to objects that match + // the specified selectors. When the stream begins, it immediately sends + // an empty message back to the client. It is important to wait for + // this message before taking any actions that depend on an established + // stream of changes for consistency. + rpc Watch(WatchRequest) returns (stream WatchMessage) { + option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-manager" }; + }; +} + +message WatchRequest { + message WatchEntry { + // Kind can contain a builtin type such as "node", "secret", etc. or + // the kind specified by a custom-defined object. + string kind = 1; + + // Action (create/update/delete) + StoreActionKind action = 2; + + // Filters are combined using AND logic - an event must match + // all of them to pass the filter. + repeated SelectBy filters = 3; + } + + // Multiple entries are combined using OR logic - i.e. if an event + // matches all of the selectors specified in any single watch entry, + // the event will be sent to the client. + repeated WatchEntry entries = 1; +} + +// WatchMessage is the type of the stream that's returned to the client by +// Watch. Note that the first item of this stream will always be a WatchMessage +// with a nil Object, to signal that the stream has started. +message WatchMessage { + // Action (create/update/delete) + // Note that WatchMessage does not expose "commit" events that mark + // transaction boundaries. + StoreActionKind action = 1; + + // Matched object + Object object = 2; +} diff --git a/api/types.pb.go b/api/types.pb.go index c72328eac0..ae15790bcd 100644 --- a/api/types.pb.go +++ b/api/types.pb.go @@ -17,6 +17,7 @@ health.proto resource.proto logbroker.proto + store.proto It has these top-level messages: Version @@ -189,6 +190,12 @@ SubscriptionMessage PublishLogsMessage PublishLogsResponse + Object + SelectBySlot + SelectByCustom + SelectBy + WatchRequest + WatchMessage */ package api diff --git a/manager/manager.go b/manager/manager.go index 594272a5ae..46f795af9a 100644 --- a/manager/manager.go +++ b/manager/manager.go @@ -36,6 +36,7 @@ import ( "github.com/docker/swarmkit/manager/state" "github.com/docker/swarmkit/manager/state/raft" "github.com/docker/swarmkit/manager/state/store" + "github.com/docker/swarmkit/manager/storeapi" "github.com/docker/swarmkit/remotes" "github.com/docker/swarmkit/xnet" gogotypes "github.com/gogo/protobuf/types" @@ -390,11 +391,13 @@ func (m *Manager) Run(parent context.Context) error { } baseControlAPI := controlapi.NewServer(m.raftNode.MemoryStore(), m.raftNode, m.config.SecurityConfig, m.caserver, m.config.PluginGetter) + baseStoreAPI := storeapi.NewServer(m.raftNode.MemoryStore()) baseResourceAPI := resourceapi.New(m.raftNode.MemoryStore()) healthServer := health.NewHealthServer() localHealthServer := health.NewHealthServer() authenticatedControlAPI := api.NewAuthenticatedWrapperControlServer(baseControlAPI, authorize) + authenticatedStoreAPI := api.NewAuthenticatedWrapperStoreServer(baseStoreAPI, authorize) authenticatedResourceAPI := api.NewAuthenticatedWrapperResourceAllocatorServer(baseResourceAPI, authorize) authenticatedLogsServerAPI := api.NewAuthenticatedWrapperLogsServer(m.logbroker, authorize) authenticatedLogBrokerAPI := api.NewAuthenticatedWrapperLogBrokerServer(m.logbroker, authorize) @@ -444,6 +447,7 @@ func (m *Manager) Run(parent context.Context) error { return context.WithValue(ctx, ca.LocalRequestKey, nodeInfo), nil } localProxyControlAPI := api.NewRaftProxyControlServer(baseControlAPI, m.raftNode, handleRequestLocally, forwardAsOwnRequest) + localProxyStoreAPI := api.NewRaftProxyStoreServer(baseStoreAPI, m.raftNode, handleRequestLocally, forwardAsOwnRequest) localProxyLogsAPI := api.NewRaftProxyLogsServer(m.logbroker, m.raftNode, handleRequestLocally, forwardAsOwnRequest) localProxyDispatcherAPI := api.NewRaftProxyDispatcherServer(m.dispatcher, m.raftNode, handleRequestLocally, forwardAsOwnRequest) localProxyCAAPI := api.NewRaftProxyCAServer(m.caserver, m.raftNode, handleRequestLocally, forwardAsOwnRequest) @@ -459,6 +463,7 @@ func (m *Manager) Run(parent context.Context) error { api.RegisterHealthServer(m.server, authenticatedHealthAPI) api.RegisterRaftMembershipServer(m.server, proxyRaftMembershipAPI) api.RegisterControlServer(m.server, authenticatedControlAPI) + api.RegisterStoreServer(m.server, authenticatedStoreAPI) api.RegisterLogsServer(m.server, authenticatedLogsServerAPI) api.RegisterLogBrokerServer(m.server, proxyLogBrokerAPI) api.RegisterResourceAllocatorServer(m.server, proxyResourceAPI) @@ -466,6 +471,7 @@ func (m *Manager) Run(parent context.Context) error { grpc_prometheus.Register(m.server) api.RegisterControlServer(m.localserver, localProxyControlAPI) + api.RegisterStoreServer(m.localserver, localProxyStoreAPI) api.RegisterLogsServer(m.localserver, localProxyLogsAPI) api.RegisterHealthServer(m.localserver, localHealthServer) api.RegisterDispatcherServer(m.localserver, localProxyDispatcherAPI) diff --git a/manager/state/watch.go b/manager/state/watch.go index f309fa3842..b115e521e9 100644 --- a/manager/state/watch.go +++ b/manager/state/watch.go @@ -1,11 +1,35 @@ package state import ( + "strings" + "github.com/docker/go-events" "github.com/docker/swarmkit/api" "github.com/docker/swarmkit/watch" ) +func checkCustom(a1, a2 api.Annotations) bool { + if len(a1.Indices) == 1 { + for _, ind := range a2.Indices { + if ind.Key == a1.Indices[0].Key && ind.Val == a1.Indices[0].Val { + return true + } + } + } + return false +} + +func checkCustomPrefix(a1, a2 api.Annotations) bool { + if len(a1.Indices) == 1 { + for _, ind := range a2.Indices { + if ind.Key == a1.Indices[0].Key && strings.HasPrefix(ind.Val, a1.Indices[0].Val) { + return true + } + } + } + return false +} + // EventCommit delineates a transaction boundary. type EventCommit struct{} @@ -20,6 +44,21 @@ func TaskCheckID(t1, t2 *api.Task) bool { return t1.ID == t2.ID } +// TaskCheckIDPrefix is a TaskCheckFunc for matching task IDs by prefix. +func TaskCheckIDPrefix(t1, t2 *api.Task) bool { + return strings.HasPrefix(t2.ID, t1.ID) +} + +// TaskCheckCustom is a TaskCheckFunc for matching task custom indices. +func TaskCheckCustom(t1, t2 *api.Task) bool { + return checkCustom(t1.Annotations, t2.Annotations) +} + +// TaskCheckCustomPrefix is a TaskCheckFunc for matching task custom indices by prefix. +func TaskCheckCustomPrefix(t1, t2 *api.Task) bool { + return checkCustomPrefix(t1.Annotations, t2.Annotations) +} + // TaskCheckNodeID is a TaskCheckFunc for matching node IDs. func TaskCheckNodeID(t1, t2 *api.Task) bool { return t1.NodeID == t2.NodeID @@ -30,14 +69,49 @@ func TaskCheckServiceID(t1, t2 *api.Task) bool { return t1.ServiceID == t2.ServiceID } +// TaskCheckSlot is a TaskCheckFunc for matching slots. +func TaskCheckSlot(t1, t2 *api.Task) bool { + return t1.Slot == t2.Slot +} + +// TaskCheckDesiredState is a TaskCheckFunc for matching desired state. +func TaskCheckDesiredState(t1, t2 *api.Task) bool { + return t1.DesiredState == t2.DesiredState +} + // TaskCheckStateGreaterThan is a TaskCheckFunc for checking task state. func TaskCheckStateGreaterThan(t1, t2 *api.Task) bool { return t2.Status.State > t1.Status.State } // ServiceCheckID is a ServiceCheckFunc for matching service IDs. -func ServiceCheckID(j1, j2 *api.Service) bool { - return j1.ID == j2.ID +func ServiceCheckID(s1, s2 *api.Service) bool { + return s1.ID == s2.ID +} + +// ServiceCheckIDPrefix is a ServiceCheckFunc for matching service IDs by prefix. +func ServiceCheckIDPrefix(s1, s2 *api.Service) bool { + return strings.HasPrefix(s2.ID, s1.ID) +} + +// ServiceCheckName is a ServiceCheckFunc for matching service names. +func ServiceCheckName(s1, s2 *api.Service) bool { + return s1.Spec.Annotations.Name == s2.Spec.Annotations.Name +} + +// ServiceCheckNamePrefix is a ServiceCheckFunc for matching service names by prefix. +func ServiceCheckNamePrefix(s1, s2 *api.Service) bool { + return strings.HasPrefix(s2.Spec.Annotations.Name, s1.Spec.Annotations.Name) +} + +// ServiceCheckCustom is a ServiceCheckFunc for matching service custom indices. +func ServiceCheckCustom(s1, s2 *api.Service) bool { + return checkCustom(s1.Spec.Annotations, s2.Spec.Annotations) +} + +// ServiceCheckCustomPrefix is a ServiceCheckFunc for matching service custom indices by prefix. +func ServiceCheckCustomPrefix(s1, s2 *api.Service) bool { + return checkCustomPrefix(s1.Spec.Annotations, s2.Spec.Annotations) } // NetworkCheckID is a NetworkCheckFunc for matching network IDs. @@ -45,24 +119,140 @@ func NetworkCheckID(n1, n2 *api.Network) bool { return n1.ID == n2.ID } +// NetworkCheckIDPrefix is a NetworkCheckFunc for matching network IDs by prefix. +func NetworkCheckIDPrefix(n1, n2 *api.Network) bool { + return strings.HasPrefix(n2.ID, n1.ID) +} + +// NetworkCheckName is a NetworkCheckFunc for matching network names. +func NetworkCheckName(n1, n2 *api.Network) bool { + return n1.Spec.Annotations.Name == n2.Spec.Annotations.Name +} + +// NetworkCheckNamePrefix is a NetworkCheckFunc for matching network names by prefix. +func NetworkCheckNamePrefix(n1, n2 *api.Network) bool { + return strings.HasPrefix(n2.Spec.Annotations.Name, n1.Spec.Annotations.Name) +} + +// NetworkCheckCustom is a NetworkCheckFunc for matching network custom indices. +func NetworkCheckCustom(n1, n2 *api.Network) bool { + return checkCustom(n1.Spec.Annotations, n2.Spec.Annotations) +} + +// NetworkCheckCustomPrefix is a NetworkCheckFunc for matching network custom indices by prefix. +func NetworkCheckCustomPrefix(n1, n2 *api.Network) bool { + return checkCustomPrefix(n1.Spec.Annotations, n2.Spec.Annotations) +} + // NodeCheckID is a NodeCheckFunc for matching node IDs. func NodeCheckID(n1, n2 *api.Node) bool { return n1.ID == n2.ID } +// NodeCheckIDPrefix is a NodeCheckFunc for matching node IDs by prefix. +func NodeCheckIDPrefix(n1, n2 *api.Node) bool { + return strings.HasPrefix(n2.ID, n1.ID) +} + +// NodeCheckName is a NodeCheckFunc for matching node names. +func NodeCheckName(n1, n2 *api.Node) bool { + if n1.Description == nil || n2.Description == nil { + return false + } + return n1.Description.Hostname == n2.Description.Hostname +} + +// NodeCheckNamePrefix is a NodeCheckFunc for matching node names by prefix. +func NodeCheckNamePrefix(n1, n2 *api.Node) bool { + if n1.Description == nil || n2.Description == nil { + return false + } + return strings.HasPrefix(n2.Description.Hostname, n1.Description.Hostname) +} + +// NodeCheckCustom is a NodeCheckFunc for matching node custom indices. +func NodeCheckCustom(n1, n2 *api.Node) bool { + return checkCustom(n1.Spec.Annotations, n2.Spec.Annotations) +} + +// NodeCheckCustomPrefix is a NodeCheckFunc for matching node custom indices by prefix. +func NodeCheckCustomPrefix(n1, n2 *api.Node) bool { + return checkCustomPrefix(n1.Spec.Annotations, n2.Spec.Annotations) +} + // NodeCheckState is a NodeCheckFunc for matching node state. func NodeCheckState(n1, n2 *api.Node) bool { return n1.Status.State == n2.Status.State } +// NodeCheckRole is a NodeCheckFunc for matching node role. +func NodeCheckRole(n1, n2 *api.Node) bool { + return n1.Role == n2.Role +} + +// NodeCheckMembership is a NodeCheckFunc for matching node membership. +func NodeCheckMembership(n1, n2 *api.Node) bool { + return n1.Spec.Membership == n2.Spec.Membership +} + // ClusterCheckID is a ClusterCheckFunc for matching volume IDs. -func ClusterCheckID(v1, v2 *api.Cluster) bool { - return v1.ID == v2.ID +func ClusterCheckID(c1, c2 *api.Cluster) bool { + return c1.ID == c2.ID +} + +// ClusterCheckIDPrefix is a ClusterCheckFunc for matching cluster IDs by prefix. +func ClusterCheckIDPrefix(c1, c2 *api.Cluster) bool { + return strings.HasPrefix(c2.ID, c1.ID) +} + +// ClusterCheckName is a ClusterCheckFunc for matching cluster names. +func ClusterCheckName(c1, c2 *api.Cluster) bool { + return c1.Spec.Annotations.Name == c2.Spec.Annotations.Name +} + +// ClusterCheckNamePrefix is a ClusterCheckFunc for matching cluster names by prefix. +func ClusterCheckNamePrefix(c1, c2 *api.Cluster) bool { + return strings.HasPrefix(c2.Spec.Annotations.Name, c1.Spec.Annotations.Name) +} + +// ClusterCheckCustom is a ClusterCheckFunc for matching cluster custom indices. +func ClusterCheckCustom(c1, c2 *api.Cluster) bool { + return checkCustom(c1.Spec.Annotations, c2.Spec.Annotations) +} + +// ClusterCheckCustomPrefix is a ClusterCheckFunc for matching cluster custom indices by prefix. +func ClusterCheckCustomPrefix(c1, c2 *api.Cluster) bool { + return checkCustomPrefix(c1.Spec.Annotations, c2.Spec.Annotations) } // SecretCheckID is a SecretCheckFunc for matching secret IDs. -func SecretCheckID(v1, v2 *api.Secret) bool { - return v1.ID == v2.ID +func SecretCheckID(s1, s2 *api.Secret) bool { + return s1.ID == s2.ID +} + +// SecretCheckIDPrefix is a SecretCheckFunc for matching secret IDs by prefix. +func SecretCheckIDPrefix(s1, s2 *api.Secret) bool { + return strings.HasPrefix(s2.ID, s1.ID) +} + +// SecretCheckName is a SecretCheckFunc for matching secret names. +func SecretCheckName(s1, s2 *api.Secret) bool { + return s1.Spec.Annotations.Name == s2.Spec.Annotations.Name +} + +// SecretCheckNamePrefix is a SecretCheckFunc for matching secret names by prefix. +func SecretCheckNamePrefix(s1, s2 *api.Secret) bool { + return strings.HasPrefix(s2.Spec.Annotations.Name, s1.Spec.Annotations.Name) +} + +// SecretCheckCustom is a SecretCheckFunc for matching secret custom indices. +func SecretCheckCustom(s1, s2 *api.Secret) bool { + return checkCustom(s1.Spec.Annotations, s2.Spec.Annotations) +} + +// SecretCheckCustomPrefix is a SecretCheckFunc for matching secret custom indices by prefix. +func SecretCheckCustomPrefix(s1, s2 *api.Secret) bool { + return checkCustomPrefix(s1.Spec.Annotations, s2.Spec.Annotations) } // ResourceCheckID is a ResourceCheckFunc for matching resource IDs. @@ -75,16 +265,65 @@ func ResourceCheckKind(v1, v2 *api.Resource) bool { return v1.Kind == v2.Kind } +// ResourceCheckIDPrefix is a ResourceCheckFunc for matching resource IDs by prefix. +func ResourceCheckIDPrefix(v1, v2 *api.Resource) bool { + return strings.HasPrefix(v2.ID, v1.ID) +} + +// ResourceCheckName is a ResourceCheckFunc for matching resource names. +func ResourceCheckName(v1, v2 *api.Resource) bool { + return v1.Annotations.Name == v2.Annotations.Name +} + +// ResourceCheckNamePrefix is a ResourceCheckFunc for matching resource names by prefix. +func ResourceCheckNamePrefix(v1, v2 *api.Resource) bool { + return strings.HasPrefix(v2.Annotations.Name, v1.Annotations.Name) +} + +// ResourceCheckCustom is a ResourceCheckFunc for matching resource custom indices. +func ResourceCheckCustom(v1, v2 *api.Resource) bool { + return checkCustom(v1.Annotations, v2.Annotations) +} + +// ResourceCheckCustomPrefix is a ResourceCheckFunc for matching resource custom indices by prefix. +func ResourceCheckCustomPrefix(v1, v2 *api.Resource) bool { + return checkCustomPrefix(v1.Annotations, v2.Annotations) +} + // ExtensionCheckID is a ExtensionCheckFunc for matching extension IDs. func ExtensionCheckID(v1, v2 *api.Extension) bool { return v1.ID == v2.ID } -// ExtensionCheckName is a ExtensionCheckFunc for matching extension names names. +// ExtensionCheckIDPrefix is a ExtensionCheckFunc for matching extension IDs by +// prefix. +func ExtensionCheckIDPrefix(s1, s2 *api.Extension) bool { + return strings.HasPrefix(s2.ID, s1.ID) +} + +// ExtensionCheckName is a ExtensionCheckFunc for matching extension names. func ExtensionCheckName(v1, v2 *api.Extension) bool { return v1.Annotations.Name == v2.Annotations.Name } +// ExtensionCheckNamePrefix is a ExtensionCheckFunc for matching extension +// names by prefix. +func ExtensionCheckNamePrefix(v1, v2 *api.Extension) bool { + return strings.HasPrefix(v2.Annotations.Name, v1.Annotations.Name) +} + +// ExtensionCheckCustom is a ExtensionCheckFunc for matching extension custom +// indices. +func ExtensionCheckCustom(v1, v2 *api.Extension) bool { + return checkCustom(v1.Annotations, v2.Annotations) +} + +// ExtensionCheckCustomPrefix is a ExtensionCheckFunc for matching extension +// custom indices by prefix. +func ExtensionCheckCustomPrefix(v1, v2 *api.Extension) bool { + return checkCustomPrefix(v1.Annotations, v2.Annotations) +} + // Watch takes a variable number of events to match against. The subscriber // will receive events that match any of the arguments passed to Watch. // diff --git a/manager/storeapi/server.go b/manager/storeapi/server.go new file mode 100644 index 0000000000..b7396ba59a --- /dev/null +++ b/manager/storeapi/server.go @@ -0,0 +1,17 @@ +package storeapi + +import ( + "github.com/docker/swarmkit/manager/state/store" +) + +// Server is the store API gRPC server. +type Server struct { + store *store.MemoryStore +} + +// NewServer creates a store API server. +func NewServer(store *store.MemoryStore) *Server { + return &Server{ + store: store, + } +} diff --git a/manager/storeapi/server_test.go b/manager/storeapi/server_test.go new file mode 100644 index 0000000000..1ec5b6453f --- /dev/null +++ b/manager/storeapi/server_test.go @@ -0,0 +1,118 @@ +package storeapi + +import ( + "io/ioutil" + "log" + "net" + "os" + "testing" + "time" + + "github.com/Sirupsen/logrus" + "github.com/docker/swarmkit/api" + cautils "github.com/docker/swarmkit/ca/testutils" + "github.com/docker/swarmkit/manager/state/store" + "github.com/stretchr/testify/assert" + "golang.org/x/net/context" + "google.golang.org/grpc" + "google.golang.org/grpc/grpclog" +) + +type mockProposer struct { + index uint64 +} + +func (mp *mockProposer) ProposeValue(ctx context.Context, storeAction []api.StoreAction, cb func()) error { + if cb != nil { + cb() + } + return nil +} + +func (mp *mockProposer) GetVersion() *api.Version { + mp.index += 3 + return &api.Version{Index: mp.index} +} + +type testServer struct { + Server *Server + Client api.StoreClient + Store *store.MemoryStore + + grpcServer *grpc.Server + clientConn *grpc.ClientConn + + tempUnixSocket string +} + +func (ts *testServer) Stop() { + ts.clientConn.Close() + ts.grpcServer.Stop() + ts.Store.Close() + os.RemoveAll(ts.tempUnixSocket) +} + +func newTestServer(t *testing.T) *testServer { + ts := &testServer{} + + // Create a testCA just to get a usable RootCA object + tc := cautils.NewTestCA(nil) + tc.Stop() + + ts.Store = store.NewMemoryStore(&mockProposer{}) + assert.NotNil(t, ts.Store) + ts.Server = NewServer(ts.Store) + assert.NotNil(t, ts.Server) + + temp, err := ioutil.TempFile("", "test-socket") + assert.NoError(t, err) + assert.NoError(t, temp.Close()) + assert.NoError(t, os.Remove(temp.Name())) + + ts.tempUnixSocket = temp.Name() + + lis, err := net.Listen("unix", temp.Name()) + assert.NoError(t, err) + + ts.grpcServer = grpc.NewServer() + api.RegisterStoreServer(ts.grpcServer, ts.Server) + go func() { + // Serve will always return an error (even when properly stopped). + // Explicitly ignore it. + _ = ts.grpcServer.Serve(lis) + }() + + conn, err := grpc.Dial(temp.Name(), grpc.WithInsecure(), grpc.WithTimeout(10*time.Second), + grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) { + return net.DialTimeout("unix", addr, timeout) + })) + assert.NoError(t, err) + ts.clientConn = conn + + ts.Client = api.NewStoreClient(conn) + + return ts +} + +func createNode(t *testing.T, ts *testServer, id string, role api.NodeRole, membership api.NodeSpec_Membership, state api.NodeStatus_State) *api.Node { + node := &api.Node{ + ID: id, + Spec: api.NodeSpec{ + Membership: membership, + }, + Status: api.NodeStatus{ + State: state, + }, + Role: role, + } + err := ts.Store.Update(func(tx store.Tx) error { + return store.CreateNode(tx, node) + }) + assert.NoError(t, err) + return node +} + +func init() { + grpclog.SetLogger(log.New(ioutil.Discard, "", log.LstdFlags)) + logrus.SetOutput(ioutil.Discard) +} diff --git a/manager/storeapi/watch.go b/manager/storeapi/watch.go new file mode 100644 index 0000000000..7b93525d4a --- /dev/null +++ b/manager/storeapi/watch.go @@ -0,0 +1,676 @@ +package storeapi + +import ( + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + + "github.com/docker/swarmkit/api" + "github.com/docker/swarmkit/manager/state" +) + +var errConflictingFilters = grpc.Errorf(codes.InvalidArgument, "conflicting filters specified") + +func convertNodeWatch(action api.StoreActionKind, filters []*api.SelectBy) (api.Event, error) { + var ( + node api.Node + checkFuncs []api.NodeCheckFunc + hasRole bool + hasMembership bool + ) + + for _, filter := range filters { + switch v := filter.By.(type) { + case *api.SelectBy_ID: + if node.ID != "" { + return nil, errConflictingFilters + } + node.ID = v.ID + checkFuncs = append(checkFuncs, state.NodeCheckID) + case *api.SelectBy_IDPrefix: + if node.ID != "" { + return nil, errConflictingFilters + } + node.ID = v.IDPrefix + checkFuncs = append(checkFuncs, state.NodeCheckIDPrefix) + case *api.SelectBy_Name: + if node.Description != nil { + return nil, errConflictingFilters + } + node.Description = &api.NodeDescription{Hostname: v.Name} + checkFuncs = append(checkFuncs, state.NodeCheckName) + case *api.SelectBy_NamePrefix: + if node.Description != nil { + return nil, errConflictingFilters + } + node.Description = &api.NodeDescription{Hostname: v.NamePrefix} + checkFuncs = append(checkFuncs, state.NodeCheckNamePrefix) + case *api.SelectBy_Custom: + // TODO(aaronl): Support multiple custom indices + if len(node.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + node.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} + checkFuncs = append(checkFuncs, state.NodeCheckCustom) + case *api.SelectBy_CustomPrefix: + // TODO(aaronl): Support multiple custom indices + if len(node.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + node.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} + checkFuncs = append(checkFuncs, state.NodeCheckCustomPrefix) + case *api.SelectBy_Role: + if hasRole { + return nil, errConflictingFilters + } + node.Role = v.Role + checkFuncs = append(checkFuncs, state.NodeCheckRole) + hasRole = true + case *api.SelectBy_Membership: + if hasMembership { + return nil, errConflictingFilters + } + node.Spec.Membership = v.Membership + checkFuncs = append(checkFuncs, state.NodeCheckMembership) + hasMembership = true + default: + return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for nodes", filter.By) + } + } + + switch action { + case api.StoreActionKindCreate: + return api.EventCreateNode{Node: &node, Checks: checkFuncs}, nil + case api.StoreActionKindUpdate: + return api.EventUpdateNode{Node: &node, Checks: checkFuncs}, nil + case api.StoreActionKindRemove: + return api.EventDeleteNode{Node: &node, Checks: checkFuncs}, nil + default: + return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized store action %v", action) + } +} + +func convertServiceWatch(action api.StoreActionKind, filters []*api.SelectBy) (api.Event, error) { + var ( + service api.Service + checkFuncs []api.ServiceCheckFunc + ) + + for _, filter := range filters { + switch v := filter.By.(type) { + case *api.SelectBy_ID: + if service.ID != "" { + return nil, errConflictingFilters + } + service.ID = v.ID + checkFuncs = append(checkFuncs, state.ServiceCheckID) + case *api.SelectBy_IDPrefix: + if service.ID != "" { + return nil, errConflictingFilters + } + service.ID = v.IDPrefix + checkFuncs = append(checkFuncs, state.ServiceCheckIDPrefix) + case *api.SelectBy_Name: + if service.Spec.Annotations.Name != "" { + return nil, errConflictingFilters + } + service.Spec.Annotations.Name = v.Name + checkFuncs = append(checkFuncs, state.ServiceCheckName) + case *api.SelectBy_NamePrefix: + if service.Spec.Annotations.Name != "" { + return nil, errConflictingFilters + } + service.Spec.Annotations.Name = v.NamePrefix + checkFuncs = append(checkFuncs, state.ServiceCheckNamePrefix) + case *api.SelectBy_Custom: + // TODO(aaronl): Support multiple custom indices + if len(service.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + service.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} + checkFuncs = append(checkFuncs, state.ServiceCheckCustom) + case *api.SelectBy_CustomPrefix: + // TODO(aaronl): Support multiple custom indices + if len(service.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + service.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} + checkFuncs = append(checkFuncs, state.ServiceCheckCustomPrefix) + case *api.SelectBy_ReferencedNetworkID: + // TODO(aaronl): not supported for now + return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for services", filter.By) + case *api.SelectBy_ReferencedSecretID: + // TODO(aaronl): not supported for now + return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for services", filter.By) + default: + return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for services", filter.By) + } + } + + switch action { + case api.StoreActionKindCreate: + return api.EventCreateService{Service: &service, Checks: checkFuncs}, nil + case api.StoreActionKindUpdate: + return api.EventUpdateService{Service: &service, Checks: checkFuncs}, nil + case api.StoreActionKindRemove: + return api.EventDeleteService{Service: &service, Checks: checkFuncs}, nil + default: + return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized store action %v", action) + } +} + +func convertNetworkWatch(action api.StoreActionKind, filters []*api.SelectBy) (api.Event, error) { + var ( + network api.Network + checkFuncs []api.NetworkCheckFunc + ) + + for _, filter := range filters { + switch v := filter.By.(type) { + case *api.SelectBy_ID: + if network.ID != "" { + return nil, errConflictingFilters + } + network.ID = v.ID + checkFuncs = append(checkFuncs, state.NetworkCheckID) + case *api.SelectBy_IDPrefix: + if network.ID != "" { + return nil, errConflictingFilters + } + network.ID = v.IDPrefix + checkFuncs = append(checkFuncs, state.NetworkCheckIDPrefix) + case *api.SelectBy_Name: + if network.Spec.Annotations.Name != "" { + return nil, errConflictingFilters + } + network.Spec.Annotations.Name = v.Name + checkFuncs = append(checkFuncs, state.NetworkCheckName) + case *api.SelectBy_NamePrefix: + if network.Spec.Annotations.Name != "" { + return nil, errConflictingFilters + } + network.Spec.Annotations.Name = v.NamePrefix + checkFuncs = append(checkFuncs, state.NetworkCheckNamePrefix) + case *api.SelectBy_Custom: + // TODO(aaronl): Support multiple custom indices + if len(network.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + network.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} + checkFuncs = append(checkFuncs, state.NetworkCheckCustom) + case *api.SelectBy_CustomPrefix: + // TODO(aaronl): Support multiple custom indices + if len(network.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + network.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} + checkFuncs = append(checkFuncs, state.NetworkCheckCustomPrefix) + default: + return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for networks", filter.By) + } + } + + switch action { + case api.StoreActionKindCreate: + return api.EventCreateNetwork{Network: &network, Checks: checkFuncs}, nil + case api.StoreActionKindUpdate: + return api.EventUpdateNetwork{Network: &network, Checks: checkFuncs}, nil + case api.StoreActionKindRemove: + return api.EventDeleteNetwork{Network: &network, Checks: checkFuncs}, nil + default: + return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized store action %v", action) + } +} + +func convertClusterWatch(action api.StoreActionKind, filters []*api.SelectBy) (api.Event, error) { + var ( + cluster api.Cluster + checkFuncs []api.ClusterCheckFunc + ) + + for _, filter := range filters { + switch v := filter.By.(type) { + case *api.SelectBy_ID: + if cluster.ID != "" { + return nil, errConflictingFilters + } + cluster.ID = v.ID + checkFuncs = append(checkFuncs, state.ClusterCheckID) + case *api.SelectBy_IDPrefix: + if cluster.ID != "" { + return nil, errConflictingFilters + } + cluster.ID = v.IDPrefix + checkFuncs = append(checkFuncs, state.ClusterCheckIDPrefix) + case *api.SelectBy_Name: + if cluster.Spec.Annotations.Name != "" { + return nil, errConflictingFilters + } + cluster.Spec.Annotations.Name = v.Name + checkFuncs = append(checkFuncs, state.ClusterCheckName) + case *api.SelectBy_NamePrefix: + if cluster.Spec.Annotations.Name != "" { + return nil, errConflictingFilters + } + cluster.Spec.Annotations.Name = v.NamePrefix + checkFuncs = append(checkFuncs, state.ClusterCheckNamePrefix) + case *api.SelectBy_Custom: + // TODO(aaronl): Support multiple custom indices + if len(cluster.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + cluster.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} + checkFuncs = append(checkFuncs, state.ClusterCheckCustom) + case *api.SelectBy_CustomPrefix: + // TODO(aaronl): Support multiple custom indices + if len(cluster.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + cluster.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} + checkFuncs = append(checkFuncs, state.ClusterCheckCustomPrefix) + default: + return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for clusters", filter.By) + } + } + + switch action { + case api.StoreActionKindCreate: + return api.EventCreateCluster{Cluster: &cluster, Checks: checkFuncs}, nil + case api.StoreActionKindUpdate: + return api.EventUpdateCluster{Cluster: &cluster, Checks: checkFuncs}, nil + case api.StoreActionKindRemove: + return api.EventDeleteCluster{Cluster: &cluster, Checks: checkFuncs}, nil + default: + return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized store action %v", action) + } +} + +func convertSecretWatch(action api.StoreActionKind, filters []*api.SelectBy) (api.Event, error) { + var ( + secret api.Secret + checkFuncs []api.SecretCheckFunc + ) + + for _, filter := range filters { + switch v := filter.By.(type) { + case *api.SelectBy_ID: + if secret.ID != "" { + return nil, errConflictingFilters + } + secret.ID = v.ID + checkFuncs = append(checkFuncs, state.SecretCheckID) + case *api.SelectBy_IDPrefix: + if secret.ID != "" { + return nil, errConflictingFilters + } + secret.ID = v.IDPrefix + checkFuncs = append(checkFuncs, state.SecretCheckIDPrefix) + case *api.SelectBy_Name: + if secret.Spec.Annotations.Name != "" { + return nil, errConflictingFilters + } + secret.Spec.Annotations.Name = v.Name + checkFuncs = append(checkFuncs, state.SecretCheckName) + case *api.SelectBy_NamePrefix: + if secret.Spec.Annotations.Name != "" { + return nil, errConflictingFilters + } + secret.Spec.Annotations.Name = v.NamePrefix + checkFuncs = append(checkFuncs, state.SecretCheckNamePrefix) + case *api.SelectBy_Custom: + // TODO(aaronl): Support multiple custom indices + if len(secret.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + secret.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} + checkFuncs = append(checkFuncs, state.SecretCheckCustom) + case *api.SelectBy_CustomPrefix: + // TODO(aaronl): Support multiple custom indices + if len(secret.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + secret.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} + checkFuncs = append(checkFuncs, state.SecretCheckCustomPrefix) + default: + return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for secrets", filter.By) + } + } + + switch action { + case api.StoreActionKindCreate: + return api.EventCreateSecret{Secret: &secret, Checks: checkFuncs}, nil + case api.StoreActionKindUpdate: + return api.EventUpdateSecret{Secret: &secret, Checks: checkFuncs}, nil + case api.StoreActionKindRemove: + return api.EventDeleteSecret{Secret: &secret, Checks: checkFuncs}, nil + default: + return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized store action %v", action) + } +} + +func convertTaskWatch(action api.StoreActionKind, filters []*api.SelectBy) (api.Event, error) { + var ( + task api.Task + checkFuncs []api.TaskCheckFunc + hasDesiredState bool + ) + + for _, filter := range filters { + switch v := filter.By.(type) { + case *api.SelectBy_ID: + if task.ID != "" { + return nil, errConflictingFilters + } + task.ID = v.ID + checkFuncs = append(checkFuncs, state.TaskCheckID) + case *api.SelectBy_IDPrefix: + if task.ID != "" { + return nil, errConflictingFilters + } + task.ID = v.IDPrefix + checkFuncs = append(checkFuncs, state.TaskCheckIDPrefix) + case *api.SelectBy_Custom: + // TODO(aaronl): Support multiple custom indices + if len(task.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + task.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} + checkFuncs = append(checkFuncs, state.TaskCheckCustom) + case *api.SelectBy_CustomPrefix: + // TODO(aaronl): Support multiple custom indices + if len(task.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + task.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} + checkFuncs = append(checkFuncs, state.TaskCheckCustomPrefix) + case *api.SelectBy_ServiceID: + if task.ServiceID != "" { + return nil, errConflictingFilters + } + task.ServiceID = v.ServiceID + checkFuncs = append(checkFuncs, state.TaskCheckServiceID) + case *api.SelectBy_NodeID: + if task.NodeID != "" { + return nil, errConflictingFilters + } + task.NodeID = v.NodeID + checkFuncs = append(checkFuncs, state.TaskCheckNodeID) + case *api.SelectBy_Slot: + if task.Slot != 0 || task.ServiceID != "" { + return nil, errConflictingFilters + } + task.ServiceID = v.Slot.ServiceID + task.Slot = v.Slot.Slot + checkFuncs = append(checkFuncs, state.TaskCheckSlot, state.TaskCheckServiceID) + case *api.SelectBy_DesiredState: + if hasDesiredState { + return nil, errConflictingFilters + } + task.DesiredState = v.DesiredState + checkFuncs = append(checkFuncs, state.TaskCheckDesiredState) + hasDesiredState = true + default: + return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for tasks", filter.By) + } + } + + switch action { + case api.StoreActionKindCreate: + return api.EventCreateTask{Task: &task, Checks: checkFuncs}, nil + case api.StoreActionKindUpdate: + return api.EventUpdateTask{Task: &task, Checks: checkFuncs}, nil + case api.StoreActionKindRemove: + return api.EventDeleteTask{Task: &task, Checks: checkFuncs}, nil + default: + return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized store action %v", action) + } +} + +func convertExtensionWatch(action api.StoreActionKind, filters []*api.SelectBy) (api.Event, error) { + var ( + extension api.Extension + checkFuncs []api.ExtensionCheckFunc + ) + + for _, filter := range filters { + switch v := filter.By.(type) { + case *api.SelectBy_ID: + if extension.ID != "" { + return nil, errConflictingFilters + } + extension.ID = v.ID + checkFuncs = append(checkFuncs, state.ExtensionCheckID) + case *api.SelectBy_IDPrefix: + if extension.ID != "" { + return nil, errConflictingFilters + } + extension.ID = v.IDPrefix + checkFuncs = append(checkFuncs, state.ExtensionCheckIDPrefix) + case *api.SelectBy_Name: + if extension.Annotations.Name != "" { + return nil, errConflictingFilters + } + extension.Annotations.Name = v.Name + checkFuncs = append(checkFuncs, state.ExtensionCheckName) + case *api.SelectBy_NamePrefix: + if extension.Annotations.Name != "" { + return nil, errConflictingFilters + } + extension.Annotations.Name = v.NamePrefix + checkFuncs = append(checkFuncs, state.ExtensionCheckNamePrefix) + case *api.SelectBy_Custom: + // TODO(aaronl): Support multiple custom indices + if len(extension.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + extension.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} + checkFuncs = append(checkFuncs, state.ExtensionCheckCustom) + case *api.SelectBy_CustomPrefix: + // TODO(aaronl): Support multiple custom indices + if len(extension.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + extension.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} + checkFuncs = append(checkFuncs, state.ExtensionCheckCustomPrefix) + default: + return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for extensions", filter.By) + } + } + + switch action { + case api.StoreActionKindCreate: + return api.EventCreateExtension{Extension: &extension, Checks: checkFuncs}, nil + case api.StoreActionKindUpdate: + return api.EventUpdateExtension{Extension: &extension, Checks: checkFuncs}, nil + case api.StoreActionKindRemove: + return api.EventDeleteExtension{Extension: &extension, Checks: checkFuncs}, nil + default: + return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized store action %v", action) + } +} + +func convertResourceWatch(action api.StoreActionKind, filters []*api.SelectBy, kind string) (api.Event, error) { + resource := api.Resource{Kind: kind} + checkFuncs := []api.ResourceCheckFunc{state.ResourceCheckKind} + + for _, filter := range filters { + switch v := filter.By.(type) { + case *api.SelectBy_ID: + if resource.ID != "" { + return nil, errConflictingFilters + } + resource.ID = v.ID + checkFuncs = append(checkFuncs, state.ResourceCheckID) + case *api.SelectBy_IDPrefix: + if resource.ID != "" { + return nil, errConflictingFilters + } + resource.ID = v.IDPrefix + checkFuncs = append(checkFuncs, state.ResourceCheckIDPrefix) + case *api.SelectBy_Name: + if resource.Annotations.Name != "" { + return nil, errConflictingFilters + } + resource.Annotations.Name = v.Name + checkFuncs = append(checkFuncs, state.ResourceCheckName) + case *api.SelectBy_NamePrefix: + if resource.Annotations.Name != "" { + return nil, errConflictingFilters + } + resource.Annotations.Name = v.NamePrefix + checkFuncs = append(checkFuncs, state.ResourceCheckNamePrefix) + case *api.SelectBy_Custom: + // TODO(aaronl): Support multiple custom indices + if len(resource.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + resource.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} + checkFuncs = append(checkFuncs, state.ResourceCheckCustom) + case *api.SelectBy_CustomPrefix: + // TODO(aaronl): Support multiple custom indices + if len(resource.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + resource.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} + checkFuncs = append(checkFuncs, state.ResourceCheckCustomPrefix) + default: + return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for resource objects", filter.By) + } + } + + switch action { + case api.StoreActionKindCreate: + return api.EventCreateResource{Resource: &resource, Checks: checkFuncs}, nil + case api.StoreActionKindUpdate: + return api.EventUpdateResource{Resource: &resource, Checks: checkFuncs}, nil + case api.StoreActionKindRemove: + return api.EventDeleteResource{Resource: &resource, Checks: checkFuncs}, nil + default: + return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized store action %v", action) + } +} + +func convertWatchArgs(entries []*api.WatchRequest_WatchEntry) ([]api.Event, error) { + var events []api.Event + + for _, entry := range entries { + var ( + event api.Event + err error + ) + switch entry.Kind { + case "": + return nil, grpc.Errorf(codes.InvalidArgument, "no kind of object specified") + case "node": + event, err = convertNodeWatch(entry.Action, entry.Filters) + case "service": + event, err = convertServiceWatch(entry.Action, entry.Filters) + case "network": + event, err = convertNetworkWatch(entry.Action, entry.Filters) + case "task": + event, err = convertTaskWatch(entry.Action, entry.Filters) + case "cluster": + event, err = convertClusterWatch(entry.Action, entry.Filters) + case "secret": + event, err = convertSecretWatch(entry.Action, entry.Filters) + case "extension": + event, err = convertExtensionWatch(entry.Action, entry.Filters) + default: + event, err = convertResourceWatch(entry.Action, entry.Filters, entry.Kind) + } + if err != nil { + return nil, err + } + events = append(events, event) + } + + return events, nil +} + +func watchMessage(event api.Event) *api.WatchMessage { + switch v := event.(type) { + case api.EventCreateTask: + return &api.WatchMessage{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}} + case api.EventUpdateTask: + return &api.WatchMessage{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}} + case api.EventDeleteTask: + return &api.WatchMessage{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}} + case api.EventCreateService: + return &api.WatchMessage{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}} + case api.EventUpdateService: + return &api.WatchMessage{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}} + case api.EventDeleteService: + return &api.WatchMessage{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}} + case api.EventCreateNetwork: + return &api.WatchMessage{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}} + case api.EventUpdateNetwork: + return &api.WatchMessage{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}} + case api.EventDeleteNetwork: + return &api.WatchMessage{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}} + case api.EventCreateNode: + return &api.WatchMessage{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}} + case api.EventUpdateNode: + return &api.WatchMessage{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}} + case api.EventDeleteNode: + return &api.WatchMessage{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}} + case api.EventCreateCluster: + return &api.WatchMessage{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}} + case api.EventUpdateCluster: + return &api.WatchMessage{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}} + case api.EventDeleteCluster: + return &api.WatchMessage{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}} + case api.EventCreateSecret: + return &api.WatchMessage{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}} + case api.EventUpdateSecret: + return &api.WatchMessage{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}} + case api.EventDeleteSecret: + return &api.WatchMessage{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}} + case api.EventCreateResource: + return &api.WatchMessage{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}} + case api.EventUpdateResource: + return &api.WatchMessage{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}} + case api.EventDeleteResource: + return &api.WatchMessage{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}} + case api.EventCreateExtension: + return &api.WatchMessage{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}} + case api.EventUpdateExtension: + return &api.WatchMessage{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}} + case api.EventDeleteExtension: + return &api.WatchMessage{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}} + } + return nil +} + +// Watch starts a stream that returns any changes to objects that match +// the specified selectors. When the stream begins, it immediately sends +// an empty message back to the client. It is important to wait for +// this message before taking any actions that depend on an established +// stream of changes for consistency. +func (s *Server) Watch(request *api.WatchRequest, stream api.Store_WatchServer) error { + ctx := stream.Context() + + watchArgs, err := convertWatchArgs(request.Entries) + if err != nil { + return err + } + + watch, cancel := state.Watch(s.store.WatchQueue(), watchArgs...) + defer cancel() + + if err := stream.Send(&api.WatchMessage{}); err != nil { + return err + } + + for { + select { + case <-ctx.Done(): + return ctx.Err() + case event := <-watch: + message := watchMessage(event.(api.Event)) + if message != nil { + if err := stream.Send(message); err != nil { + return err + } + } + } + } +} diff --git a/manager/storeapi/watch_test.go b/manager/storeapi/watch_test.go new file mode 100644 index 0000000000..3928bf7098 --- /dev/null +++ b/manager/storeapi/watch_test.go @@ -0,0 +1,161 @@ +package storeapi + +import ( + "testing" + + "github.com/docker/swarmkit/api" + "github.com/docker/swarmkit/manager/state/store" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/net/context" +) + +func TestWatch(t *testing.T) { + ts := newTestServer(t) + defer ts.Stop() + + ctx := context.Background() + + // Watch for node creates + watch, err := ts.Client.Watch(ctx, &api.WatchRequest{ + Entries: []*api.WatchRequest_WatchEntry{ + { + Kind: "node", + Action: api.StoreActionKindCreate, + }, + }, + }) + assert.NoError(t, err) + + // Should receive an initial message that indicates the watch is ready + msg, err := watch.Recv() + assert.NoError(t, err) + assert.Equal(t, &api.WatchMessage{}, msg) + + createNode(t, ts, "id1", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY) + msg, err = watch.Recv() + assert.NoError(t, err) + assert.Equal(t, api.StoreActionKindCreate, msg.Action) + require.NotNil(t, msg.Object.GetNode()) + assert.Equal(t, "id1", msg.Object.GetNode().ID) + + watch.CloseSend() + + // Watch for node creates that match a name prefix and a custom index, or + // are managers + watch, err = ts.Client.Watch(ctx, &api.WatchRequest{ + Entries: []*api.WatchRequest_WatchEntry{ + { + Kind: "node", + Action: api.StoreActionKindCreate, + Filters: []*api.SelectBy{ + { + By: &api.SelectBy_NamePrefix{ + NamePrefix: "east", + }, + }, + { + By: &api.SelectBy_Custom{ + Custom: &api.SelectByCustom{ + Index: "myindex", + Value: "myval", + }, + }, + }, + }, + }, + { + Kind: "node", + Action: api.StoreActionKindCreate, + Filters: []*api.SelectBy{ + { + By: &api.SelectBy_Role{ + Role: api.NodeRoleManager, + }, + }, + }, + }, + }, + }) + assert.NoError(t, err) + + // Should receive an initial message that indicates the watch is ready + msg, err = watch.Recv() + assert.NoError(t, err) + assert.Equal(t, &api.WatchMessage{}, msg) + + createNode(t, ts, "id2", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY) + msg, err = watch.Recv() + assert.NoError(t, err) + assert.Equal(t, api.StoreActionKindCreate, msg.Action) + require.NotNil(t, msg.Object.GetNode()) + assert.Equal(t, "id2", msg.Object.GetNode().ID) + + // Shouldn't be seen by the watch + createNode(t, ts, "id3", api.NodeRoleWorker, api.NodeMembershipAccepted, api.NodeStatus_READY) + + // Shouldn't be seen either - no hostname + node := &api.Node{ + ID: "id4", + Spec: api.NodeSpec{ + Annotations: api.Annotations{ + Indices: []api.IndexEntry{ + {Key: "myindex", Val: "myval"}, + }, + }, + }, + Role: api.NodeRoleWorker, + } + err = ts.Store.Update(func(tx store.Tx) error { + return store.CreateNode(tx, node) + }) + assert.NoError(t, err) + + // Shouldn't be seen either - hostname doesn't match filter + node = &api.Node{ + ID: "id5", + Description: &api.NodeDescription{ + Hostname: "west-40", + }, + Spec: api.NodeSpec{ + Annotations: api.Annotations{ + Indices: []api.IndexEntry{ + {Key: "myindex", Val: "myval"}, + }, + }, + }, + Role: api.NodeRoleWorker, + } + err = ts.Store.Update(func(tx store.Tx) error { + return store.CreateNode(tx, node) + }) + assert.NoError(t, err) + + // This one should be seen + node = &api.Node{ + ID: "id6", + Description: &api.NodeDescription{ + Hostname: "east-95", + }, + Spec: api.NodeSpec{ + Annotations: api.Annotations{ + Indices: []api.IndexEntry{ + {Key: "myindex", Val: "myval"}, + }, + }, + }, + Role: api.NodeRoleWorker, + } + err = ts.Store.Update(func(tx store.Tx) error { + return store.CreateNode(tx, node) + }) + assert.NoError(t, err) + + msg, err = watch.Recv() + assert.NoError(t, err) + assert.Equal(t, api.StoreActionKindCreate, msg.Action) + require.NotNil(t, msg.Object.GetNode()) + assert.Equal(t, "id6", msg.Object.GetNode().ID) + + watch.CloseSend() +} From fb5ca684192eee36b90fef64a94be270981cb8f6 Mon Sep 17 00:00:00 2001 From: Aaron Lehmann Date: Wed, 1 Feb 2017 16:02:02 +0000 Subject: [PATCH 2/7] Modify external store Watch RPC to allow resuming from a known position This adds a Version to every WatchMessage, and a ResumeFrom field in the initial WatchRequest. A client can specify its last seen version to avoid doing a complete resync. Signed-off-by: Aaron Lehmann --- api/objects.pb.go | 78 ++++ api/store.pb.go | 413 +++++++++++++++++---- api/store.proto | 27 +- manager/controlapi/server_test.go | 22 +- manager/state/proposer.go | 13 + manager/state/raft/raft.go | 47 +++ manager/state/raft/raft_test.go | 73 ++++ manager/state/store/memory.go | 118 +++++- manager/state/store/memory_test.go | 232 ++++++++++-- manager/state/testutils/mock_proposer.go | 59 +++ manager/state/watch.go | 20 +- manager/storeapi/server_test.go | 20 +- manager/storeapi/watch.go | 67 ++-- manager/storeapi/watch_test.go | 64 +++- protobuf/plugin/storeobject/storeobject.go | 40 ++ 15 files changed, 1111 insertions(+), 182 deletions(-) create mode 100644 manager/state/testutils/mock_proposer.go diff --git a/api/objects.pb.go b/api/objects.pb.go index bcf401c0a0..37264443de 100644 --- a/api/objects.pb.go +++ b/api/objects.pb.go @@ -2925,6 +2925,84 @@ func NewStoreAction(c Event) (StoreAction, error) { return sa, nil } +func EventFromStoreAction(sa StoreAction) (Event, error) { + switch v := sa.Target.(type) { + case *StoreAction_Node: + switch sa.Action { + case StoreActionKindCreate: + return EventCreateNode{Node: v.Node}, nil + case StoreActionKindUpdate: + return EventUpdateNode{Node: v.Node}, nil + case StoreActionKindRemove: + return EventDeleteNode{Node: v.Node}, nil + } + case *StoreAction_Service: + switch sa.Action { + case StoreActionKindCreate: + return EventCreateService{Service: v.Service}, nil + case StoreActionKindUpdate: + return EventUpdateService{Service: v.Service}, nil + case StoreActionKindRemove: + return EventDeleteService{Service: v.Service}, nil + } + case *StoreAction_Task: + switch sa.Action { + case StoreActionKindCreate: + return EventCreateTask{Task: v.Task}, nil + case StoreActionKindUpdate: + return EventUpdateTask{Task: v.Task}, nil + case StoreActionKindRemove: + return EventDeleteTask{Task: v.Task}, nil + } + case *StoreAction_Network: + switch sa.Action { + case StoreActionKindCreate: + return EventCreateNetwork{Network: v.Network}, nil + case StoreActionKindUpdate: + return EventUpdateNetwork{Network: v.Network}, nil + case StoreActionKindRemove: + return EventDeleteNetwork{Network: v.Network}, nil + } + case *StoreAction_Cluster: + switch sa.Action { + case StoreActionKindCreate: + return EventCreateCluster{Cluster: v.Cluster}, nil + case StoreActionKindUpdate: + return EventUpdateCluster{Cluster: v.Cluster}, nil + case StoreActionKindRemove: + return EventDeleteCluster{Cluster: v.Cluster}, nil + } + case *StoreAction_Secret: + switch sa.Action { + case StoreActionKindCreate: + return EventCreateSecret{Secret: v.Secret}, nil + case StoreActionKindUpdate: + return EventUpdateSecret{Secret: v.Secret}, nil + case StoreActionKindRemove: + return EventDeleteSecret{Secret: v.Secret}, nil + } + case *StoreAction_Resource: + switch sa.Action { + case StoreActionKindCreate: + return EventCreateResource{Resource: v.Resource}, nil + case StoreActionKindUpdate: + return EventUpdateResource{Resource: v.Resource}, nil + case StoreActionKindRemove: + return EventDeleteResource{Resource: v.Resource}, nil + } + case *StoreAction_Extension: + switch sa.Action { + case StoreActionKindCreate: + return EventCreateExtension{Extension: v.Extension}, nil + case StoreActionKindUpdate: + return EventUpdateExtension{Extension: v.Extension}, nil + case StoreActionKindRemove: + return EventDeleteExtension{Extension: v.Extension}, nil + } + } + return nil, errUnknownStoreAction +} + func (this *Meta) String() string { if this == nil { return "nil" diff --git a/api/store.pb.go b/api/store.pb.go index 8660ca6b55..9a0fbe6283 100644 --- a/api/store.pb.go +++ b/api/store.pb.go @@ -845,6 +845,12 @@ type WatchRequest struct { // matches all of the selectors specified in any single watch entry, // the event will be sent to the client. Entries []*WatchRequest_WatchEntry `protobuf:"bytes,1,rep,name=entries" json:"entries,omitempty"` + // ResumeFrom provides an version to resume the watch from, if non-nil. + // The watch will return changes since this version, and continue to + // return new changes afterwards. Watch will return an error if the + // server has compacted its log and no longer has complete history to + // this point. + ResumeFrom *Version `protobuf:"bytes,2,opt,name=resume_from,json=resumeFrom" json:"resume_from,omitempty"` } func (m *WatchRequest) Reset() { *m = WatchRequest{} } @@ -870,17 +876,28 @@ func (*WatchRequest_WatchEntry) Descriptor() ([]byte, []int) { return fileDescri // Watch. Note that the first item of this stream will always be a WatchMessage // with a nil Object, to signal that the stream has started. type WatchMessage struct { + Events []*WatchMessage_Event `protobuf:"bytes,1,rep,name=events" json:"events,omitempty"` + // Index versions this change to the data store. It can be used to + // resume the watch from this point. + Version *Version `protobuf:"bytes,2,opt,name=version" json:"version,omitempty"` +} + +func (m *WatchMessage) Reset() { *m = WatchMessage{} } +func (*WatchMessage) ProtoMessage() {} +func (*WatchMessage) Descriptor() ([]byte, []int) { return fileDescriptorStore, []int{5} } + +type WatchMessage_Event struct { // Action (create/update/delete) - // Note that WatchMessage does not expose "commit" events that mark - // transaction boundaries. + // Note that WatchMessage does not expose "commit" events that + // mark transaction boundaries. Action StoreActionKind `protobuf:"varint,1,opt,name=action,proto3,enum=docker.swarmkit.v1.StoreActionKind" json:"action,omitempty"` // Matched object Object *Object `protobuf:"bytes,2,opt,name=object" json:"object,omitempty"` } -func (m *WatchMessage) Reset() { *m = WatchMessage{} } -func (*WatchMessage) ProtoMessage() {} -func (*WatchMessage) Descriptor() ([]byte, []int) { return fileDescriptorStore, []int{5} } +func (m *WatchMessage_Event) Reset() { *m = WatchMessage_Event{} } +func (*WatchMessage_Event) ProtoMessage() {} +func (*WatchMessage_Event) Descriptor() ([]byte, []int) { return fileDescriptorStore, []int{5, 0} } func init() { proto.RegisterType((*Object)(nil), "docker.swarmkit.v1.Object") @@ -890,6 +907,7 @@ func init() { proto.RegisterType((*WatchRequest)(nil), "docker.swarmkit.v1.WatchRequest") proto.RegisterType((*WatchRequest_WatchEntry)(nil), "docker.swarmkit.v1.WatchRequest.WatchEntry") proto.RegisterType((*WatchMessage)(nil), "docker.swarmkit.v1.WatchMessage") + proto.RegisterType((*WatchMessage_Event)(nil), "docker.swarmkit.v1.WatchMessage.Event") } type authenticatedWrapperStoreServer struct { @@ -1129,6 +1147,10 @@ func (m *WatchRequest) CopyFrom(src interface{}) { } } + if o.ResumeFrom != nil { + m.ResumeFrom = &Version{} + github_com_docker_swarmkit_api_deepcopy.Copy(m.ResumeFrom, o.ResumeFrom) + } } func (m *WatchRequest_WatchEntry) Copy() *WatchRequest_WatchEntry { @@ -1167,6 +1189,33 @@ func (m *WatchMessage) CopyFrom(src interface{}) { o := src.(*WatchMessage) *m = *o + if o.Events != nil { + m.Events = make([]*WatchMessage_Event, len(o.Events)) + for i := range m.Events { + m.Events[i] = &WatchMessage_Event{} + github_com_docker_swarmkit_api_deepcopy.Copy(m.Events[i], o.Events[i]) + } + } + + if o.Version != nil { + m.Version = &Version{} + github_com_docker_swarmkit_api_deepcopy.Copy(m.Version, o.Version) + } +} + +func (m *WatchMessage_Event) Copy() *WatchMessage_Event { + if m == nil { + return nil + } + o := &WatchMessage_Event{} + o.CopyFrom(m) + return o +} + +func (m *WatchMessage_Event) CopyFrom(src interface{}) { + + o := src.(*WatchMessage_Event) + *m = *o if o.Object != nil { m.Object = &Object{} github_com_docker_swarmkit_api_deepcopy.Copy(m.Object, o.Object) @@ -1671,6 +1720,16 @@ func (m *WatchRequest) MarshalTo(dAtA []byte) (int, error) { i += n } } + if m.ResumeFrom != nil { + dAtA[i] = 0x12 + i++ + i = encodeVarintStore(dAtA, i, uint64(m.ResumeFrom.Size())) + n14, err := m.ResumeFrom.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n14 + } return i, nil } @@ -1726,6 +1785,46 @@ func (m *WatchMessage) Marshal() (dAtA []byte, err error) { } func (m *WatchMessage) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Events) > 0 { + for _, msg := range m.Events { + dAtA[i] = 0xa + i++ + i = encodeVarintStore(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n + } + } + if m.Version != nil { + dAtA[i] = 0x12 + i++ + i = encodeVarintStore(dAtA, i, uint64(m.Version.Size())) + n15, err := m.Version.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n15 + } + return i, nil +} + +func (m *WatchMessage_Event) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *WatchMessage_Event) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int @@ -1739,11 +1838,11 @@ func (m *WatchMessage) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x12 i++ i = encodeVarintStore(dAtA, i, uint64(m.Object.Size())) - n14, err := m.Object.MarshalTo(dAtA[i:]) + n16, err := m.Object.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n14 + i += n16 } return i, nil } @@ -2137,6 +2236,10 @@ func (m *WatchRequest) Size() (n int) { n += 1 + l + sovStore(uint64(l)) } } + if m.ResumeFrom != nil { + l = m.ResumeFrom.Size() + n += 1 + l + sovStore(uint64(l)) + } return n } @@ -2160,6 +2263,22 @@ func (m *WatchRequest_WatchEntry) Size() (n int) { } func (m *WatchMessage) Size() (n int) { + var l int + _ = l + if len(m.Events) > 0 { + for _, e := range m.Events { + l = e.Size() + n += 1 + l + sovStore(uint64(l)) + } + } + if m.Version != nil { + l = m.Version.Size() + n += 1 + l + sovStore(uint64(l)) + } + return n +} + +func (m *WatchMessage_Event) Size() (n int) { var l int _ = l if m.Action != 0 { @@ -2464,6 +2583,7 @@ func (this *WatchRequest) String() string { } s := strings.Join([]string{`&WatchRequest{`, `Entries:` + strings.Replace(fmt.Sprintf("%v", this.Entries), "WatchRequest_WatchEntry", "WatchRequest_WatchEntry", 1) + `,`, + `ResumeFrom:` + strings.Replace(fmt.Sprintf("%v", this.ResumeFrom), "Version", "Version", 1) + `,`, `}`, }, "") return s @@ -2485,6 +2605,17 @@ func (this *WatchMessage) String() string { return "nil" } s := strings.Join([]string{`&WatchMessage{`, + `Events:` + strings.Replace(fmt.Sprintf("%v", this.Events), "WatchMessage_Event", "WatchMessage_Event", 1) + `,`, + `Version:` + strings.Replace(fmt.Sprintf("%v", this.Version), "Version", "Version", 1) + `,`, + `}`, + }, "") + return s +} +func (this *WatchMessage_Event) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&WatchMessage_Event{`, `Action:` + fmt.Sprintf("%v", this.Action) + `,`, `Object:` + strings.Replace(fmt.Sprintf("%v", this.Object), "Object", "Object", 1) + `,`, `}`, @@ -3567,6 +3698,39 @@ func (m *WatchRequest) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ResumeFrom", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ResumeFrom == nil { + m.ResumeFrom = &Version{} + } + if err := m.ResumeFrom.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipStore(dAtA[iNdEx:]) @@ -3746,6 +3910,120 @@ func (m *WatchMessage) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: WatchMessage: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Events", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Events = append(m.Events, &WatchMessage_Event{}) + if err := m.Events[len(m.Events)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Version == nil { + m.Version = &Version{} + } + if err := m.Version.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipStore(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthStore + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *WatchMessage_Event) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Event: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Event: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { case 1: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field Action", wireType) @@ -3927,63 +4205,66 @@ var ( func init() { proto.RegisterFile("store.proto", fileDescriptorStore) } var fileDescriptorStore = []byte{ - // 913 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x94, 0x95, 0xcd, 0x6e, 0x23, 0x45, - 0x10, 0xc7, 0x3d, 0x8e, 0x33, 0xb6, 0xcb, 0xf6, 0xae, 0xd4, 0xc9, 0xc2, 0xc8, 0x04, 0xdb, 0x18, - 0x21, 0x22, 0x2d, 0x78, 0xc1, 0xa0, 0x45, 0xe2, 0xe3, 0x80, 0x37, 0x91, 0x6c, 0x50, 0x96, 0xa8, - 0x8d, 0xc4, 0x31, 0x9a, 0xcc, 0x54, 0xbc, 0x83, 0xc7, 0x33, 0xa6, 0xbb, 0x9d, 0xdd, 0x9c, 0xe0, - 0x25, 0x90, 0x38, 0xf1, 0x08, 0x3c, 0xc7, 0x8a, 0x03, 0xe2, 0xc8, 0xc9, 0x62, 0xe7, 0x0e, 0xcf, - 0x80, 0xba, 0xba, 0x27, 0x0e, 0xec, 0x78, 0xd1, 0x9e, 0xa6, 0xbb, 0xe6, 0xf7, 0xaf, 0xae, 0xae, - 0xea, 0xae, 0x86, 0x86, 0x54, 0xa9, 0xc0, 0xc1, 0x52, 0xa4, 0x2a, 0x65, 0x2c, 0x4c, 0x83, 0x39, - 0x8a, 0x81, 0x7c, 0xec, 0x8b, 0xc5, 0x3c, 0x52, 0x83, 0xcb, 0xf7, 0xdb, 0x0d, 0xb9, 0xc4, 0x40, - 0x1a, 0xa0, 0xdd, 0x4a, 0xcf, 0xbf, 0xc5, 0x40, 0xe5, 0x53, 0x10, 0xfe, 0x85, 0xb2, 0xe3, 0x86, - 0xba, 0x5a, 0x62, 0xfe, 0x63, 0x7f, 0x96, 0xce, 0x52, 0x1a, 0xde, 0xd3, 0x23, 0x6b, 0xdd, 0x5b, - 0xc6, 0xab, 0x59, 0x94, 0xdc, 0x33, 0x1f, 0x63, 0xec, 0xff, 0xb6, 0x03, 0xee, 0x57, 0xe4, 0x95, - 0x0d, 0xa0, 0x92, 0xa4, 0x21, 0x7a, 0x4e, 0xcf, 0x39, 0x6c, 0x0c, 0xbd, 0xc1, 0xf3, 0xd1, 0x0c, - 0x1e, 0xa6, 0x21, 0x8e, 0x4b, 0x9c, 0x38, 0xf6, 0x11, 0x54, 0x25, 0x8a, 0xcb, 0x28, 0x40, 0xaf, - 0x4c, 0x92, 0xd7, 0x8a, 0x24, 0x53, 0x83, 0x8c, 0x4b, 0x3c, 0xa7, 0xb5, 0x30, 0x41, 0xf5, 0x38, - 0x15, 0x73, 0x6f, 0x67, 0xbb, 0xf0, 0xa1, 0x41, 0xb4, 0xd0, 0xd2, 0x3a, 0x42, 0xe5, 0xcb, 0xb9, - 0x57, 0xd9, 0x1e, 0xe1, 0xd7, 0xbe, 0xd4, 0x12, 0xe2, 0xf4, 0x42, 0x41, 0xbc, 0x92, 0x0a, 0x85, - 0xb7, 0xbb, 0x7d, 0xa1, 0x07, 0x06, 0xd1, 0x0b, 0x59, 0x9a, 0x7d, 0x08, 0xae, 0xc4, 0x40, 0xa0, - 0xf2, 0x5c, 0xd2, 0xb5, 0x8b, 0x77, 0xa6, 0x89, 0x71, 0x89, 0x5b, 0x96, 0x7d, 0x0c, 0x35, 0x81, - 0x32, 0x5d, 0x89, 0x00, 0xbd, 0x2a, 0xe9, 0x0e, 0x8a, 0x74, 0xdc, 0x32, 0xe3, 0x12, 0xbf, 0xe6, - 0xd9, 0x67, 0x50, 0xc7, 0x27, 0x0a, 0x13, 0x19, 0xa5, 0x89, 0x57, 0x23, 0xf1, 0xeb, 0x45, 0xe2, - 0xe3, 0x1c, 0x1a, 0x97, 0xf8, 0x46, 0x31, 0xaa, 0xe5, 0x55, 0xec, 0x9f, 0x42, 0x73, 0x8a, 0x31, - 0x06, 0x6a, 0x74, 0x35, 0x8d, 0x53, 0xc5, 0xde, 0x01, 0xb0, 0x79, 0x3f, 0x8b, 0x42, 0xaa, 0x6d, - 0x7d, 0xd4, 0xca, 0xd6, 0xdd, 0xba, 0x2d, 0xcc, 0xe4, 0x88, 0xd7, 0x2d, 0x30, 0x09, 0x19, 0x83, - 0x8a, 0x8c, 0x53, 0x45, 0x05, 0xad, 0x70, 0x1a, 0xf7, 0x4f, 0xe1, 0x56, 0xee, 0xf1, 0xc1, 0x4a, - 0xaa, 0x74, 0xa1, 0xa9, 0x79, 0x94, 0x58, 0x6f, 0x9c, 0xc6, 0x6c, 0x1f, 0x76, 0xa3, 0x24, 0xc4, - 0x27, 0x24, 0xad, 0x73, 0x33, 0xd1, 0xd6, 0x4b, 0x3f, 0x5e, 0x21, 0x15, 0xba, 0xce, 0xcd, 0xa4, - 0xff, 0xb3, 0x0b, 0xb5, 0xdc, 0x25, 0xf3, 0xa0, 0x7c, 0x1d, 0x98, 0x9b, 0xad, 0xbb, 0xe5, 0xc9, - 0xd1, 0xb8, 0xc4, 0xcb, 0x51, 0xc8, 0xee, 0x42, 0x3d, 0x0a, 0xcf, 0x96, 0x02, 0x2f, 0x22, 0xeb, - 0x76, 0xd4, 0xcc, 0xd6, 0xdd, 0xda, 0xe4, 0xe8, 0x94, 0x6c, 0x3a, 0x81, 0x51, 0x68, 0xc6, 0x6c, - 0x1f, 0x2a, 0x89, 0xbf, 0xb0, 0x0b, 0xd1, 0x19, 0xf5, 0x17, 0xc8, 0xde, 0x80, 0x86, 0xfe, 0xe6, - 0x4e, 0x2a, 0xf6, 0x27, 0x68, 0xa3, 0x15, 0x7e, 0x0a, 0x6e, 0x40, 0xdb, 0xb2, 0x67, 0xa4, 0x5f, - 0x5c, 0xeb, 0x9b, 0x09, 0xd0, 0x35, 0x37, 0x1a, 0x36, 0x81, 0x96, 0x19, 0xe5, 0x4b, 0xb8, 0x2f, - 0xe1, 0xa4, 0x69, 0xa4, 0x36, 0x90, 0xc1, 0xbf, 0x2a, 0x55, 0x2d, 0xa8, 0x94, 0xae, 0xf9, 0xa6, - 0x56, 0x6f, 0x41, 0x55, 0xdf, 0x43, 0x0d, 0xd7, 0x08, 0x86, 0x6c, 0xdd, 0x75, 0xf5, 0x15, 0x25, - 0xd2, 0xd5, 0x3f, 0x27, 0x21, 0xbb, 0x6f, 0x4b, 0x5a, 0xa7, 0xc0, 0x7a, 0x2f, 0x0a, 0x4c, 0x1f, - 0x18, 0x9d, 0x3a, 0xcd, 0xb3, 0x23, 0x68, 0x85, 0x28, 0x23, 0x81, 0xe1, 0x99, 0x54, 0xbe, 0x42, - 0x0f, 0x7a, 0xce, 0xe1, 0xad, 0xe2, 0x53, 0xa9, 0x6f, 0xdd, 0x54, 0x43, 0x7a, 0x53, 0x56, 0x45, - 0x73, 0x36, 0x84, 0x8a, 0x48, 0x63, 0xf4, 0x1a, 0x24, 0x3e, 0xd8, 0xd6, 0x54, 0x78, 0x1a, 0x53, - 0x63, 0xd1, 0x2c, 0x9b, 0x00, 0x2c, 0x70, 0x71, 0x8e, 0x42, 0x3e, 0x8a, 0x96, 0x5e, 0x93, 0x94, - 0x6f, 0x6f, 0x53, 0x4e, 0x97, 0x18, 0x0c, 0x4e, 0xae, 0x71, 0x5d, 0xdc, 0x8d, 0x98, 0x9d, 0xc0, - 0x1d, 0x81, 0x17, 0x28, 0x30, 0x09, 0x30, 0x3c, 0xb3, 0x7d, 0x44, 0x67, 0xac, 0x45, 0x19, 0x7b, - 0x35, 0x5b, 0x77, 0xf7, 0xf8, 0x35, 0x60, 0x5b, 0x0e, 0xa5, 0x6f, 0x4f, 0x3c, 0x67, 0x0e, 0xd9, - 0x17, 0xb0, 0x7f, 0xc3, 0x9d, 0xb9, 0xf6, 0xda, 0xdb, 0x2d, 0xf2, 0xf6, 0x4a, 0xb6, 0xee, 0xb2, - 0x8d, 0x37, 0xd3, 0x1f, 0xc8, 0x19, 0x13, 0xff, 0xb5, 0xea, 0x0b, 0x63, 0x2e, 0xd1, 0xed, 0xfc, - 0xc0, 0xea, 0xd9, 0xa8, 0x02, 0xe5, 0xd1, 0x55, 0xff, 0x2f, 0x07, 0x9a, 0xdf, 0xf8, 0x2a, 0x78, - 0xc4, 0xf1, 0xbb, 0x15, 0x4a, 0xc5, 0x8e, 0xa1, 0x8a, 0x89, 0x12, 0x11, 0x4a, 0xcf, 0xe9, 0xed, - 0x1c, 0x36, 0x86, 0x77, 0x8b, 0xf2, 0x71, 0x53, 0x62, 0x26, 0xc7, 0x89, 0x12, 0x57, 0x3c, 0xd7, - 0xb6, 0x7f, 0x74, 0x00, 0x36, 0xf6, 0xc2, 0x7b, 0xfc, 0x09, 0xb8, 0x7e, 0xa0, 0x74, 0x17, 0x2a, - 0x53, 0xe2, 0xdf, 0x2c, 0x3c, 0x30, 0xfa, 0xd5, 0xfa, 0x9c, 0xb0, 0x2f, 0xa3, 0x24, 0xe4, 0x56, - 0xc2, 0xee, 0x43, 0xf5, 0x22, 0x8a, 0x15, 0x0a, 0xe9, 0xed, 0x50, 0x98, 0x07, 0x2f, 0x3a, 0x6e, - 0x3c, 0x87, 0xfb, 0xdf, 0xdb, 0xed, 0x9e, 0xa0, 0x94, 0xfe, 0x0c, 0x6f, 0x04, 0xe1, 0xbc, 0x7c, - 0x10, 0x43, 0x70, 0xcd, 0x3b, 0x69, 0x9f, 0xa5, 0xc2, 0xe6, 0x6d, 0xba, 0x25, 0xb7, 0xe4, 0x70, - 0x01, 0xbb, 0xe4, 0x8e, 0x85, 0xb0, 0x4b, 0x91, 0xb0, 0xde, 0xff, 0x25, 0xb8, 0xbd, 0x9d, 0xb0, - 0xdb, 0xe8, 0xdf, 0xf9, 0xf5, 0x97, 0xbf, 0x7f, 0x2a, 0xdf, 0x86, 0x16, 0x11, 0xef, 0x2e, 0xfc, - 0xc4, 0x9f, 0xa1, 0x78, 0xcf, 0x19, 0x79, 0x4f, 0x9f, 0x75, 0x4a, 0x7f, 0x3c, 0xeb, 0x94, 0x7e, - 0xc8, 0x3a, 0xce, 0xd3, 0xac, 0xe3, 0xfc, 0x9e, 0x75, 0x9c, 0x3f, 0xb3, 0x8e, 0x73, 0xee, 0xd2, - 0xb3, 0xfc, 0xc1, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xd7, 0xef, 0x30, 0x33, 0x19, 0x08, 0x00, - 0x00, + // 975 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x94, 0x96, 0xdf, 0x8e, 0x22, 0x45, + 0x14, 0xc6, 0x69, 0x06, 0x1a, 0x38, 0xc0, 0x6c, 0x52, 0x33, 0xab, 0x1d, 0x1c, 0x01, 0x31, 0xea, + 0x24, 0xab, 0xac, 0xa2, 0xae, 0x89, 0xae, 0x26, 0xb2, 0x33, 0x06, 0x34, 0xb3, 0x4e, 0x0a, 0xa3, + 0x97, 0xa4, 0xa7, 0xfb, 0xc0, 0xb6, 0xd0, 0xdd, 0x58, 0x55, 0xb0, 0x33, 0x77, 0xbe, 0x84, 0x89, + 0x57, 0xbe, 0x80, 0x89, 0xcf, 0xb1, 0xf1, 0xc2, 0x78, 0xe9, 0x15, 0x71, 0xfb, 0x01, 0x7c, 0x05, + 0x4d, 0xfd, 0xe9, 0x61, 0x74, 0x9b, 0x59, 0xe7, 0x8a, 0xaa, 0xea, 0xdf, 0x77, 0xaa, 0xea, 0x3b, + 0x55, 0xa7, 0x80, 0x2a, 0x17, 0x31, 0xc3, 0xee, 0x82, 0xc5, 0x22, 0x26, 0xc4, 0x8f, 0xbd, 0x19, + 0xb2, 0x2e, 0x7f, 0xec, 0xb2, 0x70, 0x16, 0x88, 0xee, 0xea, 0x9d, 0x46, 0x95, 0x2f, 0xd0, 0xe3, + 0x1a, 0x68, 0xd4, 0xe3, 0xb3, 0x6f, 0xd1, 0x13, 0x69, 0x17, 0x98, 0x3b, 0x11, 0xa6, 0x5d, 0x15, + 0x17, 0x0b, 0x4c, 0x3f, 0xec, 0x4f, 0xe3, 0x69, 0xac, 0x9a, 0x77, 0x65, 0xcb, 0x8c, 0xee, 0x2d, + 0xe6, 0xcb, 0x69, 0x10, 0xdd, 0xd5, 0x3f, 0x7a, 0xb0, 0xf3, 0xdb, 0x0e, 0xd8, 0x5f, 0xaa, 0xa8, + 0xa4, 0x0b, 0x85, 0x28, 0xf6, 0xd1, 0xb1, 0xda, 0xd6, 0x61, 0xb5, 0xe7, 0x74, 0x9f, 0x5d, 0x4d, + 0xf7, 0x61, 0xec, 0xe3, 0x20, 0x47, 0x15, 0x47, 0x3e, 0x80, 0x12, 0x47, 0xb6, 0x0a, 0x3c, 0x74, + 0xf2, 0x4a, 0xf2, 0x52, 0x96, 0x64, 0xa4, 0x91, 0x41, 0x8e, 0xa6, 0xb4, 0x14, 0x46, 0x28, 0x1e, + 0xc7, 0x6c, 0xe6, 0xec, 0x6c, 0x17, 0x3e, 0xd4, 0x88, 0x14, 0x1a, 0x5a, 0xae, 0x50, 0xb8, 0x7c, + 0xe6, 0x14, 0xb6, 0xaf, 0xf0, 0x2b, 0x97, 0x4b, 0x89, 0xe2, 0xe4, 0x44, 0xde, 0x7c, 0xc9, 0x05, + 0x32, 0xa7, 0xb8, 0x7d, 0xa2, 0x07, 0x1a, 0x91, 0x13, 0x19, 0x9a, 0xbc, 0x07, 0x36, 0x47, 0x8f, + 0xa1, 0x70, 0x6c, 0xa5, 0x6b, 0x64, 0xef, 0x4c, 0x12, 0x83, 0x1c, 0x35, 0x2c, 0xf9, 0x10, 0xca, + 0x0c, 0x79, 0xbc, 0x64, 0x1e, 0x3a, 0x25, 0xa5, 0x3b, 0xc8, 0xd2, 0x51, 0xc3, 0x0c, 0x72, 0xf4, + 0x92, 0x27, 0x1f, 0x43, 0x05, 0xcf, 0x05, 0x46, 0x3c, 0x88, 0x23, 0xa7, 0xac, 0xc4, 0x2f, 0x67, + 0x89, 0x8f, 0x53, 0x68, 0x90, 0xa3, 0x1b, 0x45, 0xbf, 0x9c, 0x66, 0xb1, 0x73, 0x0a, 0xb5, 0x11, + 0xce, 0xd1, 0x13, 0xfd, 0x8b, 0xd1, 0x3c, 0x16, 0xe4, 0x4d, 0x00, 0xe3, 0xfb, 0x38, 0xf0, 0x55, + 0x6e, 0x2b, 0xfd, 0x7a, 0xb2, 0x6e, 0x55, 0x4c, 0x62, 0x86, 0x47, 0xb4, 0x62, 0x80, 0xa1, 0x4f, + 0x08, 0x14, 0xf8, 0x3c, 0x16, 0x2a, 0xa1, 0x05, 0xaa, 0xda, 0x9d, 0x53, 0xd8, 0x4d, 0x23, 0x3e, + 0x58, 0x72, 0x11, 0x87, 0x92, 0x9a, 0x05, 0x91, 0x89, 0x46, 0x55, 0x9b, 0xec, 0x43, 0x31, 0x88, + 0x7c, 0x3c, 0x57, 0xd2, 0x0a, 0xd5, 0x1d, 0x39, 0xba, 0x72, 0xe7, 0x4b, 0x54, 0x89, 0xae, 0x50, + 0xdd, 0xe9, 0xfc, 0x64, 0x43, 0x39, 0x0d, 0x49, 0x1c, 0xc8, 0x5f, 0x2e, 0xcc, 0x4e, 0xd6, 0xad, + 0xfc, 0xf0, 0x68, 0x90, 0xa3, 0xf9, 0xc0, 0x27, 0x77, 0xa0, 0x12, 0xf8, 0xe3, 0x05, 0xc3, 0x49, + 0x60, 0xc2, 0xf6, 0x6b, 0xc9, 0xba, 0x55, 0x1e, 0x1e, 0x9d, 0xaa, 0x31, 0x69, 0x60, 0xe0, 0xeb, + 0x36, 0xd9, 0x87, 0x42, 0xe4, 0x86, 0x66, 0x22, 0x75, 0x46, 0xdd, 0x10, 0xc9, 0x2b, 0x50, 0x95, + 0xbf, 0x69, 0x90, 0x82, 0xf9, 0x08, 0x72, 0xd0, 0x08, 0xef, 0x83, 0xed, 0xa9, 0x6d, 0x99, 0x33, + 0xd2, 0xc9, 0xce, 0xf5, 0x55, 0x03, 0x64, 0xce, 0xb5, 0x86, 0x0c, 0xa1, 0xae, 0x5b, 0xe9, 0x14, + 0xf6, 0x0d, 0x82, 0xd4, 0xb4, 0xd4, 0x2c, 0xa4, 0xfb, 0xaf, 0x4c, 0x95, 0x32, 0x32, 0x25, 0x73, + 0xbe, 0xc9, 0xd5, 0x6b, 0x50, 0x92, 0xf7, 0x50, 0xc2, 0x65, 0x05, 0x43, 0xb2, 0x6e, 0xd9, 0xf2, + 0x8a, 0x2a, 0xd2, 0x96, 0x1f, 0x87, 0x3e, 0xb9, 0x67, 0x52, 0x5a, 0x51, 0x0b, 0x6b, 0x5f, 0xb7, + 0x30, 0x79, 0x60, 0xa4, 0x75, 0x92, 0x27, 0x47, 0x50, 0xf7, 0x91, 0x07, 0x0c, 0xfd, 0x31, 0x17, + 0xae, 0x40, 0x07, 0xda, 0xd6, 0xe1, 0x6e, 0xf6, 0xa9, 0x94, 0xb7, 0x6e, 0x24, 0x21, 0xb9, 0x29, + 0xa3, 0x52, 0x7d, 0xd2, 0x83, 0x02, 0x8b, 0xe7, 0xe8, 0x54, 0x95, 0xf8, 0x60, 0x5b, 0x51, 0xa1, + 0xf1, 0x5c, 0x15, 0x16, 0xc9, 0x92, 0x21, 0x40, 0x88, 0xe1, 0x19, 0x32, 0xfe, 0x28, 0x58, 0x38, + 0x35, 0xa5, 0x7c, 0x63, 0x9b, 0x72, 0xb4, 0x40, 0xaf, 0x7b, 0x72, 0x89, 0xcb, 0xe4, 0x6e, 0xc4, + 0xe4, 0x04, 0x6e, 0x33, 0x9c, 0x20, 0xc3, 0xc8, 0x43, 0x7f, 0x6c, 0xea, 0x88, 0x74, 0xac, 0xae, + 0x1c, 0x7b, 0x31, 0x59, 0xb7, 0xf6, 0xe8, 0x25, 0x60, 0x4a, 0x8e, 0xb2, 0x6f, 0x8f, 0x3d, 0x33, + 0xec, 0x93, 0xcf, 0x61, 0xff, 0x4a, 0x38, 0x7d, 0xed, 0x65, 0xb4, 0x5d, 0x15, 0xed, 0x85, 0x64, + 0xdd, 0x22, 0x9b, 0x68, 0xba, 0x3e, 0xa8, 0x60, 0x84, 0xfd, 0x77, 0x54, 0x5e, 0x18, 0x7d, 0x89, + 0x6e, 0xa5, 0x07, 0x56, 0xf6, 0xfa, 0x05, 0xc8, 0xf7, 0x2f, 0x3a, 0x3f, 0xe7, 0xa1, 0xf6, 0x8d, + 0x2b, 0xbc, 0x47, 0x14, 0xbf, 0x5b, 0x22, 0x17, 0xe4, 0x18, 0x4a, 0x18, 0x09, 0x16, 0x20, 0x77, + 0xac, 0xf6, 0xce, 0x61, 0xb5, 0x77, 0x27, 0xcb, 0x8f, 0xab, 0x12, 0xdd, 0x39, 0x8e, 0x04, 0xbb, + 0xa0, 0xa9, 0x96, 0xdc, 0x87, 0x2a, 0x43, 0xbe, 0x0c, 0x71, 0x3c, 0x61, 0x71, 0x78, 0x5d, 0xd9, + 0xfe, 0x1a, 0x99, 0x2c, 0x2c, 0x14, 0x34, 0xff, 0x19, 0x8b, 0xc3, 0xc6, 0x0f, 0x16, 0xc0, 0x26, + 0x6a, 0x66, 0x15, 0xf8, 0x08, 0x6c, 0xd7, 0x13, 0xb2, 0x86, 0xe5, 0x55, 0xda, 0x5e, 0xcd, 0x3c, + 0x6e, 0xf2, 0xcd, 0xfb, 0x54, 0x61, 0x5f, 0x04, 0x91, 0x4f, 0x8d, 0x84, 0xdc, 0x83, 0xd2, 0x24, + 0x98, 0x0b, 0x64, 0xdc, 0xd9, 0x51, 0x9b, 0x3c, 0xb8, 0xee, 0xb0, 0xd2, 0x14, 0xee, 0xfc, 0x6d, + 0x19, 0xb7, 0x4e, 0x90, 0x73, 0x77, 0x8a, 0xe4, 0x13, 0xb0, 0x71, 0x85, 0x91, 0x48, 0xcd, 0x7a, + 0x7d, 0xab, 0x59, 0x46, 0xd1, 0x3d, 0x96, 0x38, 0x35, 0x2a, 0xf2, 0x3e, 0x94, 0x56, 0x7a, 0xff, + 0xff, 0xc7, 0xa2, 0x94, 0x6d, 0x9c, 0x43, 0x51, 0xc5, 0xb9, 0xe2, 0x82, 0x75, 0x73, 0x17, 0x7a, + 0x60, 0xeb, 0x67, 0xde, 0xcc, 0x9d, 0xf9, 0xf6, 0xe8, 0x62, 0x4f, 0x0d, 0xd9, 0x0b, 0xa1, 0xa8, + 0xc2, 0x11, 0x1f, 0x8a, 0x6a, 0x5f, 0xa4, 0xfd, 0xbc, 0xf3, 0xd1, 0x68, 0x3f, 0xcf, 0x94, 0xce, + 0xed, 0x5f, 0x7f, 0xf9, 0xeb, 0xc7, 0xfc, 0x2d, 0xa8, 0x2b, 0xe2, 0xad, 0xd0, 0x8d, 0xdc, 0x29, + 0xb2, 0xb7, 0xad, 0xbe, 0xf3, 0xe4, 0x69, 0x33, 0xf7, 0xc7, 0xd3, 0x66, 0xee, 0xfb, 0xa4, 0x69, + 0x3d, 0x49, 0x9a, 0xd6, 0xef, 0x49, 0xd3, 0xfa, 0x33, 0x69, 0x5a, 0x67, 0xb6, 0xfa, 0x57, 0xf1, + 0xee, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xb3, 0x39, 0x54, 0xe4, 0xd8, 0x08, 0x00, 0x00, } diff --git a/api/store.proto b/api/store.proto index c820b7382b..21e149fdfa 100644 --- a/api/store.proto +++ b/api/store.proto @@ -98,17 +98,32 @@ message WatchRequest { // matches all of the selectors specified in any single watch entry, // the event will be sent to the client. repeated WatchEntry entries = 1; + + // ResumeFrom provides an version to resume the watch from, if non-nil. + // The watch will return changes since this version, and continue to + // return new changes afterwards. Watch will return an error if the + // server has compacted its log and no longer has complete history to + // this point. + Version resume_from = 2; } // WatchMessage is the type of the stream that's returned to the client by // Watch. Note that the first item of this stream will always be a WatchMessage // with a nil Object, to signal that the stream has started. message WatchMessage { - // Action (create/update/delete) - // Note that WatchMessage does not expose "commit" events that mark - // transaction boundaries. - StoreActionKind action = 1; + message Event { + // Action (create/update/delete) + // Note that WatchMessage does not expose "commit" events that + // mark transaction boundaries. + StoreActionKind action = 1; + + // Matched object + Object object = 2; + } + + repeated Event events = 1; - // Matched object - Object object = 2; + // Index versions this change to the data store. It can be used to + // resume the watch from this point. + Version version = 2; } diff --git a/manager/controlapi/server_test.go b/manager/controlapi/server_test.go index 19a6e6dbe2..16844fb240 100644 --- a/manager/controlapi/server_test.go +++ b/manager/controlapi/server_test.go @@ -7,33 +7,17 @@ import ( "testing" "time" - "golang.org/x/net/context" - "google.golang.org/grpc" "github.com/docker/swarmkit/api" "github.com/docker/swarmkit/ca" cautils "github.com/docker/swarmkit/ca/testutils" "github.com/docker/swarmkit/manager/state/store" + stateutils "github.com/docker/swarmkit/manager/state/testutils" "github.com/stretchr/testify/assert" + "golang.org/x/net/context" ) -type mockProposer struct { - index uint64 -} - -func (mp *mockProposer) ProposeValue(ctx context.Context, storeAction []api.StoreAction, cb func()) error { - if cb != nil { - cb() - } - return nil -} - -func (mp *mockProposer) GetVersion() *api.Version { - mp.index += 3 - return &api.Version{Index: mp.index} -} - type testServer struct { Server *Server Client api.ControlClient @@ -61,7 +45,7 @@ func newTestServer(t *testing.T) *testServer { tc.Stop() assert.NoError(t, err) - ts.Store = store.NewMemoryStore(&mockProposer{}) + ts.Store = store.NewMemoryStore(&stateutils.MockProposer{}) assert.NotNil(t, ts.Store) ts.Server = NewServer(ts.Store, nil, securityConfig, ca.NewServer(ts.Store, securityConfig), nil) diff --git a/manager/state/proposer.go b/manager/state/proposer.go index 53390188e7..4967f98a1e 100644 --- a/manager/state/proposer.go +++ b/manager/state/proposer.go @@ -5,6 +5,13 @@ import ( "golang.org/x/net/context" ) +// A Change includes a version number and a set of store actions from a +// particular log entry. +type Change struct { + StoreActions []api.StoreAction + Version api.Version +} + // A Proposer can propose actions to a cluster. type Proposer interface { // ProposeValue adds storeAction to the distributed log. If this @@ -13,5 +20,11 @@ type Proposer interface { // sure that the changes are committed before it interacts further // with the store. ProposeValue(ctx context.Context, storeAction []api.StoreAction, cb func()) error + // GetVersion returns the monotonic index of the most recent item in + // the distributed log. GetVersion() *api.Version + // ChangesBetween returns the changes starting after "from", up to and + // including "to". If these changes are not available because the log + // has been compacted, an error will be returned. + ChangesBetween(from, to api.Version) ([]Change, error) } diff --git a/manager/state/raft/raft.go b/manager/state/raft/raft.go index 6f385f5706..aa377b7dd0 100644 --- a/manager/state/raft/raft.go +++ b/manager/state/raft/raft.go @@ -25,6 +25,7 @@ import ( "github.com/docker/swarmkit/ca" "github.com/docker/swarmkit/log" "github.com/docker/swarmkit/manager/raftselector" + "github.com/docker/swarmkit/manager/state" "github.com/docker/swarmkit/manager/state/raft/membership" "github.com/docker/swarmkit/manager/state/raft/storage" "github.com/docker/swarmkit/manager/state/raft/transport" @@ -1434,6 +1435,52 @@ func (n *Node) GetVersion() *api.Version { return &api.Version{Index: status.Commit} } +// ChangesBetween returns the changes starting after "from", up to and +// including "to". If these changes are not available because the log +// has been compacted, an error will be returned. +func (n *Node) ChangesBetween(from, to api.Version) ([]state.Change, error) { + n.stopMu.RLock() + defer n.stopMu.RUnlock() + + if from.Index > to.Index { + return nil, errors.New("versions are out of order") + } + + if !n.IsMember() { + return nil, ErrNoRaftMember + } + + // never returns error + last, _ := n.raftStore.LastIndex() + + if to.Index > last { + return nil, errors.New("last version is out of bounds") + } + + pbs, err := n.raftStore.Entries(from.Index+1, to.Index+1, math.MaxUint64) + if err != nil { + return nil, err + } + + var changes []state.Change + for _, pb := range pbs { + if pb.Type != raftpb.EntryNormal || pb.Data == nil { + continue + } + r := &api.InternalRaftRequest{} + err := proto.Unmarshal(pb.Data, r) + if err != nil { + return nil, errors.Wrap(err, "error umarshalling internal raft request") + } + + if r.Action != nil { + changes = append(changes, state.Change{StoreActions: r.Action, Version: api.Version{Index: pb.Index}}) + } + } + + return changes, nil +} + // SubscribePeers subscribes to peer updates in cluster. It sends always full // list of peers. func (n *Node) SubscribePeers() (q chan events.Event, cancel func()) { diff --git a/manager/state/raft/raft_test.go b/manager/state/raft/raft_test.go index 973e408ee4..2b4212ee41 100644 --- a/manager/state/raft/raft_test.go +++ b/manager/state/raft/raft_test.go @@ -22,6 +22,7 @@ import ( "github.com/coreos/etcd/wal" "github.com/docker/swarmkit/api" cautils "github.com/docker/swarmkit/ca/testutils" + "github.com/docker/swarmkit/manager/state" "github.com/docker/swarmkit/manager/state/raft" raftutils "github.com/docker/swarmkit/manager/state/raft/testutils" "github.com/docker/swarmkit/manager/state/store" @@ -418,6 +419,78 @@ func TestRaftNewNodeGetsData(t *testing.T) { } } +func TestChangesBetween(t *testing.T) { + t.Parallel() + + node, _ := raftutils.NewInitNode(t, tc, nil) + defer raftutils.ShutdownNode(node) + + startVersion := node.GetVersion() + + // Propose 10 values + nodeIDs := []string{"id1", "id2", "id3", "id4", "id5", "id6", "id7", "id8", "id9", "id10"} + values := make([]*api.Node, 10) + for i, nodeID := range nodeIDs { + value, err := raftutils.ProposeValue(t, node, DefaultProposalTime, nodeID) + assert.NoError(t, err, "failed to propose value") + values[i] = value + } + + versionAdd := func(version *api.Version, offset int64) api.Version { + return api.Version{Index: uint64(int64(version.Index) + offset)} + } + + expectedChanges := func(startVersion api.Version, values []*api.Node) []state.Change { + var changes []state.Change + + for i, value := range values { + changes = append(changes, + state.Change{ + Version: versionAdd(&startVersion, int64(i+1)), + StoreActions: []api.StoreAction{ + { + Action: api.StoreActionKindCreate, + Target: &api.StoreAction_Node{ + Node: value, + }, + }, + }, + }, + ) + } + + return changes + } + + // Satisfiable requests + changes, err := node.ChangesBetween(versionAdd(startVersion, -1), *startVersion) + assert.NoError(t, err) + assert.Len(t, changes, 0) + + changes, err = node.ChangesBetween(*startVersion, versionAdd(startVersion, 1)) + assert.NoError(t, err) + require.Len(t, changes, 1) + assert.Equal(t, expectedChanges(*startVersion, values[:1]), changes) + + changes, err = node.ChangesBetween(*startVersion, versionAdd(startVersion, 10)) + assert.NoError(t, err) + require.Len(t, changes, 10) + assert.Equal(t, expectedChanges(*startVersion, values), changes) + + changes, err = node.ChangesBetween(versionAdd(startVersion, 2), versionAdd(startVersion, 6)) + assert.NoError(t, err) + require.Len(t, changes, 4) + assert.Equal(t, expectedChanges(versionAdd(startVersion, 2), values[2:6]), changes) + + // Unsatisfiable requests + _, err = node.ChangesBetween(versionAdd(startVersion, -1), versionAdd(startVersion, 11)) + assert.Error(t, err) + _, err = node.ChangesBetween(versionAdd(startVersion, 11), versionAdd(startVersion, 11)) + assert.Error(t, err) + _, err = node.ChangesBetween(versionAdd(startVersion, 11), versionAdd(startVersion, 15)) + assert.Error(t, err) +} + func TestRaftRejoin(t *testing.T) { t.Parallel() diff --git a/manager/state/store/memory.go b/manager/state/store/memory.go index 4d987b5203..e0877b5179 100644 --- a/manager/state/store/memory.go +++ b/manager/state/store/memory.go @@ -180,6 +180,33 @@ type tx struct { changelist []api.Event } +// changelistBetweenVersions returns the changes after "from" up to and +// including "to". +func (s *MemoryStore) changelistBetweenVersions(from, to api.Version) ([]api.Event, error) { + if s.proposer == nil { + return nil, errors.New("store does not support versioning") + } + changes, err := s.proposer.ChangesBetween(from, to) + if err != nil { + return nil, err + } + + var changelist []api.Event + + for _, change := range changes { + for _, sa := range change.StoreActions { + event, err := api.EventFromStoreAction(sa) + if err != nil { + return nil, err + } + changelist = append(changelist, event) + } + changelist = append(changelist, state.EventCommit{Version: change.Version.Copy()}) + } + + return changelist, nil +} + // ApplyStoreActions updates a store based on StoreAction messages. func (s *MemoryStore) ApplyStoreActions(actions []api.StoreAction) error { s.updateLock.Lock() @@ -261,7 +288,11 @@ func (s *MemoryStore) update(proposer state.Proposer, cb func(Tx) error) error { s.queue.Publish(c) } if len(tx.changelist) != 0 { - s.queue.Publish(state.EventCommit{}) + if proposer != nil { + curVersion = proposer.GetVersion() + } + + s.queue.Publish(state.EventCommit{Version: curVersion}) } } else { memDBTx.Abort() @@ -755,6 +786,91 @@ func ViewAndWatch(store *MemoryStore, cb func(ReadTx) error, specifiers ...api.E return } +// WatchFrom returns a channel that will return past events from starting +// from "version", and new events until the channel is closed. If "version" +// is nil, this function is equivalent to +// +// state.Watch(store.WatchQueue(), specifiers...). +// +// If the log has been compacted and it's not possible to produce the exact +// set of events leading from "version" to the current state, this function +// will return an error, and the caller should re-sync. +// +// The watch channel must be released with watch.StopWatch when it is no +// longer needed. +func WatchFrom(store *MemoryStore, version *api.Version, specifiers ...api.Event) (chan events.Event, func(), error) { + if version == nil { + ch, cancel := state.Watch(store.WatchQueue(), specifiers...) + return ch, cancel, nil + } + + if store.proposer == nil { + return nil, nil, errors.New("store does not support versioning") + } + + var ( + curVersion *api.Version + watch chan events.Event + cancelWatch func() + ) + // Using Update to lock the store + err := store.Update(func(tx Tx) error { + // Get current version + curVersion = store.proposer.GetVersion() + // Start the watch with the store locked so events cannot be + // missed + watch, cancelWatch = state.Watch(store.WatchQueue(), specifiers...) + return nil + }) + if watch != nil && err != nil { + cancelWatch() + return nil, nil, err + } + + if curVersion == nil { + cancelWatch() + return nil, nil, errors.New("could not get current version from store") + } + + changelist, err := store.changelistBetweenVersions(*version, *curVersion) + if err != nil { + cancelWatch() + return nil, nil, err + } + + ch := make(chan events.Event) + stop := make(chan struct{}) + cancel := func() { + close(stop) + } + + go func() { + defer cancelWatch() + + matcher := state.Matcher(specifiers...) + for _, change := range changelist { + if matcher(change) { + select { + case ch <- change: + case <-stop: + return + } + } + } + + for { + select { + case <-stop: + return + case e := <-watch: + ch <- e + } + } + }() + + return ch, cancel, nil +} + // touchMeta updates an object's timestamps when necessary and bumps the version // if provided. func touchMeta(meta *api.Meta, version *api.Version) error { diff --git a/manager/state/store/memory_test.go b/manager/state/store/memory_test.go index d3a1009f1c..e6fb299590 100644 --- a/manager/state/store/memory_test.go +++ b/manager/state/store/memory_test.go @@ -10,9 +10,9 @@ import ( "github.com/docker/swarmkit/api" "github.com/docker/swarmkit/identity" "github.com/docker/swarmkit/manager/state" + "github.com/docker/swarmkit/manager/state/testutils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "golang.org/x/net/context" ) var ( @@ -905,25 +905,8 @@ func TestFailedTransaction(t *testing.T) { }) } -type mockProposer struct { - index uint64 -} - -func (mp *mockProposer) ProposeValue(ctx context.Context, storeAction []api.StoreAction, cb func()) error { - if cb != nil { - cb() - } - return nil -} - -func (mp *mockProposer) GetVersion() *api.Version { - mp.index += 3 - return &api.Version{Index: mp.index} -} - func TestVersion(t *testing.T) { - var mockProposer mockProposer - s := NewMemoryStore(&mockProposer) + s := NewMemoryStore(&testutils.MockProposer{}) assert.NotNil(t, s) var ( @@ -987,8 +970,7 @@ func TestVersion(t *testing.T) { } func TestTimestamps(t *testing.T) { - var mockProposer mockProposer - s := NewMemoryStore(&mockProposer) + s := NewMemoryStore(&testutils.MockProposer{}) assert.NotNil(t, s) var ( @@ -1039,8 +1021,7 @@ func TestTimestamps(t *testing.T) { } func TestBatch(t *testing.T) { - var mockProposer mockProposer - s := NewMemoryStore(&mockProposer) + s := NewMemoryStore(&testutils.MockProposer{}) assert.NotNil(t, s) watch, cancel := s.WatchQueue().Watch() @@ -1102,8 +1083,7 @@ func TestBatch(t *testing.T) { } func TestBatchFailure(t *testing.T) { - var mockProposer mockProposer - s := NewMemoryStore(&mockProposer) + s := NewMemoryStore(&testutils.MockProposer{}) assert.NotNil(t, s) watch, cancel := s.WatchQueue().Watch() @@ -1202,6 +1182,208 @@ func TestStoreSaveRestore(t *testing.T) { }) } +func TestWatchFrom(t *testing.T) { + s := NewMemoryStore(&testutils.MockProposer{}) + assert.NotNil(t, s) + + // Create a few nodes, 2 per transaction + for i := 0; i != 5; i++ { + committed, err := s.Batch(func(batch *Batch) error { + node := &api.Node{ + ID: "id" + strconv.Itoa(i), + Spec: api.NodeSpec{ + Annotations: api.Annotations{ + Name: "name" + strconv.Itoa(i), + }, + }, + } + + service := &api.Service{ + ID: "id" + strconv.Itoa(i), + Spec: api.ServiceSpec{ + Annotations: api.Annotations{ + Name: "name" + strconv.Itoa(i), + }, + }, + } + + batch.Update(func(tx Tx) error { + assert.NoError(t, CreateNode(tx, node)) + return nil + }) + batch.Update(func(tx Tx) error { + assert.NoError(t, CreateService(tx, service)) + return nil + }) + return nil + }) + assert.NoError(t, err) + assert.Equal(t, 2, committed) + } + + // Try to watch from an invalid index + _, _, err := WatchFrom(s, &api.Version{Index: 5000}) + assert.Error(t, err) + + watch1, cancel1, err := WatchFrom(s, &api.Version{Index: 10}, api.EventCreateNode{}, state.EventCommit{}) + require.NoError(t, err) + defer cancel1() + + for i := 0; i != 2; i++ { + select { + case event := <-watch1: + nodeEvent, ok := event.(api.EventCreateNode) + if !ok { + t.Fatal("wrong event type - expected node create") + } + + if i == 0 { + assert.Equal(t, "id3", nodeEvent.Node.ID) + } else { + assert.Equal(t, "id4", nodeEvent.Node.ID) + } + case <-time.After(time.Second): + t.Fatal("timed out waiting for event") + } + select { + case event := <-watch1: + if _, ok := event.(state.EventCommit); !ok { + t.Fatal("wrong event type - expected commit") + } + case <-time.After(time.Second): + t.Fatal("timed out waiting for event") + } + } + + watch2, cancel2, err := WatchFrom(s, &api.Version{Index: 13}, api.EventCreateService{}, state.EventCommit{}) + require.NoError(t, err) + defer cancel2() + + select { + case event := <-watch2: + serviceEvent, ok := event.(api.EventCreateService) + if !ok { + t.Fatal("wrong event type - expected service create") + } + assert.Equal(t, "id4", serviceEvent.Service.ID) + case <-time.After(time.Second): + t.Fatal("timed out waiting for event") + } + select { + case event := <-watch2: + if _, ok := event.(state.EventCommit); !ok { + t.Fatal("wrong event type - expected commit") + } + case <-time.After(time.Second): + t.Fatal("timed out waiting for event") + } + + // Create some new objects and make sure they show up in the watches. + assert.NoError(t, s.Update(func(tx Tx) error { + node := &api.Node{ + ID: "newnode", + Spec: api.NodeSpec{ + Annotations: api.Annotations{ + Name: "newnode", + }, + }, + } + + service := &api.Service{ + ID: "newservice", + Spec: api.ServiceSpec{ + Annotations: api.Annotations{ + Name: "newservice", + }, + }, + } + + assert.NoError(t, CreateNode(tx, node)) + assert.NoError(t, CreateService(tx, service)) + return nil + })) + + select { + case event := <-watch1: + nodeEvent, ok := event.(api.EventCreateNode) + if !ok { + t.Fatalf("wrong event type - expected node create, got %T", event) + } + assert.Equal(t, "newnode", nodeEvent.Node.ID) + case <-time.After(time.Second): + t.Fatal("timed out waiting for event") + } + select { + case event := <-watch1: + if _, ok := event.(state.EventCommit); !ok { + t.Fatal("wrong event type - expected commit") + } + case <-time.After(time.Second): + t.Fatal("timed out waiting for event") + } + + select { + case event := <-watch2: + serviceEvent, ok := event.(api.EventCreateService) + if !ok { + t.Fatalf("wrong event type - expected service create, got %T", event) + } + assert.Equal(t, "newservice", serviceEvent.Service.ID) + case <-time.After(time.Second): + t.Fatal("timed out waiting for event") + } + select { + case event := <-watch2: + if _, ok := event.(state.EventCommit); !ok { + t.Fatal("wrong event type - expected commit") + } + case <-time.After(time.Second): + t.Fatal("timed out waiting for event") + } + + assert.NoError(t, s.Update(func(tx Tx) error { + node := &api.Node{ + ID: "newnode2", + Spec: api.NodeSpec{ + Annotations: api.Annotations{ + Name: "newnode2", + }, + }, + } + + assert.NoError(t, CreateNode(tx, node)) + return nil + })) + + select { + case event := <-watch1: + nodeEvent, ok := event.(api.EventCreateNode) + if !ok { + t.Fatalf("wrong event type - expected node create, got %T", event) + } + assert.Equal(t, "newnode2", nodeEvent.Node.ID) + case <-time.After(time.Second): + t.Fatal("timed out waiting for event") + } + select { + case event := <-watch1: + if _, ok := event.(state.EventCommit); !ok { + t.Fatal("wrong event type - expected commit") + } + case <-time.After(time.Second): + t.Fatal("timed out waiting for event") + } + + select { + case event := <-watch2: + if _, ok := event.(state.EventCommit); !ok { + t.Fatal("wrong event type - expected commit") + } + case <-time.After(time.Second): + t.Fatal("timed out waiting for event") + } +} + const benchmarkNumNodes = 10000 func setupNodes(b *testing.B, n int) (*MemoryStore, []string) { diff --git a/manager/state/testutils/mock_proposer.go b/manager/state/testutils/mock_proposer.go new file mode 100644 index 0000000000..caf8ebaf55 --- /dev/null +++ b/manager/state/testutils/mock_proposer.go @@ -0,0 +1,59 @@ +package testutils + +import ( + "errors" + + "github.com/docker/swarmkit/api" + "github.com/docker/swarmkit/manager/state" + "golang.org/x/net/context" +) + +// MockProposer is a simple proposer implementation for use in tests. +type MockProposer struct { + index uint64 + changes []state.Change +} + +// ProposeValue propagates a value. In this mock implementation, it just stores +// the value locally. +func (mp *MockProposer) ProposeValue(ctx context.Context, storeAction []api.StoreAction, cb func()) error { + mp.index += 3 + mp.changes = append(mp.changes, + state.Change{ + Version: api.Version{Index: mp.index}, + StoreActions: storeAction, + }, + ) + if cb != nil { + cb() + } + return nil +} + +// GetVersion returns the current version. +func (mp *MockProposer) GetVersion() *api.Version { + return &api.Version{Index: mp.index} +} + +// ChangesBetween returns changes after "from" up to and including "to". +func (mp *MockProposer) ChangesBetween(from, to api.Version) ([]state.Change, error) { + var changes []state.Change + + if len(mp.changes) == 0 { + return nil, errors.New("no history") + } + + lastIndex := mp.changes[len(mp.changes)-1].Version.Index + + if to.Index > lastIndex || from.Index > lastIndex { + return nil, errors.New("out of bounds") + } + + for _, change := range mp.changes { + if change.Version.Index > from.Index && change.Version.Index <= to.Index { + changes = append(changes, change) + } + } + + return changes, nil +} diff --git a/manager/state/watch.go b/manager/state/watch.go index b115e521e9..21ea9d11bf 100644 --- a/manager/state/watch.go +++ b/manager/state/watch.go @@ -8,6 +8,17 @@ import ( "github.com/docker/swarmkit/watch" ) +// EventCommit delineates a transaction boundary. +type EventCommit struct { + Version *api.Version +} + +// Matches returns true if this event is a commit event. +func (e EventCommit) Matches(watchEvent events.Event) bool { + _, ok := watchEvent.(EventCommit) + return ok +} + func checkCustom(a1, a2 api.Annotations) bool { if len(a1.Indices) == 1 { for _, ind := range a2.Indices { @@ -30,15 +41,6 @@ func checkCustomPrefix(a1, a2 api.Annotations) bool { return false } -// EventCommit delineates a transaction boundary. -type EventCommit struct{} - -// Matches returns true if this event is a commit event. -func (e EventCommit) Matches(watchEvent events.Event) bool { - _, ok := watchEvent.(EventCommit) - return ok -} - // TaskCheckID is a TaskCheckFunc for matching task IDs. func TaskCheckID(t1, t2 *api.Task) bool { return t1.ID == t2.ID diff --git a/manager/storeapi/server_test.go b/manager/storeapi/server_test.go index 1ec5b6453f..a42868f831 100644 --- a/manager/storeapi/server_test.go +++ b/manager/storeapi/server_test.go @@ -12,28 +12,12 @@ import ( "github.com/docker/swarmkit/api" cautils "github.com/docker/swarmkit/ca/testutils" "github.com/docker/swarmkit/manager/state/store" + stateutils "github.com/docker/swarmkit/manager/state/testutils" "github.com/stretchr/testify/assert" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" ) -type mockProposer struct { - index uint64 -} - -func (mp *mockProposer) ProposeValue(ctx context.Context, storeAction []api.StoreAction, cb func()) error { - if cb != nil { - cb() - } - return nil -} - -func (mp *mockProposer) GetVersion() *api.Version { - mp.index += 3 - return &api.Version{Index: mp.index} -} - type testServer struct { Server *Server Client api.StoreClient @@ -59,7 +43,7 @@ func newTestServer(t *testing.T) *testServer { tc := cautils.NewTestCA(nil) tc.Stop() - ts.Store = store.NewMemoryStore(&mockProposer{}) + ts.Store = store.NewMemoryStore(&stateutils.MockProposer{}) assert.NotNil(t, ts.Store) ts.Server = NewServer(ts.Store) assert.NotNil(t, ts.Server) diff --git a/manager/storeapi/watch.go b/manager/storeapi/watch.go index 7b93525d4a..ece1402a36 100644 --- a/manager/storeapi/watch.go +++ b/manager/storeapi/watch.go @@ -6,6 +6,7 @@ import ( "github.com/docker/swarmkit/api" "github.com/docker/swarmkit/manager/state" + "github.com/docker/swarmkit/manager/state/store" ) var errConflictingFilters = grpc.Errorf(codes.InvalidArgument, "conflicting filters specified") @@ -586,56 +587,56 @@ func convertWatchArgs(entries []*api.WatchRequest_WatchEntry) ([]api.Event, erro return events, nil } -func watchMessage(event api.Event) *api.WatchMessage { +func watchMessageEvent(event api.Event) *api.WatchMessage_Event { switch v := event.(type) { case api.EventCreateTask: - return &api.WatchMessage{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}} case api.EventUpdateTask: - return &api.WatchMessage{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}} case api.EventDeleteTask: - return &api.WatchMessage{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}} case api.EventCreateService: - return &api.WatchMessage{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}} case api.EventUpdateService: - return &api.WatchMessage{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}} case api.EventDeleteService: - return &api.WatchMessage{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}} case api.EventCreateNetwork: - return &api.WatchMessage{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}} case api.EventUpdateNetwork: - return &api.WatchMessage{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}} case api.EventDeleteNetwork: - return &api.WatchMessage{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}} case api.EventCreateNode: - return &api.WatchMessage{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}} case api.EventUpdateNode: - return &api.WatchMessage{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}} case api.EventDeleteNode: - return &api.WatchMessage{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}} case api.EventCreateCluster: - return &api.WatchMessage{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}} case api.EventUpdateCluster: - return &api.WatchMessage{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}} case api.EventDeleteCluster: - return &api.WatchMessage{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}} case api.EventCreateSecret: - return &api.WatchMessage{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}} case api.EventUpdateSecret: - return &api.WatchMessage{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}} case api.EventDeleteSecret: - return &api.WatchMessage{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}} case api.EventCreateResource: - return &api.WatchMessage{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}} case api.EventUpdateResource: - return &api.WatchMessage{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}} case api.EventDeleteResource: - return &api.WatchMessage{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}} case api.EventCreateExtension: - return &api.WatchMessage{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}} case api.EventUpdateExtension: - return &api.WatchMessage{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}} case api.EventDeleteExtension: - return &api.WatchMessage{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}} } return nil } @@ -653,23 +654,31 @@ func (s *Server) Watch(request *api.WatchRequest, stream api.Store_WatchServer) return err } - watch, cancel := state.Watch(s.store.WatchQueue(), watchArgs...) + watchArgs = append(watchArgs, state.EventCommit{}) + watch, cancel, err := store.WatchFrom(s.store, request.ResumeFrom, watchArgs...) + if err != nil { + return err + } defer cancel() + // TODO(aaronl): Send current version in this WatchMessage? if err := stream.Send(&api.WatchMessage{}); err != nil { return err } + var events []*api.WatchMessage_Event for { select { case <-ctx.Done(): return ctx.Err() case event := <-watch: - message := watchMessage(event.(api.Event)) - if message != nil { - if err := stream.Send(message); err != nil { + if commitEvent, ok := event.(state.EventCommit); ok && len(events) > 0 { + if err := stream.Send(&api.WatchMessage{Events: events, Version: commitEvent.Version}); err != nil { return err } + events = nil + } else if eventMessage := watchMessageEvent(event.(api.Event)); eventMessage != nil { + events = append(events, eventMessage) } } } diff --git a/manager/storeapi/watch_test.go b/manager/storeapi/watch_test.go index 3928bf7098..28e5526689 100644 --- a/manager/storeapi/watch_test.go +++ b/manager/storeapi/watch_test.go @@ -35,9 +35,9 @@ func TestWatch(t *testing.T) { createNode(t, ts, "id1", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY) msg, err = watch.Recv() assert.NoError(t, err) - assert.Equal(t, api.StoreActionKindCreate, msg.Action) - require.NotNil(t, msg.Object.GetNode()) - assert.Equal(t, "id1", msg.Object.GetNode().ID) + assert.Equal(t, api.StoreActionKindCreate, msg.Events[0].Action) + require.NotNil(t, msg.Events[0].Object.GetNode()) + assert.Equal(t, "id1", msg.Events[0].Object.GetNode().ID) watch.CloseSend() @@ -87,9 +87,9 @@ func TestWatch(t *testing.T) { createNode(t, ts, "id2", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY) msg, err = watch.Recv() assert.NoError(t, err) - assert.Equal(t, api.StoreActionKindCreate, msg.Action) - require.NotNil(t, msg.Object.GetNode()) - assert.Equal(t, "id2", msg.Object.GetNode().ID) + assert.Equal(t, api.StoreActionKindCreate, msg.Events[0].Action) + require.NotNil(t, msg.Events[0].Object.GetNode()) + assert.Equal(t, "id2", msg.Events[0].Object.GetNode().ID) // Shouldn't be seen by the watch createNode(t, ts, "id3", api.NodeRoleWorker, api.NodeMembershipAccepted, api.NodeStatus_READY) @@ -153,9 +153,55 @@ func TestWatch(t *testing.T) { msg, err = watch.Recv() assert.NoError(t, err) - assert.Equal(t, api.StoreActionKindCreate, msg.Action) - require.NotNil(t, msg.Object.GetNode()) - assert.Equal(t, "id6", msg.Object.GetNode().ID) + assert.Equal(t, api.StoreActionKindCreate, msg.Events[0].Action) + require.NotNil(t, msg.Events[0].Object.GetNode()) + assert.Equal(t, "id6", msg.Events[0].Object.GetNode().ID) + + watch.CloseSend() +} + +func TestWatchResumeFrom(t *testing.T) { + ts := newTestServer(t) + defer ts.Stop() + + ctx := context.Background() + + createNode(t, ts, "id1", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY) + node2 := createNode(t, ts, "id2", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY) + + // Watch for node creates, starting from after the first node creation. + watch, err := ts.Client.Watch(ctx, &api.WatchRequest{ + Entries: []*api.WatchRequest_WatchEntry{ + { + Kind: "node", + Action: api.StoreActionKindCreate, + }, + }, + ResumeFrom: &node2.Meta.Version, + }) + assert.NoError(t, err) + + // Should receive an initial message that indicates the watch is ready + msg, err := watch.Recv() + assert.NoError(t, err) + assert.Equal(t, &api.WatchMessage{}, msg) + + msg, err = watch.Recv() + assert.NoError(t, err) + assert.Equal(t, api.StoreActionKindCreate, msg.Events[0].Action) + require.NotNil(t, msg.Events[0].Object.GetNode()) + assert.Equal(t, "id2", msg.Events[0].Object.GetNode().ID) + assert.Equal(t, node2.Meta.Version.Index+3, msg.Version.Index) + + // Create a new node + node3 := createNode(t, ts, "id3", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY) + + msg, err = watch.Recv() + assert.NoError(t, err) + assert.Equal(t, api.StoreActionKindCreate, msg.Events[0].Action) + require.NotNil(t, msg.Events[0].Object.GetNode()) + assert.Equal(t, "id3", msg.Events[0].Object.GetNode().ID) + assert.Equal(t, node3.Meta.Version.Index+3, msg.Version.Index) watch.CloseSend() } diff --git a/protobuf/plugin/storeobject/storeobject.go b/protobuf/plugin/storeobject/storeobject.go index 701a4c4e11..e141227ef8 100644 --- a/protobuf/plugin/storeobject/storeobject.go +++ b/protobuf/plugin/storeobject/storeobject.go @@ -235,6 +235,45 @@ func (d *storeObjectGen) genNewStoreAction(topLevelObjs []string) { d.P() } +func (d *storeObjectGen) genEventFromStoreAction(topLevelObjs []string) { + if len(topLevelObjs) == 0 { + return + } + + // Generate EventFromStoreAction + d.P("func EventFromStoreAction(sa StoreAction) (Event, error) {") + d.In() + d.P("switch v := sa.Target.(type) {") + for _, ccTypeName := range topLevelObjs { + d.P("case *StoreAction_", ccTypeName, ":") + d.In() + d.P("switch sa.Action {") + + d.P("case StoreActionKindCreate:") + d.In() + d.P("return EventCreate", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, "}, nil") + d.Out() + + d.P("case StoreActionKindUpdate:") + d.In() + d.P("return EventUpdate", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, "}, nil") + d.Out() + + d.P("case StoreActionKindRemove:") + d.In() + d.P("return EventDelete", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, "}, nil") + d.Out() + + d.P("}") + d.Out() + } + d.P("}") + d.P("return nil, errUnknownStoreAction") + d.Out() + d.P("}") + d.P() +} + func (d *storeObjectGen) Generate(file *generator.FileDescriptor) { d.PluginImports = generator.NewPluginImports(d.Generator) d.eventsPkg = d.NewImport("github.com/docker/go-events") @@ -262,4 +301,5 @@ func (d *storeObjectGen) Generate(file *generator.FileDescriptor) { } d.genNewStoreAction(topLevelObjs) + d.genEventFromStoreAction(topLevelObjs) } From 678fe9ed5abcd37a72b001bcc6498dcd548bea60 Mon Sep 17 00:00:00 2001 From: Aaron Lehmann Date: Mon, 13 Mar 2017 17:16:23 -0700 Subject: [PATCH 3/7] Add IncludeOldObject option to Watch RPC Signed-off-by: Aaron Lehmann --- api/objects.pb.go | 154 ++++++++++---- api/store.pb.go | 222 +++++++++++++++------ api/store.proto | 11 + api/storeobject.go | 14 +- manager/state/store/memory.go | 4 +- manager/storeapi/watch.go | 19 +- manager/storeapi/watch_test.go | 46 +++++ protobuf/plugin/storeobject/storeobject.go | 23 ++- 8 files changed, 371 insertions(+), 122 deletions(-) diff --git a/api/objects.pb.go b/api/objects.pb.go index 37264443de..c364f31ceb 100644 --- a/api/objects.pb.go +++ b/api/objects.pb.go @@ -1859,8 +1859,9 @@ func (e EventCreateNode) Matches(apiEvent github_com_docker_go_events.Event) boo } type EventUpdateNode struct { - Node *Node - Checks []NodeCheckFunc + Node *Node + OldNode *Node + Checks []NodeCheckFunc } func (e EventUpdateNode) Matches(apiEvent github_com_docker_go_events.Event) bool { @@ -1915,8 +1916,12 @@ func (m *Node) EventCreate() Event { return EventCreateNode{Node: m} } -func (m *Node) EventUpdate() Event { - return EventUpdateNode{Node: m} +func (m *Node) EventUpdate(oldObject StoreObject) Event { + if oldObject != nil { + return EventUpdateNode{Node: m, OldNode: oldObject.(*Node)} + } else { + return EventUpdateNode{Node: m} + } } func (m *Node) EventDelete() Event { @@ -1985,8 +1990,9 @@ func (e EventCreateService) Matches(apiEvent github_com_docker_go_events.Event) } type EventUpdateService struct { - Service *Service - Checks []ServiceCheckFunc + Service *Service + OldService *Service + Checks []ServiceCheckFunc } func (e EventUpdateService) Matches(apiEvent github_com_docker_go_events.Event) bool { @@ -2041,8 +2047,12 @@ func (m *Service) EventCreate() Event { return EventCreateService{Service: m} } -func (m *Service) EventUpdate() Event { - return EventUpdateService{Service: m} +func (m *Service) EventUpdate(oldObject StoreObject) Event { + if oldObject != nil { + return EventUpdateService{Service: m, OldService: oldObject.(*Service)} + } else { + return EventUpdateService{Service: m} + } } func (m *Service) EventDelete() Event { @@ -2111,8 +2121,9 @@ func (e EventCreateTask) Matches(apiEvent github_com_docker_go_events.Event) boo } type EventUpdateTask struct { - Task *Task - Checks []TaskCheckFunc + Task *Task + OldTask *Task + Checks []TaskCheckFunc } func (e EventUpdateTask) Matches(apiEvent github_com_docker_go_events.Event) bool { @@ -2167,8 +2178,12 @@ func (m *Task) EventCreate() Event { return EventCreateTask{Task: m} } -func (m *Task) EventUpdate() Event { - return EventUpdateTask{Task: m} +func (m *Task) EventUpdate(oldObject StoreObject) Event { + if oldObject != nil { + return EventUpdateTask{Task: m, OldTask: oldObject.(*Task)} + } else { + return EventUpdateTask{Task: m} + } } func (m *Task) EventDelete() Event { @@ -2237,8 +2252,9 @@ func (e EventCreateNetwork) Matches(apiEvent github_com_docker_go_events.Event) } type EventUpdateNetwork struct { - Network *Network - Checks []NetworkCheckFunc + Network *Network + OldNetwork *Network + Checks []NetworkCheckFunc } func (e EventUpdateNetwork) Matches(apiEvent github_com_docker_go_events.Event) bool { @@ -2293,8 +2309,12 @@ func (m *Network) EventCreate() Event { return EventCreateNetwork{Network: m} } -func (m *Network) EventUpdate() Event { - return EventUpdateNetwork{Network: m} +func (m *Network) EventUpdate(oldObject StoreObject) Event { + if oldObject != nil { + return EventUpdateNetwork{Network: m, OldNetwork: oldObject.(*Network)} + } else { + return EventUpdateNetwork{Network: m} + } } func (m *Network) EventDelete() Event { @@ -2363,8 +2383,9 @@ func (e EventCreateCluster) Matches(apiEvent github_com_docker_go_events.Event) } type EventUpdateCluster struct { - Cluster *Cluster - Checks []ClusterCheckFunc + Cluster *Cluster + OldCluster *Cluster + Checks []ClusterCheckFunc } func (e EventUpdateCluster) Matches(apiEvent github_com_docker_go_events.Event) bool { @@ -2419,8 +2440,12 @@ func (m *Cluster) EventCreate() Event { return EventCreateCluster{Cluster: m} } -func (m *Cluster) EventUpdate() Event { - return EventUpdateCluster{Cluster: m} +func (m *Cluster) EventUpdate(oldObject StoreObject) Event { + if oldObject != nil { + return EventUpdateCluster{Cluster: m, OldCluster: oldObject.(*Cluster)} + } else { + return EventUpdateCluster{Cluster: m} + } } func (m *Cluster) EventDelete() Event { @@ -2489,8 +2514,9 @@ func (e EventCreateSecret) Matches(apiEvent github_com_docker_go_events.Event) b } type EventUpdateSecret struct { - Secret *Secret - Checks []SecretCheckFunc + Secret *Secret + OldSecret *Secret + Checks []SecretCheckFunc } func (e EventUpdateSecret) Matches(apiEvent github_com_docker_go_events.Event) bool { @@ -2545,8 +2571,12 @@ func (m *Secret) EventCreate() Event { return EventCreateSecret{Secret: m} } -func (m *Secret) EventUpdate() Event { - return EventUpdateSecret{Secret: m} +func (m *Secret) EventUpdate(oldObject StoreObject) Event { + if oldObject != nil { + return EventUpdateSecret{Secret: m, OldSecret: oldObject.(*Secret)} + } else { + return EventUpdateSecret{Secret: m} + } } func (m *Secret) EventDelete() Event { @@ -2615,8 +2645,9 @@ func (e EventCreateResource) Matches(apiEvent github_com_docker_go_events.Event) } type EventUpdateResource struct { - Resource *Resource - Checks []ResourceCheckFunc + Resource *Resource + OldResource *Resource + Checks []ResourceCheckFunc } func (e EventUpdateResource) Matches(apiEvent github_com_docker_go_events.Event) bool { @@ -2671,8 +2702,12 @@ func (m *Resource) EventCreate() Event { return EventCreateResource{Resource: m} } -func (m *Resource) EventUpdate() Event { - return EventUpdateResource{Resource: m} +func (m *Resource) EventUpdate(oldObject StoreObject) Event { + if oldObject != nil { + return EventUpdateResource{Resource: m, OldResource: oldObject.(*Resource)} + } else { + return EventUpdateResource{Resource: m} + } } func (m *Resource) EventDelete() Event { @@ -2741,8 +2776,9 @@ func (e EventCreateExtension) Matches(apiEvent github_com_docker_go_events.Event } type EventUpdateExtension struct { - Extension *Extension - Checks []ExtensionCheckFunc + Extension *Extension + OldExtension *Extension + Checks []ExtensionCheckFunc } func (e EventUpdateExtension) Matches(apiEvent github_com_docker_go_events.Event) bool { @@ -2797,8 +2833,12 @@ func (m *Extension) EventCreate() Event { return EventCreateExtension{Extension: m} } -func (m *Extension) EventUpdate() Event { - return EventUpdateExtension{Extension: m} +func (m *Extension) EventUpdate(oldObject StoreObject) Event { + if oldObject != nil { + return EventUpdateExtension{Extension: m, OldExtension: oldObject.(*Extension)} + } else { + return EventUpdateExtension{Extension: m} + } } func (m *Extension) EventDelete() Event { @@ -2925,14 +2965,18 @@ func NewStoreAction(c Event) (StoreAction, error) { return sa, nil } -func EventFromStoreAction(sa StoreAction) (Event, error) { +func EventFromStoreAction(sa StoreAction, oldObject StoreObject) (Event, error) { switch v := sa.Target.(type) { case *StoreAction_Node: switch sa.Action { case StoreActionKindCreate: return EventCreateNode{Node: v.Node}, nil case StoreActionKindUpdate: - return EventUpdateNode{Node: v.Node}, nil + if oldObject != nil { + return EventUpdateNode{Node: v.Node, OldNode: oldObject.(*Node)}, nil + } else { + return EventUpdateNode{Node: v.Node}, nil + } case StoreActionKindRemove: return EventDeleteNode{Node: v.Node}, nil } @@ -2941,7 +2985,11 @@ func EventFromStoreAction(sa StoreAction) (Event, error) { case StoreActionKindCreate: return EventCreateService{Service: v.Service}, nil case StoreActionKindUpdate: - return EventUpdateService{Service: v.Service}, nil + if oldObject != nil { + return EventUpdateService{Service: v.Service, OldService: oldObject.(*Service)}, nil + } else { + return EventUpdateService{Service: v.Service}, nil + } case StoreActionKindRemove: return EventDeleteService{Service: v.Service}, nil } @@ -2950,7 +2998,11 @@ func EventFromStoreAction(sa StoreAction) (Event, error) { case StoreActionKindCreate: return EventCreateTask{Task: v.Task}, nil case StoreActionKindUpdate: - return EventUpdateTask{Task: v.Task}, nil + if oldObject != nil { + return EventUpdateTask{Task: v.Task, OldTask: oldObject.(*Task)}, nil + } else { + return EventUpdateTask{Task: v.Task}, nil + } case StoreActionKindRemove: return EventDeleteTask{Task: v.Task}, nil } @@ -2959,7 +3011,11 @@ func EventFromStoreAction(sa StoreAction) (Event, error) { case StoreActionKindCreate: return EventCreateNetwork{Network: v.Network}, nil case StoreActionKindUpdate: - return EventUpdateNetwork{Network: v.Network}, nil + if oldObject != nil { + return EventUpdateNetwork{Network: v.Network, OldNetwork: oldObject.(*Network)}, nil + } else { + return EventUpdateNetwork{Network: v.Network}, nil + } case StoreActionKindRemove: return EventDeleteNetwork{Network: v.Network}, nil } @@ -2968,7 +3024,11 @@ func EventFromStoreAction(sa StoreAction) (Event, error) { case StoreActionKindCreate: return EventCreateCluster{Cluster: v.Cluster}, nil case StoreActionKindUpdate: - return EventUpdateCluster{Cluster: v.Cluster}, nil + if oldObject != nil { + return EventUpdateCluster{Cluster: v.Cluster, OldCluster: oldObject.(*Cluster)}, nil + } else { + return EventUpdateCluster{Cluster: v.Cluster}, nil + } case StoreActionKindRemove: return EventDeleteCluster{Cluster: v.Cluster}, nil } @@ -2977,7 +3037,11 @@ func EventFromStoreAction(sa StoreAction) (Event, error) { case StoreActionKindCreate: return EventCreateSecret{Secret: v.Secret}, nil case StoreActionKindUpdate: - return EventUpdateSecret{Secret: v.Secret}, nil + if oldObject != nil { + return EventUpdateSecret{Secret: v.Secret, OldSecret: oldObject.(*Secret)}, nil + } else { + return EventUpdateSecret{Secret: v.Secret}, nil + } case StoreActionKindRemove: return EventDeleteSecret{Secret: v.Secret}, nil } @@ -2986,7 +3050,11 @@ func EventFromStoreAction(sa StoreAction) (Event, error) { case StoreActionKindCreate: return EventCreateResource{Resource: v.Resource}, nil case StoreActionKindUpdate: - return EventUpdateResource{Resource: v.Resource}, nil + if oldObject != nil { + return EventUpdateResource{Resource: v.Resource, OldResource: oldObject.(*Resource)}, nil + } else { + return EventUpdateResource{Resource: v.Resource}, nil + } case StoreActionKindRemove: return EventDeleteResource{Resource: v.Resource}, nil } @@ -2995,7 +3063,11 @@ func EventFromStoreAction(sa StoreAction) (Event, error) { case StoreActionKindCreate: return EventCreateExtension{Extension: v.Extension}, nil case StoreActionKindUpdate: - return EventUpdateExtension{Extension: v.Extension}, nil + if oldObject != nil { + return EventUpdateExtension{Extension: v.Extension, OldExtension: oldObject.(*Extension)}, nil + } else { + return EventUpdateExtension{Extension: v.Extension}, nil + } case StoreActionKindRemove: return EventDeleteExtension{Extension: v.Extension}, nil } diff --git a/api/store.pb.go b/api/store.pb.go index 9a0fbe6283..9e739950cd 100644 --- a/api/store.pb.go +++ b/api/store.pb.go @@ -851,6 +851,11 @@ type WatchRequest struct { // server has compacted its log and no longer has complete history to // this point. ResumeFrom *Version `protobuf:"bytes,2,opt,name=resume_from,json=resumeFrom" json:"resume_from,omitempty"` + // IncludeOldObject causes WatchMessages to include a copy of the + // previous version of the object on updates. Note that only live + // changes will include the old object (not historical changes + // retrieved using ResumeFrom). + IncludeOldObject bool `protobuf:"varint,3,opt,name=include_old_object,json=includeOldObject,proto3" json:"include_old_object,omitempty"` } func (m *WatchRequest) Reset() { *m = WatchRequest{} } @@ -893,6 +898,10 @@ type WatchMessage_Event struct { Action StoreActionKind `protobuf:"varint,1,opt,name=action,proto3,enum=docker.swarmkit.v1.StoreActionKind" json:"action,omitempty"` // Matched object Object *Object `protobuf:"bytes,2,opt,name=object" json:"object,omitempty"` + // For updates, OldObject will optionally be included in the + // watch message, containing the previous version of the + // object, if IncludeOldObject was set in WatchRequest. + OldObject *Object `protobuf:"bytes,3,opt,name=old_object,json=oldObject" json:"old_object,omitempty"` } func (m *WatchMessage_Event) Reset() { *m = WatchMessage_Event{} } @@ -1220,6 +1229,10 @@ func (m *WatchMessage_Event) CopyFrom(src interface{}) { m.Object = &Object{} github_com_docker_swarmkit_api_deepcopy.Copy(m.Object, o.Object) } + if o.OldObject != nil { + m.OldObject = &Object{} + github_com_docker_swarmkit_api_deepcopy.Copy(m.OldObject, o.OldObject) + } } // Reference imports to suppress errors if they are not otherwise used. @@ -1730,6 +1743,16 @@ func (m *WatchRequest) MarshalTo(dAtA []byte) (int, error) { } i += n14 } + if m.IncludeOldObject { + dAtA[i] = 0x18 + i++ + if m.IncludeOldObject { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } return i, nil } @@ -1844,6 +1867,16 @@ func (m *WatchMessage_Event) MarshalTo(dAtA []byte) (int, error) { } i += n16 } + if m.OldObject != nil { + dAtA[i] = 0x1a + i++ + i = encodeVarintStore(dAtA, i, uint64(m.OldObject.Size())) + n17, err := m.OldObject.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n17 + } return i, nil } @@ -2240,6 +2273,9 @@ func (m *WatchRequest) Size() (n int) { l = m.ResumeFrom.Size() n += 1 + l + sovStore(uint64(l)) } + if m.IncludeOldObject { + n += 2 + } return n } @@ -2288,6 +2324,10 @@ func (m *WatchMessage_Event) Size() (n int) { l = m.Object.Size() n += 1 + l + sovStore(uint64(l)) } + if m.OldObject != nil { + l = m.OldObject.Size() + n += 1 + l + sovStore(uint64(l)) + } return n } @@ -2584,6 +2624,7 @@ func (this *WatchRequest) String() string { s := strings.Join([]string{`&WatchRequest{`, `Entries:` + strings.Replace(fmt.Sprintf("%v", this.Entries), "WatchRequest_WatchEntry", "WatchRequest_WatchEntry", 1) + `,`, `ResumeFrom:` + strings.Replace(fmt.Sprintf("%v", this.ResumeFrom), "Version", "Version", 1) + `,`, + `IncludeOldObject:` + fmt.Sprintf("%v", this.IncludeOldObject) + `,`, `}`, }, "") return s @@ -2618,6 +2659,7 @@ func (this *WatchMessage_Event) String() string { s := strings.Join([]string{`&WatchMessage_Event{`, `Action:` + fmt.Sprintf("%v", this.Action) + `,`, `Object:` + strings.Replace(fmt.Sprintf("%v", this.Object), "Object", "Object", 1) + `,`, + `OldObject:` + strings.Replace(fmt.Sprintf("%v", this.OldObject), "Object", "Object", 1) + `,`, `}`, }, "") return s @@ -3731,6 +3773,26 @@ func (m *WatchRequest) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IncludeOldObject", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.IncludeOldObject = bool(v != 0) default: iNdEx = preIndex skippy, err := skipStore(dAtA[iNdEx:]) @@ -4076,6 +4138,39 @@ func (m *WatchMessage_Event) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OldObject", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStore + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthStore + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.OldObject == nil { + m.OldObject = &Object{} + } + if err := m.OldObject.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipStore(dAtA[iNdEx:]) @@ -4205,66 +4300,69 @@ var ( func init() { proto.RegisterFile("store.proto", fileDescriptorStore) } var fileDescriptorStore = []byte{ - // 975 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x94, 0x96, 0xdf, 0x8e, 0x22, 0x45, - 0x14, 0xc6, 0x69, 0x06, 0x1a, 0x38, 0xc0, 0x6c, 0x52, 0x33, 0xab, 0x1d, 0x1c, 0x01, 0x31, 0xea, - 0x24, 0xab, 0xac, 0xa2, 0xae, 0x89, 0xae, 0x26, 0xb2, 0x33, 0x06, 0x34, 0xb3, 0x4e, 0x0a, 0xa3, - 0x97, 0xa4, 0xa7, 0xfb, 0xc0, 0xb6, 0xd0, 0xdd, 0x58, 0x55, 0xb0, 0x33, 0x77, 0xbe, 0x84, 0x89, - 0x57, 0xbe, 0x80, 0x89, 0xcf, 0xb1, 0xf1, 0xc2, 0x78, 0xe9, 0x15, 0x71, 0xfb, 0x01, 0x7c, 0x05, - 0x4d, 0xfd, 0xe9, 0x61, 0x74, 0x9b, 0x59, 0xe7, 0x8a, 0xaa, 0xea, 0xdf, 0x77, 0xaa, 0xea, 0x3b, - 0x55, 0xa7, 0x80, 0x2a, 0x17, 0x31, 0xc3, 0xee, 0x82, 0xc5, 0x22, 0x26, 0xc4, 0x8f, 0xbd, 0x19, - 0xb2, 0x2e, 0x7f, 0xec, 0xb2, 0x70, 0x16, 0x88, 0xee, 0xea, 0x9d, 0x46, 0x95, 0x2f, 0xd0, 0xe3, - 0x1a, 0x68, 0xd4, 0xe3, 0xb3, 0x6f, 0xd1, 0x13, 0x69, 0x17, 0x98, 0x3b, 0x11, 0xa6, 0x5d, 0x15, - 0x17, 0x0b, 0x4c, 0x3f, 0xec, 0x4f, 0xe3, 0x69, 0xac, 0x9a, 0x77, 0x65, 0xcb, 0x8c, 0xee, 0x2d, - 0xe6, 0xcb, 0x69, 0x10, 0xdd, 0xd5, 0x3f, 0x7a, 0xb0, 0xf3, 0xdb, 0x0e, 0xd8, 0x5f, 0xaa, 0xa8, - 0xa4, 0x0b, 0x85, 0x28, 0xf6, 0xd1, 0xb1, 0xda, 0xd6, 0x61, 0xb5, 0xe7, 0x74, 0x9f, 0x5d, 0x4d, - 0xf7, 0x61, 0xec, 0xe3, 0x20, 0x47, 0x15, 0x47, 0x3e, 0x80, 0x12, 0x47, 0xb6, 0x0a, 0x3c, 0x74, - 0xf2, 0x4a, 0xf2, 0x52, 0x96, 0x64, 0xa4, 0x91, 0x41, 0x8e, 0xa6, 0xb4, 0x14, 0x46, 0x28, 0x1e, - 0xc7, 0x6c, 0xe6, 0xec, 0x6c, 0x17, 0x3e, 0xd4, 0x88, 0x14, 0x1a, 0x5a, 0xae, 0x50, 0xb8, 0x7c, - 0xe6, 0x14, 0xb6, 0xaf, 0xf0, 0x2b, 0x97, 0x4b, 0x89, 0xe2, 0xe4, 0x44, 0xde, 0x7c, 0xc9, 0x05, - 0x32, 0xa7, 0xb8, 0x7d, 0xa2, 0x07, 0x1a, 0x91, 0x13, 0x19, 0x9a, 0xbc, 0x07, 0x36, 0x47, 0x8f, - 0xa1, 0x70, 0x6c, 0xa5, 0x6b, 0x64, 0xef, 0x4c, 0x12, 0x83, 0x1c, 0x35, 0x2c, 0xf9, 0x10, 0xca, - 0x0c, 0x79, 0xbc, 0x64, 0x1e, 0x3a, 0x25, 0xa5, 0x3b, 0xc8, 0xd2, 0x51, 0xc3, 0x0c, 0x72, 0xf4, - 0x92, 0x27, 0x1f, 0x43, 0x05, 0xcf, 0x05, 0x46, 0x3c, 0x88, 0x23, 0xa7, 0xac, 0xc4, 0x2f, 0x67, - 0x89, 0x8f, 0x53, 0x68, 0x90, 0xa3, 0x1b, 0x45, 0xbf, 0x9c, 0x66, 0xb1, 0x73, 0x0a, 0xb5, 0x11, - 0xce, 0xd1, 0x13, 0xfd, 0x8b, 0xd1, 0x3c, 0x16, 0xe4, 0x4d, 0x00, 0xe3, 0xfb, 0x38, 0xf0, 0x55, - 0x6e, 0x2b, 0xfd, 0x7a, 0xb2, 0x6e, 0x55, 0x4c, 0x62, 0x86, 0x47, 0xb4, 0x62, 0x80, 0xa1, 0x4f, - 0x08, 0x14, 0xf8, 0x3c, 0x16, 0x2a, 0xa1, 0x05, 0xaa, 0xda, 0x9d, 0x53, 0xd8, 0x4d, 0x23, 0x3e, - 0x58, 0x72, 0x11, 0x87, 0x92, 0x9a, 0x05, 0x91, 0x89, 0x46, 0x55, 0x9b, 0xec, 0x43, 0x31, 0x88, - 0x7c, 0x3c, 0x57, 0xd2, 0x0a, 0xd5, 0x1d, 0x39, 0xba, 0x72, 0xe7, 0x4b, 0x54, 0x89, 0xae, 0x50, - 0xdd, 0xe9, 0xfc, 0x64, 0x43, 0x39, 0x0d, 0x49, 0x1c, 0xc8, 0x5f, 0x2e, 0xcc, 0x4e, 0xd6, 0xad, - 0xfc, 0xf0, 0x68, 0x90, 0xa3, 0xf9, 0xc0, 0x27, 0x77, 0xa0, 0x12, 0xf8, 0xe3, 0x05, 0xc3, 0x49, - 0x60, 0xc2, 0xf6, 0x6b, 0xc9, 0xba, 0x55, 0x1e, 0x1e, 0x9d, 0xaa, 0x31, 0x69, 0x60, 0xe0, 0xeb, - 0x36, 0xd9, 0x87, 0x42, 0xe4, 0x86, 0x66, 0x22, 0x75, 0x46, 0xdd, 0x10, 0xc9, 0x2b, 0x50, 0x95, - 0xbf, 0x69, 0x90, 0x82, 0xf9, 0x08, 0x72, 0xd0, 0x08, 0xef, 0x83, 0xed, 0xa9, 0x6d, 0x99, 0x33, - 0xd2, 0xc9, 0xce, 0xf5, 0x55, 0x03, 0x64, 0xce, 0xb5, 0x86, 0x0c, 0xa1, 0xae, 0x5b, 0xe9, 0x14, - 0xf6, 0x0d, 0x82, 0xd4, 0xb4, 0xd4, 0x2c, 0xa4, 0xfb, 0xaf, 0x4c, 0x95, 0x32, 0x32, 0x25, 0x73, - 0xbe, 0xc9, 0xd5, 0x6b, 0x50, 0x92, 0xf7, 0x50, 0xc2, 0x65, 0x05, 0x43, 0xb2, 0x6e, 0xd9, 0xf2, - 0x8a, 0x2a, 0xd2, 0x96, 0x1f, 0x87, 0x3e, 0xb9, 0x67, 0x52, 0x5a, 0x51, 0x0b, 0x6b, 0x5f, 0xb7, - 0x30, 0x79, 0x60, 0xa4, 0x75, 0x92, 0x27, 0x47, 0x50, 0xf7, 0x91, 0x07, 0x0c, 0xfd, 0x31, 0x17, - 0xae, 0x40, 0x07, 0xda, 0xd6, 0xe1, 0x6e, 0xf6, 0xa9, 0x94, 0xb7, 0x6e, 0x24, 0x21, 0xb9, 0x29, - 0xa3, 0x52, 0x7d, 0xd2, 0x83, 0x02, 0x8b, 0xe7, 0xe8, 0x54, 0x95, 0xf8, 0x60, 0x5b, 0x51, 0xa1, - 0xf1, 0x5c, 0x15, 0x16, 0xc9, 0x92, 0x21, 0x40, 0x88, 0xe1, 0x19, 0x32, 0xfe, 0x28, 0x58, 0x38, - 0x35, 0xa5, 0x7c, 0x63, 0x9b, 0x72, 0xb4, 0x40, 0xaf, 0x7b, 0x72, 0x89, 0xcb, 0xe4, 0x6e, 0xc4, - 0xe4, 0x04, 0x6e, 0x33, 0x9c, 0x20, 0xc3, 0xc8, 0x43, 0x7f, 0x6c, 0xea, 0x88, 0x74, 0xac, 0xae, - 0x1c, 0x7b, 0x31, 0x59, 0xb7, 0xf6, 0xe8, 0x25, 0x60, 0x4a, 0x8e, 0xb2, 0x6f, 0x8f, 0x3d, 0x33, - 0xec, 0x93, 0xcf, 0x61, 0xff, 0x4a, 0x38, 0x7d, 0xed, 0x65, 0xb4, 0x5d, 0x15, 0xed, 0x85, 0x64, - 0xdd, 0x22, 0x9b, 0x68, 0xba, 0x3e, 0xa8, 0x60, 0x84, 0xfd, 0x77, 0x54, 0x5e, 0x18, 0x7d, 0x89, - 0x6e, 0xa5, 0x07, 0x56, 0xf6, 0xfa, 0x05, 0xc8, 0xf7, 0x2f, 0x3a, 0x3f, 0xe7, 0xa1, 0xf6, 0x8d, - 0x2b, 0xbc, 0x47, 0x14, 0xbf, 0x5b, 0x22, 0x17, 0xe4, 0x18, 0x4a, 0x18, 0x09, 0x16, 0x20, 0x77, - 0xac, 0xf6, 0xce, 0x61, 0xb5, 0x77, 0x27, 0xcb, 0x8f, 0xab, 0x12, 0xdd, 0x39, 0x8e, 0x04, 0xbb, - 0xa0, 0xa9, 0x96, 0xdc, 0x87, 0x2a, 0x43, 0xbe, 0x0c, 0x71, 0x3c, 0x61, 0x71, 0x78, 0x5d, 0xd9, - 0xfe, 0x1a, 0x99, 0x2c, 0x2c, 0x14, 0x34, 0xff, 0x19, 0x8b, 0xc3, 0xc6, 0x0f, 0x16, 0xc0, 0x26, - 0x6a, 0x66, 0x15, 0xf8, 0x08, 0x6c, 0xd7, 0x13, 0xb2, 0x86, 0xe5, 0x55, 0xda, 0x5e, 0xcd, 0x3c, - 0x6e, 0xf2, 0xcd, 0xfb, 0x54, 0x61, 0x5f, 0x04, 0x91, 0x4f, 0x8d, 0x84, 0xdc, 0x83, 0xd2, 0x24, - 0x98, 0x0b, 0x64, 0xdc, 0xd9, 0x51, 0x9b, 0x3c, 0xb8, 0xee, 0xb0, 0xd2, 0x14, 0xee, 0xfc, 0x6d, - 0x19, 0xb7, 0x4e, 0x90, 0x73, 0x77, 0x8a, 0xe4, 0x13, 0xb0, 0x71, 0x85, 0x91, 0x48, 0xcd, 0x7a, - 0x7d, 0xab, 0x59, 0x46, 0xd1, 0x3d, 0x96, 0x38, 0x35, 0x2a, 0xf2, 0x3e, 0x94, 0x56, 0x7a, 0xff, - 0xff, 0xc7, 0xa2, 0x94, 0x6d, 0x9c, 0x43, 0x51, 0xc5, 0xb9, 0xe2, 0x82, 0x75, 0x73, 0x17, 0x7a, - 0x60, 0xeb, 0x67, 0xde, 0xcc, 0x9d, 0xf9, 0xf6, 0xe8, 0x62, 0x4f, 0x0d, 0xd9, 0x0b, 0xa1, 0xa8, - 0xc2, 0x11, 0x1f, 0x8a, 0x6a, 0x5f, 0xa4, 0xfd, 0xbc, 0xf3, 0xd1, 0x68, 0x3f, 0xcf, 0x94, 0xce, - 0xed, 0x5f, 0x7f, 0xf9, 0xeb, 0xc7, 0xfc, 0x2d, 0xa8, 0x2b, 0xe2, 0xad, 0xd0, 0x8d, 0xdc, 0x29, - 0xb2, 0xb7, 0xad, 0xbe, 0xf3, 0xe4, 0x69, 0x33, 0xf7, 0xc7, 0xd3, 0x66, 0xee, 0xfb, 0xa4, 0x69, - 0x3d, 0x49, 0x9a, 0xd6, 0xef, 0x49, 0xd3, 0xfa, 0x33, 0x69, 0x5a, 0x67, 0xb6, 0xfa, 0x57, 0xf1, - 0xee, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xb3, 0x39, 0x54, 0xe4, 0xd8, 0x08, 0x00, 0x00, + // 1013 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x94, 0x56, 0xdd, 0x6e, 0x1b, 0x45, + 0x14, 0xf6, 0x3a, 0xce, 0xda, 0x3e, 0x8e, 0x5b, 0x34, 0x49, 0x61, 0x65, 0x82, 0x6d, 0x8c, 0x80, + 0x48, 0x2d, 0x2e, 0x04, 0x28, 0x02, 0x0a, 0x12, 0x6e, 0x82, 0x6c, 0x50, 0xda, 0x68, 0x82, 0xe0, + 0xd2, 0xda, 0xec, 0x9e, 0xa4, 0x8b, 0x77, 0x77, 0xcc, 0xcc, 0xd8, 0x6d, 0xee, 0x78, 0x09, 0x24, + 0xae, 0x78, 0x04, 0x6e, 0xb8, 0xe4, 0x05, 0x2a, 0x2e, 0x10, 0x97, 0x70, 0x63, 0xd1, 0x7d, 0x00, + 0x9e, 0x01, 0xcd, 0xcf, 0xc6, 0xa1, 0x5d, 0xa7, 0xf4, 0xca, 0x33, 0xb3, 0xdf, 0x77, 0xe6, 0xec, + 0xf7, 0x9d, 0x73, 0xd6, 0xd0, 0x10, 0x92, 0x71, 0xec, 0x4f, 0x39, 0x93, 0x8c, 0x90, 0x90, 0x05, + 0x13, 0xe4, 0x7d, 0xf1, 0xc0, 0xe7, 0xc9, 0x24, 0x92, 0xfd, 0xf9, 0x3b, 0xad, 0x86, 0x98, 0x62, + 0x20, 0x0c, 0xa0, 0xd5, 0x64, 0xc7, 0xdf, 0x62, 0x20, 0xf3, 0x2d, 0x70, 0xff, 0x44, 0xda, 0x75, + 0x43, 0x9e, 0x4d, 0x31, 0x7f, 0xb0, 0x75, 0xca, 0x4e, 0x99, 0x5e, 0xde, 0x54, 0x2b, 0x7b, 0xba, + 0x39, 0x8d, 0x67, 0xa7, 0x51, 0x7a, 0xd3, 0xfc, 0x98, 0xc3, 0xde, 0xef, 0x6b, 0xe0, 0xde, 0xd3, + 0x51, 0x49, 0x1f, 0x2a, 0x29, 0x0b, 0xd1, 0x73, 0xba, 0xce, 0x4e, 0x63, 0xd7, 0xeb, 0x3f, 0x9d, + 0x4d, 0xff, 0x2e, 0x0b, 0x71, 0x58, 0xa2, 0x1a, 0x47, 0x3e, 0x80, 0xaa, 0x40, 0x3e, 0x8f, 0x02, + 0xf4, 0xca, 0x9a, 0xf2, 0x72, 0x11, 0xe5, 0xc8, 0x40, 0x86, 0x25, 0x9a, 0xa3, 0x15, 0x31, 0x45, + 0xf9, 0x80, 0xf1, 0x89, 0xb7, 0xb6, 0x9a, 0x78, 0xd7, 0x40, 0x14, 0xd1, 0xa2, 0x55, 0x86, 0xd2, + 0x17, 0x13, 0xaf, 0xb2, 0x3a, 0xc3, 0xaf, 0x7c, 0xa1, 0x28, 0x1a, 0xa7, 0x2e, 0x0a, 0xe2, 0x99, + 0x90, 0xc8, 0xbd, 0xf5, 0xd5, 0x17, 0xdd, 0x31, 0x10, 0x75, 0x91, 0x45, 0x93, 0xf7, 0xc0, 0x15, + 0x18, 0x70, 0x94, 0x9e, 0xab, 0x79, 0xad, 0xe2, 0x37, 0x53, 0x88, 0x61, 0x89, 0x5a, 0x2c, 0xf9, + 0x08, 0x6a, 0x1c, 0x05, 0x9b, 0xf1, 0x00, 0xbd, 0xaa, 0xe6, 0x6d, 0x17, 0xf1, 0xa8, 0xc5, 0x0c, + 0x4b, 0xf4, 0x1c, 0x4f, 0x3e, 0x81, 0x3a, 0x3e, 0x94, 0x98, 0x8a, 0x88, 0xa5, 0x5e, 0x4d, 0x93, + 0x5f, 0x29, 0x22, 0xef, 0xe7, 0xa0, 0x61, 0x89, 0x2e, 0x19, 0x83, 0x5a, 0xee, 0x62, 0xef, 0x10, + 0x36, 0x8e, 0x30, 0xc6, 0x40, 0x0e, 0xce, 0x8e, 0x62, 0x26, 0xc9, 0x0d, 0x00, 0xab, 0xfb, 0x38, + 0x0a, 0xb5, 0xb7, 0xf5, 0x41, 0x33, 0x5b, 0x74, 0xea, 0xd6, 0x98, 0xd1, 0x1e, 0xad, 0x5b, 0xc0, + 0x28, 0x24, 0x04, 0x2a, 0x22, 0x66, 0x52, 0x1b, 0x5a, 0xa1, 0x7a, 0xdd, 0x3b, 0x84, 0x2b, 0x79, + 0xc4, 0x3b, 0x33, 0x21, 0x59, 0xa2, 0x50, 0x93, 0x28, 0xb5, 0xd1, 0xa8, 0x5e, 0x93, 0x2d, 0x58, + 0x8f, 0xd2, 0x10, 0x1f, 0x6a, 0x6a, 0x9d, 0x9a, 0x8d, 0x3a, 0x9d, 0xfb, 0xf1, 0x0c, 0xb5, 0xd1, + 0x75, 0x6a, 0x36, 0xbd, 0x9f, 0x5c, 0xa8, 0xe5, 0x21, 0x89, 0x07, 0xe5, 0xf3, 0xc4, 0xdc, 0x6c, + 0xd1, 0x29, 0x8f, 0xf6, 0x86, 0x25, 0x5a, 0x8e, 0x42, 0x72, 0x1d, 0xea, 0x51, 0x38, 0x9e, 0x72, + 0x3c, 0x89, 0x6c, 0xd8, 0xc1, 0x46, 0xb6, 0xe8, 0xd4, 0x46, 0x7b, 0x87, 0xfa, 0x4c, 0x09, 0x18, + 0x85, 0x66, 0x4d, 0xb6, 0xa0, 0x92, 0xfa, 0x89, 0xbd, 0x48, 0xd7, 0xa8, 0x9f, 0x20, 0x79, 0x15, + 0x1a, 0xea, 0x37, 0x0f, 0x52, 0xb1, 0x0f, 0x41, 0x1d, 0x5a, 0xe2, 0x6d, 0x70, 0x03, 0xfd, 0x5a, + 0xb6, 0x46, 0x7a, 0xc5, 0x5e, 0x5f, 0x14, 0x40, 0x79, 0x6e, 0x38, 0x64, 0x04, 0x4d, 0xb3, 0xca, + 0xaf, 0x70, 0x9f, 0x23, 0xc8, 0x86, 0xa1, 0xda, 0x44, 0xfa, 0xff, 0x71, 0xaa, 0x5a, 0xe0, 0x94, + 0xf2, 0x7c, 0xe9, 0xd5, 0xeb, 0x50, 0x55, 0x7d, 0xa8, 0xc0, 0x35, 0x0d, 0x86, 0x6c, 0xd1, 0x71, + 0x55, 0x8b, 0x6a, 0xa4, 0xab, 0x1e, 0x8e, 0x42, 0x72, 0xcb, 0x5a, 0x5a, 0xd7, 0x89, 0x75, 0x2f, + 0x4b, 0x4c, 0x15, 0x8c, 0x92, 0x4e, 0xe1, 0xc9, 0x1e, 0x34, 0x43, 0x14, 0x11, 0xc7, 0x70, 0x2c, + 0xa4, 0x2f, 0xd1, 0x83, 0xae, 0xb3, 0x73, 0xa5, 0xb8, 0x2a, 0x55, 0xd7, 0x1d, 0x29, 0x90, 0x7a, + 0x29, 0xcb, 0xd2, 0x7b, 0xb2, 0x0b, 0x15, 0xce, 0x62, 0xf4, 0x1a, 0x9a, 0xbc, 0xbd, 0x6a, 0xa8, + 0x50, 0x16, 0xeb, 0xc1, 0xa2, 0xb0, 0x64, 0x04, 0x90, 0x60, 0x72, 0x8c, 0x5c, 0xdc, 0x8f, 0xa6, + 0xde, 0x86, 0x66, 0xbe, 0xb9, 0x8a, 0x79, 0x34, 0xc5, 0xa0, 0x7f, 0x70, 0x0e, 0x57, 0xe6, 0x2e, + 0xc9, 0xe4, 0x00, 0xae, 0x71, 0x3c, 0x41, 0x8e, 0x69, 0x80, 0xe1, 0xd8, 0xce, 0x11, 0xa5, 0x58, + 0x53, 0x2b, 0xf6, 0x52, 0xb6, 0xe8, 0x6c, 0xd2, 0x73, 0x80, 0x1d, 0x39, 0x5a, 0xbe, 0x4d, 0xfe, + 0xd4, 0x71, 0x48, 0xbe, 0x80, 0xad, 0x0b, 0xe1, 0x4c, 0xdb, 0xab, 0x68, 0x57, 0x74, 0xb4, 0x17, + 0xb3, 0x45, 0x87, 0x2c, 0xa3, 0x99, 0xf9, 0xa0, 0x83, 0x11, 0xfe, 0xe4, 0xa9, 0x6a, 0x18, 0xd3, + 0x44, 0x57, 0xf3, 0x82, 0x55, 0xbb, 0x41, 0x05, 0xca, 0x83, 0xb3, 0xde, 0x5f, 0x65, 0xd8, 0xf8, + 0xc6, 0x97, 0xc1, 0x7d, 0x8a, 0xdf, 0xcd, 0x50, 0x48, 0xb2, 0x0f, 0x55, 0x4c, 0x25, 0x8f, 0x50, + 0x78, 0x4e, 0x77, 0x6d, 0xa7, 0xb1, 0x7b, 0xbd, 0x48, 0x8f, 0x8b, 0x14, 0xb3, 0xd9, 0x4f, 0x25, + 0x3f, 0xa3, 0x39, 0x97, 0xdc, 0x86, 0x06, 0x47, 0x31, 0x4b, 0x70, 0x7c, 0xc2, 0x59, 0x72, 0xd9, + 0xd8, 0xfe, 0x1a, 0xb9, 0x1a, 0x2c, 0x14, 0x0c, 0xfe, 0x73, 0xce, 0x12, 0x72, 0x03, 0x48, 0x94, + 0x06, 0xf1, 0x2c, 0xc4, 0x31, 0x8b, 0xc3, 0xb1, 0xf9, 0x18, 0xe9, 0x86, 0xab, 0xd1, 0x17, 0xec, + 0x93, 0x7b, 0x71, 0x68, 0x06, 0x51, 0xeb, 0x07, 0x07, 0x60, 0x99, 0x43, 0xe1, 0xcc, 0xf8, 0x18, + 0x5c, 0x3f, 0x90, 0x6a, 0xe2, 0x95, 0xb5, 0xc9, 0xaf, 0x15, 0x16, 0xa7, 0xfa, 0x42, 0x7e, 0xa6, + 0x61, 0x5f, 0x46, 0x69, 0x48, 0x2d, 0x85, 0xdc, 0x82, 0xea, 0x49, 0x14, 0x4b, 0xe4, 0xc2, 0x5b, + 0xd3, 0x92, 0x6c, 0x5f, 0x56, 0xda, 0x34, 0x07, 0xf7, 0x7e, 0xcd, 0xb5, 0x3d, 0x40, 0x21, 0xfc, + 0x53, 0x24, 0x9f, 0x82, 0x8b, 0x73, 0x4c, 0x65, 0x2e, 0xed, 0x1b, 0x2b, 0xa5, 0xb5, 0x8c, 0xfe, + 0xbe, 0x82, 0x53, 0xcb, 0x22, 0xef, 0x43, 0x75, 0x6e, 0xd4, 0xfa, 0x3f, 0x82, 0xe6, 0xd8, 0xd6, + 0x2f, 0x0e, 0xac, 0xeb, 0x40, 0x17, 0x64, 0x70, 0x9e, 0x5f, 0x86, 0x5d, 0x70, 0xad, 0x11, 0xe5, + 0xd5, 0x9f, 0x2a, 0x63, 0x09, 0xb5, 0x48, 0xf2, 0x21, 0xc0, 0x13, 0x06, 0x5e, 0xce, 0xab, 0xb3, + 0xdc, 0xd5, 0xdd, 0x04, 0xd6, 0x75, 0x26, 0x24, 0x84, 0x75, 0xad, 0x09, 0xe9, 0x3e, 0xab, 0x12, + 0x5b, 0xdd, 0x67, 0x09, 0xda, 0xbb, 0xf6, 0xdb, 0xcf, 0xff, 0xfc, 0x58, 0xbe, 0x0a, 0x4d, 0x8d, + 0x78, 0x2b, 0xf1, 0x53, 0xff, 0x14, 0xf9, 0xdb, 0xce, 0xc0, 0x7b, 0xf4, 0xb8, 0x5d, 0xfa, 0xf3, + 0x71, 0xbb, 0xf4, 0x7d, 0xd6, 0x76, 0x1e, 0x65, 0x6d, 0xe7, 0x8f, 0xac, 0xed, 0xfc, 0x9d, 0xb5, + 0x9d, 0x63, 0x57, 0xff, 0x7f, 0x79, 0xf7, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4a, 0x57, 0xad, + 0x86, 0x42, 0x09, 0x00, 0x00, } diff --git a/api/store.proto b/api/store.proto index 21e149fdfa..8a8894c6f5 100644 --- a/api/store.proto +++ b/api/store.proto @@ -105,6 +105,12 @@ message WatchRequest { // server has compacted its log and no longer has complete history to // this point. Version resume_from = 2; + + // IncludeOldObject causes WatchMessages to include a copy of the + // previous version of the object on updates. Note that only live + // changes will include the old object (not historical changes + // retrieved using ResumeFrom). + bool include_old_object = 3; } // WatchMessage is the type of the stream that's returned to the client by @@ -119,6 +125,11 @@ message WatchMessage { // Matched object Object object = 2; + + // For updates, OldObject will optionally be included in the + // watch message, containing the previous version of the + // object, if IncludeOldObject was set in WatchRequest. + Object old_object = 3; } repeated Event events = 1; diff --git a/api/storeobject.go b/api/storeobject.go index 4aa7496441..67c6ec897b 100644 --- a/api/storeobject.go +++ b/api/storeobject.go @@ -11,13 +11,13 @@ var errUnknownStoreAction = errors.New("unrecognized action type") // StoreObject is an abstract object that can be handled by the store. type StoreObject interface { - GetID() string // Get ID - GetMeta() Meta // Retrieve metadata - SetMeta(Meta) // Set metadata - CopyStoreObject() StoreObject // Return a copy of this object - EventCreate() Event // Return a creation event - EventUpdate() Event // Return an update event - EventDelete() Event // Return a deletion event + GetID() string // Get ID + GetMeta() Meta // Retrieve metadata + SetMeta(Meta) // Set metadata + CopyStoreObject() StoreObject // Return a copy of this object + EventCreate() Event // Return a creation event + EventUpdate(oldObject StoreObject) Event // Return an update event + EventDelete() Event // Return a deletion event } // Event is the type used for events passed over watcher channels, and also diff --git a/manager/state/store/memory.go b/manager/state/store/memory.go index e0877b5179..deb4db521b 100644 --- a/manager/state/store/memory.go +++ b/manager/state/store/memory.go @@ -195,7 +195,7 @@ func (s *MemoryStore) changelistBetweenVersions(from, to api.Version) ([]api.Eve for _, change := range changes { for _, sa := range change.StoreActions { - event, err := api.EventFromStoreAction(sa) + event, err := api.EventFromStoreAction(sa, nil) if err != nil { return nil, err } @@ -529,7 +529,7 @@ func (tx *tx) update(table string, o api.StoreObject) error { err := tx.memDBTx.Insert(table, copy) if err == nil { - tx.changelist = append(tx.changelist, copy.EventUpdate()) + tx.changelist = append(tx.changelist, copy.EventUpdate(oldN)) o.SetMeta(meta) } return err diff --git a/manager/storeapi/watch.go b/manager/storeapi/watch.go index ece1402a36..fbf60dc663 100644 --- a/manager/storeapi/watch.go +++ b/manager/storeapi/watch.go @@ -592,49 +592,49 @@ func watchMessageEvent(event api.Event) *api.WatchMessage_Event { case api.EventCreateTask: return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}} case api.EventUpdateTask: - return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}, OldObject: &api.Object{Object: &api.Object_Task{Task: v.OldTask}}} case api.EventDeleteTask: return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}} case api.EventCreateService: return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}} case api.EventUpdateService: - return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}, OldObject: &api.Object{Object: &api.Object_Service{Service: v.OldService}}} case api.EventDeleteService: return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}} case api.EventCreateNetwork: return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}} case api.EventUpdateNetwork: - return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}, OldObject: &api.Object{Object: &api.Object_Network{Network: v.OldNetwork}}} case api.EventDeleteNetwork: return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}} case api.EventCreateNode: return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}} case api.EventUpdateNode: - return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}, OldObject: &api.Object{Object: &api.Object_Node{Node: v.OldNode}}} case api.EventDeleteNode: return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}} case api.EventCreateCluster: return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}} case api.EventUpdateCluster: - return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}, OldObject: &api.Object{Object: &api.Object_Cluster{Cluster: v.OldCluster}}} case api.EventDeleteCluster: return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}} case api.EventCreateSecret: return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}} case api.EventUpdateSecret: - return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}, OldObject: &api.Object{Object: &api.Object_Secret{Secret: v.OldSecret}}} case api.EventDeleteSecret: return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}} case api.EventCreateResource: return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}} case api.EventUpdateResource: - return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}, OldObject: &api.Object{Object: &api.Object_Resource{Resource: v.OldResource}}} case api.EventDeleteResource: return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}} case api.EventCreateExtension: return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}} case api.EventUpdateExtension: - return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}} + return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}, OldObject: &api.Object{Object: &api.Object_Extension{Extension: v.OldExtension}}} case api.EventDeleteExtension: return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}} } @@ -678,6 +678,9 @@ func (s *Server) Watch(request *api.WatchRequest, stream api.Store_WatchServer) } events = nil } else if eventMessage := watchMessageEvent(event.(api.Event)); eventMessage != nil { + if !request.IncludeOldObject { + eventMessage.OldObject = nil + } events = append(events, eventMessage) } } diff --git a/manager/storeapi/watch_test.go b/manager/storeapi/watch_test.go index 28e5526689..da0f6a7b7d 100644 --- a/manager/storeapi/watch_test.go +++ b/manager/storeapi/watch_test.go @@ -160,6 +160,52 @@ func TestWatch(t *testing.T) { watch.CloseSend() } +func TestWatchIncludeOldObject(t *testing.T) { + ts := newTestServer(t) + defer ts.Stop() + + ctx := context.Background() + + // Watch for node updates + watch, err := ts.Client.Watch(ctx, &api.WatchRequest{ + Entries: []*api.WatchRequest_WatchEntry{ + { + Kind: "node", + Action: api.StoreActionKindUpdate, + }, + }, + IncludeOldObject: true, + }) + assert.NoError(t, err) + + // Should receive an initial message that indicates the watch is ready + msg, err := watch.Recv() + assert.NoError(t, err) + assert.Equal(t, &api.WatchMessage{}, msg) + + createNode(t, ts, "id1", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY) + + err = ts.Store.Update(func(tx store.Tx) error { + node := store.GetNode(tx, "id1") + require.NotNil(t, node) + node.Role = api.NodeRoleWorker + return store.UpdateNode(tx, node) + }) + assert.NoError(t, err) + + msg, err = watch.Recv() + assert.NoError(t, err) + assert.Equal(t, api.StoreActionKindUpdate, msg.Events[0].Action) + require.NotNil(t, msg.Events[0].Object.GetNode()) + assert.Equal(t, "id1", msg.Events[0].Object.GetNode().ID) + assert.Equal(t, api.NodeRoleWorker, msg.Events[0].Object.GetNode().Role) + require.NotNil(t, msg.Events[0].OldObject.GetNode()) + assert.Equal(t, "id1", msg.Events[0].OldObject.GetNode().ID) + assert.Equal(t, api.NodeRoleManager, msg.Events[0].OldObject.GetNode().Role) + + watch.CloseSend() +} + func TestWatchResumeFrom(t *testing.T) { ts := newTestServer(t) defer ts.Stop() diff --git a/protobuf/plugin/storeobject/storeobject.go b/protobuf/plugin/storeobject/storeobject.go index e141227ef8..690ef06b70 100644 --- a/protobuf/plugin/storeobject/storeobject.go +++ b/protobuf/plugin/storeobject/storeobject.go @@ -45,6 +45,9 @@ func (d *storeObjectGen) genMsgStoreObject(m *generator.Descriptor, storeObject d.P("type Event", event, ccTypeName, " struct {") d.In() d.P(ccTypeName, " *", ccTypeName) + if event == "Update" { + d.P("Old", ccTypeName, " *", ccTypeName) + } d.P("Checks []", ccTypeName, "CheckFunc") d.Out() d.P("}") @@ -109,11 +112,19 @@ func (d *storeObjectGen) genMsgStoreObject(m *generator.Descriptor, storeObject d.P("}") d.P() - d.P("func (m *", ccTypeName, ") EventUpdate() Event {") + d.P("func (m *", ccTypeName, ") EventUpdate(oldObject StoreObject) Event {") + d.In() + d.P("if oldObject != nil {") + d.In() + d.P("return EventUpdate", ccTypeName, "{", ccTypeName, ": m, Old", ccTypeName, ": oldObject.(*", ccTypeName, ")}") + d.Out() + d.P("} else {") d.In() d.P("return EventUpdate", ccTypeName, "{", ccTypeName, ": m}") d.Out() d.P("}") + d.Out() + d.P("}") d.P() d.P("func (m *", ccTypeName, ") EventDelete() Event {") @@ -241,7 +252,7 @@ func (d *storeObjectGen) genEventFromStoreAction(topLevelObjs []string) { } // Generate EventFromStoreAction - d.P("func EventFromStoreAction(sa StoreAction) (Event, error) {") + d.P("func EventFromStoreAction(sa StoreAction, oldObject StoreObject) (Event, error) {") d.In() d.P("switch v := sa.Target.(type) {") for _, ccTypeName := range topLevelObjs { @@ -256,8 +267,16 @@ func (d *storeObjectGen) genEventFromStoreAction(topLevelObjs []string) { d.P("case StoreActionKindUpdate:") d.In() + d.P("if oldObject != nil {") + d.In() + d.P("return EventUpdate", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, ", Old", ccTypeName, ": oldObject.(*", ccTypeName, ")}, nil") + d.Out() + d.P("} else {") + d.In() d.P("return EventUpdate", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, "}, nil") d.Out() + d.P("}") + d.Out() d.P("case StoreActionKindRemove:") d.In() From 17dcdf83607bbd89090a1baf75426f580b29e347 Mon Sep 17 00:00:00 2001 From: Aaron Lehmann Date: Fri, 17 Mar 2017 12:20:41 -0700 Subject: [PATCH 4/7] Allow multiple watch actions to be specified by ORing them Signed-off-by: Aaron Lehmann --- api/store.pb.go | 177 +++++++++++++--------- api/store.proto | 18 ++- manager/storeapi/watch.go | 262 ++++++++++++++++++--------------- manager/storeapi/watch_test.go | 74 ++++++++-- 4 files changed, 333 insertions(+), 198 deletions(-) diff --git a/api/store.pb.go b/api/store.pb.go index 9e739950cd..e0dc2579cc 100644 --- a/api/store.pb.go +++ b/api/store.pb.go @@ -33,6 +33,36 @@ var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf +// WatchActionKind distinguishes between creations, updates, and removals. It +// is structured as a bitmap so multiple kinds of events can be requested with +// a mask. +type WatchActionKind int32 + +const ( + WatchActionKindUnknown WatchActionKind = 0 + WatchActionKindCreate WatchActionKind = 1 + WatchActionKindUpdate WatchActionKind = 2 + WatchActionKindRemove WatchActionKind = 4 +) + +var WatchActionKind_name = map[int32]string{ + 0: "WATCH_ACTION_UNKNOWN", + 1: "WATCH_ACTION_CREATE", + 2: "WATCH_ACTION_UPDATE", + 4: "WATCH_ACTION_REMOVE", +} +var WatchActionKind_value = map[string]int32{ + "WATCH_ACTION_UNKNOWN": 0, + "WATCH_ACTION_CREATE": 1, + "WATCH_ACTION_UPDATE": 2, + "WATCH_ACTION_REMOVE": 4, +} + +func (x WatchActionKind) String() string { + return proto.EnumName(WatchActionKind_name, int32(x)) +} +func (WatchActionKind) EnumDescriptor() ([]byte, []int) { return fileDescriptorStore, []int{0} } + type Object struct { // Types that are valid to be assigned to Object: // *Object_Node @@ -867,7 +897,8 @@ type WatchRequest_WatchEntry struct { // the kind specified by a custom-defined object. Kind string `protobuf:"bytes,1,opt,name=kind,proto3" json:"kind,omitempty"` // Action (create/update/delete) - Action StoreActionKind `protobuf:"varint,2,opt,name=action,proto3,enum=docker.swarmkit.v1.StoreActionKind" json:"action,omitempty"` + // This is a bitmask, so multiple actions may be OR'd together + Action WatchActionKind `protobuf:"varint,2,opt,name=action,proto3,enum=docker.swarmkit.v1.WatchActionKind" json:"action,omitempty"` // Filters are combined using AND logic - an event must match // all of them to pass the filter. Filters []*SelectBy `protobuf:"bytes,3,rep,name=filters" json:"filters,omitempty"` @@ -895,7 +926,7 @@ type WatchMessage_Event struct { // Action (create/update/delete) // Note that WatchMessage does not expose "commit" events that // mark transaction boundaries. - Action StoreActionKind `protobuf:"varint,1,opt,name=action,proto3,enum=docker.swarmkit.v1.StoreActionKind" json:"action,omitempty"` + Action WatchActionKind `protobuf:"varint,1,opt,name=action,proto3,enum=docker.swarmkit.v1.WatchActionKind" json:"action,omitempty"` // Matched object Object *Object `protobuf:"bytes,2,opt,name=object" json:"object,omitempty"` // For updates, OldObject will optionally be included in the @@ -917,6 +948,7 @@ func init() { proto.RegisterType((*WatchRequest_WatchEntry)(nil), "docker.swarmkit.v1.WatchRequest.WatchEntry") proto.RegisterType((*WatchMessage)(nil), "docker.swarmkit.v1.WatchMessage") proto.RegisterType((*WatchMessage_Event)(nil), "docker.swarmkit.v1.WatchMessage.Event") + proto.RegisterEnum("docker.swarmkit.v1.WatchActionKind", WatchActionKind_name, WatchActionKind_value) } type authenticatedWrapperStoreServer struct { @@ -3886,7 +3918,7 @@ func (m *WatchRequest_WatchEntry) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Action |= (StoreActionKind(b) & 0x7F) << shift + m.Action |= (WatchActionKind(b) & 0x7F) << shift if b < 0x80 { break } @@ -4100,7 +4132,7 @@ func (m *WatchMessage_Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Action |= (StoreActionKind(b) & 0x7F) << shift + m.Action |= (WatchActionKind(b) & 0x7F) << shift if b < 0x80 { break } @@ -4300,69 +4332,76 @@ var ( func init() { proto.RegisterFile("store.proto", fileDescriptorStore) } var fileDescriptorStore = []byte{ - // 1013 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x94, 0x56, 0xdd, 0x6e, 0x1b, 0x45, - 0x14, 0xf6, 0x3a, 0xce, 0xda, 0x3e, 0x8e, 0x5b, 0x34, 0x49, 0x61, 0x65, 0x82, 0x6d, 0x8c, 0x80, - 0x48, 0x2d, 0x2e, 0x04, 0x28, 0x02, 0x0a, 0x12, 0x6e, 0x82, 0x6c, 0x50, 0xda, 0x68, 0x82, 0xe0, - 0xd2, 0xda, 0xec, 0x9e, 0xa4, 0x8b, 0x77, 0x77, 0xcc, 0xcc, 0xd8, 0x6d, 0xee, 0x78, 0x09, 0x24, - 0xae, 0x78, 0x04, 0x6e, 0xb8, 0xe4, 0x05, 0x2a, 0x2e, 0x10, 0x97, 0x70, 0x63, 0xd1, 0x7d, 0x00, - 0x9e, 0x01, 0xcd, 0xcf, 0xc6, 0xa1, 0x5d, 0xa7, 0xf4, 0xca, 0x33, 0xb3, 0xdf, 0x77, 0xe6, 0xec, - 0xf7, 0x9d, 0x73, 0xd6, 0xd0, 0x10, 0x92, 0x71, 0xec, 0x4f, 0x39, 0x93, 0x8c, 0x90, 0x90, 0x05, - 0x13, 0xe4, 0x7d, 0xf1, 0xc0, 0xe7, 0xc9, 0x24, 0x92, 0xfd, 0xf9, 0x3b, 0xad, 0x86, 0x98, 0x62, - 0x20, 0x0c, 0xa0, 0xd5, 0x64, 0xc7, 0xdf, 0x62, 0x20, 0xf3, 0x2d, 0x70, 0xff, 0x44, 0xda, 0x75, - 0x43, 0x9e, 0x4d, 0x31, 0x7f, 0xb0, 0x75, 0xca, 0x4e, 0x99, 0x5e, 0xde, 0x54, 0x2b, 0x7b, 0xba, - 0x39, 0x8d, 0x67, 0xa7, 0x51, 0x7a, 0xd3, 0xfc, 0x98, 0xc3, 0xde, 0xef, 0x6b, 0xe0, 0xde, 0xd3, - 0x51, 0x49, 0x1f, 0x2a, 0x29, 0x0b, 0xd1, 0x73, 0xba, 0xce, 0x4e, 0x63, 0xd7, 0xeb, 0x3f, 0x9d, - 0x4d, 0xff, 0x2e, 0x0b, 0x71, 0x58, 0xa2, 0x1a, 0x47, 0x3e, 0x80, 0xaa, 0x40, 0x3e, 0x8f, 0x02, - 0xf4, 0xca, 0x9a, 0xf2, 0x72, 0x11, 0xe5, 0xc8, 0x40, 0x86, 0x25, 0x9a, 0xa3, 0x15, 0x31, 0x45, - 0xf9, 0x80, 0xf1, 0x89, 0xb7, 0xb6, 0x9a, 0x78, 0xd7, 0x40, 0x14, 0xd1, 0xa2, 0x55, 0x86, 0xd2, - 0x17, 0x13, 0xaf, 0xb2, 0x3a, 0xc3, 0xaf, 0x7c, 0xa1, 0x28, 0x1a, 0xa7, 0x2e, 0x0a, 0xe2, 0x99, - 0x90, 0xc8, 0xbd, 0xf5, 0xd5, 0x17, 0xdd, 0x31, 0x10, 0x75, 0x91, 0x45, 0x93, 0xf7, 0xc0, 0x15, - 0x18, 0x70, 0x94, 0x9e, 0xab, 0x79, 0xad, 0xe2, 0x37, 0x53, 0x88, 0x61, 0x89, 0x5a, 0x2c, 0xf9, - 0x08, 0x6a, 0x1c, 0x05, 0x9b, 0xf1, 0x00, 0xbd, 0xaa, 0xe6, 0x6d, 0x17, 0xf1, 0xa8, 0xc5, 0x0c, - 0x4b, 0xf4, 0x1c, 0x4f, 0x3e, 0x81, 0x3a, 0x3e, 0x94, 0x98, 0x8a, 0x88, 0xa5, 0x5e, 0x4d, 0x93, - 0x5f, 0x29, 0x22, 0xef, 0xe7, 0xa0, 0x61, 0x89, 0x2e, 0x19, 0x83, 0x5a, 0xee, 0x62, 0xef, 0x10, - 0x36, 0x8e, 0x30, 0xc6, 0x40, 0x0e, 0xce, 0x8e, 0x62, 0x26, 0xc9, 0x0d, 0x00, 0xab, 0xfb, 0x38, - 0x0a, 0xb5, 0xb7, 0xf5, 0x41, 0x33, 0x5b, 0x74, 0xea, 0xd6, 0x98, 0xd1, 0x1e, 0xad, 0x5b, 0xc0, - 0x28, 0x24, 0x04, 0x2a, 0x22, 0x66, 0x52, 0x1b, 0x5a, 0xa1, 0x7a, 0xdd, 0x3b, 0x84, 0x2b, 0x79, - 0xc4, 0x3b, 0x33, 0x21, 0x59, 0xa2, 0x50, 0x93, 0x28, 0xb5, 0xd1, 0xa8, 0x5e, 0x93, 0x2d, 0x58, - 0x8f, 0xd2, 0x10, 0x1f, 0x6a, 0x6a, 0x9d, 0x9a, 0x8d, 0x3a, 0x9d, 0xfb, 0xf1, 0x0c, 0xb5, 0xd1, - 0x75, 0x6a, 0x36, 0xbd, 0x9f, 0x5c, 0xa8, 0xe5, 0x21, 0x89, 0x07, 0xe5, 0xf3, 0xc4, 0xdc, 0x6c, - 0xd1, 0x29, 0x8f, 0xf6, 0x86, 0x25, 0x5a, 0x8e, 0x42, 0x72, 0x1d, 0xea, 0x51, 0x38, 0x9e, 0x72, - 0x3c, 0x89, 0x6c, 0xd8, 0xc1, 0x46, 0xb6, 0xe8, 0xd4, 0x46, 0x7b, 0x87, 0xfa, 0x4c, 0x09, 0x18, - 0x85, 0x66, 0x4d, 0xb6, 0xa0, 0x92, 0xfa, 0x89, 0xbd, 0x48, 0xd7, 0xa8, 0x9f, 0x20, 0x79, 0x15, - 0x1a, 0xea, 0x37, 0x0f, 0x52, 0xb1, 0x0f, 0x41, 0x1d, 0x5a, 0xe2, 0x6d, 0x70, 0x03, 0xfd, 0x5a, - 0xb6, 0x46, 0x7a, 0xc5, 0x5e, 0x5f, 0x14, 0x40, 0x79, 0x6e, 0x38, 0x64, 0x04, 0x4d, 0xb3, 0xca, - 0xaf, 0x70, 0x9f, 0x23, 0xc8, 0x86, 0xa1, 0xda, 0x44, 0xfa, 0xff, 0x71, 0xaa, 0x5a, 0xe0, 0x94, - 0xf2, 0x7c, 0xe9, 0xd5, 0xeb, 0x50, 0x55, 0x7d, 0xa8, 0xc0, 0x35, 0x0d, 0x86, 0x6c, 0xd1, 0x71, - 0x55, 0x8b, 0x6a, 0xa4, 0xab, 0x1e, 0x8e, 0x42, 0x72, 0xcb, 0x5a, 0x5a, 0xd7, 0x89, 0x75, 0x2f, - 0x4b, 0x4c, 0x15, 0x8c, 0x92, 0x4e, 0xe1, 0xc9, 0x1e, 0x34, 0x43, 0x14, 0x11, 0xc7, 0x70, 0x2c, - 0xa4, 0x2f, 0xd1, 0x83, 0xae, 0xb3, 0x73, 0xa5, 0xb8, 0x2a, 0x55, 0xd7, 0x1d, 0x29, 0x90, 0x7a, - 0x29, 0xcb, 0xd2, 0x7b, 0xb2, 0x0b, 0x15, 0xce, 0x62, 0xf4, 0x1a, 0x9a, 0xbc, 0xbd, 0x6a, 0xa8, - 0x50, 0x16, 0xeb, 0xc1, 0xa2, 0xb0, 0x64, 0x04, 0x90, 0x60, 0x72, 0x8c, 0x5c, 0xdc, 0x8f, 0xa6, - 0xde, 0x86, 0x66, 0xbe, 0xb9, 0x8a, 0x79, 0x34, 0xc5, 0xa0, 0x7f, 0x70, 0x0e, 0x57, 0xe6, 0x2e, - 0xc9, 0xe4, 0x00, 0xae, 0x71, 0x3c, 0x41, 0x8e, 0x69, 0x80, 0xe1, 0xd8, 0xce, 0x11, 0xa5, 0x58, - 0x53, 0x2b, 0xf6, 0x52, 0xb6, 0xe8, 0x6c, 0xd2, 0x73, 0x80, 0x1d, 0x39, 0x5a, 0xbe, 0x4d, 0xfe, - 0xd4, 0x71, 0x48, 0xbe, 0x80, 0xad, 0x0b, 0xe1, 0x4c, 0xdb, 0xab, 0x68, 0x57, 0x74, 0xb4, 0x17, - 0xb3, 0x45, 0x87, 0x2c, 0xa3, 0x99, 0xf9, 0xa0, 0x83, 0x11, 0xfe, 0xe4, 0xa9, 0x6a, 0x18, 0xd3, - 0x44, 0x57, 0xf3, 0x82, 0x55, 0xbb, 0x41, 0x05, 0xca, 0x83, 0xb3, 0xde, 0x5f, 0x65, 0xd8, 0xf8, - 0xc6, 0x97, 0xc1, 0x7d, 0x8a, 0xdf, 0xcd, 0x50, 0x48, 0xb2, 0x0f, 0x55, 0x4c, 0x25, 0x8f, 0x50, - 0x78, 0x4e, 0x77, 0x6d, 0xa7, 0xb1, 0x7b, 0xbd, 0x48, 0x8f, 0x8b, 0x14, 0xb3, 0xd9, 0x4f, 0x25, - 0x3f, 0xa3, 0x39, 0x97, 0xdc, 0x86, 0x06, 0x47, 0x31, 0x4b, 0x70, 0x7c, 0xc2, 0x59, 0x72, 0xd9, - 0xd8, 0xfe, 0x1a, 0xb9, 0x1a, 0x2c, 0x14, 0x0c, 0xfe, 0x73, 0xce, 0x12, 0x72, 0x03, 0x48, 0x94, - 0x06, 0xf1, 0x2c, 0xc4, 0x31, 0x8b, 0xc3, 0xb1, 0xf9, 0x18, 0xe9, 0x86, 0xab, 0xd1, 0x17, 0xec, - 0x93, 0x7b, 0x71, 0x68, 0x06, 0x51, 0xeb, 0x07, 0x07, 0x60, 0x99, 0x43, 0xe1, 0xcc, 0xf8, 0x18, - 0x5c, 0x3f, 0x90, 0x6a, 0xe2, 0x95, 0xb5, 0xc9, 0xaf, 0x15, 0x16, 0xa7, 0xfa, 0x42, 0x7e, 0xa6, - 0x61, 0x5f, 0x46, 0x69, 0x48, 0x2d, 0x85, 0xdc, 0x82, 0xea, 0x49, 0x14, 0x4b, 0xe4, 0xc2, 0x5b, - 0xd3, 0x92, 0x6c, 0x5f, 0x56, 0xda, 0x34, 0x07, 0xf7, 0x7e, 0xcd, 0xb5, 0x3d, 0x40, 0x21, 0xfc, - 0x53, 0x24, 0x9f, 0x82, 0x8b, 0x73, 0x4c, 0x65, 0x2e, 0xed, 0x1b, 0x2b, 0xa5, 0xb5, 0x8c, 0xfe, - 0xbe, 0x82, 0x53, 0xcb, 0x22, 0xef, 0x43, 0x75, 0x6e, 0xd4, 0xfa, 0x3f, 0x82, 0xe6, 0xd8, 0xd6, - 0x2f, 0x0e, 0xac, 0xeb, 0x40, 0x17, 0x64, 0x70, 0x9e, 0x5f, 0x86, 0x5d, 0x70, 0xad, 0x11, 0xe5, - 0xd5, 0x9f, 0x2a, 0x63, 0x09, 0xb5, 0x48, 0xf2, 0x21, 0xc0, 0x13, 0x06, 0x5e, 0xce, 0xab, 0xb3, - 0xdc, 0xd5, 0xdd, 0x04, 0xd6, 0x75, 0x26, 0x24, 0x84, 0x75, 0xad, 0x09, 0xe9, 0x3e, 0xab, 0x12, - 0x5b, 0xdd, 0x67, 0x09, 0xda, 0xbb, 0xf6, 0xdb, 0xcf, 0xff, 0xfc, 0x58, 0xbe, 0x0a, 0x4d, 0x8d, - 0x78, 0x2b, 0xf1, 0x53, 0xff, 0x14, 0xf9, 0xdb, 0xce, 0xc0, 0x7b, 0xf4, 0xb8, 0x5d, 0xfa, 0xf3, - 0x71, 0xbb, 0xf4, 0x7d, 0xd6, 0x76, 0x1e, 0x65, 0x6d, 0xe7, 0x8f, 0xac, 0xed, 0xfc, 0x9d, 0xb5, - 0x9d, 0x63, 0x57, 0xff, 0x7f, 0x79, 0xf7, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4a, 0x57, 0xad, - 0x86, 0x42, 0x09, 0x00, 0x00, + // 1127 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x94, 0x96, 0x4f, 0x6f, 0x1b, 0xc5, + 0x1b, 0xc7, 0xbd, 0x8e, 0xb3, 0xb6, 0x1f, 0xc7, 0x6d, 0x34, 0x49, 0xdb, 0xfd, 0xf9, 0x57, 0x6c, + 0x63, 0x04, 0x54, 0xb4, 0xb8, 0x10, 0x4a, 0x11, 0x50, 0x90, 0x62, 0xc7, 0xc8, 0xa6, 0x8a, 0x13, + 0x8d, 0x93, 0xe6, 0x68, 0x6d, 0x76, 0x9f, 0xa4, 0x8b, 0xf7, 0x8f, 0x99, 0x1d, 0x3b, 0xcd, 0x8d, + 0x23, 0xea, 0x1d, 0x89, 0x4b, 0xb9, 0xc0, 0x99, 0x0b, 0x37, 0x78, 0x03, 0x15, 0x07, 0xc4, 0x11, + 0x2e, 0x16, 0xf5, 0x0b, 0xe0, 0x15, 0x70, 0x40, 0x33, 0x3b, 0x9b, 0x3f, 0xee, 0x3a, 0xa5, 0x27, + 0xcf, 0xcc, 0x7e, 0x3f, 0xcf, 0x3e, 0xf3, 0x7c, 0x67, 0x1e, 0x2f, 0x14, 0x42, 0x1e, 0x30, 0xac, + 0x0f, 0x59, 0xc0, 0x03, 0x42, 0xec, 0xc0, 0x1a, 0x20, 0xab, 0x87, 0x47, 0x26, 0xf3, 0x06, 0x0e, + 0xaf, 0x8f, 0xdf, 0x2d, 0x15, 0xc2, 0x21, 0x5a, 0x61, 0x24, 0x28, 0x15, 0x83, 0xfd, 0x2f, 0xd0, + 0xe2, 0xf1, 0xb4, 0xc0, 0x8f, 0x87, 0x18, 0x4f, 0x56, 0x0f, 0x83, 0xc3, 0x40, 0x0e, 0x6f, 0x8b, + 0x91, 0x5a, 0x5d, 0x19, 0xba, 0xa3, 0x43, 0xc7, 0xbf, 0x1d, 0xfd, 0x44, 0x8b, 0xb5, 0xdf, 0x16, + 0x40, 0xdf, 0x92, 0x91, 0x48, 0x1d, 0x32, 0x7e, 0x60, 0xa3, 0xa1, 0x55, 0xb5, 0x1b, 0x85, 0x35, + 0xa3, 0xfe, 0x7c, 0x06, 0xf5, 0x6e, 0x60, 0x63, 0x3b, 0x45, 0xa5, 0x8e, 0x7c, 0x00, 0xd9, 0x10, + 0xd9, 0xd8, 0xb1, 0xd0, 0x48, 0x4b, 0xe4, 0xff, 0x49, 0x48, 0x2f, 0x92, 0xb4, 0x53, 0x34, 0x56, + 0x0b, 0xd0, 0x47, 0x7e, 0x14, 0xb0, 0x81, 0xb1, 0x30, 0x1f, 0xec, 0x46, 0x12, 0x01, 0x2a, 0xb5, + 0xc8, 0x90, 0x9b, 0xe1, 0xc0, 0xc8, 0xcc, 0xcf, 0x70, 0xc7, 0x0c, 0x05, 0x22, 0x75, 0xe2, 0x45, + 0x96, 0x3b, 0x0a, 0x39, 0x32, 0x63, 0x71, 0xfe, 0x8b, 0x9a, 0x91, 0x44, 0xbc, 0x48, 0xa9, 0xc9, + 0x1d, 0xd0, 0x43, 0xb4, 0x18, 0x72, 0x43, 0x97, 0x5c, 0x29, 0x79, 0x67, 0x42, 0xd1, 0x4e, 0x51, + 0xa5, 0x25, 0x1f, 0x41, 0x8e, 0x61, 0x18, 0x8c, 0x98, 0x85, 0x46, 0x56, 0x72, 0xd7, 0x93, 0x38, + 0xaa, 0x34, 0xed, 0x14, 0x3d, 0xd1, 0x93, 0x4f, 0x20, 0x8f, 0x8f, 0x38, 0xfa, 0xa1, 0x13, 0xf8, + 0x46, 0x4e, 0xc2, 0xaf, 0x24, 0xc1, 0xad, 0x58, 0xd4, 0x4e, 0xd1, 0x53, 0xa2, 0x91, 0x8b, 0x5d, + 0xac, 0x6d, 0xc3, 0x52, 0x0f, 0x5d, 0xb4, 0x78, 0xe3, 0xb8, 0xe7, 0x06, 0x9c, 0xdc, 0x02, 0x50, + 0x75, 0xef, 0x3b, 0xb6, 0xf4, 0x36, 0xdf, 0x28, 0x4e, 0x27, 0x95, 0xbc, 0x32, 0xa6, 0xb3, 0x41, + 0xf3, 0x4a, 0xd0, 0xb1, 0x09, 0x81, 0x4c, 0xe8, 0x06, 0x5c, 0x1a, 0x9a, 0xa1, 0x72, 0x5c, 0xdb, + 0x86, 0x4b, 0x71, 0xc4, 0xe6, 0x28, 0xe4, 0x81, 0x27, 0x54, 0x03, 0xc7, 0x57, 0xd1, 0xa8, 0x1c, + 0x93, 0x55, 0x58, 0x74, 0x7c, 0x1b, 0x1f, 0x49, 0x34, 0x4f, 0xa3, 0x89, 0x58, 0x1d, 0x9b, 0xee, + 0x08, 0xa5, 0xd1, 0x79, 0x1a, 0x4d, 0x6a, 0xdf, 0xe9, 0x90, 0x8b, 0x43, 0x12, 0x03, 0xd2, 0x27, + 0x89, 0xe9, 0xd3, 0x49, 0x25, 0xdd, 0xd9, 0x68, 0xa7, 0x68, 0xda, 0xb1, 0xc9, 0x4d, 0xc8, 0x3b, + 0x76, 0x7f, 0xc8, 0xf0, 0xc0, 0x51, 0x61, 0x1b, 0x4b, 0xd3, 0x49, 0x25, 0xd7, 0xd9, 0xd8, 0x96, + 0x6b, 0xa2, 0x80, 0x8e, 0x1d, 0x8d, 0xc9, 0x2a, 0x64, 0x7c, 0xd3, 0x53, 0x2f, 0x92, 0x67, 0xd4, + 0xf4, 0x90, 0xbc, 0x0a, 0x05, 0xf1, 0x1b, 0x07, 0xc9, 0xa8, 0x87, 0x20, 0x16, 0x15, 0x78, 0x0f, + 0x74, 0x4b, 0x6e, 0x4b, 0x9d, 0x91, 0x5a, 0xb2, 0xd7, 0x67, 0x0b, 0x20, 0x3c, 0x8f, 0x18, 0xd2, + 0x81, 0x62, 0x34, 0x8a, 0x5f, 0xa1, 0xbf, 0x44, 0x90, 0xa5, 0x08, 0x55, 0x89, 0xd4, 0xcf, 0x39, + 0x95, 0x4d, 0x70, 0x4a, 0x78, 0x7e, 0xea, 0xd5, 0xeb, 0x90, 0x15, 0xf7, 0x50, 0x88, 0x73, 0x52, + 0x0c, 0xd3, 0x49, 0x45, 0x17, 0x57, 0x54, 0x2a, 0x75, 0xf1, 0xb0, 0x63, 0x93, 0xbb, 0xca, 0xd2, + 0xbc, 0x4c, 0xac, 0x7a, 0x51, 0x62, 0xe2, 0xc0, 0x88, 0xd2, 0x09, 0x3d, 0xd9, 0x80, 0xa2, 0x8d, + 0xa1, 0xc3, 0xd0, 0xee, 0x87, 0xdc, 0xe4, 0x68, 0x40, 0x55, 0xbb, 0x71, 0x29, 0xf9, 0x54, 0x8a, + 0x5b, 0xd7, 0x13, 0x22, 0xb1, 0x29, 0x45, 0xc9, 0x39, 0x59, 0x83, 0x0c, 0x0b, 0x5c, 0x34, 0x0a, + 0x12, 0xbe, 0x3e, 0xaf, 0xa9, 0xd0, 0xc0, 0x95, 0x8d, 0x45, 0x68, 0x49, 0x07, 0xc0, 0x43, 0x6f, + 0x1f, 0x59, 0xf8, 0xd0, 0x19, 0x1a, 0x4b, 0x92, 0x7c, 0x73, 0x1e, 0xd9, 0x1b, 0xa2, 0x55, 0xdf, + 0x3c, 0x91, 0x0b, 0x73, 0x4f, 0x61, 0xb2, 0x09, 0x57, 0x18, 0x1e, 0x20, 0x43, 0xdf, 0x42, 0xbb, + 0xaf, 0xfa, 0x88, 0xa8, 0x58, 0x51, 0x56, 0xec, 0xda, 0x74, 0x52, 0x59, 0xa1, 0x27, 0x02, 0xd5, + 0x72, 0x64, 0xf9, 0x56, 0xd8, 0x73, 0xcb, 0x36, 0xf9, 0x1c, 0x56, 0xcf, 0x84, 0x8b, 0xae, 0xbd, + 0x88, 0x76, 0x49, 0x46, 0xbb, 0x3a, 0x9d, 0x54, 0xc8, 0x69, 0xb4, 0xa8, 0x3f, 0xc8, 0x60, 0x84, + 0xcd, 0xae, 0x8a, 0x0b, 0x13, 0x5d, 0xa2, 0xcb, 0xf1, 0x81, 0x15, 0xb3, 0x46, 0x06, 0xd2, 0x8d, + 0xe3, 0xda, 0x9f, 0x69, 0x58, 0xda, 0x33, 0xb9, 0xf5, 0x90, 0xe2, 0x97, 0x23, 0x0c, 0x39, 0x69, + 0x41, 0x16, 0x7d, 0xce, 0x1c, 0x0c, 0x0d, 0xad, 0xba, 0x70, 0xa3, 0xb0, 0x76, 0x33, 0xa9, 0x1e, + 0x67, 0x91, 0x68, 0xd2, 0xf2, 0x39, 0x3b, 0xa6, 0x31, 0x4b, 0xee, 0x41, 0x81, 0x61, 0x38, 0xf2, + 0xb0, 0x7f, 0xc0, 0x02, 0xef, 0xa2, 0xb6, 0xfd, 0x00, 0x99, 0x68, 0x2c, 0x14, 0x22, 0xfd, 0x67, + 0x2c, 0xf0, 0xc8, 0x2d, 0x20, 0x8e, 0x6f, 0xb9, 0x23, 0x1b, 0xfb, 0x81, 0x6b, 0xf7, 0xa3, 0x3f, + 0x20, 0x79, 0xe1, 0x72, 0x74, 0x59, 0x3d, 0xd9, 0x72, 0xed, 0xa8, 0x11, 0x95, 0xbe, 0xd1, 0x00, + 0x4e, 0x73, 0x48, 0xec, 0x19, 0x1f, 0x83, 0x6e, 0x5a, 0x5c, 0x74, 0xbc, 0xb4, 0x34, 0xf9, 0xb5, + 0xb9, 0x9b, 0x5a, 0x97, 0xb2, 0xfb, 0x8e, 0x6f, 0x53, 0x85, 0x90, 0xbb, 0x90, 0x3d, 0x70, 0x5c, + 0x8e, 0x2c, 0x34, 0x16, 0x64, 0x49, 0xae, 0x5f, 0x74, 0xb4, 0x69, 0x2c, 0xae, 0xfd, 0x12, 0xd7, + 0x76, 0x13, 0xc3, 0xd0, 0x3c, 0x44, 0xf2, 0x29, 0xe8, 0x38, 0x46, 0x9f, 0xc7, 0xa5, 0x7d, 0x63, + 0x6e, 0x16, 0x8a, 0xa8, 0xb7, 0x84, 0x9c, 0x2a, 0x8a, 0xbc, 0x0f, 0xd9, 0x71, 0x54, 0xad, 0xff, + 0x52, 0xd0, 0x58, 0x5b, 0xfa, 0x49, 0x83, 0x45, 0x19, 0xe8, 0x4c, 0x19, 0xb4, 0x97, 0x2f, 0xc3, + 0x1a, 0xe8, 0xca, 0x88, 0xf4, 0xfc, 0xbf, 0xaa, 0xc8, 0x12, 0xaa, 0x94, 0xe4, 0x43, 0x80, 0x19, + 0x03, 0x2f, 0xe6, 0xf2, 0x41, 0xec, 0xea, 0x5b, 0xff, 0x68, 0x70, 0x79, 0x26, 0x15, 0x72, 0x07, + 0x56, 0xf7, 0xd6, 0x77, 0x9a, 0xed, 0xfe, 0x7a, 0x73, 0xa7, 0xb3, 0xd5, 0xed, 0xef, 0x76, 0xef, + 0x77, 0xb7, 0xf6, 0xba, 0xcb, 0xa9, 0x52, 0xe9, 0xf1, 0x93, 0xea, 0xd5, 0x19, 0xf9, 0xae, 0x3f, + 0xf0, 0x83, 0x23, 0x91, 0xf8, 0xca, 0x39, 0xaa, 0x49, 0x5b, 0xeb, 0x3b, 0xad, 0x65, 0xad, 0xf4, + 0xbf, 0xc7, 0x4f, 0xaa, 0x57, 0x66, 0xa0, 0x26, 0xc3, 0xa8, 0x9b, 0x9c, 0x67, 0x76, 0xb7, 0x37, + 0x04, 0x93, 0x4e, 0x64, 0x76, 0x87, 0x76, 0x12, 0x43, 0x5b, 0x9b, 0x5b, 0x0f, 0x5a, 0xcb, 0x99, + 0x44, 0x86, 0xa2, 0x17, 0x8c, 0xb1, 0x74, 0xed, 0xeb, 0xef, 0xcb, 0xa9, 0x9f, 0x7f, 0x28, 0xcf, + 0x6e, 0x75, 0xcd, 0x83, 0xc5, 0x9e, 0xf8, 0x4a, 0x23, 0x36, 0x2c, 0xca, 0x67, 0xa4, 0xfa, 0xa2, + 0x8b, 0x58, 0xaa, 0xbe, 0xe8, 0x3c, 0xd5, 0xae, 0xfc, 0xfa, 0xe3, 0xdf, 0xdf, 0xa6, 0x2f, 0x43, + 0x51, 0x2a, 0xde, 0xf6, 0x4c, 0xdf, 0x3c, 0x44, 0xf6, 0x8e, 0xd6, 0x30, 0x9e, 0x3e, 0x2b, 0xa7, + 0xfe, 0x78, 0x56, 0x4e, 0x7d, 0x35, 0x2d, 0x6b, 0x4f, 0xa7, 0x65, 0xed, 0xf7, 0x69, 0x59, 0xfb, + 0x6b, 0x5a, 0xd6, 0xf6, 0x75, 0xf9, 0xf9, 0xf6, 0xde, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa9, + 0xa5, 0x8e, 0xe6, 0x35, 0x0a, 0x00, 0x00, } diff --git a/api/store.proto b/api/store.proto index 8a8894c6f5..ed7efe27a7 100644 --- a/api/store.proto +++ b/api/store.proto @@ -4,7 +4,6 @@ package docker.swarmkit.v1; import "specs.proto"; import "objects.proto"; -import "raft.proto"; import "types.proto"; import "gogoproto/gogo.proto"; import "plugin/plugin.proto"; @@ -87,7 +86,8 @@ message WatchRequest { string kind = 1; // Action (create/update/delete) - StoreActionKind action = 2; + // This is a bitmask, so multiple actions may be OR'd together + WatchActionKind action = 2; // Filters are combined using AND logic - an event must match // all of them to pass the filter. @@ -121,7 +121,7 @@ message WatchMessage { // Action (create/update/delete) // Note that WatchMessage does not expose "commit" events that // mark transaction boundaries. - StoreActionKind action = 1; + WatchActionKind action = 1; // Matched object Object object = 2; @@ -138,3 +138,15 @@ message WatchMessage { // resume the watch from this point. Version version = 2; } + +// WatchActionKind distinguishes between creations, updates, and removals. It +// is structured as a bitmap so multiple kinds of events can be requested with +// a mask. +enum WatchActionKind { + option (gogoproto.goproto_enum_prefix) = false; + option (gogoproto.enum_customname) = "WatchActionKind"; + WATCH_ACTION_UNKNOWN = 0 [(gogoproto.enumvalue_customname) = "WatchActionKindUnknown"]; // default value, invalid + WATCH_ACTION_CREATE = 1 [(gogoproto.enumvalue_customname) = "WatchActionKindCreate"]; + WATCH_ACTION_UPDATE = 2 [(gogoproto.enumvalue_customname) = "WatchActionKindUpdate"]; + WATCH_ACTION_REMOVE = 4 [(gogoproto.enumvalue_customname) = "WatchActionKindRemove"]; +} diff --git a/manager/storeapi/watch.go b/manager/storeapi/watch.go index fbf60dc663..8877edb4e9 100644 --- a/manager/storeapi/watch.go +++ b/manager/storeapi/watch.go @@ -11,7 +11,7 @@ import ( var errConflictingFilters = grpc.Errorf(codes.InvalidArgument, "conflicting filters specified") -func convertNodeWatch(action api.StoreActionKind, filters []*api.SelectBy) (api.Event, error) { +func convertNodeWatch(action api.WatchActionKind, filters []*api.SelectBy) ([]api.Event, error) { var ( node api.Node checkFuncs []api.NodeCheckFunc @@ -78,19 +78,23 @@ func convertNodeWatch(action api.StoreActionKind, filters []*api.SelectBy) (api. } } - switch action { - case api.StoreActionKindCreate: - return api.EventCreateNode{Node: &node, Checks: checkFuncs}, nil - case api.StoreActionKindUpdate: - return api.EventUpdateNode{Node: &node, Checks: checkFuncs}, nil - case api.StoreActionKindRemove: - return api.EventDeleteNode{Node: &node, Checks: checkFuncs}, nil - default: - return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized store action %v", action) + var events []api.Event + if (action & api.WatchActionKindCreate) != 0 { + events = append(events, api.EventCreateNode{Node: &node, Checks: checkFuncs}) + } + if (action & api.WatchActionKindUpdate) != 0 { + events = append(events, api.EventUpdateNode{Node: &node, Checks: checkFuncs}) + } + if (action & api.WatchActionKindRemove) != 0 { + events = append(events, api.EventDeleteNode{Node: &node, Checks: checkFuncs}) } + if len(events) == 0 { + return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized watch action %v", action) + } + return events, nil } -func convertServiceWatch(action api.StoreActionKind, filters []*api.SelectBy) (api.Event, error) { +func convertServiceWatch(action api.WatchActionKind, filters []*api.SelectBy) ([]api.Event, error) { var ( service api.Service checkFuncs []api.ServiceCheckFunc @@ -147,19 +151,23 @@ func convertServiceWatch(action api.StoreActionKind, filters []*api.SelectBy) (a } } - switch action { - case api.StoreActionKindCreate: - return api.EventCreateService{Service: &service, Checks: checkFuncs}, nil - case api.StoreActionKindUpdate: - return api.EventUpdateService{Service: &service, Checks: checkFuncs}, nil - case api.StoreActionKindRemove: - return api.EventDeleteService{Service: &service, Checks: checkFuncs}, nil - default: - return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized store action %v", action) + var events []api.Event + if (action & api.WatchActionKindCreate) != 0 { + events = append(events, api.EventCreateService{Service: &service, Checks: checkFuncs}) + } + if (action & api.WatchActionKindUpdate) != 0 { + events = append(events, api.EventUpdateService{Service: &service, Checks: checkFuncs}) + } + if (action & api.WatchActionKindRemove) != 0 { + events = append(events, api.EventDeleteService{Service: &service, Checks: checkFuncs}) } + if len(events) == 0 { + return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized watch action %v", action) + } + return events, nil } -func convertNetworkWatch(action api.StoreActionKind, filters []*api.SelectBy) (api.Event, error) { +func convertNetworkWatch(action api.WatchActionKind, filters []*api.SelectBy) ([]api.Event, error) { var ( network api.Network checkFuncs []api.NetworkCheckFunc @@ -210,19 +218,23 @@ func convertNetworkWatch(action api.StoreActionKind, filters []*api.SelectBy) (a } } - switch action { - case api.StoreActionKindCreate: - return api.EventCreateNetwork{Network: &network, Checks: checkFuncs}, nil - case api.StoreActionKindUpdate: - return api.EventUpdateNetwork{Network: &network, Checks: checkFuncs}, nil - case api.StoreActionKindRemove: - return api.EventDeleteNetwork{Network: &network, Checks: checkFuncs}, nil - default: - return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized store action %v", action) + var events []api.Event + if (action & api.WatchActionKindCreate) != 0 { + events = append(events, api.EventCreateNetwork{Network: &network, Checks: checkFuncs}) + } + if (action & api.WatchActionKindUpdate) != 0 { + events = append(events, api.EventUpdateNetwork{Network: &network, Checks: checkFuncs}) + } + if (action & api.WatchActionKindRemove) != 0 { + events = append(events, api.EventDeleteNetwork{Network: &network, Checks: checkFuncs}) } + if len(events) == 0 { + return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized watch action %v", action) + } + return events, nil } -func convertClusterWatch(action api.StoreActionKind, filters []*api.SelectBy) (api.Event, error) { +func convertClusterWatch(action api.WatchActionKind, filters []*api.SelectBy) ([]api.Event, error) { var ( cluster api.Cluster checkFuncs []api.ClusterCheckFunc @@ -273,19 +285,23 @@ func convertClusterWatch(action api.StoreActionKind, filters []*api.SelectBy) (a } } - switch action { - case api.StoreActionKindCreate: - return api.EventCreateCluster{Cluster: &cluster, Checks: checkFuncs}, nil - case api.StoreActionKindUpdate: - return api.EventUpdateCluster{Cluster: &cluster, Checks: checkFuncs}, nil - case api.StoreActionKindRemove: - return api.EventDeleteCluster{Cluster: &cluster, Checks: checkFuncs}, nil - default: - return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized store action %v", action) + var events []api.Event + if (action & api.WatchActionKindCreate) != 0 { + events = append(events, api.EventCreateCluster{Cluster: &cluster, Checks: checkFuncs}) + } + if (action & api.WatchActionKindUpdate) != 0 { + events = append(events, api.EventUpdateCluster{Cluster: &cluster, Checks: checkFuncs}) + } + if (action & api.WatchActionKindRemove) != 0 { + events = append(events, api.EventDeleteCluster{Cluster: &cluster, Checks: checkFuncs}) } + if len(events) == 0 { + return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized watch action %v", action) + } + return events, nil } -func convertSecretWatch(action api.StoreActionKind, filters []*api.SelectBy) (api.Event, error) { +func convertSecretWatch(action api.WatchActionKind, filters []*api.SelectBy) ([]api.Event, error) { var ( secret api.Secret checkFuncs []api.SecretCheckFunc @@ -336,19 +352,23 @@ func convertSecretWatch(action api.StoreActionKind, filters []*api.SelectBy) (ap } } - switch action { - case api.StoreActionKindCreate: - return api.EventCreateSecret{Secret: &secret, Checks: checkFuncs}, nil - case api.StoreActionKindUpdate: - return api.EventUpdateSecret{Secret: &secret, Checks: checkFuncs}, nil - case api.StoreActionKindRemove: - return api.EventDeleteSecret{Secret: &secret, Checks: checkFuncs}, nil - default: - return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized store action %v", action) + var events []api.Event + if (action & api.WatchActionKindCreate) != 0 { + events = append(events, api.EventCreateSecret{Secret: &secret, Checks: checkFuncs}) + } + if (action & api.WatchActionKindUpdate) != 0 { + events = append(events, api.EventUpdateSecret{Secret: &secret, Checks: checkFuncs}) + } + if (action & api.WatchActionKindRemove) != 0 { + events = append(events, api.EventDeleteSecret{Secret: &secret, Checks: checkFuncs}) } + if len(events) == 0 { + return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized watch action %v", action) + } + return events, nil } -func convertTaskWatch(action api.StoreActionKind, filters []*api.SelectBy) (api.Event, error) { +func convertTaskWatch(action api.WatchActionKind, filters []*api.SelectBy) ([]api.Event, error) { var ( task api.Task checkFuncs []api.TaskCheckFunc @@ -414,19 +434,23 @@ func convertTaskWatch(action api.StoreActionKind, filters []*api.SelectBy) (api. } } - switch action { - case api.StoreActionKindCreate: - return api.EventCreateTask{Task: &task, Checks: checkFuncs}, nil - case api.StoreActionKindUpdate: - return api.EventUpdateTask{Task: &task, Checks: checkFuncs}, nil - case api.StoreActionKindRemove: - return api.EventDeleteTask{Task: &task, Checks: checkFuncs}, nil - default: - return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized store action %v", action) + var events []api.Event + if (action & api.WatchActionKindCreate) != 0 { + events = append(events, api.EventCreateTask{Task: &task, Checks: checkFuncs}) + } + if (action & api.WatchActionKindUpdate) != 0 { + events = append(events, api.EventUpdateTask{Task: &task, Checks: checkFuncs}) + } + if (action & api.WatchActionKindRemove) != 0 { + events = append(events, api.EventDeleteTask{Task: &task, Checks: checkFuncs}) } + if len(events) == 0 { + return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized watch action %v", action) + } + return events, nil } -func convertExtensionWatch(action api.StoreActionKind, filters []*api.SelectBy) (api.Event, error) { +func convertExtensionWatch(action api.WatchActionKind, filters []*api.SelectBy) ([]api.Event, error) { var ( extension api.Extension checkFuncs []api.ExtensionCheckFunc @@ -477,19 +501,23 @@ func convertExtensionWatch(action api.StoreActionKind, filters []*api.SelectBy) } } - switch action { - case api.StoreActionKindCreate: - return api.EventCreateExtension{Extension: &extension, Checks: checkFuncs}, nil - case api.StoreActionKindUpdate: - return api.EventUpdateExtension{Extension: &extension, Checks: checkFuncs}, nil - case api.StoreActionKindRemove: - return api.EventDeleteExtension{Extension: &extension, Checks: checkFuncs}, nil - default: - return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized store action %v", action) + var events []api.Event + if (action & api.WatchActionKindCreate) != 0 { + events = append(events, api.EventCreateExtension{Extension: &extension, Checks: checkFuncs}) + } + if (action & api.WatchActionKindUpdate) != 0 { + events = append(events, api.EventUpdateExtension{Extension: &extension, Checks: checkFuncs}) + } + if (action & api.WatchActionKindRemove) != 0 { + events = append(events, api.EventDeleteExtension{Extension: &extension, Checks: checkFuncs}) } + if len(events) == 0 { + return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized watch action %v", action) + } + return events, nil } -func convertResourceWatch(action api.StoreActionKind, filters []*api.SelectBy, kind string) (api.Event, error) { +func convertResourceWatch(action api.WatchActionKind, filters []*api.SelectBy, kind string) ([]api.Event, error) { resource := api.Resource{Kind: kind} checkFuncs := []api.ResourceCheckFunc{state.ResourceCheckKind} @@ -538,16 +566,20 @@ func convertResourceWatch(action api.StoreActionKind, filters []*api.SelectBy, k } } - switch action { - case api.StoreActionKindCreate: - return api.EventCreateResource{Resource: &resource, Checks: checkFuncs}, nil - case api.StoreActionKindUpdate: - return api.EventUpdateResource{Resource: &resource, Checks: checkFuncs}, nil - case api.StoreActionKindRemove: - return api.EventDeleteResource{Resource: &resource, Checks: checkFuncs}, nil - default: - return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized store action %v", action) + var events []api.Event + if (action & api.WatchActionKindCreate) != 0 { + events = append(events, api.EventCreateResource{Resource: &resource, Checks: checkFuncs}) + } + if (action & api.WatchActionKindUpdate) != 0 { + events = append(events, api.EventUpdateResource{Resource: &resource, Checks: checkFuncs}) + } + if (action & api.WatchActionKindRemove) != 0 { + events = append(events, api.EventDeleteResource{Resource: &resource, Checks: checkFuncs}) } + if len(events) == 0 { + return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized watch action %v", action) + } + return events, nil } func convertWatchArgs(entries []*api.WatchRequest_WatchEntry) ([]api.Event, error) { @@ -555,33 +587,33 @@ func convertWatchArgs(entries []*api.WatchRequest_WatchEntry) ([]api.Event, erro for _, entry := range entries { var ( - event api.Event - err error + newEvents []api.Event + err error ) switch entry.Kind { case "": return nil, grpc.Errorf(codes.InvalidArgument, "no kind of object specified") case "node": - event, err = convertNodeWatch(entry.Action, entry.Filters) + newEvents, err = convertNodeWatch(entry.Action, entry.Filters) case "service": - event, err = convertServiceWatch(entry.Action, entry.Filters) + newEvents, err = convertServiceWatch(entry.Action, entry.Filters) case "network": - event, err = convertNetworkWatch(entry.Action, entry.Filters) + newEvents, err = convertNetworkWatch(entry.Action, entry.Filters) case "task": - event, err = convertTaskWatch(entry.Action, entry.Filters) + newEvents, err = convertTaskWatch(entry.Action, entry.Filters) case "cluster": - event, err = convertClusterWatch(entry.Action, entry.Filters) + newEvents, err = convertClusterWatch(entry.Action, entry.Filters) case "secret": - event, err = convertSecretWatch(entry.Action, entry.Filters) + newEvents, err = convertSecretWatch(entry.Action, entry.Filters) case "extension": - event, err = convertExtensionWatch(entry.Action, entry.Filters) + newEvents, err = convertExtensionWatch(entry.Action, entry.Filters) default: - event, err = convertResourceWatch(entry.Action, entry.Filters, entry.Kind) + newEvents, err = convertResourceWatch(entry.Action, entry.Filters, entry.Kind) } if err != nil { return nil, err } - events = append(events, event) + events = append(events, newEvents...) } return events, nil @@ -590,53 +622,53 @@ func convertWatchArgs(entries []*api.WatchRequest_WatchEntry) ([]api.Event, erro func watchMessageEvent(event api.Event) *api.WatchMessage_Event { switch v := event.(type) { case api.EventCreateTask: - return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindCreate, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}} case api.EventUpdateTask: - return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}, OldObject: &api.Object{Object: &api.Object_Task{Task: v.OldTask}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindUpdate, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}, OldObject: &api.Object{Object: &api.Object_Task{Task: v.OldTask}}} case api.EventDeleteTask: - return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindRemove, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}} case api.EventCreateService: - return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindCreate, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}} case api.EventUpdateService: - return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}, OldObject: &api.Object{Object: &api.Object_Service{Service: v.OldService}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindUpdate, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}, OldObject: &api.Object{Object: &api.Object_Service{Service: v.OldService}}} case api.EventDeleteService: - return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindRemove, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}} case api.EventCreateNetwork: - return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindCreate, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}} case api.EventUpdateNetwork: - return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}, OldObject: &api.Object{Object: &api.Object_Network{Network: v.OldNetwork}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindUpdate, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}, OldObject: &api.Object{Object: &api.Object_Network{Network: v.OldNetwork}}} case api.EventDeleteNetwork: - return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindRemove, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}} case api.EventCreateNode: - return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindCreate, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}} case api.EventUpdateNode: - return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}, OldObject: &api.Object{Object: &api.Object_Node{Node: v.OldNode}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindUpdate, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}, OldObject: &api.Object{Object: &api.Object_Node{Node: v.OldNode}}} case api.EventDeleteNode: - return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindRemove, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}} case api.EventCreateCluster: - return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindCreate, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}} case api.EventUpdateCluster: - return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}, OldObject: &api.Object{Object: &api.Object_Cluster{Cluster: v.OldCluster}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindUpdate, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}, OldObject: &api.Object{Object: &api.Object_Cluster{Cluster: v.OldCluster}}} case api.EventDeleteCluster: - return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindRemove, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}} case api.EventCreateSecret: - return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindCreate, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}} case api.EventUpdateSecret: - return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}, OldObject: &api.Object{Object: &api.Object_Secret{Secret: v.OldSecret}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindUpdate, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}, OldObject: &api.Object{Object: &api.Object_Secret{Secret: v.OldSecret}}} case api.EventDeleteSecret: - return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindRemove, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}} case api.EventCreateResource: - return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindCreate, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}} case api.EventUpdateResource: - return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}, OldObject: &api.Object{Object: &api.Object_Resource{Resource: v.OldResource}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindUpdate, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}, OldObject: &api.Object{Object: &api.Object_Resource{Resource: v.OldResource}}} case api.EventDeleteResource: - return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindRemove, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}} case api.EventCreateExtension: - return &api.WatchMessage_Event{Action: api.StoreActionKindCreate, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindCreate, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}} case api.EventUpdateExtension: - return &api.WatchMessage_Event{Action: api.StoreActionKindUpdate, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}, OldObject: &api.Object{Object: &api.Object_Extension{Extension: v.OldExtension}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindUpdate, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}, OldObject: &api.Object{Object: &api.Object_Extension{Extension: v.OldExtension}}} case api.EventDeleteExtension: - return &api.WatchMessage_Event{Action: api.StoreActionKindRemove, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}} + return &api.WatchMessage_Event{Action: api.WatchActionKindRemove, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}} } return nil } diff --git a/manager/storeapi/watch_test.go b/manager/storeapi/watch_test.go index da0f6a7b7d..ded7c519db 100644 --- a/manager/storeapi/watch_test.go +++ b/manager/storeapi/watch_test.go @@ -21,7 +21,7 @@ func TestWatch(t *testing.T) { Entries: []*api.WatchRequest_WatchEntry{ { Kind: "node", - Action: api.StoreActionKindCreate, + Action: api.WatchActionKindCreate, }, }, }) @@ -35,7 +35,7 @@ func TestWatch(t *testing.T) { createNode(t, ts, "id1", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY) msg, err = watch.Recv() assert.NoError(t, err) - assert.Equal(t, api.StoreActionKindCreate, msg.Events[0].Action) + assert.Equal(t, api.WatchActionKindCreate, msg.Events[0].Action) require.NotNil(t, msg.Events[0].Object.GetNode()) assert.Equal(t, "id1", msg.Events[0].Object.GetNode().ID) @@ -47,7 +47,7 @@ func TestWatch(t *testing.T) { Entries: []*api.WatchRequest_WatchEntry{ { Kind: "node", - Action: api.StoreActionKindCreate, + Action: api.WatchActionKindCreate, Filters: []*api.SelectBy{ { By: &api.SelectBy_NamePrefix{ @@ -66,7 +66,7 @@ func TestWatch(t *testing.T) { }, { Kind: "node", - Action: api.StoreActionKindCreate, + Action: api.WatchActionKindCreate, Filters: []*api.SelectBy{ { By: &api.SelectBy_Role{ @@ -87,7 +87,7 @@ func TestWatch(t *testing.T) { createNode(t, ts, "id2", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY) msg, err = watch.Recv() assert.NoError(t, err) - assert.Equal(t, api.StoreActionKindCreate, msg.Events[0].Action) + assert.Equal(t, api.WatchActionKindCreate, msg.Events[0].Action) require.NotNil(t, msg.Events[0].Object.GetNode()) assert.Equal(t, "id2", msg.Events[0].Object.GetNode().ID) @@ -153,13 +153,65 @@ func TestWatch(t *testing.T) { msg, err = watch.Recv() assert.NoError(t, err) - assert.Equal(t, api.StoreActionKindCreate, msg.Events[0].Action) + assert.Equal(t, api.WatchActionKindCreate, msg.Events[0].Action) require.NotNil(t, msg.Events[0].Object.GetNode()) assert.Equal(t, "id6", msg.Events[0].Object.GetNode().ID) watch.CloseSend() } +func TestWatchMultipleActions(t *testing.T) { + ts := newTestServer(t) + defer ts.Stop() + + ctx := context.Background() + + // Watch for node creates + watch, err := ts.Client.Watch(ctx, &api.WatchRequest{ + Entries: []*api.WatchRequest_WatchEntry{ + { + Kind: "node", + Action: api.WatchActionKindCreate | api.WatchActionKindRemove, + }, + }, + }) + assert.NoError(t, err) + + // Should receive an initial message that indicates the watch is ready + msg, err := watch.Recv() + assert.NoError(t, err) + assert.Equal(t, &api.WatchMessage{}, msg) + + createNode(t, ts, "id1", api.NodeRoleManager, api.NodeMembershipAccepted, api.NodeStatus_READY) + msg, err = watch.Recv() + assert.NoError(t, err) + assert.Equal(t, api.WatchActionKindCreate, msg.Events[0].Action) + require.NotNil(t, msg.Events[0].Object.GetNode()) + assert.Equal(t, "id1", msg.Events[0].Object.GetNode().ID) + + // Update should not be seen + err = ts.Store.Update(func(tx store.Tx) error { + node := store.GetNode(tx, "id1") + require.NotNil(t, node) + node.Role = api.NodeRoleWorker + return store.UpdateNode(tx, node) + }) + assert.NoError(t, err) + + // Delete should be seen + err = ts.Store.Update(func(tx store.Tx) error { + return store.DeleteNode(tx, "id1") + }) + assert.NoError(t, err) + msg, err = watch.Recv() + assert.NoError(t, err) + assert.Equal(t, api.WatchActionKindRemove, msg.Events[0].Action) + require.NotNil(t, msg.Events[0].Object.GetNode()) + assert.Equal(t, "id1", msg.Events[0].Object.GetNode().ID) + + watch.CloseSend() +} + func TestWatchIncludeOldObject(t *testing.T) { ts := newTestServer(t) defer ts.Stop() @@ -171,7 +223,7 @@ func TestWatchIncludeOldObject(t *testing.T) { Entries: []*api.WatchRequest_WatchEntry{ { Kind: "node", - Action: api.StoreActionKindUpdate, + Action: api.WatchActionKindUpdate, }, }, IncludeOldObject: true, @@ -195,7 +247,7 @@ func TestWatchIncludeOldObject(t *testing.T) { msg, err = watch.Recv() assert.NoError(t, err) - assert.Equal(t, api.StoreActionKindUpdate, msg.Events[0].Action) + assert.Equal(t, api.WatchActionKindUpdate, msg.Events[0].Action) require.NotNil(t, msg.Events[0].Object.GetNode()) assert.Equal(t, "id1", msg.Events[0].Object.GetNode().ID) assert.Equal(t, api.NodeRoleWorker, msg.Events[0].Object.GetNode().Role) @@ -220,7 +272,7 @@ func TestWatchResumeFrom(t *testing.T) { Entries: []*api.WatchRequest_WatchEntry{ { Kind: "node", - Action: api.StoreActionKindCreate, + Action: api.WatchActionKindCreate, }, }, ResumeFrom: &node2.Meta.Version, @@ -234,7 +286,7 @@ func TestWatchResumeFrom(t *testing.T) { msg, err = watch.Recv() assert.NoError(t, err) - assert.Equal(t, api.StoreActionKindCreate, msg.Events[0].Action) + assert.Equal(t, api.WatchActionKindCreate, msg.Events[0].Action) require.NotNil(t, msg.Events[0].Object.GetNode()) assert.Equal(t, "id2", msg.Events[0].Object.GetNode().ID) assert.Equal(t, node2.Meta.Version.Index+3, msg.Version.Index) @@ -244,7 +296,7 @@ func TestWatchResumeFrom(t *testing.T) { msg, err = watch.Recv() assert.NoError(t, err) - assert.Equal(t, api.StoreActionKindCreate, msg.Events[0].Action) + assert.Equal(t, api.WatchActionKindCreate, msg.Events[0].Action) require.NotNil(t, msg.Events[0].Object.GetNode()) assert.Equal(t, "id3", msg.Events[0].Object.GetNode().ID) assert.Equal(t, node3.Meta.Version.Index+3, msg.Version.Index) From d439fd723bddacb56f1f585e23938c5c40ed8197 Mon Sep 17 00:00:00 2001 From: Aaron Lehmann Date: Fri, 17 Mar 2017 15:11:49 -0700 Subject: [PATCH 5/7] Code-generate WatchMessageEvent Signed-off-by: Aaron Lehmann --- api/objects.pb.go | 86 ++++++++++++++++++++++ manager/storeapi/watch.go | 56 +------------- protobuf/plugin/storeobject/storeobject.go | 39 ++++++++++ 3 files changed, 126 insertions(+), 55 deletions(-) diff --git a/api/objects.pb.go b/api/objects.pb.go index c364f31ceb..cf21b1c1e9 100644 --- a/api/objects.pb.go +++ b/api/objects.pb.go @@ -3075,6 +3075,92 @@ func EventFromStoreAction(sa StoreAction, oldObject StoreObject) (Event, error) return nil, errUnknownStoreAction } +func WatchMessageEvent(c Event) *WatchMessage_Event { + switch v := c.(type) { + case EventCreateNode: + return &WatchMessage_Event{Action: WatchActionKindCreate, Object: &Object{Object: &Object_Node{Node: v.Node}}} + case EventUpdateNode: + if v.OldNode != nil { + return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_Node{Node: v.Node}}, OldObject: &Object{Object: &Object_Node{Node: v.OldNode}}} + } else { + return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_Node{Node: v.Node}}} + } + case EventDeleteNode: + return &WatchMessage_Event{Action: WatchActionKindRemove, Object: &Object{Object: &Object_Node{Node: v.Node}}} + case EventCreateService: + return &WatchMessage_Event{Action: WatchActionKindCreate, Object: &Object{Object: &Object_Service{Service: v.Service}}} + case EventUpdateService: + if v.OldService != nil { + return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_Service{Service: v.Service}}, OldObject: &Object{Object: &Object_Service{Service: v.OldService}}} + } else { + return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_Service{Service: v.Service}}} + } + case EventDeleteService: + return &WatchMessage_Event{Action: WatchActionKindRemove, Object: &Object{Object: &Object_Service{Service: v.Service}}} + case EventCreateTask: + return &WatchMessage_Event{Action: WatchActionKindCreate, Object: &Object{Object: &Object_Task{Task: v.Task}}} + case EventUpdateTask: + if v.OldTask != nil { + return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_Task{Task: v.Task}}, OldObject: &Object{Object: &Object_Task{Task: v.OldTask}}} + } else { + return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_Task{Task: v.Task}}} + } + case EventDeleteTask: + return &WatchMessage_Event{Action: WatchActionKindRemove, Object: &Object{Object: &Object_Task{Task: v.Task}}} + case EventCreateNetwork: + return &WatchMessage_Event{Action: WatchActionKindCreate, Object: &Object{Object: &Object_Network{Network: v.Network}}} + case EventUpdateNetwork: + if v.OldNetwork != nil { + return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_Network{Network: v.Network}}, OldObject: &Object{Object: &Object_Network{Network: v.OldNetwork}}} + } else { + return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_Network{Network: v.Network}}} + } + case EventDeleteNetwork: + return &WatchMessage_Event{Action: WatchActionKindRemove, Object: &Object{Object: &Object_Network{Network: v.Network}}} + case EventCreateCluster: + return &WatchMessage_Event{Action: WatchActionKindCreate, Object: &Object{Object: &Object_Cluster{Cluster: v.Cluster}}} + case EventUpdateCluster: + if v.OldCluster != nil { + return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_Cluster{Cluster: v.Cluster}}, OldObject: &Object{Object: &Object_Cluster{Cluster: v.OldCluster}}} + } else { + return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_Cluster{Cluster: v.Cluster}}} + } + case EventDeleteCluster: + return &WatchMessage_Event{Action: WatchActionKindRemove, Object: &Object{Object: &Object_Cluster{Cluster: v.Cluster}}} + case EventCreateSecret: + return &WatchMessage_Event{Action: WatchActionKindCreate, Object: &Object{Object: &Object_Secret{Secret: v.Secret}}} + case EventUpdateSecret: + if v.OldSecret != nil { + return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_Secret{Secret: v.Secret}}, OldObject: &Object{Object: &Object_Secret{Secret: v.OldSecret}}} + } else { + return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_Secret{Secret: v.Secret}}} + } + case EventDeleteSecret: + return &WatchMessage_Event{Action: WatchActionKindRemove, Object: &Object{Object: &Object_Secret{Secret: v.Secret}}} + case EventCreateResource: + return &WatchMessage_Event{Action: WatchActionKindCreate, Object: &Object{Object: &Object_Resource{Resource: v.Resource}}} + case EventUpdateResource: + if v.OldResource != nil { + return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_Resource{Resource: v.Resource}}, OldObject: &Object{Object: &Object_Resource{Resource: v.OldResource}}} + } else { + return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_Resource{Resource: v.Resource}}} + } + case EventDeleteResource: + return &WatchMessage_Event{Action: WatchActionKindRemove, Object: &Object{Object: &Object_Resource{Resource: v.Resource}}} + case EventCreateExtension: + return &WatchMessage_Event{Action: WatchActionKindCreate, Object: &Object{Object: &Object_Extension{Extension: v.Extension}}} + case EventUpdateExtension: + if v.OldExtension != nil { + return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_Extension{Extension: v.Extension}}, OldObject: &Object{Object: &Object_Extension{Extension: v.OldExtension}}} + } else { + return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_Extension{Extension: v.Extension}}} + } + case EventDeleteExtension: + return &WatchMessage_Event{Action: WatchActionKindRemove, Object: &Object{Object: &Object_Extension{Extension: v.Extension}}} + } + return nil +} + func (this *Meta) String() string { if this == nil { return "nil" diff --git a/manager/storeapi/watch.go b/manager/storeapi/watch.go index 8877edb4e9..919e866a4e 100644 --- a/manager/storeapi/watch.go +++ b/manager/storeapi/watch.go @@ -619,60 +619,6 @@ func convertWatchArgs(entries []*api.WatchRequest_WatchEntry) ([]api.Event, erro return events, nil } -func watchMessageEvent(event api.Event) *api.WatchMessage_Event { - switch v := event.(type) { - case api.EventCreateTask: - return &api.WatchMessage_Event{Action: api.WatchActionKindCreate, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}} - case api.EventUpdateTask: - return &api.WatchMessage_Event{Action: api.WatchActionKindUpdate, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}, OldObject: &api.Object{Object: &api.Object_Task{Task: v.OldTask}}} - case api.EventDeleteTask: - return &api.WatchMessage_Event{Action: api.WatchActionKindRemove, Object: &api.Object{Object: &api.Object_Task{Task: v.Task}}} - case api.EventCreateService: - return &api.WatchMessage_Event{Action: api.WatchActionKindCreate, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}} - case api.EventUpdateService: - return &api.WatchMessage_Event{Action: api.WatchActionKindUpdate, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}, OldObject: &api.Object{Object: &api.Object_Service{Service: v.OldService}}} - case api.EventDeleteService: - return &api.WatchMessage_Event{Action: api.WatchActionKindRemove, Object: &api.Object{Object: &api.Object_Service{Service: v.Service}}} - case api.EventCreateNetwork: - return &api.WatchMessage_Event{Action: api.WatchActionKindCreate, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}} - case api.EventUpdateNetwork: - return &api.WatchMessage_Event{Action: api.WatchActionKindUpdate, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}, OldObject: &api.Object{Object: &api.Object_Network{Network: v.OldNetwork}}} - case api.EventDeleteNetwork: - return &api.WatchMessage_Event{Action: api.WatchActionKindRemove, Object: &api.Object{Object: &api.Object_Network{Network: v.Network}}} - case api.EventCreateNode: - return &api.WatchMessage_Event{Action: api.WatchActionKindCreate, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}} - case api.EventUpdateNode: - return &api.WatchMessage_Event{Action: api.WatchActionKindUpdate, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}, OldObject: &api.Object{Object: &api.Object_Node{Node: v.OldNode}}} - case api.EventDeleteNode: - return &api.WatchMessage_Event{Action: api.WatchActionKindRemove, Object: &api.Object{Object: &api.Object_Node{Node: v.Node}}} - case api.EventCreateCluster: - return &api.WatchMessage_Event{Action: api.WatchActionKindCreate, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}} - case api.EventUpdateCluster: - return &api.WatchMessage_Event{Action: api.WatchActionKindUpdate, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}, OldObject: &api.Object{Object: &api.Object_Cluster{Cluster: v.OldCluster}}} - case api.EventDeleteCluster: - return &api.WatchMessage_Event{Action: api.WatchActionKindRemove, Object: &api.Object{Object: &api.Object_Cluster{Cluster: v.Cluster}}} - case api.EventCreateSecret: - return &api.WatchMessage_Event{Action: api.WatchActionKindCreate, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}} - case api.EventUpdateSecret: - return &api.WatchMessage_Event{Action: api.WatchActionKindUpdate, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}, OldObject: &api.Object{Object: &api.Object_Secret{Secret: v.OldSecret}}} - case api.EventDeleteSecret: - return &api.WatchMessage_Event{Action: api.WatchActionKindRemove, Object: &api.Object{Object: &api.Object_Secret{Secret: v.Secret}}} - case api.EventCreateResource: - return &api.WatchMessage_Event{Action: api.WatchActionKindCreate, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}} - case api.EventUpdateResource: - return &api.WatchMessage_Event{Action: api.WatchActionKindUpdate, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}, OldObject: &api.Object{Object: &api.Object_Resource{Resource: v.OldResource}}} - case api.EventDeleteResource: - return &api.WatchMessage_Event{Action: api.WatchActionKindRemove, Object: &api.Object{Object: &api.Object_Resource{Resource: v.Resource}}} - case api.EventCreateExtension: - return &api.WatchMessage_Event{Action: api.WatchActionKindCreate, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}} - case api.EventUpdateExtension: - return &api.WatchMessage_Event{Action: api.WatchActionKindUpdate, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}, OldObject: &api.Object{Object: &api.Object_Extension{Extension: v.OldExtension}}} - case api.EventDeleteExtension: - return &api.WatchMessage_Event{Action: api.WatchActionKindRemove, Object: &api.Object{Object: &api.Object_Extension{Extension: v.Extension}}} - } - return nil -} - // Watch starts a stream that returns any changes to objects that match // the specified selectors. When the stream begins, it immediately sends // an empty message back to the client. It is important to wait for @@ -709,7 +655,7 @@ func (s *Server) Watch(request *api.WatchRequest, stream api.Store_WatchServer) return err } events = nil - } else if eventMessage := watchMessageEvent(event.(api.Event)); eventMessage != nil { + } else if eventMessage := api.WatchMessageEvent(event.(api.Event)); eventMessage != nil { if !request.IncludeOldObject { eventMessage.OldObject = nil } diff --git a/protobuf/plugin/storeobject/storeobject.go b/protobuf/plugin/storeobject/storeobject.go index 690ef06b70..fdb84f379e 100644 --- a/protobuf/plugin/storeobject/storeobject.go +++ b/protobuf/plugin/storeobject/storeobject.go @@ -246,6 +246,44 @@ func (d *storeObjectGen) genNewStoreAction(topLevelObjs []string) { d.P() } +func (d *storeObjectGen) genWatchMessageEvent(topLevelObjs []string) { + if len(topLevelObjs) == 0 { + return + } + + // Generate WatchMessageEvent + d.P("func WatchMessageEvent(c Event) *WatchMessage_Event {") + d.In() + d.P("switch v := c.(type) {") + for _, ccTypeName := range topLevelObjs { + d.P("case EventCreate", ccTypeName, ":") + d.In() + d.P("return &WatchMessage_Event{Action: WatchActionKindCreate, Object: &Object{Object: &Object_", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, "}}}") + d.Out() + d.P("case EventUpdate", ccTypeName, ":") + d.In() + d.P("if v.Old", ccTypeName, " != nil {") + d.In() + d.P("return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, "}}, OldObject: &Object{Object: &Object_", ccTypeName, "{", ccTypeName, ": v.Old", ccTypeName, "}}}") + d.Out() + d.P("} else {") + d.In() + d.P("return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, "}}}") + d.Out() + d.P("}") + d.Out() + d.P("case EventDelete", ccTypeName, ":") + d.In() + d.P("return &WatchMessage_Event{Action: WatchActionKindRemove, Object: &Object{Object: &Object_", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, "}}}") + d.Out() + } + d.P("}") + d.P("return nil") + d.Out() + d.P("}") + d.P() +} + func (d *storeObjectGen) genEventFromStoreAction(topLevelObjs []string) { if len(topLevelObjs) == 0 { return @@ -321,4 +359,5 @@ func (d *storeObjectGen) Generate(file *generator.FileDescriptor) { d.genNewStoreAction(topLevelObjs) d.genEventFromStoreAction(topLevelObjs) + d.genWatchMessageEvent(topLevelObjs) } From f51e689f74a2f87c4c11a2f35073d38d828e496c Mon Sep 17 00:00:00 2001 From: Aaron Lehmann Date: Fri, 17 Mar 2017 16:28:29 -0700 Subject: [PATCH 6/7] Code generate event check functions Signed-off-by: Aaron Lehmann --- api/objects.pb.go | 399 +++++++++--- api/objects.proto | 95 ++- api/storeobject.go | 23 + ca/server.go | 3 +- ca/testutils/cautils.go | 3 +- manager/dispatcher/dispatcher.go | 13 +- manager/manager.go | 3 +- manager/orchestrator/restart/restart.go | 6 +- manager/orchestrator/update/updater.go | 4 +- manager/state/watch.go | 299 --------- manager/storeapi/watch.go | 106 ++-- protobuf/plugin/plugin.pb.go | 693 ++++++++++++++++++++- protobuf/plugin/plugin.proto | 24 + protobuf/plugin/storeobject/storeobject.go | 153 +++++ 14 files changed, 1338 insertions(+), 486 deletions(-) diff --git a/api/objects.pb.go b/api/objects.pb.go index cf21b1c1e9..48cadf4a34 100644 --- a/api/objects.pb.go +++ b/api/objects.pb.go @@ -1928,6 +1928,44 @@ func (m *Node) EventDelete() Event { return EventDeleteNode{Node: m} } +func NodeCheckID(v1, v2 *Node) bool { + return v1.ID == v2.ID +} + +func NodeCheckIDPrefix(v1, v2 *Node) bool { + return strings.HasPrefix(v2.ID, v1.ID) +} + +func NodeCheckName(v1, v2 *Node) bool { + if v1.Description == nil || v2.Description == nil { + return false + } + return v1.Description.Hostname == v2.Description.Hostname +} + +func NodeCheckNamePrefix(v1, v2 *Node) bool { + if v1.Description == nil || v2.Description == nil { + return false + } + return strings.HasPrefix(v2.Description.Hostname, v1.Description.Hostname) +} + +func NodeCheckCustom(v1, v2 *Node) bool { + return checkCustom(v1.Spec.Annotations, v2.Spec.Annotations) +} + +func NodeCheckCustomPrefix(v1, v2 *Node) bool { + return checkCustomPrefix(v1.Spec.Annotations, v2.Spec.Annotations) +} + +func NodeCheckRole(v1, v2 *Node) bool { + return v1.Role == v2.Role +} + +func NodeCheckMembership(v1, v2 *Node) bool { + return v1.Spec.Membership == v2.Spec.Membership +} + type NodeIndexerByID struct{} func (indexer NodeIndexerByID) FromArgs(args ...interface{}) ([]byte, error) { @@ -2059,6 +2097,30 @@ func (m *Service) EventDelete() Event { return EventDeleteService{Service: m} } +func ServiceCheckID(v1, v2 *Service) bool { + return v1.ID == v2.ID +} + +func ServiceCheckIDPrefix(v1, v2 *Service) bool { + return strings.HasPrefix(v2.ID, v1.ID) +} + +func ServiceCheckName(v1, v2 *Service) bool { + return v1.Spec.Annotations.Name == v2.Spec.Annotations.Name +} + +func ServiceCheckNamePrefix(v1, v2 *Service) bool { + return strings.HasPrefix(v2.Spec.Annotations.Name, v1.Spec.Annotations.Name) +} + +func ServiceCheckCustom(v1, v2 *Service) bool { + return checkCustom(v1.Spec.Annotations, v2.Spec.Annotations) +} + +func ServiceCheckCustomPrefix(v1, v2 *Service) bool { + return checkCustomPrefix(v1.Spec.Annotations, v2.Spec.Annotations) +} + type ServiceIndexerByID struct{} func (indexer ServiceIndexerByID) FromArgs(args ...interface{}) ([]byte, error) { @@ -2190,6 +2252,46 @@ func (m *Task) EventDelete() Event { return EventDeleteTask{Task: m} } +func TaskCheckID(v1, v2 *Task) bool { + return v1.ID == v2.ID +} + +func TaskCheckIDPrefix(v1, v2 *Task) bool { + return strings.HasPrefix(v2.ID, v1.ID) +} + +func TaskCheckName(v1, v2 *Task) bool { + return v1.Annotations.Name == v2.Annotations.Name +} + +func TaskCheckNamePrefix(v1, v2 *Task) bool { + return strings.HasPrefix(v2.Annotations.Name, v1.Annotations.Name) +} + +func TaskCheckCustom(v1, v2 *Task) bool { + return checkCustom(v1.Annotations, v2.Annotations) +} + +func TaskCheckCustomPrefix(v1, v2 *Task) bool { + return checkCustomPrefix(v1.Annotations, v2.Annotations) +} + +func TaskCheckNodeID(v1, v2 *Task) bool { + return v1.NodeID == v2.NodeID +} + +func TaskCheckServiceID(v1, v2 *Task) bool { + return v1.ServiceID == v2.ServiceID +} + +func TaskCheckSlot(v1, v2 *Task) bool { + return v1.Slot == v2.Slot +} + +func TaskCheckDesiredState(v1, v2 *Task) bool { + return v1.DesiredState == v2.DesiredState +} + type TaskIndexerByID struct{} func (indexer TaskIndexerByID) FromArgs(args ...interface{}) ([]byte, error) { @@ -2321,6 +2423,30 @@ func (m *Network) EventDelete() Event { return EventDeleteNetwork{Network: m} } +func NetworkCheckID(v1, v2 *Network) bool { + return v1.ID == v2.ID +} + +func NetworkCheckIDPrefix(v1, v2 *Network) bool { + return strings.HasPrefix(v2.ID, v1.ID) +} + +func NetworkCheckName(v1, v2 *Network) bool { + return v1.Spec.Annotations.Name == v2.Spec.Annotations.Name +} + +func NetworkCheckNamePrefix(v1, v2 *Network) bool { + return strings.HasPrefix(v2.Spec.Annotations.Name, v1.Spec.Annotations.Name) +} + +func NetworkCheckCustom(v1, v2 *Network) bool { + return checkCustom(v1.Spec.Annotations, v2.Spec.Annotations) +} + +func NetworkCheckCustomPrefix(v1, v2 *Network) bool { + return checkCustomPrefix(v1.Spec.Annotations, v2.Spec.Annotations) +} + type NetworkIndexerByID struct{} func (indexer NetworkIndexerByID) FromArgs(args ...interface{}) ([]byte, error) { @@ -2452,6 +2578,30 @@ func (m *Cluster) EventDelete() Event { return EventDeleteCluster{Cluster: m} } +func ClusterCheckID(v1, v2 *Cluster) bool { + return v1.ID == v2.ID +} + +func ClusterCheckIDPrefix(v1, v2 *Cluster) bool { + return strings.HasPrefix(v2.ID, v1.ID) +} + +func ClusterCheckName(v1, v2 *Cluster) bool { + return v1.Spec.Annotations.Name == v2.Spec.Annotations.Name +} + +func ClusterCheckNamePrefix(v1, v2 *Cluster) bool { + return strings.HasPrefix(v2.Spec.Annotations.Name, v1.Spec.Annotations.Name) +} + +func ClusterCheckCustom(v1, v2 *Cluster) bool { + return checkCustom(v1.Spec.Annotations, v2.Spec.Annotations) +} + +func ClusterCheckCustomPrefix(v1, v2 *Cluster) bool { + return checkCustomPrefix(v1.Spec.Annotations, v2.Spec.Annotations) +} + type ClusterIndexerByID struct{} func (indexer ClusterIndexerByID) FromArgs(args ...interface{}) ([]byte, error) { @@ -2583,6 +2733,30 @@ func (m *Secret) EventDelete() Event { return EventDeleteSecret{Secret: m} } +func SecretCheckID(v1, v2 *Secret) bool { + return v1.ID == v2.ID +} + +func SecretCheckIDPrefix(v1, v2 *Secret) bool { + return strings.HasPrefix(v2.ID, v1.ID) +} + +func SecretCheckName(v1, v2 *Secret) bool { + return v1.Spec.Annotations.Name == v2.Spec.Annotations.Name +} + +func SecretCheckNamePrefix(v1, v2 *Secret) bool { + return strings.HasPrefix(v2.Spec.Annotations.Name, v1.Spec.Annotations.Name) +} + +func SecretCheckCustom(v1, v2 *Secret) bool { + return checkCustom(v1.Spec.Annotations, v2.Spec.Annotations) +} + +func SecretCheckCustomPrefix(v1, v2 *Secret) bool { + return checkCustomPrefix(v1.Spec.Annotations, v2.Spec.Annotations) +} + type SecretIndexerByID struct{} func (indexer SecretIndexerByID) FromArgs(args ...interface{}) ([]byte, error) { @@ -2714,6 +2888,34 @@ func (m *Resource) EventDelete() Event { return EventDeleteResource{Resource: m} } +func ResourceCheckID(v1, v2 *Resource) bool { + return v1.ID == v2.ID +} + +func ResourceCheckIDPrefix(v1, v2 *Resource) bool { + return strings.HasPrefix(v2.ID, v1.ID) +} + +func ResourceCheckName(v1, v2 *Resource) bool { + return v1.Annotations.Name == v2.Annotations.Name +} + +func ResourceCheckNamePrefix(v1, v2 *Resource) bool { + return strings.HasPrefix(v2.Annotations.Name, v1.Annotations.Name) +} + +func ResourceCheckCustom(v1, v2 *Resource) bool { + return checkCustom(v1.Annotations, v2.Annotations) +} + +func ResourceCheckCustomPrefix(v1, v2 *Resource) bool { + return checkCustomPrefix(v1.Annotations, v2.Annotations) +} + +func ResourceCheckKind(v1, v2 *Resource) bool { + return v1.Kind == v2.Kind +} + type ResourceIndexerByID struct{} func (indexer ResourceIndexerByID) FromArgs(args ...interface{}) ([]byte, error) { @@ -2845,6 +3047,30 @@ func (m *Extension) EventDelete() Event { return EventDeleteExtension{Extension: m} } +func ExtensionCheckID(v1, v2 *Extension) bool { + return v1.ID == v2.ID +} + +func ExtensionCheckIDPrefix(v1, v2 *Extension) bool { + return strings.HasPrefix(v2.ID, v1.ID) +} + +func ExtensionCheckName(v1, v2 *Extension) bool { + return v1.Annotations.Name == v2.Annotations.Name +} + +func ExtensionCheckNamePrefix(v1, v2 *Extension) bool { + return strings.HasPrefix(v2.Annotations.Name, v1.Annotations.Name) +} + +func ExtensionCheckCustom(v1, v2 *Extension) bool { + return checkCustom(v1.Annotations, v2.Annotations) +} + +func ExtensionCheckCustomPrefix(v1, v2 *Extension) bool { + return checkCustomPrefix(v1.Annotations, v2.Annotations) +} + type ExtensionIndexerByID struct{} func (indexer ExtensionIndexerByID) FromArgs(args ...interface{}) ([]byte, error) { @@ -6183,89 +6409,92 @@ var ( func init() { proto.RegisterFile("objects.proto", fileDescriptorObjects) } var fileDescriptorObjects = []byte{ - // 1333 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xcc, 0x57, 0xc1, 0x8f, 0x1b, 0xb5, - 0x17, 0xde, 0x49, 0x66, 0x93, 0xcc, 0xcb, 0x66, 0xf5, 0xfb, 0xb9, 0xa5, 0x4c, 0x97, 0x25, 0x59, - 0xb6, 0x02, 0x55, 0xa8, 0xca, 0x42, 0x29, 0x68, 0x5b, 0x28, 0x90, 0x64, 0x23, 0x88, 0x4a, 0x69, - 0xe5, 0x96, 0xf6, 0x18, 0x79, 0x67, 0xdc, 0x30, 0x64, 0x32, 0x1e, 0xd9, 0x4e, 0x4a, 0x6e, 0x88, - 0x23, 0x47, 0x84, 0xc4, 0x0d, 0x89, 0x0b, 0x67, 0xae, 0xfc, 0x07, 0x7b, 0xe4, 0xc8, 0x69, 0x45, - 0x73, 0xe3, 0xc2, 0xdf, 0x80, 0xec, 0xf1, 0x64, 0x67, 0x9b, 0xc9, 0x6e, 0x8b, 0xaa, 0x15, 0xa7, - 0xd8, 0xe3, 0xef, 0x7b, 0x7e, 0xcf, 0xfe, 0xfc, 0xd9, 0x81, 0x1a, 0xdb, 0xff, 0x8a, 0x7a, 0x52, - 0x34, 0x63, 0xce, 0x24, 0x43, 0xc8, 0x67, 0xde, 0x90, 0xf2, 0xa6, 0x78, 0x4c, 0xf8, 0x68, 0x18, - 0xc8, 0xe6, 0xe4, 0xed, 0x8d, 0xaa, 0x9c, 0xc6, 0xd4, 0x00, 0x36, 0xaa, 0x22, 0xa6, 0x5e, 0xda, - 0x69, 0x0c, 0x18, 0x1b, 0x84, 0x74, 0x47, 0xf7, 0xf6, 0xc7, 0x8f, 0x76, 0x64, 0x30, 0xa2, 0x42, - 0x92, 0x51, 0x6c, 0x00, 0xe7, 0x07, 0x6c, 0xc0, 0x74, 0x73, 0x47, 0xb5, 0xcc, 0xd7, 0x8b, 0x4f, - 0xd3, 0x48, 0x34, 0x35, 0x43, 0xe7, 0xe2, 0x70, 0x3c, 0x08, 0xa2, 0x9d, 0xe4, 0x27, 0xf9, 0xb8, - 0xfd, 0x9b, 0x05, 0xf6, 0x6d, 0x2a, 0x09, 0x7a, 0x1f, 0xca, 0x13, 0xca, 0x45, 0xc0, 0x22, 0xd7, - 0xda, 0xb2, 0x2e, 0x57, 0xaf, 0xbe, 0xd2, 0x5c, 0xcc, 0xb7, 0xf9, 0x20, 0x81, 0xb4, 0xed, 0x83, - 0xc3, 0xc6, 0x0a, 0x4e, 0x19, 0xe8, 0x3a, 0x80, 0xc7, 0x29, 0x91, 0xd4, 0xef, 0x13, 0xe9, 0x16, - 0x34, 0x7f, 0xa3, 0x99, 0xa4, 0xd2, 0x4c, 0x53, 0x69, 0xde, 0x4f, 0x2b, 0xc0, 0x8e, 0x41, 0xb7, - 0xa4, 0xa2, 0x8e, 0x63, 0x3f, 0xa5, 0x16, 0x4f, 0xa7, 0x1a, 0x74, 0x4b, 0x6e, 0xff, 0x6c, 0x83, - 0xfd, 0x39, 0xf3, 0x29, 0xba, 0x00, 0x85, 0xc0, 0xd7, 0x69, 0x3b, 0xed, 0xd2, 0xec, 0xb0, 0x51, - 0xe8, 0xed, 0xe1, 0x42, 0xe0, 0xa3, 0xab, 0x60, 0x8f, 0xa8, 0x24, 0x26, 0x21, 0x37, 0xaf, 0x20, - 0x55, 0xbb, 0xa9, 0x46, 0x63, 0xd1, 0x7b, 0x60, 0xab, 0x6d, 0x30, 0x99, 0x6c, 0xe6, 0x71, 0xd4, - 0x9c, 0xf7, 0x62, 0xea, 0xa5, 0x3c, 0x85, 0x47, 0x5d, 0xa8, 0xfa, 0x54, 0x78, 0x3c, 0x88, 0xa5, - 0x5a, 0x43, 0x5b, 0xd3, 0x2f, 0x2d, 0xa3, 0xef, 0x1d, 0x41, 0x71, 0x96, 0x87, 0x3e, 0x80, 0x92, - 0x90, 0x44, 0x8e, 0x85, 0xbb, 0xaa, 0x23, 0xd4, 0x97, 0x26, 0xa0, 0x51, 0x26, 0x05, 0xc3, 0x41, - 0x9f, 0xc2, 0xfa, 0x88, 0x44, 0x64, 0x40, 0x79, 0xdf, 0x44, 0x29, 0xe9, 0x28, 0xaf, 0xe5, 0x96, - 0x9e, 0x20, 0x93, 0x40, 0xb8, 0x36, 0xca, 0x76, 0x51, 0x17, 0x80, 0x48, 0x49, 0xbc, 0x2f, 0x47, - 0x34, 0x92, 0x6e, 0x59, 0x47, 0x79, 0x3d, 0x37, 0x17, 0x2a, 0x1f, 0x33, 0x3e, 0x6c, 0xcd, 0xc1, - 0x38, 0x43, 0x44, 0x9f, 0x40, 0xd5, 0xa3, 0x5c, 0x06, 0x8f, 0x02, 0x8f, 0x48, 0xea, 0x56, 0x74, - 0x9c, 0x46, 0x5e, 0x9c, 0xce, 0x11, 0xcc, 0x14, 0x95, 0x65, 0xa2, 0xb7, 0xc0, 0xe6, 0x2c, 0xa4, - 0xae, 0xb3, 0x65, 0x5d, 0x5e, 0x5f, 0xbe, 0x2d, 0x98, 0x85, 0x14, 0x6b, 0xe4, 0x0d, 0xfb, 0xbb, - 0x1f, 0xb7, 0x57, 0xb6, 0xff, 0x2e, 0x42, 0xf9, 0x1e, 0xe5, 0x93, 0xc0, 0x7b, 0xb1, 0x32, 0xb9, - 0x7e, 0x4c, 0x26, 0xb9, 0x15, 0x99, 0x69, 0x17, 0x94, 0xb2, 0x0b, 0x15, 0x1a, 0xf9, 0x31, 0x0b, - 0x22, 0x69, 0x64, 0x92, 0x5b, 0x4e, 0xd7, 0x60, 0xf0, 0x1c, 0x8d, 0xba, 0x50, 0x4b, 0xd4, 0xdf, - 0x3f, 0xa6, 0x91, 0xad, 0x3c, 0xfa, 0x17, 0x1a, 0x68, 0x36, 0x77, 0x6d, 0x9c, 0xe9, 0xa1, 0x3d, - 0xa8, 0xc5, 0x9c, 0x4e, 0x02, 0x36, 0x16, 0x7d, 0x5d, 0x44, 0xe9, 0x99, 0x8a, 0xc0, 0x6b, 0x29, - 0x4b, 0xf5, 0xd0, 0x87, 0xb0, 0xa6, 0xc8, 0xfd, 0xd4, 0x35, 0xe0, 0x54, 0xd7, 0xc0, 0xda, 0xe0, - 0x4c, 0x07, 0xdd, 0x81, 0x97, 0x8e, 0x65, 0x31, 0x0f, 0x54, 0x3d, 0x3d, 0xd0, 0xb9, 0x6c, 0x26, - 0xe6, 0xa3, 0xd9, 0xf0, 0x9f, 0x0a, 0x50, 0x49, 0x97, 0x0e, 0x5d, 0x33, 0xbb, 0x64, 0x2d, 0x5f, - 0xa7, 0x14, 0xab, 0x2b, 0x4c, 0x36, 0xe8, 0x1a, 0xac, 0xc6, 0x8c, 0x4b, 0xe1, 0x16, 0xb6, 0x8a, - 0xcb, 0x8e, 0xe0, 0x5d, 0xc6, 0x65, 0x87, 0x45, 0x8f, 0x82, 0x01, 0x4e, 0xc0, 0xe8, 0x21, 0x54, - 0x27, 0x01, 0x97, 0x63, 0x12, 0xf6, 0x83, 0x58, 0xb8, 0x45, 0xcd, 0x7d, 0xe3, 0xa4, 0x29, 0x9b, - 0x0f, 0x12, 0x7c, 0xef, 0x6e, 0x7b, 0x7d, 0x76, 0xd8, 0x80, 0x79, 0x57, 0x60, 0x30, 0xa1, 0x7a, - 0xb1, 0xd8, 0xb8, 0x0d, 0xce, 0x7c, 0x04, 0x5d, 0x01, 0x88, 0x92, 0x13, 0xd7, 0x9f, 0x6b, 0xb9, - 0x36, 0x3b, 0x6c, 0x38, 0xe6, 0x1c, 0xf6, 0xf6, 0xb0, 0x63, 0x00, 0x3d, 0x1f, 0x21, 0xb0, 0x89, - 0xef, 0x73, 0xad, 0x6c, 0x07, 0xeb, 0xf6, 0xf6, 0xf7, 0x25, 0xb0, 0xef, 0x13, 0x31, 0x3c, 0x6b, - 0xd7, 0x54, 0x73, 0x2e, 0x9c, 0x85, 0x2b, 0x00, 0x22, 0x51, 0x98, 0x2a, 0xc7, 0x3e, 0x2a, 0xc7, - 0xe8, 0x4e, 0x95, 0x63, 0x00, 0x49, 0x39, 0x22, 0x64, 0x52, 0xcb, 0xde, 0xc6, 0xba, 0x8d, 0x2e, - 0x41, 0x39, 0x62, 0xbe, 0xa6, 0x97, 0x34, 0x1d, 0x66, 0x87, 0x8d, 0x92, 0xf2, 0x82, 0xde, 0x1e, - 0x2e, 0xa9, 0xa1, 0x9e, 0xaf, 0x6c, 0x88, 0x44, 0x11, 0x93, 0x44, 0x79, 0xac, 0x30, 0x76, 0x96, - 0xab, 0xf7, 0xd6, 0x11, 0x2c, 0xb5, 0xa1, 0x0c, 0x13, 0x3d, 0x80, 0x73, 0x69, 0xbe, 0xd9, 0x80, - 0x95, 0xe7, 0x09, 0x88, 0x4c, 0x84, 0xcc, 0x48, 0xc6, 0xf6, 0x9d, 0xe5, 0xb6, 0xaf, 0x57, 0x30, - 0xcf, 0xf6, 0xdb, 0x50, 0xf3, 0xa9, 0x08, 0x38, 0xf5, 0xb5, 0x31, 0x50, 0x7d, 0x16, 0xd7, 0xaf, - 0xbe, 0x7a, 0x52, 0x10, 0x8a, 0xd7, 0x0c, 0x47, 0xf7, 0x50, 0x0b, 0x2a, 0x46, 0x37, 0xc2, 0xad, - 0x6a, 0xed, 0x3e, 0xa3, 0xdd, 0xcf, 0x69, 0xc7, 0x8c, 0x6d, 0xed, 0xb9, 0x8c, 0xed, 0x3a, 0x40, - 0xc8, 0x06, 0x7d, 0x9f, 0x07, 0x13, 0xca, 0xdd, 0x9a, 0x79, 0x04, 0xe4, 0x70, 0xf7, 0x34, 0x02, - 0x3b, 0x21, 0x1b, 0x24, 0xcd, 0x05, 0x1b, 0x5a, 0x7f, 0x3e, 0x1b, 0x32, 0xae, 0xf1, 0xad, 0x05, - 0xff, 0x5f, 0x28, 0x0d, 0xbd, 0x0b, 0x65, 0x53, 0xdc, 0x49, 0x6f, 0x22, 0xc3, 0xc3, 0x29, 0x16, - 0x6d, 0x82, 0xa3, 0x4e, 0x1a, 0x15, 0x82, 0x26, 0x1e, 0xe2, 0xe0, 0xa3, 0x0f, 0xc8, 0x85, 0x32, - 0x09, 0x03, 0xa2, 0xc6, 0x8a, 0x7a, 0x2c, 0xed, 0x6e, 0xff, 0x50, 0x80, 0xb2, 0x09, 0x76, 0xd6, - 0x77, 0x95, 0x99, 0x76, 0xe1, 0x7c, 0xde, 0x84, 0xb5, 0x64, 0x53, 0x8c, 0xb0, 0xec, 0x53, 0xb7, - 0xa6, 0x9a, 0xe0, 0x13, 0x51, 0xdd, 0x04, 0x3b, 0x88, 0xc9, 0xc8, 0xdc, 0x53, 0xb9, 0x33, 0xf7, - 0xee, 0xb6, 0x6e, 0xdf, 0x89, 0x93, 0xf3, 0x51, 0x99, 0x1d, 0x36, 0x6c, 0xf5, 0x01, 0x6b, 0x9a, - 0xd9, 0x9b, 0x5f, 0x56, 0xa1, 0xdc, 0x09, 0xc7, 0x42, 0x52, 0x7e, 0xd6, 0xcb, 0x62, 0xa6, 0x5d, - 0x58, 0x96, 0x0e, 0x94, 0x39, 0x63, 0xb2, 0xef, 0x91, 0x93, 0x56, 0x04, 0x33, 0x26, 0x3b, 0xad, - 0xf6, 0xba, 0x22, 0x2a, 0x53, 0x4a, 0xfa, 0xb8, 0xa4, 0xa8, 0x1d, 0x82, 0x1e, 0xc2, 0x85, 0xd4, - 0xca, 0xf7, 0x19, 0x93, 0x42, 0x72, 0x12, 0xf7, 0x87, 0x74, 0xaa, 0xae, 0xf5, 0xe2, 0xb2, 0x47, - 0x5b, 0x37, 0xf2, 0xf8, 0x54, 0x2f, 0xd7, 0x2d, 0x3a, 0xc5, 0xe7, 0x4d, 0x80, 0x76, 0xca, 0xbf, - 0x45, 0xa7, 0x02, 0x7d, 0x04, 0x9b, 0x74, 0x0e, 0x53, 0x11, 0xfb, 0x21, 0x19, 0xa9, 0x4b, 0xaa, - 0xef, 0x85, 0xcc, 0x1b, 0x6a, 0x9f, 0xb4, 0xf1, 0x45, 0x9a, 0x0d, 0xf5, 0x59, 0x82, 0xe8, 0x28, - 0x00, 0x12, 0xe0, 0xee, 0x87, 0xc4, 0x1b, 0x86, 0x81, 0x50, 0xef, 0xf2, 0xcc, 0x3b, 0x4c, 0x59, - 0x9d, 0xca, 0x6d, 0xf7, 0x84, 0xd5, 0x6a, 0xb6, 0x8f, 0xb8, 0x99, 0x57, 0x9d, 0xe8, 0x46, 0x92, - 0x4f, 0xf1, 0xcb, 0xfb, 0xf9, 0xa3, 0xa8, 0x0d, 0xd5, 0x71, 0xa4, 0xa6, 0x4f, 0xd6, 0xc0, 0x79, - 0xd6, 0x35, 0x80, 0x84, 0xa5, 0x2a, 0xdf, 0x98, 0xc0, 0xe6, 0x49, 0x93, 0xa3, 0xff, 0x41, 0x71, - 0x48, 0xa7, 0x89, 0x7e, 0xb0, 0x6a, 0xa2, 0x8f, 0x61, 0x75, 0x42, 0xc2, 0x31, 0x35, 0xca, 0x79, - 0x33, 0x6f, 0xbe, 0xfc, 0x90, 0x38, 0x21, 0xde, 0x28, 0xec, 0x5a, 0x46, 0xa8, 0xbf, 0x5a, 0x50, - 0xba, 0x47, 0x3d, 0x4e, 0xe5, 0x0b, 0xd5, 0xe9, 0xee, 0x31, 0x9d, 0xd6, 0xf3, 0x5f, 0x69, 0x6a, - 0xd6, 0x05, 0x99, 0x6e, 0x40, 0x25, 0x88, 0x24, 0xe5, 0x11, 0x09, 0xb5, 0x4e, 0x2b, 0x78, 0xde, - 0x37, 0x29, 0xff, 0x65, 0x41, 0x05, 0x53, 0xc1, 0xc6, 0xfc, 0x05, 0xbf, 0x8f, 0x9f, 0xba, 0x71, - 0x8b, 0xff, 0xfa, 0xc6, 0x45, 0x60, 0x0f, 0x83, 0xc8, 0xbc, 0x0d, 0xb0, 0x6e, 0xa3, 0x26, 0x94, - 0x63, 0x32, 0x0d, 0x19, 0xf1, 0x8d, 0xb3, 0x9c, 0x5f, 0xf8, 0xc3, 0xd8, 0x8a, 0xa6, 0x38, 0x05, - 0x99, 0x5a, 0x0f, 0x2c, 0x70, 0xba, 0x5f, 0x4b, 0x1a, 0xe9, 0xe7, 0xe7, 0x7f, 0xb2, 0xd8, 0xad, - 0xc5, 0x3f, 0x91, 0xce, 0xb1, 0xff, 0x87, 0x49, 0x29, 0x6d, 0xf7, 0xe0, 0x49, 0x7d, 0xe5, 0x8f, - 0x27, 0xf5, 0x95, 0x6f, 0x66, 0x75, 0xeb, 0x60, 0x56, 0xb7, 0x7e, 0x9f, 0xd5, 0xad, 0x3f, 0x67, - 0x75, 0x6b, 0xbf, 0xa4, 0x57, 0xe0, 0x9d, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xe5, 0x6e, 0x08, - 0x2c, 0x7c, 0x10, 0x00, 0x00, + // 1390 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xcc, 0x57, 0xc1, 0x6f, 0x1b, 0x45, + 0x17, 0xef, 0xda, 0x1b, 0xdb, 0xfb, 0x9c, 0x58, 0xf9, 0xa6, 0xf9, 0xf2, 0x6d, 0xf3, 0xe5, 0xb3, + 0xf3, 0xb9, 0x02, 0x55, 0xa8, 0x72, 0x4a, 0x29, 0x28, 0x0d, 0x14, 0x6a, 0x27, 0x16, 0xb5, 0x4a, + 0x69, 0x34, 0x2d, 0x2d, 0x37, 0x33, 0xd9, 0x9d, 0xba, 0x8b, 0xd7, 0x3b, 0xab, 0x9d, 0xb1, 0x8b, + 0x6f, 0x88, 0x63, 0xfe, 0x81, 0xdc, 0x38, 0x70, 0xe2, 0x0e, 0x17, 0x2e, 0x9c, 0x7b, 0xe4, 0x84, + 0x38, 0x45, 0xd4, 0xff, 0x05, 0x12, 0x07, 0x34, 0xb3, 0xb3, 0xce, 0xa6, 0x5e, 0x27, 0x2d, 0xaa, + 0x2a, 0x4e, 0x9e, 0xd9, 0xf9, 0xfd, 0xde, 0xbc, 0xf7, 0xe6, 0x37, 0x6f, 0x9e, 0x61, 0x89, 0xed, + 0x7f, 0x49, 0x1d, 0xc1, 0x1b, 0x61, 0xc4, 0x04, 0x43, 0xc8, 0x65, 0x4e, 0x9f, 0x46, 0x0d, 0xfe, + 0x84, 0x44, 0x83, 0xbe, 0x27, 0x1a, 0xa3, 0xb7, 0xd7, 0xca, 0x62, 0x1c, 0x52, 0x0d, 0x58, 0x2b, + 0xf3, 0x90, 0x3a, 0xc9, 0xa4, 0xd6, 0x63, 0xac, 0xe7, 0xd3, 0x4d, 0x35, 0xdb, 0x1f, 0x3e, 0xda, + 0x14, 0xde, 0x80, 0x72, 0x41, 0x06, 0xa1, 0x06, 0xac, 0xf4, 0x58, 0x8f, 0xa9, 0xe1, 0xa6, 0x1c, + 0xe9, 0xaf, 0x17, 0x9e, 0xa7, 0x91, 0x60, 0xac, 0x97, 0xce, 0x87, 0xfe, 0xb0, 0xe7, 0x05, 0x9b, + 0xf1, 0x4f, 0xfc, 0xb1, 0xfe, 0x93, 0x01, 0xe6, 0x1d, 0x2a, 0x08, 0x7a, 0x1f, 0x8a, 0x23, 0x1a, + 0x71, 0x8f, 0x05, 0xb6, 0xb1, 0x61, 0x5c, 0x2a, 0x5f, 0xfd, 0x6f, 0x63, 0xd6, 0xdf, 0xc6, 0x83, + 0x18, 0xd2, 0x32, 0x9f, 0x1e, 0xd5, 0xce, 0xe1, 0x84, 0x81, 0xae, 0x03, 0x38, 0x11, 0x25, 0x82, + 0xba, 0x5d, 0x22, 0xec, 0x9c, 0xe2, 0xaf, 0x35, 0x62, 0x57, 0x1a, 0x89, 0x2b, 0x8d, 0xfb, 0x49, + 0x04, 0xd8, 0xd2, 0xe8, 0xa6, 0x90, 0xd4, 0x61, 0xe8, 0x26, 0xd4, 0xfc, 0xd9, 0x54, 0x8d, 0x6e, + 0x8a, 0xfa, 0x0f, 0x26, 0x98, 0x9f, 0x32, 0x97, 0xa2, 0x55, 0xc8, 0x79, 0xae, 0x72, 0xdb, 0x6a, + 0x15, 0x26, 0x47, 0xb5, 0x5c, 0x67, 0x17, 0xe7, 0x3c, 0x17, 0x5d, 0x05, 0x73, 0x40, 0x05, 0xd1, + 0x0e, 0xd9, 0x59, 0x01, 0xc9, 0xd8, 0x75, 0x34, 0x0a, 0x8b, 0xde, 0x03, 0x53, 0x1e, 0x83, 0xf6, + 0x64, 0x3d, 0x8b, 0x23, 0xf7, 0xbc, 0x17, 0x52, 0x27, 0xe1, 0x49, 0x3c, 0x6a, 0x43, 0xd9, 0xa5, + 0xdc, 0x89, 0xbc, 0x50, 0xc8, 0x1c, 0x9a, 0x8a, 0x7e, 0x71, 0x1e, 0x7d, 0xf7, 0x18, 0x8a, 0xd3, + 0x3c, 0xf4, 0x01, 0x14, 0xb8, 0x20, 0x62, 0xc8, 0xed, 0x05, 0x65, 0xa1, 0x3a, 0xd7, 0x01, 0x85, + 0xd2, 0x2e, 0x68, 0x0e, 0xba, 0x05, 0x95, 0x01, 0x09, 0x48, 0x8f, 0x46, 0x5d, 0x6d, 0xa5, 0xa0, + 0xac, 0xfc, 0x3f, 0x33, 0xf4, 0x18, 0x19, 0x1b, 0xc2, 0x4b, 0x83, 0xf4, 0x14, 0xb5, 0x01, 0x88, + 0x10, 0xc4, 0x79, 0x3c, 0xa0, 0x81, 0xb0, 0x8b, 0xca, 0xca, 0x1b, 0x99, 0xbe, 0x50, 0xf1, 0x84, + 0x45, 0xfd, 0xe6, 0x14, 0x8c, 0x53, 0x44, 0xf4, 0x31, 0x94, 0x1d, 0x1a, 0x09, 0xef, 0x91, 0xe7, + 0x10, 0x41, 0xed, 0x92, 0xb2, 0x53, 0xcb, 0xb2, 0xb3, 0x73, 0x0c, 0xd3, 0x41, 0xa5, 0x99, 0xe8, + 0x0a, 0x98, 0x11, 0xf3, 0xa9, 0x6d, 0x6d, 0x18, 0x97, 0x2a, 0xf3, 0x8f, 0x05, 0x33, 0x9f, 0x62, + 0x85, 0xdc, 0x5e, 0x3d, 0x38, 0xac, 0x23, 0x58, 0x2e, 0x19, 0xcb, 0x86, 0x92, 0x86, 0x71, 0xc5, + 0xf8, 0xdc, 0xf8, 0xc2, 0xa8, 0xff, 0x99, 0x87, 0xe2, 0x3d, 0x1a, 0x8d, 0x3c, 0xe7, 0xd5, 0x0a, + 0xe7, 0xfa, 0x09, 0xe1, 0x64, 0xc6, 0xa8, 0xb7, 0x9d, 0xd1, 0xce, 0x16, 0x94, 0x68, 0xe0, 0x86, + 0xcc, 0x0b, 0x84, 0x16, 0x4e, 0x66, 0x80, 0x6d, 0x8d, 0xc1, 0x53, 0x34, 0x6a, 0xc3, 0x52, 0x7c, + 0x1f, 0xba, 0x27, 0x54, 0xb3, 0x91, 0x45, 0xff, 0x4c, 0x01, 0xf5, 0x71, 0x2f, 0x0e, 0x53, 0x33, + 0xb4, 0x0b, 0x4b, 0x61, 0x44, 0x47, 0x1e, 0x1b, 0xf2, 0xae, 0x0a, 0xa2, 0xf0, 0x42, 0x41, 0xe0, + 0xc5, 0x84, 0x25, 0x67, 0xe8, 0x43, 0x58, 0x94, 0xe4, 0x6e, 0x52, 0x47, 0xe0, 0xcc, 0x3a, 0x82, + 0x55, 0xc9, 0xd3, 0x13, 0x74, 0x17, 0xfe, 0x7d, 0xc2, 0x8b, 0xa9, 0xa1, 0xf2, 0xd9, 0x86, 0xce, + 0xa7, 0x3d, 0xd1, 0x1f, 0xb7, 0xd1, 0xc1, 0x61, 0xbd, 0x02, 0x8b, 0x69, 0x09, 0xd4, 0xbf, 0xcd, + 0x41, 0x29, 0x49, 0x24, 0xba, 0xa6, 0xcf, 0xcc, 0x98, 0x9f, 0xb5, 0x04, 0xab, 0xe2, 0x8d, 0x8f, + 0xeb, 0x1a, 0x2c, 0x84, 0x2c, 0x12, 0xdc, 0xce, 0x6d, 0xe4, 0xe7, 0x5d, 0xd1, 0x3d, 0x16, 0x89, + 0x1d, 0x16, 0x3c, 0xf2, 0x7a, 0x38, 0x06, 0xa3, 0x87, 0x50, 0x1e, 0x79, 0x91, 0x18, 0x12, 0xbf, + 0xeb, 0x85, 0xdc, 0xce, 0x2b, 0xee, 0x9b, 0xa7, 0x6d, 0xd9, 0x78, 0x10, 0xe3, 0x3b, 0x7b, 0xad, + 0xca, 0xe4, 0xa8, 0x06, 0xd3, 0x29, 0xc7, 0xa0, 0x4d, 0x75, 0x42, 0xbe, 0x76, 0x07, 0xac, 0xe9, + 0x0a, 0xba, 0x0c, 0x10, 0xc4, 0x37, 0xb2, 0x3b, 0x55, 0xf6, 0xd2, 0xe4, 0xa8, 0x66, 0xe9, 0x7b, + 0xda, 0xd9, 0xc5, 0x96, 0x06, 0x74, 0x5c, 0x84, 0xc0, 0x24, 0xae, 0x1b, 0x29, 0x9d, 0x5b, 0x58, + 0x8d, 0xeb, 0xdf, 0x17, 0xc0, 0xbc, 0x4f, 0x78, 0xff, 0x75, 0x57, 0x55, 0xb9, 0xe7, 0xcc, 0xcd, + 0xb8, 0x0c, 0xc0, 0x63, 0xbd, 0xc9, 0x70, 0xcc, 0xe3, 0x70, 0xb4, 0x0a, 0x65, 0x38, 0x1a, 0x10, + 0x87, 0xc3, 0x7d, 0x26, 0xd4, 0x25, 0x30, 0xb1, 0x1a, 0xa3, 0x8b, 0x50, 0x0c, 0x98, 0xab, 0xe8, + 0x05, 0x45, 0x87, 0xc9, 0x51, 0xad, 0x20, 0x6b, 0x45, 0x67, 0x17, 0x17, 0xe4, 0x52, 0xc7, 0x95, + 0x65, 0x8a, 0x04, 0x01, 0x13, 0x44, 0xd6, 0x60, 0xae, 0xcb, 0x5d, 0xa6, 0xfa, 0x9b, 0xc7, 0xb0, + 0xa4, 0x4c, 0xa5, 0x98, 0xe8, 0x01, 0x9c, 0x4f, 0xfc, 0x4d, 0x1b, 0x2c, 0xbd, 0x8c, 0x41, 0xa4, + 0x2d, 0xa4, 0x56, 0x52, 0xcf, 0x82, 0x35, 0xff, 0x59, 0x50, 0x19, 0xcc, 0x7a, 0x16, 0x5a, 0xb0, + 0xe4, 0x52, 0xee, 0x45, 0xd4, 0x55, 0x65, 0x82, 0xaa, 0x9b, 0x59, 0xb9, 0xfa, 0xbf, 0xd3, 0x8c, + 0x50, 0xbc, 0xa8, 0x39, 0x6a, 0x86, 0x9a, 0x50, 0xd2, 0xba, 0xe1, 0x76, 0x59, 0x69, 0xf7, 0x05, + 0x9f, 0x83, 0x29, 0xed, 0x44, 0x99, 0x5b, 0x7c, 0xa9, 0x32, 0x77, 0x1d, 0xc0, 0x67, 0xbd, 0xae, + 0x1b, 0x79, 0x23, 0x1a, 0xd9, 0x4b, 0xba, 0x49, 0xc8, 0xe0, 0xee, 0x2a, 0x04, 0xb6, 0x7c, 0xd6, + 0x8b, 0x87, 0x33, 0x45, 0xa9, 0xf2, 0x72, 0x45, 0x69, 0x7b, 0xed, 0xe0, 0xb0, 0xbe, 0x0a, 0x2b, + 0xe9, 0x1a, 0xb2, 0x65, 0xdc, 0x34, 0x6e, 0x19, 0x7b, 0x46, 0xfd, 0x1b, 0x03, 0xfe, 0x35, 0x13, + 0x30, 0x7a, 0x17, 0x8a, 0x3a, 0xe4, 0xd3, 0x3a, 0x29, 0xcd, 0xc3, 0x09, 0x16, 0xad, 0x83, 0x25, + 0xef, 0x1f, 0xe5, 0x9c, 0xc6, 0x95, 0xc5, 0xc2, 0xc7, 0x1f, 0x90, 0x0d, 0x45, 0xe2, 0x7b, 0x44, + 0xae, 0xe5, 0xd5, 0x5a, 0x32, 0xad, 0x7f, 0x97, 0x83, 0xa2, 0x36, 0xf6, 0xba, 0xdf, 0x33, 0xbd, + 0xed, 0xcc, 0xad, 0xbd, 0x01, 0x8b, 0xf1, 0x51, 0x69, 0xb9, 0x99, 0x67, 0x1e, 0x58, 0x39, 0xc6, + 0xc7, 0x52, 0xbb, 0x01, 0xa6, 0x17, 0x92, 0x81, 0x7e, 0xcb, 0x32, 0x77, 0xee, 0xec, 0x35, 0xef, + 0xdc, 0x0d, 0xe3, 0x5b, 0x53, 0x9a, 0x1c, 0xd5, 0x4c, 0xf9, 0x01, 0x2b, 0x5a, 0x66, 0xd5, 0xff, + 0x71, 0x01, 0x8a, 0x3b, 0xfe, 0x90, 0x0b, 0x1a, 0xbd, 0xee, 0x24, 0xe9, 0x6d, 0x67, 0x92, 0xb4, + 0x03, 0xc5, 0x88, 0x31, 0xd1, 0x75, 0xc8, 0x69, 0xf9, 0xc1, 0x8c, 0x89, 0x9d, 0x66, 0xab, 0x22, + 0x89, 0xb2, 0x70, 0xc5, 0x73, 0x5c, 0x90, 0xd4, 0x1d, 0x82, 0x1e, 0xc2, 0x6a, 0x52, 0xee, 0xf7, + 0x19, 0x13, 0x5c, 0x44, 0x24, 0xec, 0xf6, 0xe9, 0x58, 0x36, 0x02, 0xf9, 0x79, 0x8d, 0x5f, 0x3b, + 0x70, 0xa2, 0xb1, 0x4a, 0xde, 0x6d, 0x3a, 0xc6, 0x2b, 0xda, 0x40, 0x2b, 0xe1, 0xdf, 0xa6, 0x63, + 0x8e, 0x3e, 0x82, 0x75, 0x3a, 0x85, 0x49, 0x8b, 0x5d, 0x9f, 0x0c, 0xe4, 0x43, 0xd6, 0x75, 0x7c, + 0xe6, 0xf4, 0x55, 0x2d, 0x35, 0xf1, 0x05, 0x9a, 0x36, 0xf5, 0x49, 0x8c, 0xd8, 0x91, 0x00, 0xc4, + 0xc1, 0xde, 0xf7, 0x89, 0xd3, 0xf7, 0x3d, 0x2e, 0x7b, 0xfb, 0x54, 0x2f, 0x27, 0xcb, 0xa1, 0xf4, + 0x6d, 0xeb, 0x94, 0x6c, 0x35, 0x5a, 0xc7, 0xdc, 0x54, 0x67, 0xc8, 0xdb, 0x81, 0x88, 0xc6, 0xf8, + 0x3f, 0xfb, 0xd9, 0xab, 0xa8, 0x05, 0xe5, 0x61, 0x20, 0xb7, 0x8f, 0x73, 0x60, 0xbd, 0x68, 0x0e, + 0x20, 0x66, 0xc9, 0xc8, 0xd7, 0x46, 0xb0, 0x7e, 0xda, 0xe6, 0x68, 0x19, 0xf2, 0x7d, 0x3a, 0x8e, + 0xf5, 0x83, 0xe5, 0x10, 0xdd, 0x84, 0x85, 0x11, 0xf1, 0x87, 0x54, 0x2b, 0xe7, 0xad, 0xac, 0xfd, + 0xb2, 0x4d, 0xe2, 0x98, 0xb8, 0x9d, 0xdb, 0x32, 0x32, 0x65, 0xfb, 0xb3, 0x01, 0x85, 0x7b, 0xd4, + 0x89, 0xa8, 0x78, 0xa5, 0xaa, 0xdd, 0x3a, 0xa1, 0xda, 0x6a, 0x76, 0x97, 0x27, 0x77, 0x9d, 0x11, + 0xed, 0x1a, 0x94, 0xbc, 0x40, 0xd0, 0x28, 0x20, 0xbe, 0x52, 0x6d, 0x09, 0x4f, 0xe7, 0x99, 0x01, + 0xfc, 0x61, 0x40, 0x09, 0x53, 0xce, 0x86, 0xd1, 0x2b, 0xee, 0xb6, 0x9f, 0x7b, 0xb1, 0xf3, 0x7f, + 0xfb, 0xc5, 0x46, 0x60, 0xf6, 0xbd, 0x40, 0xf7, 0x16, 0x58, 0x8d, 0x51, 0x03, 0x8a, 0x21, 0x19, + 0xfb, 0x8c, 0xb8, 0xba, 0x06, 0xad, 0xcc, 0xfc, 0x21, 0x6d, 0x06, 0x63, 0x9c, 0x80, 0xb6, 0x57, + 0x0e, 0x0e, 0xeb, 0xcb, 0x50, 0x49, 0x47, 0xfe, 0xd8, 0xa8, 0xff, 0x6a, 0x80, 0xd5, 0xfe, 0x4a, + 0xd0, 0x40, 0x35, 0xb7, 0xff, 0xc8, 0xe0, 0x37, 0x66, 0xff, 0xb4, 0x5a, 0x27, 0xfe, 0x8f, 0x66, + 0x1d, 0x6a, 0xcb, 0x7e, 0xfa, 0xac, 0x7a, 0xee, 0xb7, 0x67, 0xd5, 0x73, 0x5f, 0x4f, 0xaa, 0xc6, + 0xd3, 0x49, 0xd5, 0xf8, 0x65, 0x52, 0x35, 0x7e, 0x9f, 0x54, 0x8d, 0xfd, 0x82, 0xca, 0xcf, 0x3b, + 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0x01, 0x4f, 0xd2, 0x2a, 0xfa, 0x10, 0x00, 0x00, } diff --git a/api/objects.proto b/api/objects.proto index 616925555e..9c0525e724 100644 --- a/api/objects.proto +++ b/api/objects.proto @@ -26,7 +26,18 @@ message Meta { // Node provides the internal node state as seen by the cluster. message Node { - option (docker.protobuf.plugin.store_object) = { }; + option (docker.protobuf.plugin.store_object) = { + watch_selectors: { + id: true + id_prefix: true + name: true + name_prefix: true + custom: true + custom_prefix: true + role: true + membership: true + } + }; // ID specifies the identity of the node. string id = 1; @@ -67,7 +78,16 @@ message Node { } message Service { - option (docker.protobuf.plugin.store_object) = { }; + option (docker.protobuf.plugin.store_object) = { + watch_selectors: { + id: true + id_prefix: true + name: true + name_prefix: true + custom: true + custom_prefix: true + } + }; string id = 1; @@ -137,7 +157,20 @@ message Endpoint { // immutable and idempotent. Once it is dispatched to a node, it will not be // dispatched to another node. message Task { - option (docker.protobuf.plugin.store_object) = { }; + option (docker.protobuf.plugin.store_object) = { + watch_selectors: { + id: true + id_prefix: true + name: true + name_prefix: true + custom: true + custom_prefix: true + service_id: true + node_id: true + slot: true + desired_state: true + } + }; string id = 1; @@ -225,7 +258,16 @@ message NetworkAttachment { } message Network { - option (docker.protobuf.plugin.store_object) = { }; + option (docker.protobuf.plugin.store_object) = { + watch_selectors: { + id: true + id_prefix: true + name: true + name_prefix: true + custom: true + custom_prefix: true + } + }; string id = 1; @@ -243,7 +285,16 @@ message Network { // Cluster provides global cluster settings. message Cluster { - option (docker.protobuf.plugin.store_object) = { }; + option (docker.protobuf.plugin.store_object) = { + watch_selectors: { + id: true + id_prefix: true + name: true + name_prefix: true + custom: true + custom_prefix: true + } + }; string id = 1; @@ -281,7 +332,16 @@ message Cluster { // information that is generated from the secret data in the `spec`, such as // the digest and size of the secret data. message Secret { - option (docker.protobuf.plugin.store_object) = { }; + option (docker.protobuf.plugin.store_object) = { + watch_selectors: { + id: true + id_prefix: true + name: true + name_prefix: true + custom: true + custom_prefix: true + } + }; string id = 1; @@ -299,7 +359,17 @@ message Secret { // SwarmKit can serve as a store for these objects without understanding their // meanings. message Resource { - option (docker.protobuf.plugin.store_object) = { }; + option (docker.protobuf.plugin.store_object) = { + watch_selectors: { + id: true + id_prefix: true + name: true + name_prefix: true + custom: true + custom_prefix: true + kind: true + } + }; string id = 1 [(gogoproto.customname) = "ID"]; @@ -320,7 +390,16 @@ message Resource { // Extension declares a type of "resource" object. This message provides some // metadata about the objects. message Extension { - option (docker.protobuf.plugin.store_object) = { }; + option (docker.protobuf.plugin.store_object) = { + watch_selectors: { + id: true + id_prefix: true + name: true + name_prefix: true + custom: true + custom_prefix: true + } + }; string id = 1 [(gogoproto.customname) = "ID"]; diff --git a/api/storeobject.go b/api/storeobject.go index 67c6ec897b..3cfd915209 100644 --- a/api/storeobject.go +++ b/api/storeobject.go @@ -3,6 +3,7 @@ package api import ( "errors" "fmt" + "strings" "github.com/docker/go-events" ) @@ -78,3 +79,25 @@ func prefixFromArgs(args ...interface{}) ([]byte, error) { } return val, nil } + +func checkCustom(a1, a2 Annotations) bool { + if len(a1.Indices) == 1 { + for _, ind := range a2.Indices { + if ind.Key == a1.Indices[0].Key && ind.Val == a1.Indices[0].Val { + return true + } + } + } + return false +} + +func checkCustomPrefix(a1, a2 Annotations) bool { + if len(a1.Indices) == 1 { + for _, ind := range a2.Indices { + if ind.Key == a1.Indices[0].Key && strings.HasPrefix(ind.Val, a1.Indices[0].Val) { + return true + } + } + } + return false +} diff --git a/ca/server.go b/ca/server.go index b78c00f396..25ac2114b0 100644 --- a/ca/server.go +++ b/ca/server.go @@ -12,7 +12,6 @@ import ( "github.com/docker/swarmkit/api/equality" "github.com/docker/swarmkit/identity" "github.com/docker/swarmkit/log" - "github.com/docker/swarmkit/manager/state" "github.com/docker/swarmkit/manager/state/store" gogotypes "github.com/gogo/protobuf/types" "github.com/pkg/errors" @@ -129,7 +128,7 @@ func (s *Server) NodeCertificateStatus(ctx context.Context, request *api.NodeCer event := api.EventUpdateNode{ Node: &api.Node{ID: request.NodeID}, - Checks: []api.NodeCheckFunc{state.NodeCheckID}, + Checks: []api.NodeCheckFunc{api.NodeCheckID}, } // Retrieve the current value of the certificate with this token, and create a watcher diff --git a/ca/testutils/cautils.go b/ca/testutils/cautils.go index fb5f02039c..c48f5575cd 100644 --- a/ca/testutils/cautils.go +++ b/ca/testutils/cautils.go @@ -21,7 +21,6 @@ import ( "github.com/docker/swarmkit/connectionbroker" "github.com/docker/swarmkit/identity" "github.com/docker/swarmkit/ioutils" - "github.com/docker/swarmkit/manager/state" "github.com/docker/swarmkit/manager/state/store" "github.com/docker/swarmkit/remotes" "github.com/stretchr/testify/assert" @@ -193,7 +192,7 @@ func NewTestCAFromRootCA(t *testing.T, tempBaseDir string, rootCA ca.RootCA, krw }, api.EventUpdateCluster{ Cluster: &api.Cluster{ID: organization}, - Checks: []api.ClusterCheckFunc{state.ClusterCheckID}, + Checks: []api.ClusterCheckFunc{api.ClusterCheckID}, }, ) assert.NoError(t, err) diff --git a/manager/dispatcher/dispatcher.go b/manager/dispatcher/dispatcher.go index 8bfae2047d..eeec4657b4 100644 --- a/manager/dispatcher/dispatcher.go +++ b/manager/dispatcher/dispatcher.go @@ -17,7 +17,6 @@ import ( "github.com/docker/swarmkit/api/equality" "github.com/docker/swarmkit/ca" "github.com/docker/swarmkit/log" - "github.com/docker/swarmkit/manager/state" "github.com/docker/swarmkit/manager/state/store" "github.com/docker/swarmkit/remotes" "github.com/docker/swarmkit/watch" @@ -702,11 +701,11 @@ func (d *Dispatcher) Tasks(r *api.TasksRequest, stream api.Dispatcher_TasksServe return nil }, api.EventCreateTask{Task: &api.Task{NodeID: nodeID}, - Checks: []api.TaskCheckFunc{state.TaskCheckNodeID}}, + Checks: []api.TaskCheckFunc{api.TaskCheckNodeID}}, api.EventUpdateTask{Task: &api.Task{NodeID: nodeID}, - Checks: []api.TaskCheckFunc{state.TaskCheckNodeID}}, + Checks: []api.TaskCheckFunc{api.TaskCheckNodeID}}, api.EventDeleteTask{Task: &api.Task{NodeID: nodeID}, - Checks: []api.TaskCheckFunc{state.TaskCheckNodeID}}, + Checks: []api.TaskCheckFunc{api.TaskCheckNodeID}}, ) if err != nil { return err @@ -916,9 +915,9 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche return nil }, api.EventUpdateTask{Task: &api.Task{NodeID: nodeID}, - Checks: []api.TaskCheckFunc{state.TaskCheckNodeID}}, + Checks: []api.TaskCheckFunc{api.TaskCheckNodeID}}, api.EventDeleteTask{Task: &api.Task{NodeID: nodeID}, - Checks: []api.TaskCheckFunc{state.TaskCheckNodeID}}, + Checks: []api.TaskCheckFunc{api.TaskCheckNodeID}}, api.EventUpdateSecret{}, api.EventDeleteSecret{}, ) @@ -1337,7 +1336,7 @@ func (d *Dispatcher) Session(r *api.SessionRequest, stream api.Dispatcher_Sessio nodeObj = store.GetNode(readTx, nodeID) return nil }, api.EventUpdateNode{Node: &api.Node{ID: nodeID}, - Checks: []api.NodeCheckFunc{state.NodeCheckID}}, + Checks: []api.NodeCheckFunc{api.NodeCheckID}}, ) if cancel != nil { defer cancel() diff --git a/manager/manager.go b/manager/manager.go index 46f795af9a..cb3cb43fdb 100644 --- a/manager/manager.go +++ b/manager/manager.go @@ -33,7 +33,6 @@ import ( "github.com/docker/swarmkit/manager/orchestrator/taskreaper" "github.com/docker/swarmkit/manager/resourceapi" "github.com/docker/swarmkit/manager/scheduler" - "github.com/docker/swarmkit/manager/state" "github.com/docker/swarmkit/manager/state/raft" "github.com/docker/swarmkit/manager/state/store" "github.com/docker/swarmkit/manager/storeapi" @@ -701,7 +700,7 @@ func (m *Manager) watchForClusterChanges(ctx context.Context) error { }, api.EventUpdateCluster{ Cluster: &api.Cluster{ID: clusterID}, - Checks: []api.ClusterCheckFunc{state.ClusterCheckID}, + Checks: []api.ClusterCheckFunc{api.ClusterCheckID}, }, ) if err != nil { diff --git a/manager/orchestrator/restart/restart.go b/manager/orchestrator/restart/restart.go index 58af5f216d..091c9e150a 100644 --- a/manager/orchestrator/restart/restart.go +++ b/manager/orchestrator/restart/restart.go @@ -329,15 +329,15 @@ func (r *Supervisor) DelayStart(ctx context.Context, _ store.Tx, oldTask *api.Ta r.store.WatchQueue(), api.EventUpdateTask{ Task: &api.Task{ID: oldTask.ID, Status: api.TaskStatus{State: api.TaskStateRunning}}, - Checks: []api.TaskCheckFunc{state.TaskCheckID, state.TaskCheckStateGreaterThan}, + Checks: []api.TaskCheckFunc{api.TaskCheckID, state.TaskCheckStateGreaterThan}, }, api.EventUpdateNode{ Node: &api.Node{ID: oldTask.NodeID, Status: api.NodeStatus{State: api.NodeStatus_DOWN}}, - Checks: []api.NodeCheckFunc{state.NodeCheckID, state.NodeCheckState}, + Checks: []api.NodeCheckFunc{api.NodeCheckID, state.NodeCheckState}, }, api.EventDeleteNode{ Node: &api.Node{ID: oldTask.NodeID}, - Checks: []api.NodeCheckFunc{state.NodeCheckID}, + Checks: []api.NodeCheckFunc{api.NodeCheckID}, }, ) } diff --git a/manager/orchestrator/update/updater.go b/manager/orchestrator/update/updater.go index bf331df8fc..3e99624709 100644 --- a/manager/orchestrator/update/updater.go +++ b/manager/orchestrator/update/updater.go @@ -211,7 +211,7 @@ func (u *Updater) Run(ctx context.Context, slots []orchestrator.Slot) { u.store.WatchQueue(), api.EventUpdateTask{ Task: &api.Task{ServiceID: service.ID, Status: api.TaskStatus{State: api.TaskStateRunning}}, - Checks: []api.TaskCheckFunc{state.TaskCheckServiceID, state.TaskCheckStateGreaterThan}, + Checks: []api.TaskCheckFunc{api.TaskCheckServiceID, state.TaskCheckStateGreaterThan}, }, ) defer cancelWatch() @@ -368,7 +368,7 @@ func (u *Updater) updateTask(ctx context.Context, slot orchestrator.Slot, update // Kick off the watch before even creating the updated task. This is in order to avoid missing any event. taskUpdates, cancel := state.Watch(u.watchQueue, api.EventUpdateTask{ Task: &api.Task{ID: updated.ID}, - Checks: []api.TaskCheckFunc{state.TaskCheckID}, + Checks: []api.TaskCheckFunc{api.TaskCheckID}, }) defer cancel() diff --git a/manager/state/watch.go b/manager/state/watch.go index 21ea9d11bf..ad0ebd75fa 100644 --- a/manager/state/watch.go +++ b/manager/state/watch.go @@ -1,8 +1,6 @@ package state import ( - "strings" - "github.com/docker/go-events" "github.com/docker/swarmkit/api" "github.com/docker/swarmkit/watch" @@ -19,313 +17,16 @@ func (e EventCommit) Matches(watchEvent events.Event) bool { return ok } -func checkCustom(a1, a2 api.Annotations) bool { - if len(a1.Indices) == 1 { - for _, ind := range a2.Indices { - if ind.Key == a1.Indices[0].Key && ind.Val == a1.Indices[0].Val { - return true - } - } - } - return false -} - -func checkCustomPrefix(a1, a2 api.Annotations) bool { - if len(a1.Indices) == 1 { - for _, ind := range a2.Indices { - if ind.Key == a1.Indices[0].Key && strings.HasPrefix(ind.Val, a1.Indices[0].Val) { - return true - } - } - } - return false -} - -// TaskCheckID is a TaskCheckFunc for matching task IDs. -func TaskCheckID(t1, t2 *api.Task) bool { - return t1.ID == t2.ID -} - -// TaskCheckIDPrefix is a TaskCheckFunc for matching task IDs by prefix. -func TaskCheckIDPrefix(t1, t2 *api.Task) bool { - return strings.HasPrefix(t2.ID, t1.ID) -} - -// TaskCheckCustom is a TaskCheckFunc for matching task custom indices. -func TaskCheckCustom(t1, t2 *api.Task) bool { - return checkCustom(t1.Annotations, t2.Annotations) -} - -// TaskCheckCustomPrefix is a TaskCheckFunc for matching task custom indices by prefix. -func TaskCheckCustomPrefix(t1, t2 *api.Task) bool { - return checkCustomPrefix(t1.Annotations, t2.Annotations) -} - -// TaskCheckNodeID is a TaskCheckFunc for matching node IDs. -func TaskCheckNodeID(t1, t2 *api.Task) bool { - return t1.NodeID == t2.NodeID -} - -// TaskCheckServiceID is a TaskCheckFunc for matching service IDs. -func TaskCheckServiceID(t1, t2 *api.Task) bool { - return t1.ServiceID == t2.ServiceID -} - -// TaskCheckSlot is a TaskCheckFunc for matching slots. -func TaskCheckSlot(t1, t2 *api.Task) bool { - return t1.Slot == t2.Slot -} - -// TaskCheckDesiredState is a TaskCheckFunc for matching desired state. -func TaskCheckDesiredState(t1, t2 *api.Task) bool { - return t1.DesiredState == t2.DesiredState -} - // TaskCheckStateGreaterThan is a TaskCheckFunc for checking task state. func TaskCheckStateGreaterThan(t1, t2 *api.Task) bool { return t2.Status.State > t1.Status.State } -// ServiceCheckID is a ServiceCheckFunc for matching service IDs. -func ServiceCheckID(s1, s2 *api.Service) bool { - return s1.ID == s2.ID -} - -// ServiceCheckIDPrefix is a ServiceCheckFunc for matching service IDs by prefix. -func ServiceCheckIDPrefix(s1, s2 *api.Service) bool { - return strings.HasPrefix(s2.ID, s1.ID) -} - -// ServiceCheckName is a ServiceCheckFunc for matching service names. -func ServiceCheckName(s1, s2 *api.Service) bool { - return s1.Spec.Annotations.Name == s2.Spec.Annotations.Name -} - -// ServiceCheckNamePrefix is a ServiceCheckFunc for matching service names by prefix. -func ServiceCheckNamePrefix(s1, s2 *api.Service) bool { - return strings.HasPrefix(s2.Spec.Annotations.Name, s1.Spec.Annotations.Name) -} - -// ServiceCheckCustom is a ServiceCheckFunc for matching service custom indices. -func ServiceCheckCustom(s1, s2 *api.Service) bool { - return checkCustom(s1.Spec.Annotations, s2.Spec.Annotations) -} - -// ServiceCheckCustomPrefix is a ServiceCheckFunc for matching service custom indices by prefix. -func ServiceCheckCustomPrefix(s1, s2 *api.Service) bool { - return checkCustomPrefix(s1.Spec.Annotations, s2.Spec.Annotations) -} - -// NetworkCheckID is a NetworkCheckFunc for matching network IDs. -func NetworkCheckID(n1, n2 *api.Network) bool { - return n1.ID == n2.ID -} - -// NetworkCheckIDPrefix is a NetworkCheckFunc for matching network IDs by prefix. -func NetworkCheckIDPrefix(n1, n2 *api.Network) bool { - return strings.HasPrefix(n2.ID, n1.ID) -} - -// NetworkCheckName is a NetworkCheckFunc for matching network names. -func NetworkCheckName(n1, n2 *api.Network) bool { - return n1.Spec.Annotations.Name == n2.Spec.Annotations.Name -} - -// NetworkCheckNamePrefix is a NetworkCheckFunc for matching network names by prefix. -func NetworkCheckNamePrefix(n1, n2 *api.Network) bool { - return strings.HasPrefix(n2.Spec.Annotations.Name, n1.Spec.Annotations.Name) -} - -// NetworkCheckCustom is a NetworkCheckFunc for matching network custom indices. -func NetworkCheckCustom(n1, n2 *api.Network) bool { - return checkCustom(n1.Spec.Annotations, n2.Spec.Annotations) -} - -// NetworkCheckCustomPrefix is a NetworkCheckFunc for matching network custom indices by prefix. -func NetworkCheckCustomPrefix(n1, n2 *api.Network) bool { - return checkCustomPrefix(n1.Spec.Annotations, n2.Spec.Annotations) -} - -// NodeCheckID is a NodeCheckFunc for matching node IDs. -func NodeCheckID(n1, n2 *api.Node) bool { - return n1.ID == n2.ID -} - -// NodeCheckIDPrefix is a NodeCheckFunc for matching node IDs by prefix. -func NodeCheckIDPrefix(n1, n2 *api.Node) bool { - return strings.HasPrefix(n2.ID, n1.ID) -} - -// NodeCheckName is a NodeCheckFunc for matching node names. -func NodeCheckName(n1, n2 *api.Node) bool { - if n1.Description == nil || n2.Description == nil { - return false - } - return n1.Description.Hostname == n2.Description.Hostname -} - -// NodeCheckNamePrefix is a NodeCheckFunc for matching node names by prefix. -func NodeCheckNamePrefix(n1, n2 *api.Node) bool { - if n1.Description == nil || n2.Description == nil { - return false - } - return strings.HasPrefix(n2.Description.Hostname, n1.Description.Hostname) -} - -// NodeCheckCustom is a NodeCheckFunc for matching node custom indices. -func NodeCheckCustom(n1, n2 *api.Node) bool { - return checkCustom(n1.Spec.Annotations, n2.Spec.Annotations) -} - -// NodeCheckCustomPrefix is a NodeCheckFunc for matching node custom indices by prefix. -func NodeCheckCustomPrefix(n1, n2 *api.Node) bool { - return checkCustomPrefix(n1.Spec.Annotations, n2.Spec.Annotations) -} - // NodeCheckState is a NodeCheckFunc for matching node state. func NodeCheckState(n1, n2 *api.Node) bool { return n1.Status.State == n2.Status.State } -// NodeCheckRole is a NodeCheckFunc for matching node role. -func NodeCheckRole(n1, n2 *api.Node) bool { - return n1.Role == n2.Role -} - -// NodeCheckMembership is a NodeCheckFunc for matching node membership. -func NodeCheckMembership(n1, n2 *api.Node) bool { - return n1.Spec.Membership == n2.Spec.Membership -} - -// ClusterCheckID is a ClusterCheckFunc for matching volume IDs. -func ClusterCheckID(c1, c2 *api.Cluster) bool { - return c1.ID == c2.ID -} - -// ClusterCheckIDPrefix is a ClusterCheckFunc for matching cluster IDs by prefix. -func ClusterCheckIDPrefix(c1, c2 *api.Cluster) bool { - return strings.HasPrefix(c2.ID, c1.ID) -} - -// ClusterCheckName is a ClusterCheckFunc for matching cluster names. -func ClusterCheckName(c1, c2 *api.Cluster) bool { - return c1.Spec.Annotations.Name == c2.Spec.Annotations.Name -} - -// ClusterCheckNamePrefix is a ClusterCheckFunc for matching cluster names by prefix. -func ClusterCheckNamePrefix(c1, c2 *api.Cluster) bool { - return strings.HasPrefix(c2.Spec.Annotations.Name, c1.Spec.Annotations.Name) -} - -// ClusterCheckCustom is a ClusterCheckFunc for matching cluster custom indices. -func ClusterCheckCustom(c1, c2 *api.Cluster) bool { - return checkCustom(c1.Spec.Annotations, c2.Spec.Annotations) -} - -// ClusterCheckCustomPrefix is a ClusterCheckFunc for matching cluster custom indices by prefix. -func ClusterCheckCustomPrefix(c1, c2 *api.Cluster) bool { - return checkCustomPrefix(c1.Spec.Annotations, c2.Spec.Annotations) -} - -// SecretCheckID is a SecretCheckFunc for matching secret IDs. -func SecretCheckID(s1, s2 *api.Secret) bool { - return s1.ID == s2.ID -} - -// SecretCheckIDPrefix is a SecretCheckFunc for matching secret IDs by prefix. -func SecretCheckIDPrefix(s1, s2 *api.Secret) bool { - return strings.HasPrefix(s2.ID, s1.ID) -} - -// SecretCheckName is a SecretCheckFunc for matching secret names. -func SecretCheckName(s1, s2 *api.Secret) bool { - return s1.Spec.Annotations.Name == s2.Spec.Annotations.Name -} - -// SecretCheckNamePrefix is a SecretCheckFunc for matching secret names by prefix. -func SecretCheckNamePrefix(s1, s2 *api.Secret) bool { - return strings.HasPrefix(s2.Spec.Annotations.Name, s1.Spec.Annotations.Name) -} - -// SecretCheckCustom is a SecretCheckFunc for matching secret custom indices. -func SecretCheckCustom(s1, s2 *api.Secret) bool { - return checkCustom(s1.Spec.Annotations, s2.Spec.Annotations) -} - -// SecretCheckCustomPrefix is a SecretCheckFunc for matching secret custom indices by prefix. -func SecretCheckCustomPrefix(s1, s2 *api.Secret) bool { - return checkCustomPrefix(s1.Spec.Annotations, s2.Spec.Annotations) -} - -// ResourceCheckID is a ResourceCheckFunc for matching resource IDs. -func ResourceCheckID(v1, v2 *api.Resource) bool { - return v1.ID == v2.ID -} - -// ResourceCheckKind is a ResourceCheckFunc for matching resource kinds. -func ResourceCheckKind(v1, v2 *api.Resource) bool { - return v1.Kind == v2.Kind -} - -// ResourceCheckIDPrefix is a ResourceCheckFunc for matching resource IDs by prefix. -func ResourceCheckIDPrefix(v1, v2 *api.Resource) bool { - return strings.HasPrefix(v2.ID, v1.ID) -} - -// ResourceCheckName is a ResourceCheckFunc for matching resource names. -func ResourceCheckName(v1, v2 *api.Resource) bool { - return v1.Annotations.Name == v2.Annotations.Name -} - -// ResourceCheckNamePrefix is a ResourceCheckFunc for matching resource names by prefix. -func ResourceCheckNamePrefix(v1, v2 *api.Resource) bool { - return strings.HasPrefix(v2.Annotations.Name, v1.Annotations.Name) -} - -// ResourceCheckCustom is a ResourceCheckFunc for matching resource custom indices. -func ResourceCheckCustom(v1, v2 *api.Resource) bool { - return checkCustom(v1.Annotations, v2.Annotations) -} - -// ResourceCheckCustomPrefix is a ResourceCheckFunc for matching resource custom indices by prefix. -func ResourceCheckCustomPrefix(v1, v2 *api.Resource) bool { - return checkCustomPrefix(v1.Annotations, v2.Annotations) -} - -// ExtensionCheckID is a ExtensionCheckFunc for matching extension IDs. -func ExtensionCheckID(v1, v2 *api.Extension) bool { - return v1.ID == v2.ID -} - -// ExtensionCheckIDPrefix is a ExtensionCheckFunc for matching extension IDs by -// prefix. -func ExtensionCheckIDPrefix(s1, s2 *api.Extension) bool { - return strings.HasPrefix(s2.ID, s1.ID) -} - -// ExtensionCheckName is a ExtensionCheckFunc for matching extension names. -func ExtensionCheckName(v1, v2 *api.Extension) bool { - return v1.Annotations.Name == v2.Annotations.Name -} - -// ExtensionCheckNamePrefix is a ExtensionCheckFunc for matching extension -// names by prefix. -func ExtensionCheckNamePrefix(v1, v2 *api.Extension) bool { - return strings.HasPrefix(v2.Annotations.Name, v1.Annotations.Name) -} - -// ExtensionCheckCustom is a ExtensionCheckFunc for matching extension custom -// indices. -func ExtensionCheckCustom(v1, v2 *api.Extension) bool { - return checkCustom(v1.Annotations, v2.Annotations) -} - -// ExtensionCheckCustomPrefix is a ExtensionCheckFunc for matching extension -// custom indices by prefix. -func ExtensionCheckCustomPrefix(v1, v2 *api.Extension) bool { - return checkCustomPrefix(v1.Annotations, v2.Annotations) -} - // Watch takes a variable number of events to match against. The subscriber // will receive events that match any of the arguments passed to Watch. // diff --git a/manager/storeapi/watch.go b/manager/storeapi/watch.go index 919e866a4e..505a428e2c 100644 --- a/manager/storeapi/watch.go +++ b/manager/storeapi/watch.go @@ -26,52 +26,52 @@ func convertNodeWatch(action api.WatchActionKind, filters []*api.SelectBy) ([]ap return nil, errConflictingFilters } node.ID = v.ID - checkFuncs = append(checkFuncs, state.NodeCheckID) + checkFuncs = append(checkFuncs, api.NodeCheckID) case *api.SelectBy_IDPrefix: if node.ID != "" { return nil, errConflictingFilters } node.ID = v.IDPrefix - checkFuncs = append(checkFuncs, state.NodeCheckIDPrefix) + checkFuncs = append(checkFuncs, api.NodeCheckIDPrefix) case *api.SelectBy_Name: if node.Description != nil { return nil, errConflictingFilters } node.Description = &api.NodeDescription{Hostname: v.Name} - checkFuncs = append(checkFuncs, state.NodeCheckName) + checkFuncs = append(checkFuncs, api.NodeCheckName) case *api.SelectBy_NamePrefix: if node.Description != nil { return nil, errConflictingFilters } node.Description = &api.NodeDescription{Hostname: v.NamePrefix} - checkFuncs = append(checkFuncs, state.NodeCheckNamePrefix) + checkFuncs = append(checkFuncs, api.NodeCheckNamePrefix) case *api.SelectBy_Custom: // TODO(aaronl): Support multiple custom indices if len(node.Spec.Annotations.Indices) != 0 { return nil, errConflictingFilters } node.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} - checkFuncs = append(checkFuncs, state.NodeCheckCustom) + checkFuncs = append(checkFuncs, api.NodeCheckCustom) case *api.SelectBy_CustomPrefix: // TODO(aaronl): Support multiple custom indices if len(node.Spec.Annotations.Indices) != 0 { return nil, errConflictingFilters } node.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} - checkFuncs = append(checkFuncs, state.NodeCheckCustomPrefix) + checkFuncs = append(checkFuncs, api.NodeCheckCustomPrefix) case *api.SelectBy_Role: if hasRole { return nil, errConflictingFilters } node.Role = v.Role - checkFuncs = append(checkFuncs, state.NodeCheckRole) + checkFuncs = append(checkFuncs, api.NodeCheckRole) hasRole = true case *api.SelectBy_Membership: if hasMembership { return nil, errConflictingFilters } node.Spec.Membership = v.Membership - checkFuncs = append(checkFuncs, state.NodeCheckMembership) + checkFuncs = append(checkFuncs, api.NodeCheckMembership) hasMembership = true default: return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for nodes", filter.By) @@ -107,39 +107,39 @@ func convertServiceWatch(action api.WatchActionKind, filters []*api.SelectBy) ([ return nil, errConflictingFilters } service.ID = v.ID - checkFuncs = append(checkFuncs, state.ServiceCheckID) + checkFuncs = append(checkFuncs, api.ServiceCheckID) case *api.SelectBy_IDPrefix: if service.ID != "" { return nil, errConflictingFilters } service.ID = v.IDPrefix - checkFuncs = append(checkFuncs, state.ServiceCheckIDPrefix) + checkFuncs = append(checkFuncs, api.ServiceCheckIDPrefix) case *api.SelectBy_Name: if service.Spec.Annotations.Name != "" { return nil, errConflictingFilters } service.Spec.Annotations.Name = v.Name - checkFuncs = append(checkFuncs, state.ServiceCheckName) + checkFuncs = append(checkFuncs, api.ServiceCheckName) case *api.SelectBy_NamePrefix: if service.Spec.Annotations.Name != "" { return nil, errConflictingFilters } service.Spec.Annotations.Name = v.NamePrefix - checkFuncs = append(checkFuncs, state.ServiceCheckNamePrefix) + checkFuncs = append(checkFuncs, api.ServiceCheckNamePrefix) case *api.SelectBy_Custom: // TODO(aaronl): Support multiple custom indices if len(service.Spec.Annotations.Indices) != 0 { return nil, errConflictingFilters } service.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} - checkFuncs = append(checkFuncs, state.ServiceCheckCustom) + checkFuncs = append(checkFuncs, api.ServiceCheckCustom) case *api.SelectBy_CustomPrefix: // TODO(aaronl): Support multiple custom indices if len(service.Spec.Annotations.Indices) != 0 { return nil, errConflictingFilters } service.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} - checkFuncs = append(checkFuncs, state.ServiceCheckCustomPrefix) + checkFuncs = append(checkFuncs, api.ServiceCheckCustomPrefix) case *api.SelectBy_ReferencedNetworkID: // TODO(aaronl): not supported for now return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for services", filter.By) @@ -180,39 +180,39 @@ func convertNetworkWatch(action api.WatchActionKind, filters []*api.SelectBy) ([ return nil, errConflictingFilters } network.ID = v.ID - checkFuncs = append(checkFuncs, state.NetworkCheckID) + checkFuncs = append(checkFuncs, api.NetworkCheckID) case *api.SelectBy_IDPrefix: if network.ID != "" { return nil, errConflictingFilters } network.ID = v.IDPrefix - checkFuncs = append(checkFuncs, state.NetworkCheckIDPrefix) + checkFuncs = append(checkFuncs, api.NetworkCheckIDPrefix) case *api.SelectBy_Name: if network.Spec.Annotations.Name != "" { return nil, errConflictingFilters } network.Spec.Annotations.Name = v.Name - checkFuncs = append(checkFuncs, state.NetworkCheckName) + checkFuncs = append(checkFuncs, api.NetworkCheckName) case *api.SelectBy_NamePrefix: if network.Spec.Annotations.Name != "" { return nil, errConflictingFilters } network.Spec.Annotations.Name = v.NamePrefix - checkFuncs = append(checkFuncs, state.NetworkCheckNamePrefix) + checkFuncs = append(checkFuncs, api.NetworkCheckNamePrefix) case *api.SelectBy_Custom: // TODO(aaronl): Support multiple custom indices if len(network.Spec.Annotations.Indices) != 0 { return nil, errConflictingFilters } network.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} - checkFuncs = append(checkFuncs, state.NetworkCheckCustom) + checkFuncs = append(checkFuncs, api.NetworkCheckCustom) case *api.SelectBy_CustomPrefix: // TODO(aaronl): Support multiple custom indices if len(network.Spec.Annotations.Indices) != 0 { return nil, errConflictingFilters } network.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} - checkFuncs = append(checkFuncs, state.NetworkCheckCustomPrefix) + checkFuncs = append(checkFuncs, api.NetworkCheckCustomPrefix) default: return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for networks", filter.By) } @@ -247,39 +247,39 @@ func convertClusterWatch(action api.WatchActionKind, filters []*api.SelectBy) ([ return nil, errConflictingFilters } cluster.ID = v.ID - checkFuncs = append(checkFuncs, state.ClusterCheckID) + checkFuncs = append(checkFuncs, api.ClusterCheckID) case *api.SelectBy_IDPrefix: if cluster.ID != "" { return nil, errConflictingFilters } cluster.ID = v.IDPrefix - checkFuncs = append(checkFuncs, state.ClusterCheckIDPrefix) + checkFuncs = append(checkFuncs, api.ClusterCheckIDPrefix) case *api.SelectBy_Name: if cluster.Spec.Annotations.Name != "" { return nil, errConflictingFilters } cluster.Spec.Annotations.Name = v.Name - checkFuncs = append(checkFuncs, state.ClusterCheckName) + checkFuncs = append(checkFuncs, api.ClusterCheckName) case *api.SelectBy_NamePrefix: if cluster.Spec.Annotations.Name != "" { return nil, errConflictingFilters } cluster.Spec.Annotations.Name = v.NamePrefix - checkFuncs = append(checkFuncs, state.ClusterCheckNamePrefix) + checkFuncs = append(checkFuncs, api.ClusterCheckNamePrefix) case *api.SelectBy_Custom: // TODO(aaronl): Support multiple custom indices if len(cluster.Spec.Annotations.Indices) != 0 { return nil, errConflictingFilters } cluster.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} - checkFuncs = append(checkFuncs, state.ClusterCheckCustom) + checkFuncs = append(checkFuncs, api.ClusterCheckCustom) case *api.SelectBy_CustomPrefix: // TODO(aaronl): Support multiple custom indices if len(cluster.Spec.Annotations.Indices) != 0 { return nil, errConflictingFilters } cluster.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} - checkFuncs = append(checkFuncs, state.ClusterCheckCustomPrefix) + checkFuncs = append(checkFuncs, api.ClusterCheckCustomPrefix) default: return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for clusters", filter.By) } @@ -314,39 +314,39 @@ func convertSecretWatch(action api.WatchActionKind, filters []*api.SelectBy) ([] return nil, errConflictingFilters } secret.ID = v.ID - checkFuncs = append(checkFuncs, state.SecretCheckID) + checkFuncs = append(checkFuncs, api.SecretCheckID) case *api.SelectBy_IDPrefix: if secret.ID != "" { return nil, errConflictingFilters } secret.ID = v.IDPrefix - checkFuncs = append(checkFuncs, state.SecretCheckIDPrefix) + checkFuncs = append(checkFuncs, api.SecretCheckIDPrefix) case *api.SelectBy_Name: if secret.Spec.Annotations.Name != "" { return nil, errConflictingFilters } secret.Spec.Annotations.Name = v.Name - checkFuncs = append(checkFuncs, state.SecretCheckName) + checkFuncs = append(checkFuncs, api.SecretCheckName) case *api.SelectBy_NamePrefix: if secret.Spec.Annotations.Name != "" { return nil, errConflictingFilters } secret.Spec.Annotations.Name = v.NamePrefix - checkFuncs = append(checkFuncs, state.SecretCheckNamePrefix) + checkFuncs = append(checkFuncs, api.SecretCheckNamePrefix) case *api.SelectBy_Custom: // TODO(aaronl): Support multiple custom indices if len(secret.Spec.Annotations.Indices) != 0 { return nil, errConflictingFilters } secret.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} - checkFuncs = append(checkFuncs, state.SecretCheckCustom) + checkFuncs = append(checkFuncs, api.SecretCheckCustom) case *api.SelectBy_CustomPrefix: // TODO(aaronl): Support multiple custom indices if len(secret.Spec.Annotations.Indices) != 0 { return nil, errConflictingFilters } secret.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} - checkFuncs = append(checkFuncs, state.SecretCheckCustomPrefix) + checkFuncs = append(checkFuncs, api.SecretCheckCustomPrefix) default: return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for secrets", filter.By) } @@ -382,52 +382,52 @@ func convertTaskWatch(action api.WatchActionKind, filters []*api.SelectBy) ([]ap return nil, errConflictingFilters } task.ID = v.ID - checkFuncs = append(checkFuncs, state.TaskCheckID) + checkFuncs = append(checkFuncs, api.TaskCheckID) case *api.SelectBy_IDPrefix: if task.ID != "" { return nil, errConflictingFilters } task.ID = v.IDPrefix - checkFuncs = append(checkFuncs, state.TaskCheckIDPrefix) + checkFuncs = append(checkFuncs, api.TaskCheckIDPrefix) case *api.SelectBy_Custom: // TODO(aaronl): Support multiple custom indices if len(task.Annotations.Indices) != 0 { return nil, errConflictingFilters } task.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} - checkFuncs = append(checkFuncs, state.TaskCheckCustom) + checkFuncs = append(checkFuncs, api.TaskCheckCustom) case *api.SelectBy_CustomPrefix: // TODO(aaronl): Support multiple custom indices if len(task.Annotations.Indices) != 0 { return nil, errConflictingFilters } task.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} - checkFuncs = append(checkFuncs, state.TaskCheckCustomPrefix) + checkFuncs = append(checkFuncs, api.TaskCheckCustomPrefix) case *api.SelectBy_ServiceID: if task.ServiceID != "" { return nil, errConflictingFilters } task.ServiceID = v.ServiceID - checkFuncs = append(checkFuncs, state.TaskCheckServiceID) + checkFuncs = append(checkFuncs, api.TaskCheckServiceID) case *api.SelectBy_NodeID: if task.NodeID != "" { return nil, errConflictingFilters } task.NodeID = v.NodeID - checkFuncs = append(checkFuncs, state.TaskCheckNodeID) + checkFuncs = append(checkFuncs, api.TaskCheckNodeID) case *api.SelectBy_Slot: if task.Slot != 0 || task.ServiceID != "" { return nil, errConflictingFilters } task.ServiceID = v.Slot.ServiceID task.Slot = v.Slot.Slot - checkFuncs = append(checkFuncs, state.TaskCheckSlot, state.TaskCheckServiceID) + checkFuncs = append(checkFuncs, api.TaskCheckSlot, api.TaskCheckServiceID) case *api.SelectBy_DesiredState: if hasDesiredState { return nil, errConflictingFilters } task.DesiredState = v.DesiredState - checkFuncs = append(checkFuncs, state.TaskCheckDesiredState) + checkFuncs = append(checkFuncs, api.TaskCheckDesiredState) hasDesiredState = true default: return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for tasks", filter.By) @@ -463,39 +463,39 @@ func convertExtensionWatch(action api.WatchActionKind, filters []*api.SelectBy) return nil, errConflictingFilters } extension.ID = v.ID - checkFuncs = append(checkFuncs, state.ExtensionCheckID) + checkFuncs = append(checkFuncs, api.ExtensionCheckID) case *api.SelectBy_IDPrefix: if extension.ID != "" { return nil, errConflictingFilters } extension.ID = v.IDPrefix - checkFuncs = append(checkFuncs, state.ExtensionCheckIDPrefix) + checkFuncs = append(checkFuncs, api.ExtensionCheckIDPrefix) case *api.SelectBy_Name: if extension.Annotations.Name != "" { return nil, errConflictingFilters } extension.Annotations.Name = v.Name - checkFuncs = append(checkFuncs, state.ExtensionCheckName) + checkFuncs = append(checkFuncs, api.ExtensionCheckName) case *api.SelectBy_NamePrefix: if extension.Annotations.Name != "" { return nil, errConflictingFilters } extension.Annotations.Name = v.NamePrefix - checkFuncs = append(checkFuncs, state.ExtensionCheckNamePrefix) + checkFuncs = append(checkFuncs, api.ExtensionCheckNamePrefix) case *api.SelectBy_Custom: // TODO(aaronl): Support multiple custom indices if len(extension.Annotations.Indices) != 0 { return nil, errConflictingFilters } extension.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} - checkFuncs = append(checkFuncs, state.ExtensionCheckCustom) + checkFuncs = append(checkFuncs, api.ExtensionCheckCustom) case *api.SelectBy_CustomPrefix: // TODO(aaronl): Support multiple custom indices if len(extension.Annotations.Indices) != 0 { return nil, errConflictingFilters } extension.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} - checkFuncs = append(checkFuncs, state.ExtensionCheckCustomPrefix) + checkFuncs = append(checkFuncs, api.ExtensionCheckCustomPrefix) default: return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for extensions", filter.By) } @@ -519,7 +519,7 @@ func convertExtensionWatch(action api.WatchActionKind, filters []*api.SelectBy) func convertResourceWatch(action api.WatchActionKind, filters []*api.SelectBy, kind string) ([]api.Event, error) { resource := api.Resource{Kind: kind} - checkFuncs := []api.ResourceCheckFunc{state.ResourceCheckKind} + checkFuncs := []api.ResourceCheckFunc{api.ResourceCheckKind} for _, filter := range filters { switch v := filter.By.(type) { @@ -528,39 +528,39 @@ func convertResourceWatch(action api.WatchActionKind, filters []*api.SelectBy, k return nil, errConflictingFilters } resource.ID = v.ID - checkFuncs = append(checkFuncs, state.ResourceCheckID) + checkFuncs = append(checkFuncs, api.ResourceCheckID) case *api.SelectBy_IDPrefix: if resource.ID != "" { return nil, errConflictingFilters } resource.ID = v.IDPrefix - checkFuncs = append(checkFuncs, state.ResourceCheckIDPrefix) + checkFuncs = append(checkFuncs, api.ResourceCheckIDPrefix) case *api.SelectBy_Name: if resource.Annotations.Name != "" { return nil, errConflictingFilters } resource.Annotations.Name = v.Name - checkFuncs = append(checkFuncs, state.ResourceCheckName) + checkFuncs = append(checkFuncs, api.ResourceCheckName) case *api.SelectBy_NamePrefix: if resource.Annotations.Name != "" { return nil, errConflictingFilters } resource.Annotations.Name = v.NamePrefix - checkFuncs = append(checkFuncs, state.ResourceCheckNamePrefix) + checkFuncs = append(checkFuncs, api.ResourceCheckNamePrefix) case *api.SelectBy_Custom: // TODO(aaronl): Support multiple custom indices if len(resource.Annotations.Indices) != 0 { return nil, errConflictingFilters } resource.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} - checkFuncs = append(checkFuncs, state.ResourceCheckCustom) + checkFuncs = append(checkFuncs, api.ResourceCheckCustom) case *api.SelectBy_CustomPrefix: // TODO(aaronl): Support multiple custom indices if len(resource.Annotations.Indices) != 0 { return nil, errConflictingFilters } resource.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} - checkFuncs = append(checkFuncs, state.ResourceCheckCustomPrefix) + checkFuncs = append(checkFuncs, api.ResourceCheckCustomPrefix) default: return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for resource objects", filter.By) } diff --git a/protobuf/plugin/plugin.pb.go b/protobuf/plugin/plugin.pb.go index 9d89cd5cd0..6a021f42e9 100644 --- a/protobuf/plugin/plugin.pb.go +++ b/protobuf/plugin/plugin.pb.go @@ -9,6 +9,7 @@ plugin.proto It has these top-level messages: + WatchSelectors StoreObject TLSAuthorization */ @@ -19,6 +20,8 @@ import fmt "fmt" import math "math" import google_protobuf "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" +import github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto" + import strings "strings" import reflect "reflect" @@ -35,13 +38,39 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package -type StoreObject struct { +type WatchSelectors struct { + // supported by all object types + ID *bool `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` + IDPrefix *bool `protobuf:"varint,2,opt,name=id_prefix,json=idPrefix" json:"id_prefix,omitempty"` + Name *bool `protobuf:"varint,3,opt,name=name" json:"name,omitempty"` + NamePrefix *bool `protobuf:"varint,4,opt,name=name_prefix,json=namePrefix" json:"name_prefix,omitempty"` + Custom *bool `protobuf:"varint,5,opt,name=custom" json:"custom,omitempty"` + CustomPrefix *bool `protobuf:"varint,6,opt,name=custom_prefix,json=customPrefix" json:"custom_prefix,omitempty"` + // supported by tasks only + ServiceID *bool `protobuf:"varint,7,opt,name=service_id,json=serviceId" json:"service_id,omitempty"` + NodeID *bool `protobuf:"varint,8,opt,name=node_id,json=nodeId" json:"node_id,omitempty"` + Slot *bool `protobuf:"varint,9,opt,name=slot" json:"slot,omitempty"` + DesiredState *bool `protobuf:"varint,10,opt,name=desired_state,json=desiredState" json:"desired_state,omitempty"` + // supported by nodes only + Role *bool `protobuf:"varint,11,opt,name=role" json:"role,omitempty"` + Membership *bool `protobuf:"varint,12,opt,name=membership" json:"membership,omitempty"` + // supported by: resource + Kind *bool `protobuf:"varint,13,opt,name=kind" json:"kind,omitempty"` XXX_unrecognized []byte `json:"-"` } +func (m *WatchSelectors) Reset() { *m = WatchSelectors{} } +func (*WatchSelectors) ProtoMessage() {} +func (*WatchSelectors) Descriptor() ([]byte, []int) { return fileDescriptorPlugin, []int{0} } + +type StoreObject struct { + WatchSelectors *WatchSelectors `protobuf:"bytes,1,req,name=watch_selectors,json=watchSelectors" json:"watch_selectors,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + func (m *StoreObject) Reset() { *m = StoreObject{} } func (*StoreObject) ProtoMessage() {} -func (*StoreObject) Descriptor() ([]byte, []int) { return fileDescriptorPlugin, []int{0} } +func (*StoreObject) Descriptor() ([]byte, []int) { return fileDescriptorPlugin, []int{1} } type TLSAuthorization struct { // Roles contains the acceptable TLS OU roles for the handler. @@ -55,7 +84,7 @@ type TLSAuthorization struct { func (m *TLSAuthorization) Reset() { *m = TLSAuthorization{} } func (*TLSAuthorization) ProtoMessage() {} -func (*TLSAuthorization) Descriptor() ([]byte, []int) { return fileDescriptorPlugin, []int{1} } +func (*TLSAuthorization) Descriptor() ([]byte, []int) { return fileDescriptorPlugin, []int{2} } var E_Deepcopy = &proto.ExtensionDesc{ ExtendedType: (*google_protobuf.MessageOptions)(nil), @@ -82,12 +111,164 @@ var E_TlsAuthorization = &proto.ExtensionDesc{ } func init() { + proto.RegisterType((*WatchSelectors)(nil), "docker.protobuf.plugin.WatchSelectors") proto.RegisterType((*StoreObject)(nil), "docker.protobuf.plugin.StoreObject") proto.RegisterType((*TLSAuthorization)(nil), "docker.protobuf.plugin.TLSAuthorization") proto.RegisterExtension(E_Deepcopy) proto.RegisterExtension(E_StoreObject) proto.RegisterExtension(E_TlsAuthorization) } +func (m *WatchSelectors) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *WatchSelectors) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.ID != nil { + dAtA[i] = 0x8 + i++ + if *m.ID { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + if m.IDPrefix != nil { + dAtA[i] = 0x10 + i++ + if *m.IDPrefix { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + if m.Name != nil { + dAtA[i] = 0x18 + i++ + if *m.Name { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + if m.NamePrefix != nil { + dAtA[i] = 0x20 + i++ + if *m.NamePrefix { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + if m.Custom != nil { + dAtA[i] = 0x28 + i++ + if *m.Custom { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + if m.CustomPrefix != nil { + dAtA[i] = 0x30 + i++ + if *m.CustomPrefix { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + if m.ServiceID != nil { + dAtA[i] = 0x38 + i++ + if *m.ServiceID { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + if m.NodeID != nil { + dAtA[i] = 0x40 + i++ + if *m.NodeID { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + if m.Slot != nil { + dAtA[i] = 0x48 + i++ + if *m.Slot { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + if m.DesiredState != nil { + dAtA[i] = 0x50 + i++ + if *m.DesiredState { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + if m.Role != nil { + dAtA[i] = 0x58 + i++ + if *m.Role { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + if m.Membership != nil { + dAtA[i] = 0x60 + i++ + if *m.Membership { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + if m.Kind != nil { + dAtA[i] = 0x68 + i++ + if *m.Kind { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + func (m *StoreObject) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -103,6 +284,18 @@ func (m *StoreObject) MarshalTo(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.WatchSelectors == nil { + return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("watch_selectors") + } else { + dAtA[i] = 0xa + i++ + i = encodeVarintPlugin(dAtA, i, uint64(m.WatchSelectors.Size())) + n1, err := m.WatchSelectors.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n1 + } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } @@ -182,9 +375,61 @@ func encodeVarintPlugin(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return offset + 1 } +func (m *WatchSelectors) Size() (n int) { + var l int + _ = l + if m.ID != nil { + n += 2 + } + if m.IDPrefix != nil { + n += 2 + } + if m.Name != nil { + n += 2 + } + if m.NamePrefix != nil { + n += 2 + } + if m.Custom != nil { + n += 2 + } + if m.CustomPrefix != nil { + n += 2 + } + if m.ServiceID != nil { + n += 2 + } + if m.NodeID != nil { + n += 2 + } + if m.Slot != nil { + n += 2 + } + if m.DesiredState != nil { + n += 2 + } + if m.Role != nil { + n += 2 + } + if m.Membership != nil { + n += 2 + } + if m.Kind != nil { + n += 2 + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func (m *StoreObject) Size() (n int) { var l int _ = l + if m.WatchSelectors != nil { + l = m.WatchSelectors.Size() + n += 1 + l + sovPlugin(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -222,11 +467,35 @@ func sovPlugin(x uint64) (n int) { func sozPlugin(x uint64) (n int) { return sovPlugin(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } +func (this *WatchSelectors) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&WatchSelectors{`, + `ID:` + valueToStringPlugin(this.ID) + `,`, + `IDPrefix:` + valueToStringPlugin(this.IDPrefix) + `,`, + `Name:` + valueToStringPlugin(this.Name) + `,`, + `NamePrefix:` + valueToStringPlugin(this.NamePrefix) + `,`, + `Custom:` + valueToStringPlugin(this.Custom) + `,`, + `CustomPrefix:` + valueToStringPlugin(this.CustomPrefix) + `,`, + `ServiceID:` + valueToStringPlugin(this.ServiceID) + `,`, + `NodeID:` + valueToStringPlugin(this.NodeID) + `,`, + `Slot:` + valueToStringPlugin(this.Slot) + `,`, + `DesiredState:` + valueToStringPlugin(this.DesiredState) + `,`, + `Role:` + valueToStringPlugin(this.Role) + `,`, + `Membership:` + valueToStringPlugin(this.Membership) + `,`, + `Kind:` + valueToStringPlugin(this.Kind) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} func (this *StoreObject) String() string { if this == nil { return "nil" } s := strings.Join([]string{`&StoreObject{`, + `WatchSelectors:` + strings.Replace(fmt.Sprintf("%v", this.WatchSelectors), "WatchSelectors", "WatchSelectors", 1) + `,`, `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") @@ -252,7 +521,332 @@ func valueToStringPlugin(v interface{}) string { pv := reflect.Indirect(rv).Interface() return fmt.Sprintf("*%v", pv) } +func (m *WatchSelectors) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: WatchSelectors: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: WatchSelectors: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.ID = &b + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IDPrefix", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.IDPrefix = &b + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.Name = &b + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NamePrefix", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.NamePrefix = &b + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Custom", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.Custom = &b + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CustomPrefix", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.CustomPrefix = &b + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ServiceID", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.ServiceID = &b + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NodeID", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.NodeID = &b + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Slot", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.Slot = &b + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DesiredState", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.DesiredState = &b + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Role", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.Role = &b + case 12: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Membership", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.Membership = &b + case 13: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Kind", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.Kind = &b + default: + iNdEx = preIndex + skippy, err := skipPlugin(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthPlugin + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *StoreObject) Unmarshal(dAtA []byte) error { + var hasFields [1]uint64 l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -281,6 +875,40 @@ func (m *StoreObject) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: StoreObject: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WatchSelectors", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPlugin + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.WatchSelectors == nil { + m.WatchSelectors = &WatchSelectors{} + } + if err := m.WatchSelectors.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + hasFields[0] |= uint64(0x00000001) default: iNdEx = preIndex skippy, err := skipPlugin(dAtA[iNdEx:]) @@ -297,6 +925,9 @@ func (m *StoreObject) Unmarshal(dAtA []byte) error { iNdEx += skippy } } + if hasFields[0]&uint64(0x00000001) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("watch_selectors") + } if iNdEx > l { return io.ErrUnexpectedEOF @@ -512,24 +1143,40 @@ var ( func init() { proto.RegisterFile("plugin.proto", fileDescriptorPlugin) } var fileDescriptorPlugin = []byte{ - // 296 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x29, 0xc8, 0x29, 0x4d, - 0xcf, 0xcc, 0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x4b, 0xc9, 0x4f, 0xce, 0x4e, 0x2d, - 0x82, 0xf0, 0x92, 0x4a, 0xd3, 0xf4, 0x20, 0xb2, 0x52, 0x0a, 0xe9, 0xf9, 0xf9, 0xe9, 0x39, 0xa9, - 0xfa, 0x30, 0x71, 0xfd, 0x94, 0xd4, 0xe2, 0xe4, 0xa2, 0xcc, 0x82, 0x92, 0x7c, 0xa8, 0x5a, 0x25, - 0x5e, 0x2e, 0xee, 0xe0, 0x92, 0xfc, 0xa2, 0x54, 0xff, 0xa4, 0xac, 0xd4, 0xe4, 0x12, 0x25, 0x17, - 0x2e, 0x81, 0x10, 0x9f, 0x60, 0xc7, 0xd2, 0x92, 0x8c, 0xfc, 0xa2, 0xcc, 0xaa, 0xc4, 0x92, 0xcc, - 0xfc, 0x3c, 0x21, 0x11, 0x2e, 0xd6, 0xa2, 0xfc, 0x9c, 0xd4, 0x62, 0x09, 0x46, 0x05, 0x66, 0x0d, - 0xce, 0x20, 0x08, 0x47, 0x48, 0x8a, 0x8b, 0x23, 0x33, 0xaf, 0x38, 0x35, 0xb9, 0xb4, 0x28, 0x55, - 0x82, 0x49, 0x81, 0x51, 0x83, 0x23, 0x08, 0xce, 0xb7, 0x72, 0xe6, 0xe2, 0x48, 0x49, 0x4d, 0x2d, - 0x48, 0xce, 0x2f, 0xa8, 0x14, 0x92, 0xd7, 0x83, 0xb8, 0x01, 0xe1, 0x36, 0xdf, 0xd4, 0xe2, 0xe2, - 0xc4, 0xf4, 0x54, 0xff, 0x02, 0x90, 0xe9, 0xc5, 0x12, 0x1f, 0x16, 0xb1, 0x80, 0xb4, 0x5b, 0xb1, - 0x94, 0x14, 0x95, 0xa6, 0x06, 0xc1, 0x35, 0x5a, 0x65, 0x72, 0xf1, 0x14, 0x83, 0x5c, 0x16, 0x9f, - 0x0f, 0x76, 0x1a, 0x61, 0x83, 0x3e, 0x82, 0x0d, 0xe2, 0x36, 0x52, 0xd6, 0xc3, 0x1e, 0x1a, 0x7a, - 0x48, 0x1e, 0x0d, 0xe2, 0x2e, 0x46, 0x70, 0xac, 0x2a, 0xb8, 0x04, 0x4b, 0x72, 0x8a, 0xe3, 0x13, - 0x51, 0xbc, 0x2d, 0x87, 0xc5, 0xbe, 0x92, 0x8c, 0xfc, 0x14, 0x98, 0x75, 0x2f, 0x9f, 0xf6, 0x2a, - 0x83, 0xed, 0xd3, 0xc0, 0x65, 0x1f, 0x7a, 0x48, 0x06, 0x09, 0x94, 0xe4, 0x14, 0xa3, 0x88, 0x38, - 0x49, 0x9c, 0x78, 0x28, 0xc7, 0x70, 0xe3, 0xa1, 0x1c, 0x43, 0xc3, 0x23, 0x39, 0xc6, 0x13, 0x8f, - 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x11, 0x10, 0x00, 0x00, 0xff, 0xff, - 0xc2, 0x49, 0xd6, 0x3b, 0xe1, 0x01, 0x00, 0x00, + // 551 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x52, 0xc1, 0x6e, 0xd3, 0x40, + 0x10, 0xad, 0xd3, 0x36, 0x4d, 0xc6, 0x69, 0x29, 0x2b, 0x54, 0xad, 0x7a, 0xb0, 0xab, 0x46, 0x42, + 0x41, 0x42, 0xa9, 0xd4, 0x63, 0x6e, 0x94, 0x5c, 0x22, 0x01, 0x45, 0x0e, 0x12, 0x37, 0x2c, 0xd7, + 0x3b, 0x4d, 0x96, 0x3a, 0x5e, 0x6b, 0x77, 0x4d, 0x0b, 0x27, 0x7e, 0x80, 0x0f, 0xe0, 0xca, 0xd7, + 0xf4, 0xc8, 0x91, 0x53, 0x44, 0x2d, 0x71, 0xe0, 0x06, 0x7f, 0x80, 0x76, 0xd7, 0x69, 0x09, 0x6a, + 0xc5, 0xc9, 0x33, 0x6f, 0xe6, 0xcd, 0xcc, 0xdb, 0x67, 0xe8, 0x14, 0x59, 0x39, 0xe1, 0x79, 0xbf, + 0x90, 0x42, 0x0b, 0xb2, 0xc3, 0x44, 0x7a, 0x86, 0xd2, 0x65, 0x27, 0xe5, 0x69, 0xdf, 0x55, 0x77, + 0xf7, 0x26, 0x42, 0x4c, 0x32, 0x3c, 0x58, 0xe0, 0x07, 0x0c, 0x55, 0x2a, 0x79, 0xa1, 0x45, 0xdd, + 0xbb, 0xff, 0x79, 0x15, 0xb6, 0x5e, 0x27, 0x3a, 0x9d, 0x8e, 0x31, 0xc3, 0x54, 0x0b, 0xa9, 0xc8, + 0x0e, 0x34, 0x38, 0xa3, 0xde, 0x9e, 0xd7, 0x6b, 0x1d, 0x35, 0xab, 0x79, 0xd8, 0x18, 0x0d, 0xa3, + 0x06, 0x67, 0xe4, 0x11, 0xb4, 0x39, 0x8b, 0x0b, 0x89, 0xa7, 0xfc, 0x82, 0x36, 0x6c, 0xb9, 0x53, + 0xcd, 0xc3, 0xd6, 0x68, 0xf8, 0xd2, 0x62, 0x51, 0x8b, 0x33, 0x17, 0x11, 0x02, 0x6b, 0x79, 0x32, + 0x43, 0xba, 0x6a, 0xba, 0x22, 0x1b, 0x93, 0x10, 0x7c, 0xf3, 0x5d, 0x0c, 0x58, 0xb3, 0x25, 0x30, + 0x50, 0x4d, 0xda, 0x81, 0x66, 0x5a, 0x2a, 0x2d, 0x66, 0x74, 0xdd, 0xd6, 0xea, 0x8c, 0x74, 0x61, + 0xd3, 0x45, 0x0b, 0x6a, 0xd3, 0x96, 0x3b, 0x0e, 0xac, 0xc9, 0x8f, 0x01, 0x14, 0xca, 0x77, 0x3c, + 0xc5, 0x98, 0x33, 0xba, 0x61, 0xaf, 0xdb, 0xac, 0xe6, 0x61, 0x7b, 0xec, 0xd0, 0xd1, 0x30, 0x6a, + 0xd7, 0x0d, 0x23, 0x46, 0xba, 0xb0, 0x91, 0x0b, 0x66, 0x5b, 0x5b, 0xb6, 0x15, 0xaa, 0x79, 0xd8, + 0x7c, 0x21, 0x98, 0xe9, 0x6b, 0x9a, 0xd2, 0x88, 0x19, 0x11, 0x2a, 0x13, 0x9a, 0xb6, 0x9d, 0x08, + 0x13, 0x9b, 0x5b, 0x18, 0x2a, 0x2e, 0x91, 0xc5, 0x4a, 0x27, 0x1a, 0x29, 0xb8, 0x5b, 0x6a, 0x70, + 0x6c, 0x30, 0x43, 0x94, 0x22, 0x43, 0xea, 0x3b, 0xa2, 0x89, 0x49, 0x00, 0x30, 0xc3, 0xd9, 0x09, + 0x4a, 0x35, 0xe5, 0x05, 0xed, 0x38, 0xf1, 0x37, 0x88, 0xe1, 0x9c, 0xf1, 0x9c, 0xd1, 0x4d, 0xc7, + 0x31, 0xf1, 0xfe, 0x1b, 0xf0, 0xc7, 0x5a, 0x48, 0x3c, 0x3e, 0x79, 0x8b, 0xa9, 0x26, 0xc7, 0x70, + 0xef, 0xdc, 0x38, 0x15, 0xab, 0x85, 0x55, 0xd4, 0xdb, 0x6b, 0xf4, 0xfc, 0xc3, 0x87, 0xfd, 0xdb, + 0xed, 0xef, 0x2f, 0x1b, 0x1b, 0x6d, 0x9d, 0x2f, 0xe5, 0xfb, 0x43, 0xd8, 0x7e, 0xf5, 0x6c, 0xfc, + 0xa4, 0xd4, 0x53, 0x21, 0xf9, 0x87, 0x44, 0x73, 0x91, 0x93, 0x07, 0xb0, 0x6e, 0xee, 0x35, 0xa3, + 0x57, 0x7b, 0xed, 0xc8, 0x25, 0x64, 0x17, 0x5a, 0x3c, 0x57, 0x98, 0x96, 0x12, 0x9d, 0xf3, 0xd1, + 0x75, 0x3e, 0x78, 0x0a, 0x2d, 0x86, 0x58, 0xa4, 0xa2, 0x78, 0x4f, 0xc2, 0xbe, 0xfb, 0xe1, 0x6e, + 0x2e, 0x79, 0x8e, 0x4a, 0x25, 0x13, 0x3c, 0x2e, 0xcc, 0x74, 0x45, 0x7f, 0x7d, 0xb1, 0xbe, 0x0f, + 0xd6, 0xb4, 0x2c, 0x31, 0xba, 0x26, 0x0e, 0x38, 0x74, 0x94, 0x91, 0x1a, 0x0b, 0xa7, 0xf5, 0xbf, + 0x83, 0x7e, 0xdb, 0x41, 0xfe, 0x61, 0xf7, 0x2e, 0xed, 0x7f, 0xbd, 0x5c, 0xe4, 0xab, 0x9b, 0x64, + 0x70, 0x01, 0xf7, 0x75, 0xa6, 0xe2, 0x64, 0x49, 0x76, 0x70, 0xcb, 0x3e, 0x3d, 0x15, 0x6c, 0xb1, + 0xee, 0xe7, 0x8f, 0x4f, 0x5d, 0xbb, 0xaf, 0x77, 0xd7, 0xbe, 0x7f, 0x5f, 0x32, 0xda, 0xd6, 0x99, + 0x5a, 0x42, 0x8e, 0xe8, 0xe5, 0x55, 0xb0, 0xf2, 0xed, 0x2a, 0x58, 0xf9, 0x58, 0x05, 0xde, 0x65, + 0x15, 0x78, 0x5f, 0xab, 0xc0, 0xfb, 0x5e, 0x05, 0xde, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x94, + 0xd6, 0x21, 0x73, 0xce, 0x03, 0x00, 0x00, } diff --git a/protobuf/plugin/plugin.proto b/protobuf/plugin/plugin.proto index aa29c23965..312517d718 100644 --- a/protobuf/plugin/plugin.proto +++ b/protobuf/plugin/plugin.proto @@ -4,7 +4,31 @@ package docker.protobuf.plugin; import "google/protobuf/descriptor.proto"; +message WatchSelectors { + // supported by all object types + optional bool id = 1; + optional bool id_prefix = 2; + optional bool name = 3; + optional bool name_prefix = 4; + optional bool custom = 5; + optional bool custom_prefix = 6; + + // supported by tasks only + optional bool service_id = 7; + optional bool node_id = 8; + optional bool slot = 9; + optional bool desired_state = 10; + + // supported by nodes only + optional bool role = 11; + optional bool membership = 12; + + // supported by: resource + optional bool kind = 13; +} + message StoreObject { + required WatchSelectors watch_selectors = 1; } extend google.protobuf.MessageOptions { diff --git a/protobuf/plugin/storeobject/storeobject.go b/protobuf/plugin/storeobject/storeobject.go index fdb84f379e..a1c09b4bc4 100644 --- a/protobuf/plugin/storeobject/storeobject.go +++ b/protobuf/plugin/storeobject/storeobject.go @@ -134,6 +134,159 @@ func (d *storeObjectGen) genMsgStoreObject(m *generator.Descriptor, storeObject d.P("}") d.P() + // Generate event check functions + + if storeObject.WatchSelectors.ID != nil && *storeObject.WatchSelectors.ID { + d.P("func ", ccTypeName, "CheckID(v1, v2 *", ccTypeName, ") bool {") + d.In() + d.P("return v1.ID == v2.ID") + d.Out() + d.P("}") + d.P() + } + + if storeObject.WatchSelectors.IDPrefix != nil && *storeObject.WatchSelectors.IDPrefix { + d.P("func ", ccTypeName, "CheckIDPrefix(v1, v2 *", ccTypeName, ") bool {") + d.In() + d.P("return ", d.stringsPkg.Use(), ".HasPrefix(v2.ID, v1.ID)") + d.Out() + d.P("}") + d.P() + } + + if storeObject.WatchSelectors.Name != nil && *storeObject.WatchSelectors.Name { + d.P("func ", ccTypeName, "CheckName(v1, v2 *", ccTypeName, ") bool {") + d.In() + // Node is a special case + if *m.Name == "Node" { + d.P("if v1.Description == nil || v2.Description == nil {") + d.In() + d.P("return false") + d.Out() + d.P("}") + d.P("return v1.Description.Hostname == v2.Description.Hostname") + } else if _, hasNoSpec := typesWithNoSpec[*m.Name]; hasNoSpec { + d.P("return v1.Annotations.Name == v2.Annotations.Name") + } else { + d.P("return v1.Spec.Annotations.Name == v2.Spec.Annotations.Name") + } + d.Out() + d.P("}") + d.P() + } + + if storeObject.WatchSelectors.NamePrefix != nil && *storeObject.WatchSelectors.NamePrefix { + d.P("func ", ccTypeName, "CheckNamePrefix(v1, v2 *", ccTypeName, ") bool {") + d.In() + // Node is a special case + if *m.Name == "Node" { + d.P("if v1.Description == nil || v2.Description == nil {") + d.In() + d.P("return false") + d.Out() + d.P("}") + d.P("return ", d.stringsPkg.Use(), ".HasPrefix(v2.Description.Hostname, v1.Description.Hostname)") + } else if _, hasNoSpec := typesWithNoSpec[*m.Name]; hasNoSpec { + d.P("return ", d.stringsPkg.Use(), ".HasPrefix(v2.Annotations.Name, v1.Annotations.Name)") + } else { + d.P("return ", d.stringsPkg.Use(), ".HasPrefix(v2.Spec.Annotations.Name, v1.Spec.Annotations.Name)") + } + d.Out() + d.P("}") + d.P() + } + + if storeObject.WatchSelectors.Custom != nil && *storeObject.WatchSelectors.Custom { + d.P("func ", ccTypeName, "CheckCustom(v1, v2 *", ccTypeName, ") bool {") + d.In() + // Node is a special case + if _, hasNoSpec := typesWithNoSpec[*m.Name]; hasNoSpec { + d.P("return checkCustom(v1.Annotations, v2.Annotations)") + } else { + d.P("return checkCustom(v1.Spec.Annotations, v2.Spec.Annotations)") + } + d.Out() + d.P("}") + d.P() + } + + if storeObject.WatchSelectors.CustomPrefix != nil && *storeObject.WatchSelectors.CustomPrefix { + d.P("func ", ccTypeName, "CheckCustomPrefix(v1, v2 *", ccTypeName, ") bool {") + d.In() + // Node is a special case + if _, hasNoSpec := typesWithNoSpec[*m.Name]; hasNoSpec { + d.P("return checkCustomPrefix(v1.Annotations, v2.Annotations)") + } else { + d.P("return checkCustomPrefix(v1.Spec.Annotations, v2.Spec.Annotations)") + } + d.Out() + d.P("}") + d.P() + } + + if storeObject.WatchSelectors.NodeID != nil && *storeObject.WatchSelectors.NodeID { + d.P("func ", ccTypeName, "CheckNodeID(v1, v2 *", ccTypeName, ") bool {") + d.In() + d.P("return v1.NodeID == v2.NodeID") + d.Out() + d.P("}") + d.P() + } + + if storeObject.WatchSelectors.ServiceID != nil && *storeObject.WatchSelectors.ServiceID { + d.P("func ", ccTypeName, "CheckServiceID(v1, v2 *", ccTypeName, ") bool {") + d.In() + d.P("return v1.ServiceID == v2.ServiceID") + d.Out() + d.P("}") + d.P() + } + + if storeObject.WatchSelectors.Slot != nil && *storeObject.WatchSelectors.Slot { + d.P("func ", ccTypeName, "CheckSlot(v1, v2 *", ccTypeName, ") bool {") + d.In() + d.P("return v1.Slot == v2.Slot") + d.Out() + d.P("}") + d.P() + } + + if storeObject.WatchSelectors.DesiredState != nil && *storeObject.WatchSelectors.DesiredState { + d.P("func ", ccTypeName, "CheckDesiredState(v1, v2 *", ccTypeName, ") bool {") + d.In() + d.P("return v1.DesiredState == v2.DesiredState") + d.Out() + d.P("}") + d.P() + } + + if storeObject.WatchSelectors.Role != nil && *storeObject.WatchSelectors.Role { + d.P("func ", ccTypeName, "CheckRole(v1, v2 *", ccTypeName, ") bool {") + d.In() + d.P("return v1.Role == v2.Role") + d.Out() + d.P("}") + d.P() + } + + if storeObject.WatchSelectors.Membership != nil && *storeObject.WatchSelectors.Membership { + d.P("func ", ccTypeName, "CheckMembership(v1, v2 *", ccTypeName, ") bool {") + d.In() + d.P("return v1.Spec.Membership == v2.Spec.Membership") + d.Out() + d.P("}") + d.P() + } + + if storeObject.WatchSelectors.Kind != nil && *storeObject.WatchSelectors.Kind { + d.P("func ", ccTypeName, "CheckKind(v1, v2 *", ccTypeName, ") bool {") + d.In() + d.P("return v1.Kind == v2.Kind") + d.Out() + d.P("}") + d.P() + } + // Generate indexer by ID d.P("type ", ccTypeName, "IndexerByID struct{}") From 9472ac4309b7f08d7136e75fa7c75d812574016c Mon Sep 17 00:00:00 2001 From: Aaron Lehmann Date: Fri, 17 Mar 2017 17:53:11 -0700 Subject: [PATCH 7/7] Code-generate the other type-specific parts of watch API implementation Signed-off-by: Aaron Lehmann --- api/objects.pb.go | 574 +++++++++++++++++++ api/storeobject.go | 7 +- manager/storeapi/watch.go | 614 +-------------------- protobuf/plugin/storeobject/storeobject.go | 335 ++++++++++- 4 files changed, 902 insertions(+), 628 deletions(-) diff --git a/api/objects.pb.go b/api/objects.pb.go index 48cadf4a34..d38c383e6e 100644 --- a/api/objects.pb.go +++ b/api/objects.pb.go @@ -1966,6 +1966,84 @@ func NodeCheckMembership(v1, v2 *Node) bool { return v1.Spec.Membership == v2.Spec.Membership } +func ConvertNodeWatch(action WatchActionKind, filters []*SelectBy) ([]Event, error) { + var ( + m Node + checkFuncs []NodeCheckFunc + hasRole bool + hasMembership bool + ) + + for _, filter := range filters { + switch v := filter.By.(type) { + case *SelectBy_ID: + if m.ID != "" { + return nil, errConflictingFilters + } + m.ID = v.ID + checkFuncs = append(checkFuncs, NodeCheckID) + case *SelectBy_IDPrefix: + if m.ID != "" { + return nil, errConflictingFilters + } + m.ID = v.IDPrefix + checkFuncs = append(checkFuncs, NodeCheckIDPrefix) + case *SelectBy_Name: + if m.Description != nil { + return nil, errConflictingFilters + } + m.Description = &NodeDescription{Hostname: v.Name} + checkFuncs = append(checkFuncs, NodeCheckName) + case *SelectBy_NamePrefix: + if m.Description != nil { + return nil, errConflictingFilters + } + m.Description = &NodeDescription{Hostname: v.NamePrefix} + checkFuncs = append(checkFuncs, NodeCheckNamePrefix) + case *SelectBy_Custom: + if len(m.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + m.Spec.Annotations.Indices = []IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} + checkFuncs = append(checkFuncs, NodeCheckCustom) + case *SelectBy_CustomPrefix: + if len(m.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + m.Spec.Annotations.Indices = []IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} + checkFuncs = append(checkFuncs, NodeCheckCustomPrefix) + case *SelectBy_Role: + if hasRole { + return nil, errConflictingFilters + } + hasRole = true + m.Role = v.Role + checkFuncs = append(checkFuncs, NodeCheckRole) + case *SelectBy_Membership: + if hasMembership { + return nil, errConflictingFilters + } + hasMembership = true + m.Spec.Membership = v.Membership + checkFuncs = append(checkFuncs, NodeCheckMembership) + } + } + var events []Event + if (action & WatchActionKindCreate) != 0 { + events = append(events, EventCreateNode{Node: &m, Checks: checkFuncs}) + } + if (action & WatchActionKindUpdate) != 0 { + events = append(events, EventUpdateNode{Node: &m, Checks: checkFuncs}) + } + if (action & WatchActionKindRemove) != 0 { + events = append(events, EventDeleteNode{Node: &m, Checks: checkFuncs}) + } + if len(events) == 0 { + return nil, errUnrecognizedAction + } + return events, nil +} + type NodeIndexerByID struct{} func (indexer NodeIndexerByID) FromArgs(args ...interface{}) ([]byte, error) { @@ -2121,6 +2199,68 @@ func ServiceCheckCustomPrefix(v1, v2 *Service) bool { return checkCustomPrefix(v1.Spec.Annotations, v2.Spec.Annotations) } +func ConvertServiceWatch(action WatchActionKind, filters []*SelectBy) ([]Event, error) { + var ( + m Service + checkFuncs []ServiceCheckFunc + ) + + for _, filter := range filters { + switch v := filter.By.(type) { + case *SelectBy_ID: + if m.ID != "" { + return nil, errConflictingFilters + } + m.ID = v.ID + checkFuncs = append(checkFuncs, ServiceCheckID) + case *SelectBy_IDPrefix: + if m.ID != "" { + return nil, errConflictingFilters + } + m.ID = v.IDPrefix + checkFuncs = append(checkFuncs, ServiceCheckIDPrefix) + case *SelectBy_Name: + if m.Spec.Annotations.Name != "" { + return nil, errConflictingFilters + } + m.Spec.Annotations.Name = v.Name + checkFuncs = append(checkFuncs, ServiceCheckName) + case *SelectBy_NamePrefix: + if m.Spec.Annotations.Name != "" { + return nil, errConflictingFilters + } + m.Spec.Annotations.Name = v.NamePrefix + checkFuncs = append(checkFuncs, ServiceCheckNamePrefix) + case *SelectBy_Custom: + if len(m.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + m.Spec.Annotations.Indices = []IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} + checkFuncs = append(checkFuncs, ServiceCheckCustom) + case *SelectBy_CustomPrefix: + if len(m.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + m.Spec.Annotations.Indices = []IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} + checkFuncs = append(checkFuncs, ServiceCheckCustomPrefix) + } + } + var events []Event + if (action & WatchActionKindCreate) != 0 { + events = append(events, EventCreateService{Service: &m, Checks: checkFuncs}) + } + if (action & WatchActionKindUpdate) != 0 { + events = append(events, EventUpdateService{Service: &m, Checks: checkFuncs}) + } + if (action & WatchActionKindRemove) != 0 { + events = append(events, EventDeleteService{Service: &m, Checks: checkFuncs}) + } + if len(events) == 0 { + return nil, errUnrecognizedAction + } + return events, nil +} + type ServiceIndexerByID struct{} func (indexer ServiceIndexerByID) FromArgs(args ...interface{}) ([]byte, error) { @@ -2292,6 +2432,95 @@ func TaskCheckDesiredState(v1, v2 *Task) bool { return v1.DesiredState == v2.DesiredState } +func ConvertTaskWatch(action WatchActionKind, filters []*SelectBy) ([]Event, error) { + var ( + m Task + checkFuncs []TaskCheckFunc + hasDesiredState bool + ) + + for _, filter := range filters { + switch v := filter.By.(type) { + case *SelectBy_ID: + if m.ID != "" { + return nil, errConflictingFilters + } + m.ID = v.ID + checkFuncs = append(checkFuncs, TaskCheckID) + case *SelectBy_IDPrefix: + if m.ID != "" { + return nil, errConflictingFilters + } + m.ID = v.IDPrefix + checkFuncs = append(checkFuncs, TaskCheckIDPrefix) + case *SelectBy_Name: + if m.Annotations.Name != "" { + return nil, errConflictingFilters + } + m.Annotations.Name = v.Name + checkFuncs = append(checkFuncs, TaskCheckName) + case *SelectBy_NamePrefix: + if m.Annotations.Name != "" { + return nil, errConflictingFilters + } + m.Annotations.Name = v.NamePrefix + checkFuncs = append(checkFuncs, TaskCheckNamePrefix) + case *SelectBy_Custom: + if len(m.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + m.Annotations.Indices = []IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} + checkFuncs = append(checkFuncs, TaskCheckCustom) + case *SelectBy_CustomPrefix: + if len(m.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + m.Annotations.Indices = []IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} + checkFuncs = append(checkFuncs, TaskCheckCustomPrefix) + case *SelectBy_ServiceID: + if m.ServiceID != "" { + return nil, errConflictingFilters + } + m.ServiceID = v.ServiceID + checkFuncs = append(checkFuncs, TaskCheckServiceID) + case *SelectBy_NodeID: + if m.NodeID != "" { + return nil, errConflictingFilters + } + m.NodeID = v.NodeID + checkFuncs = append(checkFuncs, TaskCheckNodeID) + case *SelectBy_Slot: + if m.Slot != 0 || m.ServiceID != "" { + return nil, errConflictingFilters + } + m.ServiceID = v.Slot.ServiceID + m.Slot = v.Slot.Slot + checkFuncs = append(checkFuncs, TaskCheckNodeID, TaskCheckSlot) + case *SelectBy_DesiredState: + if hasDesiredState { + return nil, errConflictingFilters + } + hasDesiredState = true + m.DesiredState = v.DesiredState + checkFuncs = append(checkFuncs, TaskCheckDesiredState) + } + } + var events []Event + if (action & WatchActionKindCreate) != 0 { + events = append(events, EventCreateTask{Task: &m, Checks: checkFuncs}) + } + if (action & WatchActionKindUpdate) != 0 { + events = append(events, EventUpdateTask{Task: &m, Checks: checkFuncs}) + } + if (action & WatchActionKindRemove) != 0 { + events = append(events, EventDeleteTask{Task: &m, Checks: checkFuncs}) + } + if len(events) == 0 { + return nil, errUnrecognizedAction + } + return events, nil +} + type TaskIndexerByID struct{} func (indexer TaskIndexerByID) FromArgs(args ...interface{}) ([]byte, error) { @@ -2447,6 +2676,68 @@ func NetworkCheckCustomPrefix(v1, v2 *Network) bool { return checkCustomPrefix(v1.Spec.Annotations, v2.Spec.Annotations) } +func ConvertNetworkWatch(action WatchActionKind, filters []*SelectBy) ([]Event, error) { + var ( + m Network + checkFuncs []NetworkCheckFunc + ) + + for _, filter := range filters { + switch v := filter.By.(type) { + case *SelectBy_ID: + if m.ID != "" { + return nil, errConflictingFilters + } + m.ID = v.ID + checkFuncs = append(checkFuncs, NetworkCheckID) + case *SelectBy_IDPrefix: + if m.ID != "" { + return nil, errConflictingFilters + } + m.ID = v.IDPrefix + checkFuncs = append(checkFuncs, NetworkCheckIDPrefix) + case *SelectBy_Name: + if m.Spec.Annotations.Name != "" { + return nil, errConflictingFilters + } + m.Spec.Annotations.Name = v.Name + checkFuncs = append(checkFuncs, NetworkCheckName) + case *SelectBy_NamePrefix: + if m.Spec.Annotations.Name != "" { + return nil, errConflictingFilters + } + m.Spec.Annotations.Name = v.NamePrefix + checkFuncs = append(checkFuncs, NetworkCheckNamePrefix) + case *SelectBy_Custom: + if len(m.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + m.Spec.Annotations.Indices = []IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} + checkFuncs = append(checkFuncs, NetworkCheckCustom) + case *SelectBy_CustomPrefix: + if len(m.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + m.Spec.Annotations.Indices = []IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} + checkFuncs = append(checkFuncs, NetworkCheckCustomPrefix) + } + } + var events []Event + if (action & WatchActionKindCreate) != 0 { + events = append(events, EventCreateNetwork{Network: &m, Checks: checkFuncs}) + } + if (action & WatchActionKindUpdate) != 0 { + events = append(events, EventUpdateNetwork{Network: &m, Checks: checkFuncs}) + } + if (action & WatchActionKindRemove) != 0 { + events = append(events, EventDeleteNetwork{Network: &m, Checks: checkFuncs}) + } + if len(events) == 0 { + return nil, errUnrecognizedAction + } + return events, nil +} + type NetworkIndexerByID struct{} func (indexer NetworkIndexerByID) FromArgs(args ...interface{}) ([]byte, error) { @@ -2602,6 +2893,68 @@ func ClusterCheckCustomPrefix(v1, v2 *Cluster) bool { return checkCustomPrefix(v1.Spec.Annotations, v2.Spec.Annotations) } +func ConvertClusterWatch(action WatchActionKind, filters []*SelectBy) ([]Event, error) { + var ( + m Cluster + checkFuncs []ClusterCheckFunc + ) + + for _, filter := range filters { + switch v := filter.By.(type) { + case *SelectBy_ID: + if m.ID != "" { + return nil, errConflictingFilters + } + m.ID = v.ID + checkFuncs = append(checkFuncs, ClusterCheckID) + case *SelectBy_IDPrefix: + if m.ID != "" { + return nil, errConflictingFilters + } + m.ID = v.IDPrefix + checkFuncs = append(checkFuncs, ClusterCheckIDPrefix) + case *SelectBy_Name: + if m.Spec.Annotations.Name != "" { + return nil, errConflictingFilters + } + m.Spec.Annotations.Name = v.Name + checkFuncs = append(checkFuncs, ClusterCheckName) + case *SelectBy_NamePrefix: + if m.Spec.Annotations.Name != "" { + return nil, errConflictingFilters + } + m.Spec.Annotations.Name = v.NamePrefix + checkFuncs = append(checkFuncs, ClusterCheckNamePrefix) + case *SelectBy_Custom: + if len(m.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + m.Spec.Annotations.Indices = []IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} + checkFuncs = append(checkFuncs, ClusterCheckCustom) + case *SelectBy_CustomPrefix: + if len(m.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + m.Spec.Annotations.Indices = []IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} + checkFuncs = append(checkFuncs, ClusterCheckCustomPrefix) + } + } + var events []Event + if (action & WatchActionKindCreate) != 0 { + events = append(events, EventCreateCluster{Cluster: &m, Checks: checkFuncs}) + } + if (action & WatchActionKindUpdate) != 0 { + events = append(events, EventUpdateCluster{Cluster: &m, Checks: checkFuncs}) + } + if (action & WatchActionKindRemove) != 0 { + events = append(events, EventDeleteCluster{Cluster: &m, Checks: checkFuncs}) + } + if len(events) == 0 { + return nil, errUnrecognizedAction + } + return events, nil +} + type ClusterIndexerByID struct{} func (indexer ClusterIndexerByID) FromArgs(args ...interface{}) ([]byte, error) { @@ -2757,6 +3110,68 @@ func SecretCheckCustomPrefix(v1, v2 *Secret) bool { return checkCustomPrefix(v1.Spec.Annotations, v2.Spec.Annotations) } +func ConvertSecretWatch(action WatchActionKind, filters []*SelectBy) ([]Event, error) { + var ( + m Secret + checkFuncs []SecretCheckFunc + ) + + for _, filter := range filters { + switch v := filter.By.(type) { + case *SelectBy_ID: + if m.ID != "" { + return nil, errConflictingFilters + } + m.ID = v.ID + checkFuncs = append(checkFuncs, SecretCheckID) + case *SelectBy_IDPrefix: + if m.ID != "" { + return nil, errConflictingFilters + } + m.ID = v.IDPrefix + checkFuncs = append(checkFuncs, SecretCheckIDPrefix) + case *SelectBy_Name: + if m.Spec.Annotations.Name != "" { + return nil, errConflictingFilters + } + m.Spec.Annotations.Name = v.Name + checkFuncs = append(checkFuncs, SecretCheckName) + case *SelectBy_NamePrefix: + if m.Spec.Annotations.Name != "" { + return nil, errConflictingFilters + } + m.Spec.Annotations.Name = v.NamePrefix + checkFuncs = append(checkFuncs, SecretCheckNamePrefix) + case *SelectBy_Custom: + if len(m.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + m.Spec.Annotations.Indices = []IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} + checkFuncs = append(checkFuncs, SecretCheckCustom) + case *SelectBy_CustomPrefix: + if len(m.Spec.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + m.Spec.Annotations.Indices = []IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} + checkFuncs = append(checkFuncs, SecretCheckCustomPrefix) + } + } + var events []Event + if (action & WatchActionKindCreate) != 0 { + events = append(events, EventCreateSecret{Secret: &m, Checks: checkFuncs}) + } + if (action & WatchActionKindUpdate) != 0 { + events = append(events, EventUpdateSecret{Secret: &m, Checks: checkFuncs}) + } + if (action & WatchActionKindRemove) != 0 { + events = append(events, EventDeleteSecret{Secret: &m, Checks: checkFuncs}) + } + if len(events) == 0 { + return nil, errUnrecognizedAction + } + return events, nil +} + type SecretIndexerByID struct{} func (indexer SecretIndexerByID) FromArgs(args ...interface{}) ([]byte, error) { @@ -2916,6 +3331,70 @@ func ResourceCheckKind(v1, v2 *Resource) bool { return v1.Kind == v2.Kind } +func ConvertResourceWatch(action WatchActionKind, filters []*SelectBy, kind string) ([]Event, error) { + var ( + m Resource + checkFuncs []ResourceCheckFunc + ) + m.Kind = kind + checkFuncs = append(checkFuncs, ResourceCheckKind) + + for _, filter := range filters { + switch v := filter.By.(type) { + case *SelectBy_ID: + if m.ID != "" { + return nil, errConflictingFilters + } + m.ID = v.ID + checkFuncs = append(checkFuncs, ResourceCheckID) + case *SelectBy_IDPrefix: + if m.ID != "" { + return nil, errConflictingFilters + } + m.ID = v.IDPrefix + checkFuncs = append(checkFuncs, ResourceCheckIDPrefix) + case *SelectBy_Name: + if m.Annotations.Name != "" { + return nil, errConflictingFilters + } + m.Annotations.Name = v.Name + checkFuncs = append(checkFuncs, ResourceCheckName) + case *SelectBy_NamePrefix: + if m.Annotations.Name != "" { + return nil, errConflictingFilters + } + m.Annotations.Name = v.NamePrefix + checkFuncs = append(checkFuncs, ResourceCheckNamePrefix) + case *SelectBy_Custom: + if len(m.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + m.Annotations.Indices = []IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} + checkFuncs = append(checkFuncs, ResourceCheckCustom) + case *SelectBy_CustomPrefix: + if len(m.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + m.Annotations.Indices = []IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} + checkFuncs = append(checkFuncs, ResourceCheckCustomPrefix) + } + } + var events []Event + if (action & WatchActionKindCreate) != 0 { + events = append(events, EventCreateResource{Resource: &m, Checks: checkFuncs}) + } + if (action & WatchActionKindUpdate) != 0 { + events = append(events, EventUpdateResource{Resource: &m, Checks: checkFuncs}) + } + if (action & WatchActionKindRemove) != 0 { + events = append(events, EventDeleteResource{Resource: &m, Checks: checkFuncs}) + } + if len(events) == 0 { + return nil, errUnrecognizedAction + } + return events, nil +} + type ResourceIndexerByID struct{} func (indexer ResourceIndexerByID) FromArgs(args ...interface{}) ([]byte, error) { @@ -3071,6 +3550,68 @@ func ExtensionCheckCustomPrefix(v1, v2 *Extension) bool { return checkCustomPrefix(v1.Annotations, v2.Annotations) } +func ConvertExtensionWatch(action WatchActionKind, filters []*SelectBy) ([]Event, error) { + var ( + m Extension + checkFuncs []ExtensionCheckFunc + ) + + for _, filter := range filters { + switch v := filter.By.(type) { + case *SelectBy_ID: + if m.ID != "" { + return nil, errConflictingFilters + } + m.ID = v.ID + checkFuncs = append(checkFuncs, ExtensionCheckID) + case *SelectBy_IDPrefix: + if m.ID != "" { + return nil, errConflictingFilters + } + m.ID = v.IDPrefix + checkFuncs = append(checkFuncs, ExtensionCheckIDPrefix) + case *SelectBy_Name: + if m.Annotations.Name != "" { + return nil, errConflictingFilters + } + m.Annotations.Name = v.Name + checkFuncs = append(checkFuncs, ExtensionCheckName) + case *SelectBy_NamePrefix: + if m.Annotations.Name != "" { + return nil, errConflictingFilters + } + m.Annotations.Name = v.NamePrefix + checkFuncs = append(checkFuncs, ExtensionCheckNamePrefix) + case *SelectBy_Custom: + if len(m.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + m.Annotations.Indices = []IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} + checkFuncs = append(checkFuncs, ExtensionCheckCustom) + case *SelectBy_CustomPrefix: + if len(m.Annotations.Indices) != 0 { + return nil, errConflictingFilters + } + m.Annotations.Indices = []IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} + checkFuncs = append(checkFuncs, ExtensionCheckCustomPrefix) + } + } + var events []Event + if (action & WatchActionKindCreate) != 0 { + events = append(events, EventCreateExtension{Extension: &m, Checks: checkFuncs}) + } + if (action & WatchActionKindUpdate) != 0 { + events = append(events, EventUpdateExtension{Extension: &m, Checks: checkFuncs}) + } + if (action & WatchActionKindRemove) != 0 { + events = append(events, EventDeleteExtension{Extension: &m, Checks: checkFuncs}) + } + if len(events) == 0 { + return nil, errUnrecognizedAction + } + return events, nil +} + type ExtensionIndexerByID struct{} func (indexer ExtensionIndexerByID) FromArgs(args ...interface{}) ([]byte, error) { @@ -3387,6 +3928,39 @@ func WatchMessageEvent(c Event) *WatchMessage_Event { return nil } +func ConvertWatchArgs(entries []*WatchRequest_WatchEntry) ([]Event, error) { + var events []Event + for _, entry := range entries { + var newEvents []Event + var err error + switch entry.Kind { + case "": + return nil, errNoKindSpecified + case "node": + newEvents, err = ConvertNodeWatch(entry.Action, entry.Filters) + case "service": + newEvents, err = ConvertServiceWatch(entry.Action, entry.Filters) + case "task": + newEvents, err = ConvertTaskWatch(entry.Action, entry.Filters) + case "network": + newEvents, err = ConvertNetworkWatch(entry.Action, entry.Filters) + case "cluster": + newEvents, err = ConvertClusterWatch(entry.Action, entry.Filters) + case "secret": + newEvents, err = ConvertSecretWatch(entry.Action, entry.Filters) + default: + newEvents, err = ConvertResourceWatch(entry.Action, entry.Filters, entry.Kind) + case "extension": + newEvents, err = ConvertExtensionWatch(entry.Action, entry.Filters) + } + if err != nil { + return nil, err + } + events = append(events, newEvents...) + } + return events, nil +} + func (this *Meta) String() string { if this == nil { return "nil" diff --git a/api/storeobject.go b/api/storeobject.go index 3cfd915209..48b50b72dd 100644 --- a/api/storeobject.go +++ b/api/storeobject.go @@ -8,7 +8,12 @@ import ( "github.com/docker/go-events" ) -var errUnknownStoreAction = errors.New("unrecognized action type") +var ( + errUnknownStoreAction = errors.New("unrecognized action type") + errConflictingFilters = errors.New("conflicting filters specified") + errNoKindSpecified = errors.New("no kind of object specified") + errUnrecognizedAction = errors.New("unrecognized action") +) // StoreObject is an abstract object that can be handled by the store. type StoreObject interface { diff --git a/manager/storeapi/watch.go b/manager/storeapi/watch.go index 505a428e2c..d833bbacbe 100644 --- a/manager/storeapi/watch.go +++ b/manager/storeapi/watch.go @@ -9,616 +9,6 @@ import ( "github.com/docker/swarmkit/manager/state/store" ) -var errConflictingFilters = grpc.Errorf(codes.InvalidArgument, "conflicting filters specified") - -func convertNodeWatch(action api.WatchActionKind, filters []*api.SelectBy) ([]api.Event, error) { - var ( - node api.Node - checkFuncs []api.NodeCheckFunc - hasRole bool - hasMembership bool - ) - - for _, filter := range filters { - switch v := filter.By.(type) { - case *api.SelectBy_ID: - if node.ID != "" { - return nil, errConflictingFilters - } - node.ID = v.ID - checkFuncs = append(checkFuncs, api.NodeCheckID) - case *api.SelectBy_IDPrefix: - if node.ID != "" { - return nil, errConflictingFilters - } - node.ID = v.IDPrefix - checkFuncs = append(checkFuncs, api.NodeCheckIDPrefix) - case *api.SelectBy_Name: - if node.Description != nil { - return nil, errConflictingFilters - } - node.Description = &api.NodeDescription{Hostname: v.Name} - checkFuncs = append(checkFuncs, api.NodeCheckName) - case *api.SelectBy_NamePrefix: - if node.Description != nil { - return nil, errConflictingFilters - } - node.Description = &api.NodeDescription{Hostname: v.NamePrefix} - checkFuncs = append(checkFuncs, api.NodeCheckNamePrefix) - case *api.SelectBy_Custom: - // TODO(aaronl): Support multiple custom indices - if len(node.Spec.Annotations.Indices) != 0 { - return nil, errConflictingFilters - } - node.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} - checkFuncs = append(checkFuncs, api.NodeCheckCustom) - case *api.SelectBy_CustomPrefix: - // TODO(aaronl): Support multiple custom indices - if len(node.Spec.Annotations.Indices) != 0 { - return nil, errConflictingFilters - } - node.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} - checkFuncs = append(checkFuncs, api.NodeCheckCustomPrefix) - case *api.SelectBy_Role: - if hasRole { - return nil, errConflictingFilters - } - node.Role = v.Role - checkFuncs = append(checkFuncs, api.NodeCheckRole) - hasRole = true - case *api.SelectBy_Membership: - if hasMembership { - return nil, errConflictingFilters - } - node.Spec.Membership = v.Membership - checkFuncs = append(checkFuncs, api.NodeCheckMembership) - hasMembership = true - default: - return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for nodes", filter.By) - } - } - - var events []api.Event - if (action & api.WatchActionKindCreate) != 0 { - events = append(events, api.EventCreateNode{Node: &node, Checks: checkFuncs}) - } - if (action & api.WatchActionKindUpdate) != 0 { - events = append(events, api.EventUpdateNode{Node: &node, Checks: checkFuncs}) - } - if (action & api.WatchActionKindRemove) != 0 { - events = append(events, api.EventDeleteNode{Node: &node, Checks: checkFuncs}) - } - if len(events) == 0 { - return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized watch action %v", action) - } - return events, nil -} - -func convertServiceWatch(action api.WatchActionKind, filters []*api.SelectBy) ([]api.Event, error) { - var ( - service api.Service - checkFuncs []api.ServiceCheckFunc - ) - - for _, filter := range filters { - switch v := filter.By.(type) { - case *api.SelectBy_ID: - if service.ID != "" { - return nil, errConflictingFilters - } - service.ID = v.ID - checkFuncs = append(checkFuncs, api.ServiceCheckID) - case *api.SelectBy_IDPrefix: - if service.ID != "" { - return nil, errConflictingFilters - } - service.ID = v.IDPrefix - checkFuncs = append(checkFuncs, api.ServiceCheckIDPrefix) - case *api.SelectBy_Name: - if service.Spec.Annotations.Name != "" { - return nil, errConflictingFilters - } - service.Spec.Annotations.Name = v.Name - checkFuncs = append(checkFuncs, api.ServiceCheckName) - case *api.SelectBy_NamePrefix: - if service.Spec.Annotations.Name != "" { - return nil, errConflictingFilters - } - service.Spec.Annotations.Name = v.NamePrefix - checkFuncs = append(checkFuncs, api.ServiceCheckNamePrefix) - case *api.SelectBy_Custom: - // TODO(aaronl): Support multiple custom indices - if len(service.Spec.Annotations.Indices) != 0 { - return nil, errConflictingFilters - } - service.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} - checkFuncs = append(checkFuncs, api.ServiceCheckCustom) - case *api.SelectBy_CustomPrefix: - // TODO(aaronl): Support multiple custom indices - if len(service.Spec.Annotations.Indices) != 0 { - return nil, errConflictingFilters - } - service.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} - checkFuncs = append(checkFuncs, api.ServiceCheckCustomPrefix) - case *api.SelectBy_ReferencedNetworkID: - // TODO(aaronl): not supported for now - return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for services", filter.By) - case *api.SelectBy_ReferencedSecretID: - // TODO(aaronl): not supported for now - return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for services", filter.By) - default: - return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for services", filter.By) - } - } - - var events []api.Event - if (action & api.WatchActionKindCreate) != 0 { - events = append(events, api.EventCreateService{Service: &service, Checks: checkFuncs}) - } - if (action & api.WatchActionKindUpdate) != 0 { - events = append(events, api.EventUpdateService{Service: &service, Checks: checkFuncs}) - } - if (action & api.WatchActionKindRemove) != 0 { - events = append(events, api.EventDeleteService{Service: &service, Checks: checkFuncs}) - } - if len(events) == 0 { - return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized watch action %v", action) - } - return events, nil -} - -func convertNetworkWatch(action api.WatchActionKind, filters []*api.SelectBy) ([]api.Event, error) { - var ( - network api.Network - checkFuncs []api.NetworkCheckFunc - ) - - for _, filter := range filters { - switch v := filter.By.(type) { - case *api.SelectBy_ID: - if network.ID != "" { - return nil, errConflictingFilters - } - network.ID = v.ID - checkFuncs = append(checkFuncs, api.NetworkCheckID) - case *api.SelectBy_IDPrefix: - if network.ID != "" { - return nil, errConflictingFilters - } - network.ID = v.IDPrefix - checkFuncs = append(checkFuncs, api.NetworkCheckIDPrefix) - case *api.SelectBy_Name: - if network.Spec.Annotations.Name != "" { - return nil, errConflictingFilters - } - network.Spec.Annotations.Name = v.Name - checkFuncs = append(checkFuncs, api.NetworkCheckName) - case *api.SelectBy_NamePrefix: - if network.Spec.Annotations.Name != "" { - return nil, errConflictingFilters - } - network.Spec.Annotations.Name = v.NamePrefix - checkFuncs = append(checkFuncs, api.NetworkCheckNamePrefix) - case *api.SelectBy_Custom: - // TODO(aaronl): Support multiple custom indices - if len(network.Spec.Annotations.Indices) != 0 { - return nil, errConflictingFilters - } - network.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} - checkFuncs = append(checkFuncs, api.NetworkCheckCustom) - case *api.SelectBy_CustomPrefix: - // TODO(aaronl): Support multiple custom indices - if len(network.Spec.Annotations.Indices) != 0 { - return nil, errConflictingFilters - } - network.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} - checkFuncs = append(checkFuncs, api.NetworkCheckCustomPrefix) - default: - return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for networks", filter.By) - } - } - - var events []api.Event - if (action & api.WatchActionKindCreate) != 0 { - events = append(events, api.EventCreateNetwork{Network: &network, Checks: checkFuncs}) - } - if (action & api.WatchActionKindUpdate) != 0 { - events = append(events, api.EventUpdateNetwork{Network: &network, Checks: checkFuncs}) - } - if (action & api.WatchActionKindRemove) != 0 { - events = append(events, api.EventDeleteNetwork{Network: &network, Checks: checkFuncs}) - } - if len(events) == 0 { - return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized watch action %v", action) - } - return events, nil -} - -func convertClusterWatch(action api.WatchActionKind, filters []*api.SelectBy) ([]api.Event, error) { - var ( - cluster api.Cluster - checkFuncs []api.ClusterCheckFunc - ) - - for _, filter := range filters { - switch v := filter.By.(type) { - case *api.SelectBy_ID: - if cluster.ID != "" { - return nil, errConflictingFilters - } - cluster.ID = v.ID - checkFuncs = append(checkFuncs, api.ClusterCheckID) - case *api.SelectBy_IDPrefix: - if cluster.ID != "" { - return nil, errConflictingFilters - } - cluster.ID = v.IDPrefix - checkFuncs = append(checkFuncs, api.ClusterCheckIDPrefix) - case *api.SelectBy_Name: - if cluster.Spec.Annotations.Name != "" { - return nil, errConflictingFilters - } - cluster.Spec.Annotations.Name = v.Name - checkFuncs = append(checkFuncs, api.ClusterCheckName) - case *api.SelectBy_NamePrefix: - if cluster.Spec.Annotations.Name != "" { - return nil, errConflictingFilters - } - cluster.Spec.Annotations.Name = v.NamePrefix - checkFuncs = append(checkFuncs, api.ClusterCheckNamePrefix) - case *api.SelectBy_Custom: - // TODO(aaronl): Support multiple custom indices - if len(cluster.Spec.Annotations.Indices) != 0 { - return nil, errConflictingFilters - } - cluster.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} - checkFuncs = append(checkFuncs, api.ClusterCheckCustom) - case *api.SelectBy_CustomPrefix: - // TODO(aaronl): Support multiple custom indices - if len(cluster.Spec.Annotations.Indices) != 0 { - return nil, errConflictingFilters - } - cluster.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} - checkFuncs = append(checkFuncs, api.ClusterCheckCustomPrefix) - default: - return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for clusters", filter.By) - } - } - - var events []api.Event - if (action & api.WatchActionKindCreate) != 0 { - events = append(events, api.EventCreateCluster{Cluster: &cluster, Checks: checkFuncs}) - } - if (action & api.WatchActionKindUpdate) != 0 { - events = append(events, api.EventUpdateCluster{Cluster: &cluster, Checks: checkFuncs}) - } - if (action & api.WatchActionKindRemove) != 0 { - events = append(events, api.EventDeleteCluster{Cluster: &cluster, Checks: checkFuncs}) - } - if len(events) == 0 { - return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized watch action %v", action) - } - return events, nil -} - -func convertSecretWatch(action api.WatchActionKind, filters []*api.SelectBy) ([]api.Event, error) { - var ( - secret api.Secret - checkFuncs []api.SecretCheckFunc - ) - - for _, filter := range filters { - switch v := filter.By.(type) { - case *api.SelectBy_ID: - if secret.ID != "" { - return nil, errConflictingFilters - } - secret.ID = v.ID - checkFuncs = append(checkFuncs, api.SecretCheckID) - case *api.SelectBy_IDPrefix: - if secret.ID != "" { - return nil, errConflictingFilters - } - secret.ID = v.IDPrefix - checkFuncs = append(checkFuncs, api.SecretCheckIDPrefix) - case *api.SelectBy_Name: - if secret.Spec.Annotations.Name != "" { - return nil, errConflictingFilters - } - secret.Spec.Annotations.Name = v.Name - checkFuncs = append(checkFuncs, api.SecretCheckName) - case *api.SelectBy_NamePrefix: - if secret.Spec.Annotations.Name != "" { - return nil, errConflictingFilters - } - secret.Spec.Annotations.Name = v.NamePrefix - checkFuncs = append(checkFuncs, api.SecretCheckNamePrefix) - case *api.SelectBy_Custom: - // TODO(aaronl): Support multiple custom indices - if len(secret.Spec.Annotations.Indices) != 0 { - return nil, errConflictingFilters - } - secret.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} - checkFuncs = append(checkFuncs, api.SecretCheckCustom) - case *api.SelectBy_CustomPrefix: - // TODO(aaronl): Support multiple custom indices - if len(secret.Spec.Annotations.Indices) != 0 { - return nil, errConflictingFilters - } - secret.Spec.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} - checkFuncs = append(checkFuncs, api.SecretCheckCustomPrefix) - default: - return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for secrets", filter.By) - } - } - - var events []api.Event - if (action & api.WatchActionKindCreate) != 0 { - events = append(events, api.EventCreateSecret{Secret: &secret, Checks: checkFuncs}) - } - if (action & api.WatchActionKindUpdate) != 0 { - events = append(events, api.EventUpdateSecret{Secret: &secret, Checks: checkFuncs}) - } - if (action & api.WatchActionKindRemove) != 0 { - events = append(events, api.EventDeleteSecret{Secret: &secret, Checks: checkFuncs}) - } - if len(events) == 0 { - return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized watch action %v", action) - } - return events, nil -} - -func convertTaskWatch(action api.WatchActionKind, filters []*api.SelectBy) ([]api.Event, error) { - var ( - task api.Task - checkFuncs []api.TaskCheckFunc - hasDesiredState bool - ) - - for _, filter := range filters { - switch v := filter.By.(type) { - case *api.SelectBy_ID: - if task.ID != "" { - return nil, errConflictingFilters - } - task.ID = v.ID - checkFuncs = append(checkFuncs, api.TaskCheckID) - case *api.SelectBy_IDPrefix: - if task.ID != "" { - return nil, errConflictingFilters - } - task.ID = v.IDPrefix - checkFuncs = append(checkFuncs, api.TaskCheckIDPrefix) - case *api.SelectBy_Custom: - // TODO(aaronl): Support multiple custom indices - if len(task.Annotations.Indices) != 0 { - return nil, errConflictingFilters - } - task.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} - checkFuncs = append(checkFuncs, api.TaskCheckCustom) - case *api.SelectBy_CustomPrefix: - // TODO(aaronl): Support multiple custom indices - if len(task.Annotations.Indices) != 0 { - return nil, errConflictingFilters - } - task.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} - checkFuncs = append(checkFuncs, api.TaskCheckCustomPrefix) - case *api.SelectBy_ServiceID: - if task.ServiceID != "" { - return nil, errConflictingFilters - } - task.ServiceID = v.ServiceID - checkFuncs = append(checkFuncs, api.TaskCheckServiceID) - case *api.SelectBy_NodeID: - if task.NodeID != "" { - return nil, errConflictingFilters - } - task.NodeID = v.NodeID - checkFuncs = append(checkFuncs, api.TaskCheckNodeID) - case *api.SelectBy_Slot: - if task.Slot != 0 || task.ServiceID != "" { - return nil, errConflictingFilters - } - task.ServiceID = v.Slot.ServiceID - task.Slot = v.Slot.Slot - checkFuncs = append(checkFuncs, api.TaskCheckSlot, api.TaskCheckServiceID) - case *api.SelectBy_DesiredState: - if hasDesiredState { - return nil, errConflictingFilters - } - task.DesiredState = v.DesiredState - checkFuncs = append(checkFuncs, api.TaskCheckDesiredState) - hasDesiredState = true - default: - return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for tasks", filter.By) - } - } - - var events []api.Event - if (action & api.WatchActionKindCreate) != 0 { - events = append(events, api.EventCreateTask{Task: &task, Checks: checkFuncs}) - } - if (action & api.WatchActionKindUpdate) != 0 { - events = append(events, api.EventUpdateTask{Task: &task, Checks: checkFuncs}) - } - if (action & api.WatchActionKindRemove) != 0 { - events = append(events, api.EventDeleteTask{Task: &task, Checks: checkFuncs}) - } - if len(events) == 0 { - return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized watch action %v", action) - } - return events, nil -} - -func convertExtensionWatch(action api.WatchActionKind, filters []*api.SelectBy) ([]api.Event, error) { - var ( - extension api.Extension - checkFuncs []api.ExtensionCheckFunc - ) - - for _, filter := range filters { - switch v := filter.By.(type) { - case *api.SelectBy_ID: - if extension.ID != "" { - return nil, errConflictingFilters - } - extension.ID = v.ID - checkFuncs = append(checkFuncs, api.ExtensionCheckID) - case *api.SelectBy_IDPrefix: - if extension.ID != "" { - return nil, errConflictingFilters - } - extension.ID = v.IDPrefix - checkFuncs = append(checkFuncs, api.ExtensionCheckIDPrefix) - case *api.SelectBy_Name: - if extension.Annotations.Name != "" { - return nil, errConflictingFilters - } - extension.Annotations.Name = v.Name - checkFuncs = append(checkFuncs, api.ExtensionCheckName) - case *api.SelectBy_NamePrefix: - if extension.Annotations.Name != "" { - return nil, errConflictingFilters - } - extension.Annotations.Name = v.NamePrefix - checkFuncs = append(checkFuncs, api.ExtensionCheckNamePrefix) - case *api.SelectBy_Custom: - // TODO(aaronl): Support multiple custom indices - if len(extension.Annotations.Indices) != 0 { - return nil, errConflictingFilters - } - extension.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} - checkFuncs = append(checkFuncs, api.ExtensionCheckCustom) - case *api.SelectBy_CustomPrefix: - // TODO(aaronl): Support multiple custom indices - if len(extension.Annotations.Indices) != 0 { - return nil, errConflictingFilters - } - extension.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} - checkFuncs = append(checkFuncs, api.ExtensionCheckCustomPrefix) - default: - return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for extensions", filter.By) - } - } - - var events []api.Event - if (action & api.WatchActionKindCreate) != 0 { - events = append(events, api.EventCreateExtension{Extension: &extension, Checks: checkFuncs}) - } - if (action & api.WatchActionKindUpdate) != 0 { - events = append(events, api.EventUpdateExtension{Extension: &extension, Checks: checkFuncs}) - } - if (action & api.WatchActionKindRemove) != 0 { - events = append(events, api.EventDeleteExtension{Extension: &extension, Checks: checkFuncs}) - } - if len(events) == 0 { - return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized watch action %v", action) - } - return events, nil -} - -func convertResourceWatch(action api.WatchActionKind, filters []*api.SelectBy, kind string) ([]api.Event, error) { - resource := api.Resource{Kind: kind} - checkFuncs := []api.ResourceCheckFunc{api.ResourceCheckKind} - - for _, filter := range filters { - switch v := filter.By.(type) { - case *api.SelectBy_ID: - if resource.ID != "" { - return nil, errConflictingFilters - } - resource.ID = v.ID - checkFuncs = append(checkFuncs, api.ResourceCheckID) - case *api.SelectBy_IDPrefix: - if resource.ID != "" { - return nil, errConflictingFilters - } - resource.ID = v.IDPrefix - checkFuncs = append(checkFuncs, api.ResourceCheckIDPrefix) - case *api.SelectBy_Name: - if resource.Annotations.Name != "" { - return nil, errConflictingFilters - } - resource.Annotations.Name = v.Name - checkFuncs = append(checkFuncs, api.ResourceCheckName) - case *api.SelectBy_NamePrefix: - if resource.Annotations.Name != "" { - return nil, errConflictingFilters - } - resource.Annotations.Name = v.NamePrefix - checkFuncs = append(checkFuncs, api.ResourceCheckNamePrefix) - case *api.SelectBy_Custom: - // TODO(aaronl): Support multiple custom indices - if len(resource.Annotations.Indices) != 0 { - return nil, errConflictingFilters - } - resource.Annotations.Indices = []api.IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}} - checkFuncs = append(checkFuncs, api.ResourceCheckCustom) - case *api.SelectBy_CustomPrefix: - // TODO(aaronl): Support multiple custom indices - if len(resource.Annotations.Indices) != 0 { - return nil, errConflictingFilters - } - resource.Annotations.Indices = []api.IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}} - checkFuncs = append(checkFuncs, api.ResourceCheckCustomPrefix) - default: - return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for resource objects", filter.By) - } - } - - var events []api.Event - if (action & api.WatchActionKindCreate) != 0 { - events = append(events, api.EventCreateResource{Resource: &resource, Checks: checkFuncs}) - } - if (action & api.WatchActionKindUpdate) != 0 { - events = append(events, api.EventUpdateResource{Resource: &resource, Checks: checkFuncs}) - } - if (action & api.WatchActionKindRemove) != 0 { - events = append(events, api.EventDeleteResource{Resource: &resource, Checks: checkFuncs}) - } - if len(events) == 0 { - return nil, grpc.Errorf(codes.InvalidArgument, "unrecognized watch action %v", action) - } - return events, nil -} - -func convertWatchArgs(entries []*api.WatchRequest_WatchEntry) ([]api.Event, error) { - var events []api.Event - - for _, entry := range entries { - var ( - newEvents []api.Event - err error - ) - switch entry.Kind { - case "": - return nil, grpc.Errorf(codes.InvalidArgument, "no kind of object specified") - case "node": - newEvents, err = convertNodeWatch(entry.Action, entry.Filters) - case "service": - newEvents, err = convertServiceWatch(entry.Action, entry.Filters) - case "network": - newEvents, err = convertNetworkWatch(entry.Action, entry.Filters) - case "task": - newEvents, err = convertTaskWatch(entry.Action, entry.Filters) - case "cluster": - newEvents, err = convertClusterWatch(entry.Action, entry.Filters) - case "secret": - newEvents, err = convertSecretWatch(entry.Action, entry.Filters) - case "extension": - newEvents, err = convertExtensionWatch(entry.Action, entry.Filters) - default: - newEvents, err = convertResourceWatch(entry.Action, entry.Filters, entry.Kind) - } - if err != nil { - return nil, err - } - events = append(events, newEvents...) - } - - return events, nil -} - // Watch starts a stream that returns any changes to objects that match // the specified selectors. When the stream begins, it immediately sends // an empty message back to the client. It is important to wait for @@ -627,9 +17,9 @@ func convertWatchArgs(entries []*api.WatchRequest_WatchEntry) ([]api.Event, erro func (s *Server) Watch(request *api.WatchRequest, stream api.Store_WatchServer) error { ctx := stream.Context() - watchArgs, err := convertWatchArgs(request.Entries) + watchArgs, err := api.ConvertWatchArgs(request.Entries) if err != nil { - return err + return grpc.Errorf(codes.InvalidArgument, "%s", err.Error()) } watchArgs = append(watchArgs, state.EventCommit{}) diff --git a/protobuf/plugin/storeobject/storeobject.go b/protobuf/plugin/storeobject/storeobject.go index a1c09b4bc4..225802afb0 100644 --- a/protobuf/plugin/storeobject/storeobject.go +++ b/protobuf/plugin/storeobject/storeobject.go @@ -1,6 +1,8 @@ package storeobject import ( + "strings" + "github.com/docker/swarmkit/protobuf/plugin" "github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/protoc-gen-gogo/generator" @@ -287,6 +289,273 @@ func (d *storeObjectGen) genMsgStoreObject(m *generator.Descriptor, storeObject d.P() } + // Generate Convert*Watch function, for watch API. + if ccTypeName == "Resource" { + d.P("func ConvertResourceWatch(action WatchActionKind, filters []*SelectBy, kind string) ([]Event, error) {") + } else { + d.P("func Convert", ccTypeName, "Watch(action WatchActionKind, filters []*SelectBy) ([]Event, error) {") + } + d.In() + d.P("var (") + d.In() + d.P("m ", ccTypeName) + d.P("checkFuncs []", ccTypeName, "CheckFunc") + if storeObject.WatchSelectors.DesiredState != nil && *storeObject.WatchSelectors.DesiredState { + d.P("hasDesiredState bool") + } + if storeObject.WatchSelectors.Role != nil && *storeObject.WatchSelectors.Role { + d.P("hasRole bool") + } + if storeObject.WatchSelectors.Membership != nil && *storeObject.WatchSelectors.Membership { + d.P("hasMembership bool") + } + d.Out() + d.P(")") + if ccTypeName == "Resource" { + d.P("m.Kind = kind") + d.P("checkFuncs = append(checkFuncs, ResourceCheckKind)") + } + d.P() + d.P("for _, filter := range filters {") + d.In() + d.P("switch v := filter.By.(type) {") + + if storeObject.WatchSelectors.ID != nil && *storeObject.WatchSelectors.ID { + d.P("case *SelectBy_ID:") + d.In() + d.P(`if m.ID != "" {`) + d.In() + d.P("return nil, errConflictingFilters") + d.Out() + d.P("}") + d.P("m.ID = v.ID") + d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckID)") + d.Out() + } + if storeObject.WatchSelectors.IDPrefix != nil && *storeObject.WatchSelectors.IDPrefix { + d.P("case *SelectBy_IDPrefix:") + d.In() + d.P(`if m.ID != "" {`) + d.In() + d.P("return nil, errConflictingFilters") + d.Out() + d.P("}") + d.P("m.ID = v.IDPrefix") + d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckIDPrefix)") + d.Out() + } + if storeObject.WatchSelectors.Name != nil && *storeObject.WatchSelectors.Name { + d.P("case *SelectBy_Name:") + d.In() + if *m.Name == "Node" { + d.P("if m.Description != nil {") + d.In() + d.P("return nil, errConflictingFilters") + d.Out() + d.P("}") + d.P("m.Description = &NodeDescription{Hostname: v.Name}") + + } else if _, hasNoSpec := typesWithNoSpec[*m.Name]; hasNoSpec { + d.P(`if m.Annotations.Name != "" {`) + d.In() + d.P("return nil, errConflictingFilters") + d.Out() + d.P("}") + d.P("m.Annotations.Name = v.Name") + } else { + d.P(`if m.Spec.Annotations.Name != "" {`) + d.In() + d.P("return nil, errConflictingFilters") + d.Out() + d.P("}") + d.P("m.Spec.Annotations.Name = v.Name") + } + d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckName)") + d.Out() + } + if storeObject.WatchSelectors.NamePrefix != nil && *storeObject.WatchSelectors.NamePrefix { + d.P("case *SelectBy_NamePrefix:") + d.In() + if *m.Name == "Node" { + d.P("if m.Description != nil {") + d.In() + d.P("return nil, errConflictingFilters") + d.Out() + d.P("}") + d.P("m.Description = &NodeDescription{Hostname: v.NamePrefix}") + + } else if _, hasNoSpec := typesWithNoSpec[*m.Name]; hasNoSpec { + d.P(`if m.Annotations.Name != "" {`) + d.In() + d.P("return nil, errConflictingFilters") + d.Out() + d.P("}") + d.P("m.Annotations.Name = v.NamePrefix") + } else { + d.P(`if m.Spec.Annotations.Name != "" {`) + d.In() + d.P("return nil, errConflictingFilters") + d.Out() + d.P("}") + d.P("m.Spec.Annotations.Name = v.NamePrefix") + } + d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckNamePrefix)") + d.Out() + } + if storeObject.WatchSelectors.Custom != nil && *storeObject.WatchSelectors.Custom { + d.P("case *SelectBy_Custom:") + d.In() + if _, hasNoSpec := typesWithNoSpec[*m.Name]; hasNoSpec { + d.P(`if len(m.Annotations.Indices) != 0 {`) + d.In() + d.P("return nil, errConflictingFilters") + d.Out() + d.P("}") + d.P("m.Annotations.Indices = []IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}}") + } else { + d.P(`if len(m.Spec.Annotations.Indices) != 0 {`) + d.In() + d.P("return nil, errConflictingFilters") + d.Out() + d.P("}") + d.P("m.Spec.Annotations.Indices = []IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}}") + } + d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckCustom)") + d.Out() + } + if storeObject.WatchSelectors.CustomPrefix != nil && *storeObject.WatchSelectors.CustomPrefix { + d.P("case *SelectBy_CustomPrefix:") + d.In() + if _, hasNoSpec := typesWithNoSpec[*m.Name]; hasNoSpec { + d.P(`if len(m.Annotations.Indices) != 0 {`) + d.In() + d.P("return nil, errConflictingFilters") + d.Out() + d.P("}") + d.P("m.Annotations.Indices = []IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}}") + } else { + d.P(`if len(m.Spec.Annotations.Indices) != 0 {`) + d.In() + d.P("return nil, errConflictingFilters") + d.Out() + d.P("}") + d.P("m.Spec.Annotations.Indices = []IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}}") + } + d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckCustomPrefix)") + d.Out() + } + if storeObject.WatchSelectors.ServiceID != nil && *storeObject.WatchSelectors.ServiceID { + d.P("case *SelectBy_ServiceID:") + d.In() + d.P(`if m.ServiceID != "" {`) + d.In() + d.P("return nil, errConflictingFilters") + d.Out() + d.P("}") + d.P("m.ServiceID = v.ServiceID") + d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckServiceID)") + d.Out() + } + if storeObject.WatchSelectors.NodeID != nil && *storeObject.WatchSelectors.NodeID { + d.P("case *SelectBy_NodeID:") + d.In() + d.P(`if m.NodeID != "" {`) + d.In() + d.P("return nil, errConflictingFilters") + d.Out() + d.P("}") + d.P("m.NodeID = v.NodeID") + d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckNodeID)") + d.Out() + } + if storeObject.WatchSelectors.Slot != nil && *storeObject.WatchSelectors.Slot { + d.P("case *SelectBy_Slot:") + d.In() + d.P(`if m.Slot != 0 || m.ServiceID != "" {`) + d.In() + d.P("return nil, errConflictingFilters") + d.Out() + d.P("}") + d.P("m.ServiceID = v.Slot.ServiceID") + d.P("m.Slot = v.Slot.Slot") + d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckNodeID, ", ccTypeName, "CheckSlot)") + d.Out() + } + if storeObject.WatchSelectors.DesiredState != nil && *storeObject.WatchSelectors.DesiredState { + d.P("case *SelectBy_DesiredState:") + d.In() + d.P(`if hasDesiredState {`) + d.In() + d.P("return nil, errConflictingFilters") + d.Out() + d.P("}") + d.P("hasDesiredState = true") + d.P("m.DesiredState = v.DesiredState") + d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckDesiredState)") + d.Out() + } + if storeObject.WatchSelectors.Role != nil && *storeObject.WatchSelectors.Role { + d.P("case *SelectBy_Role:") + d.In() + d.P(`if hasRole {`) + d.In() + d.P("return nil, errConflictingFilters") + d.Out() + d.P("}") + d.P("hasRole = true") + d.P("m.Role = v.Role") + d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckRole)") + d.Out() + } + if storeObject.WatchSelectors.Membership != nil && *storeObject.WatchSelectors.Membership { + d.P("case *SelectBy_Membership:") + d.In() + d.P(`if hasMembership {`) + d.In() + d.P("return nil, errConflictingFilters") + d.Out() + d.P("}") + d.P("hasMembership = true") + d.P("m.Spec.Membership = v.Membership") + d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckMembership)") + d.Out() + } + + d.P("}") + d.Out() + d.P("}") + d.P("var events []Event") + d.P("if (action & WatchActionKindCreate) != 0 {") + d.In() + d.P("events = append(events, EventCreate", ccTypeName, "{", ccTypeName, ": &m, Checks: checkFuncs})") + d.Out() + d.P("}") + d.P("if (action & WatchActionKindUpdate) != 0 {") + d.In() + d.P("events = append(events, EventUpdate", ccTypeName, "{", ccTypeName, ": &m, Checks: checkFuncs})") + d.Out() + d.P("}") + d.P("if (action & WatchActionKindRemove) != 0 {") + d.In() + d.P("events = append(events, EventDelete", ccTypeName, "{", ccTypeName, ": &m, Checks: checkFuncs})") + d.Out() + d.P("}") + d.P("if len(events) == 0 {") + d.In() + d.P("return nil, errUnrecognizedAction") + d.Out() + d.P("}") + d.P("return events, nil") + d.Out() + d.P("}") + d.P() + + /* switch v := filter.By.(type) { + default: + return nil, grpc.Errorf(codes.InvalidArgument, "selector type %T is unsupported for tasks", filter.By) + } + */ + // Generate indexer by ID d.P("type ", ccTypeName, "IndexerByID struct{}") @@ -362,10 +631,6 @@ func (d *storeObjectGen) genPrefixFromArgs(indexerName string) { } func (d *storeObjectGen) genNewStoreAction(topLevelObjs []string) { - if len(topLevelObjs) == 0 { - return - } - // Generate NewStoreAction d.P("func NewStoreAction(c Event) (StoreAction, error) {") d.In() @@ -400,10 +665,6 @@ func (d *storeObjectGen) genNewStoreAction(topLevelObjs []string) { } func (d *storeObjectGen) genWatchMessageEvent(topLevelObjs []string) { - if len(topLevelObjs) == 0 { - return - } - // Generate WatchMessageEvent d.P("func WatchMessageEvent(c Event) *WatchMessage_Event {") d.In() @@ -438,10 +699,6 @@ func (d *storeObjectGen) genWatchMessageEvent(topLevelObjs []string) { } func (d *storeObjectGen) genEventFromStoreAction(topLevelObjs []string) { - if len(topLevelObjs) == 0 { - return - } - // Generate EventFromStoreAction d.P("func EventFromStoreAction(sa StoreAction, oldObject StoreObject) (Event, error) {") d.In() @@ -484,6 +741,49 @@ func (d *storeObjectGen) genEventFromStoreAction(topLevelObjs []string) { d.P() } +func (d *storeObjectGen) genConvertWatchArgs(topLevelObjs []string) { + // Generate ConvertWatchArgs + d.P("func ConvertWatchArgs(entries []*WatchRequest_WatchEntry) ([]Event, error) {") + d.In() + d.P("var events []Event") + d.P("for _, entry := range entries {") + d.In() + d.P("var newEvents []Event") + d.P("var err error") + d.P("switch entry.Kind {") + d.P(`case "":`) + d.In() + d.P("return nil, errNoKindSpecified") + d.Out() + for _, ccTypeName := range topLevelObjs { + if ccTypeName == "Resource" { + d.P("default:") + d.In() + d.P("newEvents, err = ConvertResourceWatch(entry.Action, entry.Filters, entry.Kind)") + d.Out() + } else { + d.P(`case "`, strings.ToLower(ccTypeName), `":`) + d.In() + d.P("newEvents, err = Convert", ccTypeName, "Watch(entry.Action, entry.Filters)") + d.Out() + } + } + d.P("}") + d.P("if err != nil {") + d.In() + d.P("return nil, err") + d.Out() + d.P("}") + d.P("events = append(events, newEvents...)") + + d.Out() + d.P("}") + d.P("return events, nil") + d.Out() + d.P("}") + d.P() +} + func (d *storeObjectGen) Generate(file *generator.FileDescriptor) { d.PluginImports = generator.NewPluginImports(d.Generator) d.eventsPkg = d.NewImport("github.com/docker/go-events") @@ -510,7 +810,12 @@ func (d *storeObjectGen) Generate(file *generator.FileDescriptor) { topLevelObjs = append(topLevelObjs, generator.CamelCaseSlice(m.TypeName())) } - d.genNewStoreAction(topLevelObjs) - d.genEventFromStoreAction(topLevelObjs) - d.genWatchMessageEvent(topLevelObjs) + if len(topLevelObjs) != 0 { + d.genNewStoreAction(topLevelObjs) + d.genEventFromStoreAction(topLevelObjs) + + // for watch API + d.genWatchMessageEvent(topLevelObjs) + d.genConvertWatchArgs(topLevelObjs) + } }