mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-10 12:32:03 +00:00
AWS: Use a strongly typed mountDevice
We've had problems in the past from using a string with passing the wrong value when detaching; stronger typing would have caught this for us.
This commit is contained in:
parent
7ca0fa431b
commit
03900b1dc9
@ -802,12 +802,16 @@ func (self *AWSCloud) GetZone() (cloudprovider.Zone, error) {
|
|||||||
type awsInstanceType struct {
|
type awsInstanceType struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used to represent a mount device for attaching an EBS volume
|
||||||
|
// This should be stored as a single letter (i.e. c, not sdc or /dev/sdc)
|
||||||
|
type mountDevice string
|
||||||
|
|
||||||
// TODO: Also return number of mounts allowed?
|
// TODO: Also return number of mounts allowed?
|
||||||
func (self *awsInstanceType) getEBSMountDevices() []string {
|
func (self *awsInstanceType) getEBSMountDevices() []mountDevice {
|
||||||
// See: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/block-device-mapping-concepts.html
|
// See: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/block-device-mapping-concepts.html
|
||||||
devices := []string{}
|
devices := []mountDevice{}
|
||||||
for c := 'f'; c <= 'p'; c++ {
|
for c := 'f'; c <= 'p'; c++ {
|
||||||
devices = append(devices, fmt.Sprintf("%c", c))
|
devices = append(devices, mountDevice(fmt.Sprintf("%c", c)))
|
||||||
}
|
}
|
||||||
return devices
|
return devices
|
||||||
}
|
}
|
||||||
@ -825,7 +829,7 @@ type awsInstance struct {
|
|||||||
|
|
||||||
// We must cache because otherwise there is a race condition,
|
// We must cache because otherwise there is a race condition,
|
||||||
// where we assign a device mapping and then get a second request before we attach the volume
|
// where we assign a device mapping and then get a second request before we attach the volume
|
||||||
deviceMappings map[string]string
|
deviceMappings map[mountDevice]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAWSInstance(ec2 EC2, awsID, nodeName string) *awsInstance {
|
func newAWSInstance(ec2 EC2, awsID, nodeName string) *awsInstance {
|
||||||
@ -864,9 +868,10 @@ func (self *awsInstance) getInfo() (*ec2.Instance, error) {
|
|||||||
return instances[0], nil
|
return instances[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assigns an unused mountpoint (device) for the specified volume.
|
// Gets the mountDevice already assigned to the volume, or assigns an unused mountDevice.
|
||||||
// If the volume is already assigned, this will return the existing mountpoint and true
|
// If the volume is already assigned, this will return the existing mountDevice with alreadyAttached=true.
|
||||||
func (self *awsInstance) assignMountpoint(volumeID string) (mountpoint string, alreadyAttached bool, err error) {
|
// Otherwise the mountDevice is assigned by finding the first available mountDevice, and it is returned with alreadyAttached=false.
|
||||||
|
func (self *awsInstance) getMountDevice(volumeID string) (assigned mountDevice, alreadyAttached bool, err error) {
|
||||||
instanceType := self.getInstanceType()
|
instanceType := self.getInstanceType()
|
||||||
if instanceType == nil {
|
if instanceType == nil {
|
||||||
return "", false, fmt.Errorf("could not get instance type for instance: %s", self.awsID)
|
return "", false, fmt.Errorf("could not get instance type for instance: %s", self.awsID)
|
||||||
@ -884,35 +889,38 @@ func (self *awsInstance) assignMountpoint(volumeID string) (mountpoint string, a
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", false, err
|
return "", false, err
|
||||||
}
|
}
|
||||||
deviceMappings := map[string]string{}
|
deviceMappings := map[mountDevice]string{}
|
||||||
for _, blockDevice := range info.BlockDeviceMappings {
|
for _, blockDevice := range info.BlockDeviceMappings {
|
||||||
mountpoint := orEmpty(blockDevice.DeviceName)
|
name := aws.StringValue(blockDevice.DeviceName)
|
||||||
if strings.HasPrefix(mountpoint, "/dev/sd") {
|
if strings.HasPrefix(name, "/dev/sd") {
|
||||||
mountpoint = mountpoint[7:]
|
name = name[7:]
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(mountpoint, "/dev/xvd") {
|
if strings.HasPrefix(name, "/dev/xvd") {
|
||||||
mountpoint = mountpoint[8:]
|
name = name[8:]
|
||||||
}
|
}
|
||||||
deviceMappings[mountpoint] = orEmpty(blockDevice.Ebs.VolumeId)
|
if len(name) != 1 {
|
||||||
|
glog.Warningf("Unexpected EBS DeviceName: %q", aws.StringValue(blockDevice.DeviceName))
|
||||||
|
}
|
||||||
|
deviceMappings[mountDevice(name)] = aws.StringValue(blockDevice.Ebs.VolumeId)
|
||||||
}
|
}
|
||||||
self.deviceMappings = deviceMappings
|
self.deviceMappings = deviceMappings
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to see if this volume is already assigned a device on this machine
|
// Check to see if this volume is already assigned a device on this machine
|
||||||
for mountpoint, mappingVolumeID := range self.deviceMappings {
|
for mountDevice, mappingVolumeID := range self.deviceMappings {
|
||||||
if volumeID == mappingVolumeID {
|
if volumeID == mappingVolumeID {
|
||||||
glog.Warningf("Got assignment call for already-assigned volume: %s@%s", mountpoint, mappingVolumeID)
|
glog.Warningf("Got assignment call for already-assigned volume: %s@%s", mountDevice, mappingVolumeID)
|
||||||
return mountpoint, true, nil
|
return mountDevice, true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check all the valid mountpoints to see if any of them are free
|
// Check all the valid mountpoints to see if any of them are free
|
||||||
valid := instanceType.getEBSMountDevices()
|
valid := instanceType.getEBSMountDevices()
|
||||||
chosen := ""
|
chosen := mountDevice("")
|
||||||
for _, device := range valid {
|
for _, mountDevice := range valid {
|
||||||
_, found := self.deviceMappings[device]
|
_, found := self.deviceMappings[mountDevice]
|
||||||
if !found {
|
if !found {
|
||||||
chosen = device
|
chosen = mountDevice
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -928,7 +936,7 @@ func (self *awsInstance) assignMountpoint(volumeID string) (mountpoint string, a
|
|||||||
return chosen, false, nil
|
return chosen, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *awsInstance) releaseMountDevice(volumeID string, mountDevice string) {
|
func (self *awsInstance) releaseMountDevice(volumeID string, mountDevice mountDevice) {
|
||||||
self.mutex.Lock()
|
self.mutex.Lock()
|
||||||
defer self.mutex.Unlock()
|
defer self.mutex.Unlock()
|
||||||
|
|
||||||
@ -1130,24 +1138,24 @@ func (c *AWSCloud) AttachDisk(instanceName string, diskName string, readOnly boo
|
|||||||
return "", errors.New("AWS volumes cannot be mounted read-only")
|
return "", errors.New("AWS volumes cannot be mounted read-only")
|
||||||
}
|
}
|
||||||
|
|
||||||
mountpoint, alreadyAttached, err := awsInstance.assignMountpoint(disk.awsID)
|
mountDevice, alreadyAttached, err := awsInstance.getMountDevice(disk.awsID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inside the instance, the mountpoint always looks like /dev/xvdX (?)
|
// Inside the instance, the mountpoint always looks like /dev/xvdX (?)
|
||||||
hostDevice := "/dev/xvd" + mountpoint
|
hostDevice := "/dev/xvd" + string(mountDevice)
|
||||||
// In the EC2 API, it is sometimes is /dev/sdX and sometimes /dev/xvdX
|
// In the EC2 API, it is sometimes is /dev/sdX and sometimes /dev/xvdX
|
||||||
// We are running on the node here, so we check if /dev/xvda exists to determine this
|
// We are running on the node here, so we check if /dev/xvda exists to determine this
|
||||||
ec2Device := "/dev/xvd" + mountpoint
|
ec2Device := "/dev/xvd" + string(mountDevice)
|
||||||
if _, err := os.Stat("/dev/xvda"); os.IsNotExist(err) {
|
if _, err := os.Stat("/dev/xvda"); os.IsNotExist(err) {
|
||||||
ec2Device = "/dev/sd" + mountpoint
|
ec2Device = "/dev/sd" + string(mountDevice)
|
||||||
}
|
}
|
||||||
|
|
||||||
attached := false
|
attached := false
|
||||||
defer func() {
|
defer func() {
|
||||||
if !attached {
|
if !attached {
|
||||||
awsInstance.releaseMountDevice(disk.awsID, mountpoint)
|
awsInstance.releaseMountDevice(disk.awsID, mountDevice)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user