Example #1
0
def delete_downtime(params):
    """Delete a scheduled downtime"""
    body = params['body']
    live = sites.live()
    delete_type = body['delete_type']
    if delete_type == "query":
        downtime_commands.delete_downtime_with_query(live, body['query'])
    elif delete_type == "by_id":
        downtime_commands.delete_downtime(live, body['downtime_id'])
    elif delete_type == "params":
        hostname = body['host_name']
        if "service_descriptions" not in body:
            host_expr = And(Downtimes.host_name.op("=", hostname),
                            Downtimes.is_service.op('=', 0))
            downtime_commands.delete_downtime_with_query(live, host_expr)
        else:
            services_expr = And(
                Downtimes.host_name.op('=', hostname),
                Or(*[
                    Downtimes.service_description == svc_desc
                    for svc_desc in body['service_descriptions']
                ]))
            downtime_commands.delete_downtime_with_query(live, services_expr)
    else:
        return problem(
            status=400,
            title="Unhandled delete_type.",
            detail=f"The downtime-type {delete_type!r} is not supported.")
    return Response(status=204)
Example #2
0
def schedule_host_downtime(
    connection,
    host_name: Union[List[str], str],
    start_time: dt.datetime,
    end_time: dt.datetime,
    include_all_services: bool = False,
    recur: RecurMode = 'fixed',
    trigger_id: int = 0,
    duration: int = 0,
    user_id: str = '',
    comment: str = '',
):
    """Schedule the downtime of a host.

    Notes:
        If `include_all_services` is set to True, the services table is only queried
        once, instead of len(host_name) times. If a lot of hosts are to be scheduled, this
        will save N queries. Issuing the command is still done sequentially.

    Args:
        connection:
            A livestatus connection object.

        host_name:
            The host-name for which this downtime is for.

        start_time:
            When the downtime shall begin.

        end_time:
            When the downtime shall end.

        include_all_services:
            If set, downtimes for all services associated with the given host will be scheduled.
            Defaults to False.

        recur:
            The recurring mode of the new downtime. Available modes are:
                * fixed
                * hour
                * day
                * week
                * second_week
                * fourth_week
                * weekday_start
                * weekday_end
                * day_of_month

            This only works when using the Enterprise Editions. Defaults to 'fixed'.

        trigger_id:
            The id of another downtime-entry. If given (other than 0) then this downtime will be
            triggered by the other downtime.

        duration:
            Duration in seconds. When set, the downtime does not begin automatically at a nominated
            time, but when a real problem status appears for the host. Consequencely, the
            start_time/end_time is only the time window in which the scheduled downtime can begin.

        user_id:

        comment:
            A comment which will be added to the downtime.

    See Also:
      * https://assets.nagios.com/downloads/nagioscore/docs/externalcmds/cmdinfo.php?command_id=118
      * https://assets.nagios.com/downloads/nagioscore/docs/externalcmds/cmdinfo.php?command_id=122

    Examples:
        >>> import pytz
        >>> _start_time = dt.datetime(1970, 1, 1, tzinfo=pytz.timezone("UTC"))
        >>> _end_time = dt.datetime(1970, 1, 2, tzinfo=pytz.timezone("UTC"))

        >>> from cmk.gui.livestatus_utils.testing import simple_expect
        >>> cmd = "COMMAND [...] SCHEDULE_HOST_DOWNTIME;example.com;0;86400;16;0;120;;Boom"
        >>> with simple_expect(cmd, match_type="ellipsis") as live:
        ...     schedule_host_downtime(live,
        ...             'example.com',
        ...             _start_time,
        ...             _end_time,
        ...             recur="day_of_month",
        ...             duration=120,
        ...             comment="Boom")

    """
    if isinstance(host_name, str):
        host_names = [host_name]
    else:
        host_names = host_name

    for _host_name in host_names:
        _schedule_downtime(
            connection,
            "SCHEDULE_HOST_DOWNTIME",
            _host_name,
            None,
            start_time,
            end_time,
            recur,
            trigger_id,
            duration,
            user_id,
            comment,
        )

    if include_all_services:
        services = Query(
            [tables.Services.host_name, tables.Services.description],
            Or(*[tables.Services.host_name.equals(_host_name)
                 for _host_name in host_names])).fetch_values(connection)

        for _host_name, service_description in services:
            schedule_service_downtime(
                connection,
                host_name=_host_name,
                service_description=service_description,
                start_time=start_time,
                end_time=end_time,
                recur=recur,
                trigger_id=trigger_id,
                duration=duration,
                user_id=user_id,
                comment=comment,
            )
