diff --git a/bin/ansible b/bin/ansible index 60d2bf42cbb..7e1aa01a932 100755 --- a/bin/ansible +++ b/bin/ansible @@ -79,7 +79,7 @@ if __name__ == '__main__': else: raise - cli = mycli(sys.argv, display=display) + cli = mycli(sys.argv) cli.parse() sys.exit(cli.run()) diff --git a/lib/ansible/cli/__init__.py b/lib/ansible/cli/__init__.py index 6045b5171a3..f1839fdc0bd 100644 --- a/lib/ansible/cli/__init__.py +++ b/lib/ansible/cli/__init__.py @@ -33,7 +33,14 @@ from ansible import __version__ from ansible import constants as C from ansible.errors import AnsibleError, AnsibleOptionsError from ansible.utils.unicode import to_bytes -from ansible.utils.display import Display + +try: + from __main__ import display + display = display +except ImportError: + from ansible.utils.display import Display + display = Display() + class SortedOptParser(optparse.OptionParser): '''Optparser which sorts the options by opt before outputting --help''' @@ -44,6 +51,7 @@ class SortedOptParser(optparse.OptionParser): self.option_list.sort(key=operator.methodcaller('get_opt_string')) return optparse.OptionParser.format_help(self, formatter=None) + class CLI(object): ''' code behind bin/ansible* programs ''' @@ -59,7 +67,7 @@ class CLI(object): LESS_OPTS = 'FRSX' # -F (quit-if-one-screen) -R (allow raw ansi control chars) # -S (chop long lines) -X (disable termcap init and de-init) - def __init__(self, args, display=None): + def __init__(self, args): """ Base init method for all command line programs """ @@ -69,11 +77,6 @@ class CLI(object): self.parser = None self.action = None - if display is None: - self.display = Display() - else: - self.display = display - def set_action(self): """ Get the action the user wants to execute from the sys argv list. @@ -102,9 +105,9 @@ class CLI(object): if self.options.verbosity > 0: if C.CONFIG_FILE: - self.display.display("Using %s as config file" % C.CONFIG_FILE) + display.display("Using %s as config file" % C.CONFIG_FILE) else: - self.display.display("No config file found; using defaults") + display.display("No config file found; using defaults") @staticmethod def ask_vault_passwords(ask_new_vault_pass=False, rekey=False): @@ -135,7 +138,6 @@ class CLI(object): return vault_pass, new_vault_pass - def ask_passwords(self): ''' prompt for connection and become passwords if needed ''' @@ -164,7 +166,6 @@ class CLI(object): return (sshpass, becomepass) - def normalize_become_options(self): ''' this keeps backwards compatibility with sudo/su self.options ''' self.options.become_ask_pass = self.options.become_ask_pass or self.options.ask_sudo_pass or self.options.ask_su_pass or C.DEFAULT_BECOME_ASK_PASS @@ -179,7 +180,6 @@ class CLI(object): self.options.become = True self.options.become_method = 'su' - def validate_conflicts(self, vault_opts=False, runas_opts=False, fork_opts=False): ''' check for conflicting options ''' @@ -190,7 +190,6 @@ class CLI(object): if (op.ask_vault_pass and op.vault_password_file): self.parser.error("--ask-vault-pass and --vault-password-file are mutually exclusive") - if runas_opts: # Check for privilege escalation conflicts if (op.su or op.su_user or op.ask_su_pass) and \ @@ -215,7 +214,7 @@ class CLI(object): @staticmethod def base_parser(usage="", output_opts=False, runas_opts=False, meta_opts=False, runtask_opts=False, vault_opts=False, module_opts=False, - async_opts=False, connect_opts=False, subset_opts=False, check_opts=False, inventory_opts=False, epilog=None, fork_opts=False): + async_opts=False, connect_opts=False, subset_opts=False, check_opts=False, inventory_opts=False, epilog=None, fork_opts=False): ''' create an options parser for most ansible scripts ''' # TODO: implement epilog parsing @@ -257,7 +256,6 @@ class CLI(object): parser.add_option('--output', default=None, dest='output_file', help='output file name for encrypt or decrypt; use - for stdout') - if subset_opts: parser.add_option('-t', '--tags', dest='tags', default='all', help="only run plays and tasks tagged with these values") @@ -295,7 +293,6 @@ class CLI(object): parser.add_option('--ask-become-pass', default=False, dest='become_ask_pass', action='store_true', help='ask for privilege escalation password') - if connect_opts: parser.add_option('-k', '--ask-pass', default=C.DEFAULT_ASK_PASS, dest='ask_pass', action='store_true', help='ask for connection password') @@ -427,7 +424,7 @@ class CLI(object): result = CLI._git_repo_info(repo_path) submodules = os.path.join(basedir, '.gitmodules') if not os.path.exists(submodules): - return result + return result f = open(submodules) for line in f: tokens = line.strip().split(' ') @@ -440,21 +437,20 @@ class CLI(object): f.close() return result - def pager(self, text): ''' find reasonable way to display text ''' # this is a much simpler form of what is in pydoc.py if not sys.stdout.isatty(): - self.display.display(text) + display.display(text) elif 'PAGER' in os.environ: if sys.platform == 'win32': - self.display.display(text) + display.display(text) else: self.pager_pipe(text, os.environ['PAGER']) elif subprocess.call('(less --version) 2> /dev/null', shell = True) == 0: self.pager_pipe(text, 'less') else: - self.display.display(text) + display.display(text) @staticmethod def pager_pipe(text, cmd): @@ -521,4 +517,3 @@ class CLI(object): if os.pathsep in data: data = data.split(os.pathsep)[0] return data - diff --git a/lib/ansible/cli/adhoc.py b/lib/ansible/cli/adhoc.py index 7d611bf1f0b..0ebae3a27a2 100644 --- a/lib/ansible/cli/adhoc.py +++ b/lib/ansible/cli/adhoc.py @@ -34,6 +34,14 @@ from ansible.plugins import get_all_plugin_loaders from ansible.utils.vars import load_extra_vars from ansible.vars import VariableManager +try: + from __main__ import display + display = display +except ImportError: + from ansible.utils.display import Display + display = Display() + + ######################################################## class AdHocCLI(CLI): @@ -68,7 +76,7 @@ class AdHocCLI(CLI): if len(self.args) != 1: raise AnsibleOptionsError("Missing target hosts") - self.display.verbosity = self.options.verbosity + display.verbosity = self.options.verbosity self.validate_conflicts(runas_opts=True, vault_opts=True, fork_opts=True) return True @@ -86,7 +94,6 @@ class AdHocCLI(CLI): super(AdHocCLI, self).run() - # only thing left should be host pattern pattern = self.args[0] @@ -121,7 +128,7 @@ class AdHocCLI(CLI): hosts = inventory.list_hosts(pattern) no_hosts = False if len(hosts) == 0: - self.display.warning("provided hosts list is empty, only localhost is available") + display.warning("provided hosts list is empty, only localhost is available") no_hosts = True if self.options.subset: @@ -131,9 +138,9 @@ class AdHocCLI(CLI): raise AnsibleError("Specified --limit does not match any hosts") if self.options.listhosts: - self.display.display(' hosts (%d):' % len(hosts)) + display.display(' hosts (%d):' % len(hosts)) for host in hosts: - self.display.display(' %s' % host) + display.display(' %s' % host) return 0 if self.options.module_name in C.MODULE_REQUIRE_ARGS and not self.options.module_args: @@ -168,7 +175,6 @@ class AdHocCLI(CLI): inventory=inventory, variable_manager=variable_manager, loader=loader, - display=self.display, options=self.options, passwords=passwords, stdout_callback=cb, diff --git a/lib/ansible/cli/doc.py b/lib/ansible/cli/doc.py index 8c1acd705c7..d4a713142ba 100644 --- a/lib/ansible/cli/doc.py +++ b/lib/ansible/cli/doc.py @@ -31,15 +31,23 @@ from ansible.plugins import module_loader from ansible.cli import CLI from ansible.utils import module_docs +try: + from __main__ import display + display = display +except ImportError: + from ansible.utils.display import Display + display = Display() + + class DocCLI(CLI): """ Vault command line class """ BLACKLIST_EXTS = ('.pyc', '.swp', '.bak', '~', '.rpm', '.md', '.txt') IGNORE_FILES = [ "COPYING", "CONTRIBUTING", "LICENSE", "README", "VERSION", "GUIDELINES", "test-docs.sh"] - def __init__(self, args, display=None): + def __init__(self, args): - super(DocCLI, self).__init__(args, display) + super(DocCLI, self).__init__(args) self.module_list = [] def parse(self): @@ -56,8 +64,7 @@ class DocCLI(CLI): help='Show playbook snippet for specified module(s)') self.options, self.args = self.parser.parse_args() - self.display.verbosity = self.options.verbosity - + display.verbosity = self.options.verbosity def run(self): @@ -86,7 +93,7 @@ class DocCLI(CLI): try: filename = module_loader.find_plugin(module) if filename is None: - self.display.warning("module %s not found in %s\n" % (module, DocCLI.print_paths(module_loader))) + display.warning("module %s not found in %s\n" % (module, DocCLI.print_paths(module_loader))) continue if any(filename.endswith(x) for x in self.BLACKLIST_EXTS): @@ -95,8 +102,8 @@ class DocCLI(CLI): try: doc, plainexamples, returndocs = module_docs.get_docstring(filename, verbose=(self.options.verbosity > 0)) except: - self.display.vvv(traceback.print_exc()) - self.display.error("module %s has a documentation error formatting or is missing documentation\nTo see exact traceback use -vvv" % module) + display.vvv(traceback.print_exc()) + display.error("module %s has a documentation error formatting or is missing documentation\nTo see exact traceback use -vvv" % module) continue if doc is not None: @@ -122,7 +129,7 @@ class DocCLI(CLI): # probably a quoting issue. raise AnsibleError("Parsing produced an empty object.") except Exception as e: - self.display.vvv(traceback.print_exc()) + display.vvv(traceback.print_exc()) raise AnsibleError("module %s missing documentation (or could not parse documentation): %s\n" % (module, str(e))) self.pager(text) @@ -150,9 +157,8 @@ class DocCLI(CLI): module = os.path.splitext(module)[0] # removes the extension self.module_list.append(module) - def get_module_list_text(self): - columns = self.display.columns + columns = display.columns displace = max(len(x) for x in self.module_list) linelimit = columns - displace - 5 text = [] @@ -189,7 +195,6 @@ class DocCLI(CLI): text.extend(deprecated) return "\n".join(text) - @staticmethod def print_paths(finder): ''' Returns a string suitable for printing of the search path ''' @@ -209,7 +214,7 @@ class DocCLI(CLI): text.append(" action: %s" % (doc['module'])) pad = 31 subdent = ''.join([" " for a in xrange(pad)]) - limit = self.display.columns - pad + limit = display.columns - pad for o in sorted(doc['options'].keys()): opt = doc['options'][o] @@ -229,8 +234,8 @@ class DocCLI(CLI): opt_indent=" " text = [] text.append("> %s\n" % doc['module'].upper()) - pad = self.display.columns * 0.20 - limit = max(self.display.columns - int(pad), 70) + pad = display.columns * 0.20 + limit = max(display.columns - int(pad), 70) if isinstance(doc['description'], list): desc = " ".join(doc['description']) diff --git a/lib/ansible/cli/galaxy.py b/lib/ansible/cli/galaxy.py index c32e3e49f78..c6dc1ad6587 100644 --- a/lib/ansible/cli/galaxy.py +++ b/lib/ansible/cli/galaxy.py @@ -28,7 +28,6 @@ import sys import yaml from collections import defaultdict -from distutils.version import LooseVersion from jinja2 import Environment import ansible.constants as C @@ -39,16 +38,24 @@ from ansible.galaxy.api import GalaxyAPI from ansible.galaxy.role import GalaxyRole from ansible.playbook.role.requirement import RoleRequirement +try: + from __main__ import display + display = display +except ImportError: + from ansible.utils.display import Display + display = Display() + + class GalaxyCLI(CLI): VALID_ACTIONS = ("init", "info", "install", "list", "remove", "search") SKIP_INFO_KEYS = ("name", "description", "readme_html", "related", "summary_fields", "average_aw_composite", "average_aw_score", "url" ) - def __init__(self, args, display=None): + def __init__(self, args): self.api = None self.galaxy = None - super(GalaxyCLI, self).__init__(args, display) + super(GalaxyCLI, self).__init__(args) def parse(self): ''' create an options parser for bin/ansible ''' @@ -58,7 +65,6 @@ class GalaxyCLI(CLI): epilog = "\nSee '%s --help' for more information on a specific command.\n\n" % os.path.basename(sys.argv[0]) ) - self.set_action() # options specific to actions @@ -109,8 +115,8 @@ class GalaxyCLI(CLI): # get options, args and galaxy object self.options, self.args =self.parser.parse_args() - self.display.verbosity = self.options.verbosity - self.galaxy = Galaxy(self.options, self.display) + display.verbosity = self.options.verbosity + self.galaxy = Galaxy(self.options) return True @@ -178,10 +184,10 @@ class GalaxyCLI(CLI): if os.path.isfile(role_path): raise AnsibleError("- the path %s already exists, but is a file - aborting" % role_path) elif not force: - raise AnsibleError("- the directory %s already exists." % role_path + \ - "you can use --force to re-initialize this directory,\n" + \ - "however it will reset any main.yml files that may have\n" + \ - "been modified there already.") + raise AnsibleError("- the directory %s already exists." + "you can use --force to re-initialize this directory,\n" + "however it will reset any main.yml files that may have\n" + "been modified there already." % role_path) # create the default README.md if not os.path.exists(role_path): @@ -234,7 +240,7 @@ class GalaxyCLI(CLI): f = open(main_yml_path, 'w') f.write('---\n# %s file for %s\n' % (dir,role_name)) f.close() - self.display.display("- %s was created successfully" % role_name) + display.display("- %s was created successfully" % role_name) def execute_info(self): """ @@ -297,7 +303,7 @@ class GalaxyCLI(CLI): # the user needs to specify one of either --role-file # or specify a single user/role name raise AnsibleOptionsError("- you must specify a user/role name or a roles file") - elif len(self.args) == 1 and not role_file is None: + elif len(self.args) == 1 and role_file is not None: # using a role file is mutually exclusive of specifying # the role name on the command line raise AnsibleOptionsError("- please specify a user/role name, or a roles file, but not both") @@ -320,22 +326,22 @@ class GalaxyCLI(CLI): for role in required_roles: role = RoleRequirement.role_yaml_parse(role) - self.display.debug('found role %s in yaml file' % str(role)) + display.debug('found role %s in yaml file' % str(role)) if 'name' not in role and 'scm' not in role: raise AnsibleError("Must specify name or src for role") roles_left.append(GalaxyRole(self.galaxy, **role)) else: - self.display.deprecated("going forward only the yaml format will be supported") + display.deprecated("going forward only the yaml format will be supported") # roles listed in a file, one per line for rline in f.readlines(): if rline.startswith("#") or rline.strip() == '': continue - self.display.debug('found role %s in text file' % str(rline)) + display.debug('found role %s in text file' % str(rline)) role = RoleRequirement.role_yaml_parse(rline.strip()) roles_left.append(GalaxyRole(self.galaxy, **role)) f.close() except (IOError, OSError) as e: - self.display.error('Unable to open %s: %s' % (role_file, str(e))) + display.error('Unable to open %s: %s' % (role_file, str(e))) else: # roles were specified directly, so we'll just go out grab them # (and their dependencies, unless the user doesn't want us to). @@ -343,18 +349,17 @@ class GalaxyCLI(CLI): roles_left.append(GalaxyRole(self.galaxy, rname.strip())) for role in roles_left: - self.display.debug('Installing role %s ' % role.name) + display.debug('Installing role %s ' % role.name) # query the galaxy API for the role data - role_data = None if role.install_info is not None and not force: - self.display.display('- %s is already installed, skipping.' % role.name) + display.display('- %s is already installed, skipping.' % role.name) continue try: installed = role.install() except AnsibleError as e: - self.display.warning("- %s was NOT installed successfully: %s " % (role.name, str(e))) + display.warning("- %s was NOT installed successfully: %s " % (role.name, str(e))) self.exit_without_ignore() continue @@ -362,7 +367,7 @@ class GalaxyCLI(CLI): if not no_deps and installed: role_dependencies = role.metadata.get('dependencies') or [] for dep in role_dependencies: - self.display.debug('Installing dep %s' % dep) + display.debug('Installing dep %s' % dep) dep_req = RoleRequirement() dep_info = dep_req.role_yaml_parse(dep) dep_role = GalaxyRole(self.galaxy, **dep_info) @@ -372,15 +377,15 @@ class GalaxyCLI(CLI): continue if dep_role.install_info is None or force: if dep_role not in roles_left: - self.display.display('- adding dependency: %s' % dep_role.name) + display.display('- adding dependency: %s' % dep_role.name) roles_left.append(dep_role) else: - self.display.display('- dependency %s already pending installation.' % dep_role.name) + display.display('- dependency %s already pending installation.' % dep_role.name) else: - self.display.display('- dependency %s is already installed, skipping.' % dep_role.name) + display.display('- dependency %s is already installed, skipping.' % dep_role.name) if not installed: - self.display.warning("- %s was NOT installed successfully." % role.name) + display.warning("- %s was NOT installed successfully." % role.name) self.exit_without_ignore() return 0 @@ -398,9 +403,9 @@ class GalaxyCLI(CLI): role = GalaxyRole(self.galaxy, role_name) try: if role.remove(): - self.display.display('- successfully removed %s' % role_name) + display.display('- successfully removed %s' % role_name) else: - self.display.display('- %s is not installed, skipping.' % role_name) + display.display('- %s is not installed, skipping.' % role_name) except Exception as e: raise AnsibleError("Failed to remove role %s: %s" % (role_name, str(e))) @@ -429,9 +434,9 @@ class GalaxyCLI(CLI): if not version: version = "(unknown version)" # show some more info about single roles here - self.display.display("- %s, %s" % (name, version)) + display.display("- %s, %s" % (name, version)) else: - self.display.display("- the role %s was not found" % name) + display.display("- the role %s was not found" % name) else: # show all valid roles in the roles_path directory roles_path = self.get_opt('roles_path') @@ -450,7 +455,7 @@ class GalaxyCLI(CLI): version = install_info.get("version", None) if not version: version = "(unknown version)" - self.display.display("- %s, %s" % (path_file, version)) + display.display("- %s, %s" % (path_file, version)) return 0 def execute_search(self): @@ -464,7 +469,7 @@ class GalaxyCLI(CLI): response = self.api.search_roles(search, self.options.platforms, self.options.tags) if 'count' in response: - self.galaxy.display.display("Found %d roles matching your search:\n" % response['count']) + display.display("Found %d roles matching your search:\n" % response['count']) data = '' if 'results' in response: diff --git a/lib/ansible/cli/playbook.py b/lib/ansible/cli/playbook.py index 11c4f796b9c..2407e350482 100644 --- a/lib/ansible/cli/playbook.py +++ b/lib/ansible/cli/playbook.py @@ -33,6 +33,14 @@ from ansible.parsing.dataloader import DataLoader from ansible.utils.vars import load_extra_vars from ansible.vars import VariableManager +try: + from __main__ import display + display = display +except ImportError: + from ansible.utils.display import Display + display = Display() + + #--------------------------------------------------------------------------------------------------- class PlaybookCLI(CLI): @@ -73,7 +81,7 @@ class PlaybookCLI(CLI): if len(self.args) == 0: raise AnsibleOptionsError("You must specify a playbook file to run") - self.display.verbosity = self.options.verbosity + display.verbosity = self.options.verbosity self.validate_conflicts(runas_opts=True, vault_opts=True, fork_opts=True) def run(self): @@ -129,7 +137,7 @@ class PlaybookCLI(CLI): no_hosts = False if len(inventory.list_hosts()) == 0: # Empty inventory - self.display.warning("provided hosts list is empty, only localhost is available") + display.warning("provided hosts list is empty, only localhost is available") no_hosts = True inventory.subset(self.options.subset) if len(inventory.list_hosts()) == 0 and no_hosts is False: @@ -137,14 +145,14 @@ class PlaybookCLI(CLI): raise AnsibleError("Specified --limit does not match any hosts") # create the playbook executor, which manages running the plays via a task queue manager - pbex = PlaybookExecutor(playbooks=self.args, inventory=inventory, variable_manager=variable_manager, loader=loader, display=self.display, options=self.options, passwords=passwords) + pbex = PlaybookExecutor(playbooks=self.args, inventory=inventory, variable_manager=variable_manager, loader=loader, options=self.options, passwords=passwords) results = pbex.run() if isinstance(results, list): for p in results: - self.display.display('\nplaybook: %s' % p['playbook']) + display.display('\nplaybook: %s' % p['playbook']) i = 1 for play in p['plays']: if play.name: @@ -164,7 +172,7 @@ class PlaybookCLI(CLI): for host in playhosts: msg += "\n %s" % host - self.display.display(msg) + display.display(msg) if self.options.listtags or self.options.listtasks: taskmsg = ' tasks:' @@ -180,7 +188,7 @@ class PlaybookCLI(CLI): taskmsg += " TAGS: [%s]" % ','.join(mytags.union(set(task.tags))) j = j + 1 - self.display.display(taskmsg) + display.display(taskmsg) i = i + 1 return 0 diff --git a/lib/ansible/cli/pull.py b/lib/ansible/cli/pull.py index c163b3ef0b3..841bf2b3c33 100644 --- a/lib/ansible/cli/pull.py +++ b/lib/ansible/cli/pull.py @@ -33,6 +33,14 @@ from ansible.cli import CLI from ansible.plugins import module_loader from ansible.utils.cmd_functions import run_cmd +try: + from __main__ import display + display = display +except ImportError: + from ansible.utils.display import Display + display = Display() + + ######################################################## class PullCLI(CLI): @@ -94,7 +102,7 @@ class PullCLI(CLI): if self.options.module_name not in self.SUPPORTED_REPO_MODULES: raise AnsibleOptionsError("Unsuported repo module %s, choices are %s" % (self.options.module_name, ','.join(self.SUPPORTED_REPO_MODULES))) - self.display.verbosity = self.options.verbosity + display.verbosity = self.options.verbosity self.validate_conflicts(vault_opts=True) def run(self): @@ -104,8 +112,8 @@ class PullCLI(CLI): # log command line now = datetime.datetime.now() - self.display.display(now.strftime("Starting Ansible Pull at %F %T")) - self.display.display(' '.join(sys.argv)) + display.display(now.strftime("Starting Ansible Pull at %F %T")) + display.display(' '.join(sys.argv)) # Build Checkout command # Now construct the ansible command @@ -152,19 +160,19 @@ class PullCLI(CLI): # Nap? if self.options.sleep: - self.display.display("Sleeping for %d seconds..." % self.options.sleep) - time.sleep(self.options.sleep); + display.display("Sleeping for %d seconds..." % self.options.sleep) + time.sleep(self.options.sleep) # RUN the Checkout command rc, out, err = run_cmd(cmd, live=True) if rc != 0: if self.options.force: - self.display.warning("Unable to update repository. Continuing with (forced) run of playbook.") + display.warning("Unable to update repository. Continuing with (forced) run of playbook.") else: return rc elif self.options.ifchanged and '"changed": true' not in out: - self.display.display("Repository has not changed, quitting.") + display.display("Repository has not changed, quitting.") return 0 playbook = self.select_playbook(path) @@ -197,11 +205,10 @@ class PullCLI(CLI): try: shutil.rmtree(self.options.dest) except Exception as e: - self.display.error("Failed to remove %s: %s" % (self.options.dest, str(e))) + display.error("Failed to remove %s: %s" % (self.options.dest, str(e))) return rc - def try_playbook(self, path): if not os.path.exists(path): return 1 @@ -215,7 +222,7 @@ class PullCLI(CLI): playbook = os.path.join(path, self.args[0]) rc = self.try_playbook(playbook) if rc != 0: - self.display.warning("%s: %s" % (playbook, self.PLAYBOOK_ERRORS[rc])) + display.warning("%s: %s" % (playbook, self.PLAYBOOK_ERRORS[rc])) return None return playbook else: @@ -232,5 +239,5 @@ class PullCLI(CLI): else: errors.append("%s: %s" % (pb, self.PLAYBOOK_ERRORS[rc])) if playbook is None: - self.display.warning("\n".join(errors)) + display.warning("\n".join(errors)) return playbook diff --git a/lib/ansible/cli/vault.py b/lib/ansible/cli/vault.py index f3df8b084fa..82516085b8b 100644 --- a/lib/ansible/cli/vault.py +++ b/lib/ansible/cli/vault.py @@ -27,16 +27,24 @@ from ansible.parsing.dataloader import DataLoader from ansible.parsing.vault import VaultEditor from ansible.cli import CLI +try: + from __main__ import display + display = display +except ImportError: + from ansible.utils.display import Display + display = Display() + + class VaultCLI(CLI): """ Vault command line class """ VALID_ACTIONS = ("create", "decrypt", "edit", "encrypt", "rekey", "view") - def __init__(self, args, display=None): + def __init__(self, args): self.vault_pass = None self.new_vault_pass = None - super(VaultCLI, self).__init__(args, display) + super(VaultCLI, self).__init__(args) def parse(self): @@ -63,7 +71,7 @@ class VaultCLI(CLI): self.parser.set_usage("usage: %prog rekey [options] file_name") self.options, self.args = self.parser.parse_args() - self.display.verbosity = self.options.verbosity + display.verbosity = self.options.verbosity can_output = ['encrypt', 'decrypt'] @@ -117,24 +125,24 @@ class VaultCLI(CLI): def execute_encrypt(self): if len(self.args) == 0 and sys.stdin.isatty(): - self.display.display("Reading plaintext input from stdin", stderr=True) + display.display("Reading plaintext input from stdin", stderr=True) for f in self.args or ['-']: self.editor.encrypt_file(f, output_file=self.options.output_file) if sys.stdout.isatty(): - self.display.display("Encryption successful", stderr=True) + display.display("Encryption successful", stderr=True) def execute_decrypt(self): if len(self.args) == 0 and sys.stdin.isatty(): - self.display.display("Reading ciphertext input from stdin", stderr=True) + display.display("Reading ciphertext input from stdin", stderr=True) for f in self.args or ['-']: self.editor.decrypt_file(f, output_file=self.options.output_file) if sys.stdout.isatty(): - self.display.display("Decryption successful", stderr=True) + display.display("Decryption successful", stderr=True) def execute_create(self): @@ -160,4 +168,4 @@ class VaultCLI(CLI): for f in self.args: self.editor.rekey_file(f, self.new_vault_pass) - self.display.display("Rekey successful", stderr=True) + display.display("Rekey successful", stderr=True) diff --git a/lib/ansible/executor/playbook_executor.py b/lib/ansible/executor/playbook_executor.py index dad4ef61d6c..19e812804c0 100644 --- a/lib/ansible/executor/playbook_executor.py +++ b/lib/ansible/executor/playbook_executor.py @@ -27,7 +27,6 @@ import sys from ansible.compat.six import string_types -from ansible import constants as C from ansible.executor.task_queue_manager import TaskQueueManager from ansible.playbook import Playbook from ansible.template import Templar @@ -36,6 +35,14 @@ from ansible.utils.color import colorize, hostcolor from ansible.utils.encrypt import do_encrypt from ansible.utils.unicode import to_unicode +try: + from __main__ import display + display = display +except ImportError: + from ansible.utils.display import Display + display = Display() + + class PlaybookExecutor: ''' @@ -43,12 +50,11 @@ class PlaybookExecutor: basis for bin/ansible-playbook operation. ''' - def __init__(self, playbooks, inventory, variable_manager, loader, display, options, passwords): + def __init__(self, playbooks, inventory, variable_manager, loader, options, passwords): self._playbooks = playbooks self._inventory = inventory self._variable_manager = variable_manager self._loader = loader - self._display = display self._options = options self.passwords = passwords self._unreachable_hosts = dict() @@ -56,7 +62,7 @@ class PlaybookExecutor: if options.listhosts or options.listtasks or options.listtags or options.syntax: self._tqm = None else: - self._tqm = TaskQueueManager(inventory=inventory, variable_manager=variable_manager, loader=loader, display=display, options=options, passwords=self.passwords) + self._tqm = TaskQueueManager(inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=self.passwords) def run(self): @@ -81,7 +87,7 @@ class PlaybookExecutor: i = 1 plays = pb.get_plays() - self._display.vv('%d plays in %s' % (len(plays), playbook_path)) + display.vv('%d plays in %s' % (len(plays), playbook_path)) for play in plays: if play._included_path is not None: @@ -178,18 +184,18 @@ class PlaybookExecutor: self._cleanup() if self._options.syntax: - self.display.display("No issues encountered") + display.display("No issues encountered") return result # TODO: this stat summary stuff should be cleaned up and moved # to a new method, if it even belongs here... - self._display.banner("PLAY RECAP") + display.banner("PLAY RECAP") hosts = sorted(self._tqm._stats.processed.keys()) for h in hosts: t = self._tqm._stats.summarize(h) - self._display.display(u"%s : %s %s %s %s" % ( + display.display(u"%s : %s %s %s %s" % ( hostcolor(h, t), colorize(u'ok', t['ok'], 'green'), colorize(u'changed', t['changed'], 'yellow'), @@ -198,7 +204,7 @@ class PlaybookExecutor: screen_only=True ) - self._display.display(u"%s : %s %s %s %s" % ( + display.display(u"%s : %s %s %s %s" % ( hostcolor(h, t, False), colorize(u'ok', t['ok'], None), colorize(u'changed', t['changed'], None), @@ -207,7 +213,7 @@ class PlaybookExecutor: log_only=True ) - self._display.display("", screen_only=True) + display.display("", screen_only=True) # END STATS STUFF return result @@ -230,7 +236,7 @@ class PlaybookExecutor: serial_pct = int(play.serial.replace("%","")) serial = int((serial_pct/100.0) * len(all_hosts)) else: - if play.serial is None: + if play.serial is None: serial = -1 else: serial = int(play.serial) @@ -281,12 +287,12 @@ class PlaybookExecutor: second = do_prompt("confirm " + msg, private) if result == second: break - self._display.display("***** VALUES ENTERED DO NOT MATCH ****") + display.display("***** VALUES ENTERED DO NOT MATCH ****") else: result = do_prompt(msg, private) else: result = None - self._display.warning("Not prompting as we are not in interactive mode") + display.warning("Not prompting as we are not in interactive mode") # if result is false and default is not None if not result and default is not None: @@ -298,5 +304,3 @@ class PlaybookExecutor: # handle utf-8 chars result = to_unicode(result, errors='strict') return result - - diff --git a/lib/ansible/executor/task_queue_manager.py b/lib/ansible/executor/task_queue_manager.py index b11b6a674fa..fd910c3067d 100644 --- a/lib/ansible/executor/task_queue_manager.py +++ b/lib/ansible/executor/task_queue_manager.py @@ -21,7 +21,6 @@ __metaclass__ = type import multiprocessing import os -import socket import tempfile from ansible import constants as C @@ -34,8 +33,16 @@ from ansible.playbook.play_context import PlayContext from ansible.plugins import callback_loader, strategy_loader, module_loader from ansible.template import Templar +try: + from __main__ import display + display = display +except ImportError: + from ansible.utils.display import Display + display = Display() + __all__ = ['TaskQueueManager'] + class TaskQueueManager: ''' @@ -48,12 +55,11 @@ class TaskQueueManager: which dispatches the Play's tasks to hosts. ''' - def __init__(self, inventory, variable_manager, loader, display, options, passwords, stdout_callback=None): + def __init__(self, inventory, variable_manager, loader, options, passwords, stdout_callback=None): self._inventory = inventory self._variable_manager = variable_manager self._loader = loader - self._display = display self._options = options self._stats = AggregateStats() self.passwords = passwords @@ -155,7 +161,9 @@ class TaskQueueManager: elif callback_needs_whitelist and (C.DEFAULT_CALLBACK_WHITELIST is None or callback_name not in C.DEFAULT_CALLBACK_WHITELIST): continue - self._callback_plugins.append(callback_plugin(self._display)) + # is it too late to change the API for v2 callback plugins? + # display is not necessary. + self._callback_plugins.append(callback_plugin(display)) else: self._callback_plugins.append(callback_plugin()) @@ -221,7 +229,7 @@ class TaskQueueManager: return play_return def cleanup(self): - self._display.debug("RUNNING CLEANUP") + display.debug("RUNNING CLEANUP") self.terminate() self._final_q.close() self._cleanup_processes() @@ -275,4 +283,4 @@ class TaskQueueManager: v1_method = method.replace('v2_','') v1_method(*args, **kwargs) except Exception: - self._display.warning('Error when using %s: %s' % (method, str(e))) + display.warning('Error when using %s: %s' % (method, str(e))) diff --git a/lib/ansible/galaxy/__init__.py b/lib/ansible/galaxy/__init__.py index 3b63b2df9c9..00d8c25aecf 100644 --- a/lib/ansible/galaxy/__init__.py +++ b/lib/ansible/galaxy/__init__.py @@ -28,7 +28,6 @@ import os from ansible.compat.six import string_types from ansible.errors import AnsibleError -from ansible.utils.display import Display # default_readme_template # default_meta_template @@ -37,12 +36,7 @@ from ansible.utils.display import Display class Galaxy(object): ''' Keeps global galaxy info ''' - def __init__(self, options, display=None): - - if display is None: - self.display = Display() - else: - self.display = display + def __init__(self, options): self.options = options roles_paths = getattr(self.options, 'roles_path', []) @@ -65,11 +59,9 @@ class Galaxy(object): def remove_role(self, role_name): del self.roles[role_name] - def _str_from_data_file(self, filename): myfile = os.path.join(self.DATA_PATH, filename) try: return open(myfile).read() except Exception as e: raise AnsibleError("Could not open %s: %s" % (filename, str(e))) - diff --git a/test/units/executor/test_playbook_executor.py b/test/units/executor/test_playbook_executor.py index 60cf57b2559..4a8c27c71ac 100644 --- a/test/units/executor/test_playbook_executor.py +++ b/test/units/executor/test_playbook_executor.py @@ -61,7 +61,6 @@ class TestPlayIterator(unittest.TestCase): }) mock_inventory = MagicMock() - mock_display = MagicMock() mock_var_manager = MagicMock() # fake out options to use the syntax CLI switch, which will ensure @@ -74,7 +73,6 @@ class TestPlayIterator(unittest.TestCase): inventory=mock_inventory, variable_manager=mock_var_manager, loader=fake_loader, - display=mock_display, options=mock_options, passwords=[], )