From 75ceb80572396d6445e3beb7c6a944ce0e3fff7b Mon Sep 17 00:00:00 2001 From: Nicolas Grilly Date: Fri, 24 May 2013 00:59:10 +0200 Subject: [PATCH 01/27] Escape args injected in new style modules --- hacking/test-module | 6 +++--- lib/ansible/runner/__init__.py | 8 +++++--- library/files/lineinfile | 2 +- test/TestRunner.py | 16 ++++++++-------- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/hacking/test-module b/hacking/test-module index 85d3c16a967..ef75eb3d911 100755 --- a/hacking/test-module +++ b/hacking/test-module @@ -85,10 +85,10 @@ def boilerplate_module(modfile, args): if included_boilerplate: 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) - encoded_lang = "\"\"\"%s\"\"\"" % C.DEFAULT_MODULE_LANG - empty_complex = "\"\"\"%s\"\"\"" % "{}" + encoded_lang = repr(C.DEFAULT_MODULE_LANG) + empty_complex = repr("{}") 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(module_common.REPLACER_COMPLEX, empty_complex) diff --git a/lib/ansible/runner/__init__.py b/lib/ansible/runner/__init__.py index 0f9906bb314..006b4991f84 100644 --- a/lib/ansible/runner/__init__.py +++ b/lib/ansible/runner/__init__.py @@ -699,9 +699,11 @@ class Runner(object): module_style = 'non_native_want_json' complex_args_json = utils.jsonify(complex_args) - encoded_args = "\"\"\"%s\"\"\"" % module_args.replace("\"","\\\"") - encoded_lang = "\"\"\"%s\"\"\"" % C.DEFAULT_MODULE_LANG - encoded_complex = "\"\"\"%s\"\"\"" % complex_args_json.replace("\\", "\\\\") + # We force conversion of module_args to str because module_common calls shlex.split, + # a standard library function that incorrectly handles Unicode input before Python 2.7.3. + 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_ARGS, encoded_args) diff --git a/library/files/lineinfile b/library/files/lineinfile index e23748a0e22..7aac8e81c35 100644 --- a/library/files/lineinfile +++ b/library/files/lineinfile @@ -126,7 +126,7 @@ EXAMPLES = r""" 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): diff --git a/test/TestRunner.py b/test/TestRunner.py index cf17e669986..15ed7fbe8aa 100644 --- a/test/TestRunner.py +++ b/test/TestRunner.py @@ -470,7 +470,7 @@ class TestRunner(unittest.TestCase): # The order of the test cases is important # 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', [ "dest=%s" % sample, "regexp='^(First): '", @@ -485,7 +485,7 @@ class TestRunner(unittest.TestCase): # insertafter with EOF # 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', [ "dest=%s" % sample, "insertafter=EOF", @@ -501,7 +501,7 @@ class TestRunner(unittest.TestCase): # with invalid insertafter regex # 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', [ "dest=%s" % sample, "insertafter='^abcdefgh'", @@ -515,7 +515,7 @@ class TestRunner(unittest.TestCase): # with an insertafter regex # 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', [ "dest=%s" % sample, "insertafter='^receive messages to '", @@ -534,7 +534,7 @@ class TestRunner(unittest.TestCase): target_line = 'combination of microphone, speaker, keyboard and display. It can send and' idx = artifact.index(target_line) - testline = r'\\1 of megaphone' + testline = r'\1 of megaphone' testline_after = 'combination of megaphone' testcase = ('lineinfile', [ "dest=%s" % sample, @@ -551,7 +551,7 @@ class TestRunner(unittest.TestCase): assert target_line not in artifact # Go again, should be unchanged now. - testline = r'\\1 of megaphone' + testline = r'\1 of megaphone' testline_after = 'combination of megaphone' testcase = ('lineinfile', [ "dest=%s" % sample, @@ -567,11 +567,11 @@ class TestRunner(unittest.TestCase): f = open(sample, 'a+') f.write("1 + 1 = 3" + os.linesep) f.close() - testline = r"2 + \\g = 3" + testline = r"2 + \g = 3" testline_after = "2 + 1 = 3" testcase = ('lineinfile', [ "dest=%s" % sample, - r"regexp='1 \\+ (?P\\d) = 3'", + r"regexp='1 \+ (?P\d) = 3'", "line='%s'" % testline, "backrefs=yes", ]) From 4c9ebe8522fd8ccd33f9d777a7659f6029ce7da2 Mon Sep 17 00:00:00 2001 From: Serge van Ginderachter Date: Fri, 24 May 2013 22:10:46 +0200 Subject: [PATCH 02/27] Add roles support for the script module allows to put scripts directly in a dir within the role: roles//scripts/.. Same as the copy and template module. As requested in and closes #2969 --- lib/ansible/runner/action_plugins/script.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/ansible/runner/action_plugins/script.py b/lib/ansible/runner/action_plugins/script.py index b86d9c3f1d1..8794c343c50 100644 --- a/lib/ansible/runner/action_plugins/script.py +++ b/lib/ansible/runner/action_plugins/script.py @@ -41,7 +41,10 @@ class ActionModule(object): # FIXME: error handling args = " ".join(tokens[1:]) 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'], 'scripts', source, self.runner.basedir) + else: + source = utils.path_dwim(self.runner.basedir, source) # transfer the file to a remote tmp location source = source.replace('\x00','') # why does this happen here? From 0224dc464dcc8808652d618fd0138ae39bdce3d6 Mon Sep 17 00:00:00 2001 From: Serge van Ginderachter Date: Fri, 24 May 2013 22:42:24 +0200 Subject: [PATCH 03/27] roles/x/scripts support: update docs also added example on where regular tasks fit in --- docsite/latest/rst/bestpractices.rst | 2 ++ docsite/latest/rst/playbooks.rst | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/docsite/latest/rst/bestpractices.rst b/docsite/latest/rst/bestpractices.rst index 1a1d2ea137f..ac66c3ebcd4 100644 --- a/docsite/latest/rst/bestpractices.rst +++ b/docsite/latest/rst/bestpractices.rst @@ -48,6 +48,8 @@ The top level of the directory would contain files and directories like so:: main.yml # <-- tasks file can include smaller files if warranted handlers/ # main.yml # <-- handlers file + scripts/ # + foo.sh # <-- script files for use with the script resource templates/ # <-- files for use with the template resource ntp.conf.j2 # <------- templates end in .j2 files/ # diff --git a/docsite/latest/rst/playbooks.rst b/docsite/latest/rst/playbooks.rst index 451950ad30e..ef63349a674 100644 --- a/docsite/latest/rst/playbooks.rst +++ b/docsite/latest/rst/playbooks.rst @@ -463,12 +463,14 @@ Example project structure:: roles/ common/ files/ + scripts/ templates/ tasks/ handlers/ vars/ webservers/ files/ + scripts/ templates/ tasks/ handlers/ @@ -488,6 +490,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/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 script tasks can reference scripts in roles/x/sripts/ 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, @@ -526,6 +529,8 @@ If you want to define certain tasks to happen before AND after roles are applied - shell: echo 'hello' roles: - { role: some_role } + tasks: + - shell: echo 'still busy' post_tasks: - shell: echo 'goodbye' From 5859af7285e425113b124c58def6939f3911cb4b Mon Sep 17 00:00:00 2001 From: Serge van Ginderachter Date: Sat, 25 May 2013 16:51:59 +0200 Subject: [PATCH 04/27] script support for roles: use the files/ directory instead of an additional scripts/ directory --- docsite/latest/rst/bestpractices.rst | 3 +-- docsite/latest/rst/playbooks.rst | 4 +--- lib/ansible/runner/action_plugins/script.py | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/docsite/latest/rst/bestpractices.rst b/docsite/latest/rst/bestpractices.rst index ac66c3ebcd4..c0afa4488fd 100644 --- a/docsite/latest/rst/bestpractices.rst +++ b/docsite/latest/rst/bestpractices.rst @@ -48,12 +48,11 @@ The top level of the directory would contain files and directories like so:: main.yml # <-- tasks file can include smaller files if warranted handlers/ # main.yml # <-- handlers file - scripts/ # - foo.sh # <-- script files for use with the script resource templates/ # <-- files for use with the template resource ntp.conf.j2 # <------- templates end in .j2 files/ # 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 monitoring/ # "" diff --git a/docsite/latest/rst/playbooks.rst b/docsite/latest/rst/playbooks.rst index ef63349a674..cb403b1ee39 100644 --- a/docsite/latest/rst/playbooks.rst +++ b/docsite/latest/rst/playbooks.rst @@ -463,14 +463,12 @@ Example project structure:: roles/ common/ files/ - scripts/ templates/ tasks/ handlers/ vars/ webservers/ files/ - scripts/ templates/ tasks/ handlers/ @@ -490,7 +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/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 script tasks can reference scripts in roles/x/sripts/ 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 If any files are not present, they are just ignored. So it's ok to not have a 'vars/' subdirectory for the role, diff --git a/lib/ansible/runner/action_plugins/script.py b/lib/ansible/runner/action_plugins/script.py index 8794c343c50..84c0ab015bf 100644 --- a/lib/ansible/runner/action_plugins/script.py +++ b/lib/ansible/runner/action_plugins/script.py @@ -42,7 +42,7 @@ class ActionModule(object): args = " ".join(tokens[1:]) source = template.template(self.runner.basedir, source, inject) if '_original_file' in inject: - source = utils.path_dwim_relative(inject['_original_file'], 'scripts', source, self.runner.basedir) + source = utils.path_dwim_relative(inject['_original_file'], 'files', source, self.runner.basedir) else: source = utils.path_dwim(self.runner.basedir, source) From da5be56b33aad32a3c64816d4469cbbee371370b Mon Sep 17 00:00:00 2001 From: Dylan Silva Date: Mon, 27 May 2013 11:55:29 -0700 Subject: [PATCH 05/27] Pagerduty and Pingdom modules for core --- library/monitoring/pagerduty | 157 +++++++++++++++++++++++++++++++++++ library/monitoring/pingdom | 123 +++++++++++++++++++++++++++ 2 files changed, 280 insertions(+) create mode 100644 library/monitoring/pagerduty create mode 100644 library/monitoring/pingdom diff --git a/library/monitoring/pagerduty b/library/monitoring/pagerduty new file mode 100644 index 00000000000..10309036f43 --- /dev/null +++ b/library/monitoring/pagerduty @@ -0,0 +1,157 @@ +#!/usr/bin/python + +DOCUMENTATION = ''' + +module: pagerduty +short_description: Create PagerDuty maintenance windows +description: + - This module will let you create PagerDuty maintenance windows +version_added: 0.1 +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: [] + version_added: 0.1 + name: + description: + - PagerDuty unique subdomain. + required: true + default: null + choices: [] + aliases: [] + version_added: 0.1 + user: + description: + - PagerDuty user ID. + required: true + default: null + choices: [] + aliases: [] + version_added: 0.1 + passwd: + description: + - PagerDuty user password. + required: true + default: null + choices: [] + aliases: [] + version_added: 0.1 + service: + description: + - PagerDuty service ID. + required: false + default: null + choices: [] + aliases: [] + version_added: 0.1 + hours: + description: + - Length of maintenance window in hours. + required: false + default: 1 + choices: [] + aliases: [] + version_added: 0.1 + desc: + description: + - Short description of maintenance window. + required: false + default: Created by Ansible + choices: [] + aliases: [] + version_added: 0.1 +examples: + - code: pagerduty name=companyabc user=example@example.com passwd=password123 state=ongoing" + description: List ongoing maintenance windows. + - code: pagerduty name=companyabc user=example@example.com passwd=password123 state=running service=FOO123" + description: Create a 1 hour maintenance window for service FOO123. + - code: pagerduty name=companyabc user=example@example.com passwd=password123 state=running service=FOO123 hours=4 desc=deployment" + description: Create a 4 hour maintenance window for service FOO123 with the description "deployment". +notes: + - This module does not yet have support to end maintenance windows. +''' + +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 +#<> +main() diff --git a/library/monitoring/pingdom b/library/monitoring/pingdom new file mode 100644 index 00000000000..2917e504e61 --- /dev/null +++ b/library/monitoring/pingdom @@ -0,0 +1,123 @@ +#!/usr/bin/python + +DOCUMENTATION = ''' + +module: pingdom +short_description: Pause/unpause Pingdom alerts +description: + - This module will let you pause/unpause Pingdom alerts +version_added: 0.1 +author: Justin Johns +requirements: + - pingdom Python library. Install using either of the following: + - pip install pingdom + - easy_install pingdom +options: + state: + description: + - Define whether or not the check should be running or paused. + required: true + default: null + choices: [ "running", "paused" ] + aliases: [] + version_added: 0.1 + checkid: + description: + - Pingdom ID of the check. + required: true + default: null + choices: [] + aliases: [] + version_added: 0.1 + uid: + description: + - Pingdom user ID. + required: true + default: null + choices: [] + aliases: [] + version_added: 0.1 + passwd: + description: + - Pingdom user password. + required: true + default: null + choices: [] + aliases: [] + version_added: 0.1 + key: + description: + - Pingdom API key. + required: true + default: null + choices: [] + aliases: [] + version_added: 0.1 +examples: + - code: pingdom uid=example@example.com passwd=password123 key=apipassword123 checkid=12345 state=paused + description: Pause the check with the ID of 12345. + - code: pingdom uid=example@example.com passwd=password123 key=apipassword123 checkid=12345 state=running + description: Unpause the check with the ID of 12345. +notes: + - This module does not yet have support to add/remove checks. +''' + +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 +#<> +main() From 03e9d9a7423f53e79d58bc7d5e41dd9bd8454ac2 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Tue, 28 May 2013 18:12:33 +0200 Subject: [PATCH 06/27] update info on debian/ubuntu packages --- docsite/latest/rst/gettingstarted.rst | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docsite/latest/rst/gettingstarted.rst b/docsite/latest/rst/gettingstarted.rst index 19ab7e85672..9a06563a012 100644 --- a/docsite/latest/rst/gettingstarted.rst +++ b/docsite/latest/rst/gettingstarted.rst @@ -204,7 +204,15 @@ further information on using Portfiles with MacPorts. Ubuntu and Debian +++++++++++++++++ -Ubuntu builds are available `in a PPA here `_ +Ubuntu builds are available `in a PPA here `_ and in 13.04 via +.. code-block:: bash + + $ sudo apt-get install ansible/raring-backports + +In Debian testing/unstable and Ubntu 13.10+ it is available via +.. code-block:: bach + + $ sudo apt-get install ansible Debian/Ubuntu package recipes can also be built from the source checkout, run: From e13842fad1a5eb395213fd7e107ba5d1b2fbfa8c Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Tue, 28 May 2013 18:23:12 +0200 Subject: [PATCH 07/27] add gathering-facts example --- docsite/latest/rst/examples.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docsite/latest/rst/examples.rst b/docsite/latest/rst/examples.rst index 93ffe624c5b..167dc97d381 100644 --- a/docsite/latest/rst/examples.rst +++ b/docsite/latest/rst/examples.rst @@ -213,6 +213,16 @@ the remote nodes will be terminated. Typically you'll be only be backgrounding long-running shell commands or software upgrades only. Backgrounding the copy module does not do a background file transfer. :doc:`playbooks` also support polling, and have a simplified syntax for this. +Gathering Facts +``````````````` + +For each system facts are gathered. 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 via and export the facts, see the "setup" module documentation for details how to do that. + + Limiting Selected Hosts ``````````````````````` From b625f999388faa697e2ab27528c08e43ff39aecc Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Tue, 28 May 2013 18:25:44 +0200 Subject: [PATCH 08/27] fix typo --- docsite/latest/rst/gettingstarted.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docsite/latest/rst/gettingstarted.rst b/docsite/latest/rst/gettingstarted.rst index 9a06563a012..942604a78f5 100644 --- a/docsite/latest/rst/gettingstarted.rst +++ b/docsite/latest/rst/gettingstarted.rst @@ -210,7 +210,7 @@ Ubuntu builds are available `in a PPA here Date: Tue, 28 May 2013 18:32:14 +0200 Subject: [PATCH 09/27] fix indent --- docsite/latest/rst/examples.rst | 4 ++-- docsite/latest/rst/gettingstarted.rst | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/docsite/latest/rst/examples.rst b/docsite/latest/rst/examples.rst index 167dc97d381..22c8a33eff9 100644 --- a/docsite/latest/rst/examples.rst +++ b/docsite/latest/rst/examples.rst @@ -216,9 +216,9 @@ shell commands or software upgrades only. Backgrounding the copy module does no Gathering Facts ``````````````` -For each system facts are gathered. 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: +For each system facts are gathered. 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 + $ ansible all -m setup Its also possible to filter via and export the facts, see the "setup" module documentation for details how to do that. diff --git a/docsite/latest/rst/gettingstarted.rst b/docsite/latest/rst/gettingstarted.rst index 942604a78f5..99d30e5a4ee 100644 --- a/docsite/latest/rst/gettingstarted.rst +++ b/docsite/latest/rst/gettingstarted.rst @@ -204,15 +204,19 @@ further information on using Portfiles with MacPorts. Ubuntu and Debian +++++++++++++++++ -Ubuntu builds are available `in a PPA here `_ and in 13.04 via +Ubuntu builds are available `in a PPA here `_. + +In Ubuntu 13.04 (raring) its part of the backports repository: + .. code-block:: bash - $ sudo apt-get install ansible/raring-backports + $ 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 + $ sudo apt-get install ansible Debian/Ubuntu package recipes can also be built from the source checkout, run: From 0b53c711a64d3a4b855cdcf5bc7ad074502e38f3 Mon Sep 17 00:00:00 2001 From: Darryl Stoflet Date: Tue, 28 May 2013 23:22:34 -0700 Subject: [PATCH 10/27] Adding monit modules to start/stop/monitor/unmonitor process via monit --- library/monitoring/monit | 146 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 library/monitoring/monit diff --git a/library/monitoring/monit b/library/monitoring/monit new file mode 100644 index 00000000000..de47bc0c264 --- /dev/null +++ b/library/monitoring/monit @@ -0,0 +1,146 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2013, Darryl Stoflet +# +# 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 . +# + +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 +#<> + +main() From f9cff3c4445da18f406a1626c65198ac32554324 Mon Sep 17 00:00:00 2001 From: Stoned Elipot Date: Wed, 29 May 2013 17:05:11 +0200 Subject: [PATCH 11/27] No need to expanduser() command's chdir argument twice --- library/commands/command | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/commands/command b/library/commands/command index e996c0c4a7f..ad6ed6c171e 100644 --- a/library/commands/command +++ b/library/commands/command @@ -95,7 +95,7 @@ def main(): module.fail_json(rc=256, msg="no command given") if chdir: - os.chdir(os.path.expanduser(chdir)) + os.chdir(chdir) if creates: # do not run the command if the line contains creates=filename From bbe352b544917e4733dbfcfdcbdff65056f79d99 Mon Sep 17 00:00:00 2001 From: Lorin Hochstein Date: Wed, 29 May 2013 11:38:11 -0400 Subject: [PATCH 12/27] Document: OpenStack inventory script needs grizzly The OpenStack Inventory script uses the OS-EXT-IPS:type parameter to distinguish between fixed and floating IP addresses. This was only added in the Grizzly release, see https://bugs.launchpad.net/nova/+bug/1117784 Specify in the docs that this inventory script requires Grizzly or greater. --- docsite/latest/rst/api.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docsite/latest/rst/api.rst b/docsite/latest/rst/api.rst index f037b1bc867..3c04c8902ec 100644 --- a/docsite/latest/rst/api.rst +++ b/docsite/latest/rst/api.rst @@ -306,7 +306,8 @@ To see the complete list of variables available for an instance, run the 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 ---------------- From b8045bc29e2d64d7d13d6f9d6a8bfc5780746371 Mon Sep 17 00:00:00 2001 From: Chelsea Robb Date: Thu, 30 May 2013 08:05:14 +1000 Subject: [PATCH 13/27] Updated loop documentation with explicit example of hash usage --- docsite/latest/rst/playbooks2.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docsite/latest/rst/playbooks2.rst b/docsite/latest/rst/playbooks2.rst index 5309e43eef9..a5075105cf1 100644 --- a/docsite/latest/rst/playbooks2.rst +++ b/docsite/latest/rst/playbooks2.rst @@ -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. 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 ``````````````````````````````````````` From 33870745b1a1a5b528826e88e8b982cdc1a75640 Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Wed, 29 May 2013 17:14:20 -0500 Subject: [PATCH 14/27] fix ambiguous use of automatically automatic in Roles docs --- docsite/latest/rst/playbooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docsite/latest/rst/playbooks.rst b/docsite/latest/rst/playbooks.rst index 80c49569f8f..fcf87cf2b9b 100644 --- a/docsite/latest/rst/playbooks.rst +++ b/docsite/latest/rst/playbooks.rst @@ -449,7 +449,7 @@ Roles .. versionadded: 1.2 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. Roles are just automation around 'include' directives as redescribed above, and really don't contain much From 0a28358ebcf1f78b294674dae3b2635c03eeef90 Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Wed, 29 May 2013 18:27:16 -0400 Subject: [PATCH 15/27] Minor docs tweak. --- docsite/latest/rst/examples.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docsite/latest/rst/examples.rst b/docsite/latest/rst/examples.rst index 22c8a33eff9..4c8abf7d2e7 100644 --- a/docsite/latest/rst/examples.rst +++ b/docsite/latest/rst/examples.rst @@ -216,11 +216,12 @@ shell commands or software upgrades only. Backgrounding the copy module does no Gathering Facts ``````````````` -For each system facts are gathered. 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:: +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 via and export the facts, see the "setup" module documentation for details how to do that. +Its also possible to filter this output to just export certain facts, see the "setup" module documentation for details. Limiting Selected Hosts From 80bf5d49fe598b401ba579c881b2760a6403330a Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Wed, 29 May 2013 17:29:59 -0500 Subject: [PATCH 16/27] provide link to older docs when mentioning older docs --- docsite/latest/rst/playbooks2.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docsite/latest/rst/playbooks2.rst b/docsite/latest/rst/playbooks2.rst index 5309e43eef9..da78d4b449b 100644 --- a/docsite/latest/rst/playbooks2.rst +++ b/docsite/latest/rst/playbooks2.rst @@ -262,8 +262,8 @@ Conditional Execution ````````````````````` (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 -in 1.2, although the new mechanisms are cleaner.) +the previous version of the documentation, `Ansible 1.1 Docs `_ . +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 as simple as not installing a certain package if the operating system is a particular version, From f7cabfe64edfbdf9e095a193b71b265a5be643e4 Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Wed, 29 May 2013 18:34:38 -0400 Subject: [PATCH 17/27] use EXAMPLES vs inline examples (easier to format) --- library/monitoring/pagerduty | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/library/monitoring/pagerduty b/library/monitoring/pagerduty index 10309036f43..79ce307d91f 100644 --- a/library/monitoring/pagerduty +++ b/library/monitoring/pagerduty @@ -67,17 +67,21 @@ options: choices: [] aliases: [] version_added: 0.1 -examples: - - code: pagerduty name=companyabc user=example@example.com passwd=password123 state=ongoing" - description: List ongoing maintenance windows. - - code: pagerduty name=companyabc user=example@example.com passwd=password123 state=running service=FOO123" - description: Create a 1 hour maintenance window for service FOO123. - - code: pagerduty name=companyabc user=example@example.com passwd=password123 state=running service=FOO123 hours=4 desc=deployment" - description: Create a 4 hour maintenance window for service FOO123 with the description "deployment". 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 From 5e8923c04f794b735203a6e8b24140da631378b8 Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Wed, 29 May 2013 18:35:36 -0400 Subject: [PATCH 18/27] use EXAMPLES vs examples (easier to format) --- library/monitoring/pingdom | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/library/monitoring/pingdom b/library/monitoring/pingdom index 2917e504e61..94ea6abd5a8 100644 --- a/library/monitoring/pingdom +++ b/library/monitoring/pingdom @@ -53,15 +53,18 @@ options: choices: [] aliases: [] version_added: 0.1 -examples: - - code: pingdom uid=example@example.com passwd=password123 key=apipassword123 checkid=12345 state=paused - description: Pause the check with the ID of 12345. - - code: pingdom uid=example@example.com passwd=password123 key=apipassword123 checkid=12345 state=running - description: Unpause the check with the ID of 12345. 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 From 250bcaff037492fa4a90347fcf1cc155521e6324 Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Wed, 29 May 2013 18:37:31 -0400 Subject: [PATCH 19/27] Fix docs build causing parse error message. --- library/monitoring/pingdom | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/monitoring/pingdom b/library/monitoring/pingdom index 94ea6abd5a8..cb31f8bb6cd 100644 --- a/library/monitoring/pingdom +++ b/library/monitoring/pingdom @@ -9,9 +9,7 @@ description: version_added: 0.1 author: Justin Johns requirements: - - pingdom Python library. Install using either of the following: - - pip install pingdom - - easy_install pingdom + - "pingdom python library" options: state: description: From 44e32cc45e6c721c37f5c90b339d2ffc83ba1e41 Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Wed, 29 May 2013 18:43:23 -0400 Subject: [PATCH 20/27] Some formatting fixes so docs will build, etc. --- lib/ansible/utils/module_docs.py | 1 + library/cloud/quantum_floating_ip_associate | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/ansible/utils/module_docs.py b/lib/ansible/utils/module_docs.py index 57d914cfbe4..afa4c6536ed 100755 --- a/lib/ansible/utils/module_docs.py +++ b/lib/ansible/utils/module_docs.py @@ -49,6 +49,7 @@ def get_docstring(filename, verbose=False): if 'EXAMPLES' in (t.id for t in child.targets): plainexamples = child.value.s[1:] # Skip first empty line except: + traceback.print_exc() # temp if verbose == True: traceback.print_exc() print "unable to parse %s" % filename diff --git a/library/cloud/quantum_floating_ip_associate b/library/cloud/quantum_floating_ip_associate index a20d9974edf..d39155aca91 100644 --- a/library/cloud/quantum_floating_ip_associate +++ b/library/cloud/quantum_floating_ip_associate @@ -22,7 +22,7 @@ try: from keystoneclient.v2_0 import client as ksclient import time 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 = ''' --- @@ -130,9 +130,7 @@ def _get_server_state(module, nova): return server_info, server def _get_port_id(quantum, module, instance_id): - kwargs = { - device_id': instance_id, - } + kwargs = dict(device_id = instance_id) try: ports = quantum.list_ports(**kwargs) except Exception as e: From 07361375b50445cc7f1b9a6e0f165019579eeedf Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Wed, 29 May 2013 18:56:34 -0400 Subject: [PATCH 21/27] Fix version added field in modules. --- library/monitoring/pagerduty | 9 +-------- library/monitoring/pingdom | 7 +------ 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/library/monitoring/pagerduty b/library/monitoring/pagerduty index 79ce307d91f..200d45b0491 100644 --- a/library/monitoring/pagerduty +++ b/library/monitoring/pagerduty @@ -6,7 +6,7 @@ module: pagerduty short_description: Create PagerDuty maintenance windows description: - This module will let you create PagerDuty maintenance windows -version_added: 0.1 +version_added: "1.2" author: Justin Johns requirements: - PagerDuty API access @@ -18,7 +18,6 @@ options: default: null choices: [ "running", "started", "ongoing" ] aliases: [] - version_added: 0.1 name: description: - PagerDuty unique subdomain. @@ -26,7 +25,6 @@ options: default: null choices: [] aliases: [] - version_added: 0.1 user: description: - PagerDuty user ID. @@ -34,7 +32,6 @@ options: default: null choices: [] aliases: [] - version_added: 0.1 passwd: description: - PagerDuty user password. @@ -42,7 +39,6 @@ options: default: null choices: [] aliases: [] - version_added: 0.1 service: description: - PagerDuty service ID. @@ -50,7 +46,6 @@ options: default: null choices: [] aliases: [] - version_added: 0.1 hours: description: - Length of maintenance window in hours. @@ -58,7 +53,6 @@ options: default: 1 choices: [] aliases: [] - version_added: 0.1 desc: description: - Short description of maintenance window. @@ -66,7 +60,6 @@ options: default: Created by Ansible choices: [] aliases: [] - version_added: 0.1 notes: - This module does not yet have support to end maintenance windows. ''' diff --git a/library/monitoring/pingdom b/library/monitoring/pingdom index cb31f8bb6cd..5e566e6dc4d 100644 --- a/library/monitoring/pingdom +++ b/library/monitoring/pingdom @@ -6,7 +6,7 @@ module: pingdom short_description: Pause/unpause Pingdom alerts description: - This module will let you pause/unpause Pingdom alerts -version_added: 0.1 +version_added: "1.2" author: Justin Johns requirements: - "pingdom python library" @@ -18,7 +18,6 @@ options: default: null choices: [ "running", "paused" ] aliases: [] - version_added: 0.1 checkid: description: - Pingdom ID of the check. @@ -26,7 +25,6 @@ options: default: null choices: [] aliases: [] - version_added: 0.1 uid: description: - Pingdom user ID. @@ -34,7 +32,6 @@ options: default: null choices: [] aliases: [] - version_added: 0.1 passwd: description: - Pingdom user password. @@ -42,7 +39,6 @@ options: default: null choices: [] aliases: [] - version_added: 0.1 key: description: - Pingdom API key. @@ -50,7 +46,6 @@ options: default: null choices: [] aliases: [] - version_added: 0.1 notes: - This module does not yet have support to add/remove checks. ''' From 316310968172a7a2bd2c8bd1613e52340651eff1 Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Wed, 29 May 2013 19:01:01 -0400 Subject: [PATCH 22/27] Update changelog --- CHANGELOG.md | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index acae7442156..7fe362f91ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,22 +26,20 @@ Core Features: Modules added: -* rax: module for creating instances in the rackspace cloud (uses pyrax) -* npm: node.js package management -* postgresql_priv: manages postgresql priveledges -* set_fact: sets a variable, which can be the result of a template evaluation -* hipchat: send notification events to hipchat -* ec2_elb: add and remove machines from ec2 elastic load balancers -* flowdock: send messages to flowdock during playbook runs -* pkgng: next-gen package manager for FreeBSD -* bigip_pool: load balancing with F5s -* newrelic_deployment: notifies newrelic of new deployments -* campfire: send messages to campfire during playbook runs -* mqtt: send messages to the Mosquitto message bus -* irc: send messages to IRC channels -* filesystem - a wrapper around mkfs -* jabber: send jabber chat messages -* osx_say: make OS X say things out loud +* cloud: rax: module for creating instances in the rackspace cloud (uses pyrax) +* packages: npm: node.js package management +* packages: pkgng: next-gen package manager for FreeBSD +* database: postgresql_priv: manages postgresql priveledges +* networking: bigip_pool: load balancing with F5s +* networking: ec2_elb: add and remove machines from ec2 elastic load balancers +* notification: hipchat: send notification events to hipchat +* notification: flowdock: send messages to flowdock during playbook runs +* notification: campfire: send messages to campfire during playbook runs +* notification: mqtt: send messages to the Mosquitto message bus +* notification: irc: send messages to IRC channels +* notification: filesystem - a wrapper around mkfs +* notification: jabber: send jabber chat messages +* notification: osx_say: make OS X say things out loud * openstack: keystone_user * openstack: glance_image * openstack: nova_compute @@ -53,7 +51,12 @@ Modules added: * openstack: quantum_router_gateway * openstack: quantum_router_interface * 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 @@ -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 * 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 -* +* improved NetBSD and Solaris facts +* debug module always outputs data without having to specify -v 1.1 "Mean Street" -- 4/2/2013 From 5cb0525430f0c53844656f6647c6dd47a5d2ec94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jir=CC=8Ci=CC=81=20Kubi=CC=81c=CC=8Cek?= Date: Thu, 30 May 2013 01:05:14 +0200 Subject: [PATCH 23/27] Add some FreeBSD facts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit added: * ansible_distribution * ansible_distribution_release * ansible_distribution_version * ansible_os_family * ansible_pkg_mgr * ansible_ssh_host_key_ecdsa_public Also adds ECDSA public key for all plaforms. --- CHANGELOG.md | 2 +- library/system/setup | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fe362f91ca..162fda7fcb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -122,7 +122,7 @@ the variable is still registered for the host, with the attribute skipped: True. * pip works better when sudoing from unpriveledged users * 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 -* improved NetBSD and Solaris facts +* improved FreeBSD, NetBSD and Solaris facts * debug module always outputs data without having to specify -v 1.1 "Mean Street" -- 4/2/2013 diff --git a/library/system/setup b/library/system/setup index 15a593b2666..5e4c76c3f3c 100644 --- a/library/system/setup +++ b/library/system/setup @@ -121,6 +121,7 @@ class Facts(object): { 'path' : '/opt/local/bin/pkgin', 'name' : 'pkgin' }, { 'path' : '/opt/local/bin/port', 'name' : 'macports' }, { 'path' : '/sbin/apk', 'name' : 'apk' }, + { 'path' : '/usr/sbin/pkg', 'name' : 'pkgng' }, ] def __init__(self): @@ -175,7 +176,8 @@ class Facts(object): SLED = 'Suse', OpenSuSE = 'Suse', SuSE = 'Suse', Gentoo = 'Gentoo', Archlinux = 'Archlinux', Mandriva = 'Mandrake', Mandrake = 'Mandrake', 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': @@ -189,6 +191,10 @@ class Facts(object): rc, out, err = module.run_command("/usr/bin/sw_vers -productVersion") data = out.split()[-1] 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: dist = platform.dist() self.facts['distribution'] = dist[0].capitalize() or 'NA' @@ -245,12 +251,15 @@ class Facts(object): def get_public_ssh_host_keys(self): dsa_filename = '/etc/ssh/ssh_host_dsa_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': dsa_filename = '/etc/ssh_host_dsa_key.pub' rsa_filename = '/etc/ssh_host_rsa_key.pub' + ecdsa_filename = '/etc/ssh_host_ecdsa_key.pub' dsa = get_file_content(dsa_filename) rsa = get_file_content(rsa_filename) + ecdsa = get_file_content(ecdsa_filename) if dsa is None: dsa = 'NA' else: @@ -259,6 +268,10 @@ class Facts(object): rsa = 'NA' else: 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): self.facts['pkg_mgr'] = 'unknown' From 18f8fe11495d2d99e6a5101826116937792d4c79 Mon Sep 17 00:00:00 2001 From: Mark Mandel Date: Thu, 30 May 2013 14:16:58 +1000 Subject: [PATCH 24/27] Update vagrant external inventory file to handle multiple boxes, and --list and --host params. --- plugins/inventory/vagrant.py | 132 +++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100755 plugins/inventory/vagrant.py diff --git a/plugins/inventory/vagrant.py b/plugins/inventory/vagrant.py new file mode 100755 index 00000000000..ea59a7bc023 --- /dev/null +++ b/plugins/inventory/vagrant.py @@ -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 +# +# 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 . + +# +# 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 ") +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) \ No newline at end of file From 3127bab6d60a921ddf57a840fc2fad6611fffa17 Mon Sep 17 00:00:00 2001 From: Stephen Fromm Date: Thu, 30 May 2013 10:09:11 -0700 Subject: [PATCH 25/27] Use get_bin_path to find mkfs command (issue #2983) --- library/system/filesystem | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/system/filesystem b/library/system/filesystem index 5a78c1c3945..b958f100e5c 100755 --- a/library/system/filesystem +++ b/library/system/filesystem @@ -88,11 +88,12 @@ def main(): if module.check_mode: changed = True else: + mkfs = module.get_bin_path('mkfs', required=True) cmd = None if opts is None: - cmd = "mkfs -t %s '%s'"%(fstype, dev) + cmd = "%s -t %s '%s'" % (mkfs, fstype, dev) 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) if rc == 0: changed = True From 00b3a450c7764cd1d5bc3eac0f909141acbe65c6 Mon Sep 17 00:00:00 2001 From: Stephen Fromm Date: Thu, 30 May 2013 10:15:40 -0700 Subject: [PATCH 26/27] Verify /proc/modules is readable (issue #2990) --- library/system/setup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/system/setup b/library/system/setup index 5e4c76c3f3c..f8f7926e840 100644 --- a/library/system/setup +++ b/library/system/setup @@ -1633,7 +1633,7 @@ class LinuxVirtual(Virtual): return # 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 = [] for line in open("/proc/modules").readlines(): data = line.split(" ", 1) From ba78360c528df5c42cbb5a6c6b2e1f01ab9eace6 Mon Sep 17 00:00:00 2001 From: Pol Llovet Date: Thu, 30 May 2013 14:12:23 -0600 Subject: [PATCH 27/27] Remove inline comments from inventory tokenizing. --- lib/ansible/inventory/ini.py | 4 ++-- test/inventory_dir/3comments | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 test/inventory_dir/3comments diff --git a/lib/ansible/inventory/ini.py b/lib/ansible/inventory/ini.py index 78d5743fa3a..314f2c7cd96 100644 --- a/lib/ansible/inventory/ini.py +++ b/lib/ansible/inventory/ini.py @@ -65,7 +65,7 @@ class InventoryParser(object): for line in self.lines: 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: active_group_name = active_group_name.rsplit(":", 1)[0] if active_group_name not in self.groups: @@ -78,7 +78,7 @@ class InventoryParser(object): elif line.startswith("#") or line == '': pass elif active_group_name: - tokens = shlex.split(line) + tokens = shlex.split(line.split("#")[0]) if len(tokens) == 0: continue hostname = tokens[0] diff --git a/test/inventory_dir/3comments b/test/inventory_dir/3comments new file mode 100644 index 00000000000..02ff6ec000b --- /dev/null +++ b/test/inventory_dir/3comments @@ -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: ' "