0

My work environment:

  • Ubuntu 14.04
  • Ansible 2.6.3
  • Ansible Playbook 2.6.3
  • Python 2.7.6

I'm writing an Ansible playbook which contains a task that creates a symbolic link that points to a directory somewhere else. The task uses the file module (I simplified the code for convenience of discussion):

- name: Link the app configuration.
  file:
    path: "/home/username/appConfig.lnk"
    src: "/usr/share/app_name/appConfig"
    state: link
    force: no
  become: no

If the task is executed successfully, a symbolic link /home/username/appConfig.lnk is created and points to the directory /usr/share/app_name/appConfiig.

However, in the real use case, the user is likely to modify the appConfig.lnk to point to something else which is the customized configuration that suits their needs. This is expected and valid in our use, and the /usr/share/app_name/appConfig only tries to provide a usable initial configuration.

Therefore, I want the playbook task to only create the appConfig.lnk when it does NOT exist at all. If the path /home/username/appConfig.lnk exists already, regardless if it's a symbolic link to the default configuration, a symbolic link to some other customized configuration, a file, or a directory, I want to skip the creation.

However, the file module, with force set to no, behaves like this:

  • path exists and is a directory: Fail.
  • path exists and is a file: Fail.
  • path exists and is a symbolic link pointing to some other location other than src: Automatically recreate the link to point to src.

To workaround this issue, I added a task to call stat module before:

- name: Get the app configuration status.
  stat:
    path: "/home/username/appConfig.lnk"
  register: stat_config
  become: no

- name: Link the app configuration.
  when: not stat_config.stat.exists  # <-- New condition
  file:
    path: "/home/username/appConfig.lnk"
    src: "/usr/share/app_name/appConfig"
    state: link
    force: no
  become: no

But I think this introduces the ToCToU issue, because, although highly unlikely, the appConfig.lnk may be deleted right after the stat call so the file module is skipped and I end up with a system that says everything has been done successfully but the link is NOT created.

So I'm wondering if there is a way to implement what I want but avoid the possible ToCToU issue.

yaobin
  • 2,436
  • 5
  • 33
  • 54
  • I think you might be happiest using `shell:` rather than the modules, since the logic you described is so complex – mdaniel Sep 20 '18 at 01:24

1 Answers1

0

An option would be to use the "command creates" construct.

- name: Create link
  command: ln -s /usr/share/app_name/appConfig /home/username/appConfig.lnk
  args:
    creates: /home/username/appConfig.lnk

Discussion about the command module is here

Vladimir Botka
  • 58,131
  • 4
  • 32
  • 63