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
16 changes: 3 additions & 13 deletions cmd/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,24 +448,14 @@ func addK8sSecretToTrustee(trusteeNamespace, secretName, secretNamespace string)

// handleImagePullSecrets processes imagePullSecrets from the manifest
// It detects, uploads to KBS, and prepares them for initdata
// Falls back to default service account if no imagePullSecrets in manifest
func handleImagePullSecrets(m *manifest.Manifest, cfg *config.CocoConfig, skipApply bool) ([]initdata.ImagePullSecretInfo, error) {
// Detect imagePullSecrets in the manifest
secretRefs, err := secrets.DetectSecrets(m.GetData())
// Detect imagePullSecrets in manifest, with fallback to default service account
imagePullSecretRefs, err := secrets.DetectImagePullSecretsWithServiceAccount(m.GetData())
if err != nil {
return nil, err
}

// Filter for only imagePullSecrets
var imagePullSecretRefs []secrets.SecretReference
for _, ref := range secretRefs {
for _, usage := range ref.Usages {
if usage.Type == "imagePullSecrets" {
imagePullSecretRefs = append(imagePullSecretRefs, ref)
break
}
}
}

if len(imagePullSecretRefs) == 0 {
return nil, nil // No imagePullSecrets to handle
}
Expand Down
327 changes: 327 additions & 0 deletions integration_test/manifest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,3 +408,330 @@ func TestManifest_CompleteTransformation(t *testing.T) {
t.Error("InitContainer not preserved in saved manifest")
}
}

func TestManifest_Deployment_WithSecretsAndImagePullSecrets(t *testing.T) {
m, err := manifest.Load("testdata/manifests/deployment-with-secrets-and-imagepullsecrets.yaml")
if err != nil {
t.Fatalf("Load() failed: %v", err)
}

// Verify it's a Deployment
if m.GetKind() != "Deployment" {
t.Errorf("GetKind() = %q, want %q", m.GetKind(), "Deployment")
}

// Verify GetPodSpec works for Deployment
podSpec, err := m.GetPodSpec()
if err != nil {
t.Fatalf("GetPodSpec() failed: %v", err)
}

// Verify containers exist
containers, ok := podSpec["containers"].([]interface{})
if !ok {
t.Fatal("containers not found in pod spec")
}
if len(containers) != 1 {
t.Errorf("Expected 1 container, got %d", len(containers))
}

// Verify imagePullSecrets
imagePullSecrets := m.GetImagePullSecrets()
if len(imagePullSecrets) != 1 {
t.Fatalf("Expected 1 imagePullSecret, got %d", len(imagePullSecrets))
}
if imagePullSecrets[0] != "regcred" {
t.Errorf("imagePullSecret name = %q, want %q", imagePullSecrets[0], "regcred")
}

// Verify secret references
secrets := m.GetSecretRefs()
if len(secrets) != 2 {
t.Fatalf("Expected 2 secret references, got %d", len(secrets))
}

// Verify SetRuntimeClass works for Deployment
err = m.SetRuntimeClass("kata-cc")
if err != nil {
t.Fatalf("SetRuntimeClass() failed: %v", err)
}

if m.GetRuntimeClass() != "kata-cc" {
t.Errorf("GetRuntimeClass() = %q, want %q", m.GetRuntimeClass(), "kata-cc")
}

// Verify SetAnnotation places annotation on pod template, not resource metadata
testAnnotationKey := "io.katacontainers.config.hypervisor.cc_init_data"
testAnnotationValue := "test-initdata-value"
err = m.SetAnnotation(testAnnotationKey, testAnnotationValue)
if err != nil {
t.Fatalf("SetAnnotation() failed: %v", err)
}

// Verify annotation is in spec.template.metadata.annotations
spec, _ := m.GetSpec()
template, ok := spec["template"].(map[string]interface{})
if !ok {
t.Fatal("template not found in spec")
}
templateMetadata, ok := template["metadata"].(map[string]interface{})
if !ok {
t.Fatal("metadata not found in template")
}
templateAnnotations, ok := templateMetadata["annotations"].(map[string]interface{})
if !ok {
t.Fatal("annotations not found in template metadata")
}
if templateAnnotations[testAnnotationKey] != testAnnotationValue {
t.Errorf("annotation in template = %q, want %q", templateAnnotations[testAnnotationKey], testAnnotationValue)
}

// Verify GetAnnotation retrieves from pod template
if m.GetAnnotation(testAnnotationKey) != testAnnotationValue {
t.Errorf("GetAnnotation() = %q, want %q", m.GetAnnotation(testAnnotationKey), testAnnotationValue)
}

// Verify annotation is NOT in resource-level metadata
resourceMetadata, ok := m.GetData()["metadata"].(map[string]interface{})
if ok {
if resourceAnnotations, ok := resourceMetadata["annotations"].(map[string]interface{}); ok {
if _, exists := resourceAnnotations[testAnnotationKey]; exists {
t.Error("annotation incorrectly placed in resource metadata instead of pod template")
}
}
}
}

