guettli
guettli

Reputation: 27816

Perfect Wrapper (in Python)

I run a configuration management tool which calls /usr/bin/dpkg, but does not show the stdout/stderr.

Something goes wrong and I want to debug the root of the problem.

I want to see all calls to dpkg and stdout/stderr.

I moved the original /usr/bin/dpkg to /usr/bin/dpkg-orig and wrote a wrapper:

#!/usr/bin/env python
import os
import sys
import datetime
import subx
import psutil
cmd=list(sys.argv)
cmd[0]='dpkg-orig'

def parents(pid=None):
    if pid==1:
        return '\n'
    if pid is None:
        pid = os.getpid()
    process = psutil.Process(pid)
    lines = [parents(process.ppid())]
    lines.append('Parent: %s' % ' '.join(process.cmdline()))
    return '\n'.join(lines)

result = subx.call(cmd, assert_zero_exit_status=False)
with open('/var/tmp/dpkg-calls.log', 'ab') as fd:
    fd.write('----------- %s\n' % (datetime.datetime.now()))
    fd.write('%s\n' % parents())
    fd.write('stdout:\n%s\n\n' % result.stdout)
    sys.stdout.write(result.stdout)
    fd.write('stderr:\n%s\n' % result.stderr)
    fd.write('ret: %s\n' % result.ret)
    sys.stderr.write(result.stderr)
sys.exit(result.ret)

Now I run the configuration management tool again and searched for non zero "ret:" lines.

The output:

Parent: /usr/bin/apt-get -q -y -o DPkg::Options::=--force-confold -o DPkg::Options::=--force-confdef install openssl-foo-bar-aptguettler.cert
Parent: python /usr/bin/dpkg --force-confold --force-confdef --status-fd 67 --no-triggers --unpack --auto-deconfigure /var/cache/apt/archives/openssl-foo-bar-aptguettler.cert_1-2_all.deb

stdout:


stderr:
dpkg: error: unable to read filedescriptor flags for <package status and progress file descriptor>: Bad file descriptor

ret: 2

This happens because my wrapper is not perfect yet.

The tool which calls dpkg wants to read the file descriptor but this does not work with my wrapper.

My goal:

Any idea how to achieve this?

Upvotes: 0

Views: 306

Answers (2)

fjarlq
fjarlq

Reputation: 2539

When wrapping dpkg, this error:

dpkg: error: unable to read filedescriptor flags for <package status and progress file descriptor>: Bad file descriptor

can happen if the wrapper uses subprocess.Popen with close_fds=True to open dpkg. In this case that's happening in subx.call.

Context: apt-get runs dpkg with the --status-fd 43 parameter. This is the "package status and progress file descriptor" that apt-get uses to receive certain details from dpkg. Therefore when wrapping dpkg using Python's subprocess.Popen it helps to pass close_fds=False.

Upvotes: 0

guettli
guettli

Reputation: 27816

I wrote a simple python script which solves this:

https://github.com/guettli/wrap_and_log_calls

Wrapper to log all calls to a linux command

particular use case: My configuration management tool calls /usr/bin/dpkg. An error occurs, but unfortunately my configuration management tool does not show me the whole stdout/stderr. I have no clue what's wrong.

General use case: Wrap a linux command like /usr/bin/dpkg and write out all calls to this.

Upvotes: 2

Related Questions