|
1 |
| -#!/usr/bin/env python |
| 1 | +#!/bin/sh |
2 | 2 |
|
3 |
| -# ansible_cmd |
4 | 3 | #
|
5 |
| -# Generate host overview (configuration management database) from ansible fact |
6 |
| -# gathering output. |
7 |
| -# |
8 |
| -# Usage: |
9 |
| -# |
10 |
| -# $ ansible -m setup --tree out all |
11 |
| -# $ ansible-cmdb out > cmdb.html |
| 4 | +# Wrapper script to find python version to use. |
12 | 5 | #
|
13 | 6 |
|
14 |
| -import optparse |
15 |
| -import sys |
16 |
| -import os |
17 |
| -import logging |
18 |
| -from mako import exceptions |
19 |
| -import ansiblecmdb |
20 |
| -import ansiblecmdb.util as util |
21 |
| -import ansiblecmdb.render as render |
22 |
| - |
| 7 | +# Find python binary |
| 8 | +PY_BIN=$(which python) |
| 9 | +if [ -z "$PY_BIN" ]; then |
| 10 | + PY_BIN=$(which python3) |
| 11 | +fi |
23 | 12 |
|
24 | 13 | # Verify Python version
|
25 |
| -if sys.version_info < (2, 7): |
26 |
| - sys.stderr.write( |
27 |
| - "Ansible-cmdb requires Python v2.7+. You are running {}. Support for " |
28 |
| - "Python v2.6 supported ended October 2013. You should upgrade to a " |
29 |
| - "newer version.\n".format(sys.version)) |
30 |
| - sys.exit(1) |
31 |
| - |
32 |
| - |
33 |
| -def get_logger(): |
34 |
| - """ |
35 |
| - Instantiate a logger. |
36 |
| - """ |
37 |
| - root = logging.getLogger() |
38 |
| - root.setLevel(logging.WARNING) |
39 |
| - ch = logging.StreamHandler(sys.stderr) |
40 |
| - ch.setLevel(logging.DEBUG) |
41 |
| - formatter = logging.Formatter('%(message)s') |
42 |
| - ch.setFormatter(formatter) |
43 |
| - root.addHandler(ch) |
44 |
| - return root |
45 |
| - |
46 |
| - |
47 |
| -def get_data_dir(): |
48 |
| - """ |
49 |
| - Find out our installation prefix and data directory. These can be in |
50 |
| - different places depending on how ansible-cmdb was installed. |
51 |
| - """ |
52 |
| - data_dir_paths = [ |
53 |
| - os.path.join(os.path.dirname(ansiblecmdb.__file__), 'data'), |
54 |
| - os.path.join(os.path.dirname(sys.argv[0]), '..', 'lib', 'ansiblecmdb', 'data'), |
55 |
| - '/usr/local/lib/ansiblecmdb/data', |
56 |
| - '/usr/lib/ansiblecmdb/data', |
57 |
| - ] |
58 |
| - |
59 |
| - data_dir = util.find_path(data_dir_paths, 'tpl/html_fancy.tpl') |
60 |
| - if not data_dir: |
61 |
| - sys.stdout.write("Couldn't find the data dir for the templates. I tried: {0}\n".format(", ".join(data_dir_paths))) |
62 |
| - sys.exit(1) |
63 |
| - |
64 |
| - return data_dir |
65 |
| - |
66 |
| - |
67 |
| -def get_hosts_files(option): |
68 |
| - """ |
69 |
| - Find out the location of the `hosts` file. This looks in multiple places |
70 |
| - such as the `-i` option, current dir and ansible configuration files. The |
71 |
| - first match is returned as a list. |
72 |
| - """ |
73 |
| - if option is not None: |
74 |
| - return option.split(',') |
75 |
| - |
76 |
| - # Use hosts file from the current dir if it exists |
77 |
| - if os.path.isfile('hosts'): |
78 |
| - return ['hosts'] |
79 |
| - |
80 |
| - # Perhaps it's configured in a configuration file. Try to find a |
81 |
| - # configuration file and see if it contains a `hostsfile` entry. |
82 |
| - config_locations = [ |
83 |
| - '.', |
84 |
| - '/etc/ansible/' |
85 |
| - ] |
86 |
| - config_dir = util.find_path(config_locations, 'ansible.cfg') |
87 |
| - log.debug('config_dir = {0}'.format(config_dir)) |
88 |
| - if config_dir: |
89 |
| - with open(os.path.join(config_dir, 'ansible.cfg'), 'r') as cf: |
90 |
| - for line in cf: |
91 |
| - if line.startswith('hostfile'): |
92 |
| - return [line.split('=', 1)[1].strip()] |
93 |
| - |
94 |
| - |
95 |
| -def parse_user_params(user_params): |
96 |
| - """ |
97 |
| - Parse the user params (-p/--params) and them as a dict. |
98 |
| - """ |
99 |
| - if user_params: |
100 |
| - params = {} |
101 |
| - try: |
102 |
| - for param in options.params.split(','): |
103 |
| - param_key, param_value = param.split('=', 1) |
104 |
| - params[param_key] = param_value |
105 |
| - except ValueError as e: |
106 |
| - sys.stdout.write("Invalid params specified. Should be in format: <key=value>[,<key=value>..]\n") |
107 |
| - sys.exit(1) |
108 |
| - return params |
109 |
| - else: |
110 |
| - return {} |
111 |
| - |
112 |
| - |
113 |
| -if __name__ == "__main__": |
114 |
| - log = get_logger() |
115 |
| - data_dir = get_data_dir() |
116 |
| - tpl_dir = os.path.join(data_dir, 'tpl') |
117 |
| - static_dir = os.path.join(data_dir, 'static') |
118 |
| - version = open(os.path.join(data_dir, 'VERSION')).read().strip() |
119 |
| - |
120 |
| - parser = optparse.OptionParser(version="%prog v{0}".format(version)) |
121 |
| - parser.set_usage(sys.argv[0] + " [option] <dir> > output.html") |
122 |
| - parser.add_option("-t", "--template", dest="template", action="store", default='html_fancy', help="Template to use. Default is 'html_fancy'") |
123 |
| - parser.add_option("-i", "--inventory", dest="inventory", action="store", default=None, help="Inventory to read extra info from") |
124 |
| - parser.add_option("-f", "--fact-cache", dest="fact_cache", action="store_true", default=False, help="<dir> contains fact-cache files") |
125 |
| - parser.add_option("-p", "--params", dest="params", action="store", default=None, help="Params to send to template") |
126 |
| - parser.add_option("-d", "--debug", dest="debug", action="store_true", default=False, help="Show debug output") |
127 |
| - parser.add_option("-q", "--quiet", dest="quiet", action="store_true", default=False, help="Don't report warnings") |
128 |
| - parser.add_option("-c", "--columns", dest="columns", action="store", default=None, help="Show only given columns") |
129 |
| - parser.add_option("--exclude-cols", dest="exclude_columns", action="store", default=None, help="Exclude cols from output") |
130 |
| - (options, args) = parser.parse_args() |
131 |
| - |
132 |
| - if len(args) < 1: |
133 |
| - parser.print_usage() |
134 |
| - sys.stderr.write("The <dir> argument is mandatory\n") |
135 |
| - sys.exit(1) |
136 |
| - |
137 |
| - if options.quiet: |
138 |
| - log.setLevel(logging.ERROR) |
139 |
| - elif options.debug: |
140 |
| - log.setLevel(logging.DEBUG) |
141 |
| - |
142 |
| - hosts_files = get_hosts_files(options.inventory) |
143 |
| - |
144 |
| - # Handle template params |
145 |
| - params = { |
146 |
| - 'lib_dir': data_dir, # Backwards compatibility for custom templates < ansible-cmdb v1.7 |
147 |
| - 'data_dir': data_dir, |
148 |
| - 'version': version, |
149 |
| - 'log': log, |
150 |
| - 'columns': None, |
151 |
| - 'exclude_columns': None, |
152 |
| - } |
153 |
| - params.update(parse_user_params(options.params)) |
154 |
| - if options.columns is not None: |
155 |
| - params['columns'] = options.columns.split(',') |
156 |
| - if options.exclude_columns is not None: |
157 |
| - params['exclude_columns'] = options.exclude_columns.split(',') |
158 |
| - |
159 |
| - # Log some debug information |
160 |
| - log.debug('data_dir = {0}'.format(data_dir)) |
161 |
| - log.debug('tpl_dir = {0}'.format(tpl_dir)) |
162 |
| - log.debug('static_dir = {0}'.format(static_dir)) |
163 |
| - log.debug('inventory files = {0}'.format(hosts_files)) |
164 |
| - log.debug('template params = {0}'.format(params)) |
165 |
| - |
166 |
| - ansible = ansiblecmdb.Ansible(args, hosts_files, options.fact_cache, debug=options.debug) |
167 |
| - |
168 |
| - # Render a template with the gathered host info |
169 |
| - renderer = render.Render(options.template, ['.', tpl_dir]) |
170 |
| - if renderer.tpl_file is None: |
171 |
| - sys.stderr.write("Template '{0}' not found at any of \n {1}\n".format(options.template, "\n ".join(renderer.tpl_possibilities))) |
172 |
| - sys.exit(1) |
173 |
| - |
174 |
| - # Make sure we always output in UTF-8, regardless of the user's locale / |
175 |
| - # terminal encoding. This is different in Python 2 and 3. |
176 |
| - try: |
177 |
| - output = renderer.render(ansible.hosts, params) |
178 |
| - if output: |
179 |
| - if sys.version_info[0] == 3: |
180 |
| - sys.stdout.buffer.write(output.lstrip()) |
181 |
| - else: |
182 |
| - sys.stdout.write(output.lstrip()) |
183 |
| - except Exception as err: |
184 |
| - full_err = exceptions.text_error_template().render().replace("\n", "\n ") |
185 |
| - debug_cmd = "{0} -d {1}".format(sys.argv[0], ' '.join(sys.argv[1:])) |
186 |
| - debug_txt = ("Whoops, it looks like something went wrong while rendering the template.\n\n" |
187 |
| - "The reported error was: {0}: {1}\n\nThe full error was:{2}\n" |
188 |
| - "The output is probably not correct.\n\n".format(err.__class__.__name__, err, full_err)) |
189 |
| - if err.__class__.__name__ == "KeyError": |
190 |
| - debug_txt += "!!! This is probably a problem with missing information in your host facts\n\n" |
191 |
| - if not options.debug: |
192 |
| - debug_txt += ("You can re-run ansible-cmdb with the -d switch to turn on debugging\n" |
193 |
| - "to get an insight in what might be going wrong:\n\n" |
194 |
| - " {0}\n\n".format(debug_cmd)) |
195 |
| - debug_txt += \ |
196 |
| -"""\ |
197 |
| -You can report a bug on the issue tracker: |
198 |
| -
|
199 |
| - https://github.com/fboender/ansible-cmdb/issues |
200 |
| -
|
201 |
| -Please include the debugging output (-d switch) in the report! |
202 |
| -
|
203 |
| -If you can, also include the hosts file and the facts file for the last host |
204 |
| -that rendered properly ('Rendering host...' in the output. If these files must |
205 |
| -remain confidential, you can send them to ferry.boender@gmail.com instead. |
206 |
| -""" |
207 |
| - sys.stderr.write(debug_txt) |
208 |
| - sys.exit(1) |
| 14 | +PY_VMAJOR=$($PY_BIN -c "import sys; print(sys.version_info.major)") |
| 15 | +PY_VMINOR=$($PY_BIN -c "import sys; print(sys.version_info.minor)") |
| 16 | + |
| 17 | +if [ "$PY_VMAJOR" -eq 2 -a "$PY_VMINOR" -lt 7 ]; then |
| 18 | + echo "Python v2.7 or v3.0 or higher is required" >&2 |
| 19 | + exit 1 |
| 20 | +fi |
| 21 | + |
| 22 | +# Find path to the real ansible-cmdb python script |
| 23 | +BIN_DIR=$(dirname $0) |
| 24 | +if [ -f "$BIN_DIR/ansible-cmdb.py" ]; then |
| 25 | + ANSIBLE_CMDB="$BIN_DIR/ansible-cmdb.py" |
| 26 | +elif [ -f "$BIN_DIR/../lib/ansible-cmdb/ansible-cmdb.py" ]; then |
| 27 | + ANSIBLE_CMDB="$BIN_DIR/../lib/ansible-cmdb/ansible-cmdb.py" |
| 28 | +else |
| 29 | + echo "Couldn't find $BIN_DIR/ansible-cmdb.py in . or $BIN_DIR/../lib/ansible-cmdb (cwd=$PWD)" >&2 |
| 30 | + exit 2 |
| 31 | +fi |
| 32 | + |
| 33 | +# Run it |
| 34 | +$PY_BIN $ANSIBLE_CMDB "$@" |
0 commit comments