Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store config errors and warnings into Configuration attributes #1984

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions shinken/daemons/arbiterdaemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,9 @@ def load_config_file(self):
logger.info("Cutting the hosts and services into parts")
self.confs = self.conf.cut_into_parts()

# Display warnings, no matter if config was correct or not
self.conf.show_warnings()

# The conf can be incorrect here if the cut into parts see errors like
# a realm with hosts and not schedulers for it
if not self.conf.conf_is_correct:
Expand Down
32 changes: 14 additions & 18 deletions shinken/objects/checkmodulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,41 +64,37 @@ def get_check_command(self, t_to_go):

# Should have all properties, or a void check_period
def is_correct(self):
state = True
cls = self.__class__

# Raised all previously saw errors like unknown commands or timeperiods
if self.configuration_errors != []:
state = False
for err in self.configuration_errors:
logger.error("[item::%s] %s", self.get_name(), err)

for prop, entry in cls.properties.items():
if prop not in cls._special_properties:
if not hasattr(self, prop) and entry.required:
logger.warning("[checkmodulation::%s] %s property not set",
self.get_name(), prop)
state = False # Bad boy...
self.configuration_errors.append(
"[checkmodulation::%s] %s property not set" % (
self.get_name(), prop)
)

# Ok now we manage special cases...
# Service part
if not hasattr(self, 'check_command'):
logger.warning("[checkmodulation::%s] do not have any check_command defined",
self.get_name())
state = False
self.configuration_errors.append(
"[checkmodulation::%s] do not have any check_command defined" % (self.get_name())
)
else:
if self.check_command is None:
logger.warning("[checkmodulation::%s] a check_command is missing", self.get_name())
state = False
self.configuration_errors.append(
"[checkmodulation::%s] a check_command is missing" % (self.get_name())
)
if not self.check_command.is_valid():
logger.warning("[checkmodulation::%s] a check_command is invalid", self.get_name())
state = False
self.configuration_errors.append(
"[checkmodulation::%s] a check_command is invalid" % (self.get_name())
)

# Ok just put None as check_period, means 24x7
if not hasattr(self, 'check_period'):
self.check_period = None

return state
return not self.has_errors()


# In the scheduler we need to relink the commandCall with
Expand Down
170 changes: 121 additions & 49 deletions shinken/objects/config.py

Large diffs are not rendered by default.

24 changes: 15 additions & 9 deletions shinken/objects/contact.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,35 +170,41 @@ def get_notification_commands(self, type):
# Check is required prop are set:
# contacts OR contactgroups is need
def is_correct(self):
state = True
cls = self.__class__

# All of the above are checks in the notificationways part
for prop, entry in cls.properties.items():
if prop not in _special_properties:
if not hasattr(self, prop) and entry.required:
logger.error("[contact::%s] %s property not set", self.get_name(), prop)
state = False # Bad boy...
self.configuration_errors.append(
"[contact::%s] %s property not set" % (
self.get_name(), prop
)
)

# There is a case where there is no nw: when there is not special_prop defined
# at all!!
if self.notificationways == []:
for p in _special_properties:
if not hasattr(self, p):
logger.error("[contact::%s] %s property is missing", self.get_name(), p)
state = False
self.configuration_errors.append(
"[contact::%s] %s property is missing" % (
self.get_name(), p
)
)

if hasattr(self, 'contact_name'):
for c in cls.illegal_object_name_chars:
if c in self.contact_name:
logger.error("[contact::%s] %s character not allowed in contact_name",
self.get_name(), c)
state = False
self.configuration_errors.append(
"[contact::%s] %s character not allowed in "
"contact_name" % (self.get_name(), c)
)
else:
if hasattr(self, 'alias'): # take the alias if we miss the contact_name
self.contact_name = self.alias

return state
return not self.has_errors()

# Raise a log entry when a downtime begins
# CONTACT DOWNTIME ALERT:
Expand Down
6 changes: 4 additions & 2 deletions shinken/objects/contactgroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,10 @@ def get_contacts_by_explosion(self, contactgroups):
# so if True here, it must be a loop in HG
# calls... not GOOD!
if self.rec_tag:
logger.error("[contactgroup::%s] got a loop in contactgroup definition",
self.get_name())
self.configuration_errors.append(
"[contactgroup::%s] got a loop in contactgroup definition" % (
self.get_name())
)
if self.has('members'):
return self.members
else:
Expand Down
48 changes: 29 additions & 19 deletions shinken/objects/escalation.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,6 @@ def get_next_notif_time(self, t_wished, status, creation_time, interval):
# template are always correct
# contacts OR contactgroups is need
def is_correct(self):
state = True
cls = self.__class__

# If we got the _time parameters, we are time based. Unless, we are not :)
Expand All @@ -155,37 +154,48 @@ def is_correct(self):
for prop, entry in cls.properties.items():
if prop not in special_properties:
if not hasattr(self, prop) and entry.required:
logger.info('%s: I do not have %s', self.get_name(), prop)
state = False # Bad boy...
self.configuration_errors.append(
'%s: I do not have %s' % (self.get_name(), prop)
)

# Raised all previously saw errors like unknown contacts and co
if self.configuration_errors != []:
state = False
for err in self.configuration_errors:
logger.info(err)

# Ok now we manage special cases...
if not hasattr(self, 'contacts') and not hasattr(self, 'contact_groups'):
logger.info('%s: I do not have contacts nor contact_groups', self.get_name())
state = False
self.configuration_errors.append(
'%s: I do not have contacts nor contact_groups' % (
self.get_name()
)
)

# If time_based or not, we do not check all properties
if self.time_based:
if not hasattr(self, 'first_notification_time'):
logger.info('%s: I do not have first_notification_time', self.get_name())
state = False
self.configuration_errors.append(
'%s: I do not have first_notification_time' % (
self.get_name()
)
)
if not hasattr(self, 'last_notification_time'):
logger.info('%s: I do not have last_notification_time', self.get_name())
state = False
self.configuration_errors.append(
'%s: I do not have last_notification_time' % (
self.get_name()
)
)
else: # we check classical properties
if not hasattr(self, 'first_notification'):
logger.info('%s: I do not have first_notification', self.get_name())
state = False
self.configuration_errors.append(
'%s: I do not have first_notification' % (
self.get_name()
)
)
if not hasattr(self, 'last_notification'):
logger.info('%s: I do not have last_notification', self.get_name())
state = False
self.configuration_errors.append(
'%s: I do not have last_notification' % (
self.get_name()
)
)

return state
return not self.has_errors()


class Escalations(Items):
Expand Down
82 changes: 39 additions & 43 deletions shinken/objects/host.py
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,6 @@ def fill_predictive_missing_parameters(self):
# Check is required prop are set:
# contacts OR contactgroups is need
def is_correct(self):
state = True
cls = self.__class__

source = getattr(self, 'imported_from', 'unknown')
Expand All @@ -692,54 +691,50 @@ def is_correct(self):
for prop, entry in cls.properties.items():
if prop not in special_properties:
if not hasattr(self, prop) and entry.required:
logger.error("[host::%s] %s property not set", self.get_name(), prop)
state = False # Bad boy...

# Then look if we have some errors in the conf
# Juts print warnings, but raise errors
for err in self.configuration_warnings:
logger.warning("[host::%s] %s", self.get_name(), err)

# Raised all previously saw errors like unknown contacts and co
if self.configuration_errors != []:
state = False
for err in self.configuration_errors:
logger.error("[host::%s] %s", self.get_name(), err)
self.configuration_errors.append(
"[host::%s] %s property not set" % (self.get_name(), prop)
)

if not hasattr(self, 'notification_period'):
self.notification_period = None

# Ok now we manage special cases...
if self.notifications_enabled and self.contacts == []:
logger.warning("The host %s has no contacts nor contact_groups in (%s)",
self.get_name(), source)
self.configuration_warnings.append(
"The host %s has no contacts nor contact_groups in (%s)" % (
self.get_name(), source)
)

if getattr(self, 'event_handler', None) and not self.event_handler.is_valid():
logger.error("%s: my event_handler %s is invalid",
self.get_name(), self.event_handler.command)
state = False
self.configuration_errors.append(
"%s: my event_handler %s is invalid" % (self.get_name(),
self.event_handler.command)
)

if getattr(self, 'check_command', None) is None:
logger.error("%s: I've got no check_command", self.get_name())
state = False
self.configuration_errors.append(
"%s: I've got no check_command" % (self.get_name()))
# Ok got a command, but maybe it's invalid
else:
if not self.check_command.is_valid():
logger.error("%s: my check_command %s is invalid",
self.get_name(), self.check_command.command)
state = False
self.configuration_errors.append(
"%s: my check_command %s is invalid" % (self.get_name(),
self.check_command.command)
)
if self.got_business_rule:
if not self.business_rule.is_valid():
logger.error("%s: my business rule is invalid", self.get_name(),)
self.configuration_errors.append(
"%s: my business rule is invalid" % (self.get_name()))
for bperror in self.business_rule.configuration_errors:
logger.error("[host::%s] %s", self.get_name(), bperror)
state = False
self.configuration_errors.append(
"[host::%s] %s" % (self.get_name(), bperror))

