Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(deploy): support ephemeral storage requests limits labels #1936

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions pkg/transformer/kubernetes/k8sutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand All @@ -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
}
}
Expand Down
97 changes: 97 additions & 0 deletions pkg/transformer/kubernetes/k8sutils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions script/test/cmd/tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 9 additions & 0 deletions script/test/fixtures/deploy/labels/compose.yaml
Original file line number Diff line number Diff line change
@@ -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
47 changes: 47 additions & 0 deletions script/test/fixtures/deploy/labels/output-k8s.yaml
Original file line number Diff line number Diff line change
@@ -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

Loading