-p has been replaced by a required option. Various docs changes.

This commit is contained in:
Michael DeHaan 2012-03-01 22:10:47 -05:00
parent 4ce1f1dd5e
commit 847846af0e
7 changed files with 89 additions and 77 deletions

View file

@ -66,22 +66,22 @@ Example:
192.168.10.52
When running ansible commands, specific hosts are addressed by wildcard or group name.
The default pattern is '*', meaning all ansible hosts.
This is required for all ansible commands.
-p '*.example.com'
-p 'atlanta;raleigh'
-p 'database*;appserver*'
-p '192.168.10.50;192.168.10.52'
'*.example.com'
'atlanta;raleigh'
'database*;appserver*'
'192.168.10.50;192.168.10.52'
Example: Massive Parallelism and Running Shell Commands
=======================================================
Reboot all web servers in Atlanta, 10 at a time:
ssh-agent bash
ssh-add ~/.ssh/id_rsa.pub
> ssh-agent bash
> ssh-add ~/.ssh/id_rsa.pub
ansible -p "atlanta-web*" -f 10 -n command -a "/sbin/reboot"
> ansible atlanta -a "/sbin/reboot" -f 10
The -f 10 specifies the usage of 10 simultaneous processes.
@ -98,15 +98,15 @@ them as template sources.
To just transfer a file directly to many different servers:
ansible -n copy -a "/etc/hosts /tmp/hosts"
> ansible atlanta copy -a "/etc/hosts /tmp/hosts"
To use templating, first run the setup module to put the template variables you would
like to use on the remote host. Then use the template module to write the
files using the templates. Templates are written in Jinja2 format.
ansible -p webservers -n setup -a "favcolor=red ntp_server=192.168.1.1"
ansible -p webservers -n template -a "src=/srv/motd.j2 dest=/etc/motd"
ansible -p webservers -n template -a "src=/srv/ntp.j2 dest=/etc/ntp.conf"
> ansible webservers -m setup -a "favcolor=red ntp_server=192.168.1.1"
> ansible webservers -m template -a "src=/srv/motd.j2 dest=/etc/motd"
> ansible webservers -m template -a "src=/srv/ntp.j2 dest=/etc/ntp.conf"
Need something like the fqdn in a template? If facter or ohai are installed, data from these projects
will also be made available to the template engine, using 'facter_' and 'ohai_' prefixes for each.
@ -116,7 +116,7 @@ Example: Software Deployment From Source Control
Deploy your webapp straight from git
ansible -p webservers -n git -a "repo=git://foo dest=/srv/myapp version=HEAD"
> ansible webservers -m git -a "repo=git://foo dest=/srv/myapp version=HEAD"
Other Modules
=============

View file

@ -38,37 +38,33 @@ class Cli(object):
pass
def runner(self):
parser = OptionParser()
parser = OptionParser(usage = 'ansible <host-pattern> [options]')
parser.add_option("-a", "--args", dest="module_args",
help="module arguments", default=C.DEFAULT_MODULE_ARGS)
parser.add_option('-f','--forks', dest='forks', default=C.DEFAULT_FORKS, type='int',
help='set the number of forks to start up')
parser.add_option("-p", "--host-pattern", dest="hosts",
help="hostname glob or group name", default=C.DEFAULT_PATTERN)
parser.add_option("-i", "--inventory", dest="inventory",
help="inventory host list", default=C.DEFAULT_HOST_LIST)
help='number of parallel processes to use')
parser.add_option("-i", "--inventory-file", dest="inventory",
help="inventory host file", default=C.DEFAULT_HOST_LIST)
parser.add_option("-k", "--ask-pass", default=False, action="store_true",
help="ask the user to input the ssh password for connecting")
parser.add_option("-m", "--module-path", dest="module_path",
help="ask for SSH password")
parser.add_option("-M", "--module-path", dest="module_path",
help="path to module library", default=C.DEFAULT_MODULE_PATH)
parser.add_option("-n", "--name", dest="module_name",
help="module name to execute", default=None)
parser.add_option("-m", "--module-name", dest="module_name",
help="module name to execute", default=C.DEFAULT_MODULE_NAME)
parser.add_option('-o', '--one-line', dest='one_line', action='store_true',
help="try to print output on one line")
help="condense output")
parser.add_option('-t', '--tree', dest='tree', default=None,
help="if specified, a directory name to save output to, one file per host")
help="log output to this directory")
parser.add_option('-T', '--timeout', default=C.DEFAULT_TIMEOUT, type='int',
dest='timeout', help="set the timeout in seconds for ssh")
dest='timeout', help="set the SSH timeout in seconds")
parser.add_option('-u', '--user', default=C.DEFAULT_REMOTE_USER,
dest='remote_user', help='set the default username')
dest='remote_user', help='connect as this user')
options, args = parser.parse_args()
if options.module_name is None:
print >> sys.stderr, "-n is required"
if len(args) == 0 or len(args) > 1:
parser.print_help()
sys.exit(1)
# TODO: more shell like splitting on module_args would
# be a good idea
pattern = args[0]
sshpass = None
if options.ask_pass:
@ -85,7 +81,7 @@ class Cli(object):
host_list=options.inventory,
timeout=options.timeout,
forks=options.forks,
pattern=options.hosts,
pattern=pattern,
verbose=True,
)
return runner
@ -95,6 +91,10 @@ class Cli(object):
# if specifying output destination (aka tree output saves), create the
# directory to output to
if results is None:
print >> sys.stderr, "No hosts matched"
sys.exit(1)
options = self.options
# TODO: split into function
@ -117,64 +117,64 @@ class Cli(object):
for hostname in sorted(results['contacted']):
result = results['contacted'][hostname]
# TODO: refactor
rc = 0
msg = ''
failed = False
stdout = None
stderr = None
traceback = None
error = None
if type(result) == dict:
failed = result.get('failed', 0)
msg = result.get('msg', '')
if module_name == 'command':
# TODO: refactor
rc = result.get('rc',0)
stdout = result.get('stdout', '')
stderr = result.get('stderr', '')
traceback = result.get('traceback', '')
error = result.get('error', '')
# detect and show failures, if any
if rc != 0 or failed:
msg = "Error: %s: \n" % hostname
if stdout:
msg += stdout
if stderr:
msg += stderr
if traceback:
msg += traceback
if error:
msg += error
print >> sys.stderr, msg
continue
if options.one_line:
# try to print everything on one line, but don't strip newlines
# if the command output happend to be too long
if module_name == 'command':
msg = "(stdout) %s" % stdout
if stderr.rstrip() != '':
msg = "(stdout) %s (stderr) %s" % (stdout,stderr)
print "%s | rc=%s | %s" % (
hostname, rc, msg
)
if not failed:
buf = "(stdout) %s" % stdout
if stderr.rstrip() != '':
buf = "(stdout) %s (stderr) %s" % (stdout,stderr)
print "%s | rc=%s | %s" % (
hostname, rc, buf
)
else:
print "%s | (error) %s" % (hostname, msg)
else:
print "%s | %s" % (hostname, result)
else:
# summarize response from command in multiple lines
buf = ''
if module_name == 'command':
buf = ''
buf += "%s | rc=%s >>\n" % (hostname, rc)
if not failed:
buf += "%s | rc=%s >>\n" % (hostname, rc)
else:
buf += "%s | rc=%s | FAILED >>\n" % (hostname, rc)
buf += stdout
if stderr:
buf += stderr
if msg:
buf += msg
print buf
if options.tree:
path = os.path.join(options.tree, hostname)
fd = open(path, "w+")
fd.write(buf)
fd.close()
else:
print "%s >>" % hostname
print json.dumps(result, indent=4, sort_keys=True)
if not failed:
buf += "%s >>" % hostname
else:
buf += "%s | FAILED >>" % hostname
buf += json.dumps(result, indent=4, sort_keys=True)
if options.tree:
path = os.path.join(options.tree, hostname)
fd = open(path, "w+")
fd.write(buf)
fd.close()
if len(results['dark'].keys()) > 0:
print >> sys.stderr, "*** Hosts which could not be contacted or did not respond: ***"

