Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix hostpath hotplug not working when volume on separate device #6308

Merged
merged 3 commits into from
Sep 2, 2021

Conversation

awels
Copy link
Member

@awels awels commented Aug 26, 2021

Signed-off-by: Alexander Wels awels@redhat.com

What this PR does / why we need it:
findmnt returns device[path relative in device] when looking up the
source of a mount by container pid. So on separate device that often
returned / which is not where it is mounted in the boot device.

This PR modifies the check to look up the device, and then the path
where the device is mounted, and combines the two paths to get the
path relative to the boot device so we can properly bind mount the
hostpath volume into another container.

Which issue(s) this PR fixes (optional, in fixes #<issue number>(, fixes #<issue_number>, ...) format, will close the issue(s) when PR gets merged):
Fixes #6303

Special notes for your reviewer:
I have made some modifications to disks-images-provider.yaml.in and the entrypoint.sh. In particular I am mounting the host root directory under /host, and then chrooting the losetup commands. This is needed because it will not allow one to create more than 1 loop back device in the container otherwise.

Release note:

BugFix: hotplug was broken when using it with a hostpath volume that was on a separate device.

@kubevirt-bot kubevirt-bot added release-note Denotes a PR that will be considered when it comes time to generate release notes. dco-signoff: yes Indicates the PR's author has DCO signed all their commits. labels Aug 26, 2021
@awels
Copy link
Member Author

awels commented Aug 26, 2021

/cherrypick release-0.44

@kubevirt-bot
Copy link
Contributor

@awels: once the present PR merges, I will cherry-pick it on top of release-0.44 in a new PR and assign it to you.

In response to this:

/cherrypick release-0.44

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@awels
Copy link
Member Author

awels commented Aug 27, 2021

/retest

@awels
Copy link
Member Author

awels commented Aug 27, 2021

/retest

@awels awels force-pushed the hotplug_separate_device branch 2 times, most recently from 5dfe7fd to 01761e9 Compare August 27, 2021 23:48
}
// Check if the path was relative to the device.
if _, err := os.Stat(filepath.Join(util.HostRootMount, source)); err != nil {
return filepath.Join(deviceFindMnt[0].Target, source), nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why it only checks if hostRoot/source exists and does not check deviceFindMnt[0].Target/source.

Also this code is run when file not found or storage isBlock? Is the logic the same for both?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if _, err := os.Stat(filepath.Join(util.HostRootMount, source)); os.IsNotExist(err) || isBlock 

Checks if the returned path doesn't exists, or if the returned path does exist, but is a block device (isBlock)
If either is true, then we call deviceFindMnt with that path. Basically figuring out where this path is mounted (if it is a block device for instance). If found return the target (mount path). If not found we try again but this time with the SourceDevice part of the findmnt information. The arguments passed to findmtn return 'source' in the following format:

/dev/device[/path/relative/to/device]

findmnt.GetSourceDevice() returns the /dev/device part
findmnt.GetSourcePath() returns /path/relative/to/device part

Once I get to

if _, err := os.Stat(filepath.Join(util.HostRootMount, source)); err != nil {

I know that deviceFindMnt[0].Target is the path the device is mounted on relative to the boot partition. And I know that source is the path relative to the device. So the two combined will be the path I am looking for. I can check if that path exists, but if it doesn't I have no recourse to do anything but return an error, and the caller of this function is going to try and do stuff with the path immeidately as well, and error if it doesn't exist then.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this explains it. I just wonder if this can be simplified.

Comment on lines +138 to +141
test := FindmntInfo{
Source: "/dev/test",
}
Expect(test.GetSourceDevice()).To(Equal(""))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why wouldn't this test case return /dev/test ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the regex is looking for .*[.+] so no [ ] is no match. This is because I am calling findmnt with arguments that should never return /dev/test for a filesystem mount.

Copy link
Contributor

@jean-edouard jean-edouard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/approve
This looks ok to me, just a few comments in-line.
@davidvossel @brybacki have your concerns been addressed?

@@ -34,7 +34,8 @@ num=$(losetup -l | wc -l)
[ ${num} -gt 100 ] && echo "attached loopdevices have reach limit number(100)" && exit 1

# Put LOOP_DEVICE in /etc/bashrc in order to detach this loop device when the pod stopped.
LOOP_DEVICE=$(losetup --find --show /local-storage/cirros.img.raw)
LOOP_DEVICE=$(chroot /host losetup --find --show /mnt/local-storage/cirros.img.raw)
echo $LOOP_DEVICE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leftover debug print?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes and no, I can remove it, but I think it would be useful for people to see what loopback device was created.

ls -al /local-storage/hp_file.img
# Put LOOP_DEVICE_HP in /etc/bashrc in order to detach this loop device when the pod stopped.
LOOP_DEVICE_HP=$(chroot /host losetup --verbose --find --show /mnt/local-storage/hp_file.img)
echo $LOOP_DEVICE_HP
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leftover debug print?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes and no, I can remove it, but I think it would be useful for people to see what loopback device was created.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you leave it I'd suggest making it a bit more verbose so people know what it's about!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not that passionate about it, I am removing it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if people really want to know, you can look in /etc/bashrc to find out.

match := sourceRgx.FindStringSubmatch(f.Source)
if len(match) != 2 {
return strings.TrimPrefix(f.Source, rhcosPrefix)
}
return strings.TrimPrefix(match[1], rhcosPrefix)
}

func (f *FindmntInfo) GetSourceDevice() string {
match := deviceRgx.FindStringSubmatch(f.Source)
if len(match) == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: we really want len(match) to be exactly 2, like in the function above.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I can flip the logic to

if len(match) == 2 {
  return match[1]
}
return ""

@kubevirt-bot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: jean-edouard

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@kubevirt-bot kubevirt-bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Aug 31, 2021
findmnt returns device[path relative in device] when looking up the
source of a mount by container pid. So on separate device that often
returned /<path> which is not where it is mounted in the boot device.

This PR modifies the check to look up the device, and then the path
where the device is mounted, and combines the two paths to get the
path relative to the boot device so we can properly bind mount the
hostpath volume into another container.

Signed-off-by: Alexander Wels <awels@redhat.com>
Signed-off-by: Alexander Wels <awels@redhat.com>
Signed-off-by: Alexander Wels <awels@redhat.com>
@awels
Copy link
Member Author

awels commented Sep 1, 2021

/test pull-kubevirt-e2e-k8s-1.20-sig-compute

@davidvossel
Copy link
Member

This looks ok to me, just a few comments in-line.
@davidvossel @brybacki have your concerns been addressed?

yep

@brybacki
Copy link
Contributor

brybacki commented Sep 2, 2021

This looks ok to me, just a few comments in-line.
@davidvossel @brybacki have your concerns been addressed?

yep

Yes

@jean-edouard
Copy link
Contributor

/lgtm

@kubevirt-bot kubevirt-bot added the lgtm Indicates that a PR is ready to be merged. label Sep 2, 2021
@kubevirt-bot kubevirt-bot merged commit 78e64e1 into kubevirt:main Sep 2, 2021
@kubevirt-bot
Copy link
Contributor

@awels: new pull request created: #6344

In response to this:

/cherrypick release-0.44

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@kubevirt-bot
Copy link
Contributor

@awels: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Rerun command
pull-kubevirt-e2e-k8s-1.21-sig-compute 25933f4 link /test pull-kubevirt-e2e-k8s-1.21-sig-compute

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. dco-signoff: yes Indicates the PR's author has DCO signed all their commits. lgtm Indicates that a PR is ready to be merged. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/L
Projects
None yet
Development

Successfully merging this pull request may close these issues.

hostpath hotplug with path on separate device does not work
5 participants