mirror of
https://github.com/containers/podman
synced 2024-10-19 16:54:07 +00:00
Merge pull request #14266 from tupyy/add-blockdevice-play-kube
Expose block and character devices with play kube
This commit is contained in:
commit
e11d8d4650
|
@ -381,6 +381,22 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener
|
|||
Options: options,
|
||||
}
|
||||
s.Volumes = append(s.Volumes, &cmVolume)
|
||||
case KubeVolumeTypeCharDevice:
|
||||
// We are setting the path as hostPath:mountPath to comply with pkg/specgen/generate.DeviceFromPath.
|
||||
// The type is here just to improve readability as it is not taken into account when the actual device is created.
|
||||
device := spec.LinuxDevice{
|
||||
Path: fmt.Sprintf("%s:%s", volumeSource.Source, volume.MountPath),
|
||||
Type: "c",
|
||||
}
|
||||
s.Devices = append(s.Devices, device)
|
||||
case KubeVolumeTypeBlockDevice:
|
||||
// We are setting the path as hostPath:mountPath to comply with pkg/specgen/generate.DeviceFromPath.
|
||||
// The type is here just to improve readability as it is not taken into account when the actual device is created.
|
||||
device := spec.LinuxDevice{
|
||||
Path: fmt.Sprintf("%s:%s", volumeSource.Source, volume.MountPath),
|
||||
Type: "b",
|
||||
}
|
||||
s.Devices = append(s.Devices, device)
|
||||
default:
|
||||
return nil, errors.Errorf("Unsupported volume source type")
|
||||
}
|
||||
|
|
|
@ -22,8 +22,10 @@ type KubeVolumeType int
|
|||
|
||||
const (
|
||||
KubeVolumeTypeBindMount KubeVolumeType = iota
|
||||
KubeVolumeTypeNamed KubeVolumeType = iota
|
||||
KubeVolumeTypeConfigMap KubeVolumeType = iota
|
||||
KubeVolumeTypeNamed
|
||||
KubeVolumeTypeConfigMap
|
||||
KubeVolumeTypeBlockDevice
|
||||
KubeVolumeTypeCharDevice
|
||||
)
|
||||
|
||||
//nolint:revive
|
||||
|
@ -78,7 +80,30 @@ func VolumeFromHostPath(hostPath *v1.HostPathVolumeSource) (*KubeVolume, error)
|
|||
if st.Mode()&os.ModeSocket != os.ModeSocket {
|
||||
return nil, errors.Errorf("checking HostPathSocket: path %s is not a socket", hostPath.Path)
|
||||
}
|
||||
|
||||
case v1.HostPathBlockDev:
|
||||
dev, err := os.Stat(hostPath.Path)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error checking HostPathBlockDevice")
|
||||
}
|
||||
if dev.Mode()&os.ModeCharDevice == os.ModeCharDevice {
|
||||
return nil, errors.Errorf("checking HostPathDevice: path %s is not a block device", hostPath.Path)
|
||||
}
|
||||
return &KubeVolume{
|
||||
Type: KubeVolumeTypeBlockDevice,
|
||||
Source: hostPath.Path,
|
||||
}, nil
|
||||
case v1.HostPathCharDev:
|
||||
dev, err := os.Stat(hostPath.Path)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error checking HostPathCharDevice")
|
||||
}
|
||||
if dev.Mode()&os.ModeCharDevice != os.ModeCharDevice {
|
||||
return nil, errors.Errorf("checking HostPathCharDevice: path %s is not a character device", hostPath.Path)
|
||||
}
|
||||
return &KubeVolume{
|
||||
Type: KubeVolumeTypeCharDevice,
|
||||
Source: hostPath.Path,
|
||||
}, nil
|
||||
case v1.HostPathDirectory:
|
||||
case v1.HostPathFile:
|
||||
case v1.HostPathUnset:
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/containers/podman/v4/pkg/util"
|
||||
. "github.com/containers/podman/v4/test/utils"
|
||||
"github.com/containers/storage/pkg/stringid"
|
||||
"github.com/google/uuid"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/onsi/gomega/format"
|
||||
|
@ -3685,4 +3686,150 @@ ENV OPENJ9_JAVA_OPTIONS=%q
|
|||
Expect(usernsInCtr).Should(Exit(0))
|
||||
Expect(string(usernsInCtr.Out.Contents())).To(Not(Equal(string(initialUsernsConfig))))
|
||||
})
|
||||
|
||||
// Check the block devices are exposed inside container
|
||||
It("ddpodman play kube expose block device inside container", func() {
|
||||
SkipIfRootless("It needs root access to create devices")
|
||||
|
||||
// randomize the folder name to avoid error when running tests with multiple nodes
|
||||
uuid, err := uuid.NewUUID()
|
||||
Expect(err).To(BeNil())
|
||||
devFolder := fmt.Sprintf("/dev/foodev%x", uuid[:6])
|
||||
Expect(os.MkdirAll(devFolder, os.ModePerm)).To(BeNil())
|
||||
defer os.RemoveAll(devFolder)
|
||||
|
||||
devicePath := fmt.Sprintf("%s/blockdevice", devFolder)
|
||||
mknod := SystemExec("mknod", []string{devicePath, "b", "7", "0"})
|
||||
mknod.WaitWithDefaultTimeout()
|
||||
Expect(mknod).Should(Exit(0))
|
||||
|
||||
blockVolume := getHostPathVolume("BlockDevice", devicePath)
|
||||
|
||||
pod := getPod(withVolume(blockVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false))))
|
||||
err = generateKubeYaml("pod", pod, kubeYaml)
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
|
||||
kube.WaitWithDefaultTimeout()
|
||||
Expect(kube).Should(Exit(0))
|
||||
|
||||
// Container should be in running state
|
||||
inspect := podmanTest.Podman([]string{"inspect", "--format", "{{.State.Status}}", "testPod-" + defaultCtrName})
|
||||
inspect.WaitWithDefaultTimeout()
|
||||
Expect(inspect).Should(Exit(0))
|
||||
Expect(inspect.OutputToString()).To(ContainSubstring("running"))
|
||||
|
||||
// Container should have a block device /dev/loop1
|
||||
inspect = podmanTest.Podman([]string{"inspect", "--format", "{{.HostConfig.Devices}}", "testPod-" + defaultCtrName})
|
||||
inspect.WaitWithDefaultTimeout()
|
||||
Expect(inspect).Should(Exit(0))
|
||||
Expect(inspect.OutputToString()).To(ContainSubstring(devicePath))
|
||||
})
|
||||
|
||||
// Check the char devices are exposed inside container
|
||||
It("ddpodman play kube expose character device inside container", func() {
|
||||
SkipIfRootless("It needs root access to create devices")
|
||||
|
||||
// randomize the folder name to avoid error when running tests with multiple nodes
|
||||
uuid, err := uuid.NewUUID()
|
||||
Expect(err).To(BeNil())
|
||||
devFolder := fmt.Sprintf("/dev/foodev%x", uuid[:6])
|
||||
Expect(os.MkdirAll(devFolder, os.ModePerm)).To(BeNil())
|
||||
defer os.RemoveAll(devFolder)
|
||||
|
||||
devicePath := fmt.Sprintf("%s/chardevice", devFolder)
|
||||
mknod := SystemExec("mknod", []string{devicePath, "c", "3", "1"})
|
||||
mknod.WaitWithDefaultTimeout()
|
||||
Expect(mknod).Should(Exit(0))
|
||||
|
||||
charVolume := getHostPathVolume("CharDevice", devicePath)
|
||||
|
||||
pod := getPod(withVolume(charVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false))))
|
||||
err = generateKubeYaml("pod", pod, kubeYaml)
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
|
||||
kube.WaitWithDefaultTimeout()
|
||||
Expect(kube).Should(Exit(0))
|
||||
|
||||
// Container should be in running state
|
||||
inspect := podmanTest.Podman([]string{"inspect", "--format", "{{.State.Status}}", "testPod-" + defaultCtrName})
|
||||
inspect.WaitWithDefaultTimeout()
|
||||
Expect(inspect).Should(Exit(0))
|
||||
Expect(inspect.OutputToString()).To(ContainSubstring("running"))
|
||||
|
||||
// Container should have a block device /dev/loop1
|
||||
inspect = podmanTest.Podman([]string{"inspect", "--format", "{{.HostConfig.Devices}}", "testPod-" + defaultCtrName})
|
||||
inspect.WaitWithDefaultTimeout()
|
||||
Expect(inspect).Should(Exit(0))
|
||||
Expect(inspect.OutputToString()).To(ContainSubstring(devicePath))
|
||||
})
|
||||
|
||||
It("podman play kube reports error when the device does not exists", func() {
|
||||
SkipIfRootless("It needs root access to create devices")
|
||||
|
||||
devicePath := "/dev/foodevdir/baddevice"
|
||||
|
||||
blockVolume := getHostPathVolume("BlockDevice", devicePath)
|
||||
|
||||
pod := getPod(withVolume(blockVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false))))
|
||||
err = generateKubeYaml("pod", pod, kubeYaml)
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
|
||||
kube.WaitWithDefaultTimeout()
|
||||
Expect(kube).Should(Exit(125))
|
||||
})
|
||||
|
||||
It("ddpodman play kube reports error when we try to expose char device as block device", func() {
|
||||
SkipIfRootless("It needs root access to create devices")
|
||||
|
||||
// randomize the folder name to avoid error when running tests with multiple nodes
|
||||
uuid, err := uuid.NewUUID()
|
||||
Expect(err).To(BeNil())
|
||||
devFolder := fmt.Sprintf("/dev/foodev%x", uuid[:6])
|
||||
Expect(os.MkdirAll(devFolder, os.ModePerm)).To(BeNil())
|
||||
defer os.RemoveAll(devFolder)
|
||||
|
||||
devicePath := fmt.Sprintf("%s/chardevice", devFolder)
|
||||
mknod := SystemExec("mknod", []string{devicePath, "c", "3", "1"})
|
||||
mknod.WaitWithDefaultTimeout()
|
||||
Expect(mknod).Should(Exit(0))
|
||||
|
||||
charVolume := getHostPathVolume("BlockDevice", devicePath)
|
||||
|
||||
pod := getPod(withVolume(charVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false))))
|
||||
err = generateKubeYaml("pod", pod, kubeYaml)
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
|
||||
kube.WaitWithDefaultTimeout()
|
||||
Expect(kube).Should(Exit(125))
|
||||
})
|
||||
|
||||
It("ddpodman play kube reports error when we try to expose block device as char device", func() {
|
||||
SkipIfRootless("It needs root access to create devices")
|
||||
|
||||
// randomize the folder name to avoid error when running tests with multiple nodes
|
||||
uuid, err := uuid.NewUUID()
|
||||
Expect(err).To(BeNil())
|
||||
devFolder := fmt.Sprintf("/dev/foodev%x", uuid[:6])
|
||||
Expect(os.MkdirAll(devFolder, os.ModePerm)).To(BeNil())
|
||||
|
||||
devicePath := fmt.Sprintf("%s/blockdevice", devFolder)
|
||||
mknod := SystemExec("mknod", []string{devicePath, "b", "7", "0"})
|
||||
mknod.WaitWithDefaultTimeout()
|
||||
Expect(mknod).Should(Exit(0))
|
||||
|
||||
charVolume := getHostPathVolume("CharDevice", devicePath)
|
||||
|
||||
pod := getPod(withVolume(charVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false))))
|
||||
err = generateKubeYaml("pod", pod, kubeYaml)
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
|
||||
kube.WaitWithDefaultTimeout()
|
||||
Expect(kube).Should(Exit(125))
|
||||
})
|
||||
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue