예제 #1
0
def schedule_servicegroup_service_downtime(
    connection,
    servicegroup_name: str,
    start_time: dt.datetime,
    end_time: dt.datetime,
    include_hosts: bool = False,
    recur: RecurMode = 'fixed',
    trigger_id: int = 0,
    duration: int = 0,
    user_id: str = '',
    comment: str = '',
):
    """Schedules downtime for all hosts, which have services in a given servicegroup.

    Args:
        connection:
            A LiveStatus connection object.

        servicegroup_name:
            The name of the service group. Any host having a service in this group will be
            A downtime will be scheduled for all hosts in this group.

        start_time:
            When the downtime shall begin.

        end_time:
            When the downtime shall end.

        include_hosts:
            When set to True, all hosts will also receive a scheduled downtime, not just their
            services which belong to this service group.

        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. Consequently, 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.

        connection:

    """
    members: List[List[str]] = Query(
        [tables.Servicegroups.members],
        tables.Servicegroups.name.equals(servicegroup_name),
    ).value(connection)
    for host_name, service_description in members:
        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,
        )

    if include_hosts:
        host_names = _deduplicate([_host_name for _host_name, _ in members])
        schedule_host_downtime(
            connection,
            host_name=host_names,
            start_time=start_time,
            end_time=end_time,
            recur=recur,
            trigger_id=trigger_id,
            duration=duration,
            user_id=user_id,
            comment=comment,
        )
예제 #2
0
def schedule_hostgroup_host_downtime(
    connection,
    hostgroup_name: 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 = '',
):
    """Schedules downtime for all hosts in a given hostgroup.

    Args:
        connection:
            A LiveStatus connection object.

        hostgroup_name:
            The name of the hostgroup. A downtime will be scheduled for all hosts in this hostgroup.

        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. Consequently, 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.

        connection:

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

    """
    members: List[str] = Query([tables.Hostgroups.members],
                               tables.Hostgroups.name.equals(hostgroup_name)).value(connection)
    schedule_host_downtime(
        connection,
        host_name=members,
        start_time=start_time,
        end_time=end_time,
        include_all_services=include_all_services,
        recur=recur,
        trigger_id=trigger_id,
        duration=duration,
        user_id=user_id,
        comment=comment,
    )
예제 #3
0
def acknowledge_servicegroup_problem(
    connection,
    servicegroup_name: str,
    sticky: bool = False,
    notify: bool = False,
    persistent: bool = False,
    user: str = "",
    comment: str = "",
):
    """Acknowledge the problems of the current services of the service group

    When acknowledging a problem, further notifications for the respective services are disabled, as
    long as a specific service doesn't change state. At state change, notifications are re-enabled.

    Args:
        connection:
            A livestatus connection object.

        servicegroup_name:
            The host-name for which this acknowledgement is for.

        sticky:
            If set, only a state-change of the service to an OK state will discard the
            acknowledgement. Otherwise it will be discarded on any state-change. Defaults to False.

        notify:
            If set, notifications will be sent out to the configured contacts. Defaults to False.

        persistent:
            If set, the comment will persist a restart. Defaults to False.

        user:
        comment:
            If set, this comment will be stored alongside the acknowledgement.

    Raises:
        ValueError:
            When the service group could not be found.

    """
    with detailed_connection(connection) as conn:
        group_entries = Query(
            [tables.Servicegroups.members],
            tables.Servicegroups.name.equals(servicegroup_name),
        ).fetchall(conn)

    acknowledgement = 2 if sticky else 1  # 1: normal, 2: sticky

    for entry in group_entries:
        site_id = entry["site"]
        for host_name, service_description in entry["members"]:
            send_command(
                connection,
                "ACKNOWLEDGE_SVC_PROBLEM",
                [
                    host_name,
                    service_description,
                    acknowledgement,
                    int(notify),
                    int(persistent),
                    user,
                    comment,
                ],
                site_id=site_id,
            )
예제 #4
0
def host_is_monitored(host_name: str) -> bool:
    return bool(
        Query([Hosts.name], Hosts.name == host_name).first_value(sites.live()))
예제 #5
0
def acknowledge_host_problem(
    connection,
    host_name,
    sticky: bool = False,
    notify: bool = False,
    persistent: bool = False,
    user: str = "",
    comment: str = "",
):
    """Acknowledge the current problem for the given host.

    When acknowledging a problem, notifications for the host are disabled, as long as the
    host doesn't change state. At state change, notifications are re-enabled.

    Args:
        connection:
            A livestatus connection object.

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

        sticky:
            If set, only a state-change of the host to an UP state will discard the acknowledgement.
            Otherwise it will be discarded on any state-change. Defaults to False.

        notify:
            If set, notifications will be sent out to the configured contacts. Defaults to False.

        persistent:
            If set, the comment will persist a restart. Defaults to False.

        user:
        comment:
            If set, this comment will be stored alongside the acknowledgement.

    Examples:

        >>> from cmk.gui.livestatus_utils.testing import simple_expect
        >>> cmd = "COMMAND [...] ACKNOWLEDGE_HOST_PROBLEM;example.com;1;0;0;;"
        >>> with simple_expect() as live:
        ...     _ = live.expect_query("GET hosts\\nColumns: name\\nFilter: name = example.com")
        ...     _ = live.expect_query(cmd, match_type="ellipsis")
        ...     acknowledge_host_problem(live, 'example.com')

    """
    acknowledgement = 2 if sticky else 1  # 1: normal, 2: sticky

    with detailed_connection(connection) as conn:
        site_id = Query([Hosts.name], Hosts.name.equals(host_name)).first_value(conn)

    return send_command(
        connection,
        "ACKNOWLEDGE_HOST_PROBLEM",
        [
            host_name,
            acknowledgement,
            int(notify),
            int(persistent),
            user,
            comment,
        ],
        site_id=site_id,
    )
예제 #6
0
def _query_site(connection, host_name: str) -> str:
    with detailed_connection(connection) as conn:
        site_id = Query([Hosts.name], Hosts.name.equals(host_name)).first_value(conn)
        if not isinstance(site_id, str):
            raise QueryException
    return site_id
예제 #7
0
def create_service_related_downtime(params):
    """Create a service related scheduled downtime"""
    body = params["body"]
    live = sites.live()

    downtime_type: DowntimeType = body["downtime_type"]

    if downtime_type == "service":
        host_name = body["host_name"]
        with detailed_connection(live) as conn:
            site_id = Query(columns=[Hosts.name], filter_expr=Hosts.name.op("=", host_name)).value(
                conn
            )
        downtime_commands.schedule_service_downtime(
            live,
            site_id,
            host_name=body["host_name"],
            service_description=body["service_descriptions"],
            start_time=body["start_time"],
            end_time=body["end_time"],
            recur=body["recur"],
            duration=body["duration"],
            user_id=user.ident,
            comment=body.get(
                "comment",
                f"Downtime for services {', '.join(body['service_descriptions'])!r}@{body['host_name']!r}",
            ),
        )
    elif downtime_type == "servicegroup":
        downtime_commands.schedule_servicegroup_service_downtime(
            live,
            servicegroup_name=body["servicegroup_name"],
            start_time=body["start_time"],
            end_time=body["end_time"],
            recur=body["recur"],
            duration=body["duration"],
            user_id=user.ident,
            comment=body.get("comment", f"Downtime for servicegroup {body['servicegroup_name']!r}"),
        )
    elif downtime_type == "service_by_query":
        try:
            downtime_commands.schedule_services_downtimes_with_query(
                live,
                query=body["query"],
                start_time=body["start_time"],
                end_time=body["end_time"],
                recur=body["recur"],
                duration=body["duration"],
                user_id=user.ident,
                comment=body.get("comment", ""),
            )
        except QueryException:
            return problem(
                status=422,
                title="Query did not match any service",
                detail="The provided query returned an empty list so no downtime was set",
            )
    else:
        return problem(
            status=400,
            title="Unhandled downtime-type.",
            detail=f"The downtime-type {downtime_type!r} is not supported.",
        )

    return Response(status=204)
