예제 #1
0
    def prepare_ansible_config_command(self,
                                       action,
                                       config_file=None,
                                       only_changed=None):

        if action not in AnsibleCfgConfig._supported_actions:
            raise ConfigurationError(
                "Invalid action {0}, valid value is one of either {1}".format(
                    action, ", ".join(AnsibleCfgConfig._supported_actions)))

        if action != 'dump' and only_changed:
            raise ConfigurationError(
                "only_changed is applicable for action 'dump'")
        self._prepare_env(runner_mode=self.runner_mode)
        self.cmdline_args = []

        self.cmdline_args.append(action)
        if config_file:
            self.cmdline_args.extend(['-c', config_file])

        if only_changed:
            self.cmdline_args.append('--only-changed')

        self.command = [self._ansible_config_exec_path] + self.cmdline_args
        self._handle_command_wrap(self.execution_mode, self.cmdline_args)
예제 #2
0
    def get_contents(self, path):
        '''
        Loads the contents of the file specified by path

        Args:
            path (string): The relative or absolute path to the file to
                be loaded.  If the path is relative, then it is combined
                with the base_path to generate a full path string

        Returns:
            string: The contents of the file as a string

        Raises:
            ConfigurationError: If the file cannot be loaded
        '''
        try:
            if not os.path.exists(path):
                raise ConfigurationError('specified path does not exist %s' %
                                         path)

            with open(path) as f:
                data = f.read()

            return data

        except (IOError, OSError) as exc:
            raise ConfigurationError('error trying to load file contents: %s' %
                                     exc)
예제 #3
0
    def prepare_plugin_docs_command(self, plugin_names, plugin_type=None, response_format=None,
                                    snippet=False, playbook_dir=None, module_path=None):

        if response_format and response_format not in DocConfig._supported_response_formats:
            raise ConfigurationError("Invalid response_format {0}, valid value is one of either {1}".format(response_format,
                                                                                                            ", ".join(DocConfig._supported_response_formats)))

        if not isinstance(plugin_names, list):
            raise ConfigurationError("plugin_names should be of type list, instead received {0} of type {1}".format(plugin_names, type(plugin_names)))

        self._prepare_env(runner_mode=self.runner_mode)
        self.command = ['ansible-doc']
        self.cmdline_args = []

        if response_format == 'json':
            self.cmdline_args.append('-j')

        if snippet:
            self.cmdline_args.append('-s')

        if plugin_type:
            self.cmdline_args.extend(['-t', plugin_type])

        if playbook_dir:
            self.cmdline_args.extend(['--playbook-dir', playbook_dir])

        if module_path:
            self.cmdline_args.extend(['-M', module_path])

        self.cmdline_args.append(" ".join(plugin_names))

        self.command = ['ansible-doc'] + self.cmdline_args
        self._handle_command_wrap(self.execution_mode, self.cmdline_args)
예제 #4
0
    def prepare(self):
        if self.private_data_dir is None:
            raise ConfigurationError("Runner Base Directory is not defined")
        if self.playbook is None: # TODO: ad-hoc mode, module and args
            raise ConfigurationError("Runner playbook is not defined")
        if not os.path.exists(self.artifact_dir):
            os.makedirs(self.artifact_dir)

        self.prepare_inventory()
        self.prepare_env()
        self.prepare_command()

        # write the SSH key data into a fifo read by ssh-agent
        if self.ssh_key_data:
            self.ssh_key_path = os.path.join(self.artifact_dir, 'ssh_key_data')
            self.ssh_auth_sock = os.path.join(self.artifact_dir, 'ssh_auth.sock')
            self.open_fifo_write(self.ssh_key_path, self.ssh_key_data)
            self.command = self.wrap_args_with_ssh_agent(self.command, self.ssh_key_path, self.ssh_auth_sock)

        # Use local callback directory
        callback_dir = os.getenv('AWX_LIB_DIRECTORY')
        if callback_dir is None:
            callback_dir = os.path.join(os.path.split(os.path.abspath(__file__))[0],
                                        "callbacks")
        self.env['ANSIBLE_CALLBACK_PLUGINS'] = callback_dir
        if 'AD_HOC_COMMAND_ID' in self.env:
            self.env['ANSIBLE_STDOUT_CALLBACK'] = 'minimal'
        else:
            self.env['ANSIBLE_STDOUT_CALLBACK'] = 'awx_display'
        self.env['ANSIBLE_RETRY_FILES_ENABLED'] = 'False'
        self.env['ANSIBLE_HOST_KEY_CHECKING'] = 'False'
        self.env['AWX_ISOLATED_DATA_DIR'] = self.artifact_dir
        self.env['PYTHONPATH'] = self.env.get('PYTHONPATH', '') + callback_dir + ':'
예제 #5
0
    def prepare_inventory_command(self,
                                  action,
                                  inventories,
                                  response_format=None,
                                  host=None,
                                  playbook_dir=None,
                                  vault_ids=None,
                                  vault_password_file=None):

        if action not in InventoryConfig._supported_actions:
            raise ConfigurationError(
                "Invalid action {0}, valid value is one of either {1}".format(
                    action, ", ".join(InventoryConfig._supported_actions)))

        if response_format and response_format not in InventoryConfig._supported_response_formats:
            raise ConfigurationError(
                "Invalid response_format {0}, valid value is one of "
                "either {1}".format(
                    response_format,
                    ", ".join(InventoryConfig._supported_response_formats)))

        if not isinstance(inventories, list):
            raise ConfigurationError(
                "inventories should be of type list, instead received {0} of type {1}"
                .format(inventories, type(inventories)))

        if action == "host" and host is None:
            raise ConfigurationError(
                "Value of host parameter is required when action in 'host'")

        if action == "graph" and response_format and response_format != 'json':
            raise ConfigurationError(
                "'graph' action supports only 'json' response format")

        self._prepare_env(runner_mode=self.runner_mode)
        self.cmdline_args = []

        self.cmdline_args.append('--{0}'.format(action))
        if action == 'host':
            self.cmdline_args.append(host)

        for inv in inventories:
            self.cmdline_args.extend(['-i', inv])

        if response_format in ['yaml', 'toml']:
            self.cmdline_args.append('--{0}'.format(response_format))

        if playbook_dir:
            self.cmdline_args.extend(['--playbook-dir', playbook_dir])

        if vault_ids:
            self.cmdline_args.extend(['--vault-id', vault_ids])

        if vault_password_file:
            self.cmdline_args.extend(
                ['--vault-password-file', vault_password_file])

        self.command = ['ansible-inventory'] + self.cmdline_args
        self._handle_command_wrap(self.execution_mode, self.cmdline_args)
