8000 Copy plugin code bug · Issue #84344 · ansible/ansible · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
Copy plugin code bug #84344
Open
Open
@spyinx

Description

@spyinx

Summary

When i read code in lib/ansible/plugins/action/copy.py, i find a bug in it:

class ActionModule(ActionBase):

    TRANSFERS_FILES = True
    
    # ...
    
    def run(self, tmp=None, task_vars=None):
        ''' handler for file transfer operations '''
        
        # ...
        
        implicit_directories = set()
        for source_full, source_rel in source_files['files']:
            # copy files over.  This happens first as directories that have
            # a file do not need to be created later

            # We only follow symlinks for files in the non-recursive case
            if source_files['directories']:
                follow = False
            else:
                follow = boolean(self._task.args.get('follow', False), strict=False)
            module_return = self._copy_file(source_full, source_rel, content, content_tempfile, dest, task_vars, follow)
            if module_return is None:
                continue

            if module_return.get('failed'):   
                result.update(module_return)
                return self._ensure_invocation(result)

            ###################bug here !!!!###################
            paths = os.path.split(source_rel)
            dir_path = ''
            for dir_component in paths:
                os.path.join(dir_path, dir_component)
                implicit_directories.add(dir_path)
            ##############################################
            if 'diff' in result and not result['diff']:
                del result['diff']
            module_executed = True
            changed = changed or module_return.get('changed', False)

            # ...

look at example code as follow:

>>> import os
>>> dir_path = ''
>>> os.path.join(dir_path, 'xxxxx')
'xxxxx'
>>> dir_path
''
>>> 

dir_path always be empty string and thus implicit_directories always be a set with one empty data!!!!

Issue Type

Bug Report

Component Name

copy

Ansible Version

$ ansible --version
ansible [core 2.17.6]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /opt/python3.12/lib/python3.12/site-packages/ansible_core-2.17.6-py3.12.egg/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /opt/python3.12/bin/ansible
  python version = 3.12.4 (main, Nov 13 2024, 10:46:13) [GCC 10.2.1 20200825 (Alibaba 10.2.1-3.8 2.32)] (/opt/python3.12/bin/python3)
  jinja version = 3.1.4
  libyaml = True

Configuration

# if using a version older than ansible-core 2.12 you should omit the '-t all'
$ ansible-config dump --only-changed -t all
CONFIG_FILE() = /etc/ansible/ansible.cfg

OS / Environment

Alibaba Cloud Linux release 3 (Soaring Falcon

Steps to Reproduce

  • create directories:
[store@spyinx ~]$ cat create_dirs.sh 
#! /bin/bash

for i in `seq 1 100`
do
    mkdir test-create-$i
    cd test-create-$i
done

touch test.txt
[store@spyinx ~]$ sh create_dirs.sh 
  • run ansible
[store@spyinx ~]$ rm -rf dest
[store@spyinx ~]$ time ansible spyinx -i hosts -m copy -a "src=/home/store/test-create-1 dest=dest"
spyinx | CHANGED => {
    "changed": true,
    "dest": "dest/",
    "src": "/home/store/test-create-1"
}

real	0m34.394s
user	0m2.923s
sys	0m1.169s
[store@spyinx ~]$ time ansible spyinx -i hosts -m copy -a "src=/home/store/test-create-1 dest=dest"    # 再次执行
spyinx | SUCCESS => {
    "changed": false,
    "dest": "dest/",
    "src": "/home/store/test-create-1"
}

real	0m36.739s
user	0m3.141s
sys	0m1.301s

because it will use file module to create all the directories, then it is slow !!!

Expected Results

i change the code:

[root@spyinx ansible]# git diff lib/ansible/plugins/action/copy.py
diff --git a/lib/ansible/plugins/action/copy.py b/lib/ansible/plugins/action/copy.py
index 2047671b47..f3abf22985 100644
--- a/lib/ansible/plugins/action/copy.py
+++ b/lib/ansible/plugins/action/copy.py
@@ -525,11 +525,13 @@ class ActionModule(ActionBase):
                 result.update(module_return)
                 return self._ensure_invocation(result)
 
-            paths = os.path.split(source_rel)
+            paths = source_rel.split(os.path.sep)
             dir_path = ''
-            for dir_component in paths:
-                os.path.join(dir_path, dir_component)
+            # skip last file name
+            for dir_component in paths[:-1]:
+                dir_path = os.path.join(dir_path, dir_component)
                 implicit_directories.add(dir_path)
+
             if 'diff' in result and not result['diff']:
                 del result['diff']
             module_executed = True

then run it again:

[store@spyinx ~]$ rm -rf dest
[store@spyinx ~]$ time ansible spyinx -i hosts -m copy -a "src=/home/store/test-create-1 dest=dest"
spyinx | CHANGED => {
    "changed": true,
    "dest": "dest/",
    "src": "/home/store/test-create-1"
}

real	0m4.098s
user	0m1.167s
sys	0m0.224s
[store@spyinx ~]$ time ansible spyinx -i hosts -m copy -a "src=/home/store/test-create-1 dest=dest"    # 再次执行
spyinx | SUCCESS => {
    "changed": false,
    "dest": "dest/",
    "src": "/home/store/test-create-1"
}

real	0m3.710s
user	0m0.993s
sys	0m0.216s

only leaf directories will be created by file module, the others have already been created when using copy module to transfer file

Actual Results

[store@spyinx ~]$ time ansible spyinx -i hosts -m copy -a "src=/home/store/test-create-1 dest=dest"
spyinx | CHANGED => {
    "changed": true,
    "dest": "dest/",
    "src": "/home/store/test-create-1"
}

real	0m34.394s
user	0m2.923s
sys	0m1.169s
[store@spyinx ~]$ time ansible spyinx -i hosts -m copy -a "src=/home/store/test-create-1 dest=dest"    # 再次执行
spyinx | SUCCESS => {
    "changed": false,
    "dest": "dest/",
    "src": "/home/store/test-create-1"
}

real	0m36.739s
user	0m3.141s
sys	0m1.301s

Code of Conduct

  • I agree to follow the Ansible Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    affects_2.17bugThis issue/PR relates to a bug.has_prThis issue has an associated PR.moduleThis issue/PR relates to a module.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0