Example #3
0
def tree_to_expr(filter_dict, table: Any = None) -> QueryExpression:
    """Turn a filter-dict into a QueryExpression.

    Examples:

        >>> tree_to_expr({'op': '=', 'left': 'hosts.name', 'right': 'example.com'})
        Filter(name = example.com)

        >>> tree_to_expr({'op': '!=', 'left': 'hosts.name', 'right': 'example.com'})
        Filter(name != example.com)

        >>> tree_to_expr({'op': '!=', 'left': 'name', 'right': 'example.com'}, 'hosts')
        Filter(name != example.com)

        >>> tree_to_expr({'op': 'and', \
                          'expr': [{'op': '=', 'left': 'hosts.name', 'right': 'example.com'}, \
                          {'op': '=', 'left': 'hosts.state', 'right': 0}]})
        And(Filter(name = example.com), Filter(state = 0))

        >>> tree_to_expr({'op': 'or', \
                          'expr': [{'op': '=', 'left': 'hosts.name', 'right': 'example.com'}, \
                          {'op': '=', 'left': 'hosts.name', 'right': 'heute'}]})
        Or(Filter(name = example.com), Filter(name = heute))

        >>> tree_to_expr({'op': 'not', \
                          'expr': {'op': '=', 'left': 'hosts.name', 'right': 'example.com'}})
        Not(Filter(name = example.com))

        >>> tree_to_expr({'op': 'not', \
                          'expr': {'op': 'not', \
                                   'expr': {'op': '=', \
                                            'left': 'hosts.name', \
                                            'right': 'example.com'}}})
        Not(Not(Filter(name = example.com)))

        >>> from cmk.utils.livestatus_helpers.tables import Hosts
        >>> tree_to_expr({'op': 'not', 'expr': Hosts.name == 'example.com'})
        Not(Filter(name = example.com))

        >>> tree_to_expr({'op': 'no_way', \
                          'expr': {'op': '=', 'left': 'hosts.name', 'right': 'example.com'}})
        Traceback (most recent call last):
        ...
        ValueError: Unknown operator: no_way

    Args:
        filter_dict:
            A filter-dict, which can either be persisted or passed over the wire.

        table:
            Optionally a table name. Only used when the columns are used in plain form
            (without table name prefixes).

    Returns:
        A valid LiveStatus query expression.

    Raises:
        ValueError: when unknown columns are queried

    """
    if not isinstance(filter_dict, dict):
        # FIXME
        #   Because of not having correct Python packages at the root-level, sometimes a
        #   locally defined class ends up having a relative dotted path, like for example
        #       <class 'expressions.BinaryExpression'>
        #   instead of
        #       <class 'cmk.utils.livestatus_helpers.expressions.BinaryExpression'>
        #   While these classes are actually the same, Python treats them distinct, so we can't
        #   just say `isinstance(filter_dict, BinaryExpression)` (or their super-type) here.
        return cast(QueryExpression, filter_dict)
    op = filter_dict["op"]
    if op in LIVESTATUS_OPERATORS:
        left = filter_dict["left"]
        if "." in left:
            _table, column = left.split(".")
            if table is not None and _table_name(table) != _table:
                raise ValueError(
                    f"This field can only query table {_table_name(table)!r}. ({left})"
                )
        else:
            if table is None:
                raise ValueError("Missing table parameter.")
            _table = _table_name(table)
            column = left
        return BinaryExpression(
            _lookup_column(_table, column),
            LiteralExpression(filter_dict["right"]),
            op,
        )

    if op == "and":
        return And(
            *[tree_to_expr(expr, table) for expr in filter_dict["expr"]])

    if op == "or":
        return Or(*[tree_to_expr(expr, table) for expr in filter_dict["expr"]])

    if op == "not":
        return Not(tree_to_expr(filter_dict["expr"], table))

    raise ValueError(f"Unknown operator: {op}")