Creates a container from its configuration to run a script or single command. The container is specifically
        created for this action. If it exists prior to the script run, it fails; optionally it can be removed by setting
        :attr:`remove_existing_before` to ``True``. The script is run by setting entrypoint and command and
        mounting the directory containing the script to the new container. After the script run, the container is
        destroyed (excluding its dependencies), unless :attr:`remove_created_after` is set to ``False``.

        :param action: Action configuration.
        :type action: dockermap.map.runner.ActionConfig
        :param c_name: Container name.
        :type c_name: unicode | str
        :param script_path: Path to the script on the Docker host. Note that this needs to have the executable bit
         set, if the script runtime (e.g. bash) requires it. If no script is to be used, (e.g. for a single command),
         this can point to a directory for writing back results to.
        :param entrypoint: Entrypoint of the container. Typically this should be the scripting executable, such as
         ``/bin/bash``.
        :type entrypoint: unicode | str
        :param command_format: Command to pass to the container. This should be any arguments to the entrypoint, and
         can include a formatting string variable ``{script_path}`` which is substituted with the path inside the
         container. The command_format can be provided as a single string or a list of strings. Of no command is set,
         ``['-c', '{script_path}']`` is assumed, which are the arguments to ``/bin/bash`` for running a single script.
        :type command_format: unicode | str | list[unicode | str] | tuple[unicode | str]
        :param wait_timeout: How long to wait for the container to finish. If not set, will be read from the client
         configuration parameter ``wait_timeout``.
        :type wait_timeout: int
        :param container_script_dir: Directory to use for the script inside the container. This is also the path where
         other files in the same directory as the script will be located.
        :type container_script_dir: unicode | str
        :param timestamps:
        :type timestamps: bool
        :param tail:
        :type tail: unicode | str
        :return: A dictionary with the container ``id``, the client alias ``client``, the stdout output ``log``, and
         the exit code ``exit_code``. In case a wait timeout occurred, instead of ``log`` and ``exit_code`` returns a
         key ``error``.
        :rtype: dict[unicode | str, dict]

def run_script(self, action, c_name, script_path=None, entrypoint=None, command_format=None,
                   wait_timeout=None, container_script_dir='/tmp/script_run', timestamps=None, tail='all'):
        """
        Creates a container from its configuration to run a script or single command. The container is specifically
        created for this action. If it exists prior to the script run, it fails; optionally it can be removed by setting
        :attr:`remove_existing_before` to ``True``. The script is run by setting entrypoint and command and
        mounting the directory containing the script to the new container. After the script run, the container is
        destroyed (excluding its dependencies), unless :attr:`remove_created_after` is set to ``False``.

        :param action: Action configuration.
        :type action: dockermap.map.runner.ActionConfig
        :param c_name: Container name.
        :type c_name: unicode | str
        :param script_path: Path to the script on the Docker host. Note that this needs to have the executable bit
         set, if the script runtime (e.g. bash) requires it. If no script is to be used, (e.g. for a single command),
         this can point to a directory for writing back results to.
        :param entrypoint: Entrypoint of the container. Typically this should be the scripting executable, such as
         ``/bin/bash``.
        :type entrypoint: unicode | str
        :param command_format: Command to pass to the container. This should be any arguments to the entrypoint, and
         can include a formatting string variable ``{script_path}`` which is substituted with the path inside the
         container. The command_format can be provided as a single string or a list of strings. Of no command is set,
         ``['-c', '{script_path}']`` is assumed, which are the arguments to ``/bin/bash`` for running a single script.
        :type command_format: unicode | str | list[unicode | str] | tuple[unicode | str]
        :param wait_timeout: How long to wait for the container to finish. If not set, will be read from the client
         configuration parameter ``wait_timeout``.
        :type wait_timeout: int
        :param container_script_dir: Directory to use for the script inside the container. This is also the path where
         other files in the same directory as the script will be located.
        :type container_script_dir: unicode | str
        :param timestamps:
        :type timestamps: bool
        :param tail:
        :type tail: unicode | str
        :return: A dictionary with the container ``id``, the client alias ``client``, the stdout output ``log``, and
         the exit code ``exit_code``. In case a wait timeout occurred, instead of ``log`` and ``exit_code`` returns a
         key ``error``.
        :rtype: dict[unicode | str, dict]
        """
        client = action.client
        client_config = action.client_config
        if script_path:
            if os.path.isdir(script_path):
                script_dir = script_path
                c_script_path = container_script_dir
            else:
                script_dir, script_name = os.path.split(script_path)
                c_script_path = posixpath.join(container_script_dir, script_name)
            if command_format:
                if isinstance(command_format, (tuple, list)):
                    command = [six.text_type(cmd_item).format(script_path=c_script_path) for cmd_item in command_format]
                elif isinstance(command_format, six.string_types):
                    command = command_format.format(script_path=c_script_path)
                else:
                    raise ValueError("Only strings and lists of strings are allowed as a command.")
            else:
                command = None
            volumes = [container_script_dir]
            binds = ['{0}:{1}:rw'.format(script_dir, container_script_dir)]
        else:
            volumes = None
            binds = None
            command = command_format

        if client_config.features['host_config']:
            create_extra_kwargs = {'host_config': dict(binds=binds)}
            start_extra_kwargs = {}
        else:
            create_extra_kwargs = {}
            start_extra_kwargs = {'binds': binds}
        created = self.create_container(action, c_name, entrypoint=entrypoint, command=command,
                                        volumes=volumes, **create_extra_kwargs)
        if not created:
            raise ScriptRunException("No new containers were created.")
        result = {'id': created['Id'], 'client': action.client_name}
        stopped = True
        try:
            self.start_container(action, c_name, **start_extra_kwargs)
            stopped = False
            timeout = wait_timeout or action.config.stop_timeout or client_config.get('timeout')
            container_id = created['Id']
            try:
                self.wait(action, c_name, timeout=timeout)
            except Timeout:
                result['error'] = "Timed out while waiting for the container to finish."
            else:
                stopped = True
                c_info = client.inspect_container(container_id)
                result['exit_code'] = c_info['State']['ExitCode']
                result['log'] = client.logs(c_name, timestamps=timestamps, tail=tail)
        finally:
            if self.remove_created_after:
                if not stopped:
                    self.stop(action, c_name, timeout=3)
                self.remove_container(action, c_name)
        return result