def on_failed(self, host, results, ignore_errors=False): if self.runner.delegate_to: host = "%s -> %s" % (host, self.runner.delegate_to) results2 = results.copy() results2.pop("invocation", None) item = results2.get("item", None) parsed = results2.get("parsed", True) module_msg = "" if not parsed: module_msg = results2.pop("msg", None) stderr = results2.pop("stderr", None) stdout = results2.pop("stdout", None) returned_msg = results2.pop("msg", None) if item: msg = "failed: [%s] => (item=%s) => %s" % (host, item, utils.jsonify(results2)) else: msg = "failed: [%s] => %s" % (host, utils.jsonify(results2)) self.display(msg, color="red", runner=self.runner) if stderr: self.display("stderr: %s" % stderr, color="red", runner=self.runner) if stdout: self.display("stdout: %s" % stdout, color="red", runner=self.runner) if returned_msg: self.display("msg: %s" % returned_msg, color="red", runner=self.runner) if not parsed and module_msg: self.display(module_msg, color="red", runner=self.runner) if ignore_errors: self.display("...ignoring", color="cyan", runner=self.runner)
def on_failed(self, host, results, ignore_errors=False): if self.runner.delegate_to: host = '%s -> %s' % (host, self.runner.delegate_to) results2 = results.copy() results2.pop('invocation', None) item = results2.get('item', None) parsed = results2.get('parsed', True) returned_msg = results2.pop('msg', None) module_msg = '' if not parsed: module_msg = results2.pop('msg', None) if item: msg = "failed: [%s] => (item=%s) => %s" % (host, item, utils.jsonify(results2)) else: msg = "failed: [%s] => %s" % (host, utils.jsonify(results2)) file_logger().error(msg) if returned_msg: file_logger().error(returned_msg) if not parsed and module_msg: file_logger().error(module_msg) if ignore_errors: file_logger().info("...ignoring") super(MyPlaybookRunnerCallbacks, self).on_failed(host, results, ignore_errors=ignore_errors)
def regular_generic_msg(hostname, result, oneline, caption): ''' output on the result of a module run that is not command ''' if not oneline: return "%s | %s >> %s\n" % (hostname, caption, utils.jsonify(result,format=True)) else: return "%s | %s >> %s\n" % (hostname, caption, utils.jsonify(result))
def on_failed(self, host, results, ignore_errors=False): delegate_to = self.runner.module_vars.get('delegate_to') if delegate_to: host = '%s -> %s' % (host, delegate_to) results2 = results.copy() results2.pop('invocation', None) item = results2.get('item', None) parsed = results2.get('parsed', True) module_msg = '' if not parsed: module_msg = results2.pop('msg', None) stderr = results2.pop('stderr', None) stdout = results2.pop('stdout', None) returned_msg = results2.pop('msg', None) if item: msg = "failed: [%s] => (item=%s) => %s" % (host, item, utils.jsonify(results2)) else: msg = "failed: [%s] => %s" % (host, utils.jsonify(results2)) display(msg, self.sqs_response_queue, self.sqs_request_message) if stderr: display("stderr: %s" % stderr, self.sqs_response_queue, self.sqs_request_message) if stdout: display("stdout: %s" % stdout, self.sqs_response_queue, self.sqs_request_message) if returned_msg: display("msg: %s" % returned_msg, self.sqs_response_queue, self.sqs_request_message) if not parsed and module_msg: display("invalid output was: %s" % module_msg, self.sqs_response_queue, self.sqs_request_message) if ignore_errors: display("...ignoring", self.sqs_response_queue, self.sqs_request_message) super(PlaybookRunnerCallbacks, self).on_failed(host, results, ignore_errors=ignore_errors)
def on_ok(self, host, host_result): item = host_result.get('item', None) host_result2 = host_result.copy() host_result2.pop('invocation', None) verbose_always = host_result2.pop('verbose_always', False) changed = host_result.get('changed', False) ok_or_changed = 'ok' if changed: ok_or_changed = 'changed' # show verbose output for non-setup module results if --verbose is used msg = '' if (not self.verbose or host_result2.get("verbose_override", None) is not None) and not verbose_always: if item: msg = "%s: [%s] => (item=%s)" % (ok_or_changed, host, item) else: if 'ansible_job_id' not in host_result or 'finished' in host_result: msg = "%s: [%s]" % (ok_or_changed, host) else: # verbose ... if item: msg = "%s: [%s] => (item=%s) => %s" % ( ok_or_changed, host, item, utils.jsonify(host_result2, format=verbose_always)) else: if 'ansible_job_id' not in host_result or 'finished' in host_result2: msg = "%s: [%s] => %s" % (ok_or_changed, host, utils.jsonify(host_result2, format=verbose_always)) if msg != '': file_logger().info(msg) if 'warnings' in host_result2 and host_result2['warnings']: for warning in host_result2['warnings']: file_logger().warn("warning: %s" % warning) super(MyPlaybookRunnerCallbacks, self).on_ok(host, host_result)
def on_failed(self, host, results, ignore_errors=False): if self.runner.delegate_to: host = '%s -> %s' % (host, self.runner.delegate_to) results2 = results.copy() results2.pop('invocation', None) item = results2.get('item', None) parsed = results2.get('parsed', True) module_msg = '' if not parsed: module_msg = results2.pop('msg', None) stderr = results2.pop('stderr', None) stdout = results2.pop('stdout', None) returned_msg = results2.pop('msg', None) if item: msg = "failed: [%s] => (item=%s) => %s" % (host, item, utils.jsonify(results2)) else: msg = "failed: [%s] => %s" % (host, utils.jsonify(results2)) display(msg, color='red', runner=self.runner) if stderr: display("stderr: %s" % stderr, color='red', runner=self.runner) if stdout: display("stdout: %s" % stdout, color='red', runner=self.runner) if returned_msg: display("msg: %s" % returned_msg, color='red', runner=self.runner) if not parsed and module_msg: display(module_msg, color='red', runner=self.runner) if ignore_errors: display("...ignoring", color='cyan', runner=self.runner) super(PlaybookRunnerCallbacks, self).on_failed(host, results, ignore_errors=ignore_errors)
def runner_on_failed(self, host, res, ignore_errors=False): results2 = res.copy() results2.pop('invocation', None) item = results2.get('item', None) if item: msg = 'failed: [%s] => (item=%s) => %s' % (host, item, utils.jsonify(results2)) else: msg = 'failed: [%s] => %s' % (host, utils.jsonify(results2)) append_to_log(msg) update_to_slack()
def runner_on_failed(self, host, res, ignore_errors=False): results2 = res.copy() results2.pop('invocation', None) item = results2.get('item', None) if item: msg = "failed: [%s] => (item=%s) => %s" % (host, item, utils.jsonify(results2)) else: msg = "failed: [%s] => %s" % (host, utils.jsonify(results2)) if self._print_failed: self.append_report(msg)
def test_recursive_copy(self): pb = 'test/playbook-recursive-copy.yml' actual = self._run(pb) expected = { "localhost": { "changed": 65, "failures": 0, "ok": 73, "skipped": 0, "unreachable": 0 } } assert utils.jsonify(expected, format=True) == utils.jsonify(actual,format=True)
def _on_any(self, host, result): result2 = result.copy() result2.pop('invocation', None) (msg, color) = host_report_msg(host, self.options.module_name, result2, self.options.one_line) display(msg, color=color, runner=self.runner) if self.options.tree: utils.write_tree_file(self.options.tree, host, utils.jsonify(result2,format=True))
def _transfer_str(self, conn, tmp, name, data): ''' transfer string to remote file ''' if type(data) == dict: data = utils.jsonify(data) afd, afile = tempfile.mkstemp() afo = os.fdopen(afd, 'w') try: if not isinstance(data, unicode): #ensure the data is valid UTF-8 data.decode('utf-8') else: data = data.encode('utf-8') afo.write(data) except: raise errors.AnsibleError("failure encoding into utf-8") afo.flush() afo.close() remote = os.path.join(tmp, name) try: conn.put_file(afile, remote) finally: os.unlink(afile) return remote
def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False, executable='/bin/sh', in_data=None): ''' run a command on the remote host ''' if in_data: raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining") vvv("EXEC COMMAND %s" % cmd) if self.runner.sudo and sudoable: raise errors.AnsibleError( "When using fireball, do not specify sudo to run your tasks. " + "Instead sudo the fireball action with sudo. " + "Task will communicate with the fireball already running in sudo mode." ) data = dict( mode='command', cmd=cmd, tmp_path=tmp_path, executable=executable, ) data = utils.jsonify(data) data = utils.encrypt(self.key, data) self.socket.send(data) response = self.socket.recv() response = utils.decrypt(self.key, response) response = utils.parse_json(response) return (response.get('rc',None), '', response.get('stdout',''), response.get('stderr',''))
def get_ezjail_module(args): import ezjail encoded_args = repr(args.encode('utf-8')) encoded_lang = repr(ansible.constants.DEFAULT_MODULE_LANG) encoded_complex = repr(jsonify({})) fn = ezjail.__file__.replace('.pyc', '.py') with open(fn) as f: module_data = f.read() module_data = module_data.replace(module_common.REPLACER, module_common.MODULE_COMMON) module_data = module_data.replace(module_common.REPLACER_ARGS, encoded_args) module_data = module_data.replace(module_common.REPLACER_LANG, encoded_lang) module_data = module_data.replace(module_common.REPLACER_COMPLEX, encoded_complex) ofn = fn.replace('/ezjail.py', '/tmp_ezjail.py') with open(ofn, 'w') as f: f.write(module_data) code = compiler.compile(module_data, ofn, 'exec') ezjail = imp.new_module('ezjail') exec code in ezjail.__dict__ ezjail.__file__ = ofn class AnsibleModule(ezjail.AnsibleModule): def get_bin_path(self, arg, required=False, opt_dirs=[]): return '/usr/bin/%s' % arg ezjail.AnsibleModule = AnsibleModule module = AnsibleModule(**ezjail.MODULE_SPECS) return ezjail, module
def ansible_jeneric(job_id, user_id): # firebase authentication SECRET = os.environ['SECRET'] authentication = FirebaseAuthentication(SECRET, True, True) # set the specific job from firebase with user user = '******' + user_id URL = 'https://deploynebula.firebaseio.com/users/' + user + '/external_data/' myExternalData = FirebaseApplication(URL, authentication) # update status to RUNNING in firebase myExternalData.patch(job_id, json.loads('{"status":"RUNNING"}')) # finally, get the actual job job = myExternalData.get(URL, job_id) myHostList = job['host_list'] +',' myModuleName = job['module_name'] myModuleArgs = job['module_args'] myPattern = job['pattern'] myRemoteUser = job['remote_user'] myRemotePass = job['remote_pass'] runString = "" for arg in myHostList, myModuleName, myModuleArgs, myPattern, myRemoteUser, myRemotePass: if ( arg ): runString = runString + arg results = ansible.runner.Runner( pattern=myPattern, forks=10, module_name=myModuleName, module_args=myModuleArgs, remote_user=myRemoteUser, remote_pass=myRemotePass, host_list=myHostList, ).run() # run the ansible stuffs #results = ansible.runner.Runner( # pattern=myHost, forks=10, # module_name='command', module_args=myCommand, #).run() # get it to a good format #data = json.loads(results) #data = json.dumps(results) # set status to COMPLETE myExternalData.patch(job_id, json.loads('{"status":"COMPLETE"}')) if type(results) == dict: results = utils.jsonify(results) # post results to firebase myExternalData.post(job_id + '/returns', results) #returns.patch(job_id + '/returns', json.dumps(results)) return results
def set(self, key, value): value2 = jsonify(value) if self._timeout > 0: # a timeout of 0 is handled as meaning 'never expire' self._cache.setex(self._make_key(key), int(self._timeout), value2) else: self._cache.set(self._make_key(key), value2) self._cache.zadd(self._keys_set, time.time(), key)
def _copy_module(self, conn, tmp, module_name, module_args, inject, complex_args=None): ''' transfer a module over SFTP, does not run it ''' # FIXME if complex args is none, set to {} if module_name.startswith("/"): raise errors.AnsibleFileNotFound("%s is not a module" % module_name) # Search module path(s) for named module. in_path = utils.plugins.module_finder.find_plugin(module_name) if in_path is None: raise errors.AnsibleFileNotFound("module %s not found in %s" % (module_name, utils.plugins.module_finder.print_paths())) out_path = os.path.join(tmp, module_name) module_data = "" module_style = 'old' with open(in_path) as f: module_data = f.read() if module_common.REPLACER in module_data: module_style = 'new' if 'WANT_JSON' in module_data: module_style = 'non_native_want_json' complex_args_json = utils.jsonify(complex_args) # We force conversion of module_args to str because module_common calls shlex.split, # a standard library function that incorrectly handles Unicode input before Python 2.7.3. encoded_args = repr(module_args.encode('utf-8')) encoded_lang = repr(C.DEFAULT_MODULE_LANG) encoded_complex = repr(complex_args_json) module_data = module_data.replace(module_common.REPLACER, module_common.MODULE_COMMON) module_data = module_data.replace(module_common.REPLACER_ARGS, encoded_args) module_data = module_data.replace(module_common.REPLACER_LANG, encoded_lang) module_data = module_data.replace(module_common.REPLACER_COMPLEX, encoded_complex) if module_style == 'new': facility = C.DEFAULT_SYSLOG_FACILITY if 'ansible_syslog_facility' in inject: facility = inject['ansible_syslog_facility'] module_data = module_data.replace('syslog.LOG_USER', "syslog.%s" % facility) lines = module_data.split("\n") shebang = None if lines[0].startswith("#!"): shebang = lines[0].strip() args = shlex.split(str(shebang[2:])) interpreter = args[0] interpreter_config = 'ansible_%s_interpreter' % os.path.basename(interpreter) if interpreter_config in inject: lines[0] = shebang = "#!%s %s" % (inject[interpreter_config], " ".join(args[1:])) module_data = "\n".join(lines) self._transfer_str(conn, tmp, module_name, module_data) return (out_path, module_style, shebang)
def on_ok(self, host, host_result): if self.runner.delegate_to: host = "%s -> %s" % (host, self.runner.delegate_to) item = host_result.get("item", None) host_result2 = host_result.copy() host_result2.pop("invocation", None) verbose_always = host_result2.pop("verbose_always", False) changed = host_result.get("changed", False) ok_or_changed = "ok" if changed: ok_or_changed = "changed" # show verbose output for non-setup module results if --verbose is used msg = "" if (not self.verbose or host_result2.get("verbose_override", None) is not None) and not verbose_always: if item: msg = "%s: [%s] => (item=%s)" % (ok_or_changed, host, item) else: if "ansible_job_id" not in host_result or "finished" in host_result: msg = "%s: [%s]" % (ok_or_changed, host) else: # verbose ... if item: msg = "%s: [%s] => (item=%s) => %s" % ( ok_or_changed, host, item, utils.jsonify(host_result2, format=verbose_always), ) else: if "ansible_job_id" not in host_result or "finished" in host_result2: msg = "%s: [%s] => %s" % (ok_or_changed, host, utils.jsonify(host_result2, format=verbose_always)) if msg != "": if not changed: self.display(msg, color="green", runner=self.runner) else: self.display(msg, color="orange", runner=self.runner) if constants.COMMAND_WARNINGS and "warnings" in host_result2 and host_result2["warnings"]: for warning in host_result2["warnings"]: self.display("warning: %s" % warning, color="purple", runner=self.runner)
def test_one(self): pb = 'test/playbook1.yml' actual = self._run(pb) expected = { "localhost": { "changed": 9, "failures": 0, "ok": 11, "skipped": 1, "unreachable": 0 } } assert utils.jsonify(expected, format=True) == utils.jsonify(actual,format=True) # make sure the template module took options from the vars section data = file('/tmp/ansible_test_data_template.out').read() assert data.find("ears") != -1, "template success"
def on_unreachable(self, host, res): if type(res) == dict: res = res.get('msg','') res = to_bytes(res) display("%s | FAILED => %s" % (host, res), stderr=True, color='red', runner=self.runner) if self.options.tree: utils.write_tree_file( self.options.tree, host, utils.jsonify(dict(failed=True, msg=res),format=True) ) super(CliRunnerCallbacks, self).on_unreachable(host, res)
def on_ok(self, host, host_result): if self.runner.delegate_to: host = '%s -> %s' % (host, self.runner.delegate_to) item = host_result.get('item', None) host_result2 = host_result.copy() host_result2.pop('invocation', None) verbose_always = host_result2.pop('verbose_always', False) changed = host_result.get('changed', False) ok_or_changed = 'ok' if changed: ok_or_changed = 'changed' # show verbose output for non-setup module results if --verbose is used msg = '' if (not self.verbose or host_result2.get("verbose_override", None) is not None) and not verbose_always: if item: msg = "%s: [%s] => (item=%s)" % (ok_or_changed, host, item) else: if 'ansible_job_id' not in host_result or 'finished' in host_result: msg = "%s: [%s]" % (ok_or_changed, host) else: # verbose ... if item: msg = "%s: [%s] => (item=%s) => %s" % (ok_or_changed, host, item, utils.jsonify(host_result2, format=verbose_always)) else: if 'ansible_job_id' not in host_result or 'finished' in host_result2: msg = "%s: [%s] => %s" % (ok_or_changed, host, utils.jsonify(host_result2, format=verbose_always)) if msg != '': if not changed: display(msg, color='green', runner=self.runner, task_id=self.task_id) else: display(msg, color='yellow', runner=self.runner, task_id=self.task_id) if constants.COMMAND_WARNINGS and 'warnings' in host_result2 and host_result2['warnings']: for warning in host_result2['warnings']: display("warning: %s" % warning, color='purple', runner=self.runner, task_id=self.task_id) super(PlaybookRunnerCallbacks, self).on_ok(host, host_result)
def test_one(self): pb = os.path.join(self.test_dir, 'playbook1.yml') actual = self._run(pb) # if different, this will output to screen print "**ACTUAL**" print utils.jsonify(actual, format=True) expected = { "localhost": { "changed": 9, "failures": 0, "ok": 11, "skipped": 1, "unreachable": 0 } } print "**EXPECTED**" print utils.jsonify(expected, format=True) assert utils.jsonify(expected, format=True) == utils.jsonify(actual,format=True) # make sure the template module took options from the vars section data = file('/tmp/ansible_test_data_template.out').read() print data assert data.find("ears") != -1, "template success"
def fetch_file(self, in_path, out_path): ''' save a remote file to the specified path ''' vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host) data = dict(mode='fetch', in_path=in_path) data = utils.jsonify(data) data = utils.encrypt(self.key, data) if self.send_data(data): raise errors.AnsibleError("failed to initiate the file fetch with %s" % self.host) fh = open(out_path, "w") try: bytes = 0 while True: response = self.recv_data() if not response: raise errors.AnsibleError("Failed to get a response from %s" % self.host) response = utils.decrypt(self.key, response) response = utils.parse_json(response) if response.get('failed', False): raise errors.AnsibleError("Error during file fetch, aborting") out = base64.b64decode(response['data']) fh.write(out) bytes += len(out) # send an empty response back to signify we # received the last chunk without errors data = utils.jsonify(dict()) data = utils.encrypt(self.key, data) if self.send_data(data): raise errors.AnsibleError("failed to send ack during file fetch") if response.get('last', False): break finally: # we don't currently care about this final response, # we just receive it and drop it. It may be used at some # point in the future or we may just have the put/fetch # operations not send back a final response at all response = self.recv_data() vvv("FETCH wrote %d bytes to %s" % (bytes, out_path)) fh.close()
def _test_playbook_undefined_vars(self, playbook, fail_on_undefined): # save DEFAULT_UNDEFINED_VAR_BEHAVIOR so we can restore it in the end of the test saved_undefined_var_behavior = C.DEFAULT_UNDEFINED_VAR_BEHAVIOR C.DEFAULT_UNDEFINED_VAR_BEHAVIOR = fail_on_undefined test_callbacks = TestCallbacks() playbook = ansible.playbook.PlayBook( playbook=os.path.join(self.test_dir, 'test_playbook_undefined_vars', playbook), host_list='test/test_playbook_undefined_vars/hosts', stats=ans_callbacks.AggregateStats(), callbacks=test_callbacks, runner_callbacks=test_callbacks ) actual = playbook.run() C.DEFAULT_UNDEFINED_VAR_BEHAVIOR = saved_undefined_var_behavior # if different, this will output to screen print "**ACTUAL**" print utils.jsonify(actual, format=True) expected = { "localhost": { "changed": 0, "failures": 0, "ok": int(not fail_on_undefined) + 1, "skipped": 0, "unreachable": int(fail_on_undefined) } } print "**EXPECTED**" print utils.jsonify(expected, format=True) assert utils.jsonify(expected, format=True) == utils.jsonify(actual, format=True)
def test_playbook_always_run(self): test_callbacks = TestCallbacks() playbook = ansible.playbook.PlayBook( playbook=os.path.join(self.test_dir, 'playbook-always-run.yml'), host_list='test/ansible_hosts', stats=ans_callbacks.AggregateStats(), callbacks=test_callbacks, runner_callbacks=test_callbacks, check=True ) actual = playbook.run() # if different, this will output to screen print "**ACTUAL**" print utils.jsonify(actual, format=True) expected = { "localhost": { "changed": 4, "failures": 0, "ok": 4, "skipped": 8, "unreachable": 0 } } print "**EXPECTED**" print utils.jsonify(expected, format=True) assert utils.jsonify(expected, format=True) == utils.jsonify(actual,format=True)
def test_templated_includes(self): pb = os.path.join(self.test_dir, 'playbook-templated-includer.yml') actual = self._run(pb, extra_vars={ 'dir': self.test_dir }) # if different, this will output to screen print "**ACTUAL**" actual_json = utils.jsonify(actual, format=True) print actual_json expected = { "localhost": { "changed": 0, "failures": 0, "ok": 2, "skipped": 0, "unreachable": 0 } } expected_json = utils.jsonify(expected, format=True) print "**EXPECTED**" print expected_json assert actual_json == expected_json
def modify_module(self, module_path, complex_args, module_args, inject): with open(module_path) as f: # read in the module source module_data = f.read() (module_data, module_style) = self._find_snippet_imports(module_data, module_path) complex_args_json = utils.jsonify(complex_args) # We force conversion of module_args to str because module_common calls shlex.split, # a standard library function that incorrectly handles Unicode input before Python 2.7.3. # Note: it would be better to do all this conversion at the border # (when the data is originally parsed into data structures) but # it's currently coming from too many sources to make that # effective. try: encoded_args = repr(module_args.encode('utf-8')) except UnicodeDecodeError: encoded_args = repr(module_args) try: encoded_complex = repr(complex_args_json.encode('utf-8')) except UnicodeDecodeError: encoded_complex = repr(complex_args_json.encode('utf-8')) # these strings should be part of the 'basic' snippet which is required to be included module_data = module_data.replace(REPLACER_VERSION, repr(__version__)) module_data = module_data.replace(REPLACER_SELINUX, ','.join(C.DEFAULT_SELINUX_SPECIAL_FS)) module_data = module_data.replace(REPLACER_ARGS, encoded_args) module_data = module_data.replace(REPLACER_COMPLEX, encoded_complex) if module_style == 'new': facility = C.DEFAULT_SYSLOG_FACILITY if 'ansible_syslog_facility' in inject: facility = inject['ansible_syslog_facility'] module_data = module_data.replace('syslog.LOG_USER', "syslog.%s" % facility) lines = module_data.split("\n") shebang = None if lines[0].startswith("#!"): shebang = lines[0].strip() args = shlex.split(str(shebang[2:])) interpreter = args[0] interpreter_config = 'ansible_%s_interpreter' % os.path.basename(interpreter) if interpreter_config in inject: interpreter = to_bytes(inject[interpreter_config], errors='strict') lines[0] = shebang = "#!%s %s" % (interpreter, " ".join(args[1:])) module_data = "\n".join(lines) return (module_data, module_style, shebang)
def on_ok(self, host, host_result): delegate_to = self.runner.module_vars.get('delegate_to') if delegate_to: host = '%s -> %s' % (host, delegate_to) item = host_result.get('item', None) host_result2 = host_result.copy() host_result2.pop('invocation', None) verbose_always = host_result2.pop('verbose_always', False) changed = host_result.get('changed', False) ok_or_changed = 'ok' if changed: ok_or_changed = 'changed' # show verbose output for non-setup module results if --verbose is used msg = '' if (not self.verbose or host_result2.get("verbose_override",None) is not None) and not verbose_always: if item: msg = "%s: [%s] => (item=%s)" % (ok_or_changed, host, item) else: if 'ansible_job_id' not in host_result or 'finished' in host_result: msg = "%s: [%s]" % (ok_or_changed, host) else: # verbose ... if item: msg = "%s: [%s] => (item=%s) => %s" % (ok_or_changed, host, item, utils.jsonify(host_result2, format=verbose_always)) else: if 'ansible_job_id' not in host_result or 'finished' in host_result2: msg = "%s: [%s] => %s" % (ok_or_changed, host, utils.jsonify(host_result2, format=verbose_always)) if msg != '': if not changed: display(msg, self.sqs_response_queue, self.sqs_request_message) else: display(msg, self.sqs_response_queue, self.sqs_request_message) super(PlaybookRunnerCallbacks, self).on_ok(host, host_result)
def put_file(self, in_path, out_path): ''' transfer a file from local to remote ''' vvv("PUT %s TO %s" % (in_path, out_path), host=self.host) if not os.path.exists(in_path): raise errors.AnsibleFileNotFound("file or module does not exist: %s" % in_path) data = file(in_path).read() data = dict(mode='put', data=data, out_path=out_path) data = utils.jsonify(data) data = utils.encrypt(self.key, data) self.socket.send(data) response = self.socket.recv() response = utils.decrypt(self.key, response) response = utils.parse_json(response)
def fetch_file(self, in_path, out_path): ''' save a remote file to the specified path ''' vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host) data = dict(mode='fetch', file=in_path) data = utils.jsonify(data) data = utils.encrypt(self.key, data) self.socket.send(data) response = self.socket.recv() response = utils.decrypt(self.key, response) response = utils.parse_json(response) response = response['data'] fh = open(out_path, "w") fh.write(response) fh.close()
def put_file(self, in_path, out_path): ''' transfer a file from local to remote ''' vvv("PUT %s TO %s" % (in_path, out_path), host=self.host) if not os.path.exists(in_path): raise errors.AnsibleFileNotFound("file or module does not exist: %s" % in_path) fd = file(in_path, 'rb') fstat = os.stat(in_path) try: vvv("PUT file is %d bytes" % fstat.st_size) last = False while fd.tell() <= fstat.st_size and not last: vvvv("file position currently %ld, file size is %ld" % (fd.tell(), fstat.st_size)) data = fd.read(CHUNK_SIZE) if fd.tell() >= fstat.st_size: last = True data = dict(mode='put', data=base64.b64encode(data), out_path=out_path, last=last) if self.runner.sudo: data['user'] = self.runner.sudo_user data = utils.jsonify(data) data = utils.encrypt(self.key, data) if self.send_data(data): raise errors.AnsibleError("failed to send the file to %s" % self.host) response = self.recv_data() if not response: raise errors.AnsibleError("Failed to get a response from %s" % self.host) response = utils.decrypt(self.key, response) response = utils.parse_json(response) if response.get('failed',False): raise errors.AnsibleError("failed to put the file in the requested location") finally: fd.close() vvvv("waiting for final response after PUT") response = self.recv_data() if not response: raise errors.AnsibleError("Failed to get a response from %s" % self.host) response = utils.decrypt(self.key, response) response = utils.parse_json(response) if response.get('failed',False): raise errors.AnsibleError("failed to put the file in the requested location")
def put_file(self, in_path, out_path): ''' transfer a file from local to remote ''' vvv("PUT %s TO %s" % (in_path, out_path), host=self.host) if not os.path.exists(in_path): raise errors.AnsibleFileNotFound("file or module does not exist: %s" % in_path) data = file(in_path).read() data = base64.b64encode(data) data = dict(mode='put', data=data, out_path=out_path) # TODO: support chunked file transfer data = utils.jsonify(data) data = utils.encrypt(self.key, data) self.socket.send(data) response = self.socket.recv() response = utils.decrypt(self.key, response) response = utils.parse_json(response)
def modify_module(self, module_path, complex_args, module_args, inject): with open(module_path) as f: # read in the module source module_data = f.read() (module_data, module_style) = self._find_snippet_imports(module_data, module_path) complex_args_json = utils.jsonify(complex_args) # We force conversion of module_args to str because module_common calls shlex.split, # a standard library function that incorrectly handles Unicode input before Python 2.7.3. try: encoded_args = repr(module_args.encode('utf-8')) except UnicodeDecodeError: encoded_args = repr(module_args) encoded_complex = repr(complex_args_json) # these strings should be part of the 'basic' snippet which is required to be included module_data = module_data.replace(REPLACER_VERSION, repr(__version__)) module_data = module_data.replace(REPLACER_ARGS, encoded_args) module_data = module_data.replace(REPLACER_COMPLEX, encoded_complex) if module_style == 'new': facility = C.DEFAULT_SYSLOG_FACILITY if 'ansible_syslog_facility' in inject: facility = inject['ansible_syslog_facility'] module_data = module_data.replace('syslog.LOG_USER', "syslog.%s" % facility) lines = module_data.split("\n") shebang = None if lines[0].startswith("#!"): shebang = lines[0].strip() args = shlex.split(str(shebang[2:])) interpreter = args[0] interpreter_config = 'ansible_%s_interpreter' % os.path.basename(interpreter) if interpreter_config in inject: lines[0] = shebang = "#!%s %s" % (inject[interpreter_config], " ".join(args[1:])) module_data = "\n".join(lines) return (module_data, module_style, shebang)
def validate_user(self): ''' Checks the remote uid of the accelerated daemon vs. the one specified for this play and will cause the accel daemon to exit if they don't match ''' vvvv("%s: sending request for validate_user" % self.host) data = dict( mode='validate_user', username=self.user, ) data = utils.jsonify(data) data = utils.encrypt(self.key, data) if self.send_data(data): raise AnsibleError("Failed to send command to %s" % self.host) vvvv("%s: waiting for validate_user response" % self.host) while True: # we loop here while waiting for the response, because a # long running command may cause us to receive keepalive packets # ({"pong":"true"}) rather than the response we want. response = self.recv_data() if not response: raise AnsibleError("Failed to get a response from %s" % self.host) response = utils.decrypt(self.key, response) response = utils.parse_json(response) if "pong" in response: # it's a keepalive, go back to waiting vvvv("%s: received a keepalive packet" % self.host) continue else: vvvv("%s: received the validate_user response: %s" % (self.host, response)) break if response.get('failed'): return False else: return response.get('rc') == 0
def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False, executable='/bin/sh', in_data=None, su_user=None, su=None): ''' run a command on the remote host ''' if in_data: raise errors.AnsibleError( "Internal Error: this module does not support optimized module pipelining" ) vvv("EXEC COMMAND %s" % cmd) if (self.runner.sudo and sudoable) or (self.runner.su and su): raise errors.AnsibleError( "When using fireball, do not specify sudo or su to run your tasks. " + "Instead sudo the fireball action with sudo. " + "Task will communicate with the fireball already running in sudo mode." ) data = dict( mode='command', cmd=cmd, tmp_path=tmp_path, executable=executable, ) data = utils.jsonify(data) data = utils.encrypt(self.key, data) self.socket.send(data) response = self.socket.recv() response = utils.decrypt(self.key, response) response = utils.parse_json(response) return (response.get('rc', None), '', response.get('stdout', ''), response.get('stderr', ''))
def _copy_module(self, conn, tmp, module_name, module_args, inject, complex_args=None): ''' transfer a module over SFTP, does not run it ''' # FIXME if complex args is none, set to {} if module_name.startswith("/"): raise errors.AnsibleFileNotFound("%s is not a module" % module_name) # Search module path(s) for named module. in_path = utils.plugins.module_finder.find_plugin(module_name) if in_path is None: raise errors.AnsibleFileNotFound("module %s not found in %s" % (module_name, utils.plugins.module_finder.print_paths())) out_path = os.path.join(tmp, module_name) module_data = "" is_new_style=False with open(in_path) as f: module_data = f.read() if module_common.REPLACER in module_data: is_new_style=True complex_args_json = utils.jsonify(complex_args) encoded_args = "\"\"\"%s\"\"\"" % module_args.replace("\"","\\\"") encoded_lang = "\"\"\"%s\"\"\"" % C.DEFAULT_MODULE_LANG encoded_complex = "\"\"\"%s\"\"\"" % complex_args_json.replace("\\", "\\\\") module_data = module_data.replace(module_common.REPLACER, module_common.MODULE_COMMON) module_data = module_data.replace(module_common.REPLACER_ARGS, encoded_args) module_data = module_data.replace(module_common.REPLACER_LANG, encoded_lang) module_data = module_data.replace(module_common.REPLACER_COMPLEX, encoded_complex) if is_new_style: facility = C.DEFAULT_SYSLOG_FACILITY if 'ansible_syslog_facility' in inject: facility = inject['ansible_syslog_facility'] module_data = module_data.replace('syslog.LOG_USER', "syslog.%s" % facility) lines = module_data.split("\n") shebang = None if lines[0].startswith("#!"): shebang = lines[0] args = shlex.split(str(shebang[2:])) interpreter = args[0] interpreter_config = 'ansible_%s_interpreter' % os.path.basename(interpreter) if interpreter_config in inject: lines[0] = shebang = "#!%s %s" % (inject[interpreter_config], " ".join(args[1:])) module_data = "\n".join(lines) self._transfer_str(conn, tmp, module_name, module_data) return (out_path, is_new_style, shebang)
def _transfer_str(self, conn, tmp, name, data): ''' transfer string to remote file ''' if type(data) == dict: data = utils.jsonify(data) afd, afile = tempfile.mkstemp() afo = os.fdopen(afd, 'w') try: afo.write(data.encode('utf8')) except: raise errors.AnsibleError("failure encoding into utf-8") afo.flush() afo.close() remote = os.path.join(tmp, name) try: conn.put_file(afile, remote) finally: os.unlink(afile) return remote
def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False, executable='/bin/sh'): ''' run a command on the remote host ''' if executable == "": executable = constants.DEFAULT_EXECUTABLE if self.runner.sudo and sudoable and sudo_user: cmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd) vvv("EXEC COMMAND %s" % cmd) data = dict( mode='command', cmd=cmd, tmp_path=tmp_path, executable=executable, ) data = utils.jsonify(data) data = utils.encrypt(self.key, data) if self.send_data(data): raise errors.AnsibleError("Failed to send command to %s" % self.host) while True: # we loop here while waiting for the response, because a # long running command may cause us to receive keepalive packets # ({"pong":"true"}) rather than the response we want. response = self.recv_data() if not response: raise errors.AnsibleError("Failed to get a response from %s" % self.host) response = utils.decrypt(self.key, response) response = utils.parse_json(response) if "pong" in response: # it's a keepalive, go back to waiting vvvv("%s: received a keepalive packet" % self.host) continue else: vvvv("%s: received the response" % self.host) break return (response.get('rc',None), '', response.get('stdout',''), response.get('stderr',''))
def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False): ''' run a command on the remote host ''' vvv("EXEC COMMAND %s" % cmd) if self.runner.sudo and sudoable: raise errors.AnsibleError("fireball does not use sudo, but runs as whoever it was initiated as. (That itself is where to use sudo).") data = dict( mode='command', cmd=cmd, tmp_path=tmp_path, ) data = utils.jsonify(data) data = utils.encrypt(self.key, data) self.socket.send(data) response = self.socket.recv() response = utils.decrypt(self.key, response) response = utils.parse_json(response) return (response.get('rc',None), '', response.get('stdout',''), response.get('stderr',''))
def _executor_internal_inner(self, host, module_name, module_args, inject, port, is_chained=False): ''' decides how to invoke a module ''' # special non-user/non-fact variables: # 'groups' variable is a list of host name in each group # 'hostvars' variable contains variables for each host name # ... and is set elsewhere # 'inventory_hostname' is also set elsewhere inject['groups'] = self.inventory.groups_list() # allow module args to work as a dictionary # though it is usually a string new_args = "" if type(module_args) == dict: for (k,v) in module_args.iteritems(): new_args = new_args + "%s='%s' " % (k,v) module_args = new_args conditional = utils.template(self.basedir, self.conditional, inject) if not utils.check_conditional(conditional): result = utils.jsonify(dict(skipped=True)) self.callbacks.on_skipped(host, inject.get('item',None)) return ReturnData(host=host, result=result) conn = None actual_host = host try: delegate_to = inject.get('delegate_to', None) alternative_host = inject.get('ansible_ssh_host', None) if delegate_to is not None: actual_host = delegate_to elif alternative_host is not None: actual_host = alternative_host conn = self.connector.connect(actual_host, port) if delegate_to is not None or alternative_host is not None: conn._delegate_for = host except errors.AnsibleConnectionFailed, e: result = dict(failed=True, msg="FAILED: %s" % str(e)) return ReturnData(host=host, comm_ok=False, result=result)
def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False, executable='/bin/sh'): ''' run a command on the remote host ''' if executable == "": executable = constants.DEFAULT_EXECUTABLE if self.runner.sudo and sudoable and sudo_user: cmd, prompt = utils.make_sudo_cmd(sudo_user, executable, cmd) vvv("EXEC COMMAND %s" % cmd) data = dict( mode='command', cmd=cmd, tmp_path=tmp_path, executable=executable, ) data = utils.jsonify(data) data = utils.encrypt(self.key, data) if self.send_data(data): raise errors.AnsibleError("Failed to send command to %s" % self.host) response = self.recv_data() if not response: raise errors.AnsibleError("Failed to get a response from %s" % self.host) response = utils.decrypt(self.key, response) response = utils.parse_json(response) return (response.get('rc', None), '', response.get('stdout', ''), response.get('stderr', ''))
def test_includes(self): pb = os.path.join(self.test_dir, 'playbook-includer.yml') actual = self._run(pb) # if different, this will output to screen print "**ACTUAL**" print utils.jsonify(actual, format=True) expected = { "localhost": { "changed": 0, "failures": 0, "ok": 10, "skipped": 0, "unreachable": 0 } } print "**EXPECTED**" print utils.jsonify(expected, format=True) assert utils.jsonify(expected, format=True) == utils.jsonify(actual,format=True)
def test_lookups(self): pb = os.path.join(self.test_dir, 'lookup_plugins.yml') actual = self._run(pb) # if different, this will output to screen print "**ACTUAL**" print utils.jsonify(actual, format=True) expected = { "localhost": { "changed": 7, "failures": 0, "ok": 9, "skipped": 1, "unreachable": 0 } } print "**EXPECTED**" print utils.jsonify(expected, format=True) assert utils.jsonify(expected, format=True) == utils.jsonify(actual,format=True) print "len(EVENTS) = %d" % len(EVENTS) assert len(EVENTS) == 26
def _executor_internal_inner(self, host, module_name, module_args, inject, port, is_chained=False, complex_args=None): ''' decides how to invoke a module ''' # allow module args to work as a dictionary # though it is usually a string new_args = "" if type(module_args) == dict: for (k, v) in module_args.iteritems(): new_args = new_args + "%s='%s' " % (k, v) module_args = new_args module_name = utils.template(self.basedir, module_name, inject) module_args = utils.template(self.basedir, module_args, inject) complex_args = utils.template(self.basedir, complex_args, inject) if module_name in utils.plugins.action_loader: if self.background != 0: raise errors.AnsibleError( "async mode is not supported with the %s module" % module_name) handler = utils.plugins.action_loader.get(module_name, self) elif self.background == 0: handler = utils.plugins.action_loader.get('normal', self) else: handler = utils.plugins.action_loader.get('async', self) conditional = utils.template(self.basedir, self.conditional, inject, expand_lists=False) if not utils.check_conditional(conditional): result = utils.jsonify(dict(skipped=True)) self.callbacks.on_skipped(host, inject.get('item', None)) return ReturnData(host=host, result=result) conn = None actual_host = inject.get('ansible_ssh_host', host) actual_port = port actual_user = inject.get('ansible_ssh_user', self.remote_user) actual_pass = inject.get('ansible_ssh_pass', self.remote_pass) actual_transport = inject.get('ansible_connection', self.transport) if actual_transport in ['paramiko', 'ssh']: actual_port = inject.get('ansible_ssh_port', port) # the delegated host may have different SSH port configured, etc # and we need to transfer those, and only those, variables delegate_to = inject.get('delegate_to', None) if delegate_to is not None: delegate_to = utils.template(self.basedir, delegate_to, inject) inject = inject.copy() interpreters = [] for i in inject: if i.startswith("ansible_") and i.endswith("_interpreter"): interpreters.append(i) for i in interpreters: del inject[i] port = C.DEFAULT_REMOTE_PORT try: delegate_info = inject['hostvars'][delegate_to] actual_host = delegate_info.get('ansible_ssh_host', delegate_to) actual_port = delegate_info.get('ansible_ssh_port', port) actual_user = delegate_info.get('ansible_ssh_user', actual_user) actual_pass = delegate_info.get('ansible_ssh_pass', actual_pass) actual_transport = delegate_info.get('ansible_connection', self.transport) for i in delegate_info: if i.startswith("ansible_") and i.endswith("_interpreter"): inject[i] = delegate_info[i] except errors.AnsibleError: actual_host = delegate_to actual_port = port actual_user = utils.template(self.basedir, actual_user, inject) actual_pass = utils.template(self.basedir, actual_pass, inject) try: if actual_port is not None: actual_port = int(actual_port) except ValueError, e: result = dict( failed=True, msg= "FAILED: Configured port \"%s\" is not a valid port, expected integer" % actual_port) return ReturnData(host=host, comm_ok=False, result=result)
def _executor_internal_inner(self, host, module_name, module_args, inject, port, is_chained=False, complex_args=None): ''' decides how to invoke a module ''' # late processing of parameterized sudo_user (with_items,..) if self.sudo_user_var is not None: self.sudo_user = template.template(self.basedir, self.sudo_user_var, inject) # allow module args to work as a dictionary # though it is usually a string new_args = "" if type(module_args) == dict: for (k,v) in module_args.iteritems(): new_args = new_args + "%s='%s' " % (k,v) module_args = new_args # module_name may be dynamic (but cannot contain {{ ansible_ssh_user }}) module_name = template.template(self.basedir, module_name, inject) if module_name in utils.plugins.action_loader: if self.background != 0: raise errors.AnsibleError("async mode is not supported with the %s module" % module_name) handler = utils.plugins.action_loader.get(module_name, self) elif self.background == 0: handler = utils.plugins.action_loader.get('normal', self) else: handler = utils.plugins.action_loader.get('async', self) if type(self.conditional) != list: self.conditional = [ self.conditional ] for cond in self.conditional: if not utils.check_conditional(cond, self.basedir, inject, fail_on_undefined=self.error_on_undefined_vars): result = utils.jsonify(dict(changed=False, skipped=True)) self.callbacks.on_skipped(host, inject.get('item',None)) return ReturnData(host=host, result=result) if getattr(handler, 'setup', None) is not None: handler.setup(module_name, inject) conn = None actual_host = inject.get('ansible_ssh_host', host) # allow ansible_ssh_host to be templated actual_host = template.template(self.basedir, actual_host, inject, fail_on_undefined=True) actual_port = port actual_user = inject.get('ansible_ssh_user', self.remote_user) actual_pass = inject.get('ansible_ssh_pass', self.remote_pass) actual_transport = inject.get('ansible_connection', self.transport) actual_private_key_file = inject.get('ansible_ssh_private_key_file', self.private_key_file) if self.accelerate and actual_transport != 'local': #Fix to get the inventory name of the host to accelerate plugin if inject.get('ansible_ssh_host', None): self.accelerate_inventory_host = host else: self.accelerate_inventory_host = None # if we're using accelerated mode, force the # transport to accelerate actual_transport = "accelerate" if not self.accelerate_port: self.accelerate_port = C.ACCELERATE_PORT if actual_transport in [ 'paramiko', 'ssh', 'accelerate' ]: actual_port = inject.get('ansible_ssh_port', port) # the delegated host may have different SSH port configured, etc # and we need to transfer those, and only those, variables delegate_to = inject.get('delegate_to', None) if delegate_to is not None: delegate_to = template.template(self.basedir, delegate_to, inject) inject = inject.copy() interpreters = [] for i in inject: if i.startswith("ansible_") and i.endswith("_interpreter"): interpreters.append(i) for i in interpreters: del inject[i] port = C.DEFAULT_REMOTE_PORT try: delegate_info = inject['hostvars'][delegate_to] actual_host = delegate_info.get('ansible_ssh_host', delegate_to) # allow ansible_ssh_host to be templated actual_host = template.template(self.basedir, actual_host, inject, fail_on_undefined=True) actual_port = delegate_info.get('ansible_ssh_port', port) actual_user = delegate_info.get('ansible_ssh_user', actual_user) actual_pass = delegate_info.get('ansible_ssh_pass', actual_pass) actual_private_key_file = delegate_info.get('ansible_ssh_private_key_file', self.private_key_file) actual_transport = delegate_info.get('ansible_connection', self.transport) for i in delegate_info: if i.startswith("ansible_") and i.endswith("_interpreter"): inject[i] = delegate_info[i] except errors.AnsibleError: actual_host = delegate_to actual_port = port # user/pass may still contain variables at this stage actual_user = template.template(self.basedir, actual_user, inject) actual_pass = template.template(self.basedir, actual_pass, inject) # make actual_user available as __magic__ ansible_ssh_user variable inject['ansible_ssh_user'] = actual_user try: if actual_transport == 'accelerate': # for accelerate, we stuff both ports into a single # variable so that we don't have to mangle other function # calls just to accomodate this one case actual_port = [actual_port, self.accelerate_port] elif actual_port is not None: actual_port = int(template.template(self.basedir, actual_port, inject)) except ValueError, e: result = dict(failed=True, msg="FAILED: Configured port \"%s\" is not a valid port, expected integer" % actual_port) return ReturnData(host=host, comm_ok=False, result=result)
def _execute_module(self, conn, tmp, module_name, args, async_jid=None, async_module=None, async_limit=None, inject=None, persist_files=False, complex_args=None): ''' runs a module that has already been transferred ''' # hack to support fireball mode if module_name == 'fireball': args = "%s password=%s" % (args, base64.b64encode(str(utils.key_for_hostname(conn.host)))) if 'port' not in args: args += " port=%s" % C.ZEROMQ_PORT (remote_module_path, module_style, shebang) = self._copy_module(conn, tmp, module_name, args, inject, complex_args) environment_string = self._compute_environment_string(inject) cmd_mod = "" if self.sudo and self.sudo_user != 'root': # deal with possible umask issues once sudo'ed to other user cmd_chmod = "chmod a+r %s" % remote_module_path self._low_level_exec_command(conn, cmd_chmod, tmp, sudoable=False) cmd = "" if module_style != 'new': if 'CHECKMODE=True' in args: # if module isn't using AnsibleModuleCommon infrastructure we can't be certain it knows how to # do --check mode, so to be safe we will not run it. return ReturnData(conn=conn, result=dict(skippped=True, msg="cannot yet run check mode against old-style modules")) args = template.template(self.basedir, args, inject) # decide whether we need to transfer JSON or key=value argsfile = None if module_style == 'non_native_want_json': if complex_args: complex_args.update(utils.parse_kv(args)) argsfile = self._transfer_str(conn, tmp, 'arguments', utils.jsonify(complex_args)) else: argsfile = self._transfer_str(conn, tmp, 'arguments', utils.jsonify(utils.parse_kv(args))) else: argsfile = self._transfer_str(conn, tmp, 'arguments', args) if self.sudo and self.sudo_user != 'root': # deal with possible umask issues once sudo'ed to other user cmd_args_chmod = "chmod a+r %s" % argsfile self._low_level_exec_command(conn, cmd_args_chmod, tmp, sudoable=False) if async_jid is None: cmd = "%s %s" % (remote_module_path, argsfile) else: cmd = " ".join([str(x) for x in [remote_module_path, async_jid, async_limit, async_module, argsfile]]) else: if async_jid is None: cmd = "%s" % (remote_module_path) else: cmd = " ".join([str(x) for x in [remote_module_path, async_jid, async_limit, async_module]]) if not shebang: raise errors.AnsibleError("module is missing interpreter line") cmd = " ".join([environment_string.strip(), shebang.replace("#!","").strip(), cmd]) cmd = cmd.strip() if tmp.find("tmp") != -1 and not C.DEFAULT_KEEP_REMOTE_FILES and not persist_files: if not self.sudo or self.sudo_user == 'root': # not sudoing or sudoing to root, so can cleanup files in the same step cmd = cmd + "; rm -rf %s >/dev/null 2>&1" % tmp sudoable = True if module_name == "accelerate": # always run the accelerate module as the user # specified in the play, not the sudo_user sudoable = False res = self._low_level_exec_command(conn, cmd, tmp, sudoable=sudoable) if self.sudo and self.sudo_user != 'root': # not sudoing to root, so maybe can't delete files as that other user # have to clean up temp files as original user in a second step if tmp.find("tmp") != -1 and not C.DEFAULT_KEEP_REMOTE_FILES and not persist_files: cmd2 = "rm -rf %s >/dev/null 2>&1" % tmp self._low_level_exec_command(conn, cmd2, tmp, sudoable=False) data = utils.parse_json(res['stdout']) if 'parsed' in data and data['parsed'] == False: data['msg'] += res['stderr'] return ReturnData(conn=conn, result=data)
def _executor_internal_inner(self, host, module_name, module_args, inject, port, is_chained=False): ''' decides how to invoke a module ''' # special non-user/non-fact variables: # 'groups' variable is a list of host name in each group # 'hostvars' variable contains variables for each host name # ... and is set elsewhere # 'inventory_hostname' is also set elsewhere inject['groups'] = self.inventory.groups_list() # allow module args to work as a dictionary # though it is usually a string new_args = "" if type(module_args) == dict: for (k, v) in module_args.iteritems(): new_args = new_args + "%s='%s' " % (k, v) module_args = new_args conditional = utils.template(self.basedir, self.conditional, inject) if not utils.check_conditional(conditional): result = utils.jsonify(dict(skipped=True)) self.callbacks.on_skipped(host, inject.get('item', None)) return ReturnData(host=host, result=result) conn = None actual_host = inject.get('ansible_ssh_host', host) actual_port = port if self.transport in ['paramiko', 'ssh']: actual_port = inject.get('ansible_ssh_port', port) # the delegated host may have different SSH port configured, etc # and we need to transfer those, and only those, variables delegate_to = inject.get('delegate_to', None) if delegate_to is not None: delegate_to = utils.template(self.basedir, delegate_to, inject) inject = inject.copy() interpreters = [] for i in inject: if i.startswith("ansible_") and i.endswith("_interpreter"): interpreters.append(i) for i in interpreters: del inject[i] port = C.DEFAULT_REMOTE_PORT try: delegate_info = inject['hostvars'][delegate_to] actual_host = delegate_info.get('ansible_ssh_host', delegate_to) actual_port = delegate_info.get('ansible_ssh_port', port) for i in delegate_info: if i.startswith("ansible_") and i.endswith("_interpreter"): inject[i] = delegate_info[i] except errors.AnsibleError: actual_host = delegate_to actual_port = port try: if actual_port is not None: actual_port = int(actual_port) conn = self.connector.connect(actual_host, actual_port) if delegate_to or host != actual_host: conn.delegate = host except errors.AnsibleConnectionFailed, e: result = dict(failed=True, msg="FAILED: %s" % str(e)) return ReturnData(host=host, comm_ok=False, result=result)
def _copy_module(self, conn, tmp, module_name, module_args, inject, complex_args=None): ''' transfer a module over SFTP, does not run it ''' # FIXME if complex args is none, set to {} if module_name.startswith("/"): raise errors.AnsibleFileNotFound("%s is not a module" % module_name) # Search module path(s) for named module. in_path = utils.plugins.module_finder.find_plugin(module_name) if in_path is None: raise errors.AnsibleFileNotFound( "module %s not found in %s" % (module_name, utils.plugins.module_finder.print_paths())) out_path = os.path.join(tmp, module_name) module_data = "" module_style = 'old' with open(in_path) as f: module_data = f.read() if module_common.REPLACER in module_data: module_style = 'new' if 'WANT_JSON' in module_data: module_style = 'non_native_want_json' complex_args_json = utils.jsonify(complex_args) # We force conversion of module_args to str because module_common calls shlex.split, # a standard library function that incorrectly handles Unicode input before Python 2.7.3. encoded_args = repr(str(module_args)) encoded_lang = repr(C.DEFAULT_MODULE_LANG) encoded_complex = repr(complex_args_json) module_data = module_data.replace(module_common.REPLACER, module_common.MODULE_COMMON) module_data = module_data.replace(module_common.REPLACER_ARGS, encoded_args) module_data = module_data.replace(module_common.REPLACER_LANG, encoded_lang) module_data = module_data.replace(module_common.REPLACER_COMPLEX, encoded_complex) if module_style == 'new': facility = C.DEFAULT_SYSLOG_FACILITY if 'ansible_syslog_facility' in inject: facility = inject['ansible_syslog_facility'] module_data = module_data.replace('syslog.LOG_USER', "syslog.%s" % facility) lines = module_data.split("\n") shebang = None if lines[0].startswith("#!"): shebang = lines[0].strip() args = shlex.split(str(shebang[2:])) interpreter = args[0] interpreter_config = 'ansible_%s_interpreter' % os.path.basename( interpreter) if interpreter_config in inject: lines[0] = shebang = "#!%s %s" % (inject[interpreter_config], " ".join(args[1:])) module_data = "\n".join(lines) self._transfer_str(conn, tmp, module_name, module_data) return (out_path, module_style, shebang)
return value finally: f.close() def set(self, key, value): self._cache[key] = value cachefile = "%s/%s" % (self._cache_dir, key) try: f = codecs.open(cachefile, 'w', encoding='utf-8') except (OSError, IOError), e: utils.warning("error while trying to read %s : %s" % (cachefile, str(e))) else: f.write(utils.jsonify(value)) finally: f.close() def has_expired(self, key): cachefile = "%s/%s" % (self._cache_dir, key) try: st = os.stat(cachefile) except (OSError, IOError), e: if e.errno == errno.ENOENT: return False else: utils.warning("error while trying to stat %s : %s" % (cachefile, str(e)))