예제 #6
0
    def prepare(self):
        """
        Performs basic checks and then properly invokes

        - prepare_inventory
        - prepare_env
        - prepare_command

        It's also responsible for wrapping the command with the proper ssh agent invocation
        and setting early ANSIBLE_ environment variables.
        """
        # ansible_path = find_executable('ansible')
        # if ansible_path is None or not os.access(ansible_path, os.X_OK):
        #     raise ConfigurationError("Ansible not found. Make sure that it is installed.")
        if self.private_data_dir is None:
            raise ConfigurationError("Runner Base Directory is not defined")
        if self.module is None and self.playbook is None:  # TODO: ad-hoc mode, module and args
            raise ConfigurationError(
                "Runner playbook or module is not defined")
        if self.module and self.playbook:
            raise ConfigurationError(
                "Only one of playbook and module options are allowed")
        if not os.path.exists(self.artifact_dir):
            os.makedirs(self.artifact_dir)

        self.prepare_inventory()
        self.prepare_env()
        self.prepare_command()

        # write the SSH key data into a fifo read by ssh-agent
        if self.ssh_key_data:
            self.ssh_key_path = os.path.join(self.artifact_dir, 'ssh_key_data')
            self.open_fifo_write(self.ssh_key_path, self.ssh_key_data)
            self.command = self.wrap_args_with_ssh_agent(
                self.command, self.ssh_key_path)

        # Use local callback directory
        callback_dir = os.getenv('AWX_LIB_DIRECTORY')
        if callback_dir is None:
            callback_dir = os.path.join(
                os.path.split(os.path.abspath(__file__))[0], "callbacks")
        python_path = os.getenv('PYTHONPATH', '')
        if python_path:
            python_path += ":"
        self.env['ANSIBLE_CALLBACK_PLUGINS'] = callback_dir
        if 'AD_HOC_COMMAND_ID' in self.env:
            self.env['ANSIBLE_STDOUT_CALLBACK'] = 'minimal'
        else:
            self.env['ANSIBLE_STDOUT_CALLBACK'] = 'awx_display'
        self.env['ANSIBLE_RETRY_FILES_ENABLED'] = 'False'
        self.env['ANSIBLE_HOST_KEY_CHECKING'] = 'False'
        self.env['AWX_ISOLATED_DATA_DIR'] = self.artifact_dir

        self.env['PYTHONPATH'] = python_path + callback_dir + ':'
        if self.roles_path:
            self.env['ANSIBLE_ROLES_PATH'] = ':'.join(self.roles_path)

        if self.process_isolation:
            self.command = self.wrap_args_with_process_isolation(self.command)
예제 #7
0
    def load_file(self, path, objtype=None, encoding='utf-8'):
        '''
        Load the file specified by path

        This method will first try to load the file contents from cache and
        if there is a cache miss, it will load the contents from disk

        Args:
            path (string): The full or relative path to the file to be loaded

            encoding (string): The file contents text encoding

            objtype (object): The object type of the file contents.  This
                is used to type check the deserialized content against the
                contents loaded from disk.
                Ignore serializing if objtype is string_types

        Returns:
            object: The deserialized file contents which could be either a
                string object or a dict object

        Raises:
            ConfigurationError:
        '''
        path = self.abspath(path)
        debug('file path is %s' % path)

        if path in self._cache:
            return self._cache[path]

        try:
            debug('cache miss, attempting to load file from disk: %s' % path)
            contents = parsed_data = self.get_contents(path)
            if encoding:
                parsed_data = contents.encode(encoding)
        except ConfigurationError as exc:
            debug(exc)
            raise
        except UnicodeEncodeError:
            raise ConfigurationError('unable to encode file contents')

        if objtype is not string_types:
            for deserializer in (self._load_json, self._load_yaml):
                parsed_data = deserializer(contents)
                if parsed_data:
                    break

            if objtype and not isinstance(parsed_data, objtype):
                debug('specified file %s is not of type %s' % (path, objtype))
                raise ConfigurationError(
                    'invalid file serialization type for contents')

        self._cache[path] = parsed_data
        return parsed_data
