-
Notifications
You must be signed in to change notification settings - Fork 43
Add support for scsi for hotplugging block devices #584
Changes from all commits
7df3f45
80bdc50
3c038f1
a1a569a
07c2c88
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -340,7 +340,11 @@ type BlockDevice struct { | |
DeviceType string | ||
DeviceInfo DeviceInfo | ||
|
||
// Path at which the device appears inside the VM, outside of the container mount namespace. | ||
// SCSI Address of the block device, in case the device is attached using SCSI driver | ||
// SCSI address is in the format SCSI-Id:LUN | ||
SCSIAddr string | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't you think this should be part of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No the DeviceInfo includes fields that are common to all devices. This is specific to Block device. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense |
||
|
||
// Path at which the device appears inside the VM, outside of the container mount namespace | ||
VirtPath string | ||
} | ||
|
||
|
@@ -359,12 +363,6 @@ func (device *BlockDevice) attach(h hypervisor, c *Container) (err error) { | |
|
||
device.DeviceInfo.ID = hex.EncodeToString(randBytes) | ||
|
||
drive := Drive{ | ||
File: device.DeviceInfo.HostPath, | ||
Format: "raw", | ||
ID: makeNameID("drive", device.DeviceInfo.ID), | ||
} | ||
|
||
// Increment the block index for the pod. This is used to determine the name | ||
// for the block device in the case where the block device is used as container | ||
// rootfs and the predicted block device name needs to be provided to the agent. | ||
|
@@ -380,6 +378,13 @@ func (device *BlockDevice) attach(h hypervisor, c *Container) (err error) { | |
return err | ||
} | ||
|
||
drive := Drive{ | ||
File: device.DeviceInfo.HostPath, | ||
Format: "raw", | ||
ID: makeNameID("drive", device.DeviceInfo.ID), | ||
Index: index, | ||
} | ||
|
||
driveName, err := getVirtDriveName(index) | ||
if err != nil { | ||
return err | ||
|
@@ -393,7 +398,17 @@ func (device *BlockDevice) attach(h hypervisor, c *Container) (err error) { | |
|
||
device.DeviceInfo.Hotplugged = true | ||
|
||
device.VirtPath = filepath.Join("/dev", driveName) | ||
if c.pod.config.HypervisorConfig.BlockDeviceDriver == VirtioBlock { | ||
device.VirtPath = filepath.Join("/dev", driveName) | ||
} else { | ||
scsiAddr, err := getSCSIAddress(index) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
device.SCSIAddr = scsiAddr | ||
} | ||
|
||
return nil | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -414,13 +414,22 @@ func (h *hyper) startOneContainer(pod Pod, c *Container) error { | |
container.SystemMountsInfo.BindMountDev = c.systemMountsInfo.BindMountDev | ||
|
||
if c.state.Fstype != "" { | ||
driveName, err := getVirtDriveName(c.state.BlockIndex) | ||
if err != nil { | ||
return err | ||
// Pass a drive name only in case of block driver | ||
if pod.config.HypervisorConfig.BlockDeviceDriver == VirtioBlock { | ||
driveName, err := getVirtDriveName(c.state.BlockIndex) | ||
if err != nil { | ||
return err | ||
} | ||
container.Image = driveName | ||
} else { | ||
scsiAddr, err := getSCSIAddress(c.state.BlockIndex) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very nice that we don't need to predict here ;) |
||
if err != nil { | ||
return err | ||
} | ||
container.SCSIAddr = scsiAddr | ||
} | ||
|
||
container.Fstype = c.state.Fstype | ||
container.Image = driveName | ||
} else { | ||
|
||
if err := bindMountContainerRootfs(defaultSharedDir, pod.id, c.id, c.rootFs, false); err != nil { | ||
|
@@ -450,6 +459,7 @@ func (h *hyper) startOneContainer(pod Pod, c *Container) error { | |
Path: d.DeviceInfo.ContainerPath, | ||
AbsolutePath: true, | ||
DockerVolume: false, | ||
SCSIAddr: d.SCSIAddr, | ||
} | ||
fsmap = append(fsmap, fsmapDesc) | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -321,3 +321,30 @@ func bindUnmountAllRootfs(sharedDir string, pod Pod) { | |
} | ||
} | ||
} | ||
|
||
const maxSCSIDevices = 65535 | ||
|
||
// getSCSIIdLun gets the SCSI id and lun, based on the index of the drive being inserted. | ||
// qemu code suggests that scsi-id can take values from 0 to 255 inclusive, while lun can | ||
// take values from 0 to 16383 inclusive. But lun values over 255 do not seem to follow | ||
// consistent SCSI addressing. Hence we limit to 255. | ||
func getSCSIIdLun(index int) (int, int, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you rename to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jodh-intel This is not technically a getter for a struct field, but a function that derives the SCSI id and LUN based on an index. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah - fair point. |
||
if index < 0 { | ||
return -1, -1, fmt.Errorf("Index cannot be negative") | ||
} | ||
|
||
if index > maxSCSIDevices { | ||
return -1, -1, fmt.Errorf("Index cannot be greater than %d, maximum of %d devices are supported", maxSCSIDevices, maxSCSIDevices) | ||
} | ||
|
||
return index / 256, index % 256, nil | ||
} | ||
|
||
func getSCSIAddress(index int) (string, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment - we don't need the |
||
scsiID, lun, err := getSCSIIdLun(index) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return fmt.Sprintf("%d:%d", scsiID, lun), nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ package virtcontainers | |
import ( | ||
"bytes" | ||
"fmt" | ||
"github.com/stretchr/testify/assert" | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
|
@@ -282,3 +283,52 @@ func TestGetVirtDriveName(t *testing.T) { | |
} | ||
} | ||
} | ||
|
||
func TestGetSCSIIdLun(t *testing.T) { | ||
tests := []struct { | ||
index int | ||
expectedScsiID int | ||
expectedLun int | ||
}{ | ||
{0, 0, 0}, | ||
{1, 0, 1}, | ||
{2, 0, 2}, | ||
{255, 0, 255}, | ||
{256, 1, 0}, | ||
{257, 1, 1}, | ||
{258, 1, 2}, | ||
{512, 2, 0}, | ||
{513, 2, 1}, | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice :) |
||
|
||
for _, test := range tests { | ||
scsiID, lun, err := getSCSIIdLun(test.index) | ||
assert.Nil(t, err) | ||
|
||
if scsiID != test.expectedScsiID && lun != test.expectedLun { | ||
t.Fatalf("Expecting scsi-id:lun %d:%d, Got %d:%d", test.expectedScsiID, test.expectedLun, scsiID, lun) | ||
} | ||
} | ||
|
||
_, _, err := getSCSIIdLun(maxSCSIDevices + 1) | ||
assert.NotNil(t, err) | ||
} | ||
|
||
func TestGetSCSIAddress(t *testing.T) { | ||
tests := []struct { | ||
index int | ||
expectedSCSIAddress string | ||
}{ | ||
{0, "0:0"}, | ||
{200, "0:200"}, | ||
{255, "0:255"}, | ||
{258, "1:2"}, | ||
{512, "2:0"}, | ||
} | ||
|
||
for _, test := range tests { | ||
scsiAddr, err := getSCSIAddress(test.index) | ||
assert.Nil(t, err) | ||
assert.Equal(t, scsiAddr, test.expectedSCSIAddress) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -133,6 +133,7 @@ type FsmapDescriptor struct { | |
ReadOnly bool `json:"readOnly"` | ||
DockerVolume bool `json:"dockerVolume"` | ||
AbsolutePath bool `json:"absolutePath"` | ||
SCSIAddr string `json:"scsiAddr"` | ||
} | ||
|
||
// EnvironmentVar holds an environment variable and its value. | ||
|
@@ -207,7 +208,7 @@ type Container struct { | |
Rootfs string `json:"rootfs"` | ||
Fstype string `json:"fstype,omitempty"` | ||
Image string `json:"image"` | ||
Addr string `json:"addr,omitempty"` | ||
SCSIAddr string `json:"scsiAddr,omitempty"` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you want to change the name ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had this as Addr in the agent, but changed this to SCSIAddr following your review comment which I agree as SCSIAddr makes it clearer. Hence the change here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had forgotten... |
||
Volumes []*VolumeDescriptor `json:"volumes,omitempty"` | ||
Fsmap []*FsmapDescriptor `json:"fsmap,omitempty"` | ||
Sysctl map[string]string `json:"sysctl,omitempty"` | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add details of the format here as you did in clearcontainers/agent#205?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added details here.