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

cli/connhelper: support overriding the docker binary over SSH #5627

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

mattmacleod
Copy link

This change adds the ability to override the docker binary used when executing commands over SSH. This is useful when the docker binary is not in the PATH of the SSH user, or when the binary is not named docker.

If DOCKER_SSH_REMOTE_BINARY is set in the environment, the value will be used as the docker binary when executing commands over SSH. If the environment variable is not set, the default value of docker will be used.

Closes #5626

- Description for the changelog

Support the `DOCKER_SSH_REMOTE_BINARY` environment variable for overriding the `docker` binary used on remote SSH hosts.

- A picture of a cute animal (not mandatory but encouraged)

IMG_1013

@codecov-commenter
Copy link

codecov-commenter commented Nov 18, 2024

Codecov Report

Attention: Patch coverage is 75.00000% with 2 lines in your changes missing coverage. Please review.

Project coverage is 59.51%. Comparing base (9861ce9) to head (43dd6ea).
Report is 22 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #5627   +/-   ##
=======================================
  Coverage   59.50%   59.51%           
=======================================
  Files         346      346           
  Lines       29365    29372    +7     
=======================================
+ Hits        17474    17480    +6     
- Misses      10916    10917    +1     
  Partials      975      975           

@@ -49,7 +56,7 @@ func getConnectionHelper(daemonURL string, sshFlags []string) (*ConnectionHelper
sshFlags = disablePseudoTerminalAllocation(sshFlags)
return &ConnectionHelper{
Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) {
args := []string{"docker"}
args := []string{dockerSSHRemoteBinary()}
Copy link
Member

Choose a reason for hiding this comment

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

Having this inside of the Dialer means that it'll possibly get evaluated multiple times during a single CLI invocation – so, if something unexpected happens causing the environment variable to get unset while the process is running and Dialer gets called again a different value would get returned.

I think it'd be safer to move this evaluation up to L56 to make sure it only happens once.

Copy link
Member

Choose a reason for hiding this comment

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

something like

remoteDockerBinary := dockerSSHRemoteBinary()
return &ConnectionHelper{
			Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) {
				args := []string{remoteDockerBinary}
...

Copy link
Author

Choose a reason for hiding this comment

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

Great point – thanks @laurazard! I've updated as suggested.

@mattmacleod mattmacleod force-pushed the 5626-allow-binary-override-over-ssh branch 2 times, most recently from 82352ff to 43dd6ea Compare November 18, 2024 15:27
Comment on lines 66 to 92

func TestDockerSSHBinaryOverride(t *testing.T) {
testCases := []struct {
name string
env string
expected string
}{
{
name: "Default",
env: "",
expected: "docker",
},
{
name: "Override",
env: "other-binary",
expected: "other-binary",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Setenv(DockerSSHRemoteBinaryEnv, tc.env)
result := dockerSSHRemoteBinary()
if result != tc.expected {
t.Errorf("expected %q, got %q", tc.expected, result)
}
})
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

To be honest, the function tested here is so trivial, that it's in fact much simpler than the test code.
I don't think we really need it, but since it's already there, I guess it doesn't hurt either 🤷🏻

cli/connhelper/connhelper_test.go Outdated Show resolved Hide resolved
// commands over SSH. It defaults to "docker" if the DOCKER_SSH_REMOTE_BINARY
// environment variable is not set.
func dockerSSHRemoteBinary() string {
value := os.Getenv(DockerSSHRemoteBinaryEnv)
Copy link
Collaborator

Choose a reason for hiding this comment

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

It would probably be better if this was a per-context setting rather than a global env-variable.
However, it's a niche use-case, so I guess it's okay as an escape hatch and not really a blocker.

@thaJeztah @laurazard WDYT?

@thaJeztah
Copy link
Member

I'm honestly a bit on the fence on this change, but curious what exact issues this is resolving; from the ticket;

  • Systems where docker isn't in the path for the SSH connection, and
  • Systems where the docker binary has another name.
  • For the first one; I'm curious in what situations the docker binary would not be in PATH; that seems like a broken setup, Some of this could (depending on the situation) be addressed through ssh config (SetEnv) if the host allows it.
  • For the second one; do you have a specific example? This feature was designed to work with docker, and the requirement for it to work is for the docker CLI to be installed on the remote host; I'm wondering if there's a good use-case for using any other random binary for this purpose. If the remote has something installed trying to be docker compatible, it could of course provide an alias.

Happy to hear if there's more details to this requirement.

@mattmacleod
Copy link
Author

Hey @thaJeztah! I think this is honestly probably pretty limited in terms of applicability, and I've only raised it due to a pretty specific set of circumstances – to support remote ops to machines running BalenaOS.

These devices are running balenaEngine rather than Docker – it's a Moby-derived container engine. The upshot of all this is that the root filesystem is read-only, and the container engine CLI command is named balena instead of docker.

Since the root filesystem is readonly by design, I've got limited options in terms of things like aliases or changes that would otherwise allow this to be implemented.

We've obviously in my team got the option of building our own CLI release instead to support this pretty narrow use-case, but I figured it was generally a light-touch change that might benefit some other people too.

mattmacleod and others added 3 commits November 28, 2024 17:26
This change adds the ability to override the docker binary used when executing
commands over SSH. This is useful when the docker binary is not in the PATH of
the SSH user, or when the binary is not named `docker`.

If `DOCKER_SSH_REMOTE_BINARY` is set in the environment, the value will be used
as the docker binary when executing commands over SSH. If the environment
variable is not set, the default value of `docker` will be used.

Signed-off-by: Matthew MacLeod <matt@umm.io>
Signed-off-by: Matthew MacLeod <matt@umm.io>
Simplify test assertion

Co-authored-by: Paweł Gronowski <me@woland.xyz>
Signed-off-by: Matthew MacLeod <matt@umm.io>
@mattmacleod mattmacleod force-pushed the 5626-allow-binary-override-over-ssh branch from 67dee0e to 24fb803 Compare November 28, 2024 17:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Remove hardcoded docker CLI command name for SSH hosts
5 participants