skip to Main Content

In a shell session I have run:

 docker run --rm --net host busybox /bin/sh -c "ip route get 1 | sed -n 's/^.*src ([0-9.]*) .*$/1/p'"

The output of the command is:

10.0.2.15

But for a utility script that interfaces docker directly using python and docker-sdk I run the same command as well:

import docker
client = docker.from_env()
print(client.containers.run('busybox',["/bin/sh","-c","ip route get 1 | sed -n 's/^.*src ([0-9.]*) .*$/1/p'"],remove=True,network="host"))

But I get the following output:

b'x01n'

I tried to convert into ascii like this:

print(client.containers.run('busybox',["/bin/sh","-c","ip route get 1 | sed -n 's/^.*src ([0-9.]*) .*$/1/p'"],remove=True,network="host").decode('ascii'))

But seem not to print any printable character despite spaces. Any idea how I can retrieve the same output using python?

Edit 1

I also tried to capture the stdout:

client.containers.run('busybox',["/bin/sh","-c","ip route get 1 | sed -n 's/^.*src ([0-9.]*) .*$/1/p'"],remove=True,network="host",stdout=True)

But same result occur.

Though if I ommit the sed part seems to work fine (but having the result not filtered):

print(client.containers.run('busybox',["/bin/sh","-c","ip route get 1"],remove=True,network="host"))

Prints:

b'1.0.0.0 via 10.0.2.2 dev enp0s3  src 10.0.2.15 n'

Therefore for some reason sed part seems to break the output.

2

Answers


  1. Chosen as BEST ANSWER

    The issue is caused by unescaped 1 at sed part of the command. In order to work you must do:

    print(client.containers.run('busybox',"/bin/sh -c "ip route get 1 | sed -n 's/^.*src ([0-9.]*) .*$/\1/p'"",remove=True,network="host"))
    

    Pay attention on this string used as second argument for the functipon:

    "/bin/sh -c "ip route get 1 | sed -n 's/^.*src ([0-9.]*) .*$/\1/p'""
    #                                                   escaped this ^^
    

  2. You can avoid the escaping problem you describe in your answer by post-processing the output in Python code. This also means you don’t need a shell in your container invocation, which removes a potential level of quoting (and attendant security concerns).

    raw_output = client.containers.run('busybox', ['ip', 'route', 'get', '1'], remove=True, network='host')
    output = str(raw_output, encoding='utf-8')
    lines = output.split('n')
    for l in lines:
      words = l.split()
      try:
        src = words.index('src')
        print(words[src + 1])
      except ValueError: # 'src' not in the list
        pass
      except IndexError: # 'src' is the last word
        pass
    

    For this particular case, since you’re using the host network and then requesting network information, you’re seeing the host’s network setup. If your Docker environment is based on a virtual machine (for example, Docker Desktop) you’re seeing that VM’s network environment; this is not a portable path to find the host’s gateway address. If you’re on a native-Linux system you can often just run this command using the subprocess module without involving Docker (the decoding details are otherwise identical to what’s in this answer). Python: get default gateway for a local interface/ip address in linux has a number of other approaches that don’t require Docker.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search