From c3e1269ecb5a475d03d97fe977844582e24d0fe3 Mon Sep 17 00:00:00 2001 From: Matt Martz Date: Tue, 18 Sep 2018 09:05:20 -0500 Subject: [PATCH] [stable-2.6] Support transfering empty files to target host. Fixes #36725 (#45751) (cherry picked from commit b6fcbfe) Co-authored-by: Matt Martz --- changelogs/fragments/dd-put-empty-files.yaml | 7 +++++++ lib/ansible/plugins/connection/chroot.py | 6 +++++- lib/ansible/plugins/connection/docker.py | 8 ++++++-- lib/ansible/plugins/connection/jail.py | 6 +++++- lib/ansible/plugins/connection/kubectl.py | 8 ++++++-- lib/ansible/plugins/connection/libvirt_lxc.py | 6 +++++- lib/ansible/plugins/connection/zone.py | 6 +++++- 7 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 changelogs/fragments/dd-put-empty-files.yaml diff --git a/changelogs/fragments/dd-put-empty-files.yaml b/changelogs/fragments/dd-put-empty-files.yaml new file mode 100644 index 00000000000..eaa4406be2c --- /dev/null +++ b/changelogs/fragments/dd-put-empty-files.yaml @@ -0,0 +1,7 @@ +bugfixes: +- docker connection - Support empty files with copying to target (https://github.com/ansible/ansible/issues/36725) +- chroot connection - Support empty files with copying to target (https://github.com/ansible/ansible/issues/36725) +- jail connection - Support empty files with copying to target (https://github.com/ansible/ansible/issues/36725) +- kubectl connection - Support empty files with copying to target (https://github.com/ansible/ansible/issues/36725) +- libvirt_lxc connection - Support empty files with copying to target (https://github.com/ansible/ansible/issues/36725) +- zone connection - Support empty files with copying to target (https://github.com/ansible/ansible/issues/36725) diff --git a/lib/ansible/plugins/connection/chroot.py b/lib/ansible/plugins/connection/chroot.py index abf0d178a33..faaf6910408 100644 --- a/lib/ansible/plugins/connection/chroot.py +++ b/lib/ansible/plugins/connection/chroot.py @@ -148,8 +148,12 @@ class Connection(ConnectionBase): out_path = shlex_quote(self._prefix_login_path(out_path)) try: with open(to_bytes(in_path, errors='surrogate_or_strict'), 'rb') as in_file: + if not os.fstat(in_file.fileno()).st_size: + count = ' count=0' + else: + count = '' try: - p = self._buffered_exec_command('dd of=%s bs=%s' % (out_path, BUFSIZE), stdin=in_file) + p = self._buffered_exec_command('dd of=%s bs=%s%s' % (out_path, BUFSIZE, count), stdin=in_file) except OSError: raise AnsibleError("chroot connection requires dd command in the chroot") try: diff --git a/lib/ansible/plugins/connection/docker.py b/lib/ansible/plugins/connection/docker.py index 706f735e0b2..76859a71830 100644 --- a/lib/ansible/plugins/connection/docker.py +++ b/lib/ansible/plugins/connection/docker.py @@ -246,9 +246,13 @@ class Connection(ConnectionBase): # running containers, so we use docker exec to implement this # Although docker version 1.8 and later provide support, the # owner and group of the files are always set to root - args = self._build_exec_cmd([self._play_context.executable, "-c", "dd of=%s bs=%s" % (out_path, BUFSIZE)]) - args = [to_bytes(i, errors='surrogate_or_strict') for i in args] with open(to_bytes(in_path, errors='surrogate_or_strict'), 'rb') as in_file: + if not os.fstat(in_file.fileno()).st_size: + count = ' count=0' + else: + count = '' + args = self._build_exec_cmd([self._play_context.executable, "-c", "dd of=%s bs=%s%s" % (out_path, BUFSIZE, count)]) + args = [to_bytes(i, errors='surrogate_or_strict') for i in args] try: p = subprocess.Popen(args, stdin=in_file, stdout=subprocess.PIPE, stderr=subprocess.PIPE) diff --git a/lib/ansible/plugins/connection/jail.py b/lib/ansible/plugins/connection/jail.py index 6d1a051cc3a..8d9018ae931 100644 --- a/lib/ansible/plugins/connection/jail.py +++ b/lib/ansible/plugins/connection/jail.py @@ -158,8 +158,12 @@ class Connection(ConnectionBase): out_path = shlex_quote(self._prefix_login_path(out_path)) try: with open(to_bytes(in_path, errors='surrogate_or_strict'), 'rb') as in_file: + if not os.fstat(in_file.fileno()).st_size: + count = ' count=0' + else: + count = '' try: - p = self._buffered_exec_command('dd of=%s bs=%s' % (out_path, BUFSIZE), stdin=in_file) + p = self._buffered_exec_command('dd of=%s bs=%s%s' % (out_path, BUFSIZE, count), stdin=in_file) except OSError: raise AnsibleError("jail connection requires dd command in the jail") try: diff --git a/lib/ansible/plugins/connection/kubectl.py b/lib/ansible/plugins/connection/kubectl.py index ed42638028e..063d38d4374 100644 --- a/lib/ansible/plugins/connection/kubectl.py +++ b/lib/ansible/plugins/connection/kubectl.py @@ -300,9 +300,13 @@ class Connection(ConnectionBase): out_path = shlex_quote(out_path) # kubectl doesn't have native support for copying files into # running containers, so we use kubectl exec to implement this - args = self._build_exec_cmd([self._play_context.executable, "-c", "dd of=%s bs=%s" % (out_path, BUFSIZE)]) - args = [to_bytes(i, errors='surrogate_or_strict') for i in args] with open(to_bytes(in_path, errors='surrogate_or_strict'), 'rb') as in_file: + if not os.fstat(in_file.fileno()).st_size: + count = ' count=0' + else: + count = '' + args = self._build_exec_cmd([self._play_context.executable, "-c", "dd of=%s bs=%s%s" % (out_path, BUFSIZE, count)]) + args = [to_bytes(i, errors='surrogate_or_strict') for i in args] try: p = subprocess.Popen(args, stdin=in_file, stdout=subprocess.PIPE, stderr=subprocess.PIPE) diff --git a/lib/ansible/plugins/connection/libvirt_lxc.py b/lib/ansible/plugins/connection/libvirt_lxc.py index c731e71ad1c..10057b9cec8 100644 --- a/lib/ansible/plugins/connection/libvirt_lxc.py +++ b/lib/ansible/plugins/connection/libvirt_lxc.py @@ -138,8 +138,12 @@ class Connection(ConnectionBase): out_path = shlex_quote(self._prefix_login_path(out_path)) try: with open(to_bytes(in_path, errors='surrogate_or_strict'), 'rb') as in_file: + if not os.fstat(in_file.fileno()).st_size: + count = ' count=0' + else: + count = '' try: - p = self._buffered_exec_command('dd of=%s bs=%s' % (out_path, BUFSIZE), stdin=in_file) + p = self._buffered_exec_command('dd of=%s bs=%s%s' % (out_path, BUFSIZE, count), stdin=in_file) except OSError: raise AnsibleError("chroot connection requires dd command in the chroot") try: diff --git a/lib/ansible/plugins/connection/zone.py b/lib/ansible/plugins/connection/zone.py index f05d7530907..15ed4417a98 100644 --- a/lib/ansible/plugins/connection/zone.py +++ b/lib/ansible/plugins/connection/zone.py @@ -157,8 +157,12 @@ class Connection(ConnectionBase): out_path = shlex_quote(self._prefix_login_path(out_path)) try: with open(in_path, 'rb') as in_file: + if not os.fstat(in_file.fileno()).st_size: + count = ' count=0' + else: + count = '' try: - p = self._buffered_exec_command('dd of=%s bs=%s' % (out_path, BUFSIZE), stdin=in_file) + p = self._buffered_exec_command('dd of=%s bs=%s%s' % (out_path, BUFSIZE, count), stdin=in_file) except OSError: raise AnsibleError("jail connection requires dd command in the jail") try: