Merge branch 'integration'
Conflicts: lib/ansible/playbook.py lib/ansible/runner.py library/apt
This commit is contained in:
commit
f4bca7ea22
7 changed files with 404 additions and 161 deletions
57
apt
57
apt
|
@ -42,7 +42,7 @@ def fail_json(**kwargs):
|
|||
exit_json(rc=1, **kwargs)
|
||||
|
||||
try:
|
||||
import apt
|
||||
import apt, apt_pkg
|
||||
except ImportError:
|
||||
fail_json(msg="could not import apt, please install the python-apt package on this host")
|
||||
|
||||
|
@ -63,17 +63,30 @@ def run_apt(command):
|
|||
rc = cmd.returncode
|
||||
return rc, out, err
|
||||
|
||||
def package_status(pkgspec, cache):
|
||||
try:
|
||||
pkg = cache[pkgspec]
|
||||
except:
|
||||
fail_json(msg="No package matching '%s' is available" % pkgspec)
|
||||
return (pkg.is_installed, pkg.is_upgradable)
|
||||
def package_split(pkgspec):
|
||||
parts = pkgspec.split('=')
|
||||
if len(parts) > 1:
|
||||
return parts[0], parts[1]
|
||||
else:
|
||||
return parts[0], None
|
||||
|
||||
def install(pkgspec, cache, upgrade=False):
|
||||
(installed, upgradable) = package_status(pkgspec, cache)
|
||||
if (not installed) or (upgrade and upgradable):
|
||||
def package_status(pkgname, version, cache):
|
||||
try:
|
||||
pkg = cache[pkgname]
|
||||
except KeyError:
|
||||
fail_json(msg="No package matching '%s' is available" % pkgname)
|
||||
if version:
|
||||
return pkg.is_installed and pkg.installed.version == version, False
|
||||
else:
|
||||
return pkg.is_installed, pkg.is_upgradable
|
||||
|
||||
def install(pkgspec, cache, upgrade=False, default_release=None):
|
||||
name, version = package_split(pkgspec)
|
||||
installed, upgradable = package_status(name, version, cache)
|
||||
if not installed or (upgrade and upgradable):
|
||||
cmd = "%s -q -y install '%s'" % (APT, pkgspec)
|
||||
if default_release:
|
||||
cmd += " -t '%s'" % (default_release,)
|
||||
rc, out, err = run_apt(cmd)
|
||||
if rc:
|
||||
fail_json(msg="'apt-get install %s' failed: %s" % (pkgspec, err))
|
||||
|
@ -82,15 +95,16 @@ def install(pkgspec, cache, upgrade=False):
|
|||
return False
|
||||
|
||||
def remove(pkgspec, cache, purge=False):
|
||||
(installed, upgradable) = package_status(pkgspec, cache)
|
||||
name, version = package_split(pkgspec)
|
||||
installed, upgradable = package_status(name, version, cache)
|
||||
if not installed:
|
||||
return False
|
||||
else:
|
||||
purge = '--purge' if purge else ''
|
||||
cmd = "%s -q -y %s remove '%s'" % (APT, purge, pkgspec)
|
||||
cmd = "%s -q -y %s remove '%s'" % (APT, purge, name)
|
||||
rc, out, err = run_apt(cmd)
|
||||
if rc:
|
||||
fail_json(msg="'apt-get remove %s' failed: %s" % (pkgspec, err))
|
||||
fail_json(msg="'apt-get remove %s' failed: %s" % (name, err))
|
||||
return True
|
||||
|
||||
|
||||
|
@ -109,13 +123,14 @@ if not len(items):
|
|||
|
||||
params = {}
|
||||
for x in items:
|
||||
(k, v) = x.split("=")
|
||||
(k, v) = x.split("=", 1)
|
||||
params[k] = v
|
||||
|
||||
state = params.get('state', 'installed')
|
||||
package = params.get('pkg', params.get('package', params.get('name', None)))
|
||||
update_cache = params.get('update-cache', 'no')
|
||||
purge = params.get('purge', 'no')
|
||||
default_release = params.get('default-release', None)
|
||||
|
||||
if state not in ['installed', 'latest', 'removed']:
|
||||
fail_json(msg='invalid state')
|
||||
|
@ -130,6 +145,10 @@ if package is None and update_cache != 'yes':
|
|||
fail_json(msg='pkg=name and/or update-cache=yes is required')
|
||||
|
||||
cache = apt.Cache()
|
||||
if default_release:
|
||||
apt_pkg.config['APT::Default-Release'] = default_release
|
||||
# reopen cache w/ modified config
|
||||
cache.open()
|
||||
|
||||
if update_cache == 'yes':
|
||||
cache.update()
|
||||
|
@ -137,10 +156,16 @@ if update_cache == 'yes':
|
|||
if package == None:
|
||||
exit_json(changed=False)
|
||||
|
||||
if package.count('=') > 1:
|
||||
fail_json(msg='invalid package spec')
|
||||
|
||||
if state == 'latest':
|
||||
changed = install(package, cache, upgrade=True)
|
||||
if '=' in package:
|
||||
fail_json(msg='version number inconsistent with state=latest')
|
||||
changed = install(package, cache, upgrade=True,
|
||||
default_release=default_release)
|
||||
elif state == 'installed':
|
||||
changed = install(package, cache)
|
||||
changed = install(package, cache, default_release=default_release)
|
||||
elif state == 'removed':
|
||||
changed = remove(package, cache, purge == 'yes')
|
||||
|
||||
|
|
5
copy
5
copy
|
@ -42,7 +42,10 @@ for x in items:
|
|||
|
||||
src = params['src']
|
||||
dest = params['dest']
|
||||
|
||||
if src:
|
||||
src = os.path.expanduser(src)
|
||||
if dest:
|
||||
dest = os.path.expanduser(dest)
|
||||
|
||||
# raise an error if there is no src file
|
||||
if not os.path.exists(src):
|
||||
|
|
53
file
53
file
|
@ -72,6 +72,21 @@ def add_path_info(kwargs):
|
|||
kwargs['state'] = 'absent'
|
||||
return kwargs
|
||||
|
||||
# If selinux fails to find a default, return an array of None
|
||||
def selinux_default_context(path, mode=0):
|
||||
context = [None, None, None, None]
|
||||
if not HAVE_SELINUX:
|
||||
return context
|
||||
try:
|
||||
ret = selinux.matchpathcon(path, mode)
|
||||
except OSError:
|
||||
return context
|
||||
if ret[0] == -1:
|
||||
return context
|
||||
context = ret[1].split(':')
|
||||
debug("got default secontext=%s" % ret[1])
|
||||
return context
|
||||
|
||||
# ===========================================
|
||||
|
||||
argfile = sys.argv[1]
|
||||
|
@ -89,7 +104,11 @@ for x in items:
|
|||
|
||||
state = params.get('state','file')
|
||||
path = params.get('path', params.get('dest', params.get('name', None)))
|
||||
if path:
|
||||
path = os.path.expanduser(path)
|
||||
src = params.get('src', None)
|
||||
if src:
|
||||
src = os.path.expanduser(src)
|
||||
dest = params.get('dest', None)
|
||||
mode = params.get('mode', None)
|
||||
owner = params.get('owner', None)
|
||||
|
@ -102,8 +121,16 @@ recurse = params.get('recurse', 'false')
|
|||
seuser = params.get('seuser', None)
|
||||
serole = params.get('serole', None)
|
||||
setype = params.get('setype', None)
|
||||
serange = params.get('serange', 's0')
|
||||
secontext = [seuser, serole, setype, serange]
|
||||
selevel = params.get('serange', 's0')
|
||||
context = params.get('context', None)
|
||||
secontext = [seuser, serole, setype, selevel]
|
||||
|
||||
if context is not None:
|
||||
if context != 'default':
|
||||
fail_json(msg='invalid context: %s' % context)
|
||||
if seuser is not None or serole is not None or setype is not None:
|
||||
fail_json(msg='cannot define context=default and seuser, serole or setype')
|
||||
secontext = selinux_default_context(path)
|
||||
|
||||
if state not in [ 'file', 'directory', 'link', 'absent']:
|
||||
fail_json(msg='invalid state: %s' % state)
|
||||
|
@ -144,34 +171,14 @@ def selinux_context(path):
|
|||
debug("got current secontext=%s" % ret[1])
|
||||
return context
|
||||
|
||||
# If selinux fails to find a default, return an array of None
|
||||
def selinux_default_context(path, mode=0):
|
||||
context = [None, None, None, None]
|
||||
print >>sys.stderr, path
|
||||
if not HAVE_SELINUX:
|
||||
return context
|
||||
try:
|
||||
ret = selinux.matchpathcon(path, mode)
|
||||
except OSError:
|
||||
return context
|
||||
if ret[0] == -1:
|
||||
return context
|
||||
context = ret[1].split(':')
|
||||
debug("got default secontext=%s" % ret[1])
|
||||
return context
|
||||
|
||||
def set_context_if_different(path, context, changed):
|
||||
if not HAVE_SELINUX:
|
||||
return changed
|
||||
cur_context = selinux_context(path)
|
||||
new_context = selinux_default_context(path)
|
||||
new_context = list(cur_context)
|
||||
for i in range(len(context)):
|
||||
if context[i] is not None and context[i] != cur_context[i]:
|
||||
debug('new context was %s' % new_context[i])
|
||||
new_context[i] = context[i]
|
||||
debug('new context is %s' % new_context[i])
|
||||
elif new_context[i] is None:
|
||||
new_context[i] = cur_context[i]
|
||||
debug("current secontext is %s" % ':'.join(cur_context))
|
||||
debug("new secontext is %s" % ':'.join(new_context))
|
||||
if cur_context != new_context:
|
||||
|
|
249
setup
249
setup
|
@ -19,9 +19,16 @@
|
|||
|
||||
DEFAULT_ANSIBLE_SETUP = "/etc/ansible/setup"
|
||||
|
||||
import array
|
||||
import fcntl
|
||||
import glob
|
||||
import sys
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import shlex
|
||||
import socket
|
||||
import struct
|
||||
import subprocess
|
||||
import traceback
|
||||
|
||||
|
@ -30,6 +37,244 @@ try:
|
|||
except ImportError:
|
||||
import simplejson as json
|
||||
|
||||
_I386RE = re.compile(r'i[3456]86')
|
||||
SIOCGIFCONF = 0x8912
|
||||
SIOCGIFHWADDR = 0x8927
|
||||
MEMORY_FACTS = ['MemTotal', 'SwapTotal', 'MemFree', 'SwapFree']
|
||||
# DMI bits
|
||||
DMI_DICT = { 'form_factor': '/sys/devices/virtual/dmi/id/chassis_type',
|
||||
'product_name': '/sys/devices/virtual/dmi/id/product_name',
|
||||
'product_serial': '/sys/devices/virtual/dmi/id/product_serial',
|
||||
'product_uuid': '/sys/devices/virtual/dmi/id/product_uuid',
|
||||
'product_version': '/sys/devices/virtual/dmi/id/product_version',
|
||||
'system_vendor': '/sys/devices/virtual/dmi/id/sys_vendor' }
|
||||
# From smolt and DMI spec
|
||||
FORM_FACTOR = [ "Unknown", "Other", "Unknown", "Desktop",
|
||||
"Low Profile Desktop", "Pizza Box", "Mini Tower", "Tower",
|
||||
"Portable", "Laptop", "Notebook", "Hand Held", "Docking Station",
|
||||
"All In One", "Sub Notebook", "Space-saving", "Lunch Box",
|
||||
"Main Server Chassis", "Expansion Chassis", "Sub Chassis",
|
||||
"Bus Expansion Chassis", "Peripheral Chassis", "RAID Chassis",
|
||||
"Rack Mount Chassis", "Sealed-case PC", "Multi-system",
|
||||
"CompactPCI", "AdvancedTCA" ]
|
||||
# For the most part, we assume that platform.dist() will tell the truth.
|
||||
# This is the fallback to handle unknowns or exceptions
|
||||
OSDIST_DICT = { '/etc/redhat-release': 'RedHat',
|
||||
'/etc/vmware-release': 'VMwareESX' }
|
||||
|
||||
def get_file_content(path):
|
||||
if os.path.exists(path) and os.access(path, os.R_OK):
|
||||
data = open(path).read().strip()
|
||||
if len(data) == 0:
|
||||
data = None
|
||||
else:
|
||||
data = None
|
||||
return data
|
||||
|
||||
# platform.dist() is deprecated in 2.6
|
||||
# in 2.6 and newer, you should use platform.linux_distribution()
|
||||
def get_distribution_facts(facts):
|
||||
dist = platform.dist()
|
||||
facts['distribution'] = dist[0].capitalize() or 'NA'
|
||||
facts['distribution_version'] = dist[1] or 'NA'
|
||||
facts['distribution_release'] = dist[2] or 'NA'
|
||||
# Try to handle the exceptions now ...
|
||||
for (path, name) in OSDIST_DICT.items():
|
||||
if os.path.exists(path):
|
||||
if facts['distribution'] == 'Fedora':
|
||||
pass
|
||||
elif name == 'RedHat':
|
||||
data = get_file_content(path)
|
||||
if 'Red Hat' in data:
|
||||
facts['distribution'] = name
|
||||
else:
|
||||
facts['distribution'] = data.split()[0]
|
||||
else:
|
||||
facts['distribution'] = name
|
||||
|
||||
# Platform
|
||||
# patform.system() can be Linux, Darwin, Java, or Windows
|
||||
def get_platform_facts(facts):
|
||||
facts['system'] = platform.system()
|
||||
facts['kernel'] = platform.release()
|
||||
facts['machine'] = platform.machine()
|
||||
facts['python_version'] = platform.python_version()
|
||||
if facts['machine'] == 'x86_64':
|
||||
facts['architecture'] = facts['machine']
|
||||
elif _I386RE.search(facts['machine']):
|
||||
facts['architecture'] = 'i386'
|
||||
else:
|
||||
facts['archtecture'] = facts['machine']
|
||||
if facts['system'] == 'Linux':
|
||||
get_distribution_facts(facts)
|
||||
|
||||
def get_memory_facts(facts):
|
||||
if not os.access("/proc/meminfo", os.R_OK):
|
||||
return facts
|
||||
for line in open("/proc/meminfo").readlines():
|
||||
data = line.split(":", 1)
|
||||
key = data[0]
|
||||
if key in MEMORY_FACTS:
|
||||
val = data[1].strip().split(' ')[0]
|
||||
facts["%s_mb" % key.lower()] = long(val) / 1024
|
||||
|
||||
def get_cpu_facts(facts):
|
||||
i = 0
|
||||
physid = 0
|
||||
sockets = {}
|
||||
if not os.access("/proc/cpuinfo", os.R_OK):
|
||||
return facts
|
||||
for line in open("/proc/cpuinfo").readlines():
|
||||
data = line.split(":", 1)
|
||||
key = data[0].strip()
|
||||
if key == 'model name':
|
||||
if 'processor' not in facts:
|
||||
facts['processor'] = []
|
||||
facts['processor'].append(data[1].strip())
|
||||
i += 1
|
||||
elif key == 'physical id':
|
||||
physid = data[1].strip()
|
||||
if physid not in sockets:
|
||||
sockets[physid] = 1
|
||||
elif key == 'cpu cores':
|
||||
sockets[physid] = int(data[1].strip())
|
||||
if len(sockets) > 0:
|
||||
facts['processor_count'] = len(sockets)
|
||||
facts['processor_cores'] = reduce(lambda x, y: x + y, sockets.values())
|
||||
else:
|
||||
facts['processor_count'] = i
|
||||
facts['processor_cores'] = 'NA'
|
||||
|
||||
def get_hardware_facts(facts):
|
||||
get_memory_facts(facts)
|
||||
get_cpu_facts(facts)
|
||||
for (key,path) in DMI_DICT.items():
|
||||
data = get_file_content(path)
|
||||
if data is not None:
|
||||
if key == 'form_factor':
|
||||
facts['form_factor'] = FORM_FACTOR[int(data)]
|
||||
else:
|
||||
facts[key] = data
|
||||
else:
|
||||
facts[key] = 'NA'
|
||||
|
||||
def get_linux_virtual_facts(facts):
|
||||
if os.path.exists("/proc/xen"):
|
||||
facts['virtualization_type'] = 'xen'
|
||||
facts['virtualization_role'] = 'guest'
|
||||
if os.path.exists("/proc/xen/capabilities"):
|
||||
facts['virtualization_role'] = 'host'
|
||||
if os.path.exists("/proc/modules"):
|
||||
modules = []
|
||||
for line in open("/proc/modules").readlines():
|
||||
data = line.split(" ", 1)
|
||||
modules.append(data[0])
|
||||
if 'kvm' in modules:
|
||||
facts['virtualization_type'] = 'kvm'
|
||||
facts['virtualization_role'] = 'host'
|
||||
elif 'vboxdrv' in modules:
|
||||
facts['virtualization_type'] = 'virtualbox'
|
||||
facts['virtualization_role'] = 'host'
|
||||
elif 'vboxguest' in modules:
|
||||
facts['virtualization_type'] = 'virtualbox'
|
||||
facts['virtualization_role'] = 'guest'
|
||||
if 'QEMU' in facts['processor'][0]:
|
||||
facts['virtualization_type'] = 'kvm'
|
||||
facts['virtualization_role'] = 'guest'
|
||||
if facts['distribution'] == 'VMwareESX':
|
||||
facts['virtualization_type'] = 'VMware'
|
||||
facts['virtualization_role'] = 'host'
|
||||
# You can spawn a dmidecode process and parse that or infer from devices
|
||||
for dev_model in glob.glob('/proc/ide/hd*/model'):
|
||||
info = open(dev_model).read()
|
||||
if 'VMware' in info:
|
||||
facts['virtualization_type'] = 'VMware'
|
||||
facts['virtualization_role'] = 'guest'
|
||||
elif 'Virtual HD' in info or 'Virtual CD' in info:
|
||||
facts['virtualization_type'] = 'VirtualPC'
|
||||
facts['virtualization_role'] = 'guest'
|
||||
|
||||
def get_virtual_facts(facts):
|
||||
facts['virtualization_type'] = 'None'
|
||||
facts['virtualization_role'] = 'None'
|
||||
if facts['system'] == 'Linux':
|
||||
facts = get_linux_virtual_facts(facts)
|
||||
|
||||
# get list of interfaces that are up
|
||||
def get_interfaces():
|
||||
length = 4096
|
||||
offset = 32
|
||||
step = 32
|
||||
if platform.architecture()[0] == '64bit':
|
||||
offset = 16
|
||||
step = 40
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
names = array.array('B', '\0' * length)
|
||||
bytelen = struct.unpack('iL', fcntl.ioctl(
|
||||
s.fileno(), SIOCGIFCONF, struct.pack(
|
||||
'iL', length, names.buffer_info()[0])
|
||||
))[0]
|
||||
return [names.tostring()[i:i+offset].split('\0', 1)[0]
|
||||
for i in range(0, bytelen, step)]
|
||||
|
||||
def get_iface_hwaddr(iface):
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
info = fcntl.ioctl(s.fileno(), SIOCGIFHWADDR,
|
||||
struct.pack('256s', iface[:15]))
|
||||
return ''.join(['%02x:' % ord(char) for char in info[18:24]])[:-1]
|
||||
|
||||
def get_network_facts(facts):
|
||||
facts['fqdn'] = socket.gethostname()
|
||||
facts['hostname'] = facts['fqdn'].split('.')[0]
|
||||
facts['interfaces'] = get_interfaces()
|
||||
for iface in facts['interfaces']:
|
||||
facts[iface] = { 'macaddress': get_iface_hwaddr(iface) }
|
||||
# This is lame, but there doesn't appear to be a good way
|
||||
# to get all addresses for both IPv4 and IPv6.
|
||||
cmd = subprocess.Popen("/sbin/ifconfig %s" % iface, shell=True,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
out, err = cmd.communicate()
|
||||
for line in out.split('\n'):
|
||||
data = line.split()
|
||||
if 'inet addr' in line:
|
||||
if 'ipv4' not in facts[iface]:
|
||||
facts[iface]['ipv4'] = {}
|
||||
facts[iface]['ipv4'] = { 'address': data[1].split(':')[1],
|
||||
'netmask': data[-1].split(':')[1] }
|
||||
if 'inet6 addr' in line:
|
||||
(ip, prefix) = data[2].split('/')
|
||||
scope = data[3].split(':')[1].lower()
|
||||
if 'ipv6' not in facts[iface]:
|
||||
facts[iface]['ipv6'] = []
|
||||
facts[iface]['ipv6'].append( { 'address': ip,
|
||||
'prefix': prefix,
|
||||
'scope': scope } )
|
||||
return facts
|
||||
|
||||
def get_public_ssh_host_keys(facts):
|
||||
dsa = get_file_content('/etc/ssh/ssh_host_dsa_key.pub')
|
||||
rsa = get_file_content('/etc/ssh/ssh_host_rsa_key.pub')
|
||||
if dsa is None:
|
||||
dsa = 'NA'
|
||||
else:
|
||||
facts['ssh_host_key_dsa_public'] = dsa.split()[1]
|
||||
if rsa is None:
|
||||
rsa = 'NA'
|
||||
else:
|
||||
facts['ssh_host_key_rsa_public'] = rsa.split()[1]
|
||||
|
||||
def get_service_facts(facts):
|
||||
get_public_ssh_host_keys(facts)
|
||||
|
||||
def ansible_facts():
|
||||
facts = {}
|
||||
get_platform_facts(facts)
|
||||
get_hardware_facts(facts)
|
||||
get_virtual_facts(facts)
|
||||
get_network_facts(facts)
|
||||
get_service_facts(facts)
|
||||
return facts
|
||||
|
||||
# load config & template variables
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
|
@ -65,6 +310,10 @@ if not os.path.exists(ansible_file):
|
|||
else:
|
||||
md5sum = os.popen("md5sum %s" % ansible_file).read().split()[0]
|
||||
|
||||
# Get some basic facts in case facter or ohai are not installed
|
||||
for (k, v) in ansible_facts().items():
|
||||
setup_options["ansible_%s" % k] = v
|
||||
|
||||
# if facter is installed, and we can use --json because
|
||||
# ruby-json is ALSO installed, include facter data in the JSON
|
||||
|
||||
|
|
71
slurp
Executable file
71
slurp
Executable file
|
@ -0,0 +1,71 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# (c) 2012, Michael DeHaan <michael.dehaan@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/>.
|
||||
|
||||
import sys
|
||||
import os
|
||||
import shlex
|
||||
import base64
|
||||
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
import simplejson as json
|
||||
|
||||
# ===========================================
|
||||
# convert arguments of form a=b c=d
|
||||
# to a dictionary
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
sys.exit(1)
|
||||
argfile = sys.argv[1]
|
||||
if not os.path.exists(argfile):
|
||||
sys.exit(1)
|
||||
items = shlex.split(open(argfile, 'r').read())
|
||||
|
||||
params = {}
|
||||
for x in items:
|
||||
(k, v) = x.split("=")
|
||||
params[k] = v
|
||||
source = os.path.expanduser(params['src'])
|
||||
|
||||
# ==========================================
|
||||
|
||||
# raise an error if there is no template metadata
|
||||
if not os.path.exists(source):
|
||||
print json.dumps(dict(
|
||||
failed = 1,
|
||||
msg = "file not found: %s" % source
|
||||
))
|
||||
sys.exit(1)
|
||||
|
||||
if not os.access(source, os.R_OK):
|
||||
print json.dumps(dict(
|
||||
failed = 1,
|
||||
msg = "file is not readable: %s" % source
|
||||
))
|
||||
sys.exit(1)
|
||||
|
||||
# ==========================================
|
||||
|
||||
data = file(source).read()
|
||||
data = base64.b64encode(data)
|
||||
|
||||
print json.dumps(dict(content=data, encoding='base64'))
|
||||
sys.exit(0)
|
||||
|
119
template
119
template
|
@ -17,119 +17,8 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys
|
||||
import os
|
||||
import jinja2
|
||||
import shlex
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
import simplejson as json
|
||||
|
||||
environment = jinja2.Environment()
|
||||
|
||||
# ===========================================
|
||||
# convert arguments of form a=b c=d
|
||||
# to a dictionary
|
||||
# FIXME: make more idiomatic
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
sys.exit(1)
|
||||
argfile = sys.argv[1]
|
||||
if not os.path.exists(argfile):
|
||||
sys.exit(1)
|
||||
items = shlex.split(open(argfile, 'r').read())
|
||||
|
||||
params = {}
|
||||
for x in items:
|
||||
(k, v) = x.split("=")
|
||||
params[k] = v
|
||||
|
||||
source = params['src']
|
||||
dest = params['dest']
|
||||
metadata = params.get('metadata', '/etc/ansible/setup')
|
||||
module_vars = params.get('vars')
|
||||
|
||||
# raise an error if there is no template metadata
|
||||
if not os.path.exists(metadata):
|
||||
print json.dumps({
|
||||
"failed" : 1,
|
||||
"msg" : "Missing %s, did you run the setup module yet?" % metadata
|
||||
})
|
||||
sys.exit(1)
|
||||
|
||||
# raise an error if we can't parse the template metadata
|
||||
#data = {}
|
||||
try:
|
||||
f = open(metadata)
|
||||
data = json.loads(f.read())
|
||||
f.close()
|
||||
except:
|
||||
print json.dumps({
|
||||
"failed" : 1,
|
||||
"msg" : "Failed to parse/load %s, rerun the setup module?" % metadata
|
||||
})
|
||||
sys.exit(1)
|
||||
|
||||
if module_vars:
|
||||
try:
|
||||
f = open(module_vars)
|
||||
vars = json.loads(f.read())
|
||||
data.update(vars)
|
||||
f.close()
|
||||
except:
|
||||
print json.dumps({
|
||||
"failed" : 1,
|
||||
"msg" : "Failed to parse/load %s." % module_vars
|
||||
})
|
||||
sys.exit(1)
|
||||
|
||||
if not os.path.exists(source):
|
||||
print json.dumps({
|
||||
"failed" : 1,
|
||||
"msg" : "Source template could not be read: %s" % source
|
||||
})
|
||||
sys.exit(1)
|
||||
|
||||
source = file(source).read()
|
||||
|
||||
if os.path.isdir(dest):
|
||||
print json.dumps({
|
||||
"failed" : 1,
|
||||
"msg" : "Destination is a directory"
|
||||
})
|
||||
sys.exit(1)
|
||||
|
||||
# record md5sum of original source file so we can report if it changed
|
||||
changed = False
|
||||
md5sum = None
|
||||
if os.path.exists(dest):
|
||||
md5sum = os.popen("md5sum %s" % dest).read().split()[0]
|
||||
|
||||
try:
|
||||
# call Jinja2 here and save the new template file
|
||||
template = environment.from_string(source)
|
||||
data_out = template.render(data)
|
||||
except jinja2.TemplateError, e:
|
||||
print json.dumps({
|
||||
"failed": True,
|
||||
"msg" : e.message
|
||||
})
|
||||
sys.exit(1)
|
||||
f = open(dest, "w+")
|
||||
f.write(data_out)
|
||||
f.close()
|
||||
|
||||
# record m5sum and return success and whether things have changed
|
||||
md5sum2 = os.popen("md5sum %s" % dest).read().split()[0]
|
||||
|
||||
if md5sum != md5sum2:
|
||||
changed = True
|
||||
|
||||
# mission accomplished
|
||||
print json.dumps({
|
||||
"md5sum" : md5sum2,
|
||||
"changed" : changed
|
||||
})
|
||||
|
||||
# hey the Ansible template module isn't really a remote transferred
|
||||
# module. All the magic happens in Runner.py making use of the
|
||||
# copy module, and if not running from a playbook, also the 'slurp'
|
||||
# module.
|
||||
|
||||
|
|
3
virt
3
virt
|
@ -10,8 +10,7 @@ This software may be freely redistributed under the terms of the GNU
|
|||
general public license.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
VIRT_FAILED = 1
|
||||
|
|
Loading…
Reference in a new issue