diff --git a/awx/main/isolated/manager.py b/awx/main/isolated/manager.py index e2836ae9e8..d783662759 100644 --- a/awx/main/isolated/manager.py +++ b/awx/main/isolated/manager.py @@ -29,15 +29,17 @@ def set_pythonpath(venv_libdir, env): class IsolatedManager(object): - def __init__(self, cancelled_callback=None): + def __init__(self, cancelled_callback=None, check_callback=None): """ :param cancelled_callback: a callable - which returns `True` or `False` - signifying if the job has been prematurely cancelled """ self.cancelled_callback = cancelled_callback + self.check_callback = check_callback self.idle_timeout = max(60, 2 * settings.AWX_ISOLATED_CONNECTION_TIMEOUT) self.started_at = None + self.captured_command_artifact = False def build_runner_params(self, hosts, verbosity=1): env = dict(os.environ.items()) @@ -188,6 +190,19 @@ class IsolatedManager(object): self.private_data_dir, extravars=extravars) status, rc = runner_obj.status, runner_obj.rc + + if self.check_callback is not None and not self.captured_command_artifact: + command_path = self.path_to('artifacts', self.ident, 'command') + # If the configuration artifact has been synced back, update the model + if os.path.exists(command_path): + try: + with open(command_path, 'r') as f: + data = json.load(f) + self.check_callback(data) + self.captured_command_artifact = True + except json.decoder.JSONDecodeError: # Just in case it's not fully here yet. + pass + self.consume_events(dispatcher) last_check = time.time() diff --git a/awx/main/tasks.py b/awx/main/tasks.py index 28f8b4eb0b..186fa466a0 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -1079,6 +1079,19 @@ class BaseTask(object): self.instance = self.update_model(self.instance.pk, job_args=json.dumps(runner_config.command), job_cwd=runner_config.cwd, job_env=job_env) + def check_handler(self, config): + ''' + IsolatedManager callback triggered by the repeated checks of the isolated node + ''' + job_env = build_safe_env(config['env']) + for k, v in self.safe_cred_env.items(): + if k in job_env: + job_env[k] = v + self.instance = self.update_model(self.instance.pk, + job_args=json.dumps(config['command']), + job_cwd=config['cwd'], + job_env=job_env) + @with_path_cleanup def run(self, pk, **kwargs): @@ -1100,6 +1113,7 @@ class BaseTask(object): Needs to be an object property because status_handler uses it in a callback context ''' self.safe_env = {} + self.safe_cred_env = {} private_data_dir = None isolated_manager_instance = None @@ -1152,8 +1166,11 @@ class BaseTask(object): for credential in credentials: if credential: credential.credential_type.inject_credential( - credential, env, self.safe_env, args, private_data_dir + credential, env, self.safe_cred_env, args, private_data_dir ) + + self.safe_env.update(self.safe_cred_env) + self.write_args_file(private_data_dir, args) password_prompts = self.get_password_prompts(passwords) @@ -1215,7 +1232,8 @@ class BaseTask(object): ) ansible_runner.utils.dump_artifacts(params) isolated_manager_instance = isolated_manager.IsolatedManager( - cancelled_callback=lambda: self.update_model(self.instance.pk).cancel_flag + cancelled_callback=lambda: self.update_model(self.instance.pk).cancel_flag, + check_callback=self.check_handler, ) status, rc = isolated_manager_instance.run(self.instance, private_data_dir,