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

Fix for certain problems on Synology devices #1068

Closed
wants to merge 1 commit into from

Conversation

tammert
Copy link
Member

@tammert tammert commented Sep 4, 2021

Avoid 'assignment to entry in nil map' when *container.Config.ExposedPorts is not filled

These logs come directly from my Synology device (with the code from this PR running):

time="2021-09-04T20:05:34Z" level=debug msg="Trying to load authentication credentials." container=/homeassistant image="homeassistant/home-assistant:stable"
time="2021-09-04T20:05:34Z" level=debug msg="No credentials for homeassistant found" config_file=/config.json
time="2021-09-04T20:05:34Z" level=debug msg="Got image name: homeassistant/home-assistant:stable"
time="2021-09-04T20:05:34Z" level=debug msg="Checking if pull is needed" container=/homeassistant image="homeassistant/home-assistant:stable"
time="2021-09-04T20:05:34Z" level=debug msg="Building challenge URL" URL="https://index.docker.io/v2/"
time="2021-09-04T20:05:35Z" level=debug msg="Got response to challenge request" header="Bearer realm=\"https://auth.docker.io/token\",service=\"registry.docker.io\"" status="401 Unauthorized"
time="2021-09-04T20:05:35Z" level=debug msg="Checking challenge header content" realm="https://auth.docker.io/token" service=registry.docker.io
time="2021-09-04T20:05:35Z" level=debug msg="Setting scope for auth token" image=homeassistant/home-assistant scope="repository:homeassistant/home-assistant:pull"
time="2021-09-04T20:05:35Z" level=debug msg="No credentials found."
time="2021-09-04T20:05:35Z" level=debug msg="Parsing image ref" host=index.docker.io image=homeassistant/home-assistant normalized="docker.io/homeassistant/home-assistant:stable" tag=stable
time="2021-09-04T20:05:35Z" level=debug msg="Doing a HEAD request to fetch a digest" url="https://index.docker.io/v2/homeassistant/home-assistant/manifests/stable"
time="2021-09-04T20:05:35Z" level=debug msg="Found a remote digest to compare with" remote="sha256:43b39af7c9c63b933ba4ed17c226c97111c39a4cb379e444099292bdeedfbaff"
time="2021-09-04T20:05:35Z" level=debug msg=Comparing local="sha256:8f5fd806376b78183851cd408885bf27e82f7d9de7638c8cfcef838a6e7c31ea" remote="sha256:43b39af7c9c63b933ba4ed17c226c97111c39a4cb379e444099292bdeedfbaff"
time="2021-09-04T20:05:35Z" level=debug msg="Digests did not match, doing a pull."
time="2021-09-04T20:05:35Z" level=debug msg="Pulling image" container=/homeassistant image="homeassistant/home-assistant:stable"
time="2021-09-04T20:06:41Z" level=info msg="Found new homeassistant/home-assistant:stable image (16caae5dfda5)"
.........
time="2021-09-04T20:06:43Z" level=info msg="Stopping /homeassistant (ddc0d725a628) with SIGTERM"
time="2021-09-04T20:06:50Z" level=debug msg="Removing container ddc0d725a628"
time="2021-09-04T20:06:58Z" level=debug msg="This is the watchtower container /tender_banach"
time="2021-09-04T20:06:58Z" level=info msg="Creating /homeassistant"
time="2021-09-04T20:07:00Z" level=debug msg="Starting container /homeassistant (0fdc56784bd2)"
time="2021-09-04T20:07:02Z" level=debug msg="Session done: 4 scanned, 1 updated, 0 failed"

