Strange error when using kubernetes.core.k8s_cp module in role

I’m trying to use the kubernetes.core.k8s_cp module to copy a file to a pod however I’m getting a strange error. Here is my code:

 - name: Copy metricbeat index template to elasticsearch master pod
   kubernetes.core.k8s_cp:
     kubeconfig: "{{ context_file }}"
     context: "{{ aks_name }}"
     namespace: "{{ namespace }}"
     pod: "{{ prefix_type }}-elasticsearch-master-0"
     container: "{{ prefix-type}}-elasticsearch"
     local_path: /tmp/metricbeat_template.json
     remote_path: /tmp/metricbeat_template.json

and the error I’m getting:

    "msg": "The task includes an option with an undefined variable. The error was: 'type' is undefined\n\nThe error appears to be in '/home/runner/ng_roles/elasticsearch/tasks/index_templates.yml': line 13, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: Copy metricbeat index template to elasticsearch master pod\n  ^ here\n"
}
  1. not sure what is causing this error, there is no type option for this module
  2. how can my local_path file be relative to my ansible role? Currently this file is in ansible-roles/$role/files/ but I am not sure how I can reference that, all the documentation makes it seems like this file needs to be a path on the localhost

Is this a typo in your code or just in your post? I presume you meant prefix_type, since dashes/hyphens are illegal characters in ansible’s variable names. If this is in your code, then I would try fixing that first.

It is, I actually just found it. The copy is now working but I’m still wondering how I can have local_path refer to a file in the ansible role?

edit, this works:

local_path: "{{ role_path }}/files/metricbeat_template.json"

Place the metricbeat_template.json file, if it is a static file, in roles/my_role/files/ or if it is a jinja2 template, in roles/my_role/templates. If it’s a jinja2 template, I would also append .j2 to the filename as a rule of thumb.

Then in your task, just reference the filename in your source parameter. Ansible will search valid locations for implicit paths, starting with the role’s files/templates (in this case, since Ansible will know it’s running a task in a role and which role to look for the file).

For e.g. since k8s_cp doesn’t support jinja2 templates (unless you use the lookup plugin to render it in the content: parameter instead of local_path:)

- name: Copy metricbeat index template to elasticsearch master pod
   kubernetes.core.k8s_cp:
     kubeconfig: "{{ context_file }}"
     context: "{{ aks_name }}"
     namespace: "{{ namespace }}"
     pod: "{{ prefix_type }}-elasticsearch-master-0"
     container: "{{ prefix_type }}-elasticsearch"
     local_path: metricbeat_template.json # will find it in ./files/
     remote_path: /tmp/ # will reuse the same filename in local_path to save under this directory

Edit: Using a jinja2 template:

- name: Copy metricbeat index template to elasticsearch master pod
   kubernetes.core.k8s_cp:
     kubeconfig: "{{ context_file }}"
     context: "{{ aks_name }}"
     namespace: "{{ namespace }}"
     pod: "{{ prefix_type }}-elasticsearch-master-0"
     container: "{{ prefix_type }}-elasticsearch"
     content: "{{ lookup('template', 'metricbeat_template.json.j2') }}" # will find it in ./templates/
     remote_path: /tmp/metricbeat_template.json # need to fully qualify the path since we're saving raw content to the destination instead of copying a source file

I did actually try that and it wasn’t find it but it is working using {{ role_path }}

this is odd though, it looks like the file is getting copied however it’s not complete

from the pod where it was copied to by ansible:

wc -l /tmp/metricbeat_template.json
34662 /tmp/metricbeat_template.json

and from the ansible role:

wc -l ../files/metricbeat_template.json
35766 ../files/metricbeat_template.json

and I get errors when trying to apply the json file because it’s incomplete. any idea why that might be?

I’m going to make some recommendations based on some observations so far:

/home/runner/ng_roles/elasticsearch/tasks/index_templates.yml

Your elasticsearch role doesn’t appear to be in a proper roles location. Your working directory (wherever your playbook lives) should have a roles directory (unless you want to “install” elasticsearch in /home/runner/.ansible/roles, /usr/share/ansible/roles or /etc/ansible/roles), and elasticsearch should be immediately under roles.

