From db362dbed4d474828c854a8125c0830fcabcb9cb Mon Sep 17 00:00:00 2001 From: Janardhan Pulivarthi Date: Sat, 2 Aug 2025 13:28:30 +0530 Subject: [PATCH 1/5] implement AttachCapsuleToDeployment --- kubernetes.go | 71 +++++++++++++++++++++++++++ kubernetes_test.go | 118 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+) diff --git a/kubernetes.go b/kubernetes.go index be14faf..77f85c8 100644 --- a/kubernetes.go +++ b/kubernetes.go @@ -193,12 +193,83 @@ func (kcm *KubernetesCapsuleManager) AttachCapsuleToDeployment(deploymentName, c // This would involve updating a Deployment to mount the ConfigMap/Secret // For this implementation, we'll simulate the attachment fmt.Printf("[Kubernetes] Attaching capsule %s:%s to deployment %s\n", capsuleName, capsuleVersion, deploymentName) + kcm.client.AppsV1().Deployments(kcm.namespace).Get(context.TODO(), deploymentName, metav1.GetOptions{}) + if err != nil { + return fmt.Errorf("failed to get deployment %s: %v", deploymentName, err) + } + // does capsule exists as a ConfigMap or Secret + configMapName := fmt.Sprintf("%s-%s", capsuleName, capsuleVersion) + secretName := configMapName + + configMap, configMapErr := kcm.GetConfigMapCapsule(capsuleName, capsuleVersion) + secret, secretErr := kcm.GetSecretCapsule(capsuleName, capsuleVersion) + + var volumeName string + var volumeSource v1.volumeSource + var mountPath string + + if configMapErr == nil { + // It's a ConfigMap capsule + volumeName = fmt.Sprintf("capsule-%s-%s", capsuleName, capsureVersion) + volumeSource = v1.VolumeSource{ + ConfigMap: &v1.ConfigMapVolumeSource { + LocalObjectReference: v1.LocalObjectReference { + name: configMapName, + }, + }, + } + mountPath = fmt.Sprintf("/capsules/%s/%s", capsuleName, capsuleVersion) + } else if secretErr == nil { + // It's a Secret capsule + volumeName = fmt.Sprintf("capsule-%s-%s", capsuleName, capsuleVersion) + volumeSource = v1.VolumeSource{ + Secret: &v1.SecretVolumeSource { + SecretName: secretName, + }, + } + mountPath = fmt.Sprintf("/capsules/%s/%s", capsuleName, capsuleVersion) + } else { + return fmt.Errorf("capsule %s:%s not found", capsuleName, capsuleVersion) + } + + deployment.Spec.Template.Spec.Volumes = append( + deployment.Spec.Template.Spec.Volumes, + v1.Volume { + Name: volumeName, + VolumeSource: volumeSource, + }, + ) + // In a real implementation, this would: // 1. Get the existing Deployment // 2. Add a volume for the ConfigMap/Secret // 3. Add a volumeMount to the container spec + for i := range deployment.Spec.Template.Spec.Containers { + container := & deployment.Spec.Template.Spec.Containers[i] + + // check if this container already has the mount + for _, mount := range cotainer.VolumeMounts { + if mount.Name == volumeName { + mountExists = true + break + } + } + + } + // 4. Update the Deployment + kcm.client.AppsV1().Deployments(kcm.namespace).Update( + context.TODO(), + deployment, + metav1.UpdateOptions{}, + ) + if err != nil { + fmt.Errorf("failed to update deployment %s: %v", deploymentName, err) + } + + fmt.Printf("[Kubernetes] Capsule %s:%s attached to deployment %s at path %s\n", + capsuleName, capsuleVersion, deploymentName, mountPath) return nil } diff --git a/kubernetes_test.go b/kubernetes_test.go index 7eb13cb..8a98944 100644 --- a/kubernetes_test.go +++ b/kubernetes_test.go @@ -175,6 +175,124 @@ func TestAddKubernetesResourceCapsule(t *testing.T) { } } +func TestAttachCapsuleToDeployment(t *testing.T) { + clientset := fake.NewSimpleClientset() + + deployment := &appsv1.Deployment { + ObjectMeta: metav1.ObjectMeta { + Name: "test-deployment", + Namespace: "default", + }, + Spec: appsv1.DeploymentSpec { + Selector: &metav1.LabelSelector { + MatchLabels: map[string]string { + "app": "test", + }, + }, + Template: v1.PodTemplateSpec { + ObjectMeta: metav1.ObjectMeta { + Labels: map[string] string { + "app": "test", + }, + }, + Spec: v1.PodSpec { + Containers: []v1.Container { + Name: "test-container", + Image: "nginx:latest", + }, + }, + }, + }, + } + + // Create the deployment in the fake clientset + _, err := clientset.AppsV1().Deployments("default").Create( + context.TODO(), + deployment, + metav1.CreateOptions{}, + ) + if err != nil { + t.Fatalf("Failed to create test deployment: %v", err) + } + + // Create a test ConfigMap capsule + configMap := &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-capsule-1.0", + Namespace: "default", + Labels: map[string]string{ + "capsule.docker.io/name": "test-capsule", + "capsule.docker.io/version": "1.0", + }, + }, + Data: map[string]string{ + "test-data": "test value", + }, + } + + // Create the ConfigMap in the fake clientset + _, err = clientset.CoreV1().ConfigMaps("default").Create( + context.TODO(), + configMap, + metav1.CreateOptions{}, + ) + if err != nil { + t.Fatalf("Failed to create test ConfigMap: %v", err) + } + + // Create a KubernetesCapsuleManager with the fake clientset + kcm := &KubernetesCapsuleManager{ + client: clientset, + namespace: "default", + } + + // Attach the capsule to the deployment + err = kcm.AttachCapsuleToDeployment("test-deployment", "test-capsule", "1.0") + if err != nil { + t.Fatalf("Failed to attach capsule to deployment: %v", err) + } + + // Get the updated deployment + updatedDeployment, err := clientset.AppsV1().Deployments("default").Get( + context.TODO(), + "test-deployment", + metav1.GetOptions{}, + ) + if err != nil { + t.Fatalf("Failed to get updated deployment: %v", err) + } + + // Check that the volume was added + volumeFound := false + for _, volume := range updatedDeployment.Spec.Template.Spec.Volumes { + if volume.Name == "capsule-test-capsule-1.0" { + volumeFound = true + break + } + } + if !volumeFound { + t.Errorf("Volume for capsule was not added to the deployment") + } + + // Check that the volume mount was added to the container + container := &updatedDeployment.Spec.Template.Spec.Containers[0] + mountFound := false + for _, mount := range container.VolumeMounts { + if mount.Name == "capsule-test-capsule-1.0" { + mountFound = true + if mount.MountPath != "/capsules/test-capsule/1.0" { + t.Errorf("Unexpected mount path: got %s, want /capsules/test-capsule/1.0", mount.MountPath) + } + break + } + } + if !mountFound { + t.Errorf("Volume mount for capsule was not added to the container") + } + + t.Log("Successfully attached capsule to deployment and verified volume and mount") +} + // BenchmarkKubernetesConfigMapAccess benchmarks ConfigMap access performance func BenchmarkKubernetesConfigMapAccess(b *testing.B) { mockKCM := NewMockKubernetesCapsuleManager() From c7f7bee3e7e5b82e53841f1feb0fe757e89aa964 Mon Sep 17 00:00:00 2001 From: Janardhan Pulivarthi Date: Sat, 2 Aug 2025 13:35:17 +0530 Subject: [PATCH 2/5] fix syntax issues --- kubernetes.go | 143 ++++++++++++++++++++++++-------------------------- 1 file changed, 70 insertions(+), 73 deletions(-) diff --git a/kubernetes.go b/kubernetes.go index 77f85c8..ab9e079 100644 --- a/kubernetes.go +++ b/kubernetes.go @@ -190,88 +190,85 @@ func (kcm *KubernetesCapsuleManager) DeleteCapsule(name, version string) error { // AttachCapsuleToDeployment attaches a Resource Capsule to a Kubernetes Deployment func (kcm *KubernetesCapsuleManager) AttachCapsuleToDeployment(deploymentName, capsuleName, capsuleVersion string) error { - // This would involve updating a Deployment to mount the ConfigMap/Secret - // For this implementation, we'll simulate the attachment - fmt.Printf("[Kubernetes] Attaching capsule %s:%s to deployment %s\n", capsuleName, capsuleVersion, deploymentName) - kcm.client.AppsV1().Deployments(kcm.namespace).Get(context.TODO(), deploymentName, metav1.GetOptions{}) - if err != nil { - return fmt.Errorf("failed to get deployment %s: %v", deploymentName, err) - } - - // does capsule exists as a ConfigMap or Secret - configMapName := fmt.Sprintf("%s-%s", capsuleName, capsuleVersion) - secretName := configMapName - - configMap, configMapErr := kcm.GetConfigMapCapsule(capsuleName, capsuleVersion) - secret, secretErr := kcm.GetSecretCapsule(capsuleName, capsuleVersion) - - var volumeName string - var volumeSource v1.volumeSource - var mountPath string - - if configMapErr == nil { - // It's a ConfigMap capsule - volumeName = fmt.Sprintf("capsule-%s-%s", capsuleName, capsureVersion) - volumeSource = v1.VolumeSource{ - ConfigMap: &v1.ConfigMapVolumeSource { - LocalObjectReference: v1.LocalObjectReference { - name: configMapName, - }, - }, - } - mountPath = fmt.Sprintf("/capsules/%s/%s", capsuleName, capsuleVersion) - } else if secretErr == nil { - // It's a Secret capsule - volumeName = fmt.Sprintf("capsule-%s-%s", capsuleName, capsuleVersion) - volumeSource = v1.VolumeSource{ - Secret: &v1.SecretVolumeSource { - SecretName: secretName, - }, - } - mountPath = fmt.Sprintf("/capsules/%s/%s", capsuleName, capsuleVersion) - } else { - return fmt.Errorf("capsule %s:%s not found", capsuleName, capsuleVersion) - } + // 1. Get the existing Deployment + deployment, err := kcm.client.AppsV1().Deployments(kcm.namespace).Get(context.TODO(), deploymentName, metav1.GetOptions{}) + if err != nil { + return fmt.Errorf("failed to get deployment %s: %v", deploymentName, err) + } + // does capsule exists as a ConfigMap or Secret + configMapName := fmt.Sprintf("%s-%s", capsuleName, capsuleVersion) + secretName := configMapName + + // First, determine if the capsule exists as a ConfigMap or Secret + configMap, configMapErr := kcm.GetConfigMapCapsule(capsuleName, capsuleVersion) + secret, secretErr := kcm.GetSecretCapsule(capsuleName, capsuleVersion) + + // 2. Add a volume for the ConfigMap/Secret + var volumeName string + var volumeSource v1.VolumeSource + var mountPath string + + if configMapErr == nil { + // It's a ConfigMap capsule + volumeName = fmt.Sprintf("capsule-%s-%s", capsuleName, capsuleVersion) + volumeSource = v1.VolumeSource{ + ConfigMap: &v1.ConfigMapVolumeSource{ + LocalObjectReference: v1.LocalObjectReference{ + Name: configMapName, + }, + }, + } + mountPath = fmt.Sprintf("/capsules/%s/%s", capsuleName, capsuleVersion) + } else if secretErr == nil { + // It's a Secret capsule + volumeName = fmt.Sprintf("capsule-%s-%s", capsuleName, capsuleVersion) + volumeSource = v1.VolumeSource{ + Secret: &v1.SecretVolumeSource{ + SecretName: secretName, + }, + } + mountPath = fmt.Sprintf("/capsules/%s/%s", capsuleName, capsuleVersion) + } else { + return fmt.Errorf("capsule %s:%s not found", capsuleName, capsuleVersion) + } + deployment.Spec.Template.Spec.Volumes = append( deployment.Spec.Template.Spec.Volumes, - v1.Volume { - Name: volumeName, + v1.Volume{ + Name: volumeName, VolumeSource: volumeSource, }, ) - - // In a real implementation, this would: - // 1. Get the existing Deployment - // 2. Add a volume for the ConfigMap/Secret + + // 3. Add a volumeMount to the container spec - for i := range deployment.Spec.Template.Spec.Containers { - container := & deployment.Spec.Template.Spec.Containers[i] - + for i := range deployment.Spec.Template.Spec.Containers { + container := &deployment.Spec.Template.Spec.Containers[i] + // check if this container already has the mount for _, mount := range cotainer.VolumeMounts { - if mount.Name == volumeName { - mountExists = true - break - } - } - - } - - // 4. Update the Deployment - kcm.client.AppsV1().Deployments(kcm.namespace).Update( - context.TODO(), - deployment, - metav1.UpdateOptions{}, - ) - if err != nil { - fmt.Errorf("failed to update deployment %s: %v", deploymentName, err) - } - - fmt.Printf("[Kubernetes] Capsule %s:%s attached to deployment %s at path %s\n", - capsuleName, capsuleVersion, deploymentName, mountPath) - - return nil + if mount.Name == volumeName { + mountExists = true + break + } + } + + } + + //4. Update the deployment + _, err = kcm.client.AppsV1().Deployments(kcm.namespace).Update( + context.TODO(), + deployment, + metav1.UpdateOptions{}, + ) + if err != nil { + return fmt.Errorf("failed to update deployment %s: %v", deploymentName, err) + } + + fmt.Printf("[Kubernetes] Capsule %s:%s attached to deployment %s at path %s\n", + capsuleName, capsuleVersion, deploymentName, mountPath) + return nil } // BenchmarkKubernetesResourceAccess benchmarks access to Kubernetes resources From 7356b9decf11661ede5212b5c6ee9028e1fbbcb6 Mon Sep 17 00:00:00 2001 From: Janardhan Pulivarthi Date: Sat, 2 Aug 2025 13:42:17 +0530 Subject: [PATCH 3/5] check if mountExists --- kubernetes.go | 1 + 1 file changed, 1 insertion(+) diff --git a/kubernetes.go b/kubernetes.go index ab9e079..8930eb0 100644 --- a/kubernetes.go +++ b/kubernetes.go @@ -247,6 +247,7 @@ func (kcm *KubernetesCapsuleManager) AttachCapsuleToDeployment(deploymentName, c container := &deployment.Spec.Template.Spec.Containers[i] // check if this container already has the mount + mountExists := false for _, mount := range cotainer.VolumeMounts { if mount.Name == volumeName { mountExists = true From 4cda31de216f6d62e92e0a873cf6c73ac9296bd8 Mon Sep 17 00:00:00 2001 From: Janardhan Pulivarthi Date: Sat, 2 Aug 2025 13:45:22 +0530 Subject: [PATCH 4/5] create volumes if doesn't exists --- kubernetes.go | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/kubernetes.go b/kubernetes.go index 8930eb0..1f0b808 100644 --- a/kubernetes.go +++ b/kubernetes.go @@ -233,14 +233,24 @@ func (kcm *KubernetesCapsuleManager) AttachCapsuleToDeployment(deploymentName, c return fmt.Errorf("capsule %s:%s not found", capsuleName, capsuleVersion) } - deployment.Spec.Template.Spec.Volumes = append( - deployment.Spec.Template.Spec.Volumes, - v1.Volume{ - Name: volumeName, - VolumeSource: volumeSource, - }, - ) + volumeExists := false + for _, volume := range deployment.Spec.Template.Spec.Volumes { + if volume.Name == volumeName { + volumeExists = true + break + } + } + // Add the volume if it doesn't exist + if !volumeExists { + deployment.Spec.Template.Spec.Volumes = append( + deployment.Spec.Template.Spec.Volumes, + v1.Volume{ + Name: volumeName, + VolumeSource: volumeSource, + }, + ) + } // 3. Add a volumeMount to the container spec for i := range deployment.Spec.Template.Spec.Containers { @@ -254,6 +264,17 @@ func (kcm *KubernetesCapsuleManager) AttachCapsuleToDeployment(deploymentName, c break } } + + if !mountExists { + container.VolumeMounts = append( + container.VolumeMounts, + v1.VolumeMount{ + Name: volumeName, + MountPath: mountPath, + ReadOnly: true, + }, + ) + } } From fd064398d4a2784bafe04af63b6c34517a0d3c10 Mon Sep 17 00:00:00 2001 From: Janardhan Pulivarthi Date: Sat, 2 Aug 2025 09:26:02 +0000 Subject: [PATCH 5/5] fix build issue and use literal in slice --- kubernetes.go | 6 +++--- kubernetes_test.go | 7 +++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/kubernetes.go b/kubernetes.go index 1f0b808..2f63fd2 100644 --- a/kubernetes.go +++ b/kubernetes.go @@ -201,8 +201,8 @@ func (kcm *KubernetesCapsuleManager) AttachCapsuleToDeployment(deploymentName, c secretName := configMapName // First, determine if the capsule exists as a ConfigMap or Secret - configMap, configMapErr := kcm.GetConfigMapCapsule(capsuleName, capsuleVersion) - secret, secretErr := kcm.GetSecretCapsule(capsuleName, capsuleVersion) + _, configMapErr := kcm.GetConfigMapCapsule(capsuleName, capsuleVersion) + _, secretErr := kcm.GetSecretCapsule(capsuleName, capsuleVersion) // 2. Add a volume for the ConfigMap/Secret var volumeName string @@ -258,7 +258,7 @@ func (kcm *KubernetesCapsuleManager) AttachCapsuleToDeployment(deploymentName, c // check if this container already has the mount mountExists := false - for _, mount := range cotainer.VolumeMounts { + for _, mount := range container.VolumeMounts { if mount.Name == volumeName { mountExists = true break diff --git a/kubernetes_test.go b/kubernetes_test.go index 8a98944..c34ed40 100644 --- a/kubernetes_test.go +++ b/kubernetes_test.go @@ -6,6 +6,7 @@ import ( "os" "testing" + appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/fake" @@ -197,8 +198,10 @@ func TestAttachCapsuleToDeployment(t *testing.T) { }, Spec: v1.PodSpec { Containers: []v1.Container { - Name: "test-container", - Image: "nginx:latest", + { + Name: "test-container", + Image: "nginx:latest", + }, }, }, },