func TestManifest_ReplicaSet_WithSecretsAndImagePullSecrets(t *testing.T) {
m, err := manifest.Load("testdata/manifests/replicaset-with-secrets-and-imagepullsecrets.yaml")
if err != nil {
t.Fatalf("Load() failed: %v", err)
}

// Verify it's a ReplicaSet
if m.GetKind() != "ReplicaSet" {
t.Errorf("GetKind() = %q, want %q", m.GetKind(), "ReplicaSet")
}

// Verify GetPodSpec works for ReplicaSet
podSpec, err := m.GetPodSpec()
if err != nil {
t.Fatalf("GetPodSpec() failed: %v", err)
}

// Verify containers exist
containers, ok := podSpec["containers"].([]interface{})
if !ok {
t.Fatal("containers not found in pod spec")
}
if len(containers) != 1 {
t.Errorf("Expected 1 container, got %d", len(containers))
}

// Verify imagePullSecrets
imagePullSecrets := m.GetImagePullSecrets()
if len(imagePullSecrets) != 1 {
t.Fatalf("Expected 1 imagePullSecret, got %d", len(imagePullSecrets))
}
if imagePullSecrets[0] != "registry-credentials" {
t.Errorf("imagePullSecret name = %q, want %q", imagePullSecrets[0], "registry-credentials")
}

// Verify secret references
secrets := m.GetSecretRefs()
if len(secrets) != 2 {
t.Fatalf("Expected 2 secret references, got %d", len(secrets))
}

// Verify SetRuntimeClass works for ReplicaSet
err = m.SetRuntimeClass("kata-qemu")
if err != nil {
t.Fatalf("SetRuntimeClass() failed: %v", err)
}

if m.GetRuntimeClass() != "kata-qemu" {
t.Errorf("GetRuntimeClass() = %q, want %q", m.GetRuntimeClass(), "kata-qemu")
}

// Verify annotations go to pod template for ReplicaSet
testAnnotationKey := "io.katacontainers.config.hypervisor.cc_init_data"
testAnnotationValue := "test-replicaset-initdata"
err = m.SetAnnotation(testAnnotationKey, testAnnotationValue)
if err != nil {
t.Fatalf("SetAnnotation() failed: %v", err)
}

// Verify annotation is in spec.template.metadata.annotations
spec, _ := m.GetSpec()
template, ok := spec["template"].(map[string]interface{})
if !ok {
t.Fatal("template not found in spec")
}
templateMetadata, ok := template["metadata"].(map[string]interface{})
if !ok {
t.Fatal("metadata not found in template")
}
templateAnnotations, ok := templateMetadata["annotations"].(map[string]interface{})
if !ok {
t.Fatal("annotations not found in template metadata")
}
if templateAnnotations[testAnnotationKey] != testAnnotationValue {
t.Errorf("annotation in template = %q, want %q", templateAnnotations[testAnnotationKey], testAnnotationValue)
}
}

