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

ansible_facts.docker_container is not populated when the container does not exit cleanly #26

Closed
choppedpork opened this issue Apr 17, 2020 · 3 comments · Fixed by #58
Closed

Comments

@choppedpork
Copy link

SUMMARY

When using the docker_container module it does not seem to be possible to fail a task in a straightforward fashion like with the command module as it only returns an exit code if it is non-zero.

ISSUE TYPE
  • Bug Report
COMPONENT NAME

docker_container module

ANSIBLE VERSION
ansible 2.9.6
  config file = /Users/x/.ansible.cfg
  configured module search path = ['/Users/x/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/Cellar/ansible/2.9.6_1/libexec/lib/python3.8/site-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 3.8.2 (default, Mar 11 2020, 00:29:50) [Clang 11.0.0 (clang-1100.0.33.17)]
CONFIGURATION
ANSIBLE_PIPELINING(/Users/x/.ansible.cfg) = True
ANSIBLE_SSH_CONTROL_PATH(/Users/x/.ansible.cfg) = ~/.ssh/mux-%%r@%%h:%%p
DEFAULT_FORKS(/Users/x/.ansible.cfg) = 20
DEFAULT_TIMEOUT(/Users/x/.ansible.cfg) = 30
HOST_KEY_CHECKING(env: ANSIBLE_HOST_KEY_CHECKING) = False
RETRY_FILES_ENABLED(/Users/x/.ansible.cfg) = False
OS / ENVIRONMENT

Tested in both macOS 10.15.4 as well as Ubuntu 18.04 (using 2.9.7-1ppa~bionic)

STEPS TO REPRODUCE
- hosts: localhost
  connection: local

  tasks:
    - name: run a command in a docker container and fail based on its exit code
      docker_container:
        name: "hello"
        image: alpine
        entrypoint: /bin/sh
        command: -c 'exit 1'
        detach: no
        state: started
      failed_when: hello.ansible_facts.docker_container.State.ExitCode not in [0, 1]
      register: hello
EXPECTED RESULTS

The expectation is for this playbook to complete successfully because 1 should be a non-failing exit code as per failed_when.

ACTUAL RESULTS

The playbook fails because ansible_facts is not populated.

[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [localhost] *****************************************************************************************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [run a command in a docker container and fail based on it's exit code] ******************************************************************************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The conditional check 'hello.ansible_facts.docker_container.State.ExitCode not in [0, 1]' failed. The error was: error while evaluating conditional (hello.ansible_facts.docker_container.State.ExitCode not in [0, 1]): 'dict object' has no attribute 'ansible_facts'"}

PLAY RECAP ***********************************************************************************************************************************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0 

When I modify my playbook to use a subsequent fail task the result is the same:

(...)
    - name: run a command in a docker container and fail based on its exit code
      docker_container:
        name: "hello"
        image: alpine
        entrypoint: /bin/sh
        command: -c 'exit 1'
        detach: no
        state: started
      failed_when: false
      register: hello
    
    - name: to fail or not to fail
      fail:
      when: hello.ansible_facts.docker_container.State.ExitCode not in [0, 1]

Result:

PLAY [localhost] *****************************************************************************************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [run a command in a docker container and fail based on its exit code] *******************************************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [to fail or not to fail] ****************************************************************************************************************************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The conditional check 'hello.ansible_facts.docker_container.State.ExitCode not in [0, 1]' failed. The error was: error while evaluating conditional (hello.ansible_facts.docker_container.State.ExitCode not in [0, 1]): 'dict object' has no attribute 'ansible_facts'\n\nThe error appears to be in '/Users/x/test/bugreport.yml': line 17, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n    - name: to fail or not to fail\n      ^ here\n"}

PLAY RECAP ***********************************************************************************************************************************************************************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

I've done a little bit more digging by debugging the variable:

ok: [localhost] => {
    "hello": {
        "changed": false,
        "failed": false,
        "failed_when_result": false,
        "msg": "",
        "status": 1
    }
}

Note that the status is set to 1. When I change my docker_container command to exit 3...

ok: [localhost] => {
    "hello": {
        "changed": false,
        "failed": false,
        "failed_when_result": false,
        "msg": "",
        "status": 3
    }
}

So... when the container fails, the status field is populated in the registered variable. However when it doesn't fail, the field is not populated:

ok: [localhost] => {
    "hello": {
        "ansible_facts": {
            "docker_container": {
                "AppArmorProfile": "",
                "Args": [
                    "-c",
                    "exit 0"
                ],
                "Config": {
                    "AttachStderr": true,
                    "AttachStdin": false,
                    "AttachStdout": true,
                    "Cmd": [
                        "-c",
                        "exit 0"
                    ],
                    "Domainname": "",
                    "Entrypoint": [
                        "/bin/sh"
                    ],
                    "Env": [
                        "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
                    ],
                    "Hostname": "743aef998384",
                    "Image": "alpine",
                    "Labels": {},
                    "OnBuild": null,
                    "OpenStdin": false,
                    "StdinOnce": false,
                    "Tty": false,
                    "User": "",
                    "Volumes": null,
                    "WorkingDir": ""
                },
                "Created": "2020-04-17T09:35:10.430897891Z",
                "Driver": "overlay2",
                "ExecIDs": null,
                "GraphDriver": {
                    "Data": {
                        "LowerDir": "/var/lib/docker/overlay2/2197e175f012c5a2af4b7aaa31b9da0f7556048868d78abd3e536bf05883142e-init/diff:/var/lib/docker/overlay2/e350e1a568c7b6a376109bc5ba621d1dfecc22f36bed0fe13076539171071733/diff",
                        "MergedDir": "/var/lib/docker/overlay2/2197e175f012c5a2af4b7aaa31b9da0f7556048868d78abd3e536bf05883142e/merged",
                        "UpperDir": "/var/lib/docker/overlay2/2197e175f012c5a2af4b7aaa31b9da0f7556048868d78abd3e536bf05883142e/diff",
                        "WorkDir": "/var/lib/docker/overlay2/2197e175f012c5a2af4b7aaa31b9da0f7556048868d78abd3e536bf05883142e/work"
                    },
                    "Name": "overlay2"
                },
                "HostConfig": {
                    "AutoRemove": false,
                    "Binds": [],
                    "BlkioDeviceReadBps": null,
                    "BlkioDeviceReadIOps": null,
                    "BlkioDeviceWriteBps": null,
                    "BlkioDeviceWriteIOps": null,
                    "BlkioWeight": 0,
                    "BlkioWeightDevice": null,
                    "CapAdd": null,
                    "CapDrop": null,
                    "Capabilities": null,
                    "Cgroup": "",
                    "CgroupParent": "",
                    "ConsoleSize": [
                        0,
                        0
                    ],
                    "ContainerIDFile": "",
                    "CpuCount": 0,
                    "CpuPercent": 0,
                    "CpuPeriod": 0,
                    "CpuQuota": 0,
                    "CpuRealtimePeriod": 0,
                    "CpuRealtimeRuntime": 0,
                    "CpuShares": 0,
                    "CpusetCpus": "",
                    "CpusetMems": "",
                    "DeviceCgroupRules": null,
                    "DeviceRequests": null,
                    "Devices": null,
                    "Dns": null,
                    "DnsOptions": null,
                    "DnsSearch": null,
                    "ExtraHosts": null,
                    "GroupAdd": null,
                    "IOMaximumBandwidth": 0,
                    "IOMaximumIOps": 0,
                    "IpcMode": "private",
                    "Isolation": "",
                    "KernelMemory": 0,
                    "KernelMemoryTCP": 0,
                    "Links": null,
                    "LogConfig": {
                        "Config": {},
                        "Type": "json-file"
                    },
                    "MaskedPaths": [
                        "/proc/asound",
                        "/proc/acpi",
                        "/proc/kcore",
                        "/proc/keys",
                        "/proc/latency_stats",
                        "/proc/timer_list",
                        "/proc/timer_stats",
                        "/proc/sched_debug",
                        "/proc/scsi",
                        "/sys/firmware"
                    ],
                    "Memory": 0,
                    "MemoryReservation": 0,
                    "MemorySwap": 0,
                    "MemorySwappiness": null,
                    "NanoCpus": 0,
                    "NetworkMode": "default",
                    "OomKillDisable": false,
                    "OomScoreAdj": 0,
                    "PidMode": "",
                    "PidsLimit": null,
                    "PortBindings": null,
                    "Privileged": false,
                    "PublishAllPorts": false,
                    "ReadonlyPaths": [
                        "/proc/bus",
                        "/proc/fs",
                        "/proc/irq",
                        "/proc/sys",
                        "/proc/sysrq-trigger"
                    ],
                    "ReadonlyRootfs": false,
                    "RestartPolicy": {
                        "MaximumRetryCount": 0,
                        "Name": ""
                    },
                    "Runtime": "runc",
                    "SecurityOpt": null,
                    "ShmSize": 67108864,
                    "UTSMode": "",
                    "Ulimits": null,
                    "UsernsMode": "",
                    "VolumeDriver": "",
                    "VolumesFrom": null
                },
                "HostnamePath": "/var/lib/docker/containers/743aef99838441d4a88f4e5799777b3b6c66d3e079f6ffebd4675949a5c76795/hostname",
                "HostsPath": "/var/lib/docker/containers/743aef99838441d4a88f4e5799777b3b6c66d3e079f6ffebd4675949a5c76795/hosts",
                "Id": "743aef99838441d4a88f4e5799777b3b6c66d3e079f6ffebd4675949a5c76795",
                "Image": "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72",
                "LogPath": "/var/lib/docker/containers/743aef99838441d4a88f4e5799777b3b6c66d3e079f6ffebd4675949a5c76795/743aef99838441d4a88f4e5799777b3b6c66d3e079f6ffebd4675949a5c76795-json.log",
                "MountLabel": "",
                "Mounts": [],
                "Name": "/hello",
                "NetworkSettings": {
                    "Bridge": "",
                    "EndpointID": "",
                    "Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "HairpinMode": false,
                    "IPAddress": "",
                    "IPPrefixLen": 0,
                    "IPv6Gateway": "",
                    "LinkLocalIPv6Address": "",
                    "LinkLocalIPv6PrefixLen": 0,
                    "MacAddress": "",
                    "Networks": {
                        "bridge": {
                            "Aliases": null,
                            "DriverOpts": null,
                            "EndpointID": "",
                            "Gateway": "",
                            "GlobalIPv6Address": "",
                            "GlobalIPv6PrefixLen": 0,
                            "IPAMConfig": null,
                            "IPAddress": "",
                            "IPPrefixLen": 0,
                            "IPv6Gateway": "",
                            "Links": null,
                            "MacAddress": "",
                            "NetworkID": "16c2c7aa1efebc99254b793f1eac259f7b90caaf6dc2797e10d694e4943fc140"
                        }
                    },
                    "Ports": {},
                    "SandboxID": "01ecfe3e889fff5002d959e6f6ffa667b78e128b9cedcda897496c10c97f9f94",
                    "SandboxKey": "/var/run/docker/netns/01ecfe3e889f",
                    "SecondaryIPAddresses": null,
                    "SecondaryIPv6Addresses": null
                },
                "Output": "",
                "Path": "/bin/sh",
                "Platform": "linux",
                "ProcessLabel": "",
                "ResolvConfPath": "/var/lib/docker/containers/743aef99838441d4a88f4e5799777b3b6c66d3e079f6ffebd4675949a5c76795/resolv.conf",
                "RestartCount": 0,
                "State": {
                    "Dead": false,
                    "Error": "",
                    "ExitCode": 0,
                    "FinishedAt": "2020-04-17T09:35:10.771690264Z",
                    "OOMKilled": false,
                    "Paused": false,
                    "Pid": 0,
                    "Restarting": false,
                    "Running": false,
                    "StartedAt": "2020-04-17T09:35:10.754999961Z",
                    "Status": "exited"
                }
            }
        },
        "changed": true,
        "container": {
            "AppArmorProfile": "",
            "Args": [
                "-c",
                "exit 0"
            ],
            "Config": {
                "AttachStderr": true,
                "AttachStdin": false,
                "AttachStdout": true,
                "Cmd": [
                    "-c",
                    "exit 0"
                ],
                "Domainname": "",
                "Entrypoint": [
                    "/bin/sh"
                ],
                "Env": [
                    "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
                ],
                "Hostname": "743aef998384",
                "Image": "alpine",
                "Labels": {},
                "OnBuild": null,
                "OpenStdin": false,
                "StdinOnce": false,
                "Tty": false,
                "User": "",
                "Volumes": null,
                "WorkingDir": ""
            },
            "Created": "2020-04-17T09:35:10.430897891Z",
            "Driver": "overlay2",
            "ExecIDs": null,
            "GraphDriver": {
                "Data": {
                    "LowerDir": "/var/lib/docker/overlay2/2197e175f012c5a2af4b7aaa31b9da0f7556048868d78abd3e536bf05883142e-init/diff:/var/lib/docker/overlay2/e350e1a568c7b6a376109bc5ba621d1dfecc22f36bed0fe13076539171071733/diff",
                    "MergedDir": "/var/lib/docker/overlay2/2197e175f012c5a2af4b7aaa31b9da0f7556048868d78abd3e536bf05883142e/merged",
                    "UpperDir": "/var/lib/docker/overlay2/2197e175f012c5a2af4b7aaa31b9da0f7556048868d78abd3e536bf05883142e/diff",
                    "WorkDir": "/var/lib/docker/overlay2/2197e175f012c5a2af4b7aaa31b9da0f7556048868d78abd3e536bf05883142e/work"
                },
                "Name": "overlay2"
            },
            "HostConfig": {
                "AutoRemove": false,
                "Binds": [],
                "BlkioDeviceReadBps": null,
                "BlkioDeviceReadIOps": null,
                "BlkioDeviceWriteBps": null,
                "BlkioDeviceWriteIOps": null,
                "BlkioWeight": 0,
                "BlkioWeightDevice": null,
                "CapAdd": null,
                "CapDrop": null,
                "Capabilities": null,
                "Cgroup": "",
                "CgroupParent": "",
                "ConsoleSize": [
                    0,
                    0
                ],
                "ContainerIDFile": "",
                "CpuCount": 0,
                "CpuPercent": 0,
                "CpuPeriod": 0,
                "CpuQuota": 0,
                "CpuRealtimePeriod": 0,
                "CpuRealtimeRuntime": 0,
                "CpuShares": 0,
                "CpusetCpus": "",
                "CpusetMems": "",
                "DeviceCgroupRules": null,
                "DeviceRequests": null,
                "Devices": null,
                "Dns": null,
                "DnsOptions": null,
                "DnsSearch": null,
                "ExtraHosts": null,
                "GroupAdd": null,
                "IOMaximumBandwidth": 0,
                "IOMaximumIOps": 0,
                "IpcMode": "private",
                "Isolation": "",
                "KernelMemory": 0,
                "KernelMemoryTCP": 0,
                "Links": null,
                "LogConfig": {
                    "Config": {},
                    "Type": "json-file"
                },
                "MaskedPaths": [
                    "/proc/asound",
                    "/proc/acpi",
                    "/proc/kcore",
                    "/proc/keys",
                    "/proc/latency_stats",
                    "/proc/timer_list",
                    "/proc/timer_stats",
                    "/proc/sched_debug",
                    "/proc/scsi",
                    "/sys/firmware"
                ],
                "Memory": 0,
                "MemoryReservation": 0,
                "MemorySwap": 0,
                "MemorySwappiness": null,
                "NanoCpus": 0,
                "NetworkMode": "default",
                "OomKillDisable": false,
                "OomScoreAdj": 0,
                "PidMode": "",
                "PidsLimit": null,
                "PortBindings": null,
                "Privileged": false,
                "PublishAllPorts": false,
                "ReadonlyPaths": [
                    "/proc/bus",
                    "/proc/fs",
                    "/proc/irq",
                    "/proc/sys",
                    "/proc/sysrq-trigger"
                ],
                "ReadonlyRootfs": false,
                "RestartPolicy": {
                    "MaximumRetryCount": 0,
                    "Name": ""
                },
                "Runtime": "runc",
                "SecurityOpt": null,
                "ShmSize": 67108864,
                "UTSMode": "",
                "Ulimits": null,
                "UsernsMode": "",
                "VolumeDriver": "",
                "VolumesFrom": null
            },
            "HostnamePath": "/var/lib/docker/containers/743aef99838441d4a88f4e5799777b3b6c66d3e079f6ffebd4675949a5c76795/hostname",
            "HostsPath": "/var/lib/docker/containers/743aef99838441d4a88f4e5799777b3b6c66d3e079f6ffebd4675949a5c76795/hosts",
            "Id": "743aef99838441d4a88f4e5799777b3b6c66d3e079f6ffebd4675949a5c76795",
            "Image": "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72",
            "LogPath": "/var/lib/docker/containers/743aef99838441d4a88f4e5799777b3b6c66d3e079f6ffebd4675949a5c76795/743aef99838441d4a88f4e5799777b3b6c66d3e079f6ffebd4675949a5c76795-json.log",
            "MountLabel": "",
            "Mounts": [],
            "Name": "/hello",
            "NetworkSettings": {
                "Bridge": "",
                "EndpointID": "",
                "Gateway": "",
                "GlobalIPv6Address": "",
                "GlobalIPv6PrefixLen": 0,
                "HairpinMode": false,
                "IPAddress": "",
                "IPPrefixLen": 0,
                "IPv6Gateway": "",
                "LinkLocalIPv6Address": "",
                "LinkLocalIPv6PrefixLen": 0,
                "MacAddress": "",
                "Networks": {
                    "bridge": {
                        "Aliases": null,
                        "DriverOpts": null,
                        "EndpointID": "",
                        "Gateway": "",
                        "GlobalIPv6Address": "",
                        "GlobalIPv6PrefixLen": 0,
                        "IPAMConfig": null,
                        "IPAddress": "",
                        "IPPrefixLen": 0,
                        "IPv6Gateway": "",
                        "Links": null,
                        "MacAddress": "",
                        "NetworkID": "16c2c7aa1efebc99254b793f1eac259f7b90caaf6dc2797e10d694e4943fc140"
                    }
                },
                "Ports": {},
                "SandboxID": "01ecfe3e889fff5002d959e6f6ffa667b78e128b9cedcda897496c10c97f9f94",
                "SandboxKey": "/var/run/docker/netns/01ecfe3e889f",
                "SecondaryIPAddresses": null,
                "SecondaryIPv6Addresses": null
            },
            "Output": "",
            "Path": "/bin/sh",
            "Platform": "linux",
            "ProcessLabel": "",
            "ResolvConfPath": "/var/lib/docker/containers/743aef99838441d4a88f4e5799777b3b6c66d3e079f6ffebd4675949a5c76795/resolv.conf",
            "RestartCount": 0,
            "State": {
                "Dead": false,
                "Error": "",
                "ExitCode": 0,
                "FinishedAt": "2020-04-17T09:35:10.771690264Z",
                "OOMKilled": false,
                "Paused": false,
                "Pid": 0,
                "Restarting": false,
                "Running": false,
                "StartedAt": "2020-04-17T09:35:10.754999961Z",
                "Status": "exited"
            }
        },
        "failed": false,
        "failed_when_result": false
    }
}

All this digging has subsequently led me to a workaround:

    - name: run a command in a docker container and fail based on its exit code
      docker_container:
        name: "hello"
        image: alpine
        entrypoint: /bin/sh
        command: -c 'exit 1'
        detach: no
        state: started
      failed_when: hello.status is defined and hello.status != 1
      register: hello

Is this expected behaviour? Shouldn't the docker_container task always return the status (also - shouldn't it be called rc like for the command module)?

Thanks!

@felixfontein
Copy link
Collaborator

The module is doing exactly what it was programmed to do: https://github.com/ansible-collections/community.general/blob/master/plugins/modules/cloud/docker/docker_container.py#L2919-L2947

I have no idea why it was implemented this way. I've never used the module to run containers that are not detached.

I agree that it would make sense that status is always returned if detached=False, and also the inspection result.

BTW: you should NOT use ansible_facts.docker_container. That has been deprecated in Ansible 2.12 and will be removed ~next year. Register the task result as result and use reslut.docker_container instead.

@felixfontein felixfontein transferred this issue from ansible-collections/community.general Nov 1, 2020
@felixfontein
Copy link
Collaborator

resolved_by_pr #58

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants