diff --git a/pkg/transformer/kubernetes/k8sutils.go b/pkg/transformer/kubernetes/k8sutils.go index 3029356fc..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 { + if service.MemLimit != 0 || service.CPULimit != 0 || service.DeployLabels["kompose.ephemeral-storage.limit"] != "" { 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["kompose.ephemeral-storage.limit"]; 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["kompose.ephemeral-storage.request"] != "" { 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["kompose.ephemeral-storage.request"]; ok { + if quantity, err := resource.ParseQuantity(val); err == nil { + resourceRequests[api.ResourceEphemeralStorage] = quantity + } + } + template.Spec.Containers[0].Resources.Requests = resourceRequests } } 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 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..fc0d44f92 --- /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: + kompose.ephemeral-storage.request: 1Gi + kompose.ephemeral-storage.limit: 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..48f6ac16b --- /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 + kompose.ephemeral-storage.limit: 1Gi + kompose.ephemeral-storage.request: 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 +