2012-03-27 04:07:04 +02:00
#!/usr/bin/env python
2012-02-23 20:56:14 +01:00
2012-02-29 01:08:09 +01:00
# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
2012-02-24 01:42:05 +01:00
#
2012-02-29 01:08:09 +01:00
# This file is part of Ansible
2012-02-24 01:42:05 +01:00
#
2012-02-29 01:08:09 +01:00
# 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.
2012-02-24 01:42:05 +01:00
#
2012-02-29 01:08:09 +01:00
# 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/>.
2012-02-24 01:42:05 +01:00
2012-03-03 03:11:43 +01:00
########################################################
2015-10-20 03:36:19 +02:00
from __future__ import (absolute_import, division, print_function)
2015-05-04 04:47:26 +02:00
__metaclass__ = type
2012-03-03 03:11:43 +01:00
2014-12-16 18:20:11 +01:00
__requires__ = ['ansible']
try:
import pkg_resources
except Exception:
# Use pkg_resources to find the correct versions of libraries and set
# sys.path appropriately when there are multiversion installs. But we
# have code that better expresses the errors in the places where the code
# is actually used (the deps are optional for many code paths) so we don't
# want to fail here.
pass
2014-02-26 17:00:48 +01:00
import os
2016-04-06 08:48:37 +02:00
import shutil
2012-02-28 10:00:31 +01:00
import sys
2015-07-07 20:31:15 +02:00
import traceback
2012-03-18 22:41:44 +01:00
2015-05-13 17:15:04 +02:00
from ansible.errors import AnsibleError, AnsibleOptionsError, AnsibleParserError
2016-09-07 07:54:17 +02:00
from ansible.module_utils._text import to_text
2012-02-28 09:54:41 +01:00
2016-01-26 04:17:46 +01:00
2018-01-09 23:17:55 +01:00
# Used for determining if the system is running a new enough python version
# and should only restrict on our documented minimum versions
_PY3_MIN = sys.version_info[:2] >= (3, 5)
_PY2_MIN = (2, 6) <= sys.version_info[:2] < (3,)
_PY_MIN = _PY3_MIN or _PY2_MIN
if not _PY_MIN:
raise SystemExit('ERROR: Ansible requires a minimum of Python2 version 2.6 or Python3 version 3.5. Current version: %s' % ''.join(sys.version.splitlines()))
2015-07-05 23:46:51 +02:00
class LastResort(object):
2017-09-19 16:50:28 +02:00
# OUTPUT OF LAST RESORT
2017-09-13 03:49:24 +02:00
def display(self, msg, log_only=None):
2015-07-05 23:46:51 +02:00
print(msg, file=sys.stderr)
2015-07-24 17:24:31 +02:00
def error(self, msg, wrap_text=None):
print(msg, file=sys.stderr)
2015-07-07 20:31:15 +02:00
2012-02-28 09:54:41 +01:00
if __name__ == '__main__':
2013-04-27 16:24:26 +02:00
2015-07-05 23:46:51 +02:00
display = LastResort()
2017-09-19 16:50:28 +02:00
try: # bad ANSIBLE_CONFIG or config options can force ugly stacktrace
import ansible.constants as C
from ansible.utils.display import Display
except AnsibleOptionsError as e:
display.error(to_text(e), wrap_text=False)
sys.exit(5)
2015-05-04 04:47:26 +02:00
cli = None
2015-06-09 23:29:46 +02:00
me = os.path.basename(sys.argv[0])
2015-05-04 04:47:26 +02:00
2012-03-13 04:11:54 +01:00
try:
2015-07-05 23:24:15 +02:00
display = Display()
2015-12-11 00:03:25 +01:00
display.debug("starting run")
2015-07-05 23:24:15 +02:00
2015-11-02 20:34:08 +01:00
sub = None
2017-03-10 21:01:11 +01:00
target = me.split('-')
if target[-1][0].isdigit():
2017-06-16 17:28:37 +02:00
# Remove any version or python version info as downstreams
2017-03-10 21:01:11 +01:00
# sometimes add that
target = target[:-1]
if len(target) > 1:
sub = target[1]
myclass = "%sCLI" % sub.capitalize()
elif target[0] == 'ansible':
sub = 'adhoc'
myclass = 'AdHocCLI'
else:
raise AnsibleError("Unknown Ansible alias: %s" % me)
2015-11-02 18:46:04 +01:00
try:
2017-03-10 21:01:11 +01:00
mycli = getattr(__import__("ansible.cli.%s" % sub, fromlist=[myclass]), myclass)
2015-11-03 04:17:13 +01:00
except ImportError as e:
2016-06-02 18:49:22 +02:00
# ImportError members have changed in py3
if 'msg' in dir(e):
msg = e.msg
else:
msg = e.message
if msg.endswith(' %s' % sub):
2015-11-03 04:17:13 +01:00
raise AnsibleError("Ansible sub-program not implemented: %s" % me)
else:
raise
2016-09-12 21:57:41 +02:00
try:
args = [to_text(a, errors='surrogate_or_strict') for a in sys.argv]
except UnicodeError:
display.error('Command line args are not in utf-8, unable to continue. Ansible currently only understands utf-8')
display.display(u"The full traceback was:\n\n%s" % to_text(traceback.format_exc()))
exit_code = 6
else:
cli = mycli(args)
cli.parse()
exit_code = cli.run()
2012-03-14 01:59:05 +01:00
2015-05-04 04:47:26 +02:00
except AnsibleOptionsError as e:
cli.parser.print_help()
2016-09-07 07:54:17 +02:00
display.error(to_text(e), wrap_text=False)
2016-04-06 08:48:37 +02:00
exit_code = 5
2015-05-13 17:15:04 +02:00
except AnsibleParserError as e:
2016-09-07 07:54:17 +02:00
display.error(to_text(e), wrap_text=False)
2016-04-06 08:48:37 +02:00
exit_code = 4
2015-05-13 17:15:04 +02:00
# TQM takes care of these, but leaving comment to reserve the exit codes
# except AnsibleHostUnreachable as e:
2015-07-05 23:46:51 +02:00
# display.error(str(e))
2016-04-06 08:48:37 +02:00
# exit_code = 3
2015-05-13 17:15:04 +02:00
# except AnsibleHostFailed as e:
2015-07-05 23:46:51 +02:00
# display.error(str(e))
2016-04-06 08:48:37 +02:00
# exit_code = 2
2015-05-04 04:47:26 +02:00
except AnsibleError as e:
2016-09-07 07:54:17 +02:00
display.error(to_text(e), wrap_text=False)
2016-04-06 08:48:37 +02:00
exit_code = 1
2015-05-04 04:47:26 +02:00
except KeyboardInterrupt:
2015-07-05 23:46:51 +02:00
display.error("User interrupted execution")
2016-04-06 08:48:37 +02:00
exit_code = 99
2015-07-05 23:46:51 +02:00
except Exception as e:
2017-11-21 20:11:53 +01:00
if C.DEFAULT_DEBUG:
# Show raw stacktraces in debug mode, It also allow pdb to
# enter post mortem mode.
raise
2015-07-07 20:31:15 +02:00
have_cli_options = cli is not None and cli.options is not None
2017-06-14 17:08:34 +02:00
display.error("Unexpected Exception, this is probably a bug: %s" % to_text(e), wrap_text=False)
2015-08-06 16:02:40 +02:00
if not have_cli_options or have_cli_options and cli.options.verbosity > 2:
2016-10-10 07:04:02 +02:00
log_only = False
2017-10-02 15:59:41 +02:00
if hasattr(e, 'orig_exc'):
display.vvv('\nexception type: %s' % to_text(type(e.orig_exc)))
why = to_text(e.orig_exc)
if to_text(e) != why:
display.vvv('\noriginal msg: %s' % why)
2015-07-07 20:31:15 +02:00
else:
display.display("to see the full traceback, use -vvv")
2017-01-11 03:47:03 +01:00
log_only = True
2016-10-10 07:04:02 +02:00
display.display(u"the full traceback was:\n\n%s" % to_text(traceback.format_exc()), log_only=log_only)
2016-04-06 08:48:37 +02:00
exit_code = 250
finally:
2018-02-15 18:01:02 +01:00
# Remove ansible tmpdir
2016-04-06 08:48:37 +02:00
shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
sys.exit(exit_code)