diff --git a/api/turing/api/appcontext.go b/api/turing/api/appcontext.go index c56efe93c..54503d04b 100644 --- a/api/turing/api/appcontext.go +++ b/api/turing/api/appcontext.go @@ -81,6 +81,7 @@ func NewAppContext( // Initialise Labeller labeller.InitKubernetesLabeller( cfg.KubernetesLabelConfigs.LabelPrefix, + cfg.KubernetesLabelConfigs.NamespaceLabelPrefix, cfg.KubernetesLabelConfigs.Environment, ) diff --git a/api/turing/cluster/controller.go b/api/turing/cluster/controller.go index 9a98534d2..1757cb07e 100644 --- a/api/turing/cluster/controller.go +++ b/api/turing/cluster/controller.go @@ -11,6 +11,7 @@ import ( sparkclient "github.com/GoogleCloudPlatform/spark-on-k8s-operator/pkg/client/clientset/versioned" sparkoperatorv1beta2 "github.com/GoogleCloudPlatform/spark-on-k8s-operator/pkg/client/clientset/versioned/typed/sparkoperator.k8s.io/v1beta2" //nolint mlpcluster "github.com/caraml-dev/mlp/api/pkg/cluster" + "github.com/caraml-dev/turing/api/turing/cluster/labeller" "github.com/pkg/errors" networkingv1beta1 "istio.io/client-go/pkg/clientset/versioned/typed/networking/v1beta1" apiappsv1 "k8s.io/api/apps/v1" @@ -211,7 +212,8 @@ func (c *controller) CreateNamespace(ctx context.Context, name string) error { } ns := apicorev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ - Name: name, + Name: name, + Labels: labeller.BuildNamespaceLabels(labeller.KubernetesLabelsRequest{}), }, } _, err = c.k8sCoreClient.Namespaces().Create(ctx, &ns, metav1.CreateOptions{}) diff --git a/api/turing/cluster/controller_test.go b/api/turing/cluster/controller_test.go index 98e7e4b07..793e6270d 100644 --- a/api/turing/cluster/controller_test.go +++ b/api/turing/cluster/controller_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + "github.com/caraml-dev/turing/api/turing/cluster/labeller" "istio.io/client-go/pkg/apis/networking/v1beta1" "k8s.io/apimachinery/pkg/api/resource" @@ -1224,6 +1225,8 @@ func TestDeleteSparkApplication(t *testing.T) { } func TestCreateNamespace(t *testing.T) { + labeller.InitKubernetesLabeller("", "caraml.dev/", "") + namespace := "test-ns" nsResource := schema.GroupVersionResource{ Version: "v1", @@ -1268,6 +1271,9 @@ func TestCreateNamespace(t *testing.T) { expectedAction := k8stesting.NewCreateAction(nsResource, "", &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: namespace, + Labels: map[string]string{ + "caraml.dev/managed": "true", + }, }, }) assert.Equal(t, expectedAction, action) diff --git a/api/turing/cluster/labeller/labeller.go b/api/turing/cluster/labeller/labeller.go index 7e34a861a..3ac45182c 100644 --- a/api/turing/cluster/labeller/labeller.go +++ b/api/turing/cluster/labeller/labeller.go @@ -3,6 +3,7 @@ package labeller import ( "fmt" "regexp" + "strconv" mlp "github.com/caraml-dev/mlp/api/client" ) @@ -20,10 +21,13 @@ const ( orchestratorLabel = "orchestrator" // AppLabel refers to application of the Kubernetes Object AppLabel = "app" + // managedLabel mark the kubernetes object as being managed by specific dev + managedLabel = "managed" ) var ( prefix string + nsPrefix string environment string ) @@ -53,8 +57,9 @@ func IsValidLabel(name string) error { } // InitKubernetesLabeller builds a new KubernetesLabeller Singleton -func InitKubernetesLabeller(p, e string) { +func InitKubernetesLabeller(p, ns, e string) { prefix = p + nsPrefix = ns environment = e } @@ -71,6 +76,11 @@ func GetLabelName(name string) string { return fmt.Sprintf("%s%s", prefix, name) } +// GetNamespaceLabelName prefixes the label with the specified label and returns the formatted label name +func GetNamespaceLabelName(name string) string { + return fmt.Sprintf("%s%s", nsPrefix, name) +} + // BuildLabels builds the labels for the Kubernetes object // Combines resource labels with project labels func BuildLabels(r KubernetesLabelsRequest) map[string]string { @@ -81,6 +91,21 @@ func BuildLabels(r KubernetesLabelsRequest) map[string]string { GetLabelName(AppLabel): r.App, GetLabelName(environmentLabel): environment, } + appendFromLabelsRequest(labels, r) + return labels +} + +// BuildNamespaceLabels builds the labels for a Kubernetes namespace. +// Combines resource labels with project labels +func BuildNamespaceLabels(r KubernetesLabelsRequest) map[string]string { + labels := map[string]string{ + GetNamespaceLabelName(managedLabel): strconv.FormatBool(true), + } + appendFromLabelsRequest(labels, r) + return labels +} + +func appendFromLabelsRequest(labels map[string]string, r KubernetesLabelsRequest) { for _, label := range r.Labels { // skip label that is trying to override reserved key if _, usingReservedKeys := reservedKeys[prefix+label.Key]; usingReservedKeys { @@ -99,5 +124,4 @@ func BuildLabels(r KubernetesLabelsRequest) map[string]string { labels[label.Key] = label.Value } - return labels } diff --git a/api/turing/cluster/labeller/labeller_test.go b/api/turing/cluster/labeller/labeller_test.go index 6a4d5483e..e1987d743 100644 --- a/api/turing/cluster/labeller/labeller_test.go +++ b/api/turing/cluster/labeller/labeller_test.go @@ -38,10 +38,10 @@ func TestLabeller(t *testing.T) { for name, tt := range tests { t.Run(name, func(t *testing.T) { // Always reset singleton objects. - defer InitKubernetesLabeller("", "dev") + defer InitKubernetesLabeller("", "", "dev") if tt.doInit { - InitKubernetesLabeller(tt.prefix, "dev") + InitKubernetesLabeller(tt.prefix, "caraml.dev/", "dev") } labels := BuildLabels(KubernetesLabelsRequest{}) @@ -121,7 +121,7 @@ func TestBuildLabels(t *testing.T) { for _, tt := range tests { // Always reset singleton objects. - defer InitKubernetesLabeller("", "dev") + defer InitKubernetesLabeller("", "", "dev") t.Run(tt.name, func(t *testing.T) { got := BuildLabels(tt.request) if diff := cmp.Diff(got, tt.expected); diff != "" { diff --git a/api/turing/config/config.go b/api/turing/config/config.go index cc3ef5fbc..dca4eefb4 100644 --- a/api/turing/config/config.go +++ b/api/turing/config/config.go @@ -255,6 +255,8 @@ type KubernetesLabelConfigs struct { // orchestrator: turing // app: my-model-app LabelPrefix string + // NamespaceLabelPrefix is the prefix used for tagging kubernetes namespace. + NamespaceLabelPrefix string // Environment is the value for the environment label Environment string `validate:"required"` } diff --git a/api/turing/service/ensembling_job_service_test.go b/api/turing/service/ensembling_job_service_test.go index ed889cdc1..3cbb5f012 100644 --- a/api/turing/service/ensembling_job_service_test.go +++ b/api/turing/service/ensembling_job_service_test.go @@ -648,8 +648,8 @@ func TestGetNamespaceByComponent(t *testing.T) { } func TestCreatePodLabelSelector(t *testing.T) { - labeller.InitKubernetesLabeller("prefix/", "dev") - defer labeller.InitKubernetesLabeller("", "dev") + labeller.InitKubernetesLabeller("prefix/", "", "dev") + defer labeller.InitKubernetesLabeller("", "", "dev") ensemblerName := "name" tests := map[string]struct {