From 3ec739017dff96c3baad2637f4945f55eca8509c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Vitor=20Paes=20de=20Barros=20do=20Carmo?= Date: Fri, 27 Sep 2024 01:02:46 +0100 Subject: [PATCH 1/4] feat(deploy): support ephemeral storage requests limits labels --- pkg/transformer/kubernetes/k8sutils.go | 18 ++++++- script/test/cmd/tests.sh | 5 ++ .../test/fixtures/deploy/labels/compose.yaml | 9 ++++ .../fixtures/deploy/labels/output-k8s.yaml | 47 +++++++++++++++++++ 4 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 script/test/fixtures/deploy/labels/compose.yaml create mode 100644 script/test/fixtures/deploy/labels/output-k8s.yaml diff --git a/pkg/transformer/kubernetes/k8sutils.go b/pkg/transformer/kubernetes/k8sutils.go index 3029356fc..c4bcb7735 100644 --- a/pkg/transformer/kubernetes/k8sutils.go +++ b/pkg/transformer/kubernetes/k8sutils.go @@ -811,7 +811,7 @@ func KomposeObjectToServiceConfigGroupMapping(komposeObject *kobject.KomposeObje // TranslatePodResource config pod resources func TranslatePodResource(service *kobject.ServiceConfig, template *api.PodTemplateSpec) { // Configure the resource limits - if service.MemLimit != 0 || service.CPULimit != 0 { + if service.MemLimit != 0 || service.CPULimit != 0 || service.DeployLabels["limits.ephemeral-storage"] != "" { resourceLimit := api.ResourceList{} if service.MemLimit != 0 { @@ -822,11 +822,18 @@ func TranslatePodResource(service *kobject.ServiceConfig, template *api.PodTempl resourceLimit[api.ResourceCPU] = *resource.NewMilliQuantity(service.CPULimit, resource.DecimalSI) } + // Check for ephemeral-storage in deploy labels + if val, ok := service.DeployLabels["limits.ephemeral-storage"]; ok { + if quantity, err := resource.ParseQuantity(val); err == nil { + resourceLimit[api.ResourceEphemeralStorage] = quantity + } + } + template.Spec.Containers[0].Resources.Limits = resourceLimit } // Configure the resource requests - if service.MemReservation != 0 || service.CPUReservation != 0 { + if service.MemReservation != 0 || service.CPUReservation != 0 || service.DeployLabels["requests.ephemeral-storage"] != "" { resourceRequests := api.ResourceList{} if service.MemReservation != 0 { @@ -837,6 +844,13 @@ func TranslatePodResource(service *kobject.ServiceConfig, template *api.PodTempl resourceRequests[api.ResourceCPU] = *resource.NewMilliQuantity(service.CPUReservation, resource.DecimalSI) } + // Check for ephemeral-storage in deploy labels + if val, ok := service.DeployLabels["requests.ephemeral-storage"]; ok { + if quantity, err := resource.ParseQuantity(val); err == nil { + resourceRequests[api.ResourceEphemeralStorage] = quantity + } + } + template.Spec.Containers[0].Resources.Requests = resourceRequests } } diff --git a/script/test/cmd/tests.sh b/script/test/cmd/tests.sh index 9220fbc10..b62325cc1 100755 --- a/script/test/cmd/tests.sh +++ b/script/test/cmd/tests.sh @@ -390,4 +390,9 @@ convert::expect_success "$os_cmd" "$os_output" || exit 1 # Test label in compose.yaml appears in the output annotation k8s_cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/label/compose.yaml convert --stdout --with-kompose-annotation=false" k8s_output="$KOMPOSE_ROOT/script/test/fixtures/label/output-k8s.yaml" +convert::expect_success "$k8s_cmd" "$k8s_output" || exit 1 + +# Test deploy.labels in compose.yaml appears in the output +k8s_cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/deploy/labels/compose.yaml convert --stdout --with-kompose-annotation=false" +k8s_output="$KOMPOSE_ROOT/script/test/fixtures/deploy/labels/output-k8s.yaml" convert::expect_success "$k8s_cmd" "$k8s_output" || exit 1 \ No newline at end of file diff --git a/script/test/fixtures/deploy/labels/compose.yaml b/script/test/fixtures/deploy/labels/compose.yaml new file mode 100644 index 000000000..313f6682e --- /dev/null +++ b/script/test/fixtures/deploy/labels/compose.yaml @@ -0,0 +1,9 @@ +services: + app: + image: node:18-alpine + ports: + - 3000:3000 + deploy: + labels: + requests.ephemeral-storage: 1Gi + limits.ephemeral-storage: 1Gi diff --git a/script/test/fixtures/deploy/labels/output-k8s.yaml b/script/test/fixtures/deploy/labels/output-k8s.yaml new file mode 100644 index 000000000..2c45daab5 --- /dev/null +++ b/script/test/fixtures/deploy/labels/output-k8s.yaml @@ -0,0 +1,47 @@ +--- +apiVersion: v1 +kind: Service +metadata: + labels: + io.kompose.service: app + name: app +spec: + ports: + - name: "3000" + port: 3000 + targetPort: 3000 + selector: + io.kompose.service: app + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + io.kompose.service: app + limits.ephemeral-storage: 1Gi + requests.ephemeral-storage: 1Gi + name: app +spec: + replicas: 1 + selector: + matchLabels: + io.kompose.service: app + template: + metadata: + labels: + io.kompose.service: app + spec: + containers: + - image: node:18-alpine + name: app + ports: + - containerPort: 3000 + protocol: TCP + resources: + limits: + ephemeral-storage: 1Gi + requests: + ephemeral-storage: 1Gi + restartPolicy: Always + From 1c7c63f1e73d8cf8d54ced011322c4a51b2e7e1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Vitor=20Paes=20de=20Barros=20do=20Carmo?= Date: Fri, 4 Oct 2024 00:06:43 +0100 Subject: [PATCH 2/4] refactor: changed the deploy label to use the convention --- pkg/transformer/kubernetes/k8sutils.go | 8 ++++---- script/test/fixtures/deploy/labels/compose.yaml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/transformer/kubernetes/k8sutils.go b/pkg/transformer/kubernetes/k8sutils.go index c4bcb7735..61b940d24 100644 --- a/pkg/transformer/kubernetes/k8sutils.go +++ b/pkg/transformer/kubernetes/k8sutils.go @@ -811,7 +811,7 @@ func KomposeObjectToServiceConfigGroupMapping(komposeObject *kobject.KomposeObje // TranslatePodResource config pod resources func TranslatePodResource(service *kobject.ServiceConfig, template *api.PodTemplateSpec) { // Configure the resource limits - if service.MemLimit != 0 || service.CPULimit != 0 || service.DeployLabels["limits.ephemeral-storage"] != "" { + if service.MemLimit != 0 || service.CPULimit != 0 || service.DeployLabels["kompose.ephemeral-storage.limit"] != "" { resourceLimit := api.ResourceList{} if service.MemLimit != 0 { @@ -823,7 +823,7 @@ func TranslatePodResource(service *kobject.ServiceConfig, template *api.PodTempl } // Check for ephemeral-storage in deploy labels - if val, ok := service.DeployLabels["limits.ephemeral-storage"]; ok { + if val, ok := service.DeployLabels["kompose.ephemeral-storage.limit"]; ok { if quantity, err := resource.ParseQuantity(val); err == nil { resourceLimit[api.ResourceEphemeralStorage] = quantity } @@ -833,7 +833,7 @@ func TranslatePodResource(service *kobject.ServiceConfig, template *api.PodTempl } // Configure the resource requests - if service.MemReservation != 0 || service.CPUReservation != 0 || service.DeployLabels["requests.ephemeral-storage"] != "" { + if service.MemReservation != 0 || service.CPUReservation != 0 || service.DeployLabels["kompose.ephemeral-storage.request"] != "" { resourceRequests := api.ResourceList{} if service.MemReservation != 0 { @@ -845,7 +845,7 @@ func TranslatePodResource(service *kobject.ServiceConfig, template *api.PodTempl } // Check for ephemeral-storage in deploy labels - if val, ok := service.DeployLabels["requests.ephemeral-storage"]; ok { + if val, ok := service.DeployLabels["kompose.ephemeral-storage.request"]; ok { if quantity, err := resource.ParseQuantity(val); err == nil { resourceRequests[api.ResourceEphemeralStorage] = quantity } diff --git a/script/test/fixtures/deploy/labels/compose.yaml b/script/test/fixtures/deploy/labels/compose.yaml index 313f6682e..fc0d44f92 100644 --- a/script/test/fixtures/deploy/labels/compose.yaml +++ b/script/test/fixtures/deploy/labels/compose.yaml @@ -5,5 +5,5 @@ services: - 3000:3000 deploy: labels: - requests.ephemeral-storage: 1Gi - limits.ephemeral-storage: 1Gi + kompose.ephemeral-storage.request: 1Gi + kompose.ephemeral-storage.limit: 1Gi From 1945fe609fe538464b33186b72eae6ff8e411d5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Vitor=20Paes=20de=20Barros=20do=20Carmo?= Date: Fri, 4 Oct 2024 00:07:25 +0100 Subject: [PATCH 3/4] test: added test for the ephemeral storage labels --- pkg/transformer/kubernetes/k8sutils_test.go | 97 +++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/pkg/transformer/kubernetes/k8sutils_test.go b/pkg/transformer/kubernetes/k8sutils_test.go index 933de5ddc..ae6c498de 100644 --- a/pkg/transformer/kubernetes/k8sutils_test.go +++ b/pkg/transformer/kubernetes/k8sutils_test.go @@ -32,6 +32,7 @@ import ( hpa "k8s.io/api/autoscaling/v2beta2" api "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" ) @@ -183,6 +184,102 @@ func TestCreateServiceWithCPULimit(t *testing.T) { } } +/* +Test the creation of a service with ephemeral storage limit +*/ +func TestDeployLabelsEphemeralStorageLimit(t *testing.T) { + // An example service + service := kobject.ServiceConfig{ + ContainerName: "name", + Image: "image", + Environment: []kobject.EnvVar{{Name: "env", Value: "value"}}, + Port: []kobject.Ports{{HostPort: 123, ContainerPort: 456, Protocol: string(corev1.ProtocolTCP)}}, + Command: []string{"cmd"}, + WorkingDir: "dir", + Args: []string{"arg1", "arg2"}, + VolList: []string{"/tmp/volume"}, + Network: []string{"network1", "network2"}, + Labels: nil, + Annotations: map[string]string{"abc": "def"}, + CPUQuota: 1, + CapAdd: []string{"cap_add"}, + CapDrop: []string{"cap_drop"}, + Expose: []string{"expose"}, + Privileged: true, + Restart: "always", + DeployLabels: map[string]string{"kompose.ephemeral-storage.limit": "1Gi"}, + } + + // An example object generated via k8s runtime.Objects() + komposeObject := kobject.KomposeObject{ + ServiceConfigs: map[string]kobject.ServiceConfig{"app": service}, + } + k := Kubernetes{} + objects, err := k.Transform(komposeObject, kobject.ConvertOptions{CreateD: true, Replicas: 3}) + if err != nil { + t.Error(errors.Wrap(err, "k.Transform failed")) + } + + // Retrieve the deployment object and test that it matches the ephemeral storage limit value + for _, obj := range objects { + if deploy, ok := obj.(*appsv1.Deployment); ok { + storageLimit := deploy.Spec.Template.Spec.Containers[0].Resources.Limits.StorageEphemeral() + expectedLimit := resource.MustParse("1Gi") + if *storageLimit != expectedLimit { + t.Errorf("Expected %v for ephemeral storage limit check, got %v", expectedLimit, storageLimit) + } + } + } +} + +/* +Test the creation of a service with ephemeral storage request +*/ +func TestDeployLabelsEphemeralStorageRequest(t *testing.T) { + // An example service + service := kobject.ServiceConfig{ + ContainerName: "name", + Image: "image", + Environment: []kobject.EnvVar{{Name: "env", Value: "value"}}, + Port: []kobject.Ports{{HostPort: 123, ContainerPort: 456, Protocol: string(corev1.ProtocolTCP)}}, + Command: []string{"cmd"}, + WorkingDir: "dir", + Args: []string{"arg1", "arg2"}, + VolList: []string{"/tmp/volume"}, + Network: []string{"network1", "network2"}, + Labels: nil, + Annotations: map[string]string{"abc": "def"}, + CPUQuota: 1, + CapAdd: []string{"cap_add"}, + CapDrop: []string{"cap_drop"}, + Expose: []string{"expose"}, + Privileged: true, + Restart: "always", + DeployLabels: map[string]string{"kompose.ephemeral-storage.request": "1Gi"}, + } + + // An example object generated via k8s runtime.Objects() + komposeObject := kobject.KomposeObject{ + ServiceConfigs: map[string]kobject.ServiceConfig{"app": service}, + } + k := Kubernetes{} + objects, err := k.Transform(komposeObject, kobject.ConvertOptions{CreateD: true, Replicas: 3}) + if err != nil { + t.Error(errors.Wrap(err, "k.Transform failed")) + } + + // Retrieve the deployment object and test that it matches the ephemeral storage request value + for _, obj := range objects { + if deploy, ok := obj.(*appsv1.Deployment); ok { + storageRequest := deploy.Spec.Template.Spec.Containers[0].Resources.Requests.StorageEphemeral() + expectedRequest := resource.MustParse("1Gi") + if *storageRequest != expectedRequest { + t.Errorf("Expected %v for ephemeral storage request check, got %v", expectedRequest, storageRequest) + } + } + } +} + /* Test the creation of a service with a specified user. The expected result is that Kompose will set user in PodSpec From 073109ce3921a90028ec8d3ebb1cf2bdfb218863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Vitor=20Paes=20de=20Barros=20do=20Carmo?= Date: Thu, 31 Oct 2024 00:05:04 +0000 Subject: [PATCH 4/4] test(deploy-label): rename expected ephemeral label for test --- script/test/fixtures/deploy/labels/output-k8s.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/script/test/fixtures/deploy/labels/output-k8s.yaml b/script/test/fixtures/deploy/labels/output-k8s.yaml index 2c45daab5..48f6ac16b 100644 --- a/script/test/fixtures/deploy/labels/output-k8s.yaml +++ b/script/test/fixtures/deploy/labels/output-k8s.yaml @@ -19,8 +19,8 @@ kind: Deployment metadata: labels: io.kompose.service: app - limits.ephemeral-storage: 1Gi - requests.ephemeral-storage: 1Gi + kompose.ephemeral-storage.limit: 1Gi + kompose.ephemeral-storage.request: 1Gi name: app spec: replicas: 1