From d732c94ac23be49e71df1410027b3f39f9d86b68 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Mon, 6 Apr 2015 22:31:55 -0400 Subject: [PATCH] a bunch of updates to connection info and related, to pass down passwords also now options populate required fields in required order allowing play to override added capture of debug in action plugins when stdout is not json --- v2/ansible/executor/connection_info.py | 77 +++++++++++++++-------- v2/ansible/executor/playbook_executor.py | 5 +- v2/ansible/executor/task_queue_manager.py | 5 +- v2/ansible/playbook/play.py | 2 +- v2/ansible/plugins/action/__init__.py | 6 +- v2/ansible/plugins/connections/local.py | 3 + v2/ansible/plugins/connections/ssh.py | 4 +- v2/bin/ansible | 3 +- v2/bin/ansible-playbook | 2 +- 9 files changed, 72 insertions(+), 35 deletions(-) diff --git a/v2/ansible/executor/connection_info.py b/v2/ansible/executor/connection_info.py index 165cd1245f..19c8b130c7 100644 --- a/v2/ansible/executor/connection_info.py +++ b/v2/ansible/executor/connection_info.py @@ -38,34 +38,40 @@ class ConnectionInformation: connection/authentication information. ''' - def __init__(self, play=None, options=None): - # FIXME: implement the new methodology here for supporting - # various different auth escalation methods (becomes, etc.) + def __init__(self, play=None, options=None, passwords=None): - self.connection = C.DEFAULT_TRANSPORT + if passwords is None: + passwords = {} + + # connection + self.connection = None self.remote_addr = None - self.remote_user = 'root' - self.password = '' - self.port = 22 + self.remote_user = None + self.password = passwords.get('conn_pass','') + self.port = None self.private_key_file = None + + # privilege escalation + self.become = None + self.become_method = None + self.become_user = None + self.become_pass = passwords.get('become_pass','') + + # general flags (should we move out?) self.verbosity = 0 self.only_tags = set() self.skip_tags = set() - - # privilege escalation - self.become = False - self.become_method = C.DEFAULT_BECOME_METHOD - self.become_user = '' - self.become_pass = '' - self.no_log = False self.check_mode = False + #TODO: just pull options setup to above? + # set options before play to allow play to override them + if options: + self.set_options(options) + if play: self.set_play(play) - if options: - self.set_options(options) def __repr__(self): value = "CONNECTION INFO:\n" @@ -84,12 +90,18 @@ class ConnectionInformation: if play.connection: self.connection = play.connection - self.remote_user = play.remote_user - self.password = '' - self.port = int(play.port) if play.port else 22 - self.become = play.become - self.become_method = play.become_method - self.become_user = play.become_user + if play.remote_user: + self.remote_user = play.remote_user + + if play.port: + self.port = int(play.port) + + if play.become is not None: + self.become = play.become + if play.become_method: + self.become_method = play.become_method + if play.become_user: + self.become_user = play.become_user self.become_pass = play.become_pass # non connection related @@ -103,15 +115,30 @@ class ConnectionInformation: higher precedence than those set on the play or host. ''' - # FIXME: set other values from options here? - - self.verbosity = options.verbosity if options.connection: self.connection = options.connection + self.remote_user = options.remote_user + #if 'port' in options and options.port is not None: + # self.port = options.port + self.private_key_file = None + + # privilege escalation + self.become = options.become + self.become_method = options.become_method + self.become_user = options.become_user + self.become_pass = '' + + # general flags (should we move out?) + if options.verbosity: + self.verbosity = options.verbosity + #if options.no_log: + # self.no_log = boolean(options.no_log) if options.check: self.check_mode = boolean(options.check) + + # get the tag info from options, converting a comma-separated list # of values into a proper list if need be. We check to see if the # options have the attribute, as it is not always added via the CLI diff --git a/v2/ansible/executor/playbook_executor.py b/v2/ansible/executor/playbook_executor.py index 6504fddfc8..40c0798b00 100644 --- a/v2/ansible/executor/playbook_executor.py +++ b/v2/ansible/executor/playbook_executor.py @@ -36,18 +36,19 @@ class PlaybookExecutor: basis for bin/ansible-playbook operation. ''' - def __init__(self, playbooks, inventory, variable_manager, loader, display, options): + def __init__(self, playbooks, inventory, variable_manager, loader, display, options, conn_pass, become_pass): self._playbooks = playbooks self._inventory = inventory self._variable_manager = variable_manager self._loader = loader self._display = display self._options = options + self.passwords = {'conn_pass': conn_pass, 'become_pass': become_pass} if options.listhosts or options.listtasks or options.listtags: self._tqm = None else: - self._tqm = TaskQueueManager(inventory=inventory, callback='default', variable_manager=variable_manager, loader=loader, display=display, options=options) + self._tqm = TaskQueueManager(inventory=inventory, callback='default', variable_manager=variable_manager, loader=loader, display=display, options=options, passwords=self.passwords) def run(self): diff --git a/v2/ansible/executor/task_queue_manager.py b/v2/ansible/executor/task_queue_manager.py index d0354786da..026726b3d8 100644 --- a/v2/ansible/executor/task_queue_manager.py +++ b/v2/ansible/executor/task_queue_manager.py @@ -48,7 +48,7 @@ class TaskQueueManager: which dispatches the Play's tasks to hosts. ''' - def __init__(self, inventory, callback, variable_manager, loader, display, options): + def __init__(self, inventory, callback, variable_manager, loader, display, options, passwords): self._inventory = inventory self._variable_manager = variable_manager @@ -56,6 +56,7 @@ class TaskQueueManager: self._display = display self._options = options self._stats = AggregateStats() + self.passwords = passwords # a special flag to help us exit cleanly self._terminated = False @@ -144,7 +145,7 @@ class TaskQueueManager: new_play = play.copy() new_play.post_validate(all_vars, fail_on_undefined=False) - connection_info = ConnectionInformation(new_play, self._options) + connection_info = ConnectionInformation(new_play, self._options, self.passwords) for callback_plugin in self._callback_plugins: if hasattr(callback_plugin, 'set_connection_info'): callback_plugin.set_connection_info(connection_info) diff --git a/v2/ansible/playbook/play.py b/v2/ansible/playbook/play.py index eeabfce062..33fd5efd9f 100644 --- a/v2/ansible/playbook/play.py +++ b/v2/ansible/playbook/play.py @@ -61,7 +61,7 @@ class Play(Base, Taggable, Become): _hosts = FieldAttribute(isa='list', default=[], required=True) _name = FieldAttribute(isa='string', default='') _port = FieldAttribute(isa='int', default=22) - _remote_user = FieldAttribute(isa='string', default='root') + _remote_user = FieldAttribute(isa='string') # Variable Attributes _vars = FieldAttribute(isa='dict', default=dict()) diff --git a/v2/ansible/plugins/action/__init__.py b/v2/ansible/plugins/action/__init__.py index 2d258dd525..2f56c4df58 100644 --- a/v2/ansible/plugins/action/__init__.py +++ b/v2/ansible/plugins/action/__init__.py @@ -415,7 +415,11 @@ class ActionBase: # FIXME: in error situations, the stdout may not contain valid data, so we # should check for bad rc codes better to catch this here if 'stdout' in res and res['stdout'].strip(): - data = json.loads(self._filter_leading_non_json_lines(res['stdout'])) + try: + data = json.loads(self._filter_leading_non_json_lines(res['stdout'])) + except ValueError: + # not valid json, lets try to capture error + data = {'traceback': res['stdout']} if 'parsed' in data and data['parsed'] == False: data['msg'] += res['stderr'] # pre-split stdout into lines, if stdout is in the data and there diff --git a/v2/ansible/plugins/connections/local.py b/v2/ansible/plugins/connections/local.py index c847ee79d5..31d0b296e4 100644 --- a/v2/ansible/plugins/connections/local.py +++ b/v2/ansible/plugins/connections/local.py @@ -37,6 +37,9 @@ class Connection(ConnectionBase): def connect(self, port=None): ''' connect to the local host; nothing to do here ''' + + self._display.vvv("ESTABLISH LOCAL CONNECTION FOR USER: %s" % self._connection_info.remote_user, host=self._connection_info.remote_addr) + return self def exec_command(self, cmd, tmp_path, executable='/bin/sh', in_data=None): diff --git a/v2/ansible/plugins/connections/ssh.py b/v2/ansible/plugins/connections/ssh.py index e233a704f9..e59311ead9 100644 --- a/v2/ansible/plugins/connections/ssh.py +++ b/v2/ansible/plugins/connections/ssh.py @@ -57,7 +57,7 @@ class Connection(ConnectionBase): def connect(self): ''' connect to the remote host ''' - self._display.vvv("ESTABLISH CONNECTION FOR USER: %s" % self._connection_info.remote_user, host=self._connection_info.remote_addr) + self._display.vvv("ESTABLISH SSH CONNECTION FOR USER: %s" % self._connection_info.remote_user, host=self._connection_info.remote_addr) self._common_args = [] extra_args = C.ANSIBLE_SSH_ARGS @@ -99,7 +99,7 @@ class Connection(ConnectionBase): self._common_args += ["-o", "KbdInteractiveAuthentication=no", "-o", "PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey", "-o", "PasswordAuthentication=no"] - if self._connection_info.remote_user != pwd.getpwuid(os.geteuid())[0]: + if self._connection_info.remote_user is not None and self._connection_info.remote_user != pwd.getpwuid(os.geteuid())[0]: self._common_args += ["-o", "User="+self._connection_info.remote_user] # FIXME: figure out where this goes #self._common_args += ["-o", "ConnectTimeout=%d" % self.runner.timeout] diff --git a/v2/bin/ansible b/v2/bin/ansible index 7d2f01bc5c..9b3ccd38be 100755 --- a/v2/bin/ansible +++ b/v2/bin/ansible @@ -93,6 +93,7 @@ class Cli(object): normalize_become_options(options) (sshpass, becomepass, vault_pass) = ask_passwords(options) + passwords = { 'conn_pass': sshpass, 'become_pass': becomepass } if options.vault_password_file: # read vault_pass from a file @@ -138,7 +139,7 @@ class Cli(object): # now create a task queue manager to execute the play try: display = Display() - tqm = TaskQueueManager(inventory=inventory, callback='minimal', variable_manager=variable_manager, loader=loader, display=display, options=options) + tqm = TaskQueueManager(inventory=inventory, callback='minimal', variable_manager=variable_manager, loader=loader, display=display, options=options, passwords=passwords) result = tqm.run(play) tqm.cleanup() except AnsibleError: diff --git a/v2/bin/ansible-playbook b/v2/bin/ansible-playbook index 79c2eed785..000a0b74c7 100755 --- a/v2/bin/ansible-playbook +++ b/v2/bin/ansible-playbook @@ -127,7 +127,7 @@ def main(display, args): raise errors.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=args, inventory=inventory, variable_manager=variable_manager, loader=loader, display=display, options=options) + pbex = PlaybookExecutor(playbooks=args, inventory=inventory, variable_manager=variable_manager, loader=loader, display=display, options=options, conn_pass=sshpass, become_pass=becomepass) results = pbex.run()