Skip to content

Commit

Permalink
feat: Include mlp project labels in created resources labels (#373)
Browse files Browse the repository at this point in the history
* Update labeller

* Add Labels field to BuildLabel references

* Fix test expected value

* Update invalid label test case
  • Loading branch information
shydefoo authored Apr 1, 2024
1 parent 9fc8000 commit 40df8e9
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 8 deletions.
1 change: 1 addition & 0 deletions api/turing/batch/ensembling/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ func (r *ensemblingJobRunner) buildLabels(
Stream: mlpProject.Stream,
Team: mlpProject.Team,
App: *ensemblingJob.InfraConfig.EnsemblerName,
Labels: mlpProject.Labels,
}

return labeller.BuildLabels(rq)
Expand Down
55 changes: 53 additions & 2 deletions api/turing/cluster/labeller/labeller.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package labeller

import "fmt"
import (
"fmt"
"regexp"

mlp "github.com/caraml-dev/mlp/api/client"
)

const (
// orchestratorValue is the value of the orchestrator (which is Turing)
Expand All @@ -22,6 +27,31 @@ var (
environment string
)

var validLabelRegex = regexp.MustCompile("^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$")

var reservedKeys = map[string]bool{
orchestratorLabel: true,
environmentLabel: true,
streamLabel: true,
teamLabel: true,
AppLabel: true,
}

// ValidLabel logic reused from
// https://github.com/caraml-dev/merlin/blob/06f121c6da05c5b5f1a28389e1078aaafed67541/api/models/metadata.go#L57
func IsValidLabel(name string) error {
lengthOfName := len(name) < 64
if !(lengthOfName) {
return fmt.Errorf("length of name is greater than 63 characters")
}

if isValidName := validLabelRegex.MatchString(name); !isValidName {
return fmt.Errorf("name violates kubernetes label constraint")
}

return nil
}

// InitKubernetesLabeller builds a new KubernetesLabeller Singleton
func InitKubernetesLabeller(p, e string) {
prefix = p
Expand All @@ -33,6 +63,7 @@ type KubernetesLabelsRequest struct {
Stream string
Team string
App string
Labels []mlp.Label
}

// GetLabelName prefixes the label with the config specified label and returns the formatted label name
Expand All @@ -41,12 +72,32 @@ func GetLabelName(name string) string {
}

// BuildLabels builds the labels for the Kubernetes object
// Combines resource labels with project labels
func BuildLabels(r KubernetesLabelsRequest) map[string]string {
return map[string]string{
labels := map[string]string{
GetLabelName(orchestratorLabel): orchestratorValue,
GetLabelName(streamLabel): r.Stream,
GetLabelName(teamLabel): r.Team,
GetLabelName(AppLabel): r.App,
GetLabelName(environmentLabel): environment,
}
for _, label := range r.Labels {
// skip label that is trying to override reserved key
if _, usingReservedKeys := reservedKeys[prefix+label.Key]; usingReservedKeys {
continue
}

// skip label that has invalid key name
if err := IsValidLabel(label.Key); err != nil {
continue
}

// skip label that has invalid value name
if err := IsValidLabel(label.Value); err != nil {
continue
}

labels[label.Key] = label.Value
}
return labels
}
84 changes: 83 additions & 1 deletion api/turing/cluster/labeller/labeller_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package labeller

import "testing"
import (
"testing"

mlp "github.com/caraml-dev/mlp/api/client"
"github.com/google/go-cmp/cmp"
)

func TestLabeller(t *testing.T) {
tests := map[string]struct {
Expand Down Expand Up @@ -48,3 +53,80 @@ func TestLabeller(t *testing.T) {
})
}
}

func TestBuildLabels(t *testing.T) {
tests := []struct {
name string
request KubernetesLabelsRequest
expected map[string]string
}{
{
name: "Test with valid request",
request: KubernetesLabelsRequest{
Stream: "testStream",
Team: "testTeam",
App: "testApp",
Labels: []mlp.Label{
{Key: "customLabel1", Value: "value1"},
{Key: "customLabel2", Value: "value2"},
},
},
expected: map[string]string{
"orchestrator": "turing",
"stream": "testStream",
"team": "testTeam",
"app": "testApp",
"environment": "dev",
"customLabel1": "value1",
"customLabel2": "value2",
},
},
{
name: "Test with reserved key",
request: KubernetesLabelsRequest{
Stream: "testStream",
Team: "testTeam",
App: "testApp",
Labels: []mlp.Label{
{Key: "orchestrator", Value: "value1"}, // Reserved key
},
},
expected: map[string]string{
"orchestrator": "turing", // Should not be overridden
"stream": "testStream",
"team": "testTeam",
"app": "testApp",
"environment": "dev",
},
},
{
name: "Test with invalid label names",
request: KubernetesLabelsRequest{
Stream: "testStream",
Team: "testTeam",
App: "testApp",
Labels: []mlp.Label{
{Key: "invalid Label", Value: "value1"}, // Invalid label key
},
},
expected: map[string]string{
"orchestrator": "turing",
"stream": "testStream",
"team": "testTeam",
"app": "testApp",
"environment": "dev",
},
},
}

for _, tt := range tests {
// Always reset singleton objects.
defer InitKubernetesLabeller("", "dev")
t.Run(tt.name, func(t *testing.T) {
got := BuildLabels(tt.request)
if diff := cmp.Diff(got, tt.expected); diff != "" {
t.Errorf("BuildLabels() mismatch (-got +want):\n%s", diff)
}
})
}
}
1 change: 1 addition & 0 deletions api/turing/cluster/servicebuilder/service_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ func buildLabels(
Stream: project.Stream,
Team: project.Team,
App: router.Name,
Labels: project.Labels,
}
return labeller.BuildLabels(r)
}
12 changes: 7 additions & 5 deletions api/turing/cluster/servicebuilder/service_builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,12 @@ func TestNewEnricherService(t *testing.T) {
{Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: "/var/secret/enricher-service-account.json"},
},
Labels: map[string]string{
"app": "test-svc",
"environment": "",
"orchestrator": "turing",
"stream": "test-stream",
"team": "test-team",
"app": "test-svc",
"environment": "",
"orchestrator": "turing",
"stream": "test-stream",
"team": "test-team",
"custom-label-key": "value-1",
},
Volumes: []corev1.Volume{
{
Expand Down Expand Up @@ -108,6 +109,7 @@ func TestNewEnricherService(t *testing.T) {
Name: "test-project",
Stream: "test-stream",
Team: "test-team",
Labels: []mlp.Label{{Key: "custom-label-key", Value: "value-1"}},
}
svc, err := sb.NewEnricherService(routerVersion, project, "secret", 10, 0, 1.5, data.initialScale)
if data.err == "" {
Expand Down
1 change: 1 addition & 0 deletions api/turing/service/router_deployment_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ func (ds *deploymentService) buildEnsemblerServiceImage(
Stream: project.Stream,
Team: project.Team,
App: ensembler.Name,
Labels: project.Labels,
},
),
EnsemblerFolder: EnsemblerFolder,
Expand Down

0 comments on commit 40df8e9

Please sign in to comment.