Skip to content
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
108 changes: 99 additions & 9 deletions kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,17 +190,107 @@ 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)

// In a real implementation, this would:
// 1. Get the existing Deployment
// 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
_, configMapErr := kcm.GetConfigMapCapsule(capsuleName, capsuleVersion)
_, 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)
}

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
// 4. Update the Deployment

return nil
for i := range deployment.Spec.Template.Spec.Containers {
container := &deployment.Spec.Template.Spec.Containers[i]

// check if this container already has the mount
mountExists := false
for _, mount := range container.VolumeMounts {
if mount.Name == volumeName {
mountExists = true
break
}
}

if !mountExists {
container.VolumeMounts = append(
container.VolumeMounts,
v1.VolumeMount{
Name: volumeName,
MountPath: mountPath,
ReadOnly: true,
},
)
}

}

//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
Expand Down
121 changes: 121 additions & 0 deletions kubernetes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -175,6 +176,126 @@ 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()
Expand Down