# Creating symlinks and their parent directories

**URL:** <https://forum.ansible.com/t/creating-symlinks-and-their-parent-directories/20095>\
**Category:** Ansible Project\
**Created:** [December 29, 2015, 7:40pm UTC](https://forum.ansible.com/t/creating-symlinks-and-their-parent-directories/20095 "2015-12-29T19:40:13Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Chris\_White](https://avatars.discourse-cdn.com/v4/letter/c/e56c9b/32.png) [@Chris\_White](https://forum.ansible.com/u/Chris_White)\
**Post date:** [December 29, 2015, 7:40pm UTC](https://forum.ansible.com/t/creating-symlinks-and-their-parent-directories/20095/1 "2015-12-29T19:40:13Z")

</div>

Hey guys,

After reading the [file](http://docs.ansible.com/ansible/file_module.html) documentation a few times, doing some testing and doing some preliminary searching here I hopefully have a quick question for you.

I’m working on automating my [personal dev environment](https://github.com/christopherdwhite/superlumic-config) with [Superlumic](https://github.com/superlumic/superlumic) and have moved a lot of my ~/Library/ application data to Dropbox and am symlinking them back into place.

Since I’m creating symlinks for applications that haven’t been run yet (or even installed in the case of Mac App Store apps) so their parent directories may not already exist.

It looks like I could do this as two separate tasks with a directory state as well as a link state but I was hoping there might be a way to do them both in a single task to keep my configuration as simple and clean as possible.

Is it possible to do this in one task?

`

- name: TextExpaner Settings Directory  
file: path=/Users/cwhite/Library/Application\ Support/TextExpander/ state=directory

- name: TextExpaner Settings Symlink  
file: src=/Users/cwhite/Dropbox/TextExpander/Settings.textexpander dest=/Users/cwhite/Library/Application\ Support/TextExpander/Settings.textexpander state=link force=yes  
`

Thanks for your help!

---

<div class="post-metadata">

**Author:** ![Chris\_White](https://avatars.discourse-cdn.com/v4/letter/c/e56c9b/32.png) [@Chris\_White](https://forum.ansible.com/u/Chris_White)\
**Post date:** [January 5, 2016, 3:02am UTC](https://forum.ansible.com/t/creating-symlinks-and-their-parent-directories/20095/2 "2016-01-05T03:02:50Z")

</div>

So I take it no one else is doing this kind of thing? I pinged Ansible on Twitter and they directed me here.

---

<div class="post-metadata">

**Author:** ![Chris\_White](https://avatars.discourse-cdn.com/v4/letter/c/e56c9b/32.png) [@Chris\_White](https://forum.ansible.com/u/Chris_White)\
**Post date:** [January 5, 2016, 3:10am UTC](https://forum.ansible.com/t/creating-symlinks-and-their-parent-directories/20095/3 "2016-01-05T03:10:43Z")

</div>

Took a different approach to this and tried to set this up as a Bash command instead and discovered that it also requires the creation of the directory structure in a separate step so I’m guessing there’s no way to make Ansible do it if it isn’t built directly into the module. Looks like I’ll just need to add a second task unless anyone else has an idea.

---

<div class="post-metadata">

**Author:** ![Tim1](https://avatars.discourse-cdn.com/v4/letter/t/b782af/32.png) [@Tim1](https://forum.ansible.com/u/Tim1)\
**Post date:** [January 5, 2016, 3:51am UTC](https://forum.ansible.com/t/creating-symlinks-and-their-parent-directories/20095/4 "2016-01-05T03:51:30Z")

</div>

Hey Chris,

I typically use modules to do targeted tasks instead of trying to batch multiple operations into a single task, but in the interest of educating myself, I took a swing at putting your example into a single task. The following should give you some ideas.

- name: a play  
hosts: all  
connection: local

tasks:

- name: TextExpander Settings Directory  
file:  
path: “/tmp/Application\ Support/TextExpander/”  
state: “directory”

- name: TextExpander Settings Symlink  
file:  
src: “/tmp/Dropbox/TextExpander/Settings.textexpander”  
dest: “/tmp/Application\ Support/TextExpander/Settings.textexpander”  
state: “link”  
force: “yes”

- name: a play  
hosts: all  
connection: local

tasks:

- name: TextExpander Settings  
file:  
path: “{{ item.path|default(omit) }}”  
state: “{{ item.state }}”  
src: “{{ item.src|default(omit) }}”  
dest: “{{ item.dest|default(omit) }}”  
force: “{{ item.force|default(omit) }}”  
with\_items:
- path: “/tmp/Application\ Support/TextExpander2/”  
state: “directory”
- src: “/tmp/Dropbox/TextExpander2/Settings.textexpander”  
dest: “/tmp/Application\ Support/TextExpander2/Settings.textexpander”  
state: “link”  
force: “yes”

The first play is just a mock-up of the example you provided.

The second play is the same example (I just changed the directory name to “TextExpander2”) with a single task used with a loop and jinja’s omit filter. I’m looping over a list of dictionaries and using omit on values that I know may not exist. State always exists.

Now, does this make it look cleaner? Well, that’s subjective so I’ll let you decide. You could take the content in the with\_items list and put it in a vars file to make the play itself look smaller (and allow your list of things to grow nearly unbounded).

When I run it on my box over here it goes off without a hitch and gives me (what I think) are the results you’re looking for

SEA-ML-RUPP1:ui trupp$ ansible-playbook -i localhost, ok.yaml

PLAY [a play] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

GATHERING FACTS \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
ok: [localhost]

TASK: [TextExpander Settings Directory] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
changed: [localhost]

TASK: [TextExpander Settings Symlink] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
changed: [localhost]

PLAY [a play] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

GATHERING FACTS \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
ok: [localhost]

TASK: [TextExpander Settings] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
changed: [localhost] =\> (item={‘path’: ‘/tmp/Application Support/TextExpander2/’, ‘state’: ‘directory’})  
changed: [localhost] =\> (item={‘dest’: ‘/tmp/Application Support/TextExpander2/Settings.textexpander’, ‘src’: ‘/tmp/Dropbox/TextExpander2/Settings.textexpander’, ‘state’: ‘link’, ‘force’: ‘yes’})

PLAY RECAP \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
localhost : ok=5 changed=3 unreachable=0 failed=0

SEA-ML-RUPP1:ui trupp$

Hope that helps.

-tim

---

<div class="post-metadata">

**Author:** ![Chris\_White](https://avatars.discourse-cdn.com/v4/letter/c/e56c9b/32.png) [@Chris\_White](https://forum.ansible.com/u/Chris_White)\
**Post date:** [January 5, 2016, 8:19pm UTC](https://forum.ansible.com/t/creating-symlinks-and-their-parent-directories/20095/5 "2016-01-05T20:19:09Z")

</div>

Yep, that does help a lot Tim, thanks!

The variable idea makes a lot of sense and would at least let me cut down on the redundancies a bit, I am curious though if you could show how you’d do this type of thing with modules instead in a targeted tasks.

This is my first time using Ansible and I’m definitely coming at it from the Superlumic angle and working my way outward from there, I haven’t really dug into Modules yet at all.

If you’re curious, my full configuration is [here](https://github.com/christopherdwhite/superlumic-config).

---

<div class="post-metadata">

**Author:** ![Tim1](https://avatars.discourse-cdn.com/v4/letter/t/b782af/32.png) [@Tim1](https://forum.ansible.com/u/Tim1)\
**Post date:** [January 5, 2016, 9:17pm UTC](https://forum.ansible.com/t/creating-symlinks-and-their-parent-directories/20095/6 "2016-01-05T21:17:11Z")

</div>

Clarifying what I meant by modules.

When I’m writing the tasks in my playbooks, I tend to do a step-by-step list of tasks instead of trying to bundle multiple steps into a single task. So your original example (2 tasks) is generally how I would think of writing it. The module (in our examples here the “file” part) performs a single operation for each task. If I want it to do more operations, then I just call it in more tasks.

Some of this batching of work begins to become more structured in ansible 2.0’s blocks feature, but the example you showed in your initial post is how I would have written it pending no further requirements.

I also tend to go the individual task route to prevent myself from trying to be too smart for my own good. The example I provided that batches the work would cause a mutiny amongst my colleagues 🙂

-tim
