2012-03-07 17:35:18 +01:00
< !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" / >
2012-03-13 00:13:19 +01:00
< title > Ansible Modules — Ansible - SSH-Based Configuration Management & Deployment< / title >
2012-03-07 17:35:18 +01:00
< link rel = "stylesheet" href = "_static/default.css" type = "text/css" / >
< link rel = "stylesheet" href = "_static/pygments.css" type = "text/css" / >
2012-03-09 17:44:14 +01:00
< link rel = "stylesheet" href = "_static/bootstrap.css" type = "text/css" / >
< link rel = "stylesheet" href = "_static/bootstrap-sphinx.css" type = "text/css" / >
2012-03-07 17:35:18 +01:00
< script type = "text/javascript" >
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
2012-03-13 00:13:19 +01:00
VERSION: '0.01',
2012-03-07 17:35:18 +01:00
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
2012-03-09 17:50:07 +01:00
HAS_SOURCE: false
2012-03-07 17:35:18 +01:00
};
< / script >
< script type = "text/javascript" src = "_static/jquery.js" > < / script >
< script type = "text/javascript" src = "_static/underscore.js" > < / script >
< script type = "text/javascript" src = "_static/doctools.js" > < / script >
2012-03-09 17:44:14 +01:00
< script type = "text/javascript" src = "_static/bootstrap-dropdown.js" > < / script >
< script type = "text/javascript" src = "_static/bootstrap-scrollspy.js" > < / script >
2012-04-01 04:44:02 +02:00
< link rel = "shortcut icon" href = "_static/favicon.ico" / >
2012-03-13 00:13:19 +01:00
< link rel = "top" title = "Ansible - SSH-Based Configuration Management & Deployment" href = "index.html" / >
2012-03-11 20:34:21 +01:00
< link rel = "next" title = "YAML Syntax" href = "YAMLSyntax.html" / >
2012-03-09 17:44:14 +01:00
< link rel = "prev" title = "Command Line Examples" href = "examples.html" / >
< 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();
});
}());
2012-03-10 04:31:54 +01:00
< / script >
2012-04-28 16:46:09 +02:00
2012-03-10 04:31:54 +01:00
< 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);
})();
2012-03-09 17:44:14 +01:00
< / script >
2012-04-28 16:46:09 +02:00
< script type = "text/javascript" >
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/plusone.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
< / script >
2012-04-28 16:42:32 +02:00
< script > ( f u n c t i o n ( d , s , i d ) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/all.js#xfbml=1";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));< / script >
2012-03-09 17:44:14 +01:00
2012-03-07 17:35:18 +01:00
< / head >
< body >
2012-03-09 17:44:14 +01:00
< div class = "topbar" data-scrollspy = "scrollspy" >
< div class = "topbar-inner" >
< div class = "container" >
2012-04-18 02:47:29 +02:00
<!-- <a class="brand" href="index.html">Ansible</a> -->
2012-03-09 17:44:14 +01:00
< ul class = "nav" >
< li class = "dropdown" data-dropdown = "dropdown" >
< a href = "index.html"
2012-03-31 15:29:31 +02:00
class="dropdown-toggle">Chapter< / a >
2012-03-09 17:44:14 +01:00
< span class = "globaltoc" > < ul class = "current" >
2012-03-10 03:50:00 +01:00
< li class = "toctree-l1" > < a class = "reference internal" href = "gettingstarted.html" > Downloads & Getting Started< / a > < / li >
2012-03-09 17:44:14 +01:00
< li class = "toctree-l1" > < a class = "reference internal" href = "patterns.html" > The Inventory File, Patterns, and Groups< / a > < / li >
< li class = "toctree-l1" > < a class = "reference internal" href = "examples.html" > Command Line Examples< / a > < / li >
< li class = "toctree-l1 current" > < a class = "current reference internal" href = "" > Ansible Modules< / a > < / li >
2012-03-11 20:34:21 +01:00
< li class = "toctree-l1" > < a class = "reference internal" href = "YAMLSyntax.html" > YAML Syntax< / a > < / li >
2012-03-09 17:44:14 +01:00
< li class = "toctree-l1" > < a class = "reference internal" href = "playbooks.html" > Playbooks< / a > < / li >
2012-03-31 04:28:30 +02:00
< li class = "toctree-l1" > < a class = "reference internal" href = "api.html" > API & Integrations< / a > < / li >
2012-03-14 17:50:40 +01:00
< li class = "toctree-l1" > < a class = "reference internal" href = "moduledev.html" > Module Development Guide< / a > < / li >
2012-03-10 03:50:00 +01:00
< li class = "toctree-l1" > < a class = "reference internal" href = "faq.html" > Frequently Asked Questions< / a > < / li >
2012-03-09 17:44:14 +01:00
< / ul >
< / span >
2012-03-31 15:36:37 +02:00
< / li >
< li class = "dropdown" data-dropdown = "dropdown" >
< a href = "#"
class="dropdown-toggle">Page< / a >
< span class = "localtoc" > < ul >
< li > < a class = "reference internal" href = "#" > Ansible Modules< / a > < ul >
2012-03-27 01:48:32 +02:00
< li > < a class = "reference internal" href = "#apt" > apt< / a > < / li >
2012-04-06 17:41:18 +02:00
< li > < a class = "reference internal" href = "#command" > command< / a > < / li >
2012-03-31 15:36:37 +02:00
< li > < a class = "reference internal" href = "#copy" > copy< / a > < / li >
< li > < a class = "reference internal" href = "#facter" > facter< / a > < / li >
2012-04-13 04:47:15 +02:00
< li > < a class = "reference internal" href = "#fetch" > fetch< / a > < / li >
2012-03-31 15:36:37 +02:00
< li > < a class = "reference internal" href = "#file" > file< / a > < / li >
< li > < a class = "reference internal" href = "#git" > git< / a > < / li >
2012-03-31 18:08:28 +02:00
< li > < a class = "reference internal" href = "#group" > group< / a > < / li >
2012-03-31 15:36:37 +02:00
< li > < a class = "reference internal" href = "#ohai" > ohai< / a > < / li >
< li > < a class = "reference internal" href = "#ping" > ping< / a > < / li >
< li > < a class = "reference internal" href = "#service" > service< / a > < / li >
< li > < a class = "reference internal" href = "#setup" > setup< / a > < / li >
< li > < a class = "reference internal" href = "#shell" > shell< / a > < / li >
< li > < a class = "reference internal" href = "#template" > template< / a > < / li >
2012-03-22 06:01:02 +01:00
< li > < a class = "reference internal" href = "#user" > user< / a > < / li >
2012-04-06 17:41:18 +02:00
< li > < a class = "reference internal" href = "#virt" > virt< / a > < / li >
2012-03-31 15:36:37 +02:00
< li > < a class = "reference internal" href = "#yum" > yum< / a > < / li >
< li > < a class = "reference internal" href = "#writing-your-own-modules" > Writing your own modules< / a > < / li >
< / ul >
< / li >
< / ul >
< / span >
2012-03-09 17:44:14 +01:00
< / li >
< / ul >
< ul class = "nav secondary-nav" >
< form class = "pull-left" action = "search.html" 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 >
< / ul >
< / div >
< / div >
< / div >
2012-04-19 15:39:50 +02:00
< a href = "http://github.com/ansible/ansible" > < img style = "position: absolute; right: 0; border: 0;" src = "https://a248.e.akamai.net/assets.github.com/img/e6bef7a091f5f3138b8cd40bc3e114258dd68ddf/687474703a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f7265645f6161303030302e706e67" alt = "Fork me on GitHub" > < / a >
2012-03-09 17:44:14 +01:00
2012-03-10 16:39:34 +01:00
2012-03-09 17:44:14 +01:00
< div class = "container" >
2012-04-19 15:24:45 +02:00
< a href = "http://ansible.github.com" > < img src = "http://ansible.github.com/ansible-logo.png" alt = "Ansible" / > < / a > < br / >
2012-04-28 16:42:32 +02:00
< br / >
2012-03-09 17:44:14 +01:00
2012-03-08 19:36:47 +01:00
< div class = "section" id = "ansible-modules" >
< h1 > Ansible Modules< a class = "headerlink" href = "#ansible-modules" title = "Permalink to this headline" > ¶< / a > < / h1 >
2012-03-31 16:38:24 +02:00
< p > Ansible ships with a number of modules (called the ‘ module library’ )
that can be executed directly on remote hosts or through < a class = "reference internal" href = "playbooks.html" > < em > Playbooks< / em > < / a > .
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.< / p >
< p > Let’ s review how we execute three different modules from the command line:< / p >
< div class = "highlight-python" > < pre > ansible webservers -m service -a "name=httpd state=running"
ansible webservers -m ping
ansible webservers -m command -a "/sbin/reboot -t now"< / pre >
< / div >
< p > Each module supports taking arguments. Nearly all modules take < tt class = "docutils literal" > < span class = "pre" > key=value< / span > < / tt >
arguments, space delimited. Some modules take
no arguments, and the command/shell modules simply take the string
2012-03-15 01:57:35 +01:00
of the command you want to run.< / p >
2012-03-31 16:38:24 +02:00
< p > From playbooks, Ansible modules are executed in a very similar way:< / p >
< div class = "highlight-python" > < pre > - name: reboot the servers
action: command /sbin/reboot -t now< / pre >
< / div >
< p > All modules technically return JSON format data, though if you are using the
2012-03-10 00:29:01 +01:00
command line or playbooks, you don’ t really need to know much about
2012-03-31 16:38:24 +02:00
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 tho choose.< / p >
< p > Most modules other than command are < cite > idempotent< / cite > , meaning they will seek
2012-03-27 03:41:50 +02:00
to avoid changes to the system unless a change needs to be made. When using Ansible
2012-03-31 16:38:24 +02:00
playbooks, these modules can trigger ‘ change events’ . Unless otherwise
noted, any given module does support change hooks.< / p >
< p > Let’ s see what’ s available in the Ansible module library, out of the box:< / p >
2012-03-27 01:48:32 +02:00
< div class = "section" id = "apt" >
2012-04-06 17:41:18 +02:00
< span id = "id1" > < / span > < h2 > apt< a class = "headerlink" href = "#apt" title = "Permalink to this headline" > ¶< / a > < / h2 >
2012-03-27 01:48:32 +02:00
< p > Manages apt-packages (such as for Debian/Ubuntu).< / p >
< p > < em > pkg< / em > :< / p >
< ul class = "simple" >
2012-04-26 04:28:38 +02:00
< li > A package name or package specifier with version, like foo=1.0< / li >
2012-03-27 01:48:32 +02:00
< / ul >
< p > < em > state< / em > :< / p >
< ul class = "simple" >
2012-04-13 04:47:15 +02:00
< li > Can be either ‘ installed’ , ‘ removed’ , or ‘ latest’ . The default is ‘ installed’ .< / li >
2012-03-27 01:48:32 +02:00
< / ul >
2012-04-19 15:57:30 +02:00
< p > < em > update-cache< / em > :< / p >
< ul class = "simple" >
< li > Whether apt cache must be updated prior operation. Optional, and can be
2012-04-19 15:57:45 +02:00
‘ yes’ , or ‘ no’ . The default is ‘ no’ . This can be done as the part of a
package operation or as a seperate step.< / li >
2012-04-19 15:57:30 +02:00
< / ul >
< p > < em > purge< / em > :< / p >
< ul class = "simple" >
< li > Will force purge of configuration file for when ensure is set to ‘ removed’ .
Defaults to ‘ no’ .< / li >
< / ul >
2012-04-26 04:28:38 +02:00
< p > < em > default-release< / em > :< / p >
< ul class = "simple" >
< li > Corresponds to the -t option for apt, and sets pin priorities< / li >
< / ul >
2012-03-27 03:41:50 +02:00
< p > Example action from Ansible < a class = "reference internal" href = "playbooks.html" > < em > Playbooks< / em > < / a > :< / p >
2012-04-19 15:57:45 +02:00
< div class = "highlight-python" > < pre > apt pkg=foo update-cache=yes
2012-04-26 04:28:38 +02:00
apt pkg=foo state=removed
apt pkg=foo state=installed
apt pkg=foo=1.00 state=installed
apt pkg=nginx state=latest default-release=squeeze-backports update-cache=yes< / pre >
2012-03-27 01:48:32 +02:00
< / div >
2012-04-06 17:41:18 +02:00
< p > NOTE: the apt module cannot currently request installation of a specific software version, as the yum
module can. This should be available in a future release.< / p >
2012-03-27 01:48:32 +02:00
< / div >
2012-04-06 17:41:18 +02:00
< div class = "section" id = "command" >
< span id = "id2" > < / span > < h2 > command< a class = "headerlink" href = "#command" title = "Permalink to this headline" > ¶< / a > < / h2 >
2012-03-10 00:29:01 +01:00
< p > The command module takes the command name followed by a list of
2012-03-15 01:57:35 +01:00
arguments, space delimited.< / p >
< p > If you want to run a command through the shell (say you are using
‘ < ’ , ‘ > ’ , ‘ |’ , etc), you actually want the ‘ shell’ module instead.
The ‘ command’ module is much more secure as it’ s not affected by the user’ s environment.< / p >
< p > The given command will be executed on all selected nodes. It will not
be processed through the shell, so variables like “ $HOME” and
operations like “ < ” , “ > ” , “ |” , and “ & ” will not work. As such, all
paths to commands must be fully qualified.< / p >
2012-03-10 00:29:01 +01:00
< p > This module does not support change hooks and returns the return code
from the program as well as timing information about how long the
command was running for.< / p >
2012-03-27 03:41:50 +02:00
< p > Example action from Ansible < a class = "reference internal" href = "playbooks.html" > < em > Playbooks< / em > < / a > :< / p >
2012-03-22 06:01:02 +01:00
< div class = "highlight-python" > < pre > command /sbin/shutdown -t now< / pre >
< / div >
2012-04-06 17:41:18 +02:00
< p > If you only want to run a command if a certain file does not exist, you can do the
following:< / p >
< div class = "highlight-python" > < pre > command /usr/bin/make_database.sh arg1 arg2 creates=/path/to/database< / pre >
< / div >
< p > The < cite > creates=< / cite > option will not be passed to the executable.< / p >
2012-03-08 19:36:47 +01:00
< / div >
< div class = "section" id = "copy" >
2012-04-06 17:41:18 +02:00
< span id = "id3" > < / span > < h2 > copy< a class = "headerlink" href = "#copy" title = "Permalink to this headline" > ¶< / a > < / h2 >
2012-03-16 03:47:21 +01:00
< p > The copy module moves a file on the local box to remote locations. In addition to the options
listed below, the arguments available to the < cite > file< / cite > module can also be passed to the copy
module.< / p >
2012-03-08 19:36:47 +01:00
< p > < em > src< / em > :< / p >
2012-03-10 00:29:01 +01:00
< ul class = "simple" >
< li > Local path to a file to copy to the remote server. This can be an
absolute or relative path.< / li >
< / ul >
2012-03-08 19:36:47 +01:00
< p > < em > dest< / em > :< / p >
2012-03-10 00:29:01 +01:00
< ul class = "simple" >
< li > Remote absolute path where the file should end up.< / li >
< / ul >
2012-03-08 19:36:47 +01:00
< p > This module also returns md5sum information about the resultant file.< / p >
2012-03-27 03:41:50 +02:00
< p > Example action from Ansible < a class = "reference internal" href = "playbooks.html" > < em > Playbooks< / em > < / a > :< / p >
2012-03-22 06:01:02 +01:00
< div class = "highlight-python" > < pre > copy src=/srv/myfiles/foo.conf dest=/etc/foo.conf owner=foo group=foo mode=0644< / pre >
< / div >
2012-03-08 19:36:47 +01:00
< / div >
< div class = "section" id = "facter" >
2012-04-06 17:41:18 +02:00
< span id = "id4" > < / span > < h2 > facter< a class = "headerlink" href = "#facter" title = "Permalink to this headline" > ¶< / a > < / h2 >
2012-03-08 19:36:47 +01:00
< p > Runs the discovery program ‘ facter’ on the remote system, returning
JSON data that can be useful for inventory purposes.< / p >
< p > Requires that ‘ facter’ and ‘ ruby-json’ be installed on the remote end.< / p >
2012-03-10 00:29:01 +01:00
< p > This module is informative only - it takes no parameters & does not
support change hooks, nor does it make any changes on the system.
Playbooks do not actually use this module, they use the < a class = "reference internal" href = "#setup" > < em > setup< / em > < / a >
module behind the scenes.< / p >
2012-03-08 19:36:47 +01:00
< / div >
2012-04-13 04:47:15 +02:00
< div class = "section" id = "fetch" >
< h2 > fetch< a class = "headerlink" href = "#fetch" title = "Permalink to this headline" > ¶< / a > < / h2 >
< p > This module works like ‘ copy’ , but in reverse. It is used for fetching files
from remote machines and storing them locally in a file tree, organized by hostname.< / p >
< p > < em > src< / em > :< / p >
< ul class = "simple" >
< li > The file on the remote system to fetch. This needs to be a file, not a directory. Recursive fetching may be supported later.< / li >
< / ul >
< p > < em > dest< / em > :< / p >
< ul class = "simple" >
2012-04-19 03:22:02 +02:00
< li > A directory to save the file into. For example, if the ‘ dest’ directory is ‘ /foo’ , a src file named ‘ /tmp/bar’ on host ‘ host.example.com’ , would be saved into ‘ /foo/host.example.com/tmp/bar’ (in Ansible 0.0.3 and later).< / li >
2012-04-13 04:47:15 +02:00
< / ul >
< p > The fetch module is a useful way to gather log files from remote systems. If you require
fetching multiple files from remote systems, you may wish to execute a tar command and
then fetch the tarball.< / p >
2012-04-19 03:22:02 +02:00
< p > Example:< / p >
< div class = "highlight-python" > < pre > fetch src=/var/log/messages dest=/home/logtree< / pre >
< / div >
2012-04-13 04:47:15 +02:00
< / div >
2012-03-16 03:47:21 +01:00
< div class = "section" id = "file" >
2012-04-13 04:47:15 +02:00
< h2 > file< a class = "headerlink" href = "#file" title = "Permalink to this headline" > ¶< / a > < / h2 >
2012-04-05 02:31:04 +02:00
< p > Sets attributes of files, symlinks, and directories, or removes files/symlinks/directories.
All parameters available to the file module are also available when running the < cite > copy< / cite > or
< cite > template< / cite > modules.< / p >
2012-03-16 03:47:21 +01:00
< p > < em > dest< / em > :< / p >
< ul class = "simple" >
< li > absolute path to a file on the filesystem.< / li >
< / ul >
< p > < em > state< / em > :< / p >
< ul class = "simple" >
2012-04-05 02:31:04 +02:00
< li > either ‘ file’ , ‘ link’ , ‘ directory’ , or ‘ absent’ . The default is ‘ file’ . If ‘ directory’ , the directory and all immediate subdirectories will be created if they do not exist. If ‘ file’ , the file will NOT be created if it does not exist, specify < cite > copy< / cite > or < cite > template< / cite > for the module name instead if you need to put content at the specified location. If ‘ link’ , the symbolic link will be created or changed. If ‘ absent’ , directories will be recursively deleted, and files or symlinks will be unlinked.< / li >
2012-03-16 03:47:21 +01:00
< / ul >
< p > < em > mode< / em > :< / p >
< ul class = "simple" >
< li > the mode the file or directory should be, such as 644, as would be given to < cite > chmod< / cite > . English modes like “ g+x” are not yet supported.< / li >
< / ul >
< p > < em > owner< / em > :< / p >
< ul class = "simple" >
< li > name of user that should own the file or directory, as would be given to < cite > chown< / cite > .< / li >
< / ul >
< p > < em > group< / em > :< / p >
< ul class = "simple" >
< li > name of group that should own the file or directory, as would be given to < cite > chgrp< / cite > < / li >
< / ul >
2012-04-05 02:31:04 +02:00
< p > < em > src< / em > :< / p >
< ul class = "simple" >
< li > path of the file to link to (applies only to ‘ link’ state)< / li >
< / ul >
< p > < em > dest< / em > :< / p >
< ul class = "simple" >
< li > location where the symlink will be created for ‘ link’ state, also an alias for ‘ path’ .< / li >
< / ul >
2012-04-18 02:36:22 +02:00
< p > < em > seuser< / em > :< / p >
< ul class = "simple" >
< li > ‘ user’ part of SELinux file context. Will default to what is provided by system policy, if available. Only used on systems with SELinux present.< / li >
< / ul >
< p > < em > serole< / em > :< / p >
< ul class = "simple" >
< li > ‘ role’ part of SELinux file context. Will default to what is provided by system policy, if available. Only used on systems with SELinux present.< / li >
< / ul >
< p > < em > setype< / em > :< / p >
< ul class = "simple" >
< li > ‘ type’ part of SELinux file context. Will default to what is provided by system policy, if available. Only used on systems with SELinux present.< / li >
< / ul >
< p > < em > selevel< / em > :< / p >
< ul class = "simple" >
< li > ‘ level’ part of SELinux file context. This is the MLS and MCS attribute of the file context. It defaults to ‘ s0’ . Only used only used on hosts with SELinux present.< / li >
< / ul >
2012-04-23 02:05:32 +02:00
< p > < em > context< / em > :< / p >
< ul class = "simple" >
< li > accepts only ‘ default’ as value. This will restore a file’ s selinux context to the default context in the policy. Does nothing if no default is available.< / li >
< / ul >
2012-03-27 03:41:50 +02:00
< p > Example action from Ansible < a class = "reference internal" href = "playbooks.html" > < em > Playbooks< / em > < / a > :< / p >
2012-04-05 02:31:04 +02:00
< div class = "highlight-python" > < pre > file path=/etc/foo.conf owner=foo group=foo mode=0644
file path=/some/path owner=foo group=foo state=directory
file path=/path/to/delete state=absent
2012-04-18 02:36:22 +02:00
file src=/file/to/link/to dest=/path/to/symlink owner=foo group=foo state=link
2012-04-23 02:05:32 +02:00
file path=/some/path state=directory setype=httpd_sys_content_t
file path=/some/path state=directory context=default< / pre >
2012-03-22 06:01:02 +01:00
< / div >
2012-03-16 03:47:21 +01:00
< / div >
2012-03-08 19:36:47 +01:00
< div class = "section" id = "git" >
2012-04-13 04:47:15 +02:00
< span id = "id5" > < / span > < h2 > git< a class = "headerlink" href = "#git" title = "Permalink to this headline" > ¶< / a > < / h2 >
2012-03-09 04:50:12 +01:00
< p > Deploys software (or files) from git checkouts.< / p >
2012-03-08 19:36:47 +01:00
< p > < em > repo< / em > :< / p >
2012-03-10 00:29:01 +01:00
< ul class = "simple" >
< li > git or http protocol address of the repo to checkout.< / li >
< / ul >
2012-03-08 19:36:47 +01:00
< p > < em > dest< / em > :< / p >
2012-03-10 00:29:01 +01:00
< ul class = "simple" >
< li > Where to check it out, an absolute directory path.< / li >
< / ul >
2012-03-08 19:36:47 +01:00
< p > < em > version< / em > :< / p >
2012-03-10 00:29:01 +01:00
< ul class = "simple" >
< li > What version to check out – either the git SHA, the literal string
< tt class = "docutils literal" > < span class = "pre" > HEAD< / span > < / tt > , or a tag name.< / li >
< / ul >
2012-03-27 03:41:50 +02:00
< p > Example action from Ansible < a class = "reference internal" href = "playbooks.html" > < em > Playbooks< / em > < / a > :< / p >
2012-03-22 06:01:02 +01:00
< div class = "highlight-python" > < pre > git repo=git://foosball.example.org/path/to/repo.git dest=/srv/checkout version=release-0.22< / pre >
< / div >
2012-03-08 19:36:47 +01:00
< / div >
2012-03-31 18:08:28 +02:00
< div class = "section" id = "group" >
2012-04-13 04:47:15 +02:00
< span id = "id6" > < / span > < h2 > group< a class = "headerlink" href = "#group" title = "Permalink to this headline" > ¶< / a > < / h2 >
2012-03-31 18:08:28 +02:00
< p > Adds or removes groups.< / p >
< p > < em > name< / em > :< / p >
< ul class = "simple" >
< li > name of the group< / li >
< / ul >
< p > < em > gid< / em > :< / p >
< ul class = "simple" >
< li > optional gid to set for the group< / li >
< / ul >
< p > < em > state< / em > :< / p >
< ul class = "simple" >
< li > either ‘ absent’ , or ‘ present’ . ‘ present’ is the default.< / li >
< / ul >
< p > To control members of the group, see the users resource.< / p >
< p > Example action from Ansible < a class = "reference internal" href = "playbooks.html" > < em > Playbooks< / em > < / a > :< / p >
< div class = "highlight-python" > < pre > group name=somegroup state=present< / pre >
< / div >
< / div >
2012-03-08 19:36:47 +01:00
< div class = "section" id = "ohai" >
2012-04-13 04:47:15 +02:00
< span id = "id7" > < / span > < h2 > ohai< a class = "headerlink" href = "#ohai" title = "Permalink to this headline" > ¶< / a > < / h2 >
2012-03-10 00:29:01 +01:00
< p > Similar to the < a class = "reference internal" href = "#facter" > < em > facter< / em > < / a > module, this returns JSON inventory data.
Ohai data is a bit more verbose and nested than facter.< / p >
2012-03-08 19:36:47 +01:00
< p > Requires that ‘ ohai’ be installed on the remote end.< / p >
< p > This module is information only - it takes no parameters & does not
support change hooks, nor does it make any changes on the system.< / p >
2012-03-10 00:29:01 +01:00
< p > Playbooks should not call the ohai module, playbooks call the
< a class = "reference internal" href = "#setup" > < em > setup< / em > < / a > module behind the scenes instead.< / p >
2012-03-08 19:36:47 +01:00
< / div >
< div class = "section" id = "ping" >
2012-04-13 04:47:15 +02:00
< span id = "id8" > < / span > < h2 > ping< a class = "headerlink" href = "#ping" title = "Permalink to this headline" > ¶< / a > < / h2 >
2012-03-10 00:29:01 +01:00
< p > A trivial test module, this module always returns the integer < tt class = "docutils literal" > < span class = "pre" > 1< / span > < / tt > on
2012-03-08 19:36:47 +01:00
successful contact.< / p >
2012-03-10 00:29:01 +01:00
< p > This module does not support change hooks and is informative only - it
takes no parameters & does not support change hooks, nor does it make
any changes on the system.< / p >
2012-03-08 19:36:47 +01:00
< / div >
< div class = "section" id = "service" >
2012-04-13 04:47:15 +02:00
< span id = "id9" > < / span > < h2 > service< a class = "headerlink" href = "#service" title = "Permalink to this headline" > ¶< / a > < / h2 >
2012-03-08 19:36:47 +01:00
< p > Controls services on remote machines.< / p >
2012-03-10 00:29:01 +01:00
< p > < em > state< / em > :< / p >
< ul class = "simple" >
< li > Values are < tt class = "docutils literal" > < span class = "pre" > started< / span > < / tt > , < tt class = "docutils literal" > < span class = "pre" > stopped< / span > < / tt > , or < tt class = "docutils literal" > < span class = "pre" > restarted< / span > < / tt > .
Started/stopped are idempotent actions that will not run commands
unless necessary. < tt class = "docutils literal" > < span class = "pre" > restarted< / span > < / tt > will always bounce the service.< / li >
< / ul >
< p > < em > name< / em > :< / p >
< ul class = "simple" >
< li > The name of the service.< / li >
< / ul >
2012-03-27 03:41:50 +02:00
< p > Example action from Ansible < a class = "reference internal" href = "playbooks.html" > < em > Playbooks< / em > < / a > :< / p >
2012-03-22 06:01:02 +01:00
< div class = "highlight-python" > < pre > service name=httpd state=started
service name=httpd state=stopped
service name=httpd state=restarted< / pre >
< / div >
2012-03-08 19:36:47 +01:00
< / div >
< div class = "section" id = "setup" >
2012-04-13 04:47:15 +02:00
< span id = "id10" > < / span > < h2 > setup< a class = "headerlink" href = "#setup" title = "Permalink to this headline" > ¶< / a > < / h2 >
2012-03-08 19:36:47 +01:00
< p > Writes a JSON file containing key/value data, for use in templating.
2012-03-10 00:29:01 +01:00
Call this once before using the < a class = "reference internal" href = "#template" > < em > template< / em > < / a > module. Playbooks
will execute this module automatically as the first step in each play
using the variables section, so it is unnecessary to make explicit
calls to setup within a playbook.< / p >
2012-04-26 04:40:11 +02:00
< p > Ansible provides may ‘ facts’ about the system, automatically.< / p >
< p > Some of the variables that are supplied are listed below. These in particular
are from a VMWare Fusion 4 VM running CentOS 6.2:< / p >
< div class = "highlight-python" > < pre > "ansible_architecture": "x86_64",
"ansible_distribution": "CentOS",
"ansible_distribution_release": "Final",
"ansible_distribution_version": "6.2",
"ansible_eth0": {
"ipv4": {
"address": "REDACTED",
"netmask": "255.255.255.0"
},
"ipv6": [
{
"address": "REDACTED",
"prefix": "64",
"scope": "link"
}
],
"macaddress": "REDACTED"
},
"ansible_form_factor": "Other",
"ansible_fqdn": "localhost.localdomain",
"ansible_hostname": "localhost",
"ansible_interfaces": [
"lo",
"eth0"
],
"ansible_kernel": "2.6.32-220.2.1.el6.x86_64",
"ansible_lo": {
"ipv4": {
"address": "127.0.0.1",
"netmask": "255.0.0.0"
},
"ipv6": [
{
"address": "::1",
"prefix": "128",
"scope": "host"
}
],
"ansible_machine": "x86_64",
"ansible_memfree_mb": 89,
"ansible_memtotal_mb": 993,
"ansible_processor": [
"Intel(R) Core(TM) i7-2677M CPU @ 1.80GHz"
],
"ansible_processor_cores": "NA",
"ansible_processor_count": 1,
"ansible_product_name": "VMware Virtual Platform",
"ansible_product_serial": "REDACTED",
"ansible_product_uuid": "REDACTED",
"ansible_product_version": "None",
"ansible_python_version": "2.6.6",
"ansible_product_version": "None",
"ansible_python_version": "2.6.6",
"ansible_ssh_host_key_dsa_public": REDACTED",
"ansible_ssh_host_key_rsa_public": "REDACTED",
"ansible_swapfree_mb": 1822,
"ansible_swaptotal_mb": 2015,
"ansible_system": "Linux",
"ansible_system_vendor": "VMware, Inc.",
"ansible_virtualization_role": "None",
"ansible_virtualization_type": "None",< / pre >
< / div >
< p > More ansible facts will be added with successive releases.< / p >
2012-03-10 00:29:01 +01:00
< p > If facter or ohai are installed, variables from these programs will
also be snapshotted into the JSON file for usage in templating. These
variables are prefixed with < tt class = "docutils literal" > < span class = "pre" > facter_< / span > < / tt > and < tt class = "docutils literal" > < span class = "pre" > ohai_< / span > < / tt > so it’ s easy to
2012-04-26 04:40:11 +02:00
tell their source.< / p >
< p > All variables are bubbled up to the caller. Using the ansible facts and chosing
2012-04-19 05:02:28 +02:00
to not install facter and ohai means you can avoid ruby-dependencies
on your remote systems.< / p >
2012-03-10 00:29:01 +01:00
< p > < em > anything< / em > :< / p >
< blockquote >
< div > < ul class = "simple" >
2012-04-26 04:40:11 +02:00
< li > Any other parameters can be named basically anything, and set a < tt class = "docutils literal" > < span class = "pre" > key=value< / span > < / tt > pair in the JSON file for use in templating.< / li >
2012-03-10 00:29:01 +01:00
< / ul >
< / div > < / blockquote >
2012-03-27 03:41:50 +02:00
< p > Example action from Ansible < a class = "reference internal" href = "playbooks.html" > < em > Playbooks< / em > < / a > :< / p >
2012-03-22 06:01:02 +01:00
< div class = "highlight-python" > < pre > vars:
ntpserver: 'ntp.example.com'
xyz: 1234< / pre >
< / div >
2012-04-13 04:47:15 +02:00
< p > Example action from < cite > /usr/bin/ansible< / cite > :< / p >
< div class = "highlight-python" > < pre > ansible all -m setup -a "ntpserver=ntp.example.com xyz=1234"< / pre >
2012-03-22 06:01:02 +01:00
< / div >
2012-03-08 19:36:47 +01:00
< / div >
2012-03-15 01:57:35 +01:00
< div class = "section" id = "shell" >
2012-04-13 04:47:15 +02:00
< span id = "id11" > < / span > < h2 > shell< a class = "headerlink" href = "#shell" title = "Permalink to this headline" > ¶< / a > < / h2 >
2012-03-15 01:57:35 +01:00
< p > The shell module takes the command name followed by a list of
arguments, space delimited. It is almost exactly like the command module
but runs the command through the shell rather than directly.< / p >
< p > The given command will be executed on all selected nodes.< / p >
< p > If you want to execute a command securely and predicably, it may
be better to use the ‘ command’ module instead. Best practices
when writing playbooks will follow the trend of using ‘ command’
unless ‘ shell’ is explicitly required. When running ad-hoc commands,
use your best judgement.< / p >
< p > This module does not support change hooks and returns the return code
from the program as well as timing information about how long the
command was running for.< / p >
2012-03-22 06:01:02 +01:00
< p > Example action from a playbook:< / p >
< div class = "highlight-python" > < pre > shell somescript.sh > > somelog.txt< / pre >
< / div >
2012-03-15 01:57:35 +01:00
< / div >
2012-03-08 19:36:47 +01:00
< div class = "section" id = "template" >
2012-04-13 04:47:15 +02:00
< span id = "id12" > < / span > < h2 > template< a class = "headerlink" href = "#template" title = "Permalink to this headline" > ¶< / a > < / h2 >
2012-03-10 00:29:01 +01:00
< p > Templates a file out to a remote server. Call the < a class = "reference internal" href = "#setup" > < em > setup< / em > < / a > module
2012-03-16 03:47:21 +01:00
prior to usage if you are not running from a playbook. In addition to the options
listed below, the arguments available to the < cite > file< / cite > module can also be passed to the copy
module.< / p >
2012-03-10 00:29:01 +01:00
< p > < em > src< / em > :< / p >
< ul class = "simple" >
< li > Path of a Jinja2 formatted template on the local server. This can
be a relative or absolute path.< / li >
< / ul >
< p > < em > dest< / em > :< / p >
< ul class = "simple" >
< li > Location to render the template on the remote server.< / li >
< / ul >
2012-03-08 19:36:47 +01:00
< p > This module also returns md5sum information about the resultant file.< / p >
2012-03-22 06:01:02 +01:00
< p > Example action from a playbook:< / p >
< div class = "highlight-python" > < pre > template src=/srv/mytemplates/foo.j2 dest=/etc/foo.conf owner=foo group=foo mode=0644< / pre >
< / div >
< / div >
< div class = "section" id = "user" >
2012-04-13 04:47:15 +02:00
< span id = "id13" > < / span > < h2 > user< a class = "headerlink" href = "#user" title = "Permalink to this headline" > ¶< / a > < / h2 >
2012-03-22 06:01:02 +01:00
< p > Creates user accounts, manipulates existing user accounts, and removes user accounts.< / p >
< p > < em > name< / em > :< / p >
< ul class = "simple" >
< li > Name of the user to create, remove, or edit< / li >
< / ul >
< p > < em > comment< / em > :< / p >
< ul class = "simple" >
< li > Optionally sets the description of the user< / li >
< / ul >
2012-03-27 05:38:52 +02:00
< p > < em > group< / em > :< / p >
2012-03-22 06:01:02 +01:00
< ul class = "simple" >
2012-03-27 05:38:52 +02:00
< li > Optionally sets the user’ s primary group, takes a group name.< / li >
2012-03-22 06:01:02 +01:00
< / ul >
2012-03-31 18:08:28 +02:00
< p > < em > groups< / em > :< / p >
< ul class = "simple" >
< li > Put the user in the specified groups, takes comma delimited group names.< / li >
< / ul >
< p > < em > append< / em > :< / p >
< ul class = "simple" >
< li > If true, will only add additional groups to the user listed in ‘ groups’ , rather than making the user only be in those specified groups.< / li >
< / ul >
2012-03-22 06:01:02 +01:00
< p > < em > shell< / em > :< / p >
< ul class = "simple" >
< li > Optionally sets the user’ s shell.< / li >
< / ul >
< p > < em > createhome< / em > :< / p >
< ul class = "simple" >
< li > Whether to create the user’ s home directory. Takes ‘ yes’ , or ‘ no’ . The default is ‘ yes’ .< / li >
< / ul >
< p > < em > password< / em > :< / p >
< ul class = "simple" >
2012-03-31 18:08:28 +02:00
< li > Sets the user’ s password to this crypted value. Pass in a result from crypt. See the users example in the github examples directory for what this looks like in a playbook.< / li >
2012-03-22 06:01:02 +01:00
< / ul >
< p > < em > state< / em > :< / p >
< ul class = "simple" >
2012-03-31 18:08:28 +02:00
< li > Defaults to ‘ present’ . When ‘ absent’ , the user account will be removed if present. Optionally additional removal behaviors can be set with the ‘ force’ or ‘ remove’ parameter values (see below).< / li >
< / ul >
< p > < em > force< / em > :< / p >
< ul class = "simple" >
< li > When used with a state of ‘ absent’ , the behavior denoted in the ‘ userdel’ manpage for – force is also used when removing the user. Value is ‘ yes’ or ‘ no’ , default is ‘ no’ .< / li >
< / ul >
< p > < em > remove< / em > :< / p >
< ul class = "simple" >
< li > When used with a state of ‘ absent’ , the behavior denoted in the ‘ userdel’ manpage for – remove is also used when removing the user. Value is ‘ yes’ or ‘ no’ , default is ‘ no’ .< / li >
2012-03-22 06:01:02 +01:00
< / ul >
2012-03-27 03:41:50 +02:00
< p > Example action from Ansible < a class = "reference internal" href = "playbooks.html" > < em > Playbooks< / em > < / a > :< / p >
2012-03-22 06:01:02 +01:00
< div class = "highlight-python" > < pre > user name=mdehaan comment=awesome passwd=awWxVV.JvmdHw createhome=yes
2012-03-31 18:08:28 +02:00
user name=mdehaan groups=wheel,skynet
user name=mdehaan state=absent force=yes< / pre >
2012-03-22 06:01:02 +01:00
< / div >
2012-03-08 19:36:47 +01:00
< / div >
2012-04-06 17:41:18 +02:00
< div class = "section" id = "virt" >
2012-04-13 04:47:15 +02:00
< span id = "id14" > < / span > < h2 > virt< a class = "headerlink" href = "#virt" title = "Permalink to this headline" > ¶< / a > < / h2 >
2012-04-06 17:41:18 +02:00
< p > Manages virtual machines supported by libvirt. Requires that libvirt be installed
on the managed machine.< / p >
< p > < em > guest< / em > :< / p >
< ul class = "simple" >
< li > The name of the guest VM being managed< / li >
< / ul >
< p > < em > state< / em > < / p >
< ul class = "simple" >
< li > Desired state of the VM. Either < cite > running< / cite > , < cite > shutdown< / cite > , < cite > destroyed< / cite > , or < cite > undefined< / cite > . Note that there may be some lag for state requests like ‘ shutdown’ , and these states only refer to the virtual machine states. After starting a guest, the guest OS may not be immediately accessible.< / li >
< / ul >
< p > < em > command< / em > :< / p >
< ul class = "simple" >
< li > In addition to state management, various non-idempotent commands are available for API and script usage (but don’ t make much sense in a playbook). These mostly return information, though some also affect state. See examples below.< / li >
< / ul >
< p > Example action from Ansible < a class = "reference internal" href = "playbooks.html" > < em > Playbooks< / em > < / a > :< / p >
< div class = "highlight-python" > < pre > virt guest=alpha state=running
virt guest=alpha state=shutdown
virt guest=alpha state=destroyed
virt guest=alpha state=undefined< / pre >
< / div >
< p > Example guest management commands from /usr/bin/ansible:< / p >
< div class = "highlight-python" > < pre > ansible host -m virt -a "guest=foo command=status"
ansible host -m virt -a "guest=foo command=pause"
ansible host -m virt -a "guest=foo command=unpause"
ansible host -m virt -a "guest=foo command=get_xml"
ansible host -m virt -a "guest=foo command=autostart"< / pre >
< / div >
< p > Example host (hypervisor) management commands from /usr/bin/ansible:< / p >
2012-04-13 04:47:15 +02:00
< div class = "highlight-python" > < pre > ansible host -m virt -a "command=freemem"
ansible host -m virt -a "command=list_vms"
ansible host -m virt -a "command=info"
ansible host -m virt -a "command=nodeinfo"
ansible host -m virt -a "command=virttype"< / pre >
2012-04-06 17:41:18 +02:00
< / div >
< / div >
2012-03-10 01:04:40 +01:00
< div class = "section" id = "yum" >
2012-04-13 04:47:15 +02:00
< span id = "id15" > < / span > < h2 > yum< a class = "headerlink" href = "#yum" title = "Permalink to this headline" > ¶< / a > < / h2 >
2012-03-10 01:04:40 +01:00
< p > Will install, upgrade, remove, and list packages with the yum package manager.< / p >
< p > < em > pkg< / em > :< / p >
< ul class = "simple" >
< li > A package name or package specifier with version, like name-1.0< / li >
< / ul >
< p > < em > state< / em > :< / p >
< ul class = "simple" >
2012-04-13 04:47:15 +02:00
< li > Can be either ‘ installed’ , ‘ latest’ , or ‘ removed’ . The default is ‘ installed’ .< / li >
2012-03-10 01:04:40 +01:00
< / ul >
< p > < em > list< / em > :< / p >
< ul class = "simple" >
< li > When ‘ list’ is supplied instead of ‘ state’ , the yum module can list
various configuration attributes. Values include ‘ installed’ , ‘ updates’ ,
‘ available’ , ‘ repos’ , or any package specifier.< / li >
< / ul >
2012-03-27 03:41:50 +02:00
< p > Example action from Ansible < a class = "reference internal" href = "playbooks.html" > < em > Playbooks< / em > < / a > :< / p >
2012-04-21 18:12:46 +02:00
< div class = "highlight-python" > < pre > yum pkg=httpd state=latest
yum pkg=httpd state=removed
yum pkg=httpd state=installed< / pre >
2012-03-22 06:01:02 +01:00
< / div >
2012-03-10 01:04:40 +01:00
< / div >
2012-03-08 19:36:47 +01:00
< div class = "section" id = "writing-your-own-modules" >
2012-03-09 04:50:12 +01:00
< h2 > Writing your own modules< a class = "headerlink" href = "#writing-your-own-modules" title = "Permalink to this headline" > ¶< / a > < / h2 >
2012-03-31 16:21:28 +02:00
< p > See < a class = "reference internal" href = "moduledev.html" > < em > Module Development Guide< / em > < / a > .< / p >
2012-03-31 15:29:31 +02:00
< div class = "admonition-see-also admonition seealso" >
< p class = "first admonition-title" > See also< / p >
< dl class = "last docutils" >
< dt > < a class = "reference internal" href = "examples.html" > < em > Command Line Examples< / em > < / a > < / dt >
2012-04-13 04:47:15 +02:00
< dd > Examples of using modules in /usr/bin/ansible< / dd >
2012-03-31 15:29:31 +02:00
< dt > < a class = "reference internal" href = "playbooks.html" > < em > Playbooks< / em > < / a > < / dt >
2012-04-13 04:47:15 +02:00
< dd > Examples of using modules with /usr/bin/ansible-playbook< / dd >
2012-03-31 16:21:28 +02:00
< dt > < a class = "reference internal" href = "moduledev.html" > < em > Module Development Guide< / em > < / a > < / dt >
< dd > How to write your own modules< / dd >
2012-03-31 15:29:31 +02:00
< dt > < a class = "reference internal" href = "api.html" > < em > API & Integrations< / em > < / a > < / dt >
< dd > Examples of using modules with the Python API< / dd >
2012-04-13 04:47:15 +02:00
< dt > < a class = "reference external" href = "http://groups.google.com/group/ansible-project" > Mailing List< / a > < / dt >
2012-03-31 15:55:37 +02:00
< dd > Questions? Help? Ideas? Stop by the list on Google Groups< / dd >
< dt > < a class = "reference external" href = "http://irc.freenode.net" > irc.freenode.net< / a > < / dt >
< dd > #ansible IRC chat channel< / dd >
2012-03-31 15:29:31 +02:00
< / dl >
< / div >
2012-03-08 19:36:47 +01:00
< / div >
2012-03-07 17:35:18 +01:00
< / div >
2012-04-28 16:42:32 +02:00
< br / >
< a href = "https://twitter.com/share" class = "twitter-share-button" data-lang = "en" > Tweet< / a >
2012-03-07 17:35:18 +01:00
< / div >
2012-04-28 16:50:20 +02:00
< p >
2012-04-28 16:42:32 +02:00
< a href = "https://twitter.com/share" class = "twitter-share-button" data-text = "ansible.github.com" > Share On Twitter< / a >
< script > ! function ( d , s , id ) { var js , fjs = d . getElementsByTagName ( s ) [ 0 ] ; if ( ! d . getElementById ( id ) ) { js = d . createElement ( s ) ; js . id = id ; js . src = "//platform.twitter.com/widgets.js" ; fjs . parentNode . insertBefore ( js , fjs ) ; } } ( document , "script" , "twitter-wjs" ) ; < / script >
< g:plusone annotation = "inline" > < / g:plusone >
< div class = "fb-like" data-href = "http://ansible.github.com" data-send = "true" data-width = "450" data-show-faces = "false" > < / div >
2012-04-28 16:50:20 +02:00
< / p >
< footer class = "footer" >
< div id = "fb-root" > < / div >
< div class = "container" >
< p >
2012-03-09 17:44:14 +01:00
© Copyright 2012 Michael DeHaan.< br / >
2012-04-28 16:42:32 +02:00
Last updated on Apr 28, 2012.< br / >
2012-03-09 17:44:14 +01:00
< / p >
< / div >
< / footer >
2012-03-07 17:35:18 +01:00
< / body >
< / html >