This patch also checks specifically for a return code of 255, which
indicates an unknown SSH error of some kind. When that happens, ansible
will now recommend running with -vvvv (if not enabled) or show the
output from 'ssh -vvv' (when it is enabled)
This shouldn't generally be needed unless you're working in an environment
that uses rediculously long FQDNs; if the name is too long, you wind up
hitting unix domain socket filepath limits enforced by ssh.
The default behavior is to update_cache if changed.
If you add more then one repo, you may not want to update cache for every repo separately.
So you can now disable update_cache with this new option e.g. update_cache=no
Updating cache can also be handled using the apt module.
* Added in support for freebsd-style sysctl commands
* Replaced some functionality that was provided by module_common
* Simplified some logic in a couple of places (ie, not checking
a split with len() but instead limiting the split to 1)
Fixes#3380
By default, the service module had assumed that if the system had the
update-rc.d binary, the service was either managed via upstart or standard
sysV init-style scripts. This patch adds a check for systemctl ahead
of the other methods when update-rc.d is detected, and also simplifies
the logic around the detection of systemctl-managed services
Reported by Rumen:
TASK: [fail FAIL] *************************************************************
skipping: [hostname.com]
failed: [hostname.com] => {"failed": true}
msg: Failed as requested from task
Traceback (most recent call last):
File "/usr/local/bin/ansible-playbook", line 268, in <module>
sys.exit(main(sys.argv[1:]))
File "/usr/local/bin/ansible-playbook", line 208, in main
pb.run()
File "/Library/Python/2.7/site-packages/ansible/playbook/__init__.py", line 262, in run
if not self._run_play(play):
File "/Library/Python/2.7/site-packages/ansible/playbook/__init__.py", line 580, in _run_play
if (hosts_count - len(host_list)) > int((play.max_fail_pct)/100.0 * hosts_count):
TypeError: object of type 'NoneType' has no len()
The play was just checking for the presence of the keyword in the
YAML datastructure, and not the value of the field, so doing something
like variable substitution was always causing the play to be accelerated
* Default variables are now fed directly into roles, just like the
other variables, so that roles see their unique values rather
than those set at the global level.
* Role dependency duplicates are now determined by checking the params used
when specifying them as dependencies rather than just on the name of the
role. For example, the following would be included twice without having
to specify "allow_duplicates: true":
dependencies:
- { role: foo, x: 1 }
- { role: foo, x: 2 }
Caveats:
* requiretty must be disabled in the sudoers config
* asking for a password doesn't work yet, so any sudoers users must
be configured with NOPASSWD
* if not starting the daemon as root, the user running the daemon
must have sudoers entries to allow them to run the command as the
target sudo_user
Still needs:
* chunked file transfer/receive
* should probably move all send/recv operations to separate
functions to reduce code duplication
* initial connection setup over ssh? or do we handle that in runner?
This is based somewhat loosely on how Keyczar does things. Their
implementation does things in a much more generic way to allow for more
variance in how the cipher is created, but since we're only using one
key type most of our values are hard-coded. They also add a header to
their messages, which I am not doing (don't see the need for it
currently).
Files were being created in /tmp, but will now be created in $HOME/.ansible/cp/
Addresses CVE-2013-4259: ansible uses a socket with predictable filename in /tmp
relative pathing comes in handy on occasion, particularly when
delegating to localhost and running some command out of your playbook
repo. Making use of os.path.abspath will allow for the full path to
chdir and executable to be discovered if not provided.
The 'always_run' task clause allows one to execute a task even in
check mode.
While here implement Runner.noop_on_check() to check if a runner
really should execute its task, with respect to check mode option
and 'always_run' clause.
Also add the optional 'jinja2' argument to check_conditional() :
it allows to give this function a jinja2 expression without exposing
the 'jinja2_compare' implementation mechanism.
For some reason, ssh seems to ask for password even when
PasswordAuthentication is set to no, adding PreferredAuthentications
with the 2 options removed do the trick.
This extends ansible-pull so that it can support using other
source_control modules for checking out a playbook repository
(issue #3372). This will check to see if the module exists before
it attempts to do the checkout and will exit if the module is not found.
It requires that the module used to check out the repository support the
parameters 'name' and 'version'. The option -C, --checkout is now
optional and defaults to the module's default behavior for selecting a
branch, tag, or commit value. For git, this continues to be HEAD.
Other changes include:
* Remove git from help and use generic term(s) where needed.
* Use SortedOptParser from ansible.utils
* More abstraction of common options used between ansible and
ansible-playbook.
For issue #3372, apply consistent parameter aliases to source_control
modules. For hg, add name and version and add to documentation string.
For subversion, add version and document version and name aliases in
documentation string.
Tests `test_playbook_undefined_varsX_fail` check if ansible detects
undefined variables when `error_on_undefined_vars` is enabled. These
tests fail without "Improve behavior with error_on_undefined_vars
enabled" patch.
Tests `test_playbook_undefined_varsX_ignore` check if ansible ignores
undefined variables when `error_on_undefined_vars` is disabled.
Also modify PlayBook._run_task_internal() so error_on_undefined_vars is
testable.
Pass fail_on_undefined flag to recursive calls to `template` function,
so more undefined variables are detected.
Works only for Jinja style variables. Undefined legacy variables are
never detected.
Previously, hostvars would only expose a keys() list of hosts that had
been seen yet- however you could explicitly access the host if you knew
the name, and get the content that way. This precludes template code
from being able to safely access information about other hosts if any
limiters/tags were in use.
Additionally, the object was inconsistent for hostvars['myhost'] access
and [x[1] for x in hostvars.items() if x[0] == 'myhost'] access; this is
due to the original derivation from the dict object. .items() would be
handled by dict.items(), using the passed in setup_cache values without
using the actual lookup content.
This patch rebases the class implementation to a py2.6 dictmixin, fixing
those issues and restoring behaviour to match what the docs claim.
For link-local addresses, it is sometimes necessary to append the
interface to use for the ipv6 address. This patch extends the ipv6
regex to allow for '%ifnameX' at the end.
See https://bugzilla.redhat.com/show_bug.cgi?id=136852 for more info
Due to various inconsistencies of ssh and sftp regarding ipv6 and
ipv4 handling, some special arguments must be passed, and the
ipv6 must be passed in a specific format.
testing with a ipv6 :
ansible -u misc -i '[2002::c23e]:22,' '*' -m ping
fail due to parsing of ':' as a separator of port/ip with ipv4.
This commit add support for properly parsing 2002::c23 and the
bracket notation [2002::ce]:2222
Yum commandline permit to use a wildcard to enable and disable
repositories in the --enablerepo switch, permitting to enable
a complete set of repository at once ( like all rpmfusion, all
update-testing, etc ).
However, this doesn't work in yum due to more stringent checks
that verify that a exact match is given for the name of the
repository , see commit 5c26805.
This commit enhance the check by permitting to test more than
1 repository at a time, thus permitting to use wildcards.
Since deletion do not check the type of image or anything,
and since that's tedious to keep track of the image_id and
just adding noise to add image_id for nothing, this commit
just relax the requirement.
The block that added the original list of roles was indented too far,
and was only being reached if a role had dependencies. This resulted
in roles without dependencies from being added to the list of roles.
Credit goes to looped for reporting and diagnosing the issue.
simplified check_mode
simplified other file attribute handling in link mode
made conditionals clearer
Signed-off-by: Brian Coca <briancoca+dev@gmail.com>
Fixes#3686
Dependencies are enabled by adding a new directory/file named
meta/main.yml to the role. The format of the dependencies are:
dependencies:
- { role: foo, x: 1, y: 2 }
- { role: bar, x: 3, y: 4 }
...
Dependencies inherit variables as they are seen at the time of the
dependency inclusion. For example, if foo(x=1, y=2) has a dependency
on bar(x=3,z=4), then bar will have variables (x=3,y=2,z=4).
Different roles can have dependencies on the same role, and this
variable inheritence allows for the reuse of generic roles quite easily.
For example:
Role 'car' has the following dependencies:
dependencies:
- { role: wheel, n: 1 }
- { role: wheel, n: 2 }
- { role: wheel, n: 3 }
- { role: wheel, n: 4 }
Role 'wheel' has the following dependencies:
dependencies:
- { role: tire }
- { role: brake }
The role 'car' is then used as follows:
- { role: car, type: honda }
And tasks/main.yml in each role simply contains the following:
- name: {{ type }} whatever {{ n }}
command: echo ''
TASK: [honda tire 1]
TASK: [honda brake 1]
TASK: [honda wheel 1]
TASK: [honda tire 2]
TASK: [honda brake 2]
TASK: [honda wheel 2]
TASK: [honda tire 3]
TASK: [honda brake 3]
TASK: [honda wheel 3]
TASK: [honda tire 4]
TASK: [honda brake 4]
TASK: [honda wheel 4]
TASK: [I'm a honda] <- (this is in roles/car/tasks/main.yml)
Provide hints to playbook callers that a playbook execution had
unreachable vs failures. 2 == failures, 3 == no failures, but
unreachable hosts. 0 continues to be all good.
1. Debian Squeeze is supported out of box now.
2. Repository type "deb" or "deb-src" should be explicitly specified.
3. If a source had beed added it must be possible to remove it.
4. PPA can be only used against Ubuntu hosts.
by ensuring all basedirs, plugin paths and extra
paths are handled as absolute paths and are checked
to not add any doubles.
This fixes the corner case where e.g. the user has
an additional plugin path configured to a dir
relative to his playbooks or inventory location,
which also matches the _plugin subdir relative to
one of the basedirs in the play.
For most plugins this doesn't show as an obvious issue
except for callback_plugins, which might fire more
than once. Other plugins (inventory and template
plugins) might unnecessarily be ran twice.
e.g. ansible.cfg has
callback_plugins = ./plays/callback_plugins
and plays/ contains a playbook file:
.
├── ansible.cfg
├── inventory
└── plays
├── callback_plugins
│ └── timestamp.py
└── site.yml
modified: lib/ansible/utils/plugins.py
failed: [127.0.0.1] => {"failed": true, "parsed": false}
invalid output was: Traceback (most recent call last):
File "/tmp/ansible-1376083321.99-111209413777779/nova_compute", line 1176, in <module>
main()
File "/tmp/ansible-1376083321.99-111209413777779/nova_compute", line 239, in main
_get_server_state(module, nova)
File "/tmp/ansible-1376083321.99-111209413777779/nova_compute", line 198, in _get_server_state
private = [ x['addr'] for x in getattr(server, 'addresses').itervalues().next() if x['OS-EXT-IPS:type'] == 'fixed']
KeyError: 'OS-EXT-IPS:type'
This extension was added less than 6 month ago, and so cannot be used on a release
older than Grizzly ( like Folsom ).
Commit of the extension : https://review.openstack.org/#/c/21453/
See https://wiki.openstack.org/wiki/ReleaseNotes/Grizzly#Key_New_Features_2
The existing code was using:
a[b][c[d]]
where a[b] would always exist and c[d] would always exist.
But the nested index would not alway exist, particularly when a DigitalOcean item disapeared.
This changes that nested index to a `get` and properly handles None results.
This bug was present in two spots in this file.
Previous patch was reverted due to the fact that there was an issue
with the results not always being a dictionary (they're sometimes
a unicode string, ie. when the with_items is used with yum). This
minor change corrects that by checking for a dict object.
This plugin will list all your git repositories from a openshift
provider, and allow you to manage them using ansible.
The inventory either use a environement variable or reuse the
existing rhc configuration file if it exist.
to ensure consistent behavior, hosts should look like this:
hosts: webservers:&boston:!rack42
So when applying the host selectors, run those without the "&" first,
then the &s, then the !s.
Closes#3500
When service module is used on unsupported Linux system where init
script is used directly, LinuxService.svc_cmd is None so .endswith()
fails.
Fixes issue #3533
With the command line option "-c local", ansible and ansible-playbook
should never ask for a SSH password even if this is set in the config.
Fixes#3720
Both modules dealing with rax resources should use the same arguments
and environmental variables. The author of rax_clb_nodes did some things
better so sync rax with that effort.
I'm seeing ansible hang when trying to remove a package, and the hung
process is `whiptail` like in #2763. It looks like we only use
`APT_ENVVARS` and `DPKG_OPTIONS` for the `apt` commands in install()
and upgrade(). This change uses them in remove() as well, which fixes
the hang.
and the _meta hash contains a "hostvars", don't call --host hostname for any elements
and just serve them directly for performance enhancements with the external inventory
script and a large number of hosts.
Added support of an optional init method for action modules like rsync that need to alter the connection and other inject data before it's established.
Remove the reference to the unused "termination_list" parameter
in the ec2 module. The instance_ids parameter is the one that contains
the list of instance ids to be terminated.
Boto blindly assumes the us-east-1 region if you don't hardcode a
region in it's config, so you could end up attempting to modify ELB's
in one region from a totally different region. If a region isn't
specified then default to the region that the module is being run
within rather than the default us-east-1 region since it's a pretty
safe assumption that you intend to work on the ELB's within your
current region.
Also throw an error if a specified ELB instance doesn't exist. The old
behavior would be to silently succeed with changed=false, so if you had
so much as a typo in the name of your ELB (or were in the wrong region
like my initial testing) you wouldn't get a clear indication that a
problem had occurred.
"UnboundLocalError: local variable 'branch' referenced before assignment" is
raised in git, line 282, in switch_version.
Exception is raised when version is not branch and version checkout fails.
E.g. when version is nonexistant commit.
Treat errno 13 (permission denied) as one of the special cases in
atomic_move.
This type of error can occur because of sudo'ing to non-root user.
Fixes#3705
This enables sending messages to partychat-like services (e.g. im.partych.at).
This commit also fixes handling of 'to' argument for non-chatroom recipients.
The timeout parameter of glance-image was not being parsed into a
numeric type, causing the following error when specifying timeout:
msg: Error in creating image: unsupported operand type(s) for +: 'float' and 'str'
The apt-key command takes an optional --keyring parameter representing
the path to a specific GPG keyring to operate on. If it's not given,
the command operates on all keyring files, i.e., /etc/apt/trusted.gpg
and /etc/apt/trusted.gpg.d/*.gpg.
This change adds a 'keyring' parameter to the apt_key module and
propagates it down to the apt-key command line. The main use case this
supports is organizing keys for third-party repos into individual
keyrings in /etc/apt/trusted.gpg.d, rather than putting them all in
the default keyring.
Since ansible 1.2, it became possible to place a host_vars
directory in the same directory as a playbook, making it possible
to keep host_vars local to that playbook there. However, due to
python's os.path.dirname, a action such as:
$ ansible-playbook pb.yml
..would not pick up the host_vars as os.path.dirname("pb.yml")
returns "", unlike the unix command dirname that would return
".". Substituting "pb.yml" on the command line with "./pb.yml"
would do the trick, but is not always intuitive. This patch
solves the problem until python solves issue18547 [1].
[1] http://bugs.python.org/issue18547
When revoking privileges from a user, the GRANT OPTION is always
revoked, even if the user doesn't have it. If the user exists, this
doesn't give an error, but if the user doesn't exist, it does:
mysql> GRANT ALL ON test.* TO 'test'@'localhost';
Query OK, 0 rows affected (0.00 sec)
mysql> REVOKE GRANT OPTION ON test.* FROM 'test'@'localhost';
Query OK, 0 rows affected (0.00 sec)
mysql> REVOKE GRANT OPTION ON test.* FROM 'test'@'localhost';
Query OK, 0 rows affected (0.00 sec)
mysql> REVOKE ALL ON test.* FROM 'test'@'localhost';
Query OK, 0 rows affected (0.00 sec)
mysql> REVOKE GRANT OPTION ON test.* FROM 'test'@'localhost';
ERROR 1141 (42000): There is no such grant defined for user 'test' on
host 'localhost'
Additionally, in MySQL 5.6 this breaks replication because of
http://bugs.mysql.com/bug.php?id=68892.
Rather than revoking the GRANT OPTION and catching the error, check if
the user actually has it and only revoke it when he does.
- Update FAQ entry to refer to docsite README and reduce redundancy.
- Add additional info to docsite README: Sphinx building, link to module
documentation reference.
This fixes an asterisk glob problem in get_package_state() where a file
in /root/ could cause shell expansion if it matched the package name.
The actual problem is solved by running with shell=False.
Git is unable to checkout the specified `version` when the repository is
cloned with a reduced history (`depth`). However, if the repository is
already cloned, subsequent git module calls will update the repository
(default update=True), then properly checkout the specified `version`.
To allow the initial call to properly clone the specified `version`, at
the specified `depth`, this patch adds the `--branch` parameter when
cloning the repository.
Add follow parameter to stat module that controls whether to follow
symlinks. It defaults to no.
This then calls os.stat or os.lstat based on the value of follow.
Add lnk_source key/value pair if path is a symlink and follow=no.
Drop the statement that sets isdir=False and islnk=True when path is a
symlink that points to a directory.
Converting the argument list to a string with ' '.join causes
the shell interpreter to misparse spaces in property values.
Since the zfs command does not need shell anywhere, using
a list instead of a string works just as well with run_command.
Fixes#3545.
Current property parser breaks when values contain spaces. Since
zfs get -H returns tab separated lines, it is better to explicitly
split on tabs than on whitespace.
The file module would in some cases return dest=/path/to/file, and in other cases return path=/path/to/file, this change makes it more consistent and in line with all the other file-related modules (i.e. copy, assemble, template, ...) by using dest= instead of path= as the input and output argument. (Of course, path is still there as an alias for compatibility).
Sometimes when using digital_ocean with wait=no I get the error "No ip is found". But with wait=no I wouldn't expect there to be any IP, that gets allocated later. However, looking at the code, it turns out that with even with wait=no it waits up to 10 seconds for an IP to be allocated. We could wait longer, but with wait=no that seems like the wrong choice; it's easy enough to grab an IP later with a wait=yes command.
To make this change I removed the call to update_attr in @classmethod add. An add is always followed by an ensure_powered_on which will do the update_attr if wait=yes. It would be possible to instead do a call to update_attr with no retries and ignore the errors but I figured it would be better to be consistently not return an IP than to sometimes return it and sometimes not. Inconsistent behaviour makes debugging deployment scripts very difficult.
This diff syncs package_latest() with the changes to package_present().
I have not managed to figure out how to handle the cornercases where
stderr is set but the command has not failed, so leave a FIXME blob for
other adventurers.
* Add '-m' to pkg_add incovation to get access to the "packagename-1.0: ok"
message.
* Watch for that message if we are about to fail because of stderr in
package_present().
The keystone client needs to be passed tenant_name when authenticating the
user/password way. Also it needs auth_url instead of endpoint.
This fix adds login_tenant_name as a module parameter which is consistent
with the other OpenStack modules.
This fixes a problem when trying to install a package with a specific version
number from a local directory and the local directory is checked after a remote
repository:
Error from http://ftp.eu.openbsd.org/pub/OpenBSD/[...]/packagename-1.0.tgz
ftp: Error retrieving file: 404 Not Found
packagename-1.0: ok
Bugs:
(1) no longer allow empty jobs
(2) strip the header added by crontab package used in openSuSE and SuSE
(3) try not to leak temp files when things go wrong
(4) issue returning job names under certain conditions
Enhancements:
(1) Allow all special times not just reboot.
(2) Fail earlier by performing more input validation
(3) Add feature to allow removing cron file under /etc/cron.d
ToDo:
(1) Validate times (minute, hour, ...)
(2) Strip white space from fields such as name and job such that name=foo equals name=' foo'.
(3) More testing
-c ssh is preferred in most cases if you have ControlPersist available, otherwise if you are comfortable you
can turn off recording while leaving host key checking on, etc.
Use case: e.g. dual homed hosts on production en management network
The inventory_hostname is the regular host name and matches the
dns name on the production network; ansible connects to the host
through a management network; the dns name on the management network
is standardized and equals ${inventory_hostname}-mgt.mynetwork.com
Now this can be configured as the default in group_vars/all:
ansible_ssh_host: {{ inventory_hostname + '-mgt.mynetwork.com' }}
The `dopy` library function all_images includes a 'global' filter
by default. This was preventing private images from showing up
in --images.
The problem also made this script fail immediately for people
who had droplets previously created with private images.
str() throws an UnicodeEncodeError for code points that cannot be
represented in 7-bit ASCII. This makes it impossible to use any
non-ASCII characters in module arguments. Using encode('utf-8')
gives the desired result.
Adds more parameters which may be passed to supervisorctl: config,
serverurl, username, password
Also refactored the various `module.run_command(build_a_string)` calls
into a single `run_supervisorctl` function.
Some services have a knob (i.e. rc.conf setting) whose name
differs from that of the script. For example, lockd process
is controlled with a script called lockd, but the rc.conf
value is rpc_lockd_enable.
Fixes issue #3382.
* Always refresh droplet information (versus getting it from cache) for
--list, --host, --droplets, and --all. All the DigitalOcean calls are
pretty fast and without this change, inventory was often stale/incorrect.
For example, previously if you destroyed a droplet, the inventory
script would still find it and attempt to act on it.
* Added --force-cache option
* Added some option shortcuts -d, -r
* Added more value sanitization
* Moved the --list-hosts option that is common to both `ansible` and
`ansible-playbook` into utils/__init__.py (corrects a FIXME)
* Wrote new help text for the --list-hosts option that makes sense
for both of the commands that it applies to
* Changed the usage argument in `ansible-playbook` so that it is
setup in the base_parser method the same way that it is in
the `ansible` executable
* Updated the help text for several options to correct typos,
clarify meaning, improve readability, or fix grammatical errors.
In the case of `ansible-pull`, I changed the help text so that
it adheres to the same standards as the other executables.
The action doesn't actually change anything on a system, so setting
the status to changed is wrong. add_host is much like set_fact in that
regard.
Since changed is False by default, there is no need to explicity set
it, so just create an empty dict for result and add to it from there.
Previously, a configuration file name of None was being passed into
up2dateInitConfig(). This resulted in a correct configuration import,
but failed to properly save the configuration back to disk in the event
a different serverURL was supplied. This change removes support for
customizing the up2date filename entirely, and relies on up2date to
choose the default config filename.
Syntax like "'foo' if bar else 'baz'" is not supported by all Python
versions targetted by Ansible. Hence we break it up.
Signed-off-by: martin f. krafft <madduck@madduck.net>
ansible.constants was calling expanduser (by way of shell_expand_path)
on the entire configured value for the library and *_plugins
configuration values, but these values have always been interpreted as
multiple directories separated by os.pathsep. Thus, if you supplied
multiple directories for one of these values, typically only the first
(at least on *nix) would have e.g. "~" expanded to HOME.
Now PluginLoader does expansion on each individual path in each of
these variables.
When update-rc.d is used to enable/disable service, the changed flag was
always true (see #2189). This commit fixes that.
Signed-off-by: martin f. krafft <madduck@madduck.net>
This does two things:
* add --recursive option to git clone command in clone(). This will
initialize all submodules when cloning a remote repository.
* Add submodule_update() and call that from fetch(). submodule_update()
calls two git commands iff the file .gitmodules exists in the
repository:
* 'git submodule sync' - synchronizes the submodules' remote URL
configuration setting to the value in .gitmodules.
* 'git submodule update --init --recursive' - initialize and update
registered submodules to the commit specified in the index of the
containing repository.
If a repository was cloned without --recursive, submodule_update() will
ensure that the submodules are initialized and updated.
This replaces double conditional brackets with single ones and gets ris
of bashisms, so that the tool should be sourcable from any POSIX shell.
Constructs like [ $foo = "$bar"* ] yield filesystem-globbing behaviour
according to POSIX. A compliant way is to use case statements.
Signed-off-by: martin f. krafft <madduck@madduck.net>
In case paths contain spaces, it's better to consistently quote
variables, and to use $() instead of `` for external invocations.
Signed-off-by: martin f. krafft <madduck@madduck.net>
dirname/basename do not need an external process, shell variable
expansion can be made to do the same a bit faster.
Signed-off-by: martin f. krafft <madduck@madduck.net>
The env-setup script is not intended to be run directly, so it does not
need a shebang line, which might even create the wrong expectations.
Signed-off-by: martin f. krafft <madduck@madduck.net>
A host pattern of the form '!foo' by itself does not work, but
'all:!foo' does. If the first pattern is a negation, this commit
automatically prepends 'all'.
Signed-off-by: martin f. krafft <madduck@madduck.net>
A small error in the reuse of a variable caused packages to never get
purged. This commit fixes that.
Signed-off-by: martin f. krafft <madduck@madduck.net>
Older python-apt modules don't export Package.installed_files and there
seems to be no other way to figure out if a package is
removed-but-not-purged, so we just always assume it's purged.
Signed-off-by: martin f. krafft <madduck@madduck.net>
A package may be removed but not purged with APT. The only way to
identify this state is by looking at the list of installed files of
a package. Even if the package has no files installed, this list will be
non-empty until the package is removed:
# python -c "import apt; c=apt.Cache(); c.update(); c.open(); p=c['ruby1.8']; print p, p.installed, p.installed_files"
<Package: name:'ruby1.8' id:1425> None [u'']
# dpkg --purge ruby1.8
(Reading database ... 27904 files and directories currently installed.)
Removing ruby1.8 ...
Purging configuration files for ruby1.8 ...
# python -c "import apt; c=apt.Cache(); c.update(); c.open(); p=c['ruby1.8']; print p, p.installed, p.installed_files"
<Package: name:'ruby1.8' id:1425> None []
See http://bugs.debian.org/712749 too.
If a package is not marked installed but it still 'has_files', then it
should be processed if the request is to purge it.
Signed-off-by: martin f. krafft <madduck@madduck.net>
A small error in the reuse of a variable caused packages to never get
purged. This commit fixes that.
Signed-off-by: martin f. krafft <madduck@madduck.net>
name is used throughout Ansible, it's the "standard". This change
applies that standard to the add_host routine and updates the docs to
reflect that. Related to https://github.com/ansible/ansible/pull/3254
On machines with multiple pci domains get_device_facts would fail to
find a matching pci device causing setup to fail. Also on some platforms
there is additional information between the pci information and 'host'.
Modified get_device_facts to call lspci with the -D option and modified
the regex to account for the pci domain and to be more selective.
commit c36b66dc952dfff91043ecbca56cf3f1f8f00703
Merge: 240d7bff4cf934
Author: Michael DeHaan <michael@ansibleworks.com>
Date: Tue Jun 18 13:04:51 2013 -0400
Merge branch 'unevaluated-vars' of git://github.com/lorin/ansible into lorin_undefined
Conflicts:
lib/ansible/runner/__init__.py
commit f4cf934367
Merge: 253144007a1365
Author: Lorin Hochstein <lorin@nimbisservices.com>
Date: Thu Jun 6 11:07:41 2013 -0400
Merge branch 'devel' into unevaluated-vars
commit 253144045c
Author: Lorin Hochstein <lorin@nimbisservices.com>
Date: Thu Jun 6 11:06:37 2013 -0400
Fail template from file on undefined vars
If config option is set, raise an exception if templating from a
file and a variable is undefined.
commit aecb71d8b7
Author: Lorin Hochstein <lorin@nimbisservices.com>
Date: Wed Jun 5 17:12:12 2013 -0400
Add fail_on_undefined flag
Add a fail_on_undefined flag to the template and template_from_string methods.
If this flag is true, then re-raise the ninja2.excpetions.UndefinedError instead of
swallowing it.
commit cbb1808f05
Merge: d4bbf4941425fb
Author: Lorin Hochstein <lorin@nimbisservices.com>
Date: Wed Jun 5 16:14:12 2013 -0400
Merge branch 'devel' into unevaluated-vars
commit d4bbf492b0
Author: Lorin Hochstein <lorin@nimbisservices.com>
Date: Mon Jun 3 19:46:13 2013 -0400
template: Raise UndefinedError exception
In template_from_string, raise an undefined error if it occurs.
Have the caller catch it and throw an AnsibleUndefinedVariable
commit c947802805
Merge: 8d919d6be33bcf
Author: Lorin Hochstein <lorin@nimbisservices.com>
Date: Mon Jun 3 10:09:43 2013 -0400
Merge branch 'devel' into unevaluated-vars
commit 8d919d6c97
Merge: 0f68ad8b8630d2
Author: Lorin Hochstein <lorin@nimbisservices.com>
Date: Thu May 30 16:27:48 2013 -0400
Merge branch 'devel' into unevaluated-vars
commit 0f68ad8193
Author: Lorin Hochstein <lorin@nimbisservices.com>
Date: Thu May 30 14:32:03 2013 -0400
Optionally fail task on undefined variables
This patch introduces a new configuration option called
error_on_undefined_vars, which defaults to false.
If this option is set to true, then a task which has unevaluated
variables in its arguments will fail instead of running. Output looks
like this:
TASK: [set rabbitmq password] *************************************************
fatal: [10.20.0.7] => Undefined variables: rabbitmq_user, rabbitmq_password
hardcoded lists in ansible code, just add WITH_ITEMS_USES_LIST in a
comment anywhere, and of course, support recieving params as list.
Signed-off-by: Brian Coca <briancoca+dev@gmail.com>
Migrated all examples: in DOCUMENTATION=''' string to standalone EXAMPLES=''' string
Added deprecation warning to moduledev.rst and remove deprecated example from it
Fixed up a few typos and uppercased some acronyms.
add consistency to how EXAMPLES are formatted
this works well for 'initial password setting' on user creation and avoids
having extra tasks and conditionals.
Signed-off-by: Brian Coca <briancoca+dev@gmail.com>
The biggest change has been to package_latest since it was previously
just comparing version numbers before and after an upgrade had run.
We now parse the output from a dry run instead.
Thanks to Johan Belin for triggering the discussion :).
- The html_ify filter now escapes HTML found in module documentation.
THIS COULD AFFECT MORE THAN JUST MARKDOWN but I didn't see any modules
expecting to use e.g. HTML entities or HTML tags in their
documentation.
- The markdown_ify filter (used as jpfunc in markdown.j2) escapes at
least a few Markdown in-line formatting characters.
- Improvements to markdown.j2:
- Call jpfunc on the module name heading so that it gets escaped for
Markdown (e.g. my_module_name becomes my\_module\_name).
- Added paragraph breaks between paragraphs in the description.
- Added examples heading, which is consistent with the notes heading
below it.
Previous commit c3659741 expanded sudo_user during task construction,
but this is too early as it does not pick up variables set during
the play.
This commit moves sudo_user expansion to the runner after variables
have been merged.
'source' is actually a "bashism" and the POSIX-way of sourcing a file
uses the single dot (which is arguably less readable). Both yield the
same result, and since the script may now also be sourced from
within the hacking directory, this commit expands the usage synopsis
accordingly.
Signed-off-by: martin f. krafft <madduck@madduck.net>
Conflicts:
hacking/env-setup
Bash needs a special case to determine the dirname of the sourced path
(the hacking dir), but in all other cases, using $0 allows the script to
be sourced also from within the hacking directory, not only from its
parent.
Signed-off-by: martin f. krafft <madduck@madduck.net>
In MySQL 5.6, the root account created by default during MySQL
installation has the PROXY ... WITH GRANT OPTION privilege for ''@'',
that is, for all users.
The mysql_user module tries to revoke this privilege, but this fails:
_mysql_exceptions.ProgrammingError: (1064, "You have an error in your
SQL syntax; check the manual that corresponds to your MySQL server
version for the right syntax to use near '''@'' FROM 'root'@'localhost''
at line 1")
Quick fix: don't revoke privilege if user is root and the privilege to
revoke contains PROXY.
Link to the Inventory & Patterns page in places where the Getting
Started guide refer to it, so that users unfamiliar with the
inventory syntax can easily familiarize themselves with it.
* Clarified the meaning of 'user'
* Changed 'sshdir' to 'path' in the example
* 'sshdir' is used internally in the module, but the argument is 'path'
* Made the capitalization consistent in the descriptions
rhnreg_ks command allows users to manage registration to a Red Hat
Network (RHN) (e.g. rhn.redhat.com) server. The moduel will also
interact with the specified RHN system via XMLRPC as needed.
Before proceeding with registration, the rhnreg_ks module will enable
the system to receive updates from RHN. This involves enabling the
appropriate RHN yum plugin, as well as disabling an active
subscription-manager yum plugin.
Once enabled, the module will support the following operations:
* configure
* register
* subscribe to custom child channels (see `rhn-channel` command)
* unregister
e.g. db[01:10:3]node-[01:10]
- to do this we split off at the first [...] set, getting the list
of hosts and then repeat until none left.
- also add an optional third parameter which contains the step. (Default: 1)
so range can be [01:10:2] -> 01 03 05 07 09
The subscription_manager module acts as a wrapper to the command
'subscription-manager'. The subscription-manager utility allows users
to manage RHN registration, subscription and yum repositories from the
Red Hat Entitlement platform.
Currently, this module supports the following sub-commands:
* config
* [un]register
* subscribe
Add option to specify inventory. No default is defined since
ansible-playbook already does this and it allows an ansible.cfg in the
git repository to take precedence.
Overall, this should help ansible-pull work with less setup in advance,
which should be helpful in kickstart scenarios. Much of this was
discussed in issue #2464.
A recent change to ansible-playbook to support json extra-vars
also inadvertently broke the script when no extra-vars are
provided. Simply checking to make sure it is defined and truthy
should take care of the issue.
When invoking dmidecode, first use module.get_bin_path() and secondly
use module.run_command.
Remove sub function execute() from get_dmi_facts().
Simplify get_dmi_facts() by only using two mechanisms to determine dmi
facts: first try /sys/devices/virtual/dmi and if not available, use
dmidecode executable.
If someone has a " #" in a quoted var string, it
will interpret that as a comment and refuse to
load the inventory file due to an unbalanced
quote. Noisy failure > unexpected behavior.
When running inside a chroot userspace architecture might not
match that of the actual host.
This patch provides userspace_bits as reported by python's
platform.architecture(). Also provides userspace_architecture fact
if host is an x86 machine.
Also consolidated duplicate groups code into one get_groups_set() method.
Removed unused call to user_group_membership.
Removed sorting operations on set functions cause sets are inherently unordered.
Minor style improvements to match the rest of the code.
The new function will make the order of group names passed to the system command less determistic.
Which was already the case for modify_user_usermod() but not for other methods.
It will also strip out duplicate group names automatically which was not always the case previously.
This commit fixes a bug where the authorized_key module causes
the ~user/.ssh directory to be owned by root instead of the user,
when the manage_dir argument is not specified.
If the manage_dir argument was not specified, the module behaved as if
manage_dir was set to false, even though it's supposed to default to
true.
This module assumed that an optional argument, with no default
specified, will not be present in the module.params dictionary.
What actually seems to happen is that the argument does appear in
the module.params dictionary with a value of None.
The upside is that this line was evaluating to None instead of
true:
manage_dir = params.get("manage_dir", True)
I fixed the problem in this particular module by explicitly specifying
the default value for the manage_dir arugment. But if this bug
occurred because of a change in behavior in AnsibleModule, then other
modules may be broken as well.
The OpenStack Inventory script uses the OS-EXT-IPS:type parameter
to distinguish between fixed and floating IP addresses.
This was only added in the Grizzly release, see
https://bugs.launchpad.net/nova/+bug/1117784
Specify in the docs that this inventory script requires Grizzly
or greater.
Previously setting force=no caused copy to subversively
fail when target did not exist on remote host.
Caused by Runner._remote_md5 returning 1
when files don't exist, rather than 0.
Defines memory and CPU facts:
- memfree_mb
- memtotal_mb
- swapfree_mb
- swaptotal_mb
- processor (a list)
- processor_cores
- processor_count
- devices
As a matter of fact, on NetBSD, it is possible to get memory, swap and
processor facts exactly as on Linux. Tested on NetBSD-5, NetBSD-6 and
NetBSD-6.1 (without Linux emulation).
PluginLoader._get_paths, as of 391fb98e, was only finding plug-ins that
were in a subdirectory of one of the basedirs (i.e. in a category
directory). For example, action_plugins/foo.py would never be loaded,
but action_plugins/bar/foo.py would work.
This makes it so that "uncategorized" plug-ins in the top level of a
directory such as action_plugins will be loaded, though plug-ins in a
"category" subdirectory will still be preferred. For example,
action_plugins/bar/foo.py would be preferred over action_plugins/foo.py.
If a variable was provided for an include, in either of these ways:
---
- hosts: all
tasks:
- include: included.yml param=www-data
- include: included.yml
vars:
param: www-data
and then that param was used as the value of sudo_user in the included
tasks:
---
- name: do something as a parameterized sudo_user
command: whoami
sudo: yes
sudo_user: $param
you would receive a "failed to parse: usage: sudo" error back and the
command would not execute.
This seemed to be due to a missing call to template.template somewhere,
because the final value being passed through ssh was still `$param`.
After some digging, the issue seems to instead have been a problem with
providing the wrong context to the template for expansion. Inside the
`Task` logic, it was passing `play.vars` as the context, where
`module_vars` seemed more appropriate. After replacing it, my test case
above ran without issue. There was a comment above suggesting that the
template call might be unnecessary, but removing it made the original
error return, since it is not getting escaped later down the line. I
removed the comment since it was inaccurate.
I tried to actually incorporate my test case above into the test suite
as a regression test, but was unable to figure out how to structure it.
The existing test infrastructure seemed to only be testing for correct
number of counts in things (ok vs. changed, etc.), without regard for
whether the content generated by the command is correct. If there is an
example of a test similar to this one (where I would want to check the
JSON generated to make sure sudo_user had been converted), please let me
know and I will be happy to submit an additional patch.
Excplicity set paramiko's logging level to WARNING.
By default it inherits ansible's DEBUG logging level (set in
callbacks.py) and fills the log file with useless debug messages.
Obviously it only applies if log_path is set in ansible.cfg
This code:
```
if name.endswith('.tar.gz') or name.endswith('.tar.bz2') or
name.endswith('.zip'):
is_tar = True
```
was not checking whether name is defined since it is an
optional param.
**Summary**:
There was a bug in the previous commit; pip module would add --use-mirrors options to a source package when state is absent. The bug is resolved in this commit by checking ``not is_package`` in the if branch.
Furthermore, in order to support non-vcs source name like tarballs, we must not add -e option to the arg list. Given this circumstance, this commit have is_tar and is_vcs and the latter is checked to add -e option. Since mirrors do not make sense with vcs or tarball source, this commit will not add --use-mirrors (default to True) as always.
And also be liberal in what ansible-doc accepts as an empty
requirements specification.
While here fix a typo in template module documentation
wrt jinja2 overrides example.
Added new parameter 'encrypt' with same semantics from that of
vars_prompt. When encryption is requested a random salt will be
generated and stored along the password in the form:
'<password> salt=<salt>'.
Also store passwords with an ending '\n' for easier looking at files
with console tools. File content was being already rstripped so this
is harmless.
This will allow just making sure the repo exists w/out actually making
any chnages to it. Useful if you're going to run a play repeatedly
against a host that might have active development going on in the
repository (think initial bootstrap of a developers system, and
continued playbook runs to work on other projects).
I have something like:
apt: pkg={{ item }} state=present
with_items:
- python-pysqlite2=2.6.3-*
- python-paramiko=1.7.7.1-*
But due to the use of *'s in the version specifications, the apt ansible
module always reports changed: true. This patch fixes that.
New binary package management should be the default soon in FreeBSD, and
is already fully useable through self generated and non official binary
repositories.
- add support for pkgng
- support specifying the repository url as a parameter
- allow not to update cache
Signed-off-by: bleader <bleader@ratonland.org>
Summary:
Pip module would abort when name is a remote package address because
the module was expecting a version if ``=`` is part of the name value.
Furthermore, the pip module would require either name or requirement to
be a key, although the documentation table said neither was required.
The fact that one of them must be present is not documented in the
documentation leads to confusion. This commit added this fact as part
of description.
In this commit, we resolve the confusion by stating either ``name``
or ``requirement`` is needed. Next, if the user puts remote address
as the value of the ``name`` key, we will not use mirror. Lastly,
if the user uses the remote serivice address as the name of the
package and the user does not supply -e option in extra_vars
(which is the whole point of this commit), we will add -e to
extra_vars so pip command can run with -e option.
From issue #2820, --start-at-task does not actually run tasks
unless --step is specified. This appears to be because skip_task
is being evaluated as True in PlayBook._run_task(). This patch
ensures skip_task is set to False in the callback.
This is intended to fix#2810. It sets the context of the tmp_dest file
after shutil.move() operation and before os.rename(). This should
retain the selinux context of the file across moves.
This module handles AWS EC2 ELB registration.
* De-registration requires the instance id which can be looked up using
the ec2_facts module.
* Registration requires both the instance id and the elbs that the
instance belongs to.
De-registration will return an ec2_elb fact that can be used for
registration in post_tasks.
Author: Ton Kersten <github@tonkersten.com>
Date: Mon Apr 29 10:44:30 2013 +0200
Fixed the installation of library directories
When running install the `setup.py` give error
changing mode of /usr/bin/ansible-doc to 755
running install_data
error: can't copy './library/utilities': doesn't exist or not a regular file
make: *** [install] Error 1
Debugging 'benno' came up with this patch, which works on CentOS 6.4 and
on Ubuntu.
This implementation falls back to python-dmidecode (RHEL5.5+) if the kernel as no DMI support. Alternatively, if python-dmidecode is missing, we attempt to use the dmidecode binary (for RHEL5.4 and older) before giving up.
This fixes#376 and #1657 and also helps @lwade on RHEL5.5+.
There are various cases where a UID to username to UID mapping breaks
down. One UID can be used by two usernames, or no username. If we
always use UIDs internally, then these ambiguous cases won't be a
problem.
This implementation falls back to python-dmidecode (RHEL5.5+) if the kernel as no DMI support. Alternatively, if python-dmidecode is missing, we attempt to use the dmidecode binary (for RHEL5.4 and older) before giving up.
This fixes#376 and #1657 and also helps @lwade on RHEL5.5+.
The old test used syntax that appeared to be bash-specific and did not
work on platforms where /bin/sh did not point to bash. See issue #2742
where copy to solaris hosts failed with the error:
output: {'stdout': '', 'stderr': '/bin/sh: test: argument expected\n',
'rc': 1}
Link people right to this page on Github, so they can click "edit" right there. No need for them to search for the repo, figure out that the docsite isn't a separate repo, and navigate to the given dir.
This fixes#2632. Briefly: specifying things like paths using complex
args in a playbook will make the objects unicode instances. The selinux
module does not accept unicode instances for its char * arguments; it
wants str instances.
Per mpdehaan's comment on #2632 I just went ahead and converted all
paths to UTF-8. I don't know if it would be better to do something like
converting to locale.getpreferredencoding(), but I factored all the
conversions out into new method _to_filesystem_str, so there's only one
place that needs to be changed in the future.
This module allows you to set host facts (or export play variables to the playbook scope if you fancy that).
The module also accepts complex arguments.
```yaml
- action: set_fact fact="something" global_fact="${local_var}"'
- action: set_fact
args:
fact: something
global_fact: ${local_var}
```
- add a skip option so it won't raise an exception if you don't match anything
- make it work as a drop-in replacement for first_available_file
- document in the module comments all of the above cases
AR function was leaving some tmp files behind, want to revert, will have better implementation soon, this is the old way now.
This reverts commit f74a1fa4f0.
Lookup plugins 'sequence' and 'template' now import 'ansible.utils'
appropriately in order to use the 'listify_lookup_plugin_terms'
function.
Also, 'dnstxt' and 'env' now check to see if 'terms' is a string;
without this calls like '{{ lookup('env', 'HOME') }}' fail.
The copy action accepts force=no, which tells it not to replace an
existing file even if it differs from the source. The copy action
plug-in wasn't respecting this option when operated in check mode, so it
would report that changes are necessary in check mode even though copy
would make no changes when run normally.
Runner._remote_md5 was changed to make the logic for setting rc perhaps
a little more clear, and to make sure that rc=0 when the file does not
exist.
Look for a file with the base name of the group/host, first without
a file extension, then with a '.yml' extension, and, finally, with
a '.yaml' extension, loading vars from only the first one found.
This Module allows to manage privileges on PostgreSQL database objects
(currently: tables, sequences, functions, databases, schemas, languages and
tablespaces) as well as group role memberships.
It is basically a wrapper around most of the functionality of PostgreSQL's
GRANT and REVOKE statements with additional detection of changes and support
for dry-runs (check-mode).
postgresql_privs should work with PostgreSQL 8.4 and above. Python Module
psycopg2 is required on the remote host.
Return public SSH key if the user module is called with generate_ssh_key=yes.
Since "user" doesn't overwrite files, this also allows querying of existing
public keys.
Used in playbooks together with the "register" keyword, the returned key can be
passed to the "authorized_key" module allowing easy setup of SSH public key
authentication between remote hosts.
As documented in #2623, early variable substitution causes when_
tests to fail and possibly other side effects.
I can see the reason for this early substitution, likely introduced
in 1dfe60a6, to allow many playbook parameters to be templated.
This is a valid goal, but the recursive nature of the utils.template
function means that it goes too far.
At this point removing tasks from the list of parameters to be
substituted seems sufficient to make my tests pass. It may be the
case that other parameters should be excluded, but I suspect not.
Adding a test case. I would prefer to analyse not just the aggregate
statistics but also whether the results are as expected - I can't
see an easy way to do that with the available callbacks at present.
Technically this isn't quite valid YAML when this happens, so we make it valid. This means that if a future commander
API allows save/load it should make sure it does similar processing.
evaluate and replace '$item' with ''. Really it doesn't make sense to include multiple playbooks
via a loop variable, as you can do this with task + with_items already (and it's a simpler code
path). Given this is undocumented, this removes that feature, and we'll consider next how to
also add 'with_items' support directly to roles.
This allows the password to contain single quotes and should make it safe to
use randomly generated passwords (provided passwords can be represented in the
connection encoding).
When operating on a unicode string in python 2.6, shlex.split returns
a result that does not work with the file constructor.
To reproduce this requires a task include that is templated (this is
because the templated string is a unicode result, whereas a non-
templated string is a non-unicode string)
[will@centos6.3] $ python
Python 2.6.6 (r266:84292, Sep 11 2012, 08:34:23)
[GCC 4.4.6 20120305 (Red Hat 4.4.6-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import shlex
>>> shlex.split(u'abc')
['a\x00\x00\x00b\x00\x00\x00c\x00\x00\x00']
[will@fedora17] $ python
Python 2.7.3 (default, Jul 24 2012, 10:05:38)
[GCC 4.7.0 20120507 (Red Hat 4.7.0-5)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import shlex
>>> shlex.split(u'abc')
['abc']
The proposed fix (coercing the include parameters to string before the
shlex.split) may not be ideal but it does fix the bug for my test case.
python-selinux can't be installed w/ the yum module when missing.
Revert "Added an extra check for target nodes with selinux but without libselinux-python package installed"
This reverts commit 550986b6a1.
Use DEFAULT_EXECUTABLE when no executable is passed to
_low_level_command_exec
Works as a standard constant - can be overridden in all the normal ways
and defaults to /bin/sh
Motiviation is for a user that only has /bin/bash in /etc/sudoers
Use aptitude safe-upgrade instead of apt-get upgrade to implement
apt: upgrade=yes. Using aptitude ensures that missing dependencies
will also be installed.
Fixes#2540
Files can be inserted during server creation (like a fully formed
authorized_keys file). This code allows that to happen.
Docs were updated for formatting, location, and to add the new entry for
files.
The rax inventory plugin provides a way to discovery inventory in the
Rackspace Public Cloud by way of pyrax, the official SDK. Grouping will
be done if a group:name is found in the instance metadata. When a single
host is queried all the instance details are returned with a rax_
prefix.
Because inventory plugins cannot take extra arguments, ENV variables
must be set to point to the pyrax compatible credentials file and the
region to query against.
This library provides functionality for the Rackspace Public Cloud by
way of the official pyrax SDK (https://github.com/rackspace/pyrax). At
this time only the cloudservers service is functional. Instances can be
created or deleted. Idempotency is provided on matching instances with
the same name, flavor, image, and metadata values within a given
region.
pyrax usage does require a credentials file written out to hold username
and API key. See pyrax documentation for details
(https://github.com/rackspace/pyrax/blob/master/docs/pyrax_doc.md)
differnt from the current user. This should enable overrides for user in
.ssh/config w/o breaking any current functionality.
Signed-off-by: Brian Coca <briancoca+dev@gmail.com>
In the example, you want /bin/true to be executed if the first command has an error return code. Combining command with && will run the second only if the first is successful. Combining them with ||, the second will be run only of the first fails, what is wanted here.
Remove leading/trailing single or double quotes when parsing the my.cnf
file in mysql_user and mysql_db.
Do this so that these modules parse the my.cnf file the same way that
the mysql client does.
From: http://dev.mysql.com/doc/refman/5.0/en/option-files.html
You can optionally enclose the value within single quotation marks
or double quotation marks, which is useful if the value contains a
“#” comment character.
Fixes#2405
Allow the specification of additional locale settings (lc_collate and lc_ctype) when creating a new database (state=present).
Fail if the specified database already exists with different locale/encoding settings. (These settings can't be changed for existing databases as far as I know, and failing seems better than suggesting that no change was necessary by returning changed=False)
See issue #2471
This fixes get_remote_head() to be smarter about how to check remote
head. It checks if it is a remote branch or tag and then checks for the
remote object id associated with it. If it is sha1, get_remote_head()
returns it as-is since there doesn't appear to be a way to check a
remote repository for a specific object/sha1. is_remote_tag() is added
to help out the new functionalit in get_remote_head().
In main(), if check_mode is true and version is a sha1, the module now
checks to see if the object is present.
This fixes handling of arguments (module argument) in service_control().
It is now locally scoped such that modifications to it, in the case of a
systemd host, do not later impact subsequent calls to service_control().
See issue #2449.
Without patch:
ansible-service[6177]: Command /usr/bin/systemctl stop cups cups , daemonize True
With patch:
ansible-service[6475]: Command /usr/bin/systemctl start cups , daemonize True
I also updated the comments to reflect the case where systemd is really
being called.
This makes the log message the same, whether it is sent to systemd's
journal or to syslog. It retains the extra fields that are passed to
journal, such as MOUDLE=<name> and additional arguments. Since journal
will reflect messages to syslog, this keeps what goes to syslog
informative instead of the terse 'Ansible module invoked'.
See issue #2461.
The text parameter can contain non-ASCII characters, so we'll encode it
using UTF-8. For example the DOCUMENTATION of the bzr module has such
characters in the name of the author.
When using a .my.cnf file, when there is no user variable defined,
default to the login user.
This change has the mysql_user module behavior match the behavior
of the mysql command-line client.
Also adds an example .my.cnf to the docs.
Related to issue #2114. This hooks in check_mode to git module. This
will exit with changed=True at the following places:
* If the repo has not been cloned
* If the destination has local modifications, this will exit with
changed=True. This is because reset() will exit anyways if there are
local mods and force is False.
* If the remote HEAD commit id is not the same as that of the local HEAD.
This is determined by get_remote_head() that runs 'git ls-remote' to
determine remote HEAD.
Lastly, if this is run with check_mode enabled, this will exit with
changed=False before fetch() is invoked so that no local mods are made.
* As the FIXMEs note: only exit if enable state is going to change.
* This is already handled in service_enable_rcconf() being called by both subclasses.
Both modules seboolean and zfs have not been adapted since they defer from the default (either by having a 'null' or special state, or prefering "on"/"off" for state indication.
Arch python binary patch was broken since improvement in 785068d. This
change fixes patch, removing most of the lines thanks to the new PYTHON
variable.
New source file already uploaded on AUR.
Adds note on python 3 incompatibility
Added note about ansible_python_interpreter for people having python3 as default interpreter (mainly Arch users ?)
Should fix#2344
Adds needs_update() method which will inspect the checkout for the
current revision and then the HEAD. If the local check out is behind
HEAD, this will report changed=True and supply the revision numbers.
Fixed typo in passlib URL link
Fixed style in cryp scheme list
Fixed bullet 7 in variable precedence section
Adds statement regarding passlib requirement
As it used to be before, 'make rpm' from a cloned repository should work without the need to run hacking/env-setup. It's an easy fix, in line with what we already did for the man-pages.
The uri module can be configured to abort after a specified timeout if
it cannot connect to the configured uri. This prevents a uri action from
hanging indefinitely when the remote endpoint cannot be reached because
it is unavailable, there is a firewall in place etc. The default behavior
is left unchanged: timeout=None
This change also introduces a new type for module_parameters: int
Code was added to perform conversion from string -> int type in
module_common.py.
The new type was required in order to play nice with httplib2 which
refuses to accept (and convert) anything other than a numeric type for
the timeout value.
* Code influenced by the service module but without classes.
* Thanks to @dhozac for input and review.
* Thanks to @johanwiren for getting me to push this out the door.
This commit makes the Makefile nicer for packagers so they can select versions
of python. E.g. on a RHEL5 system with Python2.6 (installed from EPEL)
make PYTHON=python2.6 install
Added a Darwin family, commit acc1c004 had added some network facts
but weren't being shown as the Darwin family wasn't in use. This commit
reveals these facts.
A Darwin(Hardware) class has also been created ready to be populated with
hardware facts.
commit 076501459322cf6c14de742e504339d80ffdeed5
Author: Ton Kersten <tonk@tonkersten.com>
Date: Thu Feb 28 21:32:57 2013 +0100
Added date and time facts to setup
commit e057ea671395ec8847f920a63cf9524f5c8fde5f
Author: Ton Kersten <tonk@tonkersten.com>
Date: Thu Feb 28 13:02:25 2013 +0100
Fixed the service command not working
On Ubuntu 1[02].04 the service name was not recognized because
there is a SysV style init script, but not an upstart config file.
Example: The `ntp` client.
Also removed extra spaces at the end of the lines, while at it.
When running ansible -C, I get a traceback that ends with
AttributeError: Values instance has no attribute 'diff'
This fixes on_file_diff to behave similar to
PlaybookRunnerCallbacks.on_file_diff().
This updates the following modules to support check_mode:
* apt_key
* apt_repository
* easy_install
* pip - will always report changed due to the way it handles state
* seboolean
* selinux
* slurp - since nothing changes, it just adds that it supports
check_mode
* subversion - reports changed when checking out new repo and
when updating.
* supervisorctl
* svr4pkg
See issue #2114.
really due for some refactoring, but telling how a service is managed is
a little fuzzy anyway. on a systemd system typoing the service will now
give you a rather systemd specific error which is somewhat suboptimal.
management tools, which meant upstart services on CentOS6 were not startable. This tweak allows things like vmware-tools to be controlled
via the service module. More testing on other distributions (particularly with systemd) is presumably needed.
Added path expanding for dest in lineinfile
Added common file arguments to lineinfile so the module gets owner,
group, mode and SE options.
Decorated existing example to demonstate usage of file options and added
a couple more examples
Message is not set accordingly when file attributes were changed
'absent' handling code now handles the case where the file doesn't
exists (was issuing a Traceback before)
File attribute handling code has been added to the 'absent' handling
function too.
File attributes handling has been grouped in 'def check_file' since it's
required in both places.
'absent' mode now returns a message like it's counterpart 'present',
telling if file attributes were altered and if lines have matched.
Adds 'chroot' connection for executing modules chrooted to
a local dir. Requires running ansible as root.
chroot dirs should be specified in the inventory like any
other host.
You can do things like:
$ sudo -E ansible -vvv -f 1 "./chroot1,./chroot2" -c chroot \
all -m setup
$ sudo -E ansible-playbook -vvv -f 1 -i "./chroot1,./chroot2" \
-c chroot some-playbook.yml
some-playbook.yml:
---
- hosts: all
tasks:
- name: echo something
shell: echo "Yaaay!" >/tmp/foobar.txt
- name: install less
apt: pkg=less state=latest
* get_file_contents returns None when file is not available.
When /etc/mtab is pointing to /proc/mounts and /proc is not
mounted, mtab.split will traceback.
When destination sysctl file is missing, it is created.
But, for idempotency purposes, the creation process now takes place just before it is used, in the
main code path so an empty file is not left over if the code
module.fail_jsons before the file is really used.
When syscl file was missing, sysctl module was complaining about it and
bailing out.
This behaviour prevents usage of /etc/sysctl.d directory, present in
some distributions.
This patch accepts a missing sysctl.conf file so sysctl.d directory can
be used.
However, it will bail out if the destination directory doesn't exist.
be a BSD licensed snippet so that it's ok to write proprietary modules. The actual license of Ansible (GPLv3) or any modules
written for ansible (any) do not change.
Jinja extensions adds features to the jinja2 templating engine. This
patch allows module loading for the templating engine vian an
ansible.cfg configuration key (jinja_extensions).
The default behaviour doesn't change (no module loading).
Requested modules can be added coma separated in ansible.cfg
Adds whitespace handling in jinja_extension config
Added whitespace handling in jinja_extension configuration directive, so
things stay safe if user adds spaces around comas in the directives
list.
Adds config example for jinja_extensions
Added config example with multiple extentions for jinja_extensions
Now handle positive integer value in virtual files if they are separated
by group of space characters where the count is unpredictable.
Thanks to romeotheriault for filing this bug.
If we need to acquire a PTY for sudo's use, then it should really
inherit the capabilities of the calling environment. This is what
OpenSSH does, and so it makes sense to copy this behaviour for the
paramiko connection type.
Closes: #2065
Signed-off-by: martin f. krafft <madduck@madduck.net>
Postpone the paramiko.Channel.get_pty until we know sudo is used. If
sudo is not used, then we do not need a PTY. In fact, the paramiko docs
explicitly state that it's not desirable to allocate a PTY for a simple
exec_command.
Signed-off-by: martin f. krafft <madduck@madduck.net>
A collegue of mine has added basix AIX support to the setup, user and group modules.
We have tested this on AIX 5.3 and 6.1 and it works "as advertised"
Uses a generic BSD Network class, which uses ifconfig and
parses crap out of it. Modifies the Network __new__
implementation to search further down the subclass
tree
If it is a directory, change the destination path by appending the
basename of the source file, like is done if the destination ends with a
/, and try to get the MD5 of the new path.
Remove lots of re use that really shouldn't have been re in the first
place. Initialize pcidata even if lspci is unavailable, and check for
its usability before trying to use it.
Fixes#2060.
So In my Centos 5.9 machine, if there is RAID mount ansible will crash, as it cannot find scheduler file. The reason being, this should be a virtual device as there is no "device" folder under e.g. /sys/block/md0/
Here is the crash:
[kk@u1 ansible]$ ansible q3 -m setup -k -u root --tree=/tmp/facts
SSH password:
q3 | FAILED => failed to parse: /sys/block/md0
Traceback (most recent call last):
File "/root/.ansible/tmp/ansible-1360629441.14-171498703486275/setup", line 1797, in ?
main()
File "/root/.ansible/tmp/ansible-1360629441.14-171498703486275/setup", line 1050, in main
data = run_setup(module)
File "/root/.ansible/tmp/ansible-1360629441.14-171498703486275/setup", line 1000, in run_setup
facts = ansible_facts()
File "/root/.ansible/tmp/ansible-1360629441.14-171498703486275/setup", line 990, in ansible_facts
facts.update(Hardware().populate())
File "/root/.ansible/tmp/ansible-1360629441.14-171498703486275/setup", line 312, in populate
self.get_device_facts()
File "/root/.ansible/tmp/ansible-1360629441.14-171498703486275/setup", line 439, in get_device_facts
m = re.match(".*?(\[(.*)\])", scheduler)
File "/usr/lib64/python2.4/sre.py", line 129, in match
return _compile(pattern, flags).match(string)
TypeError: expected string or buffer
- added cron_file attribute: if specified, the file with appropriate
job is created in /etc/cron.d directory. Also, you can store multiple
jobs in one file. state='absent' attribute is handled in the following
way in this case: if after the deletion of the job from the file specified
by cron_file variable the file is empty, the file is deleted, otherwise
not.
- fixed the behaviour, when the backupfile is saved forever in /tmp
folder, even if the backup= atribute is not set (os.unlink() is called if
backup is not True).
- added some comments to the unobvious places
Makes it possible to remove a user from all but the primary group.
Setting 'groups=' is the equivalent to passing '-G ""' to
useradd/usermod, which is interpreted as "no group" on Linux.
Instead of having to remember when to use which one, rename template_ds
to template and move the last bit of code from template to varReplace
(which gets used for all string replacements, in the end).
This means that you can template any data type without worrying about
whether it's a string or not, and the right thing will happen.
Change ec2 fact names with colons (:) or dashes (:) to undescore (_)
so that they can be used in templates.
Note that this makes copies instead of replacing the exisitng fact
names to avoid breaking existing playbooks.
* improves error handling and reporting
* uses run_command to reduce code
* fails quicker on errors as opposed to return codes and tracebacks
* can now also specify the key as data versus needing to wget it from a file
To be consistent with the table showing available options, use
underscores in the example tasks, not hyphens, as the table doesn't
list hyphenated versions of option names, so it looks like the
examples could have typos in them.
If a relative path is passed as an argument, this change first
converts it to an absolute path.
This fixes a bug where the git module would attempt to chdir into an
invalid directory because of multiple chdir calls against a relative
path.
pkgin always returns 0 so can't be used to tell if the install or remove
worked. Instead this just queries the installed packages after
performing an operation.
This adds two dependencies to the apt_repository module: apt and
apt_pkg. These come from the package python-apt. This is used to parse
the host's sources.list and examine whether the repo is already
configured. This then eliminates the unnecessary
'add-apt-repository --remove' from running.
Hash variables are currently overriden if they are redefined. This
doesn't let the user refine hash entries or overriding selected keys,
which can, for some, be a desirable feature.
This patch let the user force hash merging by setting the
hash_behaviour value to "merge" (without the quotes) in ansible.cfg
However, by default, ansible behaves like it always did and if any value
besides "merge" is used ("replace" is suggested in the example ansible.cfg
file), it will also behave as always.
PluginLoader.add_directory() can receive None from, for example,
Inventory.add_directory(self.basedir()) if host_list is a custom list.
None has no reasonable interpretation other than ignore it.
- use boto instead of euca2ools
- improve error handling/propagation for run failures
- rename keypair to key_name (and preserve alias for old playbooks)
- should be 100% backward compatible with the euca2ools version
Adds -i to make_sudo_cmd so target user's environment gets loaded when configurationslike this are used :
- hosts: ubuntu
name: Install ruby for the configured ruby user
sudo: True
sudo_user: rubyuser
# should be ${ruby_user}, but can't for now because of #1665
tasks:
- name: Gets current ruby version
action: shell rbenv version
register: ruby_current_version
This adds "69" to the return codes from the status command that should be
considered as not running. At least "django-celery" uses this return code,
maybe others::
/venv/bin/python /code/project/manage.py celeryctl status
echo $? # 69 when not running.
A bit of googling let me to http://tldp.org/LDP/abs/html/exitcodes.html and
on a Ubuntu Server 12.10 I get::
~# cat /usr/include/sysexits.h | grep 69
#define EX_UNAVAILABLE 69 /* service unavailable */
I'm not sure if the content of sysexits.h is the same on other OS'es.
Pretty straightforward. Give it a URL with an exported GPG key for signing an
Apt repository. It downloads it and will install it using apt-key. It's even
smart enough to tell if it's already there (i.e. actually tells you if it
changed or not).
* Rename fail_on_rc_non_zero to check_rc, much more succinct.
* Simplify method defintion
* Fix command module and drop shell=shell option; whether to use
shell is determined by if args is a list.
This updates apt, apt_repository, command, cron, easy_install, facter,
fireball, git, group, mount, ohai, pip, service, setup, subversion,
supervisorctl, svr4pkg, user, and yum to take advantage of run_command
in module_common.py.
This adds a helper method that modules can call to execute a command via
subproces. It takes two arguments: the command to run and
keyword options that control how the process is executed. Supported
options are: fail_on_rc_non_zero, close_fds, and executable.
fail_on_rc_non_zero will call fail_json if the command fails. If
args is a list, the command will be run with shell=False; otherwise, if
a string, it will be run with shell=True. Otherwise, run_command() returns
the returncode, stdout, and stderr.
Without read permission to the current working directory, git-clone will
fail:
root@host:~$ sudo -u git -H git clone \
git://github.com/ansible/ansible.git /home/git/ansible
fatal: Could not change back to '/root': Permission denied
This commit ensures that the working directory is changed to the
parent-folder of the destination before doing the clone.
For compatibility with older releases as well as avoiding things like
action: raw executable= show status
to communicate with devices that don't have sh.
This commit extends the 'when_' conditions to failed and changed
json results
Additionally it makes when_{set,unset,failed,changed,int,str,flt}
behave more similiarily in that they all except and/or/not logic
Two problems here
* unchecked exception handling and erroneous assumption as to why
an exception might fire
* although the file module expands the path, when using file_args
the unexpanded path is passed.
Expected result: ~/path/to/file should work fine
Actual result: exception is because it doesn't find file with a message
about not being able to get the selinux context
Added two additional template variables
* template_fullpath - absolute path to the template
* template_run_date - date that the template was rendered
Documented these additional variables in the module documentation
Path might have to be expanded on some operations. It seems that path
containing '~' are not.
Using os.path.expanduser in appropriate places solves the problem, but
this might be required in many other places.
It seems that os.path.basename(__file__) can return a unicode
string. In this case syslog.openlog fails. Forcing the result
to a string causes the resulting error to go away.
Since we use 'raw' heavily on equipment where 'command' and 'shell' are not (yet) working (and python may need to be installed first using raw) these improvements are necessary in order to write more complex scripts (with return code handling and separated stdout/stderr).
This change includes the following changes:
- exec_command() now returns the return code of the command
- _low_level_exec_command() now returns a dict, including 'rc', 'stdout' and 'stderr'
- all users of the above interfaces have been improved to make use of the above changes
- all connection plugins have been modified to return rc and stderr
- fix the newline problem (stdout and stderr would have excess newlines)
In a future commit I intend to add assertions or error handling code to verify the return code in those places where it wasn't done. Since only the output was available, the return code was ignored, even though we expect them to be 0.
At the moment Ansible prefers yes/no for module booleans, however booleans in playbooks are still using True/False, rather than yes/no. This changes modifies boolean uses in playbooks (and man pages) to favor yes/no rather than True/False.
This change includes:
- Adaptation of documentation and examples to favor yes/no
- Modification to manpage output to favor yes/no (the docsite output already favors yes/no)
Three changes:
* Add set_default_selinux_context() to module_common that sets
a file's context according to the defaults in the policy
* In atomic_replace(), set the default context for the file if
selinux is enabled and the destination file does not exist.
* In authorized_key, set the default context when creating
$HOME/.ssh and $HOME/.ssh/authorized_keys. If these already
exist, this won't touch them.
I guess my previous pull request was confusing, by changing the message to something we already do for tasks, it makes it more clear.
Just like we say:
TASK: [foo bar]
skipping: [system01]
The message now is more clear:
PLAY [wagawaga] *******************************
skipping: no hosts matched
It makes it clear that we are skipping the play, just as is done for a task when a condition is not met.
- Do not silently ignore malformed pip requirements files.
- Properly reports changed when removing packages.
- "latest" i.e. --upgrade is *not* incompatible with requirements files.
- Less branchy, simpler logic.
- Removed pointless variable "initializations", Python doesn't need that.
Other code simplifications.
- Fun fact; pip install is (kind of) case insensitive, pip freeze is not.
So, 'sqlalchemy' will be reported as installed by install, but missing
by freeze.
The perhaps controversial change and the one that led to finding /
fixing above issues...
Instead of adding command parameters 'index', and 'find', and 'mirrors',
and etc. Added 'extra_args' which are passed onto pip.
The use case for --index-url is having a private pypi repo, like
http://pypi.python.org/pypi/localshop, to which you publish private
packages. I'm sure most every pip option has a use case for someone.
extra_args handles all those. Can reserve ansible command parameters for
the most common.
Tested with pip 1.1.
This allows patterns such as webservers:!debian:&datacenter1 to target
hosts in the webservers group, that are not in the debian group, but are
in the datacenter1 group. It also parses patterns left to right.
Add HTML-escaping to code examples in rST tempate of module-formatter
Add support for specifying port, addresses with phrases and attaching files
Add support for custom headers and document version_added for new options
X-Mailer header added :)
protect empty address lists & attachment list, and add bcc
- Added username, password arguments.
- Documented existing revision argument.
- Corrected documentation/docstrings; removed git references, use svn
nomenclature, etc.
- Refactored duplicate code, redundant shell calls, filter abuse,
inconsistent formating, etc.
- Shell quoting so it doesn't break for one guy who has spaces in
pathnames.
- svn called with '--non-interactive' and '--no-auth-cache'.
Move operations that are dependant on a remote branch under a if
is_remote_branch() conditional. While at it, remove assignment to cmd
string in same block that wasn't used when calling _run().
The git module would not pull in updates to a branch when
version=<branch>. This updates that block to checkout the branch
and then do a git reset --hard <remote>/<branch>. This
should now track updates to a branch.
I hit the following exception because errno is referenced but not imported.
```
fatal: [system01] => failed to parse: Traceback (most recent call last):
File "/root/.ansible/tmp/ansible-1354644532.37-246102819320352/copy", line 782, in <module>
main()
File "/root/.ansible/tmp/ansible-1354644532.37-246102819320352/copy", line 117, in main
module.atomic_replace(dest_tmp, dest)
File "/root/.ansible/tmp/ansible-1354644532.37-246102819320352/copy", line 772, in atomic_replace
if e.errno != errno.EPERM:
NameError: global name 'errno' is not defined
```
In a virtualenv, pip is called just pip. This fixes the pip module to
search for the virtualenv pip first before trying the pip-python and
python-pip variants. Without this, pip module would not install to the
virtualenv when that parameter is provided.
This updates _is_package_installed() to accept a requirements file
as an argument. This is used later in main() to check if python libs
specified in a requirements file are already installed. I updated
main() to consolidate the handling of install/uninstall in a single
block. This should help if someone wants to remove packages specified
by a requirements file.
This ensures we don't litter remote systems with temporary directories
that don't get cleaned up, as well as speeds things up from not having
to touch every node.
commit 48069adf0f
Author: Gregory Duchatelet <skygreg@gmail.com>
Date: Tue Nov 27 10:13:08 2012 +0100
Removing this plugin from this branch.
commit 15400fffe6
Author: Gregory Duchatelet <skygreg@gmail.com>
Date: Tue Nov 27 09:53:16 2012 +0100
Enhance _match function in inventory with regex.
--limit ~regex could be used to filter hosts or group with a regex.
Tested on cli and ansible-playbook.
commit 63c1b2e17e
Author: Gregory Duchatelet <skygreg@gmail.com>
Date: Tue Nov 27 09:03:41 2012 +0100
Revert pull request #1684
commit 7c2c6fee3a
Merge: f023a2fdd5a847
Author: Gregory Duchatelet <skygreg@gmail.com>
Date: Tue Nov 27 08:52:53 2012 +0100
Merge remote branch 'upstream/devel' into devel
commit f023a2f3df
Author: Gregory Duchatelet <skygreg@gmail.com>
Date: Mon Nov 26 20:52:27 2012 +0100
Add an inventory plugin to fetch groups and host from our CMDB.
commit c64193b4c6
Author: Gregory Duchatelet <skygreg@gmail.com>
Date: Mon Nov 26 20:43:30 2012 +0100
Added possibility to filter hosts from a group, with a regex, separating
groupname and regex with a ~
Usage in group pattern: group~filterpattern
Samples:
ansible group~server-0[1236] -m ping
ansible web~proxy -m ping
ansible web~(proxy|frontend) -m ping
Add constant DEFAULT_MODULE_LANG that defaults to C. Can be set via
environment variable ANSIBLE_MODULE_LANG or configuration variable
module_lang. Updated test-module to have same behavior.
This makes the line parsing a lot more robust (and easier to read).
Code supplied by @dhozac, thanks!
Remove re import because this is not used anywhere.
When trying to perform enabled=yes followed by enabled=no
against FreeBSD the module would die with the following error:
TypeError: sub() takes at most 4 arguments (5 given)
The target FreeBSD client (8.2) is running python 2.6.6. It seems the
extra 'flags' argument was added to re.sub() in 2.7.
In fixing this issue I have attempted to create a general atomic method
for modifying a rc.conf file. Hopefully this will make it easier to add
other rc based platorms. The strip/split magic was inspired by the user
module.
This change avoids the "tcgetattr: Invalid argument" error by making sure the ssh we start does have a proper pseudo-tty.
We could also check whether our current terminal is a proper terminal (by doing a tcgetattr ourselves) but I don't think this adds anything.
This closes#1662 (if all use-cases have been tested: sudo, passwd)
* Basically the moving parts from the original service module arranged in
subclasses.
* General structure and helper methods comes from the user module.
* Less forgiving to unsupported platforms: it requires a subclass per platform.
(This makes it easier to work on one platform without having to think about.
what other platform might be affected in unexpected ways).
* Now has basic OpenBSD support.
* Solaris support needs to be added.
Thanks to @dhozac for general advice and Linux testing.
Thanks to @bcoca for clearing up some FreeBSD questions.
Otherwise, a host in two groups, A and B, using a variable defined
in group A and all will get the value of all, as B's variables will
include the all variable.
Partially fixes#1647.
global_vars has higher precedence than inventory. Putting the all
group's variables into it overrides all other groups and hosts.
Partially fixes#1647.
I added all known virtualization types from the virt-what project. However, the few virt types that rely on cpuid information have not been implemented lacking native python cpuid access. (hyperv)
As reported on the mailinglist, the user received a ValueError when the port number was not templated (fixed in #1649) and therefore it was not an integer. This change will catch the exception and provide a proper error so it is more clear.
Added a README.md to explain the purpose of the directory
Fixed dependencies in PKGBUILD
Added patch to change python binary name for arch users, so they
don't end up using python 3 (python links to python3 by default on arch
linux).
Currently when more than one playbook is provided on the commandline, ansible-playbook --list-hosts will only consider the first playbook and stop. This change will make it work for the various different playbooks.
When the inventory is empty, or the provided --limit subset returns an empty intersection, we don't want to loop over all plays but bail out at the very start.
Executive summary: skipping a host corrupts a variable (when it is registered)
We have a play existing out of multiple tasks that check a condition, if one of these tasks fails we want to skip all next tasks in the playbook. I noticed that if we skip a task because a certain condition is met, and this task has a register-attribute, I loose the value in the variable. Which means we cannot use that variable in subsequent tasks to evaluate because it was skipped:
```
- action: command test -d /some/directory
register: task
- action: command test -f /some/directory/file
register: task
only_if: '${task.rc} == 0'
- action: do something else
only_if: '${task.rc} == 0'
```
In the above example, if the second task is skipped (because the first failed), the third action will end with a "SyntaxError: invalid syntax" complaining about the unsubstituted ${task.rc} (even though it was set by the first task and used for skipping the second).
The following play demonstrates the problem:
```
- name: Test register on ignored tasks
hosts: all
gather_facts: no
vars:
skip: true
task: { 'rc': 666 }
tasks:
- action: debug msg='skip = ${skip}, task.rc = ${task.rc}'
- name: Skip this task, just to test if task has changed
action: command ls
register: task
only_if: '${skip} != True'
- action: debug msg='skip = ${skip}, task.rc = ${task.rc}'
- name: Now use task value
action: command echo 'Works !'
only_if: '${task.rc} == 0'
```
And the enclosed fix, fixes the above problem.
After spending 10 minutes to find which playbook had an action/local_action missing, I changed the error to include the task name (if set). The error eventually was caused because I added a name to a task, but the dash before the existing action was not removed.
Update constants.py so that one can specify environmental variable
ANSIBLE_SYSLOG_FACILITY or syslog_facility in ansible.cfg to define
the syslog facility to use. Alternatively, you can specify
ansible_syslog_facility in inventory. Runner now replaces
the syslog facility in the openlog() call with the default or
the injected variables ansible_syslog_facility.
This also updates hacking/test-module to behave similarly.
Without this fix, generating documentation results in:
```
Traceback (most recent call last):
File "hacking/module_formatter.py", line 376, in <module>
main()
File "hacking/module_formatter.py", line 365, in main
text = template.render(doc)
File "/usr/lib64/python2.6/site-packages/jinja2/environment.py", line 669, in render
return self.environment.handle_exception(exc_info, True)
File "hacking/templates/man.j2", line 20, in top-level template code
{% for desc in v.description %}@{ desc | jpfunc }@{% endfor %}
File "hacking/module_formatter.py", line 94, in man_ify
t = _ITALIC.sub(r'\\fI' + r"\1" + r"\\fR", text)
TypeError: expected string or buffer
```
Currently the message prepared for --oneline mode adds a newline to the msg-string, which is then printed (adding another newline). This change removes the added newline so that successes and failures do not differ in output (except if the output is multiline).
- Make sure exit_json() always returns a changed= value
- Modify the yum module to not return failed=False
- Modify install() and latest() similar to remove() in yum module
- Changed exit_json(failed=True, **res) into a fail_json(**res)
- Make sure yum rc= value reflects loop (similar to how we fixed remove())
Rewrote switch_version() to read .git/HEAD to find branch associated
with HEAD. If in a detached HEAD state, will read
.git/refs/remotes/<remote>/HEAD.
Rename pull() to fetch(). It does a git fetch and then a
git fetch --tags.
Add _run() method to handle all subprocess.Popen calls. Change
all previous calls to subprocess.Popen to use _run().
There is no need to require thirsty mode when the destination is a directory. We add the basename of the url to the destination directory and proceed with that. If that file exists in non-thirsty mode continue as expected.
I also cleaned up some of the logic that is no longer necessary if we simply rewrite the destination from the very start the way it is expected.
Since callbacks are called with different argument-types, we have to be careful. We support two different distinct cases:
- The error information can be in one ore more of the following items (msg, stderr or stdout)
- The res/msg value returned can be a string or a list
Splitting of the packaging so that fireball mode, with the
additional requirements of 0mq, is separately packaged.
Also a end node fireball support package (reqs only).
Several modules (e.g., pip) return stdout and stderr together in a "msg" variable (and the module development docs seem to suggest that the standard practice is to return status in this variable).
This change ensures that it is printed out with correct formatting (most importantly, with newlines appearing as newlines instead of \n).
I had made and pushed this change after you already pulled the request.
@dhozac indicated that it would probably be better to use return codes > 255 for anything related to Ansible itself. Which makes sens :)
We use the lineinfile module to modify configuration files of a proprietary application. This application reads configuration options from files, but does not require those files to exist (if the default options are fine). However this application may modify the configuration file at will, so we cannot copy or template those files. And after a silent install the configuration may not exist (depending on the response file).
Whatever the case, during deployment we need to make sure some configuration options are set after the installation.
So the cleanest way to handle this situation is to allow the lineinfile module to create the file if it is missing (and this is the expected behavior). When I proposed this behavior, @sergevanginderachter needed the same functionality and was now working around it as well.
I had made and pushed this change after you already pulled the request.
@dhozac indicated that it would probably be better to use return codes > 255 for anything related to Ansible itself. Which makes sens :)
Split module into a main calling function, and a generic
(Linux useradd/usermod/userdel) User class.
Added a __new__ function that selects most appropriate superclass
Added a FreeBSD User class
Tested against FreeBSD 9.0
If this is not a certainty, playbooks will fail without an 'rc' and checking both if there is an rc, and whether the 'rc' is (not) 0 is very complicated. (especially because ${something.rc} will not be substituted and all that)
If you sudo to a non-root user, you get a permission denied error.
Here's an example:
$ ansible myserver.example.com -m postgresql_db -a "db=mydatabase" -u ubuntu -s -U postgres
myserver.example.com | FAILED >> {
"failed": true,
"msg": "chmod: changing permissions of `/tmp/ansible-
1351092257.96-157699143369671/postgresql_db': Operation not
permitted\n/usr/bin/python: can't open file '/tmp/ansible-
1351092257.96-157699143369671/postgresql_db': [Errno 13]
Permission denied\n",
"parsed": false
}
The problem is that ansible is doing the chmod as the sudo user
when it should be doing it as the remote user.
Detect when on a 'no branch' branch. If so, checkout the HEAD branch
as reported by 'git remote show <remote>'. That should put the repo
back on a branch such that git can then merge changes as necessary.
In addition, removed hard-coded references to origin and replaced
with remote var.
- The old documentation stated not to quote the variable in the function, which is obviously wrong. When using lists or integers, we have to quote otherwise the startswith() method will trip over its non-existence.
- It was unclear that the only_if statement is processed for each item when doing with_items, so I added an example making it crystal clear how this can be used in your advantage (or why a non-existing list variable can break your logic if you expected the only_if to be processed once before running the task)
This allows one to create a SSH key for user. You may define:
ssh_key_type, ssh_key_bits, ssh_key_file, ssh_key_comment,
and ssh_key_passphrase. If no passphrase is provided, the
key will be passphrase-less. This will not overwrite an existing key.
In the JSON returned, it will provide the ssh_fingerprint and
ssh_key_file.
- fixed template (it was the template), adding indentation with Jinja2
- added description of code examples to man-page template (was missing)
- fixed fireball, cron, and debug module examples to confrom
Test for when environment variable and configuration file
variable both set now tests that the environment variable takes
precedence
Removed logic that would never be triggered from
lib/ansible/constants.py
I had trouble finding this information, so though it was worth
adding to docs... but am not sure its easy to find for someone
specifically to find. At least I think this inclusion matches the
tone of document, but maybe this info should go into a FAQ
instead/as-well?
1.3.2 "Top of the World" (reprise) - September 19th, 2013
* The ControlPath variable for ssh connections is now configurable in the ansible.cfg (and via the environment variable ANSIBLE_SSH_CONTROL_PATH).
* Added a -vvvv level, which will show SSH client debugging information in the event of a failure.
* Fixed bug in apt_repository module where the repository cache was not being updated.
* Fixed bug where "too many open files" errors would be encountered due to pseudo TTY's not being closed properly.
1.3.1 "Top of the World" (reprise) - September 16th, 2013
* Fixing a bug in accelerate mode whereby the gather_facts step would always be run via sudo regardless of the play settings.
1.3 "Top of the World" - September 13th, 2013
Highlighted new features:
* accelerated mode: An enhanced fireball mode that requires zero bootstrapping and fewer requirements plus adds capabilities like sudo commands.
* role defaults: Allows roles to define a set of variables at the lowest priority. These variables can be overridden by any other variable.
* new /etc/ansible/facts.d allows JSON or INI-style facts to be provided from the remote node, and supports executable fact programs in this dir. Files must end in *.fact.
* added the ability to make undefined template variables raise errors (see ansible.cfg)
* (DOCS PENDING) sudo: True/False and sudo_user: True/False can be set at include and role level
* added changed_when: (expression) which allows overriding whether a result is changed or not and can work with registered expressions
* --extra-vars can now take a file as input, e.g., "-e @filename" and can also be formatted as YAML
* external inventory scripts may now return host variables in one pass, which allows them to be much more efficient for large numbers of hosts
* if --forks exceeds the numbers of hosts, it will be automatically reduced. Set forks to 0 and you get "as many forks as I have hosts" out of the box.
* enabled error_on_undefined_vars by default, which will make errors in playbooks more obvious
* role dependencies -- one role can now pull in another, with parameters of its own.
* added the ability to have tasks execute even during a check run (always_run).
* added the ability to set the maximum failure percentage for a group of hosts.
New modules:
* notifications: datadog_event -- send data to datadog
* cloud: digital_ocean -- module for DigitalOcean provisioning that also includes inventory support
* cloud: rds -- Amazon Relational Database Service
* cloud: linode -- modules for Linode provisioning that also includes inventory support
* packaging: rpm_key -- adds or removes RPM signing keys
* packaging: apt_repository -- rewritten to remove dependencies
* monitoring: boundary_meter -- adds or removes boundary.com meters
* net_infrastructure: dnsmadeeasy - manipulate DNS Made Easy records
* files: xattr -- manages extended attributes on files
Misc changes:
* return 3 when there are hosts that were unreachable during a run
* the yum module now supports wildcard values for the enablerepo argument
* added an inventory script to pull host information from Zabbix
* async mode no longer allows with_* lookup plugins due to incompatibilities
* Added OpenRC support (Gentoo) to the service module
* ansible_ssh_user value is available to templates
* added placement_group parameter to ec2 module
* new sha256sum parameter added to get_url module for checksum validation
* search for mount binaries in system path and sbin vs assuming path
* allowed inventory file to be read from a pipe
* added Solaris distribution facts
* fixed bug along error path in quantum_network module
* user password update mode is controllable in user module now (at creation vs. every time)
* added check mode support to the OpenBSD package module
* Fix for MySQL 5.6 compatibility
* HP UX virtualization facts
* fixed some executable bits in git
* made rhn_register module compatible with EL5
* fix for setup module epoch time on Solaris
* sudo_user is now expanded later, allowing it to be set at inventory scope
* mongodb_user module changed to also support MongoDB 2.2
* new state=hard option added to the file module for hardlinks vs softlinks
* fixes to apt module purging option behavior
* fixes for device facts with multiple PCI domains
* added "with_inventory_hostnames" lookup plugin, which can take a pattern and loop over hostnames matching the pattern and is great for use with delegate_to and so on
* ec2 module supports adding to multiple security groups
* cloudformation module includes fixes for the error path, and the 'wait_for' parameter was removed
* added --only-if-changed to ansible-pull, which runs only if the repo has changes (not default)
* added 'mandatory', a Jinja2 filter that checks if a variable is defined: {{ foo|mandatory }}
* added support for multiple size formats to the lvol module
* timing reporting on wait_for module now includes the delay time
* IRC module can now send a server password
* "~" now expanded on each component of configured plugin paths
* fix for easy_install module when dealing with virtualenv
* rackspace module now explicitly indicates rackspace vs vanilla openstack
* add_host module does not report changed=True any longer
* explanatory error message when using fireball with sudo has been improved
* git module now automatically pulls down git submodules
* negated patterns do not require "all:!foo", you can just say "!foo" now to select all not foos
* fix for Debian services always reporting changed when toggling enablement bit
* roles files now tolerate files named 'main.yaml' and 'main' in addition to main.yml
* some help cleanup to command line flags on scripts
* force option reinstated for file module so it can create symlinks to non-existent files, etc.
* added termination support to ec2 module
* --ask-sudo-pass or --sudo-user does not enable all options to use sudo in ansible-playbook
* include/role conditionals are added ahead of task conditionals so they can short circuit properly
* added pipes.quote in various places so paths with spaces are better tolerated
* error handling while executing Jinja2 filters has been improved
* upgrades to atomic replacement logic when copying files across partitions/etc
* mysql user module can try to login before requiring explicit password
* various additional options added to supervisorctl module
* only add non unique parameter on group creation when required
* allow rabbitmq_plugin to specify a non-standard RabbitMQ path
* authentication fixes to keystone_user module
* added IAM role support to EC2 module
* fixes for OpenBSD package module to avoid shell expansion
* git module upgrades to allow --depth and --version to be used together
* new lookup plugin, "with_flattened"
* extra vars (-e) variables can be used in playbook include paths
* improved reporting for invalid sudo passwords
* improved reporting for inability to find a suitable tmp location
* require libselinux-python to perform file operations if SELinux is operational
* ZFS module fixes for byte display constants and handling paths with spaces
* setup module more tolerant of gathering facts against things it does not have permission to read
* can specify name=* state=latest to update all yum modules
* major speedups to the yum module for default cases
* ec2_facts module will now run in check mode
* sleep option on service module for sleeping between stop/restart
* fix for IPv6 facts on BSD
* added Jinja2 filters: skipped, whether a result was skipped
* added Jinja2 filters: quote, quotes a string if it needs to be quoted
* allow force=yes to affect apt upgrades
* fix for saving conditionals in variable names
* support for multiple host ranges in INI inventory, e.g., db[01:10:3]node-[01:10]
* fixes/improvements to cron module
* add user_install=no option to gem module to install gems system wide
* added raw=yes to allow copying without python on remote machines
* added with_indexed_items lookup plugin
* Linode inventory plugin now significantly faster
* added recurse=yes parameter to pacman module for package removal
* apt_key module can now target specific keyrings (keyring=filename)
* ec2 module change reporting improved
* hg module now expands user paths (~)
* SSH connection type known host checking now can process hashed known_host files
* lvg module now checks for executables in more correct locations
* copy module now works correctly with sudo_user
* region parameter added to ec2_elb module
* better default XMPP module message types
* fixed conditional tests against raw booleans
* mysql module grant removal is now smarter
* apt-remove is now forced to be non-interactive
* support ; comments in INI file module
* fixes to callbacks WRT async output (fire and forget tasks now trigger callbacks!)
* folder support for s3 module
* added new example inventory plugin for Red Hat OpenShift
* and other misc. bugfixes
1.2.3 "Hear About It Later" (reprise) -- Aug 21, 2013
* Local security fixes for predictable file locations for ControlPersist and retry file paths on shared machines
on operating systems without kernel symlink/hardlink protections.
1.2.2 "Hear About It Later" (reprise) -- July 4, 2013
* Added a configuration file option [paramiko_connection] record_host_keys which allows the code that paramiko uses
to update known_hosts to be disabled. This is done because paramiko can be very slow at doing this if you have a
large number of hosts and some folks may not want this behavior. This can be toggled independently of host key checking
and does not affect the ssh transport plugin. Use of the ssh transport plugin is preferred if you have ControlPersist
capability, and Ansible by default in 1.2.1 and later will autodetect.
1.2.1 "Hear About It Later" -- July 4, 2013
* Connection default is now "smart", which discovers if the system openssh can support ControlPersist, and uses
it if so, if not falls back to paramiko.
* Host key checking is on by default. Disable it if you like by adding host_key_checking=False in the [default]
section of /etc/ansible/ansible.cfg or ~/ansible.cfg or by exporting ANSIBLE_HOST_KEY_CHECKING=False
* Paramiko now records host keys it was in contact with host key checking is on. It is somewhat sluggish when doing this,
so switch to the 'ssh' transport if this concerns you.
1.2 "Right Now" -- June 10, 2013
Core Features:
* capability to set 'all_errors_fatal: True' in a playbook to force any error to stop execution versus
a whole group or serial block needing to fail
usable, without breaking the ability to override in ansible
* ability to use variables from {{ }} syntax in mainline playbooks, new 'when' conditional, as detailed
in documentation. Can disable old style replacements in ansible.cfg if so desired, but are still active
by default.
* can set ansible_ssh_private_key_file as an inventory variable (similar to ansible_ssh_host, etc)
* 'when' statement can be affixed to task includes to auto-affix the conditional to each task therein
* cosmetic: "*****" banners in ansible-playbook output are now constant width
* --limit can now be given a filename (--limit @filename) to constrain a run to a host list on disk
* failed playbook runs will create a retry file in /var/tmp/ansible usable with --limit
* roles allow easy arrangement of reusable tasks/handlers/files/templates
* pre_tasks and post_tasks allow for separating tasks into blocks where handlers will fire around them automatically
* "meta: flush_handler" task capability added for when you really need to force handlers to run
* new --start-at-task option to ansible playbook allows starting at a specific task name in a long playbook
* added a log file for ansible/ansible-playbook, set 'log_path' in the configuration file or ANSIBLE_LOG_PATH in environment
* debug mode always outputs debug in playbooks, without needing to specify -v
* external inventory script added for Spacewalk / Red Hat Satellite servers
* It is now possible to feed JSON structures to --extra-vars. Pass in a JSON dictionary/hash to feed in complex data.
* group_vars/ and host_vars/ directories can now be kept alongside the playbook as well as inventory (or both!)
* more filters: ability to say {{ foo|success }} and {{ foo|failed }} and when: foo|success and when: foo|failed
* more filters: {{ path|basename }} and {{ path|dirname }}
* lookup plugins now use the basedir of the file they have included from, avoiding needs of ../../../ in places and
increasing the ease at which things can be reorganized.
Modules added:
* cloud: rax: module for creating instances in the rackspace cloud (uses pyrax)
* packages: npm: node.js package management
* packages: pkgng: next-gen package manager for FreeBSD
* packages: redhat_subscription: manage Red Hat subscription usage
* networking: ec2_elb: add and remove machines from ec2 elastic load balancers
* notification: hipchat: send notification events to hipchat
* notification: flowdock: send messages to flowdock during playbook runs
* notification: campfire: send messages to campfire during playbook runs
* notification: mqtt: send messages to the Mosquitto message bus
* notification: irc: send messages to IRC channels
* notification: filesystem - a wrapper around mkfs
* notification: jabber: send jabber chat messages
* notification: osx_say: make OS X say things out loud
* openstack: keystone_user
* openstack: glance_image
* openstack: nova_compute
* openstack: nova_keypair
* openstack: quantum_floating_ip
* openstack: quantum_floating_ip_associate
* openstack: quantum_network
* openstack: quantum_router
* openstack: quantum_router_gateway
* openstack: quantum_router_interface
* openstack: quantum_subnet
* monitoring: newrelic_deployment: notifies newrelic of new deployments
* monitoring: airbrake_deployment - notify airbrake of new deployments
* monitoring: pingdom
* monitoring: pagerduty
* monitoring: monit
* utility: set_fact: sets a variable, which can be the result of a template evaluation
Modules removed
* vagrant -- can't be compatible with both versions at once, just run things though the vagrant provisioner in vagrant core
Bugfixes and Misc Changes:
* service module happier if only enabled=yes|no specified and no state
* mysql_db: use --password= instead of -p in dump/import so it doesn't go interactive if no pass set
* when using -c ssh and the ansible user is the current user, don't pass a -o to allow SSH config to be
* overwrite parameter added to the s3 module
* private_ip parameter added to the ec2 module
* $FILE and $PIPE now tolerate unicode
* various plugin loading operations have been made more efficient
* hostname now uses platform.node versus socket.gethostname to be more consistant with Unix 'hostname'
* fix for SELinux operations on Unicode path names
* inventory directory locations now ignore files with .ini extensions, making hybrid inventory easier
* copy module in check-mode now reports back correct changed status when used with force=no
* added avail. zone to ec2 module
* fixes to the hash variable merging logic if so enabled in the main settings file (default is to replace, not merge hashes)
* group_vars and host_vars files can now end in a .yaml or .yml extension, (previously required no extension, still favored)
* ec2vol module improvements
* if the user module is told to generate the ssh key, the key generated is now returned in the results
* misc fixes to the Riak module
* make template module slightly more efficient
* base64encode / decode filters are now available to templates
* libvirt module can now work with multiple different libvirt connecton URIs
* fix for postgresql password escaping
* unicode fix for shlex.split in some cases
* apt module upgrade logic improved
* URI module now can follow redirects
* yum module can now install off http URLs
* sudo password now defaults to ssh password if you ask for both and just hit enter on the second prompt
* validate feature on copy and template module, for example, running visudo prior to copying the file over
* network facts upgraded to return advanced configs (bonding, etc)
* region support added to ec2 module
* riak module gets a wait for ring option
* improved check mode support in the file module
* exception handling added to handle scenario when attempt to log to systemd journal fails
* fix for upstart handling when toggling the enablement and running bits at the same time
* when registering a task with a conditional attached, and the task is skipped by the conditional,
the variable is still registered for the host, with the attribute skipped: True.
* delegate_to tasks can look up ansible_ssh_private_key_file variable from inventory correctly now
* s3 module takes a 'dest' parameter to change the destination for uploads
* apt module gets a cache_valid_time option to avoid redundant cache updates
* ec2 module better understands security groups
* fix for postgresql codec usage
* setup module now tolerant of OpenVZ interfaces
* check mode reporting improved for files and directories
* doc system now reports on module requirements
* group_by module can now also make use of globally scoped variables
* localhost and 127.0.0.1 are now fuzzy matched in inventory (are now more or less interchangeable)
* AIX improvements/fixes for users, groups, facts
* lineinfile now does atomic file replacements
* fix to not pass PasswordAuthentication=no in the config file unneccessarily for SSH connection type
* for for authorized_key on Debian Squeeze
* fixes for apt_repository module reporting changed incorrectly on certain repository types
* allow the virtualenv argument to the pip module to be a pathname
* service pattern argument now correctly read for BSD services
* fetch location can now be controlled more directly via the 'flat' parameter.
* added basename and dirname as Jinja2 filters available to all templates
* pip works better when sudoing from unpriveledged users
* fix for user creation with groups specification reporting 'changed' incorrectly in some cases
* fix for some unicode encoding errors in outputing some data in verbose mode
* improved FreeBSD, NetBSD and Solaris facts
* debug module always outputs data without having to specify -v
* fix for sysctl module creating new keys (must specify checks=none)
* NetBSD and OpenBSD support for the user and groups modules
* Add encrypted password support to password lookup
1.1 "Mean Street" -- 4/2/2013
Core Features
* added --check option for "dry run" mode
* added --diff option to show how templates or copied files change, or might change
* --list-tasks for the playbook will list the tasks without running them
* able to set the environment by setting "environment:" as a dictionary on any task (go proxy support!)
* added ansible_ssh_user and ansible_ssh_pass for per-host/group username and password
* jinja2 extensions can now be loaded from the config file
* support for complex arguments to modules (within reason)
* can specify ansible_connection=X to define the connection type in inventory variables
* a new chroot connection type
* module common code now has basic type checking (and casting) capability
* module common now supports a 'no_log' attribute to mark a field as not to be syslogged
* inventory can now point to a directory containing multiple scripts/hosts files, if using this, put group_vars/host_vars directories inside this directory
* added configurable crypt scheme for 'vars_prompt'
* skipped messages are now cyan, to differentiate them from unchanged messages.
* extensive documentation upgrades
* delegate_action to localhost (aka local_action) will always use the local connection type
Highlighted playbook changes:
@ -46,6 +667,8 @@ Highlighted playbook changes:
* setup is not run more than once when we know it is has already been run in a play that included another play, etc
* can set/override sudo and sudo_user on individual tasks in a play, defaults to what is set in the play if not present
* ability to use with_fileglob to iterate over local file patterns
* templates now use Jinja2's 'trim_blocks=True' to avoid stray newlines, small changes to templates may
be required in rare cases.
Other playbook changes:
@ -92,6 +715,8 @@ Other module Changes, Upgrades, and Fixes:
* variable '$ansible_managed' is now great to include at the top of your templates and includes useful information and a warning that it will be replaced
* "~" now expanded in command module when using creates/removes
* mysql module can do dumps and imports
* selinux policy is only required if setting to not disabled
* various fixes for yum module when working with packages not in any present repo
0.7 "Panama" -- Sept 6 2012
@ -167,13 +792,13 @@ playbooks:
* error reporting if with_items value is unbound
* with_items no longer creates lots of tasks, creates one task that makes multiple calls
* can use host_specific facts inside with_items (see above)
* at the top level of a playbook, set 'gather_facts: False' to skip fact gathering
* at the top level of a playbook, set 'gather_facts: no' to skip fact gathering
* first_available_file and with_items used together will now raise an error
* to catch typos, like 'var' for 'vars', playbooks and tasks now yell on invalid parameters
* automatically load (directory_of_inventory_file)/group_vars/groupname and /host_vars/hostname in vars_files
* playbook is now colorized, set ANSIBLE_NOCOLOR=1 if you do not like this, does not colorize if not a TTY
* hostvars now preserved between plays (regression in 0.5 from 0.4), useful for sharing vars in multinode configs
* ignore_errors: True on a task can be used to allow a task to fail and not stop the play
* ignore_errors: yes on a task can be used to allow a task to fail and not stop the play
* with_items with the apt/yum module will install/remove/update everything in a single command
inventory:
@ -232,7 +857,7 @@ internals:
* support for older versions of python-apt in the apt module
* a new "assemble" module, for constructing files from pieces of files (inspired by Puppet "fragments" idiom)
* ability to override most default values with ANSIBLE_FOO environment variables
* --module-path parameter can support multiple directories seperated with the OS path seperator
* --module-path parameter can support multiple directories separated with the OS path separator
* with_items can take a variable of type list
* ansible_python_interpreter variable available for systems with more than one Python
Ansible is a radically simple configuration-management, deployment, task-execution, and
multinode orchestration framework.
Read the documentation and more at http://ansible.cc
Read the documentation and more at http://ansibleworks.com/
Many users run straight from the development branch (it's generally fine to do so), but you might also wish to consume a release. You can find
instructions on http://ansibleworks.com/docs/gettingstarted.html for a variety of platforms. If you want a tarball of the last release, go to
http://ansibleworks.com/releases/ and you can also install with pip (though that will bring in some optional binary dependencies you normally do not need).
* [Exploring Configuration Management With Ansible](http://palominodb.com/blog/2012/08/01/exploring-configuration-management-ansible) - Palamino DB
* [You Should Consider Using SSH Based Configuration Management](http://www.lshift.net/blog/2012/07/30/you-should-consider-using-ssh-based-configuration-management) - LShift Ltd
* [Deploying Flask/uWSGI, Nginx, and Supervisorctl](http://mattupstate.github.com/python/devops/2012/08/07/flask-wsgi-application-deployment-with-ubuntu-ansible-nginx-supervisor-and-uwsgi.html) - mattupstate
* [Infracoders Presentation](http://www.danielhall.me/2012/10/ansible-talk-infra-coders/) - Daniel Hall
Disclaimer
==========
Modules and playbooks here may not be using the latest in Ansible features. When in doubt to the features of
a particular version of Ansbile, always consult [ansible.cc](http://ansible.cc) and in particular
see [Best Practices](http://ansible.cc/docs/bestpractices.html) for some tips and tricks that may be useful.
Ansible is (C) 2012, [Michael DeHaan](http://twitter.com/laserllama) and others and is available under the GPLv3 license. Content here is as specified
\fBansible\-doc\fR displays information on modules installed in Ansible libraries\&. It displays a terse listing of modules and their short descriptions, provides a printout of their DOCUMENTATION strings, and it can create a short "snippet" which can be pasted into a playbook\&.
Extra variables to inject into a playbook, in key=value key=value format\&.
Extra variables to inject into a playbook, in key=value key=value format or as quoted JSON (hashes and arrays)\&.
.RE
.PP
\fB\-f\fR\fINUM\fR, \fB\-\-forks=\fR\fINUM\fR
@ -82,6 +91,26 @@ Prompt for the password to use for playbook plays that request sudo access, if a
Desired sudo user (default=root)\&.
.RE
.PP
\fB\-\-tags\fR
.RS4
Run only these tags from the playbook
.RE
.PP
\fB\-\-syntax\-check\fR
.RS4
Look for syntax errors in the playbook, but don\(cqt run anything
.RE
.PP
\fB\-\-check\fR
.RS4
Do not make any changes on the remote system, but test resources to see what might have changed\&. Note this can not scan all possible resource types and is only a simulation\&.
.RE
.PP
\fB\-\-diff\fR
.RS4
When changing any templated files, show the unified diffs of how they changed\&. When used with \-\-check, shows how the files would have changed if \-\-check were not used\&.
ansible-pull \- set up a remote copy of ansible on each managed node
.SH"SYNOPSIS"
.sp
ansible \-d DEST \-U URL [\-C CHECKOUT ]
ansible \-d DEST \-U URL [options] [ <filename\&.yml> ]
.SH"DESCRIPTION"
.sp
\fBAnsible\fR is an extra\-simple tool/framework/API for doing \'remote things\' over SSH\&.
\fBAnsible\fR is an extra\-simple tool/framework/API for doing \*(Aqremote things\*(Aq over SSH\&.
.sp
Use ansible\-pull to set up a remote copy of ansible on each managed node, each set to run via cron and update playbook source via git\&. This inverts the default \fBpush\fR architecture of ansible into a \fBpull\fR architecture, which has near\-limitless scaling potential\&.
Use ansible\-pull to set up a remote copy of ansible on each managed node, each set to run via cron and update playbook source via a source repository\&. This inverts the default \fBpush\fR architecture of ansible into a \fBpull\fR architecture, which has near\-limitless scaling potential\&.
.sp
The setup playbook can be tuned to change the cron frequency, logging locations, and parameters to ansible\-pull\&.
.sp
This is useful both for extreme scale\-out as well as periodic remediation\&. Usage of the \fIfetch\fR module to retrieve logs from ansible\-pull runs would be an excellent way to gather and analyze remote logs from ansible\-pull\&.
.SH"OPTIONAL ARGUMENT"
.PP
\fBfilename\&.yml\fR
.RS4
The name of one the YAML format files to run as an ansible playbook\&. This can be a relative path within the checkout\&. If not provided, ansible\-pull will look for a playbook based on the host\(cqs fully\-qualified domain name and finally a playbook named
Ansible stores the hosts it can potentially operate on in an inventory file\&. The syntax is one host per line\&. Groups headers are allowed and are included on their own line, enclosed in square brackets that start the line\&.
@ -167,9 +181,9 @@ Ranges of hosts are also supported\&. For more information and additional option
.sp
/usr/share/ansible/ \(em Default module library
.sp
/etc/ansible/ansible\&.conf \(em Config file, used if present
/etc/ansible/ansible\&.cfg\(em Config file, used if present
.sp
~/\&.ansible\&.config \(em User config file, overrides the default config if present
~/\&.ansible\&.cfg \(em User config file, overrides the default config if present
.SH"ENVIRONMENT"
.sp
The following environment variables may specified\&.
@ -177,6 +191,8 @@ The following environment variables may specified\&.
ANSIBLE_HOSTS \(em Override the default ansible hosts file
.sp
ANSIBLE_LIBRARY \(em Override the default ansible module library path
.sp
ANSIBLE_CONFIG \(em Override the default ansible config file
.SH"AUTHOR"
.sp
Ansible was originally written by Michael DeHaan\&. See the AUTHORS file for a complete list of contributors\&.
@ -187,6 +203,6 @@ Copyright \(co 2012, Michael DeHaan
Ansible is released under the terms of the GPLv3 License\&.
Ansible contains a number of core modules for interacting with Amazon Web Services (AWS) and other API compatible private clouds, such as Eucalyptus. (There are other supported cloud systems, but this documentation is about AWS ones). This page illustrates some use cases for provisioning and managing hosts EC2 resources.
Requirements for the AWS modules are minimal. All of the modules require and are tested against boto 2.5 or higher. You'll need this Python module installed on the execution host. If you are using Red Hat Enterprise Linux or CentOS, install boto from `EPEL <http://fedoraproject.org/wiki/EPEL>`_:
..code-block::bash
$ yum install python-boto
Provisioning
````````````
The ec2 module provides the ability to provision instance(s) within EC2. Typically the provisioning task will be performed against your Ansible master server as a local_action.
..note::
Authentication with the AWS-related modules is handled by either
specifying your access and secret key as ENV variables or passing
them as module arguments.
..note::
To talk to specific endpoints, the environmental variable EC2_URL
can be set. This is useful if using a private cloud like Eucalyptus,
exporting the variable as EC2_URL=https://myhost:8773/services/Eucalyptus.
This can be set using the 'environment' keyword in Ansible if you like.
Provisioning a number of instances in ad-hoc mode mode:
By registering the return its then possible to dynamically create a host group consisting of these new instances. This facilitates performing configuration actions on the hosts immediately in a subsequent play::
With the host group now created, the second play in your provision playbook might now have some configuration steps::
- name: Configuration play
hosts: ec2hosts
user: ec2-user
gather_facts: true
tasks:
- name: Check NTP service
action: service name=ntpd state=started
The method above ties the configuration of a host with the provisioning step. This isn't always ideal and leads us onto the next section.
Advanced Usage
``````````````
Host Inventory
++++++++++++++
Once your nodes are spun up, you'll probably want to talk to them again. The best way to handle his is to use the ec2 inventory plugin.
Even for larger environments, you might have nodes spun up from Cloud Formations or other tooling. You don't have to use Ansible to spin up guests. Once these are created and you wish to configure them, the EC2 API can be used to return system grouping with the help of the EC2 inventory script. This script can be used to group resources by their security group or tags. Tagging is highly recommended in EC2 and can provide an easy way to sort between host groups and roles. The inventory script is documented `in the API chapter <http://www.ansibleworks.com/docs/api.html#external-inventory-scripts>`_.
You may wish to schedule a regular refresh of the inventory cache to accommodate for frequent changes in resources:
..code-block::bash
# ./ec2.py --refresh-cache
Put this into a crontab as appropriate to make calls from your Ansible master server to the EC2 API endpoints and gather host information. The aim is to keep the view of hosts as up-to-date as possible, so schedule accordingly. Playbook calls could then also be scheduled to act on the refreshed hosts inventory after each refresh. This approach means that machine images can remain "raw", containing no payload and OS-only. Configuration of the workload is handled entirely by Ansible.
Pull Configuration
++++++++++++++++++
For some the delay between refreshing host information and acting on that host information (i.e. running Ansible tasks against the hosts) may be too long. This may be the case in such scenarios where EC2 AutoScaling is being used to scale the number of instances as a result of a particular event. Such an event may require that hosts come online and are configured as soon as possible (even a 1 minute delay may be undesirable). Its possible to pre-bake machine images which contain the necessary ansible-pull script and components to pull and run a playbook via git. The machine images could be configured to run ansible-pull upon boot as part of the bootstrapping procedure.
More information on pull-mode playbooks can be found `here <http://www.ansibleworks.com/docs/playbooks2.html#pull-mode-playbooks>`_.
(Various developments around Ansible are also going to make this easier in the near future. Stay tuned!)
Use Cases
`````````
This section covers some usage examples built around a specific use case.
Example 1
+++++++++
Example 1: I'm using CloudFormation to deploy a specific infrastructure stack. I'd like to manage configuration of the instances with Ansible.
Provision instances with your tool of choice and consider using the inventory plugin to group hosts based on particular tags or security group. Consider tagging instances you wish to managed with Ansible with a suitably unique key=value tag.
Example 2
+++++++++
Example 2: I'm using AutoScaling to dynamically scale up and scale down the number of instances. This means the number of hosts is constantly fluctuating but I'm letting EC2 automatically handle the provisioning of these instances. I don't want to fully bake a machine image, I'd like to use Ansible to configure the hosts.
There are two approaches to this use case. The first is to use the inventory plugin to regularly refresh host information and then target hosts based on the latest inventory data. The second is to use ansible-pull triggered by a user-data script (specified in the launch configuration) which would then mean that each instance would fetch Ansible and the latest playbook from a git repository and run locally to configure itself.
Example 3
+++++++++
Example 3: I don't want to use Ansible to manage my instances but I'd like to consider using Ansible to build my fully-baked machine images.
There's nothing to stop you doing this. If you like working with Ansible's playbook format then writing a playbook to create an image; create an image file with dd, give it a filesystem and then install packages and finally chroot into it for further configuration. Ansible has the 'chroot' plugin for this purpose, just add the following to your inventory file::
/chroot/path ansible_connection=chroot
And in your playbook::
hosts: /chroot/path
Pending Information
```````````````````
In the future look here for more topics.
Using Ansible's S3 module
+++++++++++++++++++++++++
these modules are documented on the module page, more walk throughs coming soon
Using Ansible's Elastic Load Balancer Support
+++++++++++++++++++++++++++++++++++++++++++++
these modules are documented on the module page, more walk throughs coming soon
Using Ansible's Cloud Formation Module
++++++++++++++++++++++++++++++++++++++
these modules are documented on the module page, more walk throughs coming soon
..seealso::
:doc:`examples`
Examples of basic commands
:doc:`playbooks`
Learning ansible's configuration management language
`Mailing List <http://groups.google.com/group/ansible-project>`_
Questions? Help? Ideas? Stop by the list on Google Groups
@ -8,13 +8,12 @@ API so you have a considerable amount of power across the board.
..contents::`Table of contents`
:depth:2
:backlinks:top
Python API
----------
The Python API is very powerful, and is how the ansible CLI and ansible-playbook
are implemented.
are implemented.
It's pretty simple::
@ -35,7 +34,7 @@ expressed in the 'ansible-modules' documentation.::
{
"dark" : {
"web1.example.com" : "failure message"
}
},
"contacted" : {
"web2.example.com" : 1
}
@ -82,8 +81,8 @@ Advanced programmers may also wish to read the source to ansible itself, for
it uses the Runner() API (with all available options) to implement the
command line tools ``ansible`` and ``ansible-playbook``.
Plugins Repository
------------------
Plugins Available Online
------------------------
The remainder of features in the API docs have components available in `ansible-plugins <https://github.com/ansible/ansible/blob/devel/plugins>`_. Send us a github pull request if you develop any interesting features.
@ -91,7 +90,7 @@ External Inventory Scripts
--------------------------
Often a user of a configuration management system will want to keep inventory
in a different system. Frequent examples include LDAP, `Cobbler <http://cobbler.github.com>`_,
in a different system. Frequent examples include LDAP, `Cobbler <http://cobbler.github.com>`_,
or a piece of expensive enterprisey CMDB software. Ansible easily supports all
of these options via an external inventory system. The plugins directory contains some of these already -- including options for EC2/Eucalyptus and OpenStack, which will be detailed below.
@ -100,24 +99,74 @@ It's possible to write an external inventory script in any language. If you are
Script Conventions
``````````````````
When the external node script is called with the single argument '--list', the script must return a JSON hash/dictionary of all the groups to be managed, with a list of each host/IP as the value for each hash/dictionary element, like so::
When the external node script is called with the single argument '--list', the script must return a JSON hash/dictionary of all the groups to be managed.
Each group's value should be either a hash/dictionary containing a list of each host/IP, potential child groups, and potential group variables, or
Before version 1.0, each group could only have a list of hostnames/IP addresses, like the webservers, marietta, and 5points groups above.
When called with the arguments '--host <hostname>' (where <hostname> is a host from above), the script must return either an empty JSON
hash/dictionary, or a list of key/value variables to make available to templates or playbooks. Returning variables is optional,
hash/dictionary, or a hash/dictionary of variables to make available to templates and playbooks. Returning variables is optional,
if the script does not wish to do this, returning an empty hash/dictionary is the way to go::
{
'favcolor' : 'red',
'ntpserver' : 'wolf.example.com',
'monitoring' : 'pack.example.com'
"favcolor" : "red",
"ntpserver" : "wolf.example.com",
"monitoring" : "pack.example.com"
}
Tuning the External Inventory Script
````````````````````````````````````
..versionadded:: 1.3
The stock inventory script system detailed above works for all versions of Ansible, but calling
'--host' for every host can be rather expensive, especially if it involves expensive API calls to
a remote subsystemm. In Ansible
1.3 or later, if the inventory script returns a top level element called "_meta", it is possible
to return all of the host variables in one inventory script call. When this meta element contains
a value for "hostvars", the inventory script will not be invoked with "--host" for each host. This
results in a significant performance increase for large numbers of hosts, and also makes client
side caching easier to implement for the inventory script.
The data to be added to the top level JSON dictionary looks like this::
{
# results of inventory script as above go here
# ...
"_meta" : {
"hostvars" : {
"moocow.example.com" : { "asdf" : 1234 },
"llama.example.com" : { "asdf" : 5678 },
}
}
}
Example: The Cobbler External Inventory Script
``````````````````````````````````````````````
@ -183,7 +232,7 @@ You can use this script in one of two ways. The easiest is to use Ansible's ``-i
ansible -i ec2.py -u ubuntu us-east-1d -m ping
The second option is to copy the script to `/etc/ansible/hosts` and `chmod +x` it. You will also need to copy the ``ec2.ini`` file to `/etc/ansible/ec2.ini`. Then you can run ansible as you would normally.
The second option is to copy the script to `/etc/ansible/hosts` and `chmod +x` it. You will also need to copy the `ec2.ini <https://raw.github.com/ansible/ansible/devel/plugins/inventory/ec2.ini>`_ file to `/etc/ansible/ec2.ini`. Then you can run ansible as you would normally.
To successfully make an API call to AWS, you will need to configure Boto (the Python interface to AWS). There are a `variety of methods <http://docs.pythonboto.org/en/latest/boto_config_tut.html>`_ available, but the simplest is just to export two environment variables:
@ -192,8 +241,8 @@ To successfully make an API call to AWS, you will need to configure Boto (the Py
You can test the script by itself to make sure your config is correct
cd examples/scripts
./ec2_external_inventory.py --list
cd plugins/inventory
./ec2.py --list
After a few moments, you should see your entire EC2 inventory across all regions in JSON.
@ -207,7 +256,7 @@ Instance ID
These are groups of one since instance IDs are unique.
e.g.
``i-00112233``
``i-a1b1c1d1``
``i-a1b1c1d1``
Region
A group of all instances in an AWS region.
@ -276,13 +325,14 @@ Both ``ec2_security_group_ids`` and ``ec2_security_group_names`` are comma-separ
To see the complete list of variables available for an instance, run the script by itself::
Though not detailed here in as much depth as the EC2 module, there's also a OpenStack Nova external inventory source in the plugins directory. See the inline comments in the module source.
Though not detailed here in as much depth as the EC2 module, there's also a OpenStack Compute external inventory source in the plugins directory. It requires the Grizzly release of OpenStack or
later. See the inline comments in the module source for how to use it.
Callback Plugins
----------------
@ -293,11 +343,48 @@ system, or even (yes, really) making sound effects. Some examples are contained
Connection Type Plugins
-----------------------
By default, ansible ships with a 'paramiko' SSH, native ssh (just called 'ssh'), and 'local' connection type, which can be used
By default, ansible ships with a 'paramiko' SSH, native ssh (just called 'ssh'), and 'local' connection type, and an accelerated connection type named 'fireball'. All of these can be used
in playbooks and with /usr/bin/ansible to decide how you want to talk to remote machines. The basics of these connection types
are covered in the 'getting started' section. Should you want to extend Ansible to support other transports (SNMP? Message bus?
Carrier Pigeon?) it's as simple as copying the format of one of the existing modules and dropping it into the connection plugins
directory.
directory. The value of 'smart' for a connection allows selection of paramiko or openssh based on system capabilities, and chooses
'ssh' if OpenSSH supports ControlPersist, in Ansible 1.2.1 an later. Previous versions did not support 'smart'.
Lookup Plugins
--------------
Language constructs like "with_fileglob" and "with_items" are implemented via lookup plugins. Just like other plugin types, you can write your own.
Vars Plugins
------------
Playbook constructs like 'host_vars' and 'group_vars' work via 'vars' plugins. They inject additional variable
data into ansible runs that did not come from an inventory, playbook, or command line. Note that variables
can also be returned from inventory, so in most cases, you won't need to write or understand vars_plugins.
Filter Plugins
--------------
If you want more Jinja2 filters available in a Jinja2 template (filters like to_yaml and to_json are provided by default), they can be extended by writing a filter plugin.
Distributing Plugins
--------------------
..versionadded:: 0.8
Plugins are loaded from both Python's site_packages (those that ship with ansible) and a configured plugins directory, which defaults
to /usr/share/ansible/plugins, in a subfolder for each plugin type::
* action_plugins
* lookup_plugins
* callback_plugins
* connection_plugins
* filter_plugins
* vars_plugins
To change this path, edit the ansible configuration file.
In addition, plugins can be shipped in a subdirectory relative to a top-level playbook, in folders named the same as indicated above.
Here are some tips for making the most of Ansible.
You can find some example playbooks illustrating these best practices in our `ansible-examples repository <https://github.com/ansible/ansible-examples>`_. (NOTE: These may not use all of the features in the latest release just yet).
..contents::
:depth:2
Content Organization
++++++++++++++++++++++
The following section shows one of many possible ways to organize content. Your usage of Ansible should fit your needs,
so feel free to modify this approach and organize as you see fit.
(One thing you will definitely want to do though, is use the "roles" organization feature, which is documented as part
of the main playbooks page)
Directory Layout
````````````````
The top level of the directory would contain files and directories like so::
production # inventory file for production servers
stage # inventory file for stage environment
group_vars/
group1 # here we assign variables to particular groups
group2 # ""
host_vars/
hostname1 # if systems need specific variables, put them here
hostname2 # ""
site.yml # master playbook
webservers.yml # playbook for webserver tier
dbservers.yml # playbook for dbserver tier
roles/
common/ # this hierarchy represents a "role"
tasks/ #
main.yml # <-- tasks file can include smaller files if warranted
handlers/ #
main.yml # <-- handlers file
templates/ # <-- files for use with the template resource
ntp.conf.j2 # <------- templates end in .j2
files/ #
bar.txt # <-- files for use with the copy resource
foo.sh # <-- script files for use with the script resource
vars/ #
main.yml # <-- variables associated with this role
webtier/ # same kind of structure as "common" was above, done for the webtier role
monitoring/ # ""
fooapp/ # ""
How to Arrange Inventory, Stage vs Production
`````````````````````````````````````````````
In this example, the *production* file contains the inventory of all of your production hosts. Of course you can pull inventory from an external
data source as well, but this is just a basic example. Define groups based on purpose of the host (roles) and also geography or datacenter location::
# file: production
[atlanta-webservers]
www-atl-1.example.com
www-atl-2.example.com
[boston-webservers]
www-bos-1.example.com
www-bos-2.example.com
[atlanta-dbservers]
db-atl-1.example.com
db-atl-2.example.com
[boston-dbservers]
db-bos-1.example.com
# webservers in all geos
[webservers:children]
atlanta-webservers
boston-webservers
# dbservers in all geos
[dbservers:children]
atlanta-dbservers
boston-dbservers
# everything in the atlanta geo
[atlanta:children]
atlanta-webservers
atlanta-dbservers
# everything in the boston geo
[boston:children]
boston-webservers
boston-dbservers
Group And Host Variables
````````````````````````
Now, groups are nice for organization, but that's not all groups are good for. You can also assign variables to them! For instance, atlanta
has its own NTP servers, so when setting up ntp.conf, we should use them. Let's set those now::
---
# file: group_vars/atlanta
ntp: ntp-atlanta.example.com
backup: backup-atlanta.example.com
Variables aren't just for geographic information either! Maybe the webservers have some configuration that doesn't make sense for the database
servers::
---
# file: group_vars/webservers
apacheMaxRequestsPerChild: 3000
apacheMaxClients: 900
If we had any default values, or values that were universally true, we would put them in a file called group_vars/all::
---
# file: group_vars/all
ntp: ntp-boston.example.com
backup: backup-boston.example.com
We can define specific hardware variance in systems in a host_vars file, but avoid doing this unless you need to::
---
# file: host_vars/db-bos-1.example.com
foo_agent_port: 86
bar_agent_port: 99
Role Variables
``````````````
Variables that are associated with a given role can be defined in a main.yml file within the "vars" directory for that role. These variables are accessible not only to the role itself, but to all other roles and tasks that are part of the same playbook.::
---
# file: roles/python/vars/main.yml
python_version: "2.7.5"
pip_version: "1.3.1"
Top Level Playbooks Are Separated By Role
`````````````````````````````````````````
In site.yml, we include a playbook that defines our entire infrastructure. Note this is SUPER short, because it's just including
some other playbooks. Remember, playbooks are nothing more than lists of plays::
---
# file: site.yml
- include: webservers.yml
- include: dbservers.yml
In a file like webservers.yml (also at the top level), we simply map the configuration of the webservers group to the roles performed by the webservers group. Also notice this is incredibly short. For example::
---
# file: webservers.yml
- hosts: webservers
roles:
- common
- webtier
Task And Handler Organization For A Role
````````````````````````````````````````
Below is an example tasks file that explains how a role works. Our common role here just sets up NTP, but it could do more if we wanted::
---
# file: roles/common/tasks/main.yml
- name: be sure ntp is installed
yum: pkg=ntp state=installed
tags: ntp
- name: be sure ntp is configured
template: src=ntp.conf.j2 dest=/etc/ntp.conf
notify:
- restart ntpd
tags: ntp
- name: be sure ntpd is running and enabled
service: name=ntpd state=running enabled=yes
tags: ntp
Here is an example handlers file. As a review, handlers are only fired when certain tasks report changes, and are run at the end
of each play::
---
# file: roles/common/handlers/main.yml
- name: restart ntpd
service: name=ntpd state=restarted
What This Organization Enables (Examples)
`````````````````````````````````````````
So that's our basic organizational structure.
Now what sort of use cases does this layout enable? Lots! If I want to reconfigure my whole infrastructure, it's just::
ansible-playbook -i production site.yml
What about just reconfiguring NTP on everything? Easy.::
ansible-playbook -i production site.yml --tags ntp
What about just reconfiguring my webservers?::
ansible-playbook -i production webservers.yml
What about just my webservers in Boston?::
ansible-playbook -i production webservers.yml --limit boston
What about just the first 10, and then the next 10?::
ansible-playbook -i production webservers.yml --limit boston[0-10]
ansible-playbook -i production webservers.yml --limit boston[10-20]
And of course just basic ad-hoc stuff is also possible.::
ansible -i production -m ping
ansible -i production -m command -a '/sbin/reboot' --limit boston
And there are some useful commands to know (at least in 1.1 and higher)::
# confirm what task names would be run if I ran this command and said "just ntp tasks"
ansible-playbook -i production webservers.yml --tags ntp --list-tasks
# confirm what hostnames might be communicated with if I said "limit to boston"
ansible-playbook -i production webservers.yml --limit boston --list-hosts
Deployment vs Configuration Organization
````````````````````````````````````````
The above setup models a typical OS configuration topology. When doing multi-tier deployments, there are going
to be some additional playbooks that hop between tiers to roll out an application. In this case, 'site.yml'
may be augmented by playbooks like 'deploy_exampledotcom.yml' but the general concepts can still apply.
Ansible allows you to deploy and configure using the same tool, so you would likely reuse groups and just
keep the OS configuration in separate playbooks from the app deployment.
Stage vs Production
+++++++++++++++++++
As also mentioned above, a good way to keep your stage (or testing) and production environments separate is to use a separate inventory file for stage and production. This way you pick with -i what you are targeting. Keeping them all in one file can lead to surprises!
Testing things in a stage environment before trying in production is always a great idea. Your environments need not be the same
size and you can use group variables to control the differences between those environments.
Rolling Updates
+++++++++++++++
Understand the 'serial' keyword. If updating a webserver farm you really want to use it to control how many machines you are
updating at once in the batch.
Always Mention The State
++++++++++++++++++++++++
The 'state' parameter is optional to a lot of modules. Whether 'state=present' or 'state=absent', it's always best to leave that
parameter in your playbooks to make it clear, especially as some modules support additional states.
Group By Roles
++++++++++++++
A system can be in multiple groups. See :doc:`patterns`. Having groups named after things like
*webservers* and *dbservers* is repeated in the examples because it's a very powerful concept.
This allows playbooks to target machines based on role, as well as to assign role specific variables
using the group variable system.
Operating System and Distribution Variance
++++++++++++++++++++++++++++++++++++++++++
When dealing with a parameter that is different between two different operating systems, the best way to handle this is
by using the group_by module.
This makes a dynamic group of hosts matching certain criteria, even if that group is not defined in the inventory file::
---
# talk to all hosts just so we can learn about them
- hosts: all
tasks:
- group_by: key={{ ansible_distribution }}
# now just on the CentOS hosts...
- hosts: CentOS
gather_facts: False
tasks:
- # tasks that only happen on CentOS go here
If group-specific settings are needed, this can also be done. For example::
---
# file: group_vars/all
asdf: 10
---
# file: group_vars/CentOS
asdf: 42
In the above example, CentOS machines get the value of '42' for asdf, but other machines get '10'.
Bundling Ansible Modules With Playbooks
+++++++++++++++++++++++++++++++++++++++
..versionadded:: 0.5
If a playbook has a "./library" directory relative to its YAML file, this directory can be used to add ansible modules that will
automatically be in the ansible module path. This is a great way to keep modules that go with a playbook together.
Whitespace and Comments
+++++++++++++++++++++++
Generous use of whitespace to break things up, and use of comments (which start with '#'), is encouraged.
Always Name Tasks
+++++++++++++++++
It is possible to leave off the 'name' for a given task, though it is recommended to provide a description
about why something is being done instead. This name is shown when the playbook is run.
Keep It Simple
++++++++++++++
When you can do something simply, do something simply. Do not reach
to use every feature of Ansible together, all at once. Use what works
for you. For example, you will probably not need 'vars',
'vars_files', 'vars_prompt' and '--extra-vars' all at once,
while also using an external inventory file.
Version Control
+++++++++++++++
Use version control. Keep your playbooks and inventory file in git
(or another version control system), and commit when you make changes
to them. This way you have an audit trail describing when and why you
changed the rules that are automating your infrastructure.
..seealso::
:doc:`YAMLSyntax`
Learn about YAML syntax
:doc:`playbooks`
Review the basic playbook features
:doc:`modules`
Learn about available modules
:doc:`moduledev`
Learn how to extend Ansible by writing your own modules
All python modules (especially all submitted to core) should use the common "AnsibleModule" class to dramatically reduce the amount of boilerplate code required.
Not all modules above may take advantage of this feature. See the official documentation for more details.
Selected Playbooks
``````````````````
`Playbooks <http://www.ansibleworks.com/docs/playbooks.html>`_ are Ansible's
configuration management language. It should be easy to write your own
from scratch for most applications (we keep the language simple for EXACTLY that reason), but it can
be helpful to look at what others have done for reference and see what is possible.
The ansible-examples repo on github contains some examples of best-practices Ansible content deploying some
-`Exploring Configuration Management With Ansible <http://palominodb.com/blog/2012/08/01/exploring-configuration-management-ansible>`_ - Palamino DB
-`You Should Consider Using SSH Based Configuration Management <http://www.lshift.net/blog/2012/07/30/you-should-consider-using-ssh-based-configuration-management>`_ - LShift Ltd
-`Deploying Flask/uWSGI, Nginx, and Supervisorctl <http://mattupstate.github.com/python/devops/2012/08/07/flask-wsgi-application-deployment-with-ubuntu-ansible-nginx-supervisor-and-uwsgi.html>`_ - mattupstate
-`Infracoders Presentation <http://www.danielhall.me/2012/10/ansible-talk-infra-coders/>`_ - Daniel Hall
-`Ansible - an introduction <https://speakerdeck.com/jpmens/ansible-an-introduction>`_ - jp\_mens
-`Using Ansible to setup complex networking - <http://exarv.nl/2013/02/using-ansible-to-setup-complex-networking/>`_ - Robert Verspuy
-`Video presentation to Montreal Linux <http://www.youtube.com/embed/up3ofvQNm8c>`_ - Alexandre Bourget
-`Provisioning CentOS EC2 Instances with Ansible <http://jpmens.net/2012/11/21/provisioning-centos-ec2-instances-with-ansible/>`_ - jp\_mens
Disclaimer
``````````
Modules and playbooks here may not be using the latest in Ansible
features. When in doubt to the features of a particular version of
Ansible, always consult `ansibleworks.com <http://www.ansibleworks.com/>`_ and in
particular see `Best Practices <http://www.ansibleworks.com/docs/bestpractices.html>`_
for some tips and tricks that may be useful.
Ansible is (C) 2012, `Michael DeHaan <http://twitter.com/laserllama>`_
and others and is available under the GPLv3 license. Content here is as
@ -12,7 +12,6 @@ using `/usr/bin/ansible-playbook` -- the concepts port over directly.
..contents::
:depth:2
:backlinks:top
Parallelism and Shell Commands
@ -22,7 +21,7 @@ Let's use ansible's command line tool to reboot all web servers in Atlanta, 10 a
set up SSH-agent so it can remember our credentials::
$ ssh-agent bash
$ ssh-add ~/.ssh/id_rsa.pub
$ ssh-add ~/.ssh/id_rsa
If you don't want to use ssh-agent and want to instead SSH with a
password instead of keys, you can with ``--ask-pass`` (``-k``), but
@ -121,22 +120,23 @@ with yum.
Ensure a package is installed, but don't update it::
$ ansible webservers -m yum -a "pkg=acme state=installed"
$ ansible webservers -m yum -a "name=acme state=installed"
Ensure a package is installed to a specific version::
$ ansible webservers -m yum -a "pkg=acme-1.5 state=installed"
$ ansible webservers -m yum -a "name=acme-1.5 state=installed"
Ensure a package is at the latest version::
$ ansible webservers -m yum -a "pkg=acme state=latest"
$ ansible webservers -m yum -a "name=acme state=latest"
Ensure a package is not installed::
$ ansible webservers -m yum -a "pkg=acme state=removed"
$ ansible webservers -m yum -a "name=acme state=removed"
Currently Ansible only has modules for managing packages with yum and apt. You can install
for other packages for now using the command module or (better!) contribute a module
Ansible has modules for managing packages under many platforms. If your package manager
does not have a module available for it, you can install
for other packages using the command module or (better!) contribute a module
for other package managers. Stop by the mailing list for info/details.
Users and Groups
@ -209,6 +209,17 @@ the remote nodes will be terminated.
Typically you'll be only be backgrounding long-running
shell commands or software upgrades only. Backgrounding the copy module does not do a background file transfer. :doc:`playbooks` also support polling, and have a simplified syntax for this.
Gathering Facts
```````````````
Facts are described in the playbooks section and represent discovered variables about a
system. These can be used to implement conditional execution of tasks but also just to get ad-hoc information about your system. You can see all facts via::
$ ansible all -m setup
Its also possible to filter this output to just export certain facts, see the "setup" module documentation for details.
Limiting Selected Hosts
```````````````````````
@ -226,6 +237,8 @@ also works with ``ansible-playbook``::
$ ansible webservers:dbservers -m command -a "/bin/foo xyz" --limit region
Assuming version 0.9 or later, as with other host patterns, values to limit can be separated with ";", ":", or ",".
Now let's talk about range selection. Suppose you have 1000 servers in group 'datacenter', but only want to target one at a time. This is also easy::
$ ansible webservers[0-99] -m command -a "/bin/foo xyz"
@ -245,8 +258,8 @@ Ansible has an optional configuration file that can be used to tune settings and
the first config file it finds present:
1. File specified by the ``ANSIBLE_CONFIG`` environment variable
2. ``ansible.cfg`` in the current working directory. (version 0.8 and up)
3. ``~/.ansible.cfg``
2. ``~/.ansible.cfg``
3. ``ansible.cfg`` in the current working directory. (version 0.8 and up)
4. ``/etc/ansible/ansible.cfg``
For those running from source, a sample configuration file lives in the examples/ directory. The RPM will install configuration into /etc/ansible/ansible.cfg automatically.
While you can write ansible modules in any language, most ansible modules are written in Python, and some of these
are important core ones.
By default Ansible assumes it can find a /usr/bin/python on your remote system that is a 2.X version of Python, specifically
2.4 or higher.
Setting of an inventory variable 'ansible_python_interpreter' on any host will allow Ansible to auto-replace the interpreter
used when executing python modules. Thus, you can point to any python you want on the system if /usr/bin/python on your
system does not point to a Python 2.X interpreter.
Some Linux operating systems, such as Arch, may only have Python 3 installed by default. This is not sufficient and you will
get syntax errors trying to run modules with Python 3. Python 3 is essentially not the same
language as Python 2. Ansible modules currently need to support older Pythons for users that still have Enterprise Linux 5 deployed, so they are not yet ported to run under Python 3.0. This is not a problem though as you can just install Python 2 also on a managed host.
Python 3.0 support will likely be addressed at a later point in time when usage becomes more mainstream.
Do not replace the shebang lines of your python modules. Ansible will do this for you automatically at deploy time.
What is the best way to make content reusable/redistributable?
Technically ansible doesn't need a configuration file, but OS packages are likely to include a default one in /etc/ansible/ansible.cfg
that you may customize. You can also install your own copy in ~/.ansible.cfg or keep a copy in a directory relative to your playbook named "ansible.cfg".
For what values you can use in this file, see `the configuration file on github <https://github.com/ansible/ansible/blob/devel/examples/ansible.cfg>`_.
Generally you would configure the default module path or connection type here, among other things, though the defaults are usually
good enough for starting out.
How do I disable cowsay?
++++++++++++++++++++++++
If cowsay is installed, Ansible takes it upon itself to make your day happier when running playbooks. If you decide
that you would like to work in a professional cow-free environment, you can either uninstall cowsay, or set an environment variable::
export ANSIBLE_NOCOWS=1
How do I see a list of all of the ansible\_ variables?
Ansible by default gathers "facts" about the machines under management, and these facts can be accessed in Playbooks and in templates. To see a list of all of the facts that are available about a machine, you can run the "setup" module as an ad-hoc action::
ansible -m setup hostname
This will print out a dictionary of all of the facts that are available for that particular host.
How do I loop over a list of hosts in a group, inside of a template?
A pretty common pattern is to iterate over a list of hosts inside of a host group, perhaps to populate a template configuration
file with a list of servers. To do this, you can just access the "$groups" dictionary in your template, like this::
{% for host in groups['db_servers'] %}
{{ host }}
{% endfor %}
If you need to access facts about these hosts, for instance, the IP address of each hostname, you need to make sure that the facts have been populated. For example, make sure you have a play that talks to db_servers::
- hosts: db_servers
tasks:
- # doesn't matter what you do, just that they were talked to previously.
Then you can use the facts inside your template, like this::
The "copy" module doesn't handle recursive copies of directories. A common solution to do this is to use a local action to call 'rsync' to recursively copy files to the managed servers.
Here is an example::
---
# ...
tasks:
- name: recursively copy files from management server to target
local_action: command rsync -a /path/to/files $inventory_hostname:/path/to/target/
Note that you'll need passphrase-less SSH or ssh-agent set up to let rsync copy without prompting for a passphase or password.
How do I access shell environment variables?
++++++++++++++++++++++++++++++++++++++++++++
If you just need to access existing variables, use the 'env' lookup plugin. For example, to access the value of the HOME
environment variable on management machine::
---
# ...
vars:
local_home: "{{ lookup('env','HOME') }}"
If you need to set environment variables, see the Advanced Playbooks section about environments.
Can I get training on Ansible or find commercial support?
Yes! See `AnsibleWorks.com <http://ansibleworks.com>`_ or email `info@ansibleworks.com <mailto:info@ansibleworks.com>`_.
How do I submit a change to the documentation?
++++++++++++++++++++++++++++++++++++++++++++++
Great question! Documentation for Ansible is kept in the main project git repository, and complete instructions for contributing can be found in the docs README `viewable on GitHub <https://github.com/ansible/ansible/tree/devel/docsite/latest#readme>`_. Thanks!
I don't see my question here
++++++++++++++++++++++++++++
See the "Resources" section of the documentation for a link to the IRC and Google Group.
For the central Ansible machine, you will need an environment with Python 2.6 or greater installed. If you are running Python 2.5 on an "Enterprise Linux 5" variant, we'll show you how to add 2.6 to your distribution, but most platforms already have a new enough Python. (Note that Windows is not supported as the Ansible control machine.)
You will also want the following Python modules (installed via pip or perhaps via your OS package manager via slightly different names):
*``paramiko``
*``PyYAML``
*``jinja2``
If you are using RHEL or CentOS 5, Python is version 2.4 by default, but you can get Python 2.6 installed easily. `Use EPEL <http://fedoraproject.org/wiki/EPEL>`_ and install these dependencies as follows:
The following is a list (and re-explanation) of term definitions used elsewhere in the Ansible documentation.
Consult the documentation home page for the full documentation and to see the terms in context, but this should be a good resource
to check your knowledge of Ansible's components and understand how they fit together. It's something you might wish to read for review or
when a term comes up on the mailing list.
Action
++++++
An action is a part of a task that specifies which of the modules to run and the arguments to pass to that module. Each task can have only one action, but it may also have other parameters.
Ad Hoc
++++++
Refers to running Ansible to perform some quick command, using /usr/bin/ansible, rather than the orchestration language, which is
/usr/bin/ansible-playbook. An example of an ad-hoc command might be rebooting 50 machines in your infrastructure. Anything
you can do ad-hoc can be accomplished by writing a playbook, and playbooks can also glue lots of other operations together.
Async
+++++
Refers to a task that is configured to run in the background rather than waiting for completion. If you have a long process
that would run longer than the SSH timeout, it would make sense to launch that task in async mode. Async modes can poll
for completion every so many seconds, or can be configured to "fire and forget" in which case Ansible will not even
check on the task again, it will just kick it off and proceed to future steps. Async modes work with both /usr/bin/ansible
and /usr/bin/ansible-playbook.
Callback Plugin
+++++++++++++++
Refers to some user-written code that can intercept results from Ansible and do something with them. Some supplied examples
in the GitHub project perform custom logging, send email, or even play sound effects.
Check Mode
++++++++++
Refers to running Ansible with the --check option, which does not make any changes on the remote systems, but only outputs the changes that
might occur if the command ran without this flag. This is analogous to so-called "dry run" modes in other systems, though the user should
be warned that this does not take into account unexpected command failures or cascade effects (which is true of similar modes in other
systems). Use this to get an idea of what might happen, but it is not a substitute for a good staging environment.
Connection Type, Connection Plugin
++++++++++++++++++++++++++++++++++
By default, Ansible talks to remote machines through pluggable libraries. Ansible supports native OpenSSH ('ssh'), or a Python
implementation called 'paramiko'. OpenSSH is preferred if you are using a recent version, and also enables some features
like Kerberos and jump hosts. This is covered in the getting started section.
There are also other connection types like 'fireball' mode, which must be bootstrapped
over one of the SSH-based connection types but is very fast, and local mode, which acts on the local system.
Users can also write their own connection plugins.
Conditionals
++++++++++++
A conditional is an expression that evaluates to true or false that decides whether a given task will be executed on a given
machine or not. Ansible's conditionals include 'when_boolean',
'when_string', and 'when_integer'. These are discussed in the playbook documentation.
Diff Mode
+++++++++
A --diff flag can be passed to Ansible to show how template files change when they are overwritten, or how they might change when used
with --check mode. These diffs come out in unified diff format.
Facts
+++++
Facts are simply things that are discovered about remote nodes. While they can be used in playbooks and templates just like variables, facts
are things that are inferred, rather than set. Facts are automatically discovered by Ansible when running plays by executing the internal 'setup'
module on the remote nodes. You never have to call the setup module explicitly, it just runs, but it can be disabled to save time if it is
not needed. For the convenience of users who are switching from other configuration management systems, the fact module will also pull in facts from the 'ohai' and 'facter'
tools if they are installed, which are fact libraries from Chef and Puppet, respectively.
Filter Plugin
+++++++++++++
A filter plugin is something that most users will never need to understand. These allow for the creation of new Jinja2 filters, which
are more or less only of use to people who know what Jinja2 filters are. If you need them, you can learn how to write them in the API
docs section.
Fireball Mode
+++++++++++++
By default, Ansible uses SSH for connections -- either paramiko or native OpenSSH, a common alternative. (Ansible tries to use
'ssh' by default if possible in Ansible 1.2.1 and later, but previously defaulted to paramiko). Some users
may want to execute operations even faster though, and they can if they opt to run their tasks using an ephemeral 'fireball' message bus. What happens in this mode is that Ansible
will start talking to a node over SSH, and then set up a secure, temporary message bus that authenticates only a single machine, and that will
self destruct after a set period of time. This means the bus does not allow management of any kind after the time interval has expired.
Forks
+++++
Ansible talks to remote nodes in parallel and the level of parallelism can be set either by passing --forks, or editing the default in a configuration
file. The default is a very conservative 5 forks, though if you have a lot of RAM, you can easily set this to a value like 50 for increased
parallelism.
Gather Facts (Boolean)
++++++++++++++++++++++
Facts are mentioned above. Sometimes when running a multi-play playbook, it is desirable to have some plays that don't bother with fact
computation if they aren't going to need to utilize any of these values. Setting `gather_facts: False` on a playbook allows this implicit
fact gathering to be skipped.
Globbing
++++++++
Globbing is a way to select lots of hosts based on wildcards, rather than the name of the host specifically, or the name of the group
they are in. For instance, it is possible to select "www*" to match all hosts starting with "www". This concept is pulled directly
from Func, one of Michael's earlier projects. In addition to basic globbing, various set operations are also possible, such as
'hosts in this group and not in another group', and so on.
Group
+++++
A group consists of several hosts assigned to a pool that can be conveniently targeted together, and also given variables that they share in
common.
Group Vars
++++++++++
The "group_vars/" files are files that live in a directory alongside an inventory file, with an optional filename named after each group.
This is a convenient place to put variables that will be provided to a given group, especially complex data structures, so that these
variables do not have to be embedded in the inventory file or playbook.
Handlers
++++++++
Handlers are just like regular tasks in an Ansible playbook (see Tasks), but are only run if the Task contains a "notify" directive and
also indicates that it changed something. For example, if a config file is changed then the task referencing the config file templating
operation may notify a service restart handler. This means services can be bounced only if they need to be restarted.
Handlers can be used for things other than service restarts, but service restarts are the most common usage.
Host
++++
A host is simply a remote machine that Ansible manages. They can have individual variables assigned to them, and can also be organized
in groups. All hosts have a name they can be reached at (which is either an IP address or a domain name) and optionally a port number
if they are not to be accessed on the default SSH port.
Host Specifier
++++++++++++++
Each Play in Ansible maps a series of tasks (which define the role, purpose, or orders of a system) to a set of systems.
This "hosts:" directive in each play is often called the hosts specifier.
It may select one system, many systems, one or more groups, or even some hosts that are in one group and explicitly not in another.
Host Vars
+++++++++
Just like "Group Vars", a directory alongside the inventory file named "host_vars/" can contain a file named after each hostname in
the inventory file, in YAML format. This provides a convenient place to assign variables to the host without having to embed
them in the inventory file. The Host Vars file can also be used to define complex data structures that can't be represented in the
inventory file.
Lazy Evaluation
+++++++++++++++
In general, Ansible evaluates any variables in playbook content at the last possible second, which means that if you define a data structure
that data structure itself can define variable values within it, and everything "just works" as you would expect. This also means variable
strings can include other variables inside of those strings.
Lookup Plugin
+++++++++++++
A lookup plugin is a way to get data into Ansible from the outside world. These are how such things as "with_items", a basic looping plugin, are implemented,
but there are also lookup plugins like "with_file" which loads data from a file, and even ones for querying environment variables,
DNS text records, or key value stores. Lookup plugins can also be accessed in templates, e.g., ``{{ lookup('file','/path/to/file') }}``.
Multi-Tier
++++++++++
The concept that IT systems are not managed one system at a time, but by interactions between multiple systems, and groups of systems, in
well defined orders. For instance, a web server may need to be updated before a database server, and pieces on the web server may need
to be updated after *THAT* database server, and various load balancers and monitoring servers may need to be contacted. Ansible models
entire IT topologies and workflows rather than looking at configuration from a "one system at a time" perspective.
Idempotency
+++++++++++
The concept that change commands should only be applied when they need to be applied, and that it is better to describe the desired
state of a system than the process of how to get to that state. As an analogy, the path from North Carolina in the United States to
California involves driving a very long way West, but if I were instead in Anchorage, Alaska, driving a long way west is no longer
the right way to get to California. Ansible's Resources like you to say "put me in California" and then decide how to get there. If
you were already in California, nothing needs to happen, and it will let you know it didn't need to change anything.
Includes
++++++++
The idea that playbook files (which are nothing more than lists of plays) can include other lists of plays, and task lists
can externalize lists of tasks in other files, and similarly with handlers. Includes can be parameterized, which means that the
loaded file can pass variables. For instance, an included play for setting up a WordPress blog may take a parameter called "user"
and that play could be included more than once to create a blog for both "alice" and "bob".
Inventory
+++++++++
A file (by default, Ansible uses a simple INI format) that describes Hosts and Groups in Ansible. Inventory can also be provided
via an "Inventory Script" (sometimes called an "External Inventory Script").
Inventory Script
++++++++++++++++
A very simple program (or a complicated one) that looks up hosts, group membership for hosts, and variable information from an external
resource -- whether that be a SQL database, a CMDB solution, or something like LDAP. This concept was adapted from Puppet (where it is
called an "External Nodes Classifier") and works more or less exactly the same way.
Jinja2
++++++
Jinja2 is the preferred templating language of Ansible's template module. It is a very simple Python template language that is generally
readable and easy to write.
JSON
++++
Ansible uses JSON for return data from remote modules. This allows modules to be written in any language, not just Python.
only_if
+++++++
A deprecated form of the "when:" statement. It should no longer be used.
Library
+++++++
A collection of modules made available to /usr/bin/ansible or an Ansible playbook.
Limit Groups
++++++++++++
By passing "--limit somegroup" to ansible or ansible-playbook, the commands can be limited to a subset of hosts. For instance,
this can be used to run a playbook that normally targets an entire set of servers to one particular server.
Local Connection
++++++++++++++++
By using "connection: local" in a playbook, or passing "-c local" to /usr/bin/ansible, this indicates that we are managing the local
host and not a remote machine.
Local Action
++++++++++++
A local_action directive in a playbook targeting remote machines means that the given step will actually occur on the local
machine, but that the variable '{{ ansible_hostname }}' can be passed in to reference the remote hostname being referred to in
that step. This can be used to trigger, for example, an rsync operation.
Loops
+++++
Generally, Ansible is not a programming language. It prefers to be more declarative, though various constructs like "with_items"
allow a particular task to be repeated for multiple items in a list. Certain modules, like yum and apt, are actually optimized
for this, and can install all packages given in those lists within a single transaction, dramatically speeding up total
time to configuration.
Modules
+++++++
Modules are the units of work that Ansible ships out to remote machines. Modules are kicked off by either /usr/bin/ansible or
/usr/bin/ansible-playbook (where multiple tasks use lots of different modules in conjunction). Modules can be implemented in any
language, including Perl, Bash, or Ruby -- but can leverage some useful communal library code if written in Python. Modules just
have to return JSON or simple key=value pairs. Once modules are executed on remote machines, they are removed, so no long running
daemons are used. Ansible refers to the collection of available modules as a 'library'.
Notify
++++++
The act of a task registering a change event and informing a handler task that another action needs to be run at the end of the play.
If a handler is notified by multiple tasks, it will still be run only once. Handlers are run in the order they are listed, not
in the order that they are notified.
Orchestration
+++++++++++++
Many software automation systems use this word to mean different things. Ansible uses it as a conductor would conduct an orchestra.
A datacenter or cloud architecture is full of many systems, playing many parts -- web servers, database servers, maybe load balancers,
monitoring systems, continuous integration systems, etc. In performing any process, it is necessary to touch systems in particular orders,
often to simulate rolling updates or to deploy software correctly. Some system may perform some steps, then others, then previous systems
already processed may need to perform more steps. Along the way, emails may need to be sent or web services contacted. Ansible
orchestration is all about modelling that kind of process.
paramiko
++++++++
By default, Ansible manages machines over SSH. The library that Ansible uses by default to do this is a Python-powered library called
paramiko. The paramiko library is generally fast and easy to manage, though users desiring Kerberos or Jump Host support may wish to switch
to a native SSH binary such as OpenSSH by specifying the connection type in their playbook, or using the "-c ssh" flag.
Playbooks
+++++++++
Playbooks are the language by which Ansible orchestrates, configures, administers, or deploys systems. They are called playbooks partially because it's a sports analogy, and it's supposed to be fun using them. They aren't workbooks :)
Plays
+++++
A playbook is a list of plays. A play is minimally a mapping between a set of hosts selected by a host specifier (usually chosen by groups, but sometimes by hostname
globs) and the tasks which run on those hosts to define the role that those systems will perform. There
can be one or many plays in a playbook.
Pull Mode
+++++++++
By default, Ansible runs in push mode, which allows it very fine-grained control over when it talks to each system. Pull mode is
provided for when you would rather have nodes check in every N minutes on a particular schedule. It uses a program called ansible-pull and can also be set up (or reconfigured) using a push-mode playbook. Most Ansible users use push mode, but pull mode is included for variety and the sake
of having choices.
ansible-pull works by checking configuration orders out of git on a crontab and then managing the machine locally, using the local
connection plugin.
Push Mode
+++++++++
Push mode is the default mode of Ansible. In fact, it's not really a mode at all -- it's just how Ansible works when you aren't
thinking about it. Push mode allows Ansible to be fine-grained and conduct nodes through complex orchestration processes without
waiting for them to check in.
Register Variable
+++++++++++++++++
The result of running any task in Ansible can be stored in a variable for use in a template or a conditional statement.
The keyword used to define the variable is called 'register', taking its name from the idea of registers in assembly
programming (though Ansible will never feel like assembly programming). There are an infinite number of variable names
you can use for registration.
Resource Model
++++++++++++++
Ansible modules work in terms of resources. For instance, the file module will select a particular file
and ensure that the attributes of that resource match a particular model. As an example, we might wish to change the owner of /etc/motd
to 'root' if it is not already set to root, or set its mode to '0644' if it is not already set to '0644'. The resource models
are 'idempotent' meaning change commands are not run unless needed, and Ansible will bring the system back to a desired
state regardless of the actual state -- rather than you having to tell it how to get to the state.
Roles
+++++
Roles are units of organization in Ansible. Assigning a role to a group of hosts (or a set of groups, or host patterns, etc.) implies that they should implement a specific behavior. A role
may include applying certain variable values, certain tasks, and certain handlers -- or just one or more of these things. Because of the file structure associated with a role, roles become
redistributable units that allow you to share behavior among playbooks -- or even with other users.
Rolling Update
++++++++++++++
The act of addressing a number of nodes in a group N at a time to avoid updating them all at once and bringing the system
offline. For instance, in a web topology of 500 nodes handling very large volume, it may be reasonable to update 10 or 20
machines at a time, moving on to the next 10 or 20 when done. The "serial:" keyword in an Ansible playbook controls the
size of the rolling update pool. The default is to address the batch size all at once, so this is something that you must
opt-in to. OS configuration (such as making sure config files are correct) does not typically have to use the rolling update
model, but can do so if desired.
Runner
++++++
A core software component of Ansible that is the power behind /usr/bin/ansible directly -- and corresponds to the invocation
of each task in a playbook. The Runner is something Ansible developers may talk about, but it's not really userland
vocabulary.
Serial
++++++
See "Rolling Update".
Sudo
++++
Ansible does not require root logins, and since it's daemonless, definitely does not require root level daemons (which can
be a security concern in sensitive environments). Ansible can log in and perform many operations wrapped in a sudo command,
and can work with both password-less and password-based sudo. Some operations that don't normally work with sudo (like scp
file transfer) can be achieved with Ansible's copy, template, and fetch modules while running in sudo mode.
SSH (Native)
++++++++++++
Native OpenSSH as an Ansible transport is specified with "-c ssh" (or a config file, or a directive in the playbook)
and can be useful if wanting to login via Kerberized SSH or using SSH jump hosts, etc. In 1.2.1, 'ssh' will be used by default if the OpenSSH binary
on the control machine is sufficiently new. Previously, Ansible selected 'paramiko' as a default.
Using a client that supports ControlMaster and ControlPersist is recommended for maximum performance -- if you don't have that and don't need Kerberos, jump hosts, or other features, paramiko is a good choice. Ansible will warn you if it doesn't detect ControlMaster/ControlPersist capability.
Tags
++++
Ansible allows tagging resources in a playbook with arbitrary keywords, and then running only the parts of the playbook that
correspond to those keywords. For instance, it is possible to have an entire OS configuration, and have certain steps
labeled "ntp", and then run just the "ntp" steps to reconfigure the time server information on a remote host.
Tasks
+++++
Playbooks exist to run tasks. Tasks combine an action (a module and its arguments) with a name and optionally some other keywords (like looping directives). Handlers are also tasks, but they are a special kind of task that do not run unless they are notified by name when a task reports an underlying change on a remote system.
Templates
+++++++++
Ansible can easily transfer files to remote systems, but often it is desirable to substitute variables in other files. Variables
may come from the inventory file, Host Vars, Group Vars, or Facts. Templates use the Jinja2 template engine and can also include logical
constructs like loops and if statements.
Transport
+++++++++
Ansible uses "Connection Plugins" to define types of available transports. These are simply how Ansible will reach out to managed systems. Transports included are paramiko, SSH (using OpenSSH), fireball (an SSH-bootstrapped accelerated connection plugin), and local.
When
++++
An optional conditional statement attached to a task that is used to determine if the task should run or not. If the expression following the "when:" keyword evaluates to false, the task will be ignored.
Van Halen
+++++++++
For no particular reason, other than the fact that Michael really likes them, all Ansible releases are codenamed after Van Halen songs. There is no preference given to David Lee Roth vs. Sammy Lee Hagar-era songs, and instrumentals are also allowed. It is unlikely that there will ever be a Jump release, but a Van Halen III codename release is possible. You never know.
Vars (Variables)
++++++++++++++++
As opposed to Facts, variables are names of values (they can be simple scalar values -- integers, booleans, strings) or complex ones (dictionaries/hashes, lists) that can be used in templates and playbooks. They are declared things, not things that are inferred from the remote system's current state or nature (which is what Facts are).
YAML
++++
Ansible does not want to force people to write programming language code to automate infrastructure, so Ansible uses YAML to define playbook configuration languages and also variable files. YAML is nice because it has a minimum of syntax and is very clean and easy for people to skim. It is a good data format for configuration files and humans, but also machine readable. Ansible's usage of YAML stemmed from Michael's first use of it inside of Cobbler around 2006. YAML is fairly popular in the dynamic language community and the format has libraries available
for serialization in many different languages (Python, Perl, Ruby, etc.).
Playbooks are Ansible's orchestration language. At a basic level, playbooks can be used to manage configurations and deployments
of remote machines. At a more advanced level, they can sequence multi-tier rollouts involving rolling updates, and can delegate actions
to other hosts, interacting with monitoring servers and load balancers along the way. You can start small and pick up more features
over time as you need them. Playbooks are designed to be human-readable and are developed in a basic text language. There are multiple
ways to organize playbooks and the files they include, and we'll offer up some suggestions on that and making the most out of Ansible.
..toctree::
:maxdepth:1
playbooks
playbooks2
bestpractices
YAMLSyntax
Example Playbooks <https://github.com/ansible/ansible-examples>
Specific Solutions
``````````````````
A chance to dive into some more topics in depth:
..toctree::
:maxdepth:1
amazon_web_services
Developer Information
`````````````````````
Learn how to build modules of your own in any language. Explore Ansible's Python API and write Python plugins to integrate
with other solutions in your environment.
..toctree::
:maxdepth:1
api
moduledev
Miscellaneous
`````````````
`Learn and share neat Ansible tricks on Coderwall <https://coderwall.com/p/t/ansible>`_ - sign-in using GitHub or Twitter to vote on top tips and add your own!
`A list of some Ansible users and quotes about Ansible <http://www.ansibleworks.com/users>`_.
@ -7,9 +7,8 @@ Ansible works against multiple systems in your infrastructure at the
same time. It does this by selecting portions of systems listed in
Ansible's inventory file, which defaults to /etc/ansible/hosts.
..contents::`Table of contents`
..contents::
:depth:2
:backlinks:top
.._inventoryformat:
@ -33,16 +32,76 @@ The things in brackets are group names. You don't have to have them,
but they are useful.
If you have hosts that run on non-standard SSH ports you can put the port number
after the hostname with a colon.
after the hostname with a colon. Ports listed in any SSH config file won't be read,
so it is important that you set them if things are not running on the default port::
four.example.com:5309
badwolf.example.com:5309
In 0.6 and later, if you have a lot of hosts following similar patterns you can do this rather than listing each hostname::
Suppose you have just static IPs and want to set up some aliases that don't live in your host file, or you are connecting through tunnels. You can do things like this::
In the above example, trying to ansible against the host alias "jumper" (which may not even be a real hostname) will contact 192.168.1.50 on port 5555.
Adding a lot of hosts? In 0.6 and later, if you have a lot of hosts following similar patterns you can do this rather than listing each hostname::
[webservers]
www[01:50].example.com
Leading zeros can be included or removed, as desired, and the ranges are inclusive.
In 1.0 and later, you can also do this for alphabetic ranges::
[databases]
db-[a:f].example.com
For numeric patterns, leading zeros can be included or removed, as desired. Ranges are inclusive.
In 1.1 and later, you can also select the connection type and user on a per host basis::
All of these variables can of course also be set outside of the inventory file, in 'host_vars' if you wish
to keep your inventory file simple.
List of Reserved Inventory Parameters
+++++++++++++++++++++++++++++++++++++
As a summary, you can set these parameters as host inventory variables. (Some we have already
mentioned).
ansible_ssh_host
The name of the host to connect to, if different from the alias you wish to give to it.
ansible_ssh_port
The ssh port number, if not 22
ansible_ssh_user
The default ssh user name to use.
ansible_ssh_pass
The ssh password to use (this is insecure, we strongly recommend using --ask-pass or SSH keys)
ansible_connection
Connection type of the host. Candidates are local, ssh or paramiko. The default is paramiko before Ansible 1.2, and 'smart' afterwards which detects whether usage of 'ssh' would be feasible based on whether ControlPersist is supported.
ansible_ssh_private_key_file
Private key file used by ssh. Useful if using multiple keys and you don't want to use SSH agent.
ansible_syslog_facility
The syslog facility to log to.
ansible_python_interpreter
The target host python path. This is userful for systems with more
than one Python or not located at "/usr/bin/python" such as \*BSD, or where /usr/bin/python
is not a 2.X series Python.
ansible\_\*\_interpreter
Works for anything such as ruby or perl and works just like ansible_python_interpreter.
This replaces shebang of modules which will run on that host.
Below, we'll break down what the various features of the playbook language are.
@ -88,14 +90,24 @@ Support for running things from sudo is also available::
---
- hosts: webservers
user: yourname
sudo: True
sudo: yes
You can also use sudo on a particular task instead of the whole play::
---
- hosts: webservers
user: yourname
tasks:
- service: name=nginx state=started
sudo: yes
You can also login as you, and then sudo to different users than root::
---
- hosts: webservers
user: yourname
sudo: True
sudo: yes
sudo_user: postgres
If you need to specify a password to sudo, run `ansible-playbook` with ``--ask-sudo-pass`` (`-K`).
@ -128,37 +140,44 @@ The `vars` section contains a list of variables and values that can be used in t
van_halen_port: 5150
other: 'magic'
..note::
You can also keep variables in separate files and include them alongside inline `vars` with a `vars_files` declaration
in the play. See the `Advanced Playbooks chapter <http://www.ansibleworks.com/docs/playbooks2.html#variable-file-separation>`_
for more info.
These variables can be used later in the playbook like this::
$varname or ${varname}
The later is useful in the event you need to do something like ${other}_some_string.
Inside templates, the full power of the `Jinja2 <http://jinja.pocoo.org/docs/>`_ templating language is also available, which looks like this::
{{ varname }}
The Jinja2 documentation provides information about how to construct loops and conditionals for those
who which to use more advanced templating. This is optional and the $varname format still works in template
files.
Variables are passed through the Jinja2 templating engine. Any valid Jinja2
expression can be used between the curly braces, including the use of filters
to modify the variable (for example, `{{ varname|int }}` ensures the variable is
interpreted as an integer).
If there are discovered variables about the system, called 'facts', these variables bubble up back into the
playbook, and can be used on each system just like explicitly set variables. Ansible provides several
of these, prefixed with 'ansible', and are documented under 'setup' in the module documentation. Additionally,
facts can be gathered by ohai and facter if they are installed. Facter variables are prefixed with ``facter_`` and Ohai
variables are prefixed with``ohai_``.
Jinja2 expressions are very similar to Python and even if you are not working
with Python you should feel comfortable with them. See the `Jinja2 documentation
<http://jinja.pocoo.org/docs/templates/>`_ to learn more about the syntax.
Please note that Jinja2 loops and conditionals are only useful in Ansible
templates, not in playbooks. Use the 'when' and 'with' keywords for
conditionals and loops in Ansible playbooks.
So for instance, if I wanted
to write the hostname into the /etc/motd file, I could say::
If there are discovered variables about the system, called 'facts', these variables bubble up back into the playbook, and can be used on each system just like explicitly set variables. Ansible provides several
of these, prefixed with 'ansible', which are documented under 'setup' in the module documentation. Additionally,
facts can be gathered by ohai and facter if they are installed. Facter variables are prefixed with ``facter_`` and Ohai variables are prefixed with ``ohai_``. These add extra dependencies and are only there for ease of users
porting over from those other configuration systems. Finally, it's possible to drop files
on to the remote systems that provide additional sources of fact data, see "Facts.d" as documented
in the Advanced Playbooks section.
How about an example. If I wanted to write the hostname into the /etc/motd file, I could say::
To further advance the concept of include files, playbook files can
include other playbook files. Suppose you define the behavior of all
your webservers in "webservers.yml" and all your database servers in
"dbservers.yml". You can create a "site.yml" that would reconfigure
all of your systems like this::
----
- include: playbooks/webservers.yml
- include: playbooks/dbservers.yml
This concept works great with tags to rapidly select exactly what plays you want to run, and exactly
what parts of those plays.
Ignoring Failed Commands
````````````````````````
..deprecated:: 0.6
Generally playbooks will stop executing any more steps on a host that
has a failure. Sometimes, though, you want to continue on. To do so,
write a task that looks like this::
- name: this will not be counted as a failure
action: command /bin/false
ignore_errors: True
Accessing Complex Variable Data
```````````````````````````````
Some provided facts, like networking information, are made available as nested data structures. To access
them a simple '$foo' is not sufficient, but it is still easy to do. Here's how we get an IP address::
${ansible_eth0.ipv4.address}
It is also possible to access variables whose elements are arrays::
${somelist[0]}
And the array and hash reference syntaxes can be mixed.
In templates, the simple access form still holds, but they can also be accessed from Jinja2 in more Python-native ways if
that is preferred::
{{ ansible_eth0["ipv4"]["address"] }}
Accessing Information About Other Hosts
```````````````````````````````````````
If your database server wants to check the value of a 'fact' from another node, or an inventory variable
assigned to another node, it's easy to do so within a template or even an action line::
${hostvars.hostname.factname}
..note::
No database or other complex system is required to exchange data
between hosts. The hosts that you want to reference data from must
be included in either the current play or any previous play.
Additionally, *group_names* is a list (array) of all the groups the current host is in. This can be used in templates using Jinja2 syntax to make template source files that vary based on the group membership (or role) of the host::
{% if 'webserver' in group_names %}
# some part of a configuration file that only applies to webservers
{% endif %}
*groups* is a list of all the groups (and hosts) in the inventory. This can be used to enumerate all hosts within a group.
For example::
{% for host in groups['app_servers'] %}
# something that applies to all app servers.
{% endfor %}
Use cases include pointing a frontend proxy server to all of the app servers, setting up the correct firewall rules between servers, etc.
*inventory_hostname* is the name of the hostname as configured in Ansible's inventory host file. This can
be useful for when you don't want to rely on the discovered hostname `ansible_hostname` or for other mysterious
reasons. If you have a long FQDN, *inventory_hostname_short* (in Ansible 0.6) also contains the part up to the first
period.
Don't worry about any of this unless you think you need it. You'll know when you do.
Variable File Seperation
````````````````````````
It's a great idea to keep your playbooks under source control, but
you may wish to make the playbook source public while keeping certain
important variables private. Similarly, sometimes you may just
want to keep certain information in different files, away from
the main playbook.
You can do this by using an external variables file, or files, just like this::
---
- hosts: all
user: root
vars:
favcolor: blue
vars_files:
- /vars/external_vars.yml
tasks:
- name: this is just a placeholder
action: command /bin/echo foo
This removes the risk of sharing sensitive data with others when
sharing your playbook source with them.
The contents of each variables file is a simple YAML dictionary, like this::
---
# in the above example, this would be vars/external_vars.yml
somevar: somevalue
password: magic
..note::
It's also possible to keep per-host and per-group variables in very
similar files, this is covered in :ref:`patterns`.
Prompting For Sensitive Data
````````````````````````````
You may wish to prompt the user for certain input, and can
do so with the similarly named 'vars_prompt' section. This has uses
beyond security, for instance, you may use the same playbook for all
software releases and would prompt for a particular release version
in a push-script::
---
- hosts: all
user: root
vars:
from: "camelot"
vars_prompt:
name: "what is your name?"
quest: "what is your quest?"
favcolor: "what is your favorite color?"
There are full examples of both of these items in the github examples/playbooks directory.
An alternative form of vars_prompt allows for hiding input from the user, and may later support
some other options, but otherwise works equivalently::
vars_prompt:
- name: "some_password"
prompt: "Enter password"
private: True
- name: "release_version"
prompt: "Product release version"
private: False
Passing Variables On The Command Line
`````````````````````````````````````
In addition to `vars_prompt` and `vars_files`, it is possible to send variables over
the ansible command line. This is particularly useful when writing a generic release playbook
where you may want to pass in the version of the application to deploy::
By default tasks in playbooks block, meaning the connections stay open
until the task is done on each node. If executing playbooks with
a small parallelism value (aka ``--forks``), you may wish that long
running operations can go faster. The easiest way to do this is
to kick them off all at once and then poll until they are done.
You will also want to use asynchronous mode on very long running
operations that might be subject to timeout.
To launch a task asynchronously, specify its maximum runtime
and how frequently you would like to poll for status. The default
poll value is 10 seconds if you do not specify a value for `poll`::
---
- hosts: all
user: root
tasks:
- name: simulate long running op (15 sec), wait for up to 45, poll every 5
action: command /bin/sleep 15
async: 45
poll: 5
..note::
There is no default for the async time limit. If you leave off the
'async' keyword, the task runs synchronously, which is Ansible's
default.
Alternatively, if you do not need to wait on the task to complete, you may
"fire and forget" by specifying a poll value of 0::
---
- hosts: all
user: root
tasks:
- name: simulate long running op, allow to run for 45, fire and forget
action: command /bin/sleep 15
async: 45
poll: 0
..note::
You shouldn't "fire and forget" with operations that require
exclusive locks, such as yum transactions, if you expect to run other
commands later in the playbook against those same resources.
..note::
Using a higher value for ``--forks`` will result in kicking off asynchronous
tasks even faster. This also increases the efficiency of polling.
Local Playbooks
```````````````
It may be useful to use a playbook locally, rather than by connecting over SSH. This can be useful
for assuring the configuration of a system by putting a playbook on a crontab. This may also be used
to run a playbook inside a OS installer, such as an Anaconda kickstart.
To run an entire playbook locally, just set the "hosts:" line to "hosts:127.0.0.1" and then run the playbook like so::
ansible-playbook playbook.yml --connection=local
Alternatively, a local connection can be used in a single playbook play, even if other plays in the playbook
use the default remote connection type::
hosts: 127.0.0.1
connection: local
Turning Off Facts
`````````````````
If you know you don't need any fact data about your hosts, and know everything about your systems centrally, you
can turn off fact gathering. This has advantages in scaling ansible in push mode with very large numbers of
systems, mainly, or if you are using Ansible on experimental platforms. In any play, just do this::
- hosts: whatever
gather_facts: False
Pull-Mode Playbooks
```````````````````
The use of playbooks in local mode (above) is made extremely powerful with the addition of `ansible-pull`.
A script for setting up ansible-pull is provided in the examples/playbooks directory of the source
checkout.
The basic idea is to use Ansible to set up a remote copy of ansible on each managed node, each set to run via
cron and update playbook source via git. This interverts the default push architecture of ansible into a pull
architecture, which has near-limitless scaling potential. The setup playbook can be tuned to change
the cron frequency, logging locations, and parameters to ansible-pull.
This is useful both for extreme scale-out as well as periodic remediation. Usage of the 'fetch' module to retrieve
logs from ansible-pull runs would be an excellent way to gather and analyze remote logs from ansible-pull.
Register Variables
``````````````````
..versionadded:: 0.7
Often in a playbook it may be useful to store the result of a given command in a variable and access
it later. Use of the command module in this way can in many ways eliminate the need to write site specific facts, for
instance, you could test for the existance of a particular program.
The 'register' keyword decides what variable to save a result in. The resulting variables can be used in templates, action lines, or only_if statements. It looks like this (in an obviously trivial example)::
# this is an example to show that handlers can be included from yaml files,
# to promote reuse between different plays or even playbooks. They work
# just like normal handlers.
- name:restart apache
action:service name=httpd state=restarted
- name:restart memcached
action:service name=memcached state=restarted
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.