Open MichaelSimons opened 4 years ago
CC @wli3
Does the dotnet tool infrastructure rely on hard links?
It does not. It is a simple folder delete when uninstall
Running this scenario with diagnostic output yields the following:
Microsoft.DotNet.ToolPackage.ToolPackageException: Invalid cross-device link
---> System.IO.IOException: Invalid cross-device link
at System.IO.FileSystem.MoveDirectory(String sourceFullPath, String destFullPath)
at System.IO.Directory.Move(String sourceDirName, String destDirName)
at ToolPackageUninstaller.<>c__DisplayClass2_1.<Uninstall>b__3()
at Microsoft.DotNet.Cli.Utils.FileAccessRetrier.RetryOnMoveAccessFailure(Action action)
at ToolPackageUninstaller.<>c__DisplayClass2_0.<Uninstall>b__0()
--- End of inner exception stack trace ---
at ToolPackageUninstaller.<>c__DisplayClass2_0.<Uninstall>b__0()
at Microsoft.DotNet.Cli.TransactionalAction.<>c__DisplayClass2_0.<Run>b__0()
at Microsoft.DotNet.Cli.TransactionalAction.Run[T](Func`1 action, Action commit, Action rollback)
at Microsoft.DotNet.Cli.TransactionalAction.Run(Action action, Action commit, Action rollback)
at ToolPackageUninstaller.Uninstall(DirectoryPath packageDirectory)
at Microsoft.DotNet.Tools.Tool.Uninstall.ToolUninstallGlobalOrToolPathCommand.Execute()
Failed to uninstall tool package 'amazon.lambda.tools': Invalid cross-device link
It looks like this is caused by the logic to move the global tool package directory to a staging directory - https://github.com/dotnet/cli/blob/release/3.0.1xx/src/dotnet/ToolPackage/ToolPackageUninstaller.cs#L37
Directory.Move
does not support mounts on linux - Per the documentation
IOException
An attempt was made to move a directory to a different volume.
There is at least one open issue request Directory.Move mount support - https://github.com/dotnet/corefx/issues/41734
@MichaelSimons thank you for look into it!
So different layer is implemented with file mount in docker? It feels like a docker's implementation leak out. I need to think more about it.
Directory.Move is used since it is an atomic operation. And that basically means you cannot do an atomic operation between docker layers which could be anything
@wli3 - Docker creates an overlay mount which merges all of the Docker image layers.
Am I wrong in thinking that the best solution here is for Directory.Move to support mounts (e.g. https://github.com/dotnet/corefx/issues/41734)?
From a priority perspective, the scenario involving uninstalling a dotnet tool that was previously installed in a Docker layer seems like a low priority. The scenario involving upgrading a dotnet tool that was installed in a previous Docker layer is higher in priority but I am not sure how common that would be either. I'm speaking from a scenario perspective here, ignoring the fact that upgrade tool implementation relies on uninstalling the previous version.
Am I wrong in thinking that the best solution here is for Directory.Move to support mounts
That would be the best. But I am not sure it is possible (or very hard) to do an atomic Move between drives.
@RyanWhite25 commented on Wed Oct 30 2019
Steps to reproduce the issue
RUN dotnet tool install -g Amazon.Lambda.Tools
CMD ["/bin/sh"]
docker build
dotnet tool update -g Amazon.Lambda.Tools
dotnet tool uninstall -g Amazon.Lambda.Tools
Tool 'amazon.lambda.tools' failed to update due to the following: Failed to uninstall tool package 'amazon.lambda.tools': Cross-device link
Client: Version: 18.06.1-ce API version: 1.38 Go version: go1.10.3 Git commit: e68fc7a215d7133c34aa18e3b72b4a21fd0c6136 Built: Mon Jul 1 18:51:44 2019 OS/Arch: linux/amd64 Experimental: false
Server: Engine: Version: 18.06.1-ce API version: 1.38 (minimum version 1.12) Go version: go1.10.3 Git commit: e68fc7a/18.06.1-ce Built: Mon Jul 1 18:53:20 2019 OS/Arch: linux/amd64 Experimental: false
Containers: 20 Running: 1 Paused: 0 Stopped: 19 Images: 28 Server Version: 18.06.1-ce Storage Driver: overlay2 Backing Filesystem: xfs Supports d_type: true Native Overlay Diff: true Logging Driver: json-file Cgroup Driver: cgroupfs Plugins: Volume: local Network: bridge host macvlan null overlay Log: awslogs fluentd gcplogs gelf journald json-file logentries splunk syslog Swarm: inactive Runtimes: runc Default Runtime: runc Init Binary: docker-init containerd version: 468a545b9edcd5932818eb9de8e72413e616e86e runc version: 69663f0bd4b60df09991c08812a60108003fa340 init version: fec3683 Security Options: seccomp Profile: default Kernel Version: 4.14.138-114.102.amzn2.x86_64 Operating System: Amazon Linux 2 OSType: linux Architecture: x86_64 CPUs: 1 Total Memory: 983.7MiB Name: ip-172-31-11-191.eu-west-1.compute.internal ID: J53Z:IZEG:YQT5:E2KR:SWNZ:JTHZ:QQCE:3ZWZ:VX4M:IDVJ:5W5B:6LG5 Docker Root Dir: /var/lib/docker Debug Mode (client): false Debug Mode (server): false Registry: https://index.docker.io/v1/ Labels: Experimental: false Insecure Registries: 127.0.0.0/8 Live Restore Enabled: false