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

Support for Windows paths in the source position of the volume mounts #17113

Conversation

arixmkii
Copy link
Contributor

@arixmkii arixmkii commented Jan 13, 2023

Fixes #17098

Was tested as part of #13006 (comment)

Implementation demo isolated https://go.dev/play/p/Do-tBPHESLE (Original outdated version)

There are 2 things added. First there is added support for handling drive letters while doing value split. If drive letter is detected, then max number of elements will be increased by one, but then first two will be concatenated to reconstruct the path. Second part is basic, but working conversion of Windows path to Unix to be used, when target path is not explicitly specified.

Used regex for drive letter detection, because init would be never used in the hotpath, so, performance wise it affordable.

Signed-off-by: Arthur Sengileyev [email protected]

[NO NEW TESTS NEEDED]

Does this PR introduce a user-facing change?

None

@arixmkii
Copy link
Contributor Author

arixmkii commented Jan 13, 2023

Added NO NEW TESTS NEEDED, because obviously there are no tests for QEMU machine on Windows as of now and all the code changes are isolated behind runtime.GOOS == "windows" condition.

@arixmkii
Copy link
Contributor Author

Tested with QEMU on Windows enabled build with the following commands for machine init.

// explicitly mounting to /home/core/ps
podman machine init --image-path testing --username core --cpus 4 --memory 8192 -v C:\Temp\PodmanStorage:/home/core/ps
podman machine init --image-path testing --username core --cpus 4 --memory 8192 -v C:/Temp/PodmanStorage:/home/core/ps

// automatically mounting to /C/Temp/PodmanStorage
podman machine init --image-path testing --username core --cpus 4 --memory 8192 -v C:\Temp\PodmanStorage
podman machine init --image-path testing --username core --cpus 4 --memory 8192 -v C:/Temp/PodmanStorage

// automatically mounting to /Temp/PodmanStorage
// usage of pahts w/o drive letter should be strictly discouraged, but it is still a supported option
podman machine init --image-path testing --username core --cpus 4 --memory 8192 -v \Temp\PodmanStorage
podman machine init --image-path testing --username core --cpus 4 --memory 8192 -v /Temp/PodmanStorage

After init machines were always launched and mounts being operational were verifies using ssh into machine.

@arixmkii arixmkii force-pushed the windows-qemu-machine-volume-mounts branch 2 times, most recently from 74c591a to 3d73606 Compare January 13, 2023 22:03
@mheon
Copy link
Member

mheon commented Jan 17, 2023

@n1hility @baude PTAL

if len(paths) > 1 && driveLetterMatcher.MatchString(paths[0]) {
paths = strings.SplitN(volume, ":", 4)
newpaths := []string{paths[0] + ":" + paths[1]}
for _, v := range paths[2:] {
Copy link
Member

Choose a reason for hiding this comment

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

It's late and I can't quickly recall. If paths only has one value in it after the SplitN, i.e. the value in the volume variable had no colons, will this spit up?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is a check at line 309, that paths will have at least 2 elements len(paths) > 1.

Example of this check isolated https://go.dev/play/p/AhlcW74W5cH

@TomSweeneyRedHat
Copy link
Member

@arixmkii looks like lint is picking on you:

level=warning msg="[linters_context] sqlclosecheck is disabled because of generics. You can track the evolution of the generics support by following the https://github.com/golangci/golangci-lint/issues/2649."
level=warning msg="[linters_context] wastedassign is disabled because of generics. You can track the evolution of the generics support by following the https://github.com/golangci/golangci-lint/issues/2649."
pkg/machine/qemu/machine.go:312:5: S1011: should replace loop with `newpaths = append(newpaths, paths[2:]...)` (gosimple)
				for _, v := range paths[2:] {
				^
make: *** [Makefile:253: golangci-lint] Error 1

@arixmkii arixmkii force-pushed the windows-qemu-machine-volume-mounts branch from 3d73606 to 44a0667 Compare January 21, 2023 15:46
@arixmkii
Copy link
Contributor Author

Had another reading session about paths on Windows and it looks like this version of algorithm will fail for DOS device paths, which could used for referencing files: https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats#dos-device-paths I'm not really sure if QEMU will accept them as valid, but I can update the algorithm to handle them (here Regexp will come really handy).

@arixmkii
Copy link
Contributor Author

arixmkii commented Jan 21, 2023

Added DOS device path support in a separate commit. Will squash if it is accepted or remove it if this is not needed.

Isolated example updated: https://go.dev/play/p/WGT06ek1RmB

@arixmkii arixmkii force-pushed the windows-qemu-machine-volume-mounts branch from 922b1b6 to 6881ca3 Compare January 21, 2023 17:30
@@ -302,8 +304,24 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
for i, volume := range opts.Volumes {
tag := fmt.Sprintf("vol%d", i)
paths := strings.SplitN(volume, ":", 3)
if runtime.GOOS == "windows" {
Copy link
Member

Choose a reason for hiding this comment

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

I know this is a small amount of specific code here, but a general ask from the team is to try to break out any platform-specific code into a build-tag controlled unit (_windows etc), to try to keep code sizes from growing too rapidly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure. Will refactor and take into account for my future contributions.

source := paths[0]
target := source
if runtime.GOOS == "windows" {
Copy link
Member

Choose a reason for hiding this comment

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

in addition to the above, this should check its even necessary to do so (if paths.len > 1 [ after its been altered above])

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Valid point. And simple fix. My idea was to mirror unconditional behavior of the above, but obviously that one was for variable initialization, which is not needed here.

pkg/machine/qemu/machine.go Outdated Show resolved Hide resolved
}
target = strings.ReplaceAll(target, ":", "")
prefixRemover := regexp.MustCompile(`^//[.?]/`)
target = prefixRemover.ReplaceAllString(target, "/")
Copy link
Member

Choose a reason for hiding this comment

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

tiny nit: this could be a match target = target[3:] or ReplaceAllLiteralString

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Need to check this. I'm still not as good with Go lang as I would want to. Thank you for the hints.

@arixmkii arixmkii force-pushed the windows-qemu-machine-volume-mounts branch from 6881ca3 to 4ab3beb Compare January 29, 2023 22:52
@arixmkii
Copy link
Contributor Author

Applied some refactoring. Now getting paths and then processing of source, target, options are dedicated functions, which could be shared or platform specific.

Applied some changes to source to target path conversion on Windows. Now algorithm looks more straight forward (at least to me).

  1. replace backslashes with forward ones
  2. replace colon with slash (this is needed to support extremely rare case of relative path for a working directory on another driver - so, C:my\path would become /c/my/path instead of /cmy/path. These form is really discouraged and using relative paths as an argument to mounts would be a bad practice, but it is pretty simple fix anyway.
  3. remove known DOS device prefixes
  4. append leading slash and then eliminate any consecutive multiple slashes //+ replaced with /. They could appear if UNC paths were used (I'm not sure if QEMU will be happy about them, but just to stay on the safe side) https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats#unc-paths

@arixmkii arixmkii force-pushed the windows-qemu-machine-volume-mounts branch from 4ab3beb to d9b9248 Compare January 29, 2023 23:02
@arixmkii
Copy link
Contributor Author

Updated example https://go.dev/play/p/Do-tBPHESLE

@arixmkii arixmkii requested a review from n1hility January 29, 2023 23:09
@arixmkii
Copy link
Contributor Author

Will fix linters in the morning and resubmit.

@arixmkii arixmkii force-pushed the windows-qemu-machine-volume-mounts branch 2 times, most recently from fcc60c0 to ec39837 Compare January 30, 2023 09:56
@rhatdan
Copy link
Member

rhatdan commented Jan 30, 2023

@n1hility PTAL
Do we need this in 4.4?

@arixmkii
Copy link
Contributor Author

Do we need this in 4.4?

Sharing my opinion and giving some more insights.

Code changes are isolated in Windows specific sources (refactored parts should not change current behavior), but Windows parts for now are also cut by the Compiler/Linker process, because QEMU is not yet referenced in the list of available machines for Windows.

From my point of view, changes are safe looking and there is no need to delay it if possible, but there is no any business justification to include it in the current release, because it changes no behavior within the supported feature set.

target := strings.ReplaceAll(paths[0], "\\", "/")
target = strings.ReplaceAll(target, ":", "/")
target = strings.ReplaceAll(target, "//./", "")
target = strings.ReplaceAll(target, "//?/", "")
Copy link
Member

Choose a reason for hiding this comment

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

A minor nit, but not a blocker, is that these namespace prefixes can only occur at the start of the string, so you could just do something like:

if strings.HasPrefix(path, "//./") || strings.HasPrefix(path, "//?/") {
        path = path[4:]
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks. This is better indeed and more correct as we are eliminating only prefixes.

Applied as part of the same commit. Last line was changed to fix output of gofmt -d -s.

@@ -42,10 +42,11 @@ func extractTargetPath(paths []string) string {
 	if len(paths) > 1 {
 		return paths[1]
 	}
 	target := strings.ReplaceAll(paths[0], "\\", "/")
 	target = strings.ReplaceAll(target, ":", "/")
-	target = strings.ReplaceAll(target, "//./", "")
-	target = strings.ReplaceAll(target, "//?/", "")
+	if strings.HasPrefix(target, "//./") || strings.HasPrefix(target, "//?/") {
+		target = target[4:]
+	}
 	dedup := regexp.MustCompile(`//+`)
-	return dedup.ReplaceAllLiteralString("/" + target, "/")
+	return dedup.ReplaceAllLiteralString("/"+target, "/")
 }

@n1hility
Copy link
Member

Other than the above nit LGTM.

@n1hility
Copy link
Member

n1hility commented Jan 30, 2023

@arixmkii the reason @rhatdan is asking is we have already branched v4.4, so should this be backported after merge? Since as you mention it's not yet usable, I think we can skip the backport and target for a later 4.x, when the other patches land.

There are 2 things added. First there is added support for handling drive
letters while doing value split. If drive letter is detected, then max number
of elements will be increased by one, but then first two will be concatenated
to reconstruct the path. Second part is basic, but working, conversion of Windows
path to Unix path to be used, when target path is not explicitly specified.

Signed-off-by: Arthur Sengileyev <[email protected]>
@arixmkii arixmkii force-pushed the windows-qemu-machine-volume-mounts branch from ec39837 to 952049f Compare January 30, 2023 21:33
@arixmkii
Copy link
Contributor Author

@n1hility Thank you for the context and explaining some background processes to the community contributors. I noticed this already, when my gvproxy/installer PR was cherry-picked for the release branch. Thus, I tried to explain my opinion, that there is no need to backport this changes to the release branch, because they are more of a ground for some future work.

@arixmkii
Copy link
Contributor Author

@rhatdan @n1hility can we move forward with it? It should have no conflicts with latest head, but I can rebase and force push if needed.

@rhatdan
Copy link
Member

rhatdan commented Feb 28, 2023

/approve
/lgtm

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Feb 28, 2023
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Feb 28, 2023

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: arixmkii, rhatdan

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

@openshift-ci openshift-ci bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Feb 28, 2023
@openshift-merge-robot openshift-merge-robot merged commit 77504b2 into containers:main Feb 28, 2023
@github-actions github-actions bot added the locked - please file new issue/PR Assist humans wanting to comment on an old issue or PR with locked comments. label Sep 7, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 7, 2023
@arixmkii arixmkii deleted the windows-qemu-machine-volume-mounts branch March 1, 2024 13:55
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged. locked - please file new issue/PR Assist humans wanting to comment on an old issue or PR with locked comments. release-note-none
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feature]: QEMU Machine should support Windows Source paths for 9pfs on Windows hosts
6 participants