diff --git a/databroker/databroker.go b/databroker/databroker.go index 2e58a520a..17ce54f61 100644 --- a/databroker/databroker.go +++ b/databroker/databroker.go @@ -5,6 +5,8 @@ import ( "context" "sync/atomic" + "google.golang.org/protobuf/types/known/emptypb" + "github.com/pomerium/pomerium/config" "github.com/pomerium/pomerium/internal/databroker" databrokerpb "github.com/pomerium/pomerium/pkg/grpc/databroker" @@ -54,6 +56,13 @@ func (srv *dataBrokerServer) setKey(cfg *config.Config) { // Databroker functions +func (srv *dataBrokerServer) AcquireLease(ctx context.Context, req *databrokerpb.AcquireLeaseRequest) (*databrokerpb.AcquireLeaseResponse, error) { + if err := grpcutil.RequireSignedJWT(ctx, srv.sharedKey.Load().([]byte)); err != nil { + return nil, err + } + return srv.server.AcquireLease(ctx, req) +} + func (srv *dataBrokerServer) Get(ctx context.Context, req *databrokerpb.GetRequest) (*databrokerpb.GetResponse, error) { if err := grpcutil.RequireSignedJWT(ctx, srv.sharedKey.Load().([]byte)); err != nil { return nil, err @@ -75,6 +84,20 @@ func (srv *dataBrokerServer) Put(ctx context.Context, req *databrokerpb.PutReque return srv.server.Put(ctx, req) } +func (srv *dataBrokerServer) ReleaseLease(ctx context.Context, req *databrokerpb.ReleaseLeaseRequest) (*emptypb.Empty, error) { + if err := grpcutil.RequireSignedJWT(ctx, srv.sharedKey.Load().([]byte)); err != nil { + return nil, err + } + return srv.server.ReleaseLease(ctx, req) +} + +func (srv *dataBrokerServer) RenewLease(ctx context.Context, req *databrokerpb.RenewLeaseRequest) (*emptypb.Empty, error) { + if err := grpcutil.RequireSignedJWT(ctx, srv.sharedKey.Load().([]byte)); err != nil { + return nil, err + } + return srv.server.RenewLease(ctx, req) +} + func (srv *dataBrokerServer) SetOptions(ctx context.Context, req *databrokerpb.SetOptionsRequest) (*databrokerpb.SetOptionsResponse, error) { if err := grpcutil.RequireSignedJWT(ctx, srv.sharedKey.Load().([]byte)); err != nil { return nil, err diff --git a/internal/databroker/server.go b/internal/databroker/server.go index 428dd26d1..962042618 100644 --- a/internal/databroker/server.go +++ b/internal/databroker/server.go @@ -10,8 +10,10 @@ import ( "sync" "github.com/google/go-cmp/cmp" + "github.com/google/uuid" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/emptypb" "github.com/pomerium/pomerium/config" "github.com/pomerium/pomerium/internal/log" @@ -72,6 +74,34 @@ func (srv *Server) UpdateConfig(options ...ServerOption) { } } +// AcquireLease acquires a lease. +func (srv *Server) AcquireLease(ctx context.Context, req *databroker.AcquireLeaseRequest) (*databroker.AcquireLeaseResponse, error) { + _, span := trace.StartSpan(ctx, "databroker.grpc.AcquireLease") + defer span.End() + log.Info(ctx). + Str("peer", grpcutil.GetPeerAddr(ctx)). + Str("name", req.GetName()). + Dur("duration", req.GetDuration().AsDuration()). + Msg("acquire lease") + + db, err := srv.getBackend() + if err != nil { + return nil, err + } + + leaseID := uuid.NewString() + acquired, err := db.Lease(ctx, req.GetName(), leaseID, req.GetDuration().AsDuration()) + if err != nil { + return nil, err + } else if !acquired { + return nil, status.Error(codes.AlreadyExists, "lease is already taken") + } + + return &databroker.AcquireLeaseResponse{ + Id: leaseID, + }, nil +} + // Get gets a record from the in-memory list. func (srv *Server) Get(ctx context.Context, req *databroker.GetRequest) (*databroker.GetResponse, error) { _, span := trace.StartSpan(ctx, "databroker.grpc.Get") @@ -169,6 +199,55 @@ func (srv *Server) Put(ctx context.Context, req *databroker.PutRequest) (*databr }, nil } +// ReleaseLease releases a lease. +func (srv *Server) ReleaseLease(ctx context.Context, req *databroker.ReleaseLeaseRequest) (*emptypb.Empty, error) { + _, span := trace.StartSpan(ctx, "databroker.grpc.ReleaseLease") + defer span.End() + log.Info(ctx). + Str("peer", grpcutil.GetPeerAddr(ctx)). + Str("name", req.GetName()). + Str("id", req.GetId()). + Msg("release lease") + + db, err := srv.getBackend() + if err != nil { + return nil, err + } + + _, err = db.Lease(ctx, req.GetName(), req.GetId(), -1) + if err != nil { + return nil, err + } + + return new(emptypb.Empty), nil +} + +// RenewLease releases a lease. +func (srv *Server) RenewLease(ctx context.Context, req *databroker.RenewLeaseRequest) (*emptypb.Empty, error) { + _, span := trace.StartSpan(ctx, "databroker.grpc.RenewLease") + defer span.End() + log.Info(ctx). + Str("peer", grpcutil.GetPeerAddr(ctx)). + Str("name", req.GetName()). + Str("id", req.GetId()). + Dur("duration", req.GetDuration().AsDuration()). + Msg("renew lease") + + db, err := srv.getBackend() + if err != nil { + return nil, err + } + + acquired, err := db.Lease(ctx, req.GetName(), req.GetId(), req.GetDuration().AsDuration()) + if err != nil { + return nil, err + } else if !acquired { + return nil, status.Error(codes.AlreadyExists, "lease no longer held") + } + + return new(emptypb.Empty), nil +} + // SetOptions sets options for a type in the databroker. func (srv *Server) SetOptions(ctx context.Context, req *databroker.SetOptionsRequest) (*databroker.SetOptionsResponse, error) { _, span := trace.StartSpan(ctx, "databroker.grpc.SetOptions") diff --git a/internal/identity/manager/manager.go b/internal/identity/manager/manager.go index 9476ebdea..77d89c8bb 100644 --- a/internal/identity/manager/manager.go +++ b/internal/identity/manager/manager.go @@ -90,6 +90,12 @@ func (mgr *Manager) UpdateConfig(options ...Option) { // Run runs the manager. This method blocks until an error occurs or the given context is canceled. func (mgr *Manager) Run(ctx context.Context) error { + leaser := databroker.NewLeaser("identity_manager", time.Second*30, mgr) + return leaser.Run(ctx) +} + +// RunLeased runs the identity manager when a lease is acquired. +func (mgr *Manager) RunLeased(ctx context.Context) error { ctx = withLog(ctx) update := make(chan updateRecordsMessage, 1) clear := make(chan struct{}, 1) @@ -107,6 +113,11 @@ func (mgr *Manager) Run(ctx context.Context) error { return eg.Wait() } +// GetDataBrokerServiceClient gets the databroker client. +func (mgr *Manager) GetDataBrokerServiceClient() databroker.DataBrokerServiceClient { + return mgr.cfg.Load().dataBrokerClient +} + func (mgr *Manager) refreshLoop(ctx context.Context, update <-chan updateRecordsMessage, clear <-chan struct{}) error { // wait for initial sync select { diff --git a/pkg/grpc/databroker/databroker.go b/pkg/grpc/databroker/databroker.go index 4b4ce2ccc..2646e8a8c 100644 --- a/pkg/grpc/databroker/databroker.go +++ b/pkg/grpc/databroker/databroker.go @@ -7,6 +7,9 @@ import ( "io" ) +//go:generate go run github.com/golang/mock/mockgen -source=databroker.pb.go -destination ./mock_databroker/databroker.pb.go DataBrokerServiceClient +//go:generate go run github.com/golang/mock/mockgen -source=leaser.go -destination ./mock_databroker/leaser.go LeaserHandler + // ApplyOffsetAndLimit applies the offset and limit to the list of records. func ApplyOffsetAndLimit(all []*Record, offset, limit int) (records []*Record, totalCount int) { records = all diff --git a/pkg/grpc/databroker/databroker.pb.go b/pkg/grpc/databroker/databroker.pb.go index 069be7386..b9011d6af 100644 --- a/pkg/grpc/databroker/databroker.pb.go +++ b/pkg/grpc/databroker/databroker.pb.go @@ -14,6 +14,8 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + durationpb "google.golang.org/protobuf/types/known/durationpb" + emptypb "google.golang.org/protobuf/types/known/emptypb" timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" @@ -880,129 +882,392 @@ func (*SyncLatestResponse_Record) isSyncLatestResponse_Response() {} func (*SyncLatestResponse_Versions) isSyncLatestResponse_Response() {} +type AcquireLeaseRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Name is the name of the lease. Only a single client can hold the lease on + // the specified name at any one time. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Duration is the duration of the lease. After the duration is reached the + // lease can be acquired by other clients. + Duration *durationpb.Duration `protobuf:"bytes,2,opt,name=duration,proto3" json:"duration,omitempty"` +} + +func (x *AcquireLeaseRequest) Reset() { + *x = AcquireLeaseRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_databroker_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AcquireLeaseRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AcquireLeaseRequest) ProtoMessage() {} + +func (x *AcquireLeaseRequest) ProtoReflect() protoreflect.Message { + mi := &file_databroker_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AcquireLeaseRequest.ProtoReflect.Descriptor instead. +func (*AcquireLeaseRequest) Descriptor() ([]byte, []int) { + return file_databroker_proto_rawDescGZIP(), []int{15} +} + +func (x *AcquireLeaseRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *AcquireLeaseRequest) GetDuration() *durationpb.Duration { + if x != nil { + return x.Duration + } + return nil +} + +type AcquireLeaseResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Id is the id of the acquired lease. Subsequent calls to release or renew + // will need both the lease name and the lease id. + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *AcquireLeaseResponse) Reset() { + *x = AcquireLeaseResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_databroker_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AcquireLeaseResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AcquireLeaseResponse) ProtoMessage() {} + +func (x *AcquireLeaseResponse) ProtoReflect() protoreflect.Message { + mi := &file_databroker_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AcquireLeaseResponse.ProtoReflect.Descriptor instead. +func (*AcquireLeaseResponse) Descriptor() ([]byte, []int) { + return file_databroker_proto_rawDescGZIP(), []int{16} +} + +func (x *AcquireLeaseResponse) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type ReleaseLeaseRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *ReleaseLeaseRequest) Reset() { + *x = ReleaseLeaseRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_databroker_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReleaseLeaseRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReleaseLeaseRequest) ProtoMessage() {} + +func (x *ReleaseLeaseRequest) ProtoReflect() protoreflect.Message { + mi := &file_databroker_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReleaseLeaseRequest.ProtoReflect.Descriptor instead. +func (*ReleaseLeaseRequest) Descriptor() ([]byte, []int) { + return file_databroker_proto_rawDescGZIP(), []int{17} +} + +func (x *ReleaseLeaseRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ReleaseLeaseRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type RenewLeaseRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + Duration *durationpb.Duration `protobuf:"bytes,3,opt,name=duration,proto3" json:"duration,omitempty"` +} + +func (x *RenewLeaseRequest) Reset() { + *x = RenewLeaseRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_databroker_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RenewLeaseRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RenewLeaseRequest) ProtoMessage() {} + +func (x *RenewLeaseRequest) ProtoReflect() protoreflect.Message { + mi := &file_databroker_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RenewLeaseRequest.ProtoReflect.Descriptor instead. +func (*RenewLeaseRequest) Descriptor() ([]byte, []int) { + return file_databroker_proto_rawDescGZIP(), []int{18} +} + +func (x *RenewLeaseRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *RenewLeaseRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *RenewLeaseRequest) GetDuration() *durationpb.Duration { + if x != nil { + return x.Duration + } + return nil +} + var File_databroker_proto protoreflect.FileDescriptor var file_databroker_proto_rawDesc = []byte{ 0x0a, 0x10, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, - 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe8, 0x01, 0x0a, 0x06, 0x52, - 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x28, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x3b, 0x0a, - 0x0b, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, - 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x64, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe8, 0x01, 0x0a, 0x06, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, + 0x12, 0x28, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x65, 0x0a, 0x08, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x15, 0x6c, 0x61, 0x74, 0x65, - 0x73, 0x74, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x52, - 0x65, 0x63, 0x6f, 0x72, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x37, 0x0a, 0x07, - 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1f, 0x0a, 0x08, 0x63, 0x61, 0x70, 0x61, 0x63, - 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x48, 0x00, 0x52, 0x08, 0x63, 0x61, 0x70, - 0x61, 0x63, 0x69, 0x74, 0x79, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x63, 0x61, 0x70, - 0x61, 0x63, 0x69, 0x74, 0x79, 0x22, 0x30, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x39, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, - 0x6b, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x22, 0x66, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, - 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6f, 0x66, - 0x66, 0x73, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x5e, 0x0a, 0x0d, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x07, 0x72, - 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x64, - 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, - 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, - 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x38, 0x0a, 0x0a, 0x50, 0x75, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, - 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x06, 0x72, 0x65, - 0x63, 0x6f, 0x72, 0x64, 0x22, 0x60, 0x0a, 0x0b, 0x50, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x06, 0x72, 0x65, - 0x63, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x64, 0x61, 0x74, - 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x06, - 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x22, 0x56, 0x0a, 0x11, 0x53, 0x65, 0x74, 0x4f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, - 0x2d, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x13, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x4f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x43, - 0x0a, 0x12, 0x53, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, - 0x65, 0x72, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x22, 0x5b, 0x0a, 0x0b, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x63, - 0x6f, 0x72, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0d, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x22, 0x3a, 0x0a, 0x0c, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x2a, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x12, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x52, 0x65, - 0x63, 0x6f, 0x72, 0x64, 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x22, 0x27, 0x0a, 0x11, - 0x53, 0x79, 0x6e, 0x63, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x82, 0x01, 0x0a, 0x12, 0x53, 0x79, 0x6e, 0x63, 0x4c, 0x61, - 0x74, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x06, - 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x64, - 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x32, 0x0a, 0x08, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x64, - 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x48, 0x00, 0x52, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x0a, - 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x9a, 0x03, 0x0a, 0x11, 0x44, - 0x61, 0x74, 0x61, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x12, 0x36, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x16, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, - 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x17, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x03, 0x50, 0x75, 0x74, 0x12, - 0x16, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x50, 0x75, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, - 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x50, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x3c, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x18, 0x2e, 0x64, 0x61, 0x74, 0x61, - 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, - 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, - 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x64, - 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74, 0x4f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x64, 0x61, - 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x04, 0x53, - 0x79, 0x6e, 0x63, 0x12, 0x17, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, - 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x64, - 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x0a, 0x53, 0x79, 0x6e, 0x63, - 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, - 0x6b, 0x65, 0x72, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, - 0x65, 0x72, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, - 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, - 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x3b, 0x0a, 0x0b, 0x6d, 0x6f, + 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x6d, 0x6f, 0x64, + 0x69, 0x66, 0x69, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x64, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, + 0x41, 0x74, 0x22, 0x65, 0x0a, 0x08, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x25, + 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x15, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, + 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x37, 0x0a, 0x07, 0x4f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1f, 0x0a, 0x08, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x48, 0x00, 0x52, 0x08, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, + 0x74, 0x79, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, + 0x74, 0x79, 0x22, 0x30, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x69, 0x64, 0x22, 0x39, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, + 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x22, + 0x66, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, + 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x5e, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x64, 0x61, 0x74, 0x61, + 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x07, 0x72, + 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x38, 0x0a, 0x0a, 0x50, 0x75, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, + 0x65, 0x72, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x22, 0x60, 0x0a, 0x0b, 0x50, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, + 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x06, 0x72, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x22, 0x56, 0x0a, 0x11, 0x53, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2d, 0x0a, 0x07, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x43, 0x0a, 0x12, 0x53, + 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x2d, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, + 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x22, 0x5b, 0x0a, 0x0b, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, + 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, + 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x0a, + 0x0c, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, + 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, + 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x22, 0x27, 0x0a, 0x11, 0x53, 0x79, 0x6e, + 0x63, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x22, 0x82, 0x01, 0x0a, 0x12, 0x53, 0x79, 0x6e, 0x63, 0x4c, 0x61, 0x74, 0x65, 0x73, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x06, 0x72, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x64, 0x61, 0x74, 0x61, + 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x48, 0x00, 0x52, + 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x32, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x64, 0x61, 0x74, 0x61, + 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x48, + 0x00, 0x52, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x0a, 0x0a, 0x08, 0x72, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x60, 0x0a, 0x13, 0x41, 0x63, 0x71, 0x75, 0x69, + 0x72, 0x65, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x26, 0x0a, 0x14, 0x41, 0x63, 0x71, + 0x75, 0x69, 0x72, 0x65, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x22, 0x39, 0x0a, 0x13, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4c, 0x65, 0x61, 0x73, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x6e, 0x0a, 0x11, + 0x52, 0x65, 0x6e, 0x65, 0x77, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x32, 0xfb, 0x04, 0x0a, + 0x11, 0x44, 0x61, 0x74, 0x61, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x12, 0x51, 0x0a, 0x0c, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x4c, 0x65, 0x61, + 0x73, 0x65, 0x12, 0x1f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, + 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, + 0x2e, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x16, 0x2e, 0x64, + 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, + 0x72, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, + 0x03, 0x50, 0x75, 0x74, 0x12, 0x16, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, + 0x72, 0x2e, 0x50, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x64, + 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x50, 0x75, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x18, + 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, + 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4c, 0x65, + 0x61, 0x73, 0x65, 0x12, 0x1f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, + 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x43, 0x0a, 0x0a, + 0x52, 0x65, 0x6e, 0x65, 0x77, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x1d, 0x2e, 0x64, 0x61, 0x74, + 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x6e, 0x65, 0x77, 0x4c, 0x65, 0x61, + 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x12, 0x4b, 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x1d, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74, + 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, + 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74, 0x4f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, + 0x0a, 0x04, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x17, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, + 0x6b, 0x65, 0x72, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x18, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x53, 0x79, 0x6e, + 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x0a, 0x53, + 0x79, 0x6e, 0x63, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x2e, 0x64, 0x61, 0x74, 0x61, + 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4c, 0x61, 0x74, 0x65, 0x73, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, + 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, + 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, + 0x72, 0x70, 0x63, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1017,7 +1282,7 @@ func file_databroker_proto_rawDescGZIP() []byte { return file_databroker_proto_rawDescData } -var file_databroker_proto_msgTypes = make([]protoimpl.MessageInfo, 15) +var file_databroker_proto_msgTypes = make([]protoimpl.MessageInfo, 19) var file_databroker_proto_goTypes = []interface{}{ (*Record)(nil), // 0: databroker.Record (*Versions)(nil), // 1: databroker.Versions @@ -1034,13 +1299,19 @@ var file_databroker_proto_goTypes = []interface{}{ (*SyncResponse)(nil), // 12: databroker.SyncResponse (*SyncLatestRequest)(nil), // 13: databroker.SyncLatestRequest (*SyncLatestResponse)(nil), // 14: databroker.SyncLatestResponse - (*anypb.Any)(nil), // 15: google.protobuf.Any - (*timestamppb.Timestamp)(nil), // 16: google.protobuf.Timestamp + (*AcquireLeaseRequest)(nil), // 15: databroker.AcquireLeaseRequest + (*AcquireLeaseResponse)(nil), // 16: databroker.AcquireLeaseResponse + (*ReleaseLeaseRequest)(nil), // 17: databroker.ReleaseLeaseRequest + (*RenewLeaseRequest)(nil), // 18: databroker.RenewLeaseRequest + (*anypb.Any)(nil), // 19: google.protobuf.Any + (*timestamppb.Timestamp)(nil), // 20: google.protobuf.Timestamp + (*durationpb.Duration)(nil), // 21: google.protobuf.Duration + (*emptypb.Empty)(nil), // 22: google.protobuf.Empty } var file_databroker_proto_depIdxs = []int32{ - 15, // 0: databroker.Record.data:type_name -> google.protobuf.Any - 16, // 1: databroker.Record.modified_at:type_name -> google.protobuf.Timestamp - 16, // 2: databroker.Record.deleted_at:type_name -> google.protobuf.Timestamp + 19, // 0: databroker.Record.data:type_name -> google.protobuf.Any + 20, // 1: databroker.Record.modified_at:type_name -> google.protobuf.Timestamp + 20, // 2: databroker.Record.deleted_at:type_name -> google.protobuf.Timestamp 0, // 3: databroker.GetResponse.record:type_name -> databroker.Record 0, // 4: databroker.QueryResponse.records:type_name -> databroker.Record 0, // 5: databroker.PutRequest.record:type_name -> databroker.Record @@ -1050,23 +1321,31 @@ var file_databroker_proto_depIdxs = []int32{ 0, // 9: databroker.SyncResponse.record:type_name -> databroker.Record 0, // 10: databroker.SyncLatestResponse.record:type_name -> databroker.Record 1, // 11: databroker.SyncLatestResponse.versions:type_name -> databroker.Versions - 3, // 12: databroker.DataBrokerService.Get:input_type -> databroker.GetRequest - 7, // 13: databroker.DataBrokerService.Put:input_type -> databroker.PutRequest - 5, // 14: databroker.DataBrokerService.Query:input_type -> databroker.QueryRequest - 9, // 15: databroker.DataBrokerService.SetOptions:input_type -> databroker.SetOptionsRequest - 11, // 16: databroker.DataBrokerService.Sync:input_type -> databroker.SyncRequest - 13, // 17: databroker.DataBrokerService.SyncLatest:input_type -> databroker.SyncLatestRequest - 4, // 18: databroker.DataBrokerService.Get:output_type -> databroker.GetResponse - 8, // 19: databroker.DataBrokerService.Put:output_type -> databroker.PutResponse - 6, // 20: databroker.DataBrokerService.Query:output_type -> databroker.QueryResponse - 10, // 21: databroker.DataBrokerService.SetOptions:output_type -> databroker.SetOptionsResponse - 12, // 22: databroker.DataBrokerService.Sync:output_type -> databroker.SyncResponse - 14, // 23: databroker.DataBrokerService.SyncLatest:output_type -> databroker.SyncLatestResponse - 18, // [18:24] is the sub-list for method output_type - 12, // [12:18] is the sub-list for method input_type - 12, // [12:12] is the sub-list for extension type_name - 12, // [12:12] is the sub-list for extension extendee - 0, // [0:12] is the sub-list for field type_name + 21, // 12: databroker.AcquireLeaseRequest.duration:type_name -> google.protobuf.Duration + 21, // 13: databroker.RenewLeaseRequest.duration:type_name -> google.protobuf.Duration + 15, // 14: databroker.DataBrokerService.AcquireLease:input_type -> databroker.AcquireLeaseRequest + 3, // 15: databroker.DataBrokerService.Get:input_type -> databroker.GetRequest + 7, // 16: databroker.DataBrokerService.Put:input_type -> databroker.PutRequest + 5, // 17: databroker.DataBrokerService.Query:input_type -> databroker.QueryRequest + 17, // 18: databroker.DataBrokerService.ReleaseLease:input_type -> databroker.ReleaseLeaseRequest + 18, // 19: databroker.DataBrokerService.RenewLease:input_type -> databroker.RenewLeaseRequest + 9, // 20: databroker.DataBrokerService.SetOptions:input_type -> databroker.SetOptionsRequest + 11, // 21: databroker.DataBrokerService.Sync:input_type -> databroker.SyncRequest + 13, // 22: databroker.DataBrokerService.SyncLatest:input_type -> databroker.SyncLatestRequest + 16, // 23: databroker.DataBrokerService.AcquireLease:output_type -> databroker.AcquireLeaseResponse + 4, // 24: databroker.DataBrokerService.Get:output_type -> databroker.GetResponse + 8, // 25: databroker.DataBrokerService.Put:output_type -> databroker.PutResponse + 6, // 26: databroker.DataBrokerService.Query:output_type -> databroker.QueryResponse + 22, // 27: databroker.DataBrokerService.ReleaseLease:output_type -> google.protobuf.Empty + 22, // 28: databroker.DataBrokerService.RenewLease:output_type -> google.protobuf.Empty + 10, // 29: databroker.DataBrokerService.SetOptions:output_type -> databroker.SetOptionsResponse + 12, // 30: databroker.DataBrokerService.Sync:output_type -> databroker.SyncResponse + 14, // 31: databroker.DataBrokerService.SyncLatest:output_type -> databroker.SyncLatestResponse + 23, // [23:32] is the sub-list for method output_type + 14, // [14:23] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name } func init() { file_databroker_proto_init() } @@ -1255,6 +1534,54 @@ func file_databroker_proto_init() { return nil } } + file_databroker_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AcquireLeaseRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_databroker_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AcquireLeaseResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_databroker_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReleaseLeaseRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_databroker_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RenewLeaseRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_databroker_proto_msgTypes[2].OneofWrappers = []interface{}{} file_databroker_proto_msgTypes[14].OneofWrappers = []interface{}{ @@ -1267,7 +1594,7 @@ func file_databroker_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_databroker_proto_rawDesc, NumEnums: 0, - NumMessages: 15, + NumMessages: 19, NumExtensions: 0, NumServices: 1, }, @@ -1293,12 +1620,18 @@ const _ = grpc.SupportPackageIsVersion6 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type DataBrokerServiceClient interface { + // AcquireLease acquires a distributed mutex lease. + AcquireLease(ctx context.Context, in *AcquireLeaseRequest, opts ...grpc.CallOption) (*AcquireLeaseResponse, error) // Get gets a record. Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) // Put saves a record. Put(ctx context.Context, in *PutRequest, opts ...grpc.CallOption) (*PutResponse, error) // Query queries for records. Query(ctx context.Context, in *QueryRequest, opts ...grpc.CallOption) (*QueryResponse, error) + // ReleaseLease releases a distributed mutex lease. + ReleaseLease(ctx context.Context, in *ReleaseLeaseRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + // RenewLease renews a distributed mutex lease. + RenewLease(ctx context.Context, in *RenewLeaseRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) // SetOptions sets the options for a type in the databroker. SetOptions(ctx context.Context, in *SetOptionsRequest, opts ...grpc.CallOption) (*SetOptionsResponse, error) // Sync streams changes to records after the specified version. @@ -1315,6 +1648,15 @@ func NewDataBrokerServiceClient(cc grpc.ClientConnInterface) DataBrokerServiceCl return &dataBrokerServiceClient{cc} } +func (c *dataBrokerServiceClient) AcquireLease(ctx context.Context, in *AcquireLeaseRequest, opts ...grpc.CallOption) (*AcquireLeaseResponse, error) { + out := new(AcquireLeaseResponse) + err := c.cc.Invoke(ctx, "/databroker.DataBrokerService/AcquireLease", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *dataBrokerServiceClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) { out := new(GetResponse) err := c.cc.Invoke(ctx, "/databroker.DataBrokerService/Get", in, out, opts...) @@ -1342,6 +1684,24 @@ func (c *dataBrokerServiceClient) Query(ctx context.Context, in *QueryRequest, o return out, nil } +func (c *dataBrokerServiceClient) ReleaseLease(ctx context.Context, in *ReleaseLeaseRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, "/databroker.DataBrokerService/ReleaseLease", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *dataBrokerServiceClient) RenewLease(ctx context.Context, in *RenewLeaseRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, "/databroker.DataBrokerService/RenewLease", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *dataBrokerServiceClient) SetOptions(ctx context.Context, in *SetOptionsRequest, opts ...grpc.CallOption) (*SetOptionsResponse, error) { out := new(SetOptionsResponse) err := c.cc.Invoke(ctx, "/databroker.DataBrokerService/SetOptions", in, out, opts...) @@ -1417,12 +1777,18 @@ func (x *dataBrokerServiceSyncLatestClient) Recv() (*SyncLatestResponse, error) // DataBrokerServiceServer is the server API for DataBrokerService service. type DataBrokerServiceServer interface { + // AcquireLease acquires a distributed mutex lease. + AcquireLease(context.Context, *AcquireLeaseRequest) (*AcquireLeaseResponse, error) // Get gets a record. Get(context.Context, *GetRequest) (*GetResponse, error) // Put saves a record. Put(context.Context, *PutRequest) (*PutResponse, error) // Query queries for records. Query(context.Context, *QueryRequest) (*QueryResponse, error) + // ReleaseLease releases a distributed mutex lease. + ReleaseLease(context.Context, *ReleaseLeaseRequest) (*emptypb.Empty, error) + // RenewLease renews a distributed mutex lease. + RenewLease(context.Context, *RenewLeaseRequest) (*emptypb.Empty, error) // SetOptions sets the options for a type in the databroker. SetOptions(context.Context, *SetOptionsRequest) (*SetOptionsResponse, error) // Sync streams changes to records after the specified version. @@ -1435,6 +1801,9 @@ type DataBrokerServiceServer interface { type UnimplementedDataBrokerServiceServer struct { } +func (*UnimplementedDataBrokerServiceServer) AcquireLease(context.Context, *AcquireLeaseRequest) (*AcquireLeaseResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AcquireLease not implemented") +} func (*UnimplementedDataBrokerServiceServer) Get(context.Context, *GetRequest) (*GetResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Get not implemented") } @@ -1444,6 +1813,12 @@ func (*UnimplementedDataBrokerServiceServer) Put(context.Context, *PutRequest) ( func (*UnimplementedDataBrokerServiceServer) Query(context.Context, *QueryRequest) (*QueryResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Query not implemented") } +func (*UnimplementedDataBrokerServiceServer) ReleaseLease(context.Context, *ReleaseLeaseRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method ReleaseLease not implemented") +} +func (*UnimplementedDataBrokerServiceServer) RenewLease(context.Context, *RenewLeaseRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method RenewLease not implemented") +} func (*UnimplementedDataBrokerServiceServer) SetOptions(context.Context, *SetOptionsRequest) (*SetOptionsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SetOptions not implemented") } @@ -1458,6 +1833,24 @@ func RegisterDataBrokerServiceServer(s *grpc.Server, srv DataBrokerServiceServer s.RegisterService(&_DataBrokerService_serviceDesc, srv) } +func _DataBrokerService_AcquireLease_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AcquireLeaseRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DataBrokerServiceServer).AcquireLease(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/databroker.DataBrokerService/AcquireLease", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DataBrokerServiceServer).AcquireLease(ctx, req.(*AcquireLeaseRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _DataBrokerService_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetRequest) if err := dec(in); err != nil { @@ -1512,6 +1905,42 @@ func _DataBrokerService_Query_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _DataBrokerService_ReleaseLease_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ReleaseLeaseRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DataBrokerServiceServer).ReleaseLease(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/databroker.DataBrokerService/ReleaseLease", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DataBrokerServiceServer).ReleaseLease(ctx, req.(*ReleaseLeaseRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DataBrokerService_RenewLease_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RenewLeaseRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DataBrokerServiceServer).RenewLease(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/databroker.DataBrokerService/RenewLease", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DataBrokerServiceServer).RenewLease(ctx, req.(*RenewLeaseRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _DataBrokerService_SetOptions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(SetOptionsRequest) if err := dec(in); err != nil { @@ -1576,6 +2005,10 @@ var _DataBrokerService_serviceDesc = grpc.ServiceDesc{ ServiceName: "databroker.DataBrokerService", HandlerType: (*DataBrokerServiceServer)(nil), Methods: []grpc.MethodDesc{ + { + MethodName: "AcquireLease", + Handler: _DataBrokerService_AcquireLease_Handler, + }, { MethodName: "Get", Handler: _DataBrokerService_Get_Handler, @@ -1588,6 +2021,14 @@ var _DataBrokerService_serviceDesc = grpc.ServiceDesc{ MethodName: "Query", Handler: _DataBrokerService_Query_Handler, }, + { + MethodName: "ReleaseLease", + Handler: _DataBrokerService_ReleaseLease_Handler, + }, + { + MethodName: "RenewLease", + Handler: _DataBrokerService_RenewLease_Handler, + }, { MethodName: "SetOptions", Handler: _DataBrokerService_SetOptions_Handler, diff --git a/pkg/grpc/databroker/databroker.proto b/pkg/grpc/databroker/databroker.proto index 9e2db884e..69f2bdf29 100644 --- a/pkg/grpc/databroker/databroker.proto +++ b/pkg/grpc/databroker/databroker.proto @@ -4,6 +4,8 @@ package databroker; option go_package = "github.com/pomerium/pomerium/pkg/grpc/databroker"; import "google/protobuf/any.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/empty.proto"; import "google/protobuf/timestamp.proto"; message Record { @@ -31,9 +33,7 @@ message GetRequest { string type = 1; string id = 2; } -message GetResponse { - Record record = 1; -} +message GetResponse { Record record = 1; } message QueryRequest { string type = 1; @@ -56,17 +56,13 @@ message SetOptionsRequest { string type = 1; Options options = 2; } -message SetOptionsResponse { - Options options = 1; -} +message SetOptionsResponse { Options options = 1; } message SyncRequest { uint64 server_version = 1; uint64 record_version = 2; } -message SyncResponse { - Record record = 1; -} +message SyncResponse { Record record = 1; } message SyncLatestRequest { string type = 1; } message SyncLatestResponse { @@ -76,14 +72,43 @@ message SyncLatestResponse { } } +message AcquireLeaseRequest { + // Name is the name of the lease. Only a single client can hold the lease on + // the specified name at any one time. + string name = 1; + // Duration is the duration of the lease. After the duration is reached the + // lease can be acquired by other clients. + google.protobuf.Duration duration = 2; +} +message AcquireLeaseResponse { + // Id is the id of the acquired lease. Subsequent calls to release or renew + // will need both the lease name and the lease id. + string id = 1; +} +message ReleaseLeaseRequest { + string name = 1; + string id = 2; +} +message RenewLeaseRequest { + string name = 1; + string id = 2; + google.protobuf.Duration duration = 3; +} + // The DataBrokerService stores key-value data. service DataBrokerService { + // AcquireLease acquires a distributed mutex lease. + rpc AcquireLease(AcquireLeaseRequest) returns (AcquireLeaseResponse); // Get gets a record. rpc Get(GetRequest) returns (GetResponse); // Put saves a record. rpc Put(PutRequest) returns (PutResponse); // Query queries for records. rpc Query(QueryRequest) returns (QueryResponse); + // ReleaseLease releases a distributed mutex lease. + rpc ReleaseLease(ReleaseLeaseRequest) returns (google.protobuf.Empty); + // RenewLease renews a distributed mutex lease. + rpc RenewLease(RenewLeaseRequest) returns (google.protobuf.Empty); // SetOptions sets the options for a type in the databroker. rpc SetOptions(SetOptionsRequest) returns (SetOptionsResponse); // Sync streams changes to records after the specified version. diff --git a/pkg/grpc/databroker/leaser.go b/pkg/grpc/databroker/leaser.go new file mode 100644 index 000000000..5f4519da9 --- /dev/null +++ b/pkg/grpc/databroker/leaser.go @@ -0,0 +1,159 @@ +package databroker + +import ( + "context" + "errors" + "time" + + "github.com/cenkalti/backoff/v4" + "golang.org/x/sync/errgroup" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/durationpb" + + "github.com/pomerium/pomerium/internal/log" +) + +// a retryableError is one we'll retry later +type retryableError struct { + error +} + +func (err retryableError) Is(target error) bool { + if _, ok := target.(retryableError); ok { + return true + } + return false +} + +// A LeaserHandler is a handler for the locker. +type LeaserHandler interface { + GetDataBrokerServiceClient() DataBrokerServiceClient + RunLeased(ctx context.Context) error +} + +// A Leaser attempts to acquire a lease and if successful runs the handler. If the lease +// is released the context used for the handler will be canceled and a new lease +// acquisition will be attempted. +type Leaser struct { + handler LeaserHandler + leaseName string + ttl time.Duration +} + +// NewLeaser creates a new Leaser. +func NewLeaser(leaseName string, ttl time.Duration, handler LeaserHandler) *Leaser { + return &Leaser{ + leaseName: leaseName, + ttl: ttl, + handler: handler, + } +} + +// Run acquires the lease and runs the handler. This continues until either: +// +// 1. ctx is canceled +// 2. a non-cancel error is returned from handler +// +func (locker *Leaser) Run(ctx context.Context) error { + retryTicker := time.NewTicker(locker.ttl / 2) + defer retryTicker.Stop() + + bo := backoff.NewExponentialBackOff() + bo.MaxElapsedTime = 0 + for { + err := locker.runOnce(ctx, bo.Reset) + switch { + case err == nil: + select { + case <-ctx.Done(): + return ctx.Err() + case <-retryTicker.C: + } + case errors.Is(err, retryableError{}): + select { + case <-ctx.Done(): + return ctx.Err() + case <-time.After(bo.NextBackOff()): + } + default: + return err + } + } +} + +func (locker *Leaser) runOnce(ctx context.Context, resetBackoff func()) error { + res, err := locker.handler.GetDataBrokerServiceClient().AcquireLease(ctx, &AcquireLeaseRequest{ + Name: locker.leaseName, + Duration: durationpb.New(locker.ttl), + }) + // if the lease already exists, retry later + if status.Code(err) == codes.AlreadyExists { + return nil + } else if err != nil { + log.Warn(ctx).Err(err).Msg("leaser: error acquiring lease") + return retryableError{err} + } + resetBackoff() + leaseID := res.Id + + log.Info(ctx). + Str("lease_name", locker.leaseName). + Str("lease_id", leaseID). + Msg("leaser: lease acquired") + + return locker.withLease(ctx, leaseID) +} + +func (locker *Leaser) withLease(ctx context.Context, leaseID string) error { + // always release the lock in case the parent context is canceled + defer func() { + _, _ = locker.handler.GetDataBrokerServiceClient().ReleaseLease(context.Background(), &ReleaseLeaseRequest{ + Name: locker.leaseName, + Id: leaseID, + }) + }() + + renewTicker := time.NewTicker(locker.ttl / 2) + defer renewTicker.Stop() + + // if renewal fails, cancel the handler + runCtx, runCancel := context.WithCancel(ctx) + eg, egCtx := errgroup.WithContext(runCtx) + eg.Go(func() error { + defer runCancel() + + for { + select { + case <-egCtx.Done(): + return egCtx.Err() + case <-renewTicker.C: + } + + _, err := locker.handler.GetDataBrokerServiceClient().RenewLease(ctx, &RenewLeaseRequest{ + Name: locker.leaseName, + Id: leaseID, + Duration: durationpb.New(locker.ttl), + }) + if status.Code(err) == codes.AlreadyExists { + log.Info(ctx). + Str("lease_name", locker.leaseName). + Str("lease_id", leaseID). + Msg("leaser: lease lost") + // failed to renew lease + return nil + } else if err != nil { + log.Warn(ctx).Err(err).Msg("leaser: error renewing lease") + return retryableError{err} + } + } + }) + eg.Go(func() error { + return locker.handler.RunLeased(egCtx) + }) + err := eg.Wait() + if errors.Is(err, context.Canceled) { + err = nil + } + return err +} diff --git a/pkg/grpc/databroker/leaser_test.go b/pkg/grpc/databroker/leaser_test.go new file mode 100644 index 000000000..e17d59bdf --- /dev/null +++ b/pkg/grpc/databroker/leaser_test.go @@ -0,0 +1,138 @@ +package databroker_test + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/durationpb" + + "github.com/pomerium/pomerium/pkg/grpc/databroker" + "github.com/pomerium/pomerium/pkg/grpc/databroker/mock_databroker" +) + +func TestLeaser(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + exitErr := errors.New("EXIT") + + t.Run("acquires lease", func(t *testing.T) { + client := mock_databroker.NewMockDataBrokerServiceClient(ctrl) + client.EXPECT(). + AcquireLease(gomock.Any(), &databroker.AcquireLeaseRequest{ + Name: "TEST", + Duration: durationpb.New(time.Second * 30), + }). + Return(&databroker.AcquireLeaseResponse{ + Id: "lease1", + }, nil). + Times(1) + client.EXPECT(). + ReleaseLease(gomock.Any(), &databroker.ReleaseLeaseRequest{ + Name: "TEST", + Id: "lease1", + }). + Times(1) + + handler := mock_databroker.NewMockLeaserHandler(ctrl) + handler.EXPECT(). + GetDataBrokerServiceClient(). + Return(client). + AnyTimes() + handler.EXPECT(). + RunLeased(gomock.Any()). + Return(exitErr). + Times(1) + + leaser := databroker.NewLeaser("TEST", time.Second*30, handler) + err := leaser.Run(context.Background()) + assert.Equal(t, exitErr, err) + }) + t.Run("retries acquire", func(t *testing.T) { + client := mock_databroker.NewMockDataBrokerServiceClient(ctrl) + client.EXPECT(). + AcquireLease(gomock.Any(), &databroker.AcquireLeaseRequest{ + Name: "TEST", + Duration: durationpb.New(time.Second * 30), + }). + Return(nil, status.Error(codes.Unavailable, "UNAVAILABLE")). + Times(2) + client.EXPECT(). + AcquireLease(gomock.Any(), &databroker.AcquireLeaseRequest{ + Name: "TEST", + Duration: durationpb.New(time.Second * 30), + }). + Return(&databroker.AcquireLeaseResponse{ + Id: "lease1", + }, nil). + Times(1) + client.EXPECT(). + ReleaseLease(gomock.Any(), &databroker.ReleaseLeaseRequest{ + Name: "TEST", + Id: "lease1", + }). + Times(1) + + handler := mock_databroker.NewMockLeaserHandler(ctrl) + handler.EXPECT(). + GetDataBrokerServiceClient(). + Return(client). + AnyTimes() + handler.EXPECT(). + RunLeased(gomock.Any()). + Return(exitErr). + Times(1) + + leaser := databroker.NewLeaser("TEST", time.Second*30, handler) + err := leaser.Run(context.Background()) + assert.Equal(t, exitErr, err) + }) + t.Run("renews", func(t *testing.T) { + client := mock_databroker.NewMockDataBrokerServiceClient(ctrl) + client.EXPECT(). + AcquireLease(gomock.Any(), &databroker.AcquireLeaseRequest{ + Name: "TEST", + Duration: durationpb.New(time.Millisecond), + }). + Return(&databroker.AcquireLeaseResponse{ + Id: "lease1", + }, nil). + Times(1) + client.EXPECT(). + RenewLease(gomock.Any(), &databroker.RenewLeaseRequest{ + Name: "TEST", + Id: "lease1", + Duration: durationpb.New(time.Millisecond), + }). + MinTimes(1) + client.EXPECT(). + ReleaseLease(gomock.Any(), &databroker.ReleaseLeaseRequest{ + Name: "TEST", + Id: "lease1", + }). + Times(1) + + handler := mock_databroker.NewMockLeaserHandler(ctrl) + handler.EXPECT(). + GetDataBrokerServiceClient(). + Return(client). + AnyTimes() + handler.EXPECT(). + RunLeased(gomock.Any()). + DoAndReturn(func(ctx context.Context) error { + time.Sleep(time.Millisecond * 20) + return exitErr + }). + Times(1) + + leaser := databroker.NewLeaser("TEST", time.Millisecond, handler) + err := leaser.Run(context.Background()) + assert.Equal(t, exitErr, err) + }) +} diff --git a/pkg/grpc/databroker/mock_databroker/databroker.pb.go b/pkg/grpc/databroker/mock_databroker/databroker.pb.go new file mode 100644 index 000000000..0d4d5bb21 --- /dev/null +++ b/pkg/grpc/databroker/mock_databroker/databroker.pb.go @@ -0,0 +1,894 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: databroker.pb.go + +// Package mock_databroker is a generated GoMock package. +package mock_databroker + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + databroker "github.com/pomerium/pomerium/pkg/grpc/databroker" + grpc "google.golang.org/grpc" + metadata "google.golang.org/grpc/metadata" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +// MockisSyncLatestResponse_Response is a mock of isSyncLatestResponse_Response interface. +type MockisSyncLatestResponse_Response struct { + ctrl *gomock.Controller + recorder *MockisSyncLatestResponse_ResponseMockRecorder +} + +// MockisSyncLatestResponse_ResponseMockRecorder is the mock recorder for MockisSyncLatestResponse_Response. +type MockisSyncLatestResponse_ResponseMockRecorder struct { + mock *MockisSyncLatestResponse_Response +} + +// NewMockisSyncLatestResponse_Response creates a new mock instance. +func NewMockisSyncLatestResponse_Response(ctrl *gomock.Controller) *MockisSyncLatestResponse_Response { + mock := &MockisSyncLatestResponse_Response{ctrl: ctrl} + mock.recorder = &MockisSyncLatestResponse_ResponseMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockisSyncLatestResponse_Response) EXPECT() *MockisSyncLatestResponse_ResponseMockRecorder { + return m.recorder +} + +// isSyncLatestResponse_Response mocks base method. +func (m *MockisSyncLatestResponse_Response) isSyncLatestResponse_Response() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "isSyncLatestResponse_Response") +} + +// isSyncLatestResponse_Response indicates an expected call of isSyncLatestResponse_Response. +func (mr *MockisSyncLatestResponse_ResponseMockRecorder) isSyncLatestResponse_Response() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "isSyncLatestResponse_Response", reflect.TypeOf((*MockisSyncLatestResponse_Response)(nil).isSyncLatestResponse_Response)) +} + +// MockDataBrokerServiceClient is a mock of DataBrokerServiceClient interface. +type MockDataBrokerServiceClient struct { + ctrl *gomock.Controller + recorder *MockDataBrokerServiceClientMockRecorder +} + +// MockDataBrokerServiceClientMockRecorder is the mock recorder for MockDataBrokerServiceClient. +type MockDataBrokerServiceClientMockRecorder struct { + mock *MockDataBrokerServiceClient +} + +// NewMockDataBrokerServiceClient creates a new mock instance. +func NewMockDataBrokerServiceClient(ctrl *gomock.Controller) *MockDataBrokerServiceClient { + mock := &MockDataBrokerServiceClient{ctrl: ctrl} + mock.recorder = &MockDataBrokerServiceClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDataBrokerServiceClient) EXPECT() *MockDataBrokerServiceClientMockRecorder { + return m.recorder +} + +// AcquireLease mocks base method. +func (m *MockDataBrokerServiceClient) AcquireLease(ctx context.Context, in *databroker.AcquireLeaseRequest, opts ...grpc.CallOption) (*databroker.AcquireLeaseResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, in} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "AcquireLease", varargs...) + ret0, _ := ret[0].(*databroker.AcquireLeaseResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AcquireLease indicates an expected call of AcquireLease. +func (mr *MockDataBrokerServiceClientMockRecorder) AcquireLease(ctx, in interface{}, opts ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, in}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcquireLease", reflect.TypeOf((*MockDataBrokerServiceClient)(nil).AcquireLease), varargs...) +} + +// Get mocks base method. +func (m *MockDataBrokerServiceClient) Get(ctx context.Context, in *databroker.GetRequest, opts ...grpc.CallOption) (*databroker.GetResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, in} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Get", varargs...) + ret0, _ := ret[0].(*databroker.GetResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockDataBrokerServiceClientMockRecorder) Get(ctx, in interface{}, opts ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, in}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockDataBrokerServiceClient)(nil).Get), varargs...) +} + +// Put mocks base method. +func (m *MockDataBrokerServiceClient) Put(ctx context.Context, in *databroker.PutRequest, opts ...grpc.CallOption) (*databroker.PutResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, in} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Put", varargs...) + ret0, _ := ret[0].(*databroker.PutResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Put indicates an expected call of Put. +func (mr *MockDataBrokerServiceClientMockRecorder) Put(ctx, in interface{}, opts ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, in}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockDataBrokerServiceClient)(nil).Put), varargs...) +} + +// Query mocks base method. +func (m *MockDataBrokerServiceClient) Query(ctx context.Context, in *databroker.QueryRequest, opts ...grpc.CallOption) (*databroker.QueryResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, in} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Query", varargs...) + ret0, _ := ret[0].(*databroker.QueryResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Query indicates an expected call of Query. +func (mr *MockDataBrokerServiceClientMockRecorder) Query(ctx, in interface{}, opts ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, in}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Query", reflect.TypeOf((*MockDataBrokerServiceClient)(nil).Query), varargs...) +} + +// ReleaseLease mocks base method. +func (m *MockDataBrokerServiceClient) ReleaseLease(ctx context.Context, in *databroker.ReleaseLeaseRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, in} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ReleaseLease", varargs...) + ret0, _ := ret[0].(*emptypb.Empty) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ReleaseLease indicates an expected call of ReleaseLease. +func (mr *MockDataBrokerServiceClientMockRecorder) ReleaseLease(ctx, in interface{}, opts ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, in}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReleaseLease", reflect.TypeOf((*MockDataBrokerServiceClient)(nil).ReleaseLease), varargs...) +} + +// RenewLease mocks base method. +func (m *MockDataBrokerServiceClient) RenewLease(ctx context.Context, in *databroker.RenewLeaseRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, in} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "RenewLease", varargs...) + ret0, _ := ret[0].(*emptypb.Empty) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// RenewLease indicates an expected call of RenewLease. +func (mr *MockDataBrokerServiceClientMockRecorder) RenewLease(ctx, in interface{}, opts ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, in}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RenewLease", reflect.TypeOf((*MockDataBrokerServiceClient)(nil).RenewLease), varargs...) +} + +// SetOptions mocks base method. +func (m *MockDataBrokerServiceClient) SetOptions(ctx context.Context, in *databroker.SetOptionsRequest, opts ...grpc.CallOption) (*databroker.SetOptionsResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, in} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "SetOptions", varargs...) + ret0, _ := ret[0].(*databroker.SetOptionsResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SetOptions indicates an expected call of SetOptions. +func (mr *MockDataBrokerServiceClientMockRecorder) SetOptions(ctx, in interface{}, opts ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, in}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetOptions", reflect.TypeOf((*MockDataBrokerServiceClient)(nil).SetOptions), varargs...) +} + +// Sync mocks base method. +func (m *MockDataBrokerServiceClient) Sync(ctx context.Context, in *databroker.SyncRequest, opts ...grpc.CallOption) (databroker.DataBrokerService_SyncClient, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, in} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Sync", varargs...) + ret0, _ := ret[0].(databroker.DataBrokerService_SyncClient) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Sync indicates an expected call of Sync. +func (mr *MockDataBrokerServiceClientMockRecorder) Sync(ctx, in interface{}, opts ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, in}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sync", reflect.TypeOf((*MockDataBrokerServiceClient)(nil).Sync), varargs...) +} + +// SyncLatest mocks base method. +func (m *MockDataBrokerServiceClient) SyncLatest(ctx context.Context, in *databroker.SyncLatestRequest, opts ...grpc.CallOption) (databroker.DataBrokerService_SyncLatestClient, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, in} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "SyncLatest", varargs...) + ret0, _ := ret[0].(databroker.DataBrokerService_SyncLatestClient) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SyncLatest indicates an expected call of SyncLatest. +func (mr *MockDataBrokerServiceClientMockRecorder) SyncLatest(ctx, in interface{}, opts ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, in}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SyncLatest", reflect.TypeOf((*MockDataBrokerServiceClient)(nil).SyncLatest), varargs...) +} + +// MockDataBrokerService_SyncClient is a mock of DataBrokerService_SyncClient interface. +type MockDataBrokerService_SyncClient struct { + ctrl *gomock.Controller + recorder *MockDataBrokerService_SyncClientMockRecorder +} + +// MockDataBrokerService_SyncClientMockRecorder is the mock recorder for MockDataBrokerService_SyncClient. +type MockDataBrokerService_SyncClientMockRecorder struct { + mock *MockDataBrokerService_SyncClient +} + +// NewMockDataBrokerService_SyncClient creates a new mock instance. +func NewMockDataBrokerService_SyncClient(ctrl *gomock.Controller) *MockDataBrokerService_SyncClient { + mock := &MockDataBrokerService_SyncClient{ctrl: ctrl} + mock.recorder = &MockDataBrokerService_SyncClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDataBrokerService_SyncClient) EXPECT() *MockDataBrokerService_SyncClientMockRecorder { + return m.recorder +} + +// CloseSend mocks base method. +func (m *MockDataBrokerService_SyncClient) CloseSend() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CloseSend") + ret0, _ := ret[0].(error) + return ret0 +} + +// CloseSend indicates an expected call of CloseSend. +func (mr *MockDataBrokerService_SyncClientMockRecorder) CloseSend() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseSend", reflect.TypeOf((*MockDataBrokerService_SyncClient)(nil).CloseSend)) +} + +// Context mocks base method. +func (m *MockDataBrokerService_SyncClient) Context() context.Context { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Context") + ret0, _ := ret[0].(context.Context) + return ret0 +} + +// Context indicates an expected call of Context. +func (mr *MockDataBrokerService_SyncClientMockRecorder) Context() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Context", reflect.TypeOf((*MockDataBrokerService_SyncClient)(nil).Context)) +} + +// Header mocks base method. +func (m *MockDataBrokerService_SyncClient) Header() (metadata.MD, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Header") + ret0, _ := ret[0].(metadata.MD) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Header indicates an expected call of Header. +func (mr *MockDataBrokerService_SyncClientMockRecorder) Header() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Header", reflect.TypeOf((*MockDataBrokerService_SyncClient)(nil).Header)) +} + +// Recv mocks base method. +func (m *MockDataBrokerService_SyncClient) Recv() (*databroker.SyncResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Recv") + ret0, _ := ret[0].(*databroker.SyncResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Recv indicates an expected call of Recv. +func (mr *MockDataBrokerService_SyncClientMockRecorder) Recv() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Recv", reflect.TypeOf((*MockDataBrokerService_SyncClient)(nil).Recv)) +} + +// RecvMsg mocks base method. +func (m_2 *MockDataBrokerService_SyncClient) RecvMsg(m interface{}) error { + m_2.ctrl.T.Helper() + ret := m_2.ctrl.Call(m_2, "RecvMsg", m) + ret0, _ := ret[0].(error) + return ret0 +} + +// RecvMsg indicates an expected call of RecvMsg. +func (mr *MockDataBrokerService_SyncClientMockRecorder) RecvMsg(m interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecvMsg", reflect.TypeOf((*MockDataBrokerService_SyncClient)(nil).RecvMsg), m) +} + +// SendMsg mocks base method. +func (m_2 *MockDataBrokerService_SyncClient) SendMsg(m interface{}) error { + m_2.ctrl.T.Helper() + ret := m_2.ctrl.Call(m_2, "SendMsg", m) + ret0, _ := ret[0].(error) + return ret0 +} + +// SendMsg indicates an expected call of SendMsg. +func (mr *MockDataBrokerService_SyncClientMockRecorder) SendMsg(m interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMsg", reflect.TypeOf((*MockDataBrokerService_SyncClient)(nil).SendMsg), m) +} + +// Trailer mocks base method. +func (m *MockDataBrokerService_SyncClient) Trailer() metadata.MD { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Trailer") + ret0, _ := ret[0].(metadata.MD) + return ret0 +} + +// Trailer indicates an expected call of Trailer. +func (mr *MockDataBrokerService_SyncClientMockRecorder) Trailer() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Trailer", reflect.TypeOf((*MockDataBrokerService_SyncClient)(nil).Trailer)) +} + +// MockDataBrokerService_SyncLatestClient is a mock of DataBrokerService_SyncLatestClient interface. +type MockDataBrokerService_SyncLatestClient struct { + ctrl *gomock.Controller + recorder *MockDataBrokerService_SyncLatestClientMockRecorder +} + +// MockDataBrokerService_SyncLatestClientMockRecorder is the mock recorder for MockDataBrokerService_SyncLatestClient. +type MockDataBrokerService_SyncLatestClientMockRecorder struct { + mock *MockDataBrokerService_SyncLatestClient +} + +// NewMockDataBrokerService_SyncLatestClient creates a new mock instance. +func NewMockDataBrokerService_SyncLatestClient(ctrl *gomock.Controller) *MockDataBrokerService_SyncLatestClient { + mock := &MockDataBrokerService_SyncLatestClient{ctrl: ctrl} + mock.recorder = &MockDataBrokerService_SyncLatestClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDataBrokerService_SyncLatestClient) EXPECT() *MockDataBrokerService_SyncLatestClientMockRecorder { + return m.recorder +} + +// CloseSend mocks base method. +func (m *MockDataBrokerService_SyncLatestClient) CloseSend() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CloseSend") + ret0, _ := ret[0].(error) + return ret0 +} + +// CloseSend indicates an expected call of CloseSend. +func (mr *MockDataBrokerService_SyncLatestClientMockRecorder) CloseSend() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseSend", reflect.TypeOf((*MockDataBrokerService_SyncLatestClient)(nil).CloseSend)) +} + +// Context mocks base method. +func (m *MockDataBrokerService_SyncLatestClient) Context() context.Context { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Context") + ret0, _ := ret[0].(context.Context) + return ret0 +} + +// Context indicates an expected call of Context. +func (mr *MockDataBrokerService_SyncLatestClientMockRecorder) Context() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Context", reflect.TypeOf((*MockDataBrokerService_SyncLatestClient)(nil).Context)) +} + +// Header mocks base method. +func (m *MockDataBrokerService_SyncLatestClient) Header() (metadata.MD, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Header") + ret0, _ := ret[0].(metadata.MD) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Header indicates an expected call of Header. +func (mr *MockDataBrokerService_SyncLatestClientMockRecorder) Header() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Header", reflect.TypeOf((*MockDataBrokerService_SyncLatestClient)(nil).Header)) +} + +// Recv mocks base method. +func (m *MockDataBrokerService_SyncLatestClient) Recv() (*databroker.SyncLatestResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Recv") + ret0, _ := ret[0].(*databroker.SyncLatestResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Recv indicates an expected call of Recv. +func (mr *MockDataBrokerService_SyncLatestClientMockRecorder) Recv() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Recv", reflect.TypeOf((*MockDataBrokerService_SyncLatestClient)(nil).Recv)) +} + +// RecvMsg mocks base method. +func (m_2 *MockDataBrokerService_SyncLatestClient) RecvMsg(m interface{}) error { + m_2.ctrl.T.Helper() + ret := m_2.ctrl.Call(m_2, "RecvMsg", m) + ret0, _ := ret[0].(error) + return ret0 +} + +// RecvMsg indicates an expected call of RecvMsg. +func (mr *MockDataBrokerService_SyncLatestClientMockRecorder) RecvMsg(m interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecvMsg", reflect.TypeOf((*MockDataBrokerService_SyncLatestClient)(nil).RecvMsg), m) +} + +// SendMsg mocks base method. +func (m_2 *MockDataBrokerService_SyncLatestClient) SendMsg(m interface{}) error { + m_2.ctrl.T.Helper() + ret := m_2.ctrl.Call(m_2, "SendMsg", m) + ret0, _ := ret[0].(error) + return ret0 +} + +// SendMsg indicates an expected call of SendMsg. +func (mr *MockDataBrokerService_SyncLatestClientMockRecorder) SendMsg(m interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMsg", reflect.TypeOf((*MockDataBrokerService_SyncLatestClient)(nil).SendMsg), m) +} + +// Trailer mocks base method. +func (m *MockDataBrokerService_SyncLatestClient) Trailer() metadata.MD { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Trailer") + ret0, _ := ret[0].(metadata.MD) + return ret0 +} + +// Trailer indicates an expected call of Trailer. +func (mr *MockDataBrokerService_SyncLatestClientMockRecorder) Trailer() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Trailer", reflect.TypeOf((*MockDataBrokerService_SyncLatestClient)(nil).Trailer)) +} + +// MockDataBrokerServiceServer is a mock of DataBrokerServiceServer interface. +type MockDataBrokerServiceServer struct { + ctrl *gomock.Controller + recorder *MockDataBrokerServiceServerMockRecorder +} + +// MockDataBrokerServiceServerMockRecorder is the mock recorder for MockDataBrokerServiceServer. +type MockDataBrokerServiceServerMockRecorder struct { + mock *MockDataBrokerServiceServer +} + +// NewMockDataBrokerServiceServer creates a new mock instance. +func NewMockDataBrokerServiceServer(ctrl *gomock.Controller) *MockDataBrokerServiceServer { + mock := &MockDataBrokerServiceServer{ctrl: ctrl} + mock.recorder = &MockDataBrokerServiceServerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDataBrokerServiceServer) EXPECT() *MockDataBrokerServiceServerMockRecorder { + return m.recorder +} + +// AcquireLease mocks base method. +func (m *MockDataBrokerServiceServer) AcquireLease(arg0 context.Context, arg1 *databroker.AcquireLeaseRequest) (*databroker.AcquireLeaseResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AcquireLease", arg0, arg1) + ret0, _ := ret[0].(*databroker.AcquireLeaseResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AcquireLease indicates an expected call of AcquireLease. +func (mr *MockDataBrokerServiceServerMockRecorder) AcquireLease(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcquireLease", reflect.TypeOf((*MockDataBrokerServiceServer)(nil).AcquireLease), arg0, arg1) +} + +// Get mocks base method. +func (m *MockDataBrokerServiceServer) Get(arg0 context.Context, arg1 *databroker.GetRequest) (*databroker.GetResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", arg0, arg1) + ret0, _ := ret[0].(*databroker.GetResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockDataBrokerServiceServerMockRecorder) Get(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockDataBrokerServiceServer)(nil).Get), arg0, arg1) +} + +// Put mocks base method. +func (m *MockDataBrokerServiceServer) Put(arg0 context.Context, arg1 *databroker.PutRequest) (*databroker.PutResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Put", arg0, arg1) + ret0, _ := ret[0].(*databroker.PutResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Put indicates an expected call of Put. +func (mr *MockDataBrokerServiceServerMockRecorder) Put(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockDataBrokerServiceServer)(nil).Put), arg0, arg1) +} + +// Query mocks base method. +func (m *MockDataBrokerServiceServer) Query(arg0 context.Context, arg1 *databroker.QueryRequest) (*databroker.QueryResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Query", arg0, arg1) + ret0, _ := ret[0].(*databroker.QueryResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Query indicates an expected call of Query. +func (mr *MockDataBrokerServiceServerMockRecorder) Query(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Query", reflect.TypeOf((*MockDataBrokerServiceServer)(nil).Query), arg0, arg1) +} + +// ReleaseLease mocks base method. +func (m *MockDataBrokerServiceServer) ReleaseLease(arg0 context.Context, arg1 *databroker.ReleaseLeaseRequest) (*emptypb.Empty, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReleaseLease", arg0, arg1) + ret0, _ := ret[0].(*emptypb.Empty) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ReleaseLease indicates an expected call of ReleaseLease. +func (mr *MockDataBrokerServiceServerMockRecorder) ReleaseLease(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReleaseLease", reflect.TypeOf((*MockDataBrokerServiceServer)(nil).ReleaseLease), arg0, arg1) +} + +// RenewLease mocks base method. +func (m *MockDataBrokerServiceServer) RenewLease(arg0 context.Context, arg1 *databroker.RenewLeaseRequest) (*emptypb.Empty, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RenewLease", arg0, arg1) + ret0, _ := ret[0].(*emptypb.Empty) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// RenewLease indicates an expected call of RenewLease. +func (mr *MockDataBrokerServiceServerMockRecorder) RenewLease(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RenewLease", reflect.TypeOf((*MockDataBrokerServiceServer)(nil).RenewLease), arg0, arg1) +} + +// SetOptions mocks base method. +func (m *MockDataBrokerServiceServer) SetOptions(arg0 context.Context, arg1 *databroker.SetOptionsRequest) (*databroker.SetOptionsResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetOptions", arg0, arg1) + ret0, _ := ret[0].(*databroker.SetOptionsResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SetOptions indicates an expected call of SetOptions. +func (mr *MockDataBrokerServiceServerMockRecorder) SetOptions(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetOptions", reflect.TypeOf((*MockDataBrokerServiceServer)(nil).SetOptions), arg0, arg1) +} + +// Sync mocks base method. +func (m *MockDataBrokerServiceServer) Sync(arg0 *databroker.SyncRequest, arg1 databroker.DataBrokerService_SyncServer) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Sync", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Sync indicates an expected call of Sync. +func (mr *MockDataBrokerServiceServerMockRecorder) Sync(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sync", reflect.TypeOf((*MockDataBrokerServiceServer)(nil).Sync), arg0, arg1) +} + +// SyncLatest mocks base method. +func (m *MockDataBrokerServiceServer) SyncLatest(arg0 *databroker.SyncLatestRequest, arg1 databroker.DataBrokerService_SyncLatestServer) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SyncLatest", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// SyncLatest indicates an expected call of SyncLatest. +func (mr *MockDataBrokerServiceServerMockRecorder) SyncLatest(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SyncLatest", reflect.TypeOf((*MockDataBrokerServiceServer)(nil).SyncLatest), arg0, arg1) +} + +// MockDataBrokerService_SyncServer is a mock of DataBrokerService_SyncServer interface. +type MockDataBrokerService_SyncServer struct { + ctrl *gomock.Controller + recorder *MockDataBrokerService_SyncServerMockRecorder +} + +// MockDataBrokerService_SyncServerMockRecorder is the mock recorder for MockDataBrokerService_SyncServer. +type MockDataBrokerService_SyncServerMockRecorder struct { + mock *MockDataBrokerService_SyncServer +} + +// NewMockDataBrokerService_SyncServer creates a new mock instance. +func NewMockDataBrokerService_SyncServer(ctrl *gomock.Controller) *MockDataBrokerService_SyncServer { + mock := &MockDataBrokerService_SyncServer{ctrl: ctrl} + mock.recorder = &MockDataBrokerService_SyncServerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDataBrokerService_SyncServer) EXPECT() *MockDataBrokerService_SyncServerMockRecorder { + return m.recorder +} + +// Context mocks base method. +func (m *MockDataBrokerService_SyncServer) Context() context.Context { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Context") + ret0, _ := ret[0].(context.Context) + return ret0 +} + +// Context indicates an expected call of Context. +func (mr *MockDataBrokerService_SyncServerMockRecorder) Context() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Context", reflect.TypeOf((*MockDataBrokerService_SyncServer)(nil).Context)) +} + +// RecvMsg mocks base method. +func (m_2 *MockDataBrokerService_SyncServer) RecvMsg(m interface{}) error { + m_2.ctrl.T.Helper() + ret := m_2.ctrl.Call(m_2, "RecvMsg", m) + ret0, _ := ret[0].(error) + return ret0 +} + +// RecvMsg indicates an expected call of RecvMsg. +func (mr *MockDataBrokerService_SyncServerMockRecorder) RecvMsg(m interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecvMsg", reflect.TypeOf((*MockDataBrokerService_SyncServer)(nil).RecvMsg), m) +} + +// Send mocks base method. +func (m *MockDataBrokerService_SyncServer) Send(arg0 *databroker.SyncResponse) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Send", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Send indicates an expected call of Send. +func (mr *MockDataBrokerService_SyncServerMockRecorder) Send(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Send", reflect.TypeOf((*MockDataBrokerService_SyncServer)(nil).Send), arg0) +} + +// SendHeader mocks base method. +func (m *MockDataBrokerService_SyncServer) SendHeader(arg0 metadata.MD) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendHeader", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SendHeader indicates an expected call of SendHeader. +func (mr *MockDataBrokerService_SyncServerMockRecorder) SendHeader(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendHeader", reflect.TypeOf((*MockDataBrokerService_SyncServer)(nil).SendHeader), arg0) +} + +// SendMsg mocks base method. +func (m_2 *MockDataBrokerService_SyncServer) SendMsg(m interface{}) error { + m_2.ctrl.T.Helper() + ret := m_2.ctrl.Call(m_2, "SendMsg", m) + ret0, _ := ret[0].(error) + return ret0 +} + +// SendMsg indicates an expected call of SendMsg. +func (mr *MockDataBrokerService_SyncServerMockRecorder) SendMsg(m interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMsg", reflect.TypeOf((*MockDataBrokerService_SyncServer)(nil).SendMsg), m) +} + +// SetHeader mocks base method. +func (m *MockDataBrokerService_SyncServer) SetHeader(arg0 metadata.MD) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetHeader", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetHeader indicates an expected call of SetHeader. +func (mr *MockDataBrokerService_SyncServerMockRecorder) SetHeader(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHeader", reflect.TypeOf((*MockDataBrokerService_SyncServer)(nil).SetHeader), arg0) +} + +// SetTrailer mocks base method. +func (m *MockDataBrokerService_SyncServer) SetTrailer(arg0 metadata.MD) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetTrailer", arg0) +} + +// SetTrailer indicates an expected call of SetTrailer. +func (mr *MockDataBrokerService_SyncServerMockRecorder) SetTrailer(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTrailer", reflect.TypeOf((*MockDataBrokerService_SyncServer)(nil).SetTrailer), arg0) +} + +// MockDataBrokerService_SyncLatestServer is a mock of DataBrokerService_SyncLatestServer interface. +type MockDataBrokerService_SyncLatestServer struct { + ctrl *gomock.Controller + recorder *MockDataBrokerService_SyncLatestServerMockRecorder +} + +// MockDataBrokerService_SyncLatestServerMockRecorder is the mock recorder for MockDataBrokerService_SyncLatestServer. +type MockDataBrokerService_SyncLatestServerMockRecorder struct { + mock *MockDataBrokerService_SyncLatestServer +} + +// NewMockDataBrokerService_SyncLatestServer creates a new mock instance. +func NewMockDataBrokerService_SyncLatestServer(ctrl *gomock.Controller) *MockDataBrokerService_SyncLatestServer { + mock := &MockDataBrokerService_SyncLatestServer{ctrl: ctrl} + mock.recorder = &MockDataBrokerService_SyncLatestServerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDataBrokerService_SyncLatestServer) EXPECT() *MockDataBrokerService_SyncLatestServerMockRecorder { + return m.recorder +} + +// Context mocks base method. +func (m *MockDataBrokerService_SyncLatestServer) Context() context.Context { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Context") + ret0, _ := ret[0].(context.Context) + return ret0 +} + +// Context indicates an expected call of Context. +func (mr *MockDataBrokerService_SyncLatestServerMockRecorder) Context() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Context", reflect.TypeOf((*MockDataBrokerService_SyncLatestServer)(nil).Context)) +} + +// RecvMsg mocks base method. +func (m_2 *MockDataBrokerService_SyncLatestServer) RecvMsg(m interface{}) error { + m_2.ctrl.T.Helper() + ret := m_2.ctrl.Call(m_2, "RecvMsg", m) + ret0, _ := ret[0].(error) + return ret0 +} + +// RecvMsg indicates an expected call of RecvMsg. +func (mr *MockDataBrokerService_SyncLatestServerMockRecorder) RecvMsg(m interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecvMsg", reflect.TypeOf((*MockDataBrokerService_SyncLatestServer)(nil).RecvMsg), m) +} + +// Send mocks base method. +func (m *MockDataBrokerService_SyncLatestServer) Send(arg0 *databroker.SyncLatestResponse) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Send", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Send indicates an expected call of Send. +func (mr *MockDataBrokerService_SyncLatestServerMockRecorder) Send(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Send", reflect.TypeOf((*MockDataBrokerService_SyncLatestServer)(nil).Send), arg0) +} + +// SendHeader mocks base method. +func (m *MockDataBrokerService_SyncLatestServer) SendHeader(arg0 metadata.MD) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendHeader", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SendHeader indicates an expected call of SendHeader. +func (mr *MockDataBrokerService_SyncLatestServerMockRecorder) SendHeader(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendHeader", reflect.TypeOf((*MockDataBrokerService_SyncLatestServer)(nil).SendHeader), arg0) +} + +// SendMsg mocks base method. +func (m_2 *MockDataBrokerService_SyncLatestServer) SendMsg(m interface{}) error { + m_2.ctrl.T.Helper() + ret := m_2.ctrl.Call(m_2, "SendMsg", m) + ret0, _ := ret[0].(error) + return ret0 +} + +// SendMsg indicates an expected call of SendMsg. +func (mr *MockDataBrokerService_SyncLatestServerMockRecorder) SendMsg(m interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMsg", reflect.TypeOf((*MockDataBrokerService_SyncLatestServer)(nil).SendMsg), m) +} + +// SetHeader mocks base method. +func (m *MockDataBrokerService_SyncLatestServer) SetHeader(arg0 metadata.MD) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetHeader", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetHeader indicates an expected call of SetHeader. +func (mr *MockDataBrokerService_SyncLatestServerMockRecorder) SetHeader(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHeader", reflect.TypeOf((*MockDataBrokerService_SyncLatestServer)(nil).SetHeader), arg0) +} + +// SetTrailer mocks base method. +func (m *MockDataBrokerService_SyncLatestServer) SetTrailer(arg0 metadata.MD) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetTrailer", arg0) +} + +// SetTrailer indicates an expected call of SetTrailer. +func (mr *MockDataBrokerService_SyncLatestServerMockRecorder) SetTrailer(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTrailer", reflect.TypeOf((*MockDataBrokerService_SyncLatestServer)(nil).SetTrailer), arg0) +} diff --git a/pkg/grpc/databroker/mock_databroker/leaser.go b/pkg/grpc/databroker/mock_databroker/leaser.go new file mode 100644 index 000000000..cd0cb412c --- /dev/null +++ b/pkg/grpc/databroker/mock_databroker/leaser.go @@ -0,0 +1,64 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: leaser.go + +// Package mock_databroker is a generated GoMock package. +package mock_databroker + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + databroker "github.com/pomerium/pomerium/pkg/grpc/databroker" +) + +// MockLeaserHandler is a mock of LeaserHandler interface. +type MockLeaserHandler struct { + ctrl *gomock.Controller + recorder *MockLeaserHandlerMockRecorder +} + +// MockLeaserHandlerMockRecorder is the mock recorder for MockLeaserHandler. +type MockLeaserHandlerMockRecorder struct { + mock *MockLeaserHandler +} + +// NewMockLeaserHandler creates a new mock instance. +func NewMockLeaserHandler(ctrl *gomock.Controller) *MockLeaserHandler { + mock := &MockLeaserHandler{ctrl: ctrl} + mock.recorder = &MockLeaserHandlerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockLeaserHandler) EXPECT() *MockLeaserHandlerMockRecorder { + return m.recorder +} + +// GetDataBrokerServiceClient mocks base method. +func (m *MockLeaserHandler) GetDataBrokerServiceClient() databroker.DataBrokerServiceClient { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDataBrokerServiceClient") + ret0, _ := ret[0].(databroker.DataBrokerServiceClient) + return ret0 +} + +// GetDataBrokerServiceClient indicates an expected call of GetDataBrokerServiceClient. +func (mr *MockLeaserHandlerMockRecorder) GetDataBrokerServiceClient() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDataBrokerServiceClient", reflect.TypeOf((*MockLeaserHandler)(nil).GetDataBrokerServiceClient)) +} + +// RunLeased mocks base method. +func (m *MockLeaserHandler) RunLeased(ctx context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RunLeased", ctx) + ret0, _ := ret[0].(error) + return ret0 +} + +// RunLeased indicates an expected call of RunLeased. +func (mr *MockLeaserHandlerMockRecorder) RunLeased(ctx interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RunLeased", reflect.TypeOf((*MockLeaserHandler)(nil).RunLeased), ctx) +} diff --git a/pkg/storage/encrypted.go b/pkg/storage/encrypted.go index 61ea829c5..fcdc3d0b7 100644 --- a/pkg/storage/encrypted.go +++ b/pkg/storage/encrypted.go @@ -3,6 +3,7 @@ package storage import ( "context" "crypto/cipher" + "time" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" @@ -97,6 +98,10 @@ func (e *encryptedBackend) GetOptions(ctx context.Context, recordType string) (* return e.underlying.GetOptions(ctx, recordType) } +func (e *encryptedBackend) Lease(ctx context.Context, leaseName, leaseID string, ttl time.Duration) (bool, error) { + return e.underlying.Lease(ctx, leaseName, leaseID, ttl) +} + func (e *encryptedBackend) Put(ctx context.Context, record *databroker.Record) (uint64, error) { encrypted, err := e.encrypt(record.GetData()) if err != nil { diff --git a/pkg/storage/inmemory/backend.go b/pkg/storage/inmemory/backend.go index 3e2163a12..c298dfc71 100644 --- a/pkg/storage/inmemory/backend.go +++ b/pkg/storage/inmemory/backend.go @@ -20,6 +20,11 @@ import ( "github.com/pomerium/pomerium/pkg/storage" ) +type lease struct { + id string + expiry time.Time +} + type recordChange struct { record *databroker.Record } @@ -47,6 +52,7 @@ type Backend struct { lookup map[string]*RecordCollection capacity map[string]*uint64 changes *btree.BTree + leases map[string]*lease } // New creates a new in-memory backend storage. @@ -60,6 +66,7 @@ func New(options ...Option) *Backend { lookup: make(map[string]*RecordCollection), capacity: map[string]*uint64{}, changes: btree.New(cfg.degree), + leases: make(map[string]*lease), } if cfg.expiry != 0 { go func() { @@ -165,6 +172,37 @@ func (backend *Backend) GetOptions(_ context.Context, recordType string) (*datab return options, nil } +// Lease acquires or renews a lease. +func (backend *Backend) Lease(_ context.Context, leaseName, leaseID string, ttl time.Duration) (bool, error) { + backend.mu.Lock() + defer backend.mu.Unlock() + + l, ok := backend.leases[leaseName] + // if there is no lease, or its expired, acquire a new one. + if !ok || l.expiry.Before(time.Now()) { + backend.leases[leaseName] = &lease{ + id: leaseID, + expiry: time.Now().Add(ttl), + } + return true, nil + } + + // if the lease doesn't match, we can't acquire it + if l.id != leaseID { + return false, nil + } + + // release the lease + if ttl <= 0 { + delete(backend.leases, leaseName) + return false, nil + } + + // update the expiry (renew the lease) + l.expiry = time.Now().Add(ttl) + return true, nil +} + // Put puts a record into the in-memory store. func (backend *Backend) Put(ctx context.Context, record *databroker.Record) (serverVersion uint64, err error) { if record == nil { diff --git a/pkg/storage/inmemory/backend_test.go b/pkg/storage/inmemory/backend_test.go index 5ed2f3fb8..e67f38a5c 100644 --- a/pkg/storage/inmemory/backend_test.go +++ b/pkg/storage/inmemory/backend_test.go @@ -189,3 +189,28 @@ func TestCapacity(t *testing.T) { } assert.Equal(t, []string{"7", "8", "9"}, ids, "should contain recent records") } + +func TestLease(t *testing.T) { + ctx := context.Background() + backend := New() + { + ok, err := backend.Lease(ctx, "test", "a", time.Second*30) + require.NoError(t, err) + assert.True(t, ok, "expected a to acquire the lease") + } + { + ok, err := backend.Lease(ctx, "test", "b", time.Second*30) + require.NoError(t, err) + assert.False(t, ok, "expected b to fail to acquire the lease") + } + { + ok, err := backend.Lease(ctx, "test", "a", 0) + require.NoError(t, err) + assert.False(t, ok, "expected a to clear the lease") + } + { + ok, err := backend.Lease(ctx, "test", "b", time.Second*30) + require.NoError(t, err) + assert.True(t, ok, "expected b to to acquire the lease") + } +} diff --git a/pkg/storage/redis/redis.go b/pkg/storage/redis/redis.go index f6860d6bd..5e54dd9b5 100644 --- a/pkg/storage/redis/redis.go +++ b/pkg/storage/redis/redis.go @@ -37,6 +37,7 @@ const ( optionsKey = redisutil.KeyPrefix + "options" recordTypeChangesKeyTpl = redisutil.KeyPrefix + "changes.%s" + leaseKeyTpl = "{pomerium_v3}.lease.%s" ) // custom errors @@ -202,6 +203,43 @@ func (backend *Backend) GetOptions(ctx context.Context, recordType string) (*dat return &options, nil } +// Lease acquires or renews a lease. +func (backend *Backend) Lease(ctx context.Context, leaseName, leaseID string, ttl time.Duration) (bool, error) { + acquired := false + key := getLeaseKey(leaseName) + err := backend.client.Watch(ctx, func(tx *redis.Tx) error { + currentID, err := tx.Get(ctx, key).Result() + if errors.Is(err, redis.Nil) { + // lease hasn't been set yet + } else if err != nil { + return err + } else if leaseID != currentID { + // lease has already been taken + return nil + } + + _, err = tx.Pipelined(ctx, func(p redis.Pipeliner) error { + if ttl <= 0 { + p.Del(ctx, key) + } else { + p.Set(ctx, key, leaseID, ttl) + } + return nil + }) + if err != nil { + return err + } + acquired = ttl > 0 + return nil + }, key) + // if the transaction failed someone else must've acquired the lease + if errors.Is(err, redis.TxFailedErr) { + acquired = false + err = nil + } + return acquired, err +} + // Put puts a record into redis. func (backend *Backend) Put(ctx context.Context, record *databroker.Record) (serverVersion uint64, err error) { ctx, span := trace.StartSpan(ctx, "databroker.redis.Put") @@ -489,6 +527,10 @@ func (backend *Backend) getOrCreateServerVersion(ctx context.Context) (serverVer return serverVersion, err } +func getLeaseKey(leaseName string) string { + return fmt.Sprintf(leaseKeyTpl, leaseName) +} + func getRecordTypeChangesKey(recordType string) string { return fmt.Sprintf(recordTypeChangesKeyTpl, recordType) } diff --git a/pkg/storage/redis/redis_test.go b/pkg/storage/redis/redis_test.go index f06606507..3db24541a 100644 --- a/pkg/storage/redis/redis_test.go +++ b/pkg/storage/redis/redis_test.go @@ -248,3 +248,39 @@ func TestCapacity(t *testing.T) { return nil })) } + +func TestLease(t *testing.T) { + if os.Getenv("GITHUB_ACTION") != "" && runtime.GOOS == "darwin" { + t.Skip("Github action can not run docker on MacOS") + } + + ctx := context.Background() + require.NoError(t, testutil.WithTestRedis(false, func(rawURL string) error { + backend, err := New(rawURL) + require.NoError(t, err) + defer func() { _ = backend.Close() }() + + { + ok, err := backend.Lease(ctx, "test", "a", time.Second*30) + require.NoError(t, err) + assert.True(t, ok, "expected a to acquire the lease") + } + { + ok, err := backend.Lease(ctx, "test", "b", time.Second*30) + require.NoError(t, err) + assert.False(t, ok, "expected b to fail to acquire the lease") + } + { + ok, err := backend.Lease(ctx, "test", "a", 0) + require.NoError(t, err) + assert.False(t, ok, "expected a to clear the lease") + } + { + ok, err := backend.Lease(ctx, "test", "b", time.Second*30) + require.NoError(t, err) + assert.True(t, ok, "expected b to to acquire the lease") + } + + return nil + })) +} diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index 073da6649..dbd1d7e0c 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -5,6 +5,7 @@ import ( "context" "errors" "strings" + "time" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -47,6 +48,8 @@ type Backend interface { GetAll(ctx context.Context) (records []*databroker.Record, version *databroker.Versions, err error) // GetOptions gets the options for a type. GetOptions(ctx context.Context, recordType string) (*databroker.Options, error) + // Lease acquires a lease, or renews an existing one. If the lease is acquired true is returned. + Lease(ctx context.Context, leaseName, leaseID string, ttl time.Duration) (bool, error) // Put is used to insert or update a record. Put(ctx context.Context, record *databroker.Record) (serverVersion uint64, err error) // SetOptions sets the options for a type.