Compare commits

...

6 Commits

13 changed files with 190 additions and 52 deletions

View File

@ -1,7 +1,14 @@
Ansible Changes By Release
==========================
## 1.6 "And the Cradle Will Rock" - Active Development
## 1.6.1 "And the Cradle Will Rock" - May 7, 2014
- Fixed a bug in group_by, where systems were being grouped incorrectly.
- Fixed a bug where file descriptors may leak to a child process when using accelerate.
- Fixed a bug in apt_repository triggered when python-apt not being installed/available.
- Fixed a bug in the apache2_module module, where modules were not being disabled correctly.
## 1.6 "And the Cradle Will Rock" - May 5, 2014
Major features/changes:

View File

@ -1,21 +1,13 @@
Ansible Releases at a Glance
============================
Future
++++++
1.7 "Summer Nights" -------- SUMMER 2014
Active Development
++++++++++++++++++
1.6 "The Cradle Will Rock" - CURRENT DEVEL BRANCH
1.7 "Summer Nights" -------- CURRENT DEVEL BRANCH
Previous
++++++++
=======
1.6 "The Cradle Will Rock" - NEXT
1.6.1 "The Cradle Will Rock" - 05-07-2014
1.6 "The Cradle Will Rock" - 05-05-2014
1.5.5 "Love Walks In" -------- 04-18-2014
1.5.4 "Love Walks In" -------- 04-01-2014
1.5.3 "Love Walks In" -------- 03-13-2014

View File

@ -1 +1 @@
1.6
1.6.1

View File

@ -14,5 +14,5 @@
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
__version__ = '1.6'
__version__ = '1.6.1'
__author__ = 'Michael DeHaan'

View File

@ -38,6 +38,8 @@ class ActionModule(object):
# the group_by module does not need to pay attention to check mode.
# it always runs.
# module_args and complex_args have already been templated for the first host.
# Use them here only to check that a key argument is provided.
args = {}
if complex_args:
args.update(complex_args)
@ -68,7 +70,16 @@ class ActionModule(object):
break
if next_host:
continue
group_name = template.template(self.runner.basedir, args['key'], data)
# Template original module_args and complex_args from runner for each host.
host_module_args = template.template(self.runner.basedir, self.runner.module_args, data)
host_complex_args = template.template(self.runner.basedir, self.runner.complex_args, data)
host_args = {}
if host_complex_args:
host_args.update(host_complex_args)
host_args.update(parse_kv(host_module_args))
group_name = host_args['key']
group_name = group_name.replace(' ','-')
if group_name not in groups:
groups[group_name] = []

View File

@ -83,10 +83,11 @@ import tempfile
try:
import apt
import apt_pkg
import aptsources.distro
distro = aptsources.distro.get_distro()
import aptsources.distro as aptsources_distro
distro = aptsources_distro.get_distro()
HAVE_PYTHON_APT = True
except ImportError:
distro = None
HAVE_PYTHON_APT = False
@ -97,11 +98,16 @@ def install_python_apt(module):
if not module.check_mode:
apt_get_path = module.get_bin_path('apt-get')
if apt_get_path:
rc, so, se = module.run_command('%s update && %s install python-apt -y -q' % (apt_get_path, apt_get_path))
rc, so, se = module.run_command('%s update && %s install python-apt -y -q' % (apt_get_path, apt_get_path), use_unsafe_shell=True)
if rc == 0:
global apt, apt_pkg
global apt, apt_pkg, aptsources_distro, distro, HAVE_PYTHON_APT
import apt
import apt_pkg
import aptsources.distro as aptsources_distro
distro = aptsources_distro.get_distro()
HAVE_PYTHON_APT = True
else:
module.fail_json(msg="Failed to auto-install python-apt. Error was: '%s'" % se.strip())
class InvalidSource(Exception):
pass
@ -382,14 +388,16 @@ def main():
update_cache = module.params['update_cache']
sourceslist = None
if isinstance(distro, aptsources.distro.UbuntuDistribution):
sourceslist = UbuntuSourcesList(module,
add_ppa_signing_keys_callback=get_add_ppa_signing_key_callback(module))
elif isinstance(distro, aptsources.distro.DebianDistribution) or \
isinstance(distro, aptsources.distro.Distribution):
sourceslist = SourcesList()
if HAVE_PYTHON_APT:
if isinstance(distro, aptsources_distro.UbuntuDistribution):
sourceslist = UbuntuSourcesList(module,
add_ppa_signing_keys_callback=get_add_ppa_signing_key_callback(module))
elif HAVE_PYTHON_APT and \
isinstance(distro, aptsources_distro.DebianDistribution) or isinstance(distro, aptsources_distro.Distribution):
sourceslist = SourcesList()
else:
module.fail_json(msg='Module apt_repository supports only Debian and Ubuntu.')
module.fail_json(msg='Module apt_repository supports only Debian and Ubuntu. ' + \
'You may be seeing this because python-apt is not installed, but you requested that it not be auto-installed')
sources_before = sourceslist.dump()

