diff --git a/cmd/eventlistenersink/main.go b/cmd/eventlistenersink/main.go index a82a8e8dcd..a393e55ce2 100644 --- a/cmd/eventlistenersink/main.go +++ b/cmd/eventlistenersink/main.go @@ -128,7 +128,13 @@ func main() { Handler: mux, } - if err := srv.ListenAndServe(); err != nil { - logger.Fatalf("failed to start eventlistener sink: %v", err) + if sinkArgs.Cert == "" && sinkArgs.Key == "" { + if err := srv.ListenAndServe(); err != nil { + logger.Fatalf("failed to start eventlistener sink: %v", err) + } + } else { + if err := srv.ListenAndServeTLS(sinkArgs.Cert, sinkArgs.Key); err != nil { + logger.Fatalf("failed to start eventlistener sink: %v", err) + } } } diff --git a/docs/eventlisteners.md b/docs/eventlisteners.md index 1d728efc95..9607c64926 100644 --- a/docs/eventlisteners.md +++ b/docs/eventlisteners.md @@ -40,6 +40,8 @@ using [Event Interceptors](#Interceptors). - [Multiple EventListeners (One EventListener Per Namespace)](#multiple-eventlisteners-one-eventlistener-per-namespace) - [Multiple EventListeners (Multiple EventListeners per Namespace)](#multiple-eventlisteners-multiple-eventlisteners-per-namespace) - [ServiceAccount per EventListenerTrigger](#serviceaccount-per-eventlistenertrigger) + - [EventListener Secure Connection](#eventlistener-secure-connection) + - [Prerequisites](#prerequisites) ## Syntax @@ -273,8 +275,11 @@ Right now the allowed values as part of `podSpec` are ServiceAccountName NodeSelector Tolerations +Volumes Containers - Resources +- VolumeMounts +- Env ``` ### Logging @@ -945,3 +950,11 @@ Except as otherwise noted, the content of this page is licensed under the [Creative Commons Attribution 4.0 License](https://creativecommons.org/licenses/by/4.0/), and code samples are licensed under the [Apache 2.0 License](https://www.apache.org/licenses/LICENSE-2.0). + +## EventListener Secure Connection + +Triggers now support both `HTTP` and `HTTPS` connection by adding few configurations to eventlistener. + +Refer [example detail](../examples/eventlistener-tls-connection/README.md) to know more on how to configure eventlistener to have secure connection. + +Refer [TEP-0027](https://github.com/tektoncd/community/blob/master/teps/0027-https-connection-to-triggers-eventlistener.md) for more information on design and user stories. diff --git a/examples/eventlistener-tls-connection/README.md b/examples/eventlistener-tls-connection/README.md new file mode 100644 index 0000000000..8b78e60586 --- /dev/null +++ b/examples/eventlistener-tls-connection/README.md @@ -0,0 +1,100 @@ +## EventListener Secure Connection + +Triggers now support both `HTTP` and `HTTPS` connection by adding some configurations to eventlistener. + +### Prerequisites +* Certificates with Key and Cert +* Secret which includes those certificates + +### Try it out locally: + +#### Creating Prerequisites + +* #### Certificates with Key and Cert. + +##### 1. Steps to generate root key, cert +1. Create Root Key + ```text + openssl genrsa -des3 -out rootCA.key 4096 + ``` +2. Create and self sign the Root Certificate + ```text + openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.crt + ``` +##### 2. Steps to generate certificate (for each server) +1. Create the certificate key + ```text + openssl genrsa -out tls.key 2048 + ``` +2. Create the signing (csr) + +* The CSR is where you specify the details for the certificate you want to generate. +This request will be processed by the owner of the root key to generate the certificate. + +* **Important:** While creating the csr it is important to specify the `Common Name` providing the IP address or domain name for the service, otherwise the certificate cannot be verified. + ```text + openssl req -new -key tls.key -out tls.csr + ``` +3. Generate the certificate using the tls csr and key along with the CA Root key + ```text + openssl x509 -req -in tls.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out tls.crt -days 500 -sha256 + ``` +##### 3. Follow same steps from 2 to generate certificates for client also + +* #### Create secret which includes those certificates + ```text + kubectl create secret generic tls-secret-key --from-file=tls.crt --from-file=tls.key + ``` + +#### Configuring EventListener for TLS connection +```yaml + apiVersion: triggers.tekton.dev/v1alpha1 + kind: EventListener + metadata: + name: github-listener-interceptor + spec: + triggers: + - name: github-listener + interceptors: + - github: + secretRef: + secretName: github-secret + secretKey: secretToken + eventTypes: + - pull_request + - cel: + filter: "body.action in ['opened', 'synchronize', 'reopened']" + bindings: + - ref: github-pr-binding + template: + ref: github-template + resources: + kubernetesResource: + spec: + template: + spec: + serviceAccountName: tekton-triggers-github-sa + containers: + - env: + - name: TLS_SECRET_NAME + value: "tls-secret-key" # Name of the secret which is created above (Mandatory env for TLS connection) + - name: TLS_CERT_NAME + value: "tls.crt" # Name of the cert file (Optional, If not provided tls.crt used) + - name: TLS_KEY_NAME + value: "tls.key" # Name of the key file (Optional, If not provided tls.key used) +``` +There are **RESERVED** env to provide `HTTPS` connection to triggers eventlistener +* `TLS_SECRET_NAME` is **mandatory** env key where user specify created secret name. +* `TLS_CERT_NAME` and `TLS_KEY_NAME` are **optional** env where user specify name of the cert and key respectively, +If not provided triggers assume names as `tls.crt` and `tls.key` by default. + +1. Test by sending the sample payload. + + ```bash + curl -v \ + -H 'X-GitHub-Event: pull_request' \ + -H 'X-Hub-Signature: sha1=ba0cdc263b3492a74b601d240c27efe81c4720cb' \ + -H 'Content-Type: application/json' \ + -d '{"action": "opened", "pull_request":{"head":{"sha": "28911bbb5a3e2ea034daf1f6be0a822d50e31e73"}},"repository":{"clone_url": "https://github.com/tektoncd/triggers.git"}}' \ + https:// --cacert rootCA.crt --key client.key --cert client.crt + ``` \ No newline at end of file diff --git a/examples/github/github-eventlistener-interceptor.yaml b/examples/github/github-eventlistener-interceptor.yaml index efc7711e8f..eb8ca09e55 100644 --- a/examples/github/github-eventlistener-interceptor.yaml +++ b/examples/github/github-eventlistener-interceptor.yaml @@ -33,6 +33,14 @@ spec: limits: memory: "128Mi" cpu: "500m" + env: + - name: TLS_SECRET_NAME + value: "tls-secret-name" + - name: TLS_CERT_NAME + value: "tls.pem" + - name: TLS_KEY_NAME + value: "tls-key.pem" + --- apiVersion: triggers.tekton.dev/v1alpha1 kind: TriggerBinding diff --git a/pkg/apis/triggers/v1alpha1/event_listener_validation.go b/pkg/apis/triggers/v1alpha1/event_listener_validation.go index 99f9b774a1..860fe82b95 100644 --- a/pkg/apis/triggers/v1alpha1/event_listener_validation.go +++ b/pkg/apis/triggers/v1alpha1/event_listener_validation.go @@ -67,6 +67,7 @@ func validateKubernetesObject(orig *KubernetesResource) (errs *apis.FieldError) func containerFieldMask(in *corev1.Container) *corev1.Container { out := new(corev1.Container) out.Resources = in.Resources + out.Env = in.Env // Disallowed fields // This list clarifies which all container attributes are not allowed. @@ -90,7 +91,6 @@ func containerFieldMask(in *corev1.Container) *corev1.Container { out.TTY = false out.VolumeDevices = nil out.EnvFrom = nil - out.Env = nil return out } diff --git a/pkg/apis/triggers/v1alpha1/event_listener_validation_test.go b/pkg/apis/triggers/v1alpha1/event_listener_validation_test.go index 0639551221..0ef684c9ba 100644 --- a/pkg/apis/triggers/v1alpha1/event_listener_validation_test.go +++ b/pkg/apis/triggers/v1alpha1/event_listener_validation_test.go @@ -164,7 +164,7 @@ func Test_EventListenerValidate(t *testing.T) { bldr.EventListenerCELInterceptor("", bldr.EventListenerCELOverlay("body.value", "'testing'")), ))), }, { - name: "Valid EventListener with kubernetes resource for podspec", + name: "Valid EventListener with kubernetes env for podspec", el: bldr.EventListener("name", "namespace", bldr.EventListenerSpec( bldr.EventListenerTrigger("tt", "v1alpha1"), @@ -198,6 +198,28 @@ func Test_EventListenerValidate(t *testing.T) { }), )), )), + }, { + name: "Valid EventListener with env for TLS connection", + el: bldr.EventListener("name", "namespace", + bldr.EventListenerSpec( + bldr.EventListenerTrigger("tt", "v1alpha1"), + bldr.EventListenerResources( + bldr.EventListenerKubernetesResources( + bldr.EventListenerPodSpec(duckv1.WithPodSpec{ + Template: duckv1.PodSpecable{ + Spec: corev1.PodSpec{ + ServiceAccountName: "k8sresource", + Containers: []corev1.Container{{ + Env: []corev1.EnvVar{{ + Name: "TLS_SECRET_NAME", + Value: "tls-secret-key", + }}, + }}, + }, + }, + }), + )), + )), }} for _, test := range tests { diff --git a/pkg/reconciler/v1alpha1/eventlistener/eventlistener.go b/pkg/reconciler/v1alpha1/eventlistener/eventlistener.go index 8fbbed7dd8..38df5cdce8 100644 --- a/pkg/reconciler/v1alpha1/eventlistener/eventlistener.go +++ b/pkg/reconciler/v1alpha1/eventlistener/eventlistener.go @@ -52,7 +52,7 @@ const ( // eventListenerConfigMapName is for the automatically created ConfigMap eventListenerConfigMapName = "config-logging-triggers" // eventListenerServicePortName defines service port name for EventListener Service - eventListenerServicePortName = "http-listener" + eventListenerServicePortName = "listener" // GeneratedResourcePrefix is the name prefix for resources generated in the // EventListener reconciler GeneratedResourcePrefix = "el" @@ -120,8 +120,8 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, el *v1alpha1.EventListen // and may not have had all of the assumed default specified. el.SetDefaults(v1alpha1.WithUpgradeViaDefaulting(ctx)) - serviceReconcileError := r.reconcileService(ctx, logger, el) deploymentReconcileError := r.reconcileDeployment(ctx, logger, el) + serviceReconcileError := r.reconcileService(ctx, logger, el) return wrapError(serviceReconcileError, deploymentReconcileError) } @@ -261,120 +261,9 @@ func (r *Reconciler) reconcileDeployment(ctx context.Context, logger *zap.Sugare return err } - var replicas = ptr.Int32(1) - if el.Spec.Replicas != nil { - replicas = el.Spec.Replicas - } - var ( - tolerations []corev1.Toleration - nodeSelector, annotations, podlabels map[string]string - serviceAccountName string - resources corev1.ResourceRequirements - ) - podlabels = mergeMaps(el.Labels, GenerateResourceLabels(el.Name)) + container := getContainer(el) + deployment := getDeployment(el) - // For backward compatibility with podTemplate, serviceAccountName field as part of eventlistener. - tolerations = el.Spec.PodTemplate.Tolerations - nodeSelector = el.Spec.PodTemplate.NodeSelector - serviceAccountName = el.Spec.ServiceAccountName - - if el.Spec.Resources.KubernetesResource != nil { - if len(el.Spec.Resources.KubernetesResource.Template.Spec.Tolerations) != 0 { - tolerations = el.Spec.Resources.KubernetesResource.Template.Spec.Tolerations - } - if len(el.Spec.Resources.KubernetesResource.Template.Spec.NodeSelector) != 0 { - nodeSelector = el.Spec.Resources.KubernetesResource.Template.Spec.NodeSelector - } - if el.Spec.Resources.KubernetesResource.Template.Spec.ServiceAccountName != "" { - serviceAccountName = el.Spec.Resources.KubernetesResource.Template.Spec.ServiceAccountName - } - annotations = el.Spec.Resources.KubernetesResource.Template.Annotations - podlabels = mergeMaps(podlabels, el.Spec.Resources.KubernetesResource.Template.Labels) - if len(el.Spec.Resources.KubernetesResource.Template.Spec.Containers) != 0 { - resources = el.Spec.Resources.KubernetesResource.Template.Spec.Containers[0].Resources - } - } - container := corev1.Container{ - Name: "event-listener", - Image: *elImage, - Ports: []corev1.ContainerPort{{ - ContainerPort: int32(*ElPort), - Protocol: corev1.ProtocolTCP, - }}, - LivenessProbe: &corev1.Probe{ - Handler: corev1.Handler{ - HTTPGet: &corev1.HTTPGetAction{ - Path: "/live", - Scheme: corev1.URISchemeHTTP, - Port: intstr.FromInt((*ElPort)), - }, - }, - PeriodSeconds: int32(*PeriodSeconds), - FailureThreshold: int32(*FailureThreshold), - }, - ReadinessProbe: &corev1.Probe{ - Handler: corev1.Handler{ - HTTPGet: &corev1.HTTPGetAction{ - Path: "/live", - Scheme: corev1.URISchemeHTTP, - Port: intstr.FromInt((*ElPort)), - }, - }, - PeriodSeconds: int32(*PeriodSeconds), - FailureThreshold: int32(*FailureThreshold), - }, - Resources: resources, - Args: []string{ - "-el-name", el.Name, - "-el-namespace", el.Namespace, - "-port", strconv.Itoa(*ElPort), - }, - VolumeMounts: []corev1.VolumeMount{{ - Name: "config-logging", - MountPath: "/etc/config-logging", - }}, - Env: []corev1.EnvVar{{ - Name: "SYSTEM_NAMESPACE", - ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - FieldPath: "metadata.namespace", - }, - }, - }}, - } - - deployment := &appsv1.Deployment{ - ObjectMeta: generateObjectMeta(el), - Spec: appsv1.DeploymentSpec{ - Replicas: replicas, - Selector: &metav1.LabelSelector{ - MatchLabels: GenerateResourceLabels(el.Name), - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: podlabels, - Annotations: annotations, - }, - Spec: corev1.PodSpec{ - Tolerations: tolerations, - NodeSelector: nodeSelector, - ServiceAccountName: serviceAccountName, - Containers: []corev1.Container{container}, - - Volumes: []corev1.Volume{{ - Name: "config-logging", - VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: eventListenerConfigMapName, - }, - }, - }, - }}, - }, - }, - }, - } existingDeployment, err := r.deploymentLister.Deployments(el.Namespace).Get(el.Status.Configuration.GeneratedResourceName) switch { case err == nil: @@ -385,7 +274,7 @@ func (r *Reconciler) reconcileDeployment(ctx context.Context, logger *zap.Sugare updated := reconcileObjectMeta(&existingDeployment.ObjectMeta, deployment.ObjectMeta) if *existingDeployment.Spec.Replicas != *deployment.Spec.Replicas { if el.Spec.Replicas != nil { - existingDeployment.Spec.Replicas = replicas + existingDeployment.Spec.Replicas = deployment.Spec.Replicas updated = true } // if no replicas found as part of el.Spec then replicas from existingDeployment will be considered @@ -435,6 +324,14 @@ func (r *Reconciler) reconcileDeployment(ctx context.Context, logger *zap.Sugare existingDeployment.Spec.Template.Spec.Containers[0].Args = container.Args updated = true } + if !reflect.DeepEqual(existingDeployment.Spec.Template.Spec.Containers[0].LivenessProbe, container.LivenessProbe) { + existingDeployment.Spec.Template.Spec.Containers[0].LivenessProbe = container.LivenessProbe + updated = true + } + if !reflect.DeepEqual(existingDeployment.Spec.Template.Spec.Containers[0].ReadinessProbe, container.ReadinessProbe) { + existingDeployment.Spec.Template.Spec.Containers[0].ReadinessProbe = container.ReadinessProbe + updated = true + } if existingDeployment.Spec.Template.Spec.Containers[0].Command != nil { existingDeployment.Spec.Template.Spec.Containers[0].Command = nil updated = true @@ -443,7 +340,11 @@ func (r *Reconciler) reconcileDeployment(ctx context.Context, logger *zap.Sugare existingDeployment.Spec.Template.Spec.Containers[0].Resources = container.Resources updated = true } - if len(existingDeployment.Spec.Template.Spec.Containers[0].VolumeMounts) == 0 { + if !reflect.DeepEqual(existingDeployment.Spec.Template.Spec.Containers[0].Env, container.Env) { + existingDeployment.Spec.Template.Spec.Containers[0].Env = container.Env + updated = true + } + if !reflect.DeepEqual(existingDeployment.Spec.Template.Spec.Containers[0].VolumeMounts, deployment.Spec.Template.Spec.Containers[0].VolumeMounts) { existingDeployment.Spec.Template.Spec.Containers[0].VolumeMounts = container.VolumeMounts updated = true } @@ -476,6 +377,185 @@ func (r *Reconciler) reconcileDeployment(ctx context.Context, logger *zap.Sugare return nil } +func getDeployment(el *v1alpha1.EventListener) *appsv1.Deployment { + var replicas = ptr.Int32(1) + if el.Spec.Replicas != nil { + replicas = el.Spec.Replicas + } + var ( + tolerations []corev1.Toleration + nodeSelector, annotations, podlabels map[string]string + serviceAccountName string + ) + podlabels = mergeMaps(el.Labels, GenerateResourceLabels(el.Name)) + + // For backward compatibility with podTemplate, serviceAccountName field as part of eventlistener. + tolerations = el.Spec.PodTemplate.Tolerations + nodeSelector = el.Spec.PodTemplate.NodeSelector + serviceAccountName = el.Spec.ServiceAccountName + + vol := []corev1.Volume{{ + Name: "config-logging", + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: eventListenerConfigMapName, + }, + }, + }, + }} + + container := getContainer(el) + for i := range container.Env { + if container.Env[i].Name == "TLS_SECRET_NAME" { + vol = append(vol, corev1.Volume{ + Name: "https-connection", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: container.Env[i].Value, + }, + }, + }) + } + } + + if el.Spec.Resources.KubernetesResource != nil { + if len(el.Spec.Resources.KubernetesResource.Template.Spec.Tolerations) != 0 { + tolerations = el.Spec.Resources.KubernetesResource.Template.Spec.Tolerations + } + if len(el.Spec.Resources.KubernetesResource.Template.Spec.NodeSelector) != 0 { + nodeSelector = el.Spec.Resources.KubernetesResource.Template.Spec.NodeSelector + } + if el.Spec.Resources.KubernetesResource.Template.Spec.ServiceAccountName != "" { + serviceAccountName = el.Spec.Resources.KubernetesResource.Template.Spec.ServiceAccountName + } + annotations = el.Spec.Resources.KubernetesResource.Template.Annotations + podlabels = mergeMaps(podlabels, el.Spec.Resources.KubernetesResource.Template.Labels) + } + + return &appsv1.Deployment{ + ObjectMeta: generateObjectMeta(el), + Spec: appsv1.DeploymentSpec{ + Replicas: replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: GenerateResourceLabels(el.Name), + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: podlabels, + Annotations: annotations, + }, + Spec: corev1.PodSpec{ + Tolerations: tolerations, + NodeSelector: nodeSelector, + ServiceAccountName: serviceAccountName, + Containers: []corev1.Container{container}, + Volumes: vol, + }, + }, + }, + } +} + +func getContainer(el *v1alpha1.EventListener) corev1.Container { + var ( + // Default location fot certificate. + elCert = "/etc/triggers/tls/tls.crt" + // Default location fot key. + elKey = "/etc/triggers/tls/tls.key" + resources corev1.ResourceRequirements + ) + + vMount := []corev1.VolumeMount{{ + Name: "config-logging", + MountPath: "/etc/config-logging", + }} + + env := []corev1.EnvVar{{ + Name: "SYSTEM_NAMESPACE", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "metadata.namespace", + }, + }, + }} + + certEnv := map[string]string{} + if el.Spec.Resources.KubernetesResource != nil { + if len(el.Spec.Resources.KubernetesResource.Template.Spec.Containers) != 0 { + resources = el.Spec.Resources.KubernetesResource.Template.Spec.Containers[0].Resources + for i, e := range el.Spec.Resources.KubernetesResource.Template.Spec.Containers[0].Env { + env = append(env, e) + certEnv[el.Spec.Resources.KubernetesResource.Template.Spec.Containers[0].Env[i].Name] = + el.Spec.Resources.KubernetesResource.Template.Spec.Containers[0].Env[i].Value + } + } + } + + var scheme corev1.URIScheme + if _, ok := certEnv["TLS_SECRET_NAME"]; ok { + if v, ok := certEnv["TLS_CERT_NAME"]; ok { + elCert = "/etc/triggers/tls/" + v + } + if v, ok := certEnv["TLS_KEY_NAME"]; ok { + elKey = "/etc/triggers/tls/" + v + } + vMount = append(vMount, corev1.VolumeMount{ + Name: "https-connection", + ReadOnly: true, + MountPath: "/etc/triggers/tls", + }) + *ElPort = 8443 + scheme = corev1.URISchemeHTTPS + } else { + elCert = "" + elKey = "" + *ElPort = 8080 + scheme = corev1.URISchemeHTTP + } + + return corev1.Container{ + Name: "event-listener", + Image: *elImage, + Ports: []corev1.ContainerPort{{ + ContainerPort: int32(*ElPort), + Protocol: corev1.ProtocolTCP, + }}, + LivenessProbe: &corev1.Probe{ + Handler: corev1.Handler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: "/live", + Scheme: scheme, + Port: intstr.FromInt((*ElPort)), + }, + }, + PeriodSeconds: int32(*PeriodSeconds), + FailureThreshold: int32(*FailureThreshold), + }, + ReadinessProbe: &corev1.Probe{ + Handler: corev1.Handler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: "/live", + Scheme: scheme, + Port: intstr.FromInt((*ElPort)), + }, + }, + PeriodSeconds: int32(*PeriodSeconds), + FailureThreshold: int32(*FailureThreshold), + }, + Resources: resources, + Args: []string{ + "-el-name", el.Name, + "-el-namespace", el.Namespace, + "-port", strconv.Itoa(*ElPort), + "-tls-cert", elCert, + "-tls-key", elKey, + }, + VolumeMounts: vMount, + Env: env, + } +} + // GenerateResourceLabels generates the labels to be used on all generated resources. func GenerateResourceLabels(eventListenerName string) map[string]string { resourceLabels := make(map[string]string, len(StaticResourceLabels)+1) diff --git a/pkg/reconciler/v1alpha1/eventlistener/eventlistener_test.go b/pkg/reconciler/v1alpha1/eventlistener/eventlistener_test.go index c58d0a2031..e0447acd37 100644 --- a/pkg/reconciler/v1alpha1/eventlistener/eventlistener_test.go +++ b/pkg/reconciler/v1alpha1/eventlistener/eventlistener_test.go @@ -246,6 +246,122 @@ func makeDeployment(ops ...func(d *appsv1.Deployment)) *appsv1.Deployment { return &d } +// makeDeploymentForTLSConnection is a helper to build a Deployment that is created by an EventListener. +// It generates a basic Deployment for the simplest EventListener and accepts functions for modification +func makeDeploymentForTLSConnection(ops ...func(d *appsv1.Deployment)) *appsv1.Deployment { + ownerRefs := makeEL().GetOwnerReference() + + d := appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: generatedResourceName, + Namespace: namespace, + OwnerReferences: []metav1.OwnerReference{ + *ownerRefs, + }, + Labels: generatedLabels, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: generatedLabels, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: generatedLabels, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: "sa", + Containers: []corev1.Container{{ + Name: "event-listener", + Image: *elImage, + Ports: []corev1.ContainerPort{{ + ContainerPort: int32(8443), + Protocol: corev1.ProtocolTCP, + }}, + LivenessProbe: &corev1.Probe{ + Handler: corev1.Handler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: "/live", + Scheme: corev1.URISchemeHTTPS, + Port: intstr.FromInt((8443)), + }, + }, + PeriodSeconds: int32(*PeriodSeconds), + FailureThreshold: int32(*FailureThreshold), + }, + ReadinessProbe: &corev1.Probe{ + Handler: corev1.Handler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: "/live", + Scheme: corev1.URISchemeHTTPS, + Port: intstr.FromInt((8443)), + }, + }, + PeriodSeconds: int32(*PeriodSeconds), + FailureThreshold: int32(*FailureThreshold), + }, + Args: []string{ + "-el-name", eventListenerName, + "-el-namespace", namespace, + "-port", strconv.Itoa(8443), + }, + VolumeMounts: []corev1.VolumeMount{{ + Name: "config-logging", + MountPath: "/etc/config-logging", + }, { + Name: "https-connection", + MountPath: "/etc/triggers/tls", + ReadOnly: true, + }}, + Env: []corev1.EnvVar{{ + Name: "SYSTEM_NAMESPACE", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "metadata.namespace", + }, + }, + }, { + Name: "TLS_SECRET_NAME", + Value: "tls-secret-key", + }, { + Name: "TLS_CERT_NAME", + Value: "tls.pem", + }}, + }}, + Volumes: []corev1.Volume{{ + Name: "config-logging", + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: eventListenerConfigMapName, + }, + }, + }, + }, { + Name: "https-connection", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: "tls-secret-key", + }, + }, + }}, + }, + }, + }, + Status: appsv1.DeploymentStatus{ + Conditions: []appsv1.DeploymentCondition{ + deploymentAvailableCondition, + deploymentProgressingCondition, + }, + }, + } + + for _, op := range ops { + op(&d) + } + return &d +} + // makeService is a helper to build a Service that is created by an EventListener. // It generates a basic Service for the simplest EventListener and accepts functions for modification. func makeService(ops ...func(*corev1.Service)) *corev1.Service { @@ -285,6 +401,10 @@ func logConfig(ns string) *corev1.ConfigMap { return lc } +var withTLSPort = bldr.EventListenerStatus( + bldr.EventListenerAddress(listenerHostname(generatedResourceName, namespace, 8443)), +) + var withStatus = bldr.EventListenerStatus( bldr.EventListenerConfig(generatedResourceName), bldr.EventListenerAddress(listenerHostname(generatedResourceName, namespace, *ElPort)), @@ -396,6 +516,26 @@ func TestReconcile(t *testing.T) { } }) + elWithTLSConnection := makeEL(withStatus, withTLSPort, func(el *v1alpha1.EventListener) { + el.Spec.Resources.KubernetesResource = &v1alpha1.KubernetesResource{ + WithPodSpec: duckv1.WithPodSpec{ + Template: duckv1.PodSpecable{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Env: []corev1.EnvVar{{ + Name: "TLS_SECRET_NAME", + Value: "tls-secret-key", + }, { + Name: "TLS_CERT_NAME", + Value: "tls.pem", + }}, + }}, + }, + }, + }, + } + }) + elWithKubernetesResourceForObjectMeta := makeEL(withStatus, func(el *v1alpha1.EventListener) { el.Spec.Resources.KubernetesResource = &v1alpha1.KubernetesResource{ WithPodSpec: duckv1.WithPodSpec{ @@ -460,6 +600,8 @@ func TestReconcile(t *testing.T) { } }) + deploymentWithTLSConnection := makeDeploymentForTLSConnection() + deploymentForKubernetesResourceObjectMeta := makeDeployment(func(d *appsv1.Deployment) { d.Spec.Template.ObjectMeta.Labels = map[string]string{ "app.kubernetes.io/managed-by": "EventListener", @@ -489,6 +631,13 @@ func TestReconcile(t *testing.T) { s.Spec.Ports[0].NodePort = 30000 }) + elServiceWithTLSConnection := makeService(func(s *corev1.Service) { + s.Spec.Ports[0].Port = int32(8443) + s.Spec.Ports[0].TargetPort = intstr.IntOrString{ + IntVal: int32(8443), + } + }) + loggingConfigMap := defaultLoggingConfigMap() loggingConfigMap.ObjectMeta.Namespace = namespace reconcilerLoggingConfigMap := defaultLoggingConfigMap() @@ -499,302 +648,320 @@ func TestReconcile(t *testing.T) { key string startResources test.Resources // State of the world before we call Reconcile endResources test.Resources // Expected State of the world after calling Reconcile - }{{ - name: "create-eventlistener", - key: reconcileKey, - startResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{makeEL()}, - }, - endResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{makeEL(withStatus)}, - Deployments: []*appsv1.Deployment{makeDeployment()}, - Services: []*corev1.Service{makeService()}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - }, - }, { - name: "update-eventlistener-labels", - key: reconcileKey, - // Resources before reconcile starts: EL has extra label that deployment/svc does not - startResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{makeEL(withStatus, withAddedLabels)}, - Deployments: []*appsv1.Deployment{makeDeployment()}, - Services: []*corev1.Service{makeService()}, - }, - // We expect the deployment and services to propagate the extra label - // but the selectors in both Service and deployment should have the same - // label - endResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{makeEL(withStatus, withAddedLabels)}, - Deployments: []*appsv1.Deployment{elDeploymentWithLabels}, - Services: []*corev1.Service{elServiceWithLabels}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - }, - }, { - name: "update-eventlistener-annotations", - key: reconcileKey, - // Resources before reconcile starts: EL has annotation that deployment/svc does not - startResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{makeEL(withStatus, withAddedAnnotations)}, - Deployments: []*appsv1.Deployment{makeDeployment()}, - Services: []*corev1.Service{makeService()}, - }, - // We expect the deployment and services to propagate the annotations - endResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{makeEL(withStatus, withAddedAnnotations)}, - Deployments: []*appsv1.Deployment{elDeploymentWithAnnotations}, - Services: []*corev1.Service{elServiceWithAnnotation}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - }, - }, { - name: "update-eventlistener-serviceaccount", - key: reconcileKey, - startResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithUpdatedSA}, - Deployments: []*appsv1.Deployment{elDeploymentWithLabels}, - Services: []*corev1.Service{elService}, - }, - endResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithUpdatedSA}, - Deployments: []*appsv1.Deployment{elDeploymentWithUpdatedSA}, - Services: []*corev1.Service{elService}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - }, - }, { - name: "update-eventlistener-tolerations", - key: reconcileKey, - startResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithTolerations}, - Deployments: []*appsv1.Deployment{elDeploymentWithLabels}, - Services: []*corev1.Service{elService}, - }, - endResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithTolerations}, - Deployments: []*appsv1.Deployment{elDeploymentWithTolerations}, - Services: []*corev1.Service{elService}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - }, - }, { - name: "update-eventlistener-nodeSelector", - key: reconcileKey, - startResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithNodeSelector}, - Deployments: []*appsv1.Deployment{elDeploymentWithLabels}, - Services: []*corev1.Service{elService}, - }, - endResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithNodeSelector}, - Deployments: []*appsv1.Deployment{elDeploymentWithNodeSelector}, - Services: []*corev1.Service{elService}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - }, - }, { - name: "update-eventlistener-servicetype", - key: reconcileKey, - startResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithNodePortServiceType}, - Deployments: []*appsv1.Deployment{elDeployment}, - Services: []*corev1.Service{elServiceWithLabels}, - }, - endResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithNodePortServiceType}, - Deployments: []*appsv1.Deployment{elDeployment}, - Services: []*corev1.Service{elServiceTypeNodePort}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - }, - }, { - // Check that if a user manually updates the labels for a service, we revert the change. - name: "update-el-service-labels", - key: reconcileKey, - startResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithStatus}, - Services: []*corev1.Service{elServiceWithLabels}, - Deployments: []*appsv1.Deployment{elDeployment}, - }, - endResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithStatus}, - Services: []*corev1.Service{elService}, // We expect the service to drop the user added labels - Deployments: []*appsv1.Deployment{elDeployment}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - }, - }, { - // Check that if a user manually updates the annotations for a service, we do not revert the change. - name: "update-el-service-annotations", - key: reconcileKey, - startResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithStatus}, - Services: []*corev1.Service{elServiceWithAnnotation}, - Deployments: []*appsv1.Deployment{elDeployment}, - }, - endResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithStatus}, - Services: []*corev1.Service{elServiceWithAnnotation}, - Deployments: []*appsv1.Deployment{elDeployment}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - }, - }, { - // Checks that EL reconciler does not overwrite NodePort set by k8s (see #167) - name: "service-nodeport-update", - key: reconcileKey, - startResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithNodePortServiceType}, - Deployments: []*appsv1.Deployment{elDeployment}, - Services: []*corev1.Service{elServiceWithUpdatedNodePort}, - }, - endResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithNodePortServiceType}, - Deployments: []*appsv1.Deployment{elDeployment}, - Services: []*corev1.Service{elServiceWithUpdatedNodePort}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - }, - }, { - name: "deployment-label-update", - key: reconcileKey, - startResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithStatus}, - Deployments: []*appsv1.Deployment{elDeploymentWithLabels}, - Services: []*corev1.Service{elService}, - }, - endResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithStatus}, - Deployments: []*appsv1.Deployment{elDeployment}, - Services: []*corev1.Service{elService}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - }, - }, { - // Check that if a user manually updates the annotations for a deployment, we do not revert the change. - name: "deployment-annotation-update", - key: reconcileKey, - startResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithStatus}, - Deployments: []*appsv1.Deployment{elDeploymentWithAnnotations}, - Services: []*corev1.Service{elService}, - }, - endResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithStatus}, - Deployments: []*appsv1.Deployment{elDeploymentWithAnnotations}, - Services: []*corev1.Service{elService}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - }, - }, { - // Updating replicas on deployment itself is success because no replicas provided as part of eventlistener spec - name: "deployment-replica-update-success", - key: reconcileKey, - startResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithStatus}, - Deployments: []*appsv1.Deployment{deploymentWithUpdatedReplicas}, - Services: []*corev1.Service{elService}, - }, - endResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithStatus}, - Deployments: []*appsv1.Deployment{deploymentWithUpdatedReplicas}, - Services: []*corev1.Service{elService}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - }, - }, { - name: "eventlistener-replica-failure-status-update", - key: reconcileKey, - startResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithDeploymentReplicaFailure}, - Services: []*corev1.Service{elService}, - Deployments: []*appsv1.Deployment{elDeployment}, - }, - endResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithStatus}, - Deployments: []*appsv1.Deployment{elDeployment}, - Services: []*corev1.Service{elService}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - }, - }, { - name: "eventlistener-config-volume-mount-update", - key: reconcileKey, - startResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{makeEL(withStatus)}, - Deployments: []*appsv1.Deployment{deploymentMissingVolumes}, - }, - endResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{makeEL(withStatus)}, - Deployments: []*appsv1.Deployment{elDeployment}, - Services: []*corev1.Service{elService}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - }, - }, { - // Checks that we do not overwrite replicas changed on the deployment itself when replicas provided as part of eventlistener spec - name: "deployment-replica-update-unsuccessful", - key: reconcileKey, - startResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithReplicas}, - Deployments: []*appsv1.Deployment{deploymentWithUpdatedReplicas}, - Services: []*corev1.Service{elService}, - }, - endResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithReplicas}, - Deployments: []*appsv1.Deployment{deploymentWithUpdatedReplicasNotConsidered}, - Services: []*corev1.Service{elService}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - }, - }, { - name: "eventlistener with kubernetes resource", - key: reconcileKey, - startResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithKubernetesResource}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - }, - endResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithKubernetesResource}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - Deployments: []*appsv1.Deployment{deploymentForKubernetesResource}, - Services: []*corev1.Service{elServiceTypeNodePort}, - }, - }, { - name: "eventlistener with kubernetes resource for podtemplate objectmeta", - key: reconcileKey, - startResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithKubernetesResourceForObjectMeta}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - }, - endResources: test.Resources{ - Namespaces: []*corev1.Namespace{namespaceResource}, - EventListeners: []*v1alpha1.EventListener{elWithKubernetesResourceForObjectMeta}, - ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, - Deployments: []*appsv1.Deployment{deploymentForKubernetesResourceObjectMeta}, - Services: []*corev1.Service{elService}, + }{ + { + name: "create-eventlistener", + key: reconcileKey, + startResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{makeEL()}, + }, + endResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{makeEL(withStatus)}, + Deployments: []*appsv1.Deployment{makeDeployment()}, + Services: []*corev1.Service{makeService()}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + }, + }, { + name: "update-eventlistener-labels", + key: reconcileKey, + // Resources before reconcile starts: EL has extra label that deployment/svc does not + startResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{makeEL(withStatus, withAddedLabels)}, + Deployments: []*appsv1.Deployment{makeDeployment()}, + Services: []*corev1.Service{makeService()}, + }, + // We expect the deployment and services to propagate the extra label + // but the selectors in both Service and deployment should have the same + // label + endResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{makeEL(withStatus, withAddedLabels)}, + Deployments: []*appsv1.Deployment{elDeploymentWithLabels}, + Services: []*corev1.Service{elServiceWithLabels}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + }, + }, { + name: "update-eventlistener-annotations", + key: reconcileKey, + // Resources before reconcile starts: EL has annotation that deployment/svc does not + startResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{makeEL(withStatus, withAddedAnnotations)}, + Deployments: []*appsv1.Deployment{makeDeployment()}, + Services: []*corev1.Service{makeService()}, + }, + // We expect the deployment and services to propagate the annotations + endResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{makeEL(withStatus, withAddedAnnotations)}, + Deployments: []*appsv1.Deployment{elDeploymentWithAnnotations}, + Services: []*corev1.Service{elServiceWithAnnotation}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + }, + }, { + name: "update-eventlistener-serviceaccount", + key: reconcileKey, + startResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithUpdatedSA}, + Deployments: []*appsv1.Deployment{elDeploymentWithLabels}, + Services: []*corev1.Service{elService}, + }, + endResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithUpdatedSA}, + Deployments: []*appsv1.Deployment{elDeploymentWithUpdatedSA}, + Services: []*corev1.Service{elService}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + }, + }, { + name: "update-eventlistener-tolerations", + key: reconcileKey, + startResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithTolerations}, + Deployments: []*appsv1.Deployment{elDeploymentWithLabels}, + Services: []*corev1.Service{elService}, + }, + endResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithTolerations}, + Deployments: []*appsv1.Deployment{elDeploymentWithTolerations}, + Services: []*corev1.Service{elService}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + }, + }, { + name: "update-eventlistener-nodeSelector", + key: reconcileKey, + startResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithNodeSelector}, + Deployments: []*appsv1.Deployment{elDeploymentWithLabels}, + Services: []*corev1.Service{elService}, + }, + endResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithNodeSelector}, + Deployments: []*appsv1.Deployment{elDeploymentWithNodeSelector}, + Services: []*corev1.Service{elService}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + }, + }, { + name: "update-eventlistener-servicetype", + key: reconcileKey, + startResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithNodePortServiceType}, + Deployments: []*appsv1.Deployment{elDeployment}, + Services: []*corev1.Service{elServiceWithLabels}, + }, + endResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithNodePortServiceType}, + Deployments: []*appsv1.Deployment{elDeployment}, + Services: []*corev1.Service{elServiceTypeNodePort}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + }, + }, { + // Check that if a user manually updates the labels for a service, we revert the change. + name: "update-el-service-labels", + key: reconcileKey, + startResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithStatus}, + Services: []*corev1.Service{elServiceWithLabels}, + Deployments: []*appsv1.Deployment{elDeployment}, + }, + endResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithStatus}, + Services: []*corev1.Service{elService}, // We expect the service to drop the user added labels + Deployments: []*appsv1.Deployment{elDeployment}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + }, + }, { + // Check that if a user manually updates the annotations for a service, we do not revert the change. + name: "update-el-service-annotations", + key: reconcileKey, + startResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithStatus}, + Services: []*corev1.Service{elServiceWithAnnotation}, + Deployments: []*appsv1.Deployment{elDeployment}, + }, + endResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithStatus}, + Services: []*corev1.Service{elServiceWithAnnotation}, + Deployments: []*appsv1.Deployment{elDeployment}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + }, + }, { + // Checks that EL reconciler does not overwrite NodePort set by k8s (see #167) + name: "service-nodeport-update", + key: reconcileKey, + startResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithNodePortServiceType}, + Deployments: []*appsv1.Deployment{elDeployment}, + Services: []*corev1.Service{elServiceWithUpdatedNodePort}, + }, + endResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithNodePortServiceType}, + Deployments: []*appsv1.Deployment{elDeployment}, + Services: []*corev1.Service{elServiceWithUpdatedNodePort}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + }, + }, { + name: "deployment-label-update", + key: reconcileKey, + startResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithStatus}, + Deployments: []*appsv1.Deployment{elDeploymentWithLabels}, + Services: []*corev1.Service{elService}, + }, + endResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithStatus}, + Deployments: []*appsv1.Deployment{elDeployment}, + Services: []*corev1.Service{elService}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + }, + }, { + // Check that if a user manually updates the annotations for a deployment, we do not revert the change. + name: "deployment-annotation-update", + key: reconcileKey, + startResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithStatus}, + Deployments: []*appsv1.Deployment{elDeploymentWithAnnotations}, + Services: []*corev1.Service{elService}, + }, + endResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithStatus}, + Deployments: []*appsv1.Deployment{elDeploymentWithAnnotations}, + Services: []*corev1.Service{elService}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + }, + }, { + // Updating replicas on deployment itself is success because no replicas provided as part of eventlistener spec + name: "deployment-replica-update-success", + key: reconcileKey, + startResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithStatus}, + Deployments: []*appsv1.Deployment{deploymentWithUpdatedReplicas}, + Services: []*corev1.Service{elService}, + }, + endResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithStatus}, + Deployments: []*appsv1.Deployment{deploymentWithUpdatedReplicas}, + Services: []*corev1.Service{elService}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + }, + }, { + name: "eventlistener-replica-failure-status-update", + key: reconcileKey, + startResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithDeploymentReplicaFailure}, + Services: []*corev1.Service{elService}, + Deployments: []*appsv1.Deployment{elDeployment}, + }, + endResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithStatus}, + Deployments: []*appsv1.Deployment{elDeployment}, + Services: []*corev1.Service{elService}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + }, + }, { + name: "eventlistener-config-volume-mount-update", + key: reconcileKey, + startResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{makeEL(withStatus)}, + Deployments: []*appsv1.Deployment{deploymentMissingVolumes}, + }, + endResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{makeEL(withStatus)}, + Deployments: []*appsv1.Deployment{elDeployment}, + Services: []*corev1.Service{elService}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + }, + }, { + // Checks that we do not overwrite replicas changed on the deployment itself when replicas provided as part of eventlistener spec + name: "deployment-replica-update-unsuccessful", + key: reconcileKey, + startResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithReplicas}, + Deployments: []*appsv1.Deployment{deploymentWithUpdatedReplicas}, + Services: []*corev1.Service{elService}, + }, + endResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithReplicas}, + Deployments: []*appsv1.Deployment{deploymentWithUpdatedReplicasNotConsidered}, + Services: []*corev1.Service{elService}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + }, + }, { + name: "eventlistener with kubernetes resource", + key: reconcileKey, + startResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithKubernetesResource}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + }, + endResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithKubernetesResource}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + Deployments: []*appsv1.Deployment{deploymentForKubernetesResource}, + Services: []*corev1.Service{elServiceTypeNodePort}, + }, + }, { + name: "eventlistener with kubernetes resource for podtemplate objectmeta", + key: reconcileKey, + startResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithKubernetesResourceForObjectMeta}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + }, + endResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithKubernetesResourceForObjectMeta}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + Deployments: []*appsv1.Deployment{deploymentForKubernetesResourceObjectMeta}, + Services: []*corev1.Service{elService}, + }, }, - }} + { + name: "eventlistener with TLS connection", + key: reconcileKey, + startResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithTLSConnection}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + }, + endResources: test.Resources{ + Namespaces: []*corev1.Namespace{namespaceResource}, + EventListeners: []*v1alpha1.EventListener{elWithTLSConnection}, + ConfigMaps: []*corev1.ConfigMap{loggingConfigMap}, + Deployments: []*appsv1.Deployment{deploymentWithTLSConnection}, + Services: []*corev1.Service{elServiceWithTLSConnection}, + }, + }} + //} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Setup with startResources diff --git a/pkg/sink/initialization.go b/pkg/sink/initialization.go index 8454018772..b2cd2b9de8 100644 --- a/pkg/sink/initialization.go +++ b/pkg/sink/initialization.go @@ -41,6 +41,10 @@ var ( "The namespace of the EventListener resource for this sink.") portFlag = flag.String("port", "", "The port for the EventListener sink to listen on.") + tlsCertFlag = flag.String("tls-cert", "", + "The filename for the TLS certificate.") + tlsKeyFlag = flag.String("tls-key", "", + "The filename for the TLS key.") ) // Args define the arguments for Sink. @@ -51,6 +55,8 @@ type Args struct { ElNamespace string // Port is the port the Sink should listen on. Port string + Key string + Cert string } // Clients define the set of client dependencies Sink requires. @@ -76,6 +82,8 @@ func GetArgs() (Args, error) { ElName: *nameFlag, ElNamespace: *namespaceFlag, Port: *portFlag, + Cert: *tlsCertFlag, + Key: *tlsKeyFlag, }, nil }