예제 #8
0
def set_acknowledgement_on_hosts(params):
    """Set acknowledgement on related hosts"""
    body = params["body"]
    live = sites.live()

    sticky = body["sticky"]
    notify = body["notify"]
    persistent = body["persistent"]
    comment = body["comment"]

    acknowledge_type = body["acknowledge_type"]

    if acknowledge_type == "host":
        name = body["host_name"]
        host_state = Query([Hosts.state], Hosts.name == name).value(live)
        if not host_state:
            raise ProblemException(
                status=422,
                title=f"Host {name!r} has no problem.",
            )
        acknowledge_host_problem(
            live,
            name,
            sticky=sticky,
            notify=notify,
            persistent=persistent,
            user=user.ident,
            comment=comment,
        )
    elif acknowledge_type == "hostgroup":
        host_group = body["hostgroup_name"]
        try:
            acknowledge_hostgroup_problem(
                live,
                host_group,
                sticky=sticky,
                notify=notify,
                persistent=persistent,
                user=user.ident,
                comment=comment,
            )
        except ValueError:
            raise ProblemException(
                400,
                title="Host group could not be found.",
                detail=f"Unknown host group: {host_group}",
            )
    elif acknowledge_type == "host_by_query":
        query = body["query"]
        hosts = Query([Hosts.name], query).fetchall(live)
        if not hosts:
            raise ProblemException(
                status=422,
                title="The provided query returned no monitored hosts",
            )
        for host in hosts:
            acknowledge_host_problem(
                live,
                host.name,
                sticky=sticky,
                notify=notify,
                persistent=persistent,
                user=user.ident,
                comment=comment,
            )
    else:
        raise ProblemException(
            status=400,
            title="Unhandled acknowledge-type.",
            detail=
            f"The acknowledge-type {acknowledge_type!r} is not supported.",
        )

    return http.Response(status=204)
예제 #9
0
def set_acknowledgement_on_services(params):
    """Set acknowledgement on related services"""
    body = params["body"]
    live = sites.live()

    sticky = body["sticky"]
    notify = body["notify"]
    persistent = body["persistent"]
    comment = body["comment"]
    acknowledge_type = body["acknowledge_type"]

    if acknowledge_type == "service":
        description = unquote(body["service_description"])
        host_name = body["host_name"]
        service = Query(
            [Services.host_name, Services.description, Services.state],
            And(Services.host_name == host_name,
                Services.description == description),
        ).first(live)
        if not service:
            raise ProblemException(
                status=400,
                title=
                f"Service {description!r}@{host_name!r} could not be found.",
            )
        if not service.state:
            raise ProblemException(
                status=422,
                title=f"Service {description!r}@{host_name!r} has no problem.",
            )
        acknowledge_service_problem(
            live,
            service.host_name,
            service.description,
            sticky=sticky,
            notify=notify,
            persistent=persistent,
            user=user.ident,
            comment=comment,
        )
    elif acknowledge_type == "servicegroup":
        service_group = body["servicegroup_name"]
        try:
            acknowledge_servicegroup_problem(
                live,
                service_group,
                sticky=sticky,
                notify=notify,
                persistent=persistent,
                user=user.ident,
                comment=comment,
            )
        except ValueError:
            raise ProblemException(
                status=400,
                title="Service group could not be found.",
                detail=f"Unknown service group: {service_group}",
            )
    elif acknowledge_type == "service_by_query":
        services = Query(
            [Services.host_name, Services.description, Services.state],
            body["query"],
        ).fetchall(live)
        if not services:
            raise ProblemException(
                status=422,
                title="No services with problems found.",
                detail="All queried services are OK.",
            )

        for service in services:
            if not service.state:
                continue
            acknowledge_service_problem(
                live,
                service.host_name,
                service.description,
                sticky=sticky,
                notify=notify,
                persistent=persistent,
                user=user.ident,
                comment=comment,
            )
    else:
        raise ProblemException(
            status=400,
            title="Unhandled acknowledge-type.",
            detail=
            f"The acknowledge-type {acknowledge_type!r} is not supported.",
        )

    return http.Response(status=204)
