How does the following Ansible play work:
- name: Generate join command
command: kubeadm token create --print-join-command
register: join_command
- name: Copy join command to local file
local_action: copy content="{{ join_command.stdout_lines[0] }}" dest="./join-command"
So as I understand, local_action is the same as delegate_to
but, copy content= did not make any sense. Isn't the actual command like "cp" need to be specified?
Take this example:
local_action: command ping -c 1 {{ inventory_hostname }}
Can we use something like this:
local_action: command cp content="{{ join_command.stdout_lines[0] }}" dest="./join-command"
So as I understand, local_action is the same as delegate_to ...
local_action is similar to delegate_to: localhost, but because local_action requires you to change the syntax of tasks, it's better to always use delegate_to. That is, while for a standard task, you might write:
- name: copy a file
copy:
src: myfile
dest: /path/to/myfile
And for a delegated task, you would use exactly the same syntax with the addition of the delegate_to line:
- name: copy a file
delegate_to: localhost
copy:
src: myfile
dest: /path/to/myfile
When using local_action you have to change the syntax of the task:
- name: copy a file
local_action:
module: copy
src: myfile
dest: /path/to/myfile
copy content= did not make any sense. Isn't the actual command like "cp" need to be specified?
No, copy is the name of an ansible module. You can see some examples of above, or just take a look at the documentation.
so looking at an example: local_action: command ping -c 1 {{ inventory_hostname }} Can we say:
local_action: command cp content="{{ join_command.stdout_lines[0] }}" dest="./join-command"
You should use delegate_to, and you should write it like this:
- delegate_to: localhost
copy:
content: "{{ join_command.stdout_lines[0] }}"
dest: ./join-command
Or if you actually want to run the cp command instead of the copy module, you would write something like:
- delegate_to: localhost
command: cp some_file another_file
That is simply running the standard cp command, which knows nothing about content= or dest=.
Hard to say what's the path to dest="./join-command". The full path works as expected.
For example:
dest="{{ playbook_dir }}/join-command"
Related
I'm trying to figure out how one would copy or write the contents of a slurped variable to a remote (preferable) file. If this is not possible, what's the cleanest way to do it in steps?
I have something like this:
- name: Load r user public key
slurp:
src: *path*
register: slurped_r_key
- name: Decode r key
set_fact:
r_content: "{{ slurped_r_key.content | b64decode }}"
I want to get the contents of {{ r_content }} into a file in the remote machines that are part of an inventory group. If I cannot do that directly, what's the best way? Should I copy the contents to a local file and then scp the file over to the remote machines?
Thanks in advance!
To copy the variable to a file you can try as below:
- name: copy
copy:
content: "{{r_content}}"
dest: /tmp/testing
I am trying to make a playbook that loops over the number of files in a directory and then use those files in another playbook.
My playbook as it is now:
---
- name: Run playbooks for Raji's testing
register: scripts
roles:
- prepare_edge.yml
- prepare_iq.yml
- scriptor.yml
with_fileglob: ~/ansible/test_scripts/*
~
When I run this it doesn't work, I've tried "register: scripts" to make a variable to reference inside scriptor.yml but again the playbook fails. Any advice or help you can provide would be much appreciated.
Thanks!
P.S. I am super new to ansible
here is the scriptor.yml
---
- hosts: all
tasks:
- name: Create directory
command: mkdir /some/path/
- name: If file is a playbook
copy:
src: "{{ scripts }}"
dest: /some/path/
when: "{{ scripts }}" == "*.yml"
- name: if file is a script
shell: . ${{ scripts }}
when: "{{ scripts }}" == "*.sh"
P.S.S prepare_edge.yml and prepare_iq.yml don't reference anything and just need to be called in the loop before scriptor.yml
here is the error:
ERROR! 'register' is not a valid attribute for a Play
The error appears to have been in '/Users/JGrow33/ansible/raji_magic_playbook.yml': line 3, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- name: Run playbooks for Raji's testing
^ here
There error message you're getting is telling you that you can't run register in a Playbook.
You can accomplish what you're looking for by doing something like the following in your scriptor.yml file:
- hosts: all
tasks:
- name: Create directory
command: mkdir /some/path/
- name: If file is a playbook
copy:
src: "{{ item }}"
dest: /some/path/
with_fileglob: ~/ansible/test_scripts/*.yml
- name: if file is a script
shell: . ${{ item }}
with_fileglob: copy:
src: "{{ item }}"
dest: /some/path/
with_fileglobe: ~/ansible/test_scripts/*.sh
References
How can Ansible "register" in a variable the result of including a playbook?
How would you resolve this small script in ansible playbook ?
Files to copy are named [ServerName].[extension]
The destination server is ServeName
for file in $(ls /var/tmp)
do
ServerName=$(echo $file | awk -F. 'NF{NF--};1'
scp /var/tmp/$file $ServerName:/var/tmp/
scp /var/tmp/pkg.rpm $ServerName:/var/tmp/
ssh $ServerName "cd /var/tmp; yum -y localinstall pkg.rpm "
done
Thanks for your help
The idea would be to have something like this (but working, of course)
- name: main loop
copy:
src: "{{ item }}"
dest: "/var/tmp/myfile.json"
- name: Install package
yum:
name: "packageToInstall"
state: present
delegate_to: "{{ item.split('/')[-1][:-5] }}"
with_fileglob:
- "/var/temp/*json"
If you were to write this in yaml, you should use ansible_hostname, ansible already has several informations about the host via setup.
- name: copying files
copy:
src: /mine/file.ext
dest: /etc/{{ ansible_hostname }}.ext
More about copy in module description.
All facts gather during setup are available here.
In Ansible, I have written an Yaml playbook that takes list of host name and the executes command for each host. I have registered a variable for these task and at the end of executing a task I append output of each command to a single file.
But every time I try to append to my output file, only the last record is getting persisted.
---
- hosts: list_of_hosts
become_user: some user
vars:
output: []
tasks:
- name: some name
command: some command
register: output
failed_when: "'FAILED' in output"
- debug: msg="{{output | to_nice_json}}"
- local_action: copy content='{{output | to_nice_json}}' dest="/path/to/my/local/file"
I even tried to append using lineinfile using insertafter parameter yet was not successful.
Anything that I am missing?
You can try something like this:
- name: dummy
hosts: myhosts
serial: 1
tasks:
- name: create file
file:
dest: /tmp/foo
state: touch
delegate_to: localhost
- name: run cmd
shell: echo "{{ inventory_hostname }}"
register: op
- name: append
lineinfile:
dest: /tmp/foo
line: "{{ op }}"
insertafter: EOF
delegate_to: localhost
I have used serial: 1 as I am not sure if lineinfile tasks running in parallel will garble the output file.
Ansible doc recommend use copy:
- name: get jstack
shell: "/usr/lib/jvm/java/bin/jstack -l {{PID_JAVA_APP}}"
args:
executable: /bin/bash
register: jstackOut
- name: write jstack
copy:
content: "{{jstackOut.stdout}}"
dest: "tmp/jstack.txt"
If you want write local file, add this:
delegate_to: localhost
Why to complicate things ?
I did this like that and it worked:
ansible-playbook your_playbook.yml >> /file/you/want/to/redirect/output.txt
you can also try some parsing with grep or some other stuff with tee -a.
I'm using the ec2 module with ansible-playbook I want to set a variable to the contents of a file. Here's how I'm currently doing it.
Var with the filename
shell task to cat the file
use the result of the cat to pass to the ec2 module.
Example contents of my playbook.
vars:
amazon_linux_ami: "ami-fb8e9292"
user_data_file: "base-ami-userdata.sh"
tasks:
- name: user_data_contents
shell: cat {{ user_data_file }}
register: user_data_action
- name: launch ec2-instance
local_action:
...
user_data: "{{ user_data_action.stdout }}"
I assume there's a much easier way to do this, but I couldn't find it while searching Ansible docs.
You can use lookups in Ansible in order to get the contents of a file, e.g.
user_data: "{{ lookup('file', user_data_file) }}"
Caveat: This lookup will work with local files, not remote files.
Here's a complete example from the docs:
- hosts: all
vars:
contents: "{{ lookup('file', '/etc/foo.txt') }}"
tasks:
- debug: msg="the value of foo.txt is {{ contents }}"
You can use the slurp module to fetch a file from the remote host: (Thanks to #mlissner for suggesting it)
vars:
amazon_linux_ami: "ami-fb8e9292"
user_data_file: "base-ami-userdata.sh"
tasks:
- name: Load data
slurp:
src: "{{ user_data_file }}"
register: slurped_user_data
- name: Decode data and store as fact # You can skip this if you want to use the right hand side directly...
set_fact:
user_data: "{{ slurped_user_data.content | b64decode }}"
You can use fetch module to copy files from remote hosts to local, and lookup module to read the content of fetched files.
lookup only works on localhost. If you want to retrieve variables from a variables file you made remotely use include_vars: {{ varfile }} . Contents of {{ varfile }} should be a dictionary of the form {"key":"value"}, you will find ansible gives you trouble if you include a space after the colon.