예제 #8
0
    def prepare(self):
        """
        Performs basic checks and then properly invokes

        - prepare_inventory
        - prepare_env
        - prepare_command

        It's also responsible for wrapping the command with the proper ssh agent invocation
        and setting early ANSIBLE_ environment variables.
        """
        # ansible_path = find_executable('ansible')
        # if ansible_path is None or not os.access(ansible_path, os.X_OK):
        #     raise ConfigurationError("Ansible not found. Make sure that it is installed.")
        if self.private_data_dir is None:
            raise ConfigurationError("Runner Base Directory is not defined")
        if self.module and self.playbook:
            raise ConfigurationError(
                "Only one of playbook and module options are allowed")
        if not os.path.exists(self.artifact_dir):
            os.makedirs(self.artifact_dir, mode=0o700)
        if self.sandboxed and self.directory_isolation_path is not None:
            self.directory_isolation_path = tempfile.mkdtemp(
                prefix='runner_di_', dir=self.directory_isolation_path)
            if os.path.exists(self.project_dir):
                output.debug(
                    "Copying directory tree from {} to {} for working directory isolation"
                    .format(self.project_dir, self.directory_isolation_path))
                copy_tree(self.project_dir,
                          self.directory_isolation_path,
                          preserve_symlinks=True)

        self.prepare_env()
        self.prepare_inventory()
        self.prepare_command()

        if self.execution_mode == ExecutionMode.ANSIBLE_PLAYBOOK and self.playbook is None:
            raise ConfigurationError(
                "Runner playbook required when running ansible-playbook")
        elif self.execution_mode == ExecutionMode.ANSIBLE and self.module is None:
            raise ConfigurationError(
                "Runner module required when running ansible")
        elif self.execution_mode == ExecutionMode.NONE:
            raise ConfigurationError("No executable for runner to run")

        self._handle_command_wrap()

        debug('env:')
        for k, v in sorted(self.env.items()):
            debug(f' {k}: {v}')
        if hasattr(self, 'command') and isinstance(self.command, list):
            debug(f"command: {' '.join(self.command)}")
예제 #9
0
    def prepare_plugin_list_command(self, list_files=None, response_format=None, plugin_type=None,
                                    playbook_dir=None, module_path=None):

        if response_format and response_format not in DocConfig._supported_response_formats:
            raise ConfigurationError("Invalid response_format {0}, valid value is one of either {1}".format(response_format,
                                                                                                            ", ".join(DocConfig._supported_response_formats)))

        self._prepare_env(runner_mode=self.runner_mode)
        self.cmdline_args = []

        if list_files:
            self.cmdline_args.append('-F')
        else:
            self.cmdline_args.append('-l')

        if response_format == 'json':
            self.cmdline_args.append('-j')

        if plugin_type:
            self.cmdline_args.extend(['-t', plugin_type])

        if playbook_dir:
            self.cmdline_args.extend(['--playbook-dir', playbook_dir])

        if module_path:
            self.cmdline_args.extend(['-M', module_path])

        self.command = ['ansible-doc'] + self.cmdline_args
        self._handle_command_wrap(self.execution_mode, self.cmdline_args)
예제 #10
0
 def _ensure_path_safe_to_mount(self, path):
     if os.path.isfile(path):
         path = os.path.dirname(path)
     if os.path.join(path, "") in ('/', '/home/', '/usr/'):
         raise ConfigurationError(
             "When using containerized execution, cannot mount '/' or '/home' or '/usr'"
         )
예제 #11
0
    def __init__(self, runner_mode=None, **kwargs):
        # runner params
        self.runner_mode = runner_mode if runner_mode else 'subprocess'
        if self.runner_mode not in ['pexpect', 'subprocess']:
            raise ConfigurationError("Invalid runner mode {0}, valid value is either 'pexpect' or 'subprocess'".format(self.runner_mode))

        self.execution_mode = BaseExecutionMode.ANSIBLE_COMMANDS
        super(DocConfig, self).__init__(**kwargs)
예제 #12
0
    def __init__(self, input_fd=None, output_fd=None, error_fd=None, runner_mode=None, **kwargs):
        # subprocess runner mode params
        self.input_fd = input_fd
        self.output_fd = output_fd
        self.error_fd = error_fd

        if runner_mode == 'pexpect' and not self.input_fd:
            raise ConfigurationError("input_fd is applicable only with 'subprocess' runner mode")

        if runner_mode and runner_mode not in ['pexpect', 'subprocess']:
            raise ConfigurationError("Invalid runner mode {0}, valid value is either 'pexpect' or 'subprocess'".format(runner_mode))

        # runner params
        self.runner_mode = runner_mode

        self.execution_mode = BaseExecutionMode.NONE

        super(CommandConfig, self).__init__(**kwargs)
예제 #13
0
    def _prepare_command(self):
        """
        Determines if it is ``ansible`` command or ``generic`` command and generate the command line
        """
        if not self.executable_cmd:
            raise ConfigurationError("For CommandRunner 'executable_cmd' value is required")

        if self.executable_cmd.split(os.pathsep)[-1].startswith('ansible'):
            self.execution_mode = BaseExecutionMode.ANSIBLE_COMMANDS
        else:
            self.execution_mode = BaseExecutionMode.GENERIC_COMMANDS

        if self.cmdline_args:
            self.command = [self.executable_cmd] + self.cmdline_args
        else:
            self.command = [self.executable_cmd]

        if self.execution_mode == BaseExecutionMode.GENERIC_COMMANDS \
           and 'python' in self.executable_cmd.split(os.pathsep)[-1] and self.cmdline_args is None:
            raise ConfigurationError("Runner requires python filename for execution")
        elif self.execution_mode == BaseExecutionMode.NONE:
            raise ConfigurationError("No executable for runner to run")
예제 #14
0
    def __init__(self, runner_mode=None, **kwargs):
        # runner params
        self.runner_mode = runner_mode if runner_mode else 'subprocess'
        if self.runner_mode not in ['pexpect', 'subprocess']:
            raise ConfigurationError(
                "Invalid runner mode {0}, valid value is either 'pexpect' or 'subprocess'"
                .format(self.runner_mode))

        if kwargs.get("process_isolation"):
            self._ansible_doc_exec_path = "ansible-doc"
        else:
            self._ansible_doc_exec_path = get_executable_path("ansible-doc")

        self.execution_mode = BaseExecutionMode.ANSIBLE_COMMANDS
        super(DocConfig, self).__init__(**kwargs)
예제 #15
0
    def prepare(self):
        """
        Performs basic checks and then properly invokes

        - prepare_inventory
        - prepare_env
        - prepare_command

        It's also responsible for wrapping the command with the proper ssh agent invocation
        and setting early ANSIBLE_ environment variables.
        """
        # ansible_path = find_executable('ansible')
        # if ansible_path is None or not os.access(ansible_path, os.X_OK):
        #     raise ConfigurationError("Ansible not found. Make sure that it is installed.")
        if self.private_data_dir is None:
            raise ConfigurationError("Runner Base Directory is not defined")
        if self.module and self.playbook:
            raise ConfigurationError("Only one of playbook and module options are allowed")
        if not os.path.exists(self.artifact_dir):
            os.makedirs(self.artifact_dir, mode=0o700)
        if self.directory_isolation_path is not None:
            self.directory_isolation_path = tempfile.mkdtemp(prefix='runner_di_', dir=self.directory_isolation_path)
            if os.path.exists(self.project_dir):
                output.debug("Copying directory tree from {} to {} for working directory isolation".format(self.project_dir,
                                                                                                           self.directory_isolation_path))
                copy_tree(self.project_dir, self.directory_isolation_path, preserve_symlinks=True)

        self.prepare_inventory()
        self.prepare_env()
        self.prepare_command()

        if self.execution_mode == ExecutionMode.ANSIBLE_PLAYBOOK and self.playbook is None:
            raise ConfigurationError("Runner playbook required when running ansible-playbook")
        elif self.execution_mode == ExecutionMode.ANSIBLE and self.module is None:
            raise ConfigurationError("Runner module required when running ansible")
        elif self.execution_mode == ExecutionMode.NONE:
            raise ConfigurationError("No executable for runner to run")

        # write the SSH key data into a fifo read by ssh-agent
        if self.ssh_key_data:
            self.ssh_key_path = os.path.join(self.artifact_dir, 'ssh_key_data')
            open_fifo_write(self.ssh_key_path, self.ssh_key_data)
            self.command = self.wrap_args_with_ssh_agent(self.command, self.ssh_key_path)

        # Use local callback directory
        callback_dir = self.env.get('AWX_LIB_DIRECTORY', os.getenv('AWX_LIB_DIRECTORY'))
        if callback_dir is None:
            callback_dir = os.path.join(os.path.split(os.path.abspath(__file__))[0],
                                        "callbacks")
        python_path = self.env.get('PYTHONPATH', os.getenv('PYTHONPATH', ''))
        if python_path and not python_path.endswith(':'):
            python_path += ':'
        self.env['ANSIBLE_CALLBACK_PLUGINS'] = callback_dir
        if 'AD_HOC_COMMAND_ID' in self.env:
            self.env['ANSIBLE_STDOUT_CALLBACK'] = 'minimal'
        else:
            self.env['ANSIBLE_STDOUT_CALLBACK'] = 'awx_display'
        self.env['ANSIBLE_RETRY_FILES_ENABLED'] = 'False'
        self.env['ANSIBLE_HOST_KEY_CHECKING'] = 'False'
        self.env['AWX_ISOLATED_DATA_DIR'] = self.artifact_dir

        self.env['PYTHONPATH'] = python_path + callback_dir
        if self.roles_path:
            self.env['ANSIBLE_ROLES_PATH'] = ':'.join(self.roles_path)

        if self.process_isolation:
            self.command = self.wrap_args_with_process_isolation(self.command)

        if self.fact_cache_type == 'jsonfile':
            self.env['ANSIBLE_CACHE_PLUGIN'] = 'jsonfile'
            self.env['ANSIBLE_CACHE_PLUGIN_CONNECTION'] = self.fact_cache
