Beispiel #1
0
def diagnosis_show(categories=[],
                   issues=False,
                   full=False,
                   share=False,
                   human_readable=False):

    if not os.path.exists(DIAGNOSIS_CACHE):
        logger.warning(m18n.n("diagnosis_never_ran_yet"))
        return

    # Get all the categories
    all_categories = _list_diagnosis_categories()
    all_categories_names = [category for category, _ in all_categories]

    # Check the requested category makes sense
    if categories == []:
        categories = all_categories_names
    else:
        unknown_categories = [
            c for c in categories if c not in all_categories_names
        ]
        if unknown_categories:
            raise YunohostValidationError(
                "diagnosis_unknown_categories",
                categories=", ".join(unknown_categories))

    # Fetch all reports
    all_reports = []
    for category in categories:

        try:
            report = Diagnoser.get_cached_report(category)
        except Exception as e:
            logger.error(
                m18n.n("diagnosis_failed", category=category, error=str(e)))
            continue

        Diagnoser.i18n(report, force_remove_html_tags=share or human_readable)

        add_ignore_flag_to_issues(report)
        if not full:
            del report["timestamp"]
            del report["cached_for"]
            report["items"] = [
                item for item in report["items"] if not item["ignored"]
            ]
            for item in report["items"]:
                del item["meta"]
                del item["ignored"]
                if "data" in item:
                    del item["data"]
        if issues:
            report["items"] = [
                item for item in report["items"]
                if item["status"] in ["WARNING", "ERROR"]
            ]
            # Ignore this category if no issue was found
            if not report["items"]:
                continue

        all_reports.append(report)

    if share:
        from yunohost.utils.yunopaste import yunopaste

        content = _dump_human_readable_reports(all_reports)
        url = yunopaste(content)

        logger.info(m18n.n("log_available_on_yunopaste", url=url))
        if msettings.get("interface") == "api":
            return {"url": url}
        else:
            return
    elif human_readable:
        print(_dump_human_readable_reports(all_reports))
    else:
        return {"reports": all_reports}
Beispiel #2
0
def log_show(path,
             number=None,
             share=False,
             filter_irrelevant=False,
             with_suboperations=False):
    """
    Display a log file enriched with metadata if any.

    If the file_name is not an absolute path, it will try to search the file in
    the unit operations log path (see OPERATIONS_PATH).

    Argument:
        file_name
        number
        share
    """

    if share:
        filter_irrelevant = True

    if filter_irrelevant:
        filters = [
            r"set [+-]x$",
            r"set [+-]o xtrace$",
            r"local \w+$",
            r"local legacy_args=.*$",
            r".*Helper used in legacy mode.*",
            r"args_array=.*$",
            r"local -A args_array$",
            r"ynh_handle_getopts_args",
            r"ynh_script_progression",
        ]
    else:
        filters = []

    def _filter_lines(lines, filters=[]):

        filters = [re.compile(f) for f in filters]
        return [
            line for line in lines
            if not any(f.search(line.strip()) for f in filters)
        ]

    # Normalize log/metadata paths and filenames
    abs_path = path
    log_path = None
    if not path.startswith("/"):
        abs_path = os.path.join(OPERATIONS_PATH, path)

    if os.path.exists(abs_path) and not path.endswith(METADATA_FILE_EXT):
        log_path = abs_path

    if abs_path.endswith(METADATA_FILE_EXT) or abs_path.endswith(LOG_FILE_EXT):
        base_path = "".join(os.path.splitext(abs_path)[:-1])
    else:
        base_path = abs_path
    base_filename = os.path.basename(base_path)
    md_path = base_path + METADATA_FILE_EXT
    if log_path is None:
        log_path = base_path + LOG_FILE_EXT

    if not os.path.exists(md_path) and not os.path.exists(log_path):
        raise YunohostValidationError("log_does_exists", log=path)

    infos = {}

    # If it's a unit operation, display the name and the description
    if base_path.startswith(CATEGORIES_PATH):
        infos["description"] = _get_description_from_name(base_filename)
        infos["name"] = base_filename

    if share:
        from yunohost.utils.yunopaste import yunopaste

        content = ""
        if os.path.exists(md_path):
            content += read_file(md_path)
            content += "\n============\n\n"
        if os.path.exists(log_path):
            actual_log = read_file(log_path)
            content += "\n".join(_filter_lines(actual_log.split("\n"),
                                               filters))

        url = yunopaste(content)

        logger.info(m18n.n("log_available_on_yunopaste", url=url))
        if msettings.get("interface") == "api":
            return {"url": url}
        else:
            return

    # Display metadata if exist
    if os.path.exists(md_path):
        try:
            metadata = read_yaml(md_path)
        except MoulinetteError as e:
            error = m18n.n("log_corrupted_md_file", md_file=md_path, error=e)
            if os.path.exists(log_path):
                logger.warning(error)
            else:
                raise YunohostError(error)
        else:
            infos["metadata_path"] = md_path
            infos["metadata"] = metadata

            if "log_path" in metadata:
                log_path = metadata["log_path"]

            if with_suboperations:

                def suboperations():
                    try:
                        log_start = _get_datetime_from_name(base_filename)
                    except ValueError:
                        return

                    for filename in os.listdir(OPERATIONS_PATH):

                        if not filename.endswith(METADATA_FILE_EXT):
                            continue

                        # We first retrict search to a ~48h time window to limit the number
                        # of .yml we look into
                        try:
                            date = _get_datetime_from_name(base_filename)
                        except ValueError:
                            continue
                        if (date < log_start) or (
                                date > log_start + timedelta(hours=48)):
                            continue

                        try:
                            submetadata = read_yaml(
                                os.path.join(OPERATIONS_PATH, filename))
                        except Exception:
                            continue

                        if submetadata and submetadata.get(
                                "parent") == base_filename:
                            yield {
                                "name":
                                filename[:-len(METADATA_FILE_EXT)],
                                "description":
                                _get_description_from_name(
                                    filename[:-len(METADATA_FILE_EXT)]),
                                "success":
                                submetadata.get("success", "?"),
                            }

                metadata["suboperations"] = list(suboperations())

    # Display logs if exist
    if os.path.exists(log_path):
        from yunohost.service import _tail

        if number and filters:
            logs = _tail(log_path, int(number * 4))
        elif number:
            logs = _tail(log_path, int(number))
        else:
            logs = read_file(log_path)
        logs = _filter_lines(logs, filters)
        if number:
            logs = logs[-number:]
        infos["log_path"] = log_path
        infos["logs"] = logs

    return infos