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
def delete_downtime(connection, downtime_id): """Delete a scheduled downtime based upon the downtime id""" with detailed_connection(connection) as conn: entry = Query( [Downtimes.is_service], Downtimes.id == downtime_id, ).fetchone(conn) if entry["is_service"]: del_service_downtime(connection, downtime_id, entry["site"]) else: del_host_downtime(connection, downtime_id, entry["site"])
def delete_downtime_with_query(connection, query): """Delete scheduled downtimes based upon a query""" q = Query([Downtimes.id, Downtimes.is_service]).filter(query) with detailed_connection(connection) as conn: downtimes = [(row["site"], row["id"], row["is_service"]) for row in q.iterate(conn)] for site_id, downtime_id, is_service in downtimes: if is_service: del_service_downtime(connection, downtime_id, site_id) else: del_host_downtime(connection, downtime_id, site_id)
def schedule_services_downtimes_with_query( connection, query: QueryExpression, start_time: dt.datetime, end_time: dt.datetime, recur: RecurMode = "fixed", duration: int = 0, user_id: str = "", comment: str = "", ): """Schedule downtimes for services based upon a query""" q = Query( [Services.description, Services.host_name], query, ) with detailed_connection(connection) as conn: result = [(row["site"], row["host_name"], row["description"]) for row in q.iterate(conn)] if not result: raise QueryException for site_id, host_name, service_description in result: if not comment: downtime_comment = f"Downtime for service {service_description}@{host_name}" else: downtime_comment = comment schedule_service_downtime( connection, site_id=site_id, host_name=host_name, service_description=service_description, start_time=start_time, end_time=end_time, recur=recur, duration=duration, user_id=user_id, comment=downtime_comment, )
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 servicegroup 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 servicegroup 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, )
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, )
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)
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, )
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 service group. 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: """ with detailed_connection(connection) as conn: entries = list( Query( [tables.Servicegroups.members], tables.Servicegroups.name.equals(servicegroup_name), ).iterate(conn)) for entry in entries: site = entry["site"] for host_name, service_description in entry["members"]: 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, ) if include_hosts: host_names = _deduplicate( [host for entry in entries for (host, _) in entry["members"]]) schedule_host_downtime( connection, host_entry=host_names, start_time=start_time, end_time=end_time, recur=recur, trigger_id=trigger_id, duration=duration, user_id=user_id, comment=comment, )