2012-03-27 02:07:04 +00:00
#!/usr/bin/env python
2012-02-23 19:56:14 +00:00
2012-02-29 00:08:09 +00:00
# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
2012-02-24 00:42:05 +00:00
#
2012-02-29 00:08:09 +00:00
# This file is part of Ansible
2012-02-24 00:42:05 +00:00
#
2012-02-29 00:08:09 +00: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 00:42:05 +00:00
#
2012-02-29 00:08:09 +00: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 00:42:05 +00:00
2012-03-03 02:11:43 +00:00
########################################################
2015-10-20 01:36:19 +00:00
from __future__ import (absolute_import, division, print_function)
2015-05-04 02:47:26 +00:00
__metaclass__ = type
2012-03-03 02:11:43 +00:00
2014-12-16 17:20:11 +00: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 16:00:48 +00:00
import os
2016-04-06 06:48:37 +00:00
import shutil
2012-02-28 09:00:31 +00:00
import sys
2015-07-07 18:31:15 +00:00
import traceback
2012-03-18 21:41:44 +00:00
2015-05-13 15:15:04 +00:00
from ansible.errors import AnsibleError, AnsibleOptionsError, AnsibleParserError
2016-09-07 05:54:17 +00:00
from ansible.module_utils._text import to_text
2012-02-28 08:54:41 +00:00
2016-01-26 03:17:46 +00:00
2018-01-09 22:17:55 +00: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 21:46:51 +00:00
class LastResort(object):
2017-09-19 14:50:28 +00:00
# OUTPUT OF LAST RESORT
2017-09-13 01:49:24 +00:00
def display(self, msg, log_only=None):
2015-07-05 21:46:51 +00:00
print(msg, file=sys.stderr)
2015-07-24 15:24:31 +00:00
def error(self, msg, wrap_text=None):
print(msg, file=sys.stderr)
2015-07-07 18:31:15 +00:00
2012-02-28 08:54:41 +00:00
if __name__ == '__main__':
2013-04-27 14:24:26 +00:00
2015-07-05 21:46:51 +00:00
display = LastResort()
2017-09-19 14:50:28 +00: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 02:47:26 +00:00
cli = None
2015-06-09 21:29:46 +00:00
me = os.path.basename(sys.argv[0])
2015-05-04 02:47:26 +00:00
2012-03-13 03:11:54 +00:00
try:
2015-07-05 21:24:15 +00:00
display = Display()
2015-12-10 23:03:25 +00:00
display.debug("starting run")
2015-07-05 21:24:15 +00:00
2015-11-02 19:34:08 +00:00
sub = None
2017-03-10 20:01:11 +00:00
target = me.split('-')
if target[-1][0].isdigit():
2017-06-16 15:28:37 +00:00
# Remove any version or python version info as downstreams
2017-03-10 20:01:11 +00: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 17:46:04 +00:00
try:
2017-03-10 20:01:11 +00:00
mycli = getattr(__import__("ansible.cli.%s" % sub, fromlist=[myclass]), myclass)
2015-11-03 03:17:13 +00:00
except ImportError as e:
2016-06-02 16:49:22 +00: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 03:17:13 +00:00
raise AnsibleError("Ansible sub-program not implemented: %s" % me)
else:
raise
2016-09-12 19:57:41 +00: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 00:59:05 +00:00
2015-05-04 02:47:26 +00:00
except AnsibleOptionsError as e:
cli.parser.print_help()
2016-09-07 05:54:17 +00:00
display.error(to_text(e), wrap_text=False)
2016-04-06 06:48:37 +00:00
exit_code = 5
2015-05-13 15:15:04 +00:00
except AnsibleParserError as e:
2016-09-07 05:54:17 +00:00
display.error(to_text(e), wrap_text=False)
2016-04-06 06:48:37 +00:00
exit_code = 4
2015-05-13 15:15:04 +00:00
# TQM takes care of these, but leaving comment to reserve the exit codes
# except AnsibleHostUnreachable as e:
2015-07-05 21:46:51 +00:00
# display.error(str(e))
2016-04-06 06:48:37 +00:00
# exit_code = 3
2015-05-13 15:15:04 +00:00
# except AnsibleHostFailed as e:
2015-07-05 21:46:51 +00:00
# display.error(str(e))
2016-04-06 06:48:37 +00:00
# exit_code = 2
2015-05-04 02:47:26 +00:00
except AnsibleError as e:
2016-09-07 05:54:17 +00:00
display.error(to_text(e), wrap_text=False)
2016-04-06 06:48:37 +00:00
exit_code = 1
2015-05-04 02:47:26 +00:00
except KeyboardInterrupt:
2015-07-05 21:46:51 +00:00
display.error("User interrupted execution")
2016-04-06 06:48:37 +00:00
exit_code = 99
2015-07-05 21:46:51 +00:00
except Exception as e:
2017-11-21 19:11:53 +00:00
if C.DEFAULT_DEBUG:
# Show raw stacktraces in debug mode, It also allow pdb to
# enter post mortem mode.
raise
2015-07-07 18:31:15 +00:00
have_cli_options = cli is not None and cli.options is not None
2017-06-14 15:08:34 +00:00
display.error("Unexpected Exception, this is probably a bug: %s" % to_text(e), wrap_text=False)
2015-08-06 14:02:40 +00:00
if not have_cli_options or have_cli_options and cli.options.verbosity > 2:
2016-10-10 05:04:02 +00:00
log_only = False
2017-10-02 13:59:41 +00: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 18:31:15 +00:00
else:
display.display("to see the full traceback, use -vvv")
2017-01-11 02:47:03 +00:00
log_only = True
2016-10-10 05:04:02 +00:00
display.display(u"the full traceback was:\n\n%s" % to_text(traceback.format_exc()), log_only=log_only)
2016-04-06 06:48:37 +00:00
exit_code = 250
finally:
# Remove ansible tempdir
shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
sys.exit(exit_code)