-
Notifications
You must be signed in to change notification settings - Fork 469
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use wrapper shell script for systems without a "/usr/bin/env python"
Some systems (Ubuntu 17.04+) have nothing for "/usr/bin/env python". The have python3 instead. This commit introduces a wrapper script that finds out which python binary to use. Instead of linking bin/ansible-cmdb directly to lib/ansible-cmdb (the python script), we now link to the wrapper script.
- Loading branch information
Showing
2 changed files
with
236 additions
and
202 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,208 +1,34 @@ | ||
#!/usr/bin/env python | ||
#!/bin/sh | ||
|
||
# ansible_cmd | ||
# | ||
# Generate host overview (configuration management database) from ansible fact | ||
# gathering output. | ||
# | ||
# Usage: | ||
# | ||
# $ ansible -m setup --tree out all | ||
# $ ansible-cmdb out > cmdb.html | ||
# Wrapper script to find python version to use. | ||
# | ||
|
||
import optparse | ||
import sys | ||
import os | ||
import logging | ||
from mako import exceptions | ||
import ansiblecmdb | ||
import ansiblecmdb.util as util | ||
import ansiblecmdb.render as render | ||
|
||
# Find python binary | ||
PY_BIN=$(which python) | ||
if [ -z "$PY_BIN" ]; then | ||
PY_BIN=$(which python3) | ||
fi | ||
|
||
# Verify Python version | ||
if sys.version_info < (2, 7): | ||
sys.stderr.write( | ||
"Ansible-cmdb requires Python v2.7+. You are running {}. Support for " | ||
"Python v2.6 supported ended October 2013. You should upgrade to a " | ||
"newer version.\n".format(sys.version)) | ||
sys.exit(1) | ||
|
||
|
||
def get_logger(): | ||
""" | ||
Instantiate a logger. | ||
""" | ||
root = logging.getLogger() | ||
root.setLevel(logging.WARNING) | ||
ch = logging.StreamHandler(sys.stderr) | ||
ch.setLevel(logging.DEBUG) | ||
formatter = logging.Formatter('%(message)s') | ||
ch.setFormatter(formatter) | ||
root.addHandler(ch) | ||
return root | ||
|
||
|
||
def get_data_dir(): | ||
""" | ||
Find out our installation prefix and data directory. These can be in | ||
different places depending on how ansible-cmdb was installed. | ||
""" | ||
data_dir_paths = [ | ||
os.path.join(os.path.dirname(ansiblecmdb.__file__), 'data'), | ||
os.path.join(os.path.dirname(sys.argv[0]), '..', 'lib', 'ansiblecmdb', 'data'), | ||
'/usr/local/lib/ansiblecmdb/data', | ||
'/usr/lib/ansiblecmdb/data', | ||
] | ||
|
||
data_dir = util.find_path(data_dir_paths, 'tpl/html_fancy.tpl') | ||
if not data_dir: | ||
sys.stdout.write("Couldn't find the data dir for the templates. I tried: {0}\n".format(", ".join(data_dir_paths))) | ||
sys.exit(1) | ||
|
||
return data_dir | ||
|
||
|
||
def get_hosts_files(option): | ||
""" | ||
Find out the location of the `hosts` file. This looks in multiple places | ||
such as the `-i` option, current dir and ansible configuration files. The | ||
first match is returned as a list. | ||
""" | ||
if option is not None: | ||
return option.split(',') | ||
|
||
# Use hosts file from the current dir if it exists | ||
if os.path.isfile('hosts'): | ||
return ['hosts'] | ||
|
||
# Perhaps it's configured in a configuration file. Try to find a | ||
# configuration file and see if it contains a `hostsfile` entry. | ||
config_locations = [ | ||
'.', | ||
'/etc/ansible/' | ||
] | ||
config_dir = util.find_path(config_locations, 'ansible.cfg') | ||
log.debug('config_dir = {0}'.format(config_dir)) | ||
if config_dir: | ||
with open(os.path.join(config_dir, 'ansible.cfg'), 'r') as cf: | ||
for line in cf: | ||
if line.startswith('hostfile'): | ||
return [line.split('=', 1)[1].strip()] | ||
|
||
|
||
def parse_user_params(user_params): | ||
""" | ||
Parse the user params (-p/--params) and them as a dict. | ||
""" | ||
if user_params: | ||
params = {} | ||
try: | ||
for param in options.params.split(','): | ||
param_key, param_value = param.split('=', 1) | ||
params[param_key] = param_value | ||
except ValueError as e: | ||
sys.stdout.write("Invalid params specified. Should be in format: <key=value>[,<key=value>..]\n") | ||
sys.exit(1) | ||
return params | ||
else: | ||
return {} | ||
|
||
|
||
if __name__ == "__main__": | ||
log = get_logger() | ||
data_dir = get_data_dir() | ||
tpl_dir = os.path.join(data_dir, 'tpl') | ||
static_dir = os.path.join(data_dir, 'static') | ||
version = open(os.path.join(data_dir, 'VERSION')).read().strip() | ||
|
||
parser = optparse.OptionParser(version="%prog v{0}".format(version)) | ||
parser.set_usage(sys.argv[0] + " [option] <dir> > output.html") | ||
parser.add_option("-t", "--template", dest="template", action="store", default='html_fancy', help="Template to use. Default is 'html_fancy'") | ||
parser.add_option("-i", "--inventory", dest="inventory", action="store", default=None, help="Inventory to read extra info from") | ||
parser.add_option("-f", "--fact-cache", dest="fact_cache", action="store_true", default=False, help="<dir> contains fact-cache files") | ||
parser.add_option("-p", "--params", dest="params", action="store", default=None, help="Params to send to template") | ||
parser.add_option("-d", "--debug", dest="debug", action="store_true", default=False, help="Show debug output") | ||
parser.add_option("-q", "--quiet", dest="quiet", action="store_true", default=False, help="Don't report warnings") | ||
parser.add_option("-c", "--columns", dest="columns", action="store", default=None, help="Show only given columns") | ||
parser.add_option("--exclude-cols", dest="exclude_columns", action="store", default=None, help="Exclude cols from output") | ||
(options, args) = parser.parse_args() | ||
|
||
if len(args) < 1: | ||
parser.print_usage() | ||
sys.stderr.write("The <dir> argument is mandatory\n") | ||
sys.exit(1) | ||
|
||
if options.quiet: | ||
log.setLevel(logging.ERROR) | ||
elif options.debug: | ||
log.setLevel(logging.DEBUG) | ||
|
||
hosts_files = get_hosts_files(options.inventory) | ||
|
||
# Handle template params | ||
params = { | ||
'lib_dir': data_dir, # Backwards compatibility for custom templates < ansible-cmdb v1.7 | ||
'data_dir': data_dir, | ||
'version': version, | ||
'log': log, | ||
'columns': None, | ||
'exclude_columns': None, | ||
} | ||
params.update(parse_user_params(options.params)) | ||
if options.columns is not None: | ||
params['columns'] = options.columns.split(',') | ||
if options.exclude_columns is not None: | ||
params['exclude_columns'] = options.exclude_columns.split(',') | ||
|
||
# Log some debug information | ||
log.debug('data_dir = {0}'.format(data_dir)) | ||
log.debug('tpl_dir = {0}'.format(tpl_dir)) | ||
log.debug('static_dir = {0}'.format(static_dir)) | ||
log.debug('inventory files = {0}'.format(hosts_files)) | ||
log.debug('template params = {0}'.format(params)) | ||
|
||
ansible = ansiblecmdb.Ansible(args, hosts_files, options.fact_cache, debug=options.debug) | ||
|
||
# Render a template with the gathered host info | ||
renderer = render.Render(options.template, ['.', tpl_dir]) | ||
if renderer.tpl_file is None: | ||
sys.stderr.write("Template '{0}' not found at any of \n {1}\n".format(options.template, "\n ".join(renderer.tpl_possibilities))) | ||
sys.exit(1) | ||
|
||
# Make sure we always output in UTF-8, regardless of the user's locale / | ||
# terminal encoding. This is different in Python 2 and 3. | ||
try: | ||
output = renderer.render(ansible.hosts, params) | ||
if output: | ||
if sys.version_info[0] == 3: | ||
sys.stdout.buffer.write(output.lstrip()) | ||
else: | ||
sys.stdout.write(output.lstrip()) | ||
except Exception as err: | ||
full_err = exceptions.text_error_template().render().replace("\n", "\n ") | ||
debug_cmd = "{0} -d {1}".format(sys.argv[0], ' '.join(sys.argv[1:])) | ||
debug_txt = ("Whoops, it looks like something went wrong while rendering the template.\n\n" | ||
"The reported error was: {0}: {1}\n\nThe full error was:{2}\n" | ||
"The output is probably not correct.\n\n".format(err.__class__.__name__, err, full_err)) | ||
if err.__class__.__name__ == "KeyError": | ||
debug_txt += "!!! This is probably a problem with missing information in your host facts\n\n" | ||
if not options.debug: | ||
debug_txt += ("You can re-run ansible-cmdb with the -d switch to turn on debugging\n" | ||
"to get an insight in what might be going wrong:\n\n" | ||
" {0}\n\n".format(debug_cmd)) | ||
debug_txt += \ | ||
"""\ | ||
You can report a bug on the issue tracker: | ||
https://github.com/fboender/ansible-cmdb/issues | ||
Please include the debugging output (-d switch) in the report! | ||
If you can, also include the hosts file and the facts file for the last host | ||
that rendered properly ('Rendering host...' in the output. If these files must | ||
remain confidential, you can send them to ferry.boender@gmail.com instead. | ||
""" | ||
sys.stderr.write(debug_txt) | ||
sys.exit(1) | ||
PY_VMAJOR=$($PY_BIN -c "import sys; print(sys.version_info.major)") | ||
PY_VMINOR=$($PY_BIN -c "import sys; print(sys.version_info.minor)") | ||
|
||
if [ "$PY_VMAJOR" -eq 2 -a "$PY_VMINOR" -lt 7 ]; then | ||
echo "Python v2.7 or v3.0 or higher is required" >&2 | ||
exit 1 | ||
fi | ||
|
||
# Find path to the real ansible-cmdb python script | ||
BIN_DIR=$(dirname $0) | ||
if [ -f "$BIN_DIR/ansible-cmdb.py" ]; then | ||
ANSIBLE_CMDB="$BIN_DIR/ansible-cmdb.py" | ||
elif [ -f "$BIN_DIR/../lib/ansible-cmdb/ansible-cmdb.py" ]; then | ||
ANSIBLE_CMDB="$BIN_DIR/../lib/ansible-cmdb/ansible-cmdb.py" | ||
else | ||
echo "Couldn't find $BIN_DIR/ansible-cmdb.py in . or $BIN_DIR/../lib/ansible-cmdb (cwd=$PWD)" >&2 | ||
exit 2 | ||
fi | ||
|
||
# Run it | ||
$PY_BIN $ANSIBLE_CMDB "$@" |
Oops, something went wrong.