Merge branch 'devel' into unevaluated-vars
This commit is contained in:
commit
8d919d6c97
23 changed files with 664 additions and 51 deletions
40
CHANGELOG.md
40
CHANGELOG.md
|
@ -26,22 +26,20 @@ Core Features:
|
||||||
|
|
||||||
Modules added:
|
Modules added:
|
||||||
|
|
||||||
* rax: module for creating instances in the rackspace cloud (uses pyrax)
|
* cloud: rax: module for creating instances in the rackspace cloud (uses pyrax)
|
||||||
* npm: node.js package management
|
* packages: npm: node.js package management
|
||||||
* postgresql_priv: manages postgresql priveledges
|
* packages: pkgng: next-gen package manager for FreeBSD
|
||||||
* set_fact: sets a variable, which can be the result of a template evaluation
|
* database: postgresql_priv: manages postgresql priveledges
|
||||||
* hipchat: send notification events to hipchat
|
* networking: bigip_pool: load balancing with F5s
|
||||||
* ec2_elb: add and remove machines from ec2 elastic load balancers
|
* networking: ec2_elb: add and remove machines from ec2 elastic load balancers
|
||||||
* flowdock: send messages to flowdock during playbook runs
|
* notification: hipchat: send notification events to hipchat
|
||||||
* pkgng: next-gen package manager for FreeBSD
|
* notification: flowdock: send messages to flowdock during playbook runs
|
||||||
* bigip_pool: load balancing with F5s
|
* notification: campfire: send messages to campfire during playbook runs
|
||||||
* newrelic_deployment: notifies newrelic of new deployments
|
* notification: mqtt: send messages to the Mosquitto message bus
|
||||||
* campfire: send messages to campfire during playbook runs
|
* notification: irc: send messages to IRC channels
|
||||||
* mqtt: send messages to the Mosquitto message bus
|
* notification: filesystem - a wrapper around mkfs
|
||||||
* irc: send messages to IRC channels
|
* notification: jabber: send jabber chat messages
|
||||||
* filesystem - a wrapper around mkfs
|
* notification: osx_say: make OS X say things out loud
|
||||||
* jabber: send jabber chat messages
|
|
||||||
* osx_say: make OS X say things out loud
|
|
||||||
* openstack: keystone_user
|
* openstack: keystone_user
|
||||||
* openstack: glance_image
|
* openstack: glance_image
|
||||||
* openstack: nova_compute
|
* openstack: nova_compute
|
||||||
|
@ -53,7 +51,12 @@ Modules added:
|
||||||
* openstack: quantum_router_gateway
|
* openstack: quantum_router_gateway
|
||||||
* openstack: quantum_router_interface
|
* openstack: quantum_router_interface
|
||||||
* openstack: quantum_subnet
|
* openstack: quantum_subnet
|
||||||
* airbrake_deployment - notify airbrake of new deployments
|
* monitoring: newrelic_deployment: notifies newrelic of new deployments
|
||||||
|
* monitoring: airbrake_deployment - notify airbrake of new deployments
|
||||||
|
* monitoring: pingdom
|
||||||
|
* monitoring: pagerduty
|
||||||
|
* monitoring: monit
|
||||||
|
* utility: set_fact: sets a variable, which can be the result of a template evaluation
|
||||||
|
|
||||||
Modules removed
|
Modules removed
|
||||||
|
|
||||||
|
@ -119,7 +122,8 @@ the variable is still registered for the host, with the attribute skipped: True.
|
||||||
* pip works better when sudoing from unpriveledged users
|
* pip works better when sudoing from unpriveledged users
|
||||||
* fix for user creation with groups specification reporting 'changed' incorrectly in some cases
|
* fix for user creation with groups specification reporting 'changed' incorrectly in some cases
|
||||||
* fix for some unicode encoding errors in outputing some data in verbose mode
|
* fix for some unicode encoding errors in outputing some data in verbose mode
|
||||||
*
|
* improved FreeBSD, NetBSD and Solaris facts
|
||||||
|
* debug module always outputs data without having to specify -v
|
||||||
|
|
||||||
1.1 "Mean Street" -- 4/2/2013
|
1.1 "Mean Street" -- 4/2/2013
|
||||||
|
|
||||||
|
|
|
@ -306,7 +306,8 @@ To see the complete list of variables available for an instance, run the script
|
||||||
Example: OpenStack Inventory Script
|
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.
|
Though not detailed here in as much depth as the EC2 module, there's also a OpenStack Compute external inventory source in the plugins directory. It requires the Grizzly release of OpenStack or
|
||||||
|
later. See the inline comments in the module source for how to use it.
|
||||||
|
|
||||||
Callback Plugins
|
Callback Plugins
|
||||||
----------------
|
----------------
|
||||||
|
|
|
@ -52,6 +52,7 @@ The top level of the directory would contain files and directories like so::
|
||||||
ntp.conf.j2 # <------- templates end in .j2
|
ntp.conf.j2 # <------- templates end in .j2
|
||||||
files/ #
|
files/ #
|
||||||
bar.txt # <-- files for use with the copy resource
|
bar.txt # <-- files for use with the copy resource
|
||||||
|
foo.sh # <-- script files for use with the script resource
|
||||||
|
|
||||||
webtier/ # same kind of structure as "common" was above, done for the webtier role
|
webtier/ # same kind of structure as "common" was above, done for the webtier role
|
||||||
monitoring/ # ""
|
monitoring/ # ""
|
||||||
|
|
|
@ -213,6 +213,17 @@ the remote nodes will be terminated.
|
||||||
Typically you'll be only be backgrounding long-running
|
Typically you'll be only be backgrounding long-running
|
||||||
shell commands or software upgrades only. Backgrounding the copy module does not do a background file transfer. :doc:`playbooks` also support polling, and have a simplified syntax for this.
|
shell commands or software upgrades only. Backgrounding the copy module does not do a background file transfer. :doc:`playbooks` also support polling, and have a simplified syntax for this.
|
||||||
|
|
||||||
|
Gathering Facts
|
||||||
|
```````````````
|
||||||
|
|
||||||
|
Facts are described in the playbooks section and represent discovered variables about a
|
||||||
|
system. These can be used to implement conditional execution of tasks but also just to get ad-hoc information about your system. You can see all facts via::
|
||||||
|
|
||||||
|
$ ansible all -m setup
|
||||||
|
|
||||||
|
Its also possible to filter this output to just export certain facts, see the "setup" module documentation for details.
|
||||||
|
|
||||||
|
|
||||||
Limiting Selected Hosts
|
Limiting Selected Hosts
|
||||||
```````````````````````
|
```````````````````````
|
||||||
|
|
||||||
|
|
|
@ -204,7 +204,19 @@ further information on using Portfiles with MacPorts.
|
||||||
Ubuntu and Debian
|
Ubuntu and Debian
|
||||||
+++++++++++++++++
|
+++++++++++++++++
|
||||||
|
|
||||||
Ubuntu builds are available `in a PPA here <https://launchpad.net/~rquillo/+archive/ansible>`_
|
Ubuntu builds are available `in a PPA here <https://launchpad.net/~rquillo/+archive/ansible>`_.
|
||||||
|
|
||||||
|
In Ubuntu 13.04 (raring) its part of the backports repository:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ sudo apt-get install ansible/raring-backports
|
||||||
|
|
||||||
|
In Debian testing/unstable and Ubntu 13.10+ it is available via
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ sudo apt-get install ansible
|
||||||
|
|
||||||
Debian/Ubuntu package recipes can also be built from the source checkout, run:
|
Debian/Ubuntu package recipes can also be built from the source checkout, run:
|
||||||
|
|
||||||
|
|
|
@ -449,7 +449,7 @@ Roles
|
||||||
.. versionadded: 1.2
|
.. versionadded: 1.2
|
||||||
|
|
||||||
Now that you have learned about vars_files, tasks, and handlers, what is the best way to organize your playbooks?
|
Now that you have learned about vars_files, tasks, and handlers, what is the best way to organize your playbooks?
|
||||||
The short answer is to use roles! Roles are automatic ways of automatically loading certain vars_files, tasks, and
|
The short answer is to use roles! Roles are ways of automatically loading certain vars_files, tasks, and
|
||||||
handlers based on a known file structure. Grouping content by roles also allows easy sharing of roles with other users.
|
handlers based on a known file structure. Grouping content by roles also allows easy sharing of roles with other users.
|
||||||
|
|
||||||
Roles are just automation around 'include' directives as redescribed above, and really don't contain much
|
Roles are just automation around 'include' directives as redescribed above, and really don't contain much
|
||||||
|
@ -488,6 +488,7 @@ This designates the following behaviors, for each role 'x':
|
||||||
- If roles/x/handlers/main.yml exists, handlers listed therein will be added to the play
|
- If roles/x/handlers/main.yml exists, handlers listed therein will be added to the play
|
||||||
- If roles/x/vars/main.yml exists, variables listed therein will be added to the play
|
- If roles/x/vars/main.yml exists, variables listed therein will be added to the play
|
||||||
- Any copy tasks can reference files in roles/x/files/ without having to path them relatively or absolutely
|
- Any copy tasks can reference files in roles/x/files/ without having to path them relatively or absolutely
|
||||||
|
- Any script tasks can reference scripts in roles/x/files/ without having to path them relatively or absolutely
|
||||||
- Any template tasks can reference files in roles/x/templates/ without having to path them relatively or absolutely
|
- Any template tasks can reference files in roles/x/templates/ without having to path them relatively or absolutely
|
||||||
|
|
||||||
If any files are not present, they are just ignored. So it's ok to not have a 'vars/' subdirectory for the role,
|
If any files are not present, they are just ignored. So it's ok to not have a 'vars/' subdirectory for the role,
|
||||||
|
@ -526,6 +527,8 @@ If you want to define certain tasks to happen before AND after roles are applied
|
||||||
- shell: echo 'hello'
|
- shell: echo 'hello'
|
||||||
roles:
|
roles:
|
||||||
- { role: some_role }
|
- { role: some_role }
|
||||||
|
tasks:
|
||||||
|
- shell: echo 'still busy'
|
||||||
post_tasks:
|
post_tasks:
|
||||||
- shell: echo 'goodbye'
|
- shell: echo 'goodbye'
|
||||||
|
|
||||||
|
|
|
@ -262,8 +262,8 @@ Conditional Execution
|
||||||
`````````````````````
|
`````````````````````
|
||||||
|
|
||||||
(Note: this section covers 1.2 conditionals, if you are using a previous version, select
|
(Note: this section covers 1.2 conditionals, if you are using a previous version, select
|
||||||
the previous version of the documentation. Those conditional forms continue to be operational
|
the previous version of the documentation, `Ansible 1.1 Docs <http://ansible.cc/docs/released/1.1>`_ .
|
||||||
in 1.2, although the new mechanisms are cleaner.)
|
Those conditional forms continue to be operational in 1.2, although the new mechanisms are cleaner.)
|
||||||
|
|
||||||
Sometimes you will want to skip a particular step on a particular host. This could be something
|
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,
|
as simple as not installing a certain package if the operating system is a particular version,
|
||||||
|
@ -414,7 +414,11 @@ The yum and apt modules use with_items to execute fewer package manager transact
|
||||||
Note that the types of items you iterate over with 'with_items' do not have to be simple lists of strings.
|
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::
|
If you have a list of hashes, you can reference subkeys using things like::
|
||||||
|
|
||||||
{{ item.subKeyName }}
|
- name: add several users
|
||||||
|
action: user name={{ item.name }} state=present groups={{ item.groups }}
|
||||||
|
with_items:
|
||||||
|
- { name: 'testuser1', groups: 'wheel' }
|
||||||
|
- { name: 'testuser2', groups: 'root' }
|
||||||
|
|
||||||
Lookup Plugins - Accessing Outside Data
|
Lookup Plugins - Accessing Outside Data
|
||||||
```````````````````````````````````````
|
```````````````````````````````````````
|
||||||
|
|
|
@ -85,10 +85,10 @@ def boilerplate_module(modfile, args):
|
||||||
if included_boilerplate:
|
if included_boilerplate:
|
||||||
|
|
||||||
module_data = module_data.replace(module_common.REPLACER, module_common.MODULE_COMMON)
|
module_data = module_data.replace(module_common.REPLACER, module_common.MODULE_COMMON)
|
||||||
encoded_args = "\"\"\"%s\"\"\"" % args.replace("\"","\\\"")
|
encoded_args = repr(str(args))
|
||||||
module_data = module_data.replace(module_common.REPLACER_ARGS, encoded_args)
|
module_data = module_data.replace(module_common.REPLACER_ARGS, encoded_args)
|
||||||
encoded_lang = "\"\"\"%s\"\"\"" % C.DEFAULT_MODULE_LANG
|
encoded_lang = repr(C.DEFAULT_MODULE_LANG)
|
||||||
empty_complex = "\"\"\"%s\"\"\"" % "{}"
|
empty_complex = repr("{}")
|
||||||
module_data = module_data.replace(module_common.REPLACER_LANG, encoded_lang)
|
module_data = module_data.replace(module_common.REPLACER_LANG, encoded_lang)
|
||||||
module_data = module_data.replace('syslog.LOG_USER', "syslog.%s" % C.DEFAULT_SYSLOG_FACILITY)
|
module_data = module_data.replace('syslog.LOG_USER', "syslog.%s" % C.DEFAULT_SYSLOG_FACILITY)
|
||||||
module_data = module_data.replace(module_common.REPLACER_COMPLEX, empty_complex)
|
module_data = module_data.replace(module_common.REPLACER_COMPLEX, empty_complex)
|
||||||
|
|
|
@ -65,7 +65,7 @@ class InventoryParser(object):
|
||||||
|
|
||||||
for line in self.lines:
|
for line in self.lines:
|
||||||
if line.startswith("["):
|
if line.startswith("["):
|
||||||
active_group_name = line.replace("[","").replace("]","").strip()
|
active_group_name = line.split("#")[0].replace("[","").replace("]","").strip()
|
||||||
if line.find(":vars") != -1 or line.find(":children") != -1:
|
if line.find(":vars") != -1 or line.find(":children") != -1:
|
||||||
active_group_name = active_group_name.rsplit(":", 1)[0]
|
active_group_name = active_group_name.rsplit(":", 1)[0]
|
||||||
if active_group_name not in self.groups:
|
if active_group_name not in self.groups:
|
||||||
|
@ -78,7 +78,7 @@ class InventoryParser(object):
|
||||||
elif line.startswith("#") or line == '':
|
elif line.startswith("#") or line == '':
|
||||||
pass
|
pass
|
||||||
elif active_group_name:
|
elif active_group_name:
|
||||||
tokens = shlex.split(line)
|
tokens = shlex.split(line.split("#")[0])
|
||||||
if len(tokens) == 0:
|
if len(tokens) == 0:
|
||||||
continue
|
continue
|
||||||
hostname = tokens[0]
|
hostname = tokens[0]
|
||||||
|
|
|
@ -710,9 +710,11 @@ class Runner(object):
|
||||||
module_style = 'non_native_want_json'
|
module_style = 'non_native_want_json'
|
||||||
|
|
||||||
complex_args_json = utils.jsonify(complex_args)
|
complex_args_json = utils.jsonify(complex_args)
|
||||||
encoded_args = "\"\"\"%s\"\"\"" % module_args.replace("\"","\\\"")
|
# We force conversion of module_args to str because module_common calls shlex.split,
|
||||||
encoded_lang = "\"\"\"%s\"\"\"" % C.DEFAULT_MODULE_LANG
|
# a standard library function that incorrectly handles Unicode input before Python 2.7.3.
|
||||||
encoded_complex = "\"\"\"%s\"\"\"" % complex_args_json.replace("\\", "\\\\")
|
encoded_args = repr(str(module_args))
|
||||||
|
encoded_lang = repr(C.DEFAULT_MODULE_LANG)
|
||||||
|
encoded_complex = repr(complex_args_json)
|
||||||
|
|
||||||
module_data = module_data.replace(module_common.REPLACER, module_common.MODULE_COMMON)
|
module_data = module_data.replace(module_common.REPLACER, module_common.MODULE_COMMON)
|
||||||
module_data = module_data.replace(module_common.REPLACER_ARGS, encoded_args)
|
module_data = module_data.replace(module_common.REPLACER_ARGS, encoded_args)
|
||||||
|
|
|
@ -41,7 +41,10 @@ class ActionModule(object):
|
||||||
# FIXME: error handling
|
# FIXME: error handling
|
||||||
args = " ".join(tokens[1:])
|
args = " ".join(tokens[1:])
|
||||||
source = template.template(self.runner.basedir, source, inject)
|
source = template.template(self.runner.basedir, source, inject)
|
||||||
source = utils.path_dwim(self.runner.basedir, source)
|
if '_original_file' in inject:
|
||||||
|
source = utils.path_dwim_relative(inject['_original_file'], 'files', source, self.runner.basedir)
|
||||||
|
else:
|
||||||
|
source = utils.path_dwim(self.runner.basedir, source)
|
||||||
|
|
||||||
# transfer the file to a remote tmp location
|
# transfer the file to a remote tmp location
|
||||||
source = source.replace('\x00','') # why does this happen here?
|
source = source.replace('\x00','') # why does this happen here?
|
||||||
|
|
|
@ -49,6 +49,7 @@ def get_docstring(filename, verbose=False):
|
||||||
if 'EXAMPLES' in (t.id for t in child.targets):
|
if 'EXAMPLES' in (t.id for t in child.targets):
|
||||||
plainexamples = child.value.s[1:] # Skip first empty line
|
plainexamples = child.value.s[1:] # Skip first empty line
|
||||||
except:
|
except:
|
||||||
|
traceback.print_exc() # temp
|
||||||
if verbose == True:
|
if verbose == True:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
print "unable to parse %s" % filename
|
print "unable to parse %s" % filename
|
||||||
|
|
|
@ -22,7 +22,7 @@ try:
|
||||||
from keystoneclient.v2_0 import client as ksclient
|
from keystoneclient.v2_0 import client as ksclient
|
||||||
import time
|
import time
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print("failed=True msg='glanceclient,novaclient and keystone client are required'")
|
print "failed=True msg='glanceclient,novaclient and keystone client are required'"
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
DOCUMENTATION = '''
|
||||||
---
|
---
|
||||||
|
@ -130,9 +130,7 @@ def _get_server_state(module, nova):
|
||||||
return server_info, server
|
return server_info, server
|
||||||
|
|
||||||
def _get_port_id(quantum, module, instance_id):
|
def _get_port_id(quantum, module, instance_id):
|
||||||
kwargs = {
|
kwargs = dict(device_id = instance_id)
|
||||||
device_id': instance_id,
|
|
||||||
}
|
|
||||||
try:
|
try:
|
||||||
ports = quantum.list_ports(**kwargs)
|
ports = quantum.list_ports(**kwargs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -95,7 +95,7 @@ def main():
|
||||||
module.fail_json(rc=256, msg="no command given")
|
module.fail_json(rc=256, msg="no command given")
|
||||||
|
|
||||||
if chdir:
|
if chdir:
|
||||||
os.chdir(os.path.expanduser(chdir))
|
os.chdir(chdir)
|
||||||
|
|
||||||
if creates:
|
if creates:
|
||||||
# do not run the command if the line contains creates=filename
|
# do not run the command if the line contains creates=filename
|
||||||
|
|
|
@ -126,7 +126,7 @@ EXAMPLES = r"""
|
||||||
|
|
||||||
lineinfile: dest=/etc/sudoers state=present regexp='^%wheel' line='%wheel ALL=(ALL) NOPASSWD: ALL'
|
lineinfile: dest=/etc/sudoers state=present regexp='^%wheel' line='%wheel ALL=(ALL) NOPASSWD: ALL'
|
||||||
|
|
||||||
lineinfile: dest=/opt/jboss-as/bin/standalone.conf regexp='^(.*)Xms(\d+)m(.*)$' line='\\1Xms${xms}m\\3' backrefs=yes
|
lineinfile: dest=/opt/jboss-as/bin/standalone.conf regexp='^(.*)Xms(\d+)m(.*)$' line='\1Xms${xms}m\3' backrefs=yes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def write_changes(module,lines,dest):
|
def write_changes(module,lines,dest):
|
||||||
|
|
146
library/monitoring/monit
Normal file
146
library/monitoring/monit
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# (c) 2013, Darryl Stoflet <stoflet@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/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: monit
|
||||||
|
short_description: Manage the state of a program monitored via Monit
|
||||||
|
description:
|
||||||
|
- Manage the state of a program monitored via I(Monit)
|
||||||
|
version_added: "1.2"
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- The name of the I(monit) program/process to manage
|
||||||
|
required: true
|
||||||
|
default: null
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- The state of service
|
||||||
|
required: true
|
||||||
|
default: null
|
||||||
|
choices: [ "present", "started", "stopped", "restarted", "monitored", "unmonitored", "reloaded" ]
|
||||||
|
examples:
|
||||||
|
- code: "monit: name=httpd state=started"
|
||||||
|
description: Manage the state of program I(httpd) to be in I(started) state.
|
||||||
|
requirements: [ ]
|
||||||
|
author: Darryl Stoflet
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
arg_spec = dict(
|
||||||
|
name=dict(required=True),
|
||||||
|
state=dict(required=True, choices=['present', 'started', 'restarted', 'stopped', 'monitored', 'unmonitored', 'reloaded'])
|
||||||
|
)
|
||||||
|
|
||||||
|
module = AnsibleModule(argument_spec=arg_spec, supports_check_mode=True)
|
||||||
|
|
||||||
|
name = module.params['name']
|
||||||
|
state = module.params['state']
|
||||||
|
|
||||||
|
MONIT = module.get_bin_path('monit', True)
|
||||||
|
|
||||||
|
if state == 'reloaded':
|
||||||
|
if module.check_mode:
|
||||||
|
module.exit_json(changed=True)
|
||||||
|
rc, out, err = module.run_command('%s reload' % MONIT)
|
||||||
|
module.exit_json(changed=True, name=name, state=state)
|
||||||
|
|
||||||
|
rc, out, err = module.run_command('%s summary | grep "Process \'%s\'"' % (MONIT, name))
|
||||||
|
present = name in out
|
||||||
|
|
||||||
|
if not present and not state == 'present':
|
||||||
|
module.fail_json(msg='%s process not presently configured with monit' % name, name=name, state=state)
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
if not present:
|
||||||
|
if module.check_mode:
|
||||||
|
module.exit_json(changed=True)
|
||||||
|
module.run_command('%s reload' % MONIT, check_rc=True)
|
||||||
|
rc, out, err = module.run_command('%s summary | grep %s' % (MONIT, name))
|
||||||
|
if name in out:
|
||||||
|
module.exit_json(changed=True, name=name, state=state)
|
||||||
|
else:
|
||||||
|
module.fail_json(msg=out, name=name, state=state)
|
||||||
|
|
||||||
|
module.exit_json(changed=False, name=name, state=state)
|
||||||
|
|
||||||
|
rc, out, err = module.run_command('%s summary | grep %s' % (MONIT, name))
|
||||||
|
running = 'Running' in out
|
||||||
|
|
||||||
|
if running and (state == 'started' or state == 'monitored'):
|
||||||
|
module.exit_json(changed=False, name=name, state=state)
|
||||||
|
|
||||||
|
if running and state == 'monitored':
|
||||||
|
module.exit_json(changed=False, name=name, state=state)
|
||||||
|
|
||||||
|
if running and state == 'stopped':
|
||||||
|
if module.check_mode:
|
||||||
|
module.exit_json(changed=True)
|
||||||
|
module.run_command('%s stop %s' % (MONIT, name))
|
||||||
|
rc, out, err = module.run_command('%s summary | grep %s' % (MONIT, name))
|
||||||
|
if 'Not monitored' in out or 'stop pending' in out:
|
||||||
|
module.exit_json(changed=True, name=name, state=state)
|
||||||
|
module.fail_json(msg=out)
|
||||||
|
|
||||||
|
if running and state == 'unmonitored':
|
||||||
|
if module.check_mode:
|
||||||
|
module.exit_json(changed=True)
|
||||||
|
module.run_command('%s unmonitor %s' % (MONIT, name))
|
||||||
|
rc, out, err = module.run_command('%s summary | grep %s' % (MONIT, name))
|
||||||
|
if 'Not monitored' in out:
|
||||||
|
module.exit_json(changed=True, name=name, state=state)
|
||||||
|
module.fail_json(msg=out)
|
||||||
|
|
||||||
|
elif state == 'restarted':
|
||||||
|
if module.check_mode:
|
||||||
|
module.exit_json(changed=True)
|
||||||
|
module.run_command('%s stop %s' % (MONIT, name))
|
||||||
|
rc, out, err = module.run_command('%s start %s' % (MONIT, name))
|
||||||
|
if 'Initializing' in out:
|
||||||
|
module.exit_json(changed=True, name=name, state=state)
|
||||||
|
module.fail_json(msg=out)
|
||||||
|
|
||||||
|
elif not running and state == 'started':
|
||||||
|
if module.check_mode:
|
||||||
|
module.exit_json(changed=True)
|
||||||
|
module.run_command('%s start %s' % (MONIT, name))
|
||||||
|
rc, out, err = module.run_command('%s summary | grep %s' % (MONIT, name))
|
||||||
|
if 'Initializing' in out or 'start pending' in out:
|
||||||
|
module.exit_json(changed=True, name=name, state=state)
|
||||||
|
module.fail_json(msg=out)
|
||||||
|
|
||||||
|
elif not running and state == 'monitored':
|
||||||
|
if module.check_mode:
|
||||||
|
module.exit_json(changed=True)
|
||||||
|
module.run_command('%s monitor %s' % (MONIT, name))
|
||||||
|
rc, out, err = module.run_command('%s summary | grep %s' % (MONIT, name))
|
||||||
|
if 'Initializing' in out or 'start pending' in out:
|
||||||
|
module.exit_json(changed=True, name=name, state=state)
|
||||||
|
module.fail_json(msg=out)
|
||||||
|
|
||||||
|
module.exit_json(changed=False, name=name, state=state)
|
||||||
|
|
||||||
|
# this is magic, see lib/ansible/module_common.py
|
||||||
|
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||||
|
|
||||||
|
main()
|
154
library/monitoring/pagerduty
Normal file
154
library/monitoring/pagerduty
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
|
||||||
|
module: pagerduty
|
||||||
|
short_description: Create PagerDuty maintenance windows
|
||||||
|
description:
|
||||||
|
- This module will let you create PagerDuty maintenance windows
|
||||||
|
version_added: "1.2"
|
||||||
|
author: Justin Johns
|
||||||
|
requirements:
|
||||||
|
- PagerDuty API access
|
||||||
|
options:
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Create a maintenance window or get a list of ongoing windows.
|
||||||
|
required: true
|
||||||
|
default: null
|
||||||
|
choices: [ "running", "started", "ongoing" ]
|
||||||
|
aliases: []
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- PagerDuty unique subdomain.
|
||||||
|
required: true
|
||||||
|
default: null
|
||||||
|
choices: []
|
||||||
|
aliases: []
|
||||||
|
user:
|
||||||
|
description:
|
||||||
|
- PagerDuty user ID.
|
||||||
|
required: true
|
||||||
|
default: null
|
||||||
|
choices: []
|
||||||
|
aliases: []
|
||||||
|
passwd:
|
||||||
|
description:
|
||||||
|
- PagerDuty user password.
|
||||||
|
required: true
|
||||||
|
default: null
|
||||||
|
choices: []
|
||||||
|
aliases: []
|
||||||
|
service:
|
||||||
|
description:
|
||||||
|
- PagerDuty service ID.
|
||||||
|
required: false
|
||||||
|
default: null
|
||||||
|
choices: []
|
||||||
|
aliases: []
|
||||||
|
hours:
|
||||||
|
description:
|
||||||
|
- Length of maintenance window in hours.
|
||||||
|
required: false
|
||||||
|
default: 1
|
||||||
|
choices: []
|
||||||
|
aliases: []
|
||||||
|
desc:
|
||||||
|
description:
|
||||||
|
- Short description of maintenance window.
|
||||||
|
required: false
|
||||||
|
default: Created by Ansible
|
||||||
|
choices: []
|
||||||
|
aliases: []
|
||||||
|
notes:
|
||||||
|
- This module does not yet have support to end maintenance windows.
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES='''
|
||||||
|
# List ongoing maintenance windows.
|
||||||
|
pagerduty: name=companyabc user=example@example.com passwd=password123 state=ongoing
|
||||||
|
|
||||||
|
# Create a 1 hour maintenance window for service FOO123.
|
||||||
|
pagerduty: name=companyabc user=example@example.com passwd=password123 state=running service=FOO123"
|
||||||
|
|
||||||
|
# Create a 4 hour maintenance window for service FOO123 with the description "deployment".
|
||||||
|
pagerduty: name=companyabc user=example@example.com passwd=password123 state=running service=FOO123 hours=4 desc=deployment"
|
||||||
|
'''
|
||||||
|
|
||||||
|
import json
|
||||||
|
import datetime
|
||||||
|
import urllib2
|
||||||
|
import base64
|
||||||
|
|
||||||
|
|
||||||
|
def ongoing(name, user, passwd):
|
||||||
|
|
||||||
|
url = "https://" + name + ".pagerduty.com/api/v1/maintenance_windows/ongoing"
|
||||||
|
auth = base64.encodestring('%s:%s' % (user, passwd)).replace('\n', '')
|
||||||
|
|
||||||
|
req = urllib2.Request(url)
|
||||||
|
req.add_header("Authorization", "Basic %s" % auth)
|
||||||
|
res = urllib2.urlopen(req)
|
||||||
|
out = res.read()
|
||||||
|
|
||||||
|
return False, out
|
||||||
|
|
||||||
|
|
||||||
|
def create(name, user, passwd, service, hours, desc):
|
||||||
|
|
||||||
|
now = datetime.datetime.utcnow()
|
||||||
|
later = now + datetime.timedelta(hours=int(hours))
|
||||||
|
start = now.strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
end = later.strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
|
||||||
|
url = "https://" + name + ".pagerduty.com/api/v1/maintenance_windows"
|
||||||
|
auth = base64.encodestring('%s:%s' % (user, passwd)).replace('\n', '')
|
||||||
|
data = json.dumps({'maintenance_window': {'start_time': start, 'end_time': end, 'description': desc, 'service_ids': [service]}})
|
||||||
|
|
||||||
|
req = urllib2.Request(url, data)
|
||||||
|
req.add_header("Authorization", "Basic %s" % auth)
|
||||||
|
req.add_header('Content-Type', 'application/json')
|
||||||
|
res = urllib2.urlopen(req)
|
||||||
|
out = res.read()
|
||||||
|
|
||||||
|
return False, out
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
state=dict(required=True, choices=['running', 'started', 'ongoing']),
|
||||||
|
name=dict(required=True),
|
||||||
|
user=dict(required=True),
|
||||||
|
passwd=dict(required=True),
|
||||||
|
service=dict(required=False),
|
||||||
|
hours=dict(default='1', required=False),
|
||||||
|
desc=dict(default='Created by Ansible', required=False)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
state = module.params['state']
|
||||||
|
name = module.params['name']
|
||||||
|
user = module.params['user']
|
||||||
|
passwd = module.params['passwd']
|
||||||
|
service = module.params['service']
|
||||||
|
hours = module.params['hours']
|
||||||
|
desc = module.params['desc']
|
||||||
|
|
||||||
|
if state == "running" or state == "started":
|
||||||
|
if not service:
|
||||||
|
module.fail_json(msg="service not specified")
|
||||||
|
(rc, out) = create(name, user, passwd, service, hours, desc)
|
||||||
|
|
||||||
|
if state == "ongoing":
|
||||||
|
(rc, out) = ongoing(name, user, passwd)
|
||||||
|
|
||||||
|
if rc != 0:
|
||||||
|
module.fail_json(msg="failed", result=out)
|
||||||
|
|
||||||
|
module.exit_json(msg="success", result=out)
|
||||||
|
|
||||||
|
# include magic from lib/ansible/module_common.py
|
||||||
|
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||||
|
main()
|
119
library/monitoring/pingdom
Normal file
119
library/monitoring/pingdom
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
|
||||||
|
module: pingdom
|
||||||
|
short_description: Pause/unpause Pingdom alerts
|
||||||
|
description:
|
||||||
|
- This module will let you pause/unpause Pingdom alerts
|
||||||
|
version_added: "1.2"
|
||||||
|
author: Justin Johns
|
||||||
|
requirements:
|
||||||
|
- "pingdom python library"
|
||||||
|
options:
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Define whether or not the check should be running or paused.
|
||||||
|
required: true
|
||||||
|
default: null
|
||||||
|
choices: [ "running", "paused" ]
|
||||||
|
aliases: []
|
||||||
|
checkid:
|
||||||
|
description:
|
||||||
|
- Pingdom ID of the check.
|
||||||
|
required: true
|
||||||
|
default: null
|
||||||
|
choices: []
|
||||||
|
aliases: []
|
||||||
|
uid:
|
||||||
|
description:
|
||||||
|
- Pingdom user ID.
|
||||||
|
required: true
|
||||||
|
default: null
|
||||||
|
choices: []
|
||||||
|
aliases: []
|
||||||
|
passwd:
|
||||||
|
description:
|
||||||
|
- Pingdom user password.
|
||||||
|
required: true
|
||||||
|
default: null
|
||||||
|
choices: []
|
||||||
|
aliases: []
|
||||||
|
key:
|
||||||
|
description:
|
||||||
|
- Pingdom API key.
|
||||||
|
required: true
|
||||||
|
default: null
|
||||||
|
choices: []
|
||||||
|
aliases: []
|
||||||
|
notes:
|
||||||
|
- This module does not yet have support to add/remove checks.
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Pause the check with the ID of 12345.
|
||||||
|
pingdom: uid=example@example.com passwd=password123 key=apipassword123 checkid=12345 state=paused
|
||||||
|
|
||||||
|
# Unpause the check with the ID of 12345.
|
||||||
|
pingdom: uid=example@example.com passwd=password123 key=apipassword123 checkid=12345 state=running
|
||||||
|
'''
|
||||||
|
|
||||||
|
import pingdom
|
||||||
|
|
||||||
|
|
||||||
|
def pause(checkid, uid, passwd, key):
|
||||||
|
|
||||||
|
c = pingdom.PingdomConnection(uid, passwd, key)
|
||||||
|
c.modify_check(checkid, paused=True)
|
||||||
|
check = c.get_check(checkid)
|
||||||
|
name = check.name
|
||||||
|
result = check.status
|
||||||
|
#if result != "paused": # api output buggy - accept raw exception for now
|
||||||
|
# return (True, name, result)
|
||||||
|
return (False, name, result)
|
||||||
|
|
||||||
|
|
||||||
|
def unpause(checkid, uid, passwd, key):
|
||||||
|
|
||||||
|
c = pingdom.PingdomConnection(uid, passwd, key)
|
||||||
|
c.modify_check(checkid, paused=False)
|
||||||
|
check = c.get_check(checkid)
|
||||||
|
name = check.name
|
||||||
|
result = check.status
|
||||||
|
#if result != "up": # api output buggy - accept raw exception for now
|
||||||
|
# return (True, name, result)
|
||||||
|
return (False, name, result)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
state=dict(required=True, choices=['running', 'paused', 'started', 'stopped']),
|
||||||
|
checkid=dict(required=True),
|
||||||
|
uid=dict(required=True),
|
||||||
|
passwd=dict(required=True),
|
||||||
|
key=dict(required=True)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
checkid = module.params['checkid']
|
||||||
|
state = module.params['state']
|
||||||
|
uid = module.params['uid']
|
||||||
|
passwd = module.params['passwd']
|
||||||
|
key = module.params['key']
|
||||||
|
|
||||||
|
if (state == "paused" or state == "stopped"):
|
||||||
|
(rc, name, result) = pause(checkid, uid, passwd, key)
|
||||||
|
|
||||||
|
if (state == "running" or state == "started"):
|
||||||
|
(rc, name, result) = unpause(checkid, uid, passwd, key)
|
||||||
|
|
||||||
|
if rc != 0:
|
||||||
|
module.fail_json(checkid=checkid, name=name, status=result)
|
||||||
|
|
||||||
|
module.exit_json(checkid=checkid, name=name, status=result)
|
||||||
|
|
||||||
|
# include magic from lib/ansible/module_common.py
|
||||||
|
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||||
|
main()
|
|
@ -88,11 +88,12 @@ def main():
|
||||||
if module.check_mode:
|
if module.check_mode:
|
||||||
changed = True
|
changed = True
|
||||||
else:
|
else:
|
||||||
|
mkfs = module.get_bin_path('mkfs', required=True)
|
||||||
cmd = None
|
cmd = None
|
||||||
if opts is None:
|
if opts is None:
|
||||||
cmd = "mkfs -t %s '%s'"%(fstype, dev)
|
cmd = "%s -t %s '%s'" % (mkfs, fstype, dev)
|
||||||
else:
|
else:
|
||||||
cmd = "mkfs -t %s %s '%s'"%(fstype, opts, dev)
|
cmd = "%s -t %s %s '%s'" % (mkfs, fstype, opts, dev)
|
||||||
rc,_,err = module.run_command(cmd)
|
rc,_,err = module.run_command(cmd)
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
changed = True
|
changed = True
|
||||||
|
|
|
@ -121,6 +121,7 @@ class Facts(object):
|
||||||
{ 'path' : '/opt/local/bin/pkgin', 'name' : 'pkgin' },
|
{ 'path' : '/opt/local/bin/pkgin', 'name' : 'pkgin' },
|
||||||
{ 'path' : '/opt/local/bin/port', 'name' : 'macports' },
|
{ 'path' : '/opt/local/bin/port', 'name' : 'macports' },
|
||||||
{ 'path' : '/sbin/apk', 'name' : 'apk' },
|
{ 'path' : '/sbin/apk', 'name' : 'apk' },
|
||||||
|
{ 'path' : '/usr/sbin/pkg', 'name' : 'pkgng' },
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -175,7 +176,8 @@ class Facts(object):
|
||||||
SLED = 'Suse', OpenSuSE = 'Suse', SuSE = 'Suse', Gentoo = 'Gentoo',
|
SLED = 'Suse', OpenSuSE = 'Suse', SuSE = 'Suse', Gentoo = 'Gentoo',
|
||||||
Archlinux = 'Archlinux', Mandriva = 'Mandrake', Mandrake = 'Mandrake',
|
Archlinux = 'Archlinux', Mandriva = 'Mandrake', Mandrake = 'Mandrake',
|
||||||
Solaris = 'Solaris', Nexenta = 'Solaris', OmniOS = 'Solaris', OpenIndiana = 'Solaris',
|
Solaris = 'Solaris', Nexenta = 'Solaris', OmniOS = 'Solaris', OpenIndiana = 'Solaris',
|
||||||
SmartOS = 'Solaris', AIX = 'AIX', Alpine = 'Alpine', MacOSX = 'Darwin'
|
SmartOS = 'Solaris', AIX = 'AIX', Alpine = 'Alpine', MacOSX = 'Darwin',
|
||||||
|
FreeBSD = 'FreeBSD'
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.facts['system'] == 'AIX':
|
if self.facts['system'] == 'AIX':
|
||||||
|
@ -189,6 +191,10 @@ class Facts(object):
|
||||||
rc, out, err = module.run_command("/usr/bin/sw_vers -productVersion")
|
rc, out, err = module.run_command("/usr/bin/sw_vers -productVersion")
|
||||||
data = out.split()[-1]
|
data = out.split()[-1]
|
||||||
self.facts['distribution_version'] = data
|
self.facts['distribution_version'] = data
|
||||||
|
elif self.facts['system'] == 'FreeBSD':
|
||||||
|
self.facts['distribution'] = 'FreeBSD'
|
||||||
|
self.facts['distribution_release'] = platform.release()
|
||||||
|
self.facts['distribution_version'] = platform.version()
|
||||||
else:
|
else:
|
||||||
dist = platform.dist()
|
dist = platform.dist()
|
||||||
self.facts['distribution'] = dist[0].capitalize() or 'NA'
|
self.facts['distribution'] = dist[0].capitalize() or 'NA'
|
||||||
|
@ -245,12 +251,15 @@ class Facts(object):
|
||||||
def get_public_ssh_host_keys(self):
|
def get_public_ssh_host_keys(self):
|
||||||
dsa_filename = '/etc/ssh/ssh_host_dsa_key.pub'
|
dsa_filename = '/etc/ssh/ssh_host_dsa_key.pub'
|
||||||
rsa_filename = '/etc/ssh/ssh_host_rsa_key.pub'
|
rsa_filename = '/etc/ssh/ssh_host_rsa_key.pub'
|
||||||
|
ecdsa_filename = '/etc/ssh/ssh_host_ecdsa_key.pub'
|
||||||
|
|
||||||
if self.facts['system'] == 'Darwin':
|
if self.facts['system'] == 'Darwin':
|
||||||
dsa_filename = '/etc/ssh_host_dsa_key.pub'
|
dsa_filename = '/etc/ssh_host_dsa_key.pub'
|
||||||
rsa_filename = '/etc/ssh_host_rsa_key.pub'
|
rsa_filename = '/etc/ssh_host_rsa_key.pub'
|
||||||
|
ecdsa_filename = '/etc/ssh_host_ecdsa_key.pub'
|
||||||
dsa = get_file_content(dsa_filename)
|
dsa = get_file_content(dsa_filename)
|
||||||
rsa = get_file_content(rsa_filename)
|
rsa = get_file_content(rsa_filename)
|
||||||
|
ecdsa = get_file_content(ecdsa_filename)
|
||||||
if dsa is None:
|
if dsa is None:
|
||||||
dsa = 'NA'
|
dsa = 'NA'
|
||||||
else:
|
else:
|
||||||
|
@ -259,6 +268,10 @@ class Facts(object):
|
||||||
rsa = 'NA'
|
rsa = 'NA'
|
||||||
else:
|
else:
|
||||||
self.facts['ssh_host_key_rsa_public'] = rsa.split()[1]
|
self.facts['ssh_host_key_rsa_public'] = rsa.split()[1]
|
||||||
|
if ecdsa is None:
|
||||||
|
ecdsa = 'NA'
|
||||||
|
else:
|
||||||
|
self.facts['ssh_host_key_ecdsa_public'] = ecdsa.split()[1]
|
||||||
|
|
||||||
def get_pkg_mgr_facts(self):
|
def get_pkg_mgr_facts(self):
|
||||||
self.facts['pkg_mgr'] = 'unknown'
|
self.facts['pkg_mgr'] = 'unknown'
|
||||||
|
@ -1620,7 +1633,7 @@ class LinuxVirtual(Virtual):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Beware that we can have both kvm and virtualbox running on a single system
|
# Beware that we can have both kvm and virtualbox running on a single system
|
||||||
if os.path.exists("/proc/modules"):
|
if os.path.exists("/proc/modules") and os.access('/proc/modules', os.R_OK):
|
||||||
modules = []
|
modules = []
|
||||||
for line in open("/proc/modules").readlines():
|
for line in open("/proc/modules").readlines():
|
||||||
data = line.split(" ", 1)
|
data = line.split(" ", 1)
|
||||||
|
|
132
plugins/inventory/vagrant.py
Executable file
132
plugins/inventory/vagrant.py
Executable file
|
@ -0,0 +1,132 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
"""
|
||||||
|
Vagrant external inventory script. Automatically finds the IP of the booted vagrant vm(s), and
|
||||||
|
returns it under the host group 'vagrant'
|
||||||
|
|
||||||
|
Example Vagrant configuration using this script:
|
||||||
|
|
||||||
|
config.vm.provision :ansible do |ansible|
|
||||||
|
ansible.playbook = "./provision/your_playbook.yml"
|
||||||
|
ansible.inventory_file = "./provision/inventory/vagrant.py"
|
||||||
|
ansible.verbose = true
|
||||||
|
end
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Copyright (C) 2013 Mark Mandel <mark@compoundtheory.com>
|
||||||
|
#
|
||||||
|
# This program 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.
|
||||||
|
#
|
||||||
|
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#
|
||||||
|
# Thanks to the spacewalk.py inventory script for giving me the basic structure
|
||||||
|
# of this.
|
||||||
|
#
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import re
|
||||||
|
import string
|
||||||
|
from optparse import OptionParser
|
||||||
|
try:
|
||||||
|
import json
|
||||||
|
except:
|
||||||
|
import simplejson as json
|
||||||
|
|
||||||
|
# Options
|
||||||
|
#------------------------------
|
||||||
|
|
||||||
|
parser = OptionParser(usage="%prog [options] --list | --host <machine>")
|
||||||
|
parser.add_option('--list', default=False, dest="list", action="store_true",
|
||||||
|
help="Produce a JSON consumable grouping of Vagrant servers for Ansible")
|
||||||
|
parser.add_option('--host', default=None, dest="host",
|
||||||
|
help="Generate additional host specific details for given host for Ansible")
|
||||||
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
|
#
|
||||||
|
# helper functions
|
||||||
|
#
|
||||||
|
|
||||||
|
# get all the ssh configs for all boxes in an array of dictionaries.
|
||||||
|
def get_ssh_config():
|
||||||
|
configs = []
|
||||||
|
|
||||||
|
boxes = list_running_boxes()
|
||||||
|
|
||||||
|
for box in boxes:
|
||||||
|
config = get_a_ssh_config(box)
|
||||||
|
configs.append(config)
|
||||||
|
|
||||||
|
return configs
|
||||||
|
|
||||||
|
#list all the running boxes
|
||||||
|
def list_running_boxes():
|
||||||
|
output = subprocess.check_output(["vagrant", "status"]).split('\n')
|
||||||
|
|
||||||
|
boxes = []
|
||||||
|
|
||||||
|
for line in output:
|
||||||
|
matcher = re.search("([^\s]+)[\s]+running \(.+", line)
|
||||||
|
if matcher:
|
||||||
|
boxes.append(matcher.group(1))
|
||||||
|
|
||||||
|
|
||||||
|
return boxes
|
||||||
|
|
||||||
|
#get the ssh config for a single box
|
||||||
|
def get_a_ssh_config(box_name):
|
||||||
|
"""Gives back a map of all the machine's ssh configurations"""
|
||||||
|
|
||||||
|
output = subprocess.check_output(["vagrant", "ssh-config", box_name]).split('\n')
|
||||||
|
|
||||||
|
config = {}
|
||||||
|
for line in output:
|
||||||
|
if line.strip() != '':
|
||||||
|
matcher = re.search("( )?([a-zA-Z]+) (.*)", line)
|
||||||
|
config[matcher.group(2)] = matcher.group(3)
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
# List out servers that vagrant has running
|
||||||
|
#------------------------------
|
||||||
|
if options.list:
|
||||||
|
ssh_config = get_ssh_config()
|
||||||
|
hosts = { 'vagrant': []}
|
||||||
|
|
||||||
|
for data in ssh_config:
|
||||||
|
hosts['vagrant'].append(data['HostName'])
|
||||||
|
|
||||||
|
print json.dumps(hosts)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Get out the host details
|
||||||
|
#------------------------------
|
||||||
|
elif options.host:
|
||||||
|
result = {}
|
||||||
|
ssh_config = get_ssh_config()
|
||||||
|
|
||||||
|
details = filter(lambda x: (x['HostName'] == options.host), ssh_config)
|
||||||
|
if len(details) > 0:
|
||||||
|
#pass through the port, in case it's non standard.
|
||||||
|
result = details[0]
|
||||||
|
result['ansible_ssh_port'] = result['Port']
|
||||||
|
|
||||||
|
print json.dumps(result)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
# Print out help
|
||||||
|
#------------------------------
|
||||||
|
else:
|
||||||
|
parser.print_help()
|
||||||
|
sys.exit(1)
|
|
@ -477,7 +477,7 @@ class TestRunner(unittest.TestCase):
|
||||||
# The order of the test cases is important
|
# The order of the test cases is important
|
||||||
|
|
||||||
# The regexp doesn't match, so the line will not be added anywhere.
|
# The regexp doesn't match, so the line will not be added anywhere.
|
||||||
testline = r'\\1: Line added by default at the end of the file.'
|
testline = r'\1: Line added by default at the end of the file.'
|
||||||
testcase = ('lineinfile', [
|
testcase = ('lineinfile', [
|
||||||
"dest=%s" % sample,
|
"dest=%s" % sample,
|
||||||
"regexp='^(First): '",
|
"regexp='^(First): '",
|
||||||
|
@ -492,7 +492,7 @@ class TestRunner(unittest.TestCase):
|
||||||
|
|
||||||
# insertafter with EOF
|
# insertafter with EOF
|
||||||
# The regexp doesn't match, so the line will not be added anywhere.
|
# The regexp doesn't match, so the line will not be added anywhere.
|
||||||
testline = r'\\1: Line added with insertafter=EOF'
|
testline = r'\1: Line added with insertafter=EOF'
|
||||||
testcase = ('lineinfile', [
|
testcase = ('lineinfile', [
|
||||||
"dest=%s" % sample,
|
"dest=%s" % sample,
|
||||||
"insertafter=EOF",
|
"insertafter=EOF",
|
||||||
|
@ -508,7 +508,7 @@ class TestRunner(unittest.TestCase):
|
||||||
|
|
||||||
# with invalid insertafter regex
|
# with invalid insertafter regex
|
||||||
# The regexp doesn't match, so do nothing.
|
# The regexp doesn't match, so do nothing.
|
||||||
testline = r'\\1: Line added with an invalid insertafter regex'
|
testline = r'\1: Line added with an invalid insertafter regex'
|
||||||
testcase = ('lineinfile', [
|
testcase = ('lineinfile', [
|
||||||
"dest=%s" % sample,
|
"dest=%s" % sample,
|
||||||
"insertafter='^abcdefgh'",
|
"insertafter='^abcdefgh'",
|
||||||
|
@ -522,7 +522,7 @@ class TestRunner(unittest.TestCase):
|
||||||
|
|
||||||
# with an insertafter regex
|
# with an insertafter regex
|
||||||
# The regexp doesn't match, so do nothing.
|
# The regexp doesn't match, so do nothing.
|
||||||
testline = r'\\1: Line added with a valid insertafter regex'
|
testline = r'\1: Line added with a valid insertafter regex'
|
||||||
testcase = ('lineinfile', [
|
testcase = ('lineinfile', [
|
||||||
"dest=%s" % sample,
|
"dest=%s" % sample,
|
||||||
"insertafter='^receive messages to '",
|
"insertafter='^receive messages to '",
|
||||||
|
@ -541,7 +541,7 @@ class TestRunner(unittest.TestCase):
|
||||||
target_line = 'combination of microphone, speaker, keyboard and display. It can send and'
|
target_line = 'combination of microphone, speaker, keyboard and display. It can send and'
|
||||||
idx = artifact.index(target_line)
|
idx = artifact.index(target_line)
|
||||||
|
|
||||||
testline = r'\\1 of megaphone'
|
testline = r'\1 of megaphone'
|
||||||
testline_after = 'combination of megaphone'
|
testline_after = 'combination of megaphone'
|
||||||
testcase = ('lineinfile', [
|
testcase = ('lineinfile', [
|
||||||
"dest=%s" % sample,
|
"dest=%s" % sample,
|
||||||
|
@ -558,7 +558,7 @@ class TestRunner(unittest.TestCase):
|
||||||
assert target_line not in artifact
|
assert target_line not in artifact
|
||||||
|
|
||||||
# Go again, should be unchanged now.
|
# Go again, should be unchanged now.
|
||||||
testline = r'\\1 of megaphone'
|
testline = r'\1 of megaphone'
|
||||||
testline_after = 'combination of megaphone'
|
testline_after = 'combination of megaphone'
|
||||||
testcase = ('lineinfile', [
|
testcase = ('lineinfile', [
|
||||||
"dest=%s" % sample,
|
"dest=%s" % sample,
|
||||||
|
@ -574,11 +574,11 @@ class TestRunner(unittest.TestCase):
|
||||||
f = open(sample, 'a+')
|
f = open(sample, 'a+')
|
||||||
f.write("1 + 1 = 3" + os.linesep)
|
f.write("1 + 1 = 3" + os.linesep)
|
||||||
f.close()
|
f.close()
|
||||||
testline = r"2 + \\g<num> = 3"
|
testline = r"2 + \g<num> = 3"
|
||||||
testline_after = "2 + 1 = 3"
|
testline_after = "2 + 1 = 3"
|
||||||
testcase = ('lineinfile', [
|
testcase = ('lineinfile', [
|
||||||
"dest=%s" % sample,
|
"dest=%s" % sample,
|
||||||
r"regexp='1 \\+ (?P<num>\\d) = 3'",
|
r"regexp='1 \+ (?P<num>\d) = 3'",
|
||||||
"line='%s'" % testline,
|
"line='%s'" % testline,
|
||||||
"backrefs=yes",
|
"backrefs=yes",
|
||||||
])
|
])
|
||||||
|
|
8
test/inventory_dir/3comments
Normal file
8
test/inventory_dir/3comments
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[major-god] # group with inline comments
|
||||||
|
zeus var_a=1 # host with inline comments
|
||||||
|
# A comment
|
||||||
|
thor
|
||||||
|
|
||||||
|
[minor-god] # group with inline comment and unbalanced quotes: ' "
|
||||||
|
morpheus # host with inline comments and unbalanced quotes: ' "
|
||||||
|
# A comment with unbalanced quotes: ' "
|
Loading…
Reference in a new issue