From 9e5b88c6dd39c86444fff8ecca86e5a611d95eb6 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Wed, 3 Jul 2024 15:56:28 -0700 Subject: [PATCH] add field selectors --- pkg/services/store/entity/entity.pb.go | 4 +- pkg/services/store/entity/entity_grpc.pb.go | 38 ++++++---- pkg/storage/unified/apistore/storage.go | 11 +++ pkg/storage/unified/resource/resource.pb.go | 83 ++++++++++++--------- pkg/storage/unified/resource/resource.proto | 11 ++- 5 files changed, 92 insertions(+), 55 deletions(-) diff --git a/pkg/services/store/entity/entity.pb.go b/pkg/services/store/entity/entity.pb.go index 97cb0a6d8da..fa46488db0e 100644 --- a/pkg/services/store/entity/entity.pb.go +++ b/pkg/services/store/entity/entity.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.1 // protoc (unknown) // source: entity.proto @@ -1401,7 +1401,7 @@ type EntityListRequest struct { WithStatus bool `protobuf:"varint,10,opt,name=with_status,json=withStatus,proto3" json:"with_status,omitempty"` // list deleted entities instead of active ones Deleted bool `protobuf:"varint,12,opt,name=deleted,proto3" json:"deleted,omitempty"` - // Limit to a set of origin keys (empty is all) + // Deprecated: Limit to a set of origin keys (empty is all) OriginKeys []string `protobuf:"bytes,13,rep,name=origin_keys,json=originKeys,proto3" json:"origin_keys,omitempty"` } diff --git a/pkg/services/store/entity/entity_grpc.pb.go b/pkg/services/store/entity/entity_grpc.pb.go index fd670d1106a..9d8bed0ed0b 100644 --- a/pkg/services/store/entity/entity_grpc.pb.go +++ b/pkg/services/store/entity/entity_grpc.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 +// - protoc-gen-go-grpc v1.4.0 // - protoc (unknown) // source: entity.proto @@ -15,8 +15,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.62.0 or later. +const _ = grpc.SupportPackageIsVersion8 const ( EntityStore_Read_FullMethodName = "/entity.EntityStore/Read" @@ -32,6 +32,8 @@ const ( // EntityStoreClient is the client API for EntityStore service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// The entity store provides a basic CRUD (+watch eventually) interface for generic entities type EntityStoreClient interface { Read(ctx context.Context, in *ReadEntityRequest, opts ...grpc.CallOption) (*Entity, error) Create(ctx context.Context, in *CreateEntityRequest, opts ...grpc.CallOption) (*CreateEntityResponse, error) @@ -52,8 +54,9 @@ func NewEntityStoreClient(cc grpc.ClientConnInterface) EntityStoreClient { } func (c *entityStoreClient) Read(ctx context.Context, in *ReadEntityRequest, opts ...grpc.CallOption) (*Entity, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Entity) - err := c.cc.Invoke(ctx, EntityStore_Read_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, EntityStore_Read_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -61,8 +64,9 @@ func (c *entityStoreClient) Read(ctx context.Context, in *ReadEntityRequest, opt } func (c *entityStoreClient) Create(ctx context.Context, in *CreateEntityRequest, opts ...grpc.CallOption) (*CreateEntityResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CreateEntityResponse) - err := c.cc.Invoke(ctx, EntityStore_Create_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, EntityStore_Create_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -70,8 +74,9 @@ func (c *entityStoreClient) Create(ctx context.Context, in *CreateEntityRequest, } func (c *entityStoreClient) Update(ctx context.Context, in *UpdateEntityRequest, opts ...grpc.CallOption) (*UpdateEntityResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(UpdateEntityResponse) - err := c.cc.Invoke(ctx, EntityStore_Update_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, EntityStore_Update_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -79,8 +84,9 @@ func (c *entityStoreClient) Update(ctx context.Context, in *UpdateEntityRequest, } func (c *entityStoreClient) Delete(ctx context.Context, in *DeleteEntityRequest, opts ...grpc.CallOption) (*DeleteEntityResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(DeleteEntityResponse) - err := c.cc.Invoke(ctx, EntityStore_Delete_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, EntityStore_Delete_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -88,8 +94,9 @@ func (c *entityStoreClient) Delete(ctx context.Context, in *DeleteEntityRequest, } func (c *entityStoreClient) History(ctx context.Context, in *EntityHistoryRequest, opts ...grpc.CallOption) (*EntityHistoryResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(EntityHistoryResponse) - err := c.cc.Invoke(ctx, EntityStore_History_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, EntityStore_History_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -97,8 +104,9 @@ func (c *entityStoreClient) History(ctx context.Context, in *EntityHistoryReques } func (c *entityStoreClient) List(ctx context.Context, in *EntityListRequest, opts ...grpc.CallOption) (*EntityListResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(EntityListResponse) - err := c.cc.Invoke(ctx, EntityStore_List_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, EntityStore_List_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -106,11 +114,12 @@ func (c *entityStoreClient) List(ctx context.Context, in *EntityListRequest, opt } func (c *entityStoreClient) Watch(ctx context.Context, opts ...grpc.CallOption) (EntityStore_WatchClient, error) { - stream, err := c.cc.NewStream(ctx, &EntityStore_ServiceDesc.Streams[0], EntityStore_Watch_FullMethodName, opts...) + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &EntityStore_ServiceDesc.Streams[0], EntityStore_Watch_FullMethodName, cOpts...) if err != nil { return nil, err } - x := &entityStoreWatchClient{stream} + x := &entityStoreWatchClient{ClientStream: stream} return x, nil } @@ -137,8 +146,9 @@ func (x *entityStoreWatchClient) Recv() (*EntityWatchResponse, error) { } func (c *entityStoreClient) IsHealthy(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(HealthCheckResponse) - err := c.cc.Invoke(ctx, EntityStore_IsHealthy_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, EntityStore_IsHealthy_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -148,6 +158,8 @@ func (c *entityStoreClient) IsHealthy(ctx context.Context, in *HealthCheckReques // EntityStoreServer is the server API for EntityStore service. // All implementations should embed UnimplementedEntityStoreServer // for forward compatibility +// +// The entity store provides a basic CRUD (+watch eventually) interface for generic entities type EntityStoreServer interface { Read(context.Context, *ReadEntityRequest) (*Entity, error) Create(context.Context, *CreateEntityRequest) (*CreateEntityResponse, error) @@ -308,7 +320,7 @@ func _EntityStore_List_Handler(srv interface{}, ctx context.Context, dec func(in } func _EntityStore_Watch_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(EntityStoreServer).Watch(&entityStoreWatchServer{stream}) + return srv.(EntityStoreServer).Watch(&entityStoreWatchServer{ServerStream: stream}) } type EntityStore_WatchServer interface { diff --git a/pkg/storage/unified/apistore/storage.go b/pkg/storage/unified/apistore/storage.go index 9ccab9d2ac7..1f158bcd655 100644 --- a/pkg/storage/unified/apistore/storage.go +++ b/pkg/storage/unified/apistore/storage.go @@ -310,6 +310,17 @@ func toListRequest(key string, opts storage.ListOptions) (*resource.ListRequest, } } + if opts.Predicate.Field != nil && !opts.Predicate.Field.Empty() { + requirements := opts.Predicate.Field.Requirements() + for _, r := range requirements { + requirement := &resource.Requirement{Key: r.Field, Operator: string(r.Operator)} + if r.Value != "" { + requirement.Values = append(requirement.Values, r.Value) + } + req.Options.Labels = append(req.Options.Labels, requirement) + } + } + if opts.ResourceVersion != "" { rv, err := strconv.ParseInt(opts.ResourceVersion, 10, 64) if err != nil { diff --git a/pkg/storage/unified/resource/resource.pb.go b/pkg/storage/unified/resource/resource.pb.go index 4f46525bdff..dadb67c2bae 100644 --- a/pkg/storage/unified/resource/resource.pb.go +++ b/pkg/storage/unified/resource/resource.pb.go @@ -1153,12 +1153,16 @@ type ListOptions struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Namespace+Group+Resource+etc + // Group+Namespace+Resource (not name) Key *ResourceKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` // (best effort) Match label // Allowed to send more results than actually match because the filter will be appled // to the resutls agin in the client. That time with the full field selector Labels []*Requirement `protobuf:"bytes,2,rep,name=labels,proto3" json:"labels,omitempty"` + // (best effort) fields matcher + // Allowed to send more results than actually match because the filter will be appled + // to the resutls agin in the client. That time with the full field selector + Fields []*Requirement `protobuf:"bytes,3,rep,name=fields,proto3" json:"fields,omitempty"` } func (x *ListOptions) Reset() { @@ -1207,6 +1211,13 @@ func (x *ListOptions) GetLabels() []*Requirement { return nil } +func (x *ListOptions) GetFields() []*Requirement { + if x != nil { + return x.Fields + } + return nil +} + type ListRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1778,13 +1789,16 @@ var file_resource_proto_rawDesc = []byte{ 0x63, 0x65, 0x2e, 0x53, 0x6f, 0x72, 0x74, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x22, 0x1a, 0x0a, 0x05, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x53, 0x43, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x45, 0x53, 0x43, 0x10, 0x01, - 0x22, 0x65, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, - 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, - 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x22, 0x94, 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x06, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x2d, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, - 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x22, 0xec, 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, + 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x22, 0xec, 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, @@ -1952,33 +1966,34 @@ var file_resource_proto_depIdxs = []int32{ 1, // 8: resource.Sort.order:type_name -> resource.Sort.Order 4, // 9: resource.ListOptions.key:type_name -> resource.ResourceKey 16, // 10: resource.ListOptions.labels:type_name -> resource.Requirement - 0, // 11: resource.ListRequest.version_match:type_name -> resource.ResourceVersionMatch - 18, // 12: resource.ListRequest.options:type_name -> resource.ListOptions - 5, // 13: resource.ListResponse.items:type_name -> resource.ResourceWrapper - 18, // 14: resource.WatchRequest.options:type_name -> resource.ListOptions - 2, // 15: resource.WatchEvent.type:type_name -> resource.WatchEvent.Type - 25, // 16: resource.WatchEvent.resource:type_name -> resource.WatchEvent.Resource - 25, // 17: resource.WatchEvent.previous:type_name -> resource.WatchEvent.Resource - 3, // 18: resource.HealthCheckResponse.status:type_name -> resource.HealthCheckResponse.ServingStatus - 14, // 19: resource.ResourceStore.Read:input_type -> resource.ReadRequest - 8, // 20: resource.ResourceStore.Create:input_type -> resource.CreateRequest - 10, // 21: resource.ResourceStore.Update:input_type -> resource.UpdateRequest - 12, // 22: resource.ResourceStore.Delete:input_type -> resource.DeleteRequest - 19, // 23: resource.ResourceStore.List:input_type -> resource.ListRequest - 21, // 24: resource.ResourceStore.Watch:input_type -> resource.WatchRequest - 23, // 25: resource.Diagnostics.IsHealthy:input_type -> resource.HealthCheckRequest - 15, // 26: resource.ResourceStore.Read:output_type -> resource.ReadResponse - 9, // 27: resource.ResourceStore.Create:output_type -> resource.CreateResponse - 11, // 28: resource.ResourceStore.Update:output_type -> resource.UpdateResponse - 13, // 29: resource.ResourceStore.Delete:output_type -> resource.DeleteResponse - 20, // 30: resource.ResourceStore.List:output_type -> resource.ListResponse - 22, // 31: resource.ResourceStore.Watch:output_type -> resource.WatchEvent - 24, // 32: resource.Diagnostics.IsHealthy:output_type -> resource.HealthCheckResponse - 26, // [26:33] is the sub-list for method output_type - 19, // [19:26] is the sub-list for method input_type - 19, // [19:19] is the sub-list for extension type_name - 19, // [19:19] is the sub-list for extension extendee - 0, // [0:19] is the sub-list for field type_name + 16, // 11: resource.ListOptions.fields:type_name -> resource.Requirement + 0, // 12: resource.ListRequest.version_match:type_name -> resource.ResourceVersionMatch + 18, // 13: resource.ListRequest.options:type_name -> resource.ListOptions + 5, // 14: resource.ListResponse.items:type_name -> resource.ResourceWrapper + 18, // 15: resource.WatchRequest.options:type_name -> resource.ListOptions + 2, // 16: resource.WatchEvent.type:type_name -> resource.WatchEvent.Type + 25, // 17: resource.WatchEvent.resource:type_name -> resource.WatchEvent.Resource + 25, // 18: resource.WatchEvent.previous:type_name -> resource.WatchEvent.Resource + 3, // 19: resource.HealthCheckResponse.status:type_name -> resource.HealthCheckResponse.ServingStatus + 14, // 20: resource.ResourceStore.Read:input_type -> resource.ReadRequest + 8, // 21: resource.ResourceStore.Create:input_type -> resource.CreateRequest + 10, // 22: resource.ResourceStore.Update:input_type -> resource.UpdateRequest + 12, // 23: resource.ResourceStore.Delete:input_type -> resource.DeleteRequest + 19, // 24: resource.ResourceStore.List:input_type -> resource.ListRequest + 21, // 25: resource.ResourceStore.Watch:input_type -> resource.WatchRequest + 23, // 26: resource.Diagnostics.IsHealthy:input_type -> resource.HealthCheckRequest + 15, // 27: resource.ResourceStore.Read:output_type -> resource.ReadResponse + 9, // 28: resource.ResourceStore.Create:output_type -> resource.CreateResponse + 11, // 29: resource.ResourceStore.Update:output_type -> resource.UpdateResponse + 13, // 30: resource.ResourceStore.Delete:output_type -> resource.DeleteResponse + 20, // 31: resource.ResourceStore.List:output_type -> resource.ListResponse + 22, // 32: resource.ResourceStore.Watch:output_type -> resource.WatchEvent + 24, // 33: resource.Diagnostics.IsHealthy:output_type -> resource.HealthCheckResponse + 27, // [27:34] is the sub-list for method output_type + 20, // [20:27] is the sub-list for method input_type + 20, // [20:20] is the sub-list for extension type_name + 20, // [20:20] is the sub-list for extension extendee + 0, // [0:20] is the sub-list for field type_name } func init() { file_resource_proto_init() } diff --git a/pkg/storage/unified/resource/resource.proto b/pkg/storage/unified/resource/resource.proto index 5471d2c8c1c..47fe30df579 100644 --- a/pkg/storage/unified/resource/resource.proto +++ b/pkg/storage/unified/resource/resource.proto @@ -169,7 +169,7 @@ message Sort { } message ListOptions { - // Namespace+Group+Resource+etc + // Group+Namespace+Resource (not name) ResourceKey key = 1; // (best effort) Match label @@ -177,11 +177,10 @@ message ListOptions { // to the resutls agin in the client. That time with the full field selector repeated Requirement labels = 2; - // TODO (later!) once we have a blob > search doc - // Match fields (not yet supported) - // metadata.name - // metadata.namespace - // repeated Requirement fields = 3; + // (best effort) fields matcher + // Allowed to send more results than actually match because the filter will be appled + // to the resutls agin in the client. That time with the full field selector + repeated Requirement fields = 3; } enum ResourceVersionMatch {