@tammert tammert requested a review from simskij as a code owner September 4, 2021 20:21
config.ExposedPorts[p] = struct{}{}
// config.ExposedPorts isn't reliably in sync with HostConfig.PortBindings, so we can't assign directly to map without checking
if _, ok := config.ExposedPorts[p]; ok {
config.ExposedPorts[p] = struct{}{}
Copy link
Member Author

Choose a reason for hiding this comment

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

The whole point of this code is to empty out map entries, so we should be able to safely skip that action if the map is nil

Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure that it is... Couldn't we just assign ExposedPorts to a new map if it's nil instead? If we keep part of the config as nil we might run into issues in other parts of the code that expects it to be a map.
I think the point of this code is to explicitly add the portbindings to the exposed ports (but with no explicit mapping config), but I may be wrong here.
Since the docker daemon on Synology doesn't return any exposed ports, it's somewhat natural that it doesn't require them in the create container payload. It might break container creation on non-synology docker though...

@@ -298,9 +301,5 @@ func (c Container) VerifyConfiguration() error {
return errorInvalidConfig
}

if len(hostConfig.PortBindings) > 0 && containerConfig.ExposedPorts == nil {
Copy link
Member Author

Choose a reason for hiding this comment

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

Containers get recreated with the correct ports for me, so I'm assuming the Docker client uses the ones it finds in hostConfig.PortBindings and doesn't necessarily need those from *container.Config.ExposedPorts

Copy link
Member

Choose a reason for hiding this comment

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

If we did this instead:

if len(hostConfig.PortBindings) > 0 && containerConfig.ExposedPorts == nil {
	containerConfig.ExposedPorts = make(map[Port]struct{})
}

it would just align the docker responses for synology and non-synology docker daemons.

@tammert tammert requested review from piksel and zoispag September 4, 2021 20:28
@piksel
Copy link
Member

piksel commented Sep 5, 2021

This is essentially what we needed testing. Hopefully this is the only difference on Synology Docker. I don't remember off hand what other images caused the partial config.

@tammert
Copy link
Member Author

tammert commented Sep 5, 2021

I was thinking, maybe the Dockerfile for home-assistant omits the EXPOSE instruction, and that might explain the differences between this image and others?

@piksel
Copy link
Member

piksel commented Sep 19, 2021

That seems like the obvious cause, could you do some investigation on this? Like building a docker image with and without EXPOSE and checking docker container inspect on it when running.
From what I gathered previously on this issue, it wasn't that simple (or it might have been confusion in the communication between the users with the device and the developers).

Also, the tests fail :)

@simskij simskij removed their request for review September 29, 2021 13:21
@simskij
Copy link
Member

simskij commented Oct 16, 2021

Given that we're unable to test this ourselves, we'll have to make due with one pair of eyes on this particular fix. Let me know if you feel it's ready for merging and I'll push it through.

@tammert
Copy link
Member Author

tammert commented Oct 18, 2021

@simskij I still want to look at what @piksel mentioned, just haven't found the time yet. I'll add you as reviewers again once I feel confident the comments have been adressed

@driesvandamme
Copy link

@tammert Do you have any update on this? I'm experiencing the same issue.

Copy link
Member

@piksel piksel left a comment

Choose a reason for hiding this comment

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

I added a suggestion¹ for what would be the least intrusive change to get this working. Just doing this I think is "safe" enough to release in the next version.

¹ It's not a "proper" suggestion though, since github doesn't allow them on deleted rows for some reason...

@@ -298,9 +301,5 @@ func (c Container) VerifyConfiguration() error {
return errorInvalidConfig
}

if len(hostConfig.PortBindings) > 0 && containerConfig.ExposedPorts == nil {
Copy link
Member

Choose a reason for hiding this comment

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

If we did this instead:

if len(hostConfig.PortBindings) > 0 && containerConfig.ExposedPorts == nil {
	containerConfig.ExposedPorts = make(map[Port]struct{})
}

it would just align the docker responses for synology and non-synology docker daemons.

@driesvandamme
Copy link

@zoispag - Could you have a look at the review? Thanks!

@driesvandamme
Copy link

@tammert - Could you have a look at this? It would be great if the Container would be able to auto-update using Portainer :)
Right now it always has to be done manually with every release because of this.

@simskij
Copy link
Member

simskij commented Jan 22, 2022

This was resolved in #1183. Closing this one

@simskij simskij closed this Jan 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants