From 63b038742f4ba82c2e794ae0793d3189d35387d5 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Braun Date: Mon, 14 Oct 2019 14:09:13 +0200 Subject: [PATCH] Introduce EventListener.Spec.ServiceType Allows to set the type of the underlying eventlistener service. If not set k8s will configure the service type to ClusterIP. Depending on the cloud provider or the ingress controller used the user might need to set the service type to `NodePort` or `LoadBalancer` to expose it externally. --- docs/eventlisteners.md | 13 ++++--- .../triggers/v1alpha1/event_listener_types.go | 1 + .../v1alpha1/eventlistener/eventlistener.go | 10 ++++-- .../eventlistener/eventlistener_test.go | 36 +++++++++++++++---- 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/docs/eventlisteners.md b/docs/eventlisteners.md index 965780f27..ec299b638 100644 --- a/docs/eventlisteners.md +++ b/docs/eventlisteners.md @@ -1,4 +1,5 @@ # EventListener + `EventListener`s connect `TriggerBinding`s to `TriggerTemplate`s and provide an addressable endpoint, which is where webhooks/events are directed. @@ -9,16 +10,20 @@ with. When an `EventListener` is successfully created, a service is created that references a listener pod. This listener pod accepts the incoming events and does what has been specified in the corresponding -`TriggerBinding`s/`TriggerTemplate`s. The service created is a `ClusterIP` service -which means any other pods running in the same Kubernetes cluster can access it via the service's -cluster DNS. For external services to connect to your cluster (e.g. GitHub -sending webhooks), check out the guide on [exposing eventlisteners](./exposing-eventlisteners.md) +`TriggerBinding`s/`TriggerTemplate`s. The service created is a `ClusterIP` service +which means any other pods running in the same Kubernetes cluster can access it via the service's +cluster DNS. For external services to connect to your cluster (e.g. GitHub +sending webhooks), check out the guide on [exposing eventlisteners](./exposing-eventlisteners.md) ## Parameters + `EventListener`s can provide `params` which are merged with the `TriggerBinding` `params` and passed to the `TriggerTemplate`. Each parameter has a `name` and a `value`. +`EventListener` `spec.serviceType` can be set to `ClusterIP (default)` | `NodePort` | `LoadBalancer` +to configure the underlying `Service` resource to make it reachable externally. + ## Event Interceptors Triggers within an `EventListener` can optionally specify an interceptor field diff --git a/pkg/apis/triggers/v1alpha1/event_listener_types.go b/pkg/apis/triggers/v1alpha1/event_listener_types.go index 224211ab3..e0be7c1e4 100644 --- a/pkg/apis/triggers/v1alpha1/event_listener_types.go +++ b/pkg/apis/triggers/v1alpha1/event_listener_types.go @@ -54,6 +54,7 @@ type EventListener struct { type EventListenerSpec struct { ServiceAccountName string `json:"serviceAccountName"` Triggers []EventListenerTrigger `json:"triggers"` + ServiceType corev1.ServiceType `json:"serviceType,omitempty"` } // EventListenerTrigger represents a connection between TriggerBinding, Params, diff --git a/pkg/reconciler/v1alpha1/eventlistener/eventlistener.go b/pkg/reconciler/v1alpha1/eventlistener/eventlistener.go index e9d9d243d..3ac30bf25 100644 --- a/pkg/reconciler/v1alpha1/eventlistener/eventlistener.go +++ b/pkg/reconciler/v1alpha1/eventlistener/eventlistener.go @@ -154,8 +154,7 @@ func (c *Reconciler) reconcileService(el *v1alpha1.EventListener) error { ObjectMeta: generateObjectMeta(el), Spec: corev1.ServiceSpec{ Selector: mergeLabels(el.Labels, GenerateResourceLabels(el.Name)), - // Cannot be changed - Type: corev1.ServiceTypeClusterIP, + Type: el.Spec.ServiceType, Ports: []corev1.ServicePort{ servicePort, }, @@ -170,6 +169,13 @@ func (c *Reconciler) reconcileService(el *v1alpha1.EventListener) error { existingService.Spec.Selector = service.Spec.Selector updated = true } + if existingService.Spec.Type != service.Spec.Type { + existingService.Spec.Type = service.Spec.Type + // When transitioning from NodePort or LoadBalancer to ClusterIP + // we need to remove NodePort from Ports + existingService.Spec.Ports = service.Spec.Ports + updated = true + } if !cmp.Equal(existingService.Spec.Ports, service.Spec.Ports, cmpopts.IgnoreFields(corev1.ServicePort{}, "NodePort")) { existingService.Spec.Ports = service.Spec.Ports updated = true diff --git a/pkg/reconciler/v1alpha1/eventlistener/eventlistener_test.go b/pkg/reconciler/v1alpha1/eventlistener/eventlistener_test.go index 337bcaa48..e77615a6a 100644 --- a/pkg/reconciler/v1alpha1/eventlistener/eventlistener_test.go +++ b/pkg/reconciler/v1alpha1/eventlistener/eventlistener_test.go @@ -130,7 +130,7 @@ func Test_reconcileService(t *testing.T) { ObjectMeta: generateObjectMeta(eventListener0), Spec: corev1.ServiceSpec{ Selector: generatedLabels, - Type: corev1.ServiceTypeClusterIP, + Type: eventListener1.Spec.ServiceType, Ports: []corev1.ServicePort{ servicePort, }, @@ -457,9 +457,12 @@ func TestReconcile(t *testing.T) { eventListener2 := eventListener1.DeepCopy() eventListener2.Labels = updateLabel - eventListener3 := eventListener1.DeepCopy() + eventListener3 := eventListener2.DeepCopy() eventListener3.Spec.ServiceAccountName = updatedSa + eventListener4 := eventListener3.DeepCopy() + eventListener4.Spec.ServiceType = corev1.ServiceTypeNodePort + var replicas int32 = 1 deployment1 := &appsv1.Deployment{ ObjectMeta: generateObjectMeta(eventListener0), @@ -507,14 +510,14 @@ func TestReconcile(t *testing.T) { deployment2.Spec.Selector.MatchLabels = mergeLabels(updateLabel, generatedLabels) deployment2.Spec.Template.Labels = mergeLabels(updateLabel, generatedLabels) - deployment3 := deployment1.DeepCopy() + deployment3 := deployment2.DeepCopy() deployment3.Spec.Template.Spec.ServiceAccountName = updatedSa service1 := &corev1.Service{ ObjectMeta: generateObjectMeta(eventListener0), Spec: corev1.ServiceSpec{ Selector: generatedLabels, - Type: corev1.ServiceTypeClusterIP, + Type: eventListener1.Spec.ServiceType, Ports: []corev1.ServicePort{ servicePort, }, @@ -525,6 +528,9 @@ func TestReconcile(t *testing.T) { service2.Labels = mergeLabels(updateLabel, generatedLabels) service2.Spec.Selector = mergeLabels(updateLabel, generatedLabels) + service3 := service2.DeepCopy() + service3.Spec.Type = corev1.ServiceTypeNodePort + tests := []struct { name string key string @@ -567,14 +573,30 @@ func TestReconcile(t *testing.T) { startResources: test.TestResources{ Namespaces: []*corev1.Namespace{namespaceResource}, EventListeners: []*v1alpha1.EventListener{eventListener3}, - Deployments: []*appsv1.Deployment{deployment1}, - Services: []*corev1.Service{service1}, + Deployments: []*appsv1.Deployment{deployment2}, + Services: []*corev1.Service{service2}, }, endResources: test.TestResources{ Namespaces: []*corev1.Namespace{namespaceResource}, EventListeners: []*v1alpha1.EventListener{eventListener3}, Deployments: []*appsv1.Deployment{deployment3}, - Services: []*corev1.Service{service1}, + Services: []*corev1.Service{service2}, + }, + }, + { + name: "update-eventlistener-servicetype", + key: reconcileKey, + startResources: test.TestResources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{eventListener4}, + Deployments: []*appsv1.Deployment{deployment3}, + Services: []*corev1.Service{service2}, + }, + endResources: test.TestResources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{eventListener4}, + Deployments: []*appsv1.Deployment{deployment3}, + Services: []*corev1.Service{service3}, }, }, {