mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-08-21 01:13:56 +00:00
runtime: Add KataVirtualVolume struct in runtime
Add the corresponding data structure in the runtime part according to kata-containers/kata-containers/pull/7698. Signed-off-by: ChengyuZhu6 <chengyu.zhu@intel.com>
This commit is contained in:
parent
51c665a09c
commit
d788d4af2f
156
src/runtime/virtcontainers/types/virtual_volume.go
Normal file
156
src/runtime/virtcontainers/types/virtual_volume.go
Normal file
@ -0,0 +1,156 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
minBlockSize = 1 << 9
|
||||
maxBlockSize = 1 << 19
|
||||
)
|
||||
|
||||
const (
|
||||
KataVirtualVolumeDirectBlockType = "direct_block"
|
||||
KataVirtualVolumeImageRawBlockType = "image_raw_block"
|
||||
KataVirtualVolumeLayerRawBlockType = "layer_raw_block"
|
||||
KataVirtualVolumeImageNydusBlockType = "image_nydus_block"
|
||||
KataVirtualVolumeLayerNydusBlockType = "layer_nydus_block"
|
||||
KataVirtualVolumeImageNydusFsType = "image_nydus_fs"
|
||||
KataVirtualVolumeLayerNydusFsType = "layer_nydus_fs"
|
||||
KataVirtualVolumeImageGuestPullType = "image_guest_pull"
|
||||
)
|
||||
|
||||
// DmVerityInfo contains configuration information for DmVerity device.
|
||||
type DmVerityInfo struct {
|
||||
HashType string `json:"hashtype"`
|
||||
Hash string `json:"hash"`
|
||||
BlockNum uint64 `json:"blocknum"`
|
||||
Blocksize uint64 `json:"blocksize"`
|
||||
Hashsize uint64 `json:"hashsize"`
|
||||
Offset uint64 `json:"offset"`
|
||||
}
|
||||
|
||||
// DirectAssignedVolume contains meta information for a directly assigned volume.
|
||||
type DirectAssignedVolume struct {
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
}
|
||||
|
||||
// ImagePullVolume contains meta information for pulling an image inside the guest.
|
||||
type ImagePullVolume struct {
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
}
|
||||
|
||||
// NydusImageVolume contains Nydus image volume information.
|
||||
type NydusImageVolume struct {
|
||||
Config string `json:"config"`
|
||||
SnapshotDir string `json:"snapshot_dir"`
|
||||
}
|
||||
|
||||
// KataVirtualVolume encapsulates information for extra mount options and direct volumes.
|
||||
type KataVirtualVolume struct {
|
||||
VolumeType string `json:"volume_type"`
|
||||
Source string `json:"source,omitempty"`
|
||||
FSType string `json:"fs_type,omitempty"`
|
||||
Options []string `json:"options,omitempty"`
|
||||
DirectVolume *DirectAssignedVolume `json:"direct_volume,omitempty"`
|
||||
ImagePull *ImagePullVolume `json:"image_pull,omitempty"`
|
||||
NydusImage *NydusImageVolume `json:"nydus_image,omitempty"`
|
||||
DmVerity *DmVerityInfo `json:"dm_verity,omitempty"`
|
||||
}
|
||||
|
||||
func (d *DmVerityInfo) IsValid() error {
|
||||
err := d.validateHashType()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d.BlockNum == 0 || d.BlockNum > uint64(^uint32(0)) {
|
||||
return fmt.Errorf("Zero block count for DmVerity device %s", d.Hash)
|
||||
}
|
||||
|
||||
if !isValidBlockSize(d.Blocksize) || !isValidBlockSize(d.Hashsize) {
|
||||
return fmt.Errorf("Unsupported verity block size: data_block_size = %d, hash_block_size = %d", d.Blocksize, d.Hashsize)
|
||||
}
|
||||
|
||||
if d.Offset%d.Hashsize != 0 || d.Offset < d.Blocksize*d.BlockNum {
|
||||
return fmt.Errorf("Invalid hashvalue offset %d for DmVerity device %s", d.Offset, d.Hash)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DirectAssignedVolume) IsValid() bool {
|
||||
return d.Metadata != nil
|
||||
}
|
||||
|
||||
func (i *ImagePullVolume) IsValid() bool {
|
||||
return i.Metadata != nil
|
||||
}
|
||||
|
||||
func (n *NydusImageVolume) IsValid() bool {
|
||||
return len(n.Config) > 0 || len(n.SnapshotDir) > 0
|
||||
}
|
||||
|
||||
func (k *KataVirtualVolume) IsValid() bool {
|
||||
return len(k.VolumeType) > 0 &&
|
||||
(k.DirectVolume == nil || k.DirectVolume.IsValid()) &&
|
||||
(k.ImagePull == nil || k.ImagePull.IsValid()) &&
|
||||
(k.NydusImage == nil || k.NydusImage.IsValid()) &&
|
||||
(k.DmVerity == nil || k.DmVerity.IsValid() == nil)
|
||||
}
|
||||
|
||||
func (d *DmVerityInfo) validateHashType() error {
|
||||
switch strings.ToLower(d.HashType) {
|
||||
case "sha256":
|
||||
return d.isValidHash(64, "sha256")
|
||||
case "sha1":
|
||||
return d.isValidHash(40, "sha1")
|
||||
default:
|
||||
return fmt.Errorf("Unsupported hash algorithm %s for DmVerity device %s", d.HashType, d.Hash)
|
||||
}
|
||||
}
|
||||
|
||||
func isValidBlockSize(blockSize uint64) bool {
|
||||
return minBlockSize <= blockSize && blockSize <= maxBlockSize
|
||||
}
|
||||
|
||||
func (d *DmVerityInfo) isValidHash(expectedLen int, hashType string) error {
|
||||
_, err := hex.DecodeString(d.Hash)
|
||||
if len(d.Hash) != expectedLen || err != nil {
|
||||
return fmt.Errorf("Invalid hash value %s:%s for DmVerity device with %s", hashType, d.Hash, hashType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseDmVerityInfo(option string) (*DmVerityInfo, error) {
|
||||
no := &DmVerityInfo{}
|
||||
if err := json.Unmarshal([]byte(option), no); err != nil {
|
||||
return nil, errors.Wrapf(err, "DmVerityInfo json unmarshal err")
|
||||
}
|
||||
if err := no.IsValid(); err != nil {
|
||||
return nil, fmt.Errorf("DmVerityInfo is not correct, %+v; error = %+v", no, err)
|
||||
}
|
||||
return no, nil
|
||||
}
|
||||
|
||||
func ParseKataVirtualVolume(option string) (*KataVirtualVolume, error) {
|
||||
opt, err := base64.StdEncoding.DecodeString(option)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "KataVirtualVolume base64 decoding err")
|
||||
}
|
||||
no := &KataVirtualVolume{}
|
||||
if err := json.Unmarshal(opt, no); err != nil {
|
||||
return nil, errors.Wrapf(err, "KataVirtualVolume json unmarshal err")
|
||||
}
|
||||
if !no.IsValid() {
|
||||
return nil, fmt.Errorf("KataVirtualVolume is not correct, %+v", no)
|
||||
}
|
||||
|
||||
return no, nil
|
||||
}
|
246
src/runtime/virtcontainers/types/virtual_volume_test.go
Normal file
246
src/runtime/virtcontainers/types/virtual_volume_test.go
Normal file
@ -0,0 +1,246 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDmVerityInfoValidation(t *testing.T) {
|
||||
TestData := []DmVerityInfo{
|
||||
{
|
||||
HashType: "md5", // "md5" is not a supported hash algorithm
|
||||
Blocksize: 512,
|
||||
Hashsize: 512,
|
||||
BlockNum: 16384,
|
||||
Offset: 8388608,
|
||||
Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
|
||||
},
|
||||
{
|
||||
HashType: "sha256",
|
||||
Blocksize: 3000, // Invalid block size, not a power of 2.
|
||||
Hashsize: 512,
|
||||
BlockNum: 16384,
|
||||
Offset: 8388608,
|
||||
Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
|
||||
},
|
||||
{
|
||||
HashType: "sha256",
|
||||
Blocksize: 0, // Invalid block size, less than 512.
|
||||
Hashsize: 512,
|
||||
BlockNum: 16384,
|
||||
Offset: 8388608,
|
||||
Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
|
||||
},
|
||||
{
|
||||
HashType: "sha256",
|
||||
Blocksize: 524800, // Invalid block size, greater than 524288.
|
||||
Hashsize: 512,
|
||||
BlockNum: 16384,
|
||||
Offset: 8388608,
|
||||
Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
|
||||
},
|
||||
{
|
||||
HashType: "sha256",
|
||||
Blocksize: 512,
|
||||
Hashsize: 3000, // Invalid hash block size, not a power of 2.
|
||||
BlockNum: 16384,
|
||||
Offset: 8388608,
|
||||
Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
|
||||
},
|
||||
{
|
||||
HashType: "sha256",
|
||||
Blocksize: 512,
|
||||
Hashsize: 0, // Invalid hash block size, less than 512.
|
||||
BlockNum: 16384,
|
||||
Offset: 8388608,
|
||||
Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
|
||||
},
|
||||
{
|
||||
HashType: "sha256",
|
||||
Blocksize: 512,
|
||||
Hashsize: 524800, // Invalid hash block size, greater than 524288.
|
||||
BlockNum: 16384,
|
||||
Offset: 8388608,
|
||||
Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
|
||||
},
|
||||
{
|
||||
HashType: "sha256",
|
||||
Blocksize: 512,
|
||||
Hashsize: 512,
|
||||
BlockNum: 0, // Invalid BlockNum, it must be greater than 0.
|
||||
Offset: 8388608,
|
||||
Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
|
||||
},
|
||||
{
|
||||
HashType: "sha256",
|
||||
Blocksize: 512,
|
||||
Hashsize: 512,
|
||||
BlockNum: 16384,
|
||||
Offset: 0, // Invalid offset, it must be greater than 0.
|
||||
Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
|
||||
},
|
||||
{
|
||||
HashType: "sha256",
|
||||
Blocksize: 512,
|
||||
Hashsize: 512,
|
||||
BlockNum: 16384,
|
||||
Offset: 8193, // Invalid offset, it must be aligned to 512.
|
||||
Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
|
||||
},
|
||||
{
|
||||
HashType: "sha256",
|
||||
Blocksize: 512,
|
||||
Hashsize: 512,
|
||||
BlockNum: 16384,
|
||||
Offset: 8388608 - 4096, // Invalid offset, it must be equal to blocksize * BlockNum.
|
||||
Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
|
||||
},
|
||||
}
|
||||
|
||||
for _, d := range TestData {
|
||||
assert.Error(t, d.IsValid())
|
||||
}
|
||||
TestCorrectData := DmVerityInfo{
|
||||
HashType: "sha256",
|
||||
Blocksize: 512,
|
||||
Hashsize: 512,
|
||||
BlockNum: 16384,
|
||||
Offset: 8388608,
|
||||
Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
|
||||
}
|
||||
assert.NoError(t, TestCorrectData.IsValid())
|
||||
}
|
||||
|
||||
func TestDirectAssignedVolumeValidation(t *testing.T) {
|
||||
validDirectVolume := DirectAssignedVolume{
|
||||
Metadata: map[string]string{"key": "value"},
|
||||
}
|
||||
assert.True(t, validDirectVolume.IsValid())
|
||||
|
||||
invalidDirectVolume := DirectAssignedVolume{
|
||||
Metadata: nil,
|
||||
}
|
||||
assert.False(t, invalidDirectVolume.IsValid())
|
||||
}
|
||||
|
||||
func TestImagePullVolumeValidation(t *testing.T) {
|
||||
validImagePull := ImagePullVolume{
|
||||
Metadata: map[string]string{"key": "value"},
|
||||
}
|
||||
assert.True(t, validImagePull.IsValid())
|
||||
|
||||
invalidImagePull := ImagePullVolume{
|
||||
Metadata: nil,
|
||||
}
|
||||
assert.False(t, invalidImagePull.IsValid())
|
||||
}
|
||||
|
||||
func TestNydusImageVolumeValidation(t *testing.T) {
|
||||
validNydusImage := NydusImageVolume{
|
||||
Config: "config_value",
|
||||
SnapshotDir: "",
|
||||
}
|
||||
assert.True(t, validNydusImage.IsValid())
|
||||
|
||||
invalidNydusImage := NydusImageVolume{
|
||||
Config: "",
|
||||
SnapshotDir: "",
|
||||
}
|
||||
assert.False(t, invalidNydusImage.IsValid())
|
||||
}
|
||||
|
||||
func TestKataVirtualVolumeValidation(t *testing.T) {
|
||||
validKataVirtualVolume := KataVirtualVolume{
|
||||
VolumeType: "direct_block",
|
||||
Source: "/dev/sdb",
|
||||
FSType: "ext4",
|
||||
Options: []string{"rw"},
|
||||
DirectVolume: &DirectAssignedVolume{
|
||||
Metadata: map[string]string{"key": "value"},
|
||||
},
|
||||
// Initialize other fields
|
||||
}
|
||||
assert.True(t, validKataVirtualVolume.IsValid())
|
||||
|
||||
invalidKataVirtualVolume := KataVirtualVolume{
|
||||
VolumeType: "direct_block",
|
||||
Source: "/dev/sdb",
|
||||
FSType: "",
|
||||
Options: nil,
|
||||
DirectVolume: &DirectAssignedVolume{
|
||||
Metadata: nil,
|
||||
},
|
||||
// Initialize other fields
|
||||
}
|
||||
assert.False(t, invalidKataVirtualVolume.IsValid())
|
||||
}
|
||||
|
||||
func TestParseDmVerityInfo(t *testing.T) {
|
||||
// Create a mock valid KataVirtualVolume
|
||||
validDmVerityInfo := DmVerityInfo{
|
||||
HashType: "sha256",
|
||||
Blocksize: 512,
|
||||
Hashsize: 512,
|
||||
BlockNum: 16384,
|
||||
Offset: 8388608,
|
||||
Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174",
|
||||
}
|
||||
validKataVirtualVolumeJSON, _ := json.Marshal(validDmVerityInfo)
|
||||
|
||||
t.Run("Valid Option", func(t *testing.T) {
|
||||
volume, err := ParseDmVerityInfo(string(validKataVirtualVolumeJSON))
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, volume)
|
||||
assert.NoError(t, volume.IsValid())
|
||||
})
|
||||
|
||||
t.Run("Invalid JSON Option", func(t *testing.T) {
|
||||
volume, err := ParseDmVerityInfo("invalid_json")
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, volume)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestParseKataVirtualVolume(t *testing.T) {
|
||||
// Create a mock valid KataVirtualVolume
|
||||
validKataVirtualVolume := KataVirtualVolume{
|
||||
VolumeType: "direct_block",
|
||||
Source: "/dev/sdb",
|
||||
FSType: "ext4",
|
||||
Options: []string{"rw"},
|
||||
DirectVolume: &DirectAssignedVolume{
|
||||
Metadata: map[string]string{"key": "value"},
|
||||
},
|
||||
// Initialize other fields
|
||||
}
|
||||
validKataVirtualVolumeJSON, _ := json.Marshal(validKataVirtualVolume)
|
||||
validOption := base64.StdEncoding.EncodeToString(validKataVirtualVolumeJSON)
|
||||
|
||||
t.Run("Valid Option", func(t *testing.T) {
|
||||
volume, err := ParseKataVirtualVolume(validOption)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, volume)
|
||||
assert.True(t, volume.IsValid())
|
||||
})
|
||||
|
||||
t.Run("Invalid JSON Option", func(t *testing.T) {
|
||||
invalidJSONOption := base64.StdEncoding.EncodeToString([]byte("invalid_json"))
|
||||
volume, err := ParseKataVirtualVolume(invalidJSONOption)
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, volume)
|
||||
})
|
||||
|
||||
invalidBase64Option := "invalid_base64"
|
||||
t.Run("Invalid Base64 Option", func(t *testing.T) {
|
||||
volume, err := ParseKataVirtualVolume(invalidBase64Option)
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, volume)
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user