Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ansible - how to concatenate files contents into a variable

How can I concatenate a contents of several files into a variable?

Here's the problem: I'm trying to set public keys for a user on a remote machine. The example from the authorized_key documentation that almost works:

- name: Set up authorized_keys for the deploy user
  authorized_key: user=deploy
                  key="{{ item }}"
  with_file:
    - public_keys/doe-jane
    - public_keys/doe-john

But in fact I need to use exclusive=yes, so after the update all non-provided public keys are removed.

If the exclusive=yes is provided then only the last public key listed remains in the .ssh/authorized_keys file (also reported as a bug).

My current approach:

- name: create empty temporary keys file
  local_action: "shell > /tmp/auth_keys"

- name: concat keys to temporary file
  local_action: "shell echo {{ item }} >> /tmp/auth_keys"
  with_file:
   - public_keys/doe-jane
   - public_keys/doe-john

- name: set up authorized_keys
  authorized_key: user=deploy
                  key="{{ lookup('file', '/tmp/auth_keys') }}"
                  exclusive=yes

This works but the first two commands always produce "changed". Also I feel there must be a more elegant solution for this.

So, is there a way how to concatenate contents of several files into a variable? Or is there any better approach in general for this task?

like image 553
Ikar Pohorský Avatar asked Oct 09 '15 07:10

Ikar Pohorský


2 Answers

There's nothing overly wrong with your first option and then, as your comment mentions, simply using changed_when: False to acknowledge that this isn't something that you care about the result of it changing is a valid option.

To answer the actual question title you can, as mentioned in the GitHub "issue" you linked, simply concatenate the lookups directly in the task like so:

- name: set up authorized_keys
  authorized_key: user=deploy
                  key="{{ lookup('file', 'public_keys/doe-jane') + lookup('file', 'public_keys/doe-john')}}"
                  exclusive=yes

However, a cleaner option may be to use the assemble module to concatenate your keys.

This would then change your current approach into something more like:

- name: create concatenated keys file
  local_action: "assemble src=roles/ssh_keys/files/ssh_keys/ dest=/tmp/ssh_keys_file"

- name: set up authorized_keys
  authorized_key: user=deploy
                  key="{{ lookup('file', '/tmp/ssh_keys_file' }}"
                  exclusive=yes

This will only be marked as changed if the destination file has changed at all so running it over and over leaves a lovely wall of green.

This relies on your ssh keys all being files and in the same folder (assemble is typically used for turning conf.d style directories into a single .conf file for programs that don't use the conf.d style configuration) but this is probably the most sensible way of holding them anyway.

The benefit of this is that you can simply add/remove ssh keys from the folder specified and it will be picked up on the next play without any need to add/remove keys being explicitly defined in the task itself as well.

like image 84
ydaetskcoR Avatar answered Oct 07 '22 00:10

ydaetskcoR


If you use the assemble module, you can as well just use it to generate the remote authorized_keys file in one step instead of pre-assembling it locally, it stays green, too:

- name: deploy authorized keys
  assemble:
    remote_src: no
    src: "{{ ssh_key_dir }}"
    dest: "/home/{{ user }}/.ssh/authorized_keys"
like image 23
Remigius Stalder Avatar answered Oct 06 '22 23:10

Remigius Stalder