Compare commits

...

1096 Commits
0.7.2 ... 0.8

Author SHA1 Message Date
e07227194b Update packaging and CHANGELOG for release 2012-10-19 20:46:59 -04:00
0a47cf5ee1 update changelog 2012-10-19 20:45:06 -04:00
69fbc5ad1f Merge pull request #1388 from goozbach/selinux_bugs
make policy only be required if state is not disabled
2012-10-19 16:35:15 -07:00
ce6bd0c96d Merge pull request #1386 from jkleint/devel
Update Hadoop contrib URL.
2012-10-19 16:33:55 -07:00
f5d7005e6c Merge pull request #1387 from skvidal/devel
when a pkg is installed, but not from any repo, don't error out
2012-10-19 16:33:35 -07:00
9961c1e2ef make policy only be required if state is not disabled 2012-10-19 17:17:30 -04:00
33be7526c7 when a pkg is installed, but not from any repo, don't error out
that it is not installed.

Also when a pkg is both installed and in a repo do not look it up
more than once
2012-10-19 16:28:39 -04:00
4f3b671e47 Update Hadoop contrib URL.
References issue #1380.
2012-10-19 10:49:44 -04:00
84f485620c Merge pull request #1385 from dhozac/raise-error-for-scripts-too
Raise error for missing hosts in inventory scripts as well
2012-10-19 07:30:01 -07:00
c8245f3440 Raise error for missing hosts in inventory scripts as well 2012-10-19 16:26:12 +02:00
aed907958d Merge pull request #1383 from dhozac/fix-for-local-port
None is unfortunately not an integer
2012-10-19 07:24:48 -07:00
06923cd1f6 None is unfortunately not an integer 2012-10-19 16:18:38 +02:00
23831668c1 Update contrib/README.md 2012-10-18 21:58:17 -03:00
4b7f2579a8 delete extra else clause 2012-10-18 20:27:39 -04:00
9441bd723f Merge branch 'devel' of git://github.com/willthames/ansible into devel 2012-10-18 20:23:10 -04:00
a94a228cb4 update changelog 2012-10-18 20:21:27 -04:00
a908bd6a8f When using delegation, local_action should always use the local connection type. 2012-10-18 20:18:33 -04:00
6f05eb9b69 Merge pull request #1361 from lantins/devel
Copy module can replace symlink with a real file.
2012-10-18 16:59:45 -07:00
731ef69eae Merge pull request #1367 from jpmens/mdtempl
Add support for Github-flavored Markdown to module_formatter
2012-10-18 16:59:18 -07:00
cff8ea1434 Merge pull request #1372 from jpmens/rst_template1
module_formatter: .rst now correctly handles code examples
2012-10-18 16:58:08 -07:00
3fd77edecd Merge pull request #1373 from jpmens/who1
Addition to WhoUses + typo fix
2012-10-18 16:57:50 -07:00
d3b543c2a2 Merge pull request #1374 from brainpage/symlink_fix
symlink fix
2012-10-18 16:57:25 -07:00
ee4bb97ab7 Merge pull request #1375 from sergevanginderachter/devel
docsite: small typo in handlers example yaml
2012-10-18 16:57:06 -07:00
4e79835b34 Merge pull request #1378 from dhozac/ansible_ssh-fixes
Fixes for ansible_ssh_host and ansible_ssh_port
2012-10-18 16:54:20 -07:00
6701726ba5 Port should be an integer 2012-10-18 21:48:57 +02:00
28ca655217 Accessing a node that doesn't exist throws an exception 2012-10-18 21:48:10 +02:00
d5c5390acf typo in handlers example yaml 2012-10-18 14:35:35 +02:00
736b554691 symlink fix 2012-10-18 20:08:57 +08:00
f834c62ffb Addition to WhoUses + typo fix 2012-10-18 14:03:22 +02:00
558ca593f3 module_formatter: .rst now correctly handles code examples
- fixed template (it was the template), adding indentation with Jinja2
 - added description of code examples to man-page template (was missing)
 - fixed fireball, cron, and debug module examples to confrom
2012-10-18 13:49:19 +02:00
c98b828950 Add support for Github-flavored Markdown to module_formatter
- Uses HTML tables and Github-flavored code blocks (3 backticks)
2012-10-18 07:34:17 +02:00
3934cd7601 Fixed tests to reflect desired configuration behaviour
Test for when environment variable and configuration file
variable both set now tests that the environment variable takes
precedence

Removed logic that would never be triggered from
lib/ansible/constants.py
2012-10-18 12:53:30 +10:00
6aafb42f2f add error message if keyczar is not installed and the user tries to use fireball mode 2012-10-17 22:53:22 -04:00
ee268535f6 Fix port overrides such that with fireball mode you don't have to specify an explicit port. 2012-10-17 22:50:17 -04:00
aaa413db3b Merge branch 'documentation' of git://github.com/lantins/ansible into devel 2012-10-17 22:36:48 -04:00
feb497a9e8 Env var vs config priority fixing 2012-10-17 22:34:59 -04:00
1c77f95312 Add who uses ansible page back. 2012-10-17 22:28:24 -04:00
bde44f9df4 Add examples to user module documentation. 2012-10-18 02:55:58 +01:00
9d9431109b Fix indent of fail module example to prevent unwanted <blockquote></pre></p> <br/></blockquote> from showing up in docsite output. 2012-10-18 02:09:11 +01:00
08a6ac3fc7 Erroneous space in facter documentation. 2012-10-18 01:20:40 +01:00
84cc3e2c8a Copy module can replace symlink with a real file. 2012-10-18 01:04:52 +01:00
bb3e7f4719 Remove "the the" 2012-10-17 19:38:17 -04:00
25162c98ec Only expand lists in templating inside of module action lines, to avoid breaking usage with with_items and "in" statements, etc 2012-10-17 19:35:12 -04:00
d21d3677a6 Various tweaking of the delegate_to loop code. 2012-10-17 19:17:41 -04:00
514f9232a0 Fix ansible_ssh_host after 339c05bb 2012-10-17 19:17:41 -04:00
b0f7296dde Merge pull request #1360 from dhozac/remove-debug-print
Remove debug print statements
2012-10-17 14:05:59 -07:00
db7149da1c Remove debug print statements 2012-10-17 22:45:17 +02:00
5252b7bc93 Merge pull request #1357 from nigelm/nigelm_doc_tweaks
Added comment about long lines in playbooks
2012-10-17 07:50:12 -07:00
31d1afcb19 Added comment about long lines in playbooks
I had trouble finding this information, so though it was worth
adding to docs... but am not sure its easy to find for someone
specifically to find.  At least I think this inclusion matches the
tone of document, but maybe this info should go into a FAQ
instead/as-well?
2012-10-17 15:31:33 +01:00
4abf23d34d Merge pull request #1353 from jpmens/moduledev1
Indicate module_formatter can produce boilerplate DOCUMENTATION
2012-10-17 05:08:10 -07:00
9991dfee6c Indicate module_formatter can produce boilerplate DOCUMENTATION
add ./hacking/
2012-10-17 08:18:39 +02:00
88e4051afc Merge pull request #1351 from cocoy/ec2-v2
Fix check boto version bug #1280. Using try/except for AttributeError.
2012-10-16 20:16:40 -07:00
8344511e47 Fix check boto version bug #1280 2012-10-17 10:47:28 +08:00
c16572b6e2 Allow use of variables in delegate_to 2012-10-16 21:05:09 -04:00
339c05bb88 Allows delegate_to to use inventory host/port info. 2012-10-16 20:57:37 -04:00
ac16efe289 Fix cowsay! Moo. 2012-10-16 20:01:12 -04:00
4448391244 Merge pull request #1349 from bcoca/fix_bsd_dmesg_jails
fixed but in pulling data from dmesg command, wrong function to use as f...
2012-10-16 16:15:36 -07:00
946e9473a9 Searchindex should not be part of source control 2012-10-16 19:14:51 -04:00
63b1be4f37 Rebuild docs 2012-10-16 19:14:21 -04:00
d779f88149 more 0.8 docs 2012-10-16 19:12:31 -04:00
5be35f270c More docs 2012-10-16 19:09:15 -04:00
96f6244336 Further docs hacking 2012-10-16 19:03:54 -04:00
eef726258d more playbook docs 2012-10-16 18:58:31 -04:00
f8fcbc6bd7 more 0.8 documenting 2012-10-16 18:51:10 -04:00
620aeeb572 fixed but in pulling data from dmesg command, wrong function to use as file for for loop
Signed-off-by: Brian Coca <briancoca+ansible@gmail.com>
2012-10-16 18:44:09 -04:00
e9bf75156e Docs + fix variable precedence of environment variables (ok, ok, I give in!) 2012-10-16 18:40:01 -04:00
e5b013ea41 add docs on fireball 2012-10-16 18:30:18 -04:00
e4c935835f Fix help text 2012-10-16 18:17:44 -04:00
c9453daf28 RST typo 2012-10-16 18:17:04 -04:00
b2ea92d36d Merge pull request #1335 from phgrau/devel
Use && for executing next command if, and only if, command1 returns an e...
2012-10-16 15:16:46 -07:00
7583704144 "force=" code under the file module is problematic, remove it 2012-10-16 18:14:42 -04:00
f3407dec0e Merge branch 'basedir-plugins' of git://github.com/dhozac/ansible into devel 2012-10-16 18:00:55 -04:00
4405244224 Docs rebuild 2012-10-16 18:00:47 -04:00
fea5d36417 Merge pull request #1343 from jpmens/eeemail
typo
2012-10-16 05:47:43 -07:00
e35d5188f9 typo 2012-10-16 14:40:35 +02:00
f160502b7b Merge pull request #1337 from skvidal/devel
trivial --syntax-check option to ansible to just do the yaml validation
2012-10-15 16:24:12 -07:00
7da94e0359 Merge pull request #1334 from bcoca/cowsay4bsd
cowsay for BSD!
2012-10-15 16:22:23 -07:00
41195d0d49 trivial --syntax-check option to ansible to just do the yaml validation
check. Lots of room to make this more interesting - but not today
2012-10-15 17:48:25 -04:00
b1563c8411 Add note: Debian Squeeze has no add-apt-repository 2012-10-15 17:20:23 +02:00
eedd92d711 Use && for executing next command if, and only if, command1 returns an exit status of zero. 2012-10-15 16:56:55 +02:00
e98153d26d cowsay for BSD!
Signed-off-by: Brian Coca <briancoca+ansible@gmail.com>
2012-10-15 10:17:21 -04:00
ab44a4abba Load additional plugins from path specified in configuration 2012-10-14 21:09:24 +02:00
1aaf86069a Look for plugins in the playbook's basedir 2012-10-14 21:09:23 +02:00
036f853d42 Merge pull request #1330 from wzzrd/pip
Test for python-pip as well as pip
2012-10-14 06:57:15 -07:00
2f6b9e69a7 Test for python-pip as well as pip
On Red Hat, CentOS and Fedora systems, the pip binary will be called python-pip
instead of pip. This commit makes the pip module also check for python-pip.

The reason we check for python-pip *first*, is to have ansible fail on not
finding 'pip' and reporting *that*. This is consistent with current behaviour
and will not confuse users of Debian et al., where the 'python-pip' binary
never exists.

Tested on Fedora 18 and Ubuntu 12.04.
2012-10-14 12:14:59 +02:00
05ae500d78 Merge pull request #1329 from tbielawa/pausequotes
The pause 'prompt' parameter now requires quotes around the message.
2012-10-13 07:49:04 -07:00
8831e59700 The pause 'prompt' parameter now requires quotes around the message. 2012-10-12 23:48:08 -04:00
8dadf8a905 Use 'path' in file documentation, though src/dest work, it's less intuitive. 2012-10-12 22:08:07 -04:00
7b6f8e485a refine example 2012-10-12 21:39:35 -04:00
2c90298841 Merge pull request #1314 from apenney/bugfix/git
Check rc instead of parsing for errors.
2012-10-12 18:18:04 -07:00
fb686d40bc Merge pull request #1322 from sfromm/moduleformatter
Miscellaneous fixes to module_formatter.py
2012-10-12 17:17:59 -07:00
971dd53622 Added documentation on looping over with_* like fileglob 2012-10-12 20:15:13 -04:00
dd3beb844f add lookup plugins to setup.py 2012-10-12 20:07:45 -04:00
c5d2f6b0d3 implement lookup plugins for arbitrary enumeration over arbitrary things. See the mailing list for some cool examples. 2012-10-12 20:07:05 -04:00
60f06c36b3 Miscellaneous fixes to module_formatter.py
Try to autodetect MODULEDIR, instead of hardcoded path in jpmens
homedir.
Check if MODULEDIR exists; exit if it doesn't.
Rewrite boilerplate() to use DOCUMENTATION.yaml in examples/.  This
makes use of tbielawa's recent change that added this example file.
This also fixes -G so that it works.  boilerplate() was commented out
before.
2012-10-12 16:27:01 -07:00
29d49d415f fix mentioning of redundant aliases in module docs, remove was removed anyway 2012-10-12 18:14:09 -04:00
7644dbe330 Update some examples to explain why notify is not used 2012-10-12 18:12:22 -04:00
621708e976 user module should be using module.BOOLEANS for choices 2012-10-12 18:06:36 -04:00
aa98c84a62 HP and vsphere modules are crazy awesome but I am thinking these belong in contrib not core. 2012-10-12 17:49:48 -04:00
85d6af637a update changelog 2012-10-12 17:38:31 -04:00
70ed560fb3 Add FILES to manpage 2012-10-12 17:37:30 -04:00
6886683e16 small patch to fact gathering for when no dmesg.boot exists on freebsd, mainly happens in jails
Signed-off-by: Brian Coca <briancoca+ansible@gmail.com>
2012-10-12 17:37:30 -04:00
291648ccd9 Fix documentation consistency in .gitignore 2012-10-12 17:37:30 -04:00
579b80ab8f Fix redundancy in .gitignore file 2012-10-12 17:37:30 -04:00
d90210973d Merge pull request #1307 from sfromm/pull2
updates to ansible-pull
2012-10-12 14:34:53 -07:00
271db7bddb Merge pull request #1308 from abondis/named_action
named actions + modules list in utils.py
2012-10-12 14:33:43 -07:00
35163bce96 Merge pull request #1310 from dagwieers/hpilo_boot-cleanup
hpilo_boot: Various clean ups in documentation and code
2012-10-12 14:33:05 -07:00
b1ccda00f8 Merge pull request #1311 from dagwieers/hpilo_facts-cleanup
hpilo_facts: Various clean ups in documentation and code
2012-10-12 14:32:46 -07:00
1487b6a1bb Merge pull request #1313 from dagwieers/vsphere_facts-cleanup
vsphere_facts: Various cleanups in documentation
2012-10-12 14:32:31 -07:00
3a8dc2308b Merge pull request #1315 from dagwieers/mail-callback-improvement
This should set the sender properly.
2012-10-12 14:31:30 -07:00
a82522a5c4 Merge pull request #1317 from abondis/fix_mysql_db
fix issue with mysql authentication and states not dump or import
2012-10-12 14:26:45 -07:00
20a7227056 Merge pull request #1318 from dsummersl/cron24
fixed cron library so backups are python2.4 compatible
2012-10-12 14:25:51 -07:00
6d8d1ad426 Merge pull request #1320 from tbielawa/DOCUMENTATION
Add DOCUMENTATION for module documentation.
2012-10-12 14:25:07 -07:00
90944ec45a Merge pull request #1319 from jhoekx/virt-boot
Add virt_boot module.
2012-10-12 14:23:19 -07:00
4b04d7a914 Add DOCUMENTATION for module documentation. 2012-10-12 17:22:55 -04:00
0028a9d651 Merge pull request #1309 from abondis/tasks_sudo_option
#1303: add sudo option to tasks
2012-10-12 14:21:32 -07:00
25e415c031 Add virt_boot module to define libvirt boot parameters. 2012-10-12 22:40:04 +02:00
7399224428 fixed cron library so backups are python2.4 compatible 2012-10-12 16:34:34 -04:00
1f91a70310 fix issue with mysql authentication and states not dump or import 2012-10-12 16:26:59 -04:00
de34c7c133 This should set the sender properly. 2012-10-12 20:40:06 +02:00
f4484f800b Further cleanup to add another rc check and remove a now redundent one. 2012-10-12 18:26:40 +00:00
6042419624 Check rc instead of parsing for errors. This now catches the case where the remote branch has been deleted and you're still trying to pull against it. 2012-10-12 18:16:37 +00:00
5927373c26 Various clean ups in documentation and code
This commit improves the following items:
 - Remove the 'match' functionality, this can now be achieve by using the `fail` module together with `only_if` after running the `hpilo_facts` module. Since this gives more functionality, e.g. comparing server names, but also serial numbers or uuids with other inventory information, this is prefered. An example is added to show how this is achieved.
 - Clean up all C() calls in documentation
 - Added state=poweroff in order to power off a server. The use-case is here that in general we do not want to provision systems that are already running (this enforcement can be disabled using force=yes) but for test systems we should be able to power them off so we can start the normal provisioning process. (We could also force boot them, but that's less elegant)
 - The module now correctly indicates when something has changed. So if a server is powered off that was not off already, this is indicated, or when media boot-settings have been changed, this is also correctly indicated. Previously every call to hpilo_boot was (incorrectly) considered a change.
2012-10-12 19:49:30 +02:00
5fe8205d36 vsphere_facts: Various cleanups in documentation
This commit improves the following items:
 - Clean up all C() calls in documentation
 - Reindent the documentation
2012-10-12 19:46:20 +02:00
5612cce4a4 hpilo_facts: Various clean ups in documentation and code
This commit improves the following items:
 - Remove the 'match' functionality, this can now be achieve by using the `fail` module together with `only_if` after running the `hpilo_facts` module. Since this gives more functionality, e.g. comparing server names, but also serial numbers or uuids with other inventory information **and** a proper message, this is prefered. An example is added to show how this is achieved.
 - Clean up all C() calls in documentation
 - Remove trailing spaces in HP iLO's Serial Number output so that they can be compared to CMDB or other inventory information
2012-10-12 19:38:59 +02:00
6d183959ba #1303: add sudo option to tasks 2012-10-12 12:39:45 -04:00
2063e10c00 named actions + modules list in utils.py 2012-10-12 11:28:10 -04:00
60d3e9f3de Add --purge option to ansible-pull
Removes git checkout after playbook run.
2012-10-12 07:55:22 -07:00
034e8f59ed Clean up auto-selection of playbook and miscellaneous changes
Direct any ansible-pull specific messages to stderr.
Introduce try_playbook() and select_playbook() to remove try/except-y.
2012-10-12 07:55:22 -07:00
0841ed4796 change method of obtaining hostname to match ansible/library/setup 2012-10-12 07:55:22 -07:00
2b24131baa fetch the git repo before trying to find a playbook 2012-10-12 07:55:22 -07:00
788e11f1db Merge commits from copperlight's branch ansible-pull_playbook_parameter branch
Merged commits: 3cd25b5 and ed9fc76.  Some massaging of changes applied.
2012-10-12 07:55:22 -07:00
dfaef8061a Merge pull request #1289 from abondis/mysql_migration
mysql_db: connection test, dump/import state
2012-10-11 17:39:13 -07:00
a18e9d64c7 Merge pull request #1297 from sergevanginderachter/devel
updated gitignore for docssite stuff
2012-10-11 17:31:39 -07:00
34acc95435 Merge pull request #1296 from sergevanginderachter/da92ce796b48ec80e3ead1cfe9bcbc71f5fce805
fix missing --limit in docssite examples
2012-10-11 17:30:55 -07:00
69ad124bd2 Merge pull request #1298 from dagwieers/doc-optparse
Moving now from getopt to optparse
2012-10-11 17:30:33 -07:00
5849ab3162 Merge pull request #1300 from tbielawa/fix_module_path
Add DIST_MODULE_PATH so setup.py and ansible.spec can live in harmony
2012-10-11 17:30:23 -07:00
89f8562df9 Merge pull request #1304 from dhozac/vars_files-process-whole-list
Keep processing the rest of the vars_files even if one has vars
2012-10-11 14:56:41 -07:00
b8b34b5110 Keep processing the rest of the vars_files even if one has vars 2012-10-11 23:52:01 +02:00
baa91ebc95 Add DIST_MODULE_PATH so setup.py and ansible.spec can live in harmony. Closes #1277 2012-10-11 13:22:30 -04:00
2786149bdc Moving now from getopt to optparse
Let me know if we can move to another library instead ;-)
2012-10-11 18:14:38 +02:00
d5837aab23 Add some docssite and deb package related stuff to gitignore. 2012-10-11 18:13:08 +02:00
f3d7294690 Test for directory existance, fix exception catching granularity 2012-10-11 07:56:01 -04:00
448c89a06d It has been reported that occasionally the md5sum command on certain platforms (?) can fail, where I suspect there is noise in the output stream.
In those events, capture the output so we can report the error more properly.
2012-10-11 07:44:41 -04:00
d6b3f40cb7 Merge pull request #1290 from dagwieers/mail-doc-fix
Damn you, colons...
2012-10-11 04:20:05 -07:00
dfdf4ab8eb Damn you, colons... 2012-10-11 09:26:21 +02:00
1a51af0e38 mysql_db: use the database to test connexion, added dump and import state - requires target=path/to/a/file 2012-10-10 23:28:42 -04:00
6d2f003ceb Update formatter to not include orange blocks all over docsite page 2012-10-10 21:25:19 -04:00
7e542d78a7 Merge remote branch 'stijnopheide/jinja-relative' into devel
Conflicts:
	.gitignore
2012-10-10 20:24:12 -04:00
062484b9bd Put generated manpages back in correct directory 2012-10-10 20:09:40 -04:00
e74b9e1d34 Add .gitdir 2012-10-10 20:00:15 -04:00
b505a3796c Fix docsite example 2012-10-10 19:56:53 -04:00
e2497f0cff Merge remote branch 'abondis/named_actions_2' into devel 2012-10-10 19:53:19 -04:00
79069827c2 add presentation 2012-10-10 19:50:47 -04:00
6b0ef9fd26 Merge remote branch 'dagwieers/contrib-vsphere-boot' into devel
Conflicts:
	contrib/README.md
2012-10-10 19:50:04 -04:00
a873e1a467 Don't check in any module RST files as these are generated too. 2012-10-10 19:48:40 -04:00
e593c828b4 Merge remote branch 'dagwieers/module-mail' into devel 2012-10-10 19:46:38 -04:00
110244d7b4 Merge branch 'remove-argparse' of git://github.com/dagwieers/ansible into devel
Conflicts:
	hacking/module_formatter.py

Don't run webdocs build when building packages
2012-10-10 18:46:51 -04:00
8ae9831439 Don't check in docsite static HTML, so folks will know to just edit the RST. 2012-10-10 18:41:50 -04:00
dbeb26ad6d Don't check in modules.js either 2012-10-10 18:41:50 -04:00
fc9a6bb07c Docs/json should not be checked in 2012-10-10 18:41:50 -04:00
ee679c0190 Unified document generator and make to generate JSON and JS files 2012-10-10 18:41:50 -04:00
85fb83a5db Merge pull request #1282 from dagwieers/mail-callback
Example plugin to send out mails on error
2012-10-10 15:37:59 -07:00
da92ce796b fix missing --limit in docssite examples 2012-10-10 19:38:30 +02:00
ae94b050af Merge pull request #1283 from jhoekx/fix-inventory-api-groups
Fix inventory API groups
2012-10-10 09:51:36 -07:00
23a62f5a78 Return multiple groups from inventory API. 2012-10-10 18:35:45 +02:00
30c019447b Fix typo in inventory API test script. 2012-10-10 18:17:24 +02:00
bb58d3f20c Example plugin to send out mails on error
This is useful mostly for playbooks that run unattended and for a limited set of systems. In case of provisioninging this plugin (together with a final mail action) helps to get notified when something went wrong, or when the installation finished successfully.

Unfortunately, there is no way to enable/disable a plugin from a playbook. So installing the plugin means all other use-cases (provisioning, troubleshooting, reporting or management) all send mails on failure. Something we may want to fix in the future...
2012-10-10 17:28:00 +02:00
7788dea238 Merge pull request #1268 from dagwieers/hpilo-reboot-fix
Workaround for when HP iLO is in a state it won't accept requests
2012-10-10 05:34:22 -07:00
d855b4bcf6 Merge pull request #1270 from jhoekx/yaml-inventory-plugin
Add a yaml format inventory plugin.
2012-10-10 05:33:33 -07:00
8ae9125ff2 Merge pull request #1271 from mavimo/openstack-rackspace-update
Openstack rackspace update
2012-10-10 05:33:17 -07:00
822cb74aed Merge pull request #1274 from dagwieers/contrib-network-facts
Module network_facts to gather facts based on network information
2012-10-10 05:33:00 -07:00
f1dfddc5e5 Fix typo in autogenerated docs 2012-10-10 08:32:41 -04:00
bbf95abc8f Merge pull request #1276 from mxxcon/patch-1
Typo in example section for 'setup' module docs.
2012-10-10 05:31:22 -07:00
d5bb7258c8 Working on makefile 2012-10-10 08:03:52 -04:00
6b5f19a796 Typo in example section for 'setup' module. 2012-10-09 20:41:26 -03:00
0ebc46628a Module vsphere_boot to boot VMWare virtual machine using specific media 2012-10-10 00:29:59 +02:00
e8b0b07311 Module network_facts to gather facts based on network information 2012-10-10 00:20:50 +02:00
cdb8343ec6 Added documentation for nova inventory system 2012-10-09 21:44:39 +02:00
7fed89b51d Improved RackSpace configuration support (needed by latest version of rackspace API) 2012-10-09 21:43:58 +02:00
2290dfe1ef Add a yaml format inventory plugin.
This fixes #1265.
2012-10-09 19:56:52 +02:00
2f74cd84bd Module mail to send out emails as an action
Sending mails could be part of the workflow to have teams/responsibles perform specific task. Or simply to notify that a process has finished successfully (e.g. provisioning).
2012-10-09 19:36:23 +02:00
790ed81b14 Workaround for when HP iLO is in a state it won't accept requests
This workaround is recommended from HP iLO's documentation, but may not be sufficient in all cases. Time will tell.

I also made a few cosmetic changes with no impact.
2012-10-09 19:31:31 +02:00
de912381ac Update CHANGELOG.md 2012-10-09 10:38:48 -03:00
06688efb24 Merge pull request #1263 from dagwieers/hpilo_facts-fix
Sigh, another retypo
2012-10-09 05:22:49 -07:00
49fc8c7634 Merge pull request #1264 from dagwieers/doc-fixes
Fixes to documentation
2012-10-09 05:22:26 -07:00
98624cb394 Fixes to documentation 2012-10-09 12:42:10 +02:00
3f149e09bc Sigh, another retypo problem 2012-10-09 12:30:00 +02:00
2dcd0846ab Use getopt instead of argparse
On RHEL5 and RHEL6 there is not argparse, and 'make rpm' fails because of this.
With this change it works, and I can test and fix my own documentation...
2012-10-09 12:23:30 +02:00
e07bfd9ef8 playbook/tasks: allow to use a module's name instead of action: 2012-10-09 00:21:13 -04:00
4bd17ee518 Fix up changelog 2012-10-08 19:24:20 -04:00
dcee25c6db Update gitignore 2012-10-08 19:21:50 -04:00
3d66ca59f9 Update changelog 2012-10-08 19:20:55 -04:00
04954dbc1e Makes ports configurable for fireball. Note port defaults really belong in the connection plugins, not runner, which can be refactored later. 2012-10-08 19:03:37 -04:00
612561ad0e Merge pull request #1250 from dagwieers/hpilo_boot-fixes
Various small fixes to boolean usage and defaults
2012-10-08 14:27:20 -07:00
62a56a219b Merge pull request #1243 from dsummersl/squash2-cron
cron feature (w/o tests)
2012-10-08 14:25:55 -07:00
013aa2533a Merge pull request #1256 from tbielawa/keep_man3_dir
Keep the man3 directory. 'make docs' breaks without it.
2012-10-08 14:25:35 -07:00
1b36446ab3 Merge pull request #1255 from dagwieers/module-namespace
Add this module's namespace to the 'module_' namespace.
2012-10-08 14:25:20 -07:00
5a16a270fc Merge pull request #1257 from tbielawa/service_typo
Fix typo in service module docs
2012-10-08 14:21:41 -07:00
136a7d5604 Merge pull request #1260 from jhoekx/inventory-in-hostvars
Add inventory variables for hosts not in the play to hostvars.
2012-10-08 14:19:33 -07:00
46a4ae74a7 Add inventory variables to hostvars.
Look up only when requested and cache the result.
2012-10-08 20:26:58 +02:00
1e35ac7603 Fix typo in service module docs 2012-10-08 12:46:16 -04:00
9541b47b52 Keep the man3 directory. 'make docs' breaks without it. 2012-10-08 12:28:20 -04:00
c3a6e8dfd6 added new documentation string to cron library 2012-10-08 11:10:40 -04:00
b39aed8736 Add this module's namespace to the 'module_' namespace.
Much like we currently have *setup* register the variable `module_setup`, we would like other facts-modules register their own namespace. This means that:

 - *network_facts* registers `module_network`
 - *hpilo_facts* registers `module_hw`
 - *vsphere_facts* registers `module_hw`

In retrospect, it would have made more sense to have `setup` register `module_ansible` instead as the setup module uses the `ansible_` namesepace.

Having the `module_` namespace allows us to check whether a certain namespace has already been loaded so we can avoid running the facts module a second time using only_if.

```yaml
 - action: network_facts host=${ansible_hostname_short}
   only_if: is_unset('$module_network')
```
2012-10-08 15:13:17 +02:00
5503cfaa44 Various small fixes to boolean usage, using module.params.get and default values 2012-10-08 15:07:02 +02:00
f32778aa93 Update links to contrib 2012-10-08 08:23:11 -04:00
5c09fd4210 update links to plugins 2012-10-08 08:22:05 -04:00
343e07a31a chapter 3 manpage source does not belong in git because it includes datestamps that constantly change. Willing to re-add if datestamps
are removable.
2012-10-08 08:10:37 -04:00
4a95194424 Docs rebuild in new project structure. 2012-10-08 08:09:27 -04:00
dd727ecebf Update README 2012-10-08 08:06:48 -04:00
56e8863683 Update README 2012-10-08 08:04:21 -04:00
2319c4d74f Redundant CONTRIBUTING file 2012-10-08 08:03:59 -04:00
35fdc5411f update CONTRIBUTING 2012-10-08 08:03:44 -04:00
87d9eeae57 Remove unused graphics 2012-10-08 07:49:00 -04:00
2eac8c6c29 Merge ansible-resources tree 2012-10-08 07:48:07 -04:00
41dd4a1f93 Merge plugins tree 2012-10-08 07:45:25 -04:00
d6e4b1bf5b Subtree merge of ansible-docs 2012-10-08 07:44:38 -04:00
bb0b2305e3 rebuild 2012-10-08 07:39:06 -04:00
f010bcde33 Docs should indicate with_items and yum/apt logic is available 2012-10-08 07:38:21 -04:00
4a6b5c5de2 relative paths for (include/extends) in jinja2 templates 2012-10-08 08:56:57 +02:00
c8854a23ea Merge pull request #1251 from dagwieers/hpilo_facts-fixes
Fix typo/cosmetic change
2012-10-07 16:58:05 -07:00
63b0e5e752 Merge pull request #1252 from dagwieers/vsphere_facts-fixes
Vsphere facts fixes
2012-10-07 16:57:19 -07:00
250f52bfba Add an alias 'name=' for guest
This is the opposite as library/virt, but much better than using name= as the default option name.
2012-10-07 22:23:22 +02:00
8c5a146013 Fix typo/cosmetic change 2012-10-07 22:12:00 +02:00
c5d7ef3d7f Merge pull request #1249 from dagwieers/module-hpilo_boot
Module hpilo_boot to boot from specific media using an HP iLO interface
2012-10-07 06:12:42 -07:00
26bbac3062 Merge pull request #1246 from jpmens/nocows
Not for cow lovers: optionally disable cowsay
2012-10-07 06:11:29 -07:00
051f66cf16 Not for cow lovers: optionally disable cowsay
spaces now cow-compatible
2012-10-07 11:23:42 +02:00
b58228a73b Module hpilo_boot to boot from specific media using an HP iLO interface
This module allows to boot a system through HP iLO and can be used to start the provisioning process.
2012-10-06 23:56:50 +02:00
323cbdafb7 Merge pull request #1240 from jpmens/hpdoc
fix examples in hpilo_facts DOCUMENTATION
2012-10-06 13:39:31 -07:00
d74a61d362 Merge pull request #1248 from mmikulicic/force-color
Added a ANSIBLE_FORCE_COLOR env var, which forces the color output
2012-10-06 13:37:44 -07:00
cc82e7dd06 Added a ANSIBLE_FORCE_COLOR env var, which forces the color output no matter what ncurses says. 2012-10-06 20:36:07 +02:00
3d65d6159f cron feature (w/o tests) 2012-10-05 21:35:37 -04:00
a1c23af6fc Merge pull request #1239 from jpmens/shelldoc
fix wording of shell documentation
2012-10-05 06:11:31 -07:00
91dc8bc136 fix examples in hpilo_facts DOCUMENTATION 2012-10-05 15:07:45 +02:00
70907f574e fix wording of shell documentation 2012-10-05 14:59:49 +02:00
0679537495 Merge pull request #1235 from jpmens/man3
man pages have wrong chapter number
2012-10-05 05:10:08 -07:00
1737d6b884 Merge pull request #1236 from jpmens/manansible1
remove duplicate private-key option from manpage
2012-10-05 05:09:57 -07:00
9f1690ab64 Merge pull request #1237 from dagwieers/lineinfile-alias
Use the standard 'dest' option for target files, make 'name' an alias
2012-10-05 05:09:36 -07:00
70b063ce0e Use the standard 'dest' option for target files, make 'name' an alias 2012-10-05 11:03:14 +02:00
a9dad7f3bd remove duplicate private-key option from manpage 2012-10-05 09:18:19 +02:00
ba22ca13ba man pages have wrong chapter number 2012-10-05 09:09:49 +02:00
f470ebe6b7 Merge pull request #1213 from dagwieers/debug-module
Module debug to assist users in understanding Ansible
2012-10-04 16:28:25 -07:00
0592e1be79 Merge pull request #1222 from alopropoz/devel
Indicate errors with exit code.
2012-10-04 16:26:00 -07:00
ebc2fe08c3 Merge pull request #1218 from jpmens/jtempl3
Allow user-specified $ansible_managed string
2012-10-04 16:18:57 -07:00
a95bff0f5f Merge pull request #1230 from dagwieers/module-vsphere_facts
Module vsphere_facts to add facts from a VMWare vSphere guest
2012-10-04 16:18:39 -07:00
5d7ab8a300 Merge pull request #1231 from dagwieers/fail-doc-fix
This hopefully fixes the documentation for the fail module
2012-10-04 16:18:10 -07:00
adfc4d6f59 Merge pull request #1232 from dagwieers/module-hpilo_facts
Module hpilo_facts to add facts from HP iLO interfaces
2012-10-04 16:17:40 -07:00
8c8552ac32 Module vsphere_facts to add facts from a VMWare vSphere guest
This module gathers facts from a VMWare vSphere guest by querying vSphere. The facts include OS, network info (vlan, macaddress) and system info (cpu, memory, uuid) information. Useful information for provisioning and management.
2012-10-04 21:55:16 +02:00
e07674d756 Module hpilo_facts to add facts from HP iLO interfaces
This module gathers facts from the hardware interface by querying HP iLO. The facts include network info (vlan, macaddress) and system info (cpu, memory, uuid) information. Useful information for provisioning and management.

This module was previously named ilo_facts and mentioned in #1080, #1085, #1125 and #1217.
2012-10-04 21:50:34 +02:00
3d5c4df2ac This hopefully fixes the documentation for the fail module 2012-10-04 20:58:07 +02:00
184523ecac Merge pull request #1220 from tbielawa/pause_variables
Fix variable injection in pause module args. Closes #1209
2012-10-04 05:14:41 -07:00
c3f443f56c fix sorting 2012-10-04 07:08:13 -04:00
8f5beb74c5 Fix sort order issue 2012-10-04 07:08:01 -04:00
05464816c2 Different return codes for different errors. 2012-10-04 17:43:25 +07:00
03af450bdc Module to assist users in understanding Ansible
After helping someone on IRC he was interested to have this debug module in upstream. This module simply 'prints' a message, and can be ordered to fail if needed. It helps to troubleshoot or understand inventory/facts issues and/or experiment with statements and conditions using only_if.

Here is a small example playbook:

```yaml
- hosts: all
  tasks:
  - local_action: debug msg="System $inventory_hostname has uuid ${ansible_product_uuid}"
  - local_action: debug msg="System $inventory_hostname lacks a gateway" fail=yes
    only_if: "is_unset('$ansible_default_ipv4.gateway')"
  - local_action: debug msg="System $inventory_hostname has gateway ${ansible_default_ipv4.gateway}"
    only_if: "is_set('$ansible_default_ipv4.gateway')"
```

outputting:
```
[root@moria ansible]# ansible-playbook -v -l localhost:x220 test6.yml

PLAY [all] *********************

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

TASK: [debug msg="System $inventory_hostname has uuid $ansible_product_uuid"] *********************
ok: [localhost] => {"msg": "System localhost has uuid d125a48c-364f-4e65-b225-fed42ed61fac"}
ok: [x220] => {"msg": "System x220 has uuid d125a48c-364f-4e65-b225-fed42ed61fac"}

TASK: [debug msg="System $inventory_hostname lacks a gateway" fail=yes] *********************
failed: [localhost] => {"failed": true, "msg": "System localhost lacks a gateway", "rc": 1}
ok: [x220] => {"msg": "System x220 has gateway 192.168.1.1"}

PLAY RECAP *********************
localhost                      : ok=2    changed=0    unreachable=0    failed=1
x220                           : ok=3    changed=0    unreachable=0    failed=0

```

I had some other plans for the module, like displaying host inventory and complete inventory to help understand inventory and facts modules, but that would require an action-plugin for transfering inventory information etc... And I am not sure this is wanted/best done in a module.
2012-10-04 09:50:18 +02:00
9ed59da294 Allow user-specified $ansible_managed string with named parameters 2012-10-04 08:50:51 +02:00
9f6da7b885 Fix variable injection in pause module args. Closes #1209 2012-10-03 23:52:26 -04:00
761330b125 Fix module formatter indexing 2012-10-03 23:31:50 -04:00
94546831b4 Typo fix/rebuild 2012-10-03 23:31:19 -04:00
348b49c166 Fix typo 2012-10-03 23:27:43 -04:00
88433eb93f Fix typo / rebuild 2012-10-03 21:00:27 -04:00
826c71fcb1 Fix patterns typo, rebuild 2012-10-03 21:00:26 -04:00
e170d7304b Added documentation on file force parameter 2012-10-03 20:57:36 -04:00
a6f64a8e04 Merge pull request #1219 from tbielawa/move_modulepages
Library functions and modules should be in the 3 man page section. Also ...
2012-10-03 17:49:03 -07:00
01e922aa69 Indicate errors with exit code. 2012-10-04 03:11:14 +07:00
85fb7c6d4b Library functions and modules should be in the 3 man page section. Also the files should end in '.3' 2012-10-03 10:18:55 -04:00
8fa2070074 Merge pull request #8 from jpmens/rstlist
Makefile uses module_formatter now creates list of modules to include in .rst
2012-10-03 05:38:30 -07:00
53d24ef002 Check in generated manpage documentation from modules 2012-10-02 22:46:49 -04:00
046c6c66f2 various small doc tweaks 2012-10-02 22:43:46 -04:00
ad5433b166 include version added info for individual fields 2012-10-02 22:36:27 -04:00
f67aa85c3f Fixing various module related things. 2012-10-02 22:32:17 -04:00
85a31616de Call os.path.expanduser in the creates= and removes= section of the command module so ~/ and the like works. 2012-10-02 22:12:49 -04:00
b3548703f7 Merge pull request #1203 from dagwieers/fail-module
A fail module in order to fail execution on certain conditions
2012-10-02 19:07:38 -07:00
d14741799a Merge pull request #1204 from dagwieers/fatal-red
Make fatal errors red
2012-10-02 19:06:36 -07:00
459d9ea30d Merge pull request #1205 from dagwieers/ignore-cyan
Make ignored/skipped different from changed
2012-10-02 19:06:14 -07:00
212296e59c Merge pull request #1207 from dagwieers/gather_facts-fix
Fix gather_facts assumption that SETUP_CACHE for a host is empty
2012-10-02 19:05:54 -07:00
cef73d1545 Merge pull request #1202 from dagwieers/abort-play-abort-playbook
Abort a play at the start when no hosts matches, or no hosts are remaining
2012-10-02 19:02:27 -07:00
fedfd18774 Fix gather_facts assumption that SETUP_CACHE for a host is empty
We now check explicitely for 'module_setup' in the SETUP_CACHE in order to avoid skipping setup because SETUP_CACHE was populated some other way. Other modules can implement the same mechanism to test if they've already run.

This closes #1206.
2012-10-02 23:17:45 +02:00
f11ab4383a Make ignored/skipped different from changed
Since a skipped/ignored action is _very_ different from actual changes to a system, it always bothered me that  it was not easily distinguishable when skimming the output. This change makes ignore/skip a different color, and I chose cyan. Contemplated using dark-gray/blue, but prefered something that is readable with most terminal colors.
2012-10-02 21:49:04 +02:00
7acc0a632b Make fatal errors red 2012-10-02 21:45:42 +02:00
1d27909ec0 Added a fail module in order to fail execution on certain conditions
In some cases you may want to deliberately fail the execution of a playbook. In our provisioning workflow we want to have safeguards in place to avoid provisioning systems that are already in production. Since we reboot physical and virtual systems, it is mandatory we take all the precautions to prevent accidental provisioning.

So in our use-case we have the following at the very start of the provisioning playbook:

    ### Safeguard to protect production systems
    - local_action: fail msg="System is not ready to be staged according to CMDB"
      only_if: "'$cmdb_status' != 'to-be-staged'"

and we repeat the same task in the (separate included) play that takes care of (re)booting the system using our own boot-media, so that it cannot be accidentally separately run by someone.
2012-10-02 21:40:28 +02:00
20c1a67711 Abort a play at the start when no hosts matches, or no hosts are remaining
This change makes a distinction between no_hosts_matched and no_hosts_remaining.

In both cases we do not start facts-gathering, or run any tasks.

In the case that there are no more hosts remaining, we abort running tasks and abort the playbook.

I also cleaned up the leftovers from the previous patchsets, as these are no longer required.

This closes #1187.

Example playbook:

```yaml
---
- hosts: emptygroup
  tasks:
  - action: command date
  - action: command false

- hosts: all
  gather_facts: False
  tasks:
  - action: command ls
  - action: command false
  - action: command true

- hosts: all
  tasks:
  - action: command true
  - action: command false

- hosts: all
  tasks:
  - action: command pwd
```
2012-10-02 15:54:24 +02:00
e1b1702616 Merge pull request #1201 from dhozac/setup-once-per-node
Only gather facts once per node per playbook run
2012-10-02 06:36:31 -07:00
564a212b3c Only gather facts once per node per playbook run
Unless gather_facts: True is on the play
2012-10-02 15:30:19 +02:00
56d45074af Merge pull request #1200 from broferek/master
Fix for issue #1194
2012-10-02 06:27:03 -07:00
17423c9268 Fix issue https://github.com/ansible/ansible/issues/1194 2012-10-02 15:12:33 +02:00
9bab05bafc Merge pull request #1197 from dagwieers/utc-date
Make use of UTC dates for RPM timestamp
2012-10-02 05:32:10 -07:00
765061d445 Make use of UTC dates for RPM timestamp
So they can be shared/compared by people in different timezones
2012-10-02 14:29:57 +02:00
4677699500 Merge pull request #1195 from jpmens/jtempl
Feature: file info on templates accessible to Jinja2 templates
2012-10-02 05:18:27 -07:00
6616fba1ab Merge pull request #1189 from jpmens/nagpause
standardize DOCUMENTATION for nagios, pause
2012-10-02 05:15:56 -07:00
5f04ef8b4c Feature: file info on templates accessible to Jinja2 templates
add ansible_managed
2012-10-02 14:15:27 +02:00
7779da264d Merge pull request #1190 from jpmens/asy1
attempt at DOCUMENTATION for async_status
2012-10-02 05:15:21 -07:00
a1f192976f attempt at DOCUMENTATION for async_status 2012-10-02 09:56:55 +02:00
83029755f7 standardize DOCUMENTATION for nagios, pause 2012-10-02 09:15:11 +02:00
f897f19fc5 Teach fireball mode to disable the fireball by paying attention to 'minutes=N' (default 30) and do not let fireball module crash
on input.
2012-10-01 22:41:00 -04:00
14f7c85ce7 Include a space and a colon after prompts, so you don't have to put them in yourself. Consistent with documented behavior in examples/playbooks/prompts.yml 2012-10-01 22:15:34 -04:00
b90eccc4f8 Merge pull request #1186 from dhozac/varreplacewi-nonstr
Allow non-string types in with_items variables
2012-10-01 19:10:05 -07:00
2165351f2c Merge pull request #1185 from tbielawa/pause_docs
Add DOCUMENTATION to pause task
2012-10-01 19:09:24 -07:00
b2ad63a860 Merge pull request #1183 from tbielawa/nagios_docs
Add DOCUMENTATION to nagios module.
2012-10-01 19:08:58 -07:00
5683277e4a Be smarter about when to abort a playbook -- if it's early, we just didn't match any hosts, so keep on, hosts might be dynamic. 2012-10-01 22:07:08 -04:00
ca87fa56d8 Add DOCUMENTATION to pause task 2012-10-01 12:42:03 -04:00
f3d9f8da7b Add DOCUMENTATION to nagios module. 2012-10-01 12:26:57 -04:00
35de8da108 Merge pull request #1180 from dhozac/remove-debug-print
Remove debug print statement
2012-10-01 08:24:21 -07:00
48c5d696d2 Remove debug print statement 2012-10-01 17:23:21 +02:00
f785f1ea15 Merge pull request #1179 from dhozac/fix-per-task-mv
Give each task its own module_vars
2012-10-01 08:19:43 -07:00
a83aa1071b Give each task its own module_vars
Otherwise each task will overwrite the previous' items, among
other things.
2012-10-01 17:17:39 +02:00
695b4bcb46 Allow non-string types in with_items variables 2012-10-01 17:07:51 +02:00
886a17853f Merge pull request #1176 from jpmens/fireball-doc1
fireball DOCUMENTATION
2012-10-01 05:46:02 -07:00
f2dc815e3f fireball DOCUMENTATION
- amended
2012-10-01 14:39:15 +02:00
6600f7b7ac Merge pull request #1170 from jpmens/docspatch01
Jumbo DOCUMENTATION patch
2012-10-01 05:19:16 -07:00
ac3ec0a410 Merge pull request #1173 from dhozac/command-quote-less
Use a regexp to filter out arguments instead
2012-10-01 05:17:29 -07:00
b86dc96d55 Merge pull request #1174 from jpmens/docs-authors
Added missing attribution to all module DOCUMENTATION strings
2012-10-01 05:14:44 -07:00
a72a6e42c5 Added attribution to all module DOCUMENTATION strings 2012-10-01 12:37:51 +02:00
6477bdc6fc Use a regexp to filter out arguments instead
pipes.quote is a bit overzealous for what we want to do, quoting ;
and other characters that you most likely want to use in your shell
invocations. The regexp is the best I could come up with to be able
to only replace the parts of the arguments that shouldn't be
executed.
2012-10-01 12:13:17 +02:00
e620fed755 Jumbo DOCUMENTATION patch 2012-10-01 09:18:54 +02:00
880328c10f organize changelog 2012-09-30 21:33:38 -04:00
31a4fe412f Complain when modules do not have documentation. 2012-09-30 21:10:07 -04:00
a2f76c1c69 If all hosts in a play fail, fail the whole playbook and don't bother printing out every remaining task. 2012-09-30 21:06:00 -04:00
22f3aef4dc remove test for private function that is no longer present 2012-09-30 20:49:16 -04:00
19b78cedc8 Abort a play when there are no more hosts in it. 2012-09-30 20:48:35 -04:00
5846c1b8c4 Merge pull request #1125 from dagwieers/setup-retain
Make sure we retain facts between playbooks
2012-09-30 17:18:40 -07:00
d0eba79760 Template out sudo_user so you can pass in variables using --extra-vars 2012-09-30 20:11:51 -04:00
8e9344eef7 add an error when user tries to async something that can't be asynced 2012-09-30 20:06:55 -04:00
d9bc01f443 Merge pull request #1169 from jpmens/modformatter01
module_formatter can output lists of files to process (.rst and .tex)
2012-09-30 12:59:18 -07:00
635689b3af Merge pull request #1168 from sfromm/issue1007
Add message reporting skipped action in cli callback
2012-09-30 12:56:28 -07:00
eb8a11237c module_formatter can output lists of files to process (.rst and .tex) 2012-09-30 19:07:40 +02:00
7ef70c263f module_formatter now creates list of modules to include 2012-09-30 19:02:58 +02:00
cf3e368d15 Add message reporting skipped action in cli callback 2012-09-30 08:54:20 -07:00
190e4c26d1 Merge pull request #1167 from jpmens/slurp01
module docs for slurp
2012-09-30 08:15:19 -07:00
f67c070c0a Merge pull request #7 from jpmens/slurp
Added missing slurp and fireball to modules list
2012-09-30 08:14:52 -07:00
2275b2f950 Added missing slurp and fireball to modules list
- This list should probably be generated by module_formatter ...
- modules.rst includes _list.rst for list of modules
- module-formatter will generate that list
2012-09-30 17:11:58 +02:00
8b737c959d module docs for slurp 2012-09-30 16:58:15 +02:00
a00d6d7234 Merge pull request #1166 from mavimo/documentation-seboolean
Added DOCUMENTATION to seboolean module.
2012-09-30 06:44:02 -07:00
f9bdf07387 Added DOCUMENTATION to seboolean module. 2012-09-30 15:41:00 +02:00
f8060d109e Merge pull request #1165 from mavimo/documentation-selinux
Added DOCUMENTATION to selinux module.
2012-09-30 06:36:27 -07:00
349af83c91 Merge pull request #1164 from jpmens/modformatter
module_formatter now also uses Jinja2 trim_blocks
2012-09-30 06:36:09 -07:00
1290aa2668 Merge pull request #1163 from jpmens/fireball-doc
template DOCUMENTATION added to fireball
2012-09-30 06:35:57 -07:00
7491054ed6 Added DOCUMENTATION to selinux module. 2012-09-30 15:34:26 +02:00
e4338d0ca3 module_formatter now also uses Jinja2 trim_blocks
- Updated man template accordingly
- seem to have left in illegal char in facter DOCUMENTATION...
2012-09-30 15:06:18 +02:00
8a4df98f69 template DOCUMENTATION added to fireball 2012-09-30 14:50:32 +02:00
f13e20655e Merge pull request #1161 from jpmens/rst03
rst output template tweak for 'required'
2012-09-30 05:34:31 -07:00
f5e0fbf65b rst output template tweak for 'required' 2012-09-30 14:21:30 +02:00
e756ee3741 Merge pull request #1159 from dhozac/include-with_items
Allow task includes to work with with_items
2012-09-30 05:13:32 -07:00
5aab75e71a Merge pull request #1160 from jpmens/virt01
Attribute author of virt correctly (sorry)
2012-09-30 05:10:54 -07:00
28698d5fcf Attribute author of virt correctly (sorry) 2012-09-30 14:08:47 +02:00
b96da3e5b0 Merge pull request #1158 from jpmens/man01
documentation: man template: support empty options; add Version
2012-09-30 05:00:39 -07:00
705f19d0e2 Merge pull request #1157 from jpmens/rst01
module docs: fixed rst template
2012-09-30 05:00:07 -07:00
b8a2a526fc Merge pull request #1156 from jpmens/m-docs5
DOCUMENTATION for virt
2012-09-30 04:59:24 -07:00
39c4a4f8a7 Merge pull request #1155 from jpmens/m-docs4
DOCUMENTATION for fetch,mount,ohai,easy_install; .rst template tweaks
2012-09-30 04:57:50 -07:00
3582c20abb Merge pull request #1154 from dhozac/varreplace-list-join
Replace lists with a comma-separated join
2012-09-30 04:57:11 -07:00
bf6e783d7a Merge pull request #1152 from sfromm/moduledocs
Add module documentation for git, group, service, and user
2012-09-30 04:56:37 -07:00
8ca106d266 Merge pull request #1153 from SleeplessAnnoyedNerd/gitignore
Ignoring PyCharm/IntelliJ and Mac OS X stuff (2nd try)
2012-09-30 04:56:07 -07:00
1af4677b66 Merge pull request #1151 from sfromm/lsb
Add LSB facts, as derived from lsb_release -a
2012-09-30 04:52:45 -07:00
8a8ffa2342 Allow task includes to work with with_items 2012-09-30 13:40:52 +02:00
61ee632d23 documentation: man template: support empty options; add Version to Makefile 2012-09-30 13:33:21 +02:00
80a9016636 module docs: fixed rst template
- notes is now supported
- multiline code examples are now supported (HTML rendering was off)
2012-09-30 13:20:24 +02:00
7a3b2ac287 DOCUMENTATION for virt 2012-09-30 12:40:11 +02:00
754888d896 DOCUMENTATION for fetch,mount,ohai,easy_install
- .rst now supresses default if none is set (looks better in HTML)
  - .rst now handles empty options list
  - Fixed postgresql_user and mysql_user because YAML contained colons
  - docs for facter
2012-09-30 12:29:32 +02:00
dfee6e19ca Replace lists with a comma-separated join 2012-09-30 11:41:44 +02:00
ddb358a3cf Ignoring PyCharm/IntelliJ and Mac OS X stuff 2012-09-30 11:08:41 +02:00
ed07940386 Add LSB facts, as derived from lsb_release -a
This gathers LSB facts via lsb_release.  This complements the
platform facts collected via the platform module.  This reoprts
release, id, description, release, and codename.  It also adds
'major_release', which is the major version number of a distribution.
2012-09-29 23:58:04 -07:00
be19e21126 Add module documentation for git, group, service, and user 2012-09-29 23:50:25 -07:00
13e8ef5f35 Merge pull request #1146 from dhozac/command-escape-args
Properly parse escaped special arguments
2012-09-29 16:25:37 -07:00
7d86663dd2 Merge pull request #1150 from dhozac/varreplacefile-typo
Fix typo in $FILE()
2012-09-29 16:25:17 -07:00
62db667760 Fix typo in $FILE() 2012-09-30 01:19:22 +02:00
2d7691500e Merge pull request #1139 from lorin/config-precedence
ANSIBLE_CONFIG take precedence over ./ansible.cfg
2012-09-29 13:27:07 -07:00
e744e864d9 Merge pull request #1140 from mavimo/devel
Refs #1116: DOCUMENTATION string update
2012-09-29 13:26:42 -07:00
1fd5de21d2 Merge pull request #1149 from dhozac/non-greedy-filepipe
Complete the change from $FILE{} to $FILE()
2012-09-29 13:25:32 -07:00
8b55217df0 Merge pull request #1148 from dhozac/multiline-only_if
Allow multiline strings to work okay in only_if
2012-09-29 13:25:07 -07:00
e442175a9e Merge pull request #1147 from dhozac/filepipe-exception
Raise AnsibleError if $FILE() or $PIPE() fail
2012-09-29 13:24:48 -07:00
78911f1b26 Merge pull request #1145 from mavimo/documentation-supervisorctl
Added DOCUMENTATION to supervisorctl module.
2012-09-29 13:23:54 -07:00
4823371aff Merge pull request #1144 from mavimo/documentation-pip
Added DOCUMENTATION to pip module.
2012-09-29 13:23:41 -07:00
5599287927 Merge pull request #1143 from mavimo/documentation-shell
Added DOCUMENTATION to shell module.
2012-09-29 13:23:22 -07:00
2d81a1fa77 Complete the change from $FILE{} to $FILE()
Otherwise, parsing e.g. '$FILE(myfile)'.find("stuff") will include
everything up to the last ) as the filename.
2012-09-29 21:16:13 +02:00
be9d7df6c4 Allow multiline strings to work okay in only_if
Fixes issue #1137
2012-09-29 21:13:19 +02:00
e655e2f051 Raise AnsibleError if $FILE() or $PIPE() fail 2012-09-29 21:09:57 +02:00
9261d3962b Properly parse escaped special arguments
Fixes issue #1134
2012-09-29 21:05:49 +02:00
d80ec35183 Fixed error in author name 2012-09-29 21:04:17 +02:00
95d7b4c5db Added DOCUMENTATION to supervisorctl module. 2012-09-29 21:02:07 +02:00
ac5afcae28 Added DOCUMENTATION to pip module. 2012-09-29 20:53:28 +02:00
b1d88235f0 Added DOCUMENTATION to shell module. 2012-09-29 20:40:06 +02:00
e1c83b0367 Fixed error on official docs (reported on DOCUMENTATION string). Name param must be pkg and is required. 2012-09-29 18:23:13 +02:00
e30e9a74c2 Added DOCUMENTATION to postgresql_user module. 2012-09-29 16:46:30 +02:00
a4620920b2 Added DOCUMENTATION to postgresql_db module. 2012-09-29 16:46:13 +02:00
aa5ef9561d ANSIBLE_CONFIG take precedence over ./ansible.cfg 2012-09-29 10:44:14 -04:00
6184a0a313 Fixed doc string 2012-09-29 16:43:21 +02:00
0d0bc5e620 Added DOCUMENTATION to subversion module. 2012-09-29 16:28:55 +02:00
29ffed869c Added ping module author in docs. 2012-09-29 16:23:58 +02:00
2aaaf986d3 Added DOCUMENTATION to ping module. 2012-09-29 16:21:00 +02:00
a75348b406 Added DOCUMENTATION to musql_db module. 2012-09-29 16:15:52 +02:00
8898643c1d Added DOCUMENTATION to musql_user module. 2012-09-29 16:15:41 +02:00
9377c3f525 Merge pull request #1130 from commandtab/templates-trim-blocks
Setting trim_blocks to True
2012-09-29 05:25:56 -07:00
5a9ca1e513 Merge pull request #1135 from jpmens/mod-formatter3
Removed embedded colon in DOCUMENTATION of apt_repository
2012-09-29 05:15:42 -07:00
57c9534abb Simplify register example 2012-09-29 08:10:45 -04:00
0604d580d9 Removed embedded colon in DOCUMENTATION of apt_repository: building manpages failed 2012-09-29 12:53:17 +02:00
e108d1758c Merge pull request #1132 from jpmens/m-doc-inifile
removed EXAMPLES from ini_file
2012-09-28 17:59:30 -07:00
bc01f0d6fb Merge pull request #1133 from jpmens/doc-apt-fix
module DOCUMENTATION for apt, apt_respository cleanup
2012-09-28 17:59:10 -07:00
1193810d46 module DOCUMANTATION for apt, apt_respository cleanup 2012-09-29 01:51:55 +02:00
0649e637d3 removed EXAMPLES from ini_file
testing YAML in YAML: small glitch in rst template; a </pre></p> is outdented and causes messy display
2012-09-29 01:26:40 +02:00
ce5dceab0e Merge pull request #1128 from mavimo/devel
Added documentation to APT module
2012-09-28 16:12:58 -07:00
08a77135f3 Merge pull request #1126 from dagwieers/choices-fix
Fix to make sure only strings are being joined
2012-09-28 16:12:17 -07:00
508e6ecf43 Merge pull request #1131 from jpmens/m-docs3
Module DOCUMENTATION for template, wait_for, and yum
2012-09-28 16:11:33 -07:00
25a460fe0f Merge pull request #1127 from jpmens/m-docs1
Module DOCUMENTATION: assemble, authorized_key, command, copy
2012-09-28 16:11:03 -07:00
5e9793d742 Merge pull request #1123 from ralphbean/fireball-cleaning
Close zeromq context and socket.
2012-09-28 16:07:59 -07:00
a040807fd0 Module DOCUMENTATION for template, wait_for, and yum 2012-09-29 00:49:02 +02:00
7c600ae0d3 Setting trim_blocks to True 2012-09-28 14:58:05 -07:00
7b8bd280e8 Added documentation to APT_REPOSITORY module 2012-09-28 23:07:41 +02:00
94de4db928 Add JSON output format to DOCUMENTS and EXAMPLES parser 2012-09-28 22:38:27 +02:00
c976238a81 Added documentation to APT module 2012-09-28 22:35:29 +02:00
e0fb264a89 Module DOCUMENTATION: assemble, authorized_key, command, copy
plus a small fix in rst.j2 template
  manpages generated & checked
  modules.html generated & checked
2012-09-28 21:55:49 +02:00
27b2ae8ddc Fix to make sure only strings are being joined
Since BOOLEANS also contains integers, joining the list returns an error. Easy to test by giving a wrong value to a boolean argument:

    service name=httpd enabled=True

Since True is not in the allowed BOOLEANS, it will cause the error, which in its turn bails out because it joins strings and integers.
We may want to remove the integers from the choices since '0' and '1' are already in the list as strings. Personally I would expect only strings as arguments, not sure where these could be integers ??
2012-09-28 17:51:59 +02:00
c84e76e31d Make sure we retain facts between playbooks
This is mandatory if we want to make facts-modules (like network_facts, ilo_facts and esx_facts) work.
2012-09-28 17:44:51 +02:00
d25ee940c4 Close zeromq context and socket. 2012-09-28 08:22:53 -04:00
cc7b34e9bd Change syntax to module formatter script 2012-09-28 08:21:33 -04:00
6bbaa26f64 Merge pull request #1119 from jpmens/mod-formatter2
module_formatter fixes
2012-09-28 05:07:19 -07:00
8c370645a6 Merge pull request #1122 from dhozac/varreplace-no-repr
Revert pull request #1091
2012-09-28 05:06:05 -07:00
4b29c2cf74 Revert pull request #1091
Automatic quoting of variables in only_if breaks existing playbooks
where entire statements are put in a variable, and other cases. See
issue #1120 for details.
2012-09-28 13:58:23 +02:00
62d038dca4 module_formatter fixes 2012-09-28 09:59:43 +02:00
06cfc52afd fix tests and change nosetests flags so asserts show what comparisons failed 2012-09-27 22:12:15 -04:00
618a519ee3 Merge branch 'varreplace-lessre' of git://github.com/dhozac/ansible into devel 2012-09-27 22:08:38 -04:00
6b5088c676 update changelog 2012-09-27 21:48:38 -04:00
88f1294f74 Add ini file RST 2012-09-27 21:43:37 -04:00
0c855a85bc fix module formatter output messages 2012-09-27 21:34:28 -04:00
dff7b0fdbc Tweaking module docs as a result of integrating the new module docs generator 2012-09-27 21:33:55 -04:00
405c097c43 Various fixes for the module documentation auto-generator 2012-09-27 21:30:32 -04:00
83f277cfe6 Various tweaking to get the module formatter to work for 'make docs' in the docs project. Likely the templates for other module formatting types will have to change
by the time I'm done.
2012-09-27 21:06:31 -04:00
9a7a2a4d60 Merge branch 'mod-formatter1' of git://github.com/jpmens/ansible into devel 2012-09-27 19:50:00 -04:00
d68f22a28d Merge pull request #1115 from dagwieers/only_if-revert
Revert only_if for variables and templating prompt, little practical use
2012-09-27 16:43:24 -07:00
e7af005408 Revert only_if for variables and templating prompt
Since the condition was not templated, it wasn't working.
Only variables in local scope were used, which made this not very practical
2012-09-28 01:32:09 +02:00
10bce54ef0 Merge pull request #1098 from jpmens/ini_file
New module: manipulate INI-style settings
2012-09-27 16:03:45 -07:00
9e4fac5ebd Create a string parser for varReplace instead of using re
This fixes a few issues,
- ${foo}${bar} would be parsed as a variable named foo}${bar,
  which wouldn't be easily fixed without breaking ${foo.${bar}}
- allows escaping . in variable parts so e.g.
  ${hostvars.{test.example.com}.foo} works

This is slower than using re. 3 million templating calls take about
about twice as long to complete with this compared to the regexp,
from ~65 seconds to ~115 seconds on my laptop.
2012-09-28 01:03:34 +02:00
6506e17eff Merge pull request #1109 from dhozac/fix-varReplace-repr
Fix only_if statements referencing non-string types
2012-09-27 15:57:50 -07:00
6c6f2b46b4 Merge pull request #1110 from dhozac/rm-assemble-ap
Remove assemble action plugin, fix daisychaining
2012-09-27 15:54:27 -07:00
ee5246fc36 Merge pull request #1113 from jpmens/file_pipe
Strip trailing white space from $FILE()/$PIPE()
2012-09-27 15:54:09 -07:00
42620d2f19 Strip trailing white space from $FILE()/$PIPE() 2012-09-27 23:47:34 +02:00
b55ef665ba Fix only_if statements referencing non-string types
This fixes e.g. only_if: ${task.changed} which would always
evaluate to true due to it having been replaced by a string for its
boolean value. Also adds a test case to ensure it doesn't get
missed again.
2012-09-27 18:36:52 +02:00
66d0acfde3 Remove assemble action plugin, fix daisychaining 2012-09-27 18:30:08 +02:00
151085c745 Merge pull request #1105 from alopropoz/devel
Don't use ssh-agent if password is specified.
2012-09-27 05:29:23 -07:00
0db5ccfecb Don't use ssh-agent if password is specified. 2012-09-27 14:57:06 +07:00
69612ba16d The very first start of 'fireball mode', which uses ansible in SSH mode to deploy a ephemeral zeromq daemon (entirely optional) that is will die after
it is no longer used.  No key signing will be required.  At this point, development use only -- NOT complete.
2012-09-26 23:51:59 -04:00
d47e15a1f2 module_formatter in hacking/ 2012-09-26 20:41:44 +02:00
3035394159 Added support for module_formatter (in ansible/hacking/) 2012-09-26 20:36:48 +02:00
c2daa77089 New module: manipulate INI-style settings
split off examples from DOCUMENTATION into own array as per #1098
2012-09-26 13:44:19 +02:00
af8f11e3f7 Merge pull request #1096 from sfromm/issue1067
Ignore failure of stop command if start succeeds with state=restarted
2012-09-26 04:02:02 -07:00
19c0202aaf Ignore failure of stop command if start succeeds with state=restarted
In some cases (see issue #1067) with state=restarted, a failure to stop
the service (which wasn't running) would appear to the module to be a
failure to restart the service even though it successfully started the
service.  This changes the behavior of the service module to focus
on the return code of the start command.  If the rc of stop is not
0 and the rc of start does equal 0, it considers the service
successfully restarted.  It then ignores the rc, stdout, and stderr
from the unsuccessful stop command.
2012-09-25 22:51:13 -07:00
69517832cd Update changelog 2012-09-25 20:50:21 -04:00
c63189f650 Make output be cleaner on multi-line failed commands and parse errors. 2012-09-25 20:38:12 -04:00
07101085ca Merge pull request #1093 from brainpage/make_local_action_consistant
2 improvements to delegate_to
2012-09-25 17:17:33 -07:00
51216dcfae Add tests for varReplace repr 2012-09-25 20:14:58 -04:00
84f98534ae Make varReplace recursive instead of iterative 2012-09-25 20:14:58 -04:00
d181a64315 Use repr on replacements for only_if 2012-09-25 20:14:58 -04:00
489844f960 Merge pull request #1095 from pas256/devel
Getting negative host pattern matching to work with external inventory
2012-09-25 17:13:32 -07:00
5530d771b4 Merge pull request #1094 from sfromm/issue1048
Give nice error message if destination directory doesn't exist
2012-09-25 17:12:59 -07:00
df147ab921 Merge pull request #1089 from tbielawa/runner_pause
Add 'pause' action plugin and support plugins skipping the host loop.
2012-09-25 17:11:54 -07:00
8a4e969b93 Getting negative host pattern matching to work with external inventory
(same as commit 4caf85e37b, but for
excluded hosts as well as subsets)
2012-09-25 16:16:25 -07:00
f52624f6d2 Give nice error message if destination directory doesn't exist (issue #1048) 2012-09-25 14:57:32 -07:00
faed650bb1 allow vars in delegate_to 2012-09-26 03:47:17 +08:00
620accf117 make delegate_to localhost act like local_action 2012-09-26 02:57:00 +08:00
f500eeec1d Update README.md
URL update
2012-09-25 09:33:34 -03:00
f8a9541405 add __init__ to action plugins 2012-09-25 08:24:35 -04:00
730b617186 Add init, though it's not really used. 2012-09-25 08:21:59 -04:00
8e71b26264 Fix up 'changed' playbook output patch 2012-09-25 08:07:11 -04:00
3270c097ef Merge pull request #1090 from dagwieers/prompt-fix
Fix a typo in the prompt code
2012-09-25 04:58:43 -07:00
6b6e3c64c8 Fix a typo in the prompt code
This is unfortunately related to not being able to reuse the same code that was tested.
2012-09-25 11:51:33 +02:00
58a4d2f7b4 Add 'pause' action plugin and support plugins skipping the host loop. 2012-09-25 01:13:35 -04:00
27d3ac9dc6 Update website link 2012-09-24 21:56:37 -04:00
5dab2efcdf Fixed obvious bug with missing self parameter to is_executable method 2012-09-24 21:03:45 -04:00
29ac1a8efc Replace os.access with stat calls for determining the executability of a given path. 2012-09-24 21:03:45 -04:00
734db4ffe9 Merge pull request #1080 from dagwieers/prompt-only_if
Add an only_if option to vars_prompt to make prompts conditional
2012-09-24 17:42:17 -07:00
9778eaf4f9 Merge branch 'module_args-argument' of git://github.com/dhozac/ansible into devel 2012-09-24 20:39:48 -04:00
4e9a970616 Add an only_if option to vars_prompt to make prompts conditional
Sometimes you may want to allow variables through host_vars or inventory, but prompt for a value if it is not set or if the value does not conform to something specific. This option allows you to specify when you want to offer a prompt.

This patch also moves check_conditional to utils, and adds an is_unset() function which is nicer to read:

    only_if: "not is_set('${var}')"

vs

    only_if: "is_unset('${var}')"
2012-09-24 23:55:54 +02:00
b355dca7dd Merge pull request #1081 from dsummersl/changelabel
Modified 'ok' to 'changed' when a change has occured
2012-09-24 13:46:06 -07:00
b45437541a Merge pull request #1083 from dagwieers/prompt-template
Template the variable prompt to customize the message
2012-09-24 13:44:00 -07:00
069feb5d9c Template the variable prompt to customize the message
We have a password-prompt for a configurable login name. Since we require to ask the password for this specific login, it is important to indicate what password needs to be prov ided on the prompt. So the prompt needs to be templated. That's what this patch does.
2012-09-24 22:37:51 +02:00
04c535b1e9 Modified 'ok' to 'changed' when a change has occured 2012-09-24 16:07:56 -04:00
5d6022b001 page rebuild, FAQ now part of main site. 2012-09-23 20:43:01 -04:00
34f7e6ffa0 Pass module arguments as argument instead of keeping it in runner 2012-09-23 23:38:26 +02:00
3939f7a812 Merge pull request #1076 from SleeplessAnnoyedNerd/Issue-1075
[Issue #1075] Fixing setup module fails if PATH is not set on target hos...
2012-09-23 10:23:18 -07:00
2f97afb634 Merge pull request #1071 from dhozac/git-expanduser
User-expand the destination path of the git module
2012-09-23 10:21:04 -07:00
fc1d6ab6b5 Merge pull request #1070 from elementalvoid/devel
Distribution packaging should install all manpages
2012-09-23 10:20:49 -07:00
f5f17e98ff Merge pull request #1065 from dhozac/varreplace-include
Allow including files through variables
2012-09-23 10:20:26 -07:00
0b3e05d9a4 Merge pull request #1066 from jpmens/doc3_lineinfile
Added DOCUMENTATION to lineinfile module
2012-09-23 10:20:08 -07:00
b75c662ab7 Merge pull request #1072 from dhozac/ansible_ssh_host
Add an ansible_ssh_host inventory variable
2012-09-23 10:19:53 -07:00
4e6d89b5b5 Merge pull request #1073 from dcoutu/devel
Added cases for 'dead but subsys locked' status
2012-09-23 10:19:19 -07:00
0ff151f70b Merge pull request #1063 from jpmens/geturl_doc2
Tweak DOCUMENTATION YAML as per latest 991
2012-09-23 10:19:02 -07:00
78b7a3a115 [Issue #1075] Fixing setup module fails if PATH is not set on target host 2012-09-22 17:01:37 +02:00
8d97bb4f8e Add an ansible_ssh_host inventory variable 2012-09-22 00:57:55 +02:00
9bb83067bc Added cases for 'dead but subsys locked' status 2012-09-21 14:55:59 -04:00
f6af88fe9f User-expand the destination path of the git module 2012-09-21 19:20:05 +02:00
21e23b34d2 distribution packaging should install all manpages
closes #1069
2012-09-21 11:15:40 -06:00
5a75433ce9 Added DOCUMENTATION to lineinfile module 2012-09-19 22:29:11 +02:00
4ded8cb3b3 Change $FILE{} and $PIPE{} to $FILE() and $PIPE() 2012-09-19 17:58:16 +02:00
cc948f339c Allow including files through variables
$FILE{file} will be replaced with the contents of "file"
$PIPE{cat file} will be replaced with the output of "cat file"
2012-09-19 17:57:17 +02:00
b8c4bb9e6e Revert "Allow including files through variables"
This reverts commit bf47bb4753.

Conflicts:

	lib/ansible/utils.py
	test/TestUtils.py
2012-09-19 10:31:23 -04:00
60e0410298 Tweak DOCUMENTATION YAML as per latest 991 2012-09-19 16:09:26 +02:00
c22d86b92f Merge pull request #226 from lorin/cwd-config
Can specify ansible.cfg in current directory.
2012-09-19 06:44:41 -07:00
1bd9ea6440 Merge pull request #1062 from dagwieers/wait_for-fix
Fix on older python versions, plus various improvements
2012-09-19 06:36:56 -07:00
8912258016 Fix on older python versions, plus various improvements
This change includes:

 - (on possibly older python versions ?) a string variable test using the 'is' operator fails (so it always return ok immediately after initial delay)
 - add a missing socket.settimeout() for the state=started case (if the machine does not exist, timeout defaults to 60 seconds)
 - add a connect_timeout option to customize the default connection timeout
 - use socket.shutdown(2) to close immediately
 - return the elapsed time
2012-09-19 15:19:59 +02:00
4cd3262f50 Merge pull request #1054 from jpmens/geturl_doc1
First attempt at standardizing DOCUMENTATION string
2012-09-19 06:09:39 -07:00
e039d88438 Merge pull request #1061 from copperlight/fix-make-error
fix Makefile date command error on OSX
2012-09-19 06:06:07 -07:00
5072ed3bd3 date parsing for OSX is BSD-like 2012-09-19 05:56:55 -04:00
95bbe2ef8b Merge pull request #4 from mavimo/master
Add support for ./nova.ini file
2012-09-18 19:06:18 -07:00
b2af95e4a6 Change $FILE{} and $PIPE{} to $FILE() and $PIPE() 2012-09-18 21:34:55 -04:00
57f6ad458a update changelog 2012-09-18 21:29:00 -04:00
e1ecb95b3d Delete test that was coded against *local* resolv.conf -- obviously not going to be the same between people's computers 2012-09-18 21:16:35 -04:00
08b70949c7 Fix a test and a typo in an example 2012-09-18 21:10:07 -04:00
eefe66f1cc Squashed commit of the following:
commit 80a26a8175b779b707bc08e9d28c451c30ee4ada
Merge: b25b9fd 61e9b27
Author: Michael DeHaan <michael.dehaan@gmail.com>
Date:   Tue Sep 18 21:01:47 2012 -0400

    Merge branch 'devel' of git://github.com/alopropoz/ansible into file-force

commit 61e9b27df2
Merge: 3f6f329 16bf3e1
Author: Aleksej Romanov <alopropoz2@yandex.ru>
Date:   Thu Sep 13 20:48:02 2012 +0700

    Merge remote branch 'upstream/devel' into devel

commit 3f6f3291df
Author: Aleksej Romanov <alopropoz2@yandex.ru>
Date:   Thu Sep 13 20:41:31 2012 +0700

    'force' option for 'file' module.

commit 6223bba941
Author: Aleksej Romanov <alopropoz2@yandex.ru>
Date:   Thu Sep 13 20:40:19 2012 +0700

    changed = True when changing symlink referent, #1008. Needed for tests.
2012-09-18 21:04:42 -04:00
b25b9fd840 Merge pull request #1058 from jkleint/devel
Support iteration over command output in with_items.
2012-09-18 17:55:40 -07:00
544a8e44d7 Merge pull request #1053 from dhozac/varreplace-include
Allow including files through variables
2012-09-18 17:53:02 -07:00
e041c2e2cd First attempt at standardizing DOCUMENTATION string (new DICT) 2012-09-18 14:04:43 +02:00
e7e68e69c2 Move patch notes to CONTRIBUTING.md 2012-09-17 23:03:11 -04:00
c607ba5740 Add CONTRIBUTING.md file 2012-09-17 22:59:35 -04:00
a478e5c981 update contributing file 2012-09-17 22:55:06 -04:00
086400cde0 Add CONTRIBUTING doc since github now supports this. 2012-09-17 22:42:32 -04:00
d77be4eecf Merge pull request #1052 from romeotheriault/add-SunOSVirtual-facts
Adding SunOSVirtual facts
2012-09-17 17:27:43 -07:00
5da4ab2d90 Merge pull request #1051 from sfromm/wile-e-coyote
Add pkg_mgr fact to setup (take 2)
2012-09-17 16:59:12 -07:00
d5b8553d1c Merge pull request #1056 from dhozac/task-transport
Allow transport on tasks, and use it for local_action
2012-09-17 16:53:33 -07:00
2a002f5c0b Support iteration over command output in with_items.
When the output of a command is stored in a register, this will create a
stdout_lines field in the result object that contains stdout split into a list
of lines.  This list can then be iterated over using with_items.
2012-09-17 16:57:33 -04:00
dd11b01350 Keep delegate_to so all auxiliary logic based on that works 2012-09-17 20:28:14 +02:00
9e78b10ae3 Add test data file 2012-09-17 18:31:49 +02:00
5bb0f6908b Allow transport on tasks, and use it for local_action 2012-09-17 18:28:37 +02:00
bf47bb4753 Allow including files through variables
$FILE{file} will be replaced with the contents of "file"
$PIPE{cat file} will be replaced with the output of "cat file"
2012-09-17 16:03:59 +02:00
d72eaa3fc5 Adding SunOSVirtual facts 2012-09-16 23:14:06 -10:00
65fe7b7003 Update package manager fact innards to a list of dicts 2012-09-16 21:42:55 -07:00
94eb11a6d7 Add pkg_mgr fact to setup
This should help facilitate playbook decision making that are not
strictly distribution specific, but more package manager.
2012-09-16 21:42:54 -07:00
7df0e5259f Merge pull request #1038 from bcoca/atomic_copy2
Atomic copy2
2012-09-14 15:53:49 -07:00
70777f044d Merge pull request #1047 from lotia/get_url_require_thirsty_if_dest_is_dir
Make get_url module always return dest.
2012-09-14 15:38:08 -07:00
4cffdbbc56 Merge pull request #1049 from copperlight/ansible-pull_example_logrotate
add logrotate config
2012-09-14 15:37:39 -07:00
0f5a4e2112 add logrotate config 2012-09-14 14:01:44 -04:00
c0aac03b0c url_get module returns dest
The url_get module now includes the destination in the returned JSON.
2012-09-14 08:34:41 +01:00
99746d4a83 Indicate thirsty argument required if dest is dir.
The check for the destination being a directory is now done before
checking if the file exists, that way the user is informed that the
thirsty argument is required.
2012-09-14 08:02:30 +01:00
49db16752f Can specify ansible.cfg in current directory. 2012-09-13 14:24:50 -04:00
16bf3e15c7 Merge pull request #1042 from dhozac/yum-install-rpm
Invoke is_installed correctly from rpm path
2012-09-13 05:12:09 -07:00
56b1a8ceed Invoke is_installed correctly from rpm path 2012-09-13 12:34:52 +02:00
88d1285f33 time is what i wanted, not gmtime
Signed-off-by: Brian Coca <briancoca+ansible@gmail.com>
2012-09-12 14:52:54 -04:00
06b914c5b3 small fix to prevent temp file from living past its succesful usage
Signed-off-by: Brian Coca <briancoca+ansible@gmail.com>
2012-09-12 14:47:06 -04:00
f5481621f8 made copy atomic by creating tmp file in dest location (ensures same partition)
uses pid and epoch to prevent collisions, good enough for most cases
Signed-off-by: Brian Coca <briancoca+ansible@gmail.com>
2012-09-12 14:42:51 -04:00
4a2bf7f60a rebuild from various pull requests 2012-09-11 22:29:42 -04:00
0725dd8dc8 Merge pull request #218 from marktheunissen/fix_password
Fix parameter names in documentation: passwd doesn't exist anymore
2012-09-11 19:29:07 -07:00
aca23f9402 Merge pull request #220 from lorin/include-playbook
Document including one playbook inside another
2012-09-11 19:28:42 -07:00
f9a65f42d1 Merge pull request #221 from lorin/postgres-priv
Fix priv argument in postgresql_user example.
2012-09-11 19:27:36 -07:00
4c5d98c7ee Merge pull request #222 from romeotheriault/copy-module-backup-option-docs
add backup option to the copy modules docs
2012-09-11 19:27:09 -07:00
7f3736bc2c Merge pull request #223 from nigelm/master
Pair of trivial documentation fixes
2012-09-11 19:26:40 -07:00
1f4cb79787 Merge pull request #224 from wzzrd/master
Small fix in documentation for seliux module
2012-09-11 19:25:59 -07:00
4503ad7c04 fix broken link 2012-09-11 22:13:59 -04:00
e7eab93243 Update changelog 2012-09-11 18:08:57 -04:00
04555f525e Fix a test from a previous pull request. 2012-09-11 18:04:54 -04:00
58ad934283 Merge pull request #1024 from tima/groups-pb
Made $groups and $group_names variables accessible in with_items
2012-09-11 14:59:05 -07:00
1829d519b5 Merge pull request #1030 from lorin/import-playbook-pathfix
Support import of playbooks in other directories
2012-09-11 14:58:27 -07:00
d7f83471ae Merge pull request #1032 from mavimo/patch-2
Add support for ./ansible.cfg file
2012-09-11 14:56:22 -07:00
522a3b5974 Merge pull request #1033 from jkleint/hosts-list-fix
Fix inventory.get_hosts when hosts is a list.
2012-09-11 14:55:18 -07:00
1f8696f5c1 Fix inventory.get_hosts when hosts is a list. 2012-09-11 13:00:40 -04:00
046e43ec11 Module user - typo corrected for state 2012-09-11 11:50:31 +01:00
cf9d7cd68e added backup option to the assemble,lineinfile and template module docs 2012-09-10 17:26:18 -10:00
ba1c9b04cb Correct selinux policy name: targetted -> targeted 2012-09-10 22:08:08 +02:00
dd023d137a Add support for differnt nova.ini file location: ./nova.ini, ~/nova.ini, /etc/ansible/nova.ini 2012-09-10 18:31:40 +02:00
84f2968023 Added a paragraph linking to the Jinja2 template docs 2012-09-10 16:09:30 +01:00
0cdd081b53 Add support for ./ansible.cfg file
Ansible support configuration in:
```
~/.ansible.cfg
/etc/ansible/ansible.cfg
```

this patch add current user (usefull where user have some different projects) with the oreder:
```
./ansible.cfg
~/.ansible.cfg
/etc/ansible/ansible.cfg
```
2012-09-10 17:57:32 +03:00
9d5a79f586 Made groups.groupname and group_names variables accessible in playbooks.
Also modified code that feeds the groups data structure to templates so
that it resolves groups inside of groups to hostnames.
2012-09-10 10:42:26 -04:00
c0495c3b9b Typo fix - playbook ignoring shell status return 2012-09-10 12:31:52 +01:00
1da9d23f90 Typo fix for assemble module 2012-09-10 11:51:16 +01:00
e12f3d4029 add backup option to the copy modules docs 2012-09-09 18:12:27 -10:00
b9e100a506 Support import of playbooks in other directories
Previously, importing a playbook in a different directory didn't
work because all of the relative paths were resolved relative to
the top-level playbook.

This patch resolves relative paths on a per-play level instead of
relative to the directory of the top-level playbook.

Also removes the dirname argument from the Play._get_vars method
since this argument wasn't used in the metho dbody.
2012-09-09 22:59:56 -04:00
df779decf6 who uses + rebuild 2012-09-08 23:03:54 -04:00
565f336182 lineinfile should use 'search' everywhere 2012-09-08 14:53:34 -04:00
14a9c3ab9e Line in file regexep should match a portion of the line, not the whole line! 2012-09-07 21:03:59 -04:00
95540f40b0 Add package to setup.py 2012-09-07 21:03:59 -04:00
5b57011152 Merge pull request #1027 from mcodd/setup_bug_python24
setup not python24 compatible in 0.7
2012-09-08 05:24:09 -07:00
335f136e71 Merge pull request #1023 from lorin/postgres-user-fix
Fix postgresql_user bug
2012-09-08 05:23:29 -07:00
e795fa1ec2 Merge pull request #1014 from marktheunissen/journald
Fix regex that allows passwords to get into syslog, use journal if available.
2012-09-08 05:22:27 -07:00
925c9eb38f Merge pull request #1021 from lorin/config-key
Have ansible respect private_key_file option
2012-09-08 05:21:02 -07:00
8ebd228bd3 Merge pull request #1022 from skvidal/devel
add import sys to virt module b/c it needs it if the libvirt python
2012-09-08 05:20:07 -07:00
c0638842d8 make this python24 compatible 2012-09-07 22:47:03 -04:00
aa91e11906 Merge pull request #1025 from dhozac/action_plugins-setup
Install action_plugins
2012-09-07 16:10:36 -07:00
5b49a059ac Install action_plugins 2012-09-08 00:21:56 +02:00
20fc6a29d3 Made groups.groupname and group_names variables accessible in playbooks. 2012-09-07 18:07:52 -04:00
b3b01bb7a3 Fix postgresql_user bug
If I create a database from scratch and assign permissions by doing:

      - name: ensure database is created
        action: postgresql_db db=$dbname

      - name: ensure django user has access
        action: postgresql_user db=$dbname user=$dbuser priv=ALL password=$dbpassword

Then it fails with the error:

  File "/tmp/ansible-1347048449.32-29998829936529/postgresql_user", line 565, in <module>
    main()
  File "/tmp/ansible-1347048449.32-29998829936529/postgresql_user", line 273, in main
    changed = grant_privileges(cursor, user, privs) or changed
  File "/tmp/ansible-1347048449.32-29998829936529/postgresql_user", line 174, in grant_privileges
    changed = grant_func(cursor, user, name, privilege)\
  File "/tmp/ansible-1347048449.32-29998829936529/postgresql_user", line 132, in grant_database_privilege
    prev_priv = get_database_privileges(cursor, user, db)
  File "/tmp/ansible-1347048449.32-29998829936529/postgresql_user", line 118, in get_database_privileges
    r = re.search('%s=(C?T?c?)/[a-z]+\,?' % user, datacl)
  File "/usr/lib/python2.7/re.py", line 142, in search
    return _compile(pattern, flags).search(string)
TypeError: expected string or buffer

This fix fixes the problem by not executing the regex if the
db query on pg_database returns None.
2012-09-07 16:24:00 -04:00
20c6e5302b Fix priv argument in example.
Should be "priv", not "privs". Was correct in table, but wrong in
examples.
2012-09-07 16:18:39 -04:00
9d88b3eedd add import sys to virt module b/c it needs it if the libvirt python
module is missing
2012-09-07 16:05:42 -04:00
eabbaaec46 Have ansible respect private_key_file option
The ansible command-line tool was ignoring the private_key_file option.
2012-09-07 14:37:32 -04:00
869a97e1cb Fix comment in example config file.
The config file incorrectly mentions the --private-key-file flag.
Should be --private-key
2012-09-07 14:34:36 -04:00
ccd0952d54 Document including one playbook inside another 2012-09-07 09:16:08 -04:00
0709c48f64 Merge pull request #1018 from willthames/template_perms
Fix templates for non root sudo_user
2012-09-07 05:20:02 -07:00
f456d999a9 Fix templates for non root sudo_user
When using template module, if a restrictive umask is set, the
sudo_user won't be able to read the /tmp/ansible-dir/source file
after it is copied across following _transfer_str

I wonder if this behaviour shouldn't be abstracted somehow (as
this correction also happens after put_file in the copy module too)
2012-09-07 16:35:53 +10:00
ad9e2939bf Fix parameter names 2012-09-06 18:16:05 -07:00
c25ead382c Adapt module common code to use the systemd journal if it's available 2012-09-06 17:59:38 -07:00
022b2290bb Changelog update for 0.8 initial merges 2012-09-06 20:58:23 -04:00
dc14681530 rename isset to is_set 2012-09-06 20:55:27 -04:00
8621539341 Merge branch 'only_if-isset' of https://github.com/dhozac/ansible into devel 2012-09-06 20:55:11 -04:00
4280e00d56 Merge pull request #1000 from mavimo/patch-1
Add support to removes control param
2012-09-06 17:52:02 -07:00
7ef3e7dccb Merge pull request #1003 from bladypirat/devel
added support for custom port definition for postgresql_* modules
2012-09-06 17:51:35 -07:00
49bef3f6c2 Merge pull request #1005 from dagwieers/cmdline
Add /proc/cmdline information to the default facts
2012-09-06 17:51:19 -07:00
fa71237f8a Merge pull request #1012 from jpmens/sshhostkeysosx
Add support for RSA/DSA SSH host key detection in setup module for OS/X
2012-09-06 17:50:32 -07:00
ba97ad13e3 Merge pull request #1010 from tima/yaml-jinja
Added to_yaml and from_yaml filters to Jinja environment.
2012-09-06 17:50:01 -07:00
8a09e1281b Fixup modularized template module 2012-09-06 19:04:27 -04:00
633e513a65 Modular server-side actions (squash merge) 2012-09-06 18:57:04 -04:00
975c323e39 Release version bump 2012-09-06 18:56:38 -04:00
979b778430 Spec version fixes 2012-09-06 18:53:01 -04:00
b36aa61237 Add support for RSA/DSA SSH host key detection in setup module for OS/X
s/<8spaces>/<4spaces>/g
2012-09-06 20:40:21 +02:00
23cd7ad08a Added to_yaml and from_yaml filters to Jinja environment. 2012-09-06 10:19:56 -04:00
d158218c3f Add /proc/cmdline information to the default facts
The use-case here is that based on information in the /proc/cmdline certain actions can be taken.

A practical example in our case is that we have a play at the end of the provisioning phase that reboots the system. Since we don't want to accidentally reboot a system (or restart the network) on a production machine, having a way to separate an Anaconda post-install (sshd in chroot) with a normal system is a good way to make that distinction.

    ---
    - name: reboot
      hosts: all
      tasks:
      - action: command init 6
        only_if: "not '${ansible_cmdline.BOOT_IMAGE}'.startswith('$')"

A practical problem here is the fact that we cannot simply check whether it is set or empty:

    ---
    - name: reboot
      hosts: all
      tasks:
      - action: command init 6
        only_if: "'${ansible_cmdline.BOOT_IMAGE}'"

If ansible_cmdline was a string, a simple only_if: "'${ansible_cmdline}'.find(' BOOT_IMAGE=')" was an option, but still not very "beautiful" :-/

This implementation uses shlex.split() and uses split(sep, maxsplit=1).
2012-09-06 09:35:33 +02:00
14db2fa376 Add an isset("$var") function to only_if 2012-09-05 23:18:47 +02:00
8360f9f46c added support for custom port definition 2012-09-05 18:18:30 +02:00
a2307aa7a0 Fix error with servers without group metadata. Add this servers to undefined group. 2012-09-05 16:26:01 +02:00
2dd430d9c0 Add support to removes control param
Execute action only if specified file using param removes exist (execute reverse control of creates).

Some usage eg.:

```yaml
- name: enable apache2 default websites
  action: command /usr/sbin/a2ensite $item
creates=/etc/apache2/sites-enabled/$item
  with_items:
    - default
    - default-ssl

- name: disable apache2 default websites
  action: command /usr/sbin/a2dissite $item
removes=/etc/apache2/sites-enabled/$item
  with_items:
    - default
    - default-ssl
```
2012-09-05 14:06:47 +03:00
e4d827e6de Fix logging callback parameters 2012-09-04 21:57:34 -04:00
df5d134ab9 Merge pull request #3 from mavimo/master
Fix error with servers without group metadata.
2012-09-05 07:46:57 -07:00
151a9b385d Update list of provided facts for 0.7 2012-09-04 21:40:49 -04:00
4d003127fa Rebuild 2012-09-04 20:22:14 -04:00
074667261e rebuild 2012-09-04 20:02:28 -04:00
8cb9cace33 Merge pull request #213 from tbielawa/nagios_services_required
nagios module should advertise 'services' attribute as required.
2012-09-04 17:01:45 -07:00
e052cf4727 nagios module should advertise 'services' attribute as required. 2012-09-04 13:55:11 -04:00
16c57c6674 rebuild 2012-09-02 08:35:54 -04:00
92de282430 rebuild 2012-09-02 08:35:38 -04:00
edfcdbffa1 Merge pull request #210 from mavimo/patch-1
Fixed typo un user
2012-09-02 05:34:11 -07:00
c0d40439a1 Fixed typo un user
In playbook users is not valid, please change to user.
2012-08-31 17:44:26 +03:00
2b6d21d23c Merge pull request #2 from skvidal/master
eucalyptus support into ec2 inventory module
2012-08-31 07:09:16 -07:00
b3ee7fdd97 add eucalyptus private cloud support to the ec2 module 2012-08-31 09:52:12 -04:00
566f220d16 API docs update + fix -u reference 2012-08-30 23:55:31 -04:00
edd2a3c6ed Rebuild 2012-08-30 22:58:22 -04:00
620a6c4185 Grammar fix 2012-08-30 22:58:09 -04:00
496a2b7f56 Update README.md 2012-08-30 20:28:58 -03:00
deb51becc2 lineinfile now refactored and & in core 2012-08-30 20:27:39 -03:00
4c42721619 Merge pull request #4 from cegeddin/master
Included cegeddin playbooks in README.md
2012-08-30 16:26:46 -07:00
92c37c9c07 Add seboolean RST 2012-08-30 19:14:14 -04:00
104c3d7d6e Document SELinux modules 2012-08-30 19:14:01 -04:00
256d61e1e7 Document SELinux module 2012-08-30 19:08:05 -04:00
23ae68de4f add docs on wait_for 2012-08-30 19:01:53 -04:00
56649eb76b rebuild 2012-08-30 18:50:24 -04:00
e8a760a042 add version added 2012-08-30 18:50:10 -04:00
800bf4b232 Who uses additions 2012-08-30 18:49:31 -04:00
e7de31bb18 Fix table / rebuild 2012-08-30 18:42:45 -04:00
500941917d Add line in file, rebuild 2012-08-30 18:41:27 -04:00
a2e5d38f59 Merge pull request #209 from dhozac/lineinfile
Add lineinfile module
2012-08-30 15:40:25 -07:00
c68a5661a4 Update README.md 2012-08-30 16:15:49 -03:00
f247579221 Update README.md 2012-08-30 16:14:54 -03:00
b0c2545dc4 updated README.md to include cegeddin playbooks 2012-08-30 11:12:13 -04:00
f3ae13a052 added cegeddin repo to playbooks 2012-08-30 11:07:34 -04:00
09f7bd1a9b Add lineinfile module 2012-08-30 04:22:51 +02:00
b12eeec85f Rebuild 2012-08-28 20:48:25 -04:00
f542e10cc6 Merge pull request #205 from tbielawa/playbooks2_toc
Add auto-gen TOCs to a bunch of pages.
2012-08-28 17:45:20 -07:00
67fcd7bea1 Merge pull request #206 from tbielawa/future
You can include playbooks now.
2012-08-28 17:44:33 -07:00
87edeaf5b6 Merge pull request #1 from mavimo/master
OpenStack inventory
2012-08-28 17:43:57 -07:00
85277e9e64 You can include playbooks now. 2012-08-28 16:04:36 -04:00
d9e8a6c2e1 Added basic support for OpenStack inventory support. Tested only with RackSpace. Require python-novaclient to work. 2012-08-28 21:56:16 +02:00
b9f7ea7198 Add auto-gen TOCs to a bunch of pages. 2012-08-28 15:41:10 -04:00
47eea55d13 rebuild 2012-08-28 07:39:55 -04:00
5b6046545e Merge pull request #204 from tbielawa/nagios_cfg
change default desc for cmdfile parameter
2012-08-28 04:39:19 -07:00
720953664c change default desc for cmdfile parameter 2012-08-28 02:13:49 -04:00
989817657f Add versionadded to nagios docs 2012-08-27 22:33:31 -04:00
9e51b96a10 Rebuild 2012-08-27 22:07:35 -04:00
3830b2ce1d Remove part about module config file as I don't want to encourage modules to take configuration files. 2012-08-27 22:06:14 -04:00
3299485d9b Merge documentation sections. 2012-08-27 22:05:40 -04:00
47542aefc5 rebuild 2012-08-27 21:59:44 -04:00
be6b9b0594 Fix rst formatting + rebuild 2012-08-27 21:59:37 -04:00
d91e07b611 Undo README change 2012-08-27 21:59:36 -04:00
3a8c277cb8 updated subversion/git RST for new subversion module and git force option 2012-08-27 21:59:36 -04:00
922e34c144 updated docs for pull request #922 (subversion module) 2012-08-27 21:59:36 -04:00
c4522d9f29 Merge pull request #202 from elventear/postgresql_user
Docs for postgresql_user recent changes
2012-08-27 18:53:12 -07:00
b57e9c9a27 Merge pull request #203 from tbielawa/nagios_docs
Add docs for nagios
2012-08-27 18:52:24 -07:00
038ebac577 Fix typo 2012-08-27 19:52:47 -04:00
49cc3c05b8 Also, the mysql_user module didn't have a proper :ref: tag. 2012-08-27 15:42:07 -04:00
1133b6dd94 Put modules list into three columns. 2012-08-27 15:41:37 -04:00
ee2e913315 Remove words about using 'host' in the parameters desc. Also, fix delegate to nagios.example.com 2012-08-27 15:17:57 -04:00
68e31cf23f Add docs for nagios 2012-08-27 15:12:37 -04:00
514f491514 Missing owner option on postgresql_db 2012-08-27 10:56:48 -05:00
07580692f5 Update documentation for postgresql_user 2012-08-27 10:53:58 -05:00
3ebf6cb223 fix uptime API example 2012-08-24 19:33:14 -04:00
b8ba2d3066 Document variable precedence / rebuild 2012-08-21 22:02:43 -04:00
0483da674b Fix directory names 2012-08-21 20:37:42 -04:00
4caa76cbd8 Add a callback that logs activity for each host in /var/log/ansible/hosts 2012-08-20 20:42:57 -04:00
fce2650d5f Add connections directory 2012-08-20 20:05:41 -04:00
68f07e83d9 Moved inventory to plugins repo 2012-08-20 19:57:18 -04:00
cadd806a67 Keep inventory scripts in plugins repo 2012-08-20 19:46:45 -04:00
c351c47cea docs tweak/rebuild 2012-08-20 18:53:19 -04:00
0e83972847 Merge branch 'master' of github.com:ansible/ansible.github.com 2012-08-20 18:47:05 -04:00
a252abcc6c Rebuild 2012-08-20 18:29:56 -04:00
beb9d3ac1e Fix link 2012-08-20 18:29:43 -04:00
2019a97b4e Merge pull request #196 from tbielawa/local_action
Add docs for 'local_action' (ansible:#905). Oh, and fix 'make viewdocs'.
2012-08-20 15:29:13 -07:00
9ad592965a Add docs for 'local_action' (ansible:#905). Oh, and fix 'make viewdocs'. 2012-08-19 22:04:18 -04:00
8a9b8a727b Fix a comment 2012-08-19 10:34:25 -04:00
5c2bad90c9 Minor OSX callback fixups 2012-08-18 22:56:00 -04:00
1605fc1fad Add osx_say plugin. 2012-08-18 22:45:48 -04:00
b72b1eb50c Initial commit 2012-08-18 19:42:28 -07:00
1824dd33cf Document the new 'serial' and 'delegate_to' features. 2012-08-18 10:23:17 -04:00
6a5a7bd0f8 rebuild 2012-08-17 20:36:30 -04:00
e02457015b rebuild 2012-08-17 20:36:24 -04:00
3b562aa367 add service pattern= parameter 2012-08-17 20:36:24 -04:00
f81f541354 Merge pull request #192 from lorin/missing-dot
fix typo: ~/ansbile.cfg -> ~/.ansible.cfg
2012-08-17 17:30:59 -07:00
3c4e9fdc98 fix typo: ~/ansbile.cfg -> ~/.ansible.cfg 2012-08-17 14:27:41 -04:00
de207dc3fa rebuild 2012-08-16 22:09:45 -04:00
dad0e0fefb document --list-hosts 2012-08-16 22:08:17 -04:00
815a5408e0 New quotes from the tweet stream 2012-08-16 22:04:07 -04:00
7fc9ac4cf9 various tweaks/rebuild 2012-08-16 21:12:36 -04:00
1676ff4e2d Fix RPM path 2012-08-14 22:21:57 -04:00
44e3eef15e Document -u change 2012-08-14 22:20:47 -04:00
1ac07ee677 "Who uses" additions 2012-08-14 22:18:17 -04:00
0926c91b28 Document host ranges (new in 0.6) 2012-08-14 22:14:47 -04:00
0219d88fdd Document more playbook features in 0.7, docs build 2012-08-14 22:11:56 -04:00
7bd6fde2a3 Document --limit and range selection 2012-08-14 22:07:00 -04:00
cb0fb4c42f Merge pull request #184 from tbielawa/bashifiedexamples
'bashify' the examples page.
2012-08-14 18:26:07 -07:00
728df81bab Merge pull request #185 from tbielawa/SplitModuleRst
Break the modules docs into separate files.
2012-08-14 18:25:31 -07:00
f28ea0cda1 Break the modules docs into separate files. 2012-08-13 15:39:00 -04:00
a07e928358 'bashify' the examples page. 2012-08-13 14:51:36 -04:00
1f3e22687e rebuild 2012-08-10 01:24:32 -04:00
10c89f4d49 Merge pull request #181 from mattupstate/master
Add notes about easy_install and pip
2012-08-10 18:22:37 -07:00
41e524eb58 Add notes about easy_install and pip 2012-08-10 10:35:27 -04:00
df53801e0f fix doc example 2012-08-10 00:07:10 -04:00
ce9401beda fix typo 2012-08-09 22:13:24 -04:00
b721176bdd rebuild 2012-08-09 22:12:10 -04:00
2befb446a3 Merge branch 'RefreshBestPractices' of https://github.com/tbielawa/ansible.github.com 2012-08-09 22:11:42 -04:00
f4245ee5f0 add versionadded info to new modules 2012-08-09 22:10:57 -04:00
331cfa6b36 rebuild 2012-08-09 22:10:57 -04:00
ea3bf960aa rebuild 2012-08-09 22:10:57 -04:00
688086c54a Add consistent versionadded/deprecated tags. 2012-08-09 22:10:57 -04:00
391acfb20c Freshen up the examples page. 2012-08-09 22:10:57 -04:00
af762446a1 Merge pull request #172 from tbielawa/RefreshNotes
Refresh the use of 'note' to make it consistent.
2012-08-09 19:05:43 -07:00
54a9f17b25 formatting/rebuild 2012-08-09 22:04:34 -04:00
fc7591eeaa Merge pull request #175 from mattupstate/apt_repository
Add apt_repository documentation
2012-08-09 19:02:48 -07:00
b1c6990129 rebuild 2012-08-09 22:01:58 -04:00
3e296ae3aa Merge pull request #174 from anotherjesse/master
correct hacking/test-module arguments
2012-08-09 19:01:42 -07:00
04cc44bf17 Merge pull request #176 from mattupstate/pip
Add pip module documentation
2012-08-09 19:01:18 -07:00
4581c19fa0 rebuild 2012-08-09 22:00:45 -04:00
b3f0678f2d fix tags and reuse of link name (annoying habit of sphinx to require uniqueness in HREFs) 2012-08-09 22:00:19 -04:00
a29d532711 Merge pull request #178 from anotherjesse/link_resources
link ansible resources
2012-08-09 18:58:45 -07:00
50e95372d3 Merge pull request #177 from mattupstate/easy_install
Add basic easy_install module documentation
2012-08-09 18:57:04 -07:00
05ded8d363 Merge pull request #179 from mattupstate/supervisorctl
Add supervisorctl documentation
2012-08-09 18:56:34 -07:00
056061922e page update 2012-08-08 22:17:32 -04:00
65b3792130 Update README.md 2012-08-08 20:54:45 -03:00
ff9072db7d Add supervisorctl documentation 2012-08-08 11:04:44 -04:00
0716835e47 Rebuild 2012-08-08 08:17:35 -04:00
2085ec0971 Update the RST as well 2012-08-07 15:49:10 -07:00
2be8cbfa2b correct test-module arguments 2012-08-07 15:43:40 -07:00
d36fdb84b0 link ansible resources
Fix the link to ansible resources in moduledev and link to it
in the module list page.
2012-08-07 15:20:24 -07:00
e028ce7c2e Add apt_repository documentation 2012-08-07 17:08:58 -04:00
2f9e3d141e Add pip module documentation 2012-08-07 17:05:21 -04:00
f1ae9eb98b Add basic easy_install module documentation 2012-08-07 16:56:08 -04:00
fb5d2d10db Refresh the use of 'note' to make it consistent. 2012-08-07 02:50:48 +00:00
8328bb7d63 Lighter refresh of the Best Practices page. 2012-08-07 02:21:23 +00:00
10387cb19c Since master branch are named release-XX now, just link to examples on the devel branch. 2012-08-06 22:00:50 -04:00
d47a833a8d Merge pull request #168 from marktheunissen/add-host-to-mysql-user
Adding the host
2012-08-06 18:12:58 -07:00
866863c209 Adding the host 2012-08-06 20:03:20 -05:00
6642d2447e rebuild 2012-08-06 20:56:26 -04:00
77e471650b I actually forget. 2012-08-06 20:53:45 -04:00
532381203e Merge pull request #167 from marktheunissen/fix_mysql_docs
Fixing the MySQL docs
2012-08-06 17:52:34 -07:00
4d7f9fbb70 Fixing the MySQL docs 2012-08-03 10:31:43 -05:00
f732aa3d1c Add start of a glossary 2012-08-03 00:01:23 -04:00
fa6aa5ef98 Added info about ignore_errors: True and added a user to the who uses page 2012-08-02 22:08:00 -04:00
b9d8ca4f30 Merge pull request #166 from lorin/tasks-not-element
'tasks' should not be preceded by '-' in examples
2012-08-02 19:04:24 -07:00
ce2cdc22c4 'tasks' should not be preceded by '-' in examples 2012-08-01 22:50:03 -04:00
71d7f1acf9 add naming info to FAQ 2012-08-01 21:03:14 -04:00
157bdbbd73 slight tweak to 'who uses' 2012-08-01 20:44:34 -04:00
53328a8f80 Update README.md 2012-08-01 21:39:09 -03:00
d6a1adb1d3 Update README.md 2012-08-01 21:38:28 -03:00
980b675e5d Update README.md 2012-08-01 21:38:05 -03:00
1ff800bab3 Update README.md 2012-08-01 20:42:01 -03:00
717884b61a amend best practices 2012-08-01 00:52:48 -04:00
47629a455c rebuild 2012-08-01 00:50:35 -04:00
dde93ae55a fixup service docs 2012-08-01 00:50:16 -04:00
6dd26386af update docs readme 2012-07-31 23:30:01 -04:00
30f42b9735 Module docs cleanup + rebuild 2012-07-31 23:19:41 -04:00
5d5231c4d0 undocument service list=status, since that's gone now 2012-07-31 23:10:15 -04:00
dde17404c6 Mention the AnsibleModule common code on the docs site 2012-07-31 23:08:04 -04:00
962e6e5572 module doc updates for 0.6 (release pending soon) 2012-07-31 22:47:04 -04:00
1aa3c1522c Updating various doc items with 0.6 features, releasing soon, and removing references to things new in 0.4, which
has been out long enough to no longer be new.
2012-07-31 22:19:04 -04:00
3b5ea2aa71 Merge pull request #1 from lorin/master
Added OpenStack playbooks
2012-07-31 11:26:17 -07:00
dac0db9ca2 Add company + rebuild 2012-07-30 22:57:01 -04:00
b76e8c9028 Merge pull request #158 from ADRIyas/patch-1
Update rst/modules.rst
2012-07-31 12:40:56 -07:00
2de89035e7 Merge pull request #159 from lorin/apt-args
Minor doc fixups for apt module.
2012-07-31 12:40:24 -07:00
49385bb3a3 Minor doc fixups for apt module.
Change hyphens to underscores in argument names, e.g.:
 update-cache -> update_cache

Remove question mark in description of behavior of update_cache.
2012-07-31 09:02:37 -04:00
1e32e8bbf7 add donation link 2012-07-30 20:08:13 -04:00
2253fa1019 Update rst/modules.rst 2012-07-31 00:14:50 +08:00
75d5f2579d Merge pull request #141 from pas256/master
EC2 external inventory documentation
2012-07-29 17:14:34 -07:00
cd2f44877a Merge pull request #154 from lorin/postgres-docs
Document postgresql_db and postgresql_user modules.
2012-07-29 12:36:51 -07:00
840f3c951b Document postgresql_db and postgresql_user modules. 2012-07-29 13:49:42 -04:00
bb7ef45347 add a user + docs rebuild 2012-07-28 16:34:37 -04:00
2baf4f2e22 rebuild 2012-07-28 10:24:56 -04:00
8fb2e2707c name is optional on a task 2012-07-28 10:24:47 -04:00
a4b07056ce docs rebuild 2012-07-28 10:18:46 -04:00
c39b7261f1 node -> tier and some feature matrix reorg 2012-07-28 10:17:14 -04:00
eef5bf4778 add note about sudo_user 2012-07-28 08:42:20 -04:00
e32866d137 Update README.md
Added OpenStack playbooks
2012-07-28 00:30:03 -03:00
2078627e3b docs rebuild 2012-07-27 22:56:53 -04:00
c4a6b68cb9 Update index 2012-07-27 22:42:07 -04:00
288499e391 homepage cleanup 2012-07-27 22:30:36 -04:00
10fc56adf0 Attempt to make the home page less of a wall of text. Probably more to come. 2012-07-27 22:16:14 -04:00
db19d83e40 Update the format of the modules page to use tables. 2012-07-27 20:35:45 -04:00
58cb60c8af fix company name + docs rebuild 2012-07-27 19:22:51 -04:00
ebdb991813 link fix 2012-07-25 23:49:33 -04:00
fb7ab7b7ed fix up html 2012-07-25 23:38:47 -04:00
40d790f6b9 Add who uses to git 2012-07-25 23:36:14 -04:00
e15da1563b Rebuild 2012-07-25 23:34:20 -04:00
a4004e50df Rebuild 2012-07-25 23:34:02 -04:00
0ca377eea4 Build + cleanup who uses page 2012-07-25 23:33:47 -04:00
69e8b75dc3 Merge pull request #151 from lorin/apt-get-update
Document that apt-cache=yes is equivalent to apt-get update.
2012-07-26 07:51:42 -07:00
6491e0a1fb Merge pull request #150 from Lennie/patch-1
Update index.html
2012-07-26 07:50:26 -07:00
f187227cb6 Merge pull request #146 from lorin/git-nobranch
Remove branch arg from git docs.
2012-07-26 06:05:40 -07:00
1694146c2d Document that apt-cache=yes is equivalent to apt-get update. 2012-07-26 08:57:09 -04:00
769ea7aefc Document the 'remote' argument for the git module. 2012-07-26 08:53:05 -04:00
5a58eb16c0 Update index.html
I propose this quote from the mailinglist should go in the "What People Are Saying" section.
2012-07-26 15:34:12 +03:00
2f71eb0366 Merge pull request #140 from ludovicc/master
Document sudo_user in playbook
2012-07-25 18:48:08 -07:00
f131a7da36 Merge pull request #145 from lorin/link-to-setup
Add link to setup module when ansible vars first referenced.
2012-07-25 18:45:59 -07:00
355bfc6d21 Update README.md 2012-07-25 20:31:22 -03:00
4825c0f9c0 Update README.md 2012-07-25 20:29:46 -03:00
616cfd27b2 Update README.md 2012-07-25 20:29:13 -03:00
d7a7b6cb59 Update README.md 2012-07-25 19:54:20 -03:00
6eabfa0749 Update README.md 2012-07-25 19:34:14 -03:00
a87f46727b Update README.md 2012-07-25 19:28:46 -03:00
f39ab48239 Update README.md 2012-07-25 19:28:21 -03:00
726d0bd79f Update README.md 2012-07-25 19:25:20 -03:00
d3aaecba43 Initial commit 2012-07-25 15:03:43 -07:00
def22a9cf0 Remove branch arg from git docs.
The "branch" arg doesn't work, users should use "version" instead
for specifying branches.
2012-07-25 17:18:31 -04:00
dfd60149c0 Add link to setup module when ansible vars first referenced.
Add a cross-reference link to the setup module documentation, so
users know where to look to find more detail about what ansible
variables are available.
2012-07-25 15:21:42 -04:00
799fb60051 Rebuild 2012-07-20 11:51:23 -04:00
db014182e6 Update the inventory docs + rebuild 2012-07-20 11:51:17 -04:00
c5f791a297 Completed documentation of the EC2 external inventory script 2012-07-17 17:30:47 -07:00
4c4a96b088 Beginning to add EC2 documentation. 2012-07-16 17:57:22 -07:00
8e0560f41c Document sudo_user 2012-07-16 18:28:32 +02:00
52bcdf5e38 Merge pull request #138 from lorin/master
Fix missing colon in YAML example
2012-07-14 11:58:03 -07:00
78654d7b6d Merge pull request #137 from pas256/patch-3
Adding the documentation for 'install-recommends' to APT.
2012-07-14 11:57:32 -07:00
def40d0389 Missing a colon in a YAML example. 2012-07-10 14:39:52 -03:00
3807e16cad Adding the documentation for 'install-recommends' to APT. 2012-07-09 11:34:06 -07:00
429d1108ce Merge pull request #136 from pas256/patch-2
Issue 135: Updating to reflect reality
2012-07-06 18:04:51 -07:00
107784980e Issue 135: Updating to reflect reality 2012-07-06 11:13:40 -07:00
d3fa1c36a5 docs build + formatting fix on the modules page 2012-07-04 17:47:04 -04:00
6eb53ad540 misc doc updates for 0.5 2012-07-04 17:44:39 -04:00
c963278c58 Merge pull request #129 from goozbach/master
Add a global_vars file for use of all playbooks.
2012-07-04 11:31:14 -07:00
1669620379 Merge pull request #130 from jpalley/patch-1
Add/update documentation about magic variables.
2012-07-04 11:30:35 -07:00
c3221f12cc Add/update documentation about magic variables. 2012-07-02 14:17:21 +08:00
3aefdb0e87 added global vars to best practice 2012-06-21 16:50:57 -04:00
21381fc533 Rebuild of everything already merged 2012-06-19 21:22:27 -04:00
73f7416864 Fix formatting glitch. 2012-06-19 21:22:18 -04:00
dd7113cc63 Merge pull request #122 from alanorth/getting_started
Clarify getting started instructions for git checkouts
2012-06-15 04:38:48 -07:00
f52d403d55 Merge pull request #123 from goozbach/master
Fixed best practice
2012-06-15 04:38:05 -07:00
cf3da1bd25 vars_files doesn't use include 2012-06-14 13:19:05 -04:00
78c02a9163 Clarify getting started instructions for git checkouts
The default branch is already devel (as of June 14, 2012), so there's
no need to check this one out explicitly.  Also, it was being checked
out before we had even entered the source folder, which was obviously
a mistake.
2012-06-14 16:45:15 +03:00
1b249b87be Merge pull request #118 from nafeger/master
simple docs request about using ${var}
2012-06-12 18:03:20 -07:00
2797b9f7fb Adding note about ${vars}
Add a note about how it is possible to use ${var} in addition to $var
2012-06-12 19:32:42 -05:00
f7d4b418d5 Docs rebuild 2012-05-19 20:57:34 -04:00
e21595fcc7 Merge pull request #113 from johncallender/master
Found a couple more broken doc links
2012-05-19 17:57:10 -07:00
71350a176c Merge pull request #112 from wgjohnson/examples-edits
removed '-' from ansible calls
2012-05-19 17:56:42 -07:00
9395ebd479 Merge pull request #114 from maxjustus/master
Fix misspelling of necessary
2012-05-19 17:56:09 -07:00
abdd5c1060 Docs rebuild 2012-05-19 17:30:30 -04:00
340faa5fde Add service state=reloaded 2012-05-19 17:30:20 -04:00
72e8a40ccd Change neccesssary to necessary 2012-05-16 10:39:10 -05:00
b243b8dcbf Fixing a couple more internal doc links. 2012-05-15 18:16:32 -07:00
992c2b8234 removed '-' from ansible calls 2012-05-15 13:03:10 -07:00
b896157d61 Merge pull request #110 from johncallender/master
I noticed a few small issues in the new docs
2012-05-14 15:57:34 -07:00
25d868c654 minor format and typo edits for the 0.4 doc update. 2012-05-13 17:08:42 -07:00
b71cf6653f Add missing files 2012-05-13 12:03:24 -04:00
0127df97b5 new playbooks best practices page + docs rebuild 2012-05-13 11:56:09 -04:00
4994566124 Various docs reorg and additions 2012-05-13 11:00:02 -04:00
bdba38c790 Merge pull request #109 from dne/patch-1
Remove outdated note about apt module
2012-05-12 12:27:13 -07:00
2673b4b8a4 Remove outdated note about apt module 2012-05-12 22:22:43 +03:00
85cedf52ef fix rst + docs rebuild 2012-05-10 01:41:31 -04:00
f81000c127 Document list on service module 2012-05-10 01:41:00 -04:00
8559f0167d var section tweaks 2012-05-10 01:36:52 -04:00
c193f774c2 Doc custom facts 2012-05-10 01:33:19 -04:00
d9fe6e959b update docs 2012-05-10 01:27:34 -04:00
7ea369a068 Doc system flags 2012-05-10 01:26:40 -04:00
a00ab37b22 Document raw module. 2012-05-10 01:20:31 -04:00
c9f6a2c978 Undocument override hosts (gone in 0.4, use -i "host1,host2" if you must, but want to leave that undocumented
as it's not a best practice so much.
2012-05-10 01:05:32 -04:00
2166ed8e98 Document sudo -U 2012-05-10 01:04:26 -04:00
f4e01d2b19 notes about EPEL and release cycles 2012-05-10 00:58:27 -04:00
0151ed4508 misc clarifications 2012-05-10 00:46:12 -04:00
1051d8f5ca Update git module docs 2012-05-10 00:42:26 -04:00
7b5f77aba6 Merge pull request #107 from mcodd/executable_inventory_clarification
Clarifications/fixes for executable inventory examples
2012-05-11 15:26:18 -07:00
fc7bb858e4 Clarifications/fixes for executable inventory examples 2012-05-11 17:20:25 -04:00
2d75199d83 Fix doc error about nested groups 2012-05-06 17:16:42 -04:00
e485aec355 Rebuild 2012-05-06 17:14:21 -04:00
f0d9f9652c Document inventory format upgrades in 0.4 2012-05-06 17:13:57 -04:00
7f5c1b8f02 Temporary note about YAML support in 0.4, in case anyone tries it, coming back very very soon! 2012-05-06 15:05:42 -04:00
eadc78549f Rebuild 2012-05-02 00:55:54 -04:00
0dcbffe784 Merge branch 'minor_edits' of https://github.com/johncallender/ansible.github.com
Conflicts:
	rst/modules.rst
2012-05-02 00:55:19 -04:00
2f04126ea8 Merge pull request #94 from wgjohnson/master
Change the 'name' value for Playbook's variable example
2012-05-03 19:12:02 -07:00
77f33a70ba remove old dest entries 2012-05-03 18:01:11 -07:00
b06c4a1618 rewrite file's 'dest' argument
Previously, there were two entries for 'dest'. I've combined them in a
way that makes sense to me.

This will be superfluous when 'path' is made. Ideally, I'd like to see
'path' have the bulk of the definition, and 'dest' to be an alias to
'path'.
2012-05-03 17:47:44 -07:00
8f165e1d3c Revert "ignore eclipse's .project file"
This reverts commit 21550f6586.
2012-05-03 17:04:47 -07:00
21550f6586 ignore eclipse's .project file 2012-05-03 16:55:17 -07:00
dfd671d60e change 'name' to a better description for variable example.
'make a directory' is a bad description, since the command "template …"
doesn't actually create a directory.
2012-05-03 16:54:41 -07:00
5954a7d8cc Merge pull request #88 from sfromm/selinux
Update file documentation for se* options
2012-05-03 15:47:41 -07:00
449c60153c Merge pull request #90 from pas256/patch-1
Add UID to user module documentation
2012-05-03 15:46:59 -07:00
01576f9447 Add UID to user module documentation 2012-05-03 10:47:27 -07:00
2059c5f657 Update file documentation for se* options
Describes how you can use '_default' to seuser, serole, setype, and
selevel to use the default context from the policy, if available.
2012-05-02 12:03:56 -07:00
26c141e96e Issue #84: Doc tweaks for modules, moduledev, and playbooks 2012-05-02 06:53:29 -07:00
b247da54f1 Issue #82: Minor edits to doc text and formatting 2012-05-01 22:35:02 -07:00
1c5f5acadf Rebuild 2012-05-02 00:34:56 -04:00
0c2dd7b057 Clarify include section 2012-05-02 00:34:37 -04:00
16c4802476 Docs rebuild 2012-05-02 00:24:01 -04:00
139a1324e9 Allude to ansible-pull, more docs coming later. 2012-05-02 00:23:47 -04:00
7d228c5198 Add github fork banner to docs project to correct for missing akamai resource. 2012-04-28 11:20:38 -04:00
b388ac721e move stuff back into footer 2012-04-28 10:53:15 -04:00
07d7b7c802 Remove double tweet links 2012-04-28 10:50:55 -04:00
589ae67d95 work on footer 2012-04-28 10:50:20 -04:00
ee20586d28 Attempt to cleanup rendering of social buttons 2012-04-28 10:46:09 -04:00
57c4559a47 Attempt to add +1/like/etc buttons. 2012-04-28 10:42:32 -04:00
d049d425e6 Clarify stderr behavior of modules 2012-04-27 01:39:15 -04:00
aed5414cb6 Add note about variable precedence 2012-04-25 22:48:04 -04:00
d6368ab4fa Update facter/ohai parts to talk about ansible facts in most recent release 2012-04-25 22:46:00 -04:00
eba1340542 Document ansible facts 2012-04-25 22:40:11 -04:00
0165ceb3cc Document how to reference variables about another host from any host. 2012-04-25 22:32:24 -04:00
81773f5635 rebuild 2012-04-25 22:28:38 -04:00
c6a709a954 Add new apt options and replace 'ensure' with 'state' 2012-04-25 22:28:22 -04:00
26fb8eeb99 Update docs to explain how to get Python 2.6 going on EPEL 2012-04-25 22:25:13 -04:00
9177b7f30f rebuild 2012-04-22 20:05:32 -04:00
ab5ea63ae7 Add another item to testimonials section. 2012-04-22 20:05:11 -04:00
e38ea3807c Merge pull request #66 from sfromm/selinux 2012-04-22 16:50:13 -07:00
ab75ff5b39 Add "What People Are Saying" section. Rebuild. 2012-04-22 11:43:03 -04:00
439b218309 Add documentation for context option to file module 2012-04-21 23:51:03 -07:00
666afef0e5 Small edits to packaging section, docs rebuild 2012-04-21 12:12:46 -04:00
7b7108928e Merge pull request #62 from tbielawa/fixYumExample
Fix yum example
2012-04-21 09:09:15 -07:00
3671d046b9 Merge pull request #63 from leucos/master
Adds URL to AUR page
2012-04-21 09:08:56 -07:00
4aac448b06 Adds AUR link for Arch build
Adds URL to AUR ansile page
Adds suggestion to symlink python to python2 since most Arch users have
python3 by default. This suggestion might not be wise, though it doesn't
seem to break anything.
It might be probably wiser to have a patch for the AUR build that takes
care of this.
2012-04-20 21:34:44 +02:00
7b7428a31e Fix yum example 2012-04-20 14:26:45 -04:00
bc0980496c Typo + fix header depth 2012-04-19 10:45:41 -04:00
bbde1bdfa0 Rebuild 2012-04-19 10:15:38 -04:00
6831fb796c Shorten things up. We probably need a better slogan :) 2012-04-19 10:15:20 -04:00
f63d7bcacc Since the first h2 appears as the title (need to fix this) put something up there
that makes some sense.  Should put Ansible first in the html TITLE, need to investigate
Sphinx details
2012-04-19 10:13:45 -04:00
02bd7b74e1 rebuild 2012-04-19 09:57:45 -04:00
806fdf0fbe Clarify update-cache 2012-04-19 09:57:30 -04:00
6c99039a9b Merge pull request #58 from leucos/master
Adds doc for apt modules
2012-04-19 16:38:42 -07:00
de25ec1f29 Fixes typo
Fixes typo in apt/update-cache blurb
2012-04-19 22:27:29 +02:00
25e86ddb7d Adds doc for apt operations
Documents update-cache and puge apt module options
2012-04-19 22:25:12 +02:00
0b9610e845 reinstate 'fork me on github' ribbon 2012-04-19 09:39:50 -04:00
2eba6d71e3 Logo should link to web page index 2012-04-19 09:24:45 -04:00
85647b252d Various doc updates 2012-04-18 23:02:28 -04:00
837061879f rebuild 2012-04-18 21:22:02 -04:00
a510bdc469 Update fetch docs 2012-04-18 21:21:49 -04:00
da97024419 Explain template dep further 2012-04-17 21:02:19 -04:00
7c43ca4fb1 Make note about jinja2 dependency going away 2012-04-17 20:57:01 -04:00
cd5fe8a467 update FAQ 2012-04-17 20:54:01 -04:00
0ab8d9e193 Logo on every page. 2012-04-17 20:47:29 -04:00
6c547e5f0f Logo update 2012-04-17 20:42:46 -04:00
4c6c953992 Docs rebuild 2012-04-17 20:36:22 -04:00
9d7668207e Merge pull request #53 from sfromm/selinux
Describe selinux functionality in file module
2012-04-17 17:34:44 -07:00
b9b0cd775b Describe selinux functionality in file module 2012-04-17 17:08:17 -07:00
4f95dacee1 Document with_items 2012-04-17 20:04:24 -04:00
85f0ff2572 Remove legacy port usage, now belongs in inventory file 2012-04-17 20:00:41 -04:00
b733b43e00 Rebuild 2012-04-17 19:59:53 -04:00
1caca11647 Rebuild + port docs 2012-04-17 19:59:41 -04:00
bdeff18675 Merge pull request #52 from dagwieers/master
Fix small typo
2012-04-17 16:56:59 -07:00
48d3881d17 Document YAML inventory + eBuilds 2012-04-17 19:54:23 -04:00
4dec1d172b Fix small typo 2012-04-17 15:06:12 +02:00
b30aadcf0b Undocument --extra-vars 2012-04-16 23:07:59 -04:00
3f82b9b889 Docs rebuild 2012-04-16 22:36:58 -04:00
8c091b35c5 remove contrib repo 2012-04-16 22:36:41 -04:00
a12ee6f30b Make note about pending port change 2012-04-16 22:18:08 -04:00
55f4824735 Fix inconsistent heading sizes 2012-04-14 11:09:26 -04:00
05b559805b update index 2012-04-14 09:00:16 -04:00
e481c456e0 Fix spelling/text + docs rebuild 2012-04-14 08:56:17 -04:00
adbf3590c5 Add info about sudo. 2012-04-14 08:45:27 -04:00
2850b8d921 Add sudo password info. 2012-04-14 08:42:24 -04:00
7c1b25e49b Add some security notes 2012-04-14 08:41:10 -04:00
e030d0854c Docs rebuild 2012-04-12 22:47:15 -04:00
449725a214 Document local playbook usage. 2012-04-12 22:44:04 -04:00
ecfb22c8d8 Add info about contrib repo to docs 2012-04-12 22:33:21 -04:00
39e052acbb update virt docs 2012-04-12 22:31:43 -04:00
daed69a4b1 Stub reference to SELinux. 2012-04-12 22:30:43 -04:00
da00799c56 Document the fetch module. 2012-04-12 22:29:49 -04:00
ace0d5ade4 Merge pull request #46 from makuk66/master
some doc fixes
2012-04-12 19:24:33 -07:00
06fce9a0b3 update requirements 2012-04-12 22:23:16 -04:00
e5baf5a926 Docs rebuild 2012-04-12 21:38:47 -04:00
2b1a7dacc9 Pulling manpage references out of index so we don't have to maintain them in two places -- docs are more explanatory anyway 2012-04-12 21:34:25 -04:00
f05a84ad42 cat -> echo 2012-04-12 21:33:54 -04:00
6497570967 doc fixes 2012-04-12 23:20:52 +01:00
bef07194c0 Update docs 2012-04-06 11:41:18 -04:00
1171da6fcd Update examples page to mention group capabilities aren't all that are listed on the examples page 2012-04-04 20:33:00 -04:00
9a0e2e338c Docs build 2012-04-04 20:31:04 -04:00
c7f799675d Fix example typo + misc text 2012-04-04 20:30:41 -04:00
4d4b10309d Merge pull request #41 from mgwilliams/file-module-symlinks
docs for file module -- symbolic links
2012-04-04 17:27:27 -07:00
6a1c0ca718 Document playbook command for --extra-vars 2012-04-02 21:07:33 -04:00
fbc48a0d23 Document vars_prompt in playbooks 2012-04-02 21:03:46 -04:00
04196e20a8 docs for file module -- symbolic links 2012-04-01 17:03:13 -07:00
59d2f57d64 Add favicon to pages 2012-03-31 22:44:02 -04:00
402e3b8934 Add favicon 2012-03-31 22:32:31 -04:00
94d8ea5ee9 Add speakerdeck link. 2012-03-31 22:31:42 -04:00
a879278713 Update module docs to include new user/group control features, fix formatting on playbooks page. 2012-03-31 12:08:28 -04:00
8d92efa9fc image tweaks 2012-03-31 10:48:37 -04:00
f7a3b6a537 Update image width 2012-03-31 10:46:34 -04:00
a7c532e3f9 update architecture diagram, minor format changes 2012-03-31 10:43:34 -04:00
337de79cf4 Add sudo/port info to examples, and sudo info to playbooks. 2012-03-30 22:10:32 -04:00
f316c1b131 Docs build. 2012-03-30 22:05:45 -04:00
d17cb6a910 only_if actually works in playbooks for handler tasks, remove the note that says otherwise 2012-03-30 22:05:15 -04:00
1a5aa89be8 Attempt to explain reason for project more on the home page. 2012-03-26 23:38:52 -04:00
ace55c6160 Update user module docs 2012-03-26 23:06:14 -04:00
d7b11e4a10 Allude to apt on the examples page. 2012-03-26 21:41:50 -04:00
1f565c3d76 add documentation stub for apt, and fix agreement issues caused by Tim's doc ref link fixup. 2012-03-26 19:48:32 -04:00
d584cdf501 Merge pull request #38 from tbielawa/littlefixes
little fixes here and there (docs, makefile)
2012-03-24 13:47:36 -07:00
ef632db9f3 Fix cross-document references to 'playbooks' in the modules source.
Update manpages from ansible repo to show when options require args.

Update clean target Makefile so 'rm' doesn't print a useless error
when files aren't found while cleaning.
2012-03-23 22:38:29 -04:00
5a9fe3ac62 Update shell terminal example to reflect need to single quote shell variables. 2012-03-23 21:13:51 -04:00
5327f52c3c Remove some note callouts on the example page and inline the commentary so it's easier to read. 2012-03-22 01:14:26 -04:00
87ab7d76af Document the user module 2012-03-22 01:01:02 -04:00
315a6358b4 Mention variable for context 2012-03-21 21:02:17 -04:00
9951888af3 Docs build 2012-03-21 20:43:51 -04:00
96357407e0 Make chat a web link. 2012-03-21 20:42:31 -04:00
ee2622ee7c Show how to save conditional predicates in vars sections, which makes only_if cleaner. 2012-03-21 20:35:06 -04:00
7136ef756d Fix formatting error 2012-03-20 21:12:35 -04:00
0a20e65f92 Add subscribe link to main page 2012-03-20 21:04:47 -04:00
a045630c02 Add docs on only_if 2012-03-20 20:15:53 -04:00
a98e0a8cc4 quoting 2012-03-19 23:56:35 -04:00
6b8f5224b8 Added docs on conditional import usage 2012-03-19 23:43:03 -04:00
860fe50048 Fix grammatical error. 2012-03-18 20:41:38 -04:00
57dec507f0 List less alternative apps 2012-03-18 13:17:25 -04:00
29293ba51d Rename 'design goals' to 'features' 2012-03-18 13:08:45 -04:00
cd06703fa2 Clarify some things on index page 2012-03-18 13:03:45 -04:00
00bf6f1ebf Mention other distributions. 2012-03-18 12:55:18 -04:00
f29db92052 more complete from checkout docs 2012-03-18 12:45:23 -04:00
3f75fd575c Show how easy it is to run from checkout. 2012-03-18 12:41:00 -04:00
c81aed412a Fix rst syntax errors 2012-03-17 17:16:31 -04:00
bedde394fc Tell folks about packaged releases, but encourage usage of git. 2012-03-17 17:00:41 -04:00
e12e724a42 Fix error on examples page 2012-03-31 11:19:35 -04:00
12c3e04023 Fix reference 2012-03-31 10:51:48 -04:00
f535335fe0 Add shell module to examples page. 2012-03-31 10:50:47 -04:00
15acaec687 Crossref playbooks from async poll section 2012-03-31 10:41:29 -04:00
f708b75d41 Fix formatting 2012-03-31 10:40:01 -04:00
1a926c69a1 Added some foreshadowing of CLI syntax to the patterns page. 2012-03-31 10:38:24 -04:00
7a8397d60f link module dev guide from modules page 2012-03-31 10:21:28 -04:00
bbc2aca10f Make additional reference to playbooks examples dir 2012-03-31 10:17:35 -04:00
a4c23463fb Add IRC and google groups links to each page 2012-03-31 09:55:37 -04:00
31c353543c Reinstate page nav, various TOC structure cleanup 2012-03-31 09:36:37 -04:00
3a1bbac3a7 Move see also blocks to bottom of each page to include reading docs, remove 'fork me' to avoid text overlap,
simply menu nav so folks find the chapter link.
2012-03-31 09:29:31 -04:00
39d02eeff4 Add external inventory script info (and Cobbler example) to API page. 2012-03-30 22:28:30 -04:00
d78817c426 Add file features to examples. 2012-03-15 22:57:10 -04:00
0674c31dbc Added documentation on the 'file' module and how 'copy' and 'template' can also use the options that 'file'
provides.
2012-03-15 22:47:21 -04:00
e0bc949219 Fix doc indent level 2012-03-14 23:45:02 -04:00
ea8770ad54 Fix pathing in example 2012-03-14 13:13:32 -04:00
0427ec8ad6 Add missing file 2012-03-14 12:53:17 -04:00
d9c626e686 Added start of a module development guide, prob needs some editing and maybe some simpler examples 2012-03-14 12:50:40 -04:00
505d3942b0 Added documentation on the 'shell' module, which is a virtual module and isn't really in the library folder.
Docs build.
2012-03-14 20:57:35 -04:00
38e8771785 update docs, fix playbook page formatting 2012-03-13 21:55:55 -04:00
496686629a Slight tweaks to playbook docs + docs rebuild 2012-03-13 20:32:55 -04:00
8484fe3147 Clarify YAML doesn't always use a list as external variables files are hashes. 2012-03-12 23:18:54 -04:00
0b94d3d3f8 replace 'foo' with a more meaningful example + 1 other typo 2012-03-12 23:17:59 -04:00
37adadcc50 Updating docs, added extensive info on playbook async + external vars_files for keeping variables outside of
the playbook file.
2012-03-12 23:12:21 -04:00
cf4ac3b6b2 Add yum latest to docs and examples 2012-03-12 19:23:58 -04:00
3f834cfe3e Docs rebuild, removing submodule because it was causing build problems and I don't quite grok them :) 2012-03-12 19:13:19 -04:00
884d8af759 Attempt to force docs rebuild? Please? 2012-03-11 23:28:04 -04:00
4a184b57c8 Docs build 2012-03-11 23:20:55 -04:00
d5c239404b Update .gitignore 2012-03-11 04:23:00 -04:00
e5386b82c6 Put index.html back in git, problem with staleness was related to .buildinfo, not git. 2012-03-11 04:21:53 -04:00
e3adca1431 Makefile needs to clean things up 2012-03-11 04:21:19 -04:00
f7ff5d1055 Doc build 2012-03-11 21:53:13 -04:00
4cc8fe7561 Split paragraph 2012-03-11 21:53:00 -04:00
91d8d0e502 update faq 2012-03-11 21:47:57 -04:00
e726b9796d Fix some example command line options, add some more links to home page. 2012-03-11 21:46:05 -04:00
817cac7954 Add missing "-a" to examples page 2012-03-11 21:20:30 -04:00
0bccec9fb5 Add polling info to docs 2012-03-11 21:09:21 -04:00
d3fe5f617a Rename 'yamlscripts' to 'yamlsyntax', add some extra crosslinking to make sure folks find the
interesting docs pages, some misc editing here and there.
2012-03-11 15:34:21 -04:00
02549869b1 Attempt to force update 2012-03-11 15:04:08 -04:00
0404acfcc2 Move all html content on the website to build top level such that we do not need the redirect. 2012-03-10 22:34:53 -05:00
0035181c59 Remove URL target for clicking on arch diagram, add width/height so it loads
nicer.
2012-03-10 19:57:24 -05:00
667aa81bee Add arch diagram to website + docs build 2012-03-10 19:48:53 -05:00
a13def0fbe Add yum module to examples + playbook examples 2012-03-10 11:40:49 -05:00
8bf7e79ee3 Add yum to examples 2012-03-10 11:35:36 -05:00
d397c13d9c Added "Fork Me On Github" 2012-03-10 10:39:34 -05:00
557f4d382b add links 2012-03-09 22:58:17 -05:00
ff64996542 doc build 2012-03-09 22:49:40 -05:00
88140938cb Fix heading 2012-03-09 22:49:30 -05:00
4ecad80725 Add google stats 2012-03-09 22:31:54 -05:00
10d197d77f Add missing files 2012-03-09 22:14:31 -05:00
a631c21e5a Add ansible-playbook(1) manpage. 2012-03-09 22:11:41 -05:00
8e7ae6cf69 Minor reordering and linking some things up. 2012-03-09 21:50:00 -05:00
37864337eb Added FAQ page (limited space in menu, so trimmed some topics on lesser used bits) + docs build 2012-03-09 21:41:18 -05:00
e575c0639f Added one last image to header + docs rebuild 2012-03-09 19:13:34 -05:00
1346fd02c9 Added stub yum docs + docs rebuild 2012-03-09 19:04:40 -05:00
ef5e326215 Docs build 2012-03-09 18:51:06 -05:00
fae963a6d2 Docs build + attempt to add image to website 2012-03-09 18:29:01 -05:00
2fb25f1fe8 Merge pull request #9 from tbielawa/master
Spellcheck. Formatting. References.
2012-03-09 15:05:22 -08:00
a1010e5405 Spellcheck. Formatting. References. 2012-03-09 14:39:29 -05:00
e67e446950 Merge pull request #8 from tbielawa/master
Bootstrap
2012-03-09 08:51:46 -08:00
8bd523fe36 More bootstrap tweaks 2012-03-09 11:50:07 -05:00
f25b39b7ce Switch to the 'Sphinx Bootstrap' Theme:
https://github.com/ryan-roemer/sphinx-bootstrap-theme

Fix some rst related formatting.
2012-03-09 11:44:14 -05:00
26800d5db8 Merge branch 'master' of https://github.com/ansible/ansible.github.com 2012-03-09 11:12:34 -05:00
f3a0eb4b23 Docs build 2012-03-09 07:43:06 -05:00
e8eb7ab5ed Update docs 2012-03-09 07:42:53 -05:00
fe2d1c7cc9 Docs rebuild 2012-03-08 23:06:07 -05:00
7a4df9e2fc RST reformatting a few things 2012-03-08 23:05:52 -05:00
358859d2f3 Docs rebuild 2012-03-08 22:52:16 -05:00
bc62feb583 Don't say script 2012-03-08 22:52:02 -05:00
2c6dd03229 docs rebuild 2012-03-08 22:50:12 -05:00
1952bd0aa3 add some docs 2012-03-08 22:50:00 -05:00
cdfb64ce59 Updating ref of the ansible submodule 2012-03-08 16:33:18 -05:00
d89ee675fc Oh I have to commit these too 2012-03-08 14:07:13 -05:00
2cafb8d221 Minor docs restructuring 2012-03-08 13:53:48 -05:00
12fd193450 Docs updates 2012-03-08 13:36:47 -05:00
89a00e6385 Merge pull request #2 from tbielawa/master
No more jekyll
2012-03-08 16:39:02 -08:00
6fe8e4d348 Unjekyllify these pages. 2012-03-07 13:48:56 -05:00
26d1c8c4be Merge pull request #1 from tbielawa/master
These docs are better
2012-03-07 10:11:57 -08:00
5738f8724a Polish up more. Refactor build-site.py and Makefile. 2012-03-07 13:08:31 -05:00
baf2a05708 Polish the docs up some more. Also make 'index.html' forward to the actual html output 2012-03-07 12:41:53 -05:00
5e453555e3 Let me upgrade your docs 2012-03-07 11:35:18 -05:00
7e0ff815b9 Do I have to change something here to trigger a rebuild? 2012-03-06 19:00:52 -05:00
eadd5644b0 Fix project name from where I copied it from :) 2012-03-06 18:59:33 -05:00
bd4bda95d0 Check in files. 2012-03-06 18:58:23 -05:00
2e75c21e4b first commit 2012-03-06 18:55:16 -05:00
183 changed files with 18282 additions and 739 deletions

20
.gitignore vendored
View File

@ -1,12 +1,30 @@
# build products...
*.py[co]
build
# Emacs backup files...
*~
.\#*
# (s)rpm building stuff
# RPM stuff...
MANIFEST
dist
rpm-build
# Eclipse/PyDev stuff...
.project
.pydevproject
# PyCharm stuff...
.idea
# Mac OS X stuff...
.DS_Store
# manpage build stuff...
docs/man/man3/*
# Sublime stuff
*.sublime-project
*.sublime-workspace
# docsite stuff...
docsite/rst/modules
docsite/*.html
docsite/_static/*.gif
docsite/_static/*.png
docsite/_static/websupport.js
# deb building stuff...
debian/

View File

@ -1,7 +1,104 @@
Ansible Changes By Release
==========================
0.7 "Panama" -- release pending -- I can barely see the roadmap from the heat coming off of it.
0.8 "Cathedral" -- Oct 19, 2012
Highlighted Core Changes:
* fireball mode -- ansible can bootstrap a ephemeral 0mq (zeromq) daemon that runs as a given user and expires after X period of time. It is very fast.
* playbooks with errors now return 2 on failure. 1 indicates a more fatal syntax error. Similar for /usr/bin/ansible
* server side action code (template, etc) are now fully pluggable
* ability to write lookup plugins, like the code powering "with_fileglob" (see below)
Other Core Changes:
* ansible config file can also go in '.ansible.cfg' in cwd in addition to ~/.ansible.cfg and /etc/ansible/ansible.cfg
* fix for inventory hosts at API level when hosts spec is a list and not a colon delimited string
* ansible-pull example now sets up logrotate for the ansible-pull cron job log
* negative host matching (!hosts) fixed for external inventory script usage
* internals: os.executable check replaced with utils function so it plays nice on AIX
* Debian packaging now includes ansible-pull manpage
* magic variable 'ansible_ssh_host' can override the hostname (great for usage with tunnels)
* date command usage in build scripts fixed for OS X
* don't use SSH agent with paramiko if a password is specified
* make output be cleaner on multi-line command/shell errors
* /usr/bin/ansible now prints things when tasks are skipped, like when creates= is used with -m command and /usr/bin/ansible
* when trying to async a module that is not a 'normal' asyncable module, ansible will now let you know
* ability to access inventory variables via 'hostvars' for hosts not yet included in any play, using on demand lookups
* merged ansible-plugins, ansible-resources, and ansible-docs into the main project
* you can set ANSIBLE_NOCOWS=1 if you want to disable cowsay if it is installed. Though no one should ever want to do this! Cows are great!
* you can set ANSIBLE_FORCECOLOR=1 to force color mode even when running without a TTY
* fatal errors are now properly colored red.
* skipped messages are now cyan, to differentiate them from unchanged messages.
* extensive documentation upgrades
* delegate_action to localhost (aka local_action) will always use the local connection type
Highlighted playbook changes:
* is_set is available for use inside of an only_if expression: is_set('ansible_eth0'). We intend to further upgrade this with a 'when'
keyword providing better options to 'only_if' in the next release. Also is_unset('ansible_eth0')
* playbooks can import playbooks in other directories and then be able to import tasks relative to them
* FILE($path) now allows access of contents of file in a path, very good for use with SSH keys
* similarly PIPE($command) will run a local command and return the results of executing this command
* if all hosts in a play fail, stop the playbook, rather than letting the console log spool on by
* only_if using register variables that are booleans now works in a boolean way like you'd expect
* task includes now work with with_items (such as: include: path/to/wordpress.yml user=$item)
* when using a $list variable with $var or ${var} syntax it will automatically join with commas
* setup is not run more than once when we know it is has already been run in a play that included another play, etc
* can set/override sudo and sudo_user on individual tasks in a play, defaults to what is set in the play if not present
* ability to use with_fileglob to iterate over local file patterns
* templates now use Jinja2's 'trim_blocks=True' to avoid stray newlines, small changes to templates may
be required in rare cases.
Other playbook changes:
* to_yaml and from_yaml are available as Jinja2 filters
* $group and $group_names are now accessible in with_items
* where 'stdout' is provided a new 'stdout_lines' variable (type == list) is now generated and usable with with_items
* when local_action is used the transport is automatically overridden to the local type
* output on failed playbook commands is now nicely split for stderr/stdout and syntax errors
* if local_action is not used and delegate_to was 127.0.0.1 or localhost, use local connection regardless
* when running a playbook, and the statement has changed, prints 'changed:' now versus 'ok:' so it is obvious without colored mode
* variables now usable within vars_prompt (just not host/group vars)
* setup facts are now retained across plays (dictionary just gets updated as needed)
* --sudo-user now works with --extra-vars
* fix for multi_line strings with only_if
New Modules:
* ini_file module for manipulating INI files
* new LSB facts (release, distro, etc)
* pause module -- (pause seconds=10) (pause minutes=1) (pause prompt=foo) -- it's an action plugin
* a module for adding entries to the main crontab (though you may still wish to just drop template files into cron.d)
* debug module can be used for outputing messages without using 'shell echo'
* a fail module is now available for causing errors, you might want to use it with only_if to fail in certain conditions
Other module Changes, Upgrades, and Fixes:
* removes= exists on command just like creates=
* postgresql modules now take an optional port= parameter
* /proc/cmdline info is now available in Linux facts
* public host key detection for OS X
* lineinfile module now uses 'search' not exact 'match' in regexes, making it much more intuitive and not needing regex syntax most of the time
* added force=yes|no (default no) option for file module, which allows transition between files to directories and so on
* additional facts for SunOS virtualization
* copy module is now atomic when used across volumes
* url_get module now returns 'dest' with the location of the file saved
* fix for yum module when using local RPMs vs downloading
* cleaner error messages with copy if destination directory does not exist
* setup module now still works if PATH is not set
* service module status now correct for services with 'subsys locked' status
* misc fixes/upgrades to the wait_for module
* git module now expands any "~" in provided destination paths
* ignore stop error code failure for service module with state=restarted, always try to start
* inline documentation for modules allows documentation source to built without pull requests to the ansible-docs project, among other things
* variable '$ansible_managed' is now great to include at the top of your templates and includes useful information and a warning that it will be replaced
* "~" now expanded in command module when using creates/removes
* mysql module can do dumps and imports
* selinux policy is only required if setting to not disabled
* various fixes for yum module when working with packages not in any present repo
0.7 "Panama" -- Sept 6 2012
Module changes:

59
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,59 @@
Contributing to Ansible
=======================
It is required that you read the following information to learn how to contribute to this project.
Branch Info
===========
Here's how to understand the branches.
* The devel branch corresponds to the latest ongoing release
* Various release-X.Y branches exist for previous releases
* All feature work happens on the development branch.
* Major bug fixes will be made to the last release branch only
* See CHANGELOG.md for release notes to track each release.
Patch Instructions
==================
Contributions to the core and modules are greatly welcome.
* Required Process:
* Submit github pull requests to the "ansible/devel" branch for features
* Fixes for bugs may also be submitted to "ansible/release-X.Y" for the last release
* Make sure "make tests" passes before submitting any requests.
* Bonus points:
* Joining the mailing list
* Fixing bugs instead of sending bug reports.
* Using squash merges
* Updating the "rst/*" files in the "docsite/" directory and "docs/" manpage content
* Adding more unit tests
* Avoid:
* Sending patches to the mailing list directly.
* Sending feature pull requests to the 'release' branch instead of the devel branch
* Sending pull requests to mpdehaan's personal ansible fork.
* Sending pull requests about more than one feature in the same pull request.
* Whitespace restructuring
* Large scale refactoring without a discussion on the list
Coding Standards
================
We're not too strict on style considerations, but we require:
* python 2.6 compliant code, unless in ansible modules, then python *2.4* compliant code (no 'with', etc)
* 4-space indents, no tabs except in Makefiles
* under_scores for method names and variables, not camelCase
* GPLv3 license headers on all files, with copyright on new files with your name on it
* no single-line if statements, deeply nested list comprehensions, or clever use of metaclasses -- keep it simple
* comments where appropriate
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, persusant to the license of the project.

View File

@ -9,7 +9,7 @@
# make deb ------------------ produce a DEB
# make docs ----------------- rebuild the manpages (results are checked in)
# make tests ---------------- run the tests
# make pyflakes, make pep8 -- source code checks
# make pyflakes, make pep8 -- source code checks
########################################################
# variable section
@ -37,7 +37,11 @@ endif
ifeq ($(OS), FreeBSD)
DATE := $(shell date -j -f "%Y-%m-%d %H:%M:%s" "$(GIT_DATE)" +%Y%m%d%H%M)
else
DATE := $(shell date --date="$(GIT_DATE)" +%Y%m%d%H%M)
ifeq ($(OS), Darwin)
DATE := $(shell date -j -f "%Y-%m-%d %H:%M:%S" "$(GIT_DATE)" +%Y%m%d%H%M)
else
DATE := $(shell date --utc --date="$(GIT_DATE)" +%Y%m%d%H%M)
endif
endif
# RPM build parameters
@ -54,11 +58,11 @@ RPMNVR = "$(NAME)-$(VERSION)-$(RPMRELEASE)$(RPMDIST)"
all: clean python
tests:
PYTHONPATH=./lib nosetests -v
tests:
PYTHONPATH=./lib nosetests -d -v
# To force a rebuild of the docs run 'touch VERSION && make docs'
docs: $(MANPAGES)
docs: $(MANPAGES) modulepages
# Regenerate %.1.asciidoc if %.1.asciidoc.in has been modified more
# recently than %.1.asciidoc.
@ -92,9 +96,10 @@ clean:
@echo "Cleaning up editor backup files"
find . -type f \( -name "*~" -or -name "#*" \) -delete
find . -type f \( -name "*.swp" \) -delete
@echo "Cleaning up asciidoc to man transformations and results"
@echo "Cleaning up manpage stuff"
find ./docs/man -type f -name "*.xml" -delete
find ./docs/man -type f -name "*.asciidoc" -delete
find ./docs/man/man3 -type f -name "*.3" -delete
@echo "Cleaning up output from test runs"
rm -rf test/test_data
@echo "Cleaning up RPM building stuff"
@ -102,6 +107,8 @@ clean:
@echo "Cleaning up Debian building stuff"
rm -rf debian
rm -rf deb-build
rm -rf docs/json
rm -rf docs/js
python:
python setup.py build
@ -109,7 +116,7 @@ python:
install:
python setup.py install
sdist: clean
sdist: clean docs
python setup.py sdist -t MANIFEST.in
rpmcommon: sdist
@ -156,3 +163,20 @@ deb: debian
# for arch or gentoo, read instructions in the appropriate 'packaging' subdirectory directory
modulepages:
hacking/module_formatter.py -A $(VERSION) -t man -o docs/man/man3/ --module-dir=library --template-dir=hacking/templates
modulejson:
mkdir -p docs/json
hacking/module_formatter.py -A $(VERSION) -t json -o docs/json --module-dir=library --template-dir=hacking/templates
modulejs:
mkdir -p docs/js
make modulejson
hacking/module_formatter.py -A $(VERSION) -t js -o docs/js --module-dir=docs/json --template-dir=hacking/templates
# because this requires Sphinx it is not run as part of every build, those building the RPM and so on can ignore this
webdocs:
(cd docsite; make docs)

View File

@ -4,7 +4,7 @@ Ansible
Ansible is a radically simple configuration-management, deployment, task-execution, and
multinode orchestration framework.
Read the documentation at http://ansible.github.com
Read the documentation and more at http://ansible.cc
Design Principles
=================
@ -28,32 +28,9 @@ Branch Info
===========
* Releases are named after Van Halen songs.
* The devel branch corresponds to release 0.7, "Panama".
* The devel branch corresponds to the release actively under development.
* Various release-X.Y branches exist for previous releases
* All feature work happens on the development branch.
* Major bug fixes will be made to the last release branch only
* See CHANGELOG.md for release notes to track each release.
Patch Instructions
==================
Contributions to the core and modules are greatly welcome.
* Required Process:
* Submit github pull requests to the "ansible/devel" branch for features
* Fixes for bugs may also be submitted to "ansible/release-X.Y" for the last release
* Make sure "make tests" passes before submitting any requests.
* Bonus points:
* Joining the mailing list
* Fixing bugs instead of sending bug reports.
* Using squash merges
* Updating the "rst/*" files in the docs project and "docs/" manpage content
* Adding more unit tests
* Avoid:
* Sending patches to the mailing list directly.
* Sending feature pull requests to the 'release' branch instead of the devel branch
* Sending pull requests to mpdehaan's personal ansible fork.
* We'd love to have your contributions, read "CONTRIBUTING.md" for process notes.
Author
======

View File

@ -1,7 +1,8 @@
Ansible Releases at a Glance
============================
0.7 "Panama" ---------- X-XX-2012
0.8 "Cathedral" ------- pending
0.7 "Panama" ---------- 9-06-2012
0.6 "Cabo" ------------ 8-06-2012
0.5 "Amsterdam" ------- 7-04-2012
0.4 "Unchained" ------- 5-23-2012

View File

@ -1 +1 @@
0.7
0.8

View File

@ -127,6 +127,11 @@ if __name__ == '__main__':
(options, args) = cli.parse()
try:
(runner, results) = cli.run(options, args)
for result in results['contacted'].values():
if 'failed' in result or result.get('rc', 0) != 0:
sys.exit(2)
if results['dark']:
sys.exit(2)
except errors.AnsibleError, e:
# Generic handler for ansible specific errors
print "ERROR: %s" % str(e)

View File

@ -59,6 +59,8 @@ def main(args):
help="only run plays and tasks tagged with these values")
parser.add_option('--list-hosts', dest='listhosts', action='store_true',
help="dump out a list of hosts, each play will run against, does not run playbook!")
parser.add_option('--syntax-check', dest='syntax', action='store_true',
help="do a playbook syntax check on the playbook, do not execute the playbook")
options, args = parser.parse_args(args)
@ -121,10 +123,17 @@ def main(args):
print ' %s' % host
print '\n'
return 0
if options.syntax:
# if we've not exited by now then we are fine.
print 'Playbook Syntax is fine'
return 0
try:
pb.run()
hosts = sorted(pb.stats.processed.keys())
print callbacks.banner("PLAY RECAP")
playbook_cb.on_stats(pb.stats)
@ -138,6 +147,10 @@ def main(args):
colorize('failed', t['failures'], 'red'))
print "\n"
for h in hosts:
stats = pb.stats.summarize(h)
if stats['failures'] != 0 or stats['unreachable'] != 0:
return 2
except errors.AnsibleError, e:
print >>sys.stderr, "ERROR: %s" % e

View File

@ -1,15 +1,5 @@
#!/usr/bin/env python
# ansible-pull is a script that runs ansible in local mode
# after checking out a playbooks directory from git. There is an
# example playbook to bootstrap this script in the examples/ dir which
# installs ansible and sets it up to run on cron.
#
# usage:
# ansible-pull -d /var/ansible/local -U http://wherever/content.git -C production
#
# the git repo must contain a playbook named 'local.yml'
# (c) 2012, Stephen Fromm <sfromm@gmail.com>
#
# Ansible is free software: you can redistribute it and/or modify
@ -24,47 +14,130 @@
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# ansible-pull is a script that runs ansible in local mode
# after checking out a playbooks directory from git. There is an
# example playbook to bootstrap this script in the examples/ dir which
# installs ansible and sets it up to run on cron.
# usage:
# ansible-pull -d /var/lib/ansible \
# -U http://example.net/content.git [-C production] \
# [path/playbook.yml]
#
# the -d and -U arguments are required; the -C argument is optional.
#
# ansible-pull accepts an optional argument to specify a playbook
# location underneath the workdir and then searches the git repo
# for playbooks in the following order, stopping at the first match:
#
# 1. $workdir/path/playbook.yml, if specified
# 2. $workdir/$hostname.yml
# 3. $workdir/local.yml
#
# the git repo must contain at least one of these playbooks.
import os
import shutil
import subprocess
import sys
import datetime
import socket
from optparse import OptionParser
DEFAULT_PLAYBOOK = 'local.yml'
PLAYBOOK_ERRORS = { 1: 'File does not exist',
2: 'File is not readable' }
def _run(cmd):
print >>sys.stderr, "Running: '%s'" % cmd
cmd = subprocess.Popen(cmd, shell=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = cmd.communicate()
print out
if cmd.returncode != 0:
print err
print >>sys.stderr, err
return cmd.returncode
def try_playbook(path):
if not os.path.exists(path):
return 1
if not os.access(path, os.R_OK):
return 2
return 0
def select_playbook(path, args):
playbook = None
if len(args) > 0 and args[0] is not None:
playbook = "%s/%s" % (path, args[0])
rc = try_playbook(playbook)
if rc != 0:
print >>sys.stderr, "%s: %s" % (playbook, PLAYBOOK_ERRORS[rc])
return None
return playbook
else:
hostpb = "%s/%s.yml" % (path, socket.getfqdn())
localpb = "%s/%s" % (path, DEFAULT_PLAYBOOK)
errors = []
for pb in [hostpb, localpb]:
rc = try_playbook(pb)
if rc == 0:
playbook = pb
break
else:
errors.append("%s: %s" % (pb, PLAYBOOK_ERRORS[rc]))
if playbook is None:
print >>sys.stderr, "\n".join(errors)
return playbook
def main(args):
""" Set up and run a local playbook """
usage = "%prog [options]"
parser = OptionParser()
usage = "%prog [options] [playbook.yml]"
parser = OptionParser(usage=usage)
parser.add_option('--purge', default=False, action='store_true',
help='Purge git checkout after playbook run')
parser.add_option('-d', '--directory', dest='dest', default=None,
help='Directory to checkout git repository')
parser.add_option('-U', '--url', dest='url',
default=None,
help='Directory to clone git repository to')
parser.add_option('-U', '--url', dest='url', default=None,
help='URL of git repository')
parser.add_option('-C', '--checkout', dest='checkout',
default="HEAD",
help='Branch/Tag/Commit to checkout. Defaults to HEAD.')
options, args = parser.parse_args(args)
if not options.dest:
parser.error("Missing required directory argument")
return 1
if not options.url:
parser.error("URL for git repo not specified, use -h for help")
return 1
now = datetime.datetime.now()
print >>sys.stderr, now.strftime("Starting ansible-pull at %F %T")
git_opts = "repo=%s dest=%s version=%s" % (options.url, options.dest, options.checkout)
cmd = 'ansible all -c local -m git -a "%s"' % git_opts
print "cmd=%s" % cmd
rc = _run(cmd)
if rc != 0:
return rc
playbook = select_playbook(options.dest, args)
if playbook is None:
print >>sys.stderr, "Could not find a playbook to run."
return 1
cmd = 'ansible-playbook -c local %s' % playbook
os.chdir(options.dest)
cmd = 'ansible-playbook -c local %s' % DEFAULT_PLAYBOOK
rc = _run(cmd)
if options.purge:
os.chdir('/')
try:
shutil.rmtree(options.dest)
except Exception, e:
print >>sys.stderr, "Failed to remove %s: %s" % (options.dest, str(e))
return rc
if __name__ == '__main__':

84
contrib/README.md Normal file
View File

@ -0,0 +1,84 @@
Ansible Resources
=================
User contributed playbooks, modules, and articles. This is a small curated list, but growing. Everyone is encouraged to add to this document,
just send in a pull request!
Ansible Modules
===============
Ansible modules are a way of adding new client-side logic to ansible. They can be written in any language.
* [Official "core" ansible modules](http://ansible.cc/docs/modules.html) - various
* [mercurial](https://github.com/bradobro/ansible-module-mercurial) - bradobro
* [zypper (bash module example)](https://github.com/jpmens/ansible-zypp) - jp_mens
* [homebrew](https://gist.github.com/3170079) - swehack
* [network_facts](https://github.com/dagwieers/ansible-network-facts) - dagwieers
* [vsphere_boot](https://github.com/dagwieers/ansible-vsphere-boot) - dagwieers
Python modules using 0.6 and later can use the common "AnsibleModule" class to dramatically reduce
the amount of boilerplate code required. Not all modules above yet take advantage of this feature.
See the official documentation for more details.
Selected Playbooks
==================
[Playbooks](http://ansible.cc/docs/playbooks.html) are Ansible's configuration management language. It should
be easy to write your own from scratch for most applications, but it's always helpful to look at what others have
done for reference.
* [Hadoop](https://github.com/jkleint/ansible-hadoop) - jkleint
* [LAMP](https://github.com/fourkitchens/server-playbooks) - [Four Kitchens](http://fourkitchens.com)
* [Ganglia (demo)](https://github.com/mpdehaan/ansible-examples) - mpdehaan
* [Nginx](http://www.capsunlock.net/2012/04/ansible-nginx-playbook.html) - cocoy
* [OpenStack](http://github.com/lorin/openstack-ansible) - lorin
* [Systems Configuration](https://github.com/cegeddin/ansible-contrib) - cegeddin
* [Fedora Infrastructure](http://infrastructure.fedoraproject.org/cgit/ansible.git/tree/) - [Fedora](http://fedoraproject.org)
Callbacks and Plugins
=====================
The Ansible project has a whole repo devoted to extending ansible with new connection types, logging/event callbacks, and
inventory data storage. Talk to Cobbler and EC2, tweak the way things are logged, or even add sound effects.
* [Ansible-Plugins](https://github.com/ansible/ansible/tree/devel/plugins)
Scripts And Misc
================
Ansible isn't just a program, it's also an API. Here's some examples of some clever integrations with the "Runner" and
also Playbook APIs, and integrations with other interesting pieces of software.
* [Ansible Vagrant plugin](https://github.com/dsander/vagrant-ansible) - dsander
* [Ansible+Vagrant Tutorial](https://github.com/mattupstate/vagrant-ansible-tutorial) - mattupstate -
* [virt-install](http://fedorapeople.org/cgit/skvidal/public_git/scripts.git/tree/ansible/start-prov-boot.py) - skvidal
* [rebooting hosts](http://fedorapeople.org/cgit/skvidal/public_git/scripts.git/tree/ansible/host-reboot) - skvidal
* [uptime (API demo)](https://github.com/ansible/ansible/blob/devel/examples/scripts/uptime.py) - mpdehaan
Blogs & Articles
================
* [HighScalability.com](http://highscalability.com/blog/2012/4/18/ansible-a-simple-model-driven-configuration-management-and-c.html) - mpdehaan
* [ColoAndCloud.com interview](http://www.coloandcloud.com/editorial/an-interview-with-ansible-author-michael-dehaan/) - mpdehaan
* [dzone](http://server.dzone.com/articles/ansible-cm-deployment-and-ad) - Mitch Pronschinske
* [Configuration Management With Ansible](http://jpmens.net/2012/06/06/configuration-management-with-ansible/) - jp_mens
* [Shell Scripts As Ansible Modules](http://jpmens.net/2012/07/05/shell-scripts-as-ansible-modules/) - jp_mens
* [Ansible Facts](http://jpmens.net/2012/07/15/ansible-it-s-a-fact/) - jp_mens
* [Infrastructure as Data](http://www.capsunlock.net/2012/04/ansible-infrastructure-as-data-not-infrastructure-as-code.html) - cocoy
* [Ansible Pull Mode](http://www.capsunlock.net/2012/05/using-ansible-pull-and-user-data-to-setup-ec2-or-openstack-servers.html) - cocoy
* [Exploring Configuration Management With Ansible](http://palominodb.com/blog/2012/08/01/exploring-configuration-management-ansible) - Palamino DB
* [You Should Consider Using SSH Based Configuration Management](http://www.lshift.net/blog/2012/07/30/you-should-consider-using-ssh-based-configuration-management) - LShift Ltd
* [Deploying Flask/uWSGI, Nginx, and Supervisorctl](http://mattupstate.github.com/python/devops/2012/08/07/flask-wsgi-application-deployment-with-ubuntu-ansible-nginx-supervisor-and-uwsgi.html) - mattupstate
* [Infracoders Presentation](http://www.danielhall.me/2012/10/ansible-talk-infra-coders/) - Daniel Hall
Disclaimer
==========
Modules and playbooks here may not be using the latest in Ansible features. When in doubt to the features of
a particular version of Ansbile, always consult [ansible.cc](http://ansible.cc) and in particular
see [Best Practices](http://ansible.cc/docs/bestpractices.html) for some tips and tricks that may be useful.
Ansible is (C) 2012, [Michael DeHaan](http://twitter.com/laserllama) and others and is available under the GPLv3 license. Content here is as specified
by individual contributors.

View File

@ -2,12 +2,12 @@
.\" Title: ansible-playbook
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
.\" Date: 09/06/2012
.\" Date: 10/12/2012
.\" Manual: System administration commands
.\" Source: Ansible 0.7
.\" Source: Ansible 0.8
.\" Language: English
.\"
.TH "ANSIBLE\-PLAYBOOK" "1" "09/06/2012" "Ansible 0\&.7" "System administration commands"
.TH "ANSIBLE\-PLAYBOOK" "1" "10/12/2012" "Ansible 0\&.8" "System administration commands"
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
@ -120,6 +120,15 @@ The following environment variables may specified\&.
ANSIBLE_HOSTS \(em Override the default ansible hosts file
.sp
ANSIBLE_LIBRARY \(em Override the default ansible module library path
.SH "FILES"
.sp
/etc/ansible/hosts \(em Default inventory file
.sp
/usr/share/ansible/ \(em Default module library
.sp
/etc/ansible/ansible\&.conf \(em Config file, used if present
.sp
~/\&.ansible\&.config \(em User config file, overrides the default config if present
.SH "AUTHOR"
.sp
Ansible was originally written by Michael DeHaan\&. See the AUTHORS file for a complete list of contributors\&.

View File

@ -107,6 +107,16 @@ ANSIBLE_HOSTS -- Override the default ansible hosts file
ANSIBLE_LIBRARY -- Override the default ansible module library path
FILES
-----
/etc/ansible/hosts -- Default inventory file
/usr/share/ansible/ -- Default module library
/etc/ansible/ansible.conf -- Config file, used if present
~/.ansible.config -- User config file, overrides the default config if present
AUTHOR
------

View File

@ -1,22 +1,13 @@
'\" t
.\" Title: ansible
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
.\" Date: 08/14/2012
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
.\" Date: 09/06/2012
.\" Manual: System administration commands
.\" Source: Ansible 0.7
.\" Source: Ansible 0.8
.\" Language: English
.\"
.TH "ANSIBLE" "1" "08/14/2012" "Ansible 0\&.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 '
.TH "ANSIBLE" "1" "09/06/2012" "Ansible 0\&.8" "System administration commands"
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
@ -34,7 +25,7 @@ ansible-pull \- set up a remote copy of ansible on each managed node
ansible \-d DEST \-U URL [ \-C CHECKOUT ]
.SH "DESCRIPTION"
.sp
\fBAnsible\fR is an extra\-simple tool/framework/API for doing \*(Aqremote things\*(Aq over SSH\&.
\fBAnsible\fR is an extra\-simple tool/framework/API for doing \'remote things\' over SSH\&.
.sp
Use ansible\-pull to set up a remote copy of ansible on each managed node, each set to run via cron and update playbook source via git\&. This inverts the default \fBpush\fR architecture of ansible into a \fBpull\fR architecture, which has near\-limitless scaling potential\&.
.sp

View File

@ -2,12 +2,12 @@
.\" Title: ansible
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
.\" Date: 09/06/2012
.\" Date: 10/12/2012
.\" Manual: System administration commands
.\" Source: Ansible 0.7
.\" Source: Ansible 0.8
.\" Language: English
.\"
.TH "ANSIBLE" "1" "09/06/2012" "Ansible 0\&.7" "System administration commands"
.TH "ANSIBLE" "1" "10/12/2012" "Ansible 0\&.8" "System administration commands"
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
@ -141,11 +141,6 @@ Sudo to
instead of root\&. Implies \-\-sudo\&.
.RE
.PP
\fB\-\-private\-key=\fR\fIPRIVATE_KEY_FILE\fR
.RS 4
Use this file to authenticate the connection\&.
.RE
.PP
\fB\-c\fR \fICONNECTION\fR, \fB\-\-connection=\fR\fICONNECTION\fR
.RS 4
Connection type to use\&. Possible options are
@ -171,6 +166,10 @@ Ranges of hosts are also supported\&. For more information and additional option
/etc/ansible/hosts \(em Default inventory file
.sp
/usr/share/ansible/ \(em Default module library
.sp
/etc/ansible/ansible\&.conf \(em Config file, used if present
.sp
~/\&.ansible\&.config \(em User config file, overrides the default config if present
.SH "ENVIRONMENT"
.sp
The following environment variables may specified\&.

View File

@ -108,9 +108,6 @@ Use this remote 'USERNAME' instead of root.
Sudo to 'SUDO_USERNAME' instead of root. Implies --sudo.
*--private-key=*'PRIVATE_KEY_FILE'::
Use this file to authenticate the connection.
*-c* 'CONNECTION', *--connection=*'CONNECTION'::
Connection type to use. Possible options are 'paramiko' (SSH), 'ssh',
@ -138,6 +135,9 @@ FILES
/usr/share/ansible/ -- Default module library
/etc/ansible/ansible.conf -- Config file, used if present
~/.ansible.config -- User config file, overrides the default config if present
ENVIRONMENT
-----------

0
docs/man/man3/.gitdir Normal file
View File

13
docsite/.gitignore vendored Normal file
View File

@ -0,0 +1,13 @@
# Old compiled python stuff
*.py[co]
# package building stuff
build
# Emacs backup files...
*~
.\#*
.doctrees
# Generated docs stuff
ansible*.xml
.buildinfo
objects.inv
.doctrees

0
docsite/.nojekyll Normal file
View File

1
docsite/DOCUMENTATION.yaml Symbolic link
View File

@ -0,0 +1 @@
../examples/DOCUMENTATION.yaml

31
docsite/Makefile Normal file
View File

@ -0,0 +1,31 @@
#!/usr/bin/make
SITELIB = $(shell python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")
FORMATTER=../hacking/module_formatter.py
all: clean docs
docs: clean modules
./build-site.py
viewdocs: clean
./build-site.py view
htmldocs:
./build-site.py rst
clean:
-rm -f .buildinfo
-rm -f *.inv
-rm -rf *.doctrees
@echo "Cleaning up byte compiled python stuff"
find . -regex ".*\.py[co]$$" -delete
@echo "Cleaning up editor backup files"
find . -type f \( -name "*~" -or -name "#*" \) -delete
find . -type f \( -name "*.swp" \) -delete
.PHONEY: docs clean
modules: $(FORMATTER) ../hacking/templates/rst.j2
$(FORMATTER) -t rst --template-dir=../hacking/templates --module-dir=../library -o rst/modules/ --includes-file=rst/modules/_list.rst

23
docsite/README.md Normal file
View File

@ -0,0 +1,23 @@
Homepage and documentation source for the Ansible
=================================================
This project hosts the source behind [ansible.cc/docs](http://ansible.cc/docs)
Contributions to the documentation are welcome. To make changes, submit a pull request
that changes the restructured text files in the "rst/" directory only, and Michael can
do a docs build and push the static files.
If you do not want to learn RST format (ReStructured Text), you can also file issues
on the documentation project.
Note that module documentation can actually be generated from a DOCUMENTATION docstring
in the modules directory, so corrections to modules written as much need to be made
in the main project in the module source, rather than in the documentation for the module.
Author
======
Michael DeHaan -- michael.dehaan@gmail.com
[http://michaeldehaan.net](http://michaeldehaan.net/)

540
docsite/_static/basic.css Normal file
View File

@ -0,0 +1,540 @@
/*
* basic.css
* ~~~~~~~~~
*
* Sphinx stylesheet -- basic theme.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/* -- main layout ----------------------------------------------------------- */
div.clearer {
clear: both;
}
/* -- relbar ---------------------------------------------------------------- */
div.related {
width: 100%;
font-size: 90%;
}
div.related h3 {
display: none;
}
div.related ul {
margin: 0;
padding: 0 0 0 10px;
list-style: none;
}
div.related li {
display: inline;
}
div.related li.right {
float: right;
margin-right: 5px;
}
/* -- sidebar --------------------------------------------------------------- */
div.sphinxsidebarwrapper {
padding: 10px 5px 0 10px;
}
div.sphinxsidebar {
float: left;
width: 230px;
margin-left: -100%;
font-size: 90%;
}
div.sphinxsidebar ul {
list-style: none;
}
div.sphinxsidebar ul ul,
div.sphinxsidebar ul.want-points {
margin-left: 20px;
list-style: square;
}
div.sphinxsidebar ul ul {
margin-top: 0;
margin-bottom: 0;
}
div.sphinxsidebar form {
margin-top: 10px;
}
div.sphinxsidebar input {
border: 1px solid #98dbcc;
font-family: sans-serif;
font-size: 1em;
}
div.sphinxsidebar #searchbox input[type="text"] {
width: 170px;
}
div.sphinxsidebar #searchbox input[type="submit"] {
width: 30px;
}
img {
border: 0;
}
/* -- search page ----------------------------------------------------------- */
ul.search {
margin: 10px 0 0 20px;
padding: 0;
}
ul.search li {
padding: 5px 0 5px 20px;
background-image: url(file.png);
background-repeat: no-repeat;
background-position: 0 7px;
}
ul.search li a {
font-weight: bold;
}
ul.search li div.context {
color: #888;
margin: 2px 0 0 30px;
text-align: left;
}
ul.keywordmatches li.goodmatch a {
font-weight: bold;
}
/* -- index page ------------------------------------------------------------ */
table.contentstable {
width: 90%;
}
table.contentstable p.biglink {
line-height: 150%;
}
a.biglink {
font-size: 1.3em;
}
span.linkdescr {
font-style: italic;
padding-top: 5px;
font-size: 90%;
}
/* -- general index --------------------------------------------------------- */
table.indextable {
width: 100%;
}
table.indextable td {
text-align: left;
vertical-align: top;
}
table.indextable dl, table.indextable dd {
margin-top: 0;
margin-bottom: 0;
}
table.indextable tr.pcap {
height: 10px;
}
table.indextable tr.cap {
margin-top: 10px;
background-color: #f2f2f2;
}
img.toggler {
margin-right: 3px;
margin-top: 3px;
cursor: pointer;
}
div.modindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
div.genindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
/* -- general body styles --------------------------------------------------- */
a.headerlink {
visibility: hidden;
}
h1:hover > a.headerlink,
h2:hover > a.headerlink,
h3:hover > a.headerlink,
h4:hover > a.headerlink,
h5:hover > a.headerlink,
h6:hover > a.headerlink,
dt:hover > a.headerlink {
visibility: visible;
}
div.body p.caption {
text-align: inherit;
}
div.body td {
text-align: left;
}
.field-list ul {
padding-left: 1em;
}
.first {
margin-top: 0 !important;
}
p.rubric {
margin-top: 30px;
font-weight: bold;
}
img.align-left, .figure.align-left, object.align-left {
clear: left;
float: left;
margin-right: 1em;
}
img.align-right, .figure.align-right, object.align-right {
clear: right;
float: right;
margin-left: 1em;
}
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
/* -- sidebars -------------------------------------------------------------- */
div.sidebar {
margin: 0 0 0.5em 1em;
border: 1px solid #ddb;
padding: 7px 7px 0 7px;
background-color: #ffe;
width: 40%;
float: right;
}
p.sidebar-title {
font-weight: bold;
}
/* -- topics ---------------------------------------------------------------- */
div.topic {
border: 1px solid #ccc;
padding: 7px 7px 0 7px;
margin: 10px 0 10px 0;
}
p.topic-title {
font-size: 1.1em;
font-weight: bold;
margin-top: 10px;
}
/* -- admonitions ----------------------------------------------------------- */
div.admonition {
margin-top: 10px;
margin-bottom: 10px;
padding: 7px;
}
div.admonition dt {
font-weight: bold;
}
div.admonition dl {
margin-bottom: 0;
}
p.admonition-title {
margin: 0px 10px 5px 0px;
font-weight: bold;
}
div.body p.centered {
text-align: center;
margin-top: 25px;
}
/* -- tables ---------------------------------------------------------------- */
table.docutils {
border: 0;
border-collapse: collapse;
}
table.docutils td, table.docutils th {
padding: 1px 8px 1px 5px;
border-top: 0;
border-left: 0;
border-right: 0;
border-bottom: 1px solid #aaa;
}
table.field-list td, table.field-list th {
border: 0 !important;
}
table.footnote td, table.footnote th {
border: 0 !important;
}
th {
text-align: left;
padding-right: 5px;
}
table.citation {
border-left: solid 1px gray;
margin-left: 1px;
}
table.citation td {
border-bottom: none;
}
/* -- other body styles ----------------------------------------------------- */
ol.arabic {
list-style: decimal;
}
ol.loweralpha {
list-style: lower-alpha;
}
ol.upperalpha {
list-style: upper-alpha;
}
ol.lowerroman {
list-style: lower-roman;
}
ol.upperroman {
list-style: upper-roman;
}
dl {
margin-bottom: 15px;
}
dd p {
margin-top: 0px;
}
dd ul, dd table {
margin-bottom: 10px;
}
dd {
margin-top: 3px;
margin-bottom: 10px;
margin-left: 30px;
}
dt:target, .highlighted {
background-color: #fbe54e;
}
dl.glossary dt {
font-weight: bold;
font-size: 1.1em;
}
.field-list ul {
margin: 0;
padding-left: 1em;
}
.field-list p {
margin: 0;
}
.refcount {
color: #060;
}
.optional {
font-size: 1.3em;
}
.versionmodified {
font-style: italic;
}
.system-message {
background-color: #fda;
padding: 5px;
border: 3px solid red;
}
.footnote:target {
background-color: #ffa;
}
.line-block {
display: block;
margin-top: 1em;
margin-bottom: 1em;
}
.line-block .line-block {
margin-top: 0;
margin-bottom: 0;
margin-left: 1.5em;
}
.guilabel, .menuselection {
font-family: sans-serif;
}
.accelerator {
text-decoration: underline;
}
.classifier {
font-style: oblique;
}
abbr, acronym {
border-bottom: dotted 1px;
cursor: help;
}
/* -- code displays --------------------------------------------------------- */
pre {
overflow: auto;
overflow-y: hidden; /* fixes display issues on Chrome browsers */
}
td.linenos pre {
padding: 5px 0px;
border: 0;
background-color: transparent;
color: #aaa;
}
table.highlighttable {
margin-left: 0.5em;
}
table.highlighttable td {
padding: 0 0.5em 0 0.5em;
}
tt.descname {
background-color: transparent;
font-weight: bold;
font-size: 1.2em;
}
tt.descclassname {
background-color: transparent;
}
tt.xref, a tt {
background-color: transparent;
font-weight: bold;
}
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
background-color: transparent;
}
.viewcode-link {
float: right;
}
.viewcode-back {
float: right;
font-family: sans-serif;
}
div.viewcode-block:target {
margin: -1px -10px;
padding: 0 10px;
}
/* -- math display ---------------------------------------------------------- */
img.math {
vertical-align: middle;
}
div.body div.math p {
text-align: center;
}
span.eqno {
float: right;
}
/* -- printout stylesheet --------------------------------------------------- */
@media print {
div.document,
div.documentwrapper,
div.bodywrapper {
margin: 0 !important;
width: 100%;
}
div.sphinxsidebar,
div.related,
div.footer,
#top-link {
display: none;
}
}

55
docsite/_static/bootstrap-dropdown.js vendored Normal file
View File

@ -0,0 +1,55 @@
/* ============================================================
* bootstrap-dropdown.js v1.4.0
* http://twitter.github.com/bootstrap/javascript.html#dropdown
* ============================================================
* Copyright 2011 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ============================================================ */
!function( $ ){
"use strict"
/* DROPDOWN PLUGIN DEFINITION
* ========================== */
$.fn.dropdown = function ( selector ) {
return this.each(function () {
$(this).delegate(selector || d, 'click', function (e) {
var li = $(this).parent('li')
, isActive = li.hasClass('open')
clearMenus()
!isActive && li.toggleClass('open')
return false
})
})
}
/* APPLY TO STANDARD DROPDOWN ELEMENTS
* =================================== */
var d = 'a.menu, .dropdown-toggle'
function clearMenus() {
$(d).parent('li').removeClass('open')
}
$(function () {
$('html').bind("click", clearMenus)
$('body').dropdown( '[data-dropdown] a.menu, [data-dropdown] .dropdown-toggle' )
})
}( window.jQuery || window.ender );

107
docsite/_static/bootstrap-scrollspy.js vendored Normal file
View File

@ -0,0 +1,107 @@
/* =============================================================
* bootstrap-scrollspy.js v1.4.0
* http://twitter.github.com/bootstrap/javascript.html#scrollspy
* =============================================================
* Copyright 2011 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ============================================================== */
!function ( $ ) {
"use strict"
var $window = $(window)
function ScrollSpy( topbar, selector ) {
var processScroll = $.proxy(this.processScroll, this)
this.$topbar = $(topbar)
this.selector = selector || 'li > a'
this.refresh()
this.$topbar.delegate(this.selector, 'click', processScroll)
$window.scroll(processScroll)
this.processScroll()
}
ScrollSpy.prototype = {
refresh: function () {
this.targets = this.$topbar.find(this.selector).map(function () {
var href = $(this).attr('href')
return /^#\w/.test(href) && $(href).length ? href : null
})
this.offsets = $.map(this.targets, function (id) {
return $(id).offset().top
})
}
, processScroll: function () {
var scrollTop = $window.scrollTop() + 10
, offsets = this.offsets
, targets = this.targets
, activeTarget = this.activeTarget
, i
for (i = offsets.length; i--;) {
activeTarget != targets[i]
&& scrollTop >= offsets[i]
&& (!offsets[i + 1] || scrollTop <= offsets[i + 1])
&& this.activateButton( targets[i] )
}
}
, activateButton: function (target) {
this.activeTarget = target
this.$topbar
.find(this.selector).parent('.active')
.removeClass('active')
this.$topbar
.find(this.selector + '[href="' + target + '"]')
.parent('li')
.addClass('active')
}
}
/* SCROLLSPY PLUGIN DEFINITION
* =========================== */
$.fn.scrollSpy = function( options ) {
var scrollspy = this.data('scrollspy')
if (!scrollspy) {
return this.each(function () {
$(this).data('scrollspy', new ScrollSpy( this, options ))
})
}
if ( options === true ) {
return scrollspy
}
if ( typeof options == 'string' ) {
scrollspy[options]()
}
return this
}
$(document).ready(function () {
$('body').scrollSpy('[data-scrollspy] li > a')
})
}( window.jQuery || window.ender );

15
docsite/_static/bootstrap-sphinx.css vendored Normal file
View File

@ -0,0 +1,15 @@
/*
* bootstrap-sphinx.css
* ~~~~~~~~~~~~~~~~~~~~
*
* Sphinx stylesheet -- Twitter Bootstrap theme.
*/
body {
padding-top: 42px;
}
div.documentwrapper {
float: left;
width: 100%;
}

2467
docsite/_static/bootstrap.css vendored Normal file

File diff suppressed because it is too large Load Diff

256
docsite/_static/default.css Normal file
View File

@ -0,0 +1,256 @@
/*
* default.css_t
* ~~~~~~~~~~~~~
*
* Sphinx stylesheet -- default theme.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
@import url("basic.css");
/* -- page layout ----------------------------------------------------------- */
body {
font-family: sans-serif;
font-size: 100%;
background-color: #11303d;
color: #000;
margin: 0;
padding: 0;
}
div.document {
background-color: #1c4e63;
}
div.documentwrapper {
float: left;
width: 100%;
}
div.bodywrapper {
margin: 0 0 0 230px;
}
div.body {
background-color: #ffffff;
color: #000000;
padding: 0 20px 30px 20px;
}
div.footer {
color: #ffffff;
width: 100%;
padding: 9px 0 9px 0;
text-align: center;
font-size: 75%;
}
div.footer a {
color: #ffffff;
text-decoration: underline;
}
div.related {
background-color: #133f52;
line-height: 30px;
color: #ffffff;
}
div.related a {
color: #ffffff;
}
div.sphinxsidebar {
}
div.sphinxsidebar h3 {
font-family: 'Trebuchet MS', sans-serif;
color: #ffffff;
font-size: 1.4em;
font-weight: normal;
margin: 0;
padding: 0;
}
div.sphinxsidebar h3 a {
color: #ffffff;
}
div.sphinxsidebar h4 {
font-family: 'Trebuchet MS', sans-serif;
color: #ffffff;
font-size: 1.3em;
font-weight: normal;
margin: 5px 0 0 0;
padding: 0;
}
div.sphinxsidebar p {
color: #ffffff;
}
div.sphinxsidebar p.topless {
margin: 5px 10px 10px 10px;
}
div.sphinxsidebar ul {
margin: 10px;
padding: 0;
color: #ffffff;
}
div.sphinxsidebar a {
color: #98dbcc;
}
div.sphinxsidebar input {
border: 1px solid #98dbcc;
font-family: sans-serif;
font-size: 1em;
}
/* -- hyperlink styles ------------------------------------------------------ */
a {
color: #355f7c;
text-decoration: none;
}
a:visited {
color: #355f7c;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
/* -- body styles ----------------------------------------------------------- */
div.body h1,
div.body h2,
div.body h3,
div.body h4,
div.body h5,
div.body h6 {
font-family: 'Trebuchet MS', sans-serif;
background-color: #f2f2f2;
font-weight: normal;
color: #20435c;
border-bottom: 1px solid #ccc;
margin: 20px -20px 10px -20px;
padding: 3px 0 3px 10px;
}
div.body h1 { margin-top: 0; font-size: 200%; }
div.body h2 { font-size: 160%; }
div.body h3 { font-size: 140%; }
div.body h4 { font-size: 120%; }
div.body h5 { font-size: 110%; }
div.body h6 { font-size: 100%; }
a.headerlink {
color: #c60f0f;
font-size: 0.8em;
padding: 0 4px 0 4px;
text-decoration: none;
}
a.headerlink:hover {
background-color: #c60f0f;
color: white;
}
div.body p, div.body dd, div.body li {
text-align: justify;
line-height: 130%;
}
div.admonition p.admonition-title + p {
display: inline;
}
div.admonition p {
margin-bottom: 5px;
}
div.admonition pre {
margin-bottom: 5px;
}
div.admonition ul, div.admonition ol {
margin-bottom: 5px;
}
div.note {
background-color: #eee;
border: 1px solid #ccc;
}
div.seealso {
background-color: #ffc;
border: 1px solid #ff6;
}
div.topic {
background-color: #eee;
}
div.warning {
background-color: #ffe4e4;
border: 1px solid #f66;
}
p.admonition-title {
display: inline;
}
p.admonition-title:after {
content: ":";
}
pre {
padding: 5px;
background-color: #eeffcc;
color: #333333;
line-height: 120%;
border: 1px solid #ac9;
border-left: none;
border-right: none;
}
tt {
background-color: #ecf0f3;
padding: 0 1px 0 1px;
font-size: 0.95em;
}
th {
background-color: #ede;
}
.warning tt {
background: #efc2c2;
}
.note tt {
background: #d6d6d6;
}
.viewcode-back {
font-family: sans-serif;
}
div.viewcode-block:target {
background-color: #f4debf;
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
}

247
docsite/_static/doctools.js Normal file
View File

@ -0,0 +1,247 @@
/*
* doctools.js
* ~~~~~~~~~~~
*
* Sphinx JavaScript utilities for all documentation.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/**
* select a different prefix for underscore
*/
$u = _.noConflict();
/**
* make the code below compatible with browsers without
* an installed firebug like debugger
if (!window.console || !console.firebug) {
var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
"dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
"profile", "profileEnd"];
window.console = {};
for (var i = 0; i < names.length; ++i)
window.console[names[i]] = function() {};
}
*/
/**
* small helper function to urldecode strings
*/
jQuery.urldecode = function(x) {
return decodeURIComponent(x).replace(/\+/g, ' ');
}
/**
* small helper function to urlencode strings
*/
jQuery.urlencode = encodeURIComponent;
/**
* This function returns the parsed url parameters of the
* current request. Multiple values per key are supported,
* it will always return arrays of strings for the value parts.
*/
jQuery.getQueryParameters = function(s) {
if (typeof s == 'undefined')
s = document.location.search;
var parts = s.substr(s.indexOf('?') + 1).split('&');
var result = {};
for (var i = 0; i < parts.length; i++) {
var tmp = parts[i].split('=', 2);
var key = jQuery.urldecode(tmp[0]);
var value = jQuery.urldecode(tmp[1]);
if (key in result)
result[key].push(value);
else
result[key] = [value];
}
return result;
};
/**
* small function to check if an array contains
* a given item.
*/
jQuery.contains = function(arr, item) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] == item)
return true;
}
return false;
};
/**
* highlight a given string on a jquery object by wrapping it in
* span elements with the given class name.
*/
jQuery.fn.highlightText = function(text, className) {
function highlight(node) {
if (node.nodeType == 3) {
var val = node.nodeValue;
var pos = val.toLowerCase().indexOf(text);
if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) {
var span = document.createElement("span");
span.className = className;
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
node.parentNode.insertBefore(span, node.parentNode.insertBefore(
document.createTextNode(val.substr(pos + text.length)),
node.nextSibling));
node.nodeValue = val.substr(0, pos);
}
}
else if (!jQuery(node).is("button, select, textarea")) {
jQuery.each(node.childNodes, function() {
highlight(this);
});
}
}
return this.each(function() {
highlight(this);
});
};
/**
* Small JavaScript module for the documentation.
*/
var Documentation = {
init : function() {
this.fixFirefoxAnchorBug();
this.highlightSearchWords();
this.initIndexTable();
},
/**
* i18n support
*/
TRANSLATIONS : {},
PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
LOCALE : 'unknown',
// gettext and ngettext don't access this so that the functions
// can safely bound to a different name (_ = Documentation.gettext)
gettext : function(string) {
var translated = Documentation.TRANSLATIONS[string];
if (typeof translated == 'undefined')
return string;
return (typeof translated == 'string') ? translated : translated[0];
},
ngettext : function(singular, plural, n) {
var translated = Documentation.TRANSLATIONS[singular];
if (typeof translated == 'undefined')
return (n == 1) ? singular : plural;
return translated[Documentation.PLURALEXPR(n)];
},
addTranslations : function(catalog) {
for (var key in catalog.messages)
this.TRANSLATIONS[key] = catalog.messages[key];
this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
this.LOCALE = catalog.locale;
},
/**
* add context elements like header anchor links
*/
addContextElements : function() {
$('div[id] > :header:first').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this headline')).
appendTo(this);
});
$('dt[id]').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this definition')).
appendTo(this);
});
},
/**
* workaround a firefox stupidity
*/
fixFirefoxAnchorBug : function() {
if (document.location.hash && $.browser.mozilla)
window.setTimeout(function() {
document.location.href += '';
}, 10);
},
/**
* highlight the search words provided in the url in the text
*/
highlightSearchWords : function() {
var params = $.getQueryParameters();
var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
if (terms.length) {
var body = $('div.body');
window.setTimeout(function() {
$.each(terms, function() {
body.highlightText(this.toLowerCase(), 'highlighted');
});
}, 10);
$('<p class="highlight-link"><a href="javascript:Documentation.' +
'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
.appendTo($('#searchbox'));
}
},
/**
* init the domain index toggle buttons
*/
initIndexTable : function() {
var togglers = $('img.toggler').click(function() {
var src = $(this).attr('src');
var idnum = $(this).attr('id').substr(7);
$('tr.cg-' + idnum).toggle();
if (src.substr(-9) == 'minus.png')
$(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
else
$(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
}).css('display', '');
if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
togglers.click();
}
},
/**
* helper function to hide the search marks again
*/
hideSearchWords : function() {
$('#searchbox .highlight-link').fadeOut(300);
$('span.highlighted').removeClass('highlighted');
},
/**
* make the url absolute
*/
makeURL : function(relativeURL) {
return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
},
/**
* get the current relative url
*/
getCurrentURL : function() {
var path = document.location.pathname;
var parts = path.split(/\//);
$.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
if (this == '..')
parts.pop();
});
var url = parts.join('/');
return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
}
};
// quick alias for translations
_ = Documentation.gettext;
$(document).ready(function() {
Documentation.init();
});

BIN
docsite/_static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

BIN
docsite/_static/file.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B

154
docsite/_static/jquery.js vendored Normal file
View File

@ -0,0 +1,154 @@
/*!
* jQuery JavaScript Library v1.4.2
* http://jquery.com/
*
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* Includes Sizzle.js
* http://sizzlejs.com/
* Copyright 2010, The Dojo Foundation
* Released under the MIT, BSD, and GPL Licenses.
*
* Date: Sat Feb 13 22:33:48 2010 -0500
*/
(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);

BIN
docsite/_static/minus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

BIN
docsite/_static/plus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

View File

@ -0,0 +1,62 @@
.highlight .hll { background-color: #ffffcc }
.highlight { background: #eeffcc; }
.highlight .c { color: #408090; font-style: italic } /* Comment */
.highlight .err { border: 1px solid #FF0000 } /* Error */
.highlight .k { color: #007020; font-weight: bold } /* Keyword */
.highlight .o { color: #666666 } /* Operator */
.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #007020 } /* Comment.Preproc */
.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */
.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #A00000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #FF0000 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #303030 } /* Generic.Output */
.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #0040D0 } /* Generic.Traceback */
.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #007020 } /* Keyword.Pseudo */
.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #902000 } /* Keyword.Type */
.highlight .m { color: #208050 } /* Literal.Number */
.highlight .s { color: #4070a0 } /* Literal.String */
.highlight .na { color: #4070a0 } /* Name.Attribute */
.highlight .nb { color: #007020 } /* Name.Builtin */
.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
.highlight .no { color: #60add5 } /* Name.Constant */
.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #007020 } /* Name.Exception */
.highlight .nf { color: #06287e } /* Name.Function */
.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #bb60d5 } /* Name.Variable */
.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #208050 } /* Literal.Number.Float */
.highlight .mh { color: #208050 } /* Literal.Number.Hex */
.highlight .mi { color: #208050 } /* Literal.Number.Integer */
.highlight .mo { color: #208050 } /* Literal.Number.Oct */
.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
.highlight .sc { color: #4070a0 } /* Literal.String.Char */
.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #4070a0 } /* Literal.String.Double */
.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
.highlight .sx { color: #c65d09 } /* Literal.String.Other */
.highlight .sr { color: #235388 } /* Literal.String.Regex */
.highlight .s1 { color: #4070a0 } /* Literal.String.Single */
.highlight .ss { color: #517918 } /* Literal.String.Symbol */
.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */

View File

@ -0,0 +1,560 @@
/*
* searchtools.js_t
* ~~~~~~~~~~~~~~~~
*
* Sphinx JavaScript utilties for the full-text search.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/**
* 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 occurance, the
* latter for highlighting it.
*/
jQuery.makeSearchSummary = function(text, keywords, hlwords) {
var textLower = text.toLowerCase();
var start = 0;
$.each(keywords, function() {
var i = textLower.indexOf(this.toLowerCase());
if (i > -1)
start = i;
});
start = Math.max(start - 120, 0);
var excerpt = ((start > 0) ? '...' : '') +
$.trim(text.substr(start, 240)) +
((start + 240 - text.length) ? '...' : '');
var rv = $('<div class="context"></div>').text(excerpt);
$.each(hlwords, function() {
rv = rv.highlightText(this, 'highlighted');
});
return rv;
}
/**
* Porter Stemmer
*/
var Stemmer = function() {
var step2list = {
ational: 'ate',
tional: 'tion',
enci: 'ence',
anci: 'ance',
izer: 'ize',
bli: 'ble',
alli: 'al',
entli: 'ent',
eli: 'e',
ousli: 'ous',
ization: 'ize',
ation: 'ate',
ator: 'ate',
alism: 'al',
iveness: 'ive',
fulness: 'ful',
ousness: 'ous',
aliti: 'al',
iviti: 'ive',
biliti: 'ble',
logi: 'log'
};
var step3list = {
icate: 'ic',
ative: '',
alize: 'al',
iciti: 'ic',
ical: 'ic',
ful: '',
ness: ''
};
var c = "[^aeiou]"; // consonant
var v = "[aeiouy]"; // vowel
var C = c + "[^aeiouy]*"; // consonant sequence
var V = v + "[aeiou]*"; // vowel sequence
var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0
var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
var s_v = "^(" + C + ")?" + v; // vowel in stem
this.stemWord = function (w) {
var stem;
var suffix;
var firstch;
var origword = w;
if (w.length < 3)
return w;
var re;
var re2;
var re3;
var re4;
firstch = w.substr(0,1);
if (firstch == "y")
w = firstch.toUpperCase() + w.substr(1);
// Step 1a
re = /^(.+?)(ss|i)es$/;
re2 = /^(.+?)([^s])s$/;
if (re.test(w))
w = w.replace(re,"$1$2");
else if (re2.test(w))
w = w.replace(re2,"$1$2");
// Step 1b
re = /^(.+?)eed$/;
re2 = /^(.+?)(ed|ing)$/;
if (re.test(w)) {
var fp = re.exec(w);
re = new RegExp(mgr0);
if (re.test(fp[1])) {
re = /.$/;
w = w.replace(re,"");
}
}
else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1];
re2 = new RegExp(s_v);
if (re2.test(stem)) {
w = stem;
re2 = /(at|bl|iz)$/;
re3 = new RegExp("([^aeiouylsz])\\1$");
re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re2.test(w))
w = w + "e";
else if (re3.test(w)) {
re = /.$/;
w = w.replace(re,"");
}
else if (re4.test(w))
w = w + "e";
}
}
// Step 1c
re = /^(.+?)y$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(s_v);
if (re.test(stem))
w = stem + "i";
}
// Step 2
re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem))
w = stem + step2list[suffix];
}
// Step 3
re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem))
w = stem + step3list[suffix];
}
// Step 4
re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
re2 = /^(.+?)(s|t)(ion)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
if (re.test(stem))
w = stem;
}
else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1] + fp[2];
re2 = new RegExp(mgr1);
if (re2.test(stem))
w = stem;
}
// Step 5
re = /^(.+?)e$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
re2 = new RegExp(meq1);
re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
w = stem;
}
re = /ll$/;
re2 = new RegExp(mgr1);
if (re.test(w) && re2.test(w)) {
re = /.$/;
w = w.replace(re,"");
}
// and turn initial Y back to y
if (firstch == "y")
w = firstch.toLowerCase() + w.substr(1);
return w;
}
}
/**
* Search Module
*/
var Search = {
_index : null,
_queued_query : null,
_pulse_status : -1,
init : function() {
var params = $.getQueryParameters();
if (params.q) {
var query = params.q[0];
$('input[name="q"]')[0].value = query;
this.performSearch(query);
}
},
loadIndex : function(url) {
$.ajax({type: "GET", url: url, data: null, success: null,
dataType: "script", cache: true});
},
setIndex : function(index) {
var q;
this._index = index;
if ((q = this._queued_query) !== null) {
this._queued_query = null;
Search.query(q);
}
},
hasIndex : function() {
return this._index !== null;
},
deferQuery : function(query) {
this._queued_query = query;
},
stopPulse : function() {
this._pulse_status = 0;
},
startPulse : function() {
if (this._pulse_status >= 0)
return;
function pulse() {
Search._pulse_status = (Search._pulse_status + 1) % 4;
var dotString = '';
for (var i = 0; i < Search._pulse_status; i++)
dotString += '.';
Search.dots.text(dotString);
if (Search._pulse_status > -1)
window.setTimeout(pulse, 500);
};
pulse();
},
/**
* perform a search for something
*/
performSearch : function(query) {
// create the required interface elements
this.out = $('#search-results');
this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out);
this.dots = $('<span></span>').appendTo(this.title);
this.status = $('<p style="display: none"></p>').appendTo(this.out);
this.output = $('<ul class="search"/>').appendTo(this.out);
$('#search-progress').text(_('Preparing search...'));
this.startPulse();
// index already loaded, the browser was quick!
if (this.hasIndex())
this.query(query);
else
this.deferQuery(query);
},
query : function(query) {
var stopwords = ["and","then","into","it","as","are","in","if","for","no","there","their","was","is","be","to","that","but","they","not","such","with","by","a","on","these","of","will","this","near","the","or","at"];
// Stem the searchterms and add them to the correct list
var stemmer = new Stemmer();
var searchterms = [];
var excluded = [];
var hlterms = [];
var tmp = query.split(/\s+/);
var objectterms = [];
for (var i = 0; i < tmp.length; i++) {
if (tmp[i] != "") {
objectterms.push(tmp[i].toLowerCase());
}
if ($u.indexOf(stopwords, tmp[i]) != -1 || tmp[i].match(/^\d+$/) ||
tmp[i] == "") {
// skip this "word"
continue;
}
// stem the word
var word = stemmer.stemWord(tmp[i]).toLowerCase();
// select the correct list
if (word[0] == '-') {
var toAppend = excluded;
word = word.substr(1);
}
else {
var toAppend = searchterms;
hlterms.push(tmp[i].toLowerCase());
}
// only add if not already in the list
if (!$.contains(toAppend, word))
toAppend.push(word);
};
var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
// console.debug('SEARCH: searching for:');
// console.info('required: ', searchterms);
// console.info('excluded: ', excluded);
// prepare search
var filenames = this._index.filenames;
var titles = this._index.titles;
var terms = this._index.terms;
var fileMap = {};
var files = null;
// different result priorities
var importantResults = [];
var objectResults = [];
var regularResults = [];
var unimportantResults = [];
$('#search-progress').empty();
// lookup as object
for (var i = 0; i < objectterms.length; i++) {
var others = [].concat(objectterms.slice(0,i),
objectterms.slice(i+1, objectterms.length))
var results = this.performObjectSearch(objectterms[i], others);
// Assume first word is most likely to be the object,
// other words more likely to be in description.
// Therefore put matches for earlier words first.
// (Results are eventually used in reverse order).
objectResults = results[0].concat(objectResults);
importantResults = results[1].concat(importantResults);
unimportantResults = results[2].concat(unimportantResults);
}
// perform the search on the required terms
for (var i = 0; i < searchterms.length; i++) {
var word = searchterms[i];
// no match but word was a required one
if ((files = terms[word]) == null)
break;
if (files.length == undefined) {
files = [files];
}
// create the mapping
for (var j = 0; j < files.length; j++) {
var file = files[j];
if (file in fileMap)
fileMap[file].push(word);
else
fileMap[file] = [word];
}
}
// now check if the files don't contain excluded terms
for (var file in fileMap) {
var valid = true;
// check if all requirements are matched
if (fileMap[file].length != searchterms.length)
continue;
// ensure that none of the excluded terms is in the
// search result.
for (var i = 0; i < excluded.length; i++) {
if (terms[excluded[i]] == file ||
$.contains(terms[excluded[i]] || [], file)) {
valid = false;
break;
}
}
// if we have still a valid result we can add it
// to the result list
if (valid)
regularResults.push([filenames[file], titles[file], '', null]);
}
// delete unused variables in order to not waste
// memory until list is retrieved completely
delete filenames, titles, terms;
// now sort the regular results descending by title
regularResults.sort(function(a, b) {
var left = a[1].toLowerCase();
var right = b[1].toLowerCase();
return (left > right) ? -1 : ((left < right) ? 1 : 0);
});
// combine all results
var results = unimportantResults.concat(regularResults)
.concat(objectResults).concat(importantResults);
// print the results
var resultCount = results.length;
function displayNextItem() {
// results left, load the summary and display it
if (results.length) {
var item = results.pop();
var listItem = $('<li style="display:none"></li>');
if (DOCUMENTATION_OPTIONS.FILE_SUFFIX == '') {
// dirhtml builder
var dirname = item[0] + '/';
if (dirname.match(/\/index\/$/)) {
dirname = dirname.substring(0, dirname.length-6);
} else if (dirname == 'index/') {
dirname = '';
}
listItem.append($('<a/>').attr('href',
DOCUMENTATION_OPTIONS.URL_ROOT + dirname +
highlightstring + item[2]).html(item[1]));
} else {
// normal html builders
listItem.append($('<a/>').attr('href',
item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
highlightstring + item[2]).html(item[1]));
}
if (item[3]) {
listItem.append($('<span> (' + item[3] + ')</span>'));
Search.output.append(listItem);
listItem.slideDown(5, function() {
displayNextItem();
});
} else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
$.get(DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' +
item[0] + '.txt', function(data) {
if (data != '') {
listItem.append($.makeSearchSummary(data, searchterms, hlterms));
Search.output.append(listItem);
}
listItem.slideDown(5, function() {
displayNextItem();
});
}, "text");
} else {
// no source available, just display title
Search.output.append(listItem);
listItem.slideDown(5, function() {
displayNextItem();
});
}
}
// search finished, update title and status message
else {
Search.stopPulse();
Search.title.text(_('Search Results'));
if (!resultCount)
Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
else
Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
Search.status.fadeIn(500);
}
}
displayNextItem();
},
performObjectSearch : function(object, otherterms) {
var filenames = this._index.filenames;
var objects = this._index.objects;
var objnames = this._index.objnames;
var titles = this._index.titles;
var importantResults = [];
var objectResults = [];
var unimportantResults = [];
for (var prefix in objects) {
for (var name in objects[prefix]) {
var fullname = (prefix ? prefix + '.' : '') + name;
if (fullname.toLowerCase().indexOf(object) > -1) {
var match = objects[prefix][name];
var objname = objnames[match[1]][2];
var title = titles[match[0]];
// If more than one term searched for, we require other words to be
// found in the name/title/description
if (otherterms.length > 0) {
var haystack = (prefix + ' ' + name + ' ' +
objname + ' ' + title).toLowerCase();
var allfound = true;
for (var i = 0; i < otherterms.length; i++) {
if (haystack.indexOf(otherterms[i]) == -1) {
allfound = false;
break;
}
}
if (!allfound) {
continue;
}
}
var descr = objname + _(', in ') + title;
anchor = match[3];
if (anchor == '')
anchor = fullname;
else if (anchor == '-')
anchor = objnames[match[1]][1] + '-' + fullname;
result = [filenames[match[0]], fullname, '#'+anchor, descr];
switch (match[2]) {
case 1: objectResults.push(result); break;
case 0: importantResults.push(result); break;
case 2: unimportantResults.push(result); break;
}
}
}
}
// sort results descending
objectResults.sort(function(a, b) {
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
});
importantResults.sort(function(a, b) {
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
});
unimportantResults.sort(function(a, b) {
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
});
return [importantResults, objectResults, unimportantResults]
}
}
$(document).ready(function() {
Search.init();
});

148
docsite/_static/sidebar.js Normal file
View File

@ -0,0 +1,148 @@
/*
* sidebar.js
* ~~~~~~~~~~
*
* This script makes the Sphinx sidebar collapsible.
*
* .sphinxsidebar contains .sphinxsidebarwrapper. This script adds
* in .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton
* used to collapse and expand the sidebar.
*
* When the sidebar is collapsed the .sphinxsidebarwrapper is hidden
* and the width of the sidebar and the margin-left of the document
* are decreased. When the sidebar is expanded the opposite happens.
* This script saves a per-browser/per-session cookie used to
* remember the position of the sidebar among the pages.
* Once the browser is closed the cookie is deleted and the position
* reset to the default (expanded).
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
$(function() {
// global elements used by the functions.
// the 'sidebarbutton' element is defined as global after its
// creation, in the add_sidebar_button function
var bodywrapper = $('.bodywrapper');
var sidebar = $('.sphinxsidebar');
var sidebarwrapper = $('.sphinxsidebarwrapper');
// original margin-left of the bodywrapper and width of the sidebar
// with the sidebar expanded
var bw_margin_expanded = bodywrapper.css('margin-left');
var ssb_width_expanded = sidebar.width();
// margin-left of the bodywrapper and width of the sidebar
// with the sidebar collapsed
var bw_margin_collapsed = '.8em';
var ssb_width_collapsed = '.8em';
// colors used by the current theme
var dark_color = $('.related').css('background-color');
var light_color = $('.document').css('background-color');
function sidebar_is_collapsed() {
return sidebarwrapper.is(':not(:visible)');
}
function toggle_sidebar() {
if (sidebar_is_collapsed())
expand_sidebar();
else
collapse_sidebar();
}
function collapse_sidebar() {
sidebarwrapper.hide();
sidebar.css('width', ssb_width_collapsed);
bodywrapper.css('margin-left', bw_margin_collapsed);
sidebarbutton.css({
'margin-left': '0',
'height': bodywrapper.height()
});
sidebarbutton.find('span').text('»');
sidebarbutton.attr('title', _('Expand sidebar'));
document.cookie = 'sidebar=collapsed';
}
function expand_sidebar() {
bodywrapper.css('margin-left', bw_margin_expanded);
sidebar.css('width', ssb_width_expanded);
sidebarwrapper.show();
sidebarbutton.css({
'margin-left': ssb_width_expanded-12,
'height': bodywrapper.height()
});
sidebarbutton.find('span').text('«');
sidebarbutton.attr('title', _('Collapse sidebar'));
document.cookie = 'sidebar=expanded';
}
function add_sidebar_button() {
sidebarwrapper.css({
'float': 'left',
'margin-right': '0',
'width': ssb_width_expanded - 28
});
// create the button
sidebar.append(
'<div id="sidebarbutton"><span>&laquo;</span></div>'
);
var sidebarbutton = $('#sidebarbutton');
light_color = sidebarbutton.css('background-color');
// find the height of the viewport to center the '<<' in the page
var viewport_height;
if (window.innerHeight)
viewport_height = window.innerHeight;
else
viewport_height = $(window).height();
sidebarbutton.find('span').css({
'display': 'block',
'margin-top': (viewport_height - sidebar.position().top - 20) / 2
});
sidebarbutton.click(toggle_sidebar);
sidebarbutton.attr('title', _('Collapse sidebar'));
sidebarbutton.css({
'color': '#FFFFFF',
'border-left': '1px solid ' + dark_color,
'font-size': '1.2em',
'cursor': 'pointer',
'height': bodywrapper.height(),
'padding-top': '1px',
'margin-left': ssb_width_expanded - 12
});
sidebarbutton.hover(
function () {
$(this).css('background-color', dark_color);
},
function () {
$(this).css('background-color', light_color);
}
);
}
function set_position_from_cookie() {
if (!document.cookie)
return;
var items = document.cookie.split(';');
for(var k=0; k<items.length; k++) {
var key_val = items[k].split('=');
var key = key_val[0];
if (key == 'sidebar') {
var value = key_val[1];
if ((value == 'collapsed') && (!sidebar_is_collapsed()))
collapse_sidebar();
else if ((value == 'expanded') && (sidebar_is_collapsed()))
expand_sidebar();
}
}
}
add_sidebar_button();
var sidebarbutton = $('#sidebarbutton');
set_position_from_cookie();
});

View File

@ -0,0 +1,23 @@
// Underscore.js 0.5.5
// (c) 2009 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore is freely distributable under the terms of the MIT license.
// Portions of Underscore are inspired by or borrowed from Prototype.js,
// Oliver Steele's Functional, and John Resig's Micro-Templating.
// For all details and documentation:
// http://documentcloud.github.com/underscore/
(function(){var j=this,n=j._,i=function(a){this._wrapped=a},m=typeof StopIteration!=="undefined"?StopIteration:"__break__",b=j._=function(a){return new i(a)};if(typeof exports!=="undefined")exports._=b;var k=Array.prototype.slice,o=Array.prototype.unshift,p=Object.prototype.toString,q=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;b.VERSION="0.5.5";b.each=function(a,c,d){try{if(a.forEach)a.forEach(c,d);else if(b.isArray(a)||b.isArguments(a))for(var e=0,f=a.length;e<f;e++)c.call(d,
a[e],e,a);else{var g=b.keys(a);f=g.length;for(e=0;e<f;e++)c.call(d,a[g[e]],g[e],a)}}catch(h){if(h!=m)throw h;}return a};b.map=function(a,c,d){if(a&&b.isFunction(a.map))return a.map(c,d);var e=[];b.each(a,function(f,g,h){e.push(c.call(d,f,g,h))});return e};b.reduce=function(a,c,d,e){if(a&&b.isFunction(a.reduce))return a.reduce(b.bind(d,e),c);b.each(a,function(f,g,h){c=d.call(e,c,f,g,h)});return c};b.reduceRight=function(a,c,d,e){if(a&&b.isFunction(a.reduceRight))return a.reduceRight(b.bind(d,e),c);
var f=b.clone(b.toArray(a)).reverse();b.each(f,function(g,h){c=d.call(e,c,g,h,a)});return c};b.detect=function(a,c,d){var e;b.each(a,function(f,g,h){if(c.call(d,f,g,h)){e=f;b.breakLoop()}});return e};b.select=function(a,c,d){if(a&&b.isFunction(a.filter))return a.filter(c,d);var e=[];b.each(a,function(f,g,h){c.call(d,f,g,h)&&e.push(f)});return e};b.reject=function(a,c,d){var e=[];b.each(a,function(f,g,h){!c.call(d,f,g,h)&&e.push(f)});return e};b.all=function(a,c,d){c=c||b.identity;if(a&&b.isFunction(a.every))return a.every(c,
d);var e=true;b.each(a,function(f,g,h){(e=e&&c.call(d,f,g,h))||b.breakLoop()});return e};b.any=function(a,c,d){c=c||b.identity;if(a&&b.isFunction(a.some))return a.some(c,d);var e=false;b.each(a,function(f,g,h){if(e=c.call(d,f,g,h))b.breakLoop()});return e};b.include=function(a,c){if(b.isArray(a))return b.indexOf(a,c)!=-1;var d=false;b.each(a,function(e){if(d=e===c)b.breakLoop()});return d};b.invoke=function(a,c){var d=b.rest(arguments,2);return b.map(a,function(e){return(c?e[c]:e).apply(e,d)})};b.pluck=
function(a,c){return b.map(a,function(d){return d[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);var e={computed:-Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;g>=e.computed&&(e={value:f,computed:g})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;g<e.computed&&(e={value:f,computed:g})});return e.value};b.sortBy=function(a,c,d){return b.pluck(b.map(a,
function(e,f,g){return{value:e,criteria:c.call(d,e,f,g)}}).sort(function(e,f){e=e.criteria;f=f.criteria;return e<f?-1:e>f?1:0}),"value")};b.sortedIndex=function(a,c,d){d=d||b.identity;for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?(e=g+1):(f=g)}return e};b.toArray=function(a){if(!a)return[];if(a.toArray)return a.toArray();if(b.isArray(a))return a;if(b.isArguments(a))return k.call(a);return b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=function(a,c,d){return c&&!d?k.call(a,
0,c):a[0]};b.rest=function(a,c,d){return k.call(a,b.isUndefined(c)||d?1:c)};b.last=function(a){return a[a.length-1]};b.compact=function(a){return b.select(a,function(c){return!!c})};b.flatten=function(a){return b.reduce(a,[],function(c,d){if(b.isArray(d))return c.concat(b.flatten(d));c.push(d);return c})};b.without=function(a){var c=b.rest(arguments);return b.select(a,function(d){return!b.include(c,d)})};b.uniq=function(a,c){return b.reduce(a,[],function(d,e,f){if(0==f||(c===true?b.last(d)!=e:!b.include(d,
e)))d.push(e);return d})};b.intersect=function(a){var c=b.rest(arguments);return b.select(b.uniq(a),function(d){return b.all(c,function(e){return b.indexOf(e,d)>=0})})};b.zip=function(){for(var a=b.toArray(arguments),c=b.max(b.pluck(a,"length")),d=new Array(c),e=0;e<c;e++)d[e]=b.pluck(a,String(e));return d};b.indexOf=function(a,c){if(a.indexOf)return a.indexOf(c);for(var d=0,e=a.length;d<e;d++)if(a[d]===c)return d;return-1};b.lastIndexOf=function(a,c){if(a.lastIndexOf)return a.lastIndexOf(c);for(var d=
a.length;d--;)if(a[d]===c)return d;return-1};b.range=function(a,c,d){var e=b.toArray(arguments),f=e.length<=1;a=f?0:e[0];c=f?e[0]:e[1];d=e[2]||1;e=Math.ceil((c-a)/d);if(e<=0)return[];e=new Array(e);f=a;for(var g=0;1;f+=d){if((d>0?f-c:c-f)>=0)return e;e[g++]=f}};b.bind=function(a,c){var d=b.rest(arguments,2);return function(){return a.apply(c||j,d.concat(b.toArray(arguments)))}};b.bindAll=function(a){var c=b.rest(arguments);if(c.length==0)c=b.functions(a);b.each(c,function(d){a[d]=b.bind(a[d],a)});
return a};b.delay=function(a,c){var d=b.rest(arguments,2);return setTimeout(function(){return a.apply(a,d)},c)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(b.rest(arguments)))};b.wrap=function(a,c){return function(){var d=[a].concat(b.toArray(arguments));return c.apply(c,d)}};b.compose=function(){var a=b.toArray(arguments);return function(){for(var c=b.toArray(arguments),d=a.length-1;d>=0;d--)c=[a[d].apply(this,c)];return c[0]}};b.keys=function(a){if(b.isArray(a))return b.range(0,a.length);
var c=[];for(var d in a)q.call(a,d)&&c.push(d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=function(a){return b.select(b.keys(a),function(c){return b.isFunction(a[c])}).sort()};b.extend=function(a,c){for(var d in c)a[d]=c[d];return a};b.clone=function(a){if(b.isArray(a))return a.slice(0);return b.extend({},a)};b.tap=function(a,c){c(a);return a};b.isEqual=function(a,c){if(a===c)return true;var d=typeof a;if(d!=typeof c)return false;if(a==c)return true;if(!a&&c||a&&!c)return false;
if(a.isEqual)return a.isEqual(c);if(b.isDate(a)&&b.isDate(c))return a.getTime()===c.getTime();if(b.isNaN(a)&&b.isNaN(c))return true;if(b.isRegExp(a)&&b.isRegExp(c))return a.source===c.source&&a.global===c.global&&a.ignoreCase===c.ignoreCase&&a.multiline===c.multiline;if(d!=="object")return false;if(a.length&&a.length!==c.length)return false;d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return false;for(var f in a)if(!b.isEqual(a[f],c[f]))return false;return true};b.isEmpty=function(a){return b.keys(a).length==
0};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=function(a){return!!(a&&a.concat&&a.unshift)};b.isArguments=function(a){return a&&b.isNumber(a.length)&&!b.isArray(a)&&!r.call(a,"length")};b.isFunction=function(a){return!!(a&&a.constructor&&a.call&&a.apply)};b.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};b.isNumber=function(a){return p.call(a)==="[object Number]"};b.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};b.isRegExp=function(a){return!!(a&&
a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};b.isNaN=function(a){return b.isNumber(a)&&isNaN(a)};b.isNull=function(a){return a===null};b.isUndefined=function(a){return typeof a=="undefined"};b.noConflict=function(){j._=n;return this};b.identity=function(a){return a};b.breakLoop=function(){throw m;};var s=0;b.uniqueId=function(a){var c=s++;return a?a+c:c};b.template=function(a,c){a=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g,
" ").replace(/'(?=[^%]*%>)/g,"\t").split("'").join("\\'").split("\t").join("'").replace(/<%=(.+?)%>/g,"',$1,'").split("<%").join("');").split("%>").join("p.push('")+"');}return p.join('');");return c?a(c):a};b.forEach=b.each;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.filter=b.select;b.every=b.all;b.some=b.any;b.head=b.first;b.tail=b.rest;b.methods=b.functions;var l=function(a,c){return c?b(a).chain():a};b.each(b.functions(b),function(a){var c=b[a];i.prototype[a]=function(){var d=b.toArray(arguments);
o.call(d,this._wrapped);return l(c.apply(b,d),this._chain)}});b.each(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){c.apply(this._wrapped,arguments);return l(this._wrapped,this._chain)}});b.each(["concat","join","slice"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){return l(c.apply(this._wrapped,arguments),this._chain)}});i.prototype.chain=function(){this._chain=true;return this};i.prototype.value=function(){return this._wrapped}})();

View File

@ -0,0 +1,5 @@
<li class="dropdown" data-dropdown="dropdown">
<a href="{{ pathto(master_doc) }}"
class="dropdown-toggle">Chapter</a>
<span class="globaltoc">{{ toctree(maxdepth=1) }}</span>
</li>

View File

@ -0,0 +1,138 @@
{% extends "basic/layout.html" %}
{% set script_files = script_files + ['_static/bootstrap-dropdown.js', '_static/bootstrap-scrollspy.js'] %}
{% set css_files = ['_static/bootstrap.css', '_static/bootstrap-sphinx.css'] + css_files %}
{# Sidebar: Rework into our Boostrap nav section. #}
{% macro navBar() %}
<div class="topbar" data-scrollspy="scrollspy" >
<div class="topbar-inner">
<div class="container">
<!-- <a class="brand" href="{{ pathto(master_doc) }}">{{ shorttitle|e }}</a> -->
<ul class="nav">
{% block sidebartoc %}
<li><a href="/">Home</A>
{% include "globaltoc.html" %}
{% include "localtoc.html" %}
{% endblock %}
</ul>
<ul class="nav secondary-nav">
{% block sidebarsearch %}
{% include "searchbox.html" %}
{% endblock %}
</ul>
</div>
</div>
</div>
{% endmacro %}
<p></p>
{%- block extrahead %}
<script type="text/javascript">
(function () {
/**
* Patch TOC list.
*
* Will mutate the underlying span to have a correct ul for nav.
*
* @param $span: Span containing nested UL's to mutate.
* @param minLevel: Starting level for nested lists. (1: global, 2: local).
*/
var patchToc = function ($span, minLevel) {
var $tocList = $("<ul/>").attr('class', "dropdown-menu"),
findA;
// Find all a "internal" tags, traversing recursively.
findA = function ($elem, level) {
var level = level || 0,
$items = $elem.find("> li > a.internal, > ul, > li > ul");
// Iterate everything in order.
$items.each(function (index, item) {
var $item = $(item),
tag = item.tagName.toLowerCase(),
pad = 10 + ((level - minLevel) * 10);
if (tag === 'a' && level >= minLevel) {
// Add to existing padding.
$item.css('padding-left', pad + "px");
// Add list element.
$tocList.append($("<li/>").append($item));
} else if (tag === 'ul') {
// Recurse.
findA($item, level + 1);
}
});
};
// Start construction and return.
findA($span);
// Wipe out old list and patch in new one.
return $span.empty("ul").append($tocList);
};
$(document).ready(function () {
// Patch the global and local TOC's to be bootstrap-compliant.
patchToc($("span.globaltoc"), 1);
patchToc($("span.localtoc"), 2);
// Activate.
$('#topbar').dropdown();
});
}());
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-29861888-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type =
'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' :
'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();
</script>
{% endblock %}
{% block header %}{{ navBar() }}{% endblock %}
{# Silence the sidebar's, relbar's #}
{% block sidebar1 %}{% endblock %}
{% block sidebar2 %}{% endblock %}
{% block relbar1 %}{% endblock %}
{% block relbar2 %}{% endblock %}
{%- block content %}
<div class="container">
{% block body %} {% endblock %}
<br/>
</div>
{%- endblock %}
{%- block footer %}
<footer class="footer">
<p>
{%- if show_copyright %}
{%- if hasdoc('copyright') %}
{% trans path=pathto('copyright'), copyright=copyright|e %}&copy; <a href="{{ path }}">Copyright</a> {{ copyright }}.{% endtrans %}<br/>
{%- else %}
{% trans copyright=copyright|e %}&copy; Copyright {{ copyright }}.{% endtrans %}<br/>
{%- endif %}
{%- endif %}
{%- if last_updated %}
{% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %}<br/>
{%- endif %}
</p>
</div>
</footer>
{%- endblock %}

View File

@ -0,0 +1,5 @@
<li class="dropdown" data-dropdown="dropdown">
<a href="#"
class="dropdown-toggle">{{ _('Page') }}</a>
<span class="localtoc">{{ toc }}</span>
</li>

View File

@ -0,0 +1,8 @@
{%- if prev %}
<li><a href="{{ prev.link|e }}"
title="{{ _('previous chapter') }}">{{ "&laquo;"|safe }} {{ prev.title }}</a></li>
{%- endif %}
{%- if next %}
<li><a href="{{ next.link|e }}"
title="{{ _('next chapter') }}">{{ next.title }} {{ "&raquo;"|safe }}</a></li>
{%- endif %}

View File

@ -0,0 +1,7 @@
{%- if pagename != "search" %}
<form class="pull-left" action="{{ pathto('search') }}" method="get">
<input type="text" name="q" placeholder="Search" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
{%- endif %}

View File

@ -0,0 +1,4 @@
{%- if show_source and has_source and sourcename %}
<li><a href="{{ pathto('_sources/' + sourcename, true)|e }}"
rel="nofollow">{{ _('Source') }}</a></li>
{%- endif %}

View File

@ -0,0 +1,55 @@
/* ============================================================
* bootstrap-dropdown.js v1.4.0
* http://twitter.github.com/bootstrap/javascript.html#dropdown
* ============================================================
* Copyright 2011 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ============================================================ */
!function( $ ){
"use strict"
/* DROPDOWN PLUGIN DEFINITION
* ========================== */
$.fn.dropdown = function ( selector ) {
return this.each(function () {
$(this).delegate(selector || d, 'click', function (e) {
var li = $(this).parent('li')
, isActive = li.hasClass('open')
clearMenus()
!isActive && li.toggleClass('open')
return false
})
})
}
/* APPLY TO STANDARD DROPDOWN ELEMENTS
* =================================== */
var d = 'a.menu, .dropdown-toggle'
function clearMenus() {
$(d).parent('li').removeClass('open')
}
$(function () {
$('html').bind("click", clearMenus)
$('body').dropdown( '[data-dropdown] a.menu, [data-dropdown] .dropdown-toggle' )
})
}( window.jQuery || window.ender );

View File

@ -0,0 +1,107 @@
/* =============================================================
* bootstrap-scrollspy.js v1.4.0
* http://twitter.github.com/bootstrap/javascript.html#scrollspy
* =============================================================
* Copyright 2011 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ============================================================== */
!function ( $ ) {
"use strict"
var $window = $(window)
function ScrollSpy( topbar, selector ) {
var processScroll = $.proxy(this.processScroll, this)
this.$topbar = $(topbar)
this.selector = selector || 'li > a'
this.refresh()
this.$topbar.delegate(this.selector, 'click', processScroll)
$window.scroll(processScroll)
this.processScroll()
}
ScrollSpy.prototype = {
refresh: function () {
this.targets = this.$topbar.find(this.selector).map(function () {
var href = $(this).attr('href')
return /^#\w/.test(href) && $(href).length ? href : null
})
this.offsets = $.map(this.targets, function (id) {
return $(id).offset().top
})
}
, processScroll: function () {
var scrollTop = $window.scrollTop() + 10
, offsets = this.offsets
, targets = this.targets
, activeTarget = this.activeTarget
, i
for (i = offsets.length; i--;) {
activeTarget != targets[i]
&& scrollTop >= offsets[i]
&& (!offsets[i + 1] || scrollTop <= offsets[i + 1])
&& this.activateButton( targets[i] )
}
}
, activateButton: function (target) {
this.activeTarget = target
this.$topbar
.find(this.selector).parent('.active')
.removeClass('active')
this.$topbar
.find(this.selector + '[href="' + target + '"]')
.parent('li')
.addClass('active')
}
}
/* SCROLLSPY PLUGIN DEFINITION
* =========================== */
$.fn.scrollSpy = function( options ) {
var scrollspy = this.data('scrollspy')
if (!scrollspy) {
return this.each(function () {
$(this).data('scrollspy', new ScrollSpy( this, options ))
})
}
if ( options === true ) {
return scrollspy
}
if ( typeof options == 'string' ) {
scrollspy[options]()
}
return this
}
$(document).ready(function () {
$('body').scrollSpy('[data-scrollspy] li > a')
})
}( window.jQuery || window.ender );

View File

@ -0,0 +1,24 @@
/*
* bootstrap-sphinx.css
* ~~~~~~~~~~~~~~~~~~~~
*
* Sphinx stylesheet -- Twitter Bootstrap theme.
*/
body {
padding-top: 42px;
}
div.documentwrapper {
float: left;
width: 100%;
}
{%- block sidebarlogo %}
{%- if logo %}
.topbar h3 a, .topbar .brand {
background: transparent url("{{ logo }}") no-repeat 22px 3px;
padding-left: 62px;
}
{%- endif %}
{%- endblock %}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
# Twitter Bootstrap Theme
[theme]
inherit = basic
stylesheet = basic.css
pygments_style = tango

BIN
docsite/ansible-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
docsite/ansible_arch.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

BIN
docsite/ansible_arch2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

97
docsite/build-site.py Executable file
View File

@ -0,0 +1,97 @@
#!/usr/bin/env python
# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
#
# This file is part of the Ansible Documentation
#
# 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/>.
__docformat__ = 'restructuredtext'
import os
import sys
import traceback
from sphinx.application import Sphinx
import os
class SphinxBuilder(object):
"""
Creates HTML documentation using Sphinx.
"""
def __init__(self):
"""
Run the DocCommand.
"""
print "Creating html documentation ..."
try:
buildername = 'html'
outdir = os.path.abspath(os.getcwd())
# Create the output directory if it doesn't exist
if not os.access(outdir, os.F_OK):
os.mkdir(outdir)
doctreedir = os.path.join('./', '.doctrees')
confdir = os.path.abspath('./')
srcdir = os.path.abspath('rst')
freshenv = True
# Create the builder
app = Sphinx(srcdir,
confdir,
outdir,
doctreedir,
buildername,
{},
sys.stdout,
sys.stderr,
freshenv)
app.builder.build_all()
except ImportError, ie:
traceback.print_exc()
except Exception, ex:
print >> sys.stderr, "FAIL! exiting ... (%s)" % ex
def build_docs(self):
self.app.builder.build_all()
def build_rst_docs():
docgen = SphinxBuilder()
if __name__ == '__main__':
if '-h' in sys.argv or '--help' in sys.argv:
print "This script builds the html documentation from rst/asciidoc sources.\n"
print " Run 'make docs' to build everything."
print " Run 'make viewdocs' to build and then preview in a web browser."
sys.exit(0)
# The 'htmldocs' make target will call this scrip twith the 'rst'
# parameter' We don't need to run the 'htmlman' target then.
if "rst" in sys.argv:
build_rst_docs()
else:
# By default, preform the rst->html transformation and then
# the asciidoc->html trasnformation
build_rst_docs()
if "view" in sys.argv:
import webbrowser
if not webbrowser.open('index.html'):
print >> sys.stderr, "Could not open on your webbrowser."

206
docsite/conf.py Normal file
View File

@ -0,0 +1,206 @@
# -*- coding: utf-8 -*-
#
# documentation build configuration file, created by
# sphinx-quickstart on Sat Sep 27 13:23:22 2008-2009.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# The contents of this file are pickled, so don't put values in the namespace
# that aren't pickleable (module imports are okay, they're removed
# automatically).
#
# All configuration values have a default value; values that are commented out
# serve to show the default value.
import sys
import os
# If your extensions are in another directory, add it here. If the directory
# is relative to the documentation root, use os.path.abspath to make it
# absolute, like shown here.
#sys.path.append(os.path.abspath('some/directory'))
sys.path.insert(0, os.path.join('ansible', 'lib'))
sys.path.append(os.path.abspath('_themes'))
VERSION='0.01'
AUTHOR='Michael DeHaan'
# General configuration
# ---------------------
# Add any Sphinx extension module names here, as strings.
# They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc']
# Later on, add 'sphinx.ext.viewcode' to the list if you want to have
# colorized code generated too for references.
# Add any paths that contain templates here, relative to this directory.
templates_path = ['.templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General substitutions.
project = 'Ansible Documentation'
copyright = "2012 Michael DeHaan"
# The default replacements for |version| and |release|, also used in various
# other places throughout the built documents.
#
# The short X.Y version.
version = VERSION
# The full version, including alpha/beta/rc tags.
release = VERSION
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
#unused_docs = []
# List of directories, relative to source directories, that shouldn't be
# searched for source files.
#exclude_dirs = []
# A list of glob-style patterns that should be excluded when looking
# for source files.
exclude_patterns = ['modules']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# Options for HTML output
# -----------------------
html_theme_path = ['_themes']
html_theme = 'bootstrap'
html_short_title = 'Ansible Documentation'
# The style sheet to use for HTML and HTML Help pages. A file of that name
# must exist either in Sphinx' static/ path, or in one of the custom paths
# given in html_static_path.
html_style = 'default.css'
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
html_title = 'Ansible Documentation'
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (within the static path) to place at the top of
# the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
html_favicon = 'favicon.ico'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
#html_static_path = ['.static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_use_modindex = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, the reST sources are included in the HTML build as _sources/<name>.
html_copy_source = False
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = ''
# Output file base name for HTML help builder.
htmlhelp_basename = 'Poseidodoc'
# Options for LaTeX output
# ------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, document class
# [howto/manual]).
latex_documents = [
('index', 'ansible.tex', 'Ansible Documentation',
AUTHOR, 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_use_modindex = True
autoclass_content = 'both'

BIN
docsite/github.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>ansible-playbook</title><link rel="stylesheet" href="./docbook-xsl.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.75.2" /></head><body><div xml:lang="en" class="refentry" title="ansible-playbook" lang="en"><a id="id474207"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ansible-playbook — run an ansible playbook</p></div><div class="refsynopsisdiv" title="Synopsis"><a id="_synopsis"></a><h2>Synopsis</h2><p>ansible-playbook &lt;filename.yml&gt; … [options]</p></div><div class="refsect1" title="DESCRIPTION"><a id="_description"></a><h2>DESCRIPTION</h2><p><span class="strong"><strong>Ansible playbooks</strong></span> are a configuration and multinode deployment
system. Ansible-playbook is the tool used to run them. See the
project home page (link below) for more information.</p></div><div class="refsect1" title="ARGUMENTS"><a id="_arguments"></a><h2>ARGUMENTS</h2><div class="variablelist"><dl><dt><span class="term">
<span class="strong"><strong>filename.yml</strong></span>
</span></dt><dd>
The names of one or more YAML format files to run as ansible playbooks.
</dd></dl></div></div><div class="refsect1" title="OPTIONS"><a id="_options"></a><h2>OPTIONS</h2><div class="variablelist"><dl><dt><span class="term">
<span class="strong"><strong>-i</strong></span> <span class="emphasis"><em>PATH</em></span>, <span class="strong"><strong>--inventory=</strong></span><span class="emphasis"><em>PATH</em></span>
</span></dt><dd>
The <span class="emphasis"><em>PATH</em></span> to the inventory hosts file, which defaults to <span class="emphasis"><em>/etc/ansible/hosts</em></span>.
</dd><dt><span class="term">
<span class="strong"><strong>-M</strong></span> <span class="emphasis"><em>DIRECTORY</em></span>, <span class="strong"><strong>--module-path=</strong></span><span class="emphasis"><em>DIRECTORY</em></span>
</span></dt><dd>
The <span class="emphasis"><em>DIRECTORY</em></span> to load modules from. The default is <span class="emphasis"><em>/usr/share/ansible</em></span>.
</dd><dt><span class="term">
<span class="strong"><strong>-f</strong></span> <span class="emphasis"><em>NUM</em></span>, <span class="strong"><strong>--forks=</strong></span><span class="emphasis"><em>NUM</em></span>
</span></dt><dd>
Level of parallelism. <span class="emphasis"><em>NUM</em></span> is specified as an integer, the default is 5.
</dd><dt><span class="term">
<span class="strong"><strong>-k</strong></span>, <span class="strong"><strong>--ask-pass</strong></span>
</span></dt><dd>
Prompt for the SSH password instead of assuming key-based authentication with ssh-agent.
</dd><dt><span class="term">
<span class="strong"><strong>-T</strong></span> <span class="emphasis"><em>SECONDS</em></span>, <span class="strong"><strong>--timeout=</strong></span><span class="emphasis"><em>SECONDS</em></span>
</span></dt><dd>
Connection timeout to use when trying to talk to hosts, in <span class="emphasis"><em>SECONDS</em></span>.
</dd></dl></div></div><div class="refsect1" title="ENVIRONMENT"><a id="_environment"></a><h2>ENVIRONMENT</h2><p>The following environment variables may specified.</p><p>ANSIBLE_HOSTS  — Override the default ansible hosts file</p><p>ANSIBLE_LIBRARY — Override the default ansible module library path</p></div><div class="refsect1" title="AUTHOR"><a id="_author"></a><h2>AUTHOR</h2><p>Ansible was originally written by Michael DeHaan. See the AUTHORS file
for a complete list of contributors.</p></div><div class="refsect1" title="COPYRIGHT"><a id="_copyright"></a><h2>COPYRIGHT</h2><p>Copyright © 2012, Michael DeHaan</p><p>Ansible is released under the terms of the GPLv3 License.</p></div><div class="refsect1" title="SEE ALSO"><a id="_see_also"></a><h2>SEE ALSO</h2><p><span class="strong"><strong>ansible</strong></span>(1)</p><p>Extensive documentation as well as IRC and mailing list info
is available on the ansible home page: <a class="ulink" href="https://ansible.github.com/" target="_top">https://ansible.github.com/</a></p></div></div></body></html>

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>ansible</title><link rel="stylesheet" href="./docbook-xsl.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.75.2" /></head><body><div xml:lang="en" class="refentry" title="ansible" lang="en"><a id="id392901"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ansible — run a command somewhere else</p></div><div class="refsynopsisdiv" title="Synopsis"><a id="_synopsis"></a><h2>Synopsis</h2><p>ansible &lt;host-pattern&gt; [-f forks] [-m module_name] [-a args]</p></div><div class="refsect1" title="DESCRIPTION"><a id="_description"></a><h2>DESCRIPTION</h2><p><span class="strong"><strong>Ansible</strong></span> is an extra-simple tool/framework/API for doing 'remote things' over
SSH.</p></div><div class="refsect1" title="ARGUMENTS"><a id="_arguments"></a><h2>ARGUMENTS</h2><div class="variablelist"><dl><dt><span class="term">
<span class="strong"><strong>host-pattern</strong></span>
</span></dt><dd>
A name of a group in the inventory file, a shell-like glob selecting
hosts in inventory file, or any combination of the two separated by
semicolons.
</dd></dl></div></div><div class="refsect1" title="OPTIONS"><a id="_options"></a><h2>OPTIONS</h2><div class="variablelist"><dl><dt><span class="term">
<span class="strong"><strong>-i</strong></span> <span class="emphasis"><em>PATH</em></span>, <span class="strong"><strong>--inventory=</strong></span><span class="emphasis"><em>PATH</em></span>
</span></dt><dd>
The <span class="emphasis"><em>PATH</em></span> to the inventory hosts file, which defaults to <span class="emphasis"><em>/etc/ansible/hosts</em></span>.
</dd><dt><span class="term">
<span class="strong"><strong>-f</strong></span> <span class="emphasis"><em>NUM</em></span>, <span class="strong"><strong>--forks=</strong></span><span class="emphasis"><em>NUM</em></span>
</span></dt><dd>
Level of parallelism. <span class="emphasis"><em>NUM</em></span> is specified as an integer, the default is 5.
</dd><dt><span class="term">
<span class="strong"><strong>-m</strong></span> <span class="emphasis"><em>NAME</em></span>, <span class="strong"><strong>--module-name=</strong></span><span class="emphasis"><em>NAME</em></span>
</span></dt><dd>
Execute the module called <span class="emphasis"><em>NAME</em></span>.
</dd><dt><span class="term">
<span class="strong"><strong>-M</strong></span> <span class="emphasis"><em>DIRECTORY</em></span>, <span class="strong"><strong>--module-path=</strong></span><span class="emphasis"><em>DIRECTORY</em></span>
</span></dt><dd>
The <span class="emphasis"><em>DIRECTORY</em></span> to load modules from. The default is <span class="emphasis"><em>/usr/share/ansible</em></span>.
</dd><dt><span class="term">
<span class="strong"><strong>-a</strong></span> '<span class="emphasis"><em>ARGUMENTS</em></span>', <span class="strong"><strong>--args=</strong></span>'<span class="emphasis"><em>ARGUMENTS</em></span>'
</span></dt><dd>
The <span class="emphasis"><em>ARGUMENTS</em></span> to pass to the module.
</dd><dt><span class="term">
<span class="strong"><strong>-k</strong></span>, <span class="strong"><strong>--ask-pass</strong></span>
</span></dt><dd>
Prompt for the SSH password instead of assuming key-based authentication with ssh-agent.
</dd><dt><span class="term">
<span class="strong"><strong>-o</strong></span>, <span class="strong"><strong>--one-line</strong></span>
</span></dt><dd>
Try to output everything on one line.
</dd><dt><span class="term">
<span class="strong"><strong>-t</strong></span> <span class="emphasis"><em>DIRECTORY</em></span>, <span class="strong"><strong>--tree=</strong></span><span class="emphasis"><em>DIRECTORY</em></span>
</span></dt><dd>
Save contents in this output <span class="emphasis"><em>DIRECTORY</em></span>, with the results saved in a
file named after each host.
</dd><dt><span class="term">
<span class="strong"><strong>-T</strong></span> <span class="emphasis"><em>SECONDS</em></span>, <span class="strong"><strong>--timeout=</strong></span><span class="emphasis"><em>SECONDS</em></span>
</span></dt><dd>
Connection timeout to use when trying to talk to hosts, in <span class="emphasis"><em>SECONDS</em></span>.
</dd><dt><span class="term">
<span class="strong"><strong>-B</strong></span> <span class="emphasis"><em>NUM</em></span>, <span class="strong"><strong>--background=</strong></span><span class="emphasis"><em>NUM</em></span>
</span></dt><dd>
Run commands in the background, killing the task after <span class="emphasis"><em>NUM</em></span> seconds.
</dd><dt><span class="term">
<span class="strong"><strong>-P</strong></span> <span class="emphasis"><em>NUM</em></span>, <span class="strong"><strong>--poll=</strong></span><span class="emphasis"><em>NUM</em></span>
</span></dt><dd>
Poll a background job every <span class="emphasis"><em>NUM</em></span> seconds. Requires <span class="strong"><strong>-B</strong></span>.
</dd><dt><span class="term">
<span class="strong"><strong>-u</strong></span> <span class="emphasis"><em>USERNAME</em></span>, <span class="strong"><strong>--remote-user=</strong></span><span class="emphasis"><em>USERNAME</em></span>
</span></dt><dd>
Use this remote <span class="emphasis"><em>USERNAME</em></span> instead of root.
</dd></dl></div></div><div class="refsect1" title="INVENTORY"><a id="_inventory"></a><h2>INVENTORY</h2><p>Ansible stores the hosts it can potentially operate on in an inventory
file. The syntax is one host per line. Groups headers are allowed and
are included on their own line, enclosed in square brackets.</p></div><div class="refsect1" title="FILES"><a id="_files"></a><h2>FILES</h2><p>/etc/ansible/hosts — Default inventory file</p><p>/usr/share/ansible/ — Default module library</p></div><div class="refsect1" title="ENVIRONMENT"><a id="_environment"></a><h2>ENVIRONMENT</h2><p>The following environment variables may specified.</p><p>ANSIBLE_HOSTS  — Override the default ansible hosts file</p><p>ANSIBLE_LIBRARY — Override the default ansible module library path</p></div><div class="refsect1" title="AUTHOR"><a id="_author"></a><h2>AUTHOR</h2><p>Ansible was originally written by Michael DeHaan. See the AUTHORS file
for a complete list of contributors.</p></div><div class="refsect1" title="COPYRIGHT"><a id="_copyright"></a><h2>COPYRIGHT</h2><p>Copyright © 2012, Michael DeHaan</p><p>Ansible is released under the terms of the GPLv3 License.</p></div><div class="refsect1" title="SEE ALSO"><a id="_see_also"></a><h2>SEE ALSO</h2><p><span class="strong"><strong>ansible-playbook</strong></span>(1)</p><p>Extensive documentation as well as IRC and mailing list info
is available on the ansible home page: <a class="ulink" href="https://ansible.github.com/" target="_top">https://ansible.github.com/</a></p></div></div></body></html>

108
docsite/rst/YAMLSyntax.rst Normal file
View File

@ -0,0 +1,108 @@
YAML Syntax
===========
This page provides a basic overview of correct YAML syntax, which is how Ansible
playbooks (our configuration management language) are expressed.
We use YAML because it is easier to read and write for humans than other common
data formats like XML or JSON. Further, there are libraries available for reading
and writing YAML in most programming languages.
You may also wish to read :doc:`playbooks` at the same time to see how this
is used in practice.
YAML Basics
-----------
For `ansible`, nearly every YAML file starts with a list.
Each item in the list is a list of key/value pairs, commonly
called a "hash" or a "dictionary". So, we need to know how
to write lists and dictionaries in YAML.
There's another small quirk to YAML. All YAML files (regardless of their association with
`ansible` or not) should start with ``---``. This is just a YAML
format thing that means "this is the start of a document".
All members of a list are lines beginning at the same indentation level starting
with a ``-`` (dash) character::
---
# A list of tasty fruits
- Apple
- Orange
- Strawberry
- Mango
A dictionary is represented in a simple ``key:`` and ``value`` form::
---
# An employee record
name: Example Developer
job: Developer
skill: Elite
Dictionaries can also be represented in an abbreviated form if you really want to::
---
# An employee record
{name: Example Developer, job: Developer, skill: Elite}
.. _truthiness:
Ansible doesn't really use these too much, but you can also specify a
boolean value (true/false) in several forms::
---
knows_oop: True
likes_emacs: TRUE
uses_cvs: false
Let's combine what we learned so far in an arbitary YAML example. This really
has nothing to do with Ansible, but will give you a feel for the format::
---
# An employee record
name: Example Developer
job: Developer
skill: Elite
employed: True
foods:
- Apple
- Orange
- Strawberry
- Mango
languages:
ruby: Elite
python: Elite
dotnet: Lame
That's all you really need to know about YAML to get started writing
`Ansible` playbooks.
Gotchas
-------
While YAML is generally friendly, the following is going to be a YAML syntax error:
foo: somebody said I should put a colon here: so I did
You will want to quote any hash values using colons, like so:
foo: "somebody said I should put a colon here: so I did"
And then the colon will be preserved.
.. seealso::
:doc:`playbooks`
Learn what playbooks can do and how to write/run them.
`YAMLLint <http://yamllint.com/>`_
YAML Lint (online) helps you debug YAML syntax if you are having problems
`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
`irc.freenode.net <http://irc.freenode.net>`_
#ansible IRC chat channel

333
docsite/rst/api.rst Normal file
View File

@ -0,0 +1,333 @@
API & Integrations
==================
There are several interesting ways to use Ansible from an API perspective. You can use
the Ansible python API to control nodes, you can extend Ansible to respond to various python events,
and you can plug in inventory data from external data sources. Ansible is written in its own
API so you have a considerable amount of power across the board.
.. contents:: `Table of contents`
:depth: 2
:backlinks: top
Python API
----------
The Python API is very powerful, and is how the ansible CLI and ansible-playbook
are implemented.
It's pretty simple::
import ansible.runner
runner = ansible.runner.Runner(
module_name='ping',
module_args='',
pattern='web*',
forks=10
)
datastructure = runner.run()
The run method returns results per host, grouped by whether they
could be contacted or not. Return types are module specific, as
expressed in the 'ansible-modules' documentation.::
{
"dark" : {
"web1.example.com" : "failure message"
}
"contacted" : {
"web2.example.com" : 1
}
}
A module can return any type of JSON data it wants, so Ansible can
be used as a framework to rapidly build powerful applications and scripts.
Detailed API Example
````````````````````
The following script prints out the uptime information for all hosts::
#!/usr/bin/python
import ansible.runner
import sys
# construct the ansible runner and execute on all hosts
results = ansible.runner.Runner(
pattern='*', forks=10,
module_name='command', module_args='/usr/bin/uptime',
).run()
if results is None:
print "No hosts found"
sys.exit(1)
print "UP ***********"
for (hostname, result) in results['contacted'].items():
if not 'failed' in result:
print "%s >>> %s" % (hostname, result['stdout'])
print "FAILED *******"
for (hostname, result) in results['contacted'].items():
if 'failed' in result:
print "%s >>> %s" % (hostname, result['msg'])
print "DOWN *********"
for (hostname, result) in results['dark'].items():
print "%s >>> %s" % (hostname, result)
Advanced programmers may also wish to read the source to ansible itself, for
it uses the Runner() API (with all available options) to implement the
command line tools ``ansible`` and ``ansible-playbook``.
Plugins Available Online
------------------------
The remainder of features in the API docs have components available in `ansible-plugins <https://github.com/ansible/ansible/blob/devel/plugins>`_. Send us a github pull request if you develop any interesting features.
External Inventory Scripts
--------------------------
Often a user of a configuration management system will want to keep inventory
in a different system. Frequent examples include LDAP, `Cobbler <http://cobbler.github.com>`_,
or a piece of expensive enterprisey CMDB software. Ansible easily supports all
of these options via an external inventory system. The plugins directory contains some of these already -- including options for EC2/Eucalyptus and OpenStack, which will be detailed below.
It's possible to write an external inventory script in any language. If you are familiar with Puppet terminology, this concept is basically the same as 'external nodes', with the slight difference that it also defines which hosts are managed.
Script Conventions
``````````````````
When the external node script is called with the single argument '--list', the script must return a JSON hash/dictionary of all the groups to be managed, with a list of each host/IP as the value for each hash/dictionary element, like so::
{
'databases' : [ 'host1.example.com', 'host2.example.com' ],
'webservers' : [ 'host2.example.com', 'host3.example.com' ],
'atlanta' : [ 'host1.example.com', 'host4.example.com', 'host5.example.com' ]
}
When called with the arguments '--host <hostname>' (where <hostname> is a host from above), the script must return either an empty JSON
hash/dictionary, or a list of key/value variables to make available to templates or playbooks. Returning variables is optional,
if the script does not wish to do this, returning an empty hash/dictionary is the way to go::
{
'favcolor' : 'red',
'ntpserver' : 'wolf.example.com',
'monitoring' : 'pack.example.com'
}
Example: The Cobbler External Inventory Script
``````````````````````````````````````````````
It is expected that many Ansible users will also be `Cobbler <http://cobbler.github.com>`_ users. 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. 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/hosts and `chmod +x` the file. cobblerd will now need
to be running when you are using Ansible.
Test the file by running `./etc/ansible/hosts` directly. You should see some JSON data output, but it may not have
anything in it just yet.
Let's explore what this does. In cobbler, assume a scenario somewhat like the following::
cobbler profile add --name=webserver --distro=CentOS6-x86_64
cobbler profile edit --name=webserver --mgmt-classes="webserver" --ksmeta="a=2 b=3"
cobbler system edit --name=foo --dns-name="foo.example.com" --mgmt-classes="atlanta" --ksmeta="c=4"
cobbler system edit --name=bar --dns-name="bar.example.com" --mgmt-classes="atlanta" --ksmeta="c=5"
In the example above, the system 'foo.example.com' will be addressable by ansible directly, but will also be addressable when using the group names 'webserver' or 'atlanta'. Since Ansible uses SSH, we'll try to contract system foo over 'foo.example.com', only, never just 'foo'. Similarly, if you try "ansible foo" it wouldn't find the system... but "ansible 'foo*'" would, because the system DNS name starts with 'foo'.
The script doesn't just provide host and group info. In addition, as a bonus, when the 'setup' module is run (which happens automatically when using playbooks), the variables 'a', 'b', and 'c' will all be auto-populated in the templates::
# file: /srv/motd.j2
Welcome, I am templated with a value of a={{ a }}, b={{ b }}, and c={{ c }}
Which could be executed just like this::
ansible webserver -m setup
ansible webserver -m template -a "src=/tmp/motd.j2 dest=/etc/motd"
.. note::
The name 'webserver' came from cobbler, as did the variables for
the config file. You can still pass in your own variables like
normal in Ansible, but variables from the external inventory script
will override any that have the same name.
So, with the template above (motd.j2), this would result in the following data being written to /etc/motd for system 'foo'::
Welcome, I am templated with a value of a=2, b=3, and c=4
And on system 'bar' (bar.example.com)::
Welcome, I am templated with a value of a=2, b=3, and c=5
And technically, though there is no major good reason to do it, this also works too::
ansible webserver -m shell -a "echo {{ a }}"
So in other words, you can use those variables in arguments/actions as well. You might use this to name
a conf.d file appropriately or something similar. Who knows?
So that's the Cobbler integration support -- using the cobbler script as an example, it should be trivial to adapt Ansible to pull inventory, as well as variable information, from any data source. If you create anything interesting, please share with the mailing list, and we can keep it in the source code tree for others to use.
Example: AWS EC2 External Inventory Script
``````````````````````````````````````````
If you use Amazon Web Services EC2, maintaining an inventory file might not be the best approach. For this reason, you can use the `EC2 external inventory <https://raw.github.com/ansible/ansible/devel/plugins/inventory/ec2.py>`_ script.
You can use this script in one of two ways. The easiest is to use Ansible's ``-i`` command line option and specify the path to the script.
ansible -i ec2.py -u ubuntu us-east-1d -m ping
The second option is to copy the script to `/etc/ansible/hosts` and `chmod +x` it. You will also need to copy the ``ec2.ini`` file to `/etc/ansible/ec2.ini`. Then you can run ansible as you would normally.
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:
export AWS_ACCESS_KEY_ID='AK123'
export AWS_SECRET_ACCESS_KEY='abc123'
You can test the script by itself to make sure your config is correct
cd examples/scripts
./ec2_external_inventory.py --list
After a few moments, you should see your entire EC2 inventory across all regions in JSON.
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). 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:
Instance ID
These are groups of one since instance IDs are unique.
e.g.
``i-00112233``
``i-a1b1c1d1``
Region
A group of all instances in an AWS region.
e.g.
``us-east-1``
``us-west-2``
Availability Zone
A group of all instances in an availability zone.
e.g.
``us-east-1a``
``us-east-1b``
Security Group
Instances belong to one or more security groups. A group is created for each security group, with all characters except alphanumerics, dashes (-) converted to underscores (_). Each group is prefixed by ``security_group_``
e.g.
``security_group_default``
``security_group_webservers``
``security_group_Pete_s_Fancy_Group``
Tags
Each instance can have a variety of key/value pairs associated with it called Tags. The most common tag key is 'Name', though anything is possible. Each key/value pair is its own group of instances, again with special characters converted to underscores, in the format ``tag_KEY_VALUE``
e.g.
``tag_Name_Web``
``tag_Name_redis-master-001``
``tag_aws_cloudformation_logical-id_WebServerGroup``
When the Ansible is interacting with a specific server, the EC2 inventory script is called again with the ``--host HOST`` option. This looks up the HOST in the index cache to get the instance ID, and then makes an API call to AWS to get information about that specific instance. It then makes information about that instance available as variables to your playbooks. Each variable is prefixed by ``ec2_``. Here are some of the variables available:
- ec2_architecture
- ec2_description
- ec2_dns_name
- ec2_id
- ec2_image_id
- ec2_instance_type
- ec2_ip_address
- ec2_kernel
- ec2_key_name
- ec2_launch_time
- ec2_monitored
- ec2_ownerId
- ec2_placement
- ec2_platform
- ec2_previous_state
- ec2_private_dns_name
- ec2_private_ip_address
- ec2_public_dns_name
- ec2_ramdisk
- ec2_region
- ec2_root_device_name
- ec2_root_device_type
- ec2_security_group_ids
- ec2_security_group_names
- ec2_spot_instance_request_id
- ec2_state
- ec2_state_code
- ec2_state_reason
- ec2_status
- ec2_subnet_id
- ec2_tag_Name
- ec2_tenancy
- ec2_virtualization_type
- ec2_vpc_id
Both ``ec2_security_group_ids`` and ``ec2_security_group_names`` are comma-separated lists of all security groups. Each EC2 tag is a variable in the format ``ec2_tag_KEY``.
To see the complete list of variables available for an instance, run the script by itself::
cd examples/scripts
./ec2_external_inventory.py --host ec2-12-12-12-12.compute-1.amazonaws.com
Example: OpenStack Inventory Script
```````````````````````````````````
Though not detailed here in as much depth as the EC2 module, there's also a OpenStack Nova external inventory source in the plugins directory. See the inline comments in the module source for how to use it.
Callback Plugins
----------------
Ansible can be configured via code to respond to external events. This can include enhancing logging, signalling an external software
system, or even (yes, really) making sound effects. Some examples are contained in the plugins directory.
Connection Type Plugins
-----------------------
By default, ansible ships with a 'paramiko' SSH, native ssh (just called 'ssh'), and 'local' connection type. Release 0.8 also
added an accelerated connection type named 'fireball'. All of these can be used
in playbooks and with /usr/bin/ansible to decide how you want to talk to remote machines. The basics of these connection types
are covered in the 'getting started' section. Should you want to extend Ansible to support other transports (SNMP? Message bus?
Carrier Pigeon?) it's as simple as copying the format of one of the existing modules and dropping it into the connection plugins
directory.
Lookup Plugins
--------------
Language constructs like "with_fileglob" are implemnted via lookup plugins. Just like other plugin types, you can write your own.
Distributing Plugins
--------------------
.. versionadded: 0.8
Plugins are loaded from both Python's site_packages (those that ship with ansible) and a configured plugins directory, which defaults
to /usr/share/ansible/plugins, in a subfolder for each plugin type::
* action_plugins
* lookup_plugins
* callback_plugins
* connection_plugins
To change this path, edit the ansible configuration file.
In addition, plugins can be shipped in a subdirectory relative to a top-level playbook, in folders named the same as indicated above.
.. seealso::
:doc:`modules`
List of built-in modules
`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

@ -0,0 +1,143 @@
Best Practices
==============
Here are some tips for making the most of Ansible.
.. contents::
:depth: 2
:backlinks: top
Always Mention State
++++++++++++++++++++
The 'state' parameter is optional to a lot of modules. Whether
'state=present' or 'state=absent', it's always best to leave that
parameter in your playbooks to make it clear, especially as some
modules support additional states.
Group By Roles
++++++++++++++
A system can be in multiple groups. See :doc:`patterns`. Having groups named after things like
*webservers* and *dbservers* is repeated in the examples because it's a very powerful concept.
This allows playbooks to target machines based on role, as well as to assign role specific variables
using the group variable system.
Directory Organization
++++++++++++++++++++++
Playbooks should be organized like this::
# root of source control repository
├── acme/
│ ├── setup.yml
│ └── stop.yml
├── files/
│ └── some_file_path_foo.conf
├── handlers/
│ └── main.yml
├── tasks/
│ ├── setup.yml
│ └── stop.yml
├── templates/
│ ├── etc_acme_conf_acme.conf
│ └── etc_other_conf_other.conf
├── vars/
│ └── main.yml
└── global_vars.yml
Any directories or files not needed can be omitted. Not all modules
may require 'vars' or 'files' sections, though most will require
'handlers', 'tasks', and 'templates'. To review what each of
these sections do, see :doc:`playbooks` and :doc:`playbooks2`.
The acme/setup.yml playbook would be as simple as::
---
- hosts: webservers
user: root
vars_files:
- ../global_vars.yml
- vars/main.yml
tasks:
- include: tasks/setup.yml
handlers:
- include: handlers/main.yml
The tasks are individually broken out in 'acme/tasks/setup.yml', and handlers, which are common to all task files,
are contained in 'acme/handlers/main.yml'. As a reminder, handlers are mostly just used to notify services to restart
when things change, and these are described in :doc:`playbooks`.
Including more than one setup file or more than one handlers file is of course legal.
Bundling Ansible Modules With Playbooks
+++++++++++++++++++++++++++++++++++++++
.. versionadded:: 0.5
If a playbook has a "./library" directory relative to it's YAML file,
this directory can be used to add ansible modules that will
automatically be in the ansible module path. This is a great way to
keep modules that go with a playbook together.
Miscellaneous Tips
++++++++++++++++++
When you can do something simply, do something simply. Do not reach
to use every feature of Ansible together, all at once. Use what works
for you. For example, you should probably not need 'vars',
'vars_files', 'vars_prompt' and '--extra-vars' all at once,
while also using an external inventory file.
Optimize for readability. Whitespace between sections of YAML
documents and in between tasks is strongly encouraged, as is usage of
YAML comments, which start with '#'. It is also useful to comment
at the top of each file the purpose of the individual file and the
author, including email address.
It is possible to leave off the 'name' for a given task, though it
is recommended to provide a descriptive comment about why something is
being done instead.
Use version control. Keep your playbooks and inventory file in git
(or another version control system), and commit when you make changes
to them. This way you have an audit trail describing when and why you
changed the rules automating your infrastructure.
Resist the urge to write the same playbooks and configuration files
for heterogeneous distributions. While lots of software packages
claim to make this easy on you, the configuration files are often
quite different, to the point where it would be easier to treat them
as different playbooks. This is why, for example, Ansible has a
separate 'yum' and 'apt' module. Yum and apt have different
capabilities, and we don't want to code for the least common
denominator.
Use variables for user tunable settings versus having constants in the
tasks file or templates, so that it is easy to reconfigure a playbook.
Think about this as exposing the knobs to things you would like to
tweak.
Since a system can be in more than one group, if you have multiple
datacenters or sites, consider putting systems into groups by role,
but also different groups by geography. This allows you to assign
different variables to different geographies.
.. seealso::
:doc:`YAMLSyntax`
Learn about YAML syntax
:doc:`playbooks`
Review the basic playbook features
:doc:`modules`
Learn about available modules
:doc:`moduledev`
Learn how to extend Ansible by writing your own modules
:doc:`patterns`
Learn about how to select hosts
`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

263
docsite/rst/examples.rst Normal file
View File

@ -0,0 +1,263 @@
Command Line Examples And Next Steps
====================================
.. highlight:: bash
The following examples show how to use `/usr/bin/ansible` for running
ad hoc tasks. Start here.
For configuration management and deployments, you'll want to pick up on
using `/usr/bin/ansible-playbook` -- the concepts port over directly.
(See :doc:`playbooks` for more information about those)
.. contents::
:depth: 2
:backlinks: top
Parallelism and Shell Commands
``````````````````````````````
Let's use ansible's command line tool to reboot all web servers in Atlanta, 10 at a time. First, let's
set up SSH-agent so it can remember our credentials::
$ ssh-agent bash
$ ssh-add ~/.ssh/id_rsa.pub
If you don't want to use ssh-agent and want to instead SSH with a
password instead of keys, you can with ``--ask-pass`` (``-k``), but
it's much better to just use ssh-agent.
Now to run the command on all servers in a group, in this case,
*atlanta*, in 10 parallel forks::
$ ansible atlanta -a "/sbin/reboot" -f 10
In 0.7 and later, this will default to running from your user account. If you do not like this
behavior, pass in "-u username". (In 0.6 and before, it defaulted to root. Most folks prefered
defaulting to the current user, so we changed it).
If you want to run commands as a different user, it looks like this::
$ ansible atlanta -a "/usr/bin/foo" -u username
If you want to run commands through sudo::
$ ansible atlanta -a "/usr/bin/foo" -u username --sudo [--ask-sudo-pass]
Use ``--ask-sudo-pass`` (``-K``) if you are not using passwordless
sudo. This will interactively prompt you for the password to use.
Use of passwordless sudo makes things easier to automate, but it's not
required.
It is also possible to sudo to a user other than root using
``--sudo-user`` (``-U``)::
$ ansible atlanta -a "/usr/bin/foo" -u username -U otheruser [--ask-sudo-pass]
Ok, so those are basics. If you didn't read about patterns and groups yet, go back and read :doc:`patterns`.
The ``-f 10`` in the above specifies the usage of 10 simultaneous
processes. Normally commands also take a ``-m`` for module name, but
the default module name is 'command', so we didn't need to
specify that all of the time. We'll use ``-m`` in later examples to
run some other :doc:`modules`.
.. note::
The :ref:`command` module requires absolute paths and does not
support shell variables. If we want to execute a module using a
shell, we can do those things, and also use pipe and redirection
operators. Read more about the differences on the :doc:`modules`
page.
Using the :ref:`shell` module looks like this::
$ ansible raleigh -m shell -a 'echo $TERM'
When running any command with the ansible *ad hoc* CLI (as opposed to
:doc:`playbooks`), pay particular attention to shell quoting rules, so
the shell doesn't eat a variable before it gets passed to Ansible.
For example, using double vs single quotes in the above example would
evaluate the variable on the box you were on.
So far we've been demoing simple command execution, but most Ansible modules usually do not work like
simple scripts. They make the remote system look like you state, and run the commands necessary to
get it there. This is commonly referred to as 'idempotence', and is a core design goal of ansible.
However, we also recognize that running *ad hoc* commands is equally important, so Ansible easily supports both.
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 different servers::
$ ansible atlanta -m copy -a "src=/etc/hosts dest=/tmp/hosts"
If you use playbooks, you can also take advantage of the ``template`` module,
which takes this another step further. (See module and playbook documentation).
The ``file`` module allows changing ownership and permissions on files. These
same options can be passed directly to the ``copy`` module as well::
$ ansible webservers -m file -a "dest=/srv/foo/a.txt mode=600"
$ ansible webservers -m file -a "dest=/srv/foo/b.txt mode=600 owner=mdehaan group=mdehaan"
The ``file`` module can also create directories, similar to ``mkdir -p``::
$ ansible webservers -m file -a "dest=/path/to/c mode=644 owner=mdehaan group=mdehaan state=directory"
As well as delete directories (recursively) and delete files::
$ ansible webservers -m file -a "dest=/path/to/c state=absent"
Managing Packages
`````````````````
There are modules available for yum and apt. Here are some examples
with yum.
Ensure a package is installed, but don't update it::
$ ansible webservers -m yum -a "pkg=acme state=installed"
Ensure a package is installed to a specific version::
$ ansible webservers -m yum -a "pkg=acme-1.5 state=installed"
Ensure a package is at the latest version::
$ ansible webservers -m yum -a "pkg=acme state=latest"
Ensure a package is not installed::
$ ansible webservers -m yum -a "pkg=acme state=removed"
Currently Ansible only has modules for managing packages with yum and apt. You can install
for other packages for now using the command module or (better!) contribute a module
for other package managers. Stop by the mailing list for info/details.
Users and Groups
````````````````
The 'user' module allows easy creation and manipulation of
existing user accounts, as well as removal of user accounts that may
exist::
$ ansible all -m user -a "name=foo password=<crypted password here>"
$ ansible all -m user -a "name=foo state=absent"
See the :doc:`modules` section for details on all of the available options, including
how to manipulate groups and group membership.
Deploying From Source Control
`````````````````````````````
Deploy your webapp straight from git::
$ ansible webservers -m git -a "repo=git://foo.example.org/repo.git dest=/srv/myapp version=HEAD"
Since ansible modules can notify change handlers it is possible to
tell ansible to run specific tasks when the code is updated, such as
deploying Perl/Python/PHP/Ruby directly from git and then restarting
apache.
Managing Services
`````````````````
Ensure a service is started on all webservers::
$ ansible webservers -m service -a "name=httpd state=started"
Alternatively, restart a service on all webservers::
$ ansible webservers -m service -a "name=httpd state=restarted"
Ensure a service is stopped::
$ ansible webservers -m service -a "name=httpd state=stopped"
Time Limited Background Operations
``````````````````````````````````
Long running operations can be backgrounded, and their status can be
checked on later. The same job ID is given to the same task on all
hosts, so you won't lose track. If you kick hosts and don't want
to poll, it looks like this::
$ ansible all -B 3600 -a "/usr/bin/long_running_operation --do-stuff"
If you do decide you want to check on the job status later, you can::
$ ansible all -m async_status -a "jid=123456789"
Polling is built-in and looks like this::
$ ansible all -B 1800 -P 60 -a "/usr/bin/long_running_operation --do-stuff"
The above example says "run for 30 minutes max (``-B``: 30*60=1800),
poll for status (``-P``) every 60 seconds".
Poll mode is smart so all jobs will be started before polling will begin on any machine.
Be sure to use a high enough ``--forks`` value if you want to get all of your jobs started
very quickly. After the time limit (in seconds) runs out (``-B``), the process on
the remote nodes will be terminated.
Typically you'll be only be backgrounding long-running
shell commands or software upgrades only. Backgrounding the copy module does not do a background file transfer. :doc:`playbooks` also support polling, and have a simplified syntax for this.
Limiting Selected Hosts
```````````````````````
.. versionadded:: 0.7
What hosts you select to manage can be additionally constrained by using the '--limit' parameter or
by using 'batch' (or 'range') selectors.
As mentioned above, patterns can be strung together to select hosts in more than one group::
$ ansible webservers:dbservers -m command -a "/bin/foo xyz"
This is an "or" condition. If you want to further constrain the selection, use --limit, which
also works with ``ansible-playbook``::
$ ansible webservers:dbservers -m command -a "/bin/foo xyz" --limit region
Now let's talk about range selection. Suppose you have 1000 servers in group 'datacenter', but only want to target one at a time. This is also easy::
$ ansible webservers[0-99] -m command -a "/bin/foo xyz"
$ ansible webservers[100-199] -m command -a "/bin/foo xyz"
This will select the first 100, then the second 100, host entries in the webservers group. (It does not matter
what their names or IP addresses are).
Both of these methods can be used at the same time, and ranges can also be passed to the --limit parameter.
Configuration & Defaults
````````````````````````
.. versionadded:: 0.7
Ansible has an optional configuration file that can be used to tune settings and also eliminate the need to pass various command line flags. Ansible will look for the config file in the following order, using
the first config file it finds present:
1. File specified by the ``ANSIBLE_CONFIG`` environment variable
2. ``ansible.cfg`` in the current working directory. (version 0.8 and up)
3. ``~/.ansible.cfg``
4. ``/etc/ansible/ansible.cfg``
For those running from source, a sample configuration file lives in the examples/ directory. The RPM will install configuration into /etc/ansible/ansible.cfg automatically.
.. seealso::
:doc:`modules`
A list of available modules
:doc:`playbooks`
Using ansible for configuration management & deployment
`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

@ -0,0 +1,247 @@
Getting Started
===============
.. contents::
:depth: 2
:backlinks: top
Requirements
````````````
Requirements for Ansible are extremely minimal.
Ansible is written for Python 2.6. If you are running Python 2.5 on an "Enterprise Linux" variant,
your distribution can easily install 2.6 (see instructions in the next section). Newer versions
of Linux and OS X should already have 2.6.
In additon to Python 2.6, you will want the following packages:
* ``paramiko``
* ``PyYAML``
* ``python-jinja2``
On the managed nodes, you only need Python 2.4 or later, but if you are are running less than Python 2.6 on them, you will
also need:
* ``python-simplejson``
.. note::
Ansible's "raw" module (for executing commands in a quick and dirty
way) and the copy module -- some of the most basic features in
ansible -- don't even need that. So technically, you can use
Ansible to install python-simplejson using the raw module, which
then allows you to use everything else. (That's jumping ahead
though.)
Python 2.6 EPEL instructions for RHEL and CentOS 5
``````````````````````````````````````````````````
These distributions don't have Python 2.6 by default, but it is easily
installable. If you have not already done so, `configure EPEL
<http://fedoraproject.org/wiki/EPEL>`_
.. code-block:: bash
$ yum install python26 python26-PyYAML python26-paramiko python26-jinja2
Getting Ansible
```````````````
If you are interested in using all the latest features, you may wish to keep up to date
with the development branch of the git checkout. This also makes it easiest to contribute
back to the project.
Instructions for installing from source are below.
Ansible's release cycles are about one month long. Due to this
short release cycle, any bugs will generally be fixed in the next release versus maintaining
backports on the stable branch.
You may also wish to follow the `Github project <https://github.com/ansible/ansible>`_ if
you have a github account. This is also where we keep the issue tracker for sharing
bugs and feature ideas.
Running From Checkout
+++++++++++++++++++++
Ansible is trivially easy to run from a checkout, root permissions are not required
to use it:
.. code-block:: bash
$ git clone git://github.com/ansible/ansible.git
$ cd ./ansible
$ source ./hacking/env-setup
You can optionally specify an inventory file (see :doc:`patterns`) other than /etc/ansible/hosts:
.. code-block:: bash
$ echo "127.0.0.1" > ~/ansible_hosts
$ export ANSIBLE_HOSTS=~/ansible_hosts
Now let's test things:
.. code-block:: bash
$ ansible all -m ping --ask-pass
Make Install
++++++++++++
If you are not working from a distribution where Ansible is packaged yet, you can install Ansible
using "make install". This is done through `python-distutils`:
.. code-block:: bash
$ git clone git://github.com/ansible/ansible.git
$ cd ./ansible
$ sudo make install
Via RPM
+++++++
RPMs for the last Ansible release are available for `EPEL
<http://fedoraproject.org/wiki/EPEL>`_ 6 and currently supported
Fedora distributions. Ansible itself can manage earlier operating
systems that contain python 2.4 or higher.
.. code-block:: bash
# install the epel-release RPM if needed on CentOS, RHEL, or Scientific Linux
$ sudo yum install ansible
You can also use the ``make rpm`` command to build an RPM you can
distribute and install:
.. code-block:: bash
$ git clone git://github.com/ansible/ansible.git
$ cd ./ansible
$ make rpm
$ sudo rpm -Uvh ~/rpmbuild/ansible-*.noarch.rpm
Debian, Gentoo, Arch, Others
++++++++++++++++++++++++++++
Ubuntu builds are available `in a PPA here <https://launchpad.net/~rquillo/+archive/ansible>`_
Debian/Ubuntu package recipes can also be built from the source checkout, run:
.. code-block:: bash
$ make debian
Gentoo eBuilds are available `on github here <https://github.com/uu/ubuilds>`_
An Arch PKGBUILD is available on `AUR <https://aur.archlinux.org/packages.php?ID=58621>`_
If you have python3 installed on Arch, you probably want to symlink python to python2:
.. code-block:: bash
$ sudo ln -sf /usr/bin/python2 /usr/bin/python
If you would like to package Ansible for Homebrew, BSD, or others,
please stop by the mailing list and say hi!
Tagged Releases
+++++++++++++++
Tagged releases are available as tar.gz files from the Ansible github
project page:
* `Ansible/downloads <https://github.com/ansible/ansible/downloads>`_
Choosing Between Paramiko and Native SSH
````````````````````````````````````````
By default, ansible uses paramiko to talk to managed nodes over SSH. Paramiko is fast, works
very transparently, requires no configuration, and is a good choice for most users.
However, it does not support some advanced SSH features that folks will want to use.
.. versionadded:: 0.5
If you want to leverage more advanced SSH features (such as Kerberized
SSH or jump hosts), pass the flag "--connection=ssh" to any ansible
command, or set the ANSIBLE_TRANSPORT environment variable to
'ssh'. This will cause Ansible to use openssh tools instead.
If ANSIBLE_SSH_ARGS are not set, ansible will try to use some sensible ControlMaster options
by default. You are free to override this environment variable, but should still pass ControlMaster
options to ensure performance of this transport. With ControlMaster in use, both transports
are roughly the same speed. Without CM, the binary ssh transport is signficantly slower.
If none of this makes sense to you, the default paramiko option is probably fine.
Your first commands
```````````````````
Now that you've installed Ansible, it's time to test it.
Edit (or create) /etc/ansible/hosts and put one or more remote systems in it, for
which you have your SSH key in ``authorized_keys``::
192.168.1.50
aserver.example.org
bserver.example.org
Set up SSH agent to avoid retyping passwords:
.. code-block:: bash
$ ssh-agent bash
$ ssh-add ~/.ssh/id_rsa
(Depending on your setup, you may wish to ansible's --private-key-file option to specify a pem file instead)
Now ping all your nodes:
.. code-block:: bash
$ ansible all -m ping
In Ansible 0.7 and later, ansible will attempt to remote connect to the machines using your current
user name, just like SSH would. In 0.6 and before, this actually defaults to 'root' (we liked the current
user behavior better). To override the remote user name, just use the '-u' parameter.
If you would like to access sudo mode, there are also flags to do that:
.. code-block:: bash
# as bruce
$ ansible all -m ping -u bruce
# as bruce, sudoing to root
$ ansible all -m ping -u bruce --sudo
# as bruce, sudoing to batman
$ ansible all -m ping -u bruce --sudo --sudo-user batman
Now run a live command on all of your nodes:
.. code-block:: bash
$ ansible all -a "/bin/echo hello"
Congratulations. You've just contacted your nodes with Ansible. It's
now time to read some of the more real-world :doc:`examples`, and explore
what you can do with different modules, as well as the Ansible
:doc:`playbooks` language. Ansible is not just about running commands, it
also has powerful configuration management and deployment features. There's more to
explore, but you already have a fully working infrastructure!
.. seealso::
:doc:`examples`
Examples of basic commands
:doc:`playbooks`
Learning ansible's configuration management language
`Mailing List <http://groups.google.com/group/ansible-project>`_
Questions? Help? Ideas? Stop by the list on Google Groups
`irc.freenode.net <http://irc.freenode.net>`_
#ansible IRC chat channel

68
docsite/rst/index.rst Normal file
View File

@ -0,0 +1,68 @@
Ansible Documentation
`````````````````````
This page contains documentation about how to use `Ansible <http://ansible.cc>`_.
Before we dive into playbooks, configuration management, deployment, and orchestration, learn how to get Ansible installed and some
basic information. We'll go over how to execute ad-hoc commands in parallel across your nodes using /usr/bin/ansible. We'll also see
what sort of modules are available in Ansible's core (though you can also write your own, which we'll also show later).
.. toctree::
:maxdepth: 1
gettingstarted
patterns
examples
modules
Overview
````````
.. image:: http://ansible.cc/img/ansible_arch.png
:alt: ansible architecture diagram
:width: 566px
:height: 439px
Playbooks
`````````
Playbooks are Ansible's orchestration language. At a basic level, playbooks can be used to manage configurations and deployments
of remote machines. At a more advanced level, they can sequence multi-tier rollouts involving rolling updates, and can delegate actions
to other hosts, interacting with monitoring servers and load balancers along the way. You can start small and pick up more features
over time as you need them. Playbooks are designed to be human-readable and are developed in a basic text language. There are multiple
ways to organize playbooks and the files they include, and we'll offer up some suggestions on that and making the most out of Ansible.
.. toctree::
:maxdepth: 1
playbooks
playbooks2
bestpractices
YAMLSyntax
Developer Information
`````````````````````
Learn how to build modules of your own in any language. Explore Ansible's Python API and write Python plugins to integrate
with other solutions in your environment.
.. toctree::
:maxdepth: 1
api
moduledev
Miscellaneous
`````````````
A list of some people using Ansible.
.. toctree::
:maxdepth: 1
who_uses_ansible

412
docsite/rst/moduledev.rst Normal file
View File

@ -0,0 +1,412 @@
Module Development
==================
Ansible modules are reusable units of magic that can be used by the Ansible API,
or by the `ansible` or `ansible-playbook` programs.
Modules can be written in any language and are found in the path specified
by `ANSIBLE_LIBRARY_PATH` or the ``--module-path`` command line option.
.. contents::
:depth: 2
:backlinks: top
Tutorial
````````
Let's build a module to get and set the system time. For starters, let's build
a module that just outputs the current time.
We are going to use Python here but any language is possible. Only File I/O and outputing to standard
out are required. So, bash, C++, clojure, Python, Ruby, whatever you want
is fine.
Now Python Ansible modules contain some extremely powerful shortcuts (that all the core modules use)
but first we are going to build a module the very hard way. The reason we do this is because modules
written in any language OTHER than Python are going to have to do exactly this. We'll show the easy
way later.
So, here's an example. You would never really need to build a module to set the system time,
the 'command' module could already be used to do this. Though we're going to make one.
Reading the modules that come with ansible (linked above) is a great way to learn how to write
modules. Keep in mind, though, that some modules in ansible's source tree are internalisms,
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`::
#!/usr/bin/python
import datetime
import json
date = str(datetime.datetime.now())
print json.dumps({
"time" : date
})
Testing Modules
```````````````
There's a useful test script in the source checkout for ansible::
git clone git@github.com:ansible/ansible.git
chmod +x ansible/hacking/test-module
Let's run the script you just wrote with that::
ansible/hacking/test-module -m ./time
You should see output that looks something like this::
{u'time': u'2012-03-14 22:13:48.539183'}
If you did not, you might have a typo in your module, so recheck it and try again.
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.
Ansible internally saves arguments to an arguments file. So we must read the file
and parse it. The arguments file is just a string, so any form of arguments are legal.
Here we'll do some basic parsing to treat the input as key=value.
The example usage we are trying to achieve to set the time is::
time time="March 14 22:10"
If no time parameter is set, we'll just leave the time as is and return the current time.
.. note:
This is obviously an unrealistic idea for a module. You'd most likely just
use the shell module. However, it probably makes a decent tutorial.
Let's look at the code. Read the comments as we'll explain as we go. Note that this
is highly verbose because it's intended as an educational example. You can write modules
a lot shorter than this::
#!/usr/bin/python
# import some python modules that we'll use. These are all
# available in Python's core
import datetime
import sys
import json
import os
import shlex
# read the argument string from the arguments file
args_file = sys.argv[1]
args_data = file(args_file).read()
# for this module, we're going to do key=value style arguments
# this is up to each module to decide what it wants, but all
# core modules besides 'command' and 'shell' take key=value
# so this is highly recommended
arguments = shlex.split(args_data)
for arg in arguments:
# ignore any arguments without an equals in it
if arg.find("=") != -1:
(key, value) = arg.split("=")
# if setting the time, the key 'time'
# will contain the value we want to set the time to
if key == "time":
# now we'll affect the change. Many modules
# will strive to be 'idempotent', meaning they
# will only make changes when the desired state
# expressed to the module does not match
# the current state. Look at 'service'
# or 'yum' in the main git tree for an example
# of how that might look.
rc = os.system("date -s \"%s\"" % value)
# always handle all possible errors
#
# when returning a failure, include 'failed'
# in the return data, and explain the failure
# in 'msg'. Both of these conventions are
# required however additional keys and values
# can be added.
if rc != 0:
print json.dumps({
"failed" : True,
"msg" : "failed setting the time"
})
sys.exit(1)
# when things do not fail, we do not
# have any restrictions on what kinds of
# data are returned, but it's always a
# good idea to include whether or not
# a change was made, as that will allow
# notifiers to be used in playbooks.
date = str(datetime.datetime.now())
print json.dumps({
"time" : date,
"changed" : True
})
sys.exit(0)
# if no parameters are sent, the module may or
# may not error out, this one will just
# return the time
date = str(datetime.datetime.now())
print json.dumps({
"time" : date
})
Let's test that module::
ansible/hacking/test-module -m ./time -a time=\"March 14 12:23\"
This should return something like::
{"changed": True, "time": "2012-03-14 12:23:00.000307"}
Module Provided 'Facts'
```````````````````````
The 'setup' module that ships with Ansible provides many variables about a system that can be used in playbooks
and templates. However, it's possible to also add your own facts without modifying the system module. To do
this, just have the module return a `ansible_facts` key, like so, along with other return data::
{
"changed" : True,
"rc" : 5,
"ansible_facts" : {
"leptons" : 5000
"colors" : {
"red" : "FF0000",
"white" : "FFFFFF"
}
}
}
These 'facts' will be available to all statements called after that module (but not before) in the playbook.
A good idea might be make a module called 'site_facts' and always call it at the top of each playbook, though
we're always open to improving the selection of core facts in Ansible as well.
Common Module Boilerplate
`````````````````````````
As mentioned, if you are writing a module in Python, there are some very powerful shortcuts you can use.
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/tree/devel/library>`_ that come with Ansible.
The 'group' and 'user' modules are reasonably non-trival and showcase what this looks like.
Key parts include always ending the module file with::
# include magic from lib/ansible/module_common.py
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
main()
And instantiating the module class like::
module = AnsibleModule(
argument_spec = dict(
state = dict(default='present', choices=['present', 'absent']),
name = dict(required=True),
enabled = dict(required=True, choices=BOOLEANS),
something = dict(aliases=['whatever'])
)
)
The AnsibleModule provides lots of common code for handling returns, parses your arguments
for you, and allows you to check inputs.
Successful returns are made like this::
module.exit_json(changed=True, something_else=12345)
And failures are just as simple (where 'msg' is a required parameter to explain the error)::
module.fail_json(msg="Something fatal happened")
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
source checkout. Because of the magic involved, this is really the only way the scripts
can function outside of Ansible.
If submitting a module to ansible's core code, which we encourage, use of the AnsibleModule
class is required.
Common Pitfalls
```````````````
You should also never do this in a module::
print "some status message"
Because the output is supposed to be valid JSON. Except that's not quite true,
but we'll get to that later.
Modules must not output anything on standard error, because the system will merge
standard out with standard error and prevent the JSON from parsing. Capturing standard
error and returning it as a variable in the JSON on standard out is fine, and is, in fact,
how the command module is implemented.
If a module returns stderr or otherwise fails to produce valid JSON, the actual output
will still be shown in Ansible, but the command will not succeed.
Always use the hacking/test-module script when developing modules and it will warn
you about these kind of things.
Conventions/Recomendations
``````````````````````````
As a reminder from the example code above, here are some basic conventions
and guidelines:
* If the module is addressing an object, the parameter for that object should be called 'name' whenever possible, or accept 'name' as an alias.
* If you have a company module that returns facts specific to your installations, a good name for this module is `site_facts`.
* Modules accepting boolean status should generally accept 'yes', 'no', 'true', 'false', or anything else a user may likely throw at them. The AnsibleModule common code supports this with "choices=BOOLEANS" and a module.boolean(value) casting function.
* 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.
* 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.
* Modules should return JSON or key=value results all on one line. JSON is best if you can do JSON. All return types must be hashes (dictionaries) although they can be nested. Lists or simple scalar values are not supported, though they can be trivially contained inside a dictionary.
* 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 signficant, but continue on with 0=success and non-zero=failure for reasons of future proofing.
* As results from many hosts will be aggregrated at once, modules should return only relevant output. Returning the entire contents of a log file is generally bad form.
Shorthand Vs JSON
`````````````````
To make it easier to write modules in bash and in cases where a JSON
module might not be available, it is acceptable for a module to return
key=value output all on one line, like this. The Ansible parser
will know what to do::
somekey=1 somevalue=2 rc=3 favcolor=red
If you're writing a module in Python or Ruby or whatever, though, returning
JSON is probably the simplest way to go.
Documenting Your Module
```````````````````````
All modules included in the CORE distribution must have a
``DOCUMENTATION`` string. This string MUST be a valid YAML document
which conforms to the schema defined below. You may find it easier to
start writing your ``DOCUMENTATION`` string in an editor with YAML
syntax highlighting before you include it in your Python file.
Example
+++++++
Here's a correctly formatted YAML document we could use for a
``DOCUMENTATION`` string:
.. literalinclude:: ../DOCUMENTATION.yaml
This is available in the 'examples/' directory of the of the Ansible
github repository, and you can have that generated with
``./hacking/module_formatter.py -G``. You can copy it into your module and use
it as a starting point when writing your own docs.
Include it in your module file like this::
#!/usr/bin/env python
# Copyright header....
DOCUMENTATION = '''
---
module: modulename
short_description: This is a sentence describing the module
# ... snip ...
examples:
- code: modulename opt1=arg1 opt2=arg2
description: Optional words describing this example
'''
Building & Testing
++++++++++++++++++
Put your completed module file into the 'library' directory and then
run the command: ``make webdocs``. The new 'modules.html' file will be
built and appear in the 'docsite/' directory.
You can also test-build your docs one-by-one using the
``module_formatter.py`` script:
.. code-block:: bash
$ ./hacking/module_formatter.py -t man -M library/ -m git > ansible-git.1
$ man ./ansible-git.1
This will build a manpage for the git module, and look in the
'library/' directory for the module source. To see all the other
output formats available:
.. code-block:: bash
$ ./hacking/module_formatter.py -t --help
.. tip::
If you're having a problem with the syntax of your YAML you can
validate it on the `YAML Lint <http://www.yamllint.com/>`_ website.
Sharing Your Module
```````````````````
If you think your module is generally useful to others, a good place to share it
is in `Ansible Resources <https://github.com/ansible/ansible/tree/devel/contrib>`_. This is maintained
as a simple repo with pointers to other github projects.
Contrib modules here can be implemented in a variety of languages.
We would like to build up as many of these as possible in as many languages as possible.
`Ansible Mailing List <http://groups.google.com/group/ansible-project>`_
Getting Your Module Into Core
`````````````````````````````
High-quality modules with minimal dependencies
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.
.. seealso::
:doc:`modules`
Learn about available modules
`Ansible Resources <https://github.com/ansible/ansible/tree/devel/contrib>`_
User contributed playbooks, modules, and articles
`Github modules directory <https://github.com/ansible/ansible/tree/devel/library>`_
Browse source of core modules
`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

74
docsite/rst/modules.rst Normal file
View File

@ -0,0 +1,74 @@
Ansible Modules
===============
.. contents::
:depth: 2
:backlinks: top
Introduction
````````````
Ansible ships with a number of modules (called the 'module library')
that can be executed directly on remote hosts or through :doc:`playbooks`.
Users can also write their own modules. These modules can control system
resources, like services, packages, or files (anything really), or
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=running"
ansible webservers -m ping
ansible webservers -m command -a "/sbin/reboot -t now"
Each module supports taking arguments. Nearly all modules take ``key=value``
arguments, space delimited. Some modules take no arguments, and the
command/shell modules simply take the string of the command you want to run.
From playbooks, Ansible modules are executed in a very similar way::
- name: reboot the servers
action: command /sbin/reboot -t now
All modules technically return JSON format data, though if you are using the
command line or playbooks, you don't really need to know much about
that. If you're writing your own module, you care, and this means you do
not have to write modules in any particular language -- you get to choose.
Modules are `idempotent`, meaning they will seek to avoid changes to the system unless a change needs to be made. When using Ansible
playbooks, these modules can trigger 'change events' in the form of notifying 'handlers'
to run additional tasks.
Let's see what's available in the Ansible module library, out of the box:
.. include:: modules/_list.rst
Additional Contrib Modules
``````````````````````````
In addition to the following built-in modules, community modules are available at `Ansible Resources <http://github.com/ansible/ansible-resources>`_.
Writing your own modules
````````````````````````
See :doc:`moduledev`.
.. seealso::
`Ansible Resources (Contrib) <https://github.com/ansible/ansible-resources>`_
User contributed playbooks, modules, and articles
:doc:`examples`
Examples of using modules in /usr/bin/ansible
:doc:`playbooks`
Examples of using modules with /usr/bin/ansible-playbook
:doc:`moduledev`
How to write your own modules
:doc:`api`
Examples of using modules with the Python API
`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

215
docsite/rst/patterns.rst Normal file
View File

@ -0,0 +1,215 @@
.. _patterns:
Inventory & Patterns
====================
Ansible works against multiple systems in your infrastructure at the
same time. It does this by selecting portions of systems listed in
Ansible's inventory file, which defaults to /etc/ansible/hosts.
.. contents:: `Table of contents`
:depth: 2
:backlinks: top
.. _inventoryformat:
Hosts and Groups
++++++++++++++++
The format for /etc/ansible/hosts is an INI format and looks like this::
mail.example.com
[webservers]
foo.example.com
bar.example.com
[dbservers]
one.example.com
two.example.com
three.example.com
The things in brackets are group names. You don't have to have them,
but they are useful.
If you have hosts that run on non-standard SSH ports you can put the port number
after the hostname with a colon.
four.example.com:5309
In 0.6 and later, if you have a lot of hosts following similar patterns you can do this rather than listing each hostname::
[webservers]
www[01:50].example.com
Leading zeros can be included or removed, as desired, and the ranges are inclusive.
Selecting Targets
+++++++++++++++++
We'll go over how to use the command line in :doc:`examples` section, however, basically it looks like this::
ansible <pattern_goes_here> -m <module_name> -a <arguments>
Such as::
ansible webservers -m service -a "name=httpd state=restarted"
Within :doc:`playbooks`, these patterns can be used for even greater purposes.
Anyway, to use Ansible, you'll first need to know how to tell Ansible which hosts in your inventory file to talk to.
This is done by designating particular host names or groups of hosts.
The following patterns target all hosts in the inventory file::
all
*
Basically 'all' is an alias for '*'. It is also possible to address a specific host or hosts::
one.example.com
one.example.com:two.example.com
192.168.1.50
192.168.1.*
The following patterns address one or more groups, which are denoted
with the aforementioned bracket headers in the inventory file::
webservers
webservers:dbservers
You can exclude groups as well, for instance, all webservers not in Phoenix::
webservers:!phoenix
Individual host names (or IPs), but not groups, can also be referenced using
wildcards::
*.example.com
*.com
It's also ok to mix wildcard patterns and groups at the same time::
one*.com:dbservers
Easy enough. See :doc:`examples` and then :doc:`playbooks` for how to do things to selected hosts.
Host Variables
++++++++++++++
It is easy to assign variables to hosts that will be used later in playbooks::
[atlanta]
host1 http_port=80 maxRequestsPerChild=808
host2 http_port=303 maxRequestsPerChild=909
Group Variables
+++++++++++++++
Variables can also be applied to an entire group at once::
[atlanta]
host1
host2
[atlanta:vars]
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com
Groups of Groups, and Group Variables
+++++++++++++++++++++++++++++++++++++
It is also possible to make groups of groups and assign
variables to groups. These variables can be used by /usr/bin/ansible-playbook, but not
/usr/bin/ansible::
[atlanta]
host1
host2
[raleigh]
host2
host3
[southeast:children]
atlanta
raleigh
[southeast:vars]
some_server=foo.southeast.example.com
halon_system_timeout=30
self_destruct_countdown=60
escape_pods=2
[usa:children]
southeast
northeast
southwest
southeast
If you need to store lists or hash data, or prefer to keep host and group specific variables
seperate from the inventory file, see the next section.
Splitting Out Host and Group Specific Data
++++++++++++++++++++++++++++++++++++++++++
.. versionadded:: 0.6
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. These variable files are in YAML format.
Assuming the inventory file path is::
/etc/ansible/hosts
If the host is named 'foosball', and in groups 'raleigh' and 'webservers', variables
in YAML files at the following locations will be made available to the host::
/etc/ansible/group_vars/raleigh
/etc/ansible/group_vars/webservers
/etc/ansible/host_vars/foosball
For instance, suppose you have hosts grouped by datacenter, and each datacenter
uses some different servers. The data in the groupfile '/etc/ansible/group_vars/raleigh' for
the 'raleigh' group might look like::
---
ntp_server: acme.example.org
database_server: storage.example.org
It is ok if these files do not exist, this is an optional feature.
Tip: Keeping your inventory file and variables in a git repo (or other version control)
is an excellent way to track changes to your inventory and host variables.
.. versionadded:: 0.5
If you ever have two python interpreters on a system, set a
variable called 'ansible_python_interpreter' to the Python
interpreter path you would like to use.
YAML Inventory
++++++++++++++
.. deprecated:: 0.7
Ansible's YAML inventory format is deprecated and will be removed in
Ansible 0.7. Ansible 0.6 includes a `conversion script
<https://github.com/ansible/ansible/blob/devel/examples/scripts/yaml_to_ini.py>`_.
Usage::
yaml_to_ini.py /etc/ansible/hosts
.. seealso::
:doc:`examples`
Examples of basic commands
:doc:`playbooks`
Learning ansible's configuration management language
`Mailing List <http://groups.google.com/group/ansible-project>`_
Questions? Help? Ideas? Stop by the list on Google Groups
`irc.freenode.net <http://irc.freenode.net>`_
#ansible IRC chat channel

436
docsite/rst/playbooks.rst Normal file
View File

@ -0,0 +1,436 @@
Playbooks
=========
.. contents::
:depth: 2
:backlinks: top
Introduction
````````````
Playbooks are a completely different way to use ansible than in task execution mode, and are
particularly powerful. Simply put, playbooks are the basis for a really simple
configuration management and multi-machine deployment system,
unlike any that already exist, and one that is very well suited to deploying complex applications.
Playbooks can declare configurations, but they can also orchestrate steps of
any manual ordered process, even as different steps must bounce back and forth
between sets of machines in particular orders. They can launch tasks
synchronously or asynchronously.
While you might run the main /usr/bin/ansible program for ad-hoc
tasks, playbooks are more likely to be kept in source control and used
to push out your configuration or assure the configurations of your
remote systems are in spec.
Let's dive in and see how they work. As you go, you may wish to open
the `github examples directory <https://github.com/ansible/ansible/tree/devel/examples/playbooks>`_ in
another tab, so you can apply the theory to what things look like in practice.
Playbook Language Example
`````````````````````````
Playbooks are expressed in YAML format and have a minimum of syntax.
Each playbook is composed of one or more 'plays' in a list.
The goal of a play is map a group of hosts to some well defined roles, represented by
things ansible called tasks. At the basic level, a task is nothing more than a call
to an ansible module, which you should have learned about in earlier chapters.
By composing a playbook of multiple 'plays', it is possible to
orchestrate multi-machine deployments, running certain steps on all
machines in the webservers group, then certain steps on the database
server group, then more commands back on the webservers group, etc.
For starters, here's a playbook that contains just one play::
---
- hosts: webservers
vars:
http_port: 80
max_clients: 200
user: root
tasks:
- name: ensure apache is at the latest version
action: yum pkg=httpd state=latest
- name: write the apache config file
action: template src=/srv/httpd.j2 dest=/etc/httpd.conf
notify:
- restart apache
- name: ensure apache is running
action: service name=httpd state=started
handlers:
- name: restart apache
action: service name=httpd state=restarted
Below, we'll break down what the various features of the playbook language are.
Basics
``````
Hosts and Users
+++++++++++++++
For each play in a playbook, you get to choose which machines in your infrastructure
to target and what remote user to complete the steps (called tasks) as.
The `hosts` line is a list of one or more groups or host patterns,
separated by colons, as described in the :ref:`patterns`
documentation. The `user` is just the name of the user account::
---
- hosts: webservers
user: root
Support for running things from sudo is also available::
---
- hosts: webservers
user: yourname
sudo: True
You can also login as you, and then sudo to different users than root::
---
- hosts: webservers
user: yourname
sudo: True
sudo_user: postgres
If you need to specify a password to sudo, run `ansible-playbook` with ``--ask-sudo-pass`` (`-K`).
If you run a sudo playbook and the playbook seems to hang, it's probably stuck at the sudo prompt.
Just `Control-C` to kill it and run it again with `-K`.
.. important::
When using `sudo_user` to a user other than root, the module
arguments are briefly written into a random tempfile in /tmp.
These are deleted immediately after the command is executed. This
only occurs when sudoing from a user like 'bob' to 'timmy', not
when going from 'bob' to 'root', or logging in directly as 'bob' or
'root'. If this concerns you that this data is briefly readable
(not writeable), avoid transferring uncrypted passwords with
`sudo_user` set. In other cases, '/tmp' is not used and this does
not come into play. Ansible also takes care to not log password
parameters.
Vars section
++++++++++++
The `vars` section contains a list of variables and values that can be used in the plays, like this::
---
- hosts: webservers
user: root
vars:
http_port: 80
van_halen_port: 5150
other: 'magic'
These variables can be used later in the playbook like this::
$varname or ${varname}
The later is useful in the event you need to do something like ${other}_some_string.
Inside templates, the full power of the `Jinja2 <http://jinja.pocoo.org/docs/>`_ templating language is also available, which looks like this::
{{ varname }}
The Jinja2 documentation provides information about how to construct loops and conditionals for those
who which to use more advanced templating. This is optional and the $varname format still works in template
files.
If there are discovered variables about the system, called 'facts', these variables bubble up back into the
playbook, and can be used on each system just like explicitly set variables. Ansible provides several
of these, prefixed with 'ansible', and are documented under 'setup' in the module documentation. Additionally,
facts can be gathered by ohai and facter if they are installed. Facter variables are prefixed with ``facter_`` and Ohai
variables are prefixed with ``ohai_``.
So for instance, if I wanted
to write the hostname into the /etc/motd file, I could say::
- name: write the motd
action: template src=/srv/templates/motd.j2 dest=/etc/motd
And in /srv/templates/motd.j2::
You are logged into {{ facter_hostname }}
But we're getting ahead of ourselves. Let's talk about tasks.
Tasks list
++++++++++
Each play contains a list of tasks. Tasks are executed in order, one
at a time, against all machines matched by the host pattern,
before moving on to the next task. It is important to understand that, within a play,
all hosts are going to get the same task directives. It is the purpose of a play to map
a selection of hosts to tasks.
When running the playbook, which runs top to bottom, hosts with failed tasks are
taken out of the rotation for the entire playbook. If things fail, simply correct the playbook file and rerun.
The goal of each task is to execute a module, with very specific arguments.
Variables, as mentioned above, can be used in arguments to modules.
Modules are 'idempotent', meaning if you run them
again, they will make the changes they are told to make to bring the
system to the desired state. This makes it very safe to rerun
the same playbook multiple times. They won't change things
unless they have to change things.
The `command` and `shell` modules will typically rerun the same command again,
which is totally ok if the command is something like
'chmod' or 'setsebool', etc. Though there is a 'creates' flag available which can
be used to make these modules also idempotent.
Every task should have a `name`, which is included in the output from
running the playbook. This is output for humans, so it is
nice to have reasonably good descriptions of each task step. If the name
is not provided though, the string fed to 'action' will be used for
output.
Here is what a basic task looks like, as with most modules,
the service module takes key=value arguments::
tasks:
- name: make sure apache is running
action: service name=httpd state=running
The `command` and `shell` modules are the one modules that just takes a list
of arguments, and don't use the key=value form. This makes
them work just like you would expect. Simple::
tasks:
- name: disable selinux
action: command /sbin/setenforce 0
The command and shell module care about return codes, so if you have a command
who's successful exit code is not zero, you may wish to do this::
tasks:
- name: run this command and ignore the result
action: shell /usr/bin/somecommand && /bin/true
If the action line is getting too long for comfort you can break it on
a space and indent any continuation lines::
tasks:
- name: Copy ansible inventory file to client
action: copy src=/etc/ansible/hosts dest=/etc/ansible/hosts
owner=root group=root mode=0644
Variables can be used in action lines. Suppose you defined
a variable called 'vhost' in the 'vars' section, you could do this::
tasks:
- name: create a virtual host file for $vhost
action: template src=somefile.j2 dest=/etc/httpd/conf.d/$vhost
Those same variables are usable in templates, which we'll get to later.
Now in a very basic playbook all the tasks will be listed directly in that play, though it will usually
make more sense to break up tasks using the 'include:' directive. We'll show that a bit later.
Action Shorthand
````````````````
.. versionadded: 0.8
Rather than listing out the explicit word, "action:", like so::
action: template src=templates/foo.j2 dest=/etc/foo.conf
It is also possible to say:
template: src=templates/foo.j2 dest=/etc/foo.conf
The name of the module is simply followed by a colon and the arguments to that module. We think this is a lot more intuitive.
Our documentation has not converted over to this new format just yet as many users may still be using older versions.
You'll be able to use both formats forever.
Running Operations On Change
````````````````````````````
As we've mentioned, modules are written to be 'idempotent' and can relay when
they have made a change on the remote system. Playbooks recognize this and
have a basic event system that can be used to respond to change.
These 'notify' actions are triggered at the end of each 'play' in a playbook, and
trigger only once each. For instance, multiple resources may indicate
that apache needs to be restarted, but apache will only be bounced once.
Here's an example of restarting two services when the contents of a file
change, but only if the file changes::
- name: template configuration file
action: template src=template.j2 dest=/etc/foo.conf
notify:
- restart memcached
- restart apache
The things listed in the 'notify' section of a task are called
handlers.
Handlers are lists of tasks, not really any different from regular
tasks, that are referenced by name. Handlers are what notifiers
notify. If nothing notifies a handler, it will not run. Regardless
of how many things notify a handler, it will run only once, after all
of the tasks complete in a particular play.
Here's an example handlers section::
handlers:
- name: restart memcached
action: service name=memcached state=restarted
- name: restart apache
action: service name=apache state=restarted
Handlers are best used to restart services and trigger reboots. You probably
won't need them for much else.
.. note::
Notify handlers are always run in the order written.
Include Files And Encouraging Reuse
```````````````````````````````````
Suppose you want to reuse lists of tasks between plays or playbooks. You can use
include files to do this. Use of included task lists is a great way to define a role
that system is going to fulfill. Remember, the goal of a play in a playbook is to map
a group of systems into multiple roles. Let's see what this looks like...
A task include file simply contains a flat list of tasks, like so::
---
# possibly saved as tasks/foo.yml
- name: placeholder foo
action: command /bin/foo
- name: placeholder bar
action: command /bin/bar
Include directives look like this, and can be mixed in with regular tasks in a playbook::
tasks:
- include: tasks/foo.yml
You can also pass variables into includes. We call this a 'parameterized include'.
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 user=timmy
- include: wordpress.yml user=alice
- include: wordpress.yml user=bob
Variables passed in can then be used in the included files. You can reference them like this::
$user
(In addition to the explicitly passed in parameters, all variables from
the vars section are also available for use here as well.)
.. note::
Task include statements are only usable one-level deep.
This means task includes can not include other
task includes. This may change in a later release.
Includes can also be used in the 'handlers' section, for instance, if you
want to define how to restart apache, you only have to do that once for all
of your playbooks. You might make a handlers.yml that looks like::
---
# this might be in a file like handlers/handlers.yml
- name: restart apache
action: service name=apache state=restarted
And in your main playbook file, just include it like so, at the bottom
of a play::
handlers:
- include: handlers/handlers.yml
You can mix in includes along with your regular non-included tasks and handlers.
Includes can also be used to import one playbook file into another. This allows
you to define a top-level playbook that is composed of other playbooks.
For example::
- name: this is a play at the top level of a file
hosts: all
user: root
tasks:
- name: say hi
tags: foo
action: shell echo "hi..."
- include: load_balancers.yml
- include: webservers.yml
- include: dbservers.yml
Note that you cannot do variable substitution when including one playbook
inside another.
.. note::
You can not conditionally path the location to an include file,
like you can with 'vars_files'. If you find yourself needing to do
this, consider how you can restructure your playbook to be more
class/role oriented. This is to say you cannot use a 'fact' to
decide what include file to use. All hosts contained within the
play are going to get the same tasks. ('only_if' provides some
ability for hosts to conditionally skip tasks).
Executing A Playbook
````````````````````
Now that you've learned playbook syntax, how do you run a playbook? It's simple.
Let's run a playbook using a parallelism level of 10::
ansible-playbook playbook.yml -f 10
Tips and Tricks
```````````````
Look at the bottom of the playbook execution for a summary of the nodes that were executed
and how they performed. General failures and fatal "unreachable" communication attempts are
kept seperate in the counts.
If you ever want to see detailed output from successful modules as well as unsuccessful ones,
use the '--verbose' flag. This is available in Ansible 0.5 and later.
Also, in version 0.5 and later, Ansible playbook output is vastly upgraded if the cowsay
package is installed. Try it!
In version 0.7 and later, to see what hosts would be affected by a playbook before you run it, you
can do this::
ansible-playbook playbook.yml --list-hosts.
.. seealso::
:doc:`YAMLSyntax`
Learn about YAML syntax
:doc:`playbooks`
Review the basic Playbook language features
:doc:`playbooks2`
Learn about Advanced Playbook Features
:doc:`bestpractices`
Various tips about managing playbooks in the real world
:doc:`modules`
Learn about available modules
:doc:`moduledev`
Learn how to extend Ansible by writing your own modules
:doc:`patterns`
Learn about how to select hosts
`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

700
docsite/rst/playbooks2.rst Normal file
View File

@ -0,0 +1,700 @@
Advanced Playbooks
==================
Here are some advanced features of the playbooks language. Using all of these features
are not neccessary, but many of them will prove useful. If a feature doesn't seem immediately
relevant, feel free to skip it. For many people, the features documented in `playbooks` will
be 90% or more of what they use in Ansible.
.. contents::
:depth: 2
:backlinks: top
Tags
````
.. versionadded:: 0.6
If you have a large playbook it may become useful to be able to run a
specific part of the configuration. Both plays and tasks support a
"tags:" attribute for this reason.
Example::
tasks:
- action: yum name=$item state=installed
with_items:
- httpd
- memcached
tags:
- packages
- action: template src=templates/src.j2 dest=/etc/foo.conf
tags:
- configuration
If you wanted to just run the "configuration" and "packages" part of a very long playbook, you could do this::
ansible-playbook example.yml --tags "configuration,packages"
Playbooks Including Playbooks
`````````````````````````````
.. versionadded:: 0.6
To further advance the concept of include files, playbook files can
include other playbook files. Suppose you define the behavior of all
your webservers in "webservers.yml" and all your database servers in
"dbservers.yml". You can create a "site.yml" that would reconfigure
all of your systems like this::
----
- include: playbooks/webservers.yml
- include: playbooks/dbservers.yml
This concept works great with tags to rapidly select exactly what plays you want to run, and exactly
what parts of those plays.
Ignoring Failed Commands
````````````````````````
.. versionadded:: 0.6
Generally playbooks will stop executing any more steps on a host that
has a failure. Sometimes, though, you want to continue on. To do so,
write a task that looks like this::
- name: this will not be counted as a failure
action: command /bin/false
ignore_errors: True
Accessing Complex Variable Data
```````````````````````````````
Some provided facts, like networking information, are made available as nested data structures. To access
them a simple '$foo' is not sufficient, but it is still easy to do. Here's how we get an IP address::
${ansible_eth0.ipv4.address}
It is also possible to access variables whose elements are arrays::
${somelist[0]}
And the array and hash reference syntaxes can be mixed.
In templates, the simple access form still holds, but they can also be accessed from Jinja2 in more Python-native ways if
that is preferred::
{{ ansible_eth0["ipv4"]["address"] }}
Accessing Information About Other Hosts
```````````````````````````````````````
If your database server wants to check the value of a 'fact' from another node, or an inventory variable
assigned to another node, it's easy to do so within a template or even an action line::
${hostvars.hostname.factname}
.. note::
No database or other complex system is required to exchange data
between hosts. The hosts that you want to reference data from must
be included in either the current play or any previous play if you
are using a version prior to 0.8. If you are using 0.8, and you have
not yet contacted the host, you'll be able to read inventory variables
but not fact variables. Speak to the host by including it in a play
to make fact information available.
Additionally, *group_names* is a list (array) of all the groups the current host is in. This can be used in templates using Jinja2 syntax to make template source files that vary based on the group membership (or role) of the host::
{% if 'webserver' in group_names %}
# some part of a configuration file that only applies to webservers
{% endif %}
*groups* is a list of all the groups (and hosts) in the inventory. This can be used to enumerate all hosts within a group.
For example::
{% for host in groups['app_servers'] %}
# something that applies to all app servers.
{% endfor %}
Use cases include pointing a frontend proxy server to all of the app servers, setting up the correct firewall rules between servers, etc.
*inventory_hostname* is the name of the hostname as configured in Ansible's inventory host file. This can
be useful for when you don't want to rely on the discovered hostname `ansible_hostname` or for other mysterious
reasons. If you have a long FQDN, *inventory_hostname_short* (in Ansible 0.6) also contains the part up to the first
period.
Don't worry about any of this unless you think you need it. You'll know when you do.
Variable File Seperation
````````````````````````
It's a great idea to keep your playbooks under source control, but
you may wish to make the playbook source public while keeping certain
important variables private. Similarly, sometimes you may just
want to keep certain information in different files, away from
the main playbook.
You can do this by using an external variables file, or files, just like this::
---
- hosts: all
user: root
vars:
favcolor: blue
vars_files:
- /vars/external_vars.yml
tasks:
- name: this is just a placeholder
action: command /bin/echo foo
This removes the risk of sharing sensitive data with others when
sharing your playbook source with them.
The contents of each variables file is a simple YAML dictionary, like this::
---
# in the above example, this would be vars/external_vars.yml
somevar: somevalue
password: magic
.. note::
It's also possible to keep per-host and per-group variables in very
similar files, this is covered in :ref:`patterns`.
Prompting For Sensitive Data
````````````````````````````
You may wish to prompt the user for certain input, and can
do so with the similarly named 'vars_prompt' section. This has uses
beyond security, for instance, you may use the same playbook for all
software releases and would prompt for a particular release version
in a push-script::
---
- hosts: all
user: root
vars:
from: "camelot"
vars_prompt:
name: "what is your name?"
quest: "what is your quest?"
favcolor: "what is your favorite color?"
There are full examples of both of these items in the github examples/playbooks directory.
An alternative form of vars_prompt allows for hiding input from the user, and may later support
some other options, but otherwise works equivalently::
vars_prompt:
- name: "some_password"
prompt: "Enter password"
private: True
- name: "release_version"
prompt: "Product release version"
private: False
Passing Variables On The Command Line
`````````````````````````````````````
In addition to `vars_prompt` and `vars_files`, it is possible to send variables over
the ansible command line. This is particularly useful when writing a generic release playbook
where you may want to pass in the version of the application to deploy::
ansible-playbook release.yml --extra-vars "version=1.23.45 other_variable=foo"
This is useful, for, among other things, setting the hosts group or the user for the playbook.
Example::
-----
- user: $user
hosts: $hosts
tasks:
- ...
ansible-playbook release.yml --extra-vars "hosts=vipers user=starbuck"
Conditional Execution
`````````````````````
Sometimes you will want to skip a particular step on a particular host. This could be something
as simple as not installing a certain package if the operating system is a particular version,
or it could be something like performing some cleanup steps if a filesystem is getting full.
This is easy to do in Ansible, with the `only_if` clause, which actually is a Python expression.
Don't panic -- it's actually pretty simple::
vars:
favcolor: blue
is_favcolor_blue: "'$favcolor' == 'blue'"
is_centos: "'$facter_operatingsystem' == 'CentOS'"
tasks:
- name: "shutdown if my favorite color is blue"
action: command /sbin/shutdown -t now
only_if: '$is_favcolor_blue'
Variables from tools like `facter` and `ohai` can be used here, if installed, or you can
use variables that bubble up from ansible, which many are provided by the :ref:`setup` module. As a reminder,
these variables are prefixed, so it's `$facter_operatingsystem`, not `$operatingsystem`. Ansible's
built in variables are prefixed with `ansible_`.
The only_if expression is actually a tiny small bit of Python, so be sure to quote variables and make something
that evaluates to `True` or `False`. It is a good idea to use 'vars_files' instead of 'vars' to define
all of your conditional expressions in a way that makes them very easy to reuse between plays
and playbooks.
You cannot use live checks here, like 'os.path.exists', so don't try.
It's also easy to provide your own facts if you want, which is covered in :doc:`moduledev`. To run them, just
make a call to your own custom fact gathering module at the top of your list of tasks, and variables returned
there will be accessible to future tasks::
tasks:
- name: gather site specific fact data
action: site_facts
- action: command echo ${my_custom_fact_can_be_used_now}
One common useful trick with only_if is to key off the changed result of a last command. As an example::
tasks:
- action: template src=/templates/foo.j2 dest=/etc/foo.conf
- action: command echo 'the file has changed'
only_if: '${last_result.changed}'
$last_result is a variable automatically set by Ansible, and it is a boolean, so there is no need
to test for it against something else with an explicit equals. This assumes Ansible 0.8 and later.
In Ansible 0.8, a few shortcuts are available for testing whether a variable is defined or not::
tasks:
- action: command echo hi
only_if: is_set($some_variable)
There is a matching 'is_unset' that works the same way. Do not quote the variables inside the function.
While only_if is a pretty good option for advanced users, it exposes more guts of the engine than we'd like, and
we can do better. In 0.9, we will be adding 'when', which will be like a syntactic sugar for only_if and hide
this level of complexity -- it will numerous built in operators.
Conditional Imports
```````````````````
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
user: root
vars_files:
- "vars/common.yml"
- [ "vars/$facter_operatingsystem.yml", "vars/os_defaults.yml" ]
tasks:
- name: make sure apache is running
action: service name=$apache state=running
.. note::
The variable (`$facter_operatingsystem`) 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 up 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 -- seperating 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.
Loops
`````
To save some typing, repeated tasks can be written in short-hand like so::
- name: add user $item
action: user name=$item state=present groups=wheel
with_items:
- testuser1
- testuser2
If you have defined a YAML list in a variables file, or the 'vars' section, you can also do::
with_items: $somelist
The above would be the equivalent of::
- name: add user testuser1
action: user name=testuser1 state=present groups=wheel
- name: add user testuser2
action: user name=testuser2 state=present groups=wheel
The yum and apt modules use with_items to execute fewer package manager transactions.
Note that the types of items you iterate over with 'with_items' do not have to be simple lists of strings.
If you have a list of hashes, you can reference subkeys using things like::
${item.subKeyName}
More Loops
``````````
.. versionadded: 0.8
Various 'lookup plugins' allow additional ways to iterate over data. Ansible will have more of these
over time. In 0.8, the only lookup plugin that comes stock is 'with_fileglob', but you can also write
your own.
'with_fileglob' matches all files in a single directory, non-recursively, that match a pattern. It can
be used like this::
----
- hosts: all
tasks:
# first ensure our target directory exists
- action: file dest=/etc/fooapp state=directory
# copy each file over that matches the given pattern
- action: copy src=$item dest=/etc/fooapp/ owner=root mode=600
with_fileglob: /playbooks/files/fooapp/*
Getting values from files
`````````````````````````
.. versionadded: 0.8
Sometimes you'll want to include the content of a file directly into a playbook. You can do so using a macro.
This syntax will remain in future versions, though we will also will provide ways to do this via lookup plugins (see "More Loops") as well. What follows
is an example using the authorized_key module, which requires the actual text of the SSH key as a parameter::
tasks:
- authorized_key name=$item key=$FILE(/keys/$user1)
with_items:
- pinky
- brain
- snowball
The "$PIPE" macro works just like file, except you would feed it a command string instead. It executes locally, not remotely, as does $FILE.
Selecting Files And Templates Based On Variables
````````````````````````````````````````````````
Sometimes a configuration file you want to copy, or a template you will use may depend on a variable.
The following construct selects the first available file appropriate for the variables of a given host,
which is often much cleaner than putting a lot of if conditionals in a template.
The following example shows how to template out a configuration file that was very different between, say,
CentOS and Debian::
- name: template a file
action: template src=$item dest=/etc/myapp/foo.conf
first_available_file:
- /srv/templates/myapp/${ansible_distribution}.conf
- /srv/templates/myapp/default.conf
Asynchronous Actions and Polling
````````````````````````````````
By default tasks in playbooks block, meaning the connections stay open
until the task is done on each node. If executing playbooks with
a small parallelism value (aka ``--forks``), you may wish that long
running operations can go faster. The easiest way to do this is
to kick them off all at once and then poll until they are done.
You will also want to use asynchronous mode on very long running
operations that might be subject to timeout.
To launch a task asynchronously, specify its maximum runtime
and how frequently you would like to poll for status. The default
poll value is 10 seconds if you do not specify a value for `poll`::
---
- hosts: all
user: root
tasks:
- name: simulate long running op (15 sec), wait for up to 45, poll every 5
action: command /bin/sleep 15
async: 45
poll: 5
.. note::
There is no default for the async time limit. If you leave off the
'async' keyword, the task runs synchronously, which is Ansible's
default.
Alternatively, if you do not need to wait on the task to complete, you may
"fire and forget" by specifying a poll value of 0::
---
- hosts: all
user: root
tasks:
- name: simulate long running op, allow to run for 45, fire and forget
action: command /bin/sleep 15
async: 45
poll: 0
.. note::
You shouldn't "fire and forget" with operations that require
exclusive locks, such as yum transactions, if you expect to run other
commands later in the playbook against those same resources.
.. note::
Using a higher value for ``--forks`` will result in kicking off asynchronous
tasks even faster. This also increases the efficiency of polling.
Local Playbooks
```````````````
It may be useful to use a playbook locally, rather than by connecting over SSH. This can be useful
for assuring the configuration of a system by putting a playbook on a crontab. This may also be used
to run a playbook inside a OS installer, such as an Anaconda kickstart.
To run an entire playbook locally, just set the "hosts:" line to "hosts:127.0.0.1" and then run the playbook like so::
ansible-playbook playbook.yml --connection=local
Alternatively, a local connection can be used in a single playbook play, even if other plays in the playbook
use the default remote connection type::
hosts: 127.0.0.1
connection: local
Turning Off Facts
`````````````````
If you know you don't need any fact data about your hosts, and know everything about your systems centrally, you
can turn off fact gathering. This has advantages in scaling ansible in push mode with very large numbers of
systems, mainly, or if you are using Ansible on experimental platforms. In any play, just do this::
- hosts: whatever
gather_facts: False
Pull-Mode Playbooks
```````````````````
The use of playbooks in local mode (above) is made extremely powerful with the addition of `ansible-pull`.
A script for setting up ansible-pull is provided in the examples/playbooks directory of the source
checkout.
The basic idea is to use Ansible to set up a remote copy of ansible on each managed node, each set to run via
cron and update playbook source via git. This interverts the default push architecture of ansible into a pull
architecture, which has near-limitless scaling potential. The setup playbook can be tuned to change
the cron frequency, logging locations, and parameters to ansible-pull.
This is useful both for extreme scale-out as well as periodic remediation. Usage of the 'fetch' module to retrieve
logs from ansible-pull runs would be an excellent way to gather and analyze remote logs from ansible-pull.
Register Variables
``````````````````
.. versionadded:: 0.7
Often in a playbook it may be useful to store the result of a given command in a variable and access
it later. Use of the command module in this way can in many ways eliminate the need to write site specific facts, for
instance, you could test for the existance of a particular program.
The 'register' keyword decides what variable to save a result in. The resulting variables can be used in templates, action lines, or only_if statements. It looks like this (in an obviously trivial example)::
- name: test play
hosts: all
tasks:
- action: shell cat /etc/motd
register: motd_contents
- action: shell echo "motd contains the word hi"
only_if: "'${motd_contents.stdout}'.find('hi') != -1"
Rolling Updates
```````````````
.. versionadded:: 0.7
By default ansible will try to manage all of the machines referenced in a play in parallel. For a rolling updates
use case, you can define how many hosts ansible should manage at a single time by using the ''serial'' keyword::
- name: test play
hosts: webservers
serial: 3
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.
Delegation
``````````
.. versionadded:: 0.7
If you want to perform a task on one host with reference to other hosts, use the 'delegate_to' keyword on a task.
This is ideal for placing nodes in a load balanced pool, or removing them. It is also very useful for controlling
outage windows. Using this with the 'serial' keyword to control the number of hosts executing at one time is also
a good idea::
---
- hosts: webservers
serial: 5
tasks:
- name: take out of load balancer pool
action: command /usr/bin/take_out_of_pool $inventory_hostname
delegate_to: 127.0.0.1
- name: actual steps would go here
action: yum name=acme-web-stack state=latest
- name: add back to load balancer pool
action: command /usr/bin/add_back_to_pool $inventory_hostname
delegate_to: 127.0.0.1
Here is the same playbook as above, but using the shorthand syntax,
'local_action', for delegating to 127.0.0.1::
---
# ...
tasks:
- name: take out of load balancer pool
local_action: command /usr/bin/take_out_of_pool $inventory_hostname
# ...
- name: add back to load balancer pool
local_action: command /usr/bin/add_back_to_pool $inventory_hostname
Fireball Mode
`````````````
.. versionadded:: 0.8
Paramiko's core connection types of 'local', 'paramiko', and 'ssh' are augmented in version 0.8 by a new extra-fast
connection type called 'fireball'. It can only be used with playbooks and does require some additional setup
outside the lines of ansible's normal "no bootstrapping" philosophy. You are not required to use fireball mode
to use Ansible, though some users may appreciate it.
Fireball mode works by launching a temporary 0mq daemon from SSH that by default lives for only 30 minutes before
shutting off. Fireball mode once running uses temporary AES keys to encrypt a session, and requires direct
communication to given nodes on the configured port. The default is 5099. The fireball daemon runs as any user you
set it down as. So it can run as you, root, or so on. If multiple users are running Ansible as the same batch of hosts,
take care to use unique ports.
Fireball mode is roughly 10 times faster than paramiko for communicating with nodes and may be a good option
if you have a large number of hosts::
---
# set up the fireball transport
- hosts: all
gather_facts: False
connection: ssh
sudo: True
tasks:
- action: fireball
# these operations will occur over the fireball transport
- hosts: all
connection: fireball
sudo: True
tasks:
- action: shell echo "Hello ${item}"
with_items:
- one
- two
In order to use fireball mode, certain dependencies must be installed on both ends. You can use this playbook as a basis for initial bootstrapping on
any platform. You will also need gcc and zeromq-devel installed from your package manager, which you can of course also get Ansible to install::
---
- hosts: all
sudo: True
gather_facts: False
connection: ssh
tasks:
- action: easy_install name=pip
- action: pip name=pyzmq state=present
- action: pip name=pyasn1
- action: pip name=PyCrypto
- action: pip name=python-keyczar
For more information about fireball, see the module documentation section.
Understanding Variable Precedence
`````````````````````````````````
You have already learned about inventory host and group variables, 'vars', and 'vars_files'.
If a variable name is defined in more than one place with the same name, priority is as follows
to determine which place sets the value of the variable.
1. Variables loaded from YAML files mentioned in 'vars_files' in a playbook.
2. 'vars' as defined in the playbook.
3. facts, whether built in or custom, or variables assigned from the 'register' keyword.
4. variables passed to parameterized task include statements.
5. Host variables from inventory.
6. Group variables from inventory, in order of least specific group to most specific.
Therefore, if you want to set a default value for something you wish to override somewhere else, the best
place to set such a default is in a group variable.
Style Points
````````````
Ansible playbooks are colorized. If you do not like this, set the ANSIBLE_NOCOLOR=1 environment variable.
Ansible playbooks also look more impressive with cowsay installed, and we encourage installing this package.
.. seealso::
:doc:`YAMLSyntax`
Learn about YAML syntax
:doc:`playbooks`
Review the basic playbook features
:doc:`bestpractices`
Various tips about playbooks in the real world
:doc:`modules`
Learn about available modules
:doc:`moduledev`
Learn how to extend Ansible by writing your own modules
:doc:`patterns`
Learn about how to select hosts
`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

@ -0,0 +1,24 @@
.. _who_uses_ansible:
Who Uses Ansible
================
The following is an opt-in list of just some of the folks using Ansible -- to get your company details here, `Email Michael <mailto:michael.dehaan@gmail.com>`_.
* `Alta Language Services <http://www.altalang.com>`_ - language testing, solutions, and translation services
* `Basho <http://basho.com>`_ - makers of NoSQL engine Riak
* `CatN Hosting <http://catn.com>`_ - scalable Cloud hosting
* `Cygate AB <http://cygate.se>`_ - IT solutions from Malmo, Sweeden
* `Dag IT Solutions <http://dagit.net>`_ - Enterprise Linux & Beyond
* `Duke University Economics <http://duke.edu>`_ - Research & Education
* `The Fedora Project <http://fedoraproject.org>`_ - Produces the Popular Linux Distribution
* `Four Kitchens <http://fourkitchens.com>`_ - The Drupal Experts
* `Lizenfrei.at <http://lizenzfrei.at/>`_ - Open Source consulting and development, Austria
* `Schmooze Com <http://www.schmoozecom.com/>`_ - Creators of Industry Leading PBX Platforms
* `Scientific Computing Center, Aristotle Univ. of Thessaloniki <http://www.grid.auth.gr/en/>`_ - Grid/Cloud-Based Scientific Computing
* `Skylines.io <http://skylines.io>`_ - Real time photo search engine
* `Steelhouse <http://steelhouse.com>`_ - Behavioral commerce
* `Tomorrow Focus Technologies GmbH <http://www.t-f-t.net/>`_ - Running some of the biggest web sites in Europe
* `123i.com.br <http://123i.com.br>`_ - Find real estate in Brazil
* `Ginsys <http://ginsys.eu/>`_ - Linux infrastructure consulting from Belgium

View File

@ -0,0 +1,33 @@
---
# If a key doesn't apply to your module (ex: choices, default, or
# aliases) you can use the word 'null', or an empty list, [], where
# appropriate.
module: modulename
short_description: This is a sentence describing the module
description:
- Longer description of the module
- You might include instructions
version_added: 0.X
author: Your AWESOME name here
notes:
- Other things consumers of your module should know
requirements:
- list of required things
- like the factor package
- or a specic platform
options:
# One or more of the following
option_name:
description:
- Words go here
- that describe
- this option
required: true or false
default: a string or the word null
choices: [list, of, choices]
aliases: [list, of, aliases]
version_added: 0.X
examples:
# One or more of the following:
- code: modulename opt1=arg1 opt2=arg2
description: Optional words describing this example

View File

@ -21,7 +21,7 @@ module_name = command
remote_tmp = $HOME/.ansible/tmp
# the default pattern for ansible-playbooks ("hosts:")
# the default pattern for ansible-playbooks ("hosts:")
pattern = *
@ -62,10 +62,18 @@ remote_port=22
#remote_user=root
# if set, always use this private key file for authentication, same as if passing
# --private-key-file to ansible or ansible-playbook
# --private-key to ansible or ansible-playbook
#private_key_file=/path/to/file
# format of string $ansible_managed available within Jinja2 templates, replacing
# {file}, {host} and {uid} with template filename, host and owner respectively.
# The resulting string is passed through strftime(3) so it may contain any
# time-formatting specifiers.
#
# Example: ansible_managed = DONT TOUCH {file}: call {uid} at {host} for changes
ansible_managed = Ansible managed: {file} modified on %Y-%m-%d %H:%M:%S by {uid} on {host}
[paramiko_connection]
# nothing to configure yet

View File

@ -20,12 +20,15 @@
vars:
# schdule is fed directly to cron
# schedule is fed directly to cron
schedule: '*/15 * * * *'
# User to run ansible-pull as from cron
cron_user: root
# File that ansible will use for logs
logfile: /var/log/ansible-pull.log
# Directory to where repository will be cloned
workdir: /var/lib/ansible/local
@ -47,5 +50,7 @@
owner=root group=root mode=0644
- name: Create crontab entry to clone/pull git repository
action: template src=templates/ansible-pull.j2 dest=/etc/cron.d/ansible-pull owner=root group=root mode=0644
action: template src=templates/etc_cron.d_ansible-pull.j2 dest=/etc/cron.d/ansible-pull owner=root group=root mode=0644
- name: Create logrotate entry for ansible-pull.log
action: template src=templates/etc_logrotate.d_ansible-pull.j2 dest=/etc/logrotate.d/ansible-pull owner=root group=root mode=0644

View File

@ -42,7 +42,9 @@
# handlers can also be included from files, to promote reuse
# and simpler recipes, you may wish to only have one
# handler file for all your plays and playbooks
# handler file for all your plays and playbooks. This example really
# doesn't notify any handlers, it is just showing you how they would
# be included (see intro_example for usage).
- include: handlers/handlers.yml

View File

@ -0,0 +1,20 @@
---
# in addition to loop_with_items, the loop that works over a variable, ansible can do more sophisticated looping.
# developer types: these are powered by 'lookup_plugins' should you ever decide to write your own
# see lib/ansible/runner/lookup_plugins/fileglob.py -- they can do basically anything!
- hosts: all
gather_facts: False
tasks:
# this will copy a bunch of config files over -- dir must be created first
- file: dest=/etc/fooapp state=directory
- copy: src=$item dest=/etc/fooapp/ owner=root mode=600
with_fileglob: /playbooks/files/fooapp/*

View File

@ -10,20 +10,19 @@
tasks:
# it is possible to save the result of any command in a named register. This variable will be made
# available to tasks and templates made further down in the execution flow. Here we save the result
# of a simple 'cat' command in a variable called 'motd_contents'
# available to tasks and templates made further down in the execution flow.
- action: shell cat /etc/motd
register: motd_contents
- action: shell grep hi /etc/motd
ignore_errors: True
register: motd_result
# and here we access the register. Note that motd_contents as a variable is structured data because
# and here we access the register. Note that variable is structured data because
# it is a return from the command module. The shell module makes available variables such as
# as 'stdout', 'stderr', and 'rc'. Here's a rather trivial example that runs an arbitrary step
# if and only if the motd file contained the word 'hi'. Remember that only_if statements are
# Python expressions. This is as complicated as Ansible syntax is going to get, and the only
# time python really seeps into ansible's language.
# as 'stdout', 'stderr', and 'rc'.
# here we run the next action only if the previous grep returned true
- action: shell echo "motd contains the word hi"
only_if: "'${motd_contents.stdout}'.find('hi') != -1"
only_if: "${motd_result.rc} == 0"

View File

@ -19,4 +19,3 @@
- name: made up task just to show variables work here
action: command /bin/echo release is $release

View File

@ -1,2 +1,2 @@
# Cron job to git clone/pull a repo and then run locally
{{ schedule }} {{ cron_user }} ansible-pull -d {{ workdir }} -U {{ repo_url }} >/var/log/ansible-pull.log 2>&1
{{ schedule }} {{ cron_user }} ansible-pull -d {{ workdir }} -U {{ repo_url }} >>{{ logfile }} 2>&1

View File

@ -0,0 +1,7 @@
{{ logfile }} {
rotate 7
daily
compress
missingok
notifempty
}

372
hacking/module_formatter.py Executable file
View File

@ -0,0 +1,372 @@
#!/usr/bin/env python
# (c) 2012, Jan-Piet Mens <jpmens () 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/>.
#
import os
import sys
import yaml
import codecs
import json
import ast
from jinja2 import Environment, FileSystemLoader
import re
import optparse
import time
import datetime
import subprocess
# modules that are ok that they do not have documentation strings
BLACKLIST_MODULES = [
'async_wrapper'
]
# 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, 'library'
))
EXAMPLE_YAML=os.path.abspath(os.path.join(
os.path.dirname(os.path.realpath(__file__)), os.pardir, 'examples', 'DOCUMENTATION.yaml'
))
# There is a better way of doing this!
# TODO: somebody add U(text, http://foo.bar/) as described by Tim in #991
_ITALIC = re.compile(r"I\(([^)]+)\)")
_BOLD = re.compile(r"B\(([^)]+)\)")
_MODULE = re.compile(r"M\(([^)]+)\)")
_URL = re.compile(r"U\(([^)]+)\)")
_CONST = re.compile(r"C\(([^)]+)\)")
def latex_ify(text):
t = _ITALIC.sub("\\I{" + r"\1" + "}", text)
t = _BOLD.sub("\\B{" + r"\1" + "}", t)
t = _MODULE.sub("\\M{" + r"\1" + "}", t)
t = _URL.sub("\\url{" + r"\1" + "}", t)
t = _CONST.sub("\\C{" + r"\1" + "}", t)
return t
def html_ify(text):
t = _ITALIC.sub("<em>" + r"\1" + "</em>", text)
t = _BOLD.sub("<b>" + r"\1" + "</b>", t)
t = _MODULE.sub("<span class='module'>" + r"\1" + "</span>", t)
t = _URL.sub("<a href='" + r"\1" + "'>" + r"\1" + "</a>", t)
#t = _CONST.sub("<code>" + r"\1" + "</code>", t)
t = _CONST.sub(r"\1", t)
return t
def json_ify(text):
t = _ITALIC.sub("<em>" + r"\1" + "</em>", text)
t = _BOLD.sub("<b>" + r"\1" + "</b>", t)
t = _MODULE.sub("<span class='module'>" + r"\1" + "</span>", t)
t = _URL.sub("<a href='" + r"\1" + "'>" + r"\1" + "</a>", t)
t = _CONST.sub("<code>" + r"\1" + "</code>", t)
return t
def js_ify(text):
return text
def man_ify(text):
t = _ITALIC.sub(r'\\fI' + r"\1" + r"\\fR", text)
t = _BOLD.sub(r'\\fB' + r"\1" + r"\\fR", t)
t = _MODULE.sub(r'\\fI' + r"\1" + r"\\fR", t)
t = _URL.sub(r'\\fI' + r"\1" + r"\\fR", t)
t = _CONST.sub(r'\\fC' + r"\1" + r"\\fR", t)
return t
def rst_ify(text):
t = _ITALIC.sub(r'*' + r"\1" + r"*", text)
t = _BOLD.sub(r'**' + r"\1" + r"**", t)
# mdehaan is disabling because he finds all the Sphinx orange distracting
#t = _MODULE.sub(r'``' + r"\1" + r"``", t)
t = _MODULE.sub(r"\1", t)
t = _URL.sub(r"\1", t)
# ditto
# t = _CONST.sub(r'``' + r"\1" + r"``", t)
t = _CONST.sub(r"\1", t)
return t
def markdown_ify(text):
t = _ITALIC.sub("_" + r"\1" + "_", text)
t = _BOLD.sub("**" + r"\1" + "**", t)
t = _MODULE.sub("*" + r"\1" + "*", t)
t = _URL.sub("[" + r"\1" + "](" + r"\1" + ")", t)
t = _CONST.sub("`" + r"\1" + "`", t)
return t
# Helper for Jinja2 (format() doesn't work here...)
def rst_fmt(text, fmt):
return fmt % (text)
def rst_xline(width, char="="):
return char * width
def load_examples_section(text):
return text.split('***BREAK***')
def get_docstring(filename, verbose=False):
"""
Search for assignment of the DOCUMENTATION variable in the given file.
Parse that from YAML and return the YAML doc or None.
"""
doc = None
try:
# Thank you, Habbie, for this bit of code :-)
M = ast.parse(''.join(open(filename)))
for child in M.body:
if isinstance(child, ast.Assign):
if 'DOCUMENTATION' in (t.id for t in child.targets):
doc = yaml.load(child.value.s)
except:
if verbose:
raise
else:
print "unable to parse %s" % filename
return doc
def return_data(text, options, outputname, module):
if options.output_dir is not None:
f = open(os.path.join(options.output_dir, outputname % module), 'w')
f.write(text)
f.close()
else:
print text
def boilerplate():
if not os.path.exists(EXAMPLE_YAML):
print >>sys.stderr, "Missing example boiler plate: %S" % EXAMPLE_YAML
print file(EXAMPLE_YAML).read()
def main():
p = optparse.OptionParser(
version='%prog 1.0',
usage='usage: %prog [options] arg1 arg2',
description='Convert Ansible module DOCUMENTATION strings to other formats',
)
p.add_option("-A", "--ansible-version",
action="store",
dest="ansible_version",
default="unknown",
help="Ansible version number")
p.add_option("-M", "--module-dir",
action="store",
dest="module_dir",
default=MODULEDIR,
help="Ansible modules/ directory")
p.add_option("-T", "--template-dir",
action="store",
dest="template_dir",
default="hacking/templates",
help="directory containing Jinja2 templates")
p.add_option("-t", "--type",
action='store',
dest='type',
choices=['html', 'latex', 'man', 'rst', 'json', 'markdown'],
default='latex',
help="Output type")
p.add_option("-m", "--module",
action='append',
default=[],
dest='module_list',
help="Add modules to process in module_dir")
p.add_option("-v", "--verbose",
action='store_true',
default=False,
help="Verbose")
p.add_option("-o", "--output-dir",
action="store",
dest="output_dir",
default=None,
help="Output directory for module files")
p.add_option("-I", "--includes-file",
action="store",
dest="includes_file",
default=None,
help="Create a file containing list of processed modules")
p.add_option("-G", "--generate",
action="store_true",
dest="do_boilerplate",
default=False,
help="generate boilerplate DOCUMENTATION to stdout")
p.add_option('-V', action='version', help='Show version number and exit')
(options, args) = p.parse_args()
# print "M: %s" % options.module_dir
# print "t: %s" % options.type
# print "m: %s" % options.module_list
# print "v: %s" % options.verbose
if options.do_boilerplate:
boilerplate()
sys.exit(0)
if not options.module_dir:
print "Need module_dir"
sys.exit(1)
if not os.path.exists(options.module_dir):
print >>sys.stderr, "Module directory does not exist: %s" % options.module_dir
sys.exit(1)
if not options.template_dir:
print "Need template_dir"
sys.exit(1)
env = Environment(loader=FileSystemLoader(options.template_dir),
variable_start_string="@{",
variable_end_string="}@",
trim_blocks=True,
)
env.globals['xline'] = rst_xline
if options.type == 'latex':
env.filters['jpfunc'] = latex_ify
template = env.get_template('latex.j2')
outputname = "%s.tex"
includecmt = "% generated code\n"
includefmt = "\\input %s\n"
if options.type == 'html':
env.filters['jpfunc'] = html_ify
template = env.get_template('html.j2')
outputname = "%s.html"
includecmt = ""
includefmt = ""
if options.type == 'man':
env.filters['jpfunc'] = man_ify
template = env.get_template('man.j2')
outputname = "ansible.%s.3"
includecmt = ""
includefmt = ""
if options.type == 'rst':
env.filters['jpfunc'] = rst_ify
env.filters['html_ify'] = html_ify
env.filters['fmt'] = rst_fmt
env.filters['xline'] = rst_xline
template = env.get_template('rst.j2')
outputname = "%s.rst"
includecmt = ".. Generated by module_formatter\n"
includefmt = ".. include:: modules/%s.rst\n"
if options.type == 'json':
env.filters['jpfunc'] = json_ify
outputname = "%s.json"
includecmt = ""
includefmt = ""
if options.type == 'js':
env.filters['jpfunc'] = js_ify
template = env.get_template('js.j2')
outputname = "%s.js"
if options.type == 'markdown':
env.filters['jpfunc'] = markdown_ify
env.filters['html_ify'] = html_ify
template = env.get_template('markdown.j2')
outputname = "%s.md"
includecmt = ""
includefmt = ""
if options.includes_file is not None and includefmt != "":
incfile = open(options.includes_file, "w")
incfile.write(includecmt)
# Temporary variable required to genrate aggregated content in 'js' format.
js_data = []
for module in sorted(os.listdir(options.module_dir)):
if len(options.module_list):
if not module in options.module_list:
continue
fname = os.path.join(options.module_dir, module)
extra = os.path.join("inc", "%s.tex" % module)
if fname.endswith(".swp"):
continue
print " processing module source ---> %s" % fname
if options.type == 'js':
if fname.endswith(".json"):
f = open(fname)
j = json.load(f)
f.close()
js_data.append(j)
continue
doc = get_docstring(fname, verbose=options.verbose)
if doc is None and module not in BLACKLIST_MODULES:
sys.stderr.write("*** ERROR: CORE MODULE MISSING DOCUMENTATION: %s ***\n" % module)
#sys.exit(1)
if not doc is None:
doc['filename'] = fname
doc['docuri'] = doc['module'].replace('_', '-')
doc['now_date'] = datetime.date.today().strftime('%Y-%m-%d')
doc['ansible_version'] = options.ansible_version
if options.includes_file is not None and includefmt != "":
incfile.write(includefmt % module)
if options.verbose:
print json.dumps(doc, indent=4)
if options.type == 'latex':
if os.path.exists(extra):
f = open(extra)
extradata = f.read()
f.close()
doc['extradata'] = extradata
if options.type == 'json':
text = json.dumps(doc, indent=2)
else:
text = template.render(doc)
return_data(text, options, outputname, module)
if options.type == 'js':
docs = {}
docs['json'] = json.dumps(js_data, indent=2)
text = template.render(docs)
return_data(text, options, outputname, 'modules')
if __name__ == '__main__':
main()

View File

@ -0,0 +1,7 @@
<!-- @{ module | upper }@ -->
<h2>@{module}@</h2>
{% for desc in description -%}
@{ desc | jpfunc }@
{% endfor %}

5
hacking/templates/js.j2 Normal file
View File

@ -0,0 +1,5 @@
function AnsibleModules($scope) {
$scope.modules = @{ json }@;
$scope.orderProp = "module";
}

65
hacking/templates/man.j2 Normal file
View File

@ -0,0 +1,65 @@
.TH ANSIBLE.@{ module | upper }@ 3 "@{ now_date }@" "@{ ansible_version }@" "ANSIBLE MODULES"
." generated from @{ filename }@
.SH NAME
@{ module }@ \- @{ short_description }@
." ------ DESCRIPTION
.SH DESCRIPTION
{% for desc in description %}
.PP
@{ desc | jpfunc }@
{% endfor %}
." ------ OPTIONS
."
."
{% if options %}
.SH OPTIONS
{% for (k,v) in options.iteritems() %}
.IP @{ k }@
{% for desc in v.description %}@{ desc | jpfunc }@{% endfor %}
{% if v.get('choices') %}
.IR Choices :
{% for choice in v.get('choices',[]) %}@{ choice }@{% if not loop.last %},{%else%}.{%endif%}{% endfor %}{% endif %}
{% if v.get('required') %}(required){% endif %}
{% if v.get('default') %} (default: @{ v.get('default') }@){% endif %}
{#---------------------------------------------- #}
{% if v.get('version_added') %}
(Added in Ansible version @{ v.get('version_added') }@.)
{% endif %}
{% endfor %}
{% endif %}
."
."
." ------ NOTES
{% if notes %}
.SH NOTES
{% for note in notes %}
.PP
@{ note | jpfunc }@
{% endfor %}
{% endif %}
."
."
." ------ EXAMPLES
{% if examples is defined %}
.SH EXAMPLES
{% for e in examples %}
.PP
{% if e['description'] %}
@{ e['description'] | jpfunc }@
{% endif %}
.nf
@{ e['code'] }@
.fi
{% endfor %}
{% endif %}
." ------- AUTHOR
{% if author is defined %}
.SH AUTHOR
@{ author }@
{% endif %}
.SH SEE ALSO
.IR ansible (1),
.I http://ansible.github.com/modules.html#@{docuri}@

View File

@ -0,0 +1,55 @@
## @{ module }@
{# ------------------------------------------
#
# This is Github-flavored Markdown
#
--------------------------------------------#}
{% if version_added is defined -%}
New in version @{ version_added }@.
{% endif %}
{% for desc in description -%}
@{ desc | jpfunc }@
{% endfor %}
{% if options -%}
<table>
<tr>
<th class="head">parameter</th>
<th class="head">required</th>
<th class="head">default</th>
<th class="head">choices</th>
<th class="head">comments</th>
</tr>
{% for (k,v) in options.iteritems() %}
<tr>
<td>@{ k }@</td>
<td>{% if v.get('required', False) %}yes{% else %}no{% endif %}</td>
<td>{% if v['default'] %}@{ v['default'] }@{% endif %}</td>
<td><ul>{% for choice in v.get('choices',[]) -%}<li>@{ choice }@</li>{% endfor -%}</ul></td>
<td>{% for desc in v.description -%}@{ desc | html_ify }@{% endfor -%}{% if v['version_added'] %} (added in Ansible @{v['version_added']}@){% endif %}</td>
</tr>
{% endfor %}
</table>
{% endif %}
{% for example in examples %}
{% if example['description'] %}
* @{ example['description'] | jpfunc }@
{% endif %}
```
@{ example['code'] }@
```
{% endfor %}
{% if notes %}
#### Notes
{% for note in notes %}
@{ note | jpfunc }@
{% endfor %}
{% endif %}

64
hacking/templates/rst.j2 Normal file
View File

@ -0,0 +1,64 @@
.. _@{ module }@:
@{ module }@
``````````````````````````````
{# ------------------------------------------
#
# Please note: this looks like a core dump
# but it isn't one.
#
--------------------------------------------#}
{% if version_added is defined -%}
.. versionadded:: @{ version_added }@
{% endif %}
{% for desc in description -%}
@{ desc | jpfunc }@
{% endfor %}
{% if options -%}
.. raw:: html
<table>
<tr>
<th class="head">parameter</th>
<th class="head">required</th>
<th class="head">default</th>
<th class="head">choices</th>
<th class="head">comments</th>
</tr>
{% for (k,v) in options.iteritems() %}
<tr>
<td>@{ k }@</td>
<td>{% if v.get('required', False) %}yes{% else %}no{% endif %}</td>
<td>{% if v['default'] %}@{ v['default'] }@{% endif %}</td>
<td><ul>{% for choice in v.get('choices',[]) -%}<li>@{ choice }@</li>{% endfor -%}</ul></td>
<td>{% for desc in v.description -%}@{ desc | html_ify }@{% endfor -%}{% if v['version_added'] %} (added in Ansible @{v['version_added']}@){% endif %}</td>
</tr>
{% endfor %}
</table>
{% endif %}
.. raw:: html
{% for example in examples %}
{% if example['description'] %}<p>@{ example['description'] | html_ify }@</p>{% endif %}
<p>
<pre>
@{ example['code'] | indent(4, True) }@
</pre>
</p>
{% endfor %}
<br/>
{% if notes %}
.. raw:: html
<h4>Notes</h4>
{% for note in notes %}
<p>@{ note | html_ify }@</p>
{% endfor %}
{% endif %}

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__ = '0.7'
__version__ = '0.8'
__author__ = 'Michael DeHaan'

View File

@ -63,6 +63,12 @@ class CallbackModule(object):
def playbook_on_notify(self, host, handler):
pass
def on_no_hosts_matched(self):
pass
def on_no_hosts_remaining(self):
pass
def playbook_on_task_start(self, name, is_conditional):
pass

View File

@ -22,19 +22,29 @@ import os
import subprocess
import os.path
from ansible.color import stringc
import ansible.constants as C
dirname = os.path.dirname(__file__)
callbacks = utils.import_plugins(os.path.join(dirname, 'callback_plugins'))
callbacks = [ c.CallbackModule() for c in callbacks.values() if c.__name__ != '__init__' ]
callbacks = [ c.CallbackModule() for c in callbacks.values() ]
def load_more_callbacks(dirname):
callbacks.extend([c.CallbackModule() for c in utils.import_plugins(dirname).values()])
for i in C.DEFAULT_CALLBACK_PLUGIN_PATH.split(os.pathsep):
load_more_callbacks(i)
cowsay = None
if os.path.exists("/usr/bin/cowsay"):
if os.getenv("ANSIBLE_NOCOWS") is not None:
cowsay = None
elif os.path.exists("/usr/bin/cowsay"):
cowsay = "/usr/bin/cowsay"
elif os.path.exists("/usr/games/cowsay"):
cowsay = "/usr/games/cowsay"
elif os.path.exists("/usr/local/bin/cowsay"):
# BSD path for cowsay
cowsay = "/usr/local/bin/cowsay"
def call_callback_module(method_name, *args, **kwargs):
for callback_plugin in callbacks:
methods = [
getattr(callback_plugin, method_name, None),
@ -237,6 +247,7 @@ class CliRunnerCallbacks(DefaultRunnerCallbacks):
super(CliRunnerCallbacks, self).on_unreachable(host, res)
def on_skipped(self, host, item=None):
print "%s | skipped" % (host)
super(CliRunnerCallbacks, self).on_skipped(host, item)
def on_error(self, host, err):
@ -280,15 +291,16 @@ class PlaybookRunnerCallbacks(DefaultRunnerCallbacks):
self.stats = stats
self._async_notified = {}
def on_unreachable(self, host, msg):
def on_unreachable(self, host, results):
item = None
if type(msg) == dict:
item = msg.get('item', None)
if type(results) == dict:
item = results.get('item', None)
if item:
print "fatal: [%s] => (item=%s) => %s" % (host, item, msg)
msg = "fatal: [%s] => (item=%s) => %s" % (host, item, results)
else:
print "fatal: [%s] => %s" % (host, msg)
super(PlaybookRunnerCallbacks, self).on_unreachable(host, msg)
msg = "fatal: [%s] => %s" % (host, results)
print stringc(msg, 'red')
super(PlaybookRunnerCallbacks, self).on_unreachable(host, results)
def on_failed(self, host, results, ignore_errors=False):
@ -296,13 +308,27 @@ class PlaybookRunnerCallbacks(DefaultRunnerCallbacks):
results2.pop('invocation', None)
item = results2.get('item', None)
parsed = results2.get('parsed', True)
module_msg = ''
if not parsed:
module_msg = results2.pop('msg', None)
stderr = results2.pop('stderr', None)
stdout = results2.pop('stdout', None)
if item:
msg = "failed: [%s] => (item=%s) => %s" % (host, item, utils.jsonify(results2))
else:
msg = "failed: [%s] => %s" % (host, utils.jsonify(results2))
print stringc(msg, 'red')
if stderr:
print stringc("stderr: %s" % stderr, 'red')
if stdout:
print stringc("stdout: %s" % stdout, 'red')
if not parsed and module_msg:
print stringc("invalid output was: %s" % module_msg, 'red')
if ignore_errors:
print stringc("...ignoring", 'yellow')
print stringc("...ignoring", 'cyan')
super(PlaybookRunnerCallbacks, self).on_failed(host, results, ignore_errors=ignore_errors)
def on_ok(self, host, host_result):
@ -310,25 +336,29 @@ class PlaybookRunnerCallbacks(DefaultRunnerCallbacks):
host_result2 = host_result.copy()
host_result2.pop('invocation', None)
changed = host_result.get('changed', False)
ok_or_changed = 'ok'
if changed:
ok_or_changed = 'changed'
# show verbose output for non-setup module results if --verbose is used
msg = ''
if not self.verbose or host_result2.get("verbose_override",None) is not None:
if item:
msg = "ok: [%s] => (item=%s)" % (host,item)
msg = "%s: [%s] => (item=%s)" % (ok_or_changed, host, item)
else:
if 'ansible_job_id' not in host_result or 'finished' in host_result:
msg = "ok: [%s]" % (host)
msg = "%s: [%s]" % (ok_or_changed, host)
else:
# verbose ...
if item:
msg = "ok: [%s] => (item=%s) => %s" % (host, item, utils.jsonify(host_result2))
msg = "%s: [%s] => (item=%s) => %s" % (ok_or_changed, host, item, utils.jsonify(host_result2))
else:
if 'ansible_job_id' not in host_result or 'finished' in host_result2:
msg = "ok: [%s] => %s" % (host, utils.jsonify(host_result2))
msg = "%s: [%s] => %s" % (ok_or_changed, host, utils.jsonify(host_result2))
if msg != '':
if not 'changed' in host_result2 or not host_result['changed']:
if not changed:
print stringc(msg, 'green')
else:
print stringc(msg, 'yellow')
@ -353,11 +383,11 @@ class PlaybookRunnerCallbacks(DefaultRunnerCallbacks):
msg = "skipping: [%s] => (item=%s)" % (host, item)
else:
msg = "skipping: [%s]" % host
print stringc(msg, 'yellow')
print stringc(msg, 'cyan')
super(PlaybookRunnerCallbacks, self).on_skipped(host, item)
def on_no_hosts(self):
print stringc("no hosts matched or remaining\n", 'red')
print stringc("FATAL: no hosts matched or all hosts have already failed -- aborting\n", 'red')
super(PlaybookRunnerCallbacks, self).on_no_hosts()
def on_async_poll(self, host, res, jid, clock):
@ -395,6 +425,14 @@ class PlaybookCallbacks(object):
def on_notify(self, host, handler):
call_callback_module('playbook_on_notify', host, handler)
def on_no_hosts_matched(self):
print stringc("no hosts matched", 'red')
call_callback_module('playbook_on_no_hosts_matched')
def on_no_hosts_remaining(self):
print stringc("\nFATAL: all hosts have already failed -- aborting", 'red')
call_callback_module('playbook_on_no_hosts_remaining')
def on_task_start(self, name, is_conditional):
msg = "TASK: [%s]" % name
if is_conditional:
@ -405,7 +443,7 @@ class PlaybookCallbacks(object):
def on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None):
if prompt:
msg = prompt
msg = "%s: " % prompt
else:
msg = 'input for %s: ' % varname

View File

@ -36,6 +36,9 @@ else:
# curses returns an error (e.g. could not find terminal)
ANSIBLE_COLOR=False
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

View File

@ -21,33 +21,35 @@ import ConfigParser
import traceback
def get_config(p, section, key, env_var, default):
if env_var is not None:
value = os.environ.get(env_var, None)
if value is not None:
return value
if p is not None:
try:
return p.get(section, key)
except:
if env_var is not None:
return os.environ.get(env_var, default)
return default
else:
if env_var is not None:
return os.environ.get(env_var, default)
return default
return default
def load_config_file():
p = ConfigParser.ConfigParser()
path1 = os.path.expanduser(
os.environ.get('ANSIBLE_CONFIG', "~/.ansible.cfg"))
path2 = "/etc/ansible/ansible.cfg"
path1 = os.path.expanduser(os.environ.get('ANSIBLE_CONFIG', "~/.ansible.cfg"))
path2 = os.getcwd() + "/ansible.cfg"
path3 = "/etc/ansible/ansible.cfg"
if os.path.exists(path1):
p.read(path1)
elif os.path.exists(path2):
p.read(path2)
elif os.path.exists(path3):
p.read(path3)
else:
return None
return p
def shell_expand_path(path):
''' shell_expand_path is needed as os.path.expanduser does not work
''' 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(path)
@ -57,12 +59,16 @@ 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
DIST_MODULE_PATH = '/usr/share/ansible/'
# 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 = shell_expand_path(get_config(p, DEFAULTS, 'library', 'ANSIBLE_LIBRARY', '/usr/share/ansible'))
DEFAULT_MODULE_PATH = shell_expand_path(get_config(p, DEFAULTS, 'library', 'ANSIBLE_LIBRARY', DIST_MODULE_PATH))
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, '*')
@ -75,6 +81,12 @@ DEFAULT_PRIVATE_KEY_FILE = shell_expand_path(get_config(p, DEFAULTS, 'private_k
DEFAULT_SUDO_USER = get_config(p, DEFAULTS, 'sudo_user', 'ANSIBLE_SUDO_USER', 'root')
DEFAULT_REMOTE_PORT = int(get_config(p, DEFAULTS, 'remote_port', 'ANSIBLE_REMOTE_PORT', 22))
DEFAULT_TRANSPORT = get_config(p, DEFAULTS, 'transport', 'ANSIBLE_TRANSPORT', 'paramiko')
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}')
DEFAULT_ACTION_PLUGIN_PATH = shell_expand_path(get_config(p, DEFAULTS, 'action_plugins', None, '/usr/share/ansible_plugins/action_plugins'))
DEFAULT_CALLBACK_PLUGIN_PATH = shell_expand_path(get_config(p, DEFAULTS, 'callback_plugins', None, '/usr/share/ansible_plugins/callback_plugins'))
DEFAULT_CONNECTION_PLUGIN_PATH = shell_expand_path(get_config(p, DEFAULTS, 'connection_plugins', None, '/usr/share/ansible_plugins/connection_plugins'))
DEFAULT_LOOKUP_PLUGIN_PATH = shell_expand_path(get_config(p, DEFAULTS, 'lookup_plugins', None, '/usr/share/ansible_plugins/lookup_plugins'))
# non-configurable things
DEFAULT_REMOTE_PASS = None
@ -82,3 +94,4 @@ DEFAULT_SUDO_PASS = None
DEFAULT_SUBSET = None
ANSIBLE_SSH_ARGS = get_config(p, 'ssh_connection', 'ssh_args', 'ANSIBLE_SSH_ARGS', None)
ZEROMQ_PORT = int(get_config(p, 'fireball', 'zeromq_port', 'ANSIBLE_ZEROMQ_PORT', 5099))

View File

@ -35,7 +35,7 @@ class Inventory(object):
"""
__slots__ = [ 'host_list', 'groups', '_restriction', '_also_restriction', '_subset', '_is_script',
'parser', '_vars_per_host', '_vars_per_group', '_hosts_cache' ]
'parser', '_vars_per_host', '_vars_per_group', '_hosts_cache', '_groups_list' ]
def __init__(self, host_list=C.DEFAULT_HOST_LIST):
@ -49,6 +49,7 @@ class Inventory(object):
self._vars_per_host = {}
self._vars_per_group = {}
self._hosts_cache = {}
self._groups_list = {}
# the inventory object holds a list of groups
self.groups = []
@ -75,7 +76,7 @@ class Inventory(object):
all.add_host(Host(tokens[0], tokens[1]))
else:
all.add_host(Host(x))
elif os.access(host_list, os.X_OK):
elif utils.is_executable(host_list):
self._is_script = True
self.parser = InventoryScript(filename=host_list)
self.groups = self.parser.groups.values()
@ -96,7 +97,9 @@ class Inventory(object):
applied subsets.
"""
# process patterns
# process patterns
if isinstance(pattern, list):
pattern = ';'.join(pattern)
patterns = pattern.replace(";",":").split(":")
positive_patterns = [ p for p in patterns if not p.startswith("!") ]
negative_patterns = [ p for p in patterns if p.startswith("!") ]
@ -106,8 +109,8 @@ class Inventory(object):
# exclude hosts mentioned in a negative pattern
if len(negative_patterns):
exclude_hosts = self._get_hosts(negative_patterns)
hosts = [ h for h in hosts if h not in exclude_hosts ]
exclude_hosts = [ h.name for h in self._get_hosts(negative_patterns) ]
hosts = [ h for h in hosts if h.name not in exclude_hosts ]
# exclude hosts not in a subset, if defined
if self._subset:
@ -213,6 +216,17 @@ class Inventory(object):
continue
return results
def groups_list(self):
if not self._groups_list:
groups = {}
for g in self.groups:
groups[g.name] = [h.name for h in g.get_hosts()]
ancestors = g.get_ancestors()
for a in ancestors:
groups[a.name] = [h.name for h in a.get_hosts()]
self._groups_list = groups
return self._groups_list
def get_groups(self):
return self.groups
@ -252,8 +266,11 @@ class Inventory(object):
def _get_variables(self, hostname):
host = self.get_host(hostname)
if host is None:
raise errors.AnsibleError("host not found: %s" % hostname)
if self._is_script:
host = self.get_host(hostname)
cmd = subprocess.Popen(
[self.host_list,"--host",hostname],
stdout=subprocess.PIPE,
@ -269,11 +286,8 @@ class Inventory(object):
results['group_names'] = sorted(groups)
return results
host = self.get_host(hostname)
if host is None:
raise Exception("host not found: %s" % hostname)
return host.get_variables()
else:
return host.get_variables()
def add_group(self, group):
self.groups.append(group)

View File

@ -35,6 +35,7 @@ class InventoryScript(object):
self.groups = self._parse()
def _parse(self):
all_hosts = {}
groups = {}
self.raw = utils.parse_json(self.data)
@ -45,7 +46,9 @@ class InventoryScript(object):
group = groups[group_name] = Group(group_name)
host = None
for hostname in hosts:
host = Host(hostname)
if not hostname in all_hosts:
all_hosts[hostname] = Host(hostname)
host = all_hosts[hostname]
group.add_host(host)
# FIXME: hack shouldn't be needed
all.add_host(host)

View File

@ -49,15 +49,23 @@ import syslog
import types
import time
import shutil
import stat
try:
from hashlib import md5 as _md5
except ImportError:
from md5 import md5 as _md5
try:
from systemd import journal
has_journal = True
except ImportError:
import syslog
has_journal = False
class AnsibleModule(object):
def __init__(self, argument_spec, bypass_checks=False, no_log=False,
def __init__(self, argument_spec, bypass_checks=False, no_log=False,
check_invalid_arguments=True, mutually_exclusive=None, required_together=None,
required_one_of=None):
@ -144,7 +152,7 @@ class AnsibleModule(object):
non_zero = [ c for c in counts if c > 0 ]
if len(non_zero) > 0:
if 0 in counts:
self.fail_json(msg="parameters are required together: %s" % check)
self.fail_json(msg="parameters are required together: %s" % check)
def _check_required_arguments(self):
''' ensure all required arguments are present '''
@ -165,7 +173,7 @@ class AnsibleModule(object):
if type(choices) == list:
if k in self.params:
if self.params[k] not in choices:
choices_str=",".join(choices)
choices_str=",".join([str(c) for c in choices])
msg="value of %s must be one of: %s, got: %s" % (k, choices_str, self.params[k])
self.fail_json(msg=msg)
else:
@ -198,11 +206,27 @@ class AnsibleModule(object):
def _log_invocation(self):
''' log that ansible ran the module '''
syslog.openlog('ansible-%s' % os.path.basename(__file__))
# Sanitize possible password argument when logging
log_args = re.sub(r'password=.+ (.*)', r"password=NOT_LOGGING_PASSWORD \1", self.args)
log_args = re.sub(r'login_password=.+ (.*)', r"login_password=NOT_LOGGING_PASSWORD \1", log_args)
syslog.syslog(syslog.LOG_NOTICE, 'Invoked with %s' % log_args)
# TODO: generalize a seperate log function and make log_invocation use it
# Sanitize possible password argument when logging.
log_args = dict()
passwd_keys = ['password', 'login_password']
for param in self.params:
if param in passwd_keys:
log_args[param] = 'NOT_LOGGING_PASSWORD'
else:
log_args[param] = self.params[param]
if (has_journal):
journal_args = ["MESSAGE=Ansible module invoked", "MODULE=%s" % os.path.basename(__file__)]
for arg in log_args:
journal_args.append(arg.upper() + "=" + str(log_args[arg]))
journal.sendv(*journal_args)
else:
msg = ''
syslog.openlog('ansible-%s' % os.path.basename(__file__))
for arg in log_args:
msg = msg + arg + '=' + str(log_args[arg]) + ' '
syslog.syslog(syslog.LOG_NOTICE, 'Invoked with %s' % msg)
def get_bin_path(self, arg, required=False, opt_dirs=[]):
'''
@ -217,7 +241,7 @@ class AnsibleModule(object):
for d in opt_dirs:
if d is not None and os.path.exists(d):
paths.append(d)
paths += os.environ.get('PATH').split(':')
paths += os.environ.get('PATH', '').split(':')
bin_path = None
# mangle PATH to include /sbin dirs
for p in sbin_paths:
@ -225,7 +249,7 @@ class AnsibleModule(object):
paths.append(p)
for d in paths:
path = os.path.join(d, arg)
if os.path.exists(path) and os.access(path, os.X_OK):
if os.path.exists(path) and self.is_executable(path):
bin_path = path
break
if required and bin_path is None:
@ -260,6 +284,12 @@ class AnsibleModule(object):
print self.jsonify(kwargs)
sys.exit(1)
def is_executable(self, path):
'''is the given path executable?'''
return (stat.S_IXUSR & os.stat(path)[stat.ST_MODE]
or stat.S_IXGRP & os.stat(path)[stat.ST_MODE]
or stat.S_IXOTH & os.stat(path)[stat.ST_MODE])
def md5(self, filename):
''' Return MD5 hex digest of local file, or None if file is not present. '''
if not os.path.exists(filename):

View File

@ -20,12 +20,15 @@ import ansible.runner
import ansible.constants as C
from ansible import utils
from ansible import errors
import ansible.callbacks
import os
import collections
from play import Play
SETUP_CACHE = collections.defaultdict(dict)
plugins_dir = os.path.join(os.path.dirname(__file__), '..', 'runner')
class PlayBook(object):
'''
runs an ansible playbook, given as a datastructure or YAML filename.
@ -48,7 +51,7 @@ class PlayBook(object):
remote_user = C.DEFAULT_REMOTE_USER,
remote_pass = C.DEFAULT_REMOTE_PASS,
sudo_pass = C.DEFAULT_SUDO_PASS,
remote_port = C.DEFAULT_REMOTE_PORT,
remote_port = None,
transport = C.DEFAULT_TRANSPORT,
private_key_file = C.DEFAULT_PRIVATE_KEY_FILE,
callbacks = None,
@ -105,15 +108,21 @@ class PlayBook(object):
self.private_key_file = private_key_file
self.only_tags = only_tags
self.inventory = ansible.inventory.Inventory(host_list)
self.inventory = ansible.inventory.Inventory(host_list)
self.inventory.subset(subset)
self.modules_list = utils.get_available_modules(self.module_path)
self.lookup_plugins_list = ansible.runner.lookup_plugin_list
if not self.inventory._is_script:
self.global_vars.update(self.inventory.get_group_variables('all'))
self.basedir = os.path.dirname(playbook)
self.playbook = self._load_playbook_from_file(playbook)
(self.playbook, self.play_basedirs) = self._load_playbook_from_file(playbook)
self.module_path = self.module_path + os.pathsep + os.path.join(self.basedir, "library")
ansible.callbacks.load_more_callbacks(os.path.join(self.basedir, "callback_plugins"))
self.lookup_plugins_list.update(utils.import_plugins(os.path.join(self.basedir, 'lookup_plugins')))
# *****************************************************
@ -124,6 +133,7 @@ class PlayBook(object):
playbook_data = utils.parse_yaml_from_file(path)
accumulated_plays = []
play_basedirs = []
if type(playbook_data) != list:
raise errors.AnsibleError("parse error: playbooks must be formatted as a YAML list")
@ -134,13 +144,17 @@ class PlayBook(object):
if 'include' in play:
if len(play.keys()) == 1:
included_path = utils.path_dwim(self.basedir, play['include'])
accumulated_plays.extend(self._load_playbook_from_file(included_path))
(plays, basedirs) = self._load_playbook_from_file(included_path)
accumulated_plays.extend(plays)
play_basedirs.extend(basedirs)
else:
raise errors.AnsibleError("parse error: top level includes cannot be used with other directives: %s" % play)
else:
accumulated_plays.append(play)
play_basedirs.append(os.path.dirname(path))
return accumulated_plays
return (accumulated_plays, play_basedirs)
# *****************************************************
@ -152,8 +166,8 @@ class PlayBook(object):
# loop through all patterns and run them
self.callbacks.on_start()
for play_ds in self.playbook:
play = Play(self,play_ds)
for (play_ds, play_basedir) in zip(self.playbook, self.play_basedirs):
play = Play(self, play_ds, play_basedir)
matched_tags, unmatched_tags = play.compare_tags(self.only_tags)
matched_tags_all = matched_tags_all | matched_tags
unmatched_tags_all = unmatched_tags_all | unmatched_tags
@ -166,8 +180,8 @@ class PlayBook(object):
# if the playbook is invoked with --tags that don't exist at all in the playbooks
# then we need to raise an error so that the user can correct the arguments.
unknown_tags = set(self.only_tags) - (matched_tags_all | unmatched_tags_all)
unknown_tags.discard('all')
unknown_tags.discard('all')
if len(unknown_tags) > 0:
unmatched_tags_all.discard('all')
msg = 'tag(s) not found in playbook: %s. possible values: %s'
@ -176,7 +190,8 @@ class PlayBook(object):
raise errors.AnsibleError(msg % (unknown, unmatched))
for play in plays:
self._run_play(play)
if not self._run_play(play):
break
# summarize the results
results = {}
@ -215,10 +230,10 @@ class PlayBook(object):
timeout=self.timeout, remote_user=task.play.remote_user,
remote_port=task.play.remote_port, module_vars=task.module_vars,
private_key_file=self.private_key_file,
setup_cache=self.SETUP_CACHE, basedir=self.basedir,
setup_cache=self.SETUP_CACHE, basedir=task.play.basedir,
conditional=task.only_if, callbacks=self.runner_callbacks,
sudo=task.play.sudo, sudo_user=task.play.sudo_user,
transport=task.play.transport, sudo_pass=self.sudo_pass, is_playbook=True
sudo=task.sudo, sudo_user=task.sudo_user,
transport=task.transport, sudo_pass=task.sudo_pass, is_playbook=True
)
if task.async_seconds == 0:
@ -230,7 +245,14 @@ class PlayBook(object):
# if not polling, playbook requested fire and forget, so don't poll
results = self._async_poll(poller, task.async_seconds, task.async_poll_interval)
contacted = results.get('contacted',{})
dark = results.get('dark', {})
self.inventory.lift_restriction()
if len(contacted.keys()) == 0 and len(dark.keys()) == 0:
return None
return results
# *****************************************************
@ -242,17 +264,23 @@ class PlayBook(object):
# load up an appropriate ansible runner to run the task in parallel
results = self._run_task_internal(task)
# if no hosts are matched, carry on
if results is None:
results = {}
# if no hosts are matched, carry on
hosts_remaining = True
if results is None:
hosts_remaining = False
results = {}
contacted = results.get('contacted', {})
self.stats.compute(results, ignore_errors=task.ignore_errors)
# add facts to the global setup cache
for host, result in results['contacted'].iteritems():
for host, result in contacted.iteritems():
facts = result.get('ansible_facts', {})
self.SETUP_CACHE[host].update(facts)
if task.register:
if 'stdout' in result:
result['stdout_lines'] = result['stdout'].splitlines()
self.SETUP_CACHE[host][task.register] = result
# flag which notify handlers need to be run
@ -260,7 +288,9 @@ class PlayBook(object):
for host, results in results.get('contacted',{}).iteritems():
if results.get('changed', False):
for handler_name in task.notify:
self._flag_handler(play.handlers(), utils.template(handler_name, task.module_vars), host)
self._flag_handler(play.handlers(), utils.template(play.basedir, handler_name, task.module_vars), host)
return hosts_remaining
# *****************************************************
@ -288,8 +318,12 @@ class PlayBook(object):
host_list = [ h for h in self.inventory.list_hosts(play.hosts)
if not (h in self.stats.failures or h in self.stats.dark) ]
if not play.gather_facts:
if play.gather_facts is False:
return {}
elif play.gather_facts is None:
host_list = [h for h in host_list if h not in self.SETUP_CACHE or 'module_setup' not in self.SETUP_CACHE[h]]
if len(host_list) == 0:
return {}
self.callbacks.on_setup()
self.inventory.restrict_to(host_list)
@ -310,7 +344,8 @@ class PlayBook(object):
# let runner template out future commands
setup_ok = setup_results.get('contacted', {})
for (host, result) in setup_ok.iteritems():
self.SETUP_CACHE[host] = result.get('ansible_facts', {})
self.SETUP_CACHE[host].update({'module_setup': True})
self.SETUP_CACHE[host].update(result.get('ansible_facts', {}))
return setup_results
# *****************************************************
@ -320,6 +355,11 @@ class PlayBook(object):
self.callbacks.on_play_start(play.name)
# if no hosts matches this play, drop out
if not self.inventory.list_hosts(play.hosts):
self.callbacks.on_no_hosts_matched()
return True
# get facts from system
self._do_setup_step(play)
@ -345,6 +385,7 @@ class PlayBook(object):
self.inventory.also_restrict_to(on_hosts)
for task in play.tasks():
# only run the task if the requested tags match
should_run = False
for x in self.only_tags:
@ -353,7 +394,19 @@ class PlayBook(object):
should_run = True
break
if should_run:
self._run_task(play, task, False)
if not self._run_task(play, task, False):
# whether no hosts matched is fatal or not depends if it was on the initial step.
# if we got exactly no hosts on the first step (setup!) then the host group
# just didn't match anything and that's ok
return False
host_list = [ h for h in self.inventory.list_hosts(play.hosts)
if not (h in self.stats.failures or h in self.stats.dark) ]
# if no hosts remain, drop out
if not host_list:
self.callbacks.on_no_hosts_remaining()
return False
# run notify actions
for handler in play.handlers():
@ -364,3 +417,5 @@ class PlayBook(object):
self.inventory.lift_also_restriction()
return True

View File

@ -29,7 +29,8 @@ class Play(object):
'hosts', 'name', 'vars', 'vars_prompt', 'vars_files',
'handlers', 'remote_user', 'remote_port',
'sudo', 'sudo_user', 'transport', 'playbook',
'tags', 'gather_facts', 'serial', '_ds', '_handlers', '_tasks'
'tags', 'gather_facts', 'serial', '_ds', '_handlers', '_tasks',
'basedir'
]
# to catch typos and so forth -- these are userland names
@ -42,7 +43,7 @@ class Play(object):
# *************************************************
def __init__(self, playbook, ds):
def __init__(self, playbook, ds, basedir):
''' constructor loads from a play datastructure '''
for x in ds.keys():
@ -56,25 +57,25 @@ class Play(object):
raise errors.AnsibleError('hosts declaration is required')
elif isinstance(hosts, list):
hosts = ';'.join(hosts)
hosts = utils.template(hosts, playbook.extra_vars)
hosts = utils.template(basedir, hosts, playbook.extra_vars)
self._ds = ds
self.playbook = playbook
self.basedir = basedir
self.hosts = hosts
self.name = ds.get('name', self.hosts)
self.vars = ds.get('vars', {})
self.vars_files = ds.get('vars_files', [])
self.vars_prompt = ds.get('vars_prompt', {})
self.vars = self._get_vars(self.playbook.basedir)
self.vars = self._get_vars()
self._tasks = ds.get('tasks', [])
self._handlers = ds.get('handlers', [])
self.remote_user = utils.template(ds.get('user', self.playbook.remote_user), playbook.extra_vars)
self.remote_user = utils.template(basedir, ds.get('user', self.playbook.remote_user), playbook.extra_vars)
self.remote_port = ds.get('port', self.playbook.remote_port)
self.sudo = ds.get('sudo', self.playbook.sudo)
self.sudo_user = ds.get('sudo_user', self.playbook.sudo_user)
self.sudo_user = utils.template(basedir, ds.get('sudo_user', self.playbook.sudo_user), playbook.extra_vars)
self.transport = ds.get('connection', self.playbook.transport)
self.tags = ds.get('tags', None)
self.gather_facts = ds.get('gather_facts', True)
self.gather_facts = ds.get('gather_facts', None)
self.serial = ds.get('serial', 0)
self._update_vars_files_for_host(None)
@ -100,23 +101,29 @@ class Play(object):
tasks = ds.get(keyname, [])
results = []
for x in tasks:
task_vars = self.vars.copy()
if 'include' in x:
task_vars = self.vars.copy()
tokens = shlex.split(x['include'])
for t in tokens[1:]:
(k,v) = t.split("=", 1)
task_vars[k] = utils.template(v, task_vars)
include_file = utils.template(tokens[0], task_vars)
data = utils.parse_yaml_from_file(utils.path_dwim(self.playbook.basedir, include_file))
if 'with_items' in x:
items = utils.varReplaceWithItems(self.basedir, x['with_items'], task_vars)
else:
items = ['']
for item in items:
mv = task_vars.copy()
mv['item'] = item
for t in tokens[1:]:
(k,v) = t.split("=", 1)
mv[k] = utils.varReplaceWithItems(self.basedir, v, mv)
include_file = utils.template(self.basedir, tokens[0], mv)
data = utils.parse_yaml_from_file(utils.path_dwim(self.basedir, include_file))
for y in data:
results.append(Task(self,y,module_vars=mv.copy()))
elif type(x) == dict:
data = [x]
task_vars = self.vars.copy()
results.append(Task(self,x,module_vars=task_vars))
else:
raise Exception("unexpected task type")
for y in data:
mv = task_vars.copy()
results.append(Task(self,y,module_vars=mv))
for x in results:
if self.tags is not None:
x.tags.extend(self.tags)
@ -135,7 +142,7 @@ class Play(object):
# *************************************************
def _get_vars(self, dirname):
def _get_vars(self):
''' load the vars section from a play, accounting for all sorts of variable features
including loading from yaml files, prompting, and conditional includes of the first
file found in a list. '''
@ -164,7 +171,7 @@ class Play(object):
raise errors.AnsibleError("'vars_prompt' item is missing 'name:'")
vname = var['name']
prompt = "%s: " % var.get("prompt", vname)
prompt = var.get("prompt", vname)
private = var.get("private", True)
confirm = var.get("confirm", False)
@ -260,11 +267,11 @@ class Play(object):
found = False
sequence = []
for real_filename in filename:
filename2 = utils.template(real_filename, self.vars)
filename2 = utils.template(self.basedir, real_filename, self.vars)
filename3 = filename2
if host is not None:
filename3 = utils.template(filename2, self.playbook.SETUP_CACHE[host])
filename4 = utils.path_dwim(self.playbook.basedir, filename3)
filename3 = utils.template(self.basedir, filename2, self.playbook.SETUP_CACHE[host])
filename4 = utils.path_dwim(self.basedir, filename3)
sequence.append(filename4)
if os.path.exists(filename4):
found = True
@ -293,13 +300,13 @@ class Play(object):
else:
# just one filename supplied, load it!
filename2 = utils.template(filename, self.vars)
filename2 = utils.template(self.basedir, filename, self.vars)
filename3 = filename2
if host is not None:
filename3 = utils.template(filename2, self.playbook.SETUP_CACHE[host])
filename4 = utils.path_dwim(self.playbook.basedir, filename3)
filename3 = utils.template(self.basedir, filename2, self.playbook.SETUP_CACHE[host])
filename4 = utils.path_dwim(self.basedir, filename3)
if self._has_vars_in(filename4):
return
continue
new_vars = utils.parse_yaml_from_file(filename4)
if new_vars:
if type(new_vars) != dict:

View File

@ -26,21 +26,39 @@ class Task(object):
'notify', 'module_name', 'module_args', 'module_vars',
'play', 'notified_by', 'tags', 'register', 'with_items',
'delegate_to', 'first_available_file', 'ignore_errors',
'local_action'
'local_action', 'transport', 'sudo', 'sudo_user', 'sudo_pass',
'items_lookup_plugin', 'items_lookup_terms'
]
# to prevent typos and such
VALID_KEYS = [
'name', 'action', 'only_if', 'async', 'poll', 'notify', 'with_items',
'first_available_file', 'include', 'tags', 'register', 'ignore_errors',
'delegate_to', 'local_action'
'delegate_to', 'local_action', 'transport', 'sudo', 'sudo_user',
'sudo_pass'
]
def __init__(self, play, ds, module_vars=None):
''' constructor loads from a task or handler datastructure '''
for x in ds.keys():
if not x in Task.VALID_KEYS:
# code to allow for saying "modulename: args" versus "action: modulename args"
if x in play.playbook.modules_list:
ds['action'] = x + " " + ds[x]
ds.pop(x)
# code to allow "with_glob" and to reference a lookup plugin named glob
elif x.startswith("with_") and x != 'with_items':
plugin_name = x.replace("with_","")
if plugin_name in play.playbook.lookup_plugins_list:
ds['items_lookup_plugin'] = plugin_name
ds['items_lookup_terms'] = ds[x]
ds.pop(x)
else:
raise errors.AnsibleError("cannot find lookup plugin named %s for usage in with_%s" % (plugin_name, plugin_name))
elif not x in Task.VALID_KEYS:
raise errors.AnsibleError("%s is not a legal parameter in an Ansible task or handler" % x)
self.module_vars = module_vars
@ -50,7 +68,14 @@ class Task(object):
self.name = ds.get('name', None)
self.tags = [ 'all' ]
self.register = ds.get('register', None)
self.sudo = ds.get('sudo', play.sudo)
if self.sudo is True:
self.sudo_user = ds.get('sudo_user', play.sudo_user)
self.sudo_pass = ds.get('sudo_pass', play.playbook.sudo_pass)
else:
self.sudo_user = None
self.sudo_pass = None
# Both are defined
if ('action' in ds) and ('local_action' in ds):
raise errors.AnsibleError("the 'action' and 'local_action' attributes can not be used together")
@ -64,6 +89,14 @@ class Task(object):
else:
self.action = ds.get('action', '')
self.delegate_to = ds.get('delegate_to', None)
self.transport = ds.get('transport', play.transport)
# delegate_to can use variables
if not (self.delegate_to is None):
self.delegate_to = utils.template(None, self.delegate_to, self.module_vars)
# delegate_to: localhost should use local transport
if self.delegate_to in ['127.0.0.1', 'localhost']:
self.transport = 'local'
# notified by is used by Playbook code to flag which hosts
# need to run a notifier
@ -81,6 +114,10 @@ class Task(object):
self.first_available_file = ds.get('first_available_file', None)
self.with_items = ds.get('with_items', None)
self.items_lookup_plugin = ds.get('items_lookup_plugin', None)
self.items_lookup_terms = ds.get('items_lookup_terms', None)
self.ignore_errors = ds.get('ignore_errors', False)
# notify can be a string or a list, store as a list
@ -101,12 +138,13 @@ class Task(object):
# allow the user to list comma delimited tags
import_tags = import_tags.split(",")
self.name = utils.template(self.name, self.module_vars)
self.action = utils.template(self.action, self.module_vars)
self.name = utils.template(None, self.name, self.module_vars)
self.action = utils.template(None, self.action, self.module_vars)
# handle mutually incompatible options
if self.with_items is not None and self.first_available_file is not None:
raise errors.AnsibleError("with_items and first_available_file are mutually incompatible in a single task")
incompatibles = [ x for x in [ self.with_items, self.first_available_file, self.items_lookup_plugin ] if x is not None ]
if len(incompatibles) > 1:
raise errors.AnsibleError("with_items, with_(plugin), and first_available_file are mutually incompatible in a single task")
# make first_available_file accessable to Runner code
if self.first_available_file:
@ -117,6 +155,10 @@ class Task(object):
self.with_items = [ ]
self.module_vars['items'] = self.with_items
if self.items_lookup_plugin is not None:
self.module_vars['items_lookup_plugin'] = self.items_lookup_plugin
self.module_vars['items_lookup_terms'] = self.items_lookup_terms
# allow runner to see delegate_to option
self.module_vars['delegate_to'] = self.delegate_to

View File

@ -26,6 +26,8 @@ import tempfile
import time
import collections
import socket
import base64
import sys
import ansible.constants as C
import ansible.inventory
@ -43,6 +45,15 @@ try:
except ImportError:
HAS_ATFORK=False
dirname = os.path.dirname(__file__)
action_plugin_list = utils.import_plugins(os.path.join(dirname, 'action_plugins'))
for i in reversed(C.DEFAULT_ACTION_PLUGIN_PATH.split(os.pathsep)):
action_plugin_list.update(utils.import_plugins(i))
lookup_plugin_list = utils.import_plugins(os.path.join(dirname, 'lookup_plugins'))
for i in reversed(C.DEFAULT_LOOKUP_PLUGIN_PATH.split(os.pathsep)):
lookup_plugin_list.update(utils.import_plugins(i))
################################################
def _executor_hook(job_queue, result_queue):
@ -64,6 +75,23 @@ def _executor_hook(job_queue, result_queue):
except:
traceback.print_exc()
class HostVars(dict):
''' A special view of setup_cache that adds values from the inventory when needed. '''
def __init__(self, setup_cache, inventory):
self.setup_cache = setup_cache
self.inventory = inventory
self.lookup = {}
self.update(setup_cache)
def __getitem__(self, host):
if not host in self.lookup:
result = self.inventory.get_variables(host)
result.update(self.setup_cache.get(host, {}))
self.lookup[host] = result
return self.lookup[host]
class Runner(object):
''' core API interface to ansible '''
@ -79,7 +107,7 @@ class Runner(object):
pattern=C.DEFAULT_PATTERN, # which hosts? ex: 'all', 'acme.example.org'
remote_user=C.DEFAULT_REMOTE_USER, # ex: 'username'
remote_pass=C.DEFAULT_REMOTE_PASS, # ex: 'password123' or None if using key
remote_port=C.DEFAULT_REMOTE_PORT, # if SSH on different ports
remote_port=None, # if SSH on different ports
private_key_file=C.DEFAULT_PRIVATE_KEY_FILE, # if not using keys/passwords
sudo_pass=C.DEFAULT_SUDO_PASS, # ex: 'password123' or None
background=0, # async poll every X seconds, else 0 for non-async
@ -136,6 +164,19 @@ class Runner(object):
# ensure we are using unique tmp paths
random.seed()
# instantiate plugin classes
self.action_plugins = {}
self.lookup_plugins = {}
for (k,v) in action_plugin_list.iteritems():
self.action_plugins[k] = v.ActionModule(self)
for (k,v) in lookup_plugin_list.iteritems():
self.lookup_plugins[k] = v.LookupModule(self)
for (k,v) in utils.import_plugins(os.path.join(self.basedir, 'action_plugins')).iteritems():
self.action_plugins[k] = v.ActionModule(self)
for (k,v) in utils.import_plugins(os.path.join(self.basedir, 'lookup_plugins')).iteritems():
self.lookup_plugins[k] = v.LookupModule(self)
# *****************************************************
def _delete_remote_files(self, conn, files):
@ -145,11 +186,11 @@ class Runner(object):
# ability to turn off temp file deletion for debug purposes
return
if type(files) == str:
if type(files) in [ str, unicode ]:
files = [ files ]
for filename in files:
if filename.find('/tmp/') == -1:
raise Exception("not going to happen")
raise Exception("safeguard deletion, removal of %s is not going to happen" % filename)
self._low_level_exec_command(conn, "rm -rf %s" % filename, None)
# *****************************************************
@ -162,7 +203,10 @@ class Runner(object):
afd, afile = tempfile.mkstemp()
afo = os.fdopen(afd, 'w')
afo.write(data.encode('utf8'))
try:
afo.write(data.encode('utf8'))
except:
raise errors.AnsibleError("failure encoding into utf-8")
afo.flush()
afo.close()
@ -180,10 +224,13 @@ class Runner(object):
''' runs a module that has already been transferred '''
if type(args) == dict:
args = utils.jsonify(args,format=True)
# hack to support fireball mode
if module_name == 'fireball':
args = "%s password=%s" % (args, base64.b64encode(str(utils.key_for_hostname(conn.host))))
if 'port' not in args:
args += " port=%s" % C.ZEROMQ_PORT
(remote_module_path, is_new_style) = self._copy_module(conn, tmp, module_name, inject)
(remote_module_path, is_new_style) = self._copy_module(conn, tmp, module_name, args, inject)
cmd = "chmod u+x %s" % remote_module_path
if self.sudo and self.sudo_user != 'root':
# deal with possible umask issues once sudo'ed to other user
@ -192,7 +239,7 @@ class Runner(object):
cmd = ""
if not is_new_style:
args = utils.template(args, inject)
args = utils.template(self.basedir, args, inject)
argsfile = self._transfer_str(conn, tmp, 'arguments', args)
if async_jid is None:
cmd = "%s %s" % (remote_module_path, argsfile)
@ -209,217 +256,6 @@ class Runner(object):
# *****************************************************
def _execute_raw(self, conn, tmp, inject=None):
''' execute a non-module command for bootstrapping, or if there's no python on a device '''
return ReturnData(conn=conn, result=dict(
stdout=self._low_level_exec_command(conn, self.module_args.encode('utf-8'), tmp, sudoable = True)
))
# ***************************************************
def _execute_normal_module(self, conn, tmp, module_name, inject=None):
''' transfer & execute a module that is not 'copy' or 'template' '''
# shell and command are the same module
if module_name == 'shell':
module_name = 'command'
self.module_args += " #USE_SHELL"
vv("REMOTE_MODULE %s %s" % (module_name, self.module_args), host=conn.host)
exec_rc = self._execute_module(conn, tmp, module_name, self.module_args, inject=inject)
return exec_rc
# *****************************************************
def _execute_async_module(self, conn, tmp, module_name, inject=None):
''' transfer the given module name, plus the async module, then run it '''
# shell and command module are the same
module_args = self.module_args
if module_name == 'shell':
module_name = 'command'
module_args += " #USE_SHELL"
(module_path, is_new_style) = self._copy_module(conn, tmp, module_name, inject)
self._low_level_exec_command(conn, "chmod a+rx %s" % module_path, tmp)
return self._execute_module(conn, tmp, 'async_wrapper', module_args,
async_module=module_path,
async_jid=self.generated_jid,
async_limit=self.background,
inject=inject
)
# *****************************************************
def _execute_copy(self, conn, tmp, inject=None):
''' handler for file transfer operations '''
# load up options
options = utils.parse_kv(self.module_args)
source = options.get('src', None)
dest = options.get('dest', None)
if (source is None and not 'first_available_file' in inject) or dest is None:
result=dict(failed=True, msg="src and dest are required")
return ReturnData(conn=conn, result=result)
# if we have first_available_file in our vars
# look up the files and use the first one we find as src
if 'first_available_file' in inject:
found = False
for fn in inject.get('first_available_file'):
fn = utils.template(fn, inject)
if os.path.exists(fn):
source = fn
found = True
break
if not found:
results=dict(failed=True, msg="could not find src in first_available_file list")
return ReturnData(conn=conn, results=results)
source = utils.template(source, inject)
source = utils.path_dwim(self.basedir, source)
local_md5 = utils.md5(source)
if local_md5 is None:
result=dict(failed=True, msg="could not find src=%s" % source)
return ReturnData(conn=conn, result=result)
remote_md5 = self._remote_md5(conn, tmp, dest)
exec_rc = None
if local_md5 != remote_md5:
# transfer the file to a remote tmp location
tmp_src = tmp + os.path.basename(source)
conn.put_file(source, tmp_src)
# fix file permissions when the copy is done as a different user
if self.sudo and self.sudo_user != 'root':
self._low_level_exec_command(conn, "chmod a+r %s" % tmp_src, tmp)
# run the copy module
self.module_args = "%s src=%s" % (self.module_args, tmp_src)
return self._execute_module(conn, tmp, 'copy', self.module_args, inject=inject).daisychain('file')
else:
# no need to transfer the file, already correct md5
result = dict(changed=False, md5sum=remote_md5, transferred=False)
return ReturnData(conn=conn, result=result).daisychain('file')
# *****************************************************
def _execute_fetch(self, conn, tmp, inject=None):
''' handler for fetch operations '''
# load up options
options = utils.parse_kv(self.module_args)
source = options.get('src', None)
dest = options.get('dest', None)
if source is None or dest is None:
results = dict(failed=True, msg="src and dest are required")
return ReturnData(conn=conn, result=results)
# apply templating to source argument
source = utils.template(source, inject)
# apply templating to dest argument
dest = utils.template(dest, inject)
# files are saved in dest dir, with a subdir for each host, then the filename
dest = "%s/%s/%s" % (utils.path_dwim(self.basedir, dest), conn.host, source)
dest = dest.replace("//","/")
# calculate md5 sum for the remote file
remote_md5 = self._remote_md5(conn, tmp, source)
# these don't fail because you may want to transfer a log file that possibly MAY exist
# but keep going to fetch other log files
if remote_md5 == '0':
result = dict(msg="unable to calculate the md5 sum of the remote file", file=source, changed=False)
return ReturnData(conn=conn, result=result)
if remote_md5 == '1':
result = dict(msg="the remote file does not exist, not transferring, ignored", file=source, changed=False)
return ReturnData(conn=conn, result=result)
if remote_md5 == '2':
result = dict(msg="no read permission on remote file, not transferring, ignored", file=source, changed=False)
return ReturnData(conn=conn, result=result)
# calculate md5 sum for the local file
local_md5 = utils.md5(dest)
if remote_md5 != local_md5:
# create the containing directories, if needed
if not os.path.isdir(os.path.dirname(dest)):
os.makedirs(os.path.dirname(dest))
# fetch the file and check for changes
conn.fetch_file(source, dest)
new_md5 = utils.md5(dest)
if new_md5 != remote_md5:
result = dict(failed=True, md5sum=new_md5, msg="md5 mismatch", file=source)
return ReturnData(conn=conn, result=result)
result = dict(changed=True, md5sum=new_md5)
return ReturnData(conn=conn, result=result)
else:
result = dict(changed=False, md5sum=local_md5, file=source)
return ReturnData(conn=conn, result=result)
# *****************************************************
def _execute_template(self, conn, tmp, inject=None):
''' handler for template operations '''
if not self.is_playbook:
raise errors.AnsibleError("in current versions of ansible, templates are only usable in playbooks")
# load up options
options = utils.parse_kv(self.module_args)
source = options.get('src', None)
dest = options.get('dest', None)
if (source is None and 'first_available_file' not in inject) or dest is None:
result = dict(failed=True, msg="src and dest are required")
return ReturnData(conn=conn, comm_ok=False, result=result)
# if we have first_available_file in our vars
# look up the files and use the first one we find as src
if 'first_available_file' in inject:
found = False
for fn in self.module_vars.get('first_available_file'):
fn = utils.template(fn, inject)
if os.path.exists(fn):
source = fn
found = True
break
if not found:
result = dict(failed=True, msg="could not find src in first_available_file list")
return ReturnData(conn=conn, comm_ok=False, result=result)
source = utils.template(source, inject)
# template the source data locally & transfer
try:
resultant = utils.template_from_file(self.basedir, source, inject)
except Exception, e:
result = dict(failed=True, msg=str(e))
return ReturnData(conn=conn, comm_ok=False, result=result)
xfered = self._transfer_str(conn, tmp, 'source', resultant)
# run the copy module, queue the file module
self.module_args = "%s src=%s dest=%s" % (self.module_args, xfered, dest)
return self._execute_module(conn, tmp, 'copy', self.module_args, inject=inject).daisychain('file')
# *****************************************************
def _execute_assemble(self, conn, tmp, inject=None):
''' handler for assemble operations '''
# FIXME: once assemble is ported over to the use the new common logic, this method
# will be unneccessary as it can decide to daisychain via it's own module returns.
# and this function can be deleted.
return self._execute_module(conn, tmp, 'assemble', self.module_args, inject=inject).daisychain('file')
# *****************************************************
def _executor(self, host):
''' handler for multiprocessing library '''
@ -446,24 +282,36 @@ class Runner(object):
''' executes any module one or more times '''
host_variables = self.inventory.get_variables(host)
port = host_variables.get('ansible_ssh_port', self.remote_port)
if self.transport in [ 'paramiko', 'ssh' ]:
port = host_variables.get('ansible_ssh_port', self.remote_port)
if port is None:
port = C.DEFAULT_REMOTE_PORT
else:
# fireball, local, etc
port = self.remote_port
inject = {}
inject.update(host_variables)
inject.update(self.module_vars)
inject.update(self.setup_cache[host])
inject['hostvars'] = self.setup_cache
inject['hostvars'] = HostVars(self.setup_cache, self.inventory)
inject['group_names'] = host_variables.get('group_names', [])
inject['groups'] = self.inventory.groups_list()
# allow with_items to work in playbooks...
# apt and yum are converted into a single call, others run in a loop
items = self.module_vars.get('items', [])
if isinstance(items, basestring) and items.startswith("$"):
items = items.replace("$","")
if items in inject:
items = inject[items]
else:
raise errors.AnsibleError("unbound variable in with_items: %s" % items)
items = utils.varReplaceWithItems(self.basedir, items, inject)
# if we instead said 'with_foo' and there is a lookup module named foo...
items_plugin = self.module_vars.get('items_lookup_plugin', None)
if items_plugin is not None:
items_terms = self.module_vars.get('items_lookup_terms', '')
if items_plugin in self.lookup_plugins:
items_terms = utils.template(self.basedir, items_terms, inject)
items = self.lookup_plugins[items_plugin].run(items_terms)
if type(items) != list:
raise errors.AnsibleError("with_items only takes a list: %s" % items)
@ -475,7 +323,7 @@ class Runner(object):
# logic to decide how to run things depends on whether with_items is used
if len(items) == 0:
return self._executor_internal_inner(host, inject, port)
return self._executor_internal_inner(host, self.module_name, self.module_args, inject, port)
else:
# executing using with_items, so make multiple calls
# TODO: refactor
@ -484,17 +332,13 @@ class Runner(object):
all_changed = False
all_failed = False
results = []
# Save module name and args since daisy-chaining can overwrite them
module_name = self.module_name
module_args = self.module_args
for x in items:
self.module_name = module_name
self.module_args = module_args
inject['item'] = x
result = self._executor_internal_inner(host, inject, port)
result = self._executor_internal_inner(host, self.module_name, self.module_args, inject, port)
results.append(result.result)
if result.comm_ok == False:
all_comm_ok = False
all_failed = True
break
for x in results:
if x.get('changed') == True:
@ -502,7 +346,7 @@ class Runner(object):
if (x.get('failed') == True) or (('rc' in x) and (x['rc'] != 0)):
all_failed = True
break
msg = 'All items succeeded'
msg = 'All items completed'
if all_failed:
msg = "One or more items failed."
rd_result = dict(failed=all_failed, changed=all_changed, results=results, msg=msg)
@ -512,76 +356,84 @@ class Runner(object):
# *****************************************************
def _executor_internal_inner(self, host, inject, port, is_chained=False):
def _executor_internal_inner(self, host, module_name, module_args, inject, port, is_chained=False):
''' decides how to invoke a module '''
# FIXME: temporary, need to refactor to pass as parameters versus reassigning
prev_module_name = self.module_name
prev_module_args = self.module_args
# special non-user/non-fact variables:
# 'groups' variable is a list of host name in each group
# 'hostvars' variable contains variables for each host name
# ... and is set elsewhere
# 'inventory_hostname' is also set elsewhere
group_hosts = {}
for g in self.inventory.groups:
group_hosts[g.name] = [ h.name for h in g.hosts ]
inject['groups'] = group_hosts
inject['groups'] = self.inventory.groups_list()
# allow module args to work as a dictionary
# though it is usually a string
new_args = ""
if type(self.module_args) == dict:
for (k,v) in self.module_args.iteritems():
if type(module_args) == dict:
for (k,v) in module_args.iteritems():
new_args = new_args + "%s='%s' " % (k,v)
self.module_args = new_args
self.module_args = utils.template(self.module_args, inject)
module_args = new_args
conditional = utils.template(self.conditional, inject)
if not eval(conditional):
conditional = utils.template(self.basedir, self.conditional, inject)
if not utils.check_conditional(conditional):
result = utils.jsonify(dict(skipped=True))
self.callbacks.on_skipped(host, inject.get('item',None))
return ReturnData(host=host, result=result)
conn = None
actual_host = host
actual_host = inject.get('ansible_ssh_host', host)
actual_port = port
if self.transport in ['paramiko', 'ssh' ]:
actual_port = inject.get('ansible_ssh_port', port)
# the delegated host may have different SSH port configured, etc
# and we need to transfer those, and only those, variables
delegate_to = inject.get('delegate_to', None)
if delegate_to is not None:
delegate_to = utils.template(self.basedir, delegate_to, inject)
try:
delegate_info = inject['hostvars'][delegate_to]
actual_host = delegate_info.get('ansible_ssh_host', delegate_to)
actual_port = delegate_info.get('ansible_ssh_port', port)
except errors.AnsibleError:
actual_host = delegate_to
try:
delegate_to = inject.get('delegate_to', None)
if delegate_to is not None:
actual_host = delegate_to
conn = self.connector.connect(actual_host, port)
if delegate_to is not None:
conn._delegate_for = host
transport = None # use Runner setting
if delegate_to and actual_host in [ '127.0.0.1', 'localhost' ]:
transport = 'local'
if actual_port is not None:
actual_port = int(actual_port)
conn = self.connector.connect(actual_host, actual_port, transport=transport)
if delegate_to:
conn.delegate = host
except errors.AnsibleConnectionFailed, e:
result = dict(failed=True, msg="FAILED: %s" % str(e))
return ReturnData(host=host, comm_ok=False, result=result)
module_name = utils.template(self.module_name, inject)
module_name = utils.template(self.basedir, module_name, inject)
module_args = utils.template(self.basedir, module_args, inject, expand_lists=True)
tmp = ''
if self.module_name != 'raw':
tmp = self._make_tmp_path(conn)
result = None
handler = getattr(self, "_execute_%s" % self.module_name, None)
handler = self.action_plugins.get(module_name, None)
if handler:
result = handler(conn, tmp, inject=inject)
if self.background != 0:
raise errors.AnsibleError("async mode is not supported with the %s module" % module_name)
result = handler.run(conn, tmp, module_name, module_args, inject)
else:
if self.background == 0:
result = self._execute_normal_module(conn, tmp, module_name, inject=inject)
result = self.action_plugins['normal'].run(conn, tmp, module_name, module_args, inject)
else:
result = self._execute_async_module(conn, tmp, module_name, inject=inject)
result = self.action_plugins['async'].run(conn, tmp, module_name, module_args, inject)
if result.is_successful() and 'daisychain' in result.result:
self.module_name = result.result['daisychain']
if 'daisychain_args' in result.result:
self.module_args = result.result['daisychain_args']
result2 = self._executor_internal_inner(host, inject, port, is_chained=True)
# FIXME: remove this hack
self.module_name = prev_module_name
self.module_args = prev_module_args
result2 = self._executor_internal_inner(host, result.result['daisychain'], result.result.get('daisychain_args', {}), inject, port, is_chained=True)
changed = False
if result.result.get('changed',False) or result2.result.get('changed',False):
@ -604,8 +456,8 @@ class Runner(object):
result.result['item'] = inject['item']
result.result['invocation'] = dict(
module_args=self.module_args,
module_name=self.module_name
module_args=module_args,
module_name=module_name
)
if is_chained:
@ -628,12 +480,12 @@ class Runner(object):
sudo_user = self.sudo_user
stdin, stdout, stderr = conn.exec_command(cmd, tmp, sudo_user, sudoable=sudoable)
if type(stdout) != str:
if type(stdout) not in [ str, unicode ]:
out = "\n".join(stdout.readlines())
else:
out = stdout
if type(stderr) != str:
if type(stderr) not in [ str, unicode ]:
err = "\n".join(stderr.readlines())
else:
err = stderr
@ -655,8 +507,17 @@ class Runner(object):
cmd = " || ".join(md5s)
cmd = "%s; %s || (echo \"${rc} %s\")" % (test, cmd, path)
data = self._low_level_exec_command(conn, cmd, tmp, sudoable=False)
data = utils.last_non_blank_line(data)
return data.split()[0]
data2 = utils.last_non_blank_line(data)
try:
return data2.split()[0]
except IndexError:
sys.stderr.write("warning: md5sum command failed unusually, please report this to the list so it can be fixed\n")
sys.stderr.write("command: %s\n" % md5s)
sys.stderr.write("----\n")
sys.stderr.write("output: %s\n" % data)
sys.stderr.write("----\n")
# this will signal that it changed and allow things to keep going
return "INVALIDMD5SUM"
# *****************************************************
@ -676,25 +537,27 @@ class Runner(object):
cmd += ' && echo %s' % basetmp
result = self._low_level_exec_command(conn, cmd, None, sudoable=False)
return utils.last_non_blank_line(result).strip() + '/'
rc = utils.last_non_blank_line(result).strip() + '/'
return rc
# *****************************************************
def _copy_module(self, conn, tmp, module, inject):
def _copy_module(self, conn, tmp, module_name, module_args, inject):
''' transfer a module over SFTP, does not run it '''
if module.startswith("/"):
raise errors.AnsibleFileNotFound("%s is not a module" % module)
if module_name.startswith("/"):
raise errors.AnsibleFileNotFound("%s is not a module" % module_name)
# Search module path(s) for named module.
for module_path in self.module_path.split(os.pathsep):
in_path = os.path.expanduser(os.path.join(module_path, module))
in_path = os.path.expanduser(os.path.join(module_path, module_name))
if os.path.exists(in_path):
break
else:
raise errors.AnsibleFileNotFound("module %s not found in %s" % (module, self.module_path))
raise errors.AnsibleFileNotFound("module %s not found in %s" % (module_name, self.module_path))
out_path = os.path.join(tmp, module)
out_path = os.path.join(tmp, module_name)
module_data = ""
is_new_style=False
@ -704,7 +567,7 @@ class Runner(object):
if module_common.REPLACER in module_data:
is_new_style=True
module_data = module_data.replace(module_common.REPLACER, module_common.MODULE_COMMON)
encoded_args = "\"\"\"%s\"\"\"" % utils.template(self.module_args, inject).replace("\"","\\\"")
encoded_args = "\"\"\"%s\"\"\"" % module_args.replace("\"","\\\"")
module_data = module_data.replace(module_common.REPLACER_ARGS, encoded_args)
# use the correct python interpreter for the host
@ -715,7 +578,7 @@ class Runner(object):
module_lines[0] = "#!%s" % interpreter
module_data = "\n".join(module_lines)
self._transfer_str(conn, tmp, module, module_data)
self._transfer_str(conn, tmp, module_name, module_data)
return (out_path, is_new_style)
# *****************************************************
@ -723,9 +586,10 @@ class Runner(object):
def _parallel_exec(self, hosts):
''' handles mulitprocessing when more than 1 fork is required '''
job_queue = multiprocessing.Manager().Queue()
manager = multiprocessing.Manager()
job_queue = manager.Queue()
[job_queue.put(i) for i in hosts]
result_queue = multiprocessing.Manager().Queue()
result_queue = manager.Queue()
workers = []
for i in range(self.forks):
@ -787,7 +651,26 @@ class Runner(object):
hosts = [ (self,x) for x in hosts ]
results = None
if self.forks > 1:
# Check if this is an action plugin. Some of them are designed
# to be ran once per group of hosts. Example module: pause,
# run once per hostgroup, rather than pausing once per each
# host.
p = self.action_plugins.get(self.module_name, None)
if p and getattr(p, 'BYPASS_HOST_LOOP', None):
# Expose the current hostgroup to the bypassing plugins
self.host_set = hosts
# We aren't iterating over all the hosts in this
# group. So, just pick the first host in our group to
# construct the conn object with.
result_data = self._executor(hosts[0][1]).result
# Create a ResultData item for each host in this group
# using the returned result. If we didn't do this we would
# get false reports of dark hosts.
results = [ ReturnData(host=h[1], result=result_data, comm_ok=True) \
for h in hosts ]
del self.host_set
elif self.forks > 1:
results = self._parallel_exec(hosts)
else:
results = [ self._executor(h[1]) for h in hosts ]

View File

@ -0,0 +1,52 @@
# (c) 2012, 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/>.
import os
import pwd
import random
import traceback
import tempfile
import ansible.constants as C
from ansible import utils
from ansible import errors
from ansible import module_common
from ansible.runner.return_data import ReturnData
class ActionModule(object):
def __init__(self, runner):
self.runner = runner
def run(self, conn, tmp, module_name, module_args, inject):
''' transfer the given module name, plus the async module, then run it '''
# shell and command module are the same
if module_name == 'shell':
module_name = 'command'
module_args += " #USE_SHELL"
(module_path, is_new_style) = self.runner._copy_module(conn, tmp, module_name, module_args, inject)
self.runner._low_level_exec_command(conn, "chmod a+rx %s" % module_path, tmp)
return self.runner._execute_module(conn, tmp, 'async_wrapper', module_args,
async_module=module_path,
async_jid=self.runner.generated_jid,
async_limit=self.runner.background,
inject=inject
)

View File

@ -0,0 +1,96 @@
# (c) 2012, 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/>.
import os
import pwd
import random
import traceback
import tempfile
import ansible.constants as C
from ansible import utils
from ansible import errors
from ansible import module_common
from ansible.runner.return_data import ReturnData
class ActionModule(object):
def __init__(self, runner):
self.runner = runner
def run(self, conn, tmp, module_name, module_args, inject):
''' handler for file transfer operations '''
# load up options
options = utils.parse_kv(module_args)
source = options.get('src', None)
dest = options.get('dest', None)
if dest.endswith("/"):
base = os.path.basename(source)
dest = os.path.join(dest, base)
if (source is None and not 'first_available_file' in inject) or dest is None:
result=dict(failed=True, msg="src and dest are required")
return ReturnData(conn=conn, result=result)
# if we have first_available_file in our vars
# look up the files and use the first one we find as src
if 'first_available_file' in inject:
found = False
for fn in inject.get('first_available_file'):
fn = utils.template(self.runner.basedir, fn, inject)
if os.path.exists(fn):
source = fn
found = True
break
if not found:
results=dict(failed=True, msg="could not find src in first_available_file list")
return ReturnData(conn=conn, results=results)
source = utils.template(self.runner.basedir, source, inject)
source = utils.path_dwim(self.runner.basedir, source)
local_md5 = utils.md5(source)
if local_md5 is None:
result=dict(failed=True, msg="could not find src=%s" % source)
return ReturnData(conn=conn, result=result)
remote_md5 = self.runner._remote_md5(conn, tmp, dest)
exec_rc = None
if local_md5 != remote_md5:
# transfer the file to a remote tmp location
tmp_src = tmp + os.path.basename(source)
conn.put_file(source, tmp_src)
# fix file permissions when the copy is done as a different user
if self.runner.sudo and self.runner.sudo_user != 'root':
self.runner._low_level_exec_command(conn, "chmod a+r %s" % tmp_src, tmp)
# run the copy module
module_args = "%s src=%s" % (module_args, tmp_src)
return self.runner._execute_module(conn, tmp, 'copy', module_args, inject=inject).daisychain('file', module_args)
else:
# no need to transfer the file, already correct md5, but still need to set src so the file module
# does not freak out. It's just the basename of the file.
tmp_src = tmp + os.path.basename(source)
module_args = "%s src=%s" % (module_args, tmp_src)
result = dict(changed=False, md5sum=remote_md5, transferred=False)
return ReturnData(conn=conn, result=result).daisychain('file', module_args)

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