func TestManifest_StatefulSet_WithSecretsAndImagePullSecrets(t *testing.T) {
m, err := manifest.Load("testdata/manifests/statefulset-with-secrets-and-imagepullsecrets.yaml")
if err != nil {
t.Fatalf("Load() failed: %v", err)
}

// Verify it's a StatefulSet
if m.GetKind() != "StatefulSet" {
t.Errorf("GetKind() = %q, want %q", m.GetKind(), "StatefulSet")
}

// Verify GetPodSpec works for StatefulSet
podSpec, err := m.GetPodSpec()
if err != nil {
t.Fatalf("GetPodSpec() failed: %v", err)
}

// Verify containers exist
containers, ok := podSpec["containers"].([]interface{})
if !ok {
t.Fatal("containers not found in pod spec")
}
if len(containers) != 1 {
t.Errorf("Expected 1 container, got %d", len(containers))
}

// Verify imagePullSecrets
imagePullSecrets := m.GetImagePullSecrets()
if len(imagePullSecrets) != 1 {
t.Fatalf("Expected 1 imagePullSecret, got %d", len(imagePullSecrets))
}
if imagePullSecrets[0] != "db-registry-creds" {
t.Errorf("imagePullSecret name = %q, want %q", imagePullSecrets[0], "db-registry-creds")
}

// Verify secret references (postgres-creds with 2 keys)
secrets := m.GetSecretRefs()
if len(secrets) != 1 {
t.Fatalf("Expected 1 secret reference, got %d", len(secrets))
}

// Verify SetRuntimeClass works for StatefulSet
err = m.SetRuntimeClass("kata-clh")
if err != nil {
t.Fatalf("SetRuntimeClass() failed: %v", err)
}

if m.GetRuntimeClass() != "kata-clh" {
t.Errorf("GetRuntimeClass() = %q, want %q", m.GetRuntimeClass(), "kata-clh")
}

// Verify annotations go to pod template for StatefulSet
testAnnotationKey := "io.katacontainers.config.hypervisor.cc_init_data"
testAnnotationValue := "test-statefulset-initdata"
err = m.SetAnnotation(testAnnotationKey, testAnnotationValue)
if err != nil {
t.Fatalf("SetAnnotation() failed: %v", err)
}

// Verify annotation is in spec.template.metadata.annotations
spec, _ := m.GetSpec()
template, ok := spec["template"].(map[string]interface{})
if !ok {
t.Fatal("template not found in spec")
}
templateMetadata, ok := template["metadata"].(map[string]interface{})
if !ok {
t.Fatal("metadata not found in template")
}
templateAnnotations, ok := templateMetadata["annotations"].(map[string]interface{})
if !ok {
t.Fatal("annotations not found in template metadata")
}
if templateAnnotations[testAnnotationKey] != testAnnotationValue {
t.Errorf("annotation in template = %q, want %q", templateAnnotations[testAnnotationKey], testAnnotationValue)
}
}

func TestManifest_Job_WithSecretsAndImagePullSecrets(t *testing.T) {
m, err := manifest.Load("testdata/manifests/job-with-secrets-and-imagepullsecrets.yaml")
if err != nil {
t.Fatalf("Load() failed: %v", err)
}

// Verify it's a Job
if m.GetKind() != "Job" {
t.Errorf("GetKind() = %q, want %q", m.GetKind(), "Job")
}

// Verify GetPodSpec works for Job
podSpec, err := m.GetPodSpec()
if err != nil {
t.Fatalf("GetPodSpec() failed: %v", err)
}

// Verify containers exist
containers, ok := podSpec["containers"].([]interface{})
if !ok {
t.Fatal("containers not found in pod spec")
}
if len(containers) != 1 {
t.Errorf("Expected 1 container, got %d", len(containers))
}

// Verify imagePullSecrets
imagePullSecrets := m.GetImagePullSecrets()
if len(imagePullSecrets) != 1 {
t.Fatalf("Expected 1 imagePullSecret, got %d", len(imagePullSecrets))
}
if imagePullSecrets[0] != "processor-registry-creds" {
t.Errorf("imagePullSecret name = %q, want %q", imagePullSecrets[0], "processor-registry-creds")
}

// Verify secret references (aws-creds and api-tokens)
secrets := m.GetSecretRefs()
if len(secrets) != 2 {
t.Fatalf("Expected 2 secret references, got %d", len(secrets))
}

// Verify SetRuntimeClass works for Job
err = m.SetRuntimeClass("kata-remote")
if err != nil {
t.Fatalf("SetRuntimeClass() failed: %v", err)
}

if m.GetRuntimeClass() != "kata-remote" {
t.Errorf("GetRuntimeClass() = %q, want %q", m.GetRuntimeClass(), "kata-remote")
}

// Verify annotations go to pod template for Job
testAnnotationKey := "io.katacontainers.config.hypervisor.cc_init_data"
testAnnotationValue := "test-job-initdata"
err = m.SetAnnotation(testAnnotationKey, testAnnotationValue)
if err != nil {
t.Fatalf("SetAnnotation() failed: %v", err)
}

// Verify annotation is in spec.template.metadata.annotations
spec, _ := m.GetSpec()
template, ok := spec["template"].(map[string]interface{})
if !ok {
t.Fatal("template not found in spec")
}
templateMetadata, ok := template["metadata"].(map[string]interface{})
if !ok {
t.Fatal("metadata not found in template")
}
templateAnnotations, ok := templateMetadata["annotations"].(map[string]interface{})
if !ok {
t.Fatal("annotations not found in template metadata")
}
if templateAnnotations[testAnnotationKey] != testAnnotationValue {
t.Errorf("annotation in template = %q, want %q", templateAnnotations[testAnnotationKey], testAnnotationValue)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment-with-secrets
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: test-app
template:
metadata:
labels:
app: test-app
spec:
containers:
- name: app
image: private-registry.example.com/myapp:v1.0
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-creds
key: password
- name: API_KEY
valueFrom:
secretKeyRef:
name: api-creds
key: apikey
ports:
- containerPort: 8080
imagePullSecrets:
- name: regcred
Loading