void Downtime::TriggerDowntime(void) { if (!CanBeTriggered()) return; Log(LogNotice, "Downtime") << "Triggering downtime '" << GetName() << "'."; if (GetTriggerTime() == 0) SetTriggerTime(Utility::GetTime()); Array::Ptr triggers = GetTriggers(); { ObjectLock olock(triggers); for (const String& triggerName : triggers) { Downtime::Ptr downtime = Downtime::GetByName(triggerName); if (!downtime) continue; downtime->TriggerDowntime(); } } OnDowntimeTriggered(this); }
Value DowntimesTable::IsServiceAccessor(const Value& row) { Downtime::Ptr downtime = static_cast<Downtime::Ptr>(row); Checkable::Ptr checkable = downtime->GetCheckable(); return (dynamic_pointer_cast<Host>(checkable) ? 0 : 1); }
void Checkable::NotifyDowntimeEnd(const Downtime::Ptr& downtime) { /* don't send notifications for flexible downtimes which never triggered */ if (!downtime->GetFixed() && !downtime->IsTriggered()) return; Checkable::Ptr checkable = downtime->GetCheckable(); if (!checkable->IsPaused()) OnNotificationsRequested(checkable, NotificationDowntimeEnd, checkable->GetLastCheckResult(), downtime->GetAuthor(), downtime->GetComment(), nullptr); }
Object::Ptr DowntimesTable::ServiceAccessor(const Value& row, const Column::ObjectAccessor&) { Downtime::Ptr downtime = static_cast<Downtime::Ptr>(row); Checkable::Ptr checkable = downtime->GetCheckable(); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); return service; }
Value DowntimesTable::TriggeredByAccessor(const Value& row) { Downtime::Ptr downtime = static_cast<Downtime::Ptr>(row); String triggerDowntimeName = downtime->GetTriggeredBy(); Downtime::Ptr triggerDowntime = Downtime::GetByName(triggerDowntimeName); if (triggerDowntime) return triggerDowntime->GetLegacyId(); return Empty; }
String DowntimeNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const { Downtime::Ptr downtime = dynamic_pointer_cast<Downtime>(context); if (!downtime) return ""; String name = downtime->GetHostName(); if (!downtime->GetServiceName().IsEmpty()) name += "!" + downtime->GetServiceName(); name += "!" + shortName; return name; }
void Checkable::NotifyFlexibleDowntimeStart(const Downtime::Ptr& downtime) { if (downtime->GetFixed()) return; NotifyDowntimeInternal(downtime); }
void Checkable::NotifyDowntimeInternal(const Downtime::Ptr& downtime) { Checkable::Ptr checkable = downtime->GetCheckable(); if (!checkable->IsPaused()) OnNotificationsRequested(checkable, NotificationDowntimeStart, checkable->GetLastCheckResult(), downtime->GetAuthor(), downtime->GetComment(), nullptr); }
/** * @threadsafety Always. */ void CompatLogger::TriggerDowntimeHandler(const Downtime::Ptr& downtime) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(downtime->GetCheckable()); if (!downtime) return; std::ostringstream msgbuf; if (service) { msgbuf << "SERVICE DOWNTIME ALERT: " << host->GetName() << ";" << service->GetShortName() << ";" << "STARTED" << "; " << "Checkable has entered a period of scheduled downtime." << ""; } else { msgbuf << "HOST DOWNTIME ALERT: " << host->GetName() << ";" << "STARTED" << "; " << "Checkable has entered a period of scheduled downtime." << ""; } { ObjectLock oLock(this); WriteLine(msgbuf.str()); Flush(); } }
void Downtime::RemoveDowntime(const String& id, bool cancelled, bool expired, const MessageOrigin::Ptr& origin) { Downtime::Ptr downtime = Downtime::GetByName(id); if (!downtime) return; String config_owner = downtime->GetConfigOwner(); if (!config_owner.IsEmpty() && !expired) { Log(LogWarning, "Downtime") << "Cannot remove downtime '" << downtime->GetName() << "'. It is owned by scheduled downtime object '" << config_owner << "'"; return; } downtime->SetWasCancelled(cancelled); Log(LogNotice, "Downtime") << "Removed downtime '" << downtime->GetName() << "' from object '" << downtime->GetCheckable()->GetName() << "'."; if (downtime->GetPackage() != "_api") return; Array::Ptr errors = new Array(); if (!ConfigObjectUtility::DeleteObject(downtime, false, errors)) { ObjectLock olock(errors); for (const String& error : errors) { Log(LogCritical, "Downtime", error); } BOOST_THROW_EXCEPTION(std::runtime_error("Could not remove downtime.")); } }
/** * @threadsafety Always. */ void CompatLogger::RemoveDowntimeHandler(const Downtime::Ptr& downtime) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(downtime->GetCheckable()); if (!downtime) return; String downtime_output; String downtime_state_str; if (downtime->GetWasCancelled()) { downtime_output = "Scheduled downtime for service has been cancelled."; downtime_state_str = "CANCELLED"; } else { downtime_output = "Checkable has exited from a period of scheduled downtime."; downtime_state_str = "STOPPED"; } std::ostringstream msgbuf; if (service) { msgbuf << "SERVICE DOWNTIME ALERT: " << host->GetName() << ";" << service->GetShortName() << ";" << downtime_state_str << "; " << downtime_output << ""; } else { msgbuf << "HOST DOWNTIME ALERT: " << host->GetName() << ";" << downtime_state_str << "; " << downtime_output << ""; } { ObjectLock oLock(this); WriteLine(msgbuf.str()); Flush(); } }
void Checkable::RemoveDowntime(const String& id, bool cancelled, const MessageOrigin::Ptr& origin) { Checkable::Ptr owner = GetOwnerByDowntimeID(id); if (!owner) return; Dictionary::Ptr downtimes = owner->GetDowntimes(); Downtime::Ptr downtime = downtimes->Get(id); if (!downtime) return; int legacy_id = downtime->GetLegacyId(); String config_owner = downtime->GetConfigOwner(); if (!config_owner.IsEmpty()) { Log(LogWarning, "Checkable") << "Cannot remove downtime with ID '" << legacy_id << "'. It is owned by scheduled downtime object '" << config_owner << "'"; return; } downtimes->Remove(id); { boost::mutex::scoped_lock lock(l_DowntimeMutex); l_LegacyDowntimesCache.erase(legacy_id); l_DowntimesCache.erase(id); } downtime->SetWasCancelled(cancelled); Log(LogNotice, "Checkable") << "Removed downtime with ID '" << downtime->GetLegacyId() << "' from service '" << owner->GetName() << "'."; OnDowntimeRemoved(owner, downtime, origin); }
Dictionary::Ptr ApiActions::ScheduleDowntime(const ConfigObject::Ptr& object, const Dictionary::Ptr& params) { Checkable::Ptr checkable = static_pointer_cast<Checkable>(object); if (!checkable) return ApiActions::CreateResult(404, "Can't schedule downtime for non-existent object."); if (!params->Contains("start_time") || !params->Contains("end_time") || !params->Contains("duration") || !params->Contains("author") || !params->Contains("comment")) { return ApiActions::CreateResult(404, "Options 'start_time', 'end_time', 'duration', 'author' and 'comment' are required"); } bool fixed = false; if (params->Contains("fixed")) fixed = HttpUtility::GetLastParameter(params, "fixed"); String downtime_id = Downtime::AddDowntime(checkable, HttpUtility::GetLastParameter(params, "author"), HttpUtility::GetLastParameter(params, "comment"), HttpUtility::GetLastParameter(params, "start_time"), HttpUtility::GetLastParameter(params, "end_time"), fixed, HttpUtility::GetLastParameter(params, "trigger_id"), HttpUtility::GetLastParameter(params, "duration")); Downtime::Ptr downtime = Downtime::GetByName(downtime_id); int legacy_id = downtime->GetLegacyId(); Dictionary::Ptr additional = new Dictionary(); additional->Set("downtime_id", downtime_id); additional->Set("legacy_id", legacy_id); return ApiActions::CreateResult(200, "Successfully scheduled downtime with id '" + downtime_id + "' for object '" + checkable->GetName() + "'.", additional); }
void StatusDataWriter::DumpDowntimes(std::ostream& fp, const Checkable::Ptr& checkable) { Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); for (const Downtime::Ptr& downtime : checkable->GetDowntimes()) { if (downtime->IsExpired()) continue; if (service) fp << "servicedowntime {" << "\n" "\t" "service_description=" << service->GetShortName() << "\n"; else fp << "hostdowntime {" "\n"; Downtime::Ptr triggeredByObj = Downtime::GetByName(downtime->GetTriggeredBy()); int triggeredByLegacy = 0; if (triggeredByObj) triggeredByLegacy = triggeredByObj->GetLegacyId(); fp << "\t" << "host_name=" << host->GetName() << "\n" "\t" "downtime_id=" << downtime->GetLegacyId() << "\n" "\t" "entry_time=" << downtime->GetEntryTime() << "\n" "\t" "start_time=" << downtime->GetStartTime() << "\n" "\t" "end_time=" << downtime->GetEndTime() << "\n" "\t" "triggered_by=" << triggeredByLegacy << "\n" "\t" "fixed=" << static_cast<long>(downtime->GetFixed()) << "\n" "\t" "duration=" << static_cast<long>(downtime->GetDuration()) << "\n" "\t" "is_in_effect=" << (downtime->IsInEffect() ? 1 : 0) << "\n" "\t" "author=" << downtime->GetAuthor() << "\n" "\t" "comment=" << downtime->GetComment() << "\n" "\t" "trigger_time=" << downtime->GetTriggerTime() << "\n" "\t" "}" "\n" "\n"; } }
String Downtime::AddDowntime(const Checkable::Ptr& checkable, const String& author, const String& comment, double startTime, double endTime, bool fixed, const String& triggeredBy, double duration, const String& scheduledDowntime, const String& scheduledBy, const String& id, const MessageOrigin::Ptr& origin) { String fullName; if (id.IsEmpty()) fullName = checkable->GetName() + "!" + Utility::NewUniqueID(); else fullName = id; Dictionary::Ptr attrs = new Dictionary(); attrs->Set("author", author); attrs->Set("comment", comment); attrs->Set("start_time", startTime); attrs->Set("end_time", endTime); attrs->Set("fixed", fixed); attrs->Set("duration", duration); attrs->Set("triggered_by", triggeredBy); attrs->Set("scheduled_by", scheduledBy); attrs->Set("config_owner", scheduledDowntime); attrs->Set("entry_time", Utility::GetTime()); Host::Ptr host; Service::Ptr service; tie(host, service) = GetHostService(checkable); attrs->Set("host_name", host->GetName()); if (service) attrs->Set("service_name", service->GetShortName()); String zone = checkable->GetZoneName(); if (!zone.IsEmpty()) attrs->Set("zone", zone); String config = ConfigObjectUtility::CreateObjectConfig(Downtime::TypeInstance, fullName, true, Array::Ptr(), attrs); Array::Ptr errors = new Array(); if (!ConfigObjectUtility::CreateObject(Downtime::TypeInstance, fullName, config, errors)) { ObjectLock olock(errors); for (const String& error : errors) { Log(LogCritical, "Downtime", error); } BOOST_THROW_EXCEPTION(std::runtime_error("Could not create downtime.")); } if (!triggeredBy.IsEmpty()) { Downtime::Ptr parentDowntime = Downtime::GetByName(triggeredBy); Array::Ptr triggers = parentDowntime->GetTriggers(); ObjectLock olock(triggers); if (!triggers->Contains(fullName)) triggers->Add(fullName); } Downtime::Ptr downtime = Downtime::GetByName(fullName); if (!downtime) BOOST_THROW_EXCEPTION(std::runtime_error("Could not create downtime object.")); Log(LogNotice, "Downtime") << "Added downtime '" << downtime->GetName() << "' between '" << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", startTime) << "' and '" << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", endTime) << "'."; return fullName; }
Value DowntimesTable::CommentAccessor(const Value& row) { Downtime::Ptr downtime = static_cast<Downtime::Ptr>(row); return downtime->GetComment(); }
Value DowntimesTable::TypeAccessor(const Value& row) { Downtime::Ptr downtime = static_cast<Downtime::Ptr>(row); // 1 .. active, 0 .. pending return (downtime->IsInEffect() ? 1 : 0); }
Value DowntimesTable::EndTimeAccessor(const Value& row) { Downtime::Ptr downtime = static_cast<Downtime::Ptr>(row); return static_cast<int>(downtime->GetEndTime()); }
String Checkable::AddDowntime(const String& author, const String& comment, double startTime, double endTime, bool fixed, const String& triggeredBy, double duration, const String& scheduledBy, const String& id, const MessageOrigin::Ptr& origin) { String uid; if (id.IsEmpty()) uid = Utility::NewUniqueID(); else uid = id; Downtime::Ptr downtime = new Downtime(); downtime->SetId(uid); downtime->SetEntryTime(Utility::GetTime()); downtime->SetAuthor(author); downtime->SetComment(comment); downtime->SetStartTime(startTime); downtime->SetEndTime(endTime); downtime->SetFixed(fixed); downtime->SetDuration(duration); downtime->SetTriggeredBy(triggeredBy); downtime->SetScheduledBy(scheduledBy); if (!triggeredBy.IsEmpty()) { Downtime::Ptr triggerDowntime = GetDowntimeByID(triggeredBy); if (triggerDowntime) downtime->SetTriggeredByLegacyId(triggerDowntime->GetLegacyId()); } int legacy_id; { boost::mutex::scoped_lock lock(l_DowntimeMutex); legacy_id = l_NextDowntimeID++; } downtime->SetLegacyId(legacy_id); if (!triggeredBy.IsEmpty()) { Checkable::Ptr otherOwner = GetOwnerByDowntimeID(triggeredBy); Dictionary::Ptr otherDowntimes = otherOwner->GetDowntimes(); Downtime::Ptr otherDowntime = otherDowntimes->Get(triggeredBy); Dictionary::Ptr triggers = otherDowntime->GetTriggers(); triggers->Set(triggeredBy, triggeredBy); } GetDowntimes()->Set(uid, downtime); { boost::mutex::scoped_lock lock(l_DowntimeMutex); l_LegacyDowntimesCache[legacy_id] = uid; l_DowntimesCache[uid] = this; } Log(LogNotice, "Checkable") << "Added downtime with ID '" << downtime->GetLegacyId() << "' between '" << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", startTime) << "' and '" << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", endTime) << "'."; OnDowntimeAdded(this, downtime, origin); /* if this object is already in a NOT-OK state trigger * this downtime now *after* it has been added (important * for DB IDO, etc.) */ if (GetStateRaw() != ServiceOK) { Log(LogNotice, "Checkable") << "Checkable '" << GetName() << "' already in a NOT-OK state." << " Triggering downtime now."; TriggerDowntime(uid); } return uid; }
Value DowntimesTable::FixedAccessor(const Value& row) { Downtime::Ptr downtime = static_cast<Downtime::Ptr>(row); return downtime->GetFixed(); }
String Checkable::AddDowntime(const String& author, const String& comment, double startTime, double endTime, bool fixed, const String& triggeredBy, double duration, const String& scheduledBy, const String& id, const MessageOrigin& origin) { String uid; if (id.IsEmpty()) uid = Utility::NewUniqueID(); else uid = id; Downtime::Ptr downtime = make_shared<Downtime>(); downtime->SetId(uid); downtime->SetEntryTime(Utility::GetTime()); downtime->SetAuthor(author); downtime->SetComment(comment); downtime->SetStartTime(startTime); downtime->SetEndTime(endTime); downtime->SetFixed(fixed); downtime->SetDuration(duration); downtime->SetTriggeredBy(triggeredBy); downtime->SetScheduledBy(scheduledBy); if (!triggeredBy.IsEmpty()) { Downtime::Ptr triggerDowntime = GetDowntimeByID(triggeredBy); if (triggerDowntime) downtime->SetTriggeredByLegacyId(triggerDowntime->GetLegacyId()); } int legacy_id; { boost::mutex::scoped_lock lock(l_DowntimeMutex); legacy_id = l_NextDowntimeID++; } downtime->SetLegacyId(legacy_id); if (!triggeredBy.IsEmpty()) { Checkable::Ptr otherOwner = GetOwnerByDowntimeID(triggeredBy); Dictionary::Ptr otherDowntimes = otherOwner->GetDowntimes(); Downtime::Ptr otherDowntime = otherDowntimes->Get(triggeredBy); Dictionary::Ptr triggers = otherDowntime->GetTriggers(); triggers->Set(triggeredBy, triggeredBy); } GetDowntimes()->Set(uid, downtime); { boost::mutex::scoped_lock lock(l_DowntimeMutex); l_LegacyDowntimesCache[legacy_id] = uid; l_DowntimesCache[uid] = GetSelf(); } Log(LogNotice, "Checkable", "Added downtime with ID '" + Convert::ToString(downtime->GetLegacyId()) + "' between '" + Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", startTime) + "' and '" + Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", endTime) + "'."); OnDowntimeAdded(GetSelf(), downtime, origin); return uid; }
Value DowntimesTable::AuthorAccessor(const Value& row) { Downtime::Ptr downtime = static_cast<Downtime::Ptr>(row); return downtime->GetAuthor(); }
Value DowntimesTable::DurationAccessor(const Value& row) { Downtime::Ptr downtime = static_cast<Downtime::Ptr>(row); return downtime->GetDuration(); }