예제 #10
0
def set_acknowledgement_on_services(params):
    """Set acknowledgement on related services"""
    body = params['body']
    live = sites.live()

    sticky = body['sticky']
    notify = body['notify']
    persistent = body['persistent']
    comment = body['comment']
    acknowledge_type = body['acknowledge_type']

    if acknowledge_type == 'service':
        description = unquote(body['service_description'])
        host_name = body['host_name']
        service = Query(
            [Services.host_name, Services.description, Services.state],
            And(Services.host_name == host_name,
                Services.description == description)).first(live)
        if not service:
            raise ProblemException(
                status=400,
                title=
                f'Service {description!r}@{host_name!r} could not be found.',
            )
        if not service.state:
            raise ProblemException(
                status=422,
                title=f'Service {description!r}@{host_name!r} has no problem.',
            )
        acknowledge_service_problem(
            live,
            service.host_name,
            service.description,
            sticky=sticky,
            notify=notify,
            persistent=persistent,
            user=config.user.ident,
            comment=comment,
        )
    elif acknowledge_type == 'servicegroup':
        service_group = body['servicegroup_name']
        try:
            acknowledge_servicegroup_problem(
                live,
                service_group,
                sticky=sticky,
                notify=notify,
                persistent=persistent,
                user=config.user.ident,
                comment=comment,
            )
        except ValueError:
            raise ProblemException(
                status=400,
                title="Servicegroup could not be found.",
                detail=f"Unknown servicegroup: {service_group}",
            )
    elif acknowledge_type == 'service_by_query':
        services = Query(
            [Services.host_name, Services.description, Services.state],
            body['query'],
        ).fetchall(live)
        if not services:
            raise ProblemException(
                status=422,
                title='No services with problems found.',
                detail='All queried services are OK.',
            )

        for service in services:
            if not service.state:
                continue
            acknowledge_service_problem(
                live,
                service.host_name,
                service.description,
                sticky=sticky,
                notify=notify,
                persistent=persistent,
                user=config.user.ident,
                comment=comment,
            )
    else:
        raise ProblemException(
            status=400,
            title="Unhandled acknowledge-type.",
            detail=
            f"The acknowledge-type {acknowledge_type!r} is not supported.",
        )

    return http.Response(status=204)
예제 #11
0
def schedule_host_downtime(
    connection,
    host_entry: Union[str, List[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_entry:
            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
        >>> from cmk.gui.config import load_config
        >>> from cmk.gui.utils.script_helpers import application_and_request_context
        >>> from cmk.gui.logged_in import SuperUserContext

        >>> cmd = "COMMAND [...] SCHEDULE_HOST_DOWNTIME;example.com;0;86400;16;0;120;;Boom"
        >>> with simple_expect() as live, application_and_request_context(), SuperUserContext():
        ...     load_config()
        ...     _ = live.expect_query("GET hosts\\nColumns: name\\nFilter: name = example.com")
        ...     _ = live.expect_query(cmd, match_type="ellipsis")
        ...     schedule_host_downtime(live,
        ...             'example.com',
        ...             _start_time,
        ...             _end_time,
        ...             recur="day_of_month",
        ...             duration=120,
        ...             comment="Boom")

    """
    if isinstance(host_entry, str):
        hosts = [host_entry]
    elif host_entry:
        hosts = host_entry
    else:
        raise ValueError("List of hosts may not be empty.")

    with detailed_connection(connection) as conn:
        host_entries = [(entry["site"], entry["name"]) for entry in Query(
            [Hosts.name], Or(*[Hosts.name.equals(host)
                               for host in hosts])).fetchall(conn)]

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

    if include_all_services:
        with detailed_connection(connection) as conn:
            services = Query(
                [tables.Services.host_name, tables.Services.description],
                Or(*[
                    tables.Services.host_name.equals(_host_name)
                    for _, _host_name in host_entries
                ]),
            ).fetch_values(conn)

        for _site, _host_name, service_description in services:
            schedule_service_downtime(
                connection,
                _site,
                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,
            )