Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
DNF: fix logging, now it will work from Ansible
The Ansible dnf module uses the python dnf bindings.  In contexts like
these, stdout/stderr is owned by the host app (Ansible).  dnf should not
mess with stdout/stderr, unless the host app asks it to log there.

Specifically, it was breaking the JSON output of the Ansible module.
This was only noticeable when the etckeeper message began with a "["
character.  Ansible has a mechanism to try and skip header messages like
login banners.  However, "[" is a valid character to start a JSON document.

https://unix.stackexchange.com/questions/511210/ansible-dnf-module-module-failure/

This requires decoding the etckeeper messages into unicode.  For gory
details, see the code comment.

Also enable unicode string literals.  This reduces differences between py2
and py3 semantics; it is universal inside the dnf code.

Also when I tested the failure case, I noticed the exit code was not
printed correctly.  Fix it.
  • Loading branch information
sourcejedi committed Apr 19, 2019
1 parent c88551e commit afbdce2
Showing 1 changed file with 53 additions and 9 deletions.
62 changes: 53 additions & 9 deletions etckeeper-dnf/etckeeper.py
Expand Up @@ -7,30 +7,74 @@
# Distutils code below was copied from etckeeper-bzr distributed with v1.15
#

from __future__ import unicode_literals
from dnfpluginscore import logger

import os
import subprocess
import locale
import dnf


class Etckeeper(dnf.Plugin):

name = 'etckeeper'

def _out(self, msg):
def _debug(self, msg):
logger.debug('Etckeeper plugin: %s', msg)

def _log_pipe(self, pipe):
# etckeeper & git messages should be encoded using the default locale
# (or us-ascii, which is a strict subset).
#
# Normally py2 breaks if you print arbitrary unicode when stdout is
# not a tty (UnicodeEncodeError). However the dnf cli has a
# workaround; it will survive regardless of what we do.
#
# Then we have logging.FileHandler. In py3 it will use
# locale.getpreferredencoding(False) by default. This should match
# the default locale, unless we are on py < 3.2, AND the program
# forgot to call setlocale(LC_ALL, ""). dnf already calls
# setlocale(LC_ALL, ""), so it will be nice and consistent.
# In fact it is the dnf *library* that calls setlocale, this is not
# really recommended, but it makes me pretty confident here.
#
# errors='replace' means that decode errors give us '\ufffd', which
# causes UnicodeEncodeError in some character encodings. Let us
# simulate a round-trip through errors='replace', by replacing them
# with a question mark.
#
# The story for py2 is more complex. In libdnf 2.6.3, the logfile
# is equivalent to hardcoding a utf8 encoding. That is survivable
# (and if it changes to match py3, it will also be fine).
#
encoding = locale.getpreferredencoding(False)
for line in pipe:
line = line.decode(encoding, 'replace')
line.replace('\ufffd', '?')
line = line.rstrip('\n')
logger.info('%s', line)

def resolved(self):
self._out('pre transaction commit')
command = '%s %s' % ('etckeeper', " pre-install")
ret = os.system(command)
self._debug('pre transaction commit')
proc = subprocess.Popen(("etckeeper", "pre-install"),
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
close_fds=True)
self._log_pipe(proc.stdout)
ret = proc.wait()
if ret != 0:
raise dnf.exceptions.Error('etckeeper returned %d' % (ret >> 8))
raise dnf.exceptions.Error('etckeeper returned %d' % ret)

def transaction(self):
self._out('post transaction commit')
command = '%s %s > /dev/null' % ('etckeeper', "post-install")
os.system(command)
self._debug('post transaction commit')
proc = subprocess.Popen(("etckeeper", "post-install"),
stdout=None,
stderr=subprocess.PIPE,
close_fds=True)
self._log_pipe(proc.stderr)
ret = proc.wait()
if ret != 0:
logger.err('etckeeper returned %d' % ret)

if __name__ == "__main__":
from distutils.core import setup
Expand Down

1 comment on commit afbdce2

@webknjaz
Copy link

Choose a reason for hiding this comment

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

Please sign in to comment.