def process_cli_result(stdout: str = None, stderr: str = None): res = None try: try: res = serialize.loads(stdout) if stdout else {} except errors.PrvsnrTypeDecodeError: logger.exception('Failed to decode provisioner output') res = serialize.loads(stdout, strict=False) except Exception: logger.exception(f"Unexpected result: {stdout}") if type(res) is not dict: raise errors.ProvisionerError(f'Unexpected result {stdout}') if 'exc' in res: logger.error("Provisioner CLI failed: {!r}".format(res['exc'])) raise res['exc'] else: try: return res['ret'] except KeyError: logger.error(f"No return data found in '{stdout}', " f"stderr: '{stderr}'") raise errors.ProvisionerError( f"No return data found in '{stdout}', " f"stderr: '{stderr}'")
def _run_cmd(cmd, env: Optional[Dict] = None, **kwargs): # Note. we update a copy of current process env since # subprocess.run will replace the env of the current # process if env is not None: env_copy = os.environ.copy() env_copy.update(env) env = env_copy try: logger.debug(f"Executing command: {cmd}") res = subprocess.run(cmd, env=env, **kwargs) # subprocess.run fails expectedly except subprocess.CalledProcessError as exc: return process_cli_result(exc.stdout, exc.stderr) # subprocess.run fails unexpectedly except Exception as exc: logger.exception("Failed to execute command") raise errors.ProvisionerError(repr(exc)) from exc else: return process_cli_result(res.stdout, res.stderr)