Repository: ansible/ansible

Issue:
Kernel initramfs failed to build - module completed successfully
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Feature Request


##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
module: yum

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
```
ansible 2.3.2.0
  config file = /ifs/ansible.cfg
  configured module search path = [u'/opt/ansible/ansible_boot/.virtenv/ifs/lib/python2.7/site-packages/ansible/modules', u'/ifs/library']
  python version = 2.7.5 (default, Oct 11 2015, 17:47:16) [GCC 4.8.3 20140911 (Red Hat 4.8.3-9)]
```

##### CONFIGURATION
<!---
If using Ansible 2.4 or above, paste the results of "ansible-config dump --only-changed"

Otherwise, mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).

-->

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say "N/A" for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
-->
RHEL7 & RHEL7
##### SUMMARY
<!--- Explain the problem briefly -->

When upgrading the packages, even if yum/dracut can't build the kernel initramfs due to too not enough space in `/boot`, the command completes successfully. This is revealed on reboot, as the kernel panics because no initramfs was built.

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->

As long as the `/boot` partition is too small to build a new kernel initramfs for the newly installed kernel, yum will show dracut failing, ansible will not fail the task.

<!--- Paste example playbooks or commands between quotes below -->
```yaml
- hosts: all
  tasks:
        
    - name: (pre_event) Free space in /boot partition is greater than 40MB
      shell: df -P /boot | grep -e "^/dev" | tr -s ' ' | cut -d ' ' -f 4
      register: boot_partition_space
      # 40MB
      failed_when: boot_partition_space.stdout|int >= 40000

    # Kernel has to be an update - else name=kernel
    - name: (pre_event) Update all packages on the system
      yum:
        name: '*'
        state: latest
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->

The second task should fail when dracut fails to build the kernel initramfs

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

After the following script runs, and a reboot is issued, the server cannot boot up, as it always encounters a kernel panic.

<!--- Paste verbatim command output between quotes below -->
Stdout:
```
[...]
  Cleanup    : ncurses-base-5.9-13.20130511.el7.noarch                1012/1013
  Cleanup    : libgcc-4.8.5-11.el7.x86_64                                          1013/1013
2661 blocks

gzip: stdout: No space left on device
dracut: creation of /boot/initramfs-3.10.0-693.2.2.el7.x86_64.img failed
mkinitrd failed
warning: %posttrans(kernel-3.10.0-693.2.2.el7.x86_64) scriptlet failed, exit status 1
Uploading Package Profile
  Verifying  : zlib-1.2.7-17.el7.i686                                                1/1013
  Verifying  : yum-rhn-plugin-2.0.1-9.el7.noarch                         2/1013
[...]
```

From our custom logging callback plugin:
```
  "changed": true,
  "msg": "Warning: RPMDB altered outside of yum.\n** Found 1 pre-existing rpmdb problem(s), 'yum check' output follows:\nkatello-ca-consumer-rhelsatsy01exdu.ent.oclc.org-1.0-12.noarch is a duplicate with katello-ca-consumer-rhelsatsy01exdu.ent.oclc.org-1.0-7.noarch\nNon-fatal POSTTRANS scriptlet failure in rpm package kernel-3.10.0-693.2.2.el7.x86_64\n",
  "rc": 0,
```

So even though the return code is 0 for the yum command, - I would appreciate if the yum module would be able to catch this.


Discussion:
cc @akasurde @berenddeschouwer @mkrizek @verm666
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
@infrascripting Thanks for reporting this issue.

yum module depends upon `yum` command and its return code. In above scenario, `yum` command returns 0 as `posttrans` script failure is non-fatal and considered as warning, so yum module returns 0.

I am not sure how to handle this kind of scenario.  Any ideas or suggestions, much appreciated. 
cc @kustodian
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
It looks like the only thing we could do is search for `No space left on device` in the Yum output and if we find it, return an error about space. 
I'm not sure if it's stdout or stderr.

Resolving patch:
diff --git a/lib/ansible/modules/packaging/os/yum.py b/lib/ansible/modules/packaging/os/yum.py
--- a/lib/ansible/modules/packaging/os/yum.py
+++ b/lib/ansible/modules/packaging/os/yum.py
@@ -830,6 +830,16 @@ def exec_install(module, items, action, pkgs, res, yum_basecmd):
         res['changed'] = False
         module.fail_json(**res)
 
+    # Fail if yum prints 'No space left on device' because that means some
+    # packages failed executing their post install scripts because of lack of
+    # free space (e.g. kernel package couldn't generate initramfs). Note that
+    # yum can still exit with rc=0 even if some post scripts didn't execute
+    # correctly.
+    if 'No space left on device' in (out or err):
+        res['changed'] = False
+        res['msg'] = 'No space left on device'
+        module.fail_json(**res)
+
     # FIXME - if we did an install - go and check the rpmdb to see if it actually installed
     # look for each pkg in rpmdb
     # look for each pkg via obsoletes


Test patch: