Compare commits

..

51 Commits

Author SHA1 Message Date
157b783521 Merge pull request #6491 from jlaska/apt_repository_signing_fix
[apt_repository] Correct check_mode conditional logic
2014-03-14 11:23:41 -04:00
fc02883017 CHANGELOG and README updates for 1.5.3 2014-03-13 15:29:34 -05:00
2cf0dadb47 Revert "Rejoin args list into a string for run_command when using an unsafe shell"
This reverts commit 4273cb2d8e.
2014-03-13 14:51:08 -05:00
13692311e8 Fix typo in run_command when sending data that is not binary 2014-03-13 14:51:08 -05:00
824d42081c Update VERSION file for 1.5.3 release 2014-03-13 15:02:30 -04:00
c96c3c483c Rejoin args list into a string for run_command when using an unsafe shell
This allows the use of an args list with leading environment variables,
which otherwise would fail due to the way Popen works.
2014-03-13 13:53:25 -05:00
48a1c156ee [test_service] correct upstart service name and permissions
The 'service' utility was unable to find the 'ansible_test' service due to an
unexpected filename.  This patch corrects the filename and adjusts the
permissions to match other service scripts within /etc/init/.
2014-03-13 08:29:17 -04:00
f641cb1665 Correct ansible_distribution typo
Redhat != RedHat
2014-03-13 08:29:02 -04:00
3157dc5620 Use correct value of ansible_distribution in integration tests
This fixes integration tests when run on a RHEL system.  Oddly, the
ansible_distribution='RedHat' when run on RHEL.
2014-03-13 08:28:54 -04:00
f0a89d5bdf Correct test integration ec2 cleanup script 2014-03-13 07:50:11 -04:00
763235a83d Fix regression in dnsmadeeasy module caused by fetch_url change
Also:
* changed this module to use https for requests to the API
* fixed a bug in which a traceback was caused when the domain wasn't found

Fixes #6457
2014-03-13 07:50:11 -04:00
b489406507 Merge pull request #6461 from risaacson/modules_make_run_command_safer
Modules make run command safer
2014-03-13 07:50:11 -04:00
4c3781899e Fixes various typos introduced in a9017af2bb.
Fixes odd encoding problem with wait_for_service.
2014-03-12 21:57:29 -05:00
1728734d69 Fix test_fetch role 2014-03-12 18:51:11 -04:00
ac34b67bf4 Still more shell fixes. 2014-03-12 18:04:18 -04:00
053a5fb46f Fixup shell handling in monit module. 2014-03-12 18:04:18 -04:00
64d69a88f7 More shell fixes 2014-03-12 18:04:18 -04:00
c78a5681fc Close parens in portinstall 2014-03-12 18:04:18 -04:00
b5ce0526bc Remove files added by cherry-pick from devel 2014-03-12 18:04:18 -04:00
e6b05da55b More shell updates
Conflicts:

	library/system/debconf
2014-03-12 18:04:18 -04:00
6738737518 Fix missing colons in cpanm 2014-03-12 18:04:18 -04:00
1be68b4821 Fix typo in portinstall 2014-03-12 18:04:18 -04:00
d2036cedcc Some more run_command updates. 2014-03-12 18:04:18 -04:00
4392246b47 Fixes for run_command shell usage in remainder of packaging modules, save portinstall. 2014-03-12 18:04:18 -04:00
626f9629e2 Various commits to enable no-shell or safe-shell usage, more to come.
Conflicts:

	library/packaging/cpanm
2014-03-12 18:04:18 -04:00
80df6e4197 Only use cwd in run_command kwargs if the directory exists 2014-03-12 16:10:00 -05:00
a401f9579d git: Execute git commands in dest directory 2014-03-12 15:41:02 -05:00
fbf36040f4 Make sure the cwd exists in run_command before trying to use it 2014-03-12 15:40:55 -05:00
5c568bb00c Work around for cwd stat problems with run_command and sudo
This fixes issue #6443
2014-03-12 15:40:42 -05:00
baeabd9180 Compile ca certs into a temp file to reduce number of attempts
For those who may have a large number of certs found, this can reduce
the number of ssl connections attempted.
2014-03-12 16:11:15 -04:00
a28ff5f830 Remove validate_certs parameter from fetch_url calls 2014-03-12 16:11:04 -04:00
cb40013d15 Adding validate_certs to all modules that use fetch_url 2014-03-12 16:10:56 -04:00
f4a20feb4d Remove unused code from get_ca_certs() function 2014-03-12 16:10:48 -04:00
02b2e532db Rewriting ssl validation to try multiple certs found in paths
Previously, the function checked only for a single CA root cert, however
some distributions may have multiple certs in a directory. This will now
try any .crt or .pem file contained within several common paths for
each platform.

Fixes #6412
2014-03-12 16:10:39 -04:00
eef4096e8f Use same implementation as ssh.py for "is in host file" checks in module code, prevents git module from adding keys more than once. 2014-03-12 16:04:38 -04:00
453bedcf87 Don't process shell commands as arrays. 2014-03-12 16:03:59 -04:00
dbfcf0325e Expand environment variables and tildes passed to commands generically across the board. 2014-03-12 16:03:48 -04:00
72c7841c57 add module param to Network & sub-classes
add module param to Network and sub-classes of Network, so that ansible 1.5.1 changes to LinuxNetwork apply to all Network classes.
2014-03-12 16:03:12 -04:00
42ca3d8076 Check for hash availability during vault operations 2014-03-12 16:01:25 -04:00
b0771f3cd2 Wrap crypto.hash imports with try/except 2014-03-12 16:01:12 -04:00
521e135cb3 Fixed references to missing method in ec2 modules
Change-Id: I9b89d433b545269d111b3c290b6411aabf58dd24
2014-03-12 16:00:41 -04:00
d808604a51 Fixes #6411 Return None for ec2 api endpoints that return 404 2014-03-12 15:59:02 -04:00
e509191b76 Fix ec2_facts module by removing stray fail statement 2014-03-12 15:58:50 -04:00
de753fe99c Fix test_async by using env python 2014-03-12 15:58:04 -04:00
a9762357f9 module.run_command is intended to bypass the shell here, so can't do ">>" 2014-03-12 10:56:38 -04:00
8588ac5f60 Fix other reference to APT_ENV_VARS. 2014-03-11 10:48:52 -04:00
3bb3ce4467 Update apt module so that environment variables are set correctly since not going through shell. Very sorry folks, it will be addressed. 2014-03-11 10:48:42 -04:00
9d4589d574 version release bump for 1.5.2 2014-03-11 08:50:47 -04:00
1a470b1776 Merge branch 'release1.5.1' into release1.5.2 2014-03-11 08:43:37 -04:00
4ec3f3c1d5 Missing comma in argument spec. 2014-03-10 20:29:34 -05:00
7ad9598fe8 Missing comma in argument spec. 2014-03-10 19:39:01 -04:00
742 changed files with 56231 additions and 33682 deletions

12
.gitignore vendored
View File

@ -35,19 +35,7 @@ docsite/searchindex.js
docsite/htmlout
# deb building stuff...
debian/
deb-build
# Vim swap files
*.swp
*.swo
credentials.yml
# test output
.coverage
results.xml
coverage.xml
/test/units/cover-html
# Development
/test/develop
venv
Vagrantfile
.vagrant
ansible.egg-info/

16
.gitmodules vendored
View File

@ -1,16 +0,0 @@
[submodule "lib/ansible/modules/core"]
path = lib/ansible/modules/core
url = https://github.com/ansible/ansible-modules-core.git
branch = devel
[submodule "lib/ansible/modules/extras"]
path = lib/ansible/modules/extras
url = https://github.com/ansible/ansible-modules-extras.git
branch = devel
[submodule "v2/ansible/modules/core"]
path = v2/ansible/modules/core
url = https://github.com/ansible/ansible-modules-core.git
branch = devel
[submodule "v2/ansible/modules/extras"]
path = v2/ansible/modules/extras
url = https://github.com/ansible/ansible-modules-extras.git
branch = devel

View File

@ -1,285 +1,6 @@
Ansible Changes By Release
==========================
## 1.8.1 "You Really Got Me" - Nov 26, 2014
* Various bug fixes in postgresql and mysql modules.
* Fixed a bug related to lookup plugins used within roles not finding files based on the relative paths to the roles files/ directory.
* Fixed a bug related to vars specified in plays being templated too early, resulting in incorrect variable interpolation.
* Fixed a bug related to git submodules in bare repos.
## 1.8 "You Really Got Me" - Nov 25, 2014
Major changes:
* fact caching support, pluggable, initially supports Redis (DOCS pending)
* 'serial' size in a rolling update can be specified as a percentage
* added new Jinja2 filters, 'min' and 'max' that take lists
* new 'ansible_version' variable available contains a dictionary of version info
* For ec2 dynamic inventory, ec2.ini can has various new configuration options
* 'ansible vault view filename.yml' opens filename.yml decrypted in a pager.
* no_log parameter now surpressess data from callbacks/output as well as syslog
* ansible-galaxy install -f requirements.yml allows advanced options and installs from non-galaxy SCM sources and tarballs.
* command_warnings feature will warn about when usage of the shell/command module can be simplified to use core modules - this can be enabled in ansible.cfg
* new omit value can be used to leave off a parameter when not set, like so module_name: a=1 b={{ c | default(omit) }}, would not pass value for b (not even an empty value) if c was not set.
* developers: 'baby JSON' in module responses, originally intended for writing modules in bash, is removed as a feature to simplify logic, script module remains available for running bash scripts.
* async jobs started in "fire & forget" mode can now be checked on at a later time.
* added ability to subcategorize modules for docs.ansible.com
* added ability for shipped modules to have aliases with symlinks
* added ability to deprecate older modules by starting with "_" and including "deprecated: message why" in module docs
New Modules:
* cloud: rax_cdb - manages Rackspace Cloud Database instances
* cloud: rax_cdb_database - manages Rackspace Cloud Databases
* cloud: rax_cdb_user - manages Rackspace Cloud Database users
* monitoring: zabbix_maintaince - handles outage windows with Zabbix
* monitoring: bigpanda - support for bigpanda
* net_infrastructure: a10_server - manages server objects on A10 devices
* net_infrastructure: a10_service_group - manages service group objects on A10 devices
* net_infrastructure: a10_virtual_server - manages virtual server objects on A10 devices
* system: getent - read getent databases
Some other notable changes:
* added the ability to set "instance filters" in the ec2.ini to limit results from the inventory plugin.
* upgrades for various variable precedence items and parsing related items
* added a new "follow" parameter to the file and copy modules, which allows actions to be taken on the target of a symlink rather than the symlink itself.
* if a module should ever traceback, it will return a standard error, catchable by ignore_errors, versus an 'unreachable'
* ec2_lc: added support for multiple new parameters like kernel_id, ramdisk_id and ebs_optimized.
* ec2_elb_lb: added support for the connection_draining_timeout and cross_az_load_balancing options.
* support for symbolic representations (ie. u+rw) for file permission modes (file/copy/template modules etc.).
* docker: Added support for specifying the net type of the container.
* docker: support for specifying read-only volumes.
* docker: support for specifying the API version to use for the remote connection.
* openstack modules: various improvements
* irc: ssl support for the notification module
* npm: fix flags passed to package installation
* windows: improved error handling
* setup: additional facts on System Z
* apt_repository: certificate validation can be disabled if requested
* pagerduty module: misc improvements
* ec2_lc: public_ip boolean configurable in launch configurations
* ec2_asg: fixes related to proper termination of an autoscaling group
* win_setup: total memory fact correction
* ec2_vol: ability to list existing volumes
* ec2: can set optimized flag
* various parser improvements
* produce a friendly error message if the SSH key is too permissive
* ec2_ami_search: support for SSD and IOPS provisioned EBS images
* can set ansible_sudo_exe as an inventory variable which allows specifying
a different sudo (or equivalent) command
* git module: Submodule handling has changed. Previously if you used the
``recursive`` parameter to handle submodules, ansible would track the
submodule upstream's head revision. This has been changed to checkout the
version of the submodule specified in the superproject's git repository.
This is inline with what git submodule update does. If you want the old
behaviour use the new module parameter track_submodules=yes
* Checksumming of transferred files has been made more portable and now uses
the sha1 algorithm instead of md5 to be compatible with FIPS-140.
- As a small side effect, the fetch module no longer returns a useful value
in remote_md5. If you need a replacement, switch to using remote_checksum
which returns the sha1sum of the remote file.
* ansible-doc CLI tool contains various improvements for working with different terminals
And various other bug fixes and improvements ...
## 1.7.2 "Summer Nights" - Sep 24, 2014
- Fixes a bug in accelerate mode which caused a traceback when trying to use that connection method.
- Fixes a bug in vault where the password file option was not being used correctly internally.
- Improved multi-line parsing when using YAML literal blocks (using > or |).
- Fixed a bug with the file module and the creation of relative symlinks.
- Fixed a bug where checkmode was not being honored during the templating of files.
- Other various bug fixes.
## 1.7.1 "Summer Nights" - Aug 14, 2014
- Security fix to disallow specifying 'args:' as a string, which could allow the insertion of extra module parameters through variables.
- Performance enhancements related to previous security fixes, which could cause slowness when modules returned very large JSON results. This specifically impacted the unarchive module frequently, which returns the details of all unarchived files in the result.
- Docker module bug fixes:
* Fixed support for specifying rw/ro bind modes for volumes
* Fixed support for allowing the tag in the image parameter
- Various other bug fixes
## 1.7 "Summer Nights" - Aug 06, 2014
Major new features:
* Windows support (alpha) using native PowerShell remoting
* Tasks can now specify `run_once: true`, meaning they will be executed exactly once. This can be combined with delegate_to to trigger actions you want done just the one time versus for every host in inventory.
New inventory scripts:
* SoftLayer
* Windows Azure
New Modules:
* cloud: azure
* cloud: rax_meta
* cloud: rax_scaling_group
* cloud: rax_scaling_policy
* windows: version of setup module
* windows: version of slurp module
* windows: win_feature
* windows: win_get_url
* windows: win_msi
* windows: win_ping
* windows: win_user
* windows: win_service
* windows: win_group
Other notable changes:
* Security fixes
- Prevent the use of lookups when using legaxy "{{ }}" syntax around variables and with_* loops.
- Remove relative paths in TAR-archived file names used by ansible-galaxy.
* Inventory speed improvements for very large inventories.
* Vault password files can now be executable, to support scripts that fetch the vault password.
## 1.6.10 "And the Cradle Will Rock" - Jul 25, 2014
- Fixes an issue with the copy module when copying a directory that fails when changing file attributes and the target file already exists
- Improved unicode handling when splitting args
## 1.6.9 "And the Cradle Will Rock" - Jul 24, 2014
- Further improvements to module parameter parsing to address additional regressions caused by security fixes
## 1.6.8 "And the Cradle Will Rock" - Jul 22, 2014
- Corrects a regression in the way shell and command parameters were being parsed
## 1.6.7 "And the Cradle Will Rock" - Jul 21, 2014
- Security fixes:
* Strip lookup calls out of inventory variables and clean unsafe data
returned from lookup plugins (CVE-2014-4966)
* Make sure vars don't insert extra parameters into module args and prevent
duplicate params from superseding previous params (CVE-2014-4967)
## 1.6.6 "And the Cradle Will Rock" - Jul 01, 2014
- Security updates to further protect against the incorrect execution of untrusted data
## 1.6.4, 1.6.5 "And the Cradle Will Rock" - Jun 25, 2014
- Security updates related to evaluation of untrusted remote inputs
## 1.6.3 "And the Cradle Will Rock" - Jun 09, 2014
- Corrects a regression where handlers were run across all hosts, not just those that triggered the handler.
- Fixed a bug in which modules did not support properly moving a file atomically when su was in use.
- Fixed two bugs related to symlinks with directories when using the file module.
- Fixed a bug related to MySQL master replication syntax.
- Corrects a regression in the order of variable merging done by the internal runner code.
- Various other minor bug fixes.
## 1.6.2 "And the Cradle Will Rock" - May 23, 2014
- If an improper locale is specified, core modules will now automatically revert to using the 'C' locale.
- Modules using the fetch_url utility will now obey proxy environment variables.
- The SSL validation step in fetch_url will likewise obey proxy settings, however only proxies using the http protocol are supported.
- Fixed multiple bugs in docker module related to version changes upstream.
- Fixed a bug in the ec2_group module where egress rules were lost when a VPC was specified.
- Fixed two bugs in the synchronize module:
* a trailing slash might be lost when calculating relative paths, resulting in an incorrect destination.
* the sync might use the inventory directory incorrectly instead of the playbook or role directory.
- Files will now only be chown'd on an atomic move if the src/dest uid/gid do not match.
## 1.6.1 "And the Cradle Will Rock" - May 7, 2014
- Fixed a bug in group_by, where systems were being grouped incorrectly.
- Fixed a bug where file descriptors may leak to a child process when using accelerate.
- Fixed a bug in apt_repository triggered when python-apt not being installed/available.
- Fixed a bug in the apache2_module module, where modules were not being disabled correctly.
## 1.6 "And the Cradle Will Rock" - May 5, 2014
Major features/changes:
* The deprecated legacy variable templating system has been finally removed. Use {{ foo }} always not $foo or ${foo}.
* Any data file can also be JSON. Use sparingly -- with great power comes great responsibility. Starting file with "{" or "[" denotes JSON.
* Added 'gathering' param for ansible.cfg to change the default gather_facts policy.
* Accelerate improvements:
- multiple users can connect with different keys, when `accelerate_multi_key = yes` is specified in the ansible.cfg.
- daemon lifetime is now based on the time from the last activity, not the time from the daemon's launch.
* ansible-playbook now accepts --force-handlers to run handlers even if tasks result in failures.
* Added VMWare support with the vsphere_guest module.
New Modules:
* files: replace
* packaging: cpanm (Perl)
* packaging: portage
* packaging: composer (PHP)
* packaging: homebrew_tap (OS X)
* packaging: homebrew_cask (OS X)
* packaging: apt_rpm
* packaging: layman
* monitoring: logentries
* monitoring: rollbar_deployment
* monitoring: librato_annotation
* notification: nexmo (SMS)
* notification: twilio (SMS)
* notification: slack (Slack.com)
* notification: typetalk (Typetalk.in)
* notification: sns (Amazon)
* system: debconf
* system: ufw
* system: locale_gen
* system: alternatives
* system: capabilities
* net_infrastructure: bigip_facts
* net_infrastructure: dnssimple
* net_infrastructure: lldp
* web_infrastructure: apache2_module
* cloud: digital_ocean_domain
* cloud: digital_ocean_sshkey
* cloud: rax_identity
* cloud: rax_cbs (cloud block storage)
* cloud: rax_cbs_attachments
* cloud: ec2_asg (configure autoscaling groups)
* cloud: ec2_scaling_policy
* cloud: ec2_metric_alarm
* cloud: vsphere_guest
Other notable changes:
* example callback plugin added for hipchat
* added example inventory plugin for vcenter/vsphere
* added example inventory plugin for doing really trivial inventory from SSH config files
* libvirt module now supports destroyed and paused as states
* s3 module can specify metadata
* security token additions to ec2 modules
* setup module code moved into module_utils/, facts now accessible by other modules
* synchronize module sets relative dirs based on inventory or role path
* misc bugfixes and other parameters
* the ec2_key module now has wait/wait_timeout parameters
* added version_compare filter (see docs)
* added ability for module documentation YAML to utilize shared module snippets for common args
* apt module now accepts "deb" parameter to install local dpkg files
* regex_replace filter plugin added
* added an inventory script for Docker
* added an inventory script for Abiquo
* the get_url module now accepts url_username and url_password as parameters, so sites which require
authentication no longer need to have them embedded in the url
* ... to be filled in from changelogs ...
*
## 1.5.5 "Love Walks In" - April 18, 2014
- Security fix for vault, to ensure the umask is set to a restrictive mode before creating/editing vault files.
- Backported apt_repository security fixes relating to filename/mode upon sources list file creation.
## 1.5.4 "Love Walks In" - April 1, 2014
- Security fix for safe_eval, which further hardens the checking of the evaluation function.
- Changing order of variable precendence for system facts, to ensure that inventory variables take precedence over any facts that may be set on a host.
## 1.5.3 "Love Walks In" - March 13, 2014
- Fix validate_certs and run_command errors from previous release
@ -315,7 +36,6 @@ Major features/changes:
* Start of new integration test infrastructure (WIP, more details TBD)
* if repoquery is unavailble, the yum module will automatically attempt to install yum-utils
* ansible-vault: a framework for encrypting your playbooks and variable files
* added support for privilege escalation via 'su' into bin/ansible and bin/ansible-playbook and associated keywords 'su', 'su_user', 'su_pass' for tasks/plays
New modules:
@ -333,7 +53,7 @@ New modules:
* system: at
* utilities: assert
Other notable changes (many new module params & bugfixes may not be listed):
Other notable changes (many new module params & bugfixes may not not listed):
* no_reboot is now defaulted to "no" in the ec2_ami module to ensure filesystem consistency in the resulting AMI.
* sysctl module overhauled
@ -361,6 +81,7 @@ Other notable changes (many new module params & bugfixes may not be listed):
* md5 logic improved during sudo operation
* support for ed25519 keys in authorized_key module
* ability to set directory permissions during a recursive copy (directory_mode parameter)
* update docker module, support for using docker python library 0.3.0
## 1.4.5 "Could This Be Magic" - February 12, 2014
@ -393,7 +114,7 @@ Highlighted new features:
* Added do-until feature, which can be used to retry a failed task a specified number of times with a delay in-between the retries.
* Added failed_when option for tasks, which can be used to specify logical statements that make it easier to determine when a task has failed, or to make it easier to ignore certain non-zero return codes for some commands.
* Added the "subelement" lookup plugin, which allows iteration of the keys of a dictionary or items in a list.
* Added the capability to use either paramiko or ssh for the initial setup connection of an accelerated playbook.
* Added the capability to use either paramiko or ssh for the inital setup connection of an accelerated playbook.
* Automatically provide advice on common parser errors users encounter.
* Deprecation warnings are now shown for legacy features: when_integer/etc, only_if, include+with_items, etc. Can be disabled in ansible.cfg
* The system will now provide helpful tips around possible YAML syntax errors increasing ease of use for new users.
@ -463,7 +184,7 @@ Misc changes (all module additions/fixes may not listed):
* Added a -vvvv level, which will show SSH client debugging information in the event of a failure.
* Includes now support the more standard syntax, similar to that of role includes and dependencies.
* Changed the `user:` parameter on plays to `remote_user:` to prevent confusion with the module of the same name. Still backwards compatible on play parameters.
* Added parameter to allow the fetch module to skip the md5 validation step ('validate_md5=false'). This is useful when fetching files that are actively being written to, such as live log files.
* Added parameter to allow the fetch module to skip the md5 validation step ('validate_md5=false'). This is usefull when fetching files that are actively being written to, such as live log files.
* Inventory hosts are used in the order they appear in the inventory.
* in hosts: foo[2-5] type syntax, the iterators now are zero indexed and the last index is non-inclusive, to match Python standards.
* There is now a way for a callback plugin to disable itself. See osx_say example code for an example.
@ -722,7 +443,7 @@ Modules added:
* packages: redhat_subscription: manage Red Hat subscription usage
* packages: rhn_register: basic RHN registration
* packages: zypper (SuSE)
* database: postgresql_priv: manages postgresql privileges
* database: postgresql_priv: manages postgresql priveledges
* networking: bigip_pool: load balancing with F5s
* networking: ec2_elb: add and remove machines from ec2 elastic load balancers
* notification: hipchat: send notification events to hipchat
@ -764,7 +485,7 @@ Bugfixes and Misc Changes:
* 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 consistent with Unix 'hostname'
* 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
@ -804,8 +525,8 @@ the variable is still registered for the host, with the attribute skipped: True.
* 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 unnecessarily for SSH connection type
* for authorized_key on Debian Squeeze
* 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
@ -1231,7 +952,7 @@ Module changes:
* setup module now detects interfaces with aliases
* better handling of VM guest type detection in setup module
* new module boilerplate code to check for mutually required arguments, arguments required together, exclusive args
* add pattern= as a parameter to the service module (for init scripts that don't do status, or do poor status)
* add pattern= as a paramter to the service module (for init scripts that don't do status, or do poor status)
* various fixes to mysql & postresql modules
* added a thirsty= option (boolean, default no) to the get_url module to decide to download the file every time or not
* added a wait_for module to poll for ports being open

View File

@ -66,10 +66,8 @@ Functions and Methods
* In general, functions should not be 'too long' and should describe a meaningful amount of work
* When code gets too nested, that's usually the sign the loop body could benefit from being a function
* Parts of our existing code are not the best examples of this at times.
* Functions should have names that describe what they do, along with docstrings
* Functions should be named with_underscores
* "Don't repeat yourself" is generally a good philosophy
Variables
=========
@ -78,16 +76,6 @@ Variables
* Ansible python code uses identifiers like 'ClassesLikeThis and variables_like_this
* Module parameters should also use_underscores and not runtogether
Module Security
===============
* Modules must take steps to avoid passing user input from the shell and always check return codes
* always use module.run_command instead of subprocess or Popen or os.system -- this is mandatory
* if you use need the shell you must pass use_unsafe_shell=True to module.run_command
* if you do not need the shell, avoid using the shell
* any variables that can come from the user input with use_unsafe_shell=True must be wrapped by pipes.quote(x)
* downloads of https:// resource urls must import module_utils.urls and use the fetch_url method
Misc Preferences
================
@ -120,7 +108,7 @@ Line up variables
Don't use line continuations:
# no
if (this_is_a_very_long_line and foo and \
if (this_is_a_very_long_line and foo and /
i_am_going_to_continue_it):
bar()
@ -161,19 +149,16 @@ All contributions to the core repo should preserve original licenses and new con
Module Documentation
====================
All module pull requests must include a DOCUMENTATION docstring (YAML format,
see other modules for examples) as well as an EXAMPLES docstring, which is free form.
All module pull requests must include a DOCUMENTATION docstring (YAML format, see other modules for examples) as well as an EXAMPLES docstring, which
is free form.
When adding new modules, any new parameter must have a "version_added" attribute.
When submitting a new module, the module should have a "version_added" attribute in the
pull request as well, set to the current development version.
When adding new modules, any new parameter must have a "version_added" attribute. When submitting a new module, the module should have a "version_added"
attribute in the pull request as well, set to the current development version.
Be sure to check grammar and spelling.
It's frequently the case that modules get submitted with YAML that isn't valid,
so you can run "make webdocs" from the checkout to preview your module's documentation.
If it fails to build, take a look at your DOCUMENTATION string
or you might have a Python syntax error in there too.
It's frequently the case that modules get submitted with YAML that isn't valid, so you can run "make webdocs" from the checkout to preview your module's documentation.
If it fails to build, take a look at your DOCUMENTATION string or you might have a Python syntax error in there too.
Python Imports
==============

View File

@ -1,27 +1,183 @@
Welcome To Ansible GitHub
Ansible Community Information
==============================
The purpose of the Ansible community is to unite developers, system administrators, operations, and
IT managers to share and build great automation solutions. This document contains all sorts of
information about how to contribute and interact with Ansible. Welcome!
Ways to Interact
================
There are a lot of ways to join and be a part of the Ansible community, such as:
Sharing Ansible with Others
---------------------------
You can help share Ansible with others by telling friends and colleagues, writing a blog post,
or presenting at user groups (like DevOps groups or the local LUG or BUG). You are also
welcome to share slides on speakerdeck, sign up for a free account and tag it “Ansible”. On Twitter,
you can also share things with #ansible and may wish
to follow [@Ansible](https://twitter.com/ansible).
Sharing Content and Tips
------------------------
Join the [Ansible project mailing list](https://groups.google.com/forum/#!forum/ansible-project) and you
can share playbooks you may have written and other interesting implementation stories. Put your Ansible
content up on places like github to share with others.
Sharing A Feature Idea
----------------------
If you have an idea for a new feature, you can open a new ticket at
[github.com/ansible/ansible](https://github.com/ansible/ansible), though in general we like to
talk about feature ideas first and bring in lots of people into the discussion. Consider stopping
by the
[Ansible project mailing list](https://groups.google.com/forum/#!forum/ansible-project) ([Subscribe](https://groups.google.com/forum/#!forum/ansible-project/join))
or #ansible on irc.freenode.net. There is an overview about more mailing lists
later in this document.
Helping with Documentation
--------------------------
Ansible documentation is a community project too! If you would like to help with the
documentation, whether correcting a typo or improving a section, or maybe even
documenting a new feature, submit a github pull request to the code that
lives in the “docsite/latest/rst” subdirectory of the project. Docs are in restructured text
format. If you aren’t comfortable with restructured text, you can also open a ticket on
github about any errors you spot or sections you would like to see added. For more information
on creating pull requests, please refer to the
[github help guide](https://help.github.com/articles/using-pull-requests).
Contributing Code (Features or Bugfixes)
----------------------------------------
The Ansible project keeps it’s source on github at
[github.com/ansible/ansible](http://github.com/ansible/ansible)
and takes contributions through
[github pull requests](https://help.github.com/articles/using-pull-requests).
It is usually a good idea to join the ansible-devel list to discuss any large features prior to submission, and this
especially helps in avoiding duplicate work or efforts where we decide, upon seeing a pull request for the first
time, that revisions are needed. (This is not usually needed for module development)
When submitting patches, be sure to run the unit tests first “make tests” and always use
“git rebase” vs “git merge” (aliasing git pull to git pull --rebase is a great idea) to
avoid merge commits in your submissions. We will require resubmission of pull requests that
contain merge commits.
We’ll then review your contributions and engage with you about questions and so on. Please be
advised we have a very large and active community, so it may take awhile to get your contributions
in! Patches should be made against the 'devel' branch.
Contributions can be for new features like modules, or to fix bugs you or others have found. If you
are interested in writing new modules to be included in the core Ansible distribution, please refer
to the [Module Developers documentation on our website](http://docs.ansible.com/developing_modules.html).
Ansible's aesthetic encourages simple, readable code and consistent, conservatively extending,
backwards-compatible improvements. Code developed for Ansible needs to support Python 2.6+,
while code in modules must run under Python 2.4 or higher. Please also use a 4-space indent
and no tabs.
Tip: To easily run from a checkout, source "./hacking/env-setup" and that's it -- no install
required. You're now live!
Reporting A Bug
---------------
Bugs should be reported to [github.com/ansible/ansible](http://github.com/ansible/ansible) after
signing up for a free github account. Before reporting a bug, please use the bug/issue search
to see if the issue has already been reported.
When filing a bug, please use the [issue template](https://raw2.github.com/ansible/ansible/devel/examples/issues/ISSUE_TEMPLATE.md) to provide all relevant information.
Do not use the issue tracker for "how do I do this" type questions. These are great candidates
for IRC or the mailing list instead where things are likely to be more of a discussion.
To be respectful of reviewers time and allow us to help everyone efficiently, please
provide minimal well-reduced and well-commented examples versus sharing your entire production
playbook. Include playbook snippets and output where possible.
Content in the GitHub bug tracker can be indented four spaces to preserve formatting.
For multiple-file content, we encourage use of gist.github.com. Online pastebin content can expire.
If you are not sure if something is a bug yet, you are welcome to ask about something on
the mailing list or IRC first. As we are a very high volume project, if you determine that
you do have a bug, please be sure to open the issue yourself to ensure we have a record of
it. Don’t rely on someone else in the community to file the bug report for you.
Online Resources
================
Documentation
-------------
The main ansible documentation can be found at [docs.ansible.com](http://docs.ansible.com).
As mentioned above this is an open source project, so we accept contributions to the documentation.
You can also find some best practices examples that we recommend reading at
[ansible-examples](http://github.com/ansible/ansible-examples).
Mailing lists
-------------
Ansible has several mailing lists. Your first post to the mailing list will be
moderated (to reduce spam), so please allow a day or less for your first post.
[ansible-announce](https://groups.google.com/forum/#!forum/ansible-announce) is for release
announcements and major news. It is a low traffic read-only list and you should only get a few
emails a month.
[ansible-project](https://groups.google.com/forum/#!forum/ansible-project) is the main list, and is
used for sharing cool projects you may have built, talking about Ansible ideas, and for users to ask
questions or to help other users.
[ansible-devel](https://groups.google.com/forum/#!forum/ansible-devel) is a technical list for
developers working on Ansible and Ansible modules. Join here to discuss how to build modules,
prospective feature implementations, or technical challenges.
To subscribe to a group from a non-google account, you can email the subscription address, for
example ansible-devel+subscribe@googlegroups.com.
IRC
---
Ansible has a general purpose IRC channel available at #ansible on irc.freenode.net.
Use this channel for all types of conversations, including sharing tips, coordinating
development work, or getting help from other users.
Miscellaneous Information
=========================
Hi! Nice to see you here!
Staff
-----
If you'd like to ask a question
===============================
Ansible, Inc is a company supporting Ansible and building additional solutions based on
Ansible. We also do services and support for those that are interested. Our most
important task however is enabling all the great things that happen in the Ansible
community, including organizing software releases of Ansible. For more information about
any of these things, contact info@ansible.com
Please see [this web page ](http://docs.ansible.com/community.html) for community information, which includes pointers on how to ask questions on the [mailing lists](http://docs.ansible.com/community.html#mailing-list-information) and IRC.
On IRC, you can find us as mdehaan, jimi_c, Tybstar, and others. On the mailing list,
we post with an @ansible.com address.
The github issue tracker is not the best place for questions for various reasons, but both IRC and the mailing list are very helpful places for those things, and that page has the pointers to those.
Community Code of Conduct
-------------------------
If you'd like to contribute code
================================
Ansible’s community welcomes users of all types, backgrounds, and skill levels. Please
treat others as you expect to be treated, keep discussions positive, and avoid discrimination
or engaging in controversial debates (except vi vs emacs is cool). Posts to mailing lists
should remain focused around Ansible and IT automation. Abuse of these community guidelines
will not be tolerated and may result in banning from community resources.
Please see [this web page](http://docs.ansible.com/community.html) for information about the contribution process. Important license agreement information is also included on that page.
Contributors License Agreement
------------------------------
By contributing you agree that these contributions are your own (or approved by your employer)
and you grant a full, complete, irrevocable
copyright license to all users and developers of the project, present and future, pursuant
to the license of the project.
If you'd like to file a bug
===========================
I'd also read the community page above, but in particular, make sure you copy [this issue template](https://github.com/ansible/ansible/blob/devel/ISSUE_TEMPLATE.md) into your ticket description. We have a friendly neighborhood bot that will remind you if you forget :) This template helps us organize tickets faster and prevents asking some repeated questions, so it's very helpful to us and we appreciate your help with it.
Also please make sure you are testing on the latest released version of Ansible or the development branch.
Thanks!

View File

@ -1,28 +0,0 @@
##### Issue Type:
Can you help us out in labelling this by telling us what kind of ticket this this? You can say “Bug Report”, “Feature Idea”, “Feature Pull Request”, “New Module Pull Request”, “Bugfix Pull Request”, “Documentation Report”, or “Docs Pull Request”.
##### Ansible Version:
Let us know what version of Ansible you are using. Please supply the verbatim output from running “ansible --version”. If you're filing a ticket on a version of Ansible which is not the latest, we'd greatly appreciate it if you could retest on the latest version first. We don't expect you to test against the development branch most of the time, but we may ask for that if you have cycles. Thanks!
##### Environment:
What OS are you running Ansible from and what OS are you managing? Examples include RHEL 5/6, Centos 5/6, Ubuntu 12.04/13.10, *BSD, Solaris. If this is a generic feature request or it doesn’t apply, just say “N/A”. Not all tickets may be about operating system related things and we understand that.
##### Summary:
Please summarize your request in this space. You will earn bonus points for being succinct, but please add enough detail so we can understand the request. Thanks!
##### Steps To Reproduce:
If this is a bug ticket, please enter the steps you use to reproduce the problem in the space below. If this is a feature request, please enter the steps you would use to use the feature. If an example playbook is useful, please include a short reproducer inline, indented by four spaces. If a longer one is necessary, linking to one uploaded to gist.github.com would be great. Much appreciated!
##### Expected Results:
Please enter your expected results in this space. When running the steps supplied above in the previous section, what did you expect to happen? If showing example output, please indent your output by four spaces so it will render correctly in GitHub's viewer thingy.
##### Actual Results:
Please enter your actual results in this space. When running the steps supplied above, what actually happened? If you are showing example output, please indent your output by four spaces so it will render correctly in GitHub. Thanks again!

View File

@ -1,9 +1,8 @@
include README.md packaging/rpm/ansible.spec COPYING
include examples/hosts
include examples/ansible.cfg
include lib/ansible/module_utils/powershell.ps1
recursive-include lib/ansible/modules *
graft examples/playbooks
include packaging/distutils/setup.py
recursive-include docs *
recursive-include library *
include Makefile
include VERSION
include MANIFEST.in

106
Makefile
View File

@ -5,9 +5,7 @@
#
# useful targets:
# make sdist ---------------- produce a tarball
# make srpm ----------------- produce a SRPM
# make rpm ----------------- produce RPMs
# make deb-src -------------- produce a DEB source
# make deb ------------------ produce a DEB
# make docs ----------------- rebuild the manpages (results are checked in)
# make tests ---------------- run the tests
@ -16,13 +14,13 @@
########################################################
# variable section
NAME = ansible
NAME = "ansible"
OS = $(shell uname -s)
# Manpages are currently built with asciidoc -- would like to move to markdown
# This doesn't evaluate until it's called. The -D argument is the
# directory of the target file ($@), kinda like `dirname`.
MANPAGES := docs/man/man1/ansible.1 docs/man/man1/ansible-playbook.1 docs/man/man1/ansible-pull.1 docs/man/man1/ansible-doc.1 docs/man/man1/ansible-galaxy.1 docs/man/man1/ansible-vault.1
MANPAGES := docs/man/man1/ansible.1 docs/man/man1/ansible-playbook.1 docs/man/man1/ansible-pull.1 docs/man/man1/ansible-doc.1
ifneq ($(shell which a2x 2>/dev/null),)
ASCII2MAN = a2x -D $(dir $@) -d manpage -f manpage $<
ASCII2HTMLMAN = a2x -D docs/html/man/ -d manpage -f xhtml
@ -47,59 +45,24 @@ else
DATE := $(shell date --utc --date="$(GIT_DATE)" +%Y%m%d%H%M)
endif
# DEB build parameters
DEBUILD_BIN ?= debuild
DEBUILD_OPTS = --source-option="-I"
DPUT_BIN ?= dput
DPUT_OPTS ?=
ifeq ($(OFFICIAL),yes)
DEB_RELEASE = 1ppa
# Sign OFFICIAL builds using 'DEBSIGN_KEYID'
# DEBSIGN_KEYID is required when signing
ifneq ($(DEBSIGN_KEYID),)
DEBUILD_OPTS += -k$(DEBSIGN_KEYID)
endif
else
DEB_RELEASE = 0.git$(DATE)
# Do not sign unofficial builds
DEBUILD_OPTS += -uc -us
DPUT_OPTS += -u
endif
DEBUILD = $(DEBUILD_BIN) $(DEBUILD_OPTS)
DEB_PPA ?= ppa
# Choose the desired Ubuntu release: lucid precise saucy trusty
DEB_DIST ?= unstable
# RPM build parameters
RPMSPECDIR= packaging/rpm
RPMSPEC = $(RPMSPECDIR)/ansible.spec
RPMDIST = $(shell rpm --eval '%{?dist}')
RPMRELEASE = 1
ifneq ($(OFFICIAL),yes)
ifeq ($(OFFICIAL),)
RPMRELEASE = 0.git$(DATE)
endif
RPMNVR = "$(NAME)-$(VERSION)-$(RPMRELEASE)$(RPMDIST)"
# MOCK build parameters
MOCK_BIN ?= mock
MOCK_CFG ?=
NOSETESTS ?= nosetests
NOSETESTS3 ?= nosetests-3.3
########################################################
all: clean python
tests:
PYTHONPATH=./lib $(NOSETESTS) -d -w test/units -v # Could do: --with-coverage --cover-package=ansible
newtests:
PYTHONPATH=./v2:./lib $(NOSETESTS) -d -w v2/test -v --with-coverage --cover-package=ansible --cover-branches
newtests-py3:
PYTHONPATH=./v2:./lib $(NOSETESTS3) -d -w v2/test -v --with-coverage --cover-package=ansible --cover-branches
PYTHONPATH=./lib ANSIBLE_LIBRARY=./library $(NOSETESTS) -d -w test/units -v
authors:
sh hacking/authors.sh
@ -122,7 +85,7 @@ pep8:
@echo "# Running PEP8 Compliance Tests"
@echo "#############################################"
-pep8 -r --ignore=E501,E221,W291,W391,E302,E251,E203,W293,E231,E303,E201,E225,E261,E241 lib/ bin/
# -pep8 -r --ignore=E501,E221,W291,W391,E302,E251,E203,W293,E231,E303,E201,E225,E261,E241 --filename "*" library/
-pep8 -r --ignore=E501,E221,W291,W391,E302,E251,E203,W293,E231,E303,E201,E225,E261,E241 --filename "*" library/
pyflakes:
pyflakes lib/ansible/*.py lib/ansible/*/*.py bin/*
@ -159,27 +122,13 @@ install:
$(PYTHON) setup.py install
sdist: clean docs
$(PYTHON) setup.py sdist
$(PYTHON) setup.py sdist -t MANIFEST.in
rpmcommon: $(MANPAGES) sdist
@mkdir -p rpm-build
@cp dist/*.gz rpm-build/
@sed -e 's#^Version:.*#Version: $(VERSION)#' -e 's#^Release:.*#Release: $(RPMRELEASE)%{?dist}#' $(RPMSPEC) >rpm-build/$(NAME).spec
mock-srpm: /etc/mock/$(MOCK_CFG).cfg rpmcommon
$(MOCK_BIN) -r $(MOCK_CFG) --resultdir rpm-build/ --buildsrpm --spec rpm-build/$(NAME).spec --sources rpm-build/
@echo "#############################################"
@echo "Ansible SRPM is built:"
@echo rpm-build/*.src.rpm
@echo "#############################################"
mock-rpm: /etc/mock/$(MOCK_CFG).cfg mock-srpm
$(MOCK_BIN) -r $(MOCK_CFG) --resultdir rpm-build/ --rebuild rpm-build/$(NAME)-*.src.rpm
@echo "#############################################"
@echo "Ansible RPM is built:"
@echo rpm-build/*.noarch.rpm
@echo "#############################################"
srpm: rpmcommon
@rpmbuild --define "_topdir %(pwd)/rpm-build" \
--define "_builddir %{_topdir}" \
@ -211,48 +160,15 @@ rpm: rpmcommon
@echo "#############################################"
debian: sdist
@for DIST in $(DEB_DIST) ; do \
mkdir -p deb-build/$${DIST} ; \
tar -C deb-build/$${DIST} -xvf dist/$(NAME)-$(VERSION).tar.gz ; \
cp -a packaging/debian deb-build/$${DIST}/$(NAME)-$(VERSION)/ ; \
sed -ie "s#^$(NAME) (\([^)]*\)) \([^;]*\);#ansible (\1-$(DEB_RELEASE)~$${DIST}) $${DIST};#" deb-build/$${DIST}/$(NAME)-$(VERSION)/debian/changelog ; \
done
deb: debian
@for DIST in $(DEB_DIST) ; do \
(cd deb-build/$${DIST}/$(NAME)-$(VERSION)/ && $(DEBUILD) -b) ; \
done
@echo "#############################################"
@echo "Ansible DEB artifacts:"
@for DIST in $(DEB_DIST) ; do \
echo deb-build/$${DIST}/$(NAME)_$(VERSION)-$(DEB_RELEASE)~$${DIST}_amd64.changes ; \
done
@echo "#############################################"
deb-src: debian
@for DIST in $(DEB_DIST) ; do \
(cd deb-build/$${DIST}/$(NAME)-$(VERSION)/ && $(DEBUILD) -S) ; \
done
@echo "#############################################"
@echo "Ansible DEB artifacts:"
@for DIST in $(DEB_DIST) ; do \
echo deb-build/$${DIST}/$(NAME)_$(VERSION)-$(DEB_RELEASE)~$${DIST}_source.changes ; \
done
@echo "#############################################"
deb-upload: deb
@for DIST in $(DEB_DIST) ; do \
$(DPUT_BIN) $(DPUT_OPTS) $(DEB_PPA) deb-build/$${DIST}/$(NAME)_$(VERSION)-$(DEB_RELEASE)~$${DIST}_amd64.changes ; \
done
deb-src-upload: deb-src
@for DIST in $(DEB_DIST) ; do \
$(DPUT_BIN) $(DPUT_OPTS) $(DEB_PPA) deb-build/$${DIST}/$(NAME)_$(VERSION)-$(DEB_RELEASE)~$${DIST}_source.changes ; \
done
cp -r packaging/debian ./
chmod 755 debian/rules
fakeroot debian/rules clean
fakeroot dh_install
fakeroot debian/rules binary
# for arch or gentoo, read instructions in the appropriate 'packaging' subdirectory directory
webdocs: $(MANPAGES)
(cd docsite/; make docs)
docs: $(MANPAGES)

View File

@ -1,28 +1,24 @@
[![PyPI version](https://badge.fury.io/py/ansible.png)](http://badge.fury.io/py/ansible) [![PyPI downloads](https://pypip.in/d/ansible/badge.png)](https://pypi.python.org/pypi/ansible)
[![PyPI version](https://badge.fury.io/py/ansible.png)](http://badge.fury.io/py/ansible)
Ansible
=======
Ansible is a radically simple IT automation system. It handles configuration-management, application deployment, cloud provisioning, ad-hoc task-execution, and multinode orchestration - including trivializing things like zero downtime rolling updates with load balancers.
Ansible is a radically simple configuration-management, application deployment, task-execution, and multinode orchestration engine.
Read the documentation and more at http://ansible.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 [here](http://docs.ansible.com/intro_getting_started.html) for a variety of platforms. If you decide to go with the development branch, be sure to run "git submodule update --init --recursive" after doing a checkout.
If you want to download a tarball of a release, go to [releases.ansible.com](http://releases.ansible.com/ansible), though most users use yum (using the EPEL instructions linked above), apt (using the PPA instructions linked above), or "pip install ansible".
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 [here](http://docs.ansible.com/intro_getting_started.html) for a variety of platforms. If you want a tarball of the last release, go to [releases.ansible.com](http://releases.ansible.com/ansible) and you can also install with pip.
Design Principles
=================
* Have a dead simple setup process and a minimal learning curve
* Manage machines very quickly and in parallel
* Avoid custom-agents and additional open ports, be agentless by leveraging the existing SSH daemon
* Describe infrastructure in a language that is both machine and human friendly
* Be super fast & parallel by default
* Require no server or client daemons; use existing SSHd
* Use a language that is both machine and human friendly
* Focus on security and easy auditability/review/rewriting of content
* Manage new remote machines instantly, without bootstrapping any software
* Manage remote machines instantly, without bootstrapping
* Allow module development in any dynamic language, not just Python
* Be usable as non-root
* Be the easiest IT automation system to use, ever.
@ -30,11 +26,8 @@ Design Principles
Get Involved
============
* Read [Community Information](http://docs.ansible.com/community.html) for all kinds of ways to contribute to and interact with the project, including mailing list information and how to submit bug reports and code to Ansible.
* Read [Contributing.md](https://github.com/ansible/ansible/blob/devel/CONTRIBUTING.md) for all kinds of ways to contribute to and interact with the project, including mailing list information and how to submit bug reports and code to Ansible.
* All code submissions are done through pull requests. Take care to make sure no merge commits are in the submission, and use "git rebase" vs "git merge" for this reason. If submitting a large code change (other than modules), it's probably a good idea to join ansible-devel and talk about what you would like to do or add first and to avoid duplicate efforts. This not only helps everyone know what's going on, it also helps save time and effort if we decide some changes are needed.
* Users list: [ansible-project](http://groups.google.com/group/ansible-project)
* Development list: [ansible-devel](http://groups.google.com/group/ansible-devel)
* Announcement list: [ansible-announce](http://groups.google.com/group/ansible-announce) - read only
* irc.freenode.net: #ansible
Branch Info
@ -42,15 +35,13 @@ Branch Info
* Releases are named after Van Halen songs.
* The devel branch corresponds to the release actively under development.
* As of 1.8, modules are kept in different repos, you'll want to follow [core](https://github.com/ansible/ansible-modules-core) and [extras](https://github.com/ansible/ansible-modules-extras)
* Various release-X.Y branches exist for previous releases.
* We'd love to have your contributions, read [Community Information](http://docs.ansible.com/community.html) for notes on how to get started.
* Various release-X.Y branches exist for previous releases
* We'd love to have your contributions, read "CONTRIBUTING.md" for process notes.
Authors
=======
Author
======
Ansible was created by [Michael DeHaan](https://github.com/mpdehaan) (michael@ansible.com) and has contributions from over
900 users (and growing). Thanks everyone!
Michael DeHaan -- michael@ansible.com
Ansible is sponsored by [Ansible, Inc](http://ansible.com)
[Ansible, Inc](http://ansible.com)

View File

@ -1,32 +1,7 @@
Ansible Releases at a Glance
============================
Active Development
++++++++++++++++++
1.9 "Dancing In the Streets" WINTER 2015
Released
++++++++
1.8.1 "You Really Got Me" ---- 11-26-2014
1.8 "You Really Got Me" ---- 11-25-2014
1.7.2 "Summer Nights" -------- 09-24-2014
1.7.1 "Summer Nights" -------- 08-14-2014
1.7 "Summer Nights" -------- 08-06-2014
1.6.10 "The Cradle Will Rock" - 07-25-2014
1.6.9 "The Cradle Will Rock" - 07-24-2014
1.6.8 "The Cradle Will Rock" - 07-22-2014
1.6.7 "The Cradle Will Rock" - 07-21-2014
1.6.6 "The Cradle Will Rock" - 07-01-2014
1.6.5 "The Cradle Will Rock" - 06-25-2014
1.6.4 "The Cradle Will Rock" - 06-25-2014
1.6.3 "The Cradle Will Rock" - 06-09-2014
1.6.2 "The Cradle Will Rock" - 05-23-2014
1.6.1 "The Cradle Will Rock" - 05-07-2014
1.6 "The Cradle Will Rock" - 05-05-2014
1.5.5 "Love Walks In" -------- 04-18-2014
1.5.4 "Love Walks In" -------- 04-01-2014
1.6 "The Cradle Will Rock" - NEXT
1.5.3 "Love Walks In" -------- 03-13-2014
1.5.2 "Love Walks In" -------- 03-11-2014
1.5.1 "Love Walks In" -------- 03-10-2014

View File

@ -1 +1 @@
1.8.1
1.5.3

View File

@ -38,8 +38,6 @@ class Cli(object):
def __init__(self):
self.stats = callbacks.AggregateStats()
self.callbacks = callbacks.CliRunnerCallbacks()
if C.DEFAULT_LOAD_CALLBACK_PLUGINS:
callbacks.load_callback_plugins()
# ----------------------------------------------
@ -90,6 +88,26 @@ class Cli(object):
pattern = args[0]
"""
inventory_manager = inventory.Inventory(options.inventory)
if options.subset:
inventory_manager.subset(options.subset)
hosts = inventory_manager.list_hosts(pattern)
if len(hosts) == 0:
callbacks.display("No hosts matched")
sys.exit(0)
if options.listhosts:
for host in hosts:
callbacks.display(' %s' % host)
sys.exit(0)
if ((options.module_name == 'command' or options.module_name == 'shell')
and not options.module_args):
callbacks.display("No argument passed to %s module" % options.module_name, color='red', stderr=True)
sys.exit(1)
"""
sshpass = None
sudopass = None
su_pass = None
@ -106,15 +124,27 @@ class Cli(object):
(sshpass, sudopass, su_pass, vault_pass) = utils.ask_passwords(ask_pass=options.ask_pass, ask_sudo_pass=options.ask_sudo_pass, ask_su_pass=options.ask_su_pass, ask_vault_pass=options.ask_vault_pass)
# read vault_pass from a file
if not options.ask_vault_pass and options.vault_password_file:
vault_pass = utils.read_vault_file(options.vault_password_file)
if options.vault_password_file:
this_path = os.path.expanduser(options.vault_password_file)
try:
f = open(this_path, "rb")
tmp_vault_pass=f.read()
f.close()
except (OSError, IOError), e:
raise errors.AnsibleError("Could not read %s: %s" % (this_path, e))
inventory_manager = inventory.Inventory(options.inventory, vault_password=vault_pass)
# get rid of newline chars
tmp_vault_pass = tmp_vault_pass.strip()
if not options.ask_vault_pass:
vault_pass = tmp_vault_pass
inventory_manager = inventory.Inventory(options.inventory)
if options.subset:
inventory_manager.subset(options.subset)
hosts = inventory_manager.list_hosts(pattern)
if len(hosts) == 0:
callbacks.display("No hosts matched", stderr=True)
callbacks.display("No hosts matched")
sys.exit(0)
if options.listhosts:
@ -130,6 +160,8 @@ class Cli(object):
if options.su_user or options.ask_su_pass:
options.su = True
elif options.sudo_user or options.ask_sudo_pass:
options.sudo = True
options.sudo_user = options.sudo_user or C.DEFAULT_SUDO_USER
options.su_user = options.su_user or C.DEFAULT_SU_USER
if options.tree:

View File

@ -33,8 +33,7 @@ import traceback
MODULEDIR = C.DEFAULT_MODULE_PATH
BLACKLIST_EXTS = ('.pyc', '.swp', '.bak', '~', '.rpm')
IGNORE_FILES = [ "COPYING", "CONTRIBUTING", "LICENSE", "README" ]
BLACKLIST_EXTS = ('.swp', '.bak', '~', '.rpm')
_ITALIC = re.compile(r"I\(([^)]+)\)")
_BOLD = re.compile(r"B\(([^)]+)\)")
@ -92,14 +91,14 @@ def get_man_text(doc):
text = []
text.append("> %s\n" % doc['module'].upper())
desc = " ".join(doc['description'])
desc = "".join(doc['description'])
text.append("%s\n" % textwrap.fill(tty_ify(desc), initial_indent=" ", subsequent_indent=" "))
if 'option_keys' in doc and len(doc['option_keys']) > 0:
text.append("Options (= is mandatory):\n")
for o in sorted(doc['option_keys']):
for o in doc['option_keys']:
opt = doc['options'][o]
if opt.get('required', False):
@ -109,19 +108,16 @@ def get_man_text(doc):
text.append("%s %s" % (opt_leadin, o))
desc = " ".join(opt['description'])
desc = "".join(opt['description'])
if 'choices' in opt:
choices = ", ".join(str(i) for i in opt['choices'])
desc = desc + " (Choices: " + choices + ")"
if 'default' in opt:
default = str(opt['default'])
desc = desc + " [Default: " + default + "]"
text.append("%s\n" % textwrap.fill(tty_ify(desc), initial_indent=opt_indent,
subsequent_indent=opt_indent))
if 'notes' in doc and len(doc['notes']) > 0:
notes = " ".join(doc['notes'])
notes = "".join(doc['notes'])
text.append("Notes:%s\n" % textwrap.fill(tty_ify(notes), initial_indent=" ",
subsequent_indent=opt_indent))
@ -146,30 +142,21 @@ def get_man_text(doc):
def get_snippet_text(doc):
text = []
desc = tty_ify(" ".join(doc['short_description']))
desc = tty_ify("".join(doc['short_description']))
text.append("- name: %s" % (desc))
text.append(" action: %s" % (doc['module']))
for o in sorted(doc['options'].keys()):
for o in doc['options']:
opt = doc['options'][o]
desc = tty_ify(" ".join(opt['description']))
if opt.get('required', False):
s = o + "="
else:
s = o
desc = tty_ify("".join(opt['description']))
s = o + "="
text.append(" %-20s # %s" % (s, desc))
text.append('')
return "\n".join(text)
def get_module_list_text(module_list):
columns = max(60, int(os.popen('stty size', 'r').read().split()[1]))
displace = max(len(x) for x in module_list)
linelimit = columns - displace - 5
text = []
deprecated = []
for module in sorted(set(module_list)):
if module in module_docs.BLACKLIST_MODULES:
@ -179,52 +166,21 @@ def get_module_list_text(module_list):
if filename is None:
continue
if filename.endswith(".ps1"):
continue
if os.path.isdir(filename):
continue
try:
doc, plainexamples = module_docs.get_docstring(filename)
desc = tty_ify(doc.get('short_description', '?')).strip()
if len(desc) > linelimit:
desc = desc[:linelimit] + '...'
if module.startswith('_'): # Handle deprecated
deprecated.append("%-*s %-*.*s" % (displace, module[1:], linelimit, len(desc), desc))
else:
text.append("%-*s %-*.*s" % (displace, module, linelimit, len(desc), desc))
desc = tty_ify(doc.get('short_description', '?'))
if len(desc) > 55:
desc = desc + '...'
text.append("%-20s %-60.60s" % (module, desc))
except:
traceback.print_exc()
sys.stderr.write("ERROR: module %s has a documentation error formatting or is missing documentation\n" % module)
if len(deprecated) > 0:
text.append("\nDEPRECATED:")
text.extend(deprecated)
pass
return "\n".join(text)
def find_modules(path, module_list):
if os.path.isdir(path):
for module in os.listdir(path):
if module.startswith('.'):
continue
elif os.path.isdir(module):
find_modules(module, module_list)
elif any(module.endswith(x) for x in BLACKLIST_EXTS):
continue
elif module.startswith('__'):
continue
elif module in IGNORE_FILES:
continue
elif module.startswith('_'):
fullpath = '/'.join([path,module])
if os.path.islink(fullpath): # avoids aliases
continue
module = os.path.splitext(module)[0] # removes the extension
module_list.append(module)
def main():
p = optparse.OptionParser(
@ -257,18 +213,23 @@ def main():
utils.plugins.module_finder.add_directory(i)
if options.list_dir:
# list modules
# list all modules
paths = utils.plugins.module_finder._get_paths()
module_list = []
for path in paths:
find_modules(path, module_list)
# os.system("ls -C %s" % (path))
if os.path.isdir(path):
for module in os.listdir(path):
if any(module.endswith(x) for x in BLACKLIST_EXTS):
continue
module_list.append(module)
pager(get_module_list_text(module_list))
sys.exit()
if len(args) == 0:
p.print_help()
def print_paths(finder):
''' Returns a string suitable for printing of the search path '''
@ -278,13 +239,14 @@ def main():
if i not in ret:
ret.append(i)
return os.pathsep.join(ret)
text = ''
for module in args:
filename = utils.plugins.module_finder.find_plugin(module)
if filename is None:
sys.stderr.write("module %s not found in %s\n" % (module, print_paths(utils.plugins.module_finder)))
sys.stderr.write("module %s not found in %s\n" % (module,
print_paths(utils.plugins.module_finder)))
continue
if any(filename.endswith(x) for x in BLACKLIST_EXTS):

View File

@ -26,7 +26,6 @@ import json
import os
import os.path
import shutil
import subprocess
import sys
import tarfile
import tempfile
@ -40,8 +39,6 @@ from jinja2 import Environment
from optparse import OptionParser
import ansible.constants as C
import ansible.utils
from ansible.errors import AnsibleError
default_meta_template = """---
galaxy_info:
@ -91,7 +88,7 @@ dependencies: []
"""
default_readme_template = """Role Name
=========
========
A brief description of the role goes here.
@ -111,7 +108,7 @@ Dependencies
A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
Example Playbook
----------------
-------------------------
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
@ -135,7 +132,6 @@ An optional section for the role authors to include contact information, or a we
#-------------------------------------------------------------------------------------
VALID_ACTIONS = ("init", "info", "install", "list", "remove")
SKIP_INFO_KEYS = ("platforms","readme_html", "related", "summary_fields", "average_aw_composite", "average_aw_score", "url" )
def get_action(args):
"""
@ -174,13 +170,10 @@ def build_option_parser(action):
parser.set_usage("usage: %prog init [options] role_name")
parser.add_option(
'-p', '--init-path', dest='init_path', default="./",
help='The path in which the skeleton role will be created. '
help='The path in which the skeleton role will be created.'
'The default is the current working directory.')
parser.add_option(
'--offline', dest='offline', default=False, action='store_true',
help="Don't query the galaxy API when creating roles")
elif action == "install":
parser.set_usage("usage: %prog install [options] [-r FILE | role_name(s)[,version] | scm+role_repo_url[,version] | tar_file(s)]")
parser.set_usage("usage: %prog install [options] [-r FILE | role_name(s)[,version] | tar_file(s)]")
parser.add_option(
'-i', '--ignore-errors', dest='ignore_errors', action='store_true', default=False,
help='Ignore errors and continue with the next specified role.')
@ -188,7 +181,7 @@ def build_option_parser(action):
'-n', '--no-deps', dest='no_deps', action='store_true', default=False,
help='Don\'t download roles listed as dependencies')
parser.add_option(
'-r', '--role-file', dest='role_file',
'-r', '--role-file', dest='role_file',
help='A file containing a list of roles to be imported')
elif action == "remove":
parser.set_usage("usage: %prog remove role1 role2 ...")
@ -199,7 +192,7 @@ def build_option_parser(action):
if action != "init":
parser.add_option(
'-p', '--roles-path', dest='roles_path', default=C.DEFAULT_ROLES_PATH,
help='The path to the directory containing your roles. '
help='The path to the directory containing your roles.'
'The default is the roles_path configured in your '
'ansible.cfg file (/etc/ansible/roles if not configured)')
@ -235,10 +228,9 @@ def exit_without_ignore(options, rc=1):
"""
if not get_opt(options, "ignore_errors", False):
print '- you can use --ignore-errors to skip failed roles.'
print 'You can use --ignore-errors to skip failed roles.'
sys.exit(rc)
#-------------------------------------------------------------------------------------
# Galaxy API functions
#-------------------------------------------------------------------------------------
@ -259,7 +251,7 @@ def api_get_config(api_server):
except:
return None
def api_lookup_role_by_name(api_server, role_name, notify=True):
def api_lookup_role_by_name(api_server, role_name):
"""
Uses the Galaxy API to do a lookup on the role owner/name.
"""
@ -270,11 +262,10 @@ def api_lookup_role_by_name(api_server, role_name, notify=True):
parts = role_name.split(".")
user_name = ".".join(parts[0:-1])
role_name = parts[-1]
if notify:
print "- downloading role '%s', owned by %s" % (role_name, user_name)
print " downloading role '%s', owned by %s" % (role_name, user_name)
except:
parser.print_help()
print "- invalid role name (%s). Specify role as format: username.rolename" % role_name
print "Invalid role name (%s). You must specify username.rolename" % role_name
sys.exit(1)
url = 'https://%s/api/v1/roles/?owner__username=%s&name=%s' % (api_server,user_name,role_name)
@ -332,59 +323,9 @@ def api_get_list(api_server, what):
done = (data.get('next', None) == None)
return results
except:
print "- failed to download the %s list" % what
print " - failed to download the %s list" % what
return None
#-------------------------------------------------------------------------------------
# scm repo utility functions
#-------------------------------------------------------------------------------------
def scm_archive_role(scm, role_url, role_version, role_name):
if scm not in ['hg', 'git']:
print "- scm %s is not currently supported" % scm
return False
tempdir = tempfile.mkdtemp()
clone_cmd = [scm, 'clone', role_url, role_name]
with open('/dev/null', 'w') as devnull:
try:
print "- executing: %s" % " ".join(clone_cmd)
popen = subprocess.Popen(clone_cmd, cwd=tempdir, stdout=devnull, stderr=devnull)
except:
raise AnsibleError("error executing: %s" % " ".join(clone_cmd))
rc = popen.wait()
if rc != 0:
print "- command %s failed" % ' '.join(clone_cmd)
print " in directory %s" % tempdir
return False
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.tar')
if scm == 'hg':
archive_cmd = ['hg', 'archive', '--prefix', "%s/" % role_name]
if role_version:
archive_cmd.extend(['-r', role_version])
archive_cmd.append(temp_file.name)
if scm == 'git':
archive_cmd = ['git', 'archive', '--prefix=%s/' % role_name, '--output=%s' % temp_file.name]
if role_version:
archive_cmd.append(role_version)
else:
archive_cmd.append('HEAD')
with open('/dev/null', 'w') as devnull:
print "- executing: %s" % " ".join(archive_cmd)
popen = subprocess.Popen(archive_cmd, cwd=os.path.join(tempdir, role_name),
stderr=devnull, stdout=devnull)
rc = popen.wait()
if rc != 0:
print "- command %s failed" % ' '.join(archive_cmd)
print " in directory %s" % tempdir
return False
shutil.rmtree(tempdir)
return temp_file.name
#-------------------------------------------------------------------------------------
# Role utility functions
#-------------------------------------------------------------------------------------
@ -475,11 +416,8 @@ def fetch_role(role_name, target, role_data, options):
"""
# first grab the file and save it to a temp location
if '://' in role_name:
archive_url = role_name
else:
archive_url = 'https://github.com/%s/%s/archive/%s.tar.gz' % (role_data["github_user"], role_data["github_repo"], target)
print "- downloading role from %s" % archive_url
archive_url = 'https://github.com/%s/%s/archive/%s.tar.gz' % (role_data["github_user"], role_data["github_repo"], target)
print " - downloading role from %s" % archive_url
try:
url_file = urllib2.urlopen(archive_url)
@ -493,84 +431,72 @@ def fetch_role(role_name, target, role_data, options):
except Exception, e:
# TODO: better urllib2 error handling for error
# messages that are more exact
print "- error: failed to download the file."
print "Error: failed to download the file."
return False
def install_role(role_name, role_version, role_filename, options):
# the file is a tar, so open it that way and extract it
# to the specified (or default) roles directory
if not tarfile.is_tarfile(role_filename):
print "- error: the file downloaded was not a tar.gz"
print "Error: the file downloaded was not a tar.gz"
return False
else:
if role_filename.endswith('.gz'):
role_tar_file = tarfile.open(role_filename, "r:gz")
else:
role_tar_file = tarfile.open(role_filename, "r")
role_tar_file = tarfile.open(role_filename, "r:gz")
# verify the role's meta file
meta_file = None
members = role_tar_file.getmembers()
# next find the metadata file
for member in members:
if "/meta/main.yml" in member.name:
meta_file = member
break
if not meta_file:
print "- error: this role does not appear to have a meta/main.yml file."
print "Error: this role does not appear to have a meta/main.yml file."
return False
else:
try:
meta_file_data = yaml.safe_load(role_tar_file.extractfile(meta_file))
except:
print "- error: this role does not appear to have a valid meta/main.yml file."
print "Error: this role does not appear to have a valid meta/main.yml file."
return False
# we strip off the top-level directory for all of the files contained within
# the tar file here, since the default is 'github_repo-target', and change it
# to the specified role's name
role_path = os.path.join(get_opt(options, 'roles_path'), role_name)
role_path = os.path.join(get_opt(options, 'roles_path', '/etc/ansible/roles'), role_name)
role_path = os.path.expanduser(role_path)
print "- extracting %s to %s" % (role_name, role_path)
print " - extracting %s to %s" % (role_name, role_path)
try:
if os.path.exists(role_path):
if not os.path.isdir(role_path):
print "- error: the specified roles path exists and is not a directory."
print "Error: the specified roles path exists and is not a directory."
return False
elif not get_opt(options, "force", False):
print "- error: the specified role %s appears to already exist. Use --force to replace it." % role_name
print "Error: the specified role %s appears to already exist. Use --force to replace it." % role_name
return False
else:
# using --force, remove the old path
if not remove_role(role_name, options):
print "- error: %s doesn't appear to contain a role." % role_path
print " please remove this directory manually if you really want to put the role here."
print "Error: %s doesn't appear to contain a role." % role_path
print "Please remove this directory manually if you really want to put the role here."
return False
else:
os.makedirs(role_path)
# now we do the actual extraction to the role_path
for member in members:
# we only extract files, and remove any relative path
# bits that might be in the file for security purposes
# and drop the leading directory, as mentioned above
# we only extract files
if member.isreg():
parts = member.name.split("/")[1:]
final_parts = []
for part in parts:
if part != '..' and '~' not in part and '$' not in part:
final_parts.append(part)
member.name = os.path.join(*final_parts)
member.name = "/".join(member.name.split("/")[1:])
role_tar_file.extract(member, role_path)
# write out the install info file for later use
write_galaxy_install_info(role_name, role_version, options)
except OSError, e:
print "- error: you do not have permission to modify files in %s" % role_path
print "Error: you do not have permission to modify files in %s" % role_path
return False
# return the parsed yaml metadata
print "- %s was installed successfully" % role_name
print "%s was installed successfully" % role_name
return meta_file_data
#-------------------------------------------------------------------------------------
@ -586,13 +512,11 @@ def execute_init(args, options, parser):
init_path = get_opt(options, 'init_path', './')
api_server = get_opt(options, "api_server", "galaxy.ansible.com")
force = get_opt(options, 'force', False)
offline = get_opt(options, 'offline', False)
if not offline:
api_config = api_get_config(api_server)
if not api_config:
print "- the API server (%s) is not responding, please try again later." % api_server
sys.exit(1)
api_config = api_get_config(api_server)
if not api_config:
print "The API server (%s) is not responding, please try again later." % api_server
sys.exit(1)
try:
role_name = args.pop(0).strip()
@ -601,17 +525,18 @@ def execute_init(args, options, parser):
role_path = os.path.join(init_path, role_name)
if os.path.exists(role_path):
if os.path.isfile(role_path):
print "- the path %s already exists, but is a file - aborting" % role_path
print "The path %s already exists, but is a file - aborting" % role_path
sys.exit(1)
elif not force:
print "- the directory %s already exists." % role_path
print " you can use --force to re-initialize this directory,\n" + \
" however it will reset any main.yml files that may have\n" + \
" been modified there already."
print "The directory %s already exists." % role_path
print ""
print "You can use --force to re-initialize this directory,\n" + \
"however it will reset any main.yml files that may have\n" + \
"been modified there already."
sys.exit(1)
except Exception, e:
parser.print_help()
print "- no role name specified for init"
print "No role name specified for init"
sys.exit(1)
ROLE_DIRS = ('defaults','files','handlers','meta','tasks','templates','vars')
@ -637,13 +562,13 @@ def execute_init(args, options, parser):
# datastructure in place, plus with all of the available
# tags/platforms included (but commented out) and the
# dependencies section
platforms = []
if not offline:
platforms = api_get_list(api_server, "platforms") or []
categories = []
if not offline:
categories = api_get_list(api_server, "categories") or []
platforms = api_get_list(api_server, "platforms")
if not platforms:
platforms = []
categories = api_get_list(api_server, "categories")
if not categories:
categories = []
# group the list of platforms from the api based
# on their names, with the release field being
# appended to a list of versions
@ -670,7 +595,7 @@ def execute_init(args, options, parser):
f = open(main_yml_path, 'w')
f.write('---\n# %s file for %s\n' % (dir,role_name))
f.close()
print "- %s was created successfully" % role_name
print "%s was created successfully" % role_name
def execute_info(args, options, parser):
"""
@ -679,56 +604,7 @@ def execute_info(args, options, parser):
from the galaxy API.
"""
if len(args) == 0:
# the user needs to specify a role
parser.print_help()
print "- you must specify a user/role name"
sys.exit(1)
api_server = get_opt(options, "api_server", "galaxy.ansible.com")
api_config = api_get_config(api_server)
roles_path = get_opt(options, "roles_path")
for role in args:
role_info = {}
install_info = get_galaxy_install_info(role, options)
if install_info:
if 'version' in install_info:
install_info['intalled_version'] = install_info['version']
del install_info['version']
role_info.update(install_info)
remote_data = api_lookup_role_by_name(api_server, role, False)
if remote_data:
role_info.update(remote_data)
metadata = get_role_metadata(role, options)
if metadata:
role_info.update(metadata)
role_spec = ansible.utils.role_spec_parse(role)
if role_spec:
role_info.update(role_spec)
if role_info:
print "- %s:" % (role)
for k in sorted(role_info.keys()):
if k in SKIP_INFO_KEYS:
continue
if isinstance(role_info[k], dict):
print "\t%s: " % (k)
for key in sorted(role_info[k].keys()):
if key in SKIP_INFO_KEYS:
continue
print "\t\t%s: %s" % (key, role_info[k][key])
else:
print "\t%s: %s" % (k, role_info[k])
else:
print "- the role %s was not found" % role
pass
def execute_install(args, options, parser):
"""
@ -739,125 +615,109 @@ def execute_install(args, options, parser):
"""
role_file = get_opt(options, "role_file", None)
api_server = get_opt(options, "api_server", "galaxy.ansible.com")
no_deps = get_opt(options, "no_deps", False)
if len(args) == 0 and role_file is None:
if len(args) == 0 and not role_file:
# the user needs to specify one of either --role-file
# or specify a single user/role name
parser.print_help()
print "- you must specify a user/role name or a roles file"
print "You must specify a user/role name or a roles file"
sys.exit()
elif len(args) == 1 and not role_file is None:
elif len(args) == 1 and role_file:
# using a role file is mutually exclusive of specifying
# the role name on the command line
parser.print_help()
print "- please specify a user/role name, or a roles file, but not both"
print "Please specify a user/role name, or a roles file, but not both"
sys.exit(1)
api_server = get_opt(options, "api_server", "galaxy.ansible.com")
no_deps = get_opt(options, "no_deps", False)
roles_path = get_opt(options, "roles_path")
api_config = api_get_config(api_server)
if not api_config:
print "The API server (%s) is not responding, please try again later." % api_server
sys.exit(1)
roles_done = []
if role_file:
# roles listed in a file, one per line
# so we'll go through and grab them all
f = open(role_file, 'r')
if role_file.endswith('.yaml') or role_file.endswith('.yml'):
roles_left = map(ansible.utils.role_yaml_parse, yaml.safe_load(f))
else:
# roles listed in a file, one per line
roles_left = map(ansible.utils.role_spec_parse, f.readlines())
roles_left = f.readlines()
f.close()
else:
# roles were specified directly, so we'll just go out grab them
# (and their dependencies, unless the user doesn't want us to).
roles_left = map(ansible.utils.role_spec_parse, args)
roles_left = args
while len(roles_left) > 0:
# query the galaxy API for the role data
role_data = None
role = roles_left.pop(0)
role_src = role.get("src")
role_scm = role.get("scm")
role_path = role.get("path")
role_name = roles_left.pop(0).strip()
role_version = None
if role_path:
options.roles_path = role_path
else:
options.roles_path = roles_path
if role_name == "" or role_name.startswith("#"):
continue
elif role_name.find(',') != -1:
role_name,role_version = role_name.split(',',1)
role_name = role_name.strip()
role_version = role_version.strip()
if os.path.isfile(role_src):
if os.path.isfile(role_name):
# installing a local tar.gz
tmp_file = role_src
else:
if role_scm:
# create tar file from scm url
tmp_file = scm_archive_role(role_scm, role_src, role.get("version"), role.get("name"))
elif '://' in role_src:
# just download a URL - version will probably be in the URL
tmp_file = fetch_role(role_src, None, None, options)
tar_file = role_name
role_name = os.path.basename(role_name).replace('.tar.gz','')
if tarfile.is_tarfile(tar_file):
print " - installing %s as %s" % (tar_file, role_name)
if not install_role(role_name, role_version, tar_file, options):
exit_without_ignore(options)
else:
# installing from galaxy
api_config = api_get_config(api_server)
if not api_config:
print "- the API server (%s) is not responding, please try again later." % api_server
sys.exit(1)
print "%s (%s) was NOT installed successfully." % (role_name,tar_file)
exit_without_ignore(options)
else:
# installing remotely
role_data = api_lookup_role_by_name(api_server, role_name)
if not role_data:
print "Sorry, %s was not found on %s." % (role_name, api_server)
continue
role_data = api_lookup_role_by_name(api_server, role_src)
if not role_data:
print "- sorry, %s was not found on %s." % (role_src, api_server)
role_versions = api_fetch_role_related(api_server, 'versions', role_data['id'])
if not role_version:
# convert the version names to LooseVersion objects
# and sort them to get the latest version. If there
# are no versions in the list, we'll grab the head
# of the master branch
if len(role_versions) > 0:
loose_versions = [LooseVersion(a.get('name',None)) for a in role_versions]
loose_versions.sort()
role_version = str(loose_versions[-1])
else:
role_version = 'master'
print " no version specified, installing %s" % role_version
else:
if role_versions and role_version not in [a.get('name',None) for a in role_versions]:
print "The specified version (%s) was not found in the list of available versions." % role_version
exit_without_ignore(options)
continue
role_versions = api_fetch_role_related(api_server, 'versions', role_data['id'])
if "version" not in role or role['version'] == '':
# convert the version names to LooseVersion objects
# and sort them to get the latest version. If there
# are no versions in the list, we'll grab the head
# of the master branch
if len(role_versions) > 0:
loose_versions = [LooseVersion(a.get('name',None)) for a in role_versions]
loose_versions.sort()
role["version"] = str(loose_versions[-1])
else:
role["version"] = 'master'
elif role['version'] != 'master':
if role_versions and role["version"] not in [a.get('name', None) for a in role_versions]:
print 'role is %s' % role
print "- the specified version (%s) was not found in the list of available versions (%s)." % (role['version'], role_versions)
exit_without_ignore(options)
continue
# download the role. if --no-deps was specified, we stop here,
# otherwise we recursively grab roles and all of their deps.
tmp_file = fetch_role(role_src, role["version"], role_data, options)
installed = False
if tmp_file:
installed = install_role(role.get("name"), role.get("version"), tmp_file, options)
# we're done with the temp file, clean it up
if tmp_file != role_src:
# download the role. if --no-deps was specified, we stop here,
# otherwise we recursively grab roles and all of their deps.
tmp_file = fetch_role(role_name, role_version, role_data, options)
if tmp_file and install_role(role_name, role_version, tmp_file, options):
# we're done with the temp file, clean it up
os.unlink(tmp_file)
# install dependencies, if we want them
if not no_deps and installed:
if not role_data:
role_data = get_role_metadata(role.get("name"), options)
role_dependencies = role_data['dependencies']
else:
# install dependencies, if we want them
if not no_deps:
role_dependencies = role_data['summary_fields']['dependencies'] # api_fetch_role_related(api_server, 'dependencies', role_data['id'])
for dep in role_dependencies:
if isinstance(dep, basestring):
dep = ansible.utils.role_spec_parse(dep)
else:
dep = ansible.utils.role_yaml_parse(dep)
if not get_role_metadata(dep["name"], options):
if dep not in roles_left:
print '- adding dependency: %s' % dep["name"]
roles_left.append(dep)
for dep_name in role_dependencies:
#dep_name = "%s.%s" % (dep['owner'], dep['name'])
if not get_role_metadata(dep_name, options):
print ' adding dependency: %s' % dep_name
roles_left.append(dep_name)
else:
print '- dependency %s already pending installation.' % dep["name"]
else:
print '- dependency %s is already installed, skipping.' % dep["name"]
if not tmp_file or not installed:
print "- %s was NOT installed successfully." % role.get("name")
exit_without_ignore(options)
print ' dependency %s is already installed, skipping.' % dep_name
else:
if tmp_file:
os.unlink(tmp_file)
print "%s was NOT installed successfully." % role_name
exit_without_ignore(options)
sys.exit(0)
def execute_remove(args, options, parser):
@ -868,17 +728,17 @@ def execute_remove(args, options, parser):
if len(args) == 0:
parser.print_help()
print '- you must specify at least one role to remove.'
print 'You must specify at least one role to remove.'
sys.exit()
for role in args:
if get_role_metadata(role, options):
if remove_role(role, options):
print '- successfully removed %s' % role
print 'successfully removed %s' % role
else:
print "- failed to remove role: %s" % role
print "failed to remove role: %s" % role
else:
print '- %s is not installed, skipping.' % role
print '%s is not installed, skipping.' % role
sys.exit(0)
def execute_list(args, options, parser):
@ -890,7 +750,7 @@ def execute_list(args, options, parser):
"""
if len(args) > 1:
print "- please specify only one role to list, or specify no roles to see a full list"
print "Please specify only one role to list, or specify no roles to see a full list"
sys.exit(1)
if len(args) == 1:
@ -905,19 +765,19 @@ def execute_list(args, options, parser):
if not version:
version = "(unknown version)"
# show some more info about single roles here
print "- %s, %s" % (role_name, version)
print " %s, %s" % (role_name, version)
else:
print "- the role %s was not found" % role_name
print "The role %s was not found" % role_name
else:
# show all valid roles in the roles_path directory
roles_path = get_opt(options, 'roles_path')
roles_path = os.path.expanduser(roles_path)
if not os.path.exists(roles_path):
parser.print_help()
print "- the path %s does not exist. Please specify a valid path with --roles-path" % roles_path
print "The path %s does not exist. Please specify a valid path with --roles-path" % roles_path
sys.exit(1)
elif not os.path.isdir(roles_path):
print "- %s exists, but it is not a directory. Please specify a valid path with --roles-path" % roles_path
print "%s exists, but it is not a directory. Please specify a valid path with --roles-path" % roles_path
parser.print_help()
sys.exit(1)
path_files = os.listdir(roles_path)
@ -929,7 +789,7 @@ def execute_list(args, options, parser):
version = install_info.get("version", None)
if not version:
version = "(unknown version)"
print "- %s, %s" % (path_file, version)
print " %s, %s" % (path_file, version)
sys.exit(0)
#-------------------------------------------------------------------------------------
@ -947,7 +807,7 @@ def main():
fn = globals()["execute_%s" % action]
fn(args, options, parser)
#except KeyError, e:
# print "- error: %s is not a valid action. Valid actions are: %s" % (action, ", ".join(VALID_ACTIONS))
# print "Error: %s is not a valid action. Valid actions are: %s" % (action, ", ".join(VALID_ACTIONS))
# sys.exit(1)
if __name__ == "__main__":

View File

@ -18,21 +18,10 @@
#######################################################
#__requires__ = ['ansible']
#import pkg_resources
import sys
import os
import stat
# Augment PYTHONPATH to find Python modules relative to this file path
# This is so that we can find the modules when running from a local checkout
# installed as editable with `pip install -e ...` or `python setup.py develop`
local_module_path = os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', 'lib')
)
sys.path.append(local_module_path)
import ansible.playbook
import ansible.constants as C
import ansible.utils.template
@ -89,10 +78,6 @@ def main(args):
help="one-step-at-a-time: confirm each task before running")
parser.add_option('--start-at-task', dest='start_at',
help="start the playbook at the task matching this name")
parser.add_option('--force-handlers', dest='force_handlers', action='store_true',
help="run handlers even if a task fails")
parser.add_option('--flush-cache', dest='flush_cache', action='store_true',
help="clear the fact cache")
options, args = parser.parse_args(args)
@ -110,35 +95,49 @@ def main(args):
if (options.ask_vault_pass and options.vault_password_file):
parser.error("--ask-vault-pass and --vault-password-file are mutually exclusive")
inventory = ansible.inventory.Inventory(options.inventory)
inventory.subset(options.subset)
if len(inventory.list_hosts()) == 0:
raise errors.AnsibleError("provided hosts list is empty")
sshpass = None
sudopass = None
su_pass = None
vault_pass = None
options.ask_vault_pass = options.ask_vault_pass or C.DEFAULT_ASK_VAULT_PASS
if options.listhosts or options.syntax or options.listtasks:
(_, _, _, vault_pass) = utils.ask_passwords(ask_vault_pass=options.ask_vault_pass)
else:
if not options.listhosts and not options.syntax and not options.listtasks:
options.ask_pass = options.ask_pass or C.DEFAULT_ASK_PASS
options.ask_vault_pass = options.ask_vault_pass or C.DEFAULT_ASK_VAULT_PASS
# Never ask for an SSH password when we run with local connection
if options.connection == "local":
options.ask_pass = False
options.ask_sudo_pass = options.ask_sudo_pass or C.DEFAULT_ASK_SUDO_PASS
options.ask_su_pass = options.ask_su_pass or C.DEFAULT_ASK_SU_PASS
options.ask_vault_pass = options.ask_vault_pass or C.DEFAULT_ASK_VAULT_PASS
(sshpass, sudopass, su_pass, vault_pass) = utils.ask_passwords(ask_pass=options.ask_pass, ask_sudo_pass=options.ask_sudo_pass, ask_su_pass=options.ask_su_pass, ask_vault_pass=options.ask_vault_pass)
options.sudo_user = options.sudo_user or C.DEFAULT_SUDO_USER
options.su_user = options.su_user or C.DEFAULT_SU_USER
# read vault_pass from a file
if not options.ask_vault_pass and options.vault_password_file:
vault_pass = utils.read_vault_file(options.vault_password_file)
if options.vault_password_file:
this_path = os.path.expanduser(options.vault_password_file)
try:
f = open(this_path, "rb")
tmp_vault_pass=f.read()
f.close()
except (OSError, IOError), e:
raise errors.AnsibleError("Could not read %s: %s" % (this_path, e))
# get rid of newline chars
tmp_vault_pass = tmp_vault_pass.strip()
if not options.ask_vault_pass:
vault_pass = tmp_vault_pass
extra_vars = {}
for extra_vars_opt in options.extra_vars:
if extra_vars_opt.startswith("@"):
# Argument is a YAML file (JSON is a subset of YAML)
extra_vars = utils.combine_vars(extra_vars, utils.parse_yaml_from_file(extra_vars_opt[1:], vault_password=vault_pass))
extra_vars = utils.combine_vars(extra_vars, utils.parse_yaml_from_file(extra_vars_opt[1:]))
elif extra_vars_opt and extra_vars_opt[0] in '[{':
# Arguments as YAML
extra_vars = utils.combine_vars(extra_vars, utils.parse_yaml(extra_vars_opt))
@ -157,14 +156,12 @@ def main(args):
if not (os.path.isfile(playbook) or stat.S_ISFIFO(os.stat(playbook).st_mode)):
raise errors.AnsibleError("the playbook: %s does not appear to be a file" % playbook)
inventory = ansible.inventory.Inventory(options.inventory, vault_password=vault_pass)
inventory.subset(options.subset)
if len(inventory.list_hosts()) == 0:
raise errors.AnsibleError("provided hosts list is empty")
# run all playbooks specified on the command line
for playbook in args:
# let inventory know which playbooks are using so it can know the basedirs
inventory.set_playbook_basedir(os.path.dirname(playbook))
stats = callbacks.AggregateStats()
playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY)
if options.step:
@ -197,14 +194,9 @@ def main(args):
su=options.su,
su_pass=su_pass,
su_user=options.su_user,
vault_password=vault_pass,
force_handlers=options.force_handlers
vault_password=vault_pass
)
if options.flush_cache:
display(callbacks.banner("FLUSHING FACT CACHE"))
pb.SETUP_CACHE.flush()
if options.listhosts or options.listtasks or options.syntax:
print ''
print 'playbook: %s' % playbook
@ -212,15 +204,14 @@ def main(args):
playnum = 0
for (play_ds, play_basedir) in zip(pb.playbook, pb.play_basedirs):
playnum += 1
play = ansible.playbook.Play(pb, play_ds, play_basedir,
vault_password=pb.vault_password)
play = ansible.playbook.Play(pb, play_ds, play_basedir)
label = play.name
hosts = pb.inventory.list_hosts(play.hosts)
# Filter all tasks by given tags
if pb.only_tags != 'all':
if options.subset and not hosts:
continue
if options.listhosts:
hosts = pb.inventory.list_hosts(play.hosts)
print ' play #%d (%s): host count=%d' % (playnum, label, len(hosts))
for host in hosts:
print ' %s' % host
if options.listtasks:
matched_tags, unmatched_tags = play.compare_tags(pb.only_tags)
# Remove skipped tasks
@ -232,13 +223,6 @@ def main(args):
if unknown_tags:
continue
if options.listhosts:
print ' play #%d (%s): host count=%d' % (playnum, label, len(hosts))
for host in hosts:
print ' %s' % host
if options.listtasks:
print ' play #%d (%s):' % (playnum, label)
for task in play.tasks():
@ -247,8 +231,7 @@ def main(args):
if getattr(task, 'name', None) is not None:
# meta tasks have no names
print ' %s' % task.name
if options.listhosts or options.listtasks:
print ''
print ''
continue
if options.syntax:
@ -328,3 +311,4 @@ if __name__ == "__main__":
except KeyboardInterrupt, ke:
display("ERROR: interrupted", color='red', stderr=True)
sys.exit(1)

View File

@ -44,12 +44,9 @@ import subprocess
import sys
import datetime
import socket
import random
import time
from ansible import utils
from ansible.utils import cmd_functions
from ansible import errors
from ansible import inventory
DEFAULT_REPO_TYPE = 'git'
DEFAULT_PLAYBOOK = 'local.yml'
@ -105,8 +102,6 @@ def main(args):
help='purge checkout after playbook run')
parser.add_option('-o', '--only-if-changed', dest='ifchanged', default=False, action='store_true',
help='only run the playbook if the repository has been updated')
parser.add_option('-s', '--sleep', dest='sleep', default=None,
help='sleep for random interval (between 0 and n number of seconds) before starting. this is a useful way to disperse git requests')
parser.add_option('-f', '--force', dest='force', default=False,
action='store_true',
help='run the playbook even if the repository could '
@ -122,8 +117,6 @@ def main(args):
'Defaults to behavior of repository module.')
parser.add_option('-i', '--inventory-file', dest='inventory',
help="location of the inventory host file")
parser.add_option('-e', '--extra-vars', dest="extra_vars", action="append",
help="set additional variables as key=value or YAML/JSON", default=[])
parser.add_option('-v', '--verbose', default=False, action="callback",
callback=increment_debug,
help='Pass -vvvv to ansible-playbook')
@ -133,10 +126,6 @@ def main(args):
'Default is %s.' % DEFAULT_REPO_TYPE)
parser.add_option('--vault-password-file', dest='vault_password_file',
help="vault password file")
parser.add_option('-K', '--ask-sudo-pass', default=False, dest='ask_sudo_pass', action='store_true',
help='ask for sudo password')
parser.add_option('-t', '--tags', dest='tags', default=False,
help='only run plays and tasks tagged with these values')
options, args = parser.parse_args(args)
hostname = socket.getfqdn()
@ -153,12 +142,7 @@ def main(args):
now = datetime.datetime.now()
print >>sys.stderr, now.strftime("Starting ansible-pull at %F %T")
# Attempt to use the inventory passed in as an argument
# It might not yet have been downloaded so use localhost if note
if not options.inventory or not os.path.exists(options.inventory):
inv_opts = 'localhost,'
else:
inv_opts = options.inventory
inv_opts = 'localhost,'
limit_opts = 'localhost:%s:127.0.0.1' % hostname
repo_opts = "name=%s dest=%s" % (options.url, options.dest)
@ -174,22 +158,11 @@ def main(args):
if path is None:
sys.stderr.write("module '%s' not found.\n" % options.module_name)
return 1
cmd = 'ansible localhost -i "%s" %s -m %s -a "%s"' % (
cmd = 'ansible all -i "%s" %s -m %s -a "%s"' % (
inv_opts, base_opts, options.module_name, repo_opts
)
if options.sleep:
try:
secs = random.randint(0,int(options.sleep));
except ValueError:
parser.error("%s is not a number." % options.sleep)
return 1
print >>sys.stderr, "Sleeping for %d seconds..." % secs
time.sleep(secs);
# RUN THe CHECKOUT COMMAND
# RUN THE CHECKOUT COMMAND
rc, out, err = cmd_functions.run_cmd(cmd, live=True)
if rc != 0:
@ -212,12 +185,6 @@ def main(args):
cmd += " --vault-password-file=%s" % options.vault_password_file
if options.inventory:
cmd += ' -i "%s"' % options.inventory
for ev in options.extra_vars:
cmd += ' -e "%s"' % ev
if options.ask_sudo_pass:
cmd += ' -K'
if options.tags:
cmd += ' -t "%s"' % options.tags
os.chdir(options.dest)
# RUN THE PLAYBOOK COMMAND

View File

@ -15,18 +15,15 @@
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
# ansible-vault is a script that encrypts/decrypts YAML files. See
# http://docs.ansible.com/playbooks_vault.html for more details.
#__requires__ = ['ansible']
#import pkg_resources
# ansible-pull is a script that runs ansible in local mode
# after checking out a playbooks directory from source repo. There is an
# example playbook to bootstrap this script in the examples/ dir which
# installs ansible and sets it up to run on cron.
import os
import sys
import traceback
import ansible.constants as C
from ansible import utils
from ansible import errors
from ansible.utils.vault import VaultEditor
@ -37,7 +34,7 @@ from optparse import OptionParser
# Utility functions for parsing actions/options
#-------------------------------------------------------------------------------------
VALID_ACTIONS = ("create", "decrypt", "edit", "encrypt", "rekey", "view")
VALID_ACTIONS = ("create", "decrypt", "edit", "encrypt", "rekey")
def build_option_parser(action):
"""
@ -58,7 +55,7 @@ def build_option_parser(action):
#parser.add_option('-c', '--cipher', dest='cipher', default="AES256", help="cipher to use")
parser.add_option('--debug', dest='debug', action="store_true", help="debug")
parser.add_option('--vault-password-file', dest='password_file',
help="vault password file", default=C.DEFAULT_VAULT_PASSWORD_FILE)
help="vault password file")
# options specific to actions
if action == "create":
@ -67,8 +64,6 @@ def build_option_parser(action):
parser.set_usage("usage: %prog decrypt [options] file_name")
elif action == "edit":
parser.set_usage("usage: %prog edit [options] file_name")
elif action == "view":
parser.set_usage("usage: %prog view [options] file_name")
elif action == "encrypt":
parser.set_usage("usage: %prog encrypt [options] file_name")
elif action == "rekey":
@ -106,14 +101,23 @@ def get_opt(options, k, defval=""):
# Command functions
#-------------------------------------------------------------------------------------
def _read_password(filename):
f = open(filename, "rb")
data = f.read()
f.close
# get rid of newline chars
data = data.strip()
return data
def execute_create(args, options, parser):
if len(args) > 1:
raise errors.AnsibleError("'create' does not accept more than one filename")
if not options.password_file:
if not options.password_file:
password, new_password = utils.ask_vault_passwords(ask_vault_pass=True, confirm_vault=True)
else:
password = utils.read_vault_file(options.password_file)
password = _read_password(options.password_file)
cipher = 'AES256'
if hasattr(options, 'cipher'):
@ -124,10 +128,10 @@ def execute_create(args, options, parser):
def execute_decrypt(args, options, parser):
if not options.password_file:
if not options.password_file:
password, new_password = utils.ask_vault_passwords(ask_vault_pass=True)
else:
password = utils.read_vault_file(options.password_file)
password = _read_password(options.password_file)
cipher = 'AES256'
if hasattr(options, 'cipher'):
@ -142,12 +146,12 @@ def execute_decrypt(args, options, parser):
def execute_edit(args, options, parser):
if len(args) > 1:
raise errors.AnsibleError("edit does not accept more than one filename")
raise errors.AnsibleError("create does not accept more than one filename")
if not options.password_file:
if not options.password_file:
password, new_password = utils.ask_vault_passwords(ask_vault_pass=True)
else:
password = utils.read_vault_file(options.password_file)
password = _read_password(options.password_file)
cipher = None
@ -155,28 +159,15 @@ def execute_edit(args, options, parser):
this_editor = VaultEditor(cipher, password, f)
this_editor.edit_file()
def execute_view(args, options, parser):
if len(args) > 1:
raise errors.AnsibleError("view does not accept more than one filename")
if not options.password_file:
password, new_password = utils.ask_vault_passwords(ask_vault_pass=True)
else:
password = utils.read_vault_file(options.password_file)
cipher = None
for f in args:
this_editor = VaultEditor(cipher, password, f)
this_editor.view_file()
def execute_encrypt(args, options, parser):
if not options.password_file:
if len(args) > 1:
raise errors.AnsibleError("'create' does not accept more than one filename")
if not options.password_file:
password, new_password = utils.ask_vault_passwords(ask_vault_pass=True, confirm_vault=True)
else:
password = utils.read_vault_file(options.password_file)
password = _read_password(options.password_file)
cipher = 'AES256'
if hasattr(options, 'cipher'):
@ -190,10 +181,10 @@ def execute_encrypt(args, options, parser):
def execute_rekey(args, options, parser):
if not options.password_file:
if not options.password_file:
password, __ = utils.ask_vault_passwords(ask_vault_pass=True)
else:
password = utils.read_vault_file(options.password_file)
password = _read_password(options.password_file)
__, new_password = utils.ask_vault_passwords(ask_vault_pass=False, ask_new_vault_pass=True, confirm_new=True)
@ -214,11 +205,6 @@ def main():
parser = build_option_parser(action)
(options, args) = parser.parse_args()
if not len(args):
raise errors.AnsibleError(
"The '%s' command requires a filename as the first argument" % action
)
# execute the desired action
try:
fn = globals()["execute_%s" % action]
@ -231,3 +217,4 @@ def main():
if __name__ == "__main__":
main()

View File

@ -2,12 +2,12 @@
.\" Title: ansible-doc
.\" Author: :doctype:manpage
.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
.\" Date: 05/26/2014
.\" Date: 03/11/2014
.\" Manual: System administration commands
.\" Source: Ansible 1.7
.\" Source: Ansible 1.5.2
.\" Language: English
.\"
.TH "ANSIBLE\-DOC" "1" "05/26/2014" "Ansible 1\&.7" "System administration commands"
.TH "ANSIBLE\-DOC" "1" "03/11/2014" "Ansible 1\&.5\&.2" "System administration commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------

View File

@ -1,180 +0,0 @@
'\" t
.\" Title: ansible-galaxy
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
.\" Date: 05/26/2014
.\" Manual: System administration commands
.\" Source: Ansible 1.7
.\" Language: English
.\"
.TH "ANSIBLE\-GALAXY" "1" "05/26/2014" "Ansible 1\&.7" "System administration commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\" http://bugs.debian.org/507673
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.\" -----------------------------------------------------------------
.\" * MAIN CONTENT STARTS HERE *
.\" -----------------------------------------------------------------
.SH "NAME"
ansible-galaxy \- manage roles using galaxy\&.ansible\&.com
.SH "SYNOPSIS"
.sp
ansible\-galaxy [init|info|install|list|remove] [\-\-help] [options] \&...
.SH "DESCRIPTION"
.sp
\fBAnsible Galaxy\fR is a shared repository for Ansible roles (added in ansible version 1\&.2)\&. The ansible\-galaxy command can be used to manage these roles, or by creating a skeleton framework for roles you\(cqd like to upload to Galaxy\&.
.SH "COMMON OPTIONS"
.PP
\fB\-h\fR, \fB\-\-help\fR
.RS 4
Show a help message related to the given sub\-command\&.
.RE
.SH "INSTALL"
.sp
The \fBinstall\fR sub\-command is used to install roles\&.
.SS "USAGE"
.sp
$ ansible\-galaxy install [options] [\-r FILE | role_name(s)[,version] | tar_file(s)]
.sp
Roles can be installed in several different ways:
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
A username\&.rolename[,version] \- this will install a single role\&. The Galaxy API will be contacted to provide the information about the role, and the corresponding \&.tar\&.gz will be downloaded from
\fBgithub\&.com\fR\&. If the version is omitted, the most recent version available will be installed\&.
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
A file name, using
\fB\-r\fR
\- this will install multiple roles listed one per line\&. The format of each line is the same as above: username\&.rolename[,version]
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
A \&.tar\&.gz of a valid role you\(cqve downloaded directly from
\fBgithub\&.com\fR\&. This is mainly useful when the system running Ansible does not have access to the Galaxy API, for instance when behind a firewall or proxy\&.
.RE
.SS "OPTIONS"
.PP
\fB\-f\fR, \fB\-\-force\fR
.RS 4
Force overwriting an existing role\&.
.RE
.PP
\fB\-i\fR, \fB\-\-ignore\-errors\fR
.RS 4
Ignore errors and continue with the next specified role\&.
.RE
.PP
\fB\-n\fR, \fB\-\-no\-deps\fR
.RS 4
Don\(cqt download roles listed as dependencies\&.
.RE
.PP
\fB\-p\fR \fIROLES_PATH\fR, \fB\-\-roles\-path=\fR\fIROLES_PATH\fR
.RS 4
The path to the directory containing your roles\&. The default is the
\fBroles_path\fR
configured in your
\fBansible\&.cfg\fR
file (/etc/ansible/roles if not configured)
.RE
.PP
\fB\-r\fR \fIROLE_FILE\fR, \fB\-\-role\-file=\fR\fIROLE_FILE\fR
.RS 4
A file containing a list of roles to be imported, as specified above\&. This option cannot be used if a rolename or \&.tar\&.gz have been specified\&.
.RE
.SH "REMOVE"
.sp
The \fBremove\fR sub\-command is used to remove one or more roles\&.
.SS "USAGE"
.sp
$ ansible\-galaxy remove role1 role2 \&...
.SS "OPTIONS"
.PP
\fB\-p\fR \fIROLES_PATH\fR, \fB\-\-roles\-path=\fR\fIROLES_PATH\fR
.RS 4
The path to the directory containing your roles\&. The default is the
\fBroles_path\fR
configured in your
\fBansible\&.cfg\fR
file (/etc/ansible/roles if not configured)
.RE
.SH "INIT"
.sp
The \fBinit\fR command is used to create an empty role suitable for uploading to https://galaxy\&.ansible\&.com (or for roles in general)\&.
.SS "USAGE"
.sp
$ ansible\-galaxy init [options] role_name
.SS "OPTIONS"
.PP
\fB\-f\fR, \fB\-\-force\fR
.RS 4
Force overwriting an existing role\&.
.RE
.PP
\fB\-p\fR \fIINIT_PATH\fR, \fB\-\-init\-path=\fR\fIINIT_PATH\fR
.RS 4
The path in which the skeleton role will be created\&.The default is the current working directory\&.
.RE
.SH "LIST"
.sp
The \fBlist\fR sub\-command is used to show what roles are currently instaled\&. You can specify a role name, and if installed only that role will be shown\&.
.SS "USAGE"
.sp
$ ansible\-galaxy list [role_name]
.SS "OPTIONS"
.PP
\fB\-p\fR \fIROLES_PATH\fR, \fB\-\-roles\-path=\fR\fIROLES_PATH\fR
.RS 4
The path to the directory containing your roles\&. The default is the
\fBroles_path\fR
configured in your
\fBansible\&.cfg\fR
file (/etc/ansible/roles if not configured)
.RE
.SH "AUTHOR"
.sp
Ansible was originally written by Michael DeHaan\&. See the AUTHORS file for a complete list of contributors\&.
.SH "COPYRIGHT"
.sp
Copyright \(co 2014, Michael DeHaan
.sp
Ansible is released under the terms of the GPLv3 License\&.
.SH "SEE ALSO"
.sp
\fBansible\fR(1), \fBansible\-pull\fR(1), \fBansible\-doc\fR(1)
.sp
Extensive documentation is available in the documentation site: http://docs\&.ansible\&.com\&. IRC and mailing list info can be found in file CONTRIBUTING\&.md, available in: https://github\&.com/ansible/ansible

View File

@ -1,167 +0,0 @@
ansible-galaxy(1)
===================
:doctype: manpage
:man source: Ansible
:man version: %VERSION%
:man manual: System administration commands
NAME
----
ansible-galaxy - manage roles using galaxy.ansible.com
SYNOPSIS
--------
ansible-galaxy [init|info|install|list|remove] [--help] [options] ...
DESCRIPTION
-----------
*Ansible Galaxy* is a shared repository for Ansible roles (added in
ansible version 1.2). The ansible-galaxy command can be used to manage
these roles, or by creating a skeleton framework for roles you'd like
to upload to Galaxy.
COMMON OPTIONS
--------------
*-h*, *--help*::
Show a help message related to the given sub-command.
INSTALL
-------
The *install* sub-command is used to install roles.
USAGE
~~~~~
$ ansible-galaxy install [options] [-r FILE | role_name(s)[,version] | tar_file(s)]
Roles can be installed in several different ways:
* A username.rolename[,version] - this will install a single role. The Galaxy
API will be contacted to provide the information about the role, and the
corresponding .tar.gz will be downloaded from *github.com*. If the version
is omitted, the most recent version available will be installed.
* A file name, using *-r* - this will install multiple roles listed one per
line. The format of each line is the same as above: username.rolename[,version]
* A .tar.gz of a valid role you've downloaded directly from *github.com*. This
is mainly useful when the system running Ansible does not have access to
the Galaxy API, for instance when behind a firewall or proxy.
OPTIONS
~~~~~~~
*-f*, *--force*::
Force overwriting an existing role.
*-i*, *--ignore-errors*::
Ignore errors and continue with the next specified role.
*-n*, *--no-deps*::
Don't download roles listed as dependencies.
*-p* 'ROLES_PATH', *--roles-path=*'ROLES_PATH'::
The path to the directory containing your roles. The default is the *roles_path*
configured in your *ansible.cfg* file (/etc/ansible/roles if not configured)
*-r* 'ROLE_FILE', *--role-file=*'ROLE_FILE'::
A file containing a list of roles to be imported, as specified above. This
option cannot be used if a rolename or .tar.gz have been specified.
REMOVE
------
The *remove* sub-command is used to remove one or more roles.
USAGE
~~~~~
$ ansible-galaxy remove role1 role2 ...
OPTIONS
~~~~~~~
*-p* 'ROLES_PATH', *--roles-path=*'ROLES_PATH'::
The path to the directory containing your roles. The default is the *roles_path*
configured in your *ansible.cfg* file (/etc/ansible/roles if not configured)
INIT
----
The *init* command is used to create an empty role suitable for uploading
to https://galaxy.ansible.com (or for roles in general).
USAGE
~~~~~
$ ansible-galaxy init [options] role_name
OPTIONS
~~~~~~~
*-f*, *--force*::
Force overwriting an existing role.
*-p* 'INIT_PATH', *--init-path=*'INIT_PATH'::
The path in which the skeleton role will be created.The default is the current
working directory.
LIST
----
The *list* sub-command is used to show what roles are currently instaled.
You can specify a role name, and if installed only that role will be shown.
USAGE
~~~~~
$ ansible-galaxy list [role_name]
OPTIONS
~~~~~~~
*-p* 'ROLES_PATH', *--roles-path=*'ROLES_PATH'::
The path to the directory containing your roles. The default is the *roles_path*
configured in your *ansible.cfg* file (/etc/ansible/roles if not configured)
AUTHOR
------
Ansible was originally written by Michael DeHaan. See the AUTHORS file
for a complete list of contributors.
COPYRIGHT
---------
Copyright © 2014, Michael DeHaan
Ansible is released under the terms of the GPLv3 License.
SEE ALSO
--------
*ansible*(1), *ansible-pull*(1), *ansible-doc*(1)
Extensive documentation is available in the documentation site:
<http://docs.ansible.com>. IRC and mailing list info can be found
in file CONTRIBUTING.md, available in: <https://github.com/ansible/ansible>

View File

@ -2,12 +2,12 @@
.\" Title: ansible-playbook
.\" Author: :doctype:manpage
.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
.\" Date: 05/26/2014
.\" Date: 03/11/2014
.\" Manual: System administration commands
.\" Source: Ansible 1.7
.\" Source: Ansible 1.5.2
.\" Language: English
.\"
.TH "ANSIBLE\-PLAYBOOK" "1" "05/26/2014" "Ansible 1\&.7" "System administration commands"
.TH "ANSIBLE\-PLAYBOOK" "1" "03/11/2014" "Ansible 1\&.5\&.2" "System administration commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -91,12 +91,12 @@ Prompt for the password to use for playbook plays that request sudo access, if a
Desired sudo user (default=root)\&.
.RE
.PP
\fB\-t\fR, \fITAGS\fR, \fB\-\-tags=\fR\fITAGS\fR
\fB\-t\fR, \fITAGS\fR, \fB\fI\-\-tags=\fR\fR\fB\*(AqTAGS\fR
.RS 4
Only run plays and tasks tagged with these values\&.
.RE
.PP
\fB\-\-skip\-tags=\fR\fISKIP_TAGS\fR
\fB\fI\-\-skip\-tags=\fR\fR\fB\*(AqSKIP_TAGS\fR
.RS 4
Only run plays and tasks whose tags do not match these values\&.
.RE

View File

@ -76,11 +76,11 @@ access, if any.
Desired sudo user (default=root).
*-t*, 'TAGS', *--tags=*'TAGS'::
*-t*, 'TAGS', *'--tags=*'TAGS'::
Only run plays and tasks tagged with these values.
*--skip-tags=*'SKIP_TAGS'::
*'--skip-tags=*'SKIP_TAGS'::
Only run plays and tasks whose tags do not match these values.

View File

@ -2,12 +2,12 @@
.\" Title: ansible
.\" Author: :doctype:manpage
.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
.\" Date: 05/26/2014
.\" Date: 03/11/2014
.\" Manual: System administration commands
.\" Source: Ansible 1.7
.\" Source: Ansible 1.5.2
.\" Language: English
.\"
.TH "ANSIBLE" "1" "05/26/2014" "Ansible 1\&.7" "System administration commands"
.TH "ANSIBLE" "1" "03/11/2014" "Ansible 1\&.5\&.2" "System administration commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------

View File

@ -12,7 +12,7 @@ ansible-pull - set up a remote copy of ansible on each managed node
SYNOPSIS
--------
ansible-pull -d DEST -U URL [options] [ <filename.yml> ]
ansible -d DEST -U URL [options] [ <filename.yml> ]
DESCRIPTION

View File

@ -1,103 +0,0 @@
'\" t
.\" Title: ansible-vault
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
.\" Date: 05/26/2014
.\" Manual: System administration commands
.\" Source: Ansible 1.7
.\" Language: English
.\"
.TH "ANSIBLE\-VAULT" "1" "05/26/2014" "Ansible 1\&.7" "System administration commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\" http://bugs.debian.org/507673
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.\" -----------------------------------------------------------------
.\" * MAIN CONTENT STARTS HERE *
.\" -----------------------------------------------------------------
.SH "NAME"
ansible-vault \- manage encrypted YAML data\&.
.SH "SYNOPSIS"
.sp
ansible\-vault [create|decrypt|edit|encrypt|rekey] [\-\-help] [options] file_name
.SH "DESCRIPTION"
.sp
\fBansible\-vault\fR can encrypt any structured data file used by Ansible\&. This can include \fBgroup_vars/\fR or \fBhost_vars/\fR inventory variables, variables loaded by \fBinclude_vars\fR or \fBvars_files\fR, or variable files passed on the ansible\-playbook command line with \fB\-e @file\&.yml\fR or \fB\-e @file\&.json\fR\&. Role variables and defaults are also included!
.sp
Because Ansible tasks, handlers, and so on are also data, these can also be encrypted with vault\&. If you\(cqd like to not betray what variables you are even using, you can go as far to keep an individual task file entirely encrypted\&.
.SH "COMMON OPTIONS"
.sp
The following options are available to all sub\-commands:
.PP
\fB\-\-vault\-password\-file=\fR\fIFILE\fR
.RS 4
A file containing the vault password to be used during the encryption/decryption steps\&. Be sure to keep this file secured if it is used\&.
.RE
.PP
\fB\-h\fR, \fB\-\-help\fR
.RS 4
Show a help message related to the given sub\-command\&.
.RE
.PP
\fB\-\-debug\fR
.RS 4
Enable debugging output for troubleshooting\&.
.RE
.SH "CREATE"
.sp
\fB$ ansible\-vault create [options] FILE\fR
.sp
The \fBcreate\fR sub\-command is used to initialize a new encrypted file\&.
.sp
First you will be prompted for a password\&. The password used with vault currently must be the same for all files you wish to use together at the same time\&.
.sp
After providing a password, the tool will launch whatever editor you have defined with $EDITOR, and defaults to vim\&. Once you are done with the editor session, the file will be saved as encrypted data\&.
.sp
The default cipher is AES (which is shared\-secret based)\&.
.SH "EDIT"
.sp
\fB$ ansible\-vault edit [options] FILE\fR
.sp
The \fBedit\fR sub\-command is used to modify a file which was previously encrypted using ansible\-vault\&.
.sp
This command will decrypt the file to a temporary file and allow you to edit the file, saving it back when done and removing the temporary file\&.
.SH "REKEY"
.sp
*$ ansible\-vault rekey [options] FILE_1 [FILE_2, \&..., FILE_N]
.sp
The \fBrekey\fR command is used to change the password on a vault\-encrypted files\&. This command can update multiple files at once, and will prompt for both the old and new passwords before modifying any data\&.
.SH "ENCRYPT"
.sp
*$ ansible\-vault encrypt [options] FILE_1 [FILE_2, \&..., FILE_N]
.sp
The \fBencrypt\fR sub\-command is used to encrypt pre\-existing data files\&. As with the \fBrekey\fR command, you can specify multiple files in one command\&.
.SH "DECRYPT"
.sp
*$ ansible\-vault decrypt [options] FILE_1 [FILE_2, \&..., FILE_N]
.sp
The \fBdecrypt\fR sub\-command is used to remove all encryption from data files\&. The files will be stored as plain\-text YAML once again, so be sure that you do not run this command on data files with active passwords or other sensitive data\&. In most cases, users will want to use the \fBedit\fR sub\-command to modify the files securely\&.
.SH "AUTHOR"
.sp
Ansible was originally written by Michael DeHaan\&. See the AUTHORS file for a complete list of contributors\&.
.SH "COPYRIGHT"
.sp
Copyright \(co 2014, Michael DeHaan
.sp
Ansible is released under the terms of the GPLv3 License\&.
.SH "SEE ALSO"
.sp
\fBansible\fR(1), \fBansible\-pull\fR(1), \fBansible\-doc\fR(1)
.sp
Extensive documentation is available in the documentation site: http://docs\&.ansible\&.com\&. IRC and mailing list info can be found in file CONTRIBUTING\&.md, available in: https://github\&.com/ansible/ansible

View File

@ -1,126 +0,0 @@
ansible-vault(1)
================
:doctype: manpage
:man source: Ansible
:man version: %VERSION%
:man manual: System administration commands
NAME
----
ansible-vault - manage encrypted YAML data.
SYNOPSIS
--------
ansible-vault [create|decrypt|edit|encrypt|rekey] [--help] [options] file_name
DESCRIPTION
-----------
*ansible-vault* can encrypt any structured data file used by Ansible. This can include
*group_vars/* or *host_vars/* inventory variables, variables loaded by *include_vars* or
*vars_files*, or variable files passed on the ansible-playbook command line with
*-e @file.yml* or *-e @file.json*. Role variables and defaults are also included!
Because Ansible tasks, handlers, and so on are also data, these can also be encrypted with
vault. If you’d like to not betray what variables you are even using, you can go as far to
keep an individual task file entirely encrypted.
COMMON OPTIONS
--------------
The following options are available to all sub-commands:
*--vault-password-file=*'FILE'::
A file containing the vault password to be used during the encryption/decryption
steps. Be sure to keep this file secured if it is used.
*-h*, *--help*::
Show a help message related to the given sub-command.
*--debug*::
Enable debugging output for troubleshooting.
CREATE
------
*$ ansible-vault create [options] FILE*
The *create* sub-command is used to initialize a new encrypted file.
First you will be prompted for a password. The password used with vault currently
must be the same for all files you wish to use together at the same time.
After providing a password, the tool will launch whatever editor you have defined
with $EDITOR, and defaults to vim. Once you are done with the editor session, the
file will be saved as encrypted data.
The default cipher is AES (which is shared-secret based).
EDIT
----
*$ ansible-vault edit [options] FILE*
The *edit* sub-command is used to modify a file which was previously encrypted
using ansible-vault.
This command will decrypt the file to a temporary file and allow you to edit the
file, saving it back when done and removing the temporary file.
REKEY
-----
*$ ansible-vault rekey [options] FILE_1 [FILE_2, ..., FILE_N]
The *rekey* command is used to change the password on a vault-encrypted files.
This command can update multiple files at once, and will prompt for both the
old and new passwords before modifying any data.
ENCRYPT
-------
*$ ansible-vault encrypt [options] FILE_1 [FILE_2, ..., FILE_N]
The *encrypt* sub-command is used to encrypt pre-existing data files. As with the
*rekey* command, you can specify multiple files in one command.
DECRYPT
-------
*$ ansible-vault decrypt [options] FILE_1 [FILE_2, ..., FILE_N]
The *decrypt* sub-command is used to remove all encryption from data files. The files
will be stored as plain-text YAML once again, so be sure that you do not run this
command on data files with active passwords or other sensitive data. In most cases,
users will want to use the *edit* sub-command to modify the files securely.
AUTHOR
------
Ansible was originally written by Michael DeHaan. See the AUTHORS file
for a complete list of contributors.
COPYRIGHT
---------
Copyright © 2014, Michael DeHaan
Ansible is released under the terms of the GPLv3 License.
SEE ALSO
--------
*ansible*(1), *ansible-pull*(1), *ansible-doc*(1)
Extensive documentation is available in the documentation site:
<http://docs.ansible.com>. IRC and mailing list info can be found
in file CONTRIBUTING.md, available in: <https://github.com/ansible/ansible>

View File

@ -2,12 +2,12 @@
.\" Title: ansible
.\" Author: :doctype:manpage
.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
.\" Date: 05/26/2014
.\" Date: 03/11/2014
.\" Manual: System administration commands
.\" Source: Ansible 1.7
.\" Source: Ansible 1.5.2
.\" Language: English
.\"
.TH "ANSIBLE" "1" "05/26/2014" "Ansible 1\&.7" "System administration commands"
.TH "ANSIBLE" "1" "03/11/2014" "Ansible 1\&.5\&.2" "System administration commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------

View File

@ -10,10 +10,6 @@ docs: clean modules staticmin
-(cp *.jpg htmlout/)
-(cp *.png htmlout/)
variables:
(mkdir -p htmlout/)
dot variables.dot -Tpng -o htmlout/variables.png
viewdocs: clean staticmin
./build-site.py view
@ -40,7 +36,7 @@ clean:
.PHONEY: docs clean
modules: $(FORMATTER) ../hacking/templates/rst.j2
PYTHONPATH=../lib $(FORMATTER) -t rst --template-dir=../hacking/templates --module-dir=../lib/ansible/modules -o rst/
PYTHONPATH=../lib $(FORMATTER) -t rst --template-dir=../hacking/templates --module-dir=../library -o rst/
staticmin:
cat _themes/srtd/static/css/theme.css | sed -e 's/^[ \t]*//g; s/[ \t]*$$//g; s/\([:{;,]\) /\1/g; s/ {/{/g; s/\/\*.*\*\///g; /^$$/d' | sed -e :a -e '$$!N; s/\n\(.\)/\1/; ta' > _themes/srtd/static/css/theme.min.css

View File

@ -13,7 +13,7 @@
* helper function to return a node containing the
* search summary for a given text. keywords is a list
* of stemmed words, hlwords is the list of normal, unstemmed
* words. the first one is used to find the occurrence, the
* words. the first one is used to find the occurance, the
* latter for highlighting it.
*/
@ -557,4 +557,4 @@ var Search = {
$(document).ready(function() {
Search.init();
});
});

View File

@ -14,11 +14,18 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Google Tag Manager Data Layer -->
<script>
dataLayer = [];
</script>
<!-- End Google Tag Manager Data Layer -->
<!-- begin analytics -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-29861888-3', 'ansible.com');
ga('send', 'pageview');
</script>
<!-- end analytics -->
{% block htmltitle %}
<title>{{ title|striptags|e }}{{ titlesuffix }}</title>
@ -117,11 +124,6 @@
<body class="wy-body-for-nav">
<!-- Google Tag Manager -->
<noscript><iframe src="//www.googletagmanager.com/ns.html?id=GTM-PSB293" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-PSB293');</script>
<!-- End Google Tag Manager -->
<div class="wy-grid-for-nav">
{# SIDE NAV, TOGGLES ON MOBILE #}
@ -176,19 +178,6 @@
{# PAGE CONTENT #}
<div class="wy-nav-content">
<div class="rst-content">
<!-- AnsibleFest and free eBook preview stuff -->
<center>
<a href="http://www.ansible.com/ansiblefest-london">
<img src="http://www.ansible.com/hs-fs/hub/330046/file-2031636235-png/DL_Folder/festlondon-docs.png">
</a>
<a href="http://www.ansible.com/ansible-book">
<img src="http://www.ansible.com/hs-fs/hub/330046/file-2031636250-png/DL_Folder/Ebook-docs.png">
</a>
<br/>&nbsp;<br/>
<br/>&nbsp;<br/>
</center>
{% include "breadcrumbs.html" %}
<div id="page-content">
{% block body %}{% endblock %}

View File

@ -6,7 +6,7 @@
<script>
(function() {
var cx = '006019874985968165468:eu5pbnxp4po';
var cx = '015514069825911246756:eu5pbnxp4po';
var gcse = document.createElement('script');
gcse.type = 'text/javascript';
gcse.async = true;

View File

@ -3293,7 +3293,7 @@ code, .rst-content tt {
border: solid 1px #e1e4e5;
font-size: 75%;
padding: 0 5px;
font-family: "Inconsolata", "Consolata", "Monaco", monospace;
font-family: "Incosolata", "Consolata", "Monaco", monospace;
color: #e74c3c;
overflow-x: auto;
}
@ -3439,7 +3439,7 @@ a.wy-text-neutral:hover {
border-right: solid 1px #e6e9ea;
margin: 0;
padding: 12px 12px;
font-family: "Inconsolata", "Consolata", "Monaco", monospace;
font-family: "Incosolata", "Consolata", "Monaco", monospace;
font-size: 12px;
line-height: 1.5;
color: #d9d9d9;
@ -3449,7 +3449,7 @@ div[class^='highlight'] pre {
white-space: pre;
margin: 0;
padding: 12px 12px;
font-family: "Inconsolata", "Consolata", "Monaco", monospace;
font-family: "Incosolata", "Consolata", "Monaco", monospace;
font-size: 12px;
line-height: 1.5;
display: block;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,281 +1,9 @@
Community Information & Contributing
````````````````````````````````````
Community Information
`````````````````````
Ansible is an open source project designed to bring together administrators and developers of all kinds to collaborate on building
IT automation solutions that work well for them.
Ansible is an open source project designed to bring together developers and administrators of all kinds to collaborate on building
IT automation solutions that work well for them. Should you wish to get more involved -- whether in terms of just asking a question, helping other users, introducing new people to Ansible, or helping with the software or documentation, we welcome your contributions to the project.
Should you wish to get more involved -- whether in terms of just asking a question, helping other users, introducing new people to Ansible, or helping with the software or documentation, we welcome your contributions to the project.
`Ways to interact <https://github.com/ansible/ansible/blob/devel/CONTRIBUTING.md>`_
.. contents:: Topics
Ansible Users
=============
I've Got A Question
-------------------
We're happy to help!
Ansible questions are best asked on the `Ansible Google Group Mailing List <http://groups.google.com/group/ansible-project>`_.
This is a very large high-traffic list for answering questions and sharing tips
and tricks. Anyone can join, and email delivery is optional if you just want to read the group online. To cut down on spam, your first post is moderated, though posts are approved quickly.
Please be sure to share any relevant commands you ran, output, and detail, indicate the version of Ansible you are using when asking a question.
Where needed, link to gists or github repos to show examples, rather than sending attachments to the list.
We recommend using Google search to see if a topic has been answered recently, but comments found in older threads may no longer apply, depending on the topic.
Before you post, be sure you are running the latest stable version of Ansible. You can check this by comparing the output of 'ansible --version' with the version indicated on `PyPi <https://pypi.python.org/pypi/ansible>`.
Alternatively, you can also join our IRC channel - #ansible on irc.freenode.net. It's a very high traffic channel as well, if you don't get an answer you like, please stop by our mailing list, which is more likely
to get attention of core developers since it's asynchronous.
I'd Like To Keep Up With Release Announcements
----------------------------------------------
Release announcements are posted to ansible-project, though if you don't want to keep up with the very active list, you can join the `Ansible Announce Mailing List <http://groups.google.com/group/ansible-announce>`_
This is a low-traffic read-only list, where we'll share release announcements and occasionally links to major Ansible Events around the world.
I'd Like To Help Share and Promote Ansible
------------------------------------------
You can help share Ansible with others by telling friends and colleagues, writing a blog post,
or presenting at user groups (like DevOps groups or the local LUG).
You are also welcome to share slides on speakerdeck, sign up for a free account and tag it “Ansible”. On Twitter,
you can also share things with #ansible and may wish to `follow us <https://twitter.com/ansible>`_.
I'd Like To Help Ansible Move Faster
------------------------------------
If you're a developer, one of the most valuable things you can do is look at the github issues list and help fix bugs. We almost always prioritize bug fixing over
feature development, so clearing bugs out of the way is one of the best things you can do.
If you're not a developer, helping test pull requests for bug fixes and features is still immensely valuable. You can do this by checking out ansible, making a test
branch off the main one, merging a GitHub issue, testing, and then commenting on that particular issue on GitHub.
I'd Like To Report A Bug
------------------------------------
Ansible practices responsible disclosure - if this is a security related bug, email `security@ansible.com <mailto:security@ansible.com>`_ instead of filing a ticket or posting to the Google Group and you will receive a prompt response.
Bugs related to the core language should be reported to `github.com/ansible/ansible <http://github.com/ansible/ansible>`_ after
signing up for a free github account. Before reporting a bug, please use the bug/issue search
to see if the issue has already been reported.
MODULE related bugs however should go to `ansible-modules-core <github.com/ansible/ansible-modules-core>`_ or `ansible-modules-extras <github.com/ansible/ansible-modules-extras>`_ based on the classification of the module. This is listed on the bottom of the docs page for any module.
When filing a bug, please use the `issue template <https://github.com/ansible/ansible/raw/devel/ISSUE_TEMPLATE.md>`_ to provide all relevant information, regardless of what repo you are filing a ticket against.
Knowing your ansible version and the exact commands you are running, and what you expect, saves time and helps us help everyone with their issues
more quickly.
Do not use the issue tracker for "how do I do this" type questions. These are great candidates
for IRC or the mailing list instead where things are likely to be more of a discussion.
To be respectful of reviewers time and allow us to help everyone efficiently, please
provide minimal well-reduced and well-commented examples versus sharing your entire production
playbook. Include playbook snippets and output where possible.
When sharing YAML in playbooks, formatting can be preserved by using `code blocks <https://help.github.com/articles/github-flavored-markdown#fenced-code-blocks>`_.
For multiple-file content, we encourage use of gist.github.com. Online pastebin content can expire, so it's nice to have things around for a longer term if they
are referenced in a ticket.
If you are not sure if something is a bug yet, you are welcome to ask about something on
the mailing list or IRC first.
As we are a very high volume project, if you determine that
you do have a bug, please be sure to open the issue yourself to ensure we have a record of
it. Don’t rely on someone else in the community to file the bug report for you.
It may take some time to get to your report, see our information about priority flags below.
I'd Like To Help With Documentation
-----------------------------------
Ansible documentation is a community project too!
If you would like to help with the
documentation, whether correcting a typo or improving a section, or maybe even
documenting a new feature, submit a github pull request to the code that
lives in the “docsite/rst” subdirectory of the project for most pages, and there is an "Edit on GitHub"
link up on those.
Module documentation is generated from a DOCUMENTATION structure embedded in the source code of each module, which is in either the ansible-modules-core or ansible-modules-extra repos on github, depending on the module. Information about this is always listed on the bottom of the web documentation for each module.
Aside from modules, the main docs are in restructured text
format.
If you aren’t comfortable with restructured text, you can also open a ticket on
github about any errors you spot or sections you would like to see added. For more information
on creating pull requests, please refer to the
`github help guide <https://help.github.com/articles/using-pull-requests>`_.
For Current and Prospective Developers
=======================================
I'd Like To Learn How To Develop on Ansible
-------------------------------------------
If you're new to Ansible and would like to figure out how to work on things, stop by the ansible-devel mailing list
and say hi, and we can hook you up.
A great way to get started would be reading over some of the development documentation on the module site, and then
finding a bug to fix or small feature to add.
Modules are some of the easiest places to get started.
Contributing Code (Features or Bugfixes)
----------------------------------------
The Ansible project keeps its source on github at
`github.com/ansible/ansible <http://github.com/ansible/ansible>`_ for the core application, and two sub repos ansible/ansible-modules-core and ansible/ansible-modules-extras for module related items. If you need to know if a module is in 'core' or 'extras', consult the web documentation page for that module.
The project takes contributions through
`github pull requests <https://help.github.com/articles/using-pull-requests>`_.
It is usually a good idea to join the ansible-devel list to discuss any large features prior to submission, and this especially helps in avoiding duplicate work or efforts where we decide, upon seeing a pull request for the first time, that revisions are needed. (This is not usually needed for module development, but can be nice for large changes).
Note that we do keep Ansible to a particular aesthetic, so if you are unclear about whether a feature
is a good fit or not, having the discussion on the development list is often a lot easier than having
to modify a pull request later.
When submitting patches, be sure to run the unit tests first “make tests” and always use
“git rebase” vs “git merge” (aliasing git pull to git pull --rebase is a great idea) to
avoid merge commits in your submissions. There are also integration tests that can be run in the "test/integration" directory.
In order to keep the history clean and better audit incoming code, we will require resubmission of pull requests that contain merge commits. Use "git pull --rebase" vs "git pull" and "git rebase" vs "git merge". Also be sure to use topic branches to keep your additions on different branches, such that they won't pick up stray commits later.
We’ll then review your contributions and engage with you about questions and so on.
As we have a very large and active community, so it may take awhile to get your contributions
in! See the notes about priorities in a later section for understanding our work queue.
Patches should be made against the 'devel' branch.
Contributions can be for new features like modules, or to fix bugs you or others have found. If you
are interested in writing new modules to be included in the core Ansible distribution, please refer
to the `module development documentation <http://docs.ansible.com/developing_modules.html>`_.
Ansible's aesthetic encourages simple, readable code and consistent, conservatively extending,
backwards-compatible improvements. Code developed for Ansible needs to support Python 2.6+,
while code in modules must run under Python 2.4 or higher. Please also use a 4-space indent
and no tabs.
Tip: To easily run from a checkout, source "./hacking/env-setup" and that's it -- no install
required. You're now live!
Other Topics
============
Ansible Staff
-------------
Ansible, Inc is a company supporting Ansible and building additional solutions based on
Ansible. We also do services and support for those that are interested.
Our most
important task however is enabling all the great things that happen in the Ansible
community, including organizing software releases of Ansible. For more information about
any of these things, contact info@ansible.com
On IRC, you can find us as mdehaan, jimi_c, abadger1999, Tybstar, and others. On the mailing list,
we post with an @ansible.com address.
Mailing List Information
------------------------
Ansible has several mailing lists. Your first post to the mailing list will be
moderated (to reduce spam), so please allow a day or less for your first post.
`Ansible Project List <https://groups.google.com/forum/#!forum/ansible-project>`_ is for sharing Ansible Tips, answering questions, and general user discussion.
`Ansible Development List <https://groups.google.com/forum/#!forum/ansible-devel>`_ is for learning how to develop on Ansible, asking about prospective feature design, or discussions
about extending ansible or features in progress.
`Ansible Announce list <https://groups.google.com/forum/#!forum/ansible-announce>`_ is a read-only list that shares information about new releases of Ansible, and also rare infrequent
event information, such as announcements about an AnsibleFest coming up, which is our official conference series.
To subscribe to a group from a non-google account, you can email the subscription address, for
example ansible-devel+subscribe@googlegroups.com.
Release Numbering
-----------------
Releases ending in ".0" are major releases and this is where all new features land. Releases ending
in another integer, like "0.X.1" and "0.X.2" are dot releases, and these are only going to contain
bugfixes.
Typically we don't do dot releases for minor bugfixes (reserving these for larger items),
but may occasionally decide to cut dot releases containing a large number of smaller fixes if it's still a fairly long time before
the next release comes out.
Releases are also given code names based on Van Halen songs, that no one really uses.
Tower Support Questions
-----------------------
Ansible `Tower <http://ansible.com/tower>`_ is a UI, Server, and REST endpoint for Ansible, produced by Ansible, Inc.
If you have a question about tower, email `support@ansible.com <mailto:support@ansible.com>`_ rather than using the IRC
channel or the general project mailing list.
IRC Channel
-----------
Ansible has an IRC channel #ansible on irc.freenode.net.
Notes on Priority Flags
-----------------------
Ansible was one of the top 5 projects with the most OSS contributors on GitHub in 2013, and has over 800 contributors
to the project to date, not to mention a very large user community that has downloaded the application well over a million
times.
As a result, we have a LOT of incoming activity to process.
In the interest of transparency, we're telling you how we sort incoming requests.
In our bug tracker you'll notice some labels - P1, P2, P3, P4, and P5. These are our internal
priority orders that we use to sort tickets.
With some exceptions for easy merges (like documentation typos for instance),
we're going to spend most of our time working on P1 and P2 items first, including pull requests.
These usually relate to important bugs or features affecting large segments of the userbase. So if you see something categorized
"P3 or P4", and it's not appearing to get a lot of immediate attention, this is why.
These labels don't really have definition - they are a simple ordering. However something
affecting a major module (yum, apt, etc) is likely to be prioritized higher than a module
affecting a smaller number of users.
Since we place a strong emphasis on testing and code review, it may take a few months for a minor feature to get merged.
Don't worry though -- we'll also take periodic sweeps through the lower priority queues and give
them some attention as well, particularly in the area of new module changes. So it doesn't necessarily
mean that we'll be exhausting all of the higher-priority queues before getting to your ticket.
Every bit of effort helps - if you're wishing to expedite the inclusion of a P3 feature pull request for instance, the best thing you can do
is help close P2 bug reports.
Community Code of Conduct
-------------------------
Ansible’s community welcomes users of all types, backgrounds, and skill levels. Please
treat others as you expect to be treated, keep discussions positive, and avoid discrimination of all kinds, profanity, allegations of Cthulhu worship, or engaging in controversial debates (except vi vs emacs is cool).
The same expectations apply to community events as they do to online interactions.
Posts to mailing lists should remain focused around Ansible and IT automation. Abuse of these community guidelines will not be tolerated and may result in banning from community resources.
Contributors License Agreement
------------------------------
By contributing you agree that these contributions are your own (or approved by your employer)
and you grant a full, complete, irrevocable
copyright license to all users and developers of the project, present and future, pursuant
to the license of the project.

View File

@ -10,7 +10,6 @@ Learn how to build modules of your own in any language, and also how to extend A
developing_inventory
developing_modules
developing_plugins
developing_test_pr
Developers will also likely be interested in the fully-discoverable in :doc:`tower`. It's great for embedding Ansible in all manner of applications.

View File

@ -11,17 +11,9 @@ See :doc:`modules` for a list of various ones developed in core.
Modules can be written in any language and are found in the path specified
by `ANSIBLE_LIBRARY` or the ``--module-path`` command line option.
By default, everything that ships with ansible is pulled from its source tree, but
additional paths can be added.
The directory "./library", alongside your top level playbooks, is also automatically
added as a search directory.
Should you develop an interesting Ansible module, consider sending a pull request to the
`modules-extras project <http://github.com/ansible/ansible-modules-extras>`_. There's also a core
repo for more established and widely used modules. "Extras" modules may be promoted to core periodically,
but there's no fundamental difference in the end - both ship with ansible, all in one package, regardless
of how you acquire ansible.
`github project <http://github.com/ansible/ansible>`_ to see about getting your module
included in the core project.
.. _module_dev_tutorial:
@ -48,7 +40,7 @@ modules. Keep in mind, though, that some modules in ansible's source tree are
so look at `service` or `yum`, and don't stare too close into things like `async_wrapper` or
you'll turn to stone. Nobody ever executes async_wrapper directly.
Ok, let's get going with an example. We'll use Python. For starters, save this as a file named `time.py`::
Ok, let's get going with an example. We'll use Python. For starters, save this as a file named `time`::
#!/usr/bin/python
@ -67,13 +59,13 @@ Testing Modules
There's a useful test script in the source checkout for ansible::
git clone git@github.com:ansible/ansible.git --recursive
git clone git@github.com:ansible/ansible.git
source ansible/hacking/env-setup
chmod +x ansible/hacking/test-module
Let's run the script you just wrote with that::
ansible/hacking/test-module -m ./time.py
ansible/hacking/test-module -m ./time
You should see output that looks something like this::
@ -86,7 +78,6 @@ If you did not, you might have a typo in your module, so recheck it and try agai
Reading Input
`````````````
Let's modify the module to allow setting the current time. We'll do this by seeing
if a key value pair in the form `time=<string>` is passed in to the module.
@ -132,7 +123,7 @@ a lot shorter than this::
for arg in arguments:
# ignore any arguments without an equals in it
if "=" in arg:
if arg.find("=") != -1:
(key, value) = arg.split("=")
@ -210,7 +201,7 @@ this, just have the module return a `ansible_facts` key, like so, along with oth
"changed" : True,
"rc" : 5,
"ansible_facts" : {
"leptons" : 5000,
"leptons" : 5000
"colors" : {
"red" : "FF0000",
"white" : "FFFFFF"
@ -231,7 +222,7 @@ As mentioned, if you are writing a module in Python, there are some very powerfu
Modules are still transferred as one file, but an arguments file is no longer needed, so these are not
only shorter in terms of code, they are actually FASTER in terms of execution time.
Rather than mention these here, the best way to learn is to read some of the `source of the modules <https://github.com/ansible/ansible-modules-core>`_ that come with Ansible.
Rather than mention these here, the best way to learn is to read some of the `source of the modules <https://github.com/ansible/ansible/tree/devel/library>`_ that come with Ansible.
The 'group' and 'user' modules are reasonably non-trivial and showcase what this looks like.
@ -262,7 +253,7 @@ And failures are just as simple (where 'msg' is a required parameter to explain
module.fail_json(msg="Something fatal happened")
There are also other useful functions in the module class, such as module.sha1(path). See
There are also other useful functions in the module class, such as module.md5(path). See
lib/ansible/module_common.py in the source checkout for implementation details.
Again, modules developed this way are best tested with the hacking/test-module script in the git
@ -339,7 +330,7 @@ and guidelines:
* Include a minimum of dependencies if possible. If there are dependencies, document them at the top of the module file, and have the module raise JSON error messages when the import fails.
* Modules must be self-contained in one file to be auto-transferred by ansible.
* Modules must be self contained in one file to be auto-transferred by ansible.
* If packaging modules in an RPM, they only need to be installed on the control machine and should be dropped into /usr/share/ansible. This is entirely optional and up to you.
@ -347,7 +338,7 @@ and guidelines:
* In the event of failure, a key of 'failed' should be included, along with a string explanation in 'msg'. Modules that raise tracebacks (stacktraces) are generally considered 'poor' modules, though Ansible can deal with these returns and will automatically convert anything unparseable into a failed result. If you are using the AnsibleModule common Python code, the 'failed' element will be included for you automatically when you call 'fail_json'.
* Return codes from modules are not actually not significant, but continue on with 0=success and non-zero=failure for reasons of future proofing.
* Return codes from modules are not actually not signficant, but continue on with 0=success and non-zero=failure for reasons of future proofing.
* As results from many hosts will be aggregated at once, modules should return only relevant output. Returning the entire contents of a log file is generally bad form.
@ -402,7 +393,7 @@ support formatting with some special macros.
These formatting functions are ``U()``, ``M()``, ``I()``, and ``C()``
for URL, module, italic, and constant-width respectively. It is suggested
to use ``C()`` for file and option names, and ``I()`` when referencing
parameters; module names should be specified as ``M(module)``.
parameters; module names should be specifies as ``M(module)``.
Examples (which typically contain colons, quotes, etc.) are difficult
to format with YAML, so these must be
@ -432,55 +423,20 @@ built and appear in the 'docsite/' directory.
.. tip::
You can set the environment variable ANSIBLE_KEEP_REMOTE_FILES=1 on the controlling host to prevent ansible from
You can use ANSIBLE_KEEP_REMOTE_FILES=1 to prevent ansible from
deleting the remote files so you can debug your module.
.. _module_contribution:
Module Paths
````````````
If you are having trouble getting your module "found" by ansible, be sure it is in the ANSIBLE_LIBRARY_PATH.
If you have a fork of one of the ansible module projects, do something like this::
ANSIBLE_LIBRARY=~/ansible-modules-core:~/ansible-modules-extras
And this will make the items in your fork be loaded ahead of what ships with Ansible. Just be sure
to make sure you're not reporting bugs on versions from your fork!
To be safe, if you're working on a variant on something in Ansible's normal distribution, it's not
a bad idea to give it a new name while you are working on it, to be sure you know you're pulling
your version.
Getting Your Module Into Ansible
````````````````````````````````
Getting Your Module Into Core
`````````````````````````````
High-quality modules with minimal dependencies
can be included in the ansible, but modules (just due to the programming
can be included in the core, but core modules (just due to the programming
preferences of the developers) will need to be implemented in Python and use
the AnsibleModule common code, and should generally use consistent arguments with the rest of
the program. Stop by the mailing list to inquire about requirements if you like, and submit
a github pull request to the `extras <https://github.com/ansible/ansible-modules-extras>`_ project.
Included modules will ship with ansible, and also have a change to be promoted to 'core' status, which
gives them slightly higher development priority (though they'll work in exactly the same way).
Deprecating and making module aliases
``````````````````````````````````````
Starting in 1.8 you can deprecate modules by renaming them with a preceeding _, i.e. old_cloud.py to
_old_cloud.py, This will keep the module available but hide it from the primary docs and listing.
You can also rename modules and keep an alias to the old name by using a symlink that starts with _.
This example allows the stat module to be called with fileinfo, making the following examples equivalent
EXAMPLES = '''
ln -s stat.py _fileinfo.py
ansible -m stat -a "path=/tmp" localhost
ansible -m fileinfo -a "path=/tmp" localhost
'''
a github pull request to the main project.
.. seealso::
@ -490,7 +446,7 @@ This example allows the stat module to be called with fileinfo, making the follo
Learn about developing plugins
:doc:`developing_api`
Learn about the Python API for playbook and task execution
`GitHub modules directory <https://github.com/ansible/ansible/tree/devel/library>`_
`Github modules directory <https://github.com/ansible/ansible/tree/devel/library>`_
Browse source of core modules
`Mailing List <http://groups.google.com/group/ansible-devel>`_
Development mailing list

View File

@ -88,7 +88,7 @@ and is guaranteed to entertain and/or annoy coworkers.
Configuring
+++++++++++
To activate a callback drop it in a callback directory as configured in :ref:`ansible.cfg <callback_plugins>`.
To active a callback drop it in a callback directory as configured in :ref:`ansible.cfg <callback_plugins>`.
.. _callback_development:
@ -96,7 +96,7 @@ Development
+++++++++++
More information will come later, though see the source of any of the existing callbacks and you should be able to get started quickly.
They should be reasonably self-explanatory.
They should be reasonably self explanatory.
.. _distributing_plugins:

View File

@ -1,185 +0,0 @@
Helping Testing PRs
```````````````````
If you're a developer, one of the most valuable things you can do is look at the github issues list and help fix bugs. We almost always prioritize bug fixing over
feature development, so clearing bugs out of the way is one of the best things you can do.
Even if you're not a developer, helping test pull requests for bug fixes and features is still immensely valuable.
This goes for testing new features as well as testing bugfixes.
In many cases, code should add tests that prove it works but that's not ALWAYS possible and tests are not always comprehensive, especially when a user doesn't have access
to a wide variety of platforms, or that is using an API or web service.
In these cases, live testing against real equipment can be more valuable than automation that runs against simulated interfaces.
In any case, things should always be tested manually the first time too.
Thankfully helping test ansible is pretty straightforward, assuming you are already used to how ansible works.
Get Started with A Source Checkout
++++++++++++++++++++++++++++++++++
You can do this by checking out ansible, making a test branch off the main one, merging a GitHub issue, testing,
and then commenting on that particular issue on GitHub. Here's how:
.. note::
Testing source code from GitHub pull requests sent to us does have some inherent risk, as the source code
sent may have mistakes or malicious code that could have a negative impact on your system. We recommend
doing all testing on a virtual machine, whether a cloud instance, or locally. Some users like Vagrant
or Docker for this, but they are optional. It is also useful to have virtual machines of different Linux or
other flavors, since some features (apt vs. yum, for example) are specific to those OS versions.
First, you will need to configure your testing environment with the neccessary tools required to run our test
suites. You will need at least::
git
python-nosetests (sometimes named python-nose)
python-passlib
If you want to run the full integration test suite you'll also need the following packages installed::
svn
hg
python-pip
gem
Second, if you haven't already, clone the Ansible source code from GitHub::
git clone https://github.com/ansible/ansible.git --recursive
cd ansible/
.. note::
If you have previously forked the repository on GitHub, you could also clone it from there.
.. note::
If updating your repo for testing something module related, use "git rebase origin/devel" and then "git submodule update" to fetch
the latest development versions of modules. Skipping the "git submodule update" step will result in versions that will be stale.
Activating The Source Checkout
++++++++++++++++++++++++++++++
The Ansible source includes a script that allows you to use Ansible directly from source without requiring a
full installation, that is frequently used by developers on Ansible.
Simply source it (to use the Linux/Unix terminology) to begin using it immediately::
source ./hacking/env-setup
This script modifies the PYTHONPATH enviromnent variables (along with a few other things), which will be temporarily
set as long as your shell session is open.
If you'd like your testing environment to always use the latest source, you could call the command from startup scripts (for example,
`.bash_profile`).
Finding A Pull Request and Checking It Out On A Branch
++++++++++++++++++++++++++++++++++++++++++++++++++++++
Next, find the pull request you'd like to test and make note of the line at the top which describes the source
and destination repositories. It will look something like this::
Someuser wants to merge 1 commit into ansible:devel from someuser:feature_branch_name
.. note::
It is important that the PR request target be ansible:devel, as we do not accept pull requests into any other branch.
Dot releases are cherry-picked manually by ansible staff.
The username and branch at the end are the important parts, which will be turned into git commands as follows::
git checkout -b testing_PRXXXX devel
git pull https://github.com/someuser/ansible.git feature_branch_name
The first command creates and switches to a new branch named testing_PRXXXX, where the XXXX is the actual issue number associated
with the pull request (for example, 1234). This branch is based on the devel branch. The second command pulls the new code from the
users feature branch into the newly created branch.
.. note::
If the GitHub user interface shows that the pull request will not merge cleanly, we do not recommend proceeding if you
are not somewhat familiar with git and coding, as you will have to resolve a merge conflict. This is the responsibility of
the original pull request contributor.
.. note::
Some users do not create feature branches, which can cause problems when they have multiple, un-related commits in
their version of `devel`. If the source looks like `someuser:devel`, make sure there is only one commit listed on
the pull request.
For Those About To Test, We Salute You
++++++++++++++++++++++++++++++++++++++
At this point, you should be ready to begin testing!
If the PR is a bug-fix pull request, the first things to do are to run the suite of unit and integration tests, to ensure
the pull request does not break current functionality::
# Unit Tests
make tests
# Integration Tests
cd test/integration
make
.. note::
Ansible does provide integration tests for cloud-based modules as well, however we do not recommend using them for some users
due to the associated costs from the cloud providers. As such, typically it's better to run specific parts of the integration battery
and skip these tests.
Integration tests aren't the end all beat all - in many cases what is fixed might not *HAVE* a test, so determining if it works means
checking the functionality of the system and making sure it does what it said it would do.
Pull requests for bug-fixes should reference the bug issue number they are fixing.
We encourage users to provide playbook examples for bugs that show how to reproduce the error, and these playbooks should be used to verify the bugfix does resolve
the issue if available. You may wish to also do your own review to poke the corners of the change.
Since some reproducers can be quite involved, you might wish to create a testing directory with the issue # as a sub-
directory to keep things organized::
mkdir -p testing/XXXX # where XXXX is again the issue # for the original issue or PR
cd testing/XXXX
<create files or git clone example playbook repo>
While it should go without saying, be sure to read any playbooks before you run them. VMs help with running untrusted content greatly,
though a playbook could still do something to your computing resources that you'd rather not like.
Once the files are in place, you can run the provided playbook (if there is one) to test the functionality::
ansible-playbook -vvv playbook_name.yml
If there's not a playbook, you may have to copy and paste playbook snippets or run a ad-hoc command that was pasted in.
Our issue template also included sections for "Expected Output" and "Actual Output", which should be used to gauge the output
from the provided examples.
If the pull request resolves the issue, please leave a comment on the pull request, showing the following information:
* "Works for me!"
* The output from `ansible --version`.
In some cases, you may wish to share playbook output from the test run as well.
Example!::
Works for me! Tested on `Ansible 1.7.1`. I verified this on CentOS 6.5 and also Ubuntu 14.04.
If the PR does not resolve the issue, or if you see any failures from the unit/integration tests, just include that output instead::
This doesn't work for me.
When I ran this my toaster started making loud noises!
Output from the toaster looked like this:
```
BLARG
StrackTrace
RRRARRGGG
```
When you are done testing a feature branch, you can remove it with the following command::
git branch -D someuser-feature_branch_name
We understand some users may be inexperienced with git, or other aspects of the above procedure, so feel free to stop by ansible-devel
list for questions and we'd be happy to help answer them.

View File

@ -81,7 +81,7 @@ What is the best way to make content reusable/redistributable?
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
If you have not done so already, read all about "Roles" in the playbooks documentation. This helps you make playbook content
self-contained, and works well with things like git submodules for sharing content with others.
self contained, and works will with things like git submodules for sharing content with others.
If some of these plugin types look strange to you, see the API documentation for more details about ways Ansible can be extended.
@ -140,16 +140,16 @@ Then you can use the facts inside your template, like this::
.. _programatic_access_to_a_variable:
How do I access a variable name programmatically?
+++++++++++++++++++++++++++++++++++++++++++++++++
How do I access a variable name programatically?
++++++++++++++++++++++++++++++++++++++++++++++++
An example may come up where we need to get the ipv4 address of an arbitrary interface, where the interface to be used may be supplied
via a role parameter or other input. Variable names can be built by adding strings together, like so::
{{ hostvars[inventory_hostname]['ansible_' + which_interface]['ipv4']['address'] }}
The trick about going through hostvars is necessary because it's a dictionary of the entire namespace of variables. 'inventory_hostname'
is a magic variable that indicates the current host you are looping over in the host loop.
The trick about going through hostvars is neccessary because it's a dictionary of the entire namespace of variables. 'inventory_hostname'
is a magic variable that indiciates the current host you are looping over in the host loop.
.. _first_host_in_a_group:
@ -179,7 +179,17 @@ Notice how we interchanged the bracket syntax for dots -- that can be done anywh
How do I copy files recursively onto a target host?
+++++++++++++++++++++++++++++++++++++++++++++++++++
The "copy" module has a recursive parameter, though if you want to do something more efficient for a large number of files, take a look at the "synchronize" module instead, which wraps rsync. See the module index for info on both of these modules.
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 passphrase or password.
.. _shell_env:
@ -217,14 +227,14 @@ password hashing library is installed.
Once the library is ready, SHA512 password values can then be generated as follows::
python -c "from passlib.hash import sha512_crypt; import getpass; print sha512_crypt.encrypt(getpass.getpass())"
python -c "from passlib.hash import sha512_crypt; print sha512_crypt.encrypt('<password>')"
.. _commercial_support:
Can I get training on Ansible or find commercial support?
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Yes! See `our Guru offering <http://www.ansible.com/ansible-guru>`_ for online support, and support is also included with :doc:`tower`. You can also read our `service page <http://www.ansible.com/ansible-services>`_ and email `info@ansible.com <mailto:info@ansible.com>`_ for further details.
Yes! See `our Guru offering <http://www.ansible.com/ansible-guru>_` for online support, and support is also included with :doc:`tower`. You can also read our `service page <http://www.ansible.com/ansible-services>`_ and email `info@ansible.com <mailto:info@ansible.com>`_ for further details.
.. _web_interface:
@ -239,33 +249,17 @@ and easy to use. See :doc:`tower`.
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/blob/devel/docsite/README.md>`_. Thanks!
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!
.. _keep_secret_data:
How do I keep secret data in my playbook?
+++++++++++++++++++++++++++++++++++++++++
If you would like to keep secret data in your Ansible content and still share it publicly or keep things in source control, see :doc:`playbooks_vault`.
If you would like to keep secret data in your Ansible content and still share it publically or keep things in source control, see :doc:`playbooks_vault`.
.. _i_dont_see_my_question:
In Ansible 1.8 and later, if you have a task that you don't want to show the results or command given to it when using -v (verbose) mode, the following task or playbook attribute can be useful::
- name: secret task
shell: /usr/bin/do_something --value={{ secret_value }}
no_log: True
This can be used to keep verbose output but hide sensitive information from others who would otherwise like to be able to see the output.
The no_log attribute can also apply to an entire play::
- hosts: all
no_log: True
Though this will make the play somewhat difficult to debug. It's recommended that this
be applied to single tasks only, once a playbook is completed.
I don't see my question here
++++++++++++++++++++++++++++
@ -279,7 +273,7 @@ Please see the section below for a link to IRC and the Google Group, where you c
An introduction to playbooks
:doc:`playbooks_best_practices`
Best practices advice
`User Mailing List <http://groups.google.com/group/ansible-project>`_
`User Mailing List <http://groups.google.com/group/ansible-devel>`_
Have a question? Stop by the google group!
`irc.freenode.net <http://irc.freenode.net>`_
#ansible IRC chat channel

View File

@ -1,106 +1,10 @@
Ansible Galaxy
++++++++++++++
``````````````
"Ansible Galaxy" can either refer to a website for sharing and downloading Ansible roles, or a command line tool that helps work with roles.
`Ansible Galaxy <http://galaxy.ansible.com>`_, is a free site for finding, downloading, rating, and reviewing all kinds of community developed Ansible roles and can be a great way to get a jumpstart on your automation projects.
.. contents:: Topics
The Website
```````````
The website `Ansible Galaxy <http://galaxy.ansible.com>`_, is a free site for finding, downloading, rating, and reviewing all kinds of community developed Ansible roles and can be a great way to get a jumpstart on your automation projects.
You can sign up with social auth, and use the download client 'ansible-galaxy' is included in Ansible 1.4.2 and later.
You can sign up with social auth, and the download client 'ansible-galaxy' is included in Ansible 1.4.2 and later.
Read the "About" page on the Galaxy site for more information.
The ansible-galaxy command line tool
````````````````````````````````````
The command line ansible-galaxy has many different subcommands.
Installing Roles
----------------
The most obvious is downloading roles from the Ansible Galaxy website::
ansible-galaxy install username.rolename
Building out Role Scaffolding
-----------------------------
It can also be used to initialize the base structure of a new role, saving time on creating the various directories and main.yml files a role requires::
ansible-galaxy init rolename
Installing Multiple Roles From A File
-------------------------------------
To install multiple roles, the ansible-galaxy CLI can be fed a requirements file. All versions of ansible allow the following syntax for installing roles from the Ansible Galaxy website::
ansible-galaxy install -r requirements.txt
Where the requirements.txt looks like::
username1.foo_role
username2.bar_role
To request specific versions (tags) of a role, use this syntax in the roles file::
username1.foo_role,version
username2.bar_role,version
Available versions will be listed on the Ansible Galaxy webpage for that role.
Advanced Control over Role Requirements Files
---------------------------------------------
For more advanced control over where to download roles from, including support for remote repositories, Ansible 1.8 and later support a new YAML format for the role requirements file, which must end in a 'yml' extension. It works like this::
ansible-galaxy install -r requirements.yml
The extension is important. If the .yml extension is left off, the ansible-galaxy CLI will assume the file is in the "basic" format and will be confused.
And here's an example showing some specific version downloads from multiple sources. In one of the examples we also override the name of the role and download it as something different::
# from galaxy
- src: yatesr.timezone
# from github
- src: https://github.com/bennojoy/nginx
# from github installing to a relative path
- src: https://github.com/bennojoy/nginx
path: vagrant/roles/
# from github, overriding the name and specifying a specific tag
- src: https://github.com/bennojoy/nginx
version: master
name: nginx_role
# from a webserver, where the role is packaged in a tar.gz
- src: https://some.webserver.example.com/files/master.tar.gz
name: http-role
# from bitbucket, if bitbucket happens to be operational right now :)
- src: git+http://bitbucket.org/willthames/git-ansible-galaxy
version: v1.4
# from bitbucket, alternative syntax and caveats
- src: http://bitbucket.org/willthames/hg-ansible-galaxy
scm: hg
As you can see in the above, there are a large amount of controls available
to customize where roles can be pulled from, and what to save roles as.
Roles pulled from galaxy work as with other SCM sourced roles above. To download a role with dependencies, and automatically install those dependencies, the role must be uploaded to the Ansible Galaxy website.
.. seealso::
:doc:`playbooks_roles`
All about ansible roles
`Mailing List <http://groups.google.com/group/ansible-project>`_
Questions? Help? Ideas? Stop by the list on Google Groups
`irc.freenode.net <http://irc.freenode.net>`_
#ansible IRC chat channel

View File

@ -410,7 +410,7 @@ 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 languages (Python, Perl, Ruby, etc.).
for serialization in many different languages (Python, Perl, Ruby, etc.).
.. seealso::

View File

@ -129,7 +129,7 @@ it will be automatically discoverable via a dynamic group like so::
- ping
Using this philosophy can be a great way to manage groups dynamically, without
having to maintain separate inventory.
having to maintain seperate inventory.
.. _aws_pull:
@ -266,12 +266,12 @@ Example 4
- debug: var=hostvars[inventory_hostname]
# just show the instance-id
- debug: msg="{{ hostvars[inventory_hostname]['ansible_ec2_instance_id'] }}"
- debug: msg="{{ hostvars[inventory_hostname]['ansible_ec2_instance-id'] }}"
# Using the instanceid, call the ec2 module
# locally to remove the instance by declaring
# its state is "absent"
# it's state is "absent"
- hosts: ec2hosts
gather_facts: True
@ -288,7 +288,7 @@ Example 4
region={{ region }}
instance_ids={{ item }}
wait=true
with_items: hostvars[inventory_hostname]['ansible_ec2_instance_id']
with_items: hostvars[inventory_hostname]['ansible_ec2_instance-id']
.. note:: more examples of this are pending. You may also be interested in the ec2_ami module for taking AMIs of running instances.
@ -309,7 +309,7 @@ In the future look here for more topics.
An introduction to playbooks
:doc:`playbooks_delegation`
Delegation, useful for working with loud balancers, clouds, and locally executed steps.
`User Mailing List <http://groups.google.com/group/ansible-project>`_
`User Mailing List <http://groups.google.com/group/ansible-devel>`_
Have a question? Stop by the google group!
`irc.freenode.net <http://irc.freenode.net>`_
#ansible IRC chat channel

View File

@ -1,248 +0,0 @@
Google Cloud Platform Guide
===========================
.. gce_intro:
Introduction
------------
.. note:: This section of the documentation is under construction. We are in the process of adding more examples about all of the GCE modules and how they work together. Upgrades via github pull requests are welcomed!
Ansible contains modules for managing Google Compute Engine resources, including creating instances, controlling network access, working with persistent disks, and managing
load balancers. Additionally, there is an inventory plugin that can automatically suck down all of your GCE instances into Ansible dynamic inventory, and create groups by tag and other properties.
The GCE modules all require the apache-libcloud module, which you can install from pip:
.. code-block:: bash
$ pip install apache-libcloud
.. note:: If you're using Ansible on Mac OS X, libcloud also needs to access a CA cert chain. You'll need to download one (you can get one for `here <http://curl.haxx.se/docs/caextract.html>`_.)
Credentials
-----------
To work with the GCE modules, you'll first need to get some credentials. You can create new one from the `console <https://console.developers.google.com/>`_ by going to the "APIs and Auth" section and choosing to create a new client ID for a service account. Once you've created a new client ID and downloaded the generated private key (in the `pkcs12 format <http://en.wikipedia.org/wiki/PKCS_12>`_), you'll need to convert the key by running the following command:
.. code-block:: bash
$ openssl pkcs12 -in pkey.pkcs12 -passin pass:notasecret -nodes -nocerts | openssl rsa -out pkey.pem
There are two different ways to provide credentials to Ansible so that it can talk with Google Cloud for provisioning and configuration actions:
* by providing to the modules directly
* by populating a ``secrets.py`` file
Calling Modules By Passing Credentials
``````````````````````````````````````
For the GCE modules you can specify the credentials as arguments:
* ``service_account_email``: email associated with the project
* ``pem_file``: path to the pem file
* ``project_id``: id of the project
For example, to create a new instance using the cloud module, you can use the following configuration:
.. code-block:: yaml
- name: Create instance(s)
hosts: localhost
connection: local
gather_facts: no
vars:
service_account_email: unique-id@developer.gserviceaccount.com
pem_file: /path/to/project.pem
project_id: project-id
machine_type: n1-standard-1
image: debian-7
tasks:
- name: Launch instances
gce:
instance_names: dev
machine_type: "{{ machine_type }}"
image: "{{ image }}"
service_account_email: "{{ service_account_email }}"
pem_file: "{{ pem_file }}"
project_id: "{{ project_id }}"
Calling Modules with secrets.py
```````````````````````````````
Create a file ``secrets.py`` looking like following, and put it in some folder which is in your ``$PYTHONPATH``:
.. code-block:: python
GCE_PARAMS = ('i...@project.googleusercontent.com', '/path/to/project.pem')
GCE_KEYWORD_PARAMS = {'project': 'project-name'}
Now the modules can be used as above, but the account information can be omitted.
GCE Dynamic Inventory
---------------------
The best way to interact with your hosts is to use the gce inventory plugin, which dynamically queries GCE and tells Ansible what nodes can be managed.
Note that when using the inventory script ``gce.py``, you also need to populate the ``gce.ini`` file that you can find in the plugins/inventory directory of the ansible checkout.
To use the GCE dynamic inventory script, copy ``gce.py`` from ``plugins/inventory`` into your inventory directory and make it executable. You can specify credentials for ``gce.py`` using the ``GCE_INI_PATH`` environment variable -- the default is to look for gce.ini in the same directory as the inventory script.
Let's see if inventory is working:
.. code-block:: bash
$ ./gce.py --list
You should see output describing the hosts you have, if any, running in Google Compute Engine.
Now let's see if we can use the inventory script to talk to Google.
.. code-block:: bash
$ GCE_INI_PATH=~/.gce.ini ansible all -i gce.py -m setup
hostname | success >> {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"x.x.x.x"
],
As with all dynamic inventory plugins in Ansible, you can configure the inventory path in ansible.cfg. The recommended way to use the inventory is to create an ``inventory`` directory, and place both the ``gce.py`` script and a file containing ``localhost`` in it. This can allow for cloud inventory to be used alongside local inventory (such as a physical datacenter) or machines running in different providers.
Executing ``ansible`` or ``ansible-playbook`` and specifying the ``inventory`` directory instead of an individual file will cause ansible to evaluate each file in that directory for inventory.
Let's once again use our inventory script to see if it can talk to Google Cloud:
.. code-block:: bash
$ ansible all -i inventory/ -m setup
hostname | success >> {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"x.x.x.x"
],
The output should be similar to the previous command. If you're wanting less output and just want to check for SSH connectivity, use "-m" ping instead.
Use Cases
---------
For the following use case, let's use this small shell script as a wrapper.
.. code-block:: bash
#!/bin/bash
PLAYBOOK="$1"
if [[ -z $PLAYBOOK ]]; then
echo "You need to pass a playbook as argument to this script."
exit 1
fi
export SSL_CERT_FILE=$(pwd)/cacert.cer
export ANSIBLE_HOST_KEY_CHECKING=False
if [[ ! -f "$SSL_CERT_FILE" ]]; then
curl -O http://curl.haxx.se/ca/cacert.pem
fi
ansible-playbook -v -i inventory/ "$PLAYBOOK"
Create an instance
``````````````````
The GCE module provides the ability to provision instances within Google Compute Engine. The provisioning task is typically performed from your Ansible control server against Google Cloud's API.
A playbook would looks like this:
.. code-block:: yaml
- name: Create instance(s)
hosts: localhost
gather_facts: no
connection: local
vars:
machine_type: n1-standard-1 # default
image: debian-7
service_account_email: unique-id@developer.gserviceaccount.com
pem_file: /path/to/project.pem
project_id: project-id
tasks:
- name: Launch instances
gce:
instance_names: dev
machine_type: "{{ machine_type }}"
image: "{{ image }}"
service_account_email: "{{ service_account_email }}"
pem_file: "{{ pem_file }}"
project_id: "{{ project_id }}"
tags: webserver
register: gce
- name: Wait for SSH to come up
wait_for: host={{ item.public_ip }} port=22 delay=10 timeout=60
with_items: gce.instance_data
- name: Add host to groupname
add_host: hostname={{ item.public_ip }} groupname=new_instances
with_items: gce.instance_data
- name: Manage new instances
hosts: new_instances
connection: ssh
sudo: True
roles:
- base_configuration
- production_server
Note that use of the "add_host" module above creates a temporary, in-memory group. This means that a play in the same playbook can then manage machines
in the 'new_instances' group, if so desired. Any sort of arbitrary configuration is possible at this point.
Configuring instances in a group
````````````````````````````````
All of the created instances in GCE are grouped by tag. Since this is a cloud, it's probably best to ignore hostnames and just focus on group management.
Normally we'd also use roles here, but the following example is a simple one. Here we will also use the "gce_net" module to open up access to port 80 on
these nodes.
The variables in the 'vars' section could also be kept in a 'vars_files' file or something encrypted with Ansible-vault, if you so choose. This is just
a basic example of what is possible::
- name: Setup web servers
hosts: tag_webserver
gather_facts: no
vars:
machine_type: n1-standard-1 # default
image: debian-7
service_account_email: unique-id@developer.gserviceaccount.com
pem_file: /path/to/project.pem
project_id: project-id
roles:
- name: Install lighttpd
apt: pkg=lighttpd state=installed
sudo: True
- name: Allow HTTP
local_action: gce_net
args:
fwname: "all-http"
name: "default"
allowed: "tcp:80"
state: "present"
service_account_email: "{{ service_account_email }}"
pem_file: "{{ pem_file }}"
project_id: "{{ project_id }}"
By pointing your browser to the IP of the server, you should see a page welcoming you.
Upgrades to this documentation are welcome, hit the github link at the top right of this page if you would like to make additions!

View File

@ -11,7 +11,7 @@ Introduction
Ansible contains a number of core modules for interacting with Rackspace Cloud.
The purpose of this section is to explain how to put Ansible modules together
(and use inventory scripts) to use Ansible in a Rackspace Cloud context.
(and use inventory scripts) to use Ansible in Rackspace Cloud context.
Prerequisites for using the rax modules are minimal. In addition to ansible itself,
all of the modules require and are tested against pyrax 1.5 or higher.
@ -32,7 +32,7 @@ to add localhost to the inventory file. (Ansible may not require this manual st
[localhost]
localhost ansible_connection=local
In playbook steps, we'll typically be using the following pattern:
In playbook steps we'll typically be using the following pattern:
.. code-block:: yaml
@ -66,19 +66,21 @@ https://github.com/rackspace/pyrax/blob/master/docs/getting_started.md#authentic
Running from a Python Virtual Environment (Optional)
++++++++++++++++++++++++++++++++++++++++++++++++++++
Most users will not be using virtualenv, but some users, particularly Python developers sometimes like to.
Special considerations need to
be taken if pyrax is not installed globally but instead using a python virtualenv (it's fine if you install it globally).
There are special considerations when Ansible is installed to a Python virtualenv, rather than the default of installing at a global scope. Ansible assumes, unless otherwise instructed, that the python binary will live at /usr/bin/python. This is done via the interpreter line in modules, however when instructed by setting the inventory variable 'ansible_python_interpreter', Ansible will use this specified path instead to find Python. This can be a cause of confusion as one may assume that modules running on 'localhost', or perhaps running via 'local_action', are using the virtualenv Python interpreter. By setting this line in the inventory, the modules will execute in the virtualenv interpreter and have available the virtualenv packages, specifically pyrax. If using virtualenv, you may wish to modify your localhost inventory definition to find this location as follows:
Ansible assumes, unless otherwise instructed, that the python binary will live at
/usr/bin/python. This is done so via the interpret line in the modules, however
when instructed using ansible_python_interpreter, ansible will use this specified path instead for finding
python.
If using virtualenv, you may wish to modify your localhost inventory definition to find this location as follows:
.. code-block:: ini
[localhost]
localhost ansible_connection=local ansible_python_interpreter=/path/to/ansible_venv/bin/python
.. note::
pyrax may be installed in the global Python package scope or in a virtual environment. There are no special considerations to keep in mind when installing pyrax.
.. _provisioning:
Provisioning
@ -86,20 +88,16 @@ Provisioning
Now for the fun parts.
The 'rax' module provides the ability to provision instances within Rackspace Cloud. Typically the provisioning task will be performed from your Ansible control server (in our example, localhost) against the Rackspace cloud API. This is done for several reasons:
- Avoiding installing the pyrax library on remote nodes
- No need to encrypt and distribute credentials to remote nodes
- Speed and simplicity
The 'rax' module provides the ability to provision instances within Rackspace Cloud. Typically the
provisioning task will be performed from your Ansible control server against the Rackspace cloud API.
.. note::
Authentication with the Rackspace-related modules is handled by either
specifying your username and API key as environment variables or passing
them as module arguments, or by specifying the location of a credentials
file.
them as module arguments.
Here is a basic example of provisioning an instance in ad-hoc mode:
Here is a basic example of provisioning a instance in ad-hoc mode:
.. code-block:: bash
@ -121,9 +119,8 @@ Here's what it would look like in a playbook, assuming the parameters were defin
wait: yes
register: rax
The rax module returns data about the nodes it creates, like IP addresses, hostnames, and login passwords. By registering the return value of the step, it is possible used this data to dynamically add the resulting hosts to inventory (temporarily, in memory). This facilitates performing configuration actions on the hosts in a follow-on task. In the following example, the servers that were successfully created using the above task are dynamically added to a group called "raxhosts", with each nodes hostname, IP address, and root password being added to the inventory.
.. code-block:: yaml
By registering the return value of the step, it is then possible to dynamically add the resulting hosts to inventory (temporarily, in memory).
This facilitates performing configuration actions on the hosts immediately in a subsequent task::
- name: Add the instances we created (by public IP) to the group 'raxhosts'
local_action:
@ -135,9 +132,7 @@ The rax module returns data about the nodes it creates, like IP addresses, hostn
with_items: rax.success
when: rax.action == 'create'
With the host group now created, the next play in this playbook could now configure servers belonging to the raxhosts group.
.. code-block:: yaml
With the host group now created, a second play in your provision playbook could now configure them, for example::
- name: Configuration play
hosts: raxhosts
@ -146,6 +141,7 @@ With the host group now created, the next play in this playbook could now config
- ntp
- webserver
The method above ties the configuration of a host with the provisioning step. This isn't always what you want, and leads us
to the next section.
@ -154,28 +150,41 @@ to the next section.
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 "rax" inventory plugin, which dynamically queries Rackspace Cloud and tells Ansible what nodes you have to manage. You might want to use this even if you are spinning up Ansible via other tools, including the Rackspace Cloud user interface. The inventory plugin can be used to group resources by metadata, region, OS, etc. Utilizing metadata is highly recommended in "rax" and can provide an easy way to sort between host groups and roles. If you don't want to use the ``rax.py`` dynamic inventory script, you could also still choose to manually manage your INI inventory file, though this is less recommended.
Once your nodes are spun up, you'll probably want to talk to them again.
In Ansible it is quite possible to use multiple dynamic inventory plugins along with INI file data. Just put them in a common directory and be sure the scripts are chmod +x, and the INI-based ones are not.
The best way to handle his is to use the rax inventory plugin, which dynamically queries Rackspace Cloud and tells Ansible what
nodes you have to manage.
You might want to use this even if you are spinning up Ansible via other tools, including the Rackspace Cloud user interface.
The inventory plugin can be used to group resources by their meta data. Utilizing meta data is highly
recommended in rax and can provide an easy way to sort between host groups and roles.
If you don't want to use the ``rax.py`` dynamic inventory script, you could also still choose to manually manage your INI inventory file,
though this is less recommended.
In Ansible it is quite possible to use multiple dynamic inventory plugins along with INI file data. Just put them in a common
directory and be sure the scripts are chmod +x, and the INI-based ones are not.
.. _raxpy:
rax.py
++++++
To use the rackspace dynamic inventory script, copy ``rax.py`` into your inventory directory and make it executable. You can specify a credentails file for ``rax.py`` utilizing the ``RAX_CREDS_FILE`` environment variable.
.. note:: Dynamic inventory scripts (like ``rax.py``) are saved in ``/usr/share/ansible/inventory`` if Ansible has been installed globally. If installed to a virtualenv, the inventory scripts are installed to ``$VIRTUALENV/share/inventory``.
To use the rackspace dynamic inventory script, copy ``rax.py`` from ``plugins/inventory`` into your inventory directory and make it executable. You can specify credentials for ``rax.py`` utilizing the ``RAX_CREDS_FILE`` environment variable.
.. note:: Users of :doc:`tower` will note that dynamic inventory is natively supported by Tower, and all you have to do is associate a group with your Rackspace Cloud credentials, and it will easily synchronize without going through these steps::
$ RAX_CREDS_FILE=~/.raxpub ansible all -i rax.py -m setup
``rax.py`` also accepts a ``RAX_REGION`` environment variable, which can contain an individual region, or a comma separated list of regions.
``rax.py`` also accepts a ``RAX_REGION`` environment variable, which can contain an individual region, or a
comma separated list of regions.
When using ``rax.py``, you will not have a 'localhost' defined in the inventory.
As mentioned previously, you will often be running most of these modules outside of the host loop, and will need 'localhost' defined. The recommended way to do this, would be to create an ``inventory`` directory, and place both the ``rax.py`` script and a file containing ``localhost`` in it.
As mentioned previously, you will often be running most of these modules outside of the host loop,
and will need 'localhost' defined. The recommended way to do this, would be to create an ``inventory`` directory,
and place both the ``rax.py`` script and a file containing ``localhost`` in it.
Executing ``ansible`` or ``ansible-playbook`` and specifying the ``inventory`` directory instead
of an individual file, will cause ansible to evaluate each file in that directory for inventory.
@ -286,7 +295,8 @@ following information, which will be utilized for inventory and variables.
Standard Inventory
++++++++++++++++++
When utilizing a standard ini formatted inventory file (as opposed to the inventory plugin), it may still be advantageous to retrieve discoverable hostvar information from the Rackspace API.
When utilizing a standard ini formatted inventory file (as opposed to the inventory plugin),
it may still be adventageous to retrieve discoverable hostvar information from the Rackspace API.
This can be achieved with the ``rax_facts`` module and an inventory file similar to the following:
@ -407,10 +417,10 @@ Use Cases
This section covers some additional usage examples built around a specific use case.
.. _network_and_server:
.. _example_1:
Network and Server
++++++++++++++++++
Example 1
+++++++++
Create an isolated cloud network and build a server
@ -450,10 +460,10 @@ Create an isolated cloud network and build a server
wait_timeout: 360
register: rax
.. _complete_environment:
.. _example_2:
Complete Environment
++++++++++++++++++++
Example 2
+++++++++
Build a complete webserver environment with servers, custom networks and load balancers, install nginx and create a custom index.html
@ -556,221 +566,6 @@ Build a complete webserver environment with servers, custom networks and load ba
copy: content="{{ inventory_hostname }}" dest=/usr/share/nginx/www/index.html
owner=root group=root mode=0644
.. _rackconnect_and_manged_cloud:
RackConnect and Managed Cloud
+++++++++++++++++++++++++++++
When using RackConnect version 2 or Rackspace Managed Cloud there are Rackspace automation tasks that are executed on the servers you create after they are successfully built. If your automation executes before the RackConnect or Managed Cloud automation, you can cause failures and un-usable servers.
These examples show creating servers, and ensuring that the Rackspace automation has completed before Ansible continues onwards.
For simplicity, these examples are joined, however both are only needed when using RackConnect. When only using Managed Cloud, the RackConnect portion can be ignored.
The RackConnect portions only apply to RackConnect version 2.
.. _using_a_control_machine:
Using a Control Machine
***********************
.. code-block:: yaml
- name: Create an exact count of servers
hosts: localhost
connection: local
gather_facts: False
tasks:
- name: Server build requests
local_action:
module: rax
credentials: ~/.raxpub
name: web%03d.example.org
flavor: performance1-1
image: ubuntu-1204-lts-precise-pangolin
disk_config: manual
region: DFW
state: present
count: 1
exact_count: yes
group: web
wait: yes
register: rax
- name: Add servers to in memory groups
local_action:
module: add_host
hostname: "{{ item.name }}"
ansible_ssh_host: "{{ item.rax_accessipv4 }}"
ansible_ssh_pass: "{{ item.rax_adminpass }}"
ansible_ssh_user: root
rax_id: "{{ item.rax_id }}"
groups: web,new_web
with_items: rax.success
when: rax.action == 'create'
- name: Wait for rackconnect and managed cloud automation to complete
hosts: new_web
gather_facts: false
tasks:
- name: Wait for rackconnnect automation to complete
local_action:
module: rax_facts
credentials: ~/.raxpub
id: "{{ rax_id }}"
region: DFW
register: rax_facts
until: rax_facts.ansible_facts['rax_metadata']['rackconnect_automation_status']|default('') == 'DEPLOYED'
retries: 30
delay: 10
- name: Wait for managed cloud automation to complete
local_action:
module: rax_facts
credentials: ~/.raxpub
id: "{{ rax_id }}"
region: DFW
register: rax_facts
until: rax_facts.ansible_facts['rax_metadata']['rax_service_level_automation']|default('') == 'Complete'
retries: 30
delay: 10
- name: Base Configure Servers
hosts: web
roles:
- role: users
- role: openssh
opensshd_PermitRootLogin: "no"
- role: ntp
.. _using_ansible_pull:
Using Ansible Pull
******************
.. code-block:: yaml
---
- name: Ensure Rackconnect and Managed Cloud Automation is complete
hosts: all
connection: local
tasks:
- name: Check for completed bootstrap
stat:
path: /etc/bootstrap_complete
register: bootstrap
- name: Get region
command: xenstore-read vm-data/provider_data/region
register: rax_region
when: bootstrap.stat.exists != True
- name: Wait for rackconnect automation to complete
uri:
url: "https://{{ rax_region.stdout|trim }}.api.rackconnect.rackspace.com/v1/automation_status?format=json"
return_content: yes
register: automation_status
when: bootstrap.stat.exists != True
until: automation_status['automation_status']|default('') == 'DEPLOYED'
retries: 30
delay: 10
- name: Wait for managed cloud automation to complete
wait_for:
path: /tmp/rs_managed_cloud_automation_complete
delay: 10
when: bootstrap.stat.exists != True
- name: Set bootstrap completed
file:
path: /etc/bootstrap_complete
state: touch
owner: root
group: root
mode: 0400
- name: Base Configure Servers
hosts: all
connection: local
roles:
- role: users
- role: openssh
opensshd_PermitRootLogin: "no"
- role: ntp
.. _using_ansible_pull_with_xenstore:
Using Ansible Pull with XenStore
********************************
.. code-block:: yaml
---
- name: Ensure Rackconnect and Managed Cloud Automation is complete
hosts: all
connection: local
tasks:
- name: Check for completed bootstrap
stat:
path: /etc/bootstrap_complete
register: bootstrap
- name: Wait for rackconnect_automation_status xenstore key to exist
command: xenstore-exists vm-data/user-metadata/rackconnect_automation_status
register: rcas_exists
when: bootstrap.stat.exists != True
failed_when: rcas_exists.rc|int > 1
until: rcas_exists.rc|int == 0
retries: 30
delay: 10
- name: Wait for rackconnect automation to complete
command: xenstore-read vm-data/user-metadata/rackconnect_automation_status
register: rcas
when: bootstrap.stat.exists != True
until: rcas.stdout|replace('"', '') == 'DEPLOYED'
retries: 30
delay: 10
- name: Wait for rax_service_level_automation xenstore key to exist
command: xenstore-exists vm-data/user-metadata/rax_service_level_automation
register: rsla_exists
when: bootstrap.stat.exists != True
failed_when: rsla_exists.rc|int > 1
until: rsla_exists.rc|int == 0
retries: 30
delay: 10
- name: Wait for managed cloud automation to complete
command: xenstore-read vm-data/user-metadata/rackconnect_automation_status
register: rsla
when: bootstrap.stat.exists != True
until: rsla.stdout|replace('"', '') == 'DEPLOYED'
retries: 30
delay: 10
- name: Set bootstrap completed
file:
path: /etc/bootstrap_complete
state: touch
owner: root
group: root
mode: 0400
- name: Base Configure Servers
hosts: all
connection: local
roles:
- role: users
- role: openssh
opensshd_PermitRootLogin: "no"
- role: ntp
.. _advanced_usage:
@ -784,7 +579,7 @@ Autoscaling with Tower
:doc:`tower` also contains a very nice feature for auto-scaling use cases.
In this mode, a simple curl script can call a defined URL and the server will "dial out" to the requester
and configure an instance that is spinning up. This can be a great way to reconfigure ephemeral nodes.
and configure an instance that is spinning up. This can be a great way to reconfigure ephmeral nodes.
See the Tower documentation for more details.
A benefit of using the callback in Tower over pull mode is that job results are still centrally recorded
@ -792,16 +587,9 @@ and less information has to be shared with remote hosts.
.. _pending_information:
Orchestration in the Rackspace Cloud
++++++++++++++++++++++++++++++++++++
Ansible is a powerful orchestration tool, and rax modules allow you the opportunity to orchestrate complex tasks, deployments, and configurations. The key here is to automate provisioning of infrastructure, like any other piece of software in an environment. Complex deployments might have previously required manual manipulation of load balancers, or manual provisioning of servers. Utilizing the rax modules included with Ansible, one can make the deployment of additional nodes contingent on the current number of running nodes, or the configuration of a clustered application dependent on the number of nodes with common metadata. One could automate the following scenarios, for example:
* Servers that are removed from a Cloud Load Balancer one-by-one, updated, verified, and returned to the load balancer pool
* Expansion of an already-online environment, where nodes are provisioned, bootstrapped, configured, and software installed
* A procedure where app log files are uploaded to a central location, like Cloud Files, before a node is decommissioned
* Servers and load balancers that have DNS records created and destroyed on creation and decommissioning, respectively
Pending Information
```````````````````
More to come!

View File

@ -172,7 +172,7 @@ Here's another example, from the same template::
{% endfor %}
This loops over all of the hosts in the group called ``monitoring``, and adds an ACCEPT line for
each monitoring hosts' default IPV4 address to the current machine's iptables configuration, so that Nagios can monitor those hosts.
each monitoring hosts's default IPV4 address to the current machine's iptables configuration, so that Nagios can monitor those hosts.
You can learn a lot more about Jinja2 and its capabilities `here <http://jinja.pocoo.org/docs/>`_, and you
can read more about Ansible variables in general in the :doc:`playbooks_variables` section.
@ -184,7 +184,7 @@ The Rolling Upgrade
Now you have a fully-deployed site with web servers, a load balancer, and monitoring. How do you update it? This is where Ansible's
orchestration features come into play. While some applications use the term 'orchestration' to mean basic ordering or command-blasting, Ansible
refers to orchestration as 'conducting machines like an orchestra', and has a pretty sophisticated engine for it.
referes to orchestration as 'conducting machines like an orchestra', and has a pretty sophisticated engine for it.
Ansible has the capability to do operations on multi-tier applications in a coordinated way, making it easy to orchestrate a sophisticated zero-downtime rolling upgrade of our web application. This is implemented in a separate playbook, called ``rolling_upgrade.yml``.
@ -201,18 +201,18 @@ The next part is the update play. The first part looks like this::
user: root
serial: 1
This is just a normal play definition, operating on the ``webservers`` group. The ``serial`` keyword tells Ansible how many servers to operate on at once. If it's not specified, Ansible will parallelize these operations up to the default "forks" limit specified in the configuration file. But for a zero-downtime rolling upgrade, you may not want to operate on that many hosts at once. If you had just a handful of webservers, you may want to set ``serial`` to 1, for one host at a time. If you have 100, maybe you could set ``serial`` to 10, for ten at a time.
This is just a normal play definition, operating on the ``webservers`` group. The ``serial`` keyword tells Ansible how many servers to operate on at once. If it's not specified, Ansible will paralleize these operations up to the default "forks" limit specified in the configuration file. But for a zero-downtime rolling upgrade, you may not want to operate on that many hosts at once. If you had just a handful of webservers, you may want to set ``serial`` to 1, for one host at a time. If you have 100, maybe you could set ``serial`` to 10, for ten at a time.
Here is the next part of the update play::
pre_tasks:
- name: disable nagios alerts for this host webserver service
nagios: action=disable_alerts host={{ inventory_hostname }} services=webserver
nagios: action=disable_alerts host={{ ansible_hostname }} services=webserver
delegate_to: "{{ item }}"
with_items: groups.monitoring
- name: disable the server in haproxy
shell: echo "disable server myapplb/{{ inventory_hostname }}" | socat stdio /var/lib/haproxy/stats
shell: echo "disable server myapplb/{{ ansible_hostname }}" | socat stdio /var/lib/haproxy/stats
delegate_to: "{{ item }}"
with_items: groups.lbservers
@ -233,12 +233,12 @@ Finally, in the ``post_tasks`` section, we reverse the changes to the Nagios con
post_tasks:
- name: Enable the server in haproxy
shell: echo "enable server myapplb/{{ inventory_hostname }}" | socat stdio /var/lib/haproxy/stats
shell: echo "enable server myapplb/{{ ansible_hostname }}" | socat stdio /var/lib/haproxy/stats
delegate_to: "{{ item }}"
with_items: groups.lbservers
- name: re-enable nagios alerts
nagios: action=enable_alerts host={{ inventory_hostname }} services=webserver
nagios: action=enable_alerts host={{ ansible_hostname }} services=webserver
delegate_to: "{{ item }}"
with_items: groups.monitoring

View File

@ -7,13 +7,13 @@ Introduction
````````````
Vagrant is a tool to manage virtual machine environments, and allows you to
configure and use reproducible work environments on top of various
configure and use reproducable work environments on top of various
virtualization and cloud platforms. It also has integration with Ansible as a
provisioner for these virtual machines, and the two tools work together well.
This guide will describe how to use Vagrant and Ansible together.
If you're not familiar with Vagrant, you should visit `the documentation
If you're not familar with Vagrant, you should visit `the documentation
<http://docs.vagrantup.com/v2/>`_.
This guide assumes that you already have Ansible installed and working.
@ -93,8 +93,8 @@ Sometimes you may want to run Ansible manually against the machines. This is
pretty easy to do.
Vagrant automatically creates an inventory file for each Vagrant machine in
the same directory located under ``.vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory``.
It configures the inventory file according to the SSH tunnel that Vagrant
the same directory called ``vagrant_ansible_inventory_machinename``. It
configures the inventory file according to the SSH tunnel that Vagrant
automatically creates, and executes ``ansible-playbook`` with the correct
username and SSH key options to allow access. A typical automatically-created
inventory file may look something like this:
@ -114,7 +114,7 @@ Here is an example:
.. code-block:: bash
$ ansible-playbook -i .vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory --private-key=~/.vagrant.d/insecure_private_key -u vagrant playbook.yml
$ ansible-playbook -i vagrant_ansible_inventory_machinename --private-key=~/.vagrant.d/insecure_private_key -u vagrant playbook.yml
.. seealso::

View File

@ -8,10 +8,8 @@ This section is new and evolving. The idea here is explore particular use cases
guide_aws
guide_rax
guide_gce
guide_vagrant
guide_rolling_upgrade
test_strategies
Pending topics may include: Docker, Jenkins, Google Compute Engine, Linode/DigitalOcean, Continuous Deployment, and more.
Pending topics may include: Docker, Jenkins, Google Compute Engine, Linode/Digital Ocean, Continous Deployment, and more.

10
docsite/rst/guru.rst Normal file
View File

@ -0,0 +1,10 @@
Ansible Guru
````````````
While many users should be able to get on fine with the documentation, mailing list, and IRC, sometimes you want a bit more.
`Ansible Guru <http://ansible.com/ansible-guru>`_ is an offering from Ansible, Inc that helps users who would like more dedicated help with Ansible, including building playbooks, best practices, architecture suggestions, and more -- all from our awesome support and services team. It also includes some useful discounts and also some free T-shirts, though you shoudn't get it just for the free shirts! It's a great way to train up to becoming an Ansible expert.
For those interested, click through the link above. You can sign up in minutes!
For users looking for more hands-on help, we also have some more information on our `Services page <http://www.ansible.com/ansible-services>`_, and support is also included with :doc:`tower`.

View File

@ -16,7 +16,7 @@ We believe simplicity is relevant to all sizes of environments and design for bu
Ansible manages machines in an agentless manner. There is never a question of how to
upgrade remote daemons or the problem of not being able to manage systems because daemons are uninstalled. As OpenSSH is one of the most peer reviewed open source components, the security exposure of using the tool is greatly reduced. Ansible is decentralized -- it relies on your existing OS credentials to control access to remote machines; if needed it can easily connect with Kerberos, LDAP, and other centralized authentication management systems.
This documentation covers the current released version of Ansible (1.7.2) and also some development version features (1.8). For recent features, in each section, the version of Ansible where the feature is added is indicated. Ansible, Inc releases a new major release of Ansible approximately every 2 months. The core application evolves somewhat conservatively, valuing simplicity in language design and setup, while the community around new modules and plugins being developed and contributed moves very very quickly, typically adding 20 or so new modules in each release.
This documentation covers the current released version of Ansible (1.5.1) and also some development version features (1.6.0). For recent features, in each section, the version of Ansible where the feature is added is indicated. Ansible, Inc releases a new major release of Ansible approximately every 2 months. The core application evolves somewhat conservatively, valuing simplicity in language design and setup, while the community around new modules and plugins being developed and contributed moves very very quickly, typically adding 20 or so new modules in each release.
.. _an_introduction:
@ -34,8 +34,8 @@ This documentation covers the current released version of Ansible (1.7.2) and al
tower
community
galaxy
test_strategies
faq
glossary
YAMLSyntax
guru

View File

@ -13,5 +13,5 @@ Before we dive into the really fun parts -- playbooks, configuration management,
intro_patterns
intro_adhoc
intro_configuration
intro_windows

View File

@ -123,7 +123,7 @@ File Transfer
Here's another use case for the `/usr/bin/ansible` command line. Ansible can SCP lots of files to multiple machines in parallel.
To transfer a file directly to many servers::
To transfer a file directly to many different servers::
$ ansible atlanta -m copy -a "src=/etc/hosts dest=/tmp/hosts"
@ -154,11 +154,11 @@ with yum.
Ensure a package is installed, but don't update it::
$ ansible webservers -m yum -a "name=acme state=present"
$ ansible webservers -m yum -a "name=acme state=installed"
Ensure a package is installed to a specific version::
$ ansible webservers -m yum -a "name=acme-1.5 state=present"
$ ansible webservers -m yum -a "name=acme-1.5 state=installed"
Ensure a package is at the latest version::
@ -166,7 +166,7 @@ Ensure a package is at the latest version::
Ensure a package is not installed::
$ ansible webservers -m yum -a "name=acme state=absent"
$ ansible webservers -m yum -a "name=acme state=removed"
Ansible has modules for managing packages under many platforms. If your package manager
does not have a module available for it, you can install
@ -248,7 +248,7 @@ Be sure to use a high enough ``--forks`` value if you want to get all of your jo
very quickly. After the time limit (in seconds) runs out (``-B``), the process on
the remote nodes will be terminated.
Typically you'll only be backgrounding long-running
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 <playbooks>` also support polling, and have a simplified syntax for this.
.. _checking_facts:

View File

@ -22,7 +22,7 @@ Prior to 1.5 the order was::
* .ansible.cfg (in the home directory)
* /etc/ansible/ansible.cfg
Ansible will process the above list and use the first file found. Settings in files are not merged.
Ansible will process the above list and use the first file found. Settings in files are not merged together.
.. _getting_the_latest_configuration:
@ -99,7 +99,7 @@ ask_pass
This controls whether an Ansible playbook should prompt for a password by default. The default behavior is no::
ask_pass=True
#ask_pass=True
If using SSH keys for authentication, it's probably not needed to change this setting.
@ -111,25 +111,10 @@ ask_sudo_pass
Similar to ask_pass, this controls whether an Ansible playbook should prompt for a sudo password by default when
sudoing. The default behavior is also no::
ask_sudo_pass=True
#ask_sudo_pass=True
Users on platforms where sudo passwords are enabled should consider changing this setting.
.. _bin_ansible_callbacks:
bin_ansible_callbacks
=====================
.. versionadded:: 1.8
Controls whether callback plugins are loaded when running /usr/bin/ansible. This may be used to log activity from
the command line, send notifications, and so on. Callback plugins are always loaded for /usr/bin/ansible-playbook
if present and cannot be disabled::
bin_ansible_callbacks=False
Prior to 1.8, callbacks were never loaded for /usr/bin/ansible.
.. _callback_plugins:
callback_plugins
@ -142,30 +127,6 @@ different locations::
Most users will not need to use this feature. See :doc:`developing_plugins` for more details
.. _command_warnings:
command_warnings
================
.. versionadded:: 1.8
By default since Ansible 1.8, Ansible will warn when usage of the shell and
command module appear to be simplified by using a default Ansible module
instead. This can include reminders to use the 'git' module instead of
shell commands to execute 'git'. Using modules when possible over arbitrary
shell commands can lead to more reliable and consistent playbook runs, and
also easier to maintain playbooks::
command_warnings = False
These warnings can be silenced by adjusting the following
setting or adding warn=yes or warn=no to the end of the command line
parameter string, like so::
- name: usage of git that could be replaced with the git module
shell: git update foo warn=yes
.. _connection_plugins:
connection_plugins
@ -174,7 +135,7 @@ connection_plugins
This is a developer-centric feature that allows low-level extensions around Ansible to be loaded from
different locations::
connection_plugins = /usr/share/ansible_plugins/connection_plugins
connection_plugins = /usr/share/ansible_plugins/connection_plugins
Most users will not need to use this feature. See :doc:`developing_plugins` for more details
@ -187,7 +148,7 @@ deprecation_warnings
Allows disabling of deprecating warnings in ansible-playbook output::
deprecation_warnings = True
deprecation_warnings = True
Deprecation warnings indicate usage of legacy features that are slated for removal in a future release of Ansible.
@ -198,7 +159,7 @@ display_skipped_hosts
If set to `False`, ansible will not display any status for a task that is skipped. The default behavior is to display skipped tasks::
display_skipped_hosts=True
#display_skipped_hosts=True
Note that Ansible will always show the task header for any task, regardless of whether or not the task is skipped.
@ -210,7 +171,7 @@ error_on_undefined_vars
On by default since Ansible 1.3, this causes ansible to fail steps that reference variable names that are likely
typoed::
error_on_undefined_vars=True
#error_on_undefined_vars=True
If set to False, any '{{ template_expression }}' that contains undefined variables will be rendered in a template
or ansible action line exactly as written.
@ -223,7 +184,7 @@ executable
This indicates the command to use to spawn a shell under a sudo environment. Users may need to change this in
rare instances to /bin/bash in rare instances when sudo is constrained, but in most cases it may be left as is::
executable = /bin/bash
#executable = /bin/bash
.. _filter_plugins:
@ -233,19 +194,10 @@ filter_plugins
This is a developer-centric feature that allows low-level extensions around Ansible to be loaded from
different locations::
filter_plugins = /usr/share/ansible_plugins/filter_plugins
filter_plugins = /usr/share/ansible_plugins/filter_plugins
Most users will not need to use this feature. See :doc:`developing_plugins` for more details
.. _force_color:
force_color
===========
This options forces color mode even when running without a TTY::
force_color = 1
.. _forks:
forks
@ -257,18 +209,8 @@ network and CPU load you think you can handle. Many users may set this to 50, s
have a large number of hosts, higher values will make actions across all of those hosts complete faster. The default
is very very conservative::
forks=5
forks=5
.. _gathering:
gathering
=========
New in 1.6, the 'gathering' setting controls the default policy of facts gathering (variables discovered about remote systems).
The value 'implicit' is the default, meaning facts will be gathered per play unless 'gather_facts: False' is set in the play. The value 'explicit' is the inverse, facts will not be gathered unless directly requested in the play.
The value 'smart' means each new host that has no facts discovered will be scanned, but if the same host is addressed in multiple plays it will not be contacted again in the playbook run. This option can be useful for those wishing to save fact gathering time.
hash_behaviour
==============
@ -276,11 +218,11 @@ hash_behaviour
Ansible by default will override variables in specific precedence orders, as described in :doc:`playbooks_variables`. When a variable
of higher precedence wins, it will replace the other value.
Some users prefer that variables that are hashes (aka 'dictionaries' in Python terms) are merged. This setting is called 'merge'. This is not the default behavior and it does not affect variables whose values are scalars (integers, strings) or
Some users prefer that variables that are hashes (aka 'dictionaries' in Python terms) are merged together. This setting is called 'merge'. This is not the default behavior and it does not affect variables whose values are scalars (integers, strings) or
arrays. We generally recommend not using this setting unless you think you have an absolute need for it, and playbooks in the
official examples repos do not use this setting::
hash_behaviour=replace
#hash_behaviour=replace
The valid values are either 'replace' (the default) or 'merge'.
@ -315,6 +257,20 @@ This is a developer-specific feature that allows enabling additional Jinja2 exte
If you do not know what these do, you probably don't need to change this setting :)
.. _legacy_playbook_variables:
legacy_playbook_variables
=========================
Ansible prefers to use Jinja2 syntax '{{ like_this }}' to indicate a variable should be substituted in a particular string. However,
older versions of playbooks used a more Perl-style syntax. This syntax was undesirable as it frequently conflicted with bash and
was hard to explain to new users when referencing complicated variable hierarchies, so we have standardized on the '{{ jinja2 }}' way.
To ensure a string like '$foo' is not inadvertently replaced in a Perl or Bash script template, the old form of templating (which is
still enabled as of Ansible 1.4) can be disabled like so ::
legacy_playbook_variables = no
.. _library:
library
@ -350,17 +306,10 @@ lookup_plugins
This is a developer-centric feature that allows low-level extensions around Ansible to be loaded from
different locations::
lookup_plugins = /usr/share/ansible_plugins/lookup_plugins
lookup_plugins = /usr/share/ansible_plugins/lookup_plugins
Most users will not need to use this feature. See :doc:`developing_plugins` for more details
.. _module_lang:
module_lang
===========
This is to set the default language to communicate between the module and the system. By default, the value is 'C'.
.. _module_name:
module_name
@ -370,7 +319,7 @@ This is the default module name (-m) value for /usr/bin/ansible. The default is
Remember the command module doesn't support shell variables, pipes, or quotes, so you might wish to change
it to 'shell'::
module_name = command
module_name = command
.. _nocolor:
@ -380,7 +329,7 @@ nocolor
By default ansible will try to colorize output to give a better indication of failure and status information.
If you dislike this behavior you can turn it off by setting 'nocolor' to 1::
nocolor=0
nocolor=0
.. _nocows:
@ -391,7 +340,7 @@ By default ansible will take advantage of cowsay if installed to make /usr/bin/a
Why? We believe systems management should be a happy experience. If you do not like the cows, you can disable them
by setting 'nocows' to 1::
nocows=0
nocows=0
.. _pattern:
@ -401,7 +350,7 @@ pattern
This is the default group of hosts to talk to in a playbook if no "hosts:" stanza is supplied. The default is to talk
to all hosts. You may wish to change this to protect yourself from surprises::
hosts=*
hosts=*
Note that /usr/bin/ansible always requires a host pattern and does not use this setting, only /usr/bin/ansible-playbook.
@ -424,7 +373,7 @@ private_key_file
If you are using a pem file to authenticate with machines rather than SSH agent or passwords, you can set the default
value here to avoid re-specifying ``--ansible-private-keyfile`` with every invocation::
private_key_file=/path/to/file.pem
private_key_file=/path/to/file.pem
.. _remote_port:
@ -434,7 +383,7 @@ remote_port
This sets the default SSH port on all of your systems, for systems that didn't specify an alternative value in inventory.
The default is the standard 22::
remote_port = 22
remote_port = 22
.. _remote_tmp:
@ -456,7 +405,7 @@ remote_user
===========
This is the default username ansible will connect as for /usr/bin/ansible-playbook. Note that /usr/bin/ansible will
always default to the current user if this is not defined::
always default to the current user::
remote_user = root
@ -473,10 +422,6 @@ choose to establish a convention to checkout roles in /opt/mysite/roles like so:
roles_path = /opt/mysite/roles
Additional paths can be provided separated by colon characters, in the same way as other pathstrings::
roles_path = /opt/mysite/roles:/opt/othersite/roles
Roles will be first searched for in the playbook directory. Should a role not be found, it will indicate all the possible paths
that were searched.
@ -511,19 +456,6 @@ playbook. The default is the most logical: 'root'::
sudo_user=root
.. _system_warnings:
system_warnings
===============
.. versionadded:: 1.6
Allows disabling of warnings related to potential issues on the system running ansible itself (not on the managed hosts)::
system_warnings = True
These may include warnings about 3rd party packages or other conditions that should be resolved if possible.
.. _timeout:
timeout
@ -553,24 +485,10 @@ vars_plugins
This is a developer-centric feature that allows low-level extensions around Ansible to be loaded from
different locations::
vars_plugins = /usr/share/ansible_plugins/vars_plugins
vars_plugins = /usr/share/ansible_plugins/vars_plugins
Most users will not need to use this feature. See :doc:`developing_plugins` for more details
.. _vault_password_file:
vault_password_file
===================
.. versionadded:: 1.7
Configures the path to the Vault password file as an alternative to specifying ``--vault-password-file`` on the command line::
vault_password_file = /path/to/vault_password_file
As of 1.7 this file can also be a script. If you are using a script instead of a flat file, ensure that it is marked as executable, and that the password is printed to standard output. If your script needs to prompt for data, prompts can be sent to standard error.
.. _paramiko_settings:
Paramiko Specific Settings
@ -588,7 +506,7 @@ The default setting of yes will record newly discovered and approved (if host ke
This setting may be inefficient for large numbers of hosts, and in those situations, using the ssh transport is definitely recommended
instead. Setting it to False will improve performance and is recommended when host key checking is disabled::
record_host_keys=True
record_host_keys=True
.. _openssh_settings:
@ -617,14 +535,14 @@ control_path
This is the location to save ControlPath sockets. This defaults to::
control_path=%(directory)s/ansible-ssh-%%h-%%p-%%r
control_path=%(directory)s/ansible-ssh-%%h-%%p-%%r
On some systems with very long hostnames or very long path names (caused by long user names or
deeply nested home directories) this can exceed the character limit on
file socket names (108 characters for most platforms). In that case, you
may wish to shorten the string to something like the below::
control_path = %(directory)s/%%h-%%r
control_path = %(directory)s/%%h-%%r
Ansible 1.4 and later will instruct users to run with "-vvvv" in situations where it hits this problem
and if so it is easy to tell there is too long of a Control Path filename. This may be frequently
@ -638,7 +556,7 @@ scp_if_ssh
Occasionally users may be managing a remote system that doesn't have SFTP enabled. If set to True, we can
cause scp to be used to transfer remote files instead::
scp_if_ssh=False
scp_if_ssh=False
There's really no reason to change this unless problems are encountered, and then there's also no real drawback
to managing the switch. Most environments support SFTP by default and this doesn't usually need to be changed.
@ -662,8 +580,8 @@ recommended if you can enable it, eliminating the need for :doc:`playbooks_accel
.. _accelerate_settings:
Accelerated Mode Settings
-------------------------
Accelerate Mode Settings
------------------------
Under the [accelerate] header, the following settings are tunable for :doc:`playbooks_acceleration`. Acceleration is
a useful performance feature to use if you cannot enable :ref:`pipelining` in your environment, but is probably
@ -676,9 +594,9 @@ accelerate_port
.. versionadded:: 1.3
This is the port to use for accelerated mode::
This is the port to use for accelerate mode::
accelerate_port = 5099
accelerate_port = 5099
.. _accelerate_timeout:
@ -704,29 +622,4 @@ This setting controls the timeout for the socket connect call, and should be kep
Note, this value can be set to less than one second, however it is probably not a good idea to do so unless you're on a very fast and reliable LAN. If you're connecting to systems over the internet, it may be necessary to increase this timeout.
.. _accelerate_daemon_timeout:
accelerate_daemon_timeout
=========================
.. versionadded:: 1.6
This setting controls the timeout for the accelerated daemon, as measured in minutes. The default daemon timeout is 30 minutes::
accelerate_daemon_timeout = 30
Note, prior to 1.6, the timeout was hard-coded from the time of the daemon's launch. For version 1.6+, the timeout is now based on the last activity to the daemon and is configurable via this option.
.. _accelerate_multi_key:
accelerate_multi_key
====================
.. versionadded:: 1.6
If enabled, this setting allows multiple private keys to be uploaded to the daemon. Any clients connecting to the daemon must also enable this option::
accelerate_multi_key = yes
New clients first connect to the target node over SSH to upload the key, which is done via a local socket file, so they must have the same access as the user that launched the daemon originally.

View File

@ -10,11 +10,11 @@ in a different software system. Ansible provides a basic text-based system as d
:doc:`intro_inventory` but what if you want to use something else?
Frequent examples include pulling inventory from a cloud provider, LDAP, `Cobbler <http://cobbler.github.com>`_,
or a piece of expensive enterprisey CMDB software.
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, Rackspace Cloud, and OpenStack, examples of some of which will be detailed below.
:doc:`tower` also provides a database to store inventory results that is both web and REST Accessible. Tower syncs with all Ansible dynamic inventory sources you might be using, and also includes a graphical inventory editor. By having a database record of all of your hosts, it's easy to correlate past event history and see which ones have had failures on their last playbook runs.
doc:`tower` also provides a database to store inventory results that is both web and REST Accessible. Tower syncs with all Ansible dynamic inventory sources you might be using, and also includes a graphical inventory editor. By having a database record of all of your hosts, it's easy to correlate past event history and see which ones have had failures on their last playbook runs.
For information about writing your own dynamic inventory source, see :doc:`developing_inventory`.
@ -28,11 +28,11 @@ It is expected that many Ansible users with a reasonable amount of physical hard
While primarily used to kickoff OS installations and manage DHCP and DNS, Cobbler has a generic
layer that allows it to represent data for multiple configuration management systems (even at the same time), and has
been referred to as a 'lightweight CMDB' by some admins.
been referred to as a 'lightweight CMDB' by some admins. This particular script will communicate with Cobbler
using Cobbler's XMLRPC API.
To tie Ansible's inventory to Cobbler (optional), copy `this script <https://raw.github.com/ansible/ansible/devel/plugins/inventory/cobbler.py>`_ to /etc/ansible and `chmod +x` the file. cobblerd will now need
to be running when you are using Ansible and you'll need to use Ansible's ``-i`` command line option (e.g. ``-i /etc/ansible/cobbler.py``).
This particular script will communicate with Cobbler using Cobbler's XMLRPC API.
First test the script by running ``/etc/ansible/cobbler.py`` directly. You should see some JSON data output, but it may not have anything in it just yet.
@ -73,7 +73,7 @@ And technically, though there is no major good reason to do it, this also works
ansible webserver -m shell -a "echo {{ a }}"
So in other words, you can use those variables in arguments/actions as well.
So in other words, you can use those variables in arguments/actions as well.
.. _aws_example:
@ -87,7 +87,7 @@ marking it executable::
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 <https://raw.githubusercontent.com/ansible/ansible/devel/plugins/inventory/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::
@ -103,15 +103,12 @@ After a few moments, you should see your entire EC2 inventory across all regions
Since each region requires its own API call, if you are only using a small set of regions, feel free to edit ``ec2.ini`` and list only the regions you are interested in. There are other config options in ``ec2.ini`` including cache control, and destination variables.
At their heart, inventory files are simply a mapping from some name to a destination address. The default ``ec2.ini`` settings are configured for running Ansible from outside EC2 (from your laptop for example) -- and this is not the most efficient way to manage EC2.
At their heart, inventory files are simply a mapping from some name to a destination address. The default ``ec2.ini`` settings are configured for running Ansible from outside EC2 (from your laptop for example) -- and this is not the most efficient way to manage EC2.
If you are running Ansible from within EC2, internal DNS names and IP addresses may make more sense than public DNS names. In this case, you can modify the ``destination_variable`` in ``ec2.ini`` to be the private DNS name of an instance. This is particularly important when running Ansible within a private subnet inside a VPC, where the only way to access an instance is via its private IP address. For VPC instances, `vpc_destination_variable` in ``ec2.ini`` provides a means of using which ever `boto.ec2.instance variable <http://docs.pythonboto.org/en/latest/ref/ec2.html#module-boto.ec2.instance>`_ makes the most sense for your use case.
The EC2 external inventory provides mappings to instances from several groups:
Global
All instances are in group ``ec2``.
Instance ID
These are groups of one since instance IDs are unique.
e.g.
@ -199,8 +196,7 @@ Other inventory scripts
In addition to Cobbler and EC2, inventory scripts are also available for::
BSD Jails
DigitalOcean
Google Compute Engine
Digital Ocean
Linode
OpenShift
OpenStack Nova

View File

@ -109,7 +109,7 @@ Host Key Checking
Ansible 1.2.1 and later have host key checking enabled by default.
If a host is reinstalled and has a different key in 'known_hosts', this will result in an error message until corrected. If a host is not initially in 'known_hosts' this will result in prompting for confirmation of the key, which results in an interactive experience if using Ansible, from say, cron. You might not want this.
If a host is reinstalled and has a different key in 'known_hosts', this will result in a error message until corrected. If a host is not initially in 'known_hosts' this will result in prompting for confirmation of the key, which results in a interactive experience if using Ansible, from say, cron. You might not want this.
If you wish to disable this behavior and understand the implications, you can do so by editing /etc/ansible/ansible.cfg or ~/.ansible.cfg::
@ -126,9 +126,8 @@ Also note that host key checking in paramiko mode is reasonably slow, therefore
.. _a_note_about_logging:
Ansible will log some information about module arguments on the remote system in the remote syslog, unless a task or play is marked with a "no_log: True" attribute, explained later.
To enable basic logging on the control machine see :doc:`intro_configuration` document and set the 'log_path' configuration file setting. Enterprise users may also be interested in :doc:`tower`. Tower provides a very robust database logging feature where it is possible to drill down and see history based on hosts, projects, and particular inventories over time -- explorable both graphically and through a REST API.
Ansible will log some information about module arguments on the remote system in the remote syslog. To enable basic
logging on the control machine see :doc:`intro_configuration` document and set the 'log_path' configuration file setting. Enterprise users may also be interested in :doc:`tower`. Tower provides a very robust database logging feature where it is possible to drill down and see history based on hosts, projects, and particular inventories over time -- explorable both graphically and through a REST API.
.. seealso::

View File

@ -107,7 +107,7 @@ To install from source.
.. code-block:: bash
$ git clone git://github.com/ansible/ansible.git --recursive
$ git clone git://github.com/ansible/ansible.git
$ cd ./ansible
$ source ./hacking/env-setup
@ -117,15 +117,7 @@ If you don't have pip installed in your version of Python, install pip::
Ansible also uses the following Python modules that need to be installed::
$ sudo pip install paramiko PyYAML Jinja2 httplib2
Note when updating ansible, be sure to not only update the source tree, but also the "submodules" in git
which point at Ansible's own modules (not the same kind of modules, alas).
.. code-block:: bash
$ git pull --rebase
$ git submodule update --init --recursive
$ sudo pip install paramiko PyYAML jinja2 httplib2
Once running the env-setup script you'll be running from checkout and the default inventory file
will be /etc/ansible/hosts. You can optionally specify an inventory file (see :doc:`intro_inventory`)
@ -152,7 +144,7 @@ Latest Release Via Yum
++++++++++++++++++++++
RPMs are available from yum for `EPEL
<http://fedoraproject.org/wiki/EPEL>`_ 6, 7, and currently supported
<http://fedoraproject.org/wiki/EPEL>`_ 6 and currently supported
Fedora distributions.
Ansible itself can manage earlier operating
@ -179,19 +171,16 @@ You can also build an RPM yourself. From the root of a checkout or tarball, use
Latest Releases Via Apt (Ubuntu)
++++++++++++++++++++++++++++++++
Ubuntu builds are available `in a PPA here <https://launchpad.net/~ansible/+archive/ansible>`_.
Ubuntu builds are available `in a PPA here <https://launchpad.net/~rquillo/+archive/ansible>`_.
To configure the PPA on your machine and install ansible run these commands:
Once configured,
.. code-block:: bash
$ sudo apt-get install software-properties-common
$ sudo apt-add-repository ppa:ansible/ansible
$ sudo add-apt-repository ppa:rquillo/ansible
$ sudo apt-get update
$ sudo apt-get install ansible
.. note:: On older Ubuntu distributions, "software-properties-common" is called "python-software-properties".
Debian/Ubuntu packages can also be built from the source checkout, run:
.. code-block:: bash
@ -215,18 +204,6 @@ You may also wish to install from ports, run:
$ sudo make -C /usr/ports/sysutils/ansible install
.. _from_brew:
Latest Releases Via Homebrew (Mac OSX)
++++++++++++++++++++++++++++++++++++++
To install on a Mac, make sure you have Homebrew, then run:
.. code-block:: bash
$ brew update
$ brew install ansible
.. _from_pip:
Latest Releases Via Pip
@ -241,10 +218,6 @@ Then install Ansible with::
$ sudo pip install ansible
If you are installing on OS X Mavericks, you may encounter some noise from your compiler. A workaround is to do the following::
$ sudo CFLAGS=-Qunused-arguments CPPFLAGS=-Qunused-arguments pip install ansible
Readers that use virtualenv can also install Ansible under virtualenv, though we'd recommend to not worry about it and just install Ansible globally. Do not use easy_install to install ansible directly.
.. _tagged_releases:

View File

@ -39,10 +39,8 @@ It is ok to put systems in more than one group, for instance a server could be b
If you do, note that variables will come from all of the groups they are a member of, and variable precedence is detailed in a later chapter.
If you have hosts that run on non-standard SSH ports you can put the port number
after the hostname with a colon. Ports listed in your SSH config file won't be used with the paramiko
connection but will be used with the openssh connection.
To make things explicit, it is suggested that you set them if things are not running on the default port::
after the hostname with a colon. Ports listed in your SSH config file won't be used,
so it is important that you set them if things are not running on the default port::
badwolf.example.com:5309
@ -144,7 +142,7 @@ Splitting Out Host and Group Specific Data
The preferred practice in Ansible is actually not to store variables in the main inventory file.
In addition to storing variables directly in the INI file, host
In addition to the storing variables directly in the INI file, host
and group variables can be stored in individual files relative to the
inventory file.
@ -171,17 +169,6 @@ the 'raleigh' group might look like::
It is ok if these files do not exist, as this is an optional feature.
As an advanced use-case, you can create *directories* named after your groups or hosts, and
Ansible will read all the files in these directories. An example with the 'raleigh' group::
/etc/ansible/group_vars/raleigh/db_settings
/etc/ansible/group_vars/raleigh/cluster_settings
All hosts that are in the 'raleigh' group will have the variables defined in these files
available to them. This can be very useful to keep your variables organized when a single
file starts to be too big, or when you want to use :doc:`Ansible Vault<playbooks_vault>` on a part of a group's
variables. Note that this only works on Ansible 1.4 or later.
Tip: In Ansible 1.2 or later the group_vars/ and host_vars/ directories can exist in either
the playbook directory OR the inventory directory. If both paths exist, variables in the playbook
directory will be loaded second.
@ -207,14 +194,10 @@ mentioned::
The ssh password to use (this is insecure, we strongly recommend using --ask-pass or SSH keys)
ansible_sudo_pass
The sudo password to use (this is insecure, we strongly recommend using --ask-sudo-pass)
ansible_sudo_exe (new in version 1.8)
The sudo command path.
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_shell_type
The shell type of the target system. By default commands are formatted using 'sh'-style syntax by default. Setting this to 'csh' or 'fish' will cause commands executed on target systems to follow those shell's syntax instead.
ansible_python_interpreter
The target host python path. This is useful for systems with more
than one Python or not located at "/usr/bin/python" such as \*BSD, or where /usr/bin/python

View File

@ -68,14 +68,6 @@ It's also ok to mix wildcard patterns and groups at the same time::
one*.com:dbservers
As an advanced usage, you can also select the numbered server in a group::
webservers[0]
Or a portion of servers in a group::
webservers[0:25]
Most people don't specify patterns as regular expressions, but you can. Just start the pattern with a '~'::
~(web|db).*\.example\.com
@ -84,10 +76,6 @@ While we're jumping a bit ahead, additionally, you can add an exclusion criteria
ansible-playbook site.yml --limit datacenter2
And if you want to read the list of hosts from a file, prefix the file name with '@'. Since Ansible 1.2::
ansible-playbook site.yml --limit @retry_hosts.txt
Easy enough. See :doc:`intro_adhoc` and then :doc:`playbooks` for how to apply this knowledge.
.. seealso::

View File

@ -1,224 +0,0 @@
Windows Support
===============
.. contents:: Topics
.. _windows_how_does_it_work:
Windows: How Does It Work
`````````````````````````
As you may have already read, Ansible manages Linux/Unix machines using SSH by default.
Starting in version 1.7, Ansible also contains support for managing Windows machines. This uses
native powershell remoting, rather than SSH.
Ansible will still be run from a Linux control machine, and uses the "winrm" Python module to talk to remote hosts.
No additional software needs to be installed on the remote machines for Ansible to manage them, it still maintains the agentless properties that make it popular on Linux/Unix.
Note that it is expected you have a basic understanding of Ansible prior to jumping into this section, so if you haven't written a Linux playbook first, it might be worthwhile to dig in there first.
.. _windows_installing:
Installing on the Control Machine
`````````````````````````````````
On a Linux control machine::
pip install http://github.com/diyan/pywinrm/archive/master.zip#egg=pywinrm
.. _windows_inventory:
Inventory
`````````
Ansible's windows support relies on a few standard variables to indicate the username, password, and connection type (windows) of the remote hosts. These variables are most easily set up in inventory. This is used instead of SSH-keys or passwords as normally fed into Ansible::
[windows]
winserver1.example.com
winserver2.example.com
In group_vars/windows.yml, define the following inventory variables::
# it is suggested that these be encrypted with ansible-vault:
# ansible-vault edit group_vars/windows.yml
ansible_ssh_user: Administrator
ansible_ssh_pass: SecretPasswordGoesHere
ansible_ssh_port: 5986
ansible_connection: winrm
Notice that the ssh_port is not actually for SSH, but this is a holdover variable name from how Ansible is mostly an SSH-oriented system. Again, Windows management will not happen over SSH.
When using your playbook, don't forget to specify --ask-vault-pass to provide the password to unlock the file.
Test your configuration like so, by trying to contact your Windows nodes. Note this is not an ICMP ping, but tests the Ansible
communication channel that leverages Windows remoting::
ansible windows [-i inventory] -m win_ping --ask-vault-pass
If you haven't done anything to prep your systems yet, this won't work yet. This is covered in a later
section about how to enable powershell remoting - and if necessary - how to upgrade powershell to
a version that is 3 or higher.
You'll run this command again later though, to make sure everything is working.
.. _windows_system_prep:
Windows System Prep
```````````````````
In order for Ansible to manage your windows machines, you will have to enable Powershell remoting configured.
To automate setup of WinRM, you can run `this powershell script <https://github.com/ansible/ansible/blob/devel/examples/scripts/ConfigureRemotingForAnsible.ps1>`_ on the remote machine.
Admins may wish to modify this setup slightly, for instance to increase the timeframe of
the certificate.
.. _getting_to_powershell_three_or_higher:
Getting to Powershell 3.0 or higher
```````````````````````````````````
Powershell 3.0 or higher is needed for most provided Ansible modules for Windows, and is also required to run the above setup script.
Looking at an ansible checkout, copy the `examples/scripts/upgrade_to_ps3.ps1 <https://github.com/cchurch/ansible/blob/devel/examples/scripts/upgrade_to_ps3.ps1>`_ script onto the remote host and run a powershell console as an administrator. You will now be running Powershell 3 and can try connectivity again using the win_ping technique referenced above.
.. _what_windows_modules_are_available:
What modules are available
``````````````````````````
Most of the Ansible modules in core Ansible are written for a combination of Linux/Unix machines and arbitrary web services, though there are various
Windows modules as listed in the `"windows" subcategory of the Ansible module index <http://docs.ansible.com/list_of_windows_modules.html>`_.
Browse this index to see what is available.
In many cases, it may not be necessary to even write or use an Ansible module.
In particular, the "script" module can be used to run arbitrary powershell scripts, allowing Windows administrators familiar with powershell a very native way to do things, as in the following playbook::
- hosts: windows
tasks:
- script: foo.ps1 --argument --other-argument
Note there are a few other Ansible modules that don't start with "win" that also function, including "slurp", "raw", and "setup" (which is how fact gathering works).
.. _developers_developers_developers:
Developers: Supported modules and how it works
``````````````````````````````````````````````
Developing ansible modules are covered in a `later section of the documentation <http://developing_modules.html>`_, with a focus on Linux/Unix.
What if you want to write Windows modules for ansible though?
For Windows, ansible modules are implemented in Powershell. Skim those Linux/Unix module development chapters before proceeding.
Windows modules live in a "windows/" subfolder in the Ansible "library/" subtree. For example, if a module is named
"library/windows/win_ping", there will be embedded documentation in the "win_ping" file, and the actual powershell code will live in a "win_ping.ps1" file. Take a look at the sources and this will make more sense.
Modules (ps1 files) should start as follows::
#!powershell
# <license>
# WANT_JSON
# POWERSHELL_COMMON
# code goes here, reading in stdin as JSON and outputting JSON
The above magic is necessary to tell Ansible to mix in some common code and also know how to push modules out. The common code contains some nice wrappers around working with hash data structures and emitting JSON results, and possibly a few more useful things. Regular Ansible has this same concept for reusing Python code - this is just the windows equivalent.
What modules you see in windows/ are just a start. Additional modules may be submitted as pull requests to github.
.. _windows_and_linux_control_machine:
Reminder: You Must Have a Linux Control Machine
```````````````````````````````````````````````
Note running Ansible from a Windows control machine is NOT a goal of the project. Refrain from asking for this feature,
as it limits what technologies, features, and code we can use in the main project in the future. A Linux control machine
will be required to manage Windows hosts.
Cygwin is not supported, so please do not ask questions about Ansible running from Cygwin.
.. _windows_facts:
Windows Facts
`````````````
Just as with Linux/Unix, facts can be gathered for windows hosts, which will return things such as the operating system version. To see what variables are available about a windows host, run the following::
ansible winhost.example.com -m setup
Note that this command invocation is exactly the same as the Linux/Unix equivalent.
.. _windows_playbook_example:
Windows Playbook Examples
`````````````````````````
Look to the list of windows modules for most of what is possible, though also some modules like "raw" and "script" also work on Windows, as do "fetch" and "slurp".
Here is an example of pushing and running a powershell script::
- name: test script module
hosts: windows
tasks:
- name: run test script
script: files/test_script.ps1
Running individual commands uses the 'raw' module, as opposed to the shell or command module as is common on Linux/Unix operating systems::
- name: test raw module
hosts: windows
tasks:
- name: run ipconfig
raw: ipconfig
register: ipconfig
- debug: var=ipconfig
And for a final example, here's how to use the win_stat module to test for file existence. Note that the data returned by the win_stat module is slightly different than what is provided by the Linux equivalent::
- name: test stat module
hosts: windows
tasks:
- name: test stat module on file
win_stat: path="C:/Windows/win.ini"
register: stat_file
- debug: var=stat_file
- name: check stat_file result
assert:
that:
- "stat_file.stat.exists"
- "not stat_file.stat.isdir"
- "stat_file.stat.size > 0"
- "stat_file.stat.md5"
Again, recall that the Windows modules are all listed in the Windows category of modules, with the exception that the "raw", "script", and "fetch" modules are also available. These modules do not start with a "win" prefix.
.. _windows_contributions:
Windows Contributions
`````````````````````
Windows support in Ansible is still very new, and contributions are quite welcome, whether this is in the
form of new modules, tweaks to existing modules, documentation, or something else. Please stop by the ansible-devel mailing list if you would like to get involved and say hi.
.. seealso::
:doc:`developing_modules`
How to write modules
:doc:`playbooks`
Learning ansible's configuration management language
`List of Windows Modules <http://docs.ansible.com/list_of_windows_modules.html>`_
Windows specific module list, all implemented in powershell
`Mailing List <http://groups.google.com/group/ansible-project>`_
Questions? Help? Ideas? Stop by the list on Google Groups
`irc.freenode.net <http://irc.freenode.net>`_
#ansible IRC chat channel

View File

@ -17,7 +17,7 @@ handle executing system commands.
Let's review how we execute three different modules from the command line::
ansible webservers -m service -a "name=httpd state=started"
ansible webservers -m service -a "name=httpd state=running"
ansible webservers -m ping
ansible webservers -m command -a "/sbin/reboot -t now"

View File

@ -6,24 +6,24 @@ Accelerated Mode
You Might Not Need This!
````````````````````````
Are you running Ansible 1.5 or later? If so, you may not need accelerated mode due to a new feature called "SSH pipelining" and should read the :ref:`pipelining` section of the documentation.
Are you running Ansible 1.5 or later? If so, you may not need accelerate mode due to a new feature called "SSH pipelining" and should read the :ref:`pipelining` section of the documentation.
For users on 1.5 and later, accelerated mode only makes sense if you (A) are managing from an Enterprise Linux 6 or earlier host
For users on 1.5 and later, accelerate mode only makes sense if you are (A) are managing from an Enterprise Linux 6 or earlier host
and still are on paramiko, or (B) can't enable TTYs with sudo as described in the pipelining docs.
If you can use pipelining, Ansible will reduce the amount of files transferred over the wire,
making everything much more efficient, and performance will be on par with accelerated mode in nearly all cases, possibly excluding very large file transfer. Because less moving parts are involved, pipelining is better than accelerated mode for nearly all use cases.
making everything much more efficient, and performance will be on par with accelerate mode in nearly all cases, possibly excluding very large file transfer. Because less moving parts are involved, pipelining is better than accelerate mode for nearly all use cases.
Accelerated moded remains around in support of EL6
Accelerate mode remains around in support of EL6
control machines and other constrained environments.
Accelerated Mode Details
````````````````````````
Accelerate Mode Details
```````````````````````
While OpenSSH using the ControlPersist feature is quite fast and scalable, there is a certain small amount of overhead involved in
using SSH connections. While many people will not encounter a need, if you are running on a platform that doesn't have ControlPersist support (such as an EL6 control machine), you'll probably be even more interested in tuning options.
Accelerated mode is there to help connections work faster, but still uses SSH for initial secure key exchange. There is no
Accelerate mode is there to help connections work faster, but still uses SSH for initial secure key exchange. There is no
additional public key infrastructure to manage, and this does not require things like NTP or even DNS.
Accelerated mode can be anywhere from 2-6x faster than SSH with ControlPersist enabled, and 10x faster than paramiko.
@ -76,11 +76,4 @@ As noted above, accelerated mode also supports running tasks via sudo, however t
* You must remove requiretty from your sudoers options.
* Prompting for the sudo password is not yet supported, so the NOPASSWD option is required for sudo'ed commands.
As of Ansible version `1.6`, you can also allow the use of multiple keys for connections from multiple Ansible management nodes. To do so, add the following option
to your `ansible.cfg` configuration::
accelerate_multi_key = yes
When enabled, the daemon will open a UNIX socket file (by default `$ANSIBLE_REMOTE_TEMP/.ansible-accelerate/.local.socket`). New connections over SSH can
use this socket file to upload new keys to the daemon.

View File

@ -22,7 +22,7 @@ poll value is 10 seconds if you do not specify a value for `poll`::
tasks:
- name: simulate long running op (15 sec), wait for up to 45 sec, poll every 5 sec
- name: simulate long running op (15 sec), wait for up to 45, poll every 5
command: /bin/sleep 15
async: 45
poll: 5
@ -42,7 +42,7 @@ Alternatively, if you do not need to wait on the task to complete, you may
tasks:
- name: simulate long running op, allow to run for 45 sec, fire and forget
- name: simulate long running op, allow to run for 45, fire and forget
command: /bin/sleep 15
async: 45
poll: 0
@ -56,28 +56,6 @@ Alternatively, if you do not need to wait on the task to complete, you may
Using a higher value for ``--forks`` will result in kicking off asynchronous
tasks even faster. This also increases the efficiency of polling.
If you would like to perform a variation of the "fire and forget" where you
"fire and forget, check on it later" you can perform a task similar to the
following::
---
# Requires ansible 1.8+
- name: 'YUM - fire and forget task'
yum: name=docker-io state=installed
async: 1000
poll: 0
register: yum_sleeper
- name: 'YUM - check on fire and forget task'
async_status: jid={{ yum_sleeper.ansible_job_id }}
register: job_result
until: job_result.finished
retries: 30
.. note::
If the value of ``async:`` is not high enough, this will cause the
"check on it later" task to fail because the temporary status file that
the ``async_status:`` is looking for will not have been written
.. seealso::

View File

@ -51,10 +51,6 @@ The top level of the directory would contain files and directories like so::
foo.sh # <-- script files for use with the script resource
vars/ #
main.yml # <-- variables associated with this role
defaults/ #
main.yml # <-- default lower priority variables for this role
meta/ #
main.yml # <-- role dependencies
webtier/ # same kind of structure as "common" was above, done for the webtier role
monitoring/ # ""
@ -227,8 +223,8 @@ What about just the first 10, and then the next 10?::
And of course just basic ad-hoc stuff is also possible.::
ansible boston -i production -m ping
ansible boston -i production -m command -a '/sbin/reboot'
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)::
@ -391,7 +387,7 @@ changed the rules that are automating your infrastructure.
Learn how to extend Ansible by writing your own modules
:doc:`intro_patterns`
Learn about how to select hosts
`GitHub examples directory <https://github.com/ansible/ansible/tree/devel/examples/playbooks>`_
`Github examples directory <https://github.com/ansible/ansible/tree/devel/examples/playbooks>`_
Complete playbook files from the github project source
`Mailing List <http://groups.google.com/group/ansible-project>`_
Questions? Help? Ideas? Stop by the list on Google Groups

View File

@ -11,6 +11,9 @@ whether the hosts match other criteria. There are many options to control exec
Let's dig into what they are.
.. contents::
:depth: 2
The When Statement
``````````````````

View File

@ -5,7 +5,7 @@ Delegation, Rolling Updates, and Local Actions
Being designed for multi-tier deployments since the beginning, Ansible is great at doing things on one host on behalf of another, or doing local steps with reference to some remote hosts.
This in particular is very applicable when setting up continuous deployment infrastructure or zero downtime rolling updates, where you might be talking with load balancers or monitoring systems.
This in particular this is very applicable when setting up continuous deployment infrastructure or zero downtime rolling updates, where you might be talking with load balancers or monitoring systems.
Additional features allow for tuning the orders in which things complete, and assigning a batch window size for how many machines to process at once during a rolling update.
@ -33,18 +33,6 @@ use case, you can define how many hosts Ansible should manage at a single time b
In the above example, if we had 100 hosts, 3 hosts in the group 'webservers'
would complete the play completely before moving on to the next 3 hosts.
The ''serial'' keyword can also be specified as a percentage in Ansible 1.8 and later, which will be applied to the total number of hosts in a
play, in order to determine the number of hosts per pass::
- name: test play
hosts: websevers
serial: "30%"
If the number of hosts does not divide equally into the number of passes, the final pass will contain the remainder.
.. note::
No matter how small the percentage, the number of hosts per pass will always be 1 or greater.
.. _maximum_failure_percentage:
Maximum Failure Percentage
@ -130,42 +118,6 @@ Here is an example::
Note that you must have passphrase-less SSH keys or an ssh-agent configured for this to work, otherwise rsync
will need to ask for a passphrase.
.. _run_once:
Run Once
````````
.. versionadded:: 1.7
In some cases there may be a need to only run a task one time and only on one host. This can be achieved
by configuring "run_once" on a task::
---
# ...
tasks:
# ...
- command: /opt/application/upgrade_db.py
run_once: true
# ...
This can be optionally paired with "delegate_to" to specify an individual host to execute on::
- command: /opt/application/upgrade_db.py
run_once: true
delegate_to: web01.example.org
When "run_once" is not used with "delegate_to" it will execute on the first host, as defined by inventory,
in the group(s) of hosts targeted by the play. e.g. webservers[0] if the play targeted "hosts: webservers".
This aproach is similar, although more concise and cleaner than applying a conditional to a task such as::
- command: /opt/application/upgrade_db.py
when: inventory_hostname == webservers[0]
.. _local_playbooks:
Local Playbooks
@ -173,7 +125,7 @@ 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 an OS installer, such as an Anaconda kickstart.
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::

View File

@ -23,7 +23,7 @@ The environment can also be stored in a variable, and accessed like so::
- hosts: all
remote_user: root
# here we make a variable named "proxy_env" that is a dictionary
# here we make a variable named "env" that is a dictionary
vars:
proxy_env:
http_proxy: http://proxy.example.com:8080

View File

@ -196,7 +196,7 @@ it is recommended that you use the more conventional "module: options" format.
This recommended format is used throughout the documentation, but you may
encounter the older format in some playbooks.
Here is what a basic task looks like. As with most modules,
Here is what a basic task looks like, as with most modules,
the service module takes key=value arguments::
tasks:
@ -350,7 +350,7 @@ Assuming you load balance your checkout location, ansible-pull scales essentiall
Run ``ansible-pull --help`` for details.
There's also a `clever playbook <https://github.com/ansible/ansible-examples/blob/master/language_features/ansible_pull.yml>`_ available to configure ansible-pull via a crontab from push mode.
There's also a `clever playbook <https://github.com/ansible/ansible-examples/blob/master/language_features/ansible_pull.yml>`_ available to using ansible in push mode to configure ansible-pull via a crontab!
.. _tips_and_tricks:
@ -370,7 +370,7 @@ package is installed. Try it!
To see what hosts would be affected by a playbook before you run it, you
can do this::
ansible-playbook playbook.yml --list-hosts
ansible-playbook playbook.yml --list-hosts.
.. seealso::

View File

@ -1,15 +1,12 @@
Using Lookups
=============
Lookup plugins allow access of data in Ansible from outside sources. These plugins are evaluated on the Ansible control
machine, and can include reading the filesystem but also contacting external datastores and services.
These values are then made available using the standard templating system
Lookup plugins allow access of data in Ansible from outside sources. This can include the filesystem
but also external datastores. These values are then made available using the standard templating system
in Ansible, and are typically used to load variables or templates with information from those systems.
.. note:: This is considered an advanced feature, and many users will probably not rely on these features.
.. note:: Lookups occur on the local computer, not on the remote computer.
.. contents:: Topics
.. _getting_file_contents:
@ -73,7 +70,7 @@ Starting in version 1.4, password accepts a "chars" parameter to allow defining
# create a mysql user with a random password using only ascii letters:
- mysql_user: name={{ client }}
password="{{ lookup('password', '/tmp/passwordfile chars=ascii_letters') }}"
password="{{ lookup('password', '/tmp/passwordfile chars=ascii') }}"
priv={{ client }}_{{ tier }}_{{ role }}.*:ALL
# create a mysql user with a random password using only digits:
@ -83,7 +80,7 @@ Starting in version 1.4, password accepts a "chars" parameter to allow defining
# create a mysql user with a random password using many different char sets:
- mysql_user: name={{ client }}
password="{{ lookup('password', '/tmp/passwordfile chars=ascii_letters,digits,hexdigits,punctuation') }}"
password="{{ lookup('password', '/tmp/passwordfile chars=ascii,numbers,digits,hexdigits,punctuation') }}"
priv={{ client }}_{{ tier }}_{{ role }}.*:ALL
(...)
@ -125,8 +122,6 @@ Here are some examples::
- debug: msg="{{ lookup('template', './some_template.j2') }} is a value from evaluation of this template"
- debug: msg="{{ lookup('etcd', 'foo') }} is a value from a locally running etcd"
As an alternative you can also assign lookup plugins to variables or use them
elsewhere. This macros are evaluated each time they are used in a task (or
template)::

View File

@ -53,7 +53,7 @@ Loops can be nested as well::
- name: give users access to multiple databases
mysql_user: name={{ item[0] }} priv={{ item[1] }}.*:ALL append_privs=yes password=foo
with_nested:
- [ 'alice', 'bob' ]
- [ 'alice', 'bob', 'eve' ]
- [ 'clientdb', 'employeedb', 'providerdb' ]
As with the case of 'with_items' above, you can use previously defined variables. Just specify the variable's name without templating it with '{{ }}'::
@ -109,8 +109,6 @@ be used like this::
- copy: src={{ item }} dest=/etc/fooapp/ owner=root mode=600
with_fileglob:
- /playbooks/files/fooapp/*
.. note:: When using a relative path with ``with_fileglob`` in a role, Ansible resolves the path relative to the `roles/<rolename>/files` directory.
Looping over Parallel Sets of Data
``````````````````````````````````
@ -233,7 +231,7 @@ Sometimes you would want to retry a task until a certain condition is met. Here
retries: 5
delay: 10
The above example run the shell module recursively till the module's result has "all systems go" in its stdout or the task has
The above example run the shell module recursively till the module's result has "all systems go" in it's stdout or the task has
been retried for 5 times with a delay of 10 seconds. The default value for "retries" is 3 and "delay" is 5.
The task returns the results returned by the last task run. The results of individual retries can be viewed by -vv option.
@ -252,7 +250,7 @@ that matches a given criteria, and some of the filenames are determined by varia
- name: INTERFACES | Create Ansible header for /etc/network/interfaces
template: src={{ item }} dest=/etc/foo.conf
with_first_found:
- "{{ansible_virtualization_type}}_foo.conf"
- "{{ansible_virtualization_type}_foo.conf"
- "default_foo.conf"
This tool also has a long form version that allows for configurable search paths. Here's an example::

View File

@ -55,7 +55,7 @@ entered value so you can use it, for instance, with the user module to define a
- name: "my_password2"
prompt: "Enter password2"
private: yes
encrypt: "sha512_crypt"
encrypt: "md5_crypt"
confirm: yes
salt_size: 7

View File

@ -61,19 +61,19 @@ For instance, if deploying multiple wordpress instances, I could
contain all of my wordpress tasks in a single wordpress.yml file, and use it like so::
tasks:
- include: wordpress.yml wp_user=timmy
- include: wordpress.yml wp_user=alice
- include: wordpress.yml wp_user=bob
- include: wordpress.yml user=timmy
- include: wordpress.yml user=alice
- include: wordpress.yml user=bob
If you are running Ansible 1.4 and later, include syntax is streamlined to match roles, and also allows passing list and dictionary parameters::
tasks:
- { include: wordpress.yml, wp_user: timmy, ssh_keys: [ 'keys/one.txt', 'keys/two.txt' ] }
- { include: wordpress.yml, user: timmy, ssh_keys: [ 'keys/one.txt', 'keys/two.txt' ] }
Using either syntax, variables passed in can then be used in the included files. We'll cover them in :doc:`playbooks_variables`.
Using either syntax, variables passed in can then be used in the included files. We've already covered them a bit in :doc:`playbooks_variables`.
You can reference them like this::
{{ wp_user }}
{{ user }}
(In addition to the explicitly passed-in parameters, all variables from
the vars section are also available for use here as well.)
@ -85,7 +85,7 @@ which also supports structured variables::
- include: wordpress.yml
vars:
wp_user: timmy
remote_user: timmy
some_list_variable:
- alpha
- beta
@ -153,7 +153,7 @@ Roles
.. versionadded:: 1.2
Now that you have learned about tasks and handlers, what is the best way to organize your playbooks?
Now that you have learned about vars_files, tasks, and handlers, what is the best way to organize your playbooks?
The short answer is to use roles! Roles are ways of automatically loading certain vars_files, tasks, and
handlers based on a known file structure. Grouping content by roles also allows easy sharing of roles with other users.
@ -172,7 +172,6 @@ Example project structure::
tasks/
handlers/
vars/
defaults/
meta/
webservers/
files/
@ -180,7 +179,6 @@ Example project structure::
tasks/
handlers/
vars/
defaults/
meta/
In a playbook, it would look like this::
@ -212,7 +210,7 @@ If any files are not present, they are just ignored. So it's ok to not have a '
for instance.
Note, you are still allowed to list tasks, vars_files, and handlers "loose" in playbooks without using roles,
but roles are a good organizational feature and are highly recommended. If there are loose things in the playbook,
but roles are a good organizational feature and are highly recommended. if there are loose things in the playbook,
the roles are evaluated first.
Also, should you wish to parameterize roles, by adding variables, you can do so, like this::
@ -301,13 +299,6 @@ Role dependencies can also be specified as a full path, just like top level role
dependencies:
- { role: '/path/to/common/roles/foo', x: 1 }
Role dependencies can also be installed from source control repos or tar files, using a comma separated format of path, an optional version (tag, commit, branch etc) and optional friendly role name (an attempt is made to derive a role name from the repo name or archive filename)::
---
dependencies:
- { role: 'git+http://git.example.com/repos/role-foo,v1.1,foo' }
- { role: '/path/to/tar/file.tgz,,friendly-name' }
Roles dependencies are always executed before the role that includes them, and are recursive. By default,
roles can also only be added as a dependency once - if another role also lists it as a dependency it will
not be run again. This behavior can be overridden by adding `allow_duplicates: yes` to the `meta/main.yml` file.
@ -342,45 +333,10 @@ The resulting order of execution would be as follows::
.. note::
Variable inheritance and scope are detailed in the :doc:`playbooks_variables`.
Embedding Modules In Roles
``````````````````````````
This is an advanced topic that should not be relevant for most users.
If you write a custom module (see :doc:`developing_modules`) you may wish to distribute it as part of a role. Generally speaking, Ansible as a project is very interested
in taking high-quality modules into ansible core for inclusion, so this shouldn't be the norm, but it's quite easy to do.
A good example for this is if you worked at a company called AcmeWidgets, and wrote an internal module that helped configure your internal software, and you wanted other
people in your organization to easily use this module -- but you didn't want to tell everyone how to configure their Ansible library path.
Alongside the 'tasks' and 'handlers' structure of a role, add a directory named 'library'. In this 'library' directory, then include the module directly inside of it.
Assuming you had this::
roles/
my_custom_modules/
library/
module1
module2
The module will be usable in the role itself, as well as any roles that are called *after* this role, as follows::
- hosts: webservers
roles:
- my_custom_modules
- some_other_role_using_my_custom_modules
- yet_another_role_using_my_custom_modules
This can also be used, with some limitations, to modify modules in Ansible's core distribution, such as to use development versions of modules before they are released
in production releases. This is not always advisable as API signatures may change in core components, however, and is not always guaranteed to work. It can be a handy
way of carrying a patch against a core module, however, should you have good reason for this. Naturally the project prefers that contributions be directed back
to github whenever possible via a pull request.
Ansible Galaxy
``````````````
`Ansible Galaxy <http://galaxy.ansible.com>`_ is a free site for finding, downloading, rating, and reviewing all kinds of community developed Ansible roles and can be a great way to get a jumpstart on your automation projects.
`Ansible Galaxy <http://galaxy.ansible.com>`_, is a free site for finding, downloading, rating, and reviewing all kinds of community developed Ansible roles and can be a great way to get a jumpstart on your automation projects.
You can sign up with social auth, and the download client 'ansible-galaxy' is included in Ansible 1.4.2 and later.
@ -388,8 +344,6 @@ Read the "About" page on the Galaxy site for more information.
.. seealso::
:doc:`galaxy`
How to share roles on galaxy, role management
:doc:`YAMLSyntax`
Learn about YAML syntax
:doc:`playbooks`

View File

@ -17,4 +17,3 @@ and adopt these only if they seem relevant or useful to your environment.
playbooks_prompts
playbooks_tags
playbooks_vault
playbooks_startnstep

View File

@ -1,34 +0,0 @@
Start and Step
======================
This shows a few alternative ways to run playbooks. These modes are very useful for testing new plays or debugging.
.. _start_at_task
Start-at-task
`````````````
If you want to start executing your playbook at a particular task, you can do so with the ``--start-at`` option::
ansible-playbook playbook.yml --start-at="install packages"
The above will start executing your playbook at a task named "install packages".
.. _step
Step
````
Playbooks can also be executed interactively with ``--step``::
ansible-playbook playbook.yml --step
This will cause ansible to stop on each task, and ask if it should execute that task.
Say you had a task called "configure ssh", the playbook run will stop and ask::
Perform task: configure ssh (y/n/c):
Answering "y" will execute the task, answering "n" will skip the task, and answering "c"
will continue executing all the remaining tasks without asking.

View File

@ -5,17 +5,19 @@ Variables
While automation exists to make it easier to make things repeatable, all of your systems are likely not exactly alike.
On some systems you may want to set some behavior or configuration that is slightly different from others.
All of your systems are likely not the same. On some systems you may want to set some behavior
or configuration that is slightly different from others.
Also, some of the observed behavior or state
of remote systems might need to influence how you configure those systems. (Such as you might need to find out the IP
address of a system and even use it as a configuration value on another system).
You might have some templates for configuration files that are mostly the same, but slightly different based on those variables.
You might have some templates for configuration files that are mostly the same, but slightly different
based on those variables.
Variables in Ansible are how we deal with differences between systems.
To understand variables you'll also want to dig into :doc:`playbooks_conditionals` and :doc:`playbooks_loops`.
Once understanding variables you'll also want to dig into :doc:`playbooks_conditionals` and :doc:`playbooks_loops`.
Useful things like the "group_by" module
and the "when" conditional can also be used with variables, and to help manage differences between systems.
@ -41,7 +43,7 @@ Easy enough, let's move on.
Variables Defined in Inventory
``````````````````````````````
We've actually already covered a lot about variables in another section, so far this shouldn't be terribly new, but
We've actually already covered a lot about variables in another section, so so far this shouldn't be terribly new, but
a bit of a refresher.
Often you'll want to set variables based on what groups a machine is in. For instance, maybe machines in Boston
@ -91,7 +93,7 @@ And that will provide the most basic form of variable substitution.
This is also valid directly in playbooks, and you'll occasionally want to do things like::
template: src=foo.cfg.j2 dest={{ remote_install_path }}/foo.cfg
template: src=foo.cfg.j2 dest={{ remote_install_path}}/foo.cfg
In the above example, we used a variable to help decide where to place a file.
@ -99,7 +101,7 @@ Inside a template you automatically have access to all of the variables that are
it's more than that -- you can also read variables about other hosts. We'll show how to do that in a bit.
.. note:: ansible allows Jinja2 loops and conditionals in templates, but in playbooks, we do not use them. Ansible
playbooks are pure machine-parseable YAML. This is a rather important feature as it means it is possible to code-generate
templates are pure machine-parseable YAML. This is an rather important feature as it means it is possible to code-generate
pieces of files, or to have other ecosystem tools read Ansible files. Not everyone will need this but it can unlock
possibilities.
@ -171,55 +173,17 @@ The variable value will be used as is, but the template evaluation will raise an
Defaulting Undefined Variables
------------------------------
Jinja2 provides a useful 'default' filter, that is often a better approach to failing if a variable is not defined::
Jinja2 provides a useful 'default' filter, that is often a better approach to failing if a variable is not defined.
{{ some_variable | default(5) }}
In the above example, if the variable 'some_variable' is not defined, the value used will be 5, rather than an error
being raised.
.. _omitting_undefined_variables:
Omitting Undefined Variables and Parameters
-------------------------------------------
As of Ansible 1.8, it is possible to use the default filter to omit variables and module parameters using the special
`omit` variable::
- name: touch files with an optional mode
file: dest={{item.path}} state=touch mode={{item.mode|default(omit)}}
with_items:
- path: /tmp/foo
- path: /tmp/bar
- path: /tmp/baz
mode: "0444"
For the first two files in the list, the default mode will be determined by the umask of the system as the `mode=`
parameter will not be sent to the file module while the final file will receive the `mode=0444` option.
.. _list_filters:
List Filters
------------
These filters all operate on list variables.
.. versionadded:: 1.8
To get the minimum value from list of numbers::
{{ list1 | min }}
To get the maximum value from a list of numbers::
{{ [3, 4, 2] | max }}
.. _set_theory_filters:
Set Theory Filters
------------------
--------------------
All these functions return a unique set from sets or lists.
.. versionadded:: 1.4
@ -244,85 +208,14 @@ To get the symmetric difference of 2 lists (items exclusive to each list)::
{{ list1 | symmetric_difference(list2) }}
.. _version_comparison_filters:
Version Comparison Filters
--------------------------
.. versionadded:: 1.6
To compare a version number, such as checking if the ``ansible_distribution_version``
version is greater than or equal to '12.04', you can use the ``version_compare`` filter.
The ``version_compare`` filter can also be used to evaluate the ``ansible_distribution_version``::
{{ ansible_distribution_version | version_compare('12.04', '>=') }}
If ``ansible_distribution_version`` is greater than or equal to 12, this filter will return True, otherwise it will return False.
The ``version_compare`` filter accepts the following operators::
<, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne
This filter also accepts a 3rd parameter, ``strict`` which defines if strict version parsing should
be used. The default is ``False``, and if set as ``True`` will use more strict version parsing::
{{ sample_version_var | version_compare('1.0', operator='lt', strict=True) }}
.. _random_filter:
Random Number Filter
--------------------
.. versionadded:: 1.6
This filter can be used similar to the default jinja2 random filter (returning a random item from a sequence of
items), but can also generate a random number based on a range.
To get a random item from a list::
{{ ['a','b','c']|random }} => 'c'
To get a random number from 0 to supplied end::
{{ 59 |random}} * * * * root /script/from/cron
Get a random number from 0 to 100 but in steps of 10::
{{ 100 |random(step=10) }} => 70
Get a random number from 1 to 100 but in steps of 10::
{{ 100 |random(1, 10) }} => 31
{{ 100 |random(start=1, step=10) }} => 51
Shuffle Filter
--------------
.. versionadded:: 1.8
This filter will randomize an existing list, giving a different order every invocation.
To get a random list from an existing list::
{{ ['a','b','c']|shuffle }} => ['c','a','b']
{{ ['a','b','c']|shuffle }} => ['b','c','a']
note that when used with a non 'listable' item it is a noop, otherwise it always returns a list
.. _other_useful_filters:
Other Useful Filters
--------------------
To concatenate a list into a string::
{{ list | join(" ") }}
To get the last name of a file path, like 'foo.txt' out of '/etc/asdf/foo.txt'::
{{ path | basename }}
{{ path | basename }}
To get the directory from a path::
@ -332,18 +225,14 @@ To expand a path containing a tilde (`~`) character (new in version 1.5)::
{{ path | expanduser }}
To get the real path of a link (new in version 1.8)::
{{ path | readlink }}
To work with Base64 encoded strings::
{{ encoded | b64decode }}
{{ decoded | b64encode }}
To take a sha1sum of a filename::
To take an md5sum of a filename::
{{ filename | sha1 }}
{{ filename | md5 }}
To cast values as certain types, such as when you input a string as "True" from a vars_prompt and the system
doesn't know it is a boolean value::
@ -351,28 +240,6 @@ doesn't know it is a boolean value::
- debug: msg=test
when: some_string_value | bool
To match strings against a regex, use the "match" or "search" filter::
vars:
url: "http://example.com/users/foo/resources/bar"
tasks:
- shell: "msg='matched pattern 1'"
when: url | match("http://example.com/users/.*/resources/.*")
- debug: "msg='matched pattern 2'"
when: url | search("/users/.*/resources/.*")
'match' will require a complete match in the string, while 'search' will require a match inside of the string.
To replace text in a string with regex, use the "regex_replace" filter::
# convert "ansible" to "able"
{{ 'ansible' | regex_replace('^a.*i(.*)$', 'a\\1') }}
# convert "foobar" to "bar"
{{ 'foobar' | regex_replace('^f.*o(.*)$', '\\1') }}
A few useful filters are typically added with each new Ansible release. The development documentation shows
how to extend Ansible filters by writing your own as plugins, though in general, we encourage new ones
to be added to core so everyone can make use of them.
@ -675,7 +542,6 @@ Local Facts (Facts.d)
.. versionadded:: 1.3
As discussed in the playbooks chapter, Ansible facts are a way of getting data about remote systems for use in playbook variables.
Usually these are discovered automatically by the 'setup' module in Ansible. Users can also write custom facts modules, as described
in the API guide. However, what if you want to have a simple way to provide system or user
provided data for use in Ansible variables, without writing a fact module?
@ -703,7 +569,7 @@ And you will see the following fact added::
"ansible_local": {
"preferences": {
"general": {
"asdf" : "1",
"asdf" : "1",
"bar" : "2"
}
}
@ -716,62 +582,6 @@ And this data can be accessed in a template/playbook as::
The local namespace prevents any user supplied fact from overriding system facts
or variables defined elsewhere in the playbook.
If you have a playbook that is copying over a custom fact and then running it, making an explicit call to re-run the setup module
can allow that fact to be used during that particular play. Otherwise, it will be available in the next play that gathers fact information.
Here is an example of what that might look like::
- hosts: webservers
tasks:
- name: create directory for ansible custom facts
file: state=directory recurse=yes path=/etc/ansible/facts.d
- name: install custom impi fact
copy: src=ipmi.fact dest=/etc/ansible/facts.d
- name: re-read facts after adding custom fact
setup: filter=ansible_local
In this pattern however, you could also write a fact module as well, and may wish to consider this as an option.
.. _fact_caching:
Fact Caching
````````````
.. versionadded:: 1.8
As shown elsewhere in the docs, it is possible for one server to reference variables about another, like so::
{{ hostvars['asdf.example.com']['ansible_os_family'] }}
With "Fact Caching" disabled, in order to do this, Ansible must have already talked to 'asdf.example.com' in the
current play, or another play up higher in the playbook. This is the default configuration of ansible.
To avoid this, Ansible 1.8 allows the ability to save facts between playbook runs, but this feature must be manually
enabled. Why might this be useful?
Imagine, for instance, a very large infrastructure with thousands of hosts. Fact caching could be configured to run nightly, but
configuration of a small set of servers could run ad-hoc or periodically throughout the day. With fact-caching enabled, it would
not be necessary to "hit" all servers to reference variables and information about them.
With fact caching enabled, it is possible for machine in one group to reference variables about machines in the other group, despite
the fact that they have not been communicated with in the current execution of /usr/bin/ansible-playbook.
To configure fact caching, enable it in ansible.cfg as follows::
[defaults]
fact_caching = redis
fact_caching_timeout = 86400 # seconds
At the time of writing, Redis is the only supported fact caching engine.
To get redis up and running, perform the equivalent OS commands::
yum install redis
service redis start
pip install redis
Note that the Python redis library should be installed from pip, the version packaged in EPEL is too old for use by Ansible.
In current embodiments, this feature is in beta-level state and the Redis plugin does not support port or password configuration, this is expected to change in the near future.
.. _registered_variables:
Registered Variables
@ -856,7 +666,6 @@ A frequently used idiom is walking a group to find all IP addresses in that grou
{% endfor %}
An example of this could include pointing a frontend proxy server to all of the app servers, setting up the correct firewall rules between servers, etc.
You need to make sure that the facts of those hosts have been populated before though, for example by running a play against them if the facts have not been cached recently (fact caching was added in Ansible 1.8).
Additionally, *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
@ -865,13 +674,11 @@ period, without the rest of the domain.
*play_hosts* is available as a list of hostnames that are in scope for the current play. This may be useful for filling out templates with multiple hostnames or for injecting the list into the rules for a load balancer.
*delegate_to* is the inventory hostname of the host that the current task has been delegated to using 'delegate_to'.
Don't worry about any of this unless you think you need it. You'll know when you do.
Also available, *inventory_dir* is the pathname of the directory holding Ansible's inventory host file, *inventory_file* is the pathname and the filename pointing to the Ansible's inventory host file.
.. _variable_file_separation_details:
.. _variable_file_seperation_details:
Variable File Separation
````````````````````````
@ -950,6 +757,64 @@ As of Ansible 1.3, extra vars can be loaded from a JSON file with the "@" syntax
Also as of Ansible 1.3, extra vars can be formatted as YAML, either on the command line
or in a file as above.
.. _conditional_imports:
Conditional Imports
```````````````````
.. note:: This behavior is infrequently used in Ansible. You may wish to skip this section. The 'group_by' module as described in the module documentation is a better way to achieve this behavior in most cases.
Sometimes you will want to do certain things differently in a playbook based on certain criteria.
Having one playbook that works on multiple platforms and OS versions is a good example.
As an example, the name of the Apache package may be different between CentOS and Debian,
but it is easily handled with a minimum of syntax in an Ansible Playbook::
---
- hosts: all
remote_user: root
vars_files:
- "vars/common.yml"
- [ "vars/{{ ansible_os_family }}.yml", "vars/os_defaults.yml" ]
tasks:
- name: make sure apache is running
service: name={{ apache }} state=running
.. note::
The variable 'ansible_os_family' is being interpolated into
the list of filenames being defined for vars_files.
As a reminder, the various YAML files contain just keys and values::
---
# for vars/CentOS.yml
apache: httpd
somethingelse: 42
How does this work? If the operating system was 'CentOS', the first file Ansible would try to import
would be 'vars/CentOS.yml', followed by '/vars/os_defaults.yml' if that file
did not exist. If no files in the list were found, an error would be raised.
On Debian, it would instead first look towards 'vars/Debian.yml' instead of 'vars/CentOS.yml', before
falling back on 'vars/os_defaults.yml'. Pretty simple.
To use this conditional import feature, you'll need facter or ohai installed prior to running the playbook, but
you can of course push this out with Ansible if you like::
# for facter
ansible -m yum -a "pkg=facter ensure=installed"
ansible -m yum -a "pkg=ruby-json ensure=installed"
# for ohai
ansible -m yum -a "pkg=ohai ensure=installed"
Ansible's approach to configuration -- separating variables from tasks, keeps your playbooks
from turning into arbitrary code with ugly nested ifs, conditionals, and so on - and results
in more streamlined & auditable configuration rules -- especially because there are a
minimum of decision points to track.
.. _variable_precedence:
Variable Precedence: Where Should I Put A Variable?
@ -969,15 +834,11 @@ a use for it.
If multiple variables of the same name are defined in different places, they win in a certain order, which is::
* extra vars (-e in the command line) always win
* then comes connection variables defined in inventory (ansible_ssh_user, etc)
* then comes "most everything else" (command line switches, vars in play, included vars, etc)
* then comes the rest of the variables defined in inventory
* then comes facts discovered about a system
* -e variables always win
* then comes "most everything else"
* then comes variables defined in inventory
* then "role defaults", which are the most "defaulty" and lose in priority to everything.
.. note:: In versions prior to 1.5.4, facts discovered about a system were in the "most everything else" category above.
That seems a little theoretical. Let's show some examples and where you would choose to put what based on the kind of
control you might want over values.
@ -1019,11 +880,11 @@ See :doc:`playbooks_roles` for more info about this::
---
# file: roles/x/defaults/main.yml
# if not overridden in inventory or as a parameter, this is the value that will be used
# if not overriden in inventory or as a parameter, this is the value that will be used
http_port: 80
if you are writing a role and want to ensure the value in the role is absolutely used in that role, and is not going to be overridden
by inventory, you should put it in roles/x/vars/main.yml like so, and inventory values cannot override it. -e however, still will::
by inventory, you should but it in roles/x/vars/main.yml like so, and inventory values cannot override it. -e however, still will::
---
# file: roles/x/vars/main.yml
@ -1070,7 +931,7 @@ can set variables in there and make use of them in other roles and elsewhere in
- { role: something_else }
.. note:: There are some protections in place to avoid the need to namespace variables.
In the above, variables defined in common_settings are most definitely available to 'something' and 'something_else' tasks, but if
In the above, variables defined in common_settings are most definitely available to 'app_user' and 'something_else' tasks, but if
"something's" guaranteed to have foo set at 12, even if somewhere deep in common settings it set foo to 20.
So, that's precedence, explained in a more direct way. Don't worry about precedence, just think about if your role is defining a

View File

@ -14,7 +14,7 @@ What Can Be Encrypted With Vault
The vault feature can encrypt any structured data file used by Ansible. This can include "group_vars/" or "host_vars/" inventory variables, variables loaded by "include_vars" or "vars_files", or variable files passed on the ansible-playbook command line with "-e @file.yml" or "-e @file.json". Role variables and defaults are also included!
Because Ansible tasks, handlers, and so on are also data, these can also be encrypted with vault. If you'd like to not betray what variables you are even using, you can go as far to keep an individual task file entirely encrypted. However, that might be a little much and could annoy your coworkers :)
Because Ansible tasks, handlers, and so on are also data, these two can also be encrypted with vault. If you'd like to not betray what variables you are even using, you can go as far to keep an individual task file entirely encrypted. However, that might be a little much and could annoy your coworkers :)
.. _creating_files:
@ -83,17 +83,13 @@ To run a playbook that contains vault-encrypted data files, you must pass one of
This prompt will then be used to decrypt (in memory only) any vault encrypted files that are accessed. Currently this requires that all passwords be encrypted with the same password.
Alternatively, passwords can be specified with a file or a script, the script version will require Ansible 1.7 or later. When using this flag, ensure permissions on the file are such that no one else can access your key and do not add your key to source control::
Alternatively, passwords can be specified with a file. If this is done, be careful to ensure permissions on the file are such that no one else can access your key, and do not add your key to source control::
ansible-playbook site.yml --vault-password-file ~/.vault_pass.txt
ansible-playbook site.yml --vault-password-file ~/.vault_pass.py
The password should be a string stored as a single line in the file.
If you are using a script instead of a flat file, ensure that it is marked as executable, and that the password is printed to standard output. If your script needs to prompt for data, prompts can be sent to standard error.
This is something you may wish to do if using Ansible from a continuous integration system like Jenkins.
This is likely something you may wish to do if using Ansible from a continuous integration system like Jenkins.
(The `--vault-password-file` option can also be used with the :ref:`ansible-pull` command if you wish, though this would require distributing the keys to your nodes, so understand the implications -- vault is more intended for push mode).

View File

@ -3,7 +3,7 @@ Quickstart Video
We've recorded a short video that shows how to get started with Ansible that you may like to use alongside the documentation.
The `quickstart video <http://ansible.com/ansible-resources>`_ is about 30 minutes long and will show you some of the basics about your
The `quickstart video <http://ansible.com/ansible-resources>`_ is about 20 minutes long and will show you some of the basics about your
first steps with Ansible.
Enjoy, and be sure to visit the rest of the documentation to learn more.

View File

@ -1,264 +0,0 @@
Testing Strategies
==================
.. _testing_intro:
Integrating Testing With Ansible Playbooks
``````````````````````````````````````````
Many times, people ask, "how can I best integrate testing with Ansible playbooks?" There are many options. Ansible is actually designed
to be a "fail-fast" and ordered system, therefore it makes it easy to embed testing directly in Ansible playbooks. In this chapter,
we'll go into some patterns for integrating tests of infrastructure and discuss the right level of testing that may be appropriate.
.. note:: This is a chapter about testing the application you are deploying, not the chapter on how to test Ansible modules during development. For that content, please hop over to the Development section.
By incorporating a degree of testing into your deployment workflow, there will be fewer surprises when code hits production and, in many cases,
tests can be leveraged in production to prevent failed updates from migrating across an entire installation. Since it's push-based, it's
also very easy to run the steps on the localhost or testing servers. Ansible lets you insert as many checks and balances into your upgrade workflow as you would like to have.
The Right Level of Testing
``````````````````````````
Ansible resources are models of desired-state. As such, it should not be necessary to test that services are running, packages are
installed, or other such things. Ansible is the system that will ensure these things are declaratively true. Instead, assert these
things in your playbooks.
.. code-block:: yaml
tasks:
- service: name=foo state=running enabled=yes
If you think the service may not be running, the best thing to do is request it to be running. If the service fails to start, Ansible
will yell appropriately. (This should not be confused with whether the service is doing something functional, which we'll show more about how to
do later).
Check Mode As A Drift Test
``````````````````````````
In the above setup, `--check` mode in Ansible can be used as a layer of testing as well. If running a deployment playbook against an
existing system, using the `--check` flag to the `ansible` command will report if Ansible thinks it would have had to have made any changes to
bring the system into a desired state.
This can let you know up front if there is any need to deploy onto the given system. Ordinarily scripts and commands don't run in check mode, so if you
want certain steps to always execute in check mode, such as calls to the script module, add the 'always_run' flag::
roles:
- webserver
tasks:
- script: verify.sh
always_run: True
Modules That Are Useful for Testing
```````````````````````````````````
Certain playbook modules are particularly good for testing. Below is an example that ensures a port is open::
tasks:
- wait_for: host={{ inventory_hostname }} port=22
delegate_to: localhost
Here's an example of using the URI module to make sure a web service returns::
tasks:
- action: uri url=http://www.example.com return_content=yes
register: webpage
- fail: msg='service is not happy'
when: "'AWESOME' not in webpage.content"
It's easy to push an arbitrary script (in any language) on a remote host and the script will automatically fail if it has a non-zero return code::
tasks:
- script: test_script1
- script: test_script2 --parameter value --parameter2 value
If using roles (you should be, roles are great!), scripts pushed by the script module can live in the 'files/' directory of a role.
And the assert module makes it very easy to validate various kinds of truth::
tasks:
- shell: /usr/bin/some-command --parameter value
register: cmd_result
- assert:
that:
- "'not ready' not in cmd_result.stderr"
- "'gizmo enabled' in cmd_result.stdout"
Should you feel the need to test for existence of files that are not declaratively set by your Ansible configuration, the 'stat' module is a great choice::
tasks:
- stat: path=/path/to/something
register: p
- assert:
that:
- p.stat.exists and p.stat.isdir
As mentioned above, there's no need to check things like the return codes of commands. Ansible is checking them automatically.
Rather than checking for a user to exist, consider using the user module to make it exist.
Ansible is a fail-fast system, so when there is an error creating that user, it will stop the playbook run. You do not have
to check up behind it.
Testing Lifecycle
`````````````````
If writing some degree of basic validation of your application into your playbooks, they will run every time you deploy.
As such, deploying into a local development VM and a stage environment will both validate that things are according to plan
ahead of your production deploy.
Your workflow may be something like this::
- Use the same playbook all the time with embedded tests in development
- Use the playbook to deploy to a stage environment (with the same playbooks) that simulates production
- Run an integration test battery written by your QA team against stage
- Deploy to production, with the same integrated tests.
Something like an integration test battery should be written by your QA team if you are a production webservice. This would include
things like Selenium tests or automated API tests and would usually not be something embedded into your Ansible playbooks.
However, it does make sense to include some basic health checks into your playbooks, and in some cases it may be possible to run
a subset of the QA battery against remote nodes. This is what the next section covers.
Integrating Testing With Rolling Updates
````````````````````````````````````````
If you have read into :doc:`playbooks_delegation` it may quickly become apparent that the rolling update pattern can be extended, and you
can use the success or failure of the playbook run to decide whether to add a machine into a load balancer or not.
This is the great culmination of embedded tests::
---
- hosts: webservers
serial: 5
pre_tasks:
- name: take out of load balancer pool
command: /usr/bin/take_out_of_pool {{ inventory_hostname }}
delegate_to: 127.0.0.1
roles:
- common
- webserver
- apply_testing_checks
post_tasks:
- name: add back to load balancer pool
command: /usr/bin/add_back_to_pool {{ inventory_hostname }}
delegate_to: 127.0.0.1
Of course in the above, the "take out of the pool" and "add back" steps would be replaced with a call to a Ansible load balancer
module or appropriate shell command. You might also have steps that use a monitoring module to start and end an outage window
for the machine.
However, what you can see from the above is that tests are used as a gate -- if the "apply_testing_checks" step is not performed,
the machine will not go back into the pool.
Read the delegation chapter about "max_fail_percentage" and you can also control how many failing tests will stop a rolling update
from proceeding.
This above approach can also be modified to run a step from a testing machine remotely against a machine::
---
- hosts: webservers
serial: 5
pre_tasks:
- name: take out of load balancer pool
command: /usr/bin/take_out_of_pool {{ inventory_hostname }}
delegate_to: 127.0.0.1
roles:
- common
- webserver
tasks:
- script: /srv/qa_team/app_testing_script.sh --server {{ inventory_hostname }}
delegate_to: testing_server
post_tasks:
- name: add back to load balancer pool
command: /usr/bin/add_back_to_pool {{ inventory_hostname }}
delegate_to: 127.0.0.1
In the above example, a script is run from the testing server against a remote node prior to bringing it back into
the pool.
In the event of a problem, fix the few servers that fail using Ansible's automatically generated
retry file to repeat the deploy on just those servers.
Achieving Continuous Deployment
```````````````````````````````
If desired, the above techniques may be extended to enable continuous deployment practices.
The workflow may look like this::
- Write and use automation to deploy local development VMs
- Have a CI system like Jenkins deploy to a stage environment on every code change
- The deploy job calls testing scripts to pass/fail a build on every deploy
- If the deploy job succeeds, it runs the same deploy playbook against production inventory
Some Ansible users use the above approach to deploy a half-dozen or dozen times an hour without taking all of their infrastructure
offline. A culture of automated QA is vital if you wish to get to this level.
If you are still doing a large amount of manual QA, you should still make the decision on whether to deploy manually as well, but
it can still help to work in the rolling update patterns of the previous section and incorporate some basic health checks using
modules like 'script', 'stat', 'uri', and 'assert'.
Conclusion
``````````
Ansible believes you should not need another framework to validate basic things of your infrastructure is true. This is the case
because Ansible is an order-based system that will fail immediately on unhandled errors for a host, and prevent further configuration
of that host. This forces errors to the top and shows them in a summary at the end of the Ansible run.
However, as Ansible is designed as a multi-tier orchestration system, it makes it very easy to incorporate tests into the end of
a playbook run, either using loose tasks or roles. When used with rolling updates, testing steps can decide whether to put a machine
back into a load balanced pool or not.
Finally, because Ansible errors propagate all the way up to the return code of the Ansible program itself, and Ansible by default
runs in an easy push-based mode, Ansible is a great step to put into a build environment if you wish to use it to roll out systems
as part of a Continuous Integration/Continuous Delivery pipeline, as is covered in sections above.
The focus should not be on infrastructure testing, but on application testing, so we strongly encourage getting together with your
QA team and ask what sort of tests would make sense to run every time you deploy development VMs, and which sort of tests they would like
to run against the stage environment on every deploy. Obviously at the development stage, unit tests are great too. But don't unit
test your playbook. Ansible describes states of resources declaratively, so you don't have to. If there are cases where you want
to be sure of something though, that's great, and things like stat/assert are great go-to modules for that purpose.
In all, testing is a very organizational and site-specific thing. Everybody should be doing it, but what makes the most sense for your
environment will vary with what you are deploying and who is using it -- but everyone benefits from a more robust and reliable deployment
system.
.. seealso::
:doc:`modules`
All the documentation for Ansible modules
:doc:`playbooks`
An introduction to playbooks
:doc:`playbooks_delegation`
Delegation, useful for working with loud balancers, clouds, and locally executed steps.
`User Mailing List <http://groups.google.com/group/ansible-project>`_
Have a question? Stop by the google group!
`irc.freenode.net <http://irc.freenode.net>`_
#ansible IRC chat channel

View File

@ -1,10 +1,10 @@
Ansible Tower
`````````````
`Ansible Tower <http://ansible.com/tower>`_ (formerly 'AWX') is a web-based solution that makes Ansible even more easy to use for IT teams of all kinds. It's designed to be the hub for all of your automation tasks.
`Ansible Tower <http://ansible.com/ansible-tower>`_ (formerly 'AWX') is a web-based solution that makes Ansible even more easy to use for IT teams of all kinds. It's designed to be the hub for all of your automation tasks.
Tower allows you to control access to who can access what, even allowing sharing of SSH credentials without someone being able to transfer those credentials. Inventory can be graphically managed or synced with a wide variety of cloud sources. It logs all of your jobs, integrates well with LDAP, and has an amazing browsable REST API. Command line tools are available for easy integration with Jenkins as well. Provisioning callbacks provide great support for autoscaling topologies.
Find out more about Tower features and how to download it on the `Ansible Tower webpage <http://ansible.com/tower>`_. Tower
is free for usage for up to 10 nodes, and comes bundled with amazing support from Ansible, Inc. As you would expect, Tower is
Find out more about Tower features and how to download it on the `Ansible Tower webpage <http://ansible.com/ansible-tower>`_. Tower
is free for usage for up to 10 nodes, and comes bundled with amazing support from Ansible, Inc. As you would expect, Ansible is
installed using Ansible playbooks!

View File

@ -1,38 +0,0 @@
digraph G {
subgraph cluster_0 {
"command line variables" -> "--extra-args"
}
subgraph cluster_1 {
"role variables" -> "roles/rolename/vars.yml" -> "parameters passed to role" -> "parameters from dependent roles"
}
subgraph cluster_2 {
"top-level playbook variables" -> "vars: directives" -> "vars_files: directives";
}
subgraph cluster_3 {
"inventory variables" -> "group_vars/all" -> "group_vars/grandparent1" -> "group_vars/parent1" -> "host_vars/myhostname";
"group_vars/all" -> "group_vars/grandparent2";
"group_vars/grandparent1" -> "group_vars/parent2"
"group_vars/grandparent2" -> "host_vars/myhostname";
"group_vars/parent2" -> "host_vars/myhostname"
}
subgraph cluster_4 {
"facts" -> "gathered host facts"
"facts" -> "host facts from /etc/ansible/facts.d"
"facts" -> "set_fact"
"facts" -> "include_vars"
}
subgraph cluster_5 {
"role defaults" -> "roles/rolename/defaults.yml"
}
"command line variables" -> "role variables" -> "top-level playbook variables" -> "inventory variables" -> "role defaults" -> "facts"
}

View File

@ -12,7 +12,7 @@
# some basic default values...
hostfile = /etc/ansible/hosts
# library_path = /usr/share/my_modules/
library = /usr/share/ansible
remote_tmp = $HOME/.ansible/tmp
pattern = *
forks = 5
@ -22,17 +22,8 @@ sudo_user = root
#ask_pass = True
transport = smart
remote_port = 22
module_lang = C
# plays will gather facts by default, which contain information about
# the remote system.
#
# smart - gather by default, but don't regather if already gathered
# implicit - gather by default, turn off with gather_facts: False
# explicit - do not gather by default, must say gather_facts: True
gathering = implicit
# additional paths to search for roles in, colon separated
# additional paths to search for roles in, colon seperated
#roles_path = /etc/ansible/roles
# uncomment this to disable SSH key host checking
@ -68,6 +59,11 @@ timeout = 10
# this can also be set to 'merge'.
#hash_behaviour = replace
# How to handle variable replacement - as of 1.2, Jinja2 variable syntax is
# preferred, but we still support the old $variable replacement too.
# Turn off ${old_style} variables here if you like.
#legacy_playbook_variables = yes
# list any Jinja2 extensions to enable here:
#jinja2_extensions = jinja2.ext.do,jinja2.ext.i18n
@ -91,27 +87,7 @@ ansible_managed = Ansible managed: {file} modified on %Y-%m-%d %H:%M:%S by {uid}
# to revert the behavior to pre-1.3.
#error_on_undefined_vars = False
# by default (as of 1.6), Ansible may display warnings based on the configuration of the
# system running ansible itself. This may include warnings about 3rd party packages or
# other conditions that should be resolved if possible.
# to disable these warnings, set the following value to False:
#system_warnings = True
# by default (as of 1.4), Ansible may display deprecation warnings for language
# features that should no longer be used and will be removed in future versions.
# to disable these warnings, set the following value to False:
#deprecation_warnings = True
# (as of 1.8), Ansible can optionally warn when usage of the shell and
# command module appear to be simplified by using a default Ansible module
# instead. These warnings can be silenced by adjusting the following
# setting or adding warn=yes or warn=no to the end of the command line
# parameter string. This will for example suggest using the git module
# instead of shelling out to the git command.
# command_warnings = False
# set plugin path directories here, separate with colons
# set plugin path directories here, seperate with colons
action_plugins = /usr/share/ansible_plugins/action_plugins
callback_plugins = /usr/share/ansible_plugins/callback_plugins
connection_plugins = /usr/share/ansible_plugins/connection_plugins
@ -119,12 +95,6 @@ lookup_plugins = /usr/share/ansible_plugins/lookup_plugins
vars_plugins = /usr/share/ansible_plugins/vars_plugins
filter_plugins = /usr/share/ansible_plugins/filter_plugins
# by default callbacks are not loaded for /bin/ansible, enable this if you
# want, for example, a notification or logging callback to also apply to
# /bin/ansible runs
#bin_ansible_callbacks = False
# don't like cows? that's unfortunate.
# set to 1 if you don't want cowsay support or export ANSIBLE_NOCOWS=1
#nocows = 1
@ -147,13 +117,6 @@ filter_plugins = /usr/share/ansible_plugins/filter_plugins
# avoid issues.
#http_user_agent = ansible-agent
# if set to a persistant type (not 'memory', for example 'redis') fact values
# from previous runs in Ansible will be stored. This may be useful when
# wanting to use, for example, IP information from one group of servers
# without having to talk to them in the same playbook run to get their
# current IP information.
fact_caching = memory
[paramiko_connection]
# uncomment this line to cause the paramiko connection plugin to not record new host
@ -201,14 +164,3 @@ fact_caching = memory
accelerate_port = 5099
accelerate_timeout = 30
accelerate_connect_timeout = 5.0
# The daemon timeout is measured in minutes. This time is measured
# from the last activity to the accelerate daemon.
accelerate_daemon_timeout = 30
# If set to yes, accelerate_multi_key will allow multiple
# private keys to be uploaded to it, though each user must
# have access to the system via SSH to add a new key. The default
# is "no".
#accelerate_multi_key = yes

View File

@ -0,0 +1,28 @@
##### Issue Type:
What kind of ticket is this? You can say “Bug Report”, “Feature Idea”, “Feature Pull Request”, “New Module Pull Request”, “Bugfix Pull Request”, “Documentation Report”, or “Docs Pull Request”.
##### Ansible Version:
Please supply the verbatim output from running “ansible --version”.
##### Environment:
What OS are you running Ansible from and what OS are you managing? Examples include RHEL 5/6, Centos 5/6, Ubuntu 12.04/13.10, *BSD, Solaris. If this is a generic feature request or it doesn’t apply, just say “N/A”.
##### Summary:
Please summarize your request in this space. You will earn bonus points for being succinct, but please add enough detail so we can understand the request.
##### Steps To Reproduce:
If this is a bug ticket, please enter the steps you use to reproduce the problem in the space below. If this is a feature request, please enter the steps you would use to use the feature. If an example playbook is useful, please include a short reproducer inline, indented by four spaces. If a longer one is necessary, please link one uploaded to gist.github.com.
##### Expected Results:
Please enter your expected results in this space. When running the steps supplied above, what would you expect to happen? If showing example output, indent your output by four spaces so it will render correctly in GitHub.
##### Actual Results:
Please enter your actual results in this space. When running the steps supplied above, what actually happened? If showing example output, indent your output by four spaces so it will render correctly in GitHub.

View File

@ -1,204 +0,0 @@
# Configure a Windows host for remote management with Ansible
# -----------------------------------------------------------
#
# This script checks the current WinRM/PSRemoting configuration and makes the
# necessary changes to allow Ansible to connect, authenticate and execute
# PowerShell commands.
#
# Set $VerbosePreference = "Continue" before running the script in order to
# see the output messages.
#
# Written by Trond Hindenes <trond@hindenes.com>
# Updated by Chris Church <cchurch@ansible.com>
#
# Version 1.0 - July 6th, 2014
# Version 1.1 - November 11th, 2014
Param (
[string]$SubjectName = $env:COMPUTERNAME,
[int]$CertValidityDays = 365,
$CreateSelfSignedCert = $true
)
Function New-LegacySelfSignedCert
{
Param (
[string]$SubjectName,
[int]$ValidDays = 365
)
$name = New-Object -COM "X509Enrollment.CX500DistinguishedName.1"
$name.Encode("CN=$SubjectName", 0)
$key = New-Object -COM "X509Enrollment.CX509PrivateKey.1"
$key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
$key.KeySpec = 1
$key.Length = 1024
$key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"
$key.MachineContext = 1
$key.Create()
$serverauthoid = New-Object -COM "X509Enrollment.CObjectId.1"
$serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1")
$ekuoids = New-Object -COM "X509Enrollment.CObjectIds.1"
$ekuoids.Add($serverauthoid)
$ekuext = New-Object -COM "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
$ekuext.InitializeEncode($ekuoids)
$cert = New-Object -COM "X509Enrollment.CX509CertificateRequestCertificate.1"
$cert.InitializeFromPrivateKey(2, $key, "")
$cert.Subject = $name
$cert.Issuer = $cert.Subject
$cert.NotBefore = (Get-Date).AddDays(-1)
$cert.NotAfter = $cert.NotBefore.AddDays($ValidDays)
$cert.X509Extensions.Add($ekuext)
$cert.Encode()
$enrollment = New-Object -COM "X509Enrollment.CX509Enrollment.1"
$enrollment.InitializeFromRequest($cert)
$certdata = $enrollment.CreateRequest(0)
$enrollment.InstallResponse(2, $certdata, 0, "")
# Return the thumbprint of the last installed cert.
Get-ChildItem "Cert:\LocalMachine\my"| Sort-Object NotBefore -Descending | Select -First 1 | Select -Expand Thumbprint
}
# Setup error handling.
Trap
{
$_
Exit 1
}
$ErrorActionPreference = "Stop"
# Detect PowerShell version.
If ($PSVersionTable.PSVersion.Major -lt 3)
{
Throw "PowerShell version 3 or higher is required."
}
# Find and start the WinRM service.
Write-Verbose "Verifying WinRM service."
If (!(Get-Service "WinRM"))
{
Throw "Unable to find the WinRM service."
}
ElseIf ((Get-Service "WinRM").Status -ne "Running")
{
Write-Verbose "Starting WinRM service."
Start-Service -Name "WinRM" -ErrorAction Stop
}
# WinRM should be running; check that we have a PS session config.
If (!(Get-PSSessionConfiguration -Verbose:$false) -or (!(Get-ChildItem WSMan:\localhost\Listener)))
{
Write-Verbose "Enabling PS Remoting."
Try
{
Enable-PSRemoting -Force -ErrorAction SilentlyContinue
}
Catch
{
}
}
Else
{
Write-Verbose "PS Remoting is already enabled."
}
# Test a remoting connection to localhost, which should work.
$httpResult = Invoke-Command -ComputerName "localhost" -ScriptBlock {$env:COMPUTERNAME} -ErrorVariable httpError -ErrorAction SilentlyContinue
$httpsOptions = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
$httpsResult = New-PSSession -UseSSL -ComputerName "localhost" -SessionOption $httpsOptions -ErrorVariable httpsError -ErrorAction SilentlyContinue
If ($httpResult -and $httpsResult)
{
Write-Verbose "HTTP and HTTPS sessions are enabled."
}
ElseIf ($httpsResult -and !$httpResult)
{
Write-Verbose "HTTP sessions are disabled, HTTPS session are enabled."
}
ElseIf ($httpResult -and !$httpsResult)
{
Write-Verbose "HTTPS sessions are disabled, HTTP session are enabled."
}
Else
{
Throw "Unable to establish an HTTP or HTTPS remoting session."
}
# Make sure there is a SSL listener.
$listeners = Get-ChildItem WSMan:\localhost\Listener
If (!($listeners | Where {$_.Keys -like "TRANSPORT=HTTPS"}))
{
# HTTPS-based endpoint does not exist.
If (Get-Command "New-SelfSignedCertificate" -ErrorAction SilentlyContinue)
{
$cert = New-SelfSignedCertificate -DnsName $env:COMPUTERNAME -CertStoreLocation "Cert:\LocalMachine\My"
$thumbprint = $cert.Thumbprint
}
Else
{
$thumbprint = New-LegacySelfSignedCert -SubjectName $env:COMPUTERNAME
}
# Create the hashtables of settings to be used.
$valueset = @{}
$valueset.Add('Hostname', $env:COMPUTERNAME)
$valueset.Add('CertificateThumbprint', $thumbprint)
$selectorset = @{}
$selectorset.Add('Transport', 'HTTPS')
$selectorset.Add('Address', '*')
Write-Verbose "Enabling SSL listener."
New-WSManInstance -ResourceURI 'winrm/config/Listener' -SelectorSet $selectorset -ValueSet $valueset
}
Else
{
Write-Verbose "SSL listener is already active."
}
# Check for basic authentication.
$basicAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where {$_.Name -eq "Basic"}
If (($basicAuthSetting.Value) -eq $false)
{
Write-Verbose "Enabling basic auth support."
Set-Item -Path "WSMan:\localhost\Service\Auth\Basic" -Value $true
}
Else
{
Write-Verbose "Basic auth is already enabled."
}
# Configure firewall to allow WinRM HTTPS connections.
$fwtest1 = netsh advfirewall firewall show rule name="Allow WinRM HTTPS"
$fwtest2 = netsh advfirewall firewall show rule name="Allow WinRM HTTPS" profile=any
If ($fwtest1.count -lt 5)
{
Write-Verbose "Adding firewall rule to allow WinRM HTTPS."
netsh advfirewall firewall add rule profile=any name="Allow WinRM HTTPS" dir=in localport=5986 protocol=TCP action=allow
}
ElseIf (($fwtest1.count -ge 5) -and ($fwtest2.count -lt 5))
{
Write-Verbose "Updating firewall rule to allow WinRM HTTPS for any profile."
netsh advfirewall firewall set rule name="Allow WinRM HTTPS" new profile=any
}
Else
{
Write-Verbose "Firewall rule already exists to allow WinRM HTTPS."
}
Write-Verbose "PS Remoting has been successfully configured for Ansible."

View File

@ -1,93 +0,0 @@
# Powershell script to upgrade a PowerShell 2.0 system to PowerShell 3.0
# based on http://occasionalutility.blogspot.com/2013/11/everyday-powershell-part-7-powershell.html
#
# some Ansible modules that may use Powershell 3 features, so systems may need
# to be upgraded. This may be used by a sample playbook. Refer to the windows
# documentation on docs.ansible.com for details.
#
# - hosts: windows
# tasks:
# - script: upgrade_to_ps3.ps1
# Get version of OS
# 6.0 is 2008
# 6.1 is 2008 R2
# 6.2 is 2012
# 6.3 is 2012 R2
if ($PSVersionTable.psversion.Major -ge 3)
{
write-host "Powershell 3 Installed already; You don't need this"
Exit
}
$powershellpath = "C:\powershell"
function download-file
{
param ([string]$path, [string]$local)
$client = new-object system.net.WebClient
$client.Headers.Add("user-agent", "PowerShell")
$client.downloadfile($path, $local)
}
if (!(test-path $powershellpath))
{
New-Item -ItemType directory -Path $powershellpath
}
# .NET Framework 4.0 is necessary.
#if (($PSVersionTable.CLRVersion.Major) -lt 2)
#{
# $DownloadUrl = "http://download.microsoft.com/download/B/A/4/BA4A7E71-2906-4B2D-A0E1-80CF16844F5F/dotNetFx45_Full_x86_x64.exe"
# $FileName = $DownLoadUrl.Split('/')[-1]
# download-file $downloadurl "$powershellpath\$filename"
# ."$powershellpath\$filename" /quiet /norestart
#}
#You may need to reboot after the .NET install if so just run the script again.
# If the Operating System is above 6.2, then you already have PowerShell Version > 3
if ([Environment]::OSVersion.Version.Major -gt 6)
{
write-host "OS is new; upgrade not needed."
Exit
}
$osminor = [environment]::OSVersion.Version.Minor
$architecture = $ENV:PROCESSOR_ARCHITECTURE
if ($architecture -eq "AMD64")
{
$architecture = "x64"
}
else
{
$architecture = "x86"
}
if ($osminor -eq 1)
{
$DownloadUrl = "http://download.microsoft.com/download/E/7/6/E76850B8-DA6E-4FF5-8CCE-A24FC513FD16/Windows6.1-KB2506143-" + $architecture + ".msu"
}
elseif ($osminor -eq 0)
{
$DownloadUrl = "http://download.microsoft.com/download/E/7/6/E76850B8-DA6E-4FF5-8CCE-A24FC513FD16/Windows6.0-KB2506146-" + $architecture + ".msu"
}
else
{
# Nothing to do; In theory this point will never be reached.
Exit
}
$FileName = $DownLoadUrl.Split('/')[-1]
download-file $downloadurl "$powershellpath\$filename"
Start-Process -FilePath "$powershellpath\$filename" -ArgumentList /quiet

View File

@ -17,7 +17,7 @@ and do not wish to install them from your operating system package manager, you
can install them from pip
$ easy_install pip # if pip is not already available
$ pip install pyyaml jinja2 nose passlib pycrypto
$ pip install pyyaml jinja2
From there, follow ansible instructions on docs.ansible.com as normal.

View File

@ -21,6 +21,8 @@ PREFIX_MANPATH="$ANSIBLE_HOME/docs/man"
[[ $PYTHONPATH != ${PREFIX_PYTHONPATH}* ]] && export PYTHONPATH=$PREFIX_PYTHONPATH:$PYTHONPATH
[[ $PATH != ${PREFIX_PATH}* ]] && export PATH=$PREFIX_PATH:$PATH
unset ANSIBLE_LIBRARY
export ANSIBLE_LIBRARY="$ANSIBLE_HOME/library:`python $HACKING_DIR/get_library.py`"
[[ $MANPATH != ${PREFIX_MANPATH}* ]] && export MANPATH=$PREFIX_MANPATH:$MANPATH
# Print out values unless -q is set
@ -31,6 +33,7 @@ if [ $# -eq 0 -o "$1" != "-q" ] ; then
echo ""
echo "PATH=$PATH"
echo "PYTHONPATH=$PYTHONPATH"
echo "ANSIBLE_LIBRARY=$ANSIBLE_LIBRARY"
echo "MANPATH=$MANPATH"
echo ""

View File

@ -16,7 +16,7 @@ else
case "$PREFIX_PYTHONPATH*"
case "*"
echo "Appending PYTHONPATH"
set -gx PYTHONPATH "$PREFIX_PYTHONPATH:$PYTHONPATH"
set -gx PYTHONPATH $PREFIX_PYTHONPATH:$PYTHONPATH
end
end

View File

@ -1,6 +1,5 @@
#!/usr/bin/env python
# (c) 2012, Jan-Piet Mens <jpmens () gmail.com>
# (c) 2012-2014, Michael DeHaan <michael@ansible.com> and others
#
# This file is part of Ansible
#
@ -45,7 +44,7 @@ TO_OLD_TO_BE_NOTABLE = 1.0
# Get parent directory of the directory this script lives in
MODULEDIR=os.path.abspath(os.path.join(
os.path.dirname(os.path.realpath(__file__)), os.pardir, 'lib', 'ansible', 'modules'
os.path.dirname(os.path.realpath(__file__)), os.pardir, 'library'
))
# The name of the DOCUMENTATION template
@ -59,8 +58,6 @@ _MODULE = re.compile(r"M\(([^)]+)\)")
_URL = re.compile(r"U\(([^)]+)\)")
_CONST = re.compile(r"C\(([^)]+)\)")
DEPRECATED = " (D)"
NOTCORE = " (E)"
#####################################################################################
def rst_ify(text):
@ -109,9 +106,7 @@ def write_data(text, options, outputname, module):
''' dumps module output to a file or the screen, as requested '''
if options.output_dir is not None:
fname = os.path.join(options.output_dir, outputname % module)
fname = fname.replace(".py","")
f = open(fname, 'w')
f = open(os.path.join(options.output_dir, outputname % module), 'w')
f.write(text.encode('utf-8'))
f.close()
else:
@ -119,54 +114,22 @@ def write_data(text, options, outputname, module):
#####################################################################################
def list_modules(module_dir, depth=0):
def list_modules(module_dir):
''' returns a hash of categories, each category being a hash of module names to file paths '''
categories = dict(all=dict(),_aliases=dict())
if depth <= 3: # limit # of subdirs
files = glob.glob("%s/*" % module_dir)
for d in files:
category = os.path.splitext(os.path.basename(d))[0]
if os.path.isdir(d):
res = list_modules(d, depth + 1)
for key in res.keys():
if key in categories:
categories[key] = ansible.utils.merge_hash(categories[key], res[key])
res.pop(key, None)
if depth < 2:
categories.update(res)
else:
category = module_dir.split("/")[-1]
if not category in categories:
categories[category] = res
else:
categories[category].update(res)
else:
module = category
category = os.path.basename(module_dir)
if not d.endswith(".py") or d.endswith('__init__.py'):
# windows powershell modules have documentation stubs in python docstring
# format (they are not executed) so skip the ps1 format files
continue
elif module.startswith("_") and os.path.islink(d):
source = os.path.splitext(os.path.basename(os.path.realpath(d)))[0]
module = module.replace("_","",1)
if not d in categories['_aliases']:
categories['_aliases'][source] = [module]
else:
categories['_aliases'][source].update(module)
continue
categories = dict(all=dict())
files = glob.glob("%s/*" % module_dir)
for d in files:
if os.path.isdir(d):
files2 = glob.glob("%s/*" % d)
for f in files2:
tokens = f.split("/")
module = tokens[-1]
category = tokens[-2]
if not category in categories:
categories[category] = {}
categories[category][module] = d
categories['all'][module] = d
categories[category][module] = f
categories['all'][module] = f
return categories
#####################################################################################
@ -215,48 +178,25 @@ def jinja2_environment(template_dir, typ):
#####################################################################################
def process_module(module, options, env, template, outputname, module_map, aliases):
fname = module_map[module]
if isinstance(fname, dict):
return "SKIPPED"
basename = os.path.basename(fname)
deprecated = False
# ignore files with extensions
if not basename.endswith(".py"):
return
elif module.startswith("_"):
if os.path.islink(fname):
return # ignore, its an alias
deprecated = True
module = module.replace("_","",1)
def process_module(module, options, env, template, outputname, module_map):
print "rendering: %s" % module
fname = module_map[module]
# ignore files with extensions
if os.path.basename(fname).find(".") != -1:
return
# use ansible core library to parse out doc metadata YAML and plaintext examples
doc, examples = ansible.utils.module_docs.get_docstring(fname, verbose=options.verbose)
# crash if module is missing documentation and not explicitly hidden from docs index
if doc is None:
if module in ansible.utils.module_docs.BLACKLIST_MODULES:
return "SKIPPED"
else:
sys.stderr.write("*** ERROR: MODULE MISSING DOCUMENTATION: %s, %s ***\n" % (fname, module))
sys.exit(1)
if deprecated and 'deprecated' not in doc:
sys.stderr.write("*** ERROR: DEPRECATED MODULE MISSING 'deprecated' DOCUMENTATION: %s, %s ***\n" % (fname, module))
if doc is None and module not in ansible.utils.module_docs.BLACKLIST_MODULES:
sys.stderr.write("*** ERROR: CORE MODULE MISSING DOCUMENTATION: %s, %s ***\n" % (fname, module))
sys.exit(1)
if "/core/" in fname:
doc['core'] = True
else:
doc['core'] = False
if module in aliases:
doc['aliases'] = aliases[module]
if doc is None:
return "SKIPPED"
all_keys = []
@ -280,10 +220,9 @@ def process_module(module, options, env, template, outputname, module_map, alias
for (k,v) in doc['options'].iteritems():
all_keys.append(k)
all_keys = sorted(all_keys)
doc['option_keys'] = all_keys
doc['option_keys'] = all_keys
doc['filename'] = fname
doc['docuri'] = doc['module'].replace('_', '-')
doc['now_date'] = datetime.date.today().strftime('%Y-%m-%d')
@ -294,32 +233,13 @@ def process_module(module, options, env, template, outputname, module_map, alias
text = template.render(doc)
write_data(text, options, outputname, module)
return doc['short_description']
#####################################################################################
def print_modules(module, category_file, deprecated, core, options, env, template, outputname, module_map, aliases):
modstring = module
modname = module
if module in deprecated:
modstring = modstring + DEPRECATED
modname = "_" + module
elif module not in core:
modstring = modstring + NOTCORE
result = process_module(modname, options, env, template, outputname, module_map, aliases)
if result != "SKIPPED":
category_file.write(" %s - %s <%s_module>\n" % (modstring, result, module))
def process_category(category, categories, options, env, template, outputname):
module_map = categories[category]
aliases = {}
if '_aliases' in categories:
aliases = categories['_aliases']
category_file_path = os.path.join(options.output_dir, "list_of_%s_modules.rst" % category)
category_file = open(category_file_path, "w")
print "*** recording category %s in %s ***" % (category, category_file_path)
@ -329,27 +249,7 @@ def process_category(category, categories, options, env, template, outputname):
category = category.replace("_"," ")
category = category.title()
modules = []
deprecated = []
core = []
for module in module_map.keys():
if isinstance(module_map[module], dict):
for mod in module_map[module].keys():
if mod.startswith("_"):
mod = mod.replace("_","",1)
deprecated.append(mod)
elif '/core/' in module_map[module][mod]:
core.append(mod)
else:
if module.startswith("_"):
module = module.replace("_","",1)
deprecated.append(module)
elif '/core/' in module_map[module]:
core.append(module)
modules.append(module)
modules = module_map.keys()
modules.sort()
category_header = "%s Modules" % (category.title())
@ -359,34 +259,17 @@ def process_category(category, categories, options, env, template, outputname):
%s
%s
.. toctree:: :maxdepth: 1
.. toctree::
:maxdepth: 1
""" % (category_header, underscores))
sections = []
for module in modules:
if module in module_map and isinstance(module_map[module], dict):
sections.append(module)
continue
else:
print_modules(module, category_file, deprecated, core, options, env, template, outputname, module_map, aliases)
result = process_module(module, options, env, template, outputname, module_map)
if result != "SKIPPED":
category_file.write(" %s_module\n" % module)
sections.sort()
for section in sections:
category_file.write("\n%s\n%s\n\n" % (section.replace("_"," ").title(),'-' * len(section)))
category_file.write(".. toctree:: :maxdepth: 1\n\n")
section_modules = module_map[section].keys()
section_modules.sort()
#for module in module_map[section]:
for module in section_modules:
print_modules(module, category_file, deprecated, core, options, env, template, outputname, module_map[section], aliases)
category_file.write("""\n\n
.. note::
- %s: This marks a module as deprecated, which means a module is kept for backwards compatibility but usage is discouraged. The module documentation details page may explain more about this rationale.
- %s: This marks a module as 'extras', which means it ships with ansible but may be a newer module and possibly (but not neccessarily) less activity maintained than 'core' modules.
- Tickets filed on modules are filed to different repos than those on the main open source project. Core module tickets should be filed at `ansible/ansible-modules-core on GitHub <http://github.com/ansible/ansible-modules-core>`_, extras tickets to `ansible/ansible-modules-extras on GitHub <http://github.com/ansible/ansible-modules-extras>`_
""" % (DEPRECATED, NOTCORE))
category_file.close()
# TODO: end a new category file
@ -431,8 +314,6 @@ def main():
category_list_file.write(" :maxdepth: 1\n\n")
for category in category_names:
if category.startswith("_"):
continue
category_list_file.write(" list_of_%s_modules\n" % category)
process_category(category, categories, options, env, template, outputname)

View File

@ -10,6 +10,10 @@
@{ title }@
@{ '+' * title_len }@
{% if author %}
:Author: @{ author }@
{% endif %}
.. contents::
:local:
:depth: 1
@ -21,17 +25,6 @@
#
--------------------------------------------#}
{% if aliases is defined -%}
Aliases: @{ ','.join(aliases) }@
{% endif %}
{% if deprecated is defined -%}
DEPRECATED
----------
@{ deprecated }@
{% endif %}
Synopsis
--------
@ -112,42 +105,3 @@ Examples
{% endfor %}
{% endif %}
{% if not deprecated %}
{% if core %}
This is a Core Module
---------------------
This source of this module is hosted on GitHub in the `ansible-modules-core <http://github.com/ansible/ansible-modules-core>`_ repo.
If you believe you have found a bug in this module, and are already running the latest stable or development version of Ansible, first look in the `issue tracker at github.com/ansible/ansible-modules-core <http://github.com/ansible/ansible-modules-core>`_ to see if a bug has already been filed. If not, we would be grateful if you would file one.
Should you have a question rather than a bug report, inquries are welcome on the `ansible-project google group <https://groups.google.com/forum/#!forum/ansible-project>`_ or on Ansible's "#ansible" channel, located on irc.freenode.net. Development oriented topics should instead use the similar `ansible-devel google group <https://groups.google.com/forum/#!forum/ansible-project>`_.
Documentation updates for this module can also be edited directly by submitting a pull request to the module source code, just look for the "DOCUMENTATION" block in the source tree.
This is a "core" ansible module, which means it will receive slightly higher priority for all requests than those in the "extras" repos.
{% else %}
This is an Extras Module
------------------------
This source of this module is hosted on GitHub in the `ansible-modules-extras <http://github.com/ansible/ansible-modules-extras>`_ repo.
If you believe you have found a bug in this module, and are already running the latest stable or development version of Ansible, first look in the `issue tracker at github.com/ansible/ansible-modules-extras <http://github.com/ansible/ansible-modules-extras>`_ to see if a bug has already been filed. If not, we would be grateful if you would file one.
Should you have a question rather than a bug report, inquries are welcome on the `ansible-project google group <https://groups.google.com/forum/#!forum/ansible-project>` or on Ansible's "#ansible" channel, located on irc.freenode.net. Development oriented topics should instead use the similar `ansible-devel google group <https://groups.google.com/forum/#!forum/ansible-project>`_.
Documentation updates for this module can also be edited directly by submitting a pull request to the module source code, just look for the "DOCUMENTATION" block in the source tree.
Note that this module is designated a "extras" module. Non-core modules are still fully usable, but may receive slightly lower response rates for issues and pull requests.
Popular "extras" modules may be promoted to core modules over time.
{% endif %}
{% endif %}
For help in developing on modules, should you be so inclined, please read :doc:`community`, :doc:`developing_test_pr` and :doc:`developing_modules`.

View File

@ -23,10 +23,9 @@
# modules
#
# example:
# test-module -m ../library/commands/command -a "/bin/sleep 3"
# test-module -m ../library/system/service -a "name=httpd ensure=restarted"
# test-module -m ../library/system/service -a "name=httpd ensure=restarted" --debugger /usr/bin/pdb
# test-modulr -m ../library/file/lineinfile -a "dest=/etc/exports line='/srv/home hostname1(rw,sync)'" --check
# test-module -m ../library/command -a "/bin/sleep 3"
# test-module -m ../library/service -a "name=httpd ensure=restarted"
# test-module -m ../library/service -a "name=httpd ensure=restarted" --debugger /usr/bin/pdb
import sys
import base64
@ -60,8 +59,6 @@ def parse():
parser.add_option('-I', '--interpreter', dest='interpreter',
help="path to interpeter to use for this module (e.g. ansible_python_interpreter=/usr/bin/python)",
metavar='INTERPRETER_TYPE=INTERPRETER_PATH')
parser.add_option('-c', '--check', dest='check', action='store_true',
help="run the module in check mode")
options, args = parser.parse_args()
if not options.module_path:
parser.print_help()
@ -80,7 +77,7 @@ def write_argsfile(argstring, json=False):
argsfile.close()
return argspath
def boilerplate_module(modfile, args, interpreter, check):
def boilerplate_module(modfile, args, interpreter):
""" simulate what ansible does with new style modules """
#module_fh = open(modfile)
@ -96,10 +93,6 @@ def boilerplate_module(modfile, args, interpreter, check):
# Argument is a YAML file (JSON is a subset of YAML)
complex_args = utils.combine_vars(complex_args, utils.parse_yaml_from_file(args[1:]))
args=''
elif args.startswith("{"):
# Argument is a YAML document (not a file)
complex_args = utils.combine_vars(complex_args, utils.parse_yaml(args))
args=''
inject = {}
if interpreter:
@ -112,10 +105,6 @@ def boilerplate_module(modfile, args, interpreter, check):
if not interpreter_type.endswith('_interpreter'):
interpreter_type = '%s_interpreter' % interpreter_type
inject[interpreter_type] = interpreter_path
if check:
complex_args['CHECKMODE'] = True
(module_data, module_style, shebang) = replacer.modify_module(
modfile,
complex_args,
@ -173,7 +162,7 @@ def rundebug(debugger, modfile, argspath):
def main():
options, args = parse()
(modfile, module_style) = boilerplate_module(options.module_path, options.module_args, options.interpreter, options.check)
(modfile, module_style) = boilerplate_module(options.module_path, options.module_args, options.interpreter)
argspath=None
if module_style != 'new':

748
legacy/gce_tests.py Normal file
View File

@ -0,0 +1,748 @@
#!/usr/bin/env python
# Copyright 2013 Google Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# This is a custom functional test script for the Google Compute Engine
# ansible modules. In order to run these tests, you must:
# 1) Create a Google Cloud Platform account and enable the Google
# Compute Engine service and billing
# 2) Download, install, and configure 'gcutil'
# see [https://developers.google.com/compute/docs/gcutil/]
# 3) Convert your GCE Service Account private key from PKCS12 to PEM format
# $ openssl pkcs12 -in pkey.pkcs12 -passin pass:notasecret \
# > -nodes -nocerts | openssl rsa -out pkey.pem
# 4) Make sure you have libcloud 0.13.3 or later installed.
# 5) Make sure you have a libcloud 'secrets.py' file in your PYTHONPATH
# 6) Set GCE_PARAMS and GCE_KEYWORD_PARMS in your 'secrets.py' file.
# 7) Set up a simple hosts file
# $ echo 127.0.0.1 > ~/ansible_hosts
# $ echo "export ANSIBLE_HOSTS='~/ansible_hosts'" >> ~/.bashrc
# $ . ~/.bashrc
# 8) Set up your ansible 'hacking' environment
# $ cd ~/ansible
# $ . hacking/env-setup
# $ export ANSIBLE_HOST_KEY_CHECKING=no
# $ ansible all -m ping
# 9) Set your PROJECT variable below
# 10) Run and time the tests and log output, take ~30 minutes to run
# $ time stdbuf -oL python test/gce_tests.py 2>&1 | tee log
#
# Last update: gcutil-1.11.0 and v1beta16
# Set this to your test Project ID
PROJECT="google.com:erjohnso"
# debugging
DEBUG=False # lots of debugging output
VERBOSE=True # on failure, display ansible command and expected/actual result
# location - note that some tests rely on the module's 'default'
# region/zone, which should match the settings below.
REGION="us-central1"
ZONE="%s-a" % REGION
# Peeking is a way to trigger looking at a specified set of resources
# before and/or after a test run. The 'test_cases' data structure below
# has a few tests with 'peek_before' and 'peek_after'. When those keys
# are set and PEEKING_ENABLED is True, then these steps will be executed
# to aid in debugging tests. Normally, this is not needed.
PEEKING_ENABLED=False
# disks
DNAME="aaaaa-ansible-disk"
DNAME2="aaaaa-ansible-disk2"
DNAME6="aaaaa-ansible-inst6"
DNAME7="aaaaa-ansible-inst7"
USE_PD="true"
KERNEL="https://www.googleapis.com/compute/v1beta16/projects/google/global/kernels/gce-no-conn-track-v20130813"
# instances
INAME="aaaaa-ansible-inst"
INAME2="aaaaa-ansible-inst2"
INAME3="aaaaa-ansible-inst3"
INAME4="aaaaa-ansible-inst4"
INAME5="aaaaa-ansible-inst5"
INAME6="aaaaa-ansible-inst6"
INAME7="aaaaa-ansible-inst7"
TYPE="n1-standard-1"
IMAGE="https://www.googleapis.com/compute/v1beta16/projects/debian-cloud/global/images/debian-7-wheezy-v20131014"
NETWORK="default"
SCOPES="https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/compute,https://www.googleapis.com/auth/devstorage.full_control"
# networks / firewalls
NETWK1="ansible-network1"
NETWK2="ansible-network2"
NETWK3="ansible-network3"
CIDR1="10.240.16.0/24"
CIDR2="10.240.32.0/24"
CIDR3="10.240.64.0/24"
GW1="10.240.16.1"
GW2="10.240.32.1"
FW1="ansible-fwrule1"
FW2="ansible-fwrule2"
FW3="ansible-fwrule3"
FW4="ansible-fwrule4"
# load-balancer tests
HC1="ansible-hc1"
HC2="ansible-hc2"
HC3="ansible-hc3"
LB1="ansible-lb1"
LB2="ansible-lb2"
from commands import getstatusoutput as run
import sys
test_cases = [
{'id': '01', 'desc': 'Detach / Delete disk tests',
'setup': ['gcutil addinstance "%s" --wait_until_running --zone=%s --machine_type=%s --network=%s --service_account_scopes="%s" --image="%s" --persistent_boot_disk=%s' % (INAME, ZONE, TYPE, NETWORK, SCOPES, IMAGE, USE_PD),
'gcutil adddisk "%s" --size_gb=2 --zone=%s --wait_until_complete' % (DNAME, ZONE)],
'tests': [
{'desc': 'DETACH_ONLY but disk not found [success]',
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s detach_only=yes state=absent' % ("missing-disk", INAME, ZONE),
'r': '127.0.0.1 | success >> {"changed": false, "detach_only": true, "detached_from_instance": "%s", "name": "missing-disk", "state": "absent", "zone": "%s"}' % (INAME, ZONE),
},
{'desc': 'DETACH_ONLY but instance not found [success]',
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s detach_only=yes state=absent' % (DNAME, "missing-instance", ZONE),
'r': '127.0.0.1 | success >> {"changed": false, "detach_only": true, "detached_from_instance": "missing-instance", "name": "%s", "size_gb": 2, "state": "absent", "zone": "%s"}' % (DNAME, ZONE),
},
{'desc': 'DETACH_ONLY but neither disk nor instance exists [success]',
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s detach_only=yes state=absent' % ("missing-disk", "missing-instance", ZONE),
'r': '127.0.0.1 | success >> {"changed": false, "detach_only": true, "detached_from_instance": "missing-instance", "name": "missing-disk", "state": "absent", "zone": "%s"}' % (ZONE),
},
{'desc': 'DETACH_ONLY but disk is not currently attached [success]',
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s detach_only=yes state=absent' % (DNAME, INAME, ZONE),
'r': '127.0.0.1 | success >> {"changed": false, "detach_only": true, "detached_from_instance": "%s", "name": "%s", "size_gb": 2, "state": "absent", "zone": "%s"}' % (INAME, DNAME, ZONE),
},
{'desc': 'DETACH_ONLY disk is attached and should be detached [success]',
'setup': ['gcutil attachdisk --disk="%s,mode=READ_ONLY" --zone=%s %s' % (DNAME, ZONE, INAME), 'sleep 10'],
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s detach_only=yes state=absent' % (DNAME, INAME, ZONE),
'r': '127.0.0.1 | success >> {"attached_mode": "READ_ONLY", "attached_to_instance": "%s", "changed": true, "detach_only": true, "detached_from_instance": "%s", "name": "%s", "size_gb": 2, "state": "absent", "zone": "%s"}' % (INAME, INAME, DNAME, ZONE),
'teardown': ['gcutil detachdisk --zone=%s --device_name=%s %s' % (ZONE, DNAME, INAME)],
},
{'desc': 'DETACH_ONLY but not instance specified [FAIL]',
'm': 'gce_pd',
'a': 'name=%s zone=%s detach_only=yes state=absent' % (DNAME, ZONE),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Must specify an instance name when detaching a disk"}',
},
{'desc': 'DELETE but disk not found [success]',
'm': 'gce_pd',
'a': 'name=%s zone=%s state=absent' % ("missing-disk", ZONE),
'r': '127.0.0.1 | success >> {"changed": false, "name": "missing-disk", "state": "absent", "zone": "%s"}' % (ZONE),
},
{'desc': 'DELETE but disk is attached [FAIL]',
'setup': ['gcutil attachdisk --disk="%s,mode=READ_ONLY" --zone=%s %s' % (DNAME, ZONE, INAME), 'sleep 10'],
'm': 'gce_pd',
'a': 'name=%s zone=%s state=absent' % (DNAME, ZONE),
'r': "127.0.0.1 | FAILED >> {\"changed\": false, \"failed\": true, \"msg\": \"The disk resource 'projects/%s/zones/%s/disks/%s' is already being used by 'projects/%s/zones/%s/instances/%s'\"}" % (PROJECT, ZONE, DNAME, PROJECT, ZONE, INAME),
'teardown': ['gcutil detachdisk --zone=%s --device_name=%s %s' % (ZONE, DNAME, INAME)],
},
{'desc': 'DELETE disk [success]',
'm': 'gce_pd',
'a': 'name=%s zone=%s state=absent' % (DNAME, ZONE),
'r': '127.0.0.1 | success >> {"changed": true, "name": "%s", "size_gb": 2, "state": "absent", "zone": "%s"}' % (DNAME, ZONE),
},
],
'teardown': ['gcutil deleteinstance -f "%s" --zone=%s' % (INAME, ZONE),
'sleep 15',
'gcutil deletedisk -f "%s" --zone=%s' % (INAME, ZONE),
'sleep 10',
'gcutil deletedisk -f "%s" --zone=%s' % (DNAME, ZONE),
'sleep 10'],
},
{'id': '02', 'desc': 'Create disk but do not attach (e.g. no instance_name param)',
'setup': [],
'tests': [
{'desc': 'CREATE_NO_ATTACH "string" for size_gb [FAIL]',
'm': 'gce_pd',
'a': 'name=%s size_gb="foo" zone=%s' % (DNAME, ZONE),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Must supply a size_gb larger than 1 GB"}',
},
{'desc': 'CREATE_NO_ATTACH negative size_gb [FAIL]',
'm': 'gce_pd',
'a': 'name=%s size_gb=-2 zone=%s' % (DNAME, ZONE),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Must supply a size_gb larger than 1 GB"}',
},
{'desc': 'CREATE_NO_ATTACH size_gb exceeds quota [FAIL]',
'm': 'gce_pd',
'a': 'name=%s size_gb=9999 zone=%s' % ("big-disk", ZONE),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Requested disk size exceeds quota"}',
},
{'desc': 'CREATE_NO_ATTACH create the disk [success]',
'm': 'gce_pd',
'a': 'name=%s zone=%s' % (DNAME, ZONE),
'r': '127.0.0.1 | success >> {"changed": true, "name": "%s", "size_gb": 10, "state": "present", "zone": "%s"}' % (DNAME, ZONE),
},
{'desc': 'CREATE_NO_ATTACH but disk already exists [success]',
'm': 'gce_pd',
'a': 'name=%s zone=%s' % (DNAME, ZONE),
'r': '127.0.0.1 | success >> {"changed": false, "name": "%s", "size_gb": 10, "state": "present", "zone": "%s"}' % (DNAME, ZONE),
},
],
'teardown': ['gcutil deletedisk -f "%s" --zone=%s' % (DNAME, ZONE),
'sleep 10'],
},
{'id': '03', 'desc': 'Create and attach disk',
'setup': ['gcutil addinstance "%s" --zone=%s --machine_type=%s --network=%s --service_account_scopes="%s" --image="%s" --persistent_boot_disk=%s' % (INAME2, ZONE, TYPE, NETWORK, SCOPES, IMAGE, USE_PD),
'gcutil addinstance "%s" --zone=%s --machine_type=%s --network=%s --service_account_scopes="%s" --image="%s" --persistent_boot_disk=%s' % (INAME, ZONE, "g1-small", NETWORK, SCOPES, IMAGE, USE_PD),
'gcutil adddisk "%s" --size_gb=2 --zone=%s' % (DNAME, ZONE),
'gcutil adddisk "%s" --size_gb=2 --zone=%s --wait_until_complete' % (DNAME2, ZONE),],
'tests': [
{'desc': 'CREATE_AND_ATTACH "string" for size_gb [FAIL]',
'm': 'gce_pd',
'a': 'name=%s size_gb="foo" instance_name=%s zone=%s' % (DNAME, INAME, ZONE),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Must supply a size_gb larger than 1 GB"}',
},
{'desc': 'CREATE_AND_ATTACH negative size_gb [FAIL]',
'm': 'gce_pd',
'a': 'name=%s size_gb=-2 instance_name=%s zone=%s' % (DNAME, INAME, ZONE),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Must supply a size_gb larger than 1 GB"}',
},
{'desc': 'CREATE_AND_ATTACH size_gb exceeds quota [FAIL]',
'm': 'gce_pd',
'a': 'name=%s size_gb=9999 instance_name=%s zone=%s' % ("big-disk", INAME, ZONE),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Requested disk size exceeds quota"}',
},
{'desc': 'CREATE_AND_ATTACH missing instance [FAIL]',
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s' % (DNAME, "missing-instance", ZONE),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Instance %s does not exist in zone %s"}' % ("missing-instance", ZONE),
},
{'desc': 'CREATE_AND_ATTACH disk exists but not attached [success]',
'peek_before': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s' % (DNAME, INAME, ZONE),
'r': '127.0.0.1 | success >> {"attached_mode": "READ_ONLY", "attached_to_instance": "%s", "changed": true, "name": "%s", "size_gb": 2, "state": "present", "zone": "%s"}' % (INAME, DNAME, ZONE),
'peek_after': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
},
{'desc': 'CREATE_AND_ATTACH disk exists already attached [success]',
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s' % (DNAME, INAME, ZONE),
'r': '127.0.0.1 | success >> {"attached_mode": "READ_ONLY", "attached_to_instance": "%s", "changed": false, "name": "%s", "size_gb": 2, "state": "present", "zone": "%s"}' % (INAME, DNAME, ZONE),
},
{'desc': 'CREATE_AND_ATTACH attached RO, attempt RO to 2nd inst [success]',
'peek_before': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s' % (DNAME, INAME2, ZONE),
'r': '127.0.0.1 | success >> {"attached_mode": "READ_ONLY", "attached_to_instance": "%s", "changed": true, "name": "%s", "size_gb": 2, "state": "present", "zone": "%s"}' % (INAME2, DNAME, ZONE),
'peek_after': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
},
{'desc': 'CREATE_AND_ATTACH attached RO, attach RW to self [FAILED no-op]',
'peek_before': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s mode=READ_WRITE' % (DNAME, INAME, ZONE),
'r': '127.0.0.1 | success >> {"attached_mode": "READ_ONLY", "attached_to_instance": "%s", "changed": false, "name": "%s", "size_gb": 2, "state": "present", "zone": "%s"}' % (INAME, DNAME, ZONE),
},
{'desc': 'CREATE_AND_ATTACH attached RW, attach RW to other [FAIL]',
'setup': ['gcutil attachdisk --disk=%s,mode=READ_WRITE --zone=%s %s' % (DNAME2, ZONE, INAME), 'sleep 10'],
'peek_before': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s mode=READ_WRITE' % (DNAME2, INAME2, ZONE),
'r': "127.0.0.1 | FAILED >> {\"changed\": false, \"failed\": true, \"msg\": \"Unexpected response: HTTP return_code[200], API error code[RESOURCE_IN_USE] and message: The disk resource 'projects/%s/zones/%s/disks/%s' is already being used in read-write mode\"}" % (PROJECT, ZONE, DNAME2),
'peek_after': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
},
{'desc': 'CREATE_AND_ATTACH attach too many disks to inst [FAIL]',
'setup': ['gcutil adddisk aa-disk-dummy --size_gb=2 --zone=%s' % (ZONE),
'gcutil adddisk aa-disk-dummy2 --size_gb=2 --zone=%s --wait_until_complete' % (ZONE),
'gcutil attachdisk --disk=aa-disk-dummy --zone=%s %s' % (ZONE, INAME),
'sleep 5'],
'peek_before': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s' % ("aa-disk-dummy2", INAME, ZONE),
'r': "127.0.0.1 | FAILED >> {\"changed\": false, \"failed\": true, \"msg\": \"Unexpected response: HTTP return_code[200], API error code[LIMIT_EXCEEDED] and message: Exceeded limit 'maximum_persistent_disks' on resource 'projects/%s/zones/%s/instances/%s'. Limit: 4\"}" % (PROJECT, ZONE, INAME),
'teardown': ['gcutil detachdisk --device_name=aa-disk-dummy --zone=%s %s' % (ZONE, INAME),
'sleep 3',
'gcutil deletedisk -f aa-disk-dummy --zone=%s' % (ZONE),
'sleep 10',
'gcutil deletedisk -f aa-disk-dummy2 --zone=%s' % (ZONE),
'sleep 10'],
},
],
'teardown': ['gcutil deleteinstance -f "%s" --zone=%s' % (INAME2, ZONE),
'sleep 15',
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME, ZONE),
'sleep 15',
'gcutil deletedisk -f "%s" --zone=%s' % (INAME, ZONE),
'sleep 10',
'gcutil deletedisk -f "%s" --zone=%s' % (INAME2, ZONE),
'sleep 10',
'gcutil deletedisk -f "%s" --zone=%s' % (DNAME, ZONE),
'sleep 10',
'gcutil deletedisk -f "%s" --zone=%s' % (DNAME2, ZONE),
'sleep 10'],
},
{'id': '04', 'desc': 'Delete / destroy instances',
'setup': ['gcutil addinstance "%s" --zone=%s --machine_type=%s --image="%s" --persistent_boot_disk=false' % (INAME, ZONE, TYPE, IMAGE),
'gcutil addinstance "%s" --zone=%s --machine_type=%s --image="%s" --persistent_boot_disk=false' % (INAME2, ZONE, TYPE, IMAGE),
'gcutil addinstance "%s" --zone=%s --machine_type=%s --image="%s" --persistent_boot_disk=false' % (INAME3, ZONE, TYPE, IMAGE),
'gcutil addinstance "%s" --zone=%s --machine_type=%s --image="%s" --persistent_boot_disk=false' % (INAME4, ZONE, TYPE, IMAGE),
'gcutil addinstance "%s" --wait_until_running --zone=%s --machine_type=%s --image="%s" --persistent_boot_disk=false' % (INAME5, ZONE, TYPE, IMAGE)],
'tests': [
{'desc': 'DELETE instance, bad zone param [FAIL]',
'm': 'gce',
'a': 'name=missing-inst zone=bogus state=absent',
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "value of zone must be one of: us-central1-a,us-central1-b,us-central2-a,europe-west1-a,europe-west1-b, got: bogus"}',
},
{'desc': 'DELETE non-existent instance, no-op [success]',
'm': 'gce',
'a': 'name=missing-inst zone=%s state=absent' % (ZONE),
'r': '127.0.0.1 | success >> {"changed": false, "name": "missing-inst", "state": "absent", "zone": "%s"}' % (ZONE),
},
{'desc': 'DELETE an existing named instance [success]',
'm': 'gce',
'a': 'name=%s zone=%s state=absent' % (INAME, ZONE),
'r': '127.0.0.1 | success >> {"changed": true, "name": "%s", "state": "absent", "zone": "%s"}' % (INAME, ZONE),
},
{'desc': 'DELETE list of instances with a non-existent one [success]',
'm': 'gce',
'a': 'instance_names=%s,missing,%s zone=%s state=absent' % (INAME2,INAME3, ZONE),
'r': '127.0.0.1 | success >> {"changed": true, "instance_names": ["%s", "%s"], "state": "absent", "zone": "%s"}' % (INAME2, INAME3, ZONE),
},
{'desc': 'DELETE list of instances all pre-exist [success]',
'm': 'gce',
'a': 'instance_names=%s,%s zone=%s state=absent' % (INAME4,INAME5, ZONE),
'r': '127.0.0.1 | success >> {"changed": true, "instance_names": ["%s", "%s"], "state": "absent", "zone": "%s"}' % (INAME4, INAME5, ZONE),
},
],
'teardown': ['gcutil deleteinstance -f "%s" --zone=%s' % (INAME, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME2, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME3, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME4, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME5, ZONE),
'sleep 10'],
},
{'id': '05', 'desc': 'Create instances',
'setup': ['gcutil adddisk --source_image=%s --zone=%s %s --wait_until_complete' % (IMAGE, ZONE, DNAME7),
'gcutil addinstance boo --wait_until_running --zone=%s --machine_type=%s --network=%s --disk=%s,mode=READ_WRITE,boot --kernel=%s' % (ZONE,TYPE,NETWORK,DNAME7,KERNEL),
],
'tests': [
{'desc': 'CREATE_INSTANCE invalid image arg [FAIL]',
'm': 'gce',
'a': 'name=foo image=foo',
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Missing required create instance variable"}',
},
{'desc': 'CREATE_INSTANCE metadata a list [FAIL]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s zone=%s metadata=\'[\\"foo\\":\\"bar\\",\\"baz\\":1]\'' % (INAME,ZONE),
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "bad metadata syntax"}',
},
{'desc': 'CREATE_INSTANCE metadata not a dict [FAIL]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s zone=%s metadata=\\"foo\\":\\"bar\\",\\"baz\\":1' % (INAME,ZONE),
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "bad metadata syntax"}',
},
{'desc': 'CREATE_INSTANCE with metadata form1 [FAIL]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s zone=%s metadata=\'{"foo":"bar","baz":1}\'' % (INAME,ZONE),
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "bad metadata: malformed string"}',
},
{'desc': 'CREATE_INSTANCE with metadata form2 [FAIL]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s zone=%s metadata={\'foo\':\'bar\',\'baz\':1}' % (INAME,ZONE),
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "bad metadata: malformed string"}',
},
{'desc': 'CREATE_INSTANCE with metadata form3 [FAIL]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s zone=%s metadata="foo:bar" '% (INAME,ZONE),
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "bad metadata syntax"}',
},
{'desc': 'CREATE_INSTANCE with metadata form4 [FAIL]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s zone=%s metadata="{\'foo\':\'bar\'}"'% (INAME,ZONE),
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "bad metadata: malformed string"}',
},
{'desc': 'CREATE_INSTANCE invalid image arg [FAIL]',
'm': 'gce',
'a': 'instance_names=foo,bar image=foo',
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Missing required create instance variable"}',
},
{'desc': 'CREATE_INSTANCE single inst, using defaults [success]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s' % (INAME),
'r': '127.0.0.1 | success >> {"changed": true, "instance_data": [{"image": "debian-7-wheezy-v20130816", "machine_type": "n1-standard-1", "metadata": {}, "name": "%s", "network": "default", "private_ip": "10.240.175.15", "public_ip": "173.255.120.190", "status": "RUNNING", "tags": [], "zone": "%s"}], "name": "%s", "state": "present", "zone": "%s"}' % (INAME, ZONE, INAME, ZONE),
},
{'desc': 'CREATE_INSTANCE the same instance again, no-op [success]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s' % (INAME),
'r': '127.0.0.1 | success >> {"changed": false, "instance_data": [{"image": "debian-7-wheezy-v20130816", "machine_type": "n1-standard-1", "metadata": {}, "name": "%s", "network": "default", "private_ip": "10.240.175.15", "public_ip": "173.255.120.190", "status": "RUNNING", "tags": [], "zone": "%s"}], "name": "%s", "state": "present", "zone": "%s"}' % (INAME, ZONE, INAME, ZONE),
},
{'desc': 'CREATE_INSTANCE instance with alt type [success]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s machine_type=n1-standard-2' % (INAME2),
'r': '127.0.0.1 | success >> {"changed": true, "instance_data": [{"image": "debian-7-wheezy-v20130816", "machine_type": "n1-standard-2", "metadata": {}, "name": "%s", "network": "default", "private_ip": "10.240.192.227", "public_ip": "173.255.121.233", "status": "RUNNING", "tags": [], "zone": "%s"}], "name": "%s", "state": "present", "zone": "%s"}' % (INAME2, ZONE, INAME2, ZONE),
},
{'desc': 'CREATE_INSTANCE instance with root pd [success]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s persistent_boot_disk=yes' % (INAME3),
'r': '127.0.0.1 | success >> {"changed": true, "instance_data": [{"image": null, "machine_type": "n1-standard-1", "metadata": {}, "name": "%s", "network": "default", "private_ip": "10.240.178.140", "public_ip": "173.255.121.176", "status": "RUNNING", "tags": [], "zone": "%s"}], "name": "%s", "state": "present", "zone": "%s"}' % (INAME3, ZONE, INAME3, ZONE),
},
{'desc': 'CREATE_INSTANCE instance with root pd, that already exists [success]',
'setup': ['gcutil adddisk --source_image=%s --zone=%s %s --wait_until_complete' % (IMAGE, ZONE, DNAME6),],
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s zone=%s persistent_boot_disk=yes' % (INAME6, ZONE),
'r': '127.0.0.1 | success >> {"changed": true, "instance_data": [{"image": null, "machine_type": "n1-standard-1", "metadata": {}, "name": "%s", "network": "default", "private_ip": "10.240.178.140", "public_ip": "173.255.121.176", "status": "RUNNING", "tags": [], "zone": "%s"}], "name": "%s", "state": "present", "zone": "%s"}' % (INAME6, ZONE, INAME6, ZONE),
},
{'desc': 'CREATE_INSTANCE instance with root pd attached to other inst [FAIL]',
'm': 'gce',
'a': 'name=%s zone=%s persistent_boot_disk=yes' % (INAME7, ZONE),
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "Unexpected error attempting to create instance %s, error: The disk resource \'projects/%s/zones/%s/disks/%s\' is already being used in read-write mode"}' % (INAME7,PROJECT,ZONE,DNAME7),
},
{'desc': 'CREATE_INSTANCE use *all* the options! [success]',
'strip_numbers': True,
'm': 'gce',
'a': 'instance_names=%s,%s metadata=\'{\\"foo\\":\\"bar\\", \\"baz\\":1}\' tags=t1,t2,t3 zone=%s image=centos-6-v20130731 persistent_boot_disk=yes' % (INAME4,INAME5,ZONE),
'r': '127.0.0.1 | success >> {"changed": true, "instance_data": [{"image": null, "machine_type": "n1-standard-1", "metadata": {"baz": "1", "foo": "bar"}, "name": "%s", "network": "default", "private_ip": "10.240.130.4", "public_ip": "173.255.121.97", "status": "RUNNING", "tags": ["t1", "t2", "t3"], "zone": "%s"}, {"image": null, "machine_type": "n1-standard-1", "metadata": {"baz": "1", "foo": "bar"}, "name": "%s", "network": "default", "private_ip": "10.240.207.226", "public_ip": "173.255.121.85", "status": "RUNNING", "tags": ["t1", "t2", "t3"], "zone": "%s"}], "instance_names": ["%s", "%s"], "state": "present", "zone": "%s"}' % (INAME4, ZONE, INAME5, ZONE, INAME4, INAME5, ZONE),
},
],
'teardown': ['gcutil deleteinstance -f "%s" --zone=%s' % (INAME, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME2, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME3, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME4, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME5, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME6, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME7, ZONE),
'gcutil deleteinstance -f boo --zone=%s' % (ZONE),
'sleep 10',
'gcutil deletedisk -f "%s" --zone=%s' % (INAME3, ZONE),
'gcutil deletedisk -f "%s" --zone=%s' % (INAME4, ZONE),
'gcutil deletedisk -f "%s" --zone=%s' % (INAME5, ZONE),
'gcutil deletedisk -f "%s" --zone=%s' % (INAME6, ZONE),
'gcutil deletedisk -f "%s" --zone=%s' % (INAME7, ZONE),
'sleep 10'],
},
{'id': '06', 'desc': 'Delete / destroy networks and firewall rules',
'setup': ['gcutil addnetwork --range="%s" --gateway="%s" %s' % (CIDR1, GW1, NETWK1),
'gcutil addnetwork --range="%s" --gateway="%s" %s' % (CIDR2, GW2, NETWK2),
'sleep 5',
'gcutil addfirewall --allowed="tcp:80" --network=%s %s' % (NETWK1, FW1),
'gcutil addfirewall --allowed="tcp:80" --network=%s %s' % (NETWK2, FW2),
'sleep 5'],
'tests': [
{'desc': 'DELETE bogus named firewall [success]',
'm': 'gce_net',
'a': 'fwname=missing-fwrule state=absent',
'r': '127.0.0.1 | success >> {"changed": false, "fwname": "missing-fwrule", "state": "absent"}',
},
{'desc': 'DELETE bogus named network [success]',
'm': 'gce_net',
'a': 'name=missing-network state=absent',
'r': '127.0.0.1 | success >> {"changed": false, "name": "missing-network", "state": "absent"}',
},
{'desc': 'DELETE named firewall rule [success]',
'm': 'gce_net',
'a': 'fwname=%s state=absent' % (FW1),
'r': '127.0.0.1 | success >> {"changed": true, "fwname": "%s", "state": "absent"}' % (FW1),
'teardown': ['sleep 5'], # pause to give GCE time to delete fwrule
},
{'desc': 'DELETE unused named network [success]',
'm': 'gce_net',
'a': 'name=%s state=absent' % (NETWK1),
'r': '127.0.0.1 | success >> {"changed": true, "name": "%s", "state": "absent"}' % (NETWK1),
},
{'desc': 'DELETE named network *and* fwrule [success]',
'm': 'gce_net',
'a': 'name=%s fwname=%s state=absent' % (NETWK2, FW2),
'r': '127.0.0.1 | success >> {"changed": true, "fwname": "%s", "name": "%s", "state": "absent"}' % (FW2, NETWK2),
},
],
'teardown': ['gcutil deletenetwork -f %s' % (NETWK1),
'gcutil deletenetwork -f %s' % (NETWK2),
'sleep 5',
'gcutil deletefirewall -f %s' % (FW1),
'gcutil deletefirewall -f %s' % (FW2)],
},
{'id': '07', 'desc': 'Create networks and firewall rules',
'setup': ['gcutil addnetwork --range="%s" --gateway="%s" %s' % (CIDR1, GW1, NETWK1),
'sleep 5',
'gcutil addfirewall --allowed="tcp:80" --network=%s %s' % (NETWK1, FW1),
'sleep 5'],
'tests': [
{'desc': 'CREATE network without specifying ipv4_range [FAIL]',
'm': 'gce_net',
'a': 'name=fail',
'r': "127.0.0.1 | FAILED >> {\"changed\": false, \"failed\": true, \"msg\": \"Missing required 'ipv4_range' parameter\"}",
},
{'desc': 'CREATE network with specifying bad ipv4_range [FAIL]',
'm': 'gce_net',
'a': 'name=fail ipv4_range=bad_value',
'r': "127.0.0.1 | FAILED >> {\"changed\": false, \"failed\": true, \"msg\": \"Unexpected response: HTTP return_code[400], API error code[None] and message: Invalid value for field 'resource.IPv4Range': 'bad_value'. Must be a CIDR address range that is contained in the RFC1918 private address blocks: [10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16]\"}",
},
{'desc': 'CREATE existing network, not changed [success]',
'm': 'gce_net',
'a': 'name=%s ipv4_range=%s' % (NETWK1, CIDR1),
'r': '127.0.0.1 | success >> {"changed": false, "ipv4_range": "%s", "name": "%s", "state": "present"}' % (CIDR1, NETWK1),
},
{'desc': 'CREATE new network, changed [success]',
'm': 'gce_net',
'a': 'name=%s ipv4_range=%s' % (NETWK2, CIDR2),
'r': '127.0.0.1 | success >> {"changed": true, "ipv4_range": "10.240.32.0/24", "name": "%s", "state": "present"}' % (NETWK2),
},
{'desc': 'CREATE new fw rule missing params [FAIL]',
'm': 'gce_net',
'a': 'name=%s fwname=%s' % (NETWK1, FW1),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Missing required firewall rule parameter(s)"}',
},
{'desc': 'CREATE new fw rule bad params [FAIL]',
'm': 'gce_net',
'a': 'name=%s fwname=broken allowed=blah src_tags="one,two"' % (NETWK1),
'r': "127.0.0.1 | FAILED >> {\"changed\": false, \"failed\": true, \"msg\": \"Unexpected response: HTTP return_code[400], API error code[None] and message: Invalid value for field 'resource.allowed[0].IPProtocol': 'blah'. Must be one of [\\\"tcp\\\", \\\"udp\\\", \\\"icmp\\\"] or an IP protocol number between 0 and 255\"}",
},
{'desc': 'CREATE existing fw rule [success]',
'm': 'gce_net',
'a': 'name=%s fwname=%s allowed="tcp:80" src_tags="one,two"' % (NETWK1, FW1),
'r': '127.0.0.1 | success >> {"allowed": "tcp:80", "changed": false, "fwname": "%s", "ipv4_range": "%s", "name": "%s", "src_range": null, "src_tags": ["one", "two"], "state": "present"}' % (FW1, CIDR1, NETWK1),
},
{'desc': 'CREATE new fw rule [success]',
'm': 'gce_net',
'a': 'name=%s fwname=%s allowed="tcp:80" src_tags="one,two"' % (NETWK1, FW3),
'r': '127.0.0.1 | success >> {"allowed": "tcp:80", "changed": true, "fwname": "%s", "ipv4_range": "%s", "name": "%s", "src_range": null, "src_tags": ["one", "two"], "state": "present"}' % (FW3, CIDR1, NETWK1),
},
{'desc': 'CREATE new network *and* fw rule [success]',
'm': 'gce_net',
'a': 'name=%s ipv4_range=%s fwname=%s allowed="tcp:80" src_tags="one,two"' % (NETWK3, CIDR3, FW4),
'r': '127.0.0.1 | success >> {"allowed": "tcp:80", "changed": true, "fwname": "%s", "ipv4_range": "%s", "name": "%s", "src_range": null, "src_tags": ["one", "two"], "state": "present"}' % (FW4, CIDR3, NETWK3),
},
],
'teardown': ['gcutil deletefirewall -f %s' % (FW1),
'gcutil deletefirewall -f %s' % (FW2),
'gcutil deletefirewall -f %s' % (FW3),
'gcutil deletefirewall -f %s' % (FW4),
'sleep 5',
'gcutil deletenetwork -f %s' % (NETWK1),
'gcutil deletenetwork -f %s' % (NETWK2),
'gcutil deletenetwork -f %s' % (NETWK3),
'sleep 5'],
},
{'id': '08', 'desc': 'Create load-balancer resources',
'setup': ['gcutil addinstance "%s" --zone=%s --machine_type=%s --network=%s --service_account_scopes="%s" --image="%s" --nopersistent_boot_disk' % (INAME, ZONE, TYPE, NETWORK, SCOPES, IMAGE),
'gcutil addinstance "%s" --wait_until_running --zone=%s --machine_type=%s --network=%s --service_account_scopes="%s" --image="%s" --nopersistent_boot_disk' % (INAME2, ZONE, TYPE, NETWORK, SCOPES, IMAGE),
],
'tests': [
{'desc': 'Do nothing [FAIL]',
'm': 'gce_lb',
'a': 'httphealthcheck_port=7',
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Nothing to do, please specify a \\\"name\\\" or \\\"httphealthcheck_name\\\" parameter"}',
},
{'desc': 'CREATE_HC create basic http healthcheck [success]',
'm': 'gce_lb',
'a': 'httphealthcheck_name=%s' % (HC1),
'r': '127.0.0.1 | success >> {"changed": true, "httphealthcheck_healthy_count": 2, "httphealthcheck_host": null, "httphealthcheck_interval": 5, "httphealthcheck_name": "%s", "httphealthcheck_path": "/", "httphealthcheck_port": 80, "httphealthcheck_timeout": 5, "httphealthcheck_unhealthy_count": 2, "name": null, "state": "present"}' % (HC1),
},
{'desc': 'CREATE_HC (repeat, no-op) create basic http healthcheck [success]',
'm': 'gce_lb',
'a': 'httphealthcheck_name=%s' % (HC1),
'r': '127.0.0.1 | success >> {"changed": false, "httphealthcheck_healthy_count": 2, "httphealthcheck_host": null, "httphealthcheck_interval": 5, "httphealthcheck_name": "%s", "httphealthcheck_path": "/", "httphealthcheck_port": 80, "httphealthcheck_timeout": 5, "httphealthcheck_unhealthy_count": 2, "name": null, "state": "present"}' % (HC1),
},
{'desc': 'CREATE_HC create custom http healthcheck [success]',
'm': 'gce_lb',
'a': 'httphealthcheck_name=%s httphealthcheck_port=1234 httphealthcheck_path="/whatup" httphealthcheck_host="foo" httphealthcheck_interval=300' % (HC2),
'r': '127.0.0.1 | success >> {"changed": true, "httphealthcheck_healthy_count": 2, "httphealthcheck_host": "foo", "httphealthcheck_interval": 300, "httphealthcheck_name": "%s", "httphealthcheck_path": "/whatup", "httphealthcheck_port": 1234, "httphealthcheck_timeout": 5, "httphealthcheck_unhealthy_count": 2, "name": null, "state": "present"}' % (HC2),
},
{'desc': 'CREATE_HC create (broken) custom http healthcheck [FAIL]',
'm': 'gce_lb',
'a': 'httphealthcheck_name=%s httphealthcheck_port="string" httphealthcheck_path=7' % (HC3),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Unexpected response: HTTP return_code[400], API error code[None] and message: Invalid value for: Expected a signed integer, got \'string\' (class java.lang.String)"}',
},
{'desc': 'CREATE_LB create lb, missing region [FAIL]',
'm': 'gce_lb',
'a': 'name=%s' % (LB1),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Missing required region name"}',
},
{'desc': 'CREATE_LB create lb, bogus region [FAIL]',
'm': 'gce_lb',
'a': 'name=%s region=bogus' % (LB1),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Unexpected response: HTTP return_code[404], API error code[None] and message: The resource \'projects/%s/regions/bogus\' was not found"}' % (PROJECT),
},
{'desc': 'CREATE_LB create lb, minimal params [success]',
'strip_numbers': True,
'm': 'gce_lb',
'a': 'name=%s region=%s' % (LB1, REGION),
'r': '127.0.0.1 | success >> {"changed": true, "external_ip": "173.255.123.245", "httphealthchecks": [], "members": [], "name": "%s", "port_range": "1-65535", "protocol": "tcp", "region": "%s", "state": "present"}' % (LB1, REGION),
},
{'desc': 'CREATE_LB create lb full params [success]',
'strip_numbers': True,
'm': 'gce_lb',
'a': 'httphealthcheck_name=%s httphealthcheck_port=5055 httphealthcheck_path="/howami" name=%s port_range=8000-8888 region=%s members=%s/%s,%s/%s' % (HC3,LB2,REGION,ZONE,INAME,ZONE,INAME2),
'r': '127.0.0.1 | success >> {"changed": true, "external_ip": "173.255.126.81", "httphealthcheck_healthy_count": 2, "httphealthcheck_host": null, "httphealthcheck_interval": 5, "httphealthcheck_name": "%s", "httphealthcheck_path": "/howami", "httphealthcheck_port": 5055, "httphealthcheck_timeout": 5, "httphealthcheck_unhealthy_count": 2, "httphealthchecks": ["%s"], "members": ["%s/%s", "%s/%s"], "name": "%s", "port_range": "8000-8888", "protocol": "tcp", "region": "%s", "state": "present"}' % (HC3,HC3,ZONE,INAME,ZONE,INAME2,LB2,REGION),
},
],
'teardown': [
'gcutil deleteinstance --zone=%s -f %s %s' % (ZONE, INAME, INAME2),
'gcutil deleteforwardingrule --region=%s -f %s %s' % (REGION, LB1, LB2),
'sleep 10',
'gcutil deletetargetpool --region=%s -f %s-tp %s-tp' % (REGION, LB1, LB2),
'sleep 10',
'gcutil deletehttphealthcheck -f %s %s %s' % (HC1, HC2, HC3),
],
},
{'id': '09', 'desc': 'Destroy load-balancer resources',
'setup': ['gcutil addhttphealthcheck %s' % (HC1),
'sleep 5',
'gcutil addhttphealthcheck %s' % (HC2),
'sleep 5',
'gcutil addtargetpool --health_checks=%s --region=%s %s-tp' % (HC1, REGION, LB1),
'sleep 5',
'gcutil addforwardingrule --target=%s-tp --region=%s %s' % (LB1, REGION, LB1),
'sleep 5',
'gcutil addtargetpool --region=%s %s-tp' % (REGION, LB2),
'sleep 5',
'gcutil addforwardingrule --target=%s-tp --region=%s %s' % (LB2, REGION, LB2),
'sleep 5',
],
'tests': [
{'desc': 'DELETE_LB: delete a non-existent LB [success]',
'm': 'gce_lb',
'a': 'name=missing state=absent',
'r': '127.0.0.1 | success >> {"changed": false, "name": "missing", "state": "absent"}',
},
{'desc': 'DELETE_LB: delete a non-existent LB+HC [success]',
'm': 'gce_lb',
'a': 'name=missing httphealthcheck_name=alsomissing state=absent',
'r': '127.0.0.1 | success >> {"changed": false, "httphealthcheck_name": "alsomissing", "name": "missing", "state": "absent"}',
},
{'desc': 'DELETE_LB: destroy standalone healthcheck [success]',
'm': 'gce_lb',
'a': 'httphealthcheck_name=%s state=absent' % (HC2),
'r': '127.0.0.1 | success >> {"changed": true, "httphealthcheck_name": "%s", "name": null, "state": "absent"}' % (HC2),
},
{'desc': 'DELETE_LB: destroy standalone balancer [success]',
'm': 'gce_lb',
'a': 'name=%s state=absent' % (LB2),
'r': '127.0.0.1 | success >> {"changed": true, "name": "%s", "state": "absent"}' % (LB2),
},
{'desc': 'DELETE_LB: destroy LB+HC [success]',
'm': 'gce_lb',
'a': 'name=%s httphealthcheck_name=%s state=absent' % (LB1, HC1),
'r': '127.0.0.1 | success >> {"changed": true, "httphealthcheck_name": "%s", "name": "%s", "state": "absent"}' % (HC1,LB1),
},
],
'teardown': [
'gcutil deleteforwardingrule --region=%s -f %s %s' % (REGION, LB1, LB2),
'sleep 10',
'gcutil deletetargetpool --region=%s -f %s-tp %s-tp' % (REGION, LB1, LB2),
'sleep 10',
'gcutil deletehttphealthcheck -f %s %s' % (HC1, HC2),
],
},
]
def main(tests_to_run=[]):
for test in test_cases:
if tests_to_run and test['id'] not in tests_to_run:
continue
print "=> starting/setup '%s:%s'"% (test['id'], test['desc'])
if DEBUG: print "=debug>", test['setup']
for c in test['setup']:
(s,o) = run(c)
test_i = 1
for t in test['tests']:
if DEBUG: print "=>debug>", test_i, t['desc']
# run any test-specific setup commands
if t.has_key('setup'):
for setup in t['setup']:
(status, output) = run(setup)
# run any 'peek_before' commands
if t.has_key('peek_before') and PEEKING_ENABLED:
for setup in t['peek_before']:
(status, output) = run(setup)
# run the ansible test if 'a' exists, otherwise
# an empty 'a' directive allows test to run
# setup/teardown for a subsequent test.
if t['a']:
if DEBUG: print "=>debug>", t['m'], t['a']
acmd = "ansible all -o -m %s -a \"%s\"" % (t['m'],t['a'])
#acmd = "ANSIBLE_KEEP_REMOTE_FILES=1 ansible all -vvv -m %s -a \"%s\"" % (t['m'],t['a'])
(s,o) = run(acmd)
# check expected output
if DEBUG: print "=debug>", o.strip(), "!=", t['r']
print "=> %s.%02d '%s':" % (test['id'], test_i, t['desc']),
if t.has_key('strip_numbers'):
# strip out all numbers so we don't trip over different
# IP addresses
is_good = (o.strip().translate(None, "0123456789") == t['r'].translate(None, "0123456789"))
else:
is_good = (o.strip() == t['r'])
if is_good:
print "PASS"
else:
print "FAIL"
if VERBOSE:
print "=>", acmd
print "=> Expected:", t['r']
print "=> Got:", o.strip()
# run any 'peek_after' commands
if t.has_key('peek_after') and PEEKING_ENABLED:
for setup in t['peek_after']:
(status, output) = run(setup)
# run any test-specific teardown commands
if t.has_key('teardown'):
for td in t['teardown']:
(status, output) = run(td)
test_i += 1
print "=> completing/teardown '%s:%s'" % (test['id'], test['desc'])
if DEBUG: print "=debug>", test['teardown']
for c in test['teardown']:
(s,o) = run(c)
if __name__ == '__main__':
tests_to_run = []
if len(sys.argv) == 2:
if sys.argv[1] in ["--help", "--list"]:
print "usage: %s [id1,id2,...,idN]" % sys.argv[0]
print " * An empty argument list will execute all tests"
print " * Do not need to specify tests in numerical order"
print " * List test categories with --list or --help"
print ""
for test in test_cases:
print "\t%s:%s" % (test['id'], test['desc'])
sys.exit(0)
else:
tests_to_run = sys.argv[1].split(',')
main(tests_to_run)

View File

@ -14,5 +14,5 @@
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
__version__ = '1.8.1'
__version__ = '1.5.3'
__author__ = 'Michael DeHaan'

View File

@ -1,61 +0,0 @@
# (c) 2014, Michael DeHaan <michael.dehaan@gmail.com>
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from collections import MutableMapping
from ansible import utils
from ansible import constants as C
from ansible import errors
class FactCache(MutableMapping):
def __init__(self, *args, **kwargs):
self._plugin = utils.plugins.cache_loader.get(C.CACHE_PLUGIN)
if self._plugin is None:
return
def __getitem__(self, key):
if key not in self:
raise KeyError
return self._plugin.get(key)
def __setitem__(self, key, value):
self._plugin.set(key, value)
def __delitem__(self, key):
self._plugin.delete(key)
def __contains__(self, key):
return self._plugin.contains(key)
def __iter__(self):
return iter(self._plugin.keys())
def __len__(self):
return len(self._plugin.keys())
def copy(self):
""" Return a primitive copy of the keys and values from the cache. """
return dict([(k, v) for (k, v) in self.iteritems()])
def keys(self):
return self._plugin.keys()
def flush(self):
""" Flush the fact cache of all keys. """
self._plugin.flush()

View File

@ -1,41 +0,0 @@
# (c) 2014, Brian Coca, Josh Drake, et al
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
import exceptions
class BaseCacheModule(object):
def get(self, key):
raise exceptions.NotImplementedError
def set(self, key, value):
raise exceptions.NotImplementedError
def keys(self):
raise exceptions.NotImplementedError
def contains(self, key):
raise exceptions.NotImplementedError
def delete(self, key):
raise exceptions.NotImplementedError
def flush(self):
raise exceptions.NotImplementedError
def copy(self):
raise exceptions.NotImplementedError

View File

@ -1,137 +0,0 @@
# (c) 2014, Brian Coca, Josh Drake, et al
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
import os
import time
import json
import errno
from ansible import constants as C
from ansible import utils
from ansible.cache.base import BaseCacheModule
class CacheModule(BaseCacheModule):
"""
A caching module backed by json files.
"""
def __init__(self, *args, **kwargs):
self._timeout = float(C.CACHE_PLUGIN_TIMEOUT)
self._cache = {}
self._cache_dir = C.CACHE_PLUGIN_CONNECTION # expects a dir path
if not os.path.exists(self._cache_dir):
try:
os.makedirs(self._cache_dir)
except (OSError,IOError), e:
utils.warning("error while trying to create cache dir %s : %s" % (self._cache_dir, str(e)))
return None
def get(self, key):
if key in self._cache:
return self._cache.get(key)
if self.has_expired(key):
raise KeyError
cachefile = "%s/%s" % (self._cache_dir, key)
try:
f = open( cachefile, 'r')
except (OSError,IOError), e:
utils.warning("error while trying to write to %s : %s" % (cachefile, str(e)))
else:
value = json.load(f)
self._cache[key] = value
return value
finally:
f.close()
def set(self, key, value):
self._cache[key] = value
cachefile = "%s/%s" % (self._cache_dir, key)
try:
#TODO: check if valid keys can have invalid FS chars, base32?
f = open(cachefile, 'w')
except (OSError,IOError), e:
utils.warning("error while trying to read %s : %s" % (cachefile, str(e)))
else:
json.dump(value, f, ensure_ascii=False)
finally:
f.close()
def has_expired(self, key):
cachefile = "%s/%s" % (self._cache_dir, key)
try:
st = os.stat(cachefile)
except (OSError,IOError), e:
if e.errno == errno.ENOENT:
return False
else:
utils.warning("error while trying to stat %s : %s" % (cachefile, str(e)))
if time.time() - st.st_mtime <= self._timeout:
return False
if key in self._cache:
del self._cache[key]
return True
def keys(self):
keys = []
for k in os.listdir(self._cache_dir):
if not self.has_expired(k):
keys.append(k)
return keys
def contains(self, key):
if key in self._cache:
return True
if self.has_expired(key):
return False
try:
st = os.stat("%s/%s" % (self._cache_dir, key))
return True
except (OSError,IOError), e:
if e.errno == errno.ENOENT:
return False
else:
utils.warning("error while trying to stat %s : %s" % (cachefile, str(e)))
def delete(self, key):
del self._cache[key]
try:
os.remove("%s/%s" % (self._cache_dir, key))
except (OSError,IOError), e:
pass #TODO: only pass on non existing?
def flush(self):
self._cache = {}
for key in self.keys():
self.delete(key)
def copy(self):
ret = dict()
for key in self.keys():
ret[key] = self.get(key)
return ret

View File

@ -1,191 +0,0 @@
# (c) 2014, Brian Coca, Josh Drake, et al
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
import collections
import os
import sys
import time
import threading
from itertools import chain
from ansible import constants as C
from ansible.cache.base import BaseCacheModule
try:
import memcache
except ImportError:
print 'python-memcached is required for the memcached fact cache'
sys.exit(1)
class ProxyClientPool(object):
"""
Memcached connection pooling for thread/fork safety. Inspired by py-redis
connection pool.
Available connections are maintained in a deque and released in a FIFO manner.
"""
def __init__(self, *args, **kwargs):
self.max_connections = kwargs.pop('max_connections', 1024)
self.connection_args = args
self.connection_kwargs = kwargs
self.reset()
def reset(self):
self.pid = os.getpid()
self._num_connections = 0
self._available_connections = collections.deque(maxlen=self.max_connections)
self._locked_connections = set()
self._lock = threading.Lock()
def _check_safe(self):
if self.pid != os.getpid():
with self._lock:
if self.pid == os.getpid():
# bail out - another thread already acquired the lock
return
self.disconnect_all()
self.reset()
def get_connection(self):
self._check_safe()
try:
connection = self._available_connections.popleft()
except IndexError:
connection = self.create_connection()
self._locked_connections.add(connection)
return connection
def create_connection(self):
if self._num_connections >= self.max_connections:
raise RuntimeError("Too many memcached connections")
self._num_connections += 1
return memcache.Client(*self.connection_args, **self.connection_kwargs)
def release_connection(self, connection):
self._check_safe()
self._locked_connections.remove(connection)
self._available_connections.append(connection)
def disconnect_all(self):
for conn in chain(self._available_connections, self._locked_connections):
conn.disconnect_all()
def __getattr__(self, name):
def wrapped(*args, **kwargs):
return self._proxy_client(name, *args, **kwargs)
return wrapped
def _proxy_client(self, name, *args, **kwargs):
conn = self.get_connection()
try:
return getattr(conn, name)(*args, **kwargs)
finally:
self.release_connection(conn)
class CacheModuleKeys(collections.MutableSet):
"""
A set subclass that keeps track of insertion time and persists
the set in memcached.
"""
PREFIX = 'ansible_cache_keys'
def __init__(self, cache, *args, **kwargs):
self._cache = cache
self._keyset = dict(*args, **kwargs)
def __contains__(self, key):
return key in self._keyset
def __iter__(self):
return iter(self._keyset)
def __len__(self):
return len(self._keyset)
def add(self, key):
self._keyset[key] = time.time()
self._cache.set(self.PREFIX, self._keyset)
def discard(self, key):
del self._keyset[key]
self._cache.set(self.PREFIX, self._keyset)
def remove_by_timerange(self, s_min, s_max):
for k in self._keyset.keys():
t = self._keyset[k]
if s_min < t < s_max:
del self._keyset[k]
self._cache.set(self.PREFIX, self._keyset)
class CacheModule(BaseCacheModule):
def __init__(self, *args, **kwargs):
if C.CACHE_PLUGIN_CONNECTION:
connection = C.CACHE_PLUGIN_CONNECTION.split(',')
else:
connection = ['127.0.0.1:11211']
self._timeout = C.CACHE_PLUGIN_TIMEOUT
self._prefix = C.CACHE_PLUGIN_PREFIX
self._cache = ProxyClientPool(connection, debug=0)
self._keys = CacheModuleKeys(self._cache, self._cache.get(CacheModuleKeys.PREFIX) or [])
def _make_key(self, key):
return "{0}{1}".format(self._prefix, key)
def _expire_keys(self):
if self._timeout > 0:
expiry_age = time.time() - self._timeout
self._keys.remove_by_timerange(0, expiry_age)
def get(self, key):
value = self._cache.get(self._make_key(key))
# guard against the key not being removed from the keyset;
# this could happen in cases where the timeout value is changed
# between invocations
if value is None:
self.delete(key)
raise KeyError
return value
def set(self, key, value):
self._cache.set(self._make_key(key), value, time=self._timeout, min_compress_len=1)
self._keys.add(key)
def keys(self):
self._expire_keys()
return list(iter(self._keys))
def contains(self, key):
self._expire_keys()
return key in self._keys
def delete(self, key):
self._cache.delete(self._make_key(key))
self._keys.discard(key)
def flush(self):
for key in self.keys():
self.delete(key)
def copy(self):
return self._keys.copy()

View File

@ -1,44 +0,0 @@
# (c) 2014, Brian Coca, Josh Drake, et al
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from ansible.cache.base import BaseCacheModule
class CacheModule(BaseCacheModule):
def __init__(self, *args, **kwargs):
self._cache = {}
def get(self, key):
return self._cache.get(key)
def set(self, key, value):
self._cache[key] = value
def keys(self):
return self._cache.keys()
def contains(self, key):
return key in self._cache
def delete(self, key):
del self._cache[key]
def flush(self):
self._cache = {}
def copy(self):
return self._cache.copy()

View File

@ -1,102 +0,0 @@
# (c) 2014, Brian Coca, Josh Drake, et al
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
import collections
# FIXME: can we store these as something else before we ship it?
import sys
import time
import json
from ansible import constants as C
from ansible.cache.base import BaseCacheModule
try:
from redis import StrictRedis
except ImportError:
print "The 'redis' python module is required, 'pip install redis'"
sys.exit(1)
class CacheModule(BaseCacheModule):
"""
A caching module backed by redis.
Keys are maintained in a zset with their score being the timestamp
when they are inserted. This allows for the usage of 'zremrangebyscore'
to expire keys. This mechanism is used or a pattern matched 'scan' for
performance.
"""
def __init__(self, *args, **kwargs):
if C.CACHE_PLUGIN_CONNECTION:
connection = C.CACHE_PLUGIN_CONNECTION.split(':')
else:
connection = []
self._timeout = float(C.CACHE_PLUGIN_TIMEOUT)
self._prefix = C.CACHE_PLUGIN_PREFIX
self._cache = StrictRedis(*connection)
self._keys_set = 'ansible_cache_keys'
def _make_key(self, key):
return self._prefix + key
def get(self, key):
value = self._cache.get(self._make_key(key))
# guard against the key not being removed from the zset;
# this could happen in cases where the timeout value is changed
# between invocations
if value is None:
self.delete(key)
raise KeyError
return json.loads(value)
def set(self, key, value):
value2 = json.dumps(value)
if self._timeout > 0: # a timeout of 0 is handled as meaning 'never expire'
self._cache.setex(self._make_key(key), int(self._timeout), value2)
else:
self._cache.set(self._make_key(key), value2)
self._cache.zadd(self._keys_set, time.time(), key)
def _expire_keys(self):
if self._timeout > 0:
expiry_age = time.time() - self._timeout
self._cache.zremrangebyscore(self._keys_set, 0, expiry_age)
def keys(self):
self._expire_keys()
return self._cache.zrange(self._keys_set, 0, -1)
def contains(self, key):
self._expire_keys()
return (self._cache.zrank(self._keys_set, key) >= 0)
def delete(self, key):
self._cache.delete(self._make_key(key))
self._cache.zrem(self._keys_set, key)
def flush(self):
for key in self.keys():
self.delete(key)
def copy(self):
# FIXME: there is probably a better way to do this in redis
ret = dict()
for key in self.keys():
ret[key] = self.get(key)
return ret

View File

@ -41,6 +41,9 @@ class CallbackModule(object):
def runner_on_ok(self, host, res):
pass
def runner_on_error(self, host, msg):
pass
def runner_on_skipped(self, host, item=None):
pass
@ -86,7 +89,7 @@ class CallbackModule(object):
def playbook_on_not_import_for_host(self, host, missing_file):
pass
def playbook_on_play_start(self, name):
def playbook_on_play_start(self, pattern):
pass
def playbook_on_stats(self, stats):

View File

@ -25,7 +25,6 @@ import fnmatch
import tempfile
import fcntl
import constants
import locale
from ansible.color import stringc
import logging
@ -116,12 +115,6 @@ def log_unflock(runner):
except OSError:
pass
def set_playbook(callback, playbook):
''' used to notify callback plugins of playbook context '''
callback.playbook = playbook
for callback_plugin in callback_plugins:
callback_plugin.playbook = playbook
def set_play(callback, play):
''' used to notify callback plugins of context '''
callback.play = play
@ -257,7 +250,7 @@ def regular_generic_msg(hostname, result, oneline, caption):
def banner_cowsay(msg):
if ": [" in msg:
if msg.find(": [") != -1:
msg = msg.replace("[","")
if msg.endswith("]"):
msg = msg[:-1]
@ -344,6 +337,9 @@ class DefaultRunnerCallbacks(object):
def on_ok(self, host, res):
call_callback_module('runner_on_ok', host, res)
def on_error(self, host, msg):
call_callback_module('runner_on_error', host, msg)
def on_skipped(self, host, item=None):
call_callback_module('runner_on_skipped', host, item=item)
@ -402,6 +398,10 @@ class CliRunnerCallbacks(DefaultRunnerCallbacks):
display("%s | skipped" % (host), runner=self.runner)
super(CliRunnerCallbacks, self).on_skipped(host, item)
def on_error(self, host, err):
display("err: [%s] => %s\n" % (host, err), stderr=True, runner=self.runner)
super(CliRunnerCallbacks, self).on_error(host, err)
def on_no_hosts(self):
display("no hosts matched\n", stderr=True, runner=self.runner)
super(CliRunnerCallbacks, self).on_no_hosts()
@ -411,12 +411,11 @@ class CliRunnerCallbacks(DefaultRunnerCallbacks):
self._async_notified[jid] = clock + 1
if self._async_notified[jid] > clock:
self._async_notified[jid] = clock
display("<job %s> polling on %s, %ss remaining" % (jid, host, clock), runner=self.runner)
display("<job %s> polling, %ss remaining" % (jid, clock), runner=self.runner)
super(CliRunnerCallbacks, self).on_async_poll(host, res, jid, clock)
def on_async_ok(self, host, res, jid):
if jid:
display("<job %s> finished on %s => %s"%(jid, host, utils.jsonify(res,format=True)), runner=self.runner)
display("<job %s> finished on %s => %s"%(jid, host, utils.jsonify(res,format=True)), runner=self.runner)
super(CliRunnerCallbacks, self).on_async_ok(host, res, jid)
def on_async_failed(self, host, res, jid):
@ -450,9 +449,6 @@ class PlaybookRunnerCallbacks(DefaultRunnerCallbacks):
self._async_notified = {}
def on_unreachable(self, host, results):
if self.runner.delegate_to:
host = '%s -> %s' % (host, self.runner.delegate_to)
item = None
if type(results) == dict:
item = results.get('item', None)
@ -464,8 +460,7 @@ class PlaybookRunnerCallbacks(DefaultRunnerCallbacks):
super(PlaybookRunnerCallbacks, self).on_unreachable(host, results)
def on_failed(self, host, results, ignore_errors=False):
if self.runner.delegate_to:
host = '%s -> %s' % (host, self.runner.delegate_to)
results2 = results.copy()
results2.pop('invocation', None)
@ -492,14 +487,12 @@ class PlaybookRunnerCallbacks(DefaultRunnerCallbacks):
if returned_msg:
display("msg: %s" % returned_msg, color='red', runner=self.runner)
if not parsed and module_msg:
display(module_msg, color='red', runner=self.runner)
display("invalid output was: %s" % module_msg, color='red', runner=self.runner)
if ignore_errors:
display("...ignoring", color='cyan', runner=self.runner)
super(PlaybookRunnerCallbacks, self).on_failed(host, results, ignore_errors=ignore_errors)
def on_ok(self, host, host_result):
if self.runner.delegate_to:
host = '%s -> %s' % (host, self.runner.delegate_to)
item = host_result.get('item', None)
@ -533,15 +526,21 @@ class PlaybookRunnerCallbacks(DefaultRunnerCallbacks):
display(msg, color='green', runner=self.runner)
else:
display(msg, color='yellow', runner=self.runner)
if constants.COMMAND_WARNINGS and 'warnings' in host_result2 and host_result2['warnings']:
for warning in host_result2['warnings']:
display("warning: %s" % warning, color='purple', runner=self.runner)
super(PlaybookRunnerCallbacks, self).on_ok(host, host_result)
def on_skipped(self, host, item=None):
if self.runner.delegate_to:
host = '%s -> %s' % (host, self.runner.delegate_to)
def on_error(self, host, err):
item = err.get('item', None)
msg = ''
if item:
msg = "err: [%s] => (item=%s) => %s" % (host, item, err)
else:
msg = "err: [%s] => %s" % (host, err)
display(msg, color='red', stderr=True, runner=self.runner)
super(PlaybookRunnerCallbacks, self).on_error(host, err)
def on_skipped(self, host, item=None):
if constants.DISPLAY_SKIPPED_HOSTS:
msg = ''
if item:
@ -565,9 +564,8 @@ class PlaybookRunnerCallbacks(DefaultRunnerCallbacks):
super(PlaybookRunnerCallbacks, self).on_async_poll(host,res,jid,clock)
def on_async_ok(self, host, res, jid):
if jid:
msg = "<job %s> finished on %s"%(jid, host)
display(msg, color='cyan', runner=self.runner)
msg = "<job %s> finished on %s"%(jid, host)
display(msg, color='cyan', runner=self.runner)
super(PlaybookRunnerCallbacks, self).on_async_ok(host, res, jid)
def on_async_failed(self, host, res, jid):
@ -603,13 +601,11 @@ class PlaybookCallbacks(object):
call_callback_module('playbook_on_no_hosts_remaining')
def on_task_start(self, name, is_conditional):
name = utils.to_bytes(name)
msg = "TASK: [%s]" % name
if is_conditional:
msg = "NOTIFIED: [%s]" % name
if hasattr(self, 'start_at'):
self.start_at = utils.to_bytes(self.start_at)
if name == self.start_at or fnmatch.fnmatch(name, self.start_at):
# we found out match, we can get rid of this now
del self.start_at
@ -641,7 +637,7 @@ class PlaybookCallbacks(object):
def on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None):
if prompt and default is not None:
if prompt and default:
msg = "%s [%s]: " % (prompt, default)
elif prompt:
msg = "%s: " % prompt
@ -649,16 +645,9 @@ class PlaybookCallbacks(object):
msg = 'input for %s: ' % varname
def prompt(prompt, private):
if sys.stdout.encoding:
msg = prompt.encode(sys.stdout.encoding)
else:
# when piping the output, or at other times when stdout
# may not be the standard file descriptor, the stdout
# encoding may not be set, so default to something sane
msg = prompt.encode(locale.getpreferredencoding())
if private:
return getpass.getpass(msg)
return raw_input(msg)
return getpass.getpass(prompt)
return raw_input(prompt)
if confirm:
@ -699,9 +688,9 @@ class PlaybookCallbacks(object):
display(msg, color='cyan')
call_callback_module('playbook_on_not_import_for_host', host, missing_file)
def on_play_start(self, name):
display(banner("PLAY [%s]" % name))
call_callback_module('playbook_on_play_start', name)
def on_play_start(self, pattern):
display(banner("PLAY [%s]" % pattern))
call_callback_module('playbook_on_play_start', pattern)
def on_stats(self, stats):
call_callback_module('playbook_on_stats', stats)

View File

@ -15,6 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
import constants
@ -36,13 +37,13 @@ else:
# curses returns an error (e.g. could not find terminal)
ANSIBLE_COLOR=False
if constants.ANSIBLE_FORCE_COLOR:
if os.getenv("ANSIBLE_FORCE_COLOR") is not None:
ANSIBLE_COLOR=True
# --- begin "pretty"
#
# pretty - A miniature library that provides a Python print and stdout
# wrapper that makes colored terminal text easier to use (e.g. without
# wrapper that makes colored terminal text easier to use (eg. without
# having to mess around with ANSI escape sequences). This code is public
# domain - there is no license except that you must leave this header.
#

View File

@ -31,7 +31,7 @@ def mk_boolean(value):
else:
return False
def get_config(p, section, key, env_var, default, boolean=False, integer=False, floating=False, islist=False):
def get_config(p, section, key, env_var, default, boolean=False, integer=False, floating=False):
''' return a configuration variable with casting '''
value = _get_config(p, section, key, env_var, default)
if boolean:
@ -40,8 +40,6 @@ def get_config(p, section, key, env_var, default, boolean=False, integer=False,
return int(value)
if value and floating:
return float(value)
if value and islist:
return [x.strip() for x in value.split(',')]
return value
def _get_config(p, section, key, env_var, default):
@ -71,11 +69,7 @@ def load_config_file():
for path in [path0, path1, path2, path3]:
if path is not None and os.path.exists(path):
try:
p.read(path)
except ConfigParser.Error as e:
print "Error reading config file: \n%s" % e
sys.exit(1)
p.read(path)
return p
return None
@ -83,30 +77,38 @@ def shell_expand_path(path):
''' shell_expand_path is needed as os.path.expanduser does not work
when path is None, which is the default for ANSIBLE_PRIVATE_KEY_FILE '''
if path:
path = os.path.expanduser(os.path.expandvars(path))
path = os.path.expanduser(path)
return path
p = load_config_file()
active_user = pwd.getpwuid(os.geteuid())[0]
# Needed so the RPM can call setup.py and have modules land in the
# correct location. See #1277 for discussion
if getattr(sys, "real_prefix", None):
# in a virtualenv
DIST_MODULE_PATH = os.path.join(sys.prefix, 'share/ansible/')
else:
DIST_MODULE_PATH = '/usr/share/ansible/'
# check all of these extensions when looking for yaml files for things like
# group variables -- really anything we can load
YAML_FILENAME_EXTENSIONS = [ "", ".yml", ".yaml", ".json" ]
# group variables
YAML_FILENAME_EXTENSIONS = [ "", ".yml", ".yaml" ]
# sections in config file
DEFAULTS='defaults'
# configurable things
DEFAULT_HOST_LIST = shell_expand_path(get_config(p, DEFAULTS, 'hostfile', 'ANSIBLE_HOSTS', '/etc/ansible/hosts'))
DEFAULT_MODULE_PATH = get_config(p, DEFAULTS, 'library', 'ANSIBLE_LIBRARY', None)
DEFAULT_ROLES_PATH = shell_expand_path(get_config(p, DEFAULTS, 'roles_path', 'ANSIBLE_ROLES_PATH', '/etc/ansible/roles'))
DEFAULT_REMOTE_TMP = get_config(p, DEFAULTS, 'remote_tmp', 'ANSIBLE_REMOTE_TEMP', '$HOME/.ansible/tmp')
DEFAULT_MODULE_PATH = get_config(p, DEFAULTS, 'library', 'ANSIBLE_LIBRARY', DIST_MODULE_PATH)
DEFAULT_ROLES_PATH = get_config(p, DEFAULTS, 'roles_path', 'ANSIBLE_ROLES_PATH', '/etc/ansible/roles')
DEFAULT_REMOTE_TMP = shell_expand_path(get_config(p, DEFAULTS, 'remote_tmp', 'ANSIBLE_REMOTE_TEMP', '$HOME/.ansible/tmp'))
DEFAULT_MODULE_NAME = get_config(p, DEFAULTS, 'module_name', None, 'command')
DEFAULT_PATTERN = get_config(p, DEFAULTS, 'pattern', None, '*')
DEFAULT_FORKS = get_config(p, DEFAULTS, 'forks', 'ANSIBLE_FORKS', 5, integer=True)
DEFAULT_MODULE_ARGS = get_config(p, DEFAULTS, 'module_args', 'ANSIBLE_MODULE_ARGS', '')
DEFAULT_MODULE_LANG = get_config(p, DEFAULTS, 'module_lang', 'ANSIBLE_MODULE_LANG', 'en_US.UTF-8')
DEFAULT_MODULE_LANG = get_config(p, DEFAULTS, 'module_lang', 'ANSIBLE_MODULE_LANG', 'C')
DEFAULT_TIMEOUT = get_config(p, DEFAULTS, 'timeout', 'ANSIBLE_TIMEOUT', 10, integer=True)
DEFAULT_POLL_INTERVAL = get_config(p, DEFAULTS, 'poll_interval', 'ANSIBLE_POLL_INTERVAL', 15, integer=True)
DEFAULT_REMOTE_USER = get_config(p, DEFAULTS, 'remote_user', 'ANSIBLE_REMOTE_USER', active_user)
@ -116,7 +118,6 @@ DEFAULT_SUDO_USER = get_config(p, DEFAULTS, 'sudo_user', 'ANSIBLE
DEFAULT_ASK_SUDO_PASS = get_config(p, DEFAULTS, 'ask_sudo_pass', 'ANSIBLE_ASK_SUDO_PASS', False, boolean=True)
DEFAULT_REMOTE_PORT = get_config(p, DEFAULTS, 'remote_port', 'ANSIBLE_REMOTE_PORT', None, integer=True)
DEFAULT_ASK_VAULT_PASS = get_config(p, DEFAULTS, 'ask_vault_pass', 'ANSIBLE_ASK_VAULT_PASS', False, boolean=True)
DEFAULT_VAULT_PASSWORD_FILE = shell_expand_path(get_config(p, DEFAULTS, 'vault_password_file', 'ANSIBLE_VAULT_PASSWORD_FILE', None))
DEFAULT_TRANSPORT = get_config(p, DEFAULTS, 'transport', 'ANSIBLE_TRANSPORT', 'smart')
DEFAULT_SCP_IF_SSH = get_config(p, 'ssh_connection', 'scp_if_ssh', 'ANSIBLE_SCP_IF_SSH', False, boolean=True)
DEFAULT_MANAGED_STR = get_config(p, DEFAULTS, 'ansible_managed', None, 'Ansible managed: {file} modified on %Y-%m-%d %H:%M:%S by {uid} on {host}')
@ -126,17 +127,16 @@ DEFAULT_SUDO = get_config(p, DEFAULTS, 'sudo', 'ANSIBLE_SUDO', Fals
DEFAULT_SUDO_EXE = get_config(p, DEFAULTS, 'sudo_exe', 'ANSIBLE_SUDO_EXE', 'sudo')
DEFAULT_SUDO_FLAGS = get_config(p, DEFAULTS, 'sudo_flags', 'ANSIBLE_SUDO_FLAGS', '-H')
DEFAULT_HASH_BEHAVIOUR = get_config(p, DEFAULTS, 'hash_behaviour', 'ANSIBLE_HASH_BEHAVIOUR', 'replace')
DEFAULT_LEGACY_PLAYBOOK_VARIABLES = get_config(p, DEFAULTS, 'legacy_playbook_variables', 'ANSIBLE_LEGACY_PLAYBOOK_VARIABLES', True, boolean=True)
DEFAULT_JINJA2_EXTENSIONS = get_config(p, DEFAULTS, 'jinja2_extensions', 'ANSIBLE_JINJA2_EXTENSIONS', None)
DEFAULT_EXECUTABLE = get_config(p, DEFAULTS, 'executable', 'ANSIBLE_EXECUTABLE', '/bin/sh')
DEFAULT_SU_EXE = get_config(p, DEFAULTS, 'su_exe', 'ANSIBLE_SU_EXE', 'su')
DEFAULT_SU = get_config(p, DEFAULTS, 'su', 'ANSIBLE_SU', False, boolean=True)
DEFAULT_SU_FLAGS = get_config(p, DEFAULTS, 'su_flags', 'ANSIBLE_SU_FLAGS', '')
DEFAULT_SU_USER = get_config(p, DEFAULTS, 'su_user', 'ANSIBLE_SU_USER', 'root')
DEFAULT_ASK_SU_PASS = get_config(p, DEFAULTS, 'ask_su_pass', 'ANSIBLE_ASK_SU_PASS', False, boolean=True)
DEFAULT_GATHERING = get_config(p, DEFAULTS, 'gathering', 'ANSIBLE_GATHERING', 'implicit').lower()
DEFAULT_SU_EXE = get_config(p, DEFAULTS, 'su_exe', 'ANSIBLE_SU_EXE', 'su')
DEFAULT_SU = get_config(p, DEFAULTS, 'su', 'ANSIBLE_SU', False, boolean=True)
DEFAULT_SU_FLAGS = get_config(p, DEFAULTS, 'su_flags', 'ANSIBLE_SU_FLAGS', '')
DEFAULT_SU_USER = get_config(p, DEFAULTS, 'su_user', 'ANSIBLE_SU_USER', 'root')
DEFAULT_ASK_SU_PASS = get_config(p, DEFAULTS, 'ask_su_pass', 'ANSIBLE_ASK_SU_PASS', False, boolean=True)
DEFAULT_ACTION_PLUGIN_PATH = get_config(p, DEFAULTS, 'action_plugins', 'ANSIBLE_ACTION_PLUGINS', '/usr/share/ansible_plugins/action_plugins')
DEFAULT_CACHE_PLUGIN_PATH = get_config(p, DEFAULTS, 'cache_plugins', 'ANSIBLE_CACHE_PLUGINS', '/usr/share/ansible_plugins/cache_plugins')
DEFAULT_CALLBACK_PLUGIN_PATH = get_config(p, DEFAULTS, 'callback_plugins', 'ANSIBLE_CALLBACK_PLUGINS', '/usr/share/ansible_plugins/callback_plugins')
DEFAULT_CONNECTION_PLUGIN_PATH = get_config(p, DEFAULTS, 'connection_plugins', 'ANSIBLE_CONNECTION_PLUGINS', '/usr/share/ansible_plugins/connection_plugins')
DEFAULT_LOOKUP_PLUGIN_PATH = get_config(p, DEFAULTS, 'lookup_plugins', 'ANSIBLE_LOOKUP_PLUGINS', '/usr/share/ansible_plugins/lookup_plugins')
@ -144,22 +144,16 @@ DEFAULT_VARS_PLUGIN_PATH = get_config(p, DEFAULTS, 'vars_plugins', '
DEFAULT_FILTER_PLUGIN_PATH = get_config(p, DEFAULTS, 'filter_plugins', 'ANSIBLE_FILTER_PLUGINS', '/usr/share/ansible_plugins/filter_plugins')
DEFAULT_LOG_PATH = shell_expand_path(get_config(p, DEFAULTS, 'log_path', 'ANSIBLE_LOG_PATH', ''))
CACHE_PLUGIN = get_config(p, DEFAULTS, 'fact_caching', 'ANSIBLE_CACHE_PLUGIN', 'memory')
CACHE_PLUGIN_CONNECTION = get_config(p, DEFAULTS, 'fact_caching_connection', 'ANSIBLE_CACHE_PLUGIN_CONNECTION', None)
CACHE_PLUGIN_PREFIX = get_config(p, DEFAULTS, 'fact_caching_prefix', 'ANSIBLE_CACHE_PLUGIN_PREFIX', 'ansible_facts')
CACHE_PLUGIN_TIMEOUT = get_config(p, DEFAULTS, 'fact_caching_timeout', 'ANSIBLE_CACHE_PLUGIN_TIMEOUT', 24 * 60 * 60, integer=True)
# URL Arguments for generic module urllib2 use
DEFAULT_HTTP_USER_AGENT = get_config(p, DEFAULTS, 'http_user_agent', 'ANSIBLE_HTTP_USER_AGENT', 'ansible-agent')
DEFAULT_CA_FILE_PATH = shell_expand_path(get_config(p, DEFAULTS, 'ca_file_path', 'ANSIBLE_CA_FILE_PATH', ''))
ANSIBLE_FORCE_COLOR = get_config(p, DEFAULTS, 'force_color', 'ANSIBLE_FORCE_COLOR', None, boolean=True)
ANSIBLE_NOCOLOR = get_config(p, DEFAULTS, 'nocolor', 'ANSIBLE_NOCOLOR', None, boolean=True)
ANSIBLE_NOCOWS = get_config(p, DEFAULTS, 'nocows', 'ANSIBLE_NOCOWS', None, boolean=True)
DISPLAY_SKIPPED_HOSTS = get_config(p, DEFAULTS, 'display_skipped_hosts', 'DISPLAY_SKIPPED_HOSTS', True, boolean=True)
DEFAULT_UNDEFINED_VAR_BEHAVIOR = get_config(p, DEFAULTS, 'error_on_undefined_vars', 'ANSIBLE_ERROR_ON_UNDEFINED_VARS', True, boolean=True)
HOST_KEY_CHECKING = get_config(p, DEFAULTS, 'host_key_checking', 'ANSIBLE_HOST_KEY_CHECKING', True, boolean=True)
SYSTEM_WARNINGS = get_config(p, DEFAULTS, 'system_warnings', 'ANSIBLE_SYSTEM_WARNINGS', True, boolean=True)
DEPRECATION_WARNINGS = get_config(p, DEFAULTS, 'deprecation_warnings', 'ANSIBLE_DEPRECATION_WARNINGS', True, boolean=True)
DEFAULT_CALLABLE_WHITELIST = get_config(p, DEFAULTS, 'callable_whitelist', 'ANSIBLE_CALLABLE_WHITELIST', [], islist=True)
COMMAND_WARNINGS = get_config(p, DEFAULTS, 'command_warnings', 'ANSIBLE_COMMAND_WARNINGS', False, boolean=True)
DEFAULT_LOAD_CALLBACK_PLUGINS = get_config(p, DEFAULTS, 'bin_ansible_callbacks', 'ANSIBLE_LOAD_CALLBACK_PLUGINS', False, boolean=True)
# CONNECTION RELATED
ANSIBLE_SSH_ARGS = get_config(p, 'ssh_connection', 'ssh_args', 'ANSIBLE_SSH_ARGS', None)
@ -171,11 +165,9 @@ ZEROMQ_PORT = get_config(p, 'fireball_connection', 'zeromq_po
ACCELERATE_PORT = get_config(p, 'accelerate', 'accelerate_port', 'ACCELERATE_PORT', 5099, integer=True)
ACCELERATE_TIMEOUT = get_config(p, 'accelerate', 'accelerate_timeout', 'ACCELERATE_TIMEOUT', 30, integer=True)
ACCELERATE_CONNECT_TIMEOUT = get_config(p, 'accelerate', 'accelerate_connect_timeout', 'ACCELERATE_CONNECT_TIMEOUT', 1.0, floating=True)
ACCELERATE_DAEMON_TIMEOUT = get_config(p, 'accelerate', 'accelerate_daemon_timeout', 'ACCELERATE_DAEMON_TIMEOUT', 30, integer=True)
ACCELERATE_KEYS_DIR = get_config(p, 'accelerate', 'accelerate_keys_dir', 'ACCELERATE_KEYS_DIR', '~/.fireball.keys')
ACCELERATE_KEYS_DIR_PERMS = get_config(p, 'accelerate', 'accelerate_keys_dir_perms', 'ACCELERATE_KEYS_DIR_PERMS', '700')
ACCELERATE_KEYS_FILE_PERMS = get_config(p, 'accelerate', 'accelerate_keys_file_perms', 'ACCELERATE_KEYS_FILE_PERMS', '600')
ACCELERATE_MULTI_KEY = get_config(p, 'accelerate', 'accelerate_multi_key', 'ACCELERATE_MULTI_KEY', False, boolean=True)
PARAMIKO_PTY = get_config(p, 'paramiko_connection', 'pty', 'ANSIBLE_PARAMIKO_PTY', True, boolean=True)
# characters included in auto-generated passwords

Some files were not shown because too many files have changed in this diff Show More