View file

@ -12,7 +12,7 @@ ansible - run a command somewhere else
SYNOPSIS
--------
ansible [-f forks] [-p pattern ] [-n module_name] [-a args]
ansible <host-pattern> [-f forks] [-m module_name] [-a args]
DESCRIPTION
@ -22,6 +22,15 @@ DESCRIPTION
SSH.
ARGUMENTS
---------
*hostspec*
A name of a group in the inventory file, a shell-like glob selecting hosts in inventory
file, or any combination of the two seperated by semicolons.
OPTIONS
-------
@ -36,16 +45,11 @@ Path to the inventory hosts file, which defaults to /etc/ansible/hosts.
Level of parallelism. Specify as an integer, the default is 5.
*-n*, *--name*::
*-m*, *--module-name*::
Module name to execute.
*-a*, *--args*::
Arguments to module, as a single string.
*-p*, *--pattern*::
Hostname pattern. Accepts shell-like globs which can be seperated with ";"
@ -89,8 +93,9 @@ Ansible is released under the terms of the GPLv3 License.
SEE ALSO
--------
Ansible home page: <https://github.com/mpdehaan/ansible/>
*ansible-modules*(5),
*ansible-playbook*(5),
Ansible home page: <https://github.com/mpdehaan/ansible/>

View file

@ -19,8 +19,8 @@
# control side (aka 'overlord')
DEFAULT_HOST_LIST = '/etc/ansible/hosts'
DEFAULT_MODULE_PATH = '/usr/share/ansible'
DEFAULT_MODULE_NAME = 'ping'
DEFAULT_PATTERN = '*'
DEFAULT_MODULE_NAME = 'command'
DEFAULT_PATTERN = None
DEFAULT_FORKS = 3
DEFAULT_MODULE_ARGS = ''
DEFAULT_TIMEOUT = 10

View file

@ -152,6 +152,11 @@ class PlayBook(object):
)
results = runner.run()
# if no hosts are matched, carry on, unlike /bin/ansible
# which would warn you about this
if results is None:
results = {}
# walk through the results and build up
# summary information about successes and
# failures. TODO: split into subfunction

View file

@ -326,6 +326,8 @@ class Runner(object):
# find hosts that match the pattern
hosts = self.match_hosts(self.pattern)
if len(hosts) == 0:
return None
# attack pool of hosts in N forks
# _executor_hook does all of the work

View file

@ -45,13 +45,13 @@ try:
except (OSError, IOError), e:
print json.dumps({
"failed": 1,
"error": str(e),
"msg": str(e),
})
sys.exit(1)
except:
print json.dumps({
"failed" : 1,
"traceback" : traceback.format_exc()
"msg" : traceback.format_exc()
})
sys.exit(1)