2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
10 # | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
11 # +------------------------------------------------------------------+
13 # This file is part of Check_MK.
14 # The official homepage is at http://mathias-kettner.de/check_mk.
16 # check_mk is free software; you can redistribute it and/or modify it
17 # under the terms of the GNU General Public License as published by
18 # the Free Software Foundation in version 2. check_mk is distributed
19 # in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
20 # out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
21 # PARTICULAR PURPOSE. See the GNU General Public License for more de-
22 # tails. You should have received a copy of the GNU General Public
23 # License along with GNU Make; see the file COPYING. If not, write
24 # to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 # Boston, MA 02110-1301 USA.
26 """All core related things like direct communication with the running core"""
33 import cmk
.utils
.paths
34 import cmk
.utils
.debug
35 import cmk
.utils
.tty
as tty
36 from cmk
.utils
.exceptions
import MKGeneralException
, MKTimeout
38 import cmk_base
.console
as console
39 import cmk_base
.config
as config
40 import cmk_base
.core_config
as core_config
41 import cmk_base
.nagios_utils
42 from cmk_base
import config_cache
43 import cmk_base
.cleanup
45 # suppress "Cannot find module" error from mypy
46 import livestatus
# type: ignore
48 _restart_lock_fd
= None
51 # .--Control-------------------------------------------------------------.
53 # | / ___|___ _ __ | |_ _ __ ___ | | |
54 # | | | / _ \| '_ \| __| '__/ _ \| | |
55 # | | |__| (_) | | | | |_| | | (_) | | |
56 # | \____\___/|_| |_|\__|_| \___/|_| |
58 # +----------------------------------------------------------------------+
59 # | Invoke actions affecting the core like reload/restart |
60 # '----------------------------------------------------------------------'
64 do_restart(core
, only_reload
=True)
67 # TODO: Cleanup duplicate code with automation_restart()
68 def do_restart(core
, only_reload
=False):
72 if try_get_activation_lock():
73 # TODO: Replace by MKBailOut()/MKTerminate()?
74 console
.error("Other restart currently in progress. Aborting.\n")
77 # Save current configuration
78 if os
.path
.exists(cmk
.utils
.paths
.nagios_objects_file
):
79 backup_path
= cmk
.utils
.paths
.nagios_objects_file
+ ".save"
81 "Renaming %s to %s\n",
82 cmk
.utils
.paths
.nagios_objects_file
,
85 os
.rename(cmk
.utils
.paths
.nagios_objects_file
, backup_path
)
90 core_config
.do_create_config(core
, with_agents
=True)
91 except Exception as e
:
92 # TODO: Replace by MKBailOut()/MKTerminate()?
93 console
.error("Error creating configuration: %s\n" % e
)
95 os
.rename(backup_path
, cmk
.utils
.paths
.nagios_objects_file
)
96 if cmk
.utils
.debug
.enabled():
100 if config
.monitoring_core
== "cmc" or cmk_base
.nagios_utils
.do_check_nagiosconfig():
102 os
.remove(backup_path
)
106 do_core_action(only_reload
and "reload" or "restart")
108 # TODO: Replace by MKBailOut()/MKTerminate()?
109 console
.error("Configuration for monitoring core is invalid. Rolling back.\n")
111 broken_config_path
= "%s/check_mk_objects.cfg.broken" % cmk
.utils
.paths
.tmp_dir
112 file(broken_config_path
, "w").write(file(cmk
.utils
.paths
.nagios_objects_file
).read())
114 "The broken file has been copied to \"%s\" for analysis.\n" % broken_config_path
)
117 os
.rename(backup_path
, cmk
.utils
.paths
.nagios_objects_file
)
119 os
.remove(cmk
.utils
.paths
.nagios_objects_file
)
122 except Exception as e
:
124 if backup_path
and os
.path
.exists(backup_path
):
125 os
.remove(backup_path
)
128 if cmk
.utils
.debug
.enabled():
130 # TODO: Replace by MKBailOut()/MKTerminate()?
131 console
.error("An error occurred: %s\n" % e
)
135 def try_get_activation_lock():
136 global _restart_lock_fd
137 # In some bizarr cases (as cmk -RR) we need to avoid duplicate locking!
138 if config
.restart_locking
and _restart_lock_fd
is None:
139 lock_file
= cmk
.utils
.paths
.default_config_dir
+ "/main.mk"
140 _restart_lock_fd
= os
.open(lock_file
, os
.O_RDONLY
)
141 # Make sure that open file is not inherited to monitoring core!
142 fcntl
.fcntl(_restart_lock_fd
, fcntl
.F_SETFD
, fcntl
.FD_CLOEXEC
)
144 console
.verbose("Waiting for exclusive lock on %s.\n" % lock_file
, stream
=sys
.stderr
)
145 fcntl
.flock(_restart_lock_fd
,
146 fcntl
.LOCK_EX |
(config
.restart_locking
== "abort" and fcntl
.LOCK_NB
or 0))
152 # Action can be restart, reload, start or stop
153 def do_core_action(action
, quiet
=False):
155 console
.output("%sing monitoring core..." % action
.title())
157 if config
.monitoring_core
== "nagios":
158 os
.putenv("CORE_NOVERIFY", "yes")
159 command
= ["%s/etc/init.d/core" % cmk
.utils
.paths
.omd_root
, action
]
161 command
= ["omd", action
, "cmc"]
163 p
= subprocess
.Popen(command
, stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
, close_fds
=True)
166 output
= p
.stdout
.read()
168 console
.output("ERROR: %s\n" % output
)
169 raise MKGeneralException("Cannot %s the monitoring core: %s" % (action
, output
))
172 console
.output(tty
.ok
+ "\n")
176 # .--Timeperiods---------------------------------------------------------.
178 # | |_ _(_)_ __ ___ ___ _ __ ___ _ __(_) ___ __| |___ |
179 # | | | | | '_ ` _ \ / _ \ '_ \ / _ \ '__| |/ _ \ / _` / __| |
180 # | | | | | | | | | | __/ |_) | __/ | | | (_) | (_| \__ \ |
181 # | |_| |_|_| |_| |_|\___| .__/ \___|_| |_|\___/ \__,_|___/ |
183 # +----------------------------------------------------------------------+
184 # | Fetching timeperiods from the core |
185 # '----------------------------------------------------------------------'
188 # Check if a timeperiod is currently active. We have no other way than
189 # doing a Livestatus query. This is not really nice, but if you have a better
190 # idea, please tell me...
191 def check_timeperiod(timeperiod
):
192 # Let exceptions happen, they will be handled upstream.
194 update_timeperiods_cache()
199 if cmk
.utils
.debug
.enabled():
202 # If the query is not successful better skip this check then fail
205 # Note: This also returns True when the timeperiod is unknown
206 # The following function timeperiod_active handles this differently
207 return config_cache
.get_dict("timeperiods_cache").get(timeperiod
, True)
213 # None : unknown timeperiod
215 # Raises an exception if e.g. a timeout or connection error appears.
216 # This way errors can be handled upstream.
217 def timeperiod_active(timeperiod
):
218 update_timeperiods_cache()
219 return config_cache
.get_dict("timeperiods_cache").get(timeperiod
)
222 def update_timeperiods_cache():
223 # { "last_update": 1498820128, "timeperiods": [{"24x7": True}] }
224 # The value is store within the config cache since we need a fresh start on reload
225 tp_cache
= config_cache
.get_dict("timeperiods_cache")
228 response
= livestatus
.LocalConnection().query("GET timeperiods\nColumns: name in")
229 for tp_name
, tp_active
in response
:
230 tp_cache
[tp_name
] = bool(tp_active
)
233 def cleanup_timeperiod_caches():
234 config_cache
.get_dict("timeperiods_cache").clear()
237 cmk_base
.cleanup
.register_cleanup(cleanup_timeperiod_caches
)