roles/elasticsearch/tasks/index_templates.yml should be able to find metricbeat_template.json implicitly as roles/elasticsearch/files/metricbeat_template.json

Then when your playbook references the role, nothing should need to fully qualify the role path.


As for your copy file size mismatch, it might be helpful if we can see the error output from the task. It’s such a small file that I’m not sure what the issue would be, but it could be something as simple as not enough storage space (ephemeral or otherwise) to copy the entire file.

there was no error from the copy, it ran fine. I removed the file from the pod and it’s now working as expected, the file gets copied in it’s entirety. I’ve re-ran the task and it’s getting copied fully each time so I can’t explain why that happened but it seems to be a one off issue. Thanks for your help!

1 Like

I’ve now hit this issue a second time where the file is not being copied in it’s entirety. I’m thinking I should maybe file a bug on this. There is no error from the task that copies the file:

TASK [elasticsearch : Copy metricbeat index template to elasticsearch master pod] ***
task path: /home/runner/ng_roles/elasticsearch/tasks/index_templates.yml:13
Wednesday 28 August 2024  19:41:26 +0000 (0:00:02.427)       0:05:27.960 ******
Wednesday 28 August 2024  19:41:26 +0000 (0:00:02.427)       0:05:27.960 ******
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: 1000
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /tmp/.ansible-${USER}/tmp `"&& mkdir "` echo /tmp/.ansible-${USER}/tmp/ansible-tmp-1724874086.7639666-1703-143317466246296 `" && echo ansible-tmp-1724874086.7639666-1703-143317466246296="` echo /tmp/.ansible-${USER}/tmp/ansible-tmp-1724874086.7639666-1703-143317466246296 `" ) && sleep 0'
Using module file /usr/share/ansible/collections/ansible_collections/kubernetes/core/plugins/modules/k8s_cp.py
<127.0.0.1> PUT /home/runner/.ansible/tmp/ansible-local-29e7gjbyyu/tmplomribu2 TO /tmp/.ansible-/tmp/ansible-tmp-1724874086.7639666-1703-143317466246296/AnsiballZ_k8s_cp.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /tmp/.ansible-/tmp/ansible-tmp-1724874086.7639666-1703-143317466246296/ /tmp/.ansible-/tmp/ansible-tmp-1724874086.7639666-1703-143317466246296/AnsiballZ_k8s_cp.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '/usr/bin/python3 /tmp/.ansible-/tmp/ansible-tmp-1724874086.7639666-1703-143317466246296/AnsiballZ_k8s_cp.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /tmp/.ansible-/tmp/ansible-tmp-1724874086.7639666-1703-143317466246296/ > /dev/null 2>&1 && sleep 0'
changed: [localhost] => {
    "changed": true,
    "invocation": {
        "module_args": {
            "api_key": null,
            "ca_cert": null,
            "client_cert": null,
            "client_key": null,
            "container": "platdev2-elasticsearch",
            "content": null,
            "context": "platdev2-obsv-eastus-aks-01",
            "host": null,
            "impersonate_groups": null,
            "impersonate_user": null,
            "kubeconfig": "/tmp/k8s_context_platdev2-obsv-eastus-aks-01/kube.conf",
            "local_path": "/home/runner/ng_roles/elasticsearch/files/metricbeat_template.json",
            "namespace": "elasticsearch",
            "no_preserve": false,
            "no_proxy": null,
            "password": null,
            "persist_config": null,
            "pod": "platdev2-elasticsearch-master-0",
            "proxy": null,
            "proxy_headers": null,
            "remote_path": "/tmp/metricbeat_template.json",
            "state": "to_pod",
            "username": null,
            "validate_certs": null
        }
    },
    "result": "/home/runner/ng_roles/elasticsearch/files/metricbeat_template.json successfully copied into remote Pod into /tmp/metricbeat_template.json"
}

but the task that runs after this fails because the file is incomplete. line counts do not match between what is on the pod and the source file:

pod:

wc -l /tmp/metricbeat_template.json
35225 /tmp/metricbeat_template.json

source file:

wc -l metricbeat_template.json
35766 metricbeat_template.json

This sounds like a bug, even if there’s some quirky behavior resulting from your environment specifically. I recommend that you submit an issue to the collection and include a link back to this topic for reference.

1 Like