After a year of work, we are extremely proud to announce that Ansible 2.0 ("Over the Hills and Far Away") has been released and is now generally available. This is by far one of the most ambitious Ansible releases to date, and it reflects an enormous amount of work by the community, which continues to amaze me. Approximately 300 users have contributed code to what has been known as “v2” for some time, and 500 users have contributed code to modules since the last major Ansible release.
Why Did We Start V2?
There are many pitfalls to refactoring software, so why did we decide to tackle such a major project? At the time we started the work on v2, Ansible was approximately three years old and had recently crossed the 1,000 contributor mark. This huge rate in growth also resulted in a degree of technical debt in the code, which was beginning to show as we continued to add features.
Ultimately, we decided it was worth it to take a step back and rework some aspects of the codebase which had been prone to having features bolted on without a clear-cut architectural vision. We also rewrote from scratch much of the code which was responsible for parsing playbook and other YAML files to make adding language features easier, while providing more information about errors beyond parsing problems (more on that later). Finally, we split up and reorganized code to make things easier to find and to reduce the “utils” code, which had become a collector for bits and pieces which didn’t have any other clear-cut home.
During this entire process, one of the fundamental goals was to maintain backwards compatibility with existing playbooks. In terms of parsing and running playbooks, we believe we have hit that goal. However, there are some incompatibilities related to certain features which users need to be aware of and which we will discuss below.
Ansible 2.0 is quite a bit more than a large refactoring effort. The cleaner architecture allowed us to add several new features we had been considering for a while, plus one which became possible directly because of the refactoring.
Blocks introduce the concept of exception handling to playbooks, and were modeled after the try/except/finally structure of Python (and many other languages). This eases development of playbooks and tasks, where task failures can be caught and dealt with in a single playbook much more simply than before.
Blocks also allow users to group related tasks together using tags and conditionals, as well as many other task attributes (become settings, delegation, etc.).
Playbook Parsing, Error Reporting Improvements, and Dynamic Includes
As we noted above, the code responsible for parsing and interpreting playbooks was almost entirely rewritten from scratch. This new code provides clearer identification of errors and provides suggested fixes beyond simple YAML syntax errors.
Additionally, the include task is now executed dynamically. In Ansible 1.9.x and before, includes behaved more along the lines of a pre-processor statement, and tasks were immediately expanded in-line before any inventory data was available. This caused problems when users attempted to use includes with loops (a feature which was removed in Ansible 1.6). Ansible 2.0 brings this feature back, and is even more flexible than before.
New Execution Strategy Plugins
This is the feature we were able to add specifically due to the refactoring. Execution strategies allow users to change the way in which Ansible runs tasks on targeted hosts. Classic Ansible takes a single task and runs it on all hosts before moving onto the next task (which we now call the “linear” strategy). Ansible 2.0 also includes the “free” strategy, which allows each host to process its list of tasks as quickly as possible (still in-order) without waiting for all other hosts.
And since these are plugins (like so many other things in Ansible), users are free to come up with strategies of their own!
Ansible 2.0 also continues our long “batteries included” tradition by including over 200 new modules. Some of the highlights include:
A completely new set of modules for managing OpenStack, the leading open source cloud computing framework, developed in concert with the OpenStack community
30 new modules for improving and expanding the support for Amazon Web Services
Greatly expanded support for configuring and managing VMware environments
Expanded support for managing Microsoft Windows environments
Substantial improvements to the Docker module and new Docker connection plugin
Known Issues with Ansible 2.0
As mentioned above, there are a few incompatibilities related to existing playbooks, as well as a few known issues which we will be working on in the near future.
Plugin API Changes
Internally, one of the major code cleanups we made was to make each plugin class (actions, callbacks, lookups, etc.) inherit from a common base class. This allowed us to remove a lot of code duplication, however, it also means that the plugin API has changed significantly. Users who may have written certain kinds of plugins may need to update their plugins to work on Ansible 2.0.
Dynamic Include Problems
Due to the fact that include tasks are now evaluated at run time, Ansible no longer knows ahead of time about any tasks contained within files which have yet to be included. This presents problems in several situations (which we intend to correct in future versions):
Tags on tasks are not seen until the include is processed, so tags should now be specified on the include task rather than on individual tasks within the include, otherwise they will not be seen. Likewise, the --list-tags option will not show tags contained only in the include files.
Handlers in includes will not be seen when a task attempts to notify them, so handlers should avoid using includes at this time.
Ansible 2.0 does not currently raise an error if a non-existent tag is specified via --tags or --skip-tags. This is also related to the dynamic include problem above, and we intend to address this once the above include problems are resolved.
In Ansible 1.9.x and before, in certain situations backslashes (“\”) had to be escaped twice, resulting in a sequence of four backslashes (“\\\\”). This was particularly common when using back references with the lineinfile module. Improvements in the playbook parsing mentioned above mean that backslashes only need to be escaped once.
There are some additional minor feature changes, which we have begun documenting in a porting guide. This guide also includes some workarounds for issues such as the backslash escaping change mentioned above.
For those that need control, security, and delegation for their Ansible deployments, Ansible Tower is available via subscription tiers suitable for everyone from small companies to full-scale, mission-critical enterprise devops teams. Go to ansible.com/tower for details.