Fix failed mounts in podman connector and handle errors (#57741)

Like it's described in issue #57740 ansible podman fails to run
because of failed mount of rootless container.
This commit is contained in:
Sergey 2019-06-15 14:35:55 +03:00 committed by ansibot
parent 0d2ffdd5a6
commit 7910361b52
2 changed files with 39 additions and 16 deletions

View file

@ -0,0 +1,2 @@
bugfixes:
- ansible-podman connection plugin - Fix case when mount of podman container fails and files can't be copied to/from container. Also add error handling in case of failed podman commands. (https://github.com/ansible/ansible/issues/57740)

View file

@ -14,6 +14,7 @@ import shlex
import shutil
import subprocess
from ansible.errors import AnsibleError
from ansible.module_utils._text import to_bytes, to_native
from ansible.plugins.connection import ConnectionBase, ensure_connect
from ansible.utils.display import Display
@ -68,7 +69,7 @@ class Connection(ConnectionBase):
self._mount_point = None
self.user = self._play_context.remote_user
def _podman(self, cmd, cmd_args=None, in_data=None):
def _podman(self, cmd, cmd_args=None, in_data=None, use_container_id=True):
"""
run podman executable
@ -77,7 +78,9 @@ class Connection(ConnectionBase):
:param in_data: data passed to podman's stdin
:return: return code, stdout, stderr
"""
local_cmd = ['podman', cmd, self._container_id]
local_cmd = ['podman', cmd]
if use_container_id:
local_cmd.append(self._container_id)
if cmd_args:
local_cmd += cmd_args
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
@ -87,6 +90,9 @@ class Connection(ConnectionBase):
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate(input=in_data)
display.vvvvv("STDOUT %s" % stdout)
display.vvvvv("STDERR %s" % stderr)
display.vvvvv("RC CODE %s" % p.returncode)
stdout = to_bytes(stdout, errors='surrogate_or_strict')
stderr = to_bytes(stderr, errors='surrogate_or_strict')
return p.returncode, stdout, stderr
@ -98,8 +104,11 @@ class Connection(ConnectionBase):
"""
super(Connection, self)._connect()
rc, self._mount_point, stderr = self._podman("mount")
self._mount_point = self._mount_point.strip()
display.vvvvv("MOUNTPOINT %s RC %s STDERR %r" % (self._mount_point, rc, stderr))
if rc != 0:
display.v("Failed to mount container %s: %s" % (self._container_id, stderr.strip()))
else:
self._mount_point = self._mount_point.strip()
display.vvvvv("MOUNTPOINT %s RC %s STDERR %r" % (self._mount_point, rc, stderr))
self._connected = True
@ensure_connect
@ -121,23 +130,35 @@ class Connection(ConnectionBase):
""" Place a local file located in 'in_path' inside container at 'out_path' """
super(Connection, self).put_file(in_path, out_path)
display.vvv("PUT %s TO %s" % (in_path, out_path), host=self._container_id)
real_out_path = self._mount_point + to_bytes(out_path, errors='surrogate_or_strict')
shutil.copyfile(
to_bytes(in_path, errors='surrogate_or_strict'),
to_bytes(real_out_path, errors='surrogate_or_strict')
)
if not self._mount_point:
rc, stdout, stderr = self._podman(
"cp", [in_path, self._container_id + ":" + out_path], use_container_id=False)
if rc != 0:
raise AnsibleError("Failed to copy file from %s to %s in container %s\n%s" % (
in_path, out_path, self._container_id, stderr))
else:
real_out_path = self._mount_point + to_bytes(out_path, errors='surrogate_or_strict')
shutil.copyfile(
to_bytes(in_path, errors='surrogate_or_strict'),
to_bytes(real_out_path, errors='surrogate_or_strict')
)
def fetch_file(self, in_path, out_path):
""" obtain file specified via 'in_path' from the container and place it at 'out_path' """
super(Connection, self).fetch_file(in_path, out_path)
display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self._container_id)
real_in_path = self._mount_point + to_bytes(in_path, errors='surrogate_or_strict')
shutil.copyfile(
to_bytes(real_in_path, errors='surrogate_or_strict'),
to_bytes(out_path, errors='surrogate_or_strict')
)
if not self._mount_point:
rc, stdout, stderr = self._podman(
"cp", [self._container_id + ":" + in_path, out_path], use_container_id=False)
if rc != 0:
raise AnsibleError("Failed to fetch file from %s to %s from container %s\n%s" % (
in_path, out_path, self._container_id, stderr))
else:
real_in_path = self._mount_point + to_bytes(in_path, errors='surrogate_or_strict')
shutil.copyfile(
to_bytes(real_in_path, errors='surrogate_or_strict'),
to_bytes(out_path, errors='surrogate_or_strict')
)
def close(self):
""" unmount container's filesystem """