예제 #16
0
 def _ensure_path_safe_to_mount(path):
     if path in ('/home', '/usr'):
         raise ConfigurationError("When using containerized execution, cannot mount /home or /usr")
예제 #17
0
def get_executable_path(name):
    exec_path = find_executable(name)
    if exec_path is None:
        raise ConfigurationError(f"{name} command not found")
    return exec_path
예제 #18
0
    def prepare(self):
        """
        Performs basic checks and then properly invokes

        - prepare_inventory
        - prepare_env
        - prepare_command

        It's also responsible for wrapping the command with the proper ssh agent invocation
        and setting early ANSIBLE_ environment variables.
        """
        # ansible_path = find_executable('ansible')
        # if ansible_path is None or not os.access(ansible_path, os.X_OK):
        #     raise ConfigurationError("Ansible not found. Make sure that it is installed.")
        if self.private_data_dir is None:
            raise ConfigurationError("Runner Base Directory is not defined")
        if self.module and self.playbook:
            raise ConfigurationError(
                "Only one of playbook and module options are allowed")
        if not os.path.exists(self.artifact_dir):
            os.makedirs(self.artifact_dir, mode=0o700)
        if self.directory_isolation_path is not None:
            self.directory_isolation_path = tempfile.mkdtemp(
                prefix='runner_di_', dir=self.directory_isolation_path)
            if os.path.exists(self.project_dir):
                output.debug(
                    "Copying directory tree from {} to {} for working directory isolation"
                    .format(self.project_dir, self.directory_isolation_path))
                copy_tree(self.project_dir,
                          self.directory_isolation_path,
                          preserve_symlinks=True)

        self.prepare_inventory()
        self.prepare_env()
        self.prepare_command()

        if self.execution_mode == ExecutionMode.ANSIBLE_PLAYBOOK and self.playbook is None:
            raise ConfigurationError(
                "Runner playbook required when running ansible-playbook")
        elif self.execution_mode == ExecutionMode.ANSIBLE and self.module is None:
            raise ConfigurationError(
                "Runner module required when running ansible")
        elif self.execution_mode == ExecutionMode.NONE:
            raise ConfigurationError("No executable for runner to run")

        # write the SSH key data into a fifo read by ssh-agent
        if self.ssh_key_data:
            self.ssh_key_path = os.path.join(self.artifact_dir, 'ssh_key_data')
            open_fifo_write(self.ssh_key_path, self.ssh_key_data)
            self.command = self.wrap_args_with_ssh_agent(
                self.command, self.ssh_key_path)

        # Use local callback directory
        callback_dir = self.env.get('AWX_LIB_DIRECTORY',
                                    os.getenv('AWX_LIB_DIRECTORY'))
        if callback_dir is None:
            callback_dir = os.path.join(
                os.path.split(os.path.abspath(__file__))[0], "callbacks")
        python_path = self.env.get('PYTHONPATH', os.getenv('PYTHONPATH', ''))
        if python_path and not python_path.endswith(':'):
            python_path += ':'
        self.env['ANSIBLE_CALLBACK_PLUGINS'] = ':'.join(
            filter(None,
                   (self.env.get('ANSIBLE_CALLBACK_PLUGINS'), callback_dir)))
        if 'AD_HOC_COMMAND_ID' in self.env:
            self.env['ANSIBLE_STDOUT_CALLBACK'] = 'minimal'
        else:
            self.env['ANSIBLE_STDOUT_CALLBACK'] = 'awx_display'
        self.env['ANSIBLE_RETRY_FILES_ENABLED'] = 'False'
        if 'ANSIBLE_HOST_KEY_CHECKING' not in self.env:
            self.env['ANSIBLE_HOST_KEY_CHECKING'] = 'False'
        self.env['AWX_ISOLATED_DATA_DIR'] = self.artifact_dir

        if self.resource_profiling:
            callback_whitelist = os.environ.get('ANSIBLE_CALLBACK_WHITELIST',
                                                '').strip()
            self.env['ANSIBLE_CALLBACK_WHITELIST'] = ','.join(
                filter(None, [callback_whitelist, 'cgroup_perf_recap']))
            self.env['CGROUP_CONTROL_GROUP'] = '{}/{}'.format(
                self.resource_profiling_base_cgroup, self.ident)
            if self.resource_profiling_results_dir:
                cgroup_output_dir = self.resource_profiling_results_dir
            else:
                cgroup_output_dir = os.path.normpath(
                    os.path.join(self.private_data_dir, 'profiling_data'))

            # Create results directory if it does not exist
            if not os.path.isdir(cgroup_output_dir):
                os.mkdir(cgroup_output_dir,
                         stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)

            self.env['CGROUP_OUTPUT_DIR'] = cgroup_output_dir
            self.env['CGROUP_OUTPUT_FORMAT'] = 'json'
            self.env['CGROUP_CPU_POLL_INTERVAL'] = str(
                self.resource_profiling_cpu_poll_interval)
            self.env['CGROUP_MEMORY_POLL_INTERVAL'] = str(
                self.resource_profiling_memory_poll_interval)
            self.env['CGROUP_PID_POLL_INTERVAL'] = str(
                self.resource_profiling_pid_poll_interval)
            self.env['CGROUP_FILE_PER_TASK'] = 'True'
            self.env['CGROUP_WRITE_FILES'] = 'True'
            self.env['CGROUP_DISPLAY_RECAP'] = 'False'

        self.env['PYTHONPATH'] = python_path + callback_dir
        if self.roles_path:
            self.env['ANSIBLE_ROLES_PATH'] = ':'.join(self.roles_path)

        if self.process_isolation:
            self.command = self.wrap_args_with_process_isolation(self.command)

        if self.resource_profiling and self.execution_mode == ExecutionMode.ANSIBLE_PLAYBOOK:
            self.command = self.wrap_args_with_cgexec(self.command)

        if self.fact_cache_type == 'jsonfile':
            self.env['ANSIBLE_CACHE_PLUGIN'] = 'jsonfile'
            self.env['ANSIBLE_CACHE_PLUGIN_CONNECTION'] = self.fact_cache

        self.env["RUNNER_OMIT_EVENTS"] = str(self.omit_event_data)
        self.env["RUNNER_ONLY_FAILED_EVENTS"] = str(
            self.only_failed_event_data)