diff --git a/tests/integration/kubernetes/k8s-block-volume.bats b/tests/integration/kubernetes/k8s-block-volume.bats new file mode 100644 index 0000000000..fce8c534b0 --- /dev/null +++ b/tests/integration/kubernetes/k8s-block-volume.bats @@ -0,0 +1,85 @@ +#!/usr/bin/env bats +# +# Copyright (c) 2019 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +load "${BATS_TEST_DIRNAME}/lib.sh" +load "${BATS_TEST_DIRNAME}/../../common.bash" +load "${BATS_TEST_DIRNAME}/tests_common.sh" + +setup() { + get_pod_config_dir + + node="$(get_one_kata_node)" + pod_name="pod-block-pv" + volume_name="block-loop-pv" + volume_claim="block-loop-pvc" + ctr_dev_path="/dev/xda" + vol_capacity="500M" + + # Create Loop Device + tmp_disk_image=$(exec_host "$node" mktemp --tmpdir disk.XXXXXX.img) + exec_host "$node" truncate "$tmp_disk_image" --size "$vol_capacity" + loop_dev=$(exec_host "$node" sudo losetup -f) + exec_host "$node" sudo losetup "$loop_dev" "$tmp_disk_image" +} + +@test "Block Storage Support" { + # Create Storage Class + kubectl create -f volume/local-storage.yaml + + # Create Persistent Volume + tmp_pv_yaml=$(mktemp --tmpdir block_persistent_vol.XXXXX.yaml) + sed -e "s|LOOP_DEVICE|${loop_dev}|" volume/block-loop-pv.yaml > "$tmp_pv_yaml" + node_name="$(kubectl get node -o name)" + sed -i "s|HOSTNAME|${node_name##node/}|" "$tmp_pv_yaml" + sed -i "s|CAPACITY|${vol_capacity}|" "$tmp_pv_yaml" + kubectl create -f "$tmp_pv_yaml" + cmd="kubectl get pv/${volume_name} | grep Available" + waitForProcess "$wait_time" "$sleep_time" "$cmd" + + # Create Persistent Volume Claim + tmp_pvc_yaml=$(mktemp --tmpdir block_persistent_vol.XXXXX.yaml) + sed -e "s|CAPACITY|${vol_capacity}|" volume/block-loop-pvc.yaml > "$tmp_pvc_yaml" + kubectl create -f "$tmp_pvc_yaml" + + # Create Workload using Volume + tmp_pod_yaml=$(mktemp --tmpdir pod-pv.XXXXX.yaml) + sed -e "s|DEVICE_PATH|${ctr_dev_path}|" "${pod_config_dir}/${pod_name}.yaml" > "$tmp_pod_yaml" + kubectl create -f "$tmp_pod_yaml" + kubectl wait --for condition=ready --timeout=$timeout "pod/${pod_name}" + + # Verify persistent volume claim is bound + kubectl get "pvc/${volume_claim}" | grep "Bound" + + # make fs, mount device and write on it + kubectl exec "$pod_name" -- sh -c "mkfs.ext4 $ctr_dev_path" + ctr_mount_path="/mnt" + ctr_message="Hello World" + ctr_file="${ctr_mount_path}/file.txt" + kubectl exec "$pod_name" -- sh -c "mount $ctr_dev_path $ctr_mount_path" + kubectl exec "$pod_name" -- sh -c "echo $ctr_message > $ctr_file" + kubectl exec "$pod_name" -- sh -c "grep '$ctr_message' $ctr_file" +} + +teardown() { + # Debugging information + kubectl describe "pod/$pod_name" + + # Delete k8s resources + kubectl delete pod "$pod_name" + kubectl delete pvc "$volume_claim" + kubectl delete pv "$volume_name" + kubectl delete storageclass local-storage + + # Delete temporary yaml files + rm -f "$tmp_pv_yaml" + rm -f "$tmp_pvc_yaml" + rm -f "$tmp_pod_yaml" + + # Remove image and loop device + exec_host "$node" sudo losetup -d "$loop_dev" + exec_host "$node" rm -f "$tmp_disk_image" +} diff --git a/tests/integration/kubernetes/run_kubernetes_tests.sh b/tests/integration/kubernetes/run_kubernetes_tests.sh index 86134feb51..0daa55b112 100755 --- a/tests/integration/kubernetes/run_kubernetes_tests.sh +++ b/tests/integration/kubernetes/run_kubernetes_tests.sh @@ -42,6 +42,7 @@ else "k8s-confidential.bats" \ "k8s-sealed-secret.bats" \ "k8s-attach-handlers.bats" \ + "k8s-block-volume.bats" \ "k8s-caps.bats" \ "k8s-configmap.bats" \ "k8s-copy-file.bats" \ diff --git a/tests/integration/kubernetes/runtimeclass_workloads/pod-block-pv.yaml b/tests/integration/kubernetes/runtimeclass_workloads/pod-block-pv.yaml new file mode 100644 index 0000000000..f97d251c29 --- /dev/null +++ b/tests/integration/kubernetes/runtimeclass_workloads/pod-block-pv.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Pod +metadata: + name: pod-block-pv +spec: + terminationGracePeriodSeconds: 0 + runtimeClassName: kata + containers: + - name: my-container + image: quay.io/libpod/ubuntu:latest + command: ["tail", "-f", "/dev/null"] + volumeDevices: + - devicePath: DEVICE_PATH + name: my-volume + imagePullPolicy: IfNotPresent + securityContext: + capabilities: + add: ["SYS_ADMIN"] + volumes: + - name: my-volume + persistentVolumeClaim: + claimName: block-loop-pvc diff --git a/tests/integration/kubernetes/volume/block-loop-pv.yaml b/tests/integration/kubernetes/volume/block-loop-pv.yaml new file mode 100644 index 0000000000..298023a888 --- /dev/null +++ b/tests/integration/kubernetes/volume/block-loop-pv.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: block-loop-pv +spec: + capacity: + storage: CAPACITY + volumeMode: Block + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: local-storage + local: + path: LOOP_DEVICE + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - HOSTNAME diff --git a/tests/integration/kubernetes/volume/block-loop-pvc.yaml b/tests/integration/kubernetes/volume/block-loop-pvc.yaml new file mode 100644 index 0000000000..f8c69351b1 --- /dev/null +++ b/tests/integration/kubernetes/volume/block-loop-pvc.yaml @@ -0,0 +1,12 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: block-loop-pvc +spec: + accessModes: + - ReadWriteOnce + storageClassName: local-storage + volumeMode: Block + resources: + requests: + storage: CAPACITY diff --git a/tests/integration/kubernetes/volume/local-storage.yaml b/tests/integration/kubernetes/volume/local-storage.yaml new file mode 100644 index 0000000000..fcfb1a0f34 --- /dev/null +++ b/tests/integration/kubernetes/volume/local-storage.yaml @@ -0,0 +1,6 @@ +kind: StorageClass +apiVersion: storage.k8s.io/v1 +metadata: + name: local-storage +provisioner: kubernetes.io/no-provisioner +volumeBindingMode: WaitForFirstConsumer