if (not hasattr(self, 'notification_interval') and
self.notifications_enabled is True):
logger.error("%s: I've got no notification_interval but "
"I've got notifications enabled", self.get_name())
state = False
self.configuration_errors.append(
("%s: I've got no notification_interval but "
"I've got notifications enabled" % (self.get_name()))
)

# if no check_period, means 24x7, like for services
if not hasattr(self, 'check_period'):
Expand All @@ -748,11 +743,11 @@ def is_correct(self):
if hasattr(self, 'host_name'):
for c in cls.illegal_object_name_chars:
if c in self.host_name:
logger.error("%s: My host_name got the character %s that is not allowed.",
self.get_name(), c)
state = False
self.configuration_errors.append(
("%s: My host_name got the character "
"%s that is not allowed." % (self.get_name(), c)))

return state
return not self.has_errors()


# Search in my service if I've got the service
Expand Down Expand Up @@ -1086,12 +1081,13 @@ def raise_initial_state(self):
# Warning: The results of host 'Server' are stale by 0d 0h 0m 58s (threshold=0d 1h 0m 0s).
# I'm forcing an immediate check of the host.
def raise_freshness_log_entry(self, t_stale_by, t_threshold):
logger.warning("The results of host '%s' are stale by %s "
"(threshold=%s). I'm forcing an immediate check "
"of the host.",
self.get_name(),
format_t_into_dhms_format(t_stale_by),
format_t_into_dhms_format(t_threshold))
self.configuration_warnings.append(
"The results of host '%s' are stale by %s "
"(threshold=%s). I'm forcing an immediate check "
"of the host." % (self.get_name(),
format_t_into_dhms_format(t_stale_by),
format_t_into_dhms_format(t_threshold))
)


# Raise a log entry with a Notification alert like
Expand Down Expand Up @@ -1156,9 +1152,9 @@ def raise_flapping_stop_log_entry(self, change_ratio, threshold):

# If there is no valid time for next check, raise a log entry
def raise_no_next_check_log_entry(self):
logger.warning("I cannot schedule the check for the host '%s' "
"because there is not future valid time",
self.get_name())
self.configuration_warnings.append(
"I cannot schedule the check for the host '%s' "
"because there is not future valid time" % (self.get_name()))


# Raise a log entry when a downtime begins
Expand Down
4 changes: 3 additions & 1 deletion shinken/objects/hostdependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,9 @@ def linkify_hd_by_tp(self, timeperiods):
tp = timeperiods.find_by_name(tp_name)
hd.dependency_period = tp
except AttributeError, exp:
logger.error("[hostdependency] fail to linkify by timeperiod: %s", exp)
hd.configuration_errors.append(
"[hostdependency] fail to linkify by timeperiod: %s" % exp
)

# We backport host dep to host. So HD is not need anymore
def linkify_h_by_hd(self):
Expand Down
5 changes: 1 addition & 4 deletions shinken/objects/hostextinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,7 @@ class HostExtInfo(Item):
# Check is required prop are set:
# host_name is needed
def is_correct(self):
state = True
cls = self.__class__

return state
return True

# For get a nice name
def get_name(self):
Expand Down
14 changes: 11 additions & 3 deletions shinken/objects/hostgroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@ def get_hosts_by_explosion(self, hostgroups):
# so if True here, it must be a loop in HG
# calls... not GOOD!
if self.rec_tag:
logger.error("[hostgroup::%s] got a loop in hostgroup definition", self.get_name())
self.configuration_errors.append(
"[hostgroup::%s] got a loop in hostgroup definition" % (
self.get_name()
)
)
return self.get_hosts()

# Ok, not a loop, we tag it and continue
Expand Down Expand Up @@ -181,8 +185,12 @@ def linkify_hg_by_realms(self, realms):
h.realm = hg.realm
else:
if h.realm != hg.realm:
logger.warning("[hostgroups] host %s it not in the same realm than it's "
"hostgroup %s", h.get_name(), hg.get_name())
self.configuration_warnings.append(
"[hostgroups] host %s it not in the same realm "
"than it's hostgroup %s" % (
h.get_name(), hg.get_name()
)
)

# Add a host string to a hostgroup member
# if the host group do not exist, create it
Expand Down
Loading