Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assemble module #463

Merged
merged 1 commit into from
Jun 14, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 16 additions & 0 deletions lib/ansible/runner/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,20 @@ def _execute_template(self, conn, tmp):

# *****************************************************

def _execute_assemble(self, conn, tmp):
''' handler for assemble operations '''
module_name = 'assemble'
options = utils.parse_kv(self.module_args)
module = self._transfer_module(conn, tmp, module_name)
exec_rc = self._execute_module(conn, tmp, module, self.module_args)

if exec_rc.is_successful():
return self._chain_file_module(conn, tmp, exec_rc, options)
else:
return exec_rc

# *****************************************************

def _executor(self, host):
try:
exec_rc = self._executor_internal(host)
Expand Down Expand Up @@ -656,6 +670,8 @@ def _executor_internal(self, host):
result = self._execute_template(conn, tmp)
elif self.module_name == 'raw':
result = self._execute_raw(conn, tmp)
elif self.module_name == 'assemble':
result = self._execute_assemble(conn, tmp)
else:
if self.background == 0:
result = self._execute_normal_module(conn, tmp, module_name)
Expand Down
111 changes: 111 additions & 0 deletions library/assemble
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#!/usr/bin/python

# (c) 2012, Stephen Fromm <sfromm@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/>.

try:
import json
except ImportError:
import simplejson as json
import os
import os.path
import md5
import sys
import shlex
import shutil
import syslog
import tempfile

# Since hashlib is only available in 2.5 and onwards, this module
# uses md5 which is available in 2.4.

# ===========================================
# Support methods

def exit_json(rc=0, **kwargs):
print json.dumps(kwargs)
sys.exit(rc)

def fail_json(**kwargs):
kwargs['failed'] = True
exit_json(rc=1, **kwargs)

def assemble_from_fragments(path):
''' assemble a file from a directory of fragments '''
assembled = []
for f in sorted(os.listdir(path)):
fragment = "%s/%s" % (path, f)
if os.path.isfile(fragment):
assembled.append(file(fragment).read())
return "".join(assembled)

def write_temp_file(data):
fd, path = tempfile.mkstemp()
os.write(fd, data)
os.close(fd)
return path

# ===========================================

if len(sys.argv) == 1:
fail_json(msg="the assemble module requires arguments (-a)")

argfile = sys.argv[1]
if not os.path.exists(argfile):
fail_json(msg="Argument file not found")

args = open(argfile, 'r').read()
items = shlex.split(args)
syslog.openlog('ansible-%s' % os.path.basename(__file__))
syslog.syslog(syslog.LOG_NOTICE, 'Invoked with %s' % args)

if not len(items):
fail_json(msg="the assemble module requires arguments (-a)")

params = {}
for x in items:
(k, v) = x.split("=")
params[k] = v

changed = False
pathmd5 = None
destmd5 = None
src = params.get('src', None)
dest = params.get('dest', None)

if src:
src = os.path.expanduser(src)
if dest:
dest = os.path.expanduser(dest)

if not os.path.exists(src):
fail_json(msg="Source (%s) does not exist" % src)

if not os.path.isdir(src):
fail_json(msg="Source (%s) is not a directory" % src)

path = write_temp_file(assemble_from_fragments(src))
pathmd5 = md5.new(file(path).read()).hexdigest()

if os.path.exists(dest):
destmd5 = md5.new(file(dest).read()).hexdigest()

if pathmd5 != destmd5:
shutil.copy(path, dest)
changed = True

exit_json(md5sum=pathmd5, changed=changed)
23 changes: 23 additions & 0 deletions test/TestRunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,5 +231,28 @@ def test_git(self):
def test_service(self):
# TODO: tests for the service module
pass
def test_assemble(self):
input = self._get_test_file('assemble.d')
metadata = self._get_test_file('metadata.json')
output = self._get_stage_file('sample.out')
result = self._run('assemble', [
"src=%s" % input,
"dest=%s" % output,
"metadata=%s" % metadata
])
assert os.path.exists(output)
out = file(output).read()
assert out.find("first") != -1
assert out.find("second") != -1
assert out.find("third") != -1
assert result['changed'] == True
assert 'md5sum' in result
assert 'failed' not in result
result = self._run('assemble', [
"src=%s" % input,
"dest=%s" % output,
"metadata=%s" % metadata
])
assert result['changed'] == False


2 changes: 2 additions & 0 deletions test/assemble.d/00-source.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# This is the first comment.
[somegroup]
2 changes: 2 additions & 0 deletions test/assemble.d/01-source.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# This is the second comment.
127.0.0.2
4 changes: 4 additions & 0 deletions test/assemble.d/02.source.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# This is the third comment.
[somegroup:vars]
foo=bar
# 無 可 無 非 常 無