From 5e3fa39bfd4de4e331a3f032f04fba066f266f85 Mon Sep 17 00:00:00 2001
From: Vaibhav
Date: Wed, 1 Apr 2020 08:02:44 -0400
Subject: [PATCH] feat: added label and field selectors for resource gateway
(#571)
---
api/event-source.html | 71 ++++++++-
api/event-source.md | 136 +++++++++++++++++-
api/gateway.html | 2 +-
api/gateway.md | 3 +-
api/sensor.html | 2 +-
api/sensor.md | 3 +-
gateways/server/resource/start.go | 30 ++--
gateways/server/resource/validate.go | 25 ++++
pkg/apis/eventsources/v1alpha1/types.go | 17 ++-
.../v1alpha1/zz_generated.deepcopy.go | 28 ++--
10 files changed, 286 insertions(+), 31 deletions(-)
diff --git a/api/event-source.html b/api/event-source.html
index 35bc81c321..23087ba95c 100644
--- a/api/event-source.html
+++ b/api/event-source.html
@@ -174,6 +174,7 @@ AzureEventsHubEventSourc
+(Optional)
Namespace refers to Kubernetes namespace which is used to retrieve the shared access key and name from.
|
@@ -315,6 +316,7 @@ EmitterEventSource
+(Optional)
Namespace to use to retrieve the channel key and optional username/password
|
@@ -1025,6 +1027,7 @@ GithubEventSource
+(Optional)
Namespace refers to Kubernetes namespace which is used to retrieve webhook secret and api token from.
|
@@ -1137,6 +1140,7 @@ GitlabEventSource
+(Optional)
Namespace refers to Kubernetes namespace which is used to retrieve access token from.
|
@@ -1327,6 +1331,7 @@ HDFSEventSource
+(Optional)
Namespace refers to Kubernetes namespace which is used to retrieve cache secret and ket tab secret from.
|
@@ -1899,7 +1904,9 @@ ResourceFilter
labels
-map[string]string
+
+[]Selector
+
|
@@ -1910,7 +1917,9 @@ ResourceFilter
fields
-map[string]string
+
+[]Selector
+
|
@@ -2162,6 +2171,61 @@ SQSEventSource
+Selector
+
+
+(Appears on:
+ResourceFilter)
+
+
+ Selector represents conditional operation to select K8s objects.
+
+
SlackEventSource
@@ -2224,6 +2288,7 @@ SlackEventSource
|
+(Optional)
Namespace refers to Kubernetes namespace which is used to retrieve token and signing secret from.
|
@@ -2409,5 +2474,5 @@ StripeEventSource
Generated with gen-crd-api-reference-docs
-on git commit 1782e0f .
+on git commit 739f169 .
diff --git a/api/event-source.md b/api/event-source.md
index 6d36edc37d..570adca306 100644
--- a/api/event-source.md
+++ b/api/event-source.md
@@ -359,6 +359,8 @@ Event Hub path/name
|
+(Optional)
+
Namespace refers to Kubernetes namespace which is used to retrieve the
@@ -653,6 +655,8 @@ ChannelName refers to the channel name
|
+(Optional)
+
Namespace to use to retrieve the channel key and optional
@@ -2009,6 +2013,8 @@ GitHub upload URL (for GitHub Enterprise)
|
+(Optional)
+
Namespace refers to Kubernetes namespace which is used to retrieve
@@ -2232,6 +2238,8 @@ GitlabBaseURL is the base URL for API requests to a custom endpoint
|
+(Optional)
+
Namespace refers to Kubernetes namespace which is used to retrieve
@@ -2585,6 +2593,8 @@ must be set if either ccache or keytab is used.
|
+(Optional)
+
Namespace refers to Kubernetes namespace which is used to retrieve cache
@@ -3764,7 +3774,8 @@ Description
|
-labels map\[string\]string
+labels
+\[\]Selector
|
@@ -3780,7 +3791,8 @@ Description
-fields map\[string\]string
+fields
+\[\]Selector
|
@@ -4263,6 +4275,121 @@ monitor
+
+
+Selector
+
+
+
+
+
+(Appears on:
+ResourceFilter)
+
+
+
+
+
+
+
+Selector represents conditional operation to select K8s objects.
+
+
+
+
+
+
SlackEventSource
@@ -4386,6 +4513,8 @@ Webhook holds configuration for a REST endpoint
+(Optional)
+
Namespace refers to Kubernetes namespace which is used to retrieve token
@@ -4774,5 +4903,6 @@ all types of events will be processed. More info at
Generated with gen-crd-api-reference-docs on git
-commit 1782e0f .
+commit 739f169 .
+
diff --git a/api/gateway.html b/api/gateway.html
index a82f0300f2..f558530ed0 100644
--- a/api/gateway.html
+++ b/api/gateway.html
@@ -671,5 +671,5 @@ Subscribers
Generated with gen-crd-api-reference-docs
-on git commit 1782e0f .
+on git commit 739f169 .
diff --git a/api/gateway.md b/api/gateway.md
index 5f91474494..a176d36432 100644
--- a/api/gateway.md
+++ b/api/gateway.md
@@ -1321,5 +1321,6 @@ NATS refers to the subscribers over NATS protocol.
Generated with gen-crd-api-reference-docs on git
-commit 1782e0f .
+commit 739f169 .
+
diff --git a/api/sensor.html b/api/sensor.html
index 066f5e044f..94567110a8 100644
--- a/api/sensor.html
+++ b/api/sensor.html
@@ -3131,5 +3131,5 @@ URLArtifact
Generated with gen-crd-api-reference-docs
-on git commit 1782e0f .
+on git commit 739f169 .
diff --git a/api/sensor.md b/api/sensor.md
index 3a124f7f78..d204500f1e 100644
--- a/api/sensor.md
+++ b/api/sensor.md
@@ -6239,5 +6239,6 @@ VerifyCert decides whether the connection is secure or not
Generated with gen-crd-api-reference-docs on git
-commit 1782e0f .
+commit 739f169 .
+
diff --git a/gateways/server/resource/start.go b/gateways/server/resource/start.go
index a8f50e2567..88bca21c35 100644
--- a/gateways/server/resource/start.go
+++ b/gateways/server/resource/start.go
@@ -218,8 +218,12 @@ func (listener *EventListener) listenEvents(eventSource *gateways.EventSource, c
}
// LabelReq returns label requirements
-func LabelReq(key, value string) (*labels.Requirement, error) {
- req, err := labels.NewRequirement(key, selection.Equals, []string{value})
+func LabelReq(sel v1alpha1.Selector) (*labels.Requirement, error) {
+ op := selection.Equals
+ if sel.Operation != "" {
+ op = selection.Operator(sel.Operation)
+ }
+ req, err := labels.NewRequirement(sel.Key, op, []string{sel.Value})
if err != nil {
return nil, err
}
@@ -227,10 +231,10 @@ func LabelReq(key, value string) (*labels.Requirement, error) {
}
// LabelSelector returns label selector for resource filtering
-func LabelSelector(resourceLabels map[string]string) (labels.Selector, error) {
+func LabelSelector(selectors []v1alpha1.Selector) (labels.Selector, error) {
var labelRequirements []labels.Requirement
- for key, value := range resourceLabels {
- req, err := LabelReq(key, value)
+ for _, sel := range selectors {
+ req, err := LabelReq(sel)
if err != nil {
return nil, err
}
@@ -240,16 +244,20 @@ func LabelSelector(resourceLabels map[string]string) (labels.Selector, error) {
}
// FieldSelector returns field selector for resource filtering
-func FieldSelector(fieldSelectors map[string]string) (fields.Selector, error) {
- var selectors []fields.Selector
- for key, value := range fieldSelectors {
- selector, err := fields.ParseSelector(fmt.Sprintf("%s=%s", key, value))
+func FieldSelector(selectors []v1alpha1.Selector) (fields.Selector, error) {
+ var result []fields.Selector
+ for _, sel := range selectors {
+ op := selection.Equals
+ if sel.Operation != "" {
+ op = selection.Operator(sel.Operation)
+ }
+ selector, err := fields.ParseSelector(fmt.Sprintf("%s%s%s", sel.Key, op, sel.Value))
if err != nil {
return nil, err
}
- selectors = append(selectors, selector)
+ result = append(result, selector)
}
- return fields.AndSelectors(selectors...), nil
+ return fields.AndSelectors(result...), nil
}
// helper method to check if the object passed the user defined filters
diff --git a/gateways/server/resource/validate.go b/gateways/server/resource/validate.go
index 1a0bb5133f..480825b2a3 100644
--- a/gateways/server/resource/validate.go
+++ b/gateways/server/resource/validate.go
@@ -19,6 +19,7 @@ package resource
import (
"context"
"fmt"
+ "k8s.io/apimachinery/pkg/selection"
"github.com/argoproj/argo-events/common"
"github.com/argoproj/argo-events/gateways"
@@ -71,5 +72,29 @@ func validate(eventSource *v1alpha1.ResourceEventSource) error {
if eventSource.EventTypes == nil {
return fmt.Errorf("event types must be specified")
}
+ if eventSource.Filter != nil {
+ if eventSource.Filter.Labels != nil {
+ if err := validateSelectors(eventSource.Filter.Labels); err != nil {
+ return err
+ }
+ }
+ if eventSource.Filter.Fields != nil {
+ if err := validateSelectors(eventSource.Filter.Fields); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func validateSelectors(selectors []v1alpha1.Selector) error {
+ for _, sel := range selectors {
+ if sel.Operation == "" {
+ continue
+ }
+ if selection.Operator(sel.Operation) == "" {
+ return fmt.Errorf("unknown selection operation %s", sel.Operation)
+ }
+ }
return nil
}
diff --git a/pkg/apis/eventsources/v1alpha1/types.go b/pkg/apis/eventsources/v1alpha1/types.go
index a2c638f078..27df1cb292 100644
--- a/pkg/apis/eventsources/v1alpha1/types.go
+++ b/pkg/apis/eventsources/v1alpha1/types.go
@@ -155,13 +155,26 @@ type ResourceFilter struct {
// +optional
Prefix string `json:"prefix,omitempty" protobuf:"bytes,1,opt,name=prefix"`
// +optional
- Labels map[string]string `json:"labels,omitempty" protobuf:"bytes,2,opt,name=labels"`
+ Labels []Selector `json:"labels,omitempty" protobuf:"bytes,2,opt,name=labels"`
// +optional
- Fields map[string]string `json:"fields,omitempty" protobuf:"bytes,3,opt,name=fields"`
+ Fields []Selector `json:"fields,omitempty" protobuf:"bytes,3,opt,name=fields"`
// +optional
CreatedBy metav1.Time `json:"createdBy,omitempty" protobuf:"bytes,4,opt,name=createdBy"`
}
+// Selector represents conditional operation to select K8s objects.
+type Selector struct {
+ // Key name
+ Key string `json:"key" protobuf:"bytes,1,name=key"`
+ // Supported operations like ==, !=, <=, >= etc.
+ // Defaults to ==.
+ // Refer https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors for more info.
+ // +optional
+ Operation string `json:"operation,omitempty" protobuf:"bytes,2,opt,name=operation"`
+ // Value
+ Value string `json:"value" protobuf:"bytes,3,name=value"`
+}
+
// AMQPEventSource refers to an event-source for AMQP stream events
type AMQPEventSource struct {
// URL for rabbitmq service
diff --git a/pkg/apis/eventsources/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventsources/v1alpha1/zz_generated.deepcopy.go
index ad5630492c..51c9615de0 100644
--- a/pkg/apis/eventsources/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/eventsources/v1alpha1/zz_generated.deepcopy.go
@@ -687,17 +687,13 @@ func (in *ResourceFilter) DeepCopyInto(out *ResourceFilter) {
*out = *in
if in.Labels != nil {
in, out := &in.Labels, &out.Labels
- *out = make(map[string]string, len(*in))
- for key, val := range *in {
- (*out)[key] = val
- }
+ *out = make([]Selector, len(*in))
+ copy(*out, *in)
}
if in.Fields != nil {
in, out := &in.Fields, &out.Fields
- *out = make(map[string]string, len(*in))
- for key, val := range *in {
- (*out)[key] = val
- }
+ *out = make([]Selector, len(*in))
+ copy(*out, *in)
}
in.CreatedBy.DeepCopyInto(&out.CreatedBy)
return
@@ -770,6 +766,22 @@ func (in *SQSEventSource) DeepCopy() *SQSEventSource {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Selector) DeepCopyInto(out *Selector) {
+ *out = *in
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Selector.
+func (in *Selector) DeepCopy() *Selector {
+ if in == nil {
+ return nil
+ }
+ out := new(Selector)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SlackEventSource) DeepCopyInto(out *SlackEventSource) {
*out = *in
|