diff --git a/pkg/trait/cron.go b/pkg/trait/cron.go index 45a325e476..c2d8c839f1 100644 --- a/pkg/trait/cron.go +++ b/pkg/trait/cron.go @@ -32,6 +32,7 @@ import ( "github.com/apache/camel-k/pkg/metadata" "github.com/apache/camel-k/pkg/util" "github.com/apache/camel-k/pkg/util/kubernetes" + "github.com/apache/camel-k/pkg/util/label" "github.com/apache/camel-k/pkg/util/uri" ) @@ -292,7 +293,7 @@ func (t *cronTrait) getCronJobFor(e *Environment) *v1beta1.CronJob { Spec: batchv1.JobSpec{ Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: labels, + Labels: label.AddLabels(e.Integration.Name), Annotations: annotations, }, Spec: corev1.PodSpec{ diff --git a/pkg/trait/deployment.go b/pkg/trait/deployment.go index cf788e7908..235d9aa338 100644 --- a/pkg/trait/deployment.go +++ b/pkg/trait/deployment.go @@ -25,6 +25,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "github.com/apache/camel-k/pkg/apis/camel/v1" + "github.com/apache/camel-k/pkg/util/label" ) // The Deployment trait is responsible for generating the Kubernetes deployment that will make sure @@ -166,9 +167,7 @@ func (t *deploymentTrait) getDeploymentFor(e *Environment) *appsv1.Deployment { }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - v1.IntegrationLabel: e.Integration.Name, - }, + Labels: label.AddLabels(e.Integration.Name), Annotations: annotations, }, Spec: corev1.PodSpec{ diff --git a/pkg/trait/knative_service.go b/pkg/trait/knative_service.go index a86e7bd089..40208dde47 100644 --- a/pkg/trait/knative_service.go +++ b/pkg/trait/knative_service.go @@ -29,6 +29,7 @@ import ( v1 "github.com/apache/camel-k/pkg/apis/camel/v1" "github.com/apache/camel-k/pkg/metadata" "github.com/apache/camel-k/pkg/util/kubernetes" + "github.com/apache/camel-k/pkg/util/label" ) const ( @@ -310,7 +311,7 @@ func (t *knativeServiceTrait) getServiceFor(e *Environment) *serving.Service { ConfigurationSpec: serving.ConfigurationSpec{ Template: serving.RevisionTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: labels, + Labels: label.AddLabels(e.Integration.Name), Annotations: annotations, }, Spec: serving.RevisionSpec{ diff --git a/pkg/util/label/label.go b/pkg/util/label/label.go new file mode 100644 index 0000000000..671034e4ce --- /dev/null +++ b/pkg/util/label/label.go @@ -0,0 +1,68 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package label + +import ( + "fmt" + + v1 "github.com/apache/camel-k/pkg/apis/camel/v1" + "k8s.io/apimachinery/pkg/labels" +) + +// The AdditionalLabels is a big string consisting of key=value, set at build time +// when set are to be added to Deployments, CronJob and KNativeService whose pods +// should expose these labels + +// AdditionalLabels are labels=values, they MUST be set as key=value separated by comma , +// example: myKey1=myValue1,myKey2=myValue2 +// Also it supports replacing a value for the integration name at runtime, just use the value as "token_integration_name" +// example: myKey1=myValue1,myKey2=token_integration_name +var AdditionalLabels = "" + +var FixedLabels = map[string]string{} + +// parses the labels early on and fail fast if there are errors +func init() { + checkAdditionalLabels() +} + +func checkAdditionalLabels() { + if len(AdditionalLabels) > 0 { + var err error + FixedLabels, err = labels.ConvertSelectorToLabelsMap(AdditionalLabels) + if err != nil { + // as this should be used only in build time, it's ok to fail fast + panic(fmt.Sprintf("Error parsing AdditionalLabels %s, Error: %s\n", AdditionalLabels, err)) + } + } +} + +// parses the AdditionalLabels variable and returns as map[string]string +func AddLabels(integration string) map[string]string { + definitiveLabels := labels.Set{ + v1.IntegrationLabel: integration, + } + for k, v := range FixedLabels { + if v == "token_integration_name" { + definitiveLabels[k] = integration + } else { + definitiveLabels[k] = v + } + } + return definitiveLabels +} diff --git a/pkg/util/label/label_test.go b/pkg/util/label/label_test.go new file mode 100644 index 0000000000..2169954f9e --- /dev/null +++ b/pkg/util/label/label_test.go @@ -0,0 +1,113 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package label + +import ( + "testing" + + v1 "github.com/apache/camel-k/pkg/apis/camel/v1" + "github.com/stretchr/testify/assert" +) + +func TestParseValidEntries(t *testing.T) { + integration := "test1" + AdditionalLabels = "k1=v1,k3/k3.k3=v3.v3,k4.k4=v4,k5/k5=v5" + FixedLabels = map[string]string{} + checkAdditionalLabels() + labels := AddLabels(integration) + expected := map[string]string{ + v1.IntegrationLabel: integration, + "k1": "v1", + "k3/k3.k3": "v3.v3", + "k4.k4": "v4", + "k5/k5": "v5", + } + assert.Equal(t, expected, labels) + + AdditionalLabels = "k1=v1" + FixedLabels = map[string]string{} + checkAdditionalLabels() + labels = AddLabels(integration) + expected = map[string]string{ + v1.IntegrationLabel: integration, + "k1": "v1", + } + assert.Equal(t, expected, labels) +} + +func TestParseEmptyAdditionalLabels(t *testing.T) { + integration := "test1" + AdditionalLabels = "" + FixedLabels = map[string]string{} + checkAdditionalLabels() + labels := AddLabels(integration) + expected := map[string]string{ + v1.IntegrationLabel: integration, + } + assert.Equal(t, expected, labels) +} + +func TestParseInvalidEntry(t *testing.T) { + integration := "test1" + AdditionalLabels = "k1[=v1,k2)=v2,k@3=v3" + FixedLabels = map[string]string{} + assert.Panics(t, func() { + checkAdditionalLabels() + AddLabels(integration) + }) +} + +func TestParseIntegrationPlaceholder(t *testing.T) { + integration := "test1" + AdditionalLabels = "k1=token_integration_name,k2=v2,k3=v3,k4.k4=v4,k5/k5=v5,rht.subcomp_t=my_subcomp" + FixedLabels = map[string]string{} + checkAdditionalLabels() + labels := AddLabels(integration) + expected := map[string]string{ + v1.IntegrationLabel: integration, + "k1": integration, + "k2": "v2", + "k3": "v3", + "k4.k4": "v4", + "k5/k5": "v5", + "rht.subcomp_t": "my_subcomp", + } + assert.Equal(t, expected, labels) + + AdditionalLabels = "k1=v1,k2=v2,k3=token_integration_name" + FixedLabels = map[string]string{} + checkAdditionalLabels() + labels = AddLabels(integration) + expected = map[string]string{ + v1.IntegrationLabel: integration, + "k1": "v1", + "k2": "v2", + "k3": integration, + } + assert.Equal(t, expected, labels) + + AdditionalLabels = "k3=token_integration_name" + FixedLabels = map[string]string{} + checkAdditionalLabels() + labels = AddLabels(integration) + expected = map[string]string{ + v1.IntegrationLabel: integration, + "k3": integration, + } + assert.Equal(t, expected, labels) +}