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

drivers/docker: add support for STOPSIGNAL #10441

Merged
merged 1 commit into from
May 5, 2021
Merged

Conversation

isabeldepapel
Copy link
Contributor

Still need to figure out the tests but this is what I have so far

This fixes a bug where Nomad overrides a Dockerfile's STOPSIGNAL with
the default kill_signal (SIGTERM).

This adds a check for kill_signal. If it's not set, it calls
StopContainer instead of Signal, which uses STOPSIGNAL if it's
specified. If both kill_signal and STOPSIGNAL are set, Nomad tries to
stop the container with kill_signal first, before then calling
StopContainer.

Fixes #9989

@hashicorp-cla
Copy link

hashicorp-cla commented Apr 23, 2021

CLA assistant check
All committers have signed the CLA.

Copy link
Member

@tgross tgross left a comment

Choose a reason for hiding this comment

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

This is looking good, @isabeldepapel.

It looks like there are some tests that exercise the stop behavior vs a real Docker already (example). So you can probably verify this works by querying for Docker API events in those tests, and then making assertions about those events.

drivers/docker/handle.go Outdated Show resolved Hide resolved
// Calling StopContainer lets docker handle the stop signal (specified
// in the Dockerfile or defaulting to SIGTERM). If kill_signal is specified,
// Signal is used to kill the container with the desired signal before
// calling StopContainer
Copy link
Member

Choose a reason for hiding this comment

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

👍 Good explanatory comment for summarizing the domain-specific knowledge you'd need to understand the code here.

Copy link
Contributor

@notnoop notnoop left a comment

Choose a reason for hiding this comment

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

This looks great. Thanks @isabeldepapel

Made a couple of comments - mostly how the existing code doesn't follow some golang convention. Noting them for educational value only.

// parseSignal interprets the signal name into an os.Signal. If no name is
// provided, the docker driver defaults to SIGTERM. If the OS is Windows and
// SIGINT is provided, the signal is converted to SIGTERM.
func (h *taskHandle) parseSignal(os, signal string) (os.Signal, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This method is a simple "pure" function that doesn't depend on taskHandle/driver. You can make it a simple function and simply the tests by avoiding the dockerTest related boilerplate:

Suggested change
func (h *taskHandle) parseSignal(os, signal string) (os.Signal, error) {
func parseSignal(os, signal string) (os.Signal, error) {

Comment on lines 2921 to 2925
t.Run("default", func(t *testing.T) {
s, err := d.parseSignal(runtime.GOOS, "")
s, err := handle.parseSignal(runtime.GOOS, "")
require.NoError(t, err)
require.Equal(t, syscall.SIGTERM, s)
})
Copy link
Contributor

Choose a reason for hiding this comment

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

FWIW - These can be better expressed as table driver tests, a common pattern Nomad uses elsewhere: https://jayson.dev/blog/2019/06/table-driven-golang-subtests/#time-for-the-subtests .

Such a refactor is outside the scope of the PR; though, wanted to note it for educational value. If you do want to take it on, no objection ;-).

@@ -2911,28 +2911,33 @@ func TestDockerDriver_memoryLimits(t *testing.T) {
func TestDockerDriver_parseSignal(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Noting that Golang has a convention about test files: If the tested function is in handle.go, the tests belong in handle_test.go. It's odd that handle_test.go. Seeing how the two files are intertwined, it's fine to leave the test here.

Copy link
Contributor

@notnoop notnoop left a comment

Choose a reason for hiding this comment

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

This is great! I have few suggestions for the tests; but it's solid. I'll be happy to pair, specially with regards to the concurrency issue.

drivers/docker/driver_test.go Outdated Show resolved Hide resolved
drivers/docker/driver_test.go Outdated Show resolved Hide resolved
drivers/docker/driver_test.go Outdated Show resolved Hide resolved
drivers/docker/driver_test.go Outdated Show resolved Hide resolved
require.Equal(t, syscall.SIGHUP, s)
})
// This test asserts that Nomad isn't overriding the STOPSIGNAL in a Dockerfile
func TestDockerDriver_StopSignal(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a great test. Captures all conditions :).

drivers/docker/driver_test.go Outdated Show resolved Hide resolved
@isabeldepapel
Copy link
Contributor Author

Ready for another pass @notnoop

Copy link
Contributor

@notnoop notnoop left a comment

Choose a reason for hiding this comment

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

Looks great. A minor suggestion to the shell script - but merge away 🎉

#!/bin/sh

# Create the tarball used in TestDockerDriver_StopSignal
echo "FROM busybox:1.29.3\nSTOPSIGNAL 19" > tmpfile && docker build -t busybox:1.29.3-stopsignal - < tmpfile && rm tmpfile
Copy link
Contributor

Choose a reason for hiding this comment

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

I suspect you can avoid needing the tmp file. Also it might a bit nicer to use here-doc style in this case to avoid new lines:

Suggested change
echo "FROM busybox:1.29.3\nSTOPSIGNAL 19" > tmpfile && docker build -t busybox:1.29.3-stopsignal - < tmpfile && rm tmpfile
cat <<'EOF' | docker build -t busybox:1.29.3-stopsignal -
FROM busybox:1.29.3
STOPSIGNAL 19
EOF

This fixes a bug where Nomad overrides a Dockerfile's STOPSIGNAL with
the default kill_signal (SIGTERM).

This adds a check for kill_signal. If it's not set, it calls
StopContainer instead of Signal, which uses STOPSIGNAL if it's
specified. If both kill_signal and STOPSIGNAL are set, Nomad tries to
stop the container with kill_signal first, before then calling
StopContainer.

Fixes #9989
@isabeldepapel isabeldepapel deleted the b-docker-stopsignal branch May 5, 2021 18:24
@tgross tgross added this to the 1.1.0 milestone May 17, 2021
tgross pushed a commit that referenced this pull request May 17, 2021
drivers/docker: add support for STOPSIGNAL
@github-actions
Copy link

I'm going to lock this pull request because it has been closed for 120 days ⏳. This helps our maintainers find and focus on the active contributions.
If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 21, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Nomad doesn't respect Dockerfile's STOPSIGNAL directive
4 participants