From a756684ae5052a736e7a1f6401c85c4e82c9cabd Mon Sep 17 00:00:00 2001 From: Andrey Melnikov Date: Mon, 26 Oct 2020 15:38:03 -0700 Subject: [PATCH] feat: API support for selecting labels --- Makefile | 5 + api/api.swagger.json | 50 ++++++- api/label.pb.go | 274 +++++++++++++++++++++++++--------- api/label.pb.gw.go | 135 +++++++++++++++++ api/label.proto | 13 ++ pkg/filter.go | 2 +- pkg/labels.go | 64 ++++++++ pkg/util/sql/sql.go | 4 +- server/converter/converter.go | 23 +++ server/label_server.go | 27 ++++ 10 files changed, 527 insertions(+), 70 deletions(-) diff --git a/Makefile b/Makefile index b5dd32d..94c7921 100644 --- a/Makefile +++ b/Makefile @@ -33,6 +33,11 @@ docker-build: docker-push: docker push onepanel/core:$(COMMIT_HASH) +docker-custom: + docker build -t onepanel-core . + docker tag onepanel-core:latest onepanel/core:$(TAG) + docker push onepanel/core:$(TAG) + docker: docker-build docker-push run-tests: diff --git a/api/api.swagger.json b/api/api.swagger.json index 32345fc..63fe582 100644 --- a/api/api.swagger.json +++ b/api/api.swagger.json @@ -3,7 +3,7 @@ "info": { "title": "Onepanel", "description": "Onepanel API", - "version": "0.14.0", + "version": "0.15.0", "contact": { "name": "Onepanel project", "url": "https://github.com/onepanelio/core" @@ -108,6 +108,54 @@ ] } }, + "/apis/v1beta1/labels/{namespace}/{resource}/labels": { + "get": { + "operationId": "GetAvailableLabels", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/GetLabelsResponse" + } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/grpc.gateway.runtime.Error" + } + } + }, + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "resource", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "keyLike", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "skipKeys", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "LabelService" + ] + } + }, "/apis/v1beta1/namespaces": { "get": { "operationId": "ListNamespaces", diff --git a/api/label.pb.go b/api/label.pb.go index a1a2481..3388ab7 100644 --- a/api/label.pb.go +++ b/api/label.pb.go @@ -337,6 +337,77 @@ func (x *GetLabelsRequest) GetUid() string { return "" } +type GetAvailableLabelsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` + Resource string `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"` + KeyLike string `protobuf:"bytes,3,opt,name=keyLike,proto3" json:"keyLike,omitempty"` + SkipKeys string `protobuf:"bytes,4,opt,name=skipKeys,proto3" json:"skipKeys,omitempty"` +} + +func (x *GetAvailableLabelsRequest) Reset() { + *x = GetAvailableLabelsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_label_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetAvailableLabelsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAvailableLabelsRequest) ProtoMessage() {} + +func (x *GetAvailableLabelsRequest) ProtoReflect() protoreflect.Message { + mi := &file_label_proto_msgTypes[5] + 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 GetAvailableLabelsRequest.ProtoReflect.Descriptor instead. +func (*GetAvailableLabelsRequest) Descriptor() ([]byte, []int) { + return file_label_proto_rawDescGZIP(), []int{5} +} + +func (x *GetAvailableLabelsRequest) GetNamespace() string { + if x != nil { + return x.Namespace + } + return "" +} + +func (x *GetAvailableLabelsRequest) GetResource() string { + if x != nil { + return x.Resource + } + return "" +} + +func (x *GetAvailableLabelsRequest) GetKeyLike() string { + if x != nil { + return x.KeyLike + } + return "" +} + +func (x *GetAvailableLabelsRequest) GetSkipKeys() string { + if x != nil { + return x.SkipKeys + } + return "" +} + type GetLabelsResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -348,7 +419,7 @@ type GetLabelsResponse struct { func (x *GetLabelsResponse) Reset() { *x = GetLabelsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_label_proto_msgTypes[5] + mi := &file_label_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -361,7 +432,7 @@ func (x *GetLabelsResponse) String() string { func (*GetLabelsResponse) ProtoMessage() {} func (x *GetLabelsResponse) ProtoReflect() protoreflect.Message { - mi := &file_label_proto_msgTypes[5] + mi := &file_label_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -374,7 +445,7 @@ func (x *GetLabelsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetLabelsResponse.ProtoReflect.Descriptor instead. func (*GetLabelsResponse) Descriptor() ([]byte, []int) { - return file_label_proto_rawDescGZIP(), []int{5} + return file_label_proto_rawDescGZIP(), []int{6} } func (x *GetLabelsResponse) GetLabels() []*KeyValue { @@ -398,7 +469,7 @@ type DeleteLabelRequest struct { func (x *DeleteLabelRequest) Reset() { *x = DeleteLabelRequest{} if protoimpl.UnsafeEnabled { - mi := &file_label_proto_msgTypes[6] + mi := &file_label_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -411,7 +482,7 @@ func (x *DeleteLabelRequest) String() string { func (*DeleteLabelRequest) ProtoMessage() {} func (x *DeleteLabelRequest) ProtoReflect() protoreflect.Message { - mi := &file_label_proto_msgTypes[6] + mi := &file_label_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -424,7 +495,7 @@ func (x *DeleteLabelRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteLabelRequest.ProtoReflect.Descriptor instead. func (*DeleteLabelRequest) Descriptor() ([]byte, []int) { - return file_label_proto_rawDescGZIP(), []int{6} + return file_label_proto_rawDescGZIP(), []int{7} } func (x *DeleteLabelRequest) GetNamespace() string { @@ -490,51 +561,69 @@ var file_label_proto_rawDesc = []byte{ 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x75, 0x69, 0x64, 0x22, 0x3a, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, - 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4b, - 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x22, - 0x72, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, - 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, - 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x32, 0x8d, 0x04, 0x0a, 0x0c, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0x75, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, - 0x73, 0x12, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x75, 0x69, 0x64, 0x22, 0x8b, 0x01, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, + 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, + 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6b, + 0x65, 0x79, 0x4c, 0x69, 0x6b, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, + 0x79, 0x4c, 0x69, 0x6b, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x6b, 0x69, 0x70, 0x4b, 0x65, 0x79, + 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x6b, 0x69, 0x70, 0x4b, 0x65, 0x79, + 0x73, 0x22, 0x3a, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4b, 0x65, 0x79, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x22, 0x72, 0x0a, + 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x10, 0x0a, + 0x03, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x32, 0x98, 0x05, 0x0a, 0x0c, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x12, 0x88, 0x01, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, + 0x62, 0x6c, 0x65, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x47, 0x65, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x61, 0x62, 0x65, + 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x47, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x3a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x34, 0x12, 0x32, 0x2f, 0x61, 0x70, 0x69, 0x73, + 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x2f, + 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x7b, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x7d, 0x2f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x75, 0x0a, + 0x09, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x15, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x39, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x33, 0x12, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x7b, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x7d, 0x2f, 0x7b, 0x75, 0x69, 0x64, 0x7d, 0x2f, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x73, 0x12, 0x7d, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x73, 0x12, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x64, 0x64, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x39, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x33, 0x12, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, + 0x22, 0x41, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3b, 0x22, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x7b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x7d, 0x2f, 0x7b, - 0x75, 0x69, 0x64, 0x7d, 0x2f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x7d, 0x0a, 0x09, 0x41, - 0x64, 0x64, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x41, - 0x64, 0x64, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x41, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3b, 0x22, - 0x31, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x7b, - 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x7b, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x7d, 0x2f, 0x7b, 0x75, 0x69, 0x64, 0x7d, 0x2f, 0x6c, 0x61, 0x62, 0x65, - 0x6c, 0x73, 0x3a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x85, 0x01, 0x0a, 0x0d, 0x52, - 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x19, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, - 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x41, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3b, 0x1a, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x7d, 0x2f, 0x7b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x7d, 0x2f, 0x7b, 0x75, - 0x69, 0x64, 0x7d, 0x2f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x06, 0x6c, 0x61, 0x62, 0x65, - 0x6c, 0x73, 0x12, 0x7f, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4c, 0x61, 0x62, 0x65, - 0x6c, 0x12, 0x17, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4c, 0x61, - 0x62, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x3f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x39, 0x2a, 0x37, 0x2f, 0x61, 0x70, 0x69, - 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x7b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x7d, - 0x2f, 0x7b, 0x75, 0x69, 0x64, 0x7d, 0x2f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x2f, 0x7b, 0x6b, - 0x65, 0x79, 0x7d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x75, 0x69, 0x64, 0x7d, 0x2f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x06, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x73, 0x12, 0x85, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x70, 0x6c, + 0x61, 0x63, 0x65, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x41, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3b, + 0x1a, 0x31, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, + 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x7b, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x7d, 0x2f, 0x7b, 0x75, 0x69, 0x64, 0x7d, 0x2f, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x73, 0x3a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x7f, 0x0a, 0x0b, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x17, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x62, + 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3f, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x39, 0x2a, 0x37, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x7b, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x7d, 0x2f, 0x7b, 0x75, 0x69, 0x64, 0x7d, 0x2f, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x2f, 0x7b, 0x6b, 0x65, 0x79, 0x7d, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -549,31 +638,34 @@ func file_label_proto_rawDescGZIP() []byte { return file_label_proto_rawDescData } -var file_label_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_label_proto_msgTypes = make([]protoimpl.MessageInfo, 8) var file_label_proto_goTypes = []interface{}{ - (*KeyValue)(nil), // 0: api.KeyValue - (*Labels)(nil), // 1: api.Labels - (*AddLabelsRequest)(nil), // 2: api.AddLabelsRequest - (*ReplaceLabelsRequest)(nil), // 3: api.ReplaceLabelsRequest - (*GetLabelsRequest)(nil), // 4: api.GetLabelsRequest - (*GetLabelsResponse)(nil), // 5: api.GetLabelsResponse - (*DeleteLabelRequest)(nil), // 6: api.DeleteLabelRequest + (*KeyValue)(nil), // 0: api.KeyValue + (*Labels)(nil), // 1: api.Labels + (*AddLabelsRequest)(nil), // 2: api.AddLabelsRequest + (*ReplaceLabelsRequest)(nil), // 3: api.ReplaceLabelsRequest + (*GetLabelsRequest)(nil), // 4: api.GetLabelsRequest + (*GetAvailableLabelsRequest)(nil), // 5: api.GetAvailableLabelsRequest + (*GetLabelsResponse)(nil), // 6: api.GetLabelsResponse + (*DeleteLabelRequest)(nil), // 7: api.DeleteLabelRequest } var file_label_proto_depIdxs = []int32{ 0, // 0: api.Labels.items:type_name -> api.KeyValue 1, // 1: api.AddLabelsRequest.labels:type_name -> api.Labels 1, // 2: api.ReplaceLabelsRequest.labels:type_name -> api.Labels 0, // 3: api.GetLabelsResponse.labels:type_name -> api.KeyValue - 4, // 4: api.LabelService.GetLabels:input_type -> api.GetLabelsRequest - 2, // 5: api.LabelService.AddLabels:input_type -> api.AddLabelsRequest - 3, // 6: api.LabelService.ReplaceLabels:input_type -> api.ReplaceLabelsRequest - 6, // 7: api.LabelService.DeleteLabel:input_type -> api.DeleteLabelRequest - 5, // 8: api.LabelService.GetLabels:output_type -> api.GetLabelsResponse - 5, // 9: api.LabelService.AddLabels:output_type -> api.GetLabelsResponse - 5, // 10: api.LabelService.ReplaceLabels:output_type -> api.GetLabelsResponse - 5, // 11: api.LabelService.DeleteLabel:output_type -> api.GetLabelsResponse - 8, // [8:12] is the sub-list for method output_type - 4, // [4:8] is the sub-list for method input_type + 5, // 4: api.LabelService.GetAvailableLabels:input_type -> api.GetAvailableLabelsRequest + 4, // 5: api.LabelService.GetLabels:input_type -> api.GetLabelsRequest + 2, // 6: api.LabelService.AddLabels:input_type -> api.AddLabelsRequest + 3, // 7: api.LabelService.ReplaceLabels:input_type -> api.ReplaceLabelsRequest + 7, // 8: api.LabelService.DeleteLabel:input_type -> api.DeleteLabelRequest + 6, // 9: api.LabelService.GetAvailableLabels:output_type -> api.GetLabelsResponse + 6, // 10: api.LabelService.GetLabels:output_type -> api.GetLabelsResponse + 6, // 11: api.LabelService.AddLabels:output_type -> api.GetLabelsResponse + 6, // 12: api.LabelService.ReplaceLabels:output_type -> api.GetLabelsResponse + 6, // 13: api.LabelService.DeleteLabel:output_type -> api.GetLabelsResponse + 9, // [9:14] is the sub-list for method output_type + 4, // [4:9] is the sub-list for method input_type 4, // [4:4] is the sub-list for extension type_name 4, // [4:4] is the sub-list for extension extendee 0, // [0:4] is the sub-list for field type_name @@ -646,7 +738,7 @@ func file_label_proto_init() { } } file_label_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetLabelsResponse); i { + switch v := v.(*GetAvailableLabelsRequest); i { case 0: return &v.state case 1: @@ -658,6 +750,18 @@ func file_label_proto_init() { } } file_label_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetLabelsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_label_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DeleteLabelRequest); i { case 0: return &v.state @@ -676,7 +780,7 @@ func file_label_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_label_proto_rawDesc, NumEnums: 0, - NumMessages: 7, + NumMessages: 8, NumExtensions: 0, NumServices: 1, }, @@ -702,6 +806,7 @@ 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 LabelServiceClient interface { + GetAvailableLabels(ctx context.Context, in *GetAvailableLabelsRequest, opts ...grpc.CallOption) (*GetLabelsResponse, error) GetLabels(ctx context.Context, in *GetLabelsRequest, opts ...grpc.CallOption) (*GetLabelsResponse, error) AddLabels(ctx context.Context, in *AddLabelsRequest, opts ...grpc.CallOption) (*GetLabelsResponse, error) ReplaceLabels(ctx context.Context, in *ReplaceLabelsRequest, opts ...grpc.CallOption) (*GetLabelsResponse, error) @@ -716,6 +821,15 @@ func NewLabelServiceClient(cc grpc.ClientConnInterface) LabelServiceClient { return &labelServiceClient{cc} } +func (c *labelServiceClient) GetAvailableLabels(ctx context.Context, in *GetAvailableLabelsRequest, opts ...grpc.CallOption) (*GetLabelsResponse, error) { + out := new(GetLabelsResponse) + err := c.cc.Invoke(ctx, "/api.LabelService/GetAvailableLabels", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *labelServiceClient) GetLabels(ctx context.Context, in *GetLabelsRequest, opts ...grpc.CallOption) (*GetLabelsResponse, error) { out := new(GetLabelsResponse) err := c.cc.Invoke(ctx, "/api.LabelService/GetLabels", in, out, opts...) @@ -754,6 +868,7 @@ func (c *labelServiceClient) DeleteLabel(ctx context.Context, in *DeleteLabelReq // LabelServiceServer is the server API for LabelService service. type LabelServiceServer interface { + GetAvailableLabels(context.Context, *GetAvailableLabelsRequest) (*GetLabelsResponse, error) GetLabels(context.Context, *GetLabelsRequest) (*GetLabelsResponse, error) AddLabels(context.Context, *AddLabelsRequest) (*GetLabelsResponse, error) ReplaceLabels(context.Context, *ReplaceLabelsRequest) (*GetLabelsResponse, error) @@ -764,6 +879,9 @@ type LabelServiceServer interface { type UnimplementedLabelServiceServer struct { } +func (*UnimplementedLabelServiceServer) GetAvailableLabels(context.Context, *GetAvailableLabelsRequest) (*GetLabelsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetAvailableLabels not implemented") +} func (*UnimplementedLabelServiceServer) GetLabels(context.Context, *GetLabelsRequest) (*GetLabelsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetLabels not implemented") } @@ -781,6 +899,24 @@ func RegisterLabelServiceServer(s *grpc.Server, srv LabelServiceServer) { s.RegisterService(&_LabelService_serviceDesc, srv) } +func _LabelService_GetAvailableLabels_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetAvailableLabelsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(LabelServiceServer).GetAvailableLabels(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/api.LabelService/GetAvailableLabels", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(LabelServiceServer).GetAvailableLabels(ctx, req.(*GetAvailableLabelsRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _LabelService_GetLabels_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetLabelsRequest) if err := dec(in); err != nil { @@ -857,6 +993,10 @@ var _LabelService_serviceDesc = grpc.ServiceDesc{ ServiceName: "api.LabelService", HandlerType: (*LabelServiceServer)(nil), Methods: []grpc.MethodDesc{ + { + MethodName: "GetAvailableLabels", + Handler: _LabelService_GetAvailableLabels_Handler, + }, { MethodName: "GetLabels", Handler: _LabelService_GetLabels_Handler, diff --git a/api/label.pb.gw.go b/api/label.pb.gw.go index f837c3d..1c264cc 100644 --- a/api/label.pb.gw.go +++ b/api/label.pb.gw.go @@ -31,6 +31,97 @@ var _ = runtime.String var _ = utilities.NewDoubleArray var _ = descriptor.ForMessage +var ( + filter_LabelService_GetAvailableLabels_0 = &utilities.DoubleArray{Encoding: map[string]int{"namespace": 0, "resource": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} +) + +func request_LabelService_GetAvailableLabels_0(ctx context.Context, marshaler runtime.Marshaler, client LabelServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetAvailableLabelsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["namespace"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") + } + + protoReq.Namespace, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) + } + + val, ok = pathParams["resource"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "resource") + } + + protoReq.Resource, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "resource", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_LabelService_GetAvailableLabels_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.GetAvailableLabels(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_LabelService_GetAvailableLabels_0(ctx context.Context, marshaler runtime.Marshaler, server LabelServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetAvailableLabelsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["namespace"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") + } + + protoReq.Namespace, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) + } + + val, ok = pathParams["resource"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "resource") + } + + protoReq.Resource, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "resource", err) + } + + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_LabelService_GetAvailableLabels_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.GetAvailableLabels(ctx, &protoReq) + return msg, metadata, err + +} + func request_LabelService_GetLabels_0(ctx context.Context, marshaler runtime.Marshaler, client LabelServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq GetLabelsRequest var metadata runtime.ServerMetadata @@ -482,6 +573,26 @@ func local_request_LabelService_DeleteLabel_0(ctx context.Context, marshaler run // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. func RegisterLabelServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server LabelServiceServer) error { + mux.Handle("GET", pattern_LabelService_GetAvailableLabels_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_LabelService_GetAvailableLabels_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_LabelService_GetAvailableLabels_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_LabelService_GetLabels_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -603,6 +714,26 @@ func RegisterLabelServiceHandler(ctx context.Context, mux *runtime.ServeMux, con // "LabelServiceClient" to call the correct interceptors. func RegisterLabelServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client LabelServiceClient) error { + mux.Handle("GET", pattern_LabelService_GetAvailableLabels_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_LabelService_GetAvailableLabels_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_LabelService_GetAvailableLabels_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_LabelService_GetLabels_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -687,6 +818,8 @@ func RegisterLabelServiceHandlerClient(ctx context.Context, mux *runtime.ServeMu } var ( + pattern_LabelService_GetAvailableLabels_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4, 2, 2}, []string{"apis", "v1beta1", "labels", "namespace", "resource"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_LabelService_GetLabels_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"apis", "v1beta1", "namespace", "resource", "uid", "labels"}, "", runtime.AssumeColonVerbOpt(true))) pattern_LabelService_AddLabels_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"apis", "v1beta1", "namespace", "resource", "uid", "labels"}, "", runtime.AssumeColonVerbOpt(true))) @@ -697,6 +830,8 @@ var ( ) var ( + forward_LabelService_GetAvailableLabels_0 = runtime.ForwardResponseMessage + forward_LabelService_GetLabels_0 = runtime.ForwardResponseMessage forward_LabelService_AddLabels_0 = runtime.ForwardResponseMessage diff --git a/api/label.proto b/api/label.proto index 60c3943..c6d3976 100644 --- a/api/label.proto +++ b/api/label.proto @@ -5,6 +5,12 @@ package api; import "google/api/annotations.proto"; service LabelService { + rpc GetAvailableLabels (GetAvailableLabelsRequest) returns (GetLabelsResponse) { + option (google.api.http) = { + get: "/apis/v1beta1/labels/{namespace}/{resource}/labels" + }; + } + rpc GetLabels (GetLabelsRequest) returns (GetLabelsResponse) { option (google.api.http) = { get: "/apis/v1beta1/{namespace}/{resource}/{uid}/labels" @@ -61,6 +67,13 @@ message GetLabelsRequest { string uid = 3; } +message GetAvailableLabelsRequest { + string namespace = 1; + string resource = 2; + string keyLike = 3; + string skipKeys = 4; +} + message GetLabelsResponse { repeated KeyValue labels = 1; } diff --git a/pkg/filter.go b/pkg/filter.go index 8468599..7321b6c 100644 --- a/pkg/filter.go +++ b/pkg/filter.go @@ -22,7 +22,7 @@ func ApplyLabelSelectQuery(labelSelector string, sb sq.SelectBuilder, filter Lab return sb, err } - sb = sb.Where("%v @> ?", labelSelector, labelsJSON) + sb = sb.Where(labelSelector+" @> ?", labelsJSON) return sb, nil } diff --git a/pkg/labels.go b/pkg/labels.go index 7a41385..3b2e2eb 100644 --- a/pkg/labels.go +++ b/pkg/labels.go @@ -8,8 +8,63 @@ import ( "github.com/onepanelio/core/pkg/util/mapping" "github.com/onepanelio/core/pkg/util/types" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "strings" ) +// SelectLabelsQuery represents the options available to filter a select labels query +type SelectLabelsQuery struct { + Table string + Alias string + Namespace string + KeyLike string + Skip []string +} + +// SkipKeysFromString parses keys encoded in a string and returns an array of keys +// The separator is ";" +func SkipKeysFromString(keys string) []string { + results := make([]string, 0) + for _, key := range strings.Split(keys, ";") { + if key == "" { + continue + } + + results = append(results, key) + } + + return results +} + +// SelectLabels returns a SelectBuilder that selects key, value columns from the criteria specified in query +func SelectLabels(query *SelectLabelsQuery) sq.SelectBuilder { + // Sample query + // SELECT DISTINCT labels.* + // FROM workflow_executions w, + // jsonb_each_text(w.labels) labels + // WHERE labels.key LIKE 'ca%' + // AND labels.key NOT IN ('catdog') + // AND namespace = 'onepanel' + + fromTable := fmt.Sprintf("%s %s", query.Table, query.Alias) + fromJsonb := fmt.Sprintf("jsonb_each_text(%s.labels) labels", query.Alias) + + bld := sb.Select("key", "value"). + Distinct(). + From(fromTable + ", " + fromJsonb) + + if query.Namespace != "" { + bld = bld.Where(sq.Eq{query.Alias + ".namespace": query.Namespace}) + } + if query.KeyLike != "" { + bld = bld.Where(sq.Like{"labels.key": query.KeyLike}) + } + if len(query.Skip) != 0 { + bld = bld.Where(sq.NotEq{"labels.key": query.Skip}) + } + + return bld +} + func (c *Client) ListLabels(resource string, uid string) (labels []*Label, err error) { sb := sb.Select("labels"). From(TypeToTableName(resource)) @@ -49,6 +104,15 @@ func (c *Client) ListLabels(resource string, uid string) (labels []*Label, err e return } +// ListAvailableLabels lists the labels available for the resource specified by the query +func (c *Client) ListAvailableLabels(query *SelectLabelsQuery) (result []*Label, err error) { + selectLabelsBuilder := SelectLabels(query) + + err = c.Selectx(&result, selectLabelsBuilder) + + return +} + func (c *Client) AddLabels(namespace, resource, uid string, keyValues map[string]string) error { source, meta, err := c.GetK8sLabelResource(namespace, resource, uid) if err != nil { diff --git a/pkg/util/sql/sql.go b/pkg/util/sql/sql.go index b08eef8..4179bd0 100644 --- a/pkg/util/sql/sql.go +++ b/pkg/util/sql/sql.go @@ -1,6 +1,8 @@ package sql -import "fmt" +import ( + "fmt" +) // FormatColumnSelect returns a list of column names to be used in a SQL Select modified with optional alias and destination. // diff --git a/server/converter/converter.go b/server/converter/converter.go index 49e115f..a005884 100644 --- a/server/converter/converter.go +++ b/server/converter/converter.go @@ -37,6 +37,29 @@ func MappingToKeyValue(mapping map[string]string) []*api.KeyValue { return keyValues } +// LabelsToKeyValues converts []*v1.Label to []*api.Label +func LabelsToKeyValues(labels []*v1.Label) []*api.KeyValue { + keyValues := make([]*api.KeyValue, 0) + + for _, label := range labels { + keyValues = append(keyValues, LabelToKeyValue(label)) + } + + sort.Slice(keyValues, func(i, j int) bool { + return keyValues[i].Key < keyValues[j].Key + }) + + return keyValues +} + +// LabelToKeyValue converts a *v1.Label to *api.Label +func LabelToKeyValue(label *v1.Label) *api.KeyValue { + return &api.KeyValue{ + Key: label.Key, + Value: label.Value, + } +} + func ParameterOptionToAPI(option *v1.ParameterOption) *api.ParameterOption { apiOption := &api.ParameterOption{ Name: option.Name, diff --git a/server/label_server.go b/server/label_server.go index 9e02d5d..eaa27b4 100644 --- a/server/label_server.go +++ b/server/label_server.go @@ -5,6 +5,7 @@ import ( "github.com/onepanelio/core/api" v1 "github.com/onepanelio/core/pkg" "github.com/onepanelio/core/server/auth" + "github.com/onepanelio/core/server/converter" ) func getGroupAndResourceByIdentifier(identifier string) (group, resource string) { @@ -147,3 +148,29 @@ func (s *LabelServer) DeleteLabel(ctx context.Context, req *api.DeleteLabelReque Labels: mapLabelsToKeyValue(labels), }, nil } + +// GetAvailableLabels returns the labels available for a resource specified by the GetAvailableLabelsRequest +func (s *LabelServer) GetAvailableLabels(ctx context.Context, req *api.GetAvailableLabelsRequest) (*api.GetLabelsResponse, error) { + group, resource := getGroupAndResourceByIdentifier(req.Resource) + + client := getClient(ctx) + allowed, err := auth.IsAuthorized(client, req.Namespace, "get", group, resource, "") + if err != nil || !allowed { + return nil, err + } + + labels, err := client.ListAvailableLabels(&v1.SelectLabelsQuery{ + Table: v1.TypeToTableName(req.Resource), + Alias: "l", + Namespace: req.Namespace, + KeyLike: req.KeyLike + "%", + Skip: v1.SkipKeysFromString(req.SkipKeys), + }) + if err != nil { + return nil, err + } + + return &api.GetLabelsResponse{ + Labels: converter.LabelsToKeyValues(labels), + }, nil +}