# deploying with ansible

**URL:** <https://forum.ansible.com/t/deploying-with-ansible/15832>\
**Category:** Ansible Project\
**Tags:** galaxy-ng\
**Created:** [August 1, 2014, 12:31pm UTC](https://forum.ansible.com/t/deploying-with-ansible/15832 "2014-08-01T12:31:37Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![ramon](https://avatars.discourse-cdn.com/v4/letter/r/34f0e0/32.png) [@ramon](https://forum.ansible.com/u/ramon)\
**Post date:** [August 1, 2014, 12:31pm UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/1 "2014-08-01T12:31:37Z")

</div>

Hey All,

I posted some thoughts on deploying with Ansible, specifically some problems we tried to solve converting from Capistrano:

[http://www.future500.nl/articles/2014/07/thoughts-on-deploying-with-ansible/](http://www.future500.nl/articles/2014/07/thoughts-on-deploying-with-ansible/)

Michael de Haan pointed out that some of our “solutions” are deprecated for security reasons, so I post here to discuss other options, and deploying with Ansible in general.

Here is the role on ansible-galaxy: [https://galaxy.ansible.com/list#/roles/732](https://galaxy.ansible.com/list#/roles/732)

I’d like to point to the “deploy” module specifically: [https://github.com/f500/ansible-project\_deploy/blob/master/library/deploy](https://github.com/f500/ansible-project_deploy/blob/master/library/deploy)

- it creates a folder structure
- it generates a timestamp
- it generates facts (including the generated timestamp)
- it can remove _n_ releases

Perhaps that does some work that makes life easier for deploys?

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [August 1, 2014, 1:12pm UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/2 "2014-08-01T13:12:10Z")

</div>

So several things I wanted to comment on.

(A) What Cap calls rollbacks aren’t - it would be a rollback if it magically understood how to undo every action. That being said, some sort of try/except facility is intended for 1.8. “Rollback” logic is up to you, but failing forward is a better approach. The guide on test strategy may also be instructive.

(B) The symlink pattern thing I’d like to make more idiomatic, though I don’t think it’s hard now. This might just be a docs example, but it might be a mini-module that has a couple of modes, one that makes a timestamp and another that moves the symlink or something. I don’t know. Example may be sufficient.

(C) Yes, adding key=value arguments to existing commands must now be intercepted for security reasons. In particular this part, which I don’t really understand what it’s doing in the playbook, can’t be a thing:

```auto
  action: "{{ item.module }} {{ item.parameters }}"

```

In all though, the topic I want to concentrate on the most is (B). If we were to make a module or two to make the “timestamp’d symlink thing” more idiomatic, what might the syntax look like, etc?

One of the major goals of Ansible is to not need another deployment tool on top, like Cap. In most cases, people are already able to drop Fabric/Cap - I’d say it’s significantly more common for people to adopt ansible for application deployment needs initially - and especially with regard to load balancing and such it was designed for the purpose.

So the question is, how do we make that even easier?

---

<div class="post-metadata">

**Author:** ![ramon](https://avatars.discourse-cdn.com/v4/letter/r/34f0e0/32.png) [@ramon](https://forum.ansible.com/u/ramon)\
**Post date:** [August 4, 2014, 2:11pm UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/3 "2014-08-04T14:11:44Z")

</div>

I’ll try to get some things out of the way before responding to your (B).

About the "rollback”:  
The point wasn't really about wether Capistrano does rollbacks or not (I’ll accept that they’re not - I’m no expert on the subject), but more about how complex things can become if you’re trying to implement a central place for “rollback” in Ansible. In essence, avoiding the result of multiple tasks to influence flow of the role. Try/except would ease that pain a bit (but it wasn’t painful for us \_not\_ to have a central rollback at all).

About the “action:” syntax idea:  
\*\* never actually used \*\*  
It was an idea using (abusing) the old notation of Ansible to allow writing a more flexible role in Galaxy. The point is allowing certain moments where the consumer of the role can add their own actions, without having to copy the role.  
— it is understood that this idea will not work.

\*\* currently used in ansible-project\_deploy role \*\*  
Having a configurable list, that is used “with\_items” and the “command” module (could be shell module). The reason is the same, to allow consumers of the role to perform commands that are not part of the deploy role by default.

Answer to (B):  
We worked hard to make an easy to re-use role. The only things we found worthy of adding to a module where:  
- state=present: the automatic creation of the folder structure. The module will also create a new timestamp and return that in a fact, and delete any folders containing a “BUILD\_UNFINISHED” file.  
- state=clean: the automatic removal of old releases (which also makes assumptions on the folder structure).  
- state=absent: removal of the entire deploy folder (just to be consistent, could be done with the file module already)

None of these are hard to implement - but I tried to show in the article that it does clean up the role a bit.

Moving the symlink \*could\* be part of the module. We didn’t really see a huge benefit, it’s just a single task.

All-in-all I think we went with your mantra when people start suggesting deploy modules: “It sounds like a role to me”  
But the aim was to create a role in Galaxy that can cover most simple deploy scenarios.

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [August 4, 2014, 2:59pm UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/4 "2014-08-04T14:59:30Z")

</div>

> . Try/except would ease that pain a bit (but it wasn’t painful for us  
> \_not\_ to have a central rollback at all).

Got it - yeah I want to have something for this in 1.8

> About the “action:” syntax idea:  
> \*\* never actually used \*\*  
> It was an idea using (abusing) the old notation of Ansible to allow  
> writing a more flexible role in Galaxy. The point is allowing certain  
> moments where the consumer of the role can add their own actions, without  
> having to copy the role.  
> — it is understood that this idea will not work.
> 
> \*\* currently used in ansible-project\_deploy role \*\*  
> Having a configurable list, that is used “with\_items” and the “command”  
> module (could be shell module). The reason is the same, to allow consumers  
> of the role to perform commands that are not part of the deploy role by  
> default.
> 
> Answer to (B):  
> We worked hard to make an easy to re-use role. The only things we found  
> worthy of adding to a module where:  
> - state=present: the automatic creation of the folder structure. The  
> module will also create a new timestamp and return that in a fact, and  
> delete any folders containing a “BUILD\_UNFINISHED” file.  
> - state=clean: the automatic removal of old releases (which also makes  
> assumptions on the folder structure).  
> - state=absent: removal of the entire deploy folder (just to be  
> consistent, could be done with the file module already)

Yep, I'm basically wanting to see this doable with a module, not a role, to  
make it more adaptable by users that want different variations, and less  
boilerplate to hop through when they do.

Having a module that has a couple of modes, one might be via action plugin  
to register a consistent symlink timestamp, and another via standard module  
to make one "the one", and to clean out older timestamps, seems to make a  
lot of sense.

> All-in-all I think we went with your mantra when people start suggesting  
> deploy modules: “It sounds like a role to me”

Yeah here I'm thinking there's enough of a pattern that we can get  
something to smooth this out in core.

It also gives a good place to hang a common example.

Maybe down the right track:

# this would have to be a bypass host loop plugin or something to get a  
consistent timestamp, but maybe we don't care  
- deploy\_prepare:  
&nbsp;&nbsp;register: deploy\_timestamp

- deploy\_helper: timestamp={{ deploy\_timestamp.time }} base=/opt/base  
&nbsp;&nbsp;register: where\_to

# git checkout to where\_to.path

# symlink latest dir into live and remove other symlinks  
- deploy\_helper: timestamp={{ deploy\_timestamp.time }} base=/opt/base  
live=/opt/live clean=yes  
&nbsp;&nbsp;register

This is just me going through it really quick so I suspect we can come up  
with cleaner argument names and workflow.

---

<div class="post-metadata">

**Author:** ![ramon](https://avatars.discourse-cdn.com/v4/letter/r/34f0e0/32.png) [@ramon](https://forum.ansible.com/u/ramon)\
**Post date:** [August 4, 2014, 9:43pm UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/5 "2014-08-04T21:43:19Z")

</div>

> Having a module that has a couple of modes, one might be via action plugin to register a consistent symlink timestamp, and another via standard module to make one “the one”, and to clean out older timestamps, seems to make a lot of sense.
> 
> Maybe down the right track:
> 
> # this would have to be a bypass host loop plugin or something to get a consistent timestamp, but maybe we don’t care
> 
> - deploy\_prepare:  
> register: deploy\_timestamp

> 

> - deploy\_helper: timestamp={{ deploy\_timestamp.time }} base=/opt/base  
> register: where\_to

For the deploys we do with our galaxy role, a consistent timestamp is not an issue (small projects, single hosts). But for something in core, I would expect the ability to create a single timestamp for all hosts. I also really like the idea of a separate deploy\_helper module that takes in this timestamp - but I remarked in my blogpost that a timestamp isn’t really required (I gave ‘commit hash’ as an example folder name).

Perhaps:

- deploy\_helper: **release\_version** ={{ deploy\_timestamp.time }} base=/opt/base  
register: where\_to

Which allows for:

- deploy\_helper: release\_version={{ my\_own\_versioning\_implementation }} base=/opt/base  
register: where\_to

> # git checkout to where\_to.path

I’m assuming “where\_to.path” is the release-path-with-timestamp, and that this line is a placeholder for anything that goes on before the actual release is ready.

Question: does the deploy\_helper assume a folder structure?  
So in this case: would the where\_to.path point to “/opt/base/releases/{{ timestamp }}” ?

Our role currently places a file called “BUILD\_UNFINISHED” in the where\_to.path, and uses that file to remove failed builds (any folder containing it will die in the startup of the next deploy). That helped us out also, not having to identify where the “current” symlink is pointing to. Does that sound logical?

Param: unfinished\_file=BUILD\_UNFINISHED (or yes/no, with a fixed value maybe)

> # symlink latest dir into live and remove other symlinks
> 
> - deploy\_helper: timestamp={{ deploy\_timestamp.time }} base=/opt/base live=/opt/live clean=yes

Again: does this assume a folder structure?  
So in this case, the symlink would become: /opt/live → /opt/base/releases/{{ timestamp }} ?  
And any old releases in /opt/base/releases would be removed?

(sorry for al the questions, I’m trying to map your example to my actual cases)

---

<div class="post-metadata">

**Author:** ![Jeff\_Geerling](https://avatars.discourse-cdn.com/v4/letter/j/13edae/32.png) [@Jeff\_Geerling](https://forum.ansible.com/u/Jeff_Geerling)\
**Post date:** [August 5, 2014, 4:11pm UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/6 "2014-08-05T16:11:39Z")

</div>

Just wanted to add; this is almost exactly how we deploy PHP-based apps (with a bunch of bash scripts currently :/) at my current workplace, and having a built-in way to tidy up the process would be awesome.

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [August 5, 2014, 4:28pm UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/7 "2014-08-05T16:28:56Z")

</div>

> Having a module that has a couple of modes, one might be via action plugin
> 
> > to register a consistent symlink timestamp, and another via standard module  
> > to make one "the one", and to clean out older timestamps, seems to make a  
> > lot of sense.
> > 
> > Maybe down the right track:
> > 
> > # this would have to be a bypass host loop plugin or something to get a  
> > consistent timestamp, but maybe we don't care  
> > - deploy\_prepare:  
> > &nbsp;&nbsp;register: deploy\_timestamp
> > 
> > - deploy\_helper: timestamp={{ deploy\_timestamp.time }} base=/opt/base  
> > &nbsp;&nbsp;register: where\_to
> 
> For the deploys we do with our galaxy role, a consistent timestamp is not  
> an issue (small projects, single hosts). But for something in core, I would  
> expect the ability to create a single timestamp for all hosts. I also  
> really like the idea of a separate deploy\_helper module that takes in this  
> timestamp - but I remarked in my blogpost that a timestamp isn't really  
> required (I gave 'commit hash' as an example folder name).

Yeah, good point, and may not be an issue anywhere really because of the  
symlink, if there's good enough cleanup options.

Not requiring that seems like it would be a nice shortcut, provided that  
the module could be called to register what the "latest" was if you didn't  
pass too many arguments.

> Perhaps:  
> - deploy\_helper: \*release\_version\*={{ deploy\_timestamp.time }}  
> base=/opt/base  
> &nbsp;&nbsp;register: where\_to
> 
> Which allows for:  
> - deploy\_helper: release\_version={{ my\_own\_versioning\_implementation }}  
> base=/opt/base  
> &nbsp;&nbsp;register: where\_to
> 
> > # git checkout to where\_to.path
> 
> I'm assuming "where\_to.path" is the release-path-with-timestamp, and that  
> this line is a placeholder for anything that goes on before the actual  
> release is ready.
> 
> Question: does the deploy\_helper assume a folder structure?  
> So in this case: would the where\_to.path point to "/opt/base/releases/{{  
> timestamp }}" ?

I think it would only assume a timestamp dir in base, but it could default  
to make a subdir called "releases", sure.

I think as long as we document what it does we could make up a convention,  
because it's going to change the way you deploy your app a little bit, and  
you would not have to use unless you wanted...

> Our role currently places a file called "BUILD\_UNFINISHED" in the  
> where\_to.path, and uses that file to remove failed builds (any folder  
> containing it will die in the startup of the next deploy). That helped us  
> out also, not having to identify where the "current" symlink is pointing  
> to. Does that sound logical?
> 
> Param: unfinished\_file=BUILD\_UNFINISHED (or yes/no, with a fixed value  
> maybe)

This sounds pretty cool to me.

> # symlink latest dir into live and remove other symlinks
> 
> > - deploy\_helper: timestamp={{ deploy\_timestamp.time }} base=/opt/base  
> > live=/opt/live clean=yes
> 
> Again: does this assume a folder structure?  
> So in this case, the symlink would become: /opt/live -\>  
> /opt/base/releases/{{ timestamp }} ?  
> And any old releases in /opt/base/releases would be removed?

I think maybe you might need to pass a parameter to remove the other ones,  
and it could be optional.

> (sorry for al the questions, I'm trying to map your example to my actual  
> cases)

Yeah something like what you have, if not exactly, as a module seems really  
really cool to me.

---

<div class="post-metadata">

**Author:** ![Jasper\_N\_Brouwer](https://avatars.discourse-cdn.com/v4/letter/j/d2c977/32.png) [@Jasper\_N\_Brouwer](https://forum.ansible.com/u/Jasper_N_Brouwer)\
**Post date:** [August 6, 2014, 7:20am UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/8 "2014-08-06T07:20:51Z")

</div>

Hi all!

A little introduction for context: I'm a college/employee of Ramon de la Fuente, and we both maintain the f500.\* roles in Galaxy. So when I refer to "our module", that's the same module as the one Ramon refers to.

I'd like to sum up my thoughts on the discussion so far:

- We choose to use the same directory layout as Capistrano does:

/opt/base/current -\> /opt/base/releases/{timestamp}  
/opt/base/releases/  
/opt/base/shared/

"shared" is used for stuff that needs to survive a deploy (uploads, etc).

The main reason we chose this is because it will be familiar to people who have used Capistrano. Plus we didn't see anything wrong with this layout, it suits our needs perfectly.

We could make the exact file/directory names configurable though.

- I agree we need something to create a consistent timestamp (or whatever) to be used on all hosts.

And this probably doesn't have to be a timestamp. The reason we choose a timestamp is because it helps determine which releases should be cleaned up. We can simple order them and keep the latest X.

I suspect it should be possible to stat those directories for a creation-date, and use them for the cleanup. The directory name itself can then be whatever you like (unix timestamp, yyyymmddhhmmss style timestamp, commit hash, uuid, etc).

- Our current role also sets some facts, which are really convenient to have around:

base\_path: \<must be provided through a required option\>  
current\_symlink: \<base\_path\>/current  
releases\_path: \<base\_path\>/releases  
shared\_path: \<base\_path\>/shared  
current\_release: \<the release-timestamp/whatever that current\_symlink points to\>  
current\_release\_path: \<base\_path\>/releases/\<current\_release\>  
new\_release: \<the given/generated release-timestamp/whatever\>  
new\_release\_path: \<base\_path\>/releases/\<new\_release\>  
unfinished\_file: BUILD\_UNFINISHED

I'd like the core module to have these as well. Any thoughts on additions or changes are more than welkom!

- The cleanup process we use is 2-fold: First we remove any releases that still contain the BUILD\_UNFINISHED file. Next we remove any releases that exceed a configurable amount (keep 5 releases for example).

This 2-fold process is very important to us, because we don't want to accidentally fail 5 releases in a row and have the cleanup process remove any older releases, therefor be left with only broken releases. The releases that are kept must be successful ones.

And, we don't have this yet, but I think the cleanup should never remove the active release (the one the symlink points to), even if it's considered old). So it has to safeguard that.

---

<div class="post-metadata">

**Author:** ![vaida.dan](https://avatars.discourse-cdn.com/v4/letter/v/5daacb/32.png) [@vaida.dan](https://forum.ansible.com/u/vaida.dan)\
**Post date:** [August 14, 2014, 11:42am UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/9 "2014-08-14T11:42:31Z")

</div>

Hello,

Again, a very BIG thank you for your efforts on the deploy module.

I would like to share my suggestion, perhaps as an idea to generate a future pull request:  
With capistrano, it is possible to run some of the tasks only on specific hosts. Any plans for such a feature?  
Problem is that in the /shared folder, I have stuff that’s being shared between releases but ALSO some mounted nfs shares. I think I will create another directory in deployment root called /mounts for the NFS purposes, to avoid confusion and workarounds.  
Regardless, I think the host filter feature would come in handy.

P.S. for us, it’s important to have a simple rollback functionality so you might see a fork/pr soon.

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [August 14, 2014, 12:00pm UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/10 "2014-08-14T12:00:25Z")

</div>

“With capistrano, it is possible to run some of the tasks only on specific hosts. Any plans for such a feature?”

This has been a feature in Ansible since day 1.

- hosts: hostnames
- hosts: otherhostnames

Etc

---

<div class="post-metadata">

**Author:** ![vaida.dan](https://avatars.discourse-cdn.com/v4/letter/v/5daacb/32.png) [@vaida.dan](https://forum.ansible.com/u/vaida.dan)\
**Post date:** [August 14, 2014, 12:27pm UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/11 "2014-08-14T12:27:39Z")

</div>

That’s right. But I was referring to another thing.

Basically, I’m trying to use their deployment role as a whole, to perform certain operations only on certain hosts, while leaving all the hosts/groups, listed in the the main ‘hosts’ directive.

In my other roles, I’ve been using host\_vars or even defined the host vars in the ‘hosts’ file and used those vars as flags for acting or not on some particular tasks.

To nail it down, I am deploying on 10 nodes and each is having a custom connection string to its own Redis node. That would be handled via the /private folder, but I can’t see a built-in way for their deployment role to do this.

Perhaps I’m not looking at it from the right angle.

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [August 14, 2014, 12:34pm UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/12 "2014-08-14T12:34:07Z")

</div>

"  
Basically, I’m trying to use their deployment role as a whole, to perform certain operations only on certain hosts, while leaving all the hosts/groups, listed in the the main ‘hosts’ directive."

This is there too 🙂

ansible-playbook foo.yml --limit groupname  
ansible-playbook foo.yml --limit hostname

“To nail it down, I am deploying on 10 nodes and each is having a custom connection string to its own Redis node. That would be handled via the /private folder, but I can’t see a built-in way for their deployment role to do this.”

This doesn’t seem related.

I’d just do host\_vars/ for this, and that’s a different concept, but does not interfere with --limit.

---

<div class="post-metadata">

**Author:** ![ramon](https://avatars.discourse-cdn.com/v4/letter/r/34f0e0/32.png) [@ramon](https://forum.ansible.com/u/ramon)\
**Post date:** [October 25, 2014, 9:02pm UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/13 "2014-10-25T21:02:11Z")

</div>

Hey All,

Sorry about the radio silence on this thread, I kind of dropped the ball on this one ☹

I’m picking up where I left off, I’ll work out the options for the module to move this thing forward. I think my last ideas revolved around two options for the module, one where we have a (semi) fixed folder structure - and one where we’re only interested in the symlink and cleanup.

If anyone has had thoughts about it since august, feel free to add them - I’ll be working on this next week.

Kind regards,

Ramon

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [October 30, 2014, 5:17pm UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/14 "2014-10-30T17:17:24Z")

</div>

Nice, very much looking forward to this.

If you have a PR ready maybe reply to the list so you can make sure to get our attention on it.

Thanks!!!

---

<div class="post-metadata">

**Author:** ![ramon](https://avatars.discourse-cdn.com/v4/letter/r/34f0e0/32.png) [@ramon](https://forum.ansible.com/u/ramon)\
**Post date:** [November 2, 2014, 10:41pm UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/15 "2014-11-02T22:41:47Z")

</div>

Hey Michael (and anyone else interested),

I’ve been working on the deploy\_helper module, but it’s not ready for a pull-request just yet.

> From the perspective of a consumer, I think a common deploy role looks something like this (following along the lines of a deploy procedure that uses releases and a ‘current’ symlink):  
> The numbers are a guess at the number of tasks it would take to complete the task.

1. create the project root folder
2. create a timestamp
3. create a releases folder
4. create the shared folder

```auto
1. remove build in progress file
1. create a symlink
3. delete the old releases [find, filter, delete]
```

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [November 3, 2014, 2:23pm UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/16 "2014-11-03T14:23:14Z")

</div>

> When we take a “deploy\_helper" module into account, it could look like  
> this:
> 
> 1. deploy state=present path=/path/to/root  
> &nbsp;&nbsp;&nbsp;&nbsp;- creates project root folder  
> &nbsp;&nbsp;&nbsp;&nbsp;- returns a timestamp  
> &nbsp;&nbsp;&nbsp;&nbsp;- creates the releases folder  
> &nbsp;&nbsp;&nbsp;&nbsp;- creates the shared folder (optional)  
> ~~~clone, build, prepare~~~ (outside of the scope of the module)  
> 1. deploy state=finalize  
> &nbsp;&nbsp;&nbsp;&nbsp;- removes build in progress file  
> &nbsp;&nbsp;&nbsp;&nbsp;- creates a symlink  
> &nbsp;&nbsp;&nbsp;&nbsp;- optionally does cleanup  
> -----------------------------------------  
> This could be done in 2 tasks (+1 if we exclude the ‘shared' folder  
> creation from the module)

This looks really good to me.

I much prefer the idea of a mostly self-contained module as it makes the  
amount of work everyone has to do to use the above much more condensed.

If 2000 people use it, we might have saved the world 20,000 minutes or  
more, etc 🙂

> Looking at the options required, the module might take on this signature:
> 
> deploy\_helper parameters:  
> required:  
> &nbsp;&nbsp;&nbsp;&nbsp;path= /path/to/project-root
> 
> not required:  
> &nbsp;&nbsp;&nbsp;&nbsp;release= (default: timestamp)  
> &nbsp;&nbsp;&nbsp;&nbsp;owner= (default: null)  
> &nbsp;&nbsp;&nbsp;&nbsp;group= (default: null)  
> &nbsp;&nbsp;&nbsp;&nbsp;mode= (default: null)  
> &nbsp;&nbsp;&nbsp;&nbsp;keep\_releases= (default: 5)  
> &nbsp;&nbsp;&nbsp;&nbsp;create\_shared\_folder= (default: true)  
> &nbsp;&nbsp;&nbsp;&nbsp;releases\_path= (default: {{ path }}/releases)  
> &nbsp;&nbsp;&nbsp;&nbsp;shared\_path= (default: {{ path }}/shared)  
> &nbsp;&nbsp;&nbsp;&nbsp;current\_path= (default: {{ path }}/current)  
> &nbsp;&nbsp;&nbsp;&nbsp;unfinished\_filename= (default: DEPLOY\_UNFINISHED)
> 
> > I may be a little unclear on what the "shared path" is. Can you remind

me?

> &nbsp;&nbsp;&nbsp;&nbsp;state=[present, absent, clean, finalize, query] (default: present)
> 
> Besides your general opinion, I was pondering the following practical  
> questions:
> 
> 1: What category of module would this module be under? File?
> 
> > "web infrastructure" seems ideal for now. We may decide to reorganize

the categories in the near future.

> 2: Should the (optional) creation of a shared folder be part of a deploy  
> module?
> 
> > see my question above as I'm not quite remembering what a shared folder

is right now 🙂

> 3: Should we even be duplicating code like creation of the symlink? The  
> file module already does that...
> 
> > There should be common code for this in module\_utils. If not, we can

move the file code there and make it use that,  
to avoid duplication.

I do believe it's important to represent the "idea" (atomic deploys with  
timestamps) versus the "how", and saving as many steps as possible.

> Thanks for any feedback, kind regards,

Thanks a ton for building this!

---

<div class="post-metadata">

**Author:** ![ramon](https://avatars.discourse-cdn.com/v4/letter/r/34f0e0/32.png) [@ramon](https://forum.ansible.com/u/ramon)\
**Post date:** [November 3, 2014, 9:25pm UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/17 "2014-11-03T21:25:51Z")

</div>

Hey Michael,

Quick reply regarding the “shared folder”

With most projects there’s some form of state kept between releases. With web projects this usually means server-side session files, but possibly also user-generated content like uploaded files and such. All our projects have at least one shared folder.

root/releases/1/sessions → root/shared/sessions

root/releases/1/uploads → root/shared/uploads

root/releases/2/sessions → root/shared/sessions

root/releases/2/uploads → root/shared/uploads

Our deploy role takes care of creating and linking to the subfolders of /shared, but creation of the shared folder itself _could_ be part of the role. Not really that big of a deal though, it saves just one task - and maybe adds some confusion as to what it is and what it should do.

Kind regards,

Ramon

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [November 4, 2014, 8:48pm UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/18 "2014-11-04T20:48:33Z")

</div>

I see yeah, the symlink for the shared folder could be part of the module, but could be outside it too.

I’m fine with it being there if that’s an example.

---

<div class="post-metadata">

**Author:** ![ramon](https://avatars.discourse-cdn.com/v4/letter/r/34f0e0/32.png) [@ramon](https://forum.ansible.com/u/ramon)\
**Post date:** [November 16, 2014, 10:55pm UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/19 "2014-11-16T22:55:02Z")

</div>

Ok, Michael, and everyone else of course,

I’ve proposed the new module in a pull-request.

The module can be found here:  
[https://github.com/ansible/ansible-modules-extras/pull/110](https://github.com/ansible/ansible-modules-extras/pull/110)

The documentation (I chose to make an additional guide in the manual):  
[https://github.com/ansible/ansible/pull/9566](https://github.com/ansible/ansible/pull/9566)

And optionally, tests for the module:  
[https://github.com/ansible/ansible/pull/9567](https://github.com/ansible/ansible/pull/9567)

I split the manual and the tests up into separate pull requests, because I’m not sure if you guys want them or not…

I hope you like it, let me know what you think.

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [November 17, 2014, 8:48pm UTC](https://forum.ansible.com/t/deploying-with-ansible/15832/20 "2014-11-17T20:48:10Z")

</div>

Thanks for this!

My first thought is try to clean up the examples section so there’s no “…” … make something real world in there, and seperate it out by use case.

I would not like to see a seperate guide for this module as it sets a bit of a strange precedent, so it would be better to just show a basic set of playbooks in the examples.

We can take a look further at implementation/usage once those get fleshed out a bit, so we can tell how to run them.

Thanks!

[Next page](https://forum.ansible.com/t/deploying-with-ansible/15832.md?page=2)
