constellation/csi/test/mount_integration_test.go

174 lines
4.4 KiB
Go

//go:build integration && linux && cgo
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package integration
import (
"context"
"fmt"
"os"
"os/exec"
"testing"
"github.com/edgelesssys/constellation/v2/csi/cryptmapper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/goleak"
)
const (
DevicePath string = "testDevice"
DeviceName string = "testDeviceName"
)
func setup() {
_ = exec.Command("/bin/dd", "if=/dev/zero", fmt.Sprintf("of=%s", DevicePath), "bs=64M", "count=1").Run()
}
func teardown(devicePath string) {
_ = exec.Command("/bin/rm", "-f", devicePath).Run()
}
func cp(source, target string) error {
return exec.Command("cp", source, target).Run()
}
func resize() {
_ = exec.Command("/bin/dd", "if=/dev/zero", fmt.Sprintf("of=%s", DevicePath), "bs=32M", "count=1", "oflag=append", "conv=notrunc").Run()
}
func TestMain(m *testing.M) {
if os.Getuid() != 0 {
fmt.Printf("This test suite requires root privileges, as libcryptsetup uses the kernel's device mapper.\n")
os.Exit(1)
}
goleak.VerifyTestMain(m)
result := m.Run()
os.Exit(result)
}
func TestOpenAndClose(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
setup()
defer teardown(DevicePath)
mapper := cryptmapper.New(&fakeKMS{}, &cryptmapper.CryptDevice{})
newPath, err := mapper.OpenCryptDevice(context.Background(), DevicePath, DeviceName, false)
require.NoError(err)
assert.Equal("/dev/mapper/"+DeviceName, newPath)
// assert crypt device got created
_, err = os.Stat(newPath)
assert.NoError(err)
// assert no integrity device got created
_, err = os.Stat(newPath + "_dif")
assert.True(os.IsNotExist(err))
// Resize the device
resize()
resizedPath, err := mapper.ResizeCryptDevice(context.Background(), DeviceName)
require.NoError(err)
assert.Equal("/dev/mapper/"+DeviceName, resizedPath)
assert.NoError(mapper.CloseCryptDevice(DeviceName))
// assert crypt device got removed
_, err = os.Stat(newPath)
assert.True(os.IsNotExist(err))
// check if we can reopen the device
_, err = mapper.OpenCryptDevice(context.Background(), DevicePath, DeviceName, true)
assert.NoError(err)
assert.NoError(mapper.CloseCryptDevice(DeviceName))
}
func TestOpenAndCloseIntegrity(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
setup()
defer teardown(DevicePath)
mapper := cryptmapper.New(&fakeKMS{}, &cryptmapper.CryptDevice{})
newPath, err := mapper.OpenCryptDevice(context.Background(), DevicePath, DeviceName, true)
require.NoError(err)
assert.Equal("/dev/mapper/"+DeviceName, newPath)
// assert crypt device got created
_, err = os.Stat(newPath)
assert.NoError(err)
// assert integrity device got created
_, err = os.Stat(newPath + "_dif")
assert.NoError(err)
// integrity devices do not support resizing
resize()
_, err = mapper.ResizeCryptDevice(context.Background(), DeviceName)
assert.Error(err)
assert.NoError(mapper.CloseCryptDevice(DeviceName))
// assert crypt device got removed
_, err = os.Stat(newPath)
assert.True(os.IsNotExist(err))
// assert integrity device got removed
_, err = os.Stat(newPath + "_dif")
assert.True(os.IsNotExist(err))
// check if we can reopen the device
_, err = mapper.OpenCryptDevice(context.Background(), DevicePath, DeviceName, true)
assert.NoError(err)
assert.NoError(mapper.CloseCryptDevice(DeviceName))
}
func TestDeviceCloning(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
setup()
defer teardown(DevicePath)
mapper := cryptmapper.New(&dynamicKMS{}, &cryptmapper.CryptDevice{})
_, err := mapper.OpenCryptDevice(context.Background(), DevicePath, DeviceName, false)
assert.NoError(err)
require.NoError(cp(DevicePath, DevicePath+"-copy"))
defer teardown(DevicePath + "-copy")
_, err = mapper.OpenCryptDevice(context.Background(), DevicePath+"-copy", DeviceName+"-copy", false)
assert.NoError(err)
assert.NoError(mapper.CloseCryptDevice(DeviceName))
assert.NoError(mapper.CloseCryptDevice(DeviceName + "-copy"))
}
type fakeKMS struct{}
func (k *fakeKMS) GetDEK(_ context.Context, _ string, dekSize int) ([]byte, error) {
key := make([]byte, dekSize)
for i := range key {
key[i] = 0x41
}
return key, nil
}
type dynamicKMS struct{}
func (k *dynamicKMS) GetDEK(_ context.Context, dekID string, dekSize int) ([]byte, error) {
key := make([]byte, dekSize)
for i := range key {
key[i] = 0x41 ^ dekID[i%len(dekID)]
}
return key, nil
}