Skip to content

Commit 86af751

Browse files
committed
Add user to docker group if not superuser
This allows docker commands to function with a non-root ssh user Fixes: basecamp#980
1 parent 493c569 commit 86af751

File tree

4 files changed

+39
-0
lines changed

4 files changed

+39
-0
lines changed

lib/kamal/cli/server.rb

+8
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ def bootstrap
3232
if execute(*KAMAL.docker.superuser?, raise_on_non_zero_exit: false)
3333
info "Missing Docker on #{host}. Installing…"
3434
execute *KAMAL.docker.install
35+
begin
36+
execute *KAMAL.docker.add_group
37+
38+
# If the groups change, the session is terminated to force a re-login.
39+
# Catch the resulting IOError and inform the user
40+
rescue IOError
41+
info "Session refreshed due to group change."
42+
end
3543
else
3644
missing << host
3745
end

lib/kamal/commands/docker.rb

+6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ def superuser?
1919
[ '[ "${EUID:-$(id -u)}" -eq 0 ] || command -v sudo >/dev/null || command -v su >/dev/null' ]
2020
end
2121

22+
# If we're not root and not already in the docker group
23+
# add us to the docker group and terminate all our current sessions
24+
def add_group
25+
[ '[ "${EUID:-$(id -u)}" -eq 0 ] || id -nG "${USER:-$(id -un)}" | grep -qw docker || { sudo usermod -aG docker "${USER:-$(id -un)}" && kill -9 -1; }' ]
26+
end
27+
2228
def create_network
2329
docker :network, :create, :kamal
2430
end

test/cli/server_test.rb

+21
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class CliServerTest < CliTestCase
5252
stub_setup
5353
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:docker, "-v", raise_on_non_zero_exit: false).returns(false).at_least_once
5454
SSHKit::Backend::Abstract.any_instance.expects(:execute).with('[ "${EUID:-$(id -u)}" -eq 0 ] || command -v sudo >/dev/null || command -v su >/dev/null', raise_on_non_zero_exit: false).returns(true).at_least_once
55+
SSHKit::Backend::Abstract.any_instance.expects(:execute).with('[ "${EUID:-$(id -u)}" -eq 0 ] || id -nG "${USER:-$(id -un)}" | grep -qw docker || { sudo usermod -aG docker "${USER:-$(id -un)}" && kill -9 -1; }').at_least_once
5556
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:sh, "-c", "'curl -fsSL https://get.docker.com || wget -O - https://get.docker.com || echo \"exit 1\"'", "|", :sh).at_least_once
5657
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:mkdir, "-p", ".kamal").returns("").at_least_once
5758
Kamal::Commands::Hook.any_instance.stubs(:hook_exists?).returns(true)
@@ -66,6 +67,26 @@ class CliServerTest < CliTestCase
6667
end
6768
end
6869

70+
test "bootstrap install as sudo non-root user" do
71+
stub_setup
72+
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:docker, "-v", raise_on_non_zero_exit: false).returns(false).at_least_once
73+
SSHKit::Backend::Abstract.any_instance.expects(:execute).with('[ "${EUID:-$(id -u)}" -eq 0 ] || command -v sudo >/dev/null || command -v su >/dev/null', raise_on_non_zero_exit: false).returns(true).at_least_once
74+
SSHKit::Backend::Abstract.any_instance.expects(:execute).with('[ "${EUID:-$(id -u)}" -eq 0 ] || id -nG "${USER:-$(id -un)}" | grep -qw docker || { sudo usermod -aG docker "${USER:-$(id -un)}" && kill -9 -1; }').at_least_once.raises(IOError, "closed stream")
75+
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:sh, "-c", "'curl -fsSL https://get.docker.com || wget -O - https://get.docker.com || echo \"exit 1\"'", "|", :sh).at_least_once
76+
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:mkdir, "-p", ".kamal").returns("").at_least_once
77+
Kamal::Commands::Hook.any_instance.stubs(:hook_exists?).returns(true)
78+
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(".kamal/hooks/pre-connect", anything).at_least_once
79+
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(".kamal/hooks/docker-setup", anything).at_least_once
80+
81+
run_command("bootstrap").tap do |output|
82+
("1.1.1.1".."1.1.1.4").map do |host|
83+
assert_match "Missing Docker on #{host}. Installing…", output
84+
assert_match "Session refreshed due to group change.", output
85+
assert_match "Running the docker-setup hook", output
86+
end
87+
end
88+
end
89+
6990
private
7091
def run_command(*command)
7192
stdouted { Kamal::Cli::Server.start([ *command, "-c", "test/fixtures/deploy_with_accessories.yml" ]) }

test/commands/docker_test.rb

+4
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,8 @@ class CommandsDockerTest < ActiveSupport::TestCase
2323
test "superuser?" do
2424
assert_equal '[ "${EUID:-$(id -u)}" -eq 0 ] || command -v sudo >/dev/null || command -v su >/dev/null', @docker.superuser?.join(" ")
2525
end
26+
27+
test "add_group" do
28+
assert_equal '[ "${EUID:-$(id -u)}" -eq 0 ] || id -nG "${USER:-$(id -un)}" | grep -qw docker || { sudo usermod -aG docker "${USER:-$(id -un)}" && kill -9 -1; }', @docker.add_group.join(" ")
29+
end
2630
end

0 commit comments

Comments
 (0)