View File

@ -479,7 +479,7 @@ class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
if executable:
use_unsafe_shell = True
rc, stdout, stderr = self.server.module.run_command(data['cmd'], executable=executable, use_unsafe_shell=use_unsafe_shell)
rc, stdout, stderr = self.server.module.run_command(data['cmd'], executable=executable, use_unsafe_shell=use_unsafe_shell, close_fds=True)
if stdout is None:
stdout = ''
if stderr is None:

View File

@ -1,7 +1,7 @@
#!/usr/bin/python
#coding: utf-8 -*-
# (c) 2013, Christian Berendt <berendt@b1-systems.de>
# (c) 2013-2014, Christian Berendt <berendt@b1-systems.de>
#
# This module is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -44,39 +44,31 @@ EXAMPLES = '''
- apache2_module: state=absent name=wsgi
'''
def _module_is_enabled(module):
name = module.params['name']
a2enmod_binary = module.get_bin_path("a2enmod")
result, stdout, stderr = module.run_command("%s -q %s" % (a2enmod_binary, name))
return result == 0
def _module_is_disabled(module):
return _module_is_enabled(module) == False
import re
def _disable_module(module):
name = module.params['name']
a2dismod_binary = module.get_bin_path("a2dismod")
result, stdout, stderr = module.run_command("%s %s" % (a2dismod_binary, name))
if _module_is_disabled(module):
if re.match(r'.*already disabled.*', stdout):
module.exit_json(changed = False, result = "Success")
result, stdout, stderr = module.run_command("a2dismod %s" % name)
if result != 0:
elif result != 0:
module.fail_json(msg="Failed to disable module %s: %s" % (name, stdout))
module.exit_json(changed = True, result = "Disabled")
else:
module.exit_json(changed = True, result = "Disabled")
def _enable_module(module):
name = module.params['name']
if _module_is_enabled(module):
module.exit_json(changed = False, result = "Success")
a2enmod_binary = module.get_bin_path("a2enmod")
result, stdout, stderr = module.run_command("%s %s" % (a2enmod_binary, name))
if result != 0:
module.fail_json(msg="Failed to enable module %s: %s" % (name, stdout))
module.exit_json(changed = True, result = "Enabled")
if re.match(r'.*already enabled.*', stdout):
module.exit_json(changed = False, result = "Success")
elif result != 0:
module.fail_json(msg="Failed to enable module %s: %s" % (name, stdout))
else:
module.exit_json(changed = True, result = "Enabled")
def main():
module = AnsibleModule(
@ -95,4 +87,3 @@ def main():
# import module snippets
from ansible.module_utils.basic import *
main()

View File

@ -1,3 +1,9 @@
ansible (1.6.1) unstable; urgency=low
* 1.6.1 release
-- Michael DeHaan <michael.dehaan@gmail.com> Wed, 07 May 2014 13:30:00 -0500
ansible (1.6) unstable; urgency=low
* 1.6.0 release

View File

@ -5,7 +5,7 @@
%endif
Name: %{name}
Version: 1.6
Version: 1.6.1
Release: 1%{?dist}
Url: http://www.ansible.com
Summary: SSH-based application deployment, configuration management, and IT orchestration platform
@ -114,6 +114,9 @@ rm -rf %{buildroot}
%changelog
* Wed May 07 2014 Michael DeHaan <michael@ansible.com> - 1.6.1
- Release 1.6.1
* Mon May 05 2014 Michael DeHaan <michael@ansible.com> - 1.6.0
- Release 1.6.0

View File

@ -14,7 +14,7 @@ else
CREDENTIALS_ARG =
endif
all: non_destructive destructive check_mode test_hash test_handlers
all: non_destructive destructive check_mode test_hash test_handlers test_group_by
non_destructive:
ansible-playbook non_destructive.yml -i $(INVENTORY) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v $(TEST_FLAGS)
@ -25,6 +25,9 @@ destructive:
check_mode:
ansible-playbook check_mode.yml -i $(INVENTORY) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v --check $(TEST_FLAGS)
test_group_by:
ansible-playbook test_group_by.yml -i inventory.group_by -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v $(TEST_FLAGS)
test_handlers:
ansible-playbook test_handlers.yml -i inventory.handlers -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v $(TEST_FLAGS)

View File

@ -0,0 +1,6 @@
[lamini]
alpaca genus=vicugna
llama genus=lama
[lamini:vars]
ansible_connection=local

View File

@ -0,0 +1,111 @@
# test code for the group_by module
# (c) 2014, Chris Church <cchurch@ansible.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/>.
- hosts: lamini
gather_facts: false
tasks:
- name: group by genus
group_by: key={{ genus }}
- name: group by first three letters of genus with key in quotes
group_by: key="{{ genus | truncate(3, true, '') }}"
- name: group by first two letters of genus with key not in quotes
group_by: key={{ genus | truncate(2, true, '') }}
- name: group by genus in uppercase using complex args
group_by: { key: "{{ genus | upper() }}" }
- hosts: vicugna
gather_facts: false
tasks:
- name: verify that only the alpaca is in this group
assert: { that: "inventory_hostname == 'alpaca'" }
- name: set a fact to check that we ran this play
set_fact: genus_vicugna=true
- hosts: lama
gather_facts: false
tasks:
- name: verify that only the llama is in this group
assert: { that: "inventory_hostname == 'llama'" }
- name: set a fact to check that we ran this play
set_fact: genus_lama=true
- hosts: vic
gather_facts: false
tasks:
- name: verify that only the alpaca is in this group
assert: { that: "inventory_hostname == 'alpaca'" }
- name: set a fact to check that we ran this play
set_fact: genus_vic=true
- hosts: lam
gather_facts: false
tasks:
- name: verify that only the llama is in this group
assert: { that: "inventory_hostname == 'llama'" }
- name: set a fact to check that we ran this play
set_fact: genus_lam=true
- hosts: vi
gather_facts: false
tasks:
- name: verify that only the alpaca is in this group
assert: { that: "inventory_hostname == 'alpaca'" }
- name: set a fact to check that we ran this play
set_fact: genus_vi=true
- hosts: la
gather_facts: false
tasks:
- name: verify that only the llama is in this group
assert: { that: "inventory_hostname == 'llama'" }
- name: set a fact to check that we ran this play
set_fact: genus_la=true
- hosts: VICUGNA
gather_facts: false
tasks:
- name: verify that only the alpaca is in this group
assert: { that: "inventory_hostname == 'alpaca'" }
- name: set a fact to check that we ran this play
set_fact: genus_VICUGNA=true
- hosts: LAMA
gather_facts: false
tasks:
- name: verify that only the llama is in this group
assert: { that: "inventory_hostname == 'llama'" }
- name: set a fact to check that we ran this play
set_fact: genus_LAMA=true
- hosts: '{{genus'
gather_facts: false
tasks:
- name: no hosts should match this group
fail: msg="should never get here"
- hosts: alpaca
gather_facts: false
tasks:
- name: check that alpaca matched all four groups
assert: { that: ["genus_vicugna", "genus_vic", "genus_vi", "genus_VICUGNA"] }
- hosts: llama
gather_facts: false
tasks:
- name: check that llama matched all four groups
assert: { that: ["genus_lama", "genus_lam", "genus_